RendoJack
RendoJack

Reputation: 366

x86 ASM - Read line by line

Okay, all I want to do is just read line by line from text and then output it.


Things I do:


Problems:


.txt example

    some
    random

    text
    .model small

    .stack  100h 

    .data 
            filename    db 255 dup(0)   
            text        db 255 dup(0)
            char        db ?
            line        db 255 dup(0)           

            filehandle  dw ?

    .code 
            newline macro    ;NEW LINE 
                             ;
            mov dl, 10       ;
            mov ah, 02h      ;                   
            int 21h          ;
                             ;
            mov dl, 13       ;
            mov ah, 02h      ;                     ;
            int 21h          ;                
            endm             ;NEW LINE
    main:   

            mov ax, @data    
            mov ds, ax   

            lea si, filename
            mov ah, 01h      ;read character

    char_input:

            int 21h         

            cmp al, 0dh      ;enter     
            je zero_terminator

            mov [si], al    
            inc si

            jmp char_input  

    zero_terminator:

            mov [si], 0 

    open_file:

            lea dx, filename         
            mov al, 0          
            mov ah, 3Dh      ;open file
            int 21h  

            mov filehandle, ax

            lea si, text   

            newline

    read_line:
            mov ah, 3Fh      ;read file
            mov bx, filehandle  
            lea dx, char         
            mov cx, 1  

            int 21h  

            cmp ax, 0       ;EOF            
            je EO_file

            mov al, char        

            cmp al, 0ah     ; line feed
            je LF  

            mov [si], al
            inc si      

            jmp read_line:

    EO_file:

            lea dx, text
            mov ah, 40h     ;print 
            mov cx, 255
            mov bx, 1       
            int 21h

            mov ah, 4ch     
            int 21h 

    LF:       
            lea dx, text
            mov ah, 40h     ;print
            mov cx, 255
            mov bx, 1

            int 21h

            inc si
            jmp read_line

     end main  

Upvotes: 1

Views: 11249

Answers (1)

Michael Petch
Michael Petch

Reputation: 47573

This is meant to get you going, not to solve all the bugs in your code:

You have:

zero_terminator:
        mov [si], 0 

The idea is to move a 0 byte to the location pointed to by SI. TASM doesn't understand that you want to move a single byte to [SI] so it should be told explicitly that is what you intend:

        mov byte ptr [si], 0 

You have a typo on this line with a colon on the end:

        jmp read_line:

It should be:

        jmp read_line

The primary issue with your code is that when going to print out the characters read into the text character array you need to specify the number of characters to print in CX . You specify 255 with code like this:

LF:
        lea dx, text
        mov ah, 40h     ;print
        mov cx, 255

Since SI contains a pointer to the last character read, you can subtract the address (offset) of text from SI to get the number of characters in the buffer. So what is above could be changed to:

LF:
        lea dx, text
        mov ah, 40h     ;print
        mov cx, si      ;CX = # characters. Move pointer to last char to it
        sub cx, dx      ;Subtract the offset of text (in DX) from CX
                        ;To get the actual number of chars in the buffer

Once you print out a line you inc SI and return to reading characters. Since you have printed out the line, you may as well restart from the beginning of the text buffer by resetting SI back to the start with:

        mov si, dx ; start from beginning of buffer (DX=beginning of text buffer)

or you can just mov DX which contains the offset of text already and set SI to it with:

This is the same way you originally set things up at the start of reading data.

The EOF code you have has a similar issue where it requires the number of bytes in the buffer to be placed in ECX. So this code:

EO_file:

        lea dx, text
        mov ah, 40h     ;print
        mov cx, 255
        mov bx, 1
        int 21h

Can be changed to:

LF:
        lea dx, text
        mov ah, 40h     ;print
        mov cx, si      ;CX = # characters. Move pointer to last char to it
        sub cx, dx      ;Subtract the offset of text (in DX) from CX
                        ;To get the actual number of chars in the buffer

With all these changes you would get a program like:

    .model small
    .stack  100h

    .data
            filename    db 255 dup(0)
            text        db 255 dup(0)
            char        db ?
            line        db 255 dup(0)

            filehandle  dw ?

    .code
            newline macro    ;NEW LINE
                             ;
            mov dl, 10       ;
            mov ah, 02h      ;
            int 21h          ;
                             ;
            mov dl, 13       ;
            mov ah, 02h      ;                     ;
            int 21h          ;
            endm             ;NEW LINE
    main:

            mov ax, @data
            mov ds, ax

            lea si, filename
            mov ah, 01h      ;read character

    char_input:

            int 21h

            cmp al, 0dh      ;enter
            je zero_terminator

            mov [si], al
            inc si

            jmp char_input

    zero_terminator:

            mov byte ptr [si], 0

    open_file:

            lea dx, filename
            mov al, 0
            mov ah, 3Dh      ;open file
            int 21h

            mov filehandle, ax

            lea si, text

            newline

    read_line:
            mov ah, 3Fh      ;read file
            mov bx, filehandle
            lea dx, char
            mov cx, 1

            int 21h

            cmp ax, 0       ;EOF
            je EO_file

            mov al, char

            cmp al, 0ah     ; line feed
            je LF

            mov [si], al
            inc si

            jmp read_line

    EO_file:

            lea dx, text    ;DX=offset(address) of text
            mov ah, 40h     ;print
            mov cx, si      ;CX = # characters. Move pointer to last char to it
            sub cx, dx      ;Subtract the offset of text (in DX) from CX
                            ;To get the actual number of chars in the buffer
            mov bx, 1
            int 21h

            mov ah, 4ch
            int 21h

    LF:
            lea dx, text    ;DX=offset(address) of text
            mov ah, 40h     ;print
            mov cx, si      ;CX = # characters. Move pointer to last char to it
            sub cx, dx      ;Subtract the offset of text (in DX) from CX
                            ;To get the actual number of chars in the buffer
            mov bx, 1

            int 21h

            mov si, dx      ;Start from beginning of buffer 
                            ;(DX=beginning of text buffer)
            jmp read_line

     end main

Upvotes: 3

Related Questions