;
; Christian Groessler, Jul-2005
;
; int __fastcall__ read(int fd,void *buf,int count)
;

        .include "atari.inc"
        .import __rwsetup,__do_oserror,__inviocb,__oserror
        .export _read

_read:  jsr     __rwsetup       ; do common setup for read and write
        beq     done            ; if size 0, it's a no-op
        cpx     #$FF            ; invalid iocb?
        beq     _inviocb

.ifdef  LINEBUF
        ; E: should be always at IOCB #0
        ; fixme: what happens when user closes and reopens stdin?
        cpx     #0              ; E: handler (line oriented keyboard input)?
        beq     do_line
.endif

        lda     #GETCHR         ; iocb command code
        sta     ICCOM,x
        jsr     CIOV            ; read it
        bpl     done
        cpy     #EOFERR         ; eof is treated specially
        beq     done
        jmp     __do_oserror    ; update errno

done:   lda     ICBLL,x         ; buf len lo
        pha                     ; save
        lda     ICBLH,x         ; get buf len hi
        tax                     ; to X
okdone: lda     #0
        sta     __oserror       ; clear system dependend error code
        pla                     ; get buf len lo
        rts

_inviocb:
        jmp     __inviocb


.ifdef  LINEBUF

; line oriented input

        .segment        "EXTZP" : zeropage

index:  .res    1               ; index into line buffer
buflen: .res    1               ; length of used part of buffer
cbs:    .res    1               ; current buffer size: buflen - index
dataptr:.res    2               ; temp pointer to user buffer
copylen:.res    1               ; temp counter

        .bss

linebuf:.res    LINEBUF         ; the line buffer

        .code

do_line:
        lda     buflen          ; line buffer active?
        bne     use_buf         ; yes, get data from there

        ; save user buffer address & length
        ; update IOCB to point to line buffer
        lda     ICBLL,x
        pha
        lda     #LINEBUF
        sta     ICBLL,x
        ;--------
        lda     ICBLH,x
        pha
        lda     #0
        sta     ICBLH,x
        ;--------
        lda     ICBAL,x
        pha
        lda     #<linebuf
        sta     ICBAL,x
        ;--------
        lda     ICBAH,x
        pha
        lda     #>linebuf
        sta     ICBAH,x

        lda     #GETREC
        sta     ICCOM,x
        jsr     CIOV            ; read input data
        bpl     newbuf
        cpy     #EOFERR         ; eof is treated specially
        beq     newbuf
        pla                     ; fix stack
        pla
        pla
        pla
        jmp     __do_oserror    ; update errno

newbuf:
        lda     ICBLL,x         ; get # of bytes read
        sta     buflen
        lda     #0
        sta     index           ; fresh buffer

        ; restore user buffer address & length
        pla
        sta     ICBAH,x
        ;--------
        pla
        sta     ICBAL,x
        ;--------
        pla
        sta     ICBLH,x
        ;--------
        pla
        sta     ICBLL,x

        ; fall into use_buf
        lda     buflen

; return bytes from line buffer
; use buflen and index to access buffer
; update index
; use dataptr as a temporary pointer

use_buf:
        sec
        sbc     index           ; size of unread data in the buffer
        sta     cbs

        lda     ICBLL,x         ; buf len lo
        cmp     cbs             ; larger than buffer size?
        beq     bl1
        bcs     btsmall         ; yes, adjust length

bl1:    lda     ICBLH,x         ; get buf len hi
        bne     btsmall         ; buffer too small: buffer contents < read size

; copy ICBLL,x bytes

icbll_copy:

        lda     ICBAL,x         ; buffer address
        sta     dataptr
        lda     ICBAH,x         ; buffer address
        sta     dataptr+1
        lda     ICBLL,x
        sta     copylen
        pha                     ; remember for return value
        ldy     #0
        ldx     index

copy:   lda     linebuf,x
        sta     (dataptr),y
        iny
        inx
        dec     copylen
        bne     copy

        pla                     ; length
        pha                     ; save length to return at okdone

        clc
        adc     index
        sta     index
        cmp     buflen          ; buffer used up?
        bcc     c1              ; not yet

        lda     #0
        sta     buflen          ; indicate empty line buffer

c1:     ldx     #0
        jmp     okdone          ; return to caller

btsmall:
        lda     cbs
        sta     ICBLL,x
        bpl     icbll_copy

.endif          ; .ifdef LINEBUF

