cc65/libsrc/common/fread.s

214 lines
5.4 KiB
ArmAsm

;
; Ullrich von Bassewitz, 2002-11-22, 2004-05-14
;
; size_t __fastcall__ fread (void* buf, size_t size, size_t count, FILE* file);
; /* Read from a file */
;
.export _fread
.import _read
.import pusha0, pushax
.import incsp4, incsp6
.import ldaxysp, ldax0sp
.import pushwysp
.import tosumulax, tosudivax
.importzp ptr1, sp
.include "errno.inc"
.include "_file.inc"
.macpack generic
; ------------------------------------------------------------------------
; Code
.proc _fread
; We will place a pointer to the file descriptor into the register bank
.import regbank: zp
file = regbank
; Save two bytes from the register bank
ldy file+0
sty save
ldy file+1
sty save+1
; Save the file pointer into the register bank
sta file
stx file+1
; Check if the file is open
ldy #_FILE::f_flags
lda (file),y
and #_FOPEN ; Is the file open?
beq @L1 ; Branch if no
; Check if the stream is in an error state
lda (file),y ; get file->f_flags again
and #_FERROR
beq @L2
; File not open or in error state
@L1: lda #EINVAL
jsr __seterrno ; Set __errno, return zero in A
tax ; a/x = 0
jmp @L99 ; Bail out
; Remember if we have a pushed back character and reset the flag.
@L2: tax ; X = 0
lda (file),y
and #_FPUSHBACK
beq @L3
lda (file),y
and #<~_FPUSHBACK
sta (file),y ; file->f_flags &= ~_FPUSHBACK;
inx ; X = 1
@L3: stx pb
; Build the stackframe for read()
ldy #_FILE::f_fd
lda (file),y
jsr pusha0 ; file->f_fd
ldy #9
jsr pushwysp ; buf
; Stack is now: buf/size/count/file->fd/buf
; Calculate the number of bytes to read: count * size
ldy #7
jsr pushwysp ; count
ldy #9
jsr ldaxysp ; Get size
jsr tosumulax ; count * size -> a/x
; Check if count is zero.
cmp #0
bne @L4
cpx #0
bne @L4
; Count is zero, drop the stack frame just built and return count
jsr incsp4 ; Drop file->fd/buf
jsr ldax0sp ; Get count
jmp @L99 ; Bail out
; Check if we have a buffered char from ungetc
@L4: ldy pb
beq @L6
; We have a buffered char from ungetc. Save the low byte from count
pha
; Copy the buffer pointer into ptr1, and increment the pointer value passed
; to read() by one, so read() starts to store data at buf+1.
ldy #0
lda (sp),y
sta ptr1
add #1
sta (sp),y
iny
lda (sp),y
sta ptr1+1
adc #0
sta (sp),y ; ptr1 = buf++;
; Get the buffered character and place it as first character into the read
; buffer.
ldy #_FILE::f_pushback
lda (file),y
ldy #0
sta (ptr1),y ; *buf = file->f_pushback;
; Restore the low byte of count and decrement count by one. This may result
; in count being zero, so check for that.
pla
sub #1
bcs @L5
dex
@L5: cmp #0
bne @L6
cpx #0
beq @L8
; Call read(). This will leave the original 3 params on the stack
@L6: jsr _read
; Check for errors in read
cpx #$FF
bne @L8
cmp #$FF
bne @L8
; Error in read. Set the stream error flag and bail out. errno has already
; been set by read(). On entry to label @L7, X must be zero.
inx ; X = 0
lda #_FERROR
@L7: ldy #_FILE::f_flags ; X must be zero here!
ora (file),y
sta (file),y
txa ; a/x = 0
beq @L99 ; Return zero
; Read was ok, account for the pushed back character (if any).
@L8: add pb
bcc @L9
inx
; Check for end of file.
@L9: cmp #0 ; Zero bytes read?
bne @L10
cpx #0
bne @L10
; Zero bytes read. Set the EOF flag
lda #_FEOF
bne @L7 ; Set flag and return zero
; Return the number of items successfully read. Since we've checked for
; bytes == 0 above, size cannot be zero here, so the division is safe.
@L10: jsr pushax ; Push number of bytes read
ldy #5
jsr ldaxysp ; Get size
jsr tosudivax ; bytes / size -> a/x
@L99: ldy save ; Restore zp register
sty file
ldy save+1
sty file+1
jmp incsp6 ; Drop params, return
.endproc
; ------------------------------------------------------------------------
; Data
.bss
save: .res 2
pb: .res 1