2 * AcessOS Basic C Library
\r
6 #include <acess/sys.h>
\r
11 #include "stdio_int.h"
\r
15 #define DEBUG_BUILD 0
\r
17 // === CONSTANTS ===
\r
21 // === PROTOTYPES ===
\r
22 struct sFILE *get_file_struct();
\r
25 struct sFILE _iob[STDIO_MAX_STREAMS]; // IO Buffer
\r
26 struct sFILE *stdin; // Standard Input
\r
27 struct sFILE *stdout; // Standard Output
\r
28 struct sFILE *stderr; // Standard Error
\r
29 ///\note Initialised in SoMain
\r
30 static const int STDIN_BUFSIZ = 512;
\r
31 static const int STDOUT_BUFSIZ = 512;
\r
34 void _stdio_init(void)
\r
36 // Init FileIO Pointers
\r
39 stdin->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_READ|FILE_FLAG_LINEBUFFERED;
\r
40 stdin->Buffer = malloc(STDIN_BUFSIZ);
\r
41 stdin->BufferSpace = STDIN_BUFSIZ;
\r
45 stdout->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE|FILE_FLAG_LINEBUFFERED;
\r
46 stdout->Buffer = malloc(STDOUT_BUFSIZ);
\r
47 stdout->BufferSpace = STDOUT_BUFSIZ;
\r
51 stderr->Flags = FILE_FLAG_ALLOC|FILE_FLAG_MODE_WRITE;
\r
54 void _stdio_cleanup(void)
\r
57 for( i = 0; i < STDIO_MAX_STREAMS; i ++ )
\r
63 int _fopen_modetoflags(const char *mode)
\r
70 case 'r': flags = FILE_FLAG_MODE_READ; break;
\r
71 case 'w': flags = FILE_FLAG_MODE_WRITE; break;
\r
72 case 'a': flags = FILE_FLAG_MODE_APPEND; break;
\r
73 case 'x': flags = FILE_FLAG_MODE_EXEC; break; // Acess addon
\r
80 for( ; *mode; mode ++ )
\r
84 case 'b': flags |= FILE_FLAG_M_BINARY; break;
\r
85 case '+': flags |= FILE_FLAG_M_EXT; break;
\r
95 * \fn FILE *freopen(char *file, char *mode, FILE *fp)
\r
97 EXPORT FILE *freopen(const char *file, const char *mode, FILE *fp)
\r
101 // Sanity Check Arguments
\r
102 if(!fp || !file || !mode) return NULL;
\r
109 fp->Flags = _fopen_modetoflags(mode);
\r
110 if(fp->Flags == -1)
\r
114 switch(fp->Flags & FILE_FLAG_MODE_MASK)
\r
117 case FILE_FLAG_MODE_READ:
\r
118 openFlags = OPENFLAG_READ;
\r
119 if(fp->Flags & FILE_FLAG_M_EXT)
\r
120 openFlags |= OPENFLAG_WRITE;
\r
123 case FILE_FLAG_MODE_WRITE:
\r
124 openFlags = OPENFLAG_WRITE;
\r
125 if(fp->Flags & FILE_FLAG_M_EXT)
\r
126 openFlags |= OPENFLAG_READ;
\r
129 case FILE_FLAG_MODE_APPEND:
\r
130 openFlags = OPENFLAG_APPEND;
\r
131 if(fp->Flags & FILE_FLAG_M_EXT)
\r
132 openFlags |= OPENFLAG_READ;
\r
135 case FILE_FLAG_MODE_EXEC:
\r
136 openFlags = OPENFLAG_EXEC;
\r
142 fp->FD = _SysReopen(fp->FD, file, openFlags);
\r
144 fp->FD = _SysOpen(file, openFlags);
\r
150 if( (fp->Flags & FILE_FLAG_MODE_MASK) == FILE_FLAG_MODE_APPEND ) {
\r
151 _SysSeek(fp->FD, 0, SEEK_END); //SEEK_END
\r
157 \fn FILE *fopen(const char *file, const char *mode)
\r
158 \brief Opens a file and returns the pointer
\r
159 \param file String - Filename to open
\r
160 \param mode Mode to open in
\r
162 EXPORT FILE *fopen(const char *file, const char *mode)
\r
166 // Sanity Check Arguments
\r
167 if(!file || !mode) return NULL;
\r
169 // Create Return Structure
\r
170 retFile = get_file_struct();
\r
172 return freopen(file, mode, retFile);
\r
175 EXPORT FILE *fmemopen(void *buffer, size_t length, const char *mode)
\r
179 if( !buffer || !mode ) return NULL;
\r
181 ret = get_file_struct();
\r
184 ret->Flags = _fopen_modetoflags(mode);
\r
185 if(ret->Flags == -1) {
\r
190 ret->Buffer = buffer;
\r
191 ret->BufferPos = 0;
\r
192 ret->BufferSpace = length;
\r
197 EXPORT int fclose(FILE *fp)
\r
199 if( !(fp->Flags & FILE_FLAG_ALLOC) )
\r
202 if( fp->FD >= 0 ) {
\r
210 EXPORT int setvbuf(FILE *fp, char *buffer, int mode, size_t size)
\r
217 // Check for memory files
\r
218 if( fp->FD == -2 ) {
\r
223 // Not strictly needed, as this should only be called before any IO
\r
226 // Eliminate any pre-existing buffer
\r
228 free( fp->Buffer );
\r
230 fp->BufferSpace = 0;
\r
234 if( mode == _IONBF ) {
\r
235 // Do nothing, buffering was disabled above
\r
239 // Sanity check buffering mode before allocating
\r
240 if( mode != _IOLBF && mode != _IOFBF ) {
\r
244 // Allocate a buffer if one was not provided
\r
246 buffer = malloc(size);
\r
250 // Set buffer pointer and size
\r
251 fp->Buffer = buffer;
\r
252 fp->BufferSpace = size;
\r
255 if( mode == _IOLBF )
\r
256 fp->Flags |= FILE_FLAG_LINEBUFFERED;
\r
258 fp->Flags &= ~FILE_FLAG_LINEBUFFERED;
\r
264 int _fflush_int(FILE *fp)
\r
269 // Check the buffer contains data
\r
270 if( fp->BufferPos == 0 )
\r
273 switch(fp->Flags & FILE_FLAG_MODE_MASK)
\r
275 // Read - Flush input buffer
\r
276 case FILE_FLAG_MODE_READ:
\r
280 // Append - Seek to end and write
\r
281 case FILE_FLAG_MODE_APPEND:
\r
282 _SysSeek(fp->FD, fp->BufferOfs, SEEK_SET);
\r
283 len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos);
\r
284 if( len < fp->BufferPos )
\r
286 fp->BufferPos -= len;
\r
287 fp->BufferOfs = _SysTell(fp->FD);
\r
290 // Write - Write buffer
\r
291 case FILE_FLAG_MODE_WRITE:
\r
292 //_SysDebug("Flushing to %i '%.*s'", fp->FD, fp->BufferPos, fp->Buffer);
\r
293 len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos);
\r
294 if( len != fp->BufferPos )
\r
296 fp->BufferPos -= len;
\r
304 EXPORT void fflush(FILE *fp)
\r
306 if( !fp || fp->FD == -1 )
\r
309 // Nothing to do for memory files
\r
316 EXPORT void clearerr(FILE *fp)
\r
318 if( !fp || fp->FD == -1 )
\r
321 // TODO: Impliment clearerr()
\r
324 EXPORT int feof(FILE *fp)
\r
326 if( !fp || fp->FD == -1 )
\r
328 return !!(fp->Flags & FILE_FLAG_EOF);
\r
331 EXPORT int ferror(FILE *fp)
\r
333 if( !fp || fp->FD == -1 )
\r
337 EXPORT int fileno(FILE *stream)
\r
342 EXPORT off_t ftell(FILE *fp)
\r
344 if(!fp || fp->FD == -1) return -1;
\r
349 return _SysTell(fp->FD);
\r
352 EXPORT int fseek(FILE *fp, long int amt, int whence)
\r
354 if(!fp || fp->FD == -1) return -1;
\r
356 if( fp->FD == -2 ) {
\r
366 if( fp->BufferSpace < (size_t)amt )
\r
369 fp->Pos = fp->BufferSpace - amt;
\r
372 if(fp->Pos > (off_t)fp->BufferSpace) {
\r
373 fp->Pos = fp->BufferSpace;
\r
374 fp->Flags |= FILE_FLAG_EOF;
\r
380 _SysSeek(fp->FD, amt, whence);
\r
381 fp->Pos = _SysTell(fp->FD);
\r
386 size_t _fwrite_unbuffered(FILE *fp, size_t size, size_t num, const void *data)
\r
388 size_t ret = 0, bytes;
\r
391 bytes = _SysWrite(fp->FD, data, size);
\r
392 if( bytes == (size_t)-1 ) {
\r
394 // TODO: Set error flag
\r
397 if( bytes != size ) {
\r
398 _SysDebug("_fwrite_unbuffered: Oops, rollback %i/%i bytes!", bytes, size);
\r
399 _SysSeek(fp->FD, -bytes, SEEK_CUR);
\r
402 data = (char*)data + size;
\r
404 fp->Pos += ret * size;
\r
409 * \fn EXPORT size_t fwrite(void *ptr, size_t size, size_t num, FILE *fp)
\r
410 * \brief Write to a stream
\r
412 EXPORT size_t fwrite(const void *ptr, size_t size, size_t num, FILE *fp)
\r
416 if(!fp || fp->FD == -1)
\r
418 if( size == 0 || num == 0 )
\r
421 // Handle memory files first
\r
422 if( fp->FD == -2 ) {
\r
423 size_t avail = (fp->BufferSpace - fp->Pos) / size;
\r
425 fp->Flags |= FILE_FLAG_EOF;
\r
428 size_t bytes = num * size;
\r
429 memcpy(fp->Buffer + fp->Pos, ptr, bytes);
\r
434 switch( _GetFileMode(fp) )
\r
436 case FILE_FLAG_MODE_READ:
\r
437 case FILE_FLAG_MODE_EXEC:
\r
439 case FILE_FLAG_MODE_APPEND:
\r
440 fseek(fp, 0, SEEK_END);
\r
441 case FILE_FLAG_MODE_WRITE:
\r
442 if( fp->BufferSpace )
\r
444 // Buffering enabled
\r
445 if( fp->BufferSpace - fp->BufferPos < size*num )
\r
447 // If there's not enough space, flush and write-through
\r
448 _fflush_int(fp); // TODO: check ret
\r
449 ret = _fwrite_unbuffered(fp, size, num, ptr);
\r
451 else if( (fp->Flags & FILE_FLAG_LINEBUFFERED) && memchr(ptr,'\n',size*num) )
\r
453 // Newline present? Flush though
\r
454 _fflush_int(fp); // TODO: check ret
\r
455 ret = _fwrite_unbuffered(fp, size, num, ptr);
\r
460 memcpy( fp->Buffer + fp->BufferPos, ptr, size*num );
\r
461 fp->BufferPos += size*num;
\r
467 // Bufering disabled, write-though
\r
468 ret = _fwrite_unbuffered(fp, size, num, ptr);
\r
470 // errno should be set earlier
\r
478 * \fn EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)
\r
479 * \brief Read from a stream
\r
481 EXPORT size_t fread(void *ptr, size_t size, size_t num, FILE *fp)
\r
485 if(!fp || fp->FD == -1)
\r
487 if( size == 0 || num == 0 )
\r
490 if( fp->FD == -2 ) {
\r
491 size_t avail = (fp->BufferSpace - fp->Pos) / size;
\r
493 fp->Flags |= FILE_FLAG_EOF;
\r
494 if( num > avail ) num = avail;
\r
495 size_t bytes = num * size;
\r
496 memcpy(ptr, fp->Buffer + fp->Pos, bytes);
\r
502 ret = _SysRead(fp->FD, ptr, size*num);
\r
503 if( ret == (size_t)-1)
\r
505 if( ret == 0 && size*num > 0 ) {
\r
506 fp->Flags |= FILE_FLAG_EOF;
\r
515 * \brief Write a string to a stream (without trailing \n)
\r
517 EXPORT int fputs(const char *s, FILE *fp)
\r
519 int len = strlen(s);
\r
520 return fwrite(s, 1, len, fp);
\r
524 * \brief Read a line (and possible trailing \n into a buffer)
\r
526 EXPORT char *fgets(char *s, int size, FILE *fp)
\r
530 while( ofs < size && ch != '\n' )
\r
532 if( fread(&ch, 1, 1, fp) != 1 )
\r
542 * \fn EXPORT int fputc(int c, FILE *fp)
\r
543 * \brief Write a single character to the stream
\r
545 EXPORT int fputc(int c, FILE *fp)
\r
547 return fwrite(&c, 1, 1, fp);
\r
550 EXPORT int putchar(int c)
\r
553 return _SysWrite(_stdout, &c, 1);
\r
557 * \fn EXPORT int fgetc(FILE *fp)
\r
558 * \brief Read a character from the stream
\r
560 EXPORT int fgetc(FILE *fp)
\r
563 if( fread(&ret, 1, 1, fp) != 1 )
\r
568 EXPORT int getchar(void)
\r
571 if(_SysRead(_stdin, &ret, 1) != 1) return -1;
\r
575 // --- INTERNAL ---
\r
577 * \fn FILE *get_file_struct()
\r
578 * \brief Returns a file descriptor structure
\r
580 FILE *get_file_struct()
\r
583 for(i=0;i<STDIO_MAX_STREAMS;i++)
\r
585 if(_iob[i].Flags & FILE_FLAG_ALLOC)
\r
587 _iob[i].Flags |= FILE_FLAG_ALLOC;
\r
595 EXPORT int puts(const char *str)
\r
602 len = _SysWrite(_stdout, str, len);
\r
603 _SysWrite(_stdout, "\n", 1);
\r