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