]> git.sur5r.net Git - cc65/blob - libsrc/common/fread.s
Merge pull request #249 from polluks/master
[cc65] / libsrc / common / fread.s
1 ;
2 ; Ullrich von Bassewitz, 2002-11-22, 2004-05-14
3 ;
4 ; size_t __fastcall__ fread (void* buf, size_t size, size_t count, FILE* file);
5 ; /* Read from a file */
6 ;
7
8         .export         _fread
9
10         .import         _read
11         .import         pusha0, pushax
12         .import         incsp4, incsp6
13         .import         ldaxysp, ldax0sp
14         .import         pushwysp
15         .import         tosumulax, tosudivax
16
17         .importzp       ptr1, sp
18
19         .include        "errno.inc"
20         .include        "_file.inc"
21
22         .macpack        generic
23
24 ; ------------------------------------------------------------------------
25 ; Code
26
27 .proc   _fread
28
29 ; We will place a pointer to the file descriptor into the register bank
30
31         .import regbank: zp
32         file    = regbank
33
34 ; Save two bytes from the register bank
35
36         ldy     file+0
37         sty     save
38         ldy     file+1
39         sty     save+1
40
41 ; Save the file pointer into the register bank
42
43         sta     file
44         stx     file+1
45
46 ; Check if the file is open
47
48         ldy     #_FILE::f_flags
49         lda     (file),y
50         and     #_FOPEN                 ; Is the file open?
51         beq     @L1                     ; Branch if no
52
53 ; Check if the stream is in an error state
54
55         lda     (file),y                ; get file->f_flags again
56         and     #_FERROR
57         beq     @L2
58
59 ; File not open or in error state
60
61 @L1:    lda     #EINVAL
62         jsr     __seterrno              ; Set __errno, return zero in A
63         tax                             ; a/x = 0
64         jmp     @L99                    ; Bail out
65
66 ; Remember if we have a pushed back character and reset the flag.
67
68 @L2:    tax                             ; X = 0
69         lda     (file),y
70         and     #_FPUSHBACK
71         beq     @L3
72         lda     (file),y
73         and     #<~_FPUSHBACK
74         sta     (file),y                ; file->f_flags &= ~_FPUSHBACK;
75         inx                             ; X = 1
76 @L3:    stx     pb
77
78 ; Build the stackframe for read()
79
80         ldy     #_FILE::f_fd
81         lda     (file),y
82         jsr     pusha0                  ; file->f_fd
83
84         ldy     #9
85         jsr     pushwysp                ; buf
86
87 ; Stack is now: buf/size/count/file->fd/buf
88 ; Calculate the number of bytes to read: count * size
89
90         ldy     #7
91         jsr     pushwysp                ; count
92         ldy     #9
93         jsr     ldaxysp                 ; Get size
94         jsr     tosumulax               ; count * size -> a/x
95
96 ; Check if count is zero.
97
98         cmp     #0
99         bne     @L4
100         cpx     #0
101         bne     @L4
102
103 ; Count is zero, drop the stack frame just built and return count
104
105         jsr     incsp4                  ; Drop file->fd/buf
106         jsr     ldax0sp                 ; Get count
107         jmp     @L99                    ; Bail out
108
109 ; Check if we have a buffered char from ungetc
110
111 @L4:    ldy     pb
112         beq     @L6
113
114 ; We have a buffered char from ungetc. Save the low byte from count
115
116         pha
117
118 ; Copy the buffer pointer into ptr1, and increment the pointer value passed
119 ; to read() by one, so read() starts to store data at buf+1.
120
121         ldy     #0
122         lda     (sp),y
123         sta     ptr1
124         add     #1
125         sta     (sp),y
126         iny
127         lda     (sp),y
128         sta     ptr1+1
129         adc     #0
130         sta     (sp),y                  ; ptr1 = buf++;
131
132 ; Get the buffered character and place it as first character into the read
133 ; buffer.
134
135         ldy     #_FILE::f_pushback
136         lda     (file),y
137         ldy     #0
138         sta     (ptr1),y                ; *buf = file->f_pushback;
139
140 ; Restore the low byte of count and decrement count by one. This may result
141 ; in count being zero, so check for that.
142
143         pla
144         sub     #1
145         bcs     @L5
146         dex
147 @L5:    cmp     #0
148         bne     @L6
149         cpx     #0
150         beq     @L8
151
152 ; Call read(). This will leave the original 3 params on the stack
153
154 @L6:    jsr     _read
155
156 ; Check for errors in read
157
158         cpx     #$FF
159         bne     @L8
160         cmp     #$FF
161         bne     @L8
162
163 ; Error in read. Set the stream error flag and bail out. errno has already
164 ; been set by read(). On entry to label @L7, X must be zero. 
165
166         inx                             ; X = 0
167         lda     #_FERROR
168 @L7:    ldy     #_FILE::f_flags         ; X must be zero here!
169         ora     (file),y
170         sta     (file),y
171         txa                             ; a/x = 0
172         beq     @L99                    ; Return zero
173
174 ; Read was ok, account for the pushed back character (if any).
175
176 @L8:    add     pb
177         bcc     @L9
178         inx
179
180 ; Check for end of file.
181
182 @L9:    cmp     #0                      ; Zero bytes read?
183         bne     @L10
184         cpx     #0
185         bne     @L10
186
187 ; Zero bytes read. Set the EOF flag
188
189         lda     #_FEOF
190         bne     @L7                     ; Set flag and return zero
191
192 ; Return the number of items successfully read. Since we've checked for
193 ; bytes == 0 above, size cannot be zero here, so the division is safe.
194
195 @L10:   jsr     pushax                  ; Push number of bytes read
196         ldy     #5
197         jsr     ldaxysp                 ; Get size
198         jsr     tosudivax               ; bytes / size -> a/x
199 @L99:   ldy     save                    ; Restore zp register
200         sty     file
201         ldy     save+1
202         sty     file+1
203         jmp     incsp6                  ; Drop params, return
204
205 .endproc
206
207 ; ------------------------------------------------------------------------
208 ; Data
209
210 .bss
211 save:   .res    2
212 pb:     .res    1
213