mescc: Mes C Library: Add buffered read.
authorJan Nieuwenhuizen <janneke@gnu.org>
Sat, 27 Jul 2019 20:58:49 +0000 (22:58 +0200)
committerJan Nieuwenhuizen <janneke@gnu.org>
Sat, 27 Jul 2019 20:58:49 +0000 (22:58 +0200)
* lib/mes/__buffered_read.c: New file.
* build-aux/configure-lib.sh (libc_SOURCES): Add it.  Also add memmove.c.
(libc_tcc_SOURCES): Remove memmove.c
* lib/linux/close.c (close): Clear read buffer.
* lib/linux/_open3.c (_open3): Likewise.
* lib/linux/lseek.c (lseek): Correct for read buffer.
* lib/stdio/fwrite.c (fwrite): Likewise.
* lib/posix/read.c (read): Call __buffered_read.
* lib/posix/write.c (write): Add FIXME note about buffered reads.
* simple.sh: Update.

14 files changed:
build-aux/configure-lib.sh
include/mes/lib.h
lib/linux/_open3.c
lib/linux/close.c
lib/linux/lseek.c
lib/mes/__buffered_read.c [new file with mode: 0644]
lib/mes/fdgetc.c
lib/posix/read.c
lib/posix/write.c
lib/stdio/fread.c
lib/stdio/fseek.c
lib/stdio/fwrite.c
mes/module/mes/repl.mes
simple.sh

index 86d15b22a0369fc382f286d61f26a60b09e0480d..159aa11bd60263fba0d97fcf98b0028568d3994c 100644 (file)
@@ -78,6 +78,7 @@ fi
 libc_SOURCES="
 $libmes_SOURCES
 lib/mes/__assert_fail.c
+lib/mes/__buffered_read.c
 lib/mes/__mes_debug.c
 lib/posix/execv.c
 lib/posix/getcwd.c
@@ -101,6 +102,7 @@ lib/stdlib/realloc.c
 lib/string/memchr.c
 lib/string/memcmp.c
 lib/string/memcpy.c
+lib/string/memmove.c
 lib/string/memset.c
 lib/string/strcmp.c
 lib/string/strcpy.c
@@ -171,7 +173,6 @@ lib/stdlib/strtoll.c
 lib/stdlib/strtoul.c
 lib/stdlib/strtoull.c
 lib/string/memmem.c
-lib/string/memmove.c
 lib/string/strcat.c
 lib/string/strchr.c
 lib/string/strlwr.c
index 63d1eba91dab4dfd22b8fb6090245e1099a7b6fc..1de015fa3141d88c087a882c709ba3c2f55b62db 100644 (file)
@@ -54,11 +54,14 @@ ssize_t _read (int fd, void *buffer, size_t size);
 extern char *__brk;
 extern void (*__call_at_exit) (void);
 
+#define __FILEDES_MAX 512
+
 #if !SYSTEM_LIBC
 void __assert_fail (char *s);
+ssize_t __buffered_read (int filedes, void *buffer, size_t size);
+size_t __buffered_read_clear (int filedes);
 void _exit (int code);
 long brk (void *addr);
-
 #endif // !SYSTEM_LIBC
 
 #endif //__MES_LIB_H
index e1bf1f7b849a8e13d22a79f0853814f376ce35eb..8f103e7bcd874daccd10e9fd7ef4337574b4e783 100644 (file)
@@ -29,6 +29,9 @@ _open3 (char const *file_name, int flags, int mask)
   int r = _sys_call3 (SYS_open, (long) file_name, (int) flags, (int) mask);
   __ungetc_init ();
   if (r > 2)
-    __ungetc_clear (r);
+    {
+      __ungetc_clear (r);
+      __buffered_read_clear (r);
+    }
   return r;
 }
index 91a049c4480225731fbe3cbcd68f5e8afa126983..e25e83187e087324cab5587126ba83929f3cf661 100644 (file)
@@ -25,7 +25,7 @@
 int
 close (int filedes)
 {
-  if (filedes > 2)
-    __ungetc_clear (filedes);
+  __ungetc_clear (filedes);
+  __buffered_read_clear (filedes);
   return _sys_call1 (SYS_close, (int) filedes);
 }
index 9d21659b4237fd8b9b434b22a316afff62e97ee2..94f2f9f7a257a9c1ee4c4b244f113482a11d7229 100644 (file)
  * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <mes/lib.h>
 #include <linux/syscall.h>
 #include <syscall.h>
+#include <stdio.h>
 #include <sys/types.h>
 
 off_t
 lseek (int filedes, off_t offset, int whence)
 {
+  size_t skip = __buffered_read_clear (filedes);
+  if (whence == SEEK_CUR)
+    offset -= skip;
   return _sys_call3 (SYS_lseek, (int) filedes, (long) offset, (int) whence);
 }
