guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] 02/02: Port read/write functions take bytevectors


From: Andy Wingo
Subject: [Guile-commits] 02/02: Port read/write functions take bytevectors
Date: Mon, 11 Apr 2016 20:28:18 +0000

wingo pushed a commit to branch wip-port-refactor
in repository guile.

commit f7027a8b88452948cd6bf0fe2605ef3d9ef4dded
Author: Andy Wingo <address@hidden>
Date:   Mon Apr 11 18:40:03 2016 +0200

    Port read/write functions take bytevectors
    
    This will allow better Scheme integration for ports.
    
    * libguile/ports.h (scm_t_port_buffer): Change "holder" member to be a
      bytevector defined to have "buf" as its starting point.
      (scm_t_ptob_descriptor): Change read and write functions to take
      bytevectors as arguments and to return the number of octets read or
      written.
      (scm_make_port_type): Adapt accordingly.
      (scm_c_read_bytes, scm_c_write_bytes): New functions that take
      bytevectors.
    * libguile/ports.c (scm_make_port_type): Adapt to read/write function
      prototype change.
      (scm_c_make_port_buffer): Arrange to populate the "bytevector" field.
      (scm_i_read_bytes_unlocked): New function.
      (scm_i_read_unlocked): Use scm_i_read_bytes_unlocked.
      (scm_c_read_bytes_unlocked): New function.
      (scm_c_read_unlocked): Update comment, and always go through the
      buffer.
      (scm_c_read_bytes): New function.
      (scm_flush_unlocked): Use scm_i_write_unlocked instead of the port's
      write function.
      (scm_i_write_bytes_unlocked): New function.
      (scm_i_write_unlocked): Use scm_i_write_bytes_unlocked.
      (scm_c_write_bytes_unlocked): New function.
      (scm_c_write_unlocked): Always write through the buffer.
      (scm_c_write_bytes): New function.
      (scm_truncate_file): Remove unused variable.
      (void_port_read, void_port_write): Adapt to read/write prototype
      change.
    * libguile/fports.c (fport_read, fport_write):
    * libguile/r6rs-ports.c (bytevector_input_port_read)
      (custom_binary_input_port_read, bytevector_output_port_write)
      (custom_binary_output_port_write, transcoded_port_write)
      (transcoded_port_read): Adapt to read/write prototype
      change.
      (scm_get_bytevector_n, scm_get_bytevector_n_x)
      (scm_get_bytevector_all): Use scm_c_read_bytes.
      (scm_put_bytevector): Use scm_c_write_bytes.
    * libguile/strports.c (string_port_read, string_port_write):
    * libguile/vports.c (soft_port_write, soft_port_read): Adapt to
      read/write prototype change.
    * test-suite/standalone/test-scm-c-read.c (custom_port_read): Fix for
      read API change.
---
 libguile/fports.c                       |   26 ++--
 libguile/ports.c                        |  351 +++++++++++++++++++++++--------
 libguile/ports.h                        |   14 +-
 libguile/r6rs-ports.c                   |  153 +++++---------
 libguile/strports.c                     |   27 ++--
 libguile/vports.c                       |   29 ++-
 test-suite/standalone/test-scm-c-read.c |   12 +-
 7 files changed, 372 insertions(+), 240 deletions(-)

diff --git a/libguile/fports.c b/libguile/fports.c
index 3e47562..11aa170 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -578,29 +578,29 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate 
SCM_UNUSED)
 
 /* fill a port's read-buffer with a single read.  returns the first
    char or EOF if end of file.  */
-static void
-fport_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+fport_read (SCM port, SCM dst, size_t start, size_t count)
 {
-  long count;
+  long res;
   scm_t_fport *fp = SCM_FSTREAM (port);
-  scm_t_uint8 *ptr = dst->buf + dst->end;
-  size_t size = dst->size - dst->end;
+  signed char *ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
 
-  SCM_SYSCALL (count = read (fp->fdes, ptr, size));
-  if (count == -1)
+  SCM_SYSCALL (res = read (fp->fdes, ptr, count));
+  if (res == -1)
     scm_syserror ("fport_read");
-  dst->end += count;
+  return res;
 }
 
-static void
-fport_write (SCM port, scm_t_port_buffer *src)
+static size_t
+fport_write (SCM port, SCM src, size_t start, size_t count)
 {
   int fd = SCM_FPORT_FDES (port);
-  scm_t_uint8 *ptr = src->buf + src->cur;
-  size_t size = src->end - src->cur;
+  signed char *ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
 
-  if (full_write (fd, ptr, size) < size)
+  if (full_write (fd, ptr, count) < count)
     scm_syserror ("fport_write");
+
+  return count;
 }
 
 static scm_t_off
diff --git a/libguile/ports.c b/libguile/ports.c
index 8f07425..144daef 100644
--- a/libguile/ports.c
+++ b/libguile/ports.c
@@ -229,8 +229,10 @@ static const size_t default_buffer_size = 1024;
 
 scm_t_bits
 scm_make_port_type (char *name,
-                   void (*read) (SCM port, scm_t_port_buffer *buf),
-                   void (*write) (SCM port, scm_t_port_buffer *buf))
+                    size_t (*read) (SCM port, SCM dst, size_t start,
+                                    size_t count),
+                    size_t (*write) (SCM port, SCM src, size_t start,
+                                     size_t count))
 {
   scm_t_ptob_descriptor *desc;
   long ptobnum;
@@ -527,7 +529,8 @@ scm_c_make_port_buffer (size_t size)
   scm_t_port_buffer *ret = scm_gc_typed_calloc (scm_t_port_buffer);
 
   ret->size = size;
-  ret->buf = scm_gc_malloc_pointerless (ret->size, "port buffer");
+  ret->bytevector = scm_c_make_bytevector (size);
+  ret->buf = (scm_t_uint8 *) SCM_BYTEVECTOR_CONTENTS (ret->bytevector);
 
   return ret;
 }
