chiark / gitweb /
Qualify name given to @bres_byname@.
[mLib] / lbuf.c
diff --git a/lbuf.c b/lbuf.c
index 63eb4471bbd8c8023661d63c71117412a9dea258..ba186789f74198299efc4b273115623a58e73f72 100644 (file)
--- a/lbuf.c
+++ b/lbuf.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: lbuf.c,v 1.2 1999/05/17 20:36:08 mdw Exp $
+ * $Id: lbuf.c,v 1.6 2002/01/13 13:32:52 mdw Exp $
  *
  * Block-to-line buffering
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: lbuf.c,v $
+ * Revision 1.6  2002/01/13 13:32:52  mdw
+ * Pass line length to line handler function.  Provide a @typedef@ for
+ * handler functions.  Allow run-time configuration of line delimiters.
+ *
+ * Revision 1.5  2001/02/03 16:23:33  mdw
+ * Bug fix: handle a disable during a close-induced flush without dumping
+ * core.
+ *
+ * Revision 1.4  2000/06/17 10:38:14  mdw
+ * Add support for variable buffer sizes.
+ *
+ * Revision 1.3  1999/05/22 13:38:50  mdw
+ * Fix bug which discarded initial portions of incomplete lines.
+ *
  * Revision 1.2  1999/05/17 20:36:08  mdw
  * Make the magical constants for the buffer flags uppercase.
  *
 
 /*----- Header files ------------------------------------------------------*/
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+#include "alloc.h"
+#include "arena.h"
 #include "lbuf.h"
 
 /*----- Main code ---------------------------------------------------------*/
@@ -78,6 +95,11 @@ void lbuf_flush(lbuf *b, char *p, size_t len)
   char *base;                          /* Base address of current line */
   int cr;                              /* Carriage return state */
 
