Implement stdio line buffering semantics.
This commit is contained in:
parent
15c48f4efc
commit
a90e6d5d16
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -26,5 +26,5 @@
|
|||
|
||||
extern "C" int flbf(FILE* fp)
|
||||
{
|
||||
return !(fp->flags & _FILE_NO_BUFFER);
|
||||
return fp->buffer_mode == _IOLBF;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 )
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
Loading…
Reference in New Issue