@@ -1432,33 +1435,51 @@ scm_peek_byte_or_eof (SCM port)
   return ret;
 }
 
+static size_t
+scm_i_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count)
+{
+  size_t filled;
+  scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
+
+  assert (count <= SCM_BYTEVECTOR_LENGTH (dst));
+  assert (start + count <= SCM_BYTEVECTOR_LENGTH (dst));
+
+  filled = ptob->read (port, dst, start, count);
+
+  assert (filled <= count);
+
+  return filled;
+}
+
 /* scm_i_read_unlocked is used internally to add bytes to the given port
    buffer.  If the number of available bytes in the buffer does not
    increase after a call to scm_i_read_unlocked, that indicates EOF.  */
 static void
 scm_i_read_unlocked (SCM port, scm_t_port_buffer *buf)
 {
-  size_t prev_end = buf->end;
+  size_t count;
+
   assert (buf->end < buf->size);
 
-  SCM_PORT_DESCRIPTOR (port)->read (port, buf);
-  buf->has_eof = buf->end == prev_end;
+  count = scm_i_read_bytes_unlocked (port, buf->bytevector, buf->end,
+                                     buf->size - buf->end);
+  buf->end += count;
+  buf->has_eof = count == 0;
 }
 
-/* scm_c_read
- *
- * Used by an application to read arbitrary number of bytes from an SCM
- * port.  Same semantics as libc read, except that scm_c_read only
- * returns less than SIZE bytes if at end-of-file.
- *
- * Warning: Doesn't update port line and column counts!  */
-size_t
-scm_c_read_unlocked (SCM port, void *buffer, size_t size)
-#define FUNC_NAME "scm_c_read"
+/* Used by an application to read arbitrary number of bytes from an SCM
+   port.  Same semantics as libc read, except that scm_c_read_bytes only
+   returns less than SIZE bytes if at end-of-file.
+
+   Warning: Doesn't update port line and column counts!  */
+static size_t
+scm_c_read_bytes_unlocked (SCM port, SCM dst, size_t start, size_t count)
+#define FUNC_NAME "scm_c_read_bytes"
 {
+  size_t to_read = count;
   scm_t_port *pt;
   scm_t_port_buffer *read_buf;
-  scm_t_port_buffer dst_buf = { buffer, 0, 0, size, 0, NULL };
+  signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
 
   SCM_VALIDATE_OPINPORT (1, port);
 
@@ -1475,47 +1496,116 @@ scm_c_read_unlocked (SCM port, void *buffer, size_t 
size)
   /* Take bytes first from the port's read buffer. */
   if (read_buf->cur < read_buf->end)
     {
-      size_t to_read = dst_buf.size - dst_buf.end;
-      to_read = min (to_read, read_buf->end - read_buf->cur);
-      memcpy (dst_buf.buf + dst_buf.end, read_buf->buf + read_buf->cur,
-              to_read);
-      dst_buf.end += to_read;
-      read_buf->cur += to_read;
-    }
-
-  while (dst_buf.end < dst_buf.size)
-    /* If the read buffering is larger than our read size, buffer the
-       read.  Otherwise read into our buffer directly.  */
-    if (dst_buf.size - dst_buf.end < pt->read_buffering)
-      {
-        size_t to_read = dst_buf.size - dst_buf.end;
-        read_buf = scm_fill_input_unlocked (port);
-        if (to_read > read_buf->end - read_buf->cur)
-          to_read = read_buf->end - read_buf->cur;
-        if (to_read == 0)
-          {
-            /* Consider that we've read off this EOF.  */
-            read_buf->has_eof = 0;
+      size_t to_copy = count;
+      to_copy = min (to_copy, read_buf->end - read_buf->cur);
+      memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
+      dst_ptr += to_copy;
+      to_read -= to_copy;
+      read_buf->cur += to_copy;
+    }
+
+  while (to_read)
+    {
+      /* If the read is smaller than the buffering on the read side of
+         this port, then go through the buffer.  Otherwise fill our
+         buffer directly.  */
+      if (to_read < pt->read_buffering)
+        {
+          size_t to_copy = to_read;
+          read_buf = scm_fill_input_unlocked (port);
+          to_copy = min (to_copy, read_buf->end - read_buf->cur);
+          memcpy (dst_ptr, read_buf->buf + read_buf->cur, to_copy);
+          if (to_copy == 0)
+            {
+              /* Consider that we've read off this EOF.  */
+              read_buf->has_eof = 0;
+              break;
+            }
+          dst_ptr += to_copy;
+          to_read -= to_copy;
+          read_buf->cur += to_copy;
+        }
+      else
+        {
+          size_t filled;
+
+          filled = scm_i_read_bytes_unlocked (port, dst,
+                                              start + count - to_read,
+                                              to_read);
+          if (filled == 0)
             break;
-          }
-        memcpy (dst_buf.buf + dst_buf.end,
-                read_buf->buf + read_buf->cur,
-                to_read);
-        read_buf->cur += to_read;
-        dst_buf.end += to_read;
-      }
-    else
-      {
-        scm_i_read_unlocked (port, &dst_buf);
-        if (dst_buf.has_eof)
+          to_read -= filled;
+          dst_ptr += filled;
+        }
+    }
+
+  return count - to_read;
+}
+#undef FUNC_NAME
+
+/* Like scm_c_read_bytes, but always proxies reads through the port's
+   read buffer.  Used by an application when it wants to read into a
+   memory chunk that's not owned by Guile's GC.  */
+size_t
+scm_c_read_unlocked (SCM port, void *buffer, size_t size)
+#define FUNC_NAME "scm_c_read"
+{
+  size_t copied = 0;
+  scm_t_port *pt;
+  scm_t_port_buffer *read_buf;
+  scm_t_uint8 *dst = buffer;
+
+  SCM_VALIDATE_OPINPORT (1, port);
+
+  pt = SCM_PTAB_ENTRY (port);
+  read_buf = pt->read_buf;
+
+  if (pt->rw_random)
+    {
+      if (pt->rw_active == SCM_PORT_WRITE)
+        scm_flush_unlocked (port);
+      pt->rw_active = SCM_PORT_READ;
+    }
+
+  while (copied < size)
+    {
+      read_buf = scm_fill_input_unlocked (port);
+      /* Take bytes first from the port's read buffer. */
+      if (read_buf->cur < read_buf->end)
+        {
+          size_t to_copy = size - copied;
+          to_copy = min (to_copy, read_buf->end - read_buf->cur);
+          memcpy (dst + copied, read_buf->buf + read_buf->cur, to_copy);
+          copied += to_copy;
+          read_buf->cur += to_copy;
+        }
+      else
+        {
+          /* Consider that we've read off this EOF.  */
+          read_buf->has_eof = 0;
           break;
-      }
+        }
+    }
 
