; 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