diff --git a/readline2.c b/readline2.c
index 63968dd..999110b 100644
--- a/readline2.c
+++ b/readline2.c
@@ -2,19 +2,70 @@
 #include <tcpipx.h>
 
 
-static void HandleAppend(Handle h1, Handle h2)
+static LongWord find_crlf(const char *cp, LongWord length)
 {
-    LongWord size1, size2;
-    HUnlock(h1);
+    LongWord rv;
     
-    size1 = GetHandleSize(h1);
-    size2 = GetHandleSize(h2);
+    rv = 0;
+
     
-    SetHandleSize(size1 + size2, h1);
-    if (_toolErr) return;
+    asm {
+        
+        // scan all the full blocks.
+        ldy #0
+        ldx length+2
+        beq remainder
+        
+    loop1:
+        lda [<cp],y
+        and #0xff
+        cmp #'\r'
+        beq match
+        cmp #'\n'
+        beq match
+        iny
+        bne loop1
+        // scanned a full bank, increment cp && rv
+        // decrement x
+        inc <cp+2
+        inc <rv+2
+        dex
+        bne loop1
+        // if x = 0, drop to remainder bytes.
+        
+    remainder:
+        // scan non-full bank
+        // y = 0
+        // x is the counter var.
+        ldx <length
+        beq done
+        
+    loop2:
+        lda [<cp],y
+        and #0xff
+        cmp #'\r'
+        beq match
+        cmp #'\n'
+        beq match
+        iny
+        dex
+        beq done
+        bra loop2
+         
+    match:
+        sty <rv
+        bra exit
+        
+    done:
+        lda #-1
+        sta <rv
+        sta <rv+2
+    exit:
+    }
     
-    HandToPtr(h2, *h1 + size1, size2);     
+    return rv;
 }
+
 /*
  * read a line terminated by \r\n, \r, or \n
  *
@@ -28,7 +79,7 @@ Word ReadLine2(Word ipid, rlBuffer *buffer)
     rrBuff rb;
 
 
-    const char *cp;
+    char *cp;
     Handle h;
     LongWord hsize;
     LongWord size;
@@ -50,7 +101,7 @@ Word ReadLine2(Word ipid, rlBuffer *buffer)
     h = (Handle *)ur->uwTCPDataIn;
 
     if (!h) return 0;
-    cp = *(const char **)h;
+    cp = *(char **)h;
     
     hsize = GetHandleSize(h);
     size = find_crlf(cp, hsize);
@@ -79,44 +130,43 @@ Word ReadLine2(Word ipid, rlBuffer *buffer)
         tlen = 1;
     }
     
-    buffer->size = size;
-    buffer->term = term;
+    //buffer->size = size;
+    //buffer->term = term;
     
     // read the data.
     // read will stop reading if there was a push.
     // if using \r\n, there could be something stupid like a push in the middle,
-    // so read it in and then delete it afterwards.
+    // so read it in and then shrink it afterwards.
     //
-    size += tlen;
-    h = NULL;
+    
+    // 99% of the time, it should just be one read, but generating the handle now
+    // and reading into a pointer keeps it simpler for the case where that is not the case.
+    
+    hsize = size + tlen;
+    h = NewHandle(hsize, ur->uwUserID, attrNoSpec | attrLocked, 0);
+    if (_toolErr) return -1;
 
-    while (size)
+    buffer->size = size;
+    buffer->handle = h;
+    buffer->term = term;
+
+    cp = *(char **)h;
+    
+    while (hsize)
     {
-        Handle h2;
-        rv = TCPIPReadTCP(ipid, 2, 0, size, &rb);
+        rv = TCPIPReadTCP(ipid, 0, cp, hsize, &rb);
+        // break on tcp error?
         
-        h2 = rb.rrBuffHandle;
-        size -= rb.rrBuffCount;
-     
-        if (h)
-        {
-            // append.
-            HandleAppend(h, h2);
-            DisposeHandle(h2);
-        }
-        else
-        {
-            buffer->handle = h = h2;
-        }
+        hsize -= rb.rrBuffCount;
+        cp += rb.rrBuffCount
     }
         
     if (tlen)
     {
         // remove the delimiter
-        h = buffer->handle;
-        size = buffer->size;
         
         // if line length is 0, dispose the handle entirely.
+        // term will be set to indicate it's a blank line.
         if (!size)
         {
             DisposeHandle(h);