-  return dst_buf.end;
+  return copied;
 }
 #undef FUNC_NAME
 
 size_t
+scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t count)
+{
+  scm_i_pthread_mutex_t *lock;
+  size_t ret;
+
+  scm_c_lock_port (port, &lock);
+  ret = scm_c_read_bytes_unlocked (port, dst, start, count);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+
+  return ret;
+}
+
+size_t
 scm_c_read (SCM port, void *buffer, size_t size)
 {
   scm_i_pthread_mutex_t *lock;
@@ -2447,13 +2537,14 @@ SCM_DEFINE (scm_force_output, "force-output", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+static void scm_i_write_unlocked (SCM port, scm_t_port_buffer *src);
+
 void
 scm_flush_unlocked (SCM port)
 {
   scm_t_port_buffer *buf = SCM_PTAB_ENTRY (port)->write_buf;
   if (buf->cur < buf->end)
-    SCM_PORT_DESCRIPTOR (port)->write (port, buf);
-  buf->cur = buf->end = 0;
+    scm_i_write_unlocked (port, buf);
   SCM_PTAB_ENTRY (port)->rw_active = SCM_PORT_NEITHER;
 }
 
@@ -2520,27 +2611,56 @@ scm_puts (const char *s, SCM port)
     scm_i_pthread_mutex_unlock (lock);
 }
   
-/* scm_c_write
- *
- * Used by an application to write arbitrary number of bytes to an SCM
- * port.  Similar semantics as libc write.  However, unlike libc
- * write, scm_c_write writes the requested number of bytes and has no
- * return value.
- *
- * Warning: Doesn't update port line and column counts!
- */
-void
-scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
-#define FUNC_NAME "scm_c_write"
+static void
+scm_i_write_bytes_unlocked (SCM port, SCM src, size_t start, size_t count)
+{
+  size_t written;
+  scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (port);
+
+  assert (count <= SCM_BYTEVECTOR_LENGTH (src));
+  assert (start + count <= SCM_BYTEVECTOR_LENGTH (src));
+
+  written = ptob->write (port, src, start, count);
+
+  /* FIXME: Allow short writes?  */
+  assert (written == count);
+}
+
+static void
+scm_i_write_unlocked (SCM port, scm_t_port_buffer *src)
+{
+  size_t start, count;
+
+  assert (src->cur < src->end);
+  assert (src->end <= src->size);
+
+  /* Update cursors before attempting to write, assuming that I/O errors
+     are sticky.  That way if the write throws an error, causing the
+     computation to abort, and possibly causing the port to be collected
+     by GC when it's open, any subsequent close-port / force-output
+     won't signal *another* error.  */
+
+  start = src->cur;
+  count = src->end - src->cur;
+  src->cur = src->end = 0;
+  scm_i_write_bytes_unlocked (port, src->bytevector, start, count);
+}
+
+/* Used by an application to write arbitrary number of bytes to an SCM
+   port.  Similar semantics as libc write.  However, unlike libc write,
+   scm_c_write writes the requested number of bytes.
+
+   Warning: Doesn't update port line and column counts!  */
+static size_t
+scm_c_write_bytes_unlocked (SCM port, SCM src, size_t start, size_t count)
+#define FUNC_NAME "scm_c_write_bytes"
 {
   scm_t_port *pt;
   scm_t_port_buffer *write_buf;
-  scm_t_ptob_descriptor *ptob;
 
   SCM_VALIDATE_OPOUTPORT (1, port);
 
   pt = SCM_PTAB_ENTRY (port);
-  ptob = SCM_PORT_DESCRIPTOR (port);
   write_buf = pt->write_buf;
 
   if (pt->rw_random)
@@ -2550,7 +2670,7 @@ scm_c_write_unlocked (SCM port, const void *ptr, size_t 
size)
       pt->rw_active = SCM_PORT_WRITE;
     }
 
-  if (size < write_buf->size)
+  if (count < write_buf->size)
     {
       /* Make it so that write_buf->end is only nonzero if there are
          buffered bytes already.  */
@@ -2562,36 +2682,72 @@ scm_c_write_unlocked (SCM port, const void *ptr, size_t 
size)
          flush it beforehand.  Otherwise it could be that the buffer is
          full after filling it with the new data; if that's the case, we
          flush then instead.  */
-      if (write_buf->end + size > write_buf->size)
-        {
-          ptob->write (port, write_buf);
-          write_buf->cur = write_buf->end = 0;
-        }
+      if (write_buf->end + count > write_buf->size)
+        scm_i_write_unlocked (port, write_buf);
 
-      memcpy (write_buf->buf + write_buf->end, ptr, size);
-      write_buf->end += size;
+      memcpy (write_buf->buf + write_buf->end,
+              SCM_BYTEVECTOR_CONTENTS (src) + start,
+              count);
+      write_buf->end += count;
 
       if (write_buf->end == write_buf->size)
-        {
-          ptob->write (port, write_buf);
-          write_buf->cur = write_buf->end = 0;
-        }
+        scm_i_write_unlocked (port, write_buf);
     }
   else
     {
       /* Our write would overflow the buffer.  Flush buffered bytes (if
          needed), then write our bytes with just one syscall.  */
-
-      scm_t_port_buffer ad_hoc_buf =
-        { (scm_t_uint8 *) ptr, 0, size, size, 0, NULL };
+      size_t written;
 
       if (write_buf->cur < write_buf->end)
-        {
-          ptob->write (port, write_buf);
-          write_buf->cur = write_buf->end = 0;
-        }
+        scm_i_write_unlocked (port, write_buf);
+
+      written = SCM_PORT_DESCRIPTOR (port)->write (port, src, start, count);
+      assert (written == count);
+    }
+
+  return count;
+}
+#undef FUNC_NAME
 
