Re: [Sawfish] rep read-line limit

[ Thread Index | Date Index | More lists.tuxfamily.org/sawfish Archives ]


On Wednesday 14 March 2012 15:10:59 Teika Kazura wrote:
> Probably a librep bug. src/streams.c says:
> 
> DEFUN("read-line", Fread_line, Sread_line, (repv stream), rep_Subr1)
> /* ..
>     char buf[400];
> ..
> 
> I don't know well how to fix it. Anyone?

Maybe like this.  Not extensively tested though, and may now run out of 
memory on very long lines.  Another alternative would be a linked list 
of fixed-length string buffers, but this realloc approach seemed easier 
to code in C.

-- 
	Timo Korvola		<URL:http://www.iki.fi/tkorvola>
From 5fde6a78df6d1874ca77f9d65758875f21fc8815 Mon Sep 17 00:00:00 2001
From: Timo Korvola <tkorvola@xxxxxx>
Date: Wed, 14 Mar 2012 22:31:30 +0200
Subject: [PATCH] Cope with long lines in read-line.

Now read-line will read the line to the end or die trying (it is
possible for it to run out of memory).
---
 src/streams.c |   71 ++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 48 insertions(+), 23 deletions(-)

diff --git a/src/streams.c b/src/streams.c
index 950efc5..0711975 100644
--- a/src/streams.c
+++ b/src/streams.c
@@ -653,32 +653,57 @@ DEFUN("read-line", Fread_line, Sread_line, (repv stream), rep_Subr1) /*
 ::doc:rep.io.streams#read-line::
 read-line STREAM
 
-Read one line of text from STREAM.
+Read one line of text from STREAM.  Return it as a string.  If the
+line was terminated by a newline (instead of EOF) it is included in
+the return value.  If end of file occurs immediately before any
+characters can be read, return nil.
 ::end:: */
 {
-    char buf[400];
-    if (rep_FILEP(stream) && rep_LOCAL_FILE_P (stream))
-    {
-	/* Special case for file streams. We can read a line in one go.	 */
-	if (fgets (buf, sizeof (buf), rep_FILE (stream)->file.fh))
-	    return rep_string_dup (buf);
-	else
-	    return Qnil;
-    }
-    else
+    int bufsize = 500, offset = 0;
+    char *oldbuf = 0;
+
+    while (1)
     {
-	char *bufp = buf;
-	int len = 0, c;
-	while ((c = rep_stream_getc (stream)) != EOF)
-	{
-	    *bufp++ = (char) c;
-	    len++;
-	    if ((len >= sizeof (buf) - 1) || (c == '\n'))
-		break;
-	}
-	if (len == 0)
-	    return Qnil;
-	return rep_string_dupn (buf, len);
+        char
+            *fullbuf = realloc(oldbuf, bufsize),
+            *offbuf = fullbuf + offset;
+        int
+            readlen = 0,
+            maxread = bufsize - offset - 1;
+        if (!fullbuf)
+        {
+            free (oldbuf);
+            return rep_mem_error ();
+        }
+        oldbuf = fullbuf;
+        if (rep_FILEP(stream) && rep_LOCAL_FILE_P (stream))
+        {
+            /* Special case for file streams.
+               We can read a line in one go.  Or at least something. */
+            if (fgets (offbuf, maxread + 1, rep_FILE (stream)->file.fh))
+                readlen = strlen (offbuf);
+        }
+        else
+        {
+            char *bufp = offbuf;
+            int c;
+            while ((c = rep_stream_getc (stream)) != EOF)
+            {
+                *bufp++ = (char) c;
+                readlen++;
+                if ((readlen >= maxread) || (c == '\n'))
+                    break;
+            }
+        }
+        if (offbuf[readlen - 1] == '\n' || readlen < maxread)
+        {
+            int fulllen = offset + readlen;
+            repv rval = fulllen ? rep_string_dupn (fullbuf, fulllen) : Qnil;
+            free(fullbuf);
+            return rval;
+        }
+        offset += maxread;
+        bufsize *= 2;
     }
 }
 
-- 
1.7.2.5



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/