diff --git a/lib/mes/__buffered_read.c b/lib/mes/__buffered_read.c
new file mode 100644 (file)
index 0000000..e47cca5
--- /dev/null
@@ -0,0 +1,79 @@
+/* -*-comment-start: "//";comment-end:""-*-
+ * GNU Mes --- Maxwell Equations of Software
+ * Copyright © 2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ *
+ * This file is part of GNU Mes.
+ *
+ * GNU Mes is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * GNU Mes 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <mes/lib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define __READ_BUFFER_MAX 100
+
+struct __read_buffer
+{
+  ssize_t size;
+  char string[__READ_BUFFER_MAX];
+};
+
+struct __read_buffer *__read_cache = 0;
+
+void
+__buffered_read_init (int filedes)
+{
+  if (!__read_cache)
+    __read_cache = (struct __read_buffer *) malloc (sizeof (struct __read_buffer) * __FILEDES_MAX);
+}
+
+size_t
+__buffered_read_clear (int filedes)
+{
+  __buffered_read_init (filedes);
+  size_t size = __read_cache[filedes].size;
+  __read_cache[filedes].size = 0;
+  return size;
+}
+
+ssize_t
+__buffered_read (int filedes, void *buffer, size_t size)
+{
+  size_t todo = size;
+  __buffered_read_init (filedes);
+  struct __read_buffer *cache = &__read_cache[filedes];
+  char *p = buffer;
+  if (!cache->size && size > __READ_BUFFER_MAX)
+    return _read (filedes, buffer, size);
+  while (cache->size > 0 && todo)
+    {
+      todo--;
+      *p++ = cache->string[__READ_BUFFER_MAX - cache->size--];
+    }
+  if (todo)
+    {
+      ssize_t bytes = _read (filedes, cache->string, __READ_BUFFER_MAX);
+      if (bytes < 0)
+        return -1;
+      if (bytes)
+        {
+          cache->size = bytes;
+          if (bytes < __READ_BUFFER_MAX)
+            memmove (cache->string + __READ_BUFFER_MAX - bytes, cache->string, bytes);
+          return size - todo + __buffered_read (filedes, p, todo);
+        }
+    }
+  return size - todo;
+}
index 8dfa256c07f633dd1e4371c8d0d0333f10a4ff71..74a8eaff6202663d047b110e35e71d18821ccffe 100644 (file)
@@ -24,9 +24,7 @@
 #include <sys/resource.h>
 #include <unistd.h>
 
-#define __UNGETC_MAX 1024
-
-int __ungetc_buf[__UNGETC_MAX + 1] = { 0 };
+int __ungetc_buf[__FILEDES_MAX + 1] = { 0 };
 
 int
 __ungetc_p (int filedes)
@@ -37,8 +35,8 @@ __ungetc_p (int filedes)
 void
 __ungetc_init ()
 {
-  if (__ungetc_buf[__UNGETC_MAX] == 0)
-    memset (__ungetc_buf, -1, (__UNGETC_MAX + 1) * sizeof (int));
+  if (__ungetc_buf[__FILEDES_MAX] == 0)
+    memset (__ungetc_buf, -1, (__FILEDES_MAX + 1) * sizeof (int));
 }
 
 void
index 5fbda5341b1d89318a279756c012e82c0dd6dd1f..d47d5d154c7cd34af9baa09d3aac500f3264b9bb 100644 (file)
@@ -24,7 +24,7 @@
 ssize_t
 read (int filedes, void *buffer, size_t size)
 {
-  ssize_t bytes = _read (filedes, buffer, size);
+  ssize_t bytes = __buffered_read (filedes, buffer, size);
   if (__mes_debug () > 4)
     {
       if (bytes == 1)
index 811bc0abf737d42b7770a174958765573a1158c0..6843cd5531e4da63cb70d865908f3e3fc935c318 100644 (file)
  * along with GNU Mes.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <errno.h>
 #include <mes/lib-mini.h>
+#include <errno.h>
 
 ssize_t
 write (int filedes, void const *buffer, size_t size)
 {
+#if 0 // !MES_MINI
+  // FIXME: libc-mini has no __buffered_read_clear, lseek.
+  // and libc includes libc-mini...how to override?
+  // Let's hope everyone uses fwrite, or lseek for RDWR
+  // semantics...
+  size_t skip = __buffered_read_clear (filedes);
+  if (skip)
+    lseek (filedes, -skip, SEEK_CUR);
+#endif
   int r = _write (filedes, buffer, size);
   if (r < 0)
     {
index 77f3b864d69e99e240561b8aa58cc7a84f0e7f79..505700ca7ba77198a209e4fcc074abc65bab66a2 100644 (file)
@@ -41,9 +41,10 @@ fread (void *data, size_t size, size_t count, FILE * stream)
   int bytes = 0;
   while (__fungetc_p (stream) && todo-- && ++bytes)
     *buf++ = fgetc (stream);
+  int filedes = (long) stream;
   if (todo)
     {
-      int r = read ((int) (long) stream, buf, todo);
+      int r = read (filedes, buf, todo);
       if (r < 0 && !bytes)
         bytes = r;
       else
@@ -52,18 +53,18 @@ fread (void *data, size_t size, size_t count, FILE * stream)
 
   if (__mes_debug ())
     {
+      static char debug_buf[4096];
       eputs ("fread fd=");
-      eputs (itoa ((int) (long) stream));
+      eputs (itoa (filedes));
       eputs (" bytes=");
       eputs (itoa (bytes));
       eputs ("\n");
-      static char buf[4096];
-      if (bytes > 0 && bytes < sizeof (buf))
+      if (bytes > 0 && bytes < sizeof (debug_buf))
         {
-          strncpy (buf, data, bytes);
+          strncpy (debug_buf, data, bytes);
           buf[bytes] = 0;
           eputs ("fread buf=");
-          eputs (buf);
+          eputs (debug_buf);
           eputs ("\n");
         }
     }
index 268f9792c42b14652a2d3b5054f0c1105cab4b5c..ce468ab36def9158f62095a342712daeba88c689 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-comment-start: "//";comment-end:""-*-
  * GNU Mes --- Maxwell Equations of Software
- * Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ * Copyright © 2017,2018,2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  *
  * This file is part of GNU Mes.
  *
 int
 fseek (FILE * stream, long offset, int whence)
 {
-  off_t pos = lseek ((int) (long) stream, offset, whence);
+  int filedes = (long) stream;
+  off_t pos = lseek (filedes, offset, whence);
   if (__mes_debug ())
     {
       eputs ("fread fd=");
-      eputs (itoa ((int) (long) stream));
+      eputs (itoa (filedes));
       eputs ("  =>");
       eputs (itoa (pos));
       eputs ("\n");
index 995450e9b4e0880cb4fa57543cb0a216e9c73fae..6e048ee2a7725738b4c6011fa0df09d0a7e37554 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <mes/lib.h>
 #include <stdio.h>
+#include <unistd.h>
 
 size_t
 fwrite (void const *data, size_t size, size_t count, FILE * stream)
@@ -35,7 +36,12 @@ fwrite (void const *data, size_t size, size_t count, FILE * stream)
 
   if (!size || !count)
     return 0;
-  int bytes = write ((int) (long) stream, data, size * count);
+  // FIXME: should be in write, but that's libc-mini.
+  int filedes = (long) stream;
+  size_t skip = __buffered_read_clear (filedes);
+  if (skip)
+    lseek (filedes, -skip, SEEK_CUR);
+  int bytes = write (filedes, data, size * count);
 
   if (__mes_debug () > 2)
     {
index 4f4ab5a3249750c65d6fcec0a83d7dce93b2c296..f324420325d3ba5f6fd748332b2aac33b29ed0d0 100644 (file)
@@ -29,7 +29,7 @@
 
 (define welcome
   (string-append "GNU Mes " %version "
-Copyright (C) 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+Copyright (C) 2016,2017,2018,2019 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
 
 GNU Mes comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
 This program is free software, and you are welcome to redistribute it
index b0b02d7d346d34a7170f12c14a3a00c540ffbe6d..97e249e664b91d4fa96924512b07d73c373b12b0 100755 (executable)
--- a/simple.sh
+++ b/simple.sh
@@ -167,12 +167,14 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\
     lib/ctype/isxdigit.c\
     \
     lib/mes/__assert_fail.c\
+    lib/mes/__buffered_read.c\
     lib/mes/__mes_debug.c\
     lib/posix/execv.c\
     lib/posix/getcwd.c\
     lib/posix/getenv.c\
     lib/posix/isatty.c\
     lib/posix/open.c\
+    lib/posix/read.c\
     lib/posix/setenv.c\
     lib/posix/wait.c\
     lib/stdio/fgetc.c\
@@ -189,6 +191,7 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\
     lib/string/memchr.c\
     lib/string/memcmp.c\
     lib/string/memcpy.c\
+    lib/string/memmove.c\
     lib/string/memset.c\
     lib/string/strcmp.c\
     lib/string/strcpy.c\
@@ -207,7 +210,7 @@ $CC -g -D HAVE_CONFIG_H=1 -I include -I include/$mes_kernel/$mes_cpu\
     lib/linux/gettimeofday.c\
     lib/linux/ioctl.c\
     lib/linux/_open3.c\
-    lib/linux/read.c\
+    lib/linux/_read.c\
     lib/linux/time.c\
     lib/linux/unlink.c\
     lib/linux/waitpid.c\