Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / usr.sbin / installer / libaura / buffer.c
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 }