Implement stdio line buffering semantics.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-03-20 19:01:35 +01:00
parent 15c48f4efc
commit a90e6d5d16
14 changed files with 183 additions and 16 deletions

View File

@ -57,6 +57,7 @@ fregister.o \
fscanf.o \
fseek.o \
fseeko.o \
fsetdefaultbuf.o \
fseterr.o \
fsetlocking.o \
ftell.o \
@ -84,6 +85,8 @@ memmove.o \
memset.o \
op-new.o \
rewind.o \
setbuf.o \
setvbuf.o \
sort.o \
sprint.o \
sscanf.o \

View File

@ -2,11 +2,12 @@
#define _FILE_DECL
#define BUFSIZ 8192UL
#define _FILE_REGISTERED (1<<0)
#define _FILE_NO_BUFFER (1<<1)
#define _FILE_BUFFER_MODE_SET (1<<1)
#define _FILE_LAST_WRITE (1<<2)
#define _FILE_LAST_READ (1<<3)
#define _FILE_AUTO_LOCK (1<<4)
#define _FILE_STREAM (1<<5)
#define _FILE_BUFFER_OWNED (1<<6)
#define _FILE_MAX_PUSHBACK 8
typedef struct _FILE
{
@ -32,6 +33,7 @@ typedef struct _FILE
struct _FILE* prev;
struct _FILE* next;
int flags;
int buffer_mode;
size_t offset_input_buffer;
size_t amount_input_buffered;
size_t amount_output_buffered;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of the Sortix C Library.
@ -32,7 +32,11 @@
extern "C" int fgetc(FILE* fp)
{
if ( fp->flags & _FILE_NO_BUFFER )
if ( !(fp->flags & _FILE_BUFFER_MODE_SET) )
if ( fsetdefaultbuf(fp) != 0 )
return EOF; // TODO: ferror doesn't report error!
if ( fp->buffer_mode == _IONBF )
{
unsigned char c;
if ( fread(&c, sizeof(c), 1, fp) != 1 )

View File

@ -26,5 +26,5 @@
extern "C" int flbf(FILE* fp)
{
return !(fp->flags & _FILE_NO_BUFFER);
return fp->buffer_mode == _IOLBF;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of the Sortix C Library.
@ -27,7 +27,8 @@
static void ffreefile(FILE* fp)
{
free(fp->buffer);
if ( fp->flags & _FILE_BUFFER_OWNED )
free(fp->buffer);
free(fp);
}
@ -35,10 +36,10 @@ extern "C" FILE* fnewfile(void)
{
FILE* fp = (FILE*) calloc(sizeof(FILE), 1);
if ( !fp ) { return NULL; }
fp->buffersize = BUFSIZ;
fp->buffer = (unsigned char*) malloc(fp->buffersize);
if ( !fp->buffer ) { free(fp); return NULL; }
fp->buffersize = 0;
fp->buffer = NULL;
fp->flags = _FILE_AUTO_LOCK;
fp->buffer_mode = 0;
fp->offset_input_buffer = 0;
fp->amount_input_buffered = 0;
fp->amount_output_buffered = 0;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
This file is part of the Sortix C Library.
@ -26,7 +26,11 @@
extern "C" int fputc(int c, FILE* fp)
{
if ( fp->flags & _FILE_NO_BUFFER )
if ( !(fp->flags & _FILE_BUFFER_MODE_SET) )
if ( fsetdefaultbuf(fp) != 0 )
return EOF; // TODO: ferror doesn't report error!
if ( fp->buffer_mode == _IONBF )
{
unsigned char c_char = c;
if ( fwrite(&c_char, sizeof(c_char), 1, fp) != 1 )
@ -45,7 +49,7 @@ extern "C" int fputc(int c, FILE* fp)
return EOF;
fp->buffer[fp->amount_output_buffered++] = c;
if ( c == '\n' && fflush(fp) != 0 )
if ( fp->buffer_mode == _IOLBF && c == '\n' && fflush(fp) != 0 )
return EOF;
return c;

View File

@ -26,8 +26,11 @@
extern "C" size_t fread(void* ptr, size_t size, size_t nmemb, FILE* fp)
{
if ( fp->flags & _FILE_NO_BUFFER )
if ( fp->buffer_mode == _IONBF )
{
if ( !(fp->flags & _FILE_BUFFER_MODE_SET) )
if ( fsetdefaultbuf(fp) != 0 )
return EOF; // TODO: ferror doesn't report error!
if ( !fp->read_func )
return 0; // TODO: ferror doesn't report error!
if ( fp->flags & _FILE_LAST_WRITE )

66
libc/fsetdefaultbuf.cpp Normal file
View File

@ -0,0 +1,66 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
fsetdefaultbuf.cpp
Sets up default buffering semantics for a FILE.
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" int fsetdefaultbuf(FILE* fp)
{
char* buf = (char*) malloc(sizeof(char) * BUFSIZ);
if ( !buf )
{
// TODO: Determine whether this is truly what we would want and whether
// a buffer should be pre-allocated when the FILE is created such that
// this situation _cannot_ occur.
// Alright, we're in a bit of a situation here. Normally, we'd go
// buffered but we are out of memory. We could either fail, but that
// would mean subsequent calls such as fgetc and fputc would also fail -
// however that we are out of memory doesn't mean that IO would also
// fail. Therefore we'll revert to unbuffered semantics and hope that's
// good enough.
return setvbuf(fp, NULL, _IONBF, 0);
}
// Determine the buffering semantics depending on whether the destination is
// an interactive device or not.
#ifdef SORTIX_KERNEL
int mode = _IOLBF; // TODO: Detect this?
#else
int mode = fp->buffer_mode != -1 ? fp->buffer_mode
: isatty(fileno(fp)) ? _IOLBF : _IOFBF;
#endif
int ret = setvbuf(fp, buf, mode, BUFSIZ);
if ( ret )
{
free(buf);
return -1;
}
// The buffer now belongs to the FILE.
fp->flags |= _FILE_BUFFER_OWNED;
return ret;
}

View File

@ -26,8 +26,12 @@
extern "C" size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* fp)
{
if ( fp->flags & _FILE_NO_BUFFER )
if ( fp->buffer_mode == _IONBF )
{
if ( !(fp->flags & _FILE_BUFFER_MODE_SET) )
if ( fsetdefaultbuf(fp) != 0 )
return EOF; // TODO: ferror doesn't report error!
if ( !fp->write_func )
return 0; // TODO: ferror doesn't report error!
if ( fp->flags & _FILE_LAST_READ )

View File

@ -111,6 +111,7 @@ extern int rename(const char* oldname, const char* newname);
extern void rewind(FILE* stream);
extern int snprintf(char* restrict s, size_t n, const char* restrict format, ...);
extern void setbuf(FILE* restrict stream, char* restrict buf);
extern int setvbuf(FILE* restrict stream, char* restrict buf, int type, size_t size);
extern char* sortix_gets(void);
extern int sortix_puts(const char* str);
extern int sprintf(char* restrict s, const char* restrict format, ...);
@ -139,7 +140,6 @@ extern int getchar_unlocked(void);
extern int getc_unlocked(FILE* stream);
extern int putchar_unlocked(int c);
extern int putc_unlocked(int c, FILE* steam);
extern int setvbuf(FILE* restrict stream, char* restrict buf, int type, size_t size);
extern int vdprintf(int fildes, const char* restrict format, __gnuc_va_list ap);
extern void flockfile(FILE* file);
extern void funlockfile(FILE* file);
@ -168,6 +168,7 @@ void fseterr(FILE* fp);
void fregister(FILE* fp);
void funregister(FILE* fp);
FILE* fnewfile(void);
int fsetdefaultbuf(FILE* fp);
int fcloseall(void);
int fpipe(FILE* pipes[2]);
/* Internally used by standard library. */

34
libc/setbuf.cpp Normal file
View File

@ -0,0 +1,34 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
setbuf.cpp
Sets up buffering semantics for a FILE.
*******************************************************************************/
#include <errno.h>
#include <stdio.h>
// TODO: This function just be removed as setvbuf provides a superior interface,
// however it's currently defined in C89, C99 and C11 - so removing it
// is non-standard - and this little file doesn't hurt anyone. :-)
extern "C" void setbuf(FILE* fp, char* buf)
{
setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
}

40
libc/setvbuf.cpp Normal file
View File

@ -0,0 +1,40 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2013.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix C Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
setvbuf.cpp
Sets up buffering semantics for a FILE.
*******************************************************************************/
#include <errno.h>
#include <stdio.h>
extern "C" int setvbuf(FILE* fp, char* buf, int mode, size_t size)
{
if ( fp->flags & _FILE_BUFFER_MODE_SET )
return errno = EINVAL, -1;
fp->buffer_mode = mode;
if ( buf )
{
fp->buffer = (unsigned char*) buf;
fp->buffersize = size;
fp->flags |= _FILE_BUFFER_MODE_SET;
}
return 0;
}

View File

@ -38,6 +38,7 @@ int init_stdio()
stdin = fdio_newfile(0, "r");
stdout = fdio_newfile(1, "w");
stderr = fdio_newfile(2, "w");
setvbuf(stderr, NULL, _IONBF, 0);
return 0;
}

View File

@ -29,7 +29,11 @@
extern "C" int ungetc(int c, FILE* fp)
{
if ( !fp->read_func || (fp->flags & _FILE_NO_BUFFER) )
if ( !(fp->flags & _FILE_BUFFER_MODE_SET) )
if ( fsetdefaultbuf(fp) != 0 )
return EOF; // TODO: ferror doesn't report error!
if ( !fp->read_func || fp->buffer_mode == _IONBF )
return EOF;
if ( fp->flags & _FILE_LAST_WRITE )