summaryrefslogtreecommitdiff
path: root/userland/libc/stdio/open_memstream.c
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
committerAnton Kling <anton@kling.gg>2023-10-22 19:50:38 +0200
commit4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch)
tree80f156b7940d9d19971395f335530170c69516c7 /userland/libc/stdio/open_memstream.c
Move everything into a new repo.
Diffstat (limited to 'userland/libc/stdio/open_memstream.c')
-rw-r--r--userland/libc/stdio/open_memstream.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/userland/libc/stdio/open_memstream.c b/userland/libc/stdio/open_memstream.c
new file mode 100644
index 0000000..8f359b9
--- /dev/null
+++ b/userland/libc/stdio/open_memstream.c
@@ -0,0 +1,108 @@
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+/*
+struct __IO_FILE {
+ size_t (*write)(FILE *, const unsigned char *, size_t);
+ size_t (*read)(FILE *, unsigned char *, size_t);
+ int (*seek)(FILE *, long, int);
+ long offset_in_file;
+ int buffered_char;
+ int has_buffered_char;
+ int fd;
+ uint8_t is_eof;
+ uint8_t has_error;
+ uint64_t file_size;
+ void *cookie;
+};
+*/
+
+struct Memstream {
+ size_t buffer_usage;
+ char *buffer;
+};
+
+#define MEMSTREAM_DEF_SIZE 4096
+
+size_t memstream_write(FILE *fp, const unsigned char *buf, size_t n) {
+ struct Memstream *c = fp->cookie;
+ // FIXME: Do a reallocation
+ if (c->buffer_usage + n >= fp->file_size) {
+ n = fp->file_size - c->buffer_usage;
+ }
+
+ memcpy(c->buffer + fp->offset_in_file, buf, n);
+ fp->offset_in_file += n;
+ if (fp->offset_in_file > c->buffer_usage)
+ c->buffer_usage = fp->offset_in_file;
+ return n;
+}
+
+size_t memstream_read(FILE *fp, unsigned char *buf, size_t n) {
+ struct Memstream *c = fp->cookie;
+ size_t length_left = c->buffer_usage - fp->offset_in_file;
+ n = min(length_left, n);
+ memcpy(buf, c->buffer + fp->offset_in_file, n);
+ fp->offset_in_file += n;
+ if (0 == n)
+ fp->is_eof = 1;
+ return n;
+}
+
+int memstream_seek(FILE *stream, long offset, int whence) {
+ switch (whence) {
+ case SEEK_SET:
+ stream->offset_in_file = offset;
+ break;
+ case SEEK_CUR:
+ stream->offset_in_file += offset;
+ break;
+ case SEEK_END:
+ stream->offset_in_file = stream->file_size + offset;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ // FIXME: Error checking
+ return 0;
+}
+
+FILE *open_memstream(char **bufp, size_t *sizep) {
+ struct Memstream *c = NULL;
+ FILE *fp = malloc(sizeof(FILE));
+ if (!fp)
+ return NULL;
+
+ fp->offset_in_file = 0;
+ fp->buffered_char = 0;
+ fp->has_buffered_char = 0;
+ fp->seek = memstream_seek;
+ fp->fd = -1;
+ fp->is_eof = 0;
+ fp->has_error = 0;
+ fp->file_size = MEMSTREAM_DEF_SIZE;
+
+ fp->write = memstream_write;
+ fp->read = memstream_read;
+
+ c = malloc(sizeof(struct Memstream));
+ if (!c) {
+ goto _exit_memstream_fail;
+ }
+
+ fp->cookie = (void *)c;
+
+ c->buffer = *bufp = malloc(MEMSTREAM_DEF_SIZE);
+ if (!bufp) {
+ goto _exit_memstream_fail;
+ }
+ c->buffer_usage = 0;
+
+ return fp;
+_exit_memstream_fail:
+ free(c);
+ free(fp);
+ return NULL;
+}