Skip to content

Commit 8720eb1

Browse files
committed
Large chunk of full stdio functionality
- tmpfile - tmpnam - fclose - list of open files; close on exit - filenames in stream - flush_buffer (partial) - write (stub)
1 parent cc59208 commit 8720eb1

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed

mos-platform/common/c/stdio-full.c

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
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+
143282
FILE *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

mos-platform/common/include/stdio.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,23 @@ extern FILE *stdin;
3434
extern FILE *stdout;
3535
extern FILE *stderr;
3636

37+
#define L_tmpnam 6
38+
3739
#define SEEK_SET 0
3840
#define SEEK_CUR 1
3941
#define SEEK_END 2
4042

43+
#define TMP_MAX 25
44+
4145
// Operations on files
4246
int remove(const char *filename);
4347
int rename(const char *old, const char *_new);
48+
FILE *tmpfile(void);
49+
char *tmpnam(char *s);
4450

4551
// File access functions
4652

53+
int fclose(FILE *stream);
4754
FILE *fopen(const char *__restrict__ filename, const char *__restrict__ mode);
4855

4956
// Formated input/output functions

0 commit comments

Comments
 (0)