chiark / gitweb /
Reorder the source files again, in an attempt to make them slightly
[mLib] / lbuf.c
1 /* -*-c-*-
2  *
3  * $Id: lbuf.c,v 1.2 1999/05/17 20:36:08 mdw Exp $
4  *
5  * Block-to-line buffering
6  *
7  * (c) 1999 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: lbuf.c,v $
33  * Revision 1.2  1999/05/17 20:36:08  mdw
34  * Make the magical constants for the buffer flags uppercase.
35  *
36  * Revision 1.1  1999/05/14 21:01:14  mdw
37  * Integrated `select' handling bits from the background resolver project.
38  *
39  */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include "lbuf.h"
48
49 /*----- Main code ---------------------------------------------------------*/
50
51 /* --- @lbuf_flush@ --- *
52  *
53  * Arguments:   @lbuf *b@ = pointer to buffer block
54  *              @char *p@ = pointer to where to start searching
55  *              @size_t len@ = length of new material added
56  *
57  * Returns:     ---
58  *
59  * Use:         Flushes any complete lines in a line buffer.  New material
60  *              is assumed to have been added starting at @p@.  If @p@ is
61  *              null, then the scan starts at the beginning of the buffer,
62  *              and the size of data already in the buffer is used in place
63  *              of @len@.
64  *
65  *              It is assumed that the buffer is initially enabled.  You
66  *              shouldn't be contributing data to a disabled buffer anyway.
67  *              However, the buffer handler may at some point disable itself,
68  *              and @lbuf_flush@ can cope with this eventuality.  Any pending
69  *              data is left at the start of the buffer and can be flushed
70  *              out by calling @lbuf_flush(b, 0, 0)@ if the buffer is ever
71  *              re-enabled.
72  */
73
74 void lbuf_flush(lbuf *b, char *p, size_t len)
75 {
76   char *l;                              /* Limit of data in buffer */
77   char *q;                              /* Roving pointer through string */
78   char *base;                           /* Base address of current line */
79   int cr;                               /* Carriage return state */
80
81   /* --- Initialize variables as necessary --- */
82
83   if (!p) {
84     p = b->buf;
85     cr = 0;
86     len = b->len;
87   } else
88     cr = b->f & LBUF_CR;
89
90   l = p + len;
91
92   /* --- Clear @base@ if I'm discarding an overlong line --- */
93
94   if (b->len == sizeof(b->buf))
95     base = 0;
96   else
97     base = b->buf;
98
99   /* --- Now I march through the string --- */
100
101   for (q = p; q < l; q++) {
102
103     /* --- Quickly discard uninteresting characters --- */
104
105     if (*q != '\r' && *q != '\n') {
106       cr = 0;
107       continue;
108     }
109     if (*q == '\r') {
110       cr = 1;
111       continue;
112     }
113
114     /* --- Two choices here --- *
115      *
116      * I can either be strict about CRLF line ends, or I can be shoddy
117      * and allow bare LFs.  I'll do the latter, although I oughtn't,
118      * because it makes testing interactively and with Unix text files
119      * easier.
120      */
121
122 #ifdef STRICT_CRLF
123     if (!cr)
124       continue;
125 #endif  
126
127     /* --- I have a positive ID on a linefeed --- *
128      *
129      * If I'm interested in this string, report it to my owner.
130      */
131
132     if (base) {
133       if (cr)
134         q[-1] = 0;                      /* Exercise: why is this safe? */
135       else
136         *q = 0;
137       b->func(base, b->p);
138       if (!(b->f & LBUF_ENABLE)) {
139         base = q + 1;
140         break;
141       }
142     }
143     base = q + 1;
144     cr = 0;
145   }
146
147   /* --- Sift through the aftermath --- */
148
149   if (base) {
150     size_t len = l - base;
151     if (len == sizeof(b->buf)) {
152       b->buf[len - 1] = 0;
153       b->func(base, b->p);
154     } else if (base != b->buf)
155       memmove(b->buf, base, len);
156     b->len = len;
157     if (cr)
158       b->f |= LBUF_CR;
159     else
160       b->f &= ~LBUF_CR;
161   }
162 }
163
164 /* --- @lbuf_close@ --- *
165  *
166  * Arguments:   @lbuf *b@ = pointer to buffer block
167  *
168  * Returns:     ---
169  *
170  * Use:         Empties the buffer of any data currently lurking in it, and
171  *              informs the client that this has happened.  It's assumed that
172  *              the buffer is enabled: you shouldn't be reading close events
173  *              on disabled buffers.
174  */
175
176 void lbuf_close(lbuf *b)
177 {
178   if (b->len && b->len != sizeof(b->buf)) {
179     b->buf[b->len] = 0;
180     b->func(b->buf, b->p);
181   }
182   if (b->f & LBUF_ENABLE)
183     b->func(0, b->p);
184 }
185
186 /* --- @lbuf_free@ --- *
187  *
188  * Arguments:   @lbuf *b@ = pointer to buffer block
189  *              @char **p@ = output pointer to free space
190  *
191  * Returns:     Free buffer size.
192  *
193  * Use:         Returns the free portion of a line buffer.  Data can then be
194  *              written to this portion, and split out into lines by calling
195  *              @lbuf_flush@.
196  */
197
198 size_t lbuf_free(lbuf *b, char **p)
199 {
200   /* --- There's a special case to consider --- *
201    *
202    * If a line from the file wouldn't fit in the buffer, I truncate it and
203    * return what would fit.  The rest of the line ought to be discarded.
204    * This condition is signalled by @len = sizeof(buf)@, and means that the
205    * entire buffer is OK to be trashed.  In other cases, @len@ is the amount
206    * of space currently occupied in the buffer.  This special case is the
207    * reason this routine exists.
208    */
209
210   if (b->len == 0 || b->len == sizeof(b->buf)) {
211     *p = b->buf + b->len;
212     return (sizeof(b->buf) - b->len);
213   } else {
214     *p = b->buf;
215     return (sizeof(b->buf));
216   }
217 }
218
219 /* --- @lbuf_snarf@ --- *
220  *
221  * Arguments:   @lbuf *b@ = pointer to buffer block
222  *              @const void *p@ = pointer to input data buffer
223  *              @size_t sz@ = size of data in input buffer
224  *
225  * Returns:     ---
226  *
227  * Use:         Snarfs the data from the input buffer and spits it out as
228  *              lines.  This interface ignores the complexities of dealing
229  *              with disablement: you should be using @lbuf_free@ to
230  *              contribute data if you want to cope with that.
231  */
232
233 void lbuf_snarf(lbuf *b, const void *p, size_t sz)
234 {
235   const char *pp = p;
236   while (sz) {
237     size_t bsz;
238     char *bp;
239
240     bsz = lbuf_free(b, &bp);
241     if (bsz > sz)
242       bsz = sz;
243     memcpy(bp, pp, bsz);
244     lbuf_flush(b, bp, bsz);
245     pp += bsz;
246     sz -= bsz;
247   }
248 }
249
250 /* --- @lbuf_init@ --- *
251  *
252  * Arguments:   @lbuf *b@ = pointer to buffer block
253  *              @void (*func)(char *s, void *p)@ = handler function
254  *              @void *p@ = argument pointer for @func@
255  *
256  * Returns:     ---
257  *
258  * Use:         Initializes a line buffer block.  Any recognized lines are
259  *              passed to @func@ for processing.
260  */
261
262 void lbuf_init(lbuf *b,
263                void (*func)(char */*s*/, void */*p*/),
264                void *p)
265 {
266   b->func = func;
267   b->p = p;
268   b->len = 0;
269   b->f = LBUF_ENABLE;
270 }
271
272 /*----- That's all, folks -------------------------------------------------*/