From 9efad5f8d3ebbecdf8221d871f43bcbd15f1ac7d Mon Sep 17 00:00:00 2001
From: Anton Kling <anton@kling.gg>
Date: Sun, 22 Oct 2023 23:22:32 +0200
Subject: libc: Add a cache to the fread function for reading from files on
 disk.

This helps a ton when using functions such as fscanf that reads from a
FILE byte by byte. By creating a cache it avoids a ton of 'read'
syscalls that would otherwise be made.
---
 userland/libc/stdio/stdin.c | 33 +++++++++++++++++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

(limited to 'userland/libc/stdio/stdin.c')

diff --git a/userland/libc/stdio/stdin.c b/userland/libc/stdio/stdin.c
index ae3ab8d..2e1e50f 100644
--- a/userland/libc/stdio/stdin.c
+++ b/userland/libc/stdio/stdin.c
@@ -12,7 +12,7 @@ size_t write_fd(FILE *f, const unsigned char *s, size_t l) {
   return rc;
 }
 
-size_t read_fd(FILE *f, unsigned char *s, size_t l) {
+size_t non_cache_read_fd(FILE *f, unsigned char *s, size_t l) {
   int rc = pread(f->fd, s, l, f->offset_in_file);
   if (rc == 0)
     f->is_eof = 1;
@@ -20,11 +20,40 @@ size_t read_fd(FILE *f, unsigned char *s, size_t l) {
     f->has_error = 1;
     return 0;
   }
-  f->offset_in_file += rc;
   return rc;
 }
 
+size_t read_fd(FILE *f, unsigned char *s, size_t l) {
+  if (0 == l)
+    return 0;
+  if (!f->read_buffer) {
+    f->read_buffer = malloc(4096);
+    f->read_buffer_stored = 0;
+    f->read_buffer_has_read = 0;
+  }
+  if (f->read_buffer_stored > 0) {
+    size_t read_len = min(l, f->read_buffer_stored);
+    f->offset_in_file += read_len;
+    memcpy(s, f->read_buffer + f->read_buffer_has_read, read_len);
+    f->read_buffer_stored -= read_len;
+    f->read_buffer_has_read += read_len;
+    s += read_len;
+    l -= read_len;
+    return read_len + read_fd(f, s, l);
+  }
+  if (0 == f->read_buffer_stored) {
+    f->read_buffer_stored = non_cache_read_fd(f, f->read_buffer, 4096);
+    f->read_buffer_has_read = 0;
+    if (0 == f->read_buffer_stored) {
+      return 0;
+    }
+    return read_fd(f, s, l);
+  }
+  assert(0);
+}
+
 int seek_fd(FILE *stream, long offset, int whence) {
+  stream->read_buffer_stored = 0;
   switch (whence) {
   case SEEK_SET:
     stream->offset_in_file = offset;
-- 
cgit v1.2.3