user2835994
user2835994

Reputation: 3

Wait for user input witout enter, linux x86 assembler

im trying to program in assembler and i need to do something in order to wait for user input key (only enter or space) witout enter, like y/n options. I read about 16h in dos, its a sys_Call similar in linux? i also read about disabling canonization but look too complicated to the curse level thanks

    section .bss
    buffer  resb 1
    input resb 1
section  .data

    lineasConsola dd 3  ; Lineas (sin informacion) mostradas por defecto
    lineasPantalla dd 3 
    lineasTotales dd 0
    lineasContador dd 0


section .text

    global _start

leerInput:

    push ebx
    push ecx
    mov eax, 3      ; sys_read
    mov ebx, 0
    mov ecx, input
    mov edx, 1
    int 80h
    pop ecx
    pop ebx
    ret

leerCaracter:

    mov eax,3       ; sys_read
    mov ecx,buffer  
    mov edx,1
    int 80h
    cmp eax,0       ;eof
    je final

imprimirCaracter:

    mov eax, 4          ; sys_write
    push ebx            ; Resguardo el manejador
    mov ebx, 1
    int 80h

    pop ebx
    cmp byte[buffer],10       ; Chequeo si llegue a fin de linea
    jne leerCaracter
    ret

imprimirLineasTotales

    push ebx
    push ecx
    push edx
    mov eax, 4
    mov ebx, 1
    mov ecx, [lineasTotales]
    mov edx, 4
    int 80h
    pop edx
    pop ecx
    pop ebx
    ret

avanzarLinea ; Actualiza los contadores para poder leer una linea mas

    push ebx
    mov ebx, [lineasConsola]
    inc ebx
    mov [lineasConsola], ebx
    pop ebx
    ret


avanzarPantalla ; Actualiza los contadores para poder leer una nueva pantalla

    push ebx
    mov ebx, [lineasConsola]
    add ebx, lineasPantalla
    mov [lineasConsola], ebx
    pop ebx
    ret

_start:

    pop ebx      ; argc 
    pop ebx      ; argv[0] 
    pop ebx      ; Nombre del archivo

    mov eax,5    ; sys_open
    mov ecx,0
    int 80h 

    mov ebx,eax  ; Muevo el puntero a ebx para leerlo
    test eax,eax    
    js  exite    ; Se produjo un error al intentar abrir el archivo

leerLinea:  

    call leerCaracter          ;imprimo una linea
    push eax                   ; Llegue al final de la linea, debo aumentar la cantidad de lineas leidas y chequear si llegue al tope de la consola
    push ebx
    mov eax, [lineasTotales]
    mov ebx, [lineasConsola]
    inc eax                    ; Lei una linea
    cmp eax, ebx               ; Chequeo si complete la pantalla
    mov [lineasTotales], eax
    pop ebx
    pop eax
    jl leerLinea                ; No llene la consola
    ;call imprimirLineasTotales ; Imprimir lineas leidas hasta el momento;no funciona
    call leerInput
    cmp byte[input],'s'
    jne seguir                  ;no presione la barra
    call avanzarLinea           ; Usuario presiono la barra
    jmp leerLinea

seguir:

    cmp byte[input], 'e'            ; Usuario presiono enter
    jne exite                   ; No es la barar ni salto de linea, se produce un error
    call avanzarPantalla
    jmp leerLinea

    mov ebx, 0      ; salgo sin errores
    mov eax, 1      ; sys_exit
    int 80h



final:

    call imprimirLineasTotales
    mov ebx, 0      ; salgo sin errores
    mov eax, 1      ; sys_exit
    int 80h

exite:

    mov ebx, 6      ; If there was an error, save the errno in ebx
    mov eax, 1      ; Put the exit syscall number in eax
    int 80h         ; Bail out

Upvotes: 0

Views: 2256

Answers (3)

Chris Dodd
Chris Dodd

Reputation: 126140

By default, when reading from a terminal in Linux (which includes any terminal window or remote login, or any interactive thing with an actual keyboard involved), the kernel will collect the characters typed in a buffer, processing backspaces and the like, until a newline is entered. Only after the newline will it send the data back to the user process in response to a read system call. This is called "canonical" input processing. If you want to avoid this, and read single characters immediately as they are typed, you need to put the terminal in non-canonical mode. In C, you can do this with the tcsetattr(3) function in the C library, which you may be able to call from your assembly program. If you're trying to avoid even the C library however, you can use raw ioctl(2) system calls.

For linux, the necessary information is in the termios(3) and tty_ioctl(4) manual pages.

Upvotes: 1

Nithin
Nithin

Reputation: 191

Without changing the mode from canonical to non canonical mode, think this is not possible. This is because when user enter's a character, they get buffered inside kernel and, depending on the mode of the tty/console they get delivered to reader either before '\n' or immediately.

Upvotes: 0

user2845360
user2845360

Reputation:

Syscalls are what you're looking for, but without providing what you've tried, it's quite impossible to get into specifics of what you should be doing. Some general advice holds, though.

You can read one character at a time from terminal, which is just another file, using syscalls. Depending on the target architecture, namely the question is it 32- or 64-bit, you can find appropriate syscalls from unistd_32.h or unistd_64.h, most likely to lie in /usr/include/x86_64-linux-gnu/asm/ on your system.

The 32-bit syscalls take the syscall number in eax and arguments in ebx, ecx,edx, esi, edi and ebp. Setup those appropriately and do int 0x80.

The 64-bit syscalls take the syscall number rax and arguments in rdi, rsi, rdx, rcs, r8 and r9. Setup those appropriately and do syscall.

You might benefit from reading some other excellent Q&As on stackoverflow about assembly language programming on Linux. Actually, I think it could be taken as a recommended next step.

Upvotes: 0

Related Questions