mu/linux/304screen.subx

461 lines
11 KiB
Plaintext

# Primitives for screen control.
# Require Linux and a modern terminal.
== code
enable-screen-grid-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(flush Stdout)
(flush Stderr)
# switch to second screen buffer
(write 1 Esc)
(write 1 "[?1049h")
#
(clear-real-screen)
$enable-screen-grid-mode:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
enable-screen-type-mode:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# switch to first screen buffer
(write 1 Esc)
(write 1 "[?1049l")
$enable-screen-type-mode:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
real-screen-size: # -> nrows/eax: int, ncols/ecx: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
52/push-edx
53/push-ebx
56/push-esi
57/push-edi
#
(_maybe-open-terminal)
# var window-size-info/esi: (addr winsize)
# winsize is a type from the Linux kernel. We don't care how large it is.
81 5/subop/subtract %esp 0x40/imm32
89/<- %esi 4/r32/esp
# ioctl(*Terminal-file-descriptor, TIOCGWINSZ, window-size-info)
89/<- %edx 6/r32/esi
b9/copy-to-ecx 0x5413/imm32/TIOCGWINSZ
8b/-> *Terminal-file-descriptor 3/r32/ebx
e8/call syscall_ioctl/disp32
# some bitworking to extract 2 16-bit shorts
8b/-> *esi 0/r32/eax
25/and-eax-with 0xffff/imm32
8b/-> *esi 1/r32/ecx
c1/shift 5/subop/logical-right %ecx 0x10/imm8
$real-screen-size:end:
# . reclaim locals
81 0/subop/add %esp 0x40/imm32
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5b/pop-to-ebx
5a/pop-to-edx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
clear-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[H")
(write 1 Esc)
(write 1 "[2J")
$clear-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# row and col count from the top-left as (1, 1)
move-cursor-on-real-screen: # row: int, column: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var buf/ecx: (stream byte 32)
81 5/subop/subtract %esp 0x20/imm32
68/push 0x20/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
# construct directive in buf
(write %ecx Esc)
(write %ecx "[")
(write-int32-decimal %ecx *(ebp+8))
(write %ecx ";")
(write-int32-decimal %ecx *(ebp+0xc))
(write %ecx "H")
# flush
(write-stream 2 %ecx)
$move-cursor-on-real-screen:end:
# . reclaim locals
81 0/subop/add %esp 0x2c/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-string-to-real-screen: # s: (addr array byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 *(ebp+8))
$print-string-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-slice-to-real-screen: # s: (addr slice)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-slice-buffered Stdout *(ebp+8))
(flush Stdout)
$print-slice-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-stream-to-real-screen: # s: (addr stream byte)
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-stream-data Stdout *(ebp+8))
(flush Stdout)
$print-stream-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# print a code-point-utf8 in utf-8 (only up to 4 bytes so far)
print-code-point-utf8-to-real-screen: # c: code-point-utf8
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
50/push-eax
# var curr/eax: byte = 0
b8/copy-to-eax 0/imm32
# curr = *(ebp+8)
8a/byte-> *(ebp+8) 0/r32/al
# if (curr == 0) return
3d/compare-eax-and 0/imm32
74/jump-if-= $print-code-point-utf8-to-real-screen:end/disp8
#
(print-byte-to-real-screen %eax)
# curr = *(ebp+9)
8a/byte-> *(ebp+9) 0/r32/al
# if (curr == 0) return
3d/compare-eax-and 0/imm32
74/jump-if-= $print-code-point-utf8-to-real-screen:end/disp8
#
(print-byte-to-real-screen %eax)
# curr = *(ebp+10)
8a/byte-> *(ebp+0xa) 0/r32/al
# if (curr == 0) return
3d/compare-eax-and 0/imm32
74/jump-if-= $print-code-point-utf8-to-real-screen:end/disp8
#
(print-byte-to-real-screen %eax)
# curr = *(ebp+11)
8a/byte-> *(ebp+0xb) 0/r32/al
# if (curr == 0) return
3d/compare-eax-and 0/imm32
74/jump-if-= $print-code-point-utf8-to-real-screen:end/disp8
#
(print-byte-to-real-screen %eax)
$print-code-point-utf8-to-real-screen:end:
# . restore registers
58/pop-to-eax
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-byte-to-real-screen: # c: byte
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var s/ecx: (addr array byte)
ff 6/subop/push *(ebp+8)
68/push 1/imm32/size
89/<- %ecx 4/r32/esp
(write 1 %ecx)
$print-byte-to-real-screen:end:
# . reclaim locals
81 0/subop/add %esp 8/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-int32-hex-to-real-screen: # n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-int32-hex-buffered Stdout *(ebp+8))
(flush Stdout)
$print-int32-hex-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-int32-hex-bits-to-real-screen: # n: int, bits: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-int32-hex-bits-buffered Stdout *(ebp+8) *(ebp+0xc) *(ebp+0x10))
(flush Stdout)
$print-int32-hex-bits-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
print-int32-decimal-to-real-screen: # n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write-int32-decimal-buffered Stdout *(ebp+8))
(flush Stdout)
$print-int32-decimal-to-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
write-int32-decimal-buffered: # f: (addr buffered-file), n: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var ecx: (stream byte 16)
81 5/subop/subtract %esp 0x10/imm32
68/push 0x10/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
(write-int32-decimal %ecx *(ebp+0xc))
(write-stream-data *(ebp+8) %ecx)
$write-int32-decimal-buffered:end:
# . reclaim locals
81 0/subop/add %esp 0x1c/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
reset-formatting-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "(B")
(write 1 Esc)
(write 1 "[m")
$reset-formatting-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-color-on-real-screen: # fg: int, bg: int
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
# . save registers
51/push-ecx
# var buf/ecx: (stream byte 32)
81 5/subop/subtract %esp 0x20/imm32
68/push 0x20/imm32/size
68/push 0/imm32/read
68/push 0/imm32/write
89/<- %ecx 4/r32/esp
# construct directive in buf
# . set fg
(write %ecx Esc)
(write %ecx "[38;5;")
(write-int32-decimal %ecx *(ebp+8))
(write %ecx "m")
# . set bg
(write %ecx Esc)
(write %ecx "[48;5;")
(write-int32-decimal %ecx *(ebp+0xc))
(write %ecx "m")
# flush
(write-stream 2 %ecx)
$start-color-on-real-screen:end:
# . reclaim locals
81 0/subop/add %esp 0x2c/imm32
# . restore registers
59/pop-to-ecx
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-bold-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[1m")
$start-bold-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-underline-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[4m")
$start-underline-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
start-reverse-video-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[7m")
$start-reverse-video-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# might require enabling blinking in your terminal program
start-blinking-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[5m")
$start-blinking-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
hide-cursor-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[?25l")
$hide-cursor-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
show-cursor-on-real-screen:
# . prologue
55/push-ebp
89/<- %ebp 4/r32/esp
#
(write 1 Esc)
(write 1 "[?12l")
(write 1 Esc)
(write 1 "[?25h")
$show-cursor-on-real-screen:end:
# . epilogue
89/<- %esp 5/r32/ebp
5d/pop-to-ebp
c3/return
# This is a low-level detail; I don't think everything should be a file.
#
# Open "/dev/tty" if necessary and cache its file descriptor in Terminal-file-descriptor
# where later primitives can use it.
_maybe-open-terminal:
81 7/subop/compare *Terminal-file-descriptor -1/imm32
75/jump-if-!= $_maybe-open-terminal:epilogue/disp8
# . save registers
50/push-eax
51/push-ecx
53/push-ebx
# open("/dev/tty", O_RDWR)
bb/copy-to-ebx Terminal-filename/imm32
b9/copy-to-ecx 2/imm32/O_RDWR
e8/call syscall_open/disp32
89/<- *Terminal-file-descriptor 0/r32/eax
$_maybe-open-terminal:end:
# . restore registers
5b/pop-to-ebx
59/pop-to-ecx
58/pop-to-eax
$_maybe-open-terminal:epilogue:
c3/return
== data
Terminal-file-descriptor: # (addr int)
-1/imm32
Esc: # (addr array byte)
# size
1/imm32
# data
0x1b
Terminal-filename: # (addr kernel-string)
# "/dev/tty"
2f/slash 64/d 65/e 76/v 2f/slash 74/t 74/t 79/y 0/nul
# on Linux console
#? # "/dev/console"
#? 2f/slash 64/d 65/e 76/v 2f/slash 63/c 6f/o 6e/n 73/s 6f/o 6c/l 65/e 0/nul