Search code examples
assemblytasm

how to end the input sequence of characters: ASM: Int 21h function 01h


New to assembly.. this is the code. it reads sequence of characters and ends when you press enter

but the sequence of input characters has no limit when entered.. how to limit number of characters? for example i can only type 20 characters and the program will end?

and what does AL in CMP represent, and why 0DH? i am confused in that line (CMP AL,0DH)

MAIN PROC

;INITIALIZE DS
MOV AX,@DATA     
MOV DS,AX

MOV     DI,1000H
MOV     AH,01H
LOOP:
INT     21H
CMP     AL,0DH
JE      END
MOV     [DI],AL
INC     DI
JMP     LOOP

END:
MOV AH,4CH         ;DOS EXIT FUNCTION
INT 21H            ;EXECUTE

MAIN ENDP
END MAIN

Solution

  • The prg reads the chars one by one, storing it at Adress 1000 and following. it obviously doesnt care for the input's length, and stops as soon as 0x0d is read (which is a newline, so it reads until enter is pressed)

    ( I replaced "mov [di],al" + "inc di" with "stosb" which does exactly the same thing )

    to add a "max length" check, you could do something like this inside the loop:

    mov ax, DI
    sub ax, 0x1000
    cmp ax, <the max length you want to read>
    jae END
    

    Note: the enter is not saved, so if you change SI (that currently points to the last char entered), will have a problem determining the string's end. Better store the 0x0d too (or even better a 0x00), to have a end-of-string marker:

    MAIN PROC
    
    ;INITIALIZE DS
    MOV AX,@DATA     
    MOV DS,AX
    cld                 ; tell "stosb" to forward
    
    MOV     DI,1000H    ; address where to string will be copied to
    MOV     AH,01H      ; int 21 function 1: read char with echo
    LOOP:
       INT     21H         ; read a char from keyboard
       stosb               ; store char in string
       CMP     AL,0DH      ; stop if enter is pressed (after storing, so 0x0d will be stored too)
    JNE     LOOP
    
    END:
    MOV AH,4CH         ;DOS EXIT FUNCTION
    INT 21H            ;EXECUTE
    
    MAIN ENDP
    

    or storing a 0x00 and input's end:

    MAIN PROC
    
    ;INITIALIZE DS
    MOV AX,@DATA     
    MOV DS,AX
    cld                 ; tell "stosb" to forward
    
    MOV     DI,1000H    ; address where to string will be copied to
    MOV     AH,01H      ; int 21 function 1: read char with echo
    LOOP:
       INT     21H         ; read a char from keyboard
       CMP     AL,0DH      ; stop if enter is pressed
       JE      END
       stosb               ; save al at DI and increase DI by one
    JMP     LOOP
    
    END:
    mov [di], 0         ; terminate string (instead of 0x0d)
    MOV AH,4CH         ;DOS EXIT FUNCTION
    INT 21H            ;EXECUTE
    
    MAIN ENDP
    

    One more idea on "limit the amount of chars read" (Instead of checking DI for 0x1000+20 to jump out of the read-loop) would be to use CX as counter and loop (loop is a conditional jump that decreases CX and jumps if CX didn't reach 0):

    MAIN PROC
    
    ;INITIALIZE DS
    MOV AX,@DATA     
    MOV DS,AX
    cld                 ; tell "stosb" to forward
    
    mov     cx, 20      ; make sure to maximum read 20 chars
    MOV     DI,1000H    ; address where to string will be copied to
    MOV     AH,01H      ; int 21 function 1: read char with echo
    LOOP:
       INT     21H         ; read a char from keyboard
       CMP     AL,0DH      ; stop if enter is pressed
       JE      END
       stosb               ; save al at DI and increase DI by one
    loop     LOOP
    
    END:
    mov [di], 0         ; terminate string (instead of 0x0d)
    MOV AH,4CH         ;DOS EXIT FUNCTION
    INT 21H            ;EXECUTE
    
    MAIN ENDP