-      ptob->write (port, &ad_hoc_buf);
+/* Like scm_c_write_bytes, but always writes through the write buffer.
+   Used when an application wants to write bytes stored in an area not
+   managed by GC.  */
+void
+scm_c_write_unlocked (SCM port, const void *ptr, size_t size)
+#define FUNC_NAME "scm_c_write"
+{
+  scm_t_port *pt;
+  scm_t_port_buffer *write_buf;
+  size_t written = 0;
+  const scm_t_uint8 *src = ptr;
+
+  SCM_VALIDATE_OPOUTPORT (1, port);
+
+  pt = SCM_PTAB_ENTRY (port);
+  write_buf = pt->write_buf;
+
+  if (pt->rw_random)
+    {
+      if (pt->rw_active == SCM_PORT_READ)
+        scm_end_input_unlocked (port);
+      pt->rw_active = SCM_PORT_WRITE;
+    }
+
+  while (written < size)
+    {
+      size_t to_write = write_buf->size - write_buf->end;
+
+      if (to_write > size - written)
+        to_write = size - written;
+
+      memcpy (write_buf->buf + write_buf->end, src, to_write);
+      write_buf->end += to_write;
+      written += to_write;
+      src += to_write;
+
+      if (write_buf->end == write_buf->size)
+        scm_i_write_unlocked (port, write_buf);
     }
 }
 #undef FUNC_NAME
@@ -2606,6 +2762,16 @@ scm_c_write (SCM port, const void *ptr, size_t size)
     scm_i_pthread_mutex_unlock (lock);
 }
 
+void
+scm_c_write_bytes (SCM port, SCM src, size_t start, size_t count)
+{
+  scm_i_pthread_mutex_t *lock;
+  scm_c_lock_port (port, &lock);
+  scm_c_write_bytes_unlocked (port, src, start, count);
+  if (lock)
+    scm_i_pthread_mutex_unlock (lock);
+}
+
 /* scm_lfwrite
  *
  * This function differs from scm_c_write; it updates port line and
@@ -2846,7 +3012,6 @@ SCM_DEFINE (scm_truncate_file, "truncate-file", 1, 1, 0,
   else if (SCM_OPOUTPORTP (object))
     {
       off_t_or_off64_t c_length = scm_to_off_t_or_off64_t (length);
-      scm_t_port *pt = SCM_PTAB_ENTRY (object);
       scm_t_ptob_descriptor *ptob = SCM_PORT_DESCRIPTOR (object);
 
       if (!ptob->truncate)
@@ -3082,14 +3247,16 @@ SCM_DEFINE (scm_flush_all_ports, "flush-all-ports", 0, 
0, 0,
 
 scm_t_bits scm_tc16_void_port = 0;
 
-static void
-void_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+void_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
+  return 0;
 }
 
-static void
-void_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+void_port_write (SCM port, SCM src, size_t start, size_t count)
 {
+  return count;
 }
 
 static SCM
diff --git a/libguile/ports.h b/libguile/ports.h
index 80e3a67..e7277e3 100644
--- a/libguile/ports.h
+++ b/libguile/ports.h
@@ -87,8 +87,8 @@ typedef struct
      peek-u8 should still return EOF.  */
   int has_eof;
 