+  if (b->f & LBUF_CLOSE) {
+    b->func(0, 0, b->p);
+    return;
+  }
+
   /* --- Initialize variables as necessary --- */
 
   if (!p) {
@@ -91,7 +113,7 @@ void lbuf_flush(lbuf *b, char *p, size_t len)
 
   /* --- Clear @base@ if I'm discarding an overlong line --- */
 
-  if (b->len == sizeof(b->buf))
+  if (b->len == b->sz)
     base = 0;
   else
     base = b->buf;
@@ -102,39 +124,36 @@ void lbuf_flush(lbuf *b, char *p, size_t len)
 
     /* --- Quickly discard uninteresting characters --- */
 
-    if (*q != '\r' && *q != '\n') {
-      cr = 0;
-      continue;
-    }
-    if (*q == '\r') {
-      cr = 1;
-      continue;
+    switch (b->delim) {
+      case LBUF_CRLF:
+      case LBUF_STRICTCRLF:
+       if (*q != '\r' && *q != '\n') {
+         cr = 0;
+         continue;
+       }
+       if (*q == '\r') {
+         cr = 1;
+         continue;
+       }
+       if (!cr && b->delim == LBUF_STRICTCRLF)
+         continue;
+       break;
+      default:
+       if (*q != b->delim)
+         continue;
     }
 
-    /* --- Two choices here --- *
-     *
-     * I can either be strict about CRLF line ends, or I can be shoddy
-     * and allow bare LFs.  I'll do the latter, although I oughtn't,
-     * because it makes testing interactively and with Unix text files
-     * easier.
-     */
-
-#ifdef STRICT_CRLF
-    if (!cr)
-      continue;
-#endif 
-
-    /* --- I have a positive ID on a linefeed --- *
+    /* --- I have a positive ID on a delimiter --- *
      *
      * If I'm interested in this string, report it to my owner.
      */
 
     if (base) {
+      len = q - base;
       if (cr)
-       q[-1] = 0;                      /* Exercise: why is this safe? */
-      else
-       *q = 0;
-      b->func(base, b->p);
+       len--;                          /* Exercise: why is this safe? */
+      base[len] = 0;
+      b->func(base, len, b->p);
       if (!(b->f & LBUF_ENABLE)) {
        base = q + 1;
        break;
@@ -147,10 +166,10 @@ void lbuf_flush(lbuf *b, char *p, size_t len)
   /* --- Sift through the aftermath --- */
 
   if (base) {
-    size_t len = l - base;
-    if (len == sizeof(b->buf)) {
+    len = l - base;
+    if (len == b->sz) {
       b->buf[len - 1] = 0;
-      b->func(base, b->p);
+      b->func(base, len - 1, b->p);
     } else if (base != b->buf)
       memmove(b->buf, base, len);
     b->len = len;
@@ -170,17 +189,22 @@ void lbuf_flush(lbuf *b, char *p, size_t len)
  * Use:                Empties the buffer of any data currently lurking in it, and
  *             informs the client that this has happened.  It's assumed that
  *             the buffer is enabled: you shouldn't be reading close events
- *             on disabled buffers.
+ *             on disabled buffers.  The buffer, if allocated, is freed.
  */
 
 void lbuf_close(lbuf *b)
 {
-  if (b->len && b->len != sizeof(b->buf)) {
+  if (b->len && b->len != b->sz) {
     b->buf[b->len] = 0;
-    b->func(b->buf, b->p);
+    b->func(b->buf, b->len, b->p);
+  }
+  if (b->buf) {
+    x_free(b->a, b->buf);
+    b->buf = 0;
   }
+  b->f |= LBUF_CLOSE;
   if (b->f & LBUF_ENABLE)
-    b->func(0, b->p);
+    b->func(0, 0, b->p);
 }
 
 /* --- @lbuf_free@ --- *
@@ -192,7 +216,8 @@ void lbuf_close(lbuf *b)
  *
  * Use:                Returns the free portion of a line buffer.  Data can then be
  *             written to this portion, and split out into lines by calling
- *             @lbuf_flush@.
+ *             @lbuf_flush@.  A buffer is allocated if none currently
+ *             exists.
  */
 
 size_t lbuf_free(lbuf *b, char **p)
@@ -201,18 +226,20 @@ size_t lbuf_free(lbuf *b, char **p)
    *
    * If a line from the file wouldn't fit in the buffer, I truncate it and
    * return what would fit.  The rest of the line ought to be discarded.
-   * This condition is signalled by @len = sizeof(buf)@, and means that the
-   * entire buffer is OK to be trashed.  In other cases, @len@ is the amount
-   * of space currently occupied in the buffer.  This special case is the
-   * reason this routine exists.
+   * This condition is signalled by @len = b->sz@, and means that the entire
+   * buffer is OK to be trashed.  In other cases, @len@ is the amount of
+   * space currently occupied in the buffer.  This special case is the reason
+   * this routine exists.
    */
 
-  if (b->len == 0 || b->len == sizeof(b->buf)) {
+  if (b->len != 0 && b->len != b->sz) {
     *p = b->buf + b->len;
-    return (sizeof(b->buf) - b->len);
+    return (b->sz - b->len);
   } else {
+    if (!b->buf)
+      b->buf = x_alloc(b->a, b->sz);
     *p = b->buf;
-    return (sizeof(b->buf));
+    return (b->sz);
   }
 }
 
@@ -233,7 +260,7 @@ size_t lbuf_free(lbuf *b, char **p)
 void lbuf_snarf(lbuf *b, const void *p, size_t sz)
 {
   const char *pp = p;
-  while (sz) {
+  while (sz && (b->f & LBUF_ENABLE)) {
     size_t bsz;
     char *bp;
 
@@ -247,26 +274,69 @@ void lbuf_snarf(lbuf *b, const void *p, size_t sz)
   }
 }
 
+/* --- @lbuf_setsize@ --- *
+ *
+ * Arguments:  @lbuf *b@ = pointer to buffer block
+ *             @size_t sz@ = requested maximum line size
+ *
+ * Returns:    ---
+ *
+ * Use:                Modifies the size of the buffer associated with the block.
+ *             It is an error to resize a buffer while it contains data.
+ */
+
+void lbuf_setsize(lbuf *b, size_t sz)
+{
+  if (b->buf)
+  assert(((void)"Buffer in use in lbuf_setsize",
+        b->len == 0 || b->len == b->sz));
+  if (b->buf)
+    x_free(b->a, b->buf);
+  b->sz = sz;
+  b->buf = 0;
+}
+
 /* --- @lbuf_init@ --- *
  *
  * Arguments:  @lbuf *b@ = pointer to buffer block
- *             @void (*func)(char *s, void *p)@ = handler function
+ *             @lbuf_func *func@ = handler function
  *             @void *p@ = argument pointer for @func@
  *
  * Returns:    ---
  *
  * Use:                Initializes a line buffer block.  Any recognized lines are
- *             passed to @func@ for processing.
+ *             passed to @func@ for processing.  No buffer is initially
+ *             allocated; this is done when the buffer is actually required
+ *             for the first time.
  */
 
-void lbuf_init(lbuf *b,
-              void (*func)(char */*s*/, void */*p*/),
-              void *p)
+void lbuf_init(lbuf *b, lbuf_func *func, void *p)
 {
   b->func = func;
   b->p = p;
   b->len = 0;
   b->f = LBUF_ENABLE;
+  b->delim = LBUF_CRLF;
+  b->buf = 0;
+  b->a = arena_global;
+  lbuf_setsize(b, 256);
+}
+
+/* --- @lbuf_destroy@ --- *
+ *
+ * Arguments:  @lbuf *b@ = pointer to buffer block
+ *
+ * Returns:    ---
+ *
+ * Use:                Deallocates a line buffer and frees any resources it owned.
+ */
+
+void lbuf_destroy(lbuf *b)
+{
+  if (b->buf) {
+    x_free(b->a, b->buf);
+    b->buf = 0;
+  }
 }
 
 /*----- That's all, folks -------------------------------------------------*/