; GetShow.asm
; A package of 2 assembler procedures for performing numeric IO
; with the keyboard and a DOS window. This file must be INCLUDEd
; in any source file that uses the subroutines:
;
; INCLUDE getshow.asm
;
; Original by Alan Pinck; modified by Ian Allen idallen@ncf.ca
;
; getNum accepts keyboard input and assuming
; decimal characters representing a number
; in the range 0 to 9999, converts the input
; into a binary number which is returned in
; the AX register. Leading whitespace is skipped.
; getNum returns with the Carry flag off if
; it was successful and with the Carry flag on
; if it was not (if the keyboard input did not
; start with something that could be interpretted
; as a number, or if the number exceeds 4 digits)
;
; showNum displays the contents of AX (assumed to be
; a number in 2's complement form) as a decimal value
;
; No newlines or carriage returns are added. You will need to
; add them yourself to format your output nicely.
;--- data which is local to this package ---
diolastc db 00
dionewl db 0Dh,0Ah,"$"
dionum dw ?
; ===========================================
; showNum displays the 2's complement number
; in AX as a decimal number
showNum proc near
push ax ;save working registers
push bx
push cx
push dx
; push ax
; mov dx,offset dionewl ;ensure display is on a newline
; mov ah,09
; int 21h
; pop ax
cmp ax,0 ;test for negative
jge positive;skip ahead if positive
mov ah,02h ;display character code
mov dl,'-' ; minus sign
int 21h
mov bx,ax
sub ax,bx ;ax now zero
sub ax,bx ;ax now positive
positive:
mov bx,10 ;divide by 10 (decimal!) to convert to decimal
mov cl,0 ;count of number of digits produced
div_loop:
mov dx,0 ;setup to divide dx|ax by bx
idiv bx ;unsigned division:
;quotient in ax, remainder in dx
push dx ;save the digit (remainder)
inc cl ;keep track of number of digits
cmp ax,0 ;until nothing left to divide
jnz div_loop; loop back
show_digit:
pop dx
add dl,30h ;convert digit to ASCII code
mov ah,02h ;display character
int 21h
dec cl ;loop until all digits shown
jnz show_digit
pop dx ;restore working registers
pop cx
pop bx
pop ax
ret
showNum endp
;==========================================
; getNum returns number input (converted to
; binary) in ax
; input is assumed to be a positive, decimal
; value with a maximum of 4 digits, terminated
; with an ASCII non-digit code
; Carry flag is set (on) if an input error is
; detected (Carry flag is clear (off) if the
; input is valid
getNum proc near
push bx ;save working registers
push cx
push dx
mov dionum,0
mov bh,'9' ;setup for valid range testing
mov bl,'0'
mov cl,4 ;maximum number of digits acceptable
mov al,diolastc
cmp al,00 ;check if we no previous char available
jne gotchar ; skip input if one already here
skipwhite:
mov ah,01h ;input a char
int 21h
gotchar:
mov diolastc,al ;skip over leading blanks and
cmp al,20h
je skipwhite
cmp al,0Dh ;carriage returns
je skipwhite
cmp al,0Ah ;and newlines
je skipwhite
notwhite:
; check initial character to ensure it is a digit
cmp bh,al ; check that it's < '9'
jc bad_digit ; error if its not
sub al,bl ; subtract '0' from it
jc bad_digit ; error if its < '0'
get_loop:
mov ah,0
push ax
mov ax,dionum
mov dx,10 ; decimal based system
imul dx ; multiply ax by dx results in dx|ax
mov dionum,ax ; value of prior digits times 10
pop ax ; add this digit's value
add dionum,ax
mov ah,01 ;input a character
int 21h
mov diolastc,al ;save it incase we're finished digits
cmp bh,al ;exit getting digits if not a digit
jc get_exit
sub al,bl
jc get_exit
dec cl ;if this is not more than
jnz get_loop ; 4 digits add this digit to num
sub cl,1 ;otherwise exit with carry set
jmp bad_digit
get_exit:
mov ax,dionum ; "good" number
cmp ax,ax ; clear carry
bad_digit: ;-- if we get here something is wrong
;-- by careful coding we have ensured that
;-- the carry flag will be set
;-- this is the "error" return indicator
pop dx ;restore working registers
pop cx
pop bx
ret
getNum endp