From 36808404ca0789ab521365ca774057de1efcdbe3 Mon Sep 17 00:00:00 2001 From: Stephen Heumann Date: Sat, 2 Jul 2022 18:24:19 -0500 Subject: [PATCH] Fix fread bug causing it to discard buffered data. If you read from a file using fgetc (or another function that calls it internally), and then later read from it using fread, any data left in the buffer from fgetc would be skipped over. The pattern causing this to happen was as follows: fread called ~SetFilePointer, which (if there was buffered data) called fseek(f, 0, SEEK_CUR). fseek would call fflush, which calls ~InitBuffer. That zeros out the buffer count. fseek then calls ftell, which gets the current mark from GS/OS and then subtracts the buffer count. But the count was set to 0 in ~InitBuffer, so ftell reflects the position after any previously buffered data. fseek sets the mark to the position returned by ftell, i.e. after any data that was previously read and buffered, so that data would get skipped over. (Before commits 0047b755c9660 and c95bfc19fbe25 the behavior would be somewhat different due to the issue with ~InitBuffer that they addressed, but you could still get similar symptoms.) The fix is simply to use the buffered data (if any), rather than discarding it. Here is a test program illustrating the problem: #include char buf[BUFSIZ+1]; #define RECSIZE 2 int main(void) { FILE *f = fopen("somefile","r"); // a file with some data if (!f) return 0; fgetc(f); size_t count = fread(buf, RECSIZE, BUFSIZ/RECSIZE, f); printf("read %zu records: %s\n", count, buf); } --- stdio.asm | 103 +++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 47 deletions(-) diff --git a/stdio.asm b/stdio.asm index 1c51093..c56cdb4 100644 --- a/stdio.asm +++ b/stdio.asm @@ -1574,15 +1574,17 @@ lb4 creturn 2:err * fread start temp equ 1 +p equ 5 - csubroutine (4:ptr,4:element_size,4:count,4:stream),4 + csubroutine (4:ptr,4:element_size,4:count,4:stream),8 phb phk plb stz rdTransferCount set the # of elements read stz rdTransferCount+2 - stz pbkCount no putback characters read yet + stz extraCount no putback characters read yet + stz extraCount+2 ph4 stdin+4+FILE_flag sta >stdin+4+FILE_flag jsl SYSKEYIN read the closing cr - bra lb4 + brl lb4 lb1a short M set character sta [ptr] long M @@ -1638,10 +1638,55 @@ lb1a short M set character lda rdRequestCount ora rdRequestCount+2 bne lb1 - bra lb4 + brl lb4 lb2 sta rdRefNum set the reference number - move4 ptr,rdDataBuffer set the start address + ldy #FILE_flag if the file is being read then + lda [stream],Y + bit #_IOREAD + beq lb2c +lb2a ldy #FILE_cnt while there is buffered data... + lda [stream],Y + iny + iny + ora [stream],Y + beq lb2c + lda rdRequestCount ...and the request count is not 0 + ora rdRequestCount+2 + beq lb4 + ldy #FILE_ptr get the next character + lda [stream],Y + sta p + clc + adc #1 + sta [stream],Y + iny + iny + lda [stream],Y + sta p+2 + adc #0 + sta [stream],Y + short M + lda [p] + sta [ptr] + long M + ldy #FILE_cnt dec the # chars in the buffer + sec + lda [stream],Y + sbc #1 + sta [stream],Y + bcs lb2b + iny + iny + lda [stream],Y + dec A + sta [stream],Y +lb2b inc4 ptr adjust pointer and counts + dec4 rdRequestCount + inc4 extraCount + bra lb2a + +lb2c move4 ptr,rdDataBuffer set the start address OSRead rd read the bytes bcc lb4 cmp #$4C if the error was $4C then @@ -1650,12 +1695,7 @@ lb2 sta rdRefNum set the reference number bra lb4 lb3 ph4 FILE_pbk != -1 - lda [stream],Y - inc A - ldy #FILE_cnt or stream->FILE_cnt != 0 then - ora [stream],Y - iny - iny - ora [stream],Y - beq lb1 - ph2 #SEEK_CUR fseek(stream, 0L, SEEK_CUR) - ph4 #0 - ph4