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