;
; Ullrich von Bassewitz, 05.06.1998
;
; int atoi (const char* s);
; long atol (const char* s);
;

        .export         _atoi, _atol
        .import         negeax, __ctype
        .importzp       sreg, ptr1, ptr2, tmp1

        .include        "ctype.inc"

;
; Conversion routine (32 bit)
;

_atoi:
_atol:  sta     ptr1            ; Store s
        stx     ptr1+1
        ldy     #0
        sty     ptr2
        sty     ptr2+1          ; initial value (32 bit)
        sty     sreg
        sty     sreg+1

; Skip whitespace

L1:     lda     (ptr1),y
        tax
        lda     __ctype,x       ; get character classification
        and     #CT_SPACE_TAB   ; tab or space?
        beq     L2              ; jump if no
        iny
        bne     L1
        inc     ptr1+1
        bne     L1              ; branch always

; Check for a sign. The character is in X

L2:     txa                     ; get char
        ldx     #0              ; flag: positive
        cmp     #'+'            ; ### portable?
        beq     L3
        cmp     #'-'            ; ### portable?
        bne     L5
        dex                     ; flag: negative
L3:     iny
        bne     L5
        inc     ptr1+1

; Store the sign flag and setup for conversion

L5:     stx     tmp1            ; remember sign flag

L6:     lda     (ptr1),y        ; get next char
        tax
        lda     __ctype,x       ; get character classification
        and     #$04            ; digit?
        beq     L8              ; done

; Multiply ptr2 (the converted value) by 10

        jsr     mul2            ; * 2

        lda     sreg+1
        pha
        lda     sreg
        pha
        lda     ptr2+1
        pha
        lda     ptr2
        pha                     ; Save value

        jsr     mul2            ; * 4
        jsr     mul2            ; * 8

        clc
        pla
        adc     ptr2
        sta     ptr2
        pla
        adc     ptr2+1
        sta     ptr2+1
        pla
        adc     sreg
        sta     sreg
        pla
        adc     sreg+1
        sta     sreg+1          ; x*2 + x*8 = x*10

; Get the character back and add it

        txa                     ; get char back
        sec
        sbc     #'0'            ; make numeric value
        clc
        adc     ptr2
        sta     ptr2
        bcc     L7
        inc     ptr2+1
        bne     L7
        inc     sreg
        bne     L7
        inc     sreg+1

; Next character

L7:     iny
        bne     L6
        inc     ptr1+1
        bne     L6

; Conversion done. Load the low 16 bit into A/X

L8:     lda     ptr2
        ldx     ptr2+1

; Negate the value if necessary, otherwise we're done

        ldy     tmp1            ; sign
        beq     L9              ; Branch if positive

; Negate the 32 bit value in ptr2/sreg

        jmp     negeax

;
; Helper functions
;

mul2:   asl     ptr2
        rol     ptr2+1
        rol     sreg
        rol     sreg+1          ; * 2
L9:     rts


