1010#include <stdbool.h>
1111#include <stdio.h>
1212#include <stdlib.h>
13+ #include <string.h>
1314
1415// Flags for representing mode (see fopen()). Note these must fit the same
1516// status field as the _IO?BF flags in <stdio.h> and the internal flags below.
@@ -44,8 +45,28 @@ struct _FILE {
4445 char ungetc_buf ; // ungetc() buffer
4546 bool ungetc_buf_full ; // Number of ungetc()'ed characters
4647 unsigned status ; // Status flags; see above
48+ char * filename ; // Name the current stream has been opened with
49+ FILE * next ; // Pointer to next struct (internal)
4750};
4851
52+ static FILE serr = {.handle = 2 , .status = _IONBF | FWRITE };
53+ static FILE sout = {.handle = 1 , .status = _IONBF | FWRITE , .next = & serr };
54+ static FILE sin = {.handle = 0 , .status = _IONBF | FREAD , .next = & sout };
55+
56+ FILE * stdin = & sin ;
57+ FILE * stdout = & sout ;
58+ FILE * stderr = & serr ;
59+
60+ static FILE * filelist = & sin ;
61+
62+ asm(".section .fini,\"axR\",@progbits\n"
63+ " jsr _stdio_closeall\n" );
64+
65+ void _stdio_closeall (void ) {
66+ for (FILE * f = filelist ; f ; f = f -> next )
67+ fclose (f );
68+ }
69+
4970// Helper function that parses the C-style mode string passed to fopen() into
5071// the PDCLib flags FREAD, FWRITE, FAPPEND, FRW (read-write) and FBIN (binary
5172// mode).
@@ -138,13 +159,129 @@ static signed char stdio_open(const char *const filename, unsigned int mode) {
138159 return open (filename , osmode );
139160}
140161
162+ // Operations on files
163+
164+ FILE * tmpfile (void ) {
165+ char name [L_tmpnam ];
166+ tmpnam (name );
167+ FILE * f = fopen (name , "wb+" );
168+ f -> status |= DELONCLOSE ;
169+ return f ;
170+ }
171+
172+ char * tmpnam (char * s ) {
173+ static char filename [L_tmpnam ];
174+ if (s == NULL )
175+ s = filename ;
176+
177+ strcpy (s , "tmp00" );
178+ while (s [4 ] != '2' || s [3 ] != '4' ) {
179+ FILE * f = fopen (s , "rb" );
180+ if (!f )
181+ break ;
182+ fclose (f );
183+ if (s [3 ] == '9' ) {
184+ s [3 ] = '0' ;
185+ ++ s [4 ];
186+ } else {
187+ ++ s [3 ];
188+ }
189+ }
190+
191+ return s ;
192+ }
193+
141194// File access functions
142195
196+ int write (int fildes , const void * buf , size_t nbyte ) {
197+ // Not yet implemented
198+ if (nbyte )
199+ return -1 ;
200+ return 0 ;
201+ }
202+
203+ /* A system call that writes a stream's buffer.
204+ Returns 0 on success, EOF on write error.
205+ Sets stream error flags and errno appropriately on error.
206+ */
207+ static int flush_buffer (FILE * stream ) {
208+ // No need to handle buffers > INT_MAX, as PDCLib doesn't allow them */
209+ size_t written = 0 ;
210+ int rc ;
211+
212+ if (!(stream -> status & FBIN )) {
213+ /* TODO: Text stream conversion here */
214+ }
215+
216+ // Keep trying to write data until everything is written or an error occurs.
217+ for (;;) {
218+ rc = write (stream -> handle , stream -> buffer + written ,
219+ stream -> bufidx - written );
220+
221+ if (rc < 0 ) {
222+ /* Flag the stream */
223+ stream -> status |= ERRORFLAG ;
224+ /* Move unwritten remains to begin of buffer. */
225+ stream -> bufidx -= written ;
226+ memmove (stream -> buffer , stream -> buffer + written , stream -> bufidx );
227+ return EOF ;
228+ }
229+
230+ written += (size_t )rc ;
231+ stream -> pos += rc ;
232+
233+ if (written == stream -> bufidx ) {
234+ /* Buffer written completely. */
235+ stream -> bufidx = 0 ;
236+ return 0 ;
237+ }
238+ }
239+ }
240+
241+ // Removes the given stream from the internal list of open files.
242+ void remove_stream (FILE * stream ) {
243+ for (FILE * f ; f ; f = f -> next ) {
244+ if (f -> next == stream ) {
245+ f -> next = f -> next -> next ;
246+ break ;
247+ }
248+ }
249+ }
250+
251+ int fclose (FILE * stream ) {
252+ /* Flush buffer */
253+ if (stream -> status & FWRITE && flush_buffer (stream ) == EOF )
254+ return EOF ;
255+
256+ /* Close handle */
257+ close (stream -> handle );
258+
259+ /* Remove stream from list */
260+ remove_stream (stream );
261+
262+ /* Delete tmpfile() */
263+ if (stream -> status & DELONCLOSE )
264+ remove (stream -> filename );
265+
266+ /* Free buffer */
267+ if (stream -> status & FREEBUFFER )
268+ free (stream -> buffer );
269+
270+ /* Free filename (standard streams do not have one, but free( NULL )
271+ is a valid no-op)
272+ */
273+ free (stream -> filename );
274+
275+ /* Free stream */
276+ if (stream != stdin && stream != stdout && stream != stderr )
277+ free (stream );
278+
279+ return 0 ;
280+ }
281+
143282FILE * fopen (const char * restrict filename , const char * restrict mode ) {
144283 unsigned int fmode = filemode (mode );
145284
146- // See tmpfile(), which does much of the same.
147-
148285 // Initializing FILE structure failed.
149286 FILE * rc ;
150287 if ((rc = init_file (NULL )) == NULL )
@@ -158,6 +295,12 @@ FILE *fopen(const char *restrict filename, const char *restrict mode) {
158295 if ((rc -> handle = stdio_open (filename , rc -> status )) == -1 )
159296 return NULL ;
160297
298+ rc -> filename = malloc (strlen (filename ));
299+ strcpy (rc -> filename , filename );
300+
301+ rc -> next = filelist ;
302+ filelist = rc ;
303+
161304 return rc ;
162305}
163306
0 commit comments