libc: Implement read buffering =D
This commit is contained in:
parent
d60ad184f1
commit
420270ebd4
@ -4,7 +4,7 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
fprintf(stderr, "Writing incomplete line to stdout (_IOLBF=%d)...\n", stdout->_mode);
|
||||
fprintf(stderr, "Writing incomplete line to stdout (_IOLBF=%d)...\n", stdout->_buf.mode);
|
||||
fputs("hi!", stdout);
|
||||
sleep(3);
|
||||
putchar('\n');
|
||||
@ -14,7 +14,7 @@ int main()
|
||||
assert(f);
|
||||
assert(setvbuf(f, NULL, _IOFBF, 0) == 0);
|
||||
|
||||
fprintf(stderr, "Writing long text to file (_IOFBF=%d)...\n", f->_mode);
|
||||
fprintf(stderr, "Writing long text to file (_IOFBF=%d)...\n", f->_buf.mode);
|
||||
|
||||
fputs("Hello world!\nHow are you doing!\nThis is a test for many lines of buffering.\n", f);
|
||||
|
||||
|
@ -69,9 +69,27 @@ static int flush_write_buffer(FILE* stream)
|
||||
stream->_buf.index = 0;
|
||||
stream->_buf.size = 0;
|
||||
|
||||
stream->_buf.status &= ~FileStatusFlags::LastWrite;
|
||||
|
||||
return result < 0 ? EOF : 0;
|
||||
}
|
||||
|
||||
static int flush_read_buffer(FILE* stream)
|
||||
{
|
||||
if (stream->_buf.mode == _IONBF) return 0;
|
||||
|
||||
// Reset the stream to its expected position.
|
||||
ssize_t unread_bytes = stream->_buf.size - stream->_buf.index;
|
||||
lseek(stream->_fd, -unread_bytes, SEEK_CUR);
|
||||
|
||||
stream->_buf.index = 0;
|
||||
stream->_buf.size = 0;
|
||||
|
||||
stream->_buf.status &= ~FileStatusFlags::LastRead;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t write_into_buffer(FILE* stream, const u8* data, ssize_t size)
|
||||
{
|
||||
ssize_t total_written = 0;
|
||||
@ -81,6 +99,8 @@ static ssize_t write_into_buffer(FILE* stream, const u8* data, ssize_t size)
|
||||
ssize_t nwritten;
|
||||
if (stream->_buf.mode != _IONBF)
|
||||
{
|
||||
if (stream->_buf.status & FileStatusFlags::LastRead) flush_read_buffer(stream);
|
||||
|
||||
if ((stream->_buf.size + size) > stream->_buf.capacity)
|
||||
{
|
||||
if (flush_write_buffer(stream) < 0) return -1;
|
||||
@ -90,6 +110,8 @@ static ssize_t write_into_buffer(FILE* stream, const u8* data, ssize_t size)
|
||||
nwritten = size > size_remaining ? size_remaining : size;
|
||||
memcpy(stream->_buf.buffer + stream->_buf.size, data, nwritten);
|
||||
|
||||
stream->_buf.status |= FileStatusFlags::LastWrite;
|
||||
|
||||
stream->_buf.size += nwritten;
|
||||
|
||||
if (stream->_buf.mode == _IOLBF && memchr(data, '\n', nwritten))
|
||||
@ -108,6 +130,51 @@ static ssize_t write_into_buffer(FILE* stream, const u8* data, ssize_t size)
|
||||
return total_written;
|
||||
}
|
||||
|
||||
static ssize_t read_data_into_buffer(FILE* stream)
|
||||
{
|
||||
stream->_buf.index = 0;
|
||||
ssize_t nread = read(stream->_fd, stream->_buf.buffer, stream->_buf.capacity);
|
||||
if (nread >= 0) stream->_buf.size = nread;
|
||||
stream->_buf.status |= FileStatusFlags::LastRead;
|
||||
return nread;
|
||||
}
|
||||
|
||||
static ssize_t read_from_buffer(FILE* stream, u8* data, ssize_t size)
|
||||
{
|
||||
ssize_t total_read = 0;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
ssize_t nread;
|
||||
if (stream->_buf.mode != _IONBF)
|
||||
{
|
||||
if (stream->_buf.status & FileStatusFlags::LastWrite) flush_write_buffer(stream);
|
||||
|
||||
if (stream->_buf.size == stream->_buf.index)
|
||||
{
|
||||
ssize_t rc;
|
||||
if ((rc = read_data_into_buffer(stream)) < 0) return -1;
|
||||
if (rc == 0) return total_read;
|
||||
}
|
||||
|
||||
ssize_t size_remaining = stream->_buf.size - stream->_buf.index;
|
||||
nread = size > size_remaining ? size_remaining : size;
|
||||
memcpy(data, stream->_buf.buffer + stream->_buf.index, nread);
|
||||
|
||||
stream->_buf.index += nread;
|
||||
}
|
||||
else
|
||||
nread = read(stream->_fd, data, size > BUFSIZ ? BUFSIZ : size);
|
||||
if (nread < 0) return nread;
|
||||
if (nread == 0) return total_read;
|
||||
size -= nread;
|
||||
data += nread;
|
||||
total_read += nread;
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void _init_stdio()
|
||||
@ -117,7 +184,12 @@ extern "C"
|
||||
|
||||
int fflush(FILE* stream)
|
||||
{
|
||||
if (stream && stream->_buf.mode != _IONBF) flush_write_buffer(stream);
|
||||
if (stream && stream->_buf.mode != _IONBF)
|
||||
{
|
||||
if (stream->_buf.status & FileStatusFlags::LastWrite) flush_write_buffer(stream);
|
||||
else if (stream->_buf.status & FileStatusFlags::LastRead)
|
||||
flush_read_buffer(stream);
|
||||
}
|
||||
else if (!stream)
|
||||
{
|
||||
for (int i = 0; i < FOPEN_MAX; i++)
|
||||
@ -246,7 +318,7 @@ extern "C"
|
||||
{
|
||||
if (size * nmemb == 0) return 0;
|
||||
|
||||
ssize_t nread = read(stream->_fd, buf, size * nmemb);
|
||||
ssize_t nread = read_from_buffer(stream, (u8*)buf, size * nmemb);
|
||||
|
||||
if (nread < 0)
|
||||
{
|
||||
@ -351,7 +423,7 @@ extern "C"
|
||||
int fgetc(FILE* stream)
|
||||
{
|
||||
u8 value;
|
||||
ssize_t rc = read(stream->_fd, &value, 1);
|
||||
ssize_t rc = read_from_buffer(stream, &value, 1);
|
||||
if (rc <= 0) return EOF;
|
||||
return value;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user