about summary refs log tree commit diff stats
path: root/linux/304screen.subx
diff options
context:
space:
mode:
Diffstat (limited to 'linux/304screen.subx')
-rw-r--r--linux/304screen.subx460
1 files changed, 460 insertions, 0 deletions
diff --git a/linux/304screen.subx b/linux/304screen.subx
new file mode 100644
index 00000000..8a8df8f9
--- /dev/null
+++ b/linux/304screen.subx
@@ -0,0 +1,460 @@
+# 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
+    81 4/subop/and %eax 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 grapheme in utf-8 (only up to 4 bytes so far)
+print-grapheme-to-real-screen:  # c: grapheme
+    # . 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-grapheme-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-grapheme-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-grapheme-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-grapheme-to-real-screen:end/disp8
+    #
+    (print-byte-to-real-screen %eax)
+$print-grapheme-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