-  /* Heap object that keeps `buf' alive. */
-  void *holder;
+  /* Bytevector whose contents are [BUF, BUF + SIZE). */
+  SCM bytevector;
 } scm_t_port_buffer;
 
 
@@ -204,8 +204,8 @@ typedef struct scm_t_ptob_descriptor
   char *name;
   int (*print) (SCM exp, SCM port, scm_print_state *pstate);
 
-  void (*read) (SCM port, scm_t_port_buffer *dst);
-  void (*write) (SCM port, scm_t_port_buffer *src);
+  size_t (*read) (SCM port, SCM dst, size_t start, size_t count);
+  size_t (*write) (SCM port, SCM src, size_t start, size_t count);
   scm_t_off (*seek) (SCM port, scm_t_off OFFSET, int WHENCE);
   void (*close) (SCM port);
 
@@ -230,8 +230,8 @@ SCM_API scm_t_ptob_descriptor* scm_c_port_type_ref (long 
ptobnum);
 SCM_API long scm_c_port_type_add_x (scm_t_ptob_descriptor *desc);
 SCM_API scm_t_bits scm_make_port_type
        (char *name,
-         void (*read) (SCM port, scm_t_port_buffer *dst),
-         void (*write) (SCM port, scm_t_port_buffer *src));
+         size_t (*read) (SCM port, SCM dst, size_t start, size_t count),
+         size_t (*write) (SCM port, SCM src, size_t start, size_t count));
 SCM_API void scm_set_port_print (scm_t_bits tc,
                                 int (*print) (SCM exp,
                                               SCM port,
@@ -323,6 +323,7 @@ SCM_INLINE int scm_peek_byte_or_eof_unlocked (SCM port);
 SCM_API int scm_slow_peek_byte_or_eof_unlocked (SCM port);
 SCM_API size_t scm_c_read (SCM port, void *buffer, size_t size);
 SCM_API size_t scm_c_read_unlocked (SCM port, void *buffer, size_t size);
+SCM_API size_t scm_c_read_bytes (SCM port, SCM dst, size_t start, size_t 
count);
 SCM_API scm_t_wchar scm_getc (SCM port);
 SCM_API scm_t_wchar scm_getc_unlocked (SCM port);
 SCM_API SCM scm_read_char (SCM port);
@@ -359,6 +360,7 @@ SCM_API void scm_puts (const char *str_data, SCM port);
 SCM_INLINE void scm_puts_unlocked (const char *str_data, SCM port);
 SCM_API void scm_c_write (SCM port, const void *buffer, size_t size);
 SCM_API void scm_c_write_unlocked (SCM port, const void *buffer, size_t size);
+SCM_API void scm_c_write_bytes (SCM port, SCM src, size_t start, size_t count);
 SCM_API void scm_lfwrite (const char *ptr, size_t size, SCM port);
 SCM_API void scm_lfwrite_unlocked (const char *ptr, size_t size, SCM port);
 SCM_INTERNAL void scm_lfwrite_substr (SCM str, size_t start, size_t end,
diff --git a/libguile/r6rs-ports.c b/libguile/r6rs-ports.c
index aa54a0e..fb821bb 100644
--- a/libguile/r6rs-ports.c
+++ b/libguile/r6rs-ports.c
@@ -99,25 +99,26 @@ make_bytevector_input_port (SCM bv)
                                         (scm_t_bits) stream);
 }
 
-static void
-bytevector_input_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+bytevector_input_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
-  size_t count;
+  size_t remaining;
   struct bytevector_input_port *stream = (void *) SCM_STREAM (port);
 
   if (stream->pos >= SCM_BYTEVECTOR_LENGTH (stream->bytevector))
-    return;
+    return 0;
 
-  count = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
-  if (count > buf->size - buf->end)
-    count = buf->size - buf->end;
+  remaining = SCM_BYTEVECTOR_LENGTH (stream->bytevector) - stream->pos;
+  if (remaining < count)
+    count = remaining;
 
-  memcpy (buf->buf + buf->end,
+  memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
           SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
           count);
 
-  buf->end += count;
   stream->pos += count;
+
+  return count;
 }
 
 static scm_t_off
@@ -277,32 +278,21 @@ make_custom_binary_input_port (SCM read_proc, SCM 
get_position_proc,
                                         (scm_t_bits) stream);
 }
 
