summaryrefslogtreecommitdiff
path: root/src/user/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/user/lib')
-rw-r--r--src/user/lib/include/stdio.h7
-rw-r--r--src/user/lib/stdio/file.c102
-rw-r--r--src/user/lib/stdio/file.h4
3 files changed, 80 insertions, 33 deletions
diff --git a/src/user/lib/include/stdio.h b/src/user/lib/include/stdio.h
index a030f13..48d5058 100644
--- a/src/user/lib/include/stdio.h
+++ b/src/user/lib/include/stdio.h
@@ -14,11 +14,10 @@
#define SEEK_END 3
#define _IONBF 0
-#define _IOFBF 0
-#define _IOLBF 1
+#define _IOFBF 1
+#define _IOLBF 2
-/* size of file buffers. not that we have any */
-#define BUFSIZ 1024
+#define BUFSIZ 4096
/* stop fread() from trying to fill the entire buffer before returning
* i.e. it will call _sys_read() exactly once */
diff --git a/src/user/lib/stdio/file.c b/src/user/lib/stdio/file.c
index 9a6e555..ab424d3 100644
--- a/src/user/lib/stdio/file.c
+++ b/src/user/lib/stdio/file.c
@@ -1,12 +1,13 @@
#include "file.h"
+#include <bits/panic.h>
#include <camellia.h>
#include <camellia/syscalls.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/param.h>
#include <unistd.h>
-#include <bits/panic.h>
static FILE _stdin_null = { .fd = STDIN_FILENO };
static FILE _stdout_null = { .fd = STDOUT_FILENO };
@@ -52,6 +53,7 @@ FILE *fopen(const char *path, const char *mode) {
f = fdopen(h, mode);
if (!f) close(h);
+ setvbuf(f, NULL, _IOFBF, 0);
return f;
}
@@ -81,13 +83,11 @@ fail:
FILE *fdopen(int fd, const char *mode) {
FILE *f;
- f = malloc(sizeof *f);
- if (!f) return NULL;
- f->fd = fd;
- f->pos = mode[0] == 'a' ? -1 : 0;
- f->eof = false;
- f->error = false;
- f->extflags = 0;
+ f = calloc(1, sizeof *f);
+ if (f) {
+ f->fd = fd;
+ f->pos = mode[0] == 'a' ? -1 : 0;
+ }
return f;
}
@@ -134,10 +134,19 @@ int fextflags(FILE *f, int extflags) {
}
int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size) {
- (void)f; (void)buf; (void)size;
- if (type == _IONBF) return 0;
- errno = ENOSYS;
- return -1;
+ if (type == _IONBF) {
+ free(f->readbuf);
+ f->readbuf = NULL;
+ return 0;
+ } else if (type == _IOFBF && buf == NULL) {
+ (void) size;
+ f->rblen = 0;
+ f->rbcap = BUFSIZ;
+ f->readbuf = malloc(f->rbcap);
+ return f->readbuf ? 0 : -1;
+ } else {
+ return errno = ENOSYS, -1;
+ }
}
static void fadvance(long amt, FILE *f) {
@@ -160,14 +169,39 @@ size_t fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict f) {
}
while (pos < total) {
- long res = _sys_read(f->fd, buf + pos, total - pos, f->pos);
- if (res < 0) {
- f->error = true;
- errno = -res;
- break;
- } else if (res == 0) {
- f->eof = true;
- break;
+ long res = 0;
+ if (f->readbuf) {
+ if (0 == f->rblen && total - pos < (f->rbcap >> 1)) {
+ res = _sys_read(f->fd, f->readbuf, f->rbcap, f->pos);
+ if (res < 0) {
+ f->error = true;
+ errno = -res;
+ break;
+ } else if (res == 0) {
+ f->eof = true;
+ break;
+ } else {
+ f->rblen = res;
+ }
+ }
+ if (0 < f->rblen) {
+ res = MIN(total - pos, f->rblen);
+ memcpy(buf + pos, f->readbuf, res);
+ f->rblen -= res;
+ memmove(f->readbuf, f->readbuf + res, f->rblen);
+ }
+ }
+ if (res == 0) {
+ /* no cache hit */
+ res = _sys_read(f->fd, buf + pos, total - pos, f->pos);
+ if (res < 0) {
+ f->error = true;
+ errno = -res;
+ break;
+ } else if (res == 0) {
+ f->eof = true;
+ break;
+ }
}
pos += res;
fadvance(res, f);
@@ -210,15 +244,19 @@ int fputs(const char *s, FILE *f) {
// TODO! c file buffering
char *fgets(char *buf, int size, FILE *f) {
- char c = '\0';
- long pos = 0;
- while (pos < (size-1) && c != '\n' && fread(&c, 1, 1, f))
- buf[pos++] = c;
- buf[pos++] = '\0';
-
- if (f->eof && pos == 1) return NULL;
- if (f->error) return NULL;
- return buf;
+ int pos, c;
+ for (pos = 0; pos < size-1; pos++) {
+ c = fgetc(f);
+ if (c == EOF) break;
+ buf[pos] = c;
+ if (c == '\n') break;
+ }
+ if (pos == 0 || f->error) {
+ return NULL;
+ } else {
+ buf[pos] = '\0';
+ return buf;
+ }
}
int fgetc(FILE *f) {
@@ -254,6 +292,10 @@ int fseeko(FILE *f, off_t offset, int whence) {
break;
case SEEK_CUR:
base = f->pos;
+ // TODO untested
+ if (f->readbuf) {
+ base -= f->rblen;
+ }
break;
case SEEK_END:
base = _sys_getsize(f->fd);
@@ -264,6 +306,7 @@ int fseeko(FILE *f, off_t offset, int whence) {
errno = EINVAL;
return -1;
}
+ f->rblen = 0;
if (base >= 0 && base + offset < 0) {
/* underflow */
@@ -292,6 +335,7 @@ off_t ftello(FILE *f) {
int fclose(FILE *f) {
fflush(f);
if (f->fd > 0) close(f->fd);
+ free(f->readbuf);
if (f != &_stdin_null && f != &_stdout_null && f != &_stderr_null)
free(f);
return 0;
diff --git a/src/user/lib/stdio/file.h b/src/user/lib/stdio/file.h
index 604b070..3bd64a1 100644
--- a/src/user/lib/stdio/file.h
+++ b/src/user/lib/stdio/file.h
@@ -1,5 +1,6 @@
#pragma once
#include <stdbool.h>
+#include <stdio.h>
struct _LIBC_FILE {
int fd;
@@ -7,4 +8,7 @@ struct _LIBC_FILE {
bool eof;
bool error;
int extflags;
+
+ char *readbuf;
+ size_t rblen, rbcap;
};