1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino * Copyright (c) 2004 The DragonFly Project. All rights reserved.
3*86d7f5d3SJohn Marino *
4*86d7f5d3SJohn Marino * This code is derived from software contributed to The DragonFly Project
5*86d7f5d3SJohn Marino * by Chris Pressey <cpressey@catseye.mine.nu>.
6*86d7f5d3SJohn Marino *
7*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
8*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
9*86d7f5d3SJohn Marino * are met:
10*86d7f5d3SJohn Marino *
11*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
12*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
13*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
14*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in
15*86d7f5d3SJohn Marino * the documentation and/or other materials provided with the
16*86d7f5d3SJohn Marino * distribution.
17*86d7f5d3SJohn Marino * 3. Neither the name of The DragonFly Project nor the names of its
18*86d7f5d3SJohn Marino * contributors may be used to endorse or promote products derived
19*86d7f5d3SJohn Marino * from this software without specific, prior written permission.
20*86d7f5d3SJohn Marino *
21*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*86d7f5d3SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*86d7f5d3SJohn Marino * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*86d7f5d3SJohn Marino * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25*86d7f5d3SJohn Marino * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*86d7f5d3SJohn Marino * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*86d7f5d3SJohn Marino * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*86d7f5d3SJohn Marino * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*86d7f5d3SJohn Marino * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*86d7f5d3SJohn Marino * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*86d7f5d3SJohn Marino * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*86d7f5d3SJohn Marino * SUCH DAMAGE.
33*86d7f5d3SJohn Marino */
34*86d7f5d3SJohn Marino
35*86d7f5d3SJohn Marino /*
36*86d7f5d3SJohn Marino * extbuf.c
37*86d7f5d3SJohn Marino * $Id: buffer.c,v 1.2 2005/02/06 06:57:30 cpressey Exp $
38*86d7f5d3SJohn Marino * Routines to manipulate extensible buffers.
39*86d7f5d3SJohn Marino *
40*86d7f5d3SJohn Marino * Aura buffers are buffers that attempt to automatically expand
41*86d7f5d3SJohn Marino * when more data is written to them than they can initially hold.
42*86d7f5d3SJohn Marino * In addition, each extensible buffer contains a cursor from which
43*86d7f5d3SJohn Marino * its contents may be incrementally scanned.
44*86d7f5d3SJohn Marino */
45*86d7f5d3SJohn Marino
46*86d7f5d3SJohn Marino #include <err.h>
47*86d7f5d3SJohn Marino #include <stdarg.h>
48*86d7f5d3SJohn Marino #include <stdio.h>
49*86d7f5d3SJohn Marino #include <stdlib.h>
50*86d7f5d3SJohn Marino #include <string.h>
51*86d7f5d3SJohn Marino #include <sysexits.h>
52*86d7f5d3SJohn Marino
53*86d7f5d3SJohn Marino #include "buffer.h"
54*86d7f5d3SJohn Marino
55*86d7f5d3SJohn Marino /*
56*86d7f5d3SJohn Marino * Create a new extensible buffer with the given initial size.
57*86d7f5d3SJohn Marino */
58*86d7f5d3SJohn Marino struct aura_buffer *
aura_buffer_new(size_t size)59*86d7f5d3SJohn Marino aura_buffer_new(size_t size)
60*86d7f5d3SJohn Marino {
61*86d7f5d3SJohn Marino struct aura_buffer *e;
62*86d7f5d3SJohn Marino
63*86d7f5d3SJohn Marino e = malloc(sizeof(struct aura_buffer));
64*86d7f5d3SJohn Marino
65*86d7f5d3SJohn Marino e->len = 0;
66*86d7f5d3SJohn Marino e->size = size;
67*86d7f5d3SJohn Marino e->pos = 0;
68*86d7f5d3SJohn Marino
69*86d7f5d3SJohn Marino e->buf = malloc(size);
70*86d7f5d3SJohn Marino e->buf[0] = '\0';
71*86d7f5d3SJohn Marino
72*86d7f5d3SJohn Marino return(e);
73*86d7f5d3SJohn Marino }
74*86d7f5d3SJohn Marino
75*86d7f5d3SJohn Marino /*
76*86d7f5d3SJohn Marino * Deallocate the memory used for an extensible buffer.
77*86d7f5d3SJohn Marino */
78*86d7f5d3SJohn Marino void
aura_buffer_free(struct aura_buffer * e)79*86d7f5d3SJohn Marino aura_buffer_free(struct aura_buffer *e)
80*86d7f5d3SJohn Marino {
81*86d7f5d3SJohn Marino if (e != NULL) {
82*86d7f5d3SJohn Marino if (e->buf != NULL)
83*86d7f5d3SJohn Marino free(e->buf);
84*86d7f5d3SJohn Marino free(e);
85*86d7f5d3SJohn Marino }
86*86d7f5d3SJohn Marino }
87*86d7f5d3SJohn Marino
88*86d7f5d3SJohn Marino /*
89*86d7f5d3SJohn Marino * Return the underlying (static) buffer of an extensible buffer.
90*86d7f5d3SJohn Marino *
91*86d7f5d3SJohn Marino * NOTE that you should NEVER cache the returned pointer anywhere,
92*86d7f5d3SJohn Marino * as any further manipulation of the extensible buffer may cause
93*86d7f5d3SJohn Marino * it to be invalidated.
94*86d7f5d3SJohn Marino *
95*86d7f5d3SJohn Marino * ALSO NOTE that the buffer may contain embedded NULs, but will
96*86d7f5d3SJohn Marino * also be guaranteed to be NUL-terminated.
97*86d7f5d3SJohn Marino */
98*86d7f5d3SJohn Marino char *
aura_buffer_buf(struct aura_buffer * e)99*86d7f5d3SJohn Marino aura_buffer_buf(struct aura_buffer *e)
100*86d7f5d3SJohn Marino {
101*86d7f5d3SJohn Marino return(e->buf);
102*86d7f5d3SJohn Marino }
103*86d7f5d3SJohn Marino
104*86d7f5d3SJohn Marino /*
105*86d7f5d3SJohn Marino * Return the current length of the extensible buffer.
106*86d7f5d3SJohn Marino */
107*86d7f5d3SJohn Marino size_t
aura_buffer_len(struct aura_buffer * e)108*86d7f5d3SJohn Marino aura_buffer_len(struct aura_buffer *e)
109*86d7f5d3SJohn Marino {
110*86d7f5d3SJohn Marino return(e->len);
111*86d7f5d3SJohn Marino }
112*86d7f5d3SJohn Marino
113*86d7f5d3SJohn Marino /*
114*86d7f5d3SJohn Marino * Return the current size of the extensible buffer. This is how
115*86d7f5d3SJohn Marino * big it's length may grow to before expanded.
116*86d7f5d3SJohn Marino */
117*86d7f5d3SJohn Marino size_t
aura_buffer_size(struct aura_buffer * e)118*86d7f5d3SJohn Marino aura_buffer_size(struct aura_buffer *e)
119*86d7f5d3SJohn Marino {
120*86d7f5d3SJohn Marino return(e->size);
121*86d7f5d3SJohn Marino }
122*86d7f5d3SJohn Marino
123*86d7f5d3SJohn Marino /*
124*86d7f5d3SJohn Marino * Ensure that an extensible buffer's size is at least the given
125*86d7f5d3SJohn Marino * size. If it is not, it will be internally grown to that size.
126*86d7f5d3SJohn Marino * This does not affect the contents of the buffer in any way.
127*86d7f5d3SJohn Marino */
128*86d7f5d3SJohn Marino void
aura_buffer_ensure_size(struct aura_buffer * e,size_t size)129*86d7f5d3SJohn Marino aura_buffer_ensure_size(struct aura_buffer *e, size_t size)
130*86d7f5d3SJohn Marino {
131*86d7f5d3SJohn Marino if (e->size >= size) return;
132*86d7f5d3SJohn Marino e->size = size;
133*86d7f5d3SJohn Marino if ((e->buf = realloc(e->buf, e->size)) == NULL) {
134*86d7f5d3SJohn Marino err(EX_UNAVAILABLE, "realloc()");
135*86d7f5d3SJohn Marino }
136*86d7f5d3SJohn Marino }
137*86d7f5d3SJohn Marino
138*86d7f5d3SJohn Marino /*
139*86d7f5d3SJohn Marino * Set the contents of an extensible buffer from a regular (char *)
140*86d7f5d3SJohn Marino * buffer. The extensible buffer will grow if needed. Any existing
141*86d7f5d3SJohn Marino * contents of the extensible buffer are destroyed in this operation.
142*86d7f5d3SJohn Marino * Note that, because this requires that the length of the
143*86d7f5d3SJohn Marino * regular buffer be specified, it may safely contain NUL bytes.
144*86d7f5d3SJohn Marino */
145*86d7f5d3SJohn Marino void
aura_buffer_set(struct aura_buffer * e,const char * buf,size_t length)146*86d7f5d3SJohn Marino aura_buffer_set(struct aura_buffer *e, const char *buf, size_t length)
147*86d7f5d3SJohn Marino {
148*86d7f5d3SJohn Marino while ((length + 1) > e->size) {
149*86d7f5d3SJohn Marino e->size *= 2;
150*86d7f5d3SJohn Marino }
151*86d7f5d3SJohn Marino if ((e->buf = realloc(e->buf, e->size)) == NULL) {
152*86d7f5d3SJohn Marino err(EX_UNAVAILABLE, "realloc()");
153*86d7f5d3SJohn Marino }
154*86d7f5d3SJohn Marino memcpy(e->buf, buf, length);
155*86d7f5d3SJohn Marino e->len = length;
156*86d7f5d3SJohn Marino e->buf[e->len] = '\0';
157*86d7f5d3SJohn Marino }
158*86d7f5d3SJohn Marino
159*86d7f5d3SJohn Marino /*
160*86d7f5d3SJohn Marino * Append the contents of a regular buffer to the end of the existing
161*86d7f5d3SJohn Marino * contents of an extensible buffer. The extensible buffer will grow
162*86d7f5d3SJohn Marino * if needed. Note that, because this requires that the length of the
163*86d7f5d3SJohn Marino * regular buffer be specified, it may safely contain NUL bytes.
164*86d7f5d3SJohn Marino */
165*86d7f5d3SJohn Marino void
aura_buffer_append(struct aura_buffer * e,const char * buf,size_t length)166*86d7f5d3SJohn Marino aura_buffer_append(struct aura_buffer *e, const char *buf, size_t length)
167*86d7f5d3SJohn Marino {
168*86d7f5d3SJohn Marino while (e->len + (length + 1) > e->size) {
169*86d7f5d3SJohn Marino e->size *= 2;
170*86d7f5d3SJohn Marino }
171*86d7f5d3SJohn Marino if ((e->buf = realloc(e->buf, e->size)) == NULL) {
172*86d7f5d3SJohn Marino err(EX_UNAVAILABLE, "realloc()");
173*86d7f5d3SJohn Marino }
174*86d7f5d3SJohn Marino memcpy(e->buf + e->len, buf, length);
175*86d7f5d3SJohn Marino e->len += length;
176*86d7f5d3SJohn Marino e->buf[e->len] = '\0';
177*86d7f5d3SJohn Marino }
178*86d7f5d3SJohn Marino
179*86d7f5d3SJohn Marino /*
180*86d7f5d3SJohn Marino * Set the contents of an extensible buffer from an ASCIIZ string.
181*86d7f5d3SJohn Marino * This is identical to aura_buffer_set except that the length need not
182*86d7f5d3SJohn Marino * be specified, and the ASCIIZ string may not contain embedded NUL's.
183*86d7f5d3SJohn Marino */
184*86d7f5d3SJohn Marino void
aura_buffer_cpy(struct aura_buffer * e,const char * s)185*86d7f5d3SJohn Marino aura_buffer_cpy(struct aura_buffer *e, const char *s)
186*86d7f5d3SJohn Marino {
187*86d7f5d3SJohn Marino aura_buffer_set(e, s, strlen(s));
188*86d7f5d3SJohn Marino }
189*86d7f5d3SJohn Marino
190*86d7f5d3SJohn Marino /*
191*86d7f5d3SJohn Marino * Append the contents of an ASCIIZ string to an extensible buffer.
192*86d7f5d3SJohn Marino * This is identical to aura_buffer_append except that the length need not
193*86d7f5d3SJohn Marino * be specified, and the ASCIIZ string may not contain embedded NUL's.
194*86d7f5d3SJohn Marino */
195*86d7f5d3SJohn Marino void
aura_buffer_cat(struct aura_buffer * e,const char * s)196*86d7f5d3SJohn Marino aura_buffer_cat(struct aura_buffer *e, const char *s)
197*86d7f5d3SJohn Marino {
198*86d7f5d3SJohn Marino aura_buffer_append(e, s, strlen(s));
199*86d7f5d3SJohn Marino }
200*86d7f5d3SJohn Marino
201*86d7f5d3SJohn Marino /*
202*86d7f5d3SJohn Marino * Append the entire contents of a text file to an extensible buffer.
203*86d7f5d3SJohn Marino */
204*86d7f5d3SJohn Marino int
aura_buffer_cat_file(struct aura_buffer * e,const char * fmt,...)205*86d7f5d3SJohn Marino aura_buffer_cat_file(struct aura_buffer *e, const char *fmt, ...)
206*86d7f5d3SJohn Marino {
207*86d7f5d3SJohn Marino va_list args;
208*86d7f5d3SJohn Marino char *filename, line[1024];
209*86d7f5d3SJohn Marino FILE *f;
210*86d7f5d3SJohn Marino
211*86d7f5d3SJohn Marino va_start(args, fmt);
212*86d7f5d3SJohn Marino vasprintf(&filename, fmt, args);
213*86d7f5d3SJohn Marino va_end(args);
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino if ((f = fopen(filename, "r")) == NULL)
216*86d7f5d3SJohn Marino return(0);
217*86d7f5d3SJohn Marino
218*86d7f5d3SJohn Marino free(filename);
219*86d7f5d3SJohn Marino
220*86d7f5d3SJohn Marino while (fgets(line, 1023, f) != NULL) {
221*86d7f5d3SJohn Marino aura_buffer_cat(e, line);
222*86d7f5d3SJohn Marino }
223*86d7f5d3SJohn Marino
224*86d7f5d3SJohn Marino fclose(f);
225*86d7f5d3SJohn Marino
226*86d7f5d3SJohn Marino return(1);
227*86d7f5d3SJohn Marino }
228*86d7f5d3SJohn Marino
229*86d7f5d3SJohn Marino /*
230*86d7f5d3SJohn Marino * Append the entire output of a shell command to an extensible buffer.
231*86d7f5d3SJohn Marino */
232*86d7f5d3SJohn Marino int
aura_buffer_cat_pipe(struct aura_buffer * e,const char * fmt,...)233*86d7f5d3SJohn Marino aura_buffer_cat_pipe(struct aura_buffer *e, const char *fmt, ...)
234*86d7f5d3SJohn Marino {
235*86d7f5d3SJohn Marino va_list args;
236*86d7f5d3SJohn Marino char *command, line[1024];
237*86d7f5d3SJohn Marino FILE *p;
238*86d7f5d3SJohn Marino
239*86d7f5d3SJohn Marino va_start(args, fmt);
240*86d7f5d3SJohn Marino vasprintf(&command, fmt, args);
241*86d7f5d3SJohn Marino va_end(args);
242*86d7f5d3SJohn Marino
243*86d7f5d3SJohn Marino if ((p = popen(command, "r")) == NULL)
244*86d7f5d3SJohn Marino return(0);
245*86d7f5d3SJohn Marino
246*86d7f5d3SJohn Marino free(command);
247*86d7f5d3SJohn Marino
248*86d7f5d3SJohn Marino while (fgets(line, 1023, p) != NULL) {
249*86d7f5d3SJohn Marino aura_buffer_cat(e, line);
250*86d7f5d3SJohn Marino }
251*86d7f5d3SJohn Marino
252*86d7f5d3SJohn Marino pclose(p);
253*86d7f5d3SJohn Marino
254*86d7f5d3SJohn Marino return(1);
255*86d7f5d3SJohn Marino }
256*86d7f5d3SJohn Marino
257*86d7f5d3SJohn Marino /*** CURSORED FUNCTIONS ***/
258*86d7f5d3SJohn Marino
259*86d7f5d3SJohn Marino /*
260*86d7f5d3SJohn Marino * Note that the cursor can be anywhere from the first character to
261*86d7f5d3SJohn Marino * one position _beyond_ the last character in the buffer.
262*86d7f5d3SJohn Marino */
263*86d7f5d3SJohn Marino
264*86d7f5d3SJohn Marino int
aura_buffer_seek(struct aura_buffer * e,size_t pos)265*86d7f5d3SJohn Marino aura_buffer_seek(struct aura_buffer *e, size_t pos)
266*86d7f5d3SJohn Marino {
267*86d7f5d3SJohn Marino if (pos <= e->size) {
268*86d7f5d3SJohn Marino e->pos = pos;
269*86d7f5d3SJohn Marino return(1);
270*86d7f5d3SJohn Marino } else {
271*86d7f5d3SJohn Marino return(0);
272*86d7f5d3SJohn Marino }
273*86d7f5d3SJohn Marino }
274*86d7f5d3SJohn Marino
275*86d7f5d3SJohn Marino size_t
aura_buffer_tell(struct aura_buffer * e)276*86d7f5d3SJohn Marino aura_buffer_tell(struct aura_buffer *e)
277*86d7f5d3SJohn Marino {
278*86d7f5d3SJohn Marino return(e->pos);
279*86d7f5d3SJohn Marino }
280*86d7f5d3SJohn Marino
281*86d7f5d3SJohn Marino int
aura_buffer_eof(struct aura_buffer * e)282*86d7f5d3SJohn Marino aura_buffer_eof(struct aura_buffer *e)
283*86d7f5d3SJohn Marino {
284*86d7f5d3SJohn Marino return(e->pos >= e->size);
285*86d7f5d3SJohn Marino }
286*86d7f5d3SJohn Marino
287*86d7f5d3SJohn Marino char
aura_buffer_peek_char(struct aura_buffer * e)288*86d7f5d3SJohn Marino aura_buffer_peek_char(struct aura_buffer *e)
289*86d7f5d3SJohn Marino {
290*86d7f5d3SJohn Marino return(e->buf[e->pos]);
291*86d7f5d3SJohn Marino }
292*86d7f5d3SJohn Marino
293*86d7f5d3SJohn Marino char
aura_buffer_scan_char(struct aura_buffer * e)294*86d7f5d3SJohn Marino aura_buffer_scan_char(struct aura_buffer *e)
295*86d7f5d3SJohn Marino {
296*86d7f5d3SJohn Marino return(e->buf[e->pos++]);
297*86d7f5d3SJohn Marino }
298*86d7f5d3SJohn Marino
299*86d7f5d3SJohn Marino int
aura_buffer_compare(struct aura_buffer * e,const char * s)300*86d7f5d3SJohn Marino aura_buffer_compare(struct aura_buffer *e, const char *s)
301*86d7f5d3SJohn Marino {
302*86d7f5d3SJohn Marino size_t i, pos;
303*86d7f5d3SJohn Marino
304*86d7f5d3SJohn Marino for (i = 0, pos = e->pos; s[i] != '\0' && pos < e->size; i++, pos++) {
305*86d7f5d3SJohn Marino if (e->buf[pos] != s[i])
306*86d7f5d3SJohn Marino return(0);
307*86d7f5d3SJohn Marino }
308*86d7f5d3SJohn Marino
309*86d7f5d3SJohn Marino if (pos <= e->size) {
310*86d7f5d3SJohn Marino return(pos);
311*86d7f5d3SJohn Marino } else {
312*86d7f5d3SJohn Marino return(0);
313*86d7f5d3SJohn Marino }
314*86d7f5d3SJohn Marino }
315*86d7f5d3SJohn Marino
316*86d7f5d3SJohn Marino int
aura_buffer_expect(struct aura_buffer * e,const char * s)317*86d7f5d3SJohn Marino aura_buffer_expect(struct aura_buffer *e, const char *s)
318*86d7f5d3SJohn Marino {
319*86d7f5d3SJohn Marino int pos;
320*86d7f5d3SJohn Marino
321*86d7f5d3SJohn Marino if ((pos = aura_buffer_compare(e, s)) > 0) {
322*86d7f5d3SJohn Marino e->pos = pos;
323*86d7f5d3SJohn Marino return(1);
324*86d7f5d3SJohn Marino } else {
325*86d7f5d3SJohn Marino return(0);
326*86d7f5d3SJohn Marino }
327*86d7f5d3SJohn Marino }
328*86d7f5d3SJohn Marino
329*86d7f5d3SJohn Marino void
aura_buffer_push(struct aura_buffer * e,const void * src,size_t len)330*86d7f5d3SJohn Marino aura_buffer_push(struct aura_buffer *e, const void *src, size_t len)
331*86d7f5d3SJohn Marino {
332*86d7f5d3SJohn Marino aura_buffer_ensure_size(e, e->pos + len);
333*86d7f5d3SJohn Marino memcpy(e->buf + e->pos, src, len);
334*86d7f5d3SJohn Marino e->pos += len;
335*86d7f5d3SJohn Marino }
336*86d7f5d3SJohn Marino
337*86d7f5d3SJohn Marino int
aura_buffer_pop(struct aura_buffer * e,void * dest,size_t len)338*86d7f5d3SJohn Marino aura_buffer_pop(struct aura_buffer *e, void *dest, size_t len)
339*86d7f5d3SJohn Marino {
340*86d7f5d3SJohn Marino if (e->pos - len > 0) {
341*86d7f5d3SJohn Marino e->pos -= len;
342*86d7f5d3SJohn Marino memcpy(dest, e->buf + e->pos, len);
343*86d7f5d3SJohn Marino return(1);
344*86d7f5d3SJohn Marino } else {
345*86d7f5d3SJohn Marino return(0);
346*86d7f5d3SJohn Marino }
347*86d7f5d3SJohn Marino }
348