Metropoli BBS
VIEWER: atol.asm MODE: TEXT (ASCII)
        name    atol
        page    55,132
        title   ATOL - ASCII to long integer

;
; ATOL.ASM - convert ASCII string to 
;            long (32-bit) decimal integer.
;
;  Copyright 1987, Ziff Communications Co.
;  Ray Duncan
;
; Call with:    DS:SI = address of string
;
;               where 'string' is in the form
;               
;                  [whitespace][sign][digits]
;
; Returns:      DX:AX = result (high word in DX)
;               DS:SI = address+1 of terminator 
;
;               other registers preserved
;
; Like the C library 'atol', this routine gives no 
; warning in the event of overflow, and terminates 
; on the first invalid character.
;

blank   equ     20h             ; ASCII blank character
tab     equ     09h             ; ASCII tab character

_TEXT   segment word public 'CODE'

        assume  cs:_TEXT

        public  atol
atol    proc    near            ; ASCII to 32-bit integer

        push    bx              ; save registers
        push    cx
        push    di

        xor     bx,bx           ; initialize forming answer
        xor     dx,dx           ; in DX:BX
        xor     cx,cx           ; initialize sign flag

atol1:  lodsb                   ; scan off whitespace
        cmp     al,blank        ; ignore leading blanks
        je      atol1
        cmp     al,tab          ; ignore leading tabs
        je      atol1

        cmp     al,'+'          ; if + sign proceed
        je      atol2
        cmp     al,'-'          ; is it - sign?
        jne     atol3           ; no, test if numeric
        dec     cx              ; was - sign, set flag
                                ; for negative result

atol2:  lodsb                   ; get next character

atol3:  cmp     al,'0'          ; is character valid?
        jb      atol4           ; jump if not '0' to '9'
        cmp     al,'9'
        ja      atol4           ; jump if not '0' to '9'

        and     ax,0fh          ; isolate lower four bits
        push    ax              ; and save digit value

        mov     ax,bx           ; previous answer x 10
        mov     di,dx           ; DI:AX = copy of DX:BX

        add     bx,bx           ; * 2
        adc     dx,dx

        add     bx,bx           ; * 4
        adc     dx,dx

        add     bx,ax           ; * 5
        adc     dx,di

        add     bx,bx           ; * 10
        adc     dx,dx

        pop     ax              ; add this digit
        add     bx,ax           ; to forming answer
        adc     dx,0
        
        jmp     atol2           ; convert next digit

atol4:  mov     ax,bx           ; result low half to AX
        jcxz    atol5           ; jump if sign flag clear

        not     ax              ; take 2's complement
        not     dx              ; of DX:AX
        add     ax,1
        adc     dx,0

atol5:  pop     di              ; restore registers
        pop     cx
        pop     bx
        ret                     ; back to caller

atol    endp

_TEXT   ends
        end
[ RETURN TO DIRECTORY ]