+++ /dev/null
-/* -*-c-*-
- *
- * Block-to-line buffering
- *
- * (c) 1999 Straylight/Edgeware
- */
-
-/*----- Licensing notice --------------------------------------------------*
- *
- * This file is part of the mLib utilities library.
- *
- * mLib is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * mLib is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with mLib; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-/*----- 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 ---------------------------------------------------------*/
-
-/* --- @lbuf_flush@ --- *
- *
- * Arguments: @lbuf *b@ = pointer to buffer block
- * @char *p@ = pointer to where to start searching
- * @size_t len@ = length of new material added
- *
- * Returns: ---
- *
- * Use: Flushes any complete lines in a line buffer. New material
- * is assumed to have been added starting at @p@. If @p@ is
- * null, then the scan starts at the beginning of the buffer,
- * and the size of data already in the buffer is used in place
- * of @len@.
- *
- * It is assumed that the buffer is initially enabled. You
- * shouldn't be contributing data to a disabled buffer anyway.
- * However, the buffer handler may at some point disable itself,
- * and @lbuf_flush@ can cope with this eventuality. Any pending
- * data is left at the start of the buffer and can be flushed
- * out by calling @lbuf_flush(b, 0, 0)@ if the buffer is ever
- * re-enabled.
- */
-
-void lbuf_flush(lbuf *b, char *p, size_t len)
-{
- char *l; /* Limit of data in buffer */
- char *q; /* Roving pointer through string */
- 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) {
- p = b->buf;
- cr = 0;
- len = b->len;
- } else
- cr = b->f & LBUF_CR;
-
- l = p + len;
-
- /* --- Clear @base@ if I'm discarding an overlong line --- */
-
- if (b->len == b->sz)
- base = 0;
- else
- base = b->buf;
-
- /* --- Now I march through the string --- */
-
- for (q = p; q < l; q++) {
-
- /* --- Quickly discard uninteresting characters --- */
-
- 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;
- }
-
- /* --- 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)
- len--; /* Exercise: why is this safe? */
- base[len] = 0;
- b->func(base, len, b->p);
- if (!(b->f & LBUF_ENABLE)) {
- base = q + 1;
- break;
- }
- }
- base = q + 1;
- cr = 0;
- }
-
- /* --- Sift through the aftermath --- */
-
- if (base) {
- len = l - base;
- if (len == b->sz) {
- b->buf[len - 1] = 0;
- b->func(base, len - 1, b->p);
- } else if (base != b->buf)
- memmove(b->buf, base, len);
- b->len = len;
- if (cr)
- b->f |= LBUF_CR;
- else
- b->f &= ~LBUF_CR;
- }
-}
-
-/* --- @lbuf_close@ --- *
- *
- * Arguments: @lbuf *b@ = pointer to buffer block
- *
- * Returns: ---
- *
- * 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. The buffer, if allocated, is freed.
- */
-
-void lbuf_close(lbuf *b)
-{
- if (b->len && b->len != b->sz) {
- b->buf[b->len] = 0;
- 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, 0, b->p);
-}
-
-/* --- @lbuf_free@ --- *
- *
- * Arguments: @lbuf *b@ = pointer to buffer block
- * @char **p@ = output pointer to free space
- *
- * Returns: Free buffer size.
- *
- * 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@. A buffer is allocated if none currently
- * exists.
- */
-
-size_t lbuf_free(lbuf *b, char **p)
-{
- /* --- There's a special case to consider --- *
- *
- * 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 = 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 != b->sz) {
- *p = 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 (b->sz);
- }
-}
-
-/* --- @lbuf_snarf@ --- *
- *
- * Arguments: @lbuf *b@ = pointer to buffer block
- * @const void *p@ = pointer to input data buffer
- * @size_t sz@ = size of data in input buffer
- *
- * Returns: ---
- *
- * Use: Snarfs the data from the input buffer and spits it out as
- * lines. This interface ignores the complexities of dealing
- * with disablement: you should be using @lbuf_free@ to
- * contribute data if you want to cope with that.
- */
-
-void lbuf_snarf(lbuf *b, const void *p, size_t sz)
-{
- const char *pp = p;
- while (sz && (b->f & LBUF_ENABLE)) {
- size_t bsz;
- char *bp;
-
- bsz = lbuf_free(b, &bp);
- if (bsz > sz)
- bsz = sz;
- memcpy(bp, pp, bsz);
- lbuf_flush(b, bp, bsz);
- pp += bsz;
- sz -= bsz;
- }
-}
-
-/* --- @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
- * @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. No buffer is initially
- * allocated; this is done when the buffer is actually required
- * for the first time.
- */
-
-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 -------------------------------------------------*/