Index: linebuf.c
===================================================================
RCS file: /cvsroot/ircd-hybrid/src/Attic/linebuf.c,v
retrieving revision 7.93
diff -u -r7.93 linebuf.c
--- linebuf.c	9 Oct 2002 15:08:32 -0000	7.93
+++ linebuf.c	2 Sep 2003 14:41:35 -0000
@@ -233,151 +233,136 @@
 }
 
 /*
+ * attach a CR/LF/NUL to the end of the line, and update the length.
+ */
+static inline void
+linebuf_terminate_crlf(buf_head_t *bufhead, buf_line_t *bufline)
+{
+  bufline->buf[bufline->len++] = '\r';
+  bufline->buf[bufline->len++] = '\n';
+  bufline->buf[bufline->len] = '\0';
+  bufhead->len += 2;
+}
+
+/*
  * linebuf_copy_line
  *
- * Okay..this functions comments made absolutely no sense.
- * 
- * Basically what we do is this.  Find the first chunk of text
- * and then scan for a CRLF.  If we didn't find it, but we didn't
- * overflow our buffer..we wait for some more data.
- * If we found a CRLF, we replace them with a \0 character.
- * If we overflowed, we copy the most our buffer can handle, terminate
- * it with a \0 and return.
- *
- * The return value is the amount of data we consumed.  This could
- * be different than the size of the linebuffer, as when we discard
- * the overflow, we don't want to process it again.
+ * copy data into the given line. Return the number of bytes copied.
+ * It will try to squeeze what it can into the given buffer.
+ * If it hits an end-of-buffer before it hits a CRLF, it will flag
+ * an overflow, and skip to the next CRLF. If it hits a CRLF before
+ * filling the buffer, it will flag it terminated, and skip past
+ * the CRLF.
+ *
+ * Just remember these:
+ *
+ * - we will *always* return skipped past a CRLF.
+ * - if we hit an end-of-buffer before a CRLF is reached, we tag it as
+ *   overflowed.
+ * - if we hit a CRLF before an end-of-buffer, we terminate it and
+ *   skip the CRLF
+ * - we *always* null-terminate the buffer! 
+ * - My definition of a CRLF is one of CR, LF, CRLF, LFCR. Hrm.
+ *   We will attempt to skip multiple CRLFs in a row ..
  *
- * This still sucks in my opinion, but it seems to work.
+ * This routine probably isn't as optimal as it could be, but hey .. :)
+ *   -- adrian
  *
- * -Aaron
+ * if binary is non-zero assume the data may be compressed,
+ * so simply split up (keeping as many [\r\n]*'s in the first buffer)
  */
 static int
 linebuf_copy_line(buf_head_t *bufhead, buf_line_t *bufline,
-                  char *data, int len)
+  char *data, int len, int binary)
 {
   int cpylen = 0;	/* how many bytes we've copied */
   char *ch = data;	/* Pointer to where we are in the read data */
-  char *bufch = bufline->buf + bufline->len;
-  int clen = 0;                 /* how many bytes we've processed,
-                                   and don't ever want to see again.. */
+  char *bufch = &bufline->buf[bufline->len];
+  /* Start of where to put new data */
 
   /* If its full or terminated, ignore it */
-
-  bufline->raw = 0;
-  assert(bufline->len < BUF_DATA_SIZE);
-  if (bufline->terminated == 1)
+  if ((bufline->len == BUF_DATA_SIZE) || (bufline->terminated == 1))
     return 0;
 
-  clen = cpylen = linebuf_skip_crlf(ch, len);
-  if (clen == -1)
-    return -1;
-
-  /* This is the ~overflow case..This doesn't happen often.. */
-  if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
+  /* Next, lets enter the copy loop */
+  for(;;)
     {
-      memcpy(bufch, ch, (BUF_DATA_SIZE - bufline->len - 1));
-      bufline->buf[BUF_DATA_SIZE-1] = '\0';
-      bufch = bufline->buf + BUF_DATA_SIZE - 2;
-      while(cpylen && (*bufch == '\r' || *bufch == '\n'))
-        {
-          *bufch = '\0';
-          cpylen--;
-          bufch--;
+      /* Are we out of data? */
+      if (len == 0)
+	{
+	  /* Yes, so we mark this buffer as unterminated, and return */
+	  bufline->terminated = 0; /* XXX it should be anyway :) */
+	  break;
         }
-      bufline->terminated = 1;
-      bufline->len = BUF_DATA_SIZE - 1;
-      bufhead->len += BUF_DATA_SIZE - 1;
-      return clen;
-    }
 
-  memcpy(bufch, ch, cpylen);
-  bufch += cpylen;
-  *bufch = '\0';
-  bufch--;
+      /* Are we out of space to PUT this ? */
+      if (bufline->len == BUF_DATA_SIZE)
+	{
+	  /*
+	   * ok, we CR/LF/NUL terminate, set overflow, and loop until the
+	   * next CRLF. We then skip that, and return.
+	   */
+          if (!binary)
+          {
+            cpylen += linebuf_skip_crlf(ch, len);
+            linebuf_terminate_crlf(bufhead, bufline);
+          }
+	  /* NOTE: We're finishing, so ignore updating len */
+	  bufline->terminated = 1;
+	  break;
+	}
+
+      /* Is this a CR or LF? */
+      if ((*ch == '\r') || (*ch == '\n'))
+	{
+          if (!binary)
+            {
+              /* Skip */
+              cpylen += linebuf_skip_crlf(ch, len);
+              /* Terminate the line */
+              linebuf_terminate_crlf(bufhead, bufline);
+              /* NOTE: We're finishing, so ignore updating len */
+              bufline->terminated = 1;
+            }
+          else
+            {
+              while ((len > 0) && ((*ch == '\r') || (*ch == '\n')))
+                {
+                  *bufch = *ch;
+                  bufch++;
+                  ch++;
+                  cpylen++;
+                  assert(len > 0);
+                  len--;
+                  bufline->len++;
+                  bufhead->len++;
+                }
+              bufline->terminated =1;
+            }
+          break;
+        }
 
-  if(*bufch != '\r' && *bufch != '\n')
-    { 
-      /* No linefeed, bail for the next time */
-      bufhead->len += cpylen;
-      bufline->len += cpylen;
-      bufline->terminated = 0;
-      return clen;
+      /*
+       * phew! we can copy a byte. Do it, and update the counters.
+       * this definitely blows our register sets on most sane archs,
+       * but hey, someone can recode this later on if they want to.
+       */
+      *bufch = *ch; 
+      bufch++;
+      ch++;
+      cpylen++;
+      assert(len > 0);
+      len--;
+      bufline->len++;
+      bufhead->len++;
     }
 
-  /* Yank the CRLF off this, replace with a \0 */
-  while(cpylen && (*bufch == '\r' || *bufch == '\n'))
-    {
-      *bufch = '\0';
-      cpylen--;
-      bufch--;
-    }
-  
-  bufline->terminated = 1;
-  bufhead->len += cpylen;
-  bufline->len += cpylen;
-  return clen;
+  *bufch = '\0';
+  return cpylen;
 }
 
-/*
- * linebuf_copy_raw
- *
- * Copy as much data as possible directly into a linebuf,
- * splitting at \r\n, but without altering any data.
- *
- */
-static int
-linebuf_copy_raw(buf_head_t *bufhead, buf_line_t *bufline,
-                  char *data, int len)
-{
-  int cpylen = 0;	/* how many bytes we've copied */
-  char *ch = data;	/* Pointer to where we are in the read data */
-  char *bufch = bufline->buf + bufline->len;
-  int clen = 0;                 /* how many bytes we've processed,
-                                   and don't ever want to see again.. */
-
-  /* If its full or terminated, ignore it */
-
-  bufline->raw = 1;
-  assert(bufline->len < BUF_DATA_SIZE);
-  if (bufline->terminated == 1)
-    return 0;
 
-  clen = cpylen = linebuf_skip_crlf(ch, len);
-  if (clen == -1)
-    return -1;
 
-  /* This is the overflow case..This doesn't happen often.. */
-  if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
-    {
-      memcpy(bufch, ch, (BUF_DATA_SIZE - bufline->len - 1));
-      bufline->buf[BUF_DATA_SIZE-1] = '\0';
-      bufch = bufline->buf + BUF_DATA_SIZE - 2;
-      bufline->terminated = 1;
-      bufline->len = BUF_DATA_SIZE - 1;
-      bufhead->len += BUF_DATA_SIZE - 1;
-      return clen;
-    }
-
-  memcpy(bufch, ch, cpylen);
-  bufch += cpylen;
-  *bufch = '\0';
-  bufch--;
-
-  if(*bufch != '\r' && *bufch != '\n')
-    { 
-      /* No linefeed, bail for the next time */
-      bufhead->len += cpylen;
-      bufline->len += cpylen;
-      bufline->terminated = 0;
-      return clen;
-    }
-
-  bufline->terminated = 1;
-  bufhead->len += cpylen;
-  bufline->len += cpylen;
-  return clen;
-}
 
 
 /*
@@ -411,10 +396,7 @@
     bufline = bufhead->list.tail->data;
     assert(!bufline->flushing);
     /* just try, the worst it could do is *reject* us .. */
-    if (raw) /* if we could be dealing with 8-bit data */
-      cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
-    else
-      cpylen = linebuf_copy_line(bufhead, bufline, data, len);
+    cpylen = linebuf_copy_line(bufhead, bufline, data, len, raw);
     if (cpylen == -1)
       return -1;
     
@@ -436,10 +418,7 @@
     bufline = linebuf_new_line(bufhead);
     
     /* And parse */
-    if (raw) /* if we could be dealing with 8-bit data */
-      cpylen = linebuf_copy_raw(bufhead, bufline, data, len);
-    else
-      cpylen = linebuf_copy_line(bufhead, bufline, data, len);
+    cpylen = linebuf_copy_line(bufhead, bufline, data, len, raw);
     if (cpylen == -1)
       return -1;
 