-static void
-custom_binary_input_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+custom_binary_input_port_read (SCM port, SCM dst, size_t start, size_t count)
 #define FUNC_NAME "custom_binary_input_port_read"
 {
   struct custom_binary_port *stream = (void *) SCM_STREAM (port);
-  SCM bv, octets;
+  SCM octets;
   size_t c_octets;
 
-  /* FIXME: We need to make sure buf->buf is kept alive.  If read_buf is
-     referenced from PORT, passing PORT as the parent will do it.  But,
-     pushback could re-set PORT->read_buf, which would be a fail.  But,
-     probably buf->buf is itself GC-allocated, so we can pack it
-     directly.  But, perhaps it's not, as in scm_c_read().  In that
-     latter case we're kinda screwed and probably need to prevent
-     rewinding.  But shouldn't we always prevent rewinding?  And how can
-     we avoid allocating the bytevector at all?  */
-  bv = scm_c_take_gc_bytevector ((signed char *) (buf->buf + buf->end),
-                                 buf->size - buf->end,
-                                 PTR2SCM (buf->buf));
-
-  octets = scm_call_3 (stream->read, bv, SCM_INUM0, scm_bytevector_length 
(bv));
+  octets = scm_call_3 (stream->read, dst, scm_from_size_t (start),
+                       scm_from_size_t (count));
   c_octets = scm_to_size_t (octets);
-  if (c_octets > scm_c_bytevector_length (bv))
+  if (c_octets > count)
     scm_out_of_range (FUNC_NAME, octets);
 
-  buf->end += c_octets;
+  return c_octets;
 }
 #undef FUNC_NAME
 
@@ -405,7 +395,6 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 0, 
0,
 #define FUNC_NAME s_scm_get_bytevector_n
 {
   SCM result;
-  char *c_bv;
   unsigned c_count;
   size_t c_read;
 
@@ -413,11 +402,10 @@ SCM_DEFINE (scm_get_bytevector_n, "get-bytevector-n", 2, 
0, 0,
   c_count = scm_to_uint (count);
 
   result = scm_c_make_bytevector (c_count);
-  c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (result);
 
   if (SCM_LIKELY (c_count > 0))
     /* XXX: `scm_c_read ()' does not update the port position.  */
-    c_read = scm_c_read_unlocked (port, c_bv, c_count);
+    c_read = scm_c_read_bytes (port, result, 0, c_count);
   else
     /* Don't invoke `scm_c_read ()' since it may block.  */
     c_read = 0;
@@ -443,7 +431,6 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 4, 
0, 0,
 #define FUNC_NAME s_scm_get_bytevector_n_x
 {
   SCM result;
-  char *c_bv;
   unsigned c_start, c_count, c_len;
   size_t c_read;
 
@@ -452,14 +439,13 @@ SCM_DEFINE (scm_get_bytevector_n_x, "get-bytevector-n!", 
4, 0, 0,
   c_start = scm_to_uint (start);
   c_count = scm_to_uint (count);
 
-  c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
   c_len = SCM_BYTEVECTOR_LENGTH (bv);
 
   if (SCM_UNLIKELY (c_start + c_count > c_len))
     scm_out_of_range (FUNC_NAME, count);
 
   if (SCM_LIKELY (c_count > 0))
-    c_read = scm_c_read_unlocked (port, c_bv + c_start, c_count);
+    c_read = scm_c_read_bytes (port, bv, c_start, c_count);
   else
     /* Don't invoke `scm_c_read ()' since it may block.  */
     c_read = 0;
@@ -513,14 +499,13 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 
1, 0, 0,
 #define FUNC_NAME s_scm_get_bytevector_all
 {
   SCM result;
-  char *c_bv;
   unsigned c_len, c_count;
   size_t c_read, c_total;
 
   SCM_VALIDATE_BINARY_INPUT_PORT (1, port);
 
   c_len = c_count = 4096;
-  c_bv = (char *) scm_gc_malloc_pointerless (c_len, SCM_GC_BYTEVECTOR);
+  result = scm_c_make_bytevector (c_count);
   c_total = c_read = 0;
 
   do
@@ -528,37 +513,27 @@ SCM_DEFINE (scm_get_bytevector_all, "get-bytevector-all", 
1, 0, 0,
       if (c_total + c_read > c_len)
        {
          /* Grow the bytevector.  */
-         c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_len * 2,
-                                         SCM_GC_BYTEVECTOR);
+          SCM prev = result;
+          result = scm_c_make_bytevector (c_len * 2);
+          memcpy (SCM_BYTEVECTOR_CONTENTS (result),
+                  SCM_BYTEVECTOR_CONTENTS (prev),
+                  c_total);
          c_count = c_len;
          c_len *= 2;
        }
 
       /* `scm_c_read ()' blocks until C_COUNT bytes are available or EOF is
         reached.  */
-      c_read = scm_c_read_unlocked (port, c_bv + c_total, c_count);
+      c_read = scm_c_read_bytes (port, result, c_total, c_count);
       c_total += c_read, c_count -= c_read;
     }
   while (c_count == 0);
 
   if (c_total == 0)
-    {
-      result = SCM_EOF_VAL;
-      scm_gc_free (c_bv, c_len, SCM_GC_BYTEVECTOR);
-    }
-  else
-    {
-      if (c_len > c_total)
-       {
-         /* Shrink the bytevector.  */
-         c_bv = (char *) scm_gc_realloc (c_bv, c_len, c_total,
-                                         SCM_GC_BYTEVECTOR);
-         c_len = (unsigned) c_total;
-       }
+    return SCM_EOF_VAL;
 
-      result = scm_c_take_gc_bytevector ((signed char *) c_bv, c_len,
-                                         SCM_BOOL_F);
-    }
+  if (c_len > c_total)
+    return scm_c_shrink_bytevector (result, c_total);
 
   return result;
 }
@@ -596,14 +571,12 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
            "octets.")
 #define FUNC_NAME s_scm_put_bytevector
 {
-  char *c_bv;
   unsigned c_start, c_count, c_len;
 
   SCM_VALIDATE_BINARY_OUTPUT_PORT (1, port);
   SCM_VALIDATE_BYTEVECTOR (2, bv);
 
   c_len = SCM_BYTEVECTOR_LENGTH (bv);
-  c_bv = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
 
   if (!scm_is_eq (start, SCM_UNDEFINED))
     {
@@ -626,7 +599,7 @@ SCM_DEFINE (scm_put_bytevector, "put-bytevector", 2, 2, 0,
   else
     c_start = 0, c_count = c_len;
 
-  scm_c_write_unlocked (port, c_bv + c_start, c_count);
+  scm_c_write_bytes (port, bv, c_start, c_count);
 
   return SCM_UNSPECIFIED;
 }
@@ -777,21 +750,22 @@ make_bytevector_output_port (void)
 }
 
 /* Write octets from WRITE_BUF to the backing store.  */
-static void
-bytevector_output_port_write (SCM port, scm_t_port_buffer *write_buf)
+static size_t
+bytevector_output_port_write (SCM port, SCM src, size_t start, size_t count)
 {
-  size_t count;
   scm_t_bytevector_output_port_buffer *buf;
 
   buf = SCM_BYTEVECTOR_OUTPUT_PORT_BUFFER (port);
-  count = write_buf->end - write_buf->cur;
 
   if (buf->pos + count > buf->total_len)
     bytevector_output_port_buffer_grow (buf, buf->pos + count);
 
-  memcpy (buf->buffer + buf->pos, write_buf->buf + write_buf->cur, count);
+  memcpy (buf->buffer + buf->pos, SCM_BYTEVECTOR_CONTENTS (src) + start, 
count);
+
   buf->pos += count;
   buf->len = (buf->len > buf->pos) ? buf->len : buf->pos;
+
+  return count;
 }
 
 static scm_t_off
@@ -909,41 +883,35 @@ make_custom_binary_output_port (SCM write_proc, SCM 
get_position_proc,
 }
 
 /* Flush octets from BUF to the backing store.  */
-static void
-custom_binary_output_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+custom_binary_output_port_write (SCM port, SCM src, size_t start, size_t count)
 #define FUNC_NAME "custom_binary_output_port_write"
 {
-  size_t size, written;
+  size_t written;
   struct custom_binary_port *stream = (void *) SCM_STREAM (port);
-  SCM bv;
-
-  /* FIXME: If BUF is the same as PORT->write_buf, then the data is
-     GC-managed and we could avoid allocating a new bytevector backing
-     store.  Otherwise we have to copy, as we do here.  */
-  size = buf->end - buf->cur;
-  bv = scm_c_make_bytevector (size);
-  memcpy (SCM_BYTEVECTOR_CONTENTS (bv), buf->buf + buf->cur, size);
 
   /* Since the `write' procedure of Guile's ports has type `void', it must
      try hard to write exactly SIZE bytes, regardless of how many bytes the
      sink can handle.  */
   written = 0;
-  while (written < size)
+  while (written < count)
     {
       long int c_result;
       SCM result;
 
-      result = scm_call_3 (stream->write, bv,
-                          scm_from_size_t (written),
-                          scm_from_size_t (size - written));
+      result = scm_call_3 (stream->write, src,
+                          scm_from_size_t (start + written),
+                          scm_from_size_t (count - written));
 
       c_result = scm_to_long (result);
-      if (c_result < 0 || (size_t) c_result > (size - written))
+      if (c_result < 0 || (size_t) c_result > (count - written))
        scm_wrong_type_arg_msg (FUNC_NAME, 0, result,
                                "R6RS custom binary output port `write!' "
                                "returned a incorrect integer");
       written += c_result;
     }
+
+  return written;
 }
 #undef FUNC_NAME
 
@@ -1008,32 +976,19 @@ make_transcoded_port (SCM binary_port, unsigned long 
mode)
   return port;
 }
 
-static void
-transcoded_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+transcoded_port_write (SCM port, SCM src, size_t start, size_t count)
 {
   SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
-  scm_c_write_unlocked (bport, buf->buf + buf->cur, buf->end - buf->cur);
+  scm_c_write_bytes (bport, src, start, count);
+  return count;
 }
 
-static void
-transcoded_port_read (SCM port, scm_t_port_buffer *buf)
+static size_t
+transcoded_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
-  size_t count;
-  scm_t_port_buffer *bport_buf;
-
-  /* We can't use `scm_c_read' here, since it blocks until the whole
-     block has been read or EOF. */
-  
-  bport_buf = scm_fill_input (SCM_TRANSCODED_PORT_BINARY_PORT (port));
-  /* Consume EOF from bport.  */
-  bport_buf->has_eof = 0;
-  count = bport_buf->end - bport_buf->cur;
-  if (count > buf->size - buf->end)
-    count = buf->size - buf->end;
-
-  memcpy (buf->buf + buf->end, bport_buf->buf + bport_buf->cur, count);
-  bport_buf->cur += count;
-  buf->end += count;
+  SCM bport = SCM_TRANSCODED_PORT_BINARY_PORT (port);
+  return scm_c_read_bytes (bport, dst, start, count);
 }
 
 static void
diff --git a/libguile/strports.c b/libguile/strports.c
index 6ad7d18..e8ce67a 100644
--- a/libguile/strports.c
+++ b/libguile/strports.c
@@ -60,31 +60,29 @@ struct string_port {
   size_t len;
 };
 
-static void
-string_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+string_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
-  size_t count;
   struct string_port *stream = (void *) SCM_STREAM (port);
 
   if (stream->pos >= stream->len)
-    return;
+    return 0;
 
-  count = stream->len - stream->pos;
-  if (count > dst->size - dst->end)
-    count = dst->size - dst->end;
+  if (count > stream->len - stream->pos)
+    count = stream->len - stream->pos;
 
-  memcpy (dst->buf + dst->end,
+  memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
           SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
           count);
-  dst->end += count;
+
   stream->pos += count;
+  return count;
 }
 
-static void
-string_port_write (SCM port, scm_t_port_buffer *src)
+static size_t
+string_port_write (SCM port, SCM src, size_t start, size_t count)
 {
   struct string_port *stream = (void *) SCM_STREAM (port);
-  size_t count = src->end - src->cur;
 
   if (SCM_BYTEVECTOR_LENGTH (stream->bytevector) < stream->pos + count)
     {
@@ -101,12 +99,13 @@ string_port_write (SCM port, scm_t_port_buffer *src)
     }
 
   memcpy (SCM_BYTEVECTOR_CONTENTS (stream->bytevector) + stream->pos,
-          src->buf + src->cur,
+          SCM_BYTEVECTOR_CONTENTS (src) + start,
           count);
-  src->cur += count;
   stream->pos += count;
   if (stream->pos > stream->len)
     stream->len = stream->pos;
+
+  return count;
 }
 
 static scm_t_off
diff --git a/libguile/vports.c b/libguile/vports.c
index 82fef1e..e520570 100644
--- a/libguile/vports.c
+++ b/libguile/vports.c
@@ -72,27 +72,30 @@ soft_port_get_natural_buffer_sizes (SCM port, size_t 
*read_size,
   *write_size = 1;
 }
 
-static void
-soft_port_write (SCM port, scm_t_port_buffer *buf)
+static size_t
+soft_port_write (SCM port, SCM src, size_t start, size_t count)
 {
   struct soft_port *stream = (void *) SCM_STREAM (port);
-  scm_t_uint8 * ptr = buf->buf + buf->cur;
-  SCM str = scm_from_port_stringn ((char *) ptr, buf->end - buf->cur, port);
-  buf->end = buf->cur = 0;
+  signed char * ptr = SCM_BYTEVECTOR_CONTENTS (src) + start;
 
-  scm_call_1 (stream->write_string, str);
+  scm_call_1 (stream->write_string,
+              scm_from_port_stringn ((char *) ptr, count, port));
 
   /* Backwards compatibility.  */
   if (scm_is_true (stream->flush))
     scm_call_0 (stream->flush);
+
+  return count;
 }
 
 /* places a single char in the input buffer.  */
-static void
-soft_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+soft_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
+  size_t written;
   struct soft_port *stream = (void *) SCM_STREAM (port);
   scm_t_port_buffer *encode_buf = stream->encode_buf;
+  signed char *dst_ptr = SCM_BYTEVECTOR_CONTENTS (dst) + start;
 
   /* A character can be more than one byte, but we don't have a
      guarantee that there is more than one byte in the read buffer.  So,
@@ -106,7 +109,7 @@ soft_port_read (SCM port, scm_t_port_buffer *dst)
 
       ans = scm_call_0 (stream->read_char);
       if (scm_is_false (ans) || SCM_EOF_OBJECT_P (ans))
-        return;
+        return 0;
       SCM_ASSERT (SCM_CHARP (ans), ans, SCM_ARG1, "soft_port_read");
 
       /* It's possible to make a fast path here, but it would be fastest
@@ -119,8 +122,12 @@ soft_port_read (SCM port, scm_t_port_buffer *dst)
       free (str);
     }
 
-  while (dst->end < dst->size && encode_buf->cur < encode_buf->end)
-    dst->buf[dst->end++] = encode_buf->buf[encode_buf->cur++];
+  for (written = 0;
+       written < count && encode_buf->cur < encode_buf->end;
+       written++, encode_buf->cur++)
+    dst_ptr[written] = encode_buf->buf[encode_buf->cur];
+
+  return written;
 }
 
 
diff --git a/test-suite/standalone/test-scm-c-read.c 
b/test-suite/standalone/test-scm-c-read.c
index 86bca48..7850f34 100644
--- a/test-suite/standalone/test-scm-c-read.c
+++ b/test-suite/standalone/test-scm-c-read.c
@@ -54,18 +54,20 @@ make_port (scm_t_bits port_type)
   return scm_c_make_port (port_type, SCM_RDNG, (scm_t_bits) stream);
 }
 
-static void
-custom_port_read (SCM port, scm_t_port_buffer *dst)
+static size_t
+custom_port_read (SCM port, SCM dst, size_t start, size_t count)
 {
-  size_t to_copy = dst->size - dst->end;
+  size_t to_copy = count;
   struct custom_port *stream = (void *) SCM_STREAM (port);
 
   if (stream->pos + to_copy > stream->len)
     to_copy = stream->len - stream->pos;
 
-  memcpy (dst->buf + dst->end, stream->buf + stream->pos, to_copy);
+  memcpy (SCM_BYTEVECTOR_CONTENTS (dst) + start,
+          stream->buf + stream->pos, to_copy);
   stream->pos += to_copy;
-  dst->end += to_copy;
+
+  return to_copy;
 }
 
 /* Return true (non-zero) if BUF contains only zeros.  */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]