Search code examples
linuxnasmsystem-callsvt100

VT-100 commands are working strangely


I'm writing simple clock program with NASM. I'm using Ubuntu 14.10 Vagrant box under OSX via iTerm. Terminal is xterm, so should be VT-100 compatible.

I need to remove one line. For instance, I expect the following behaviour:

Hello, this is clock program
13:01:25 UTC+4

Next moment:

Hello, this is clock program
13:01:26 UTC+4

I wrote the following functions. For print:

func_print:
  mov eax, sys_write
  mov ebx, stdout
  int 0x80
  ret

For clear:

clr          db 0x1b,  "[K"
clr_len      equ $-clr
...
func_clear:
  mov ecx, clr
  mov edx, clr_len
  call func_print

For saving and restoring positions I use VT-100 and its commands: [7 and [8 respectively:

csave db     0x1b, "[7"
csave_len    equ $-csave

crestore     db 0x1b, "[8"
crestore_len equ $-crestore

My code:

global  _start
  _start:
    mov ecx, welcome
    mov edx, welcome_len
    call func_print

    call func_print
    call func_save_cursor_pos

    mov dword [tv_sec], 2
    mov dword [tv_usec], 0

    call func_sleep
    call func_clear

    call func_restore_cursor_pos
    mov ecx, welcome
    mov edx, welcome_len
    call func_print

    jmp func_exit

However, the result is:

vagrant@vagrant-ubuntu-trusty-64:~$ ./run.sh
Hello, this is the clock program
Hello, this is the clock program
Hello, this is the clock program
vagrant@vagrant-ubuntu-trusty-64:~$

If I change clr by adding [1A or [1B it seems to be removing lines to much higher than needed or lower:

vagrant@vagrant-ubuntu-trusty-64:~$ ./run.sh
Hello, this is the clock program
Hello, this is the clock program








Hello, this is the clock program
vagrant@vagrant-ubuntu-trusty-64:~$

How can I fix it? What is the correct code?


Solution

  • I suspect that your issue is related to the newline implied to be in welcome db "Hello, this is the clock program", 10. I can't tell for sure because you didn't post that part of your code.

    I think that this causes an issue because the newline causes the terminal to scroll - when I removed the newline from my version, it worked properly. If you only need to update one line, it works to just not have a newline.

    I suspect that the save and restore operations work on literal physical locations on the screen - not logical locations that get scrolled by newlines.

    In general, however, I'd recommend using the cursor manipulation escape codes instead:

    • When you're ready to redraw your output, write db 0x1b, "[nA" to move up n lines. (You'll need to put the number in there.)
    • Immediately after that (or after any subsequent newline), write db 0x1b, "[K" to clear that line. (You already knew this, but I'm including it for completeness.)

    I wrote an example program to implement this, based partially on yours. It displays:

    Hello, this is the clock program.
    Line two.
    

    Then, a short while later

    === TEST ===
    More.
    

    And then

    === TEST 2 ===
    Again.
    

    This technique should be generalizable to any reasonable number of lines.

    BITS 32
    section .text
    
    welcome      db "Hello, this is the clock program", 10, "Line two.", 10
    welcome_len  equ $-welcome
    
    test_str     db 0x1b, "[2A", 0x1b, "[K=== TEST ===", 10, 0x1b, "[KMore.", 10
    test_len     equ $-test_str
    
    test2_str     db 0x1b, "[2A", 0x1b, "[K=== TEST 2 ===", 10, 0x1b, "[KAgain.", 10
    test2_len     equ $-test2_str
    
    func_print:
        mov eax, 4
        mov ebx, 1
        int 0x80
        ret
    
    pause: ; Note: DON'T EVER USE THIS IN A REAL PROGRAM. This is not how you sleep properly.
        mov eax, 0
    loop:
        inc eax
        cmp eax, 1000000000
        jl loop
        ret
    
    global  _start
    _start:
        mov ecx, welcome
        mov edx, welcome_len
        call func_print
    
        call pause
    
        mov ecx, test_str
        mov edx, test_len
        call func_print
    
        call pause
    
        mov ecx, test2_str
        mov edx, test2_len
        call func_print
    
        mov eax, 1
        mov ebx, 0
        int 0x80