Mercurial > code
view buffer.c @ 0:a20beb164de8
Added buffer.c and buffer.h:
Various function to manipulate safely string buffers. It is similar to
sbuf(9) on FreeBSD but more portable and simpler.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 05 Sep 2011 23:01:29 +0200 |
parents | |
children | 22d7bb03e569 |
line wrap: on
line source
/* * buffer.c -- safe unlimited size string * * Copyright (c) 2011, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include "buffer.h" static int buffer_grow(struct buffer *, size_t); /* * Initialize a new buffer with the optional `str' as begin of buffer. */ struct buffer * buffer_new(const char *str, size_t bsize, int flags) { struct buffer *buf; if (!(buf = malloc(sizeof (struct buffer)))) return NULL; memset(buf, 0, sizeof (struct buffer)); if (bsize == 0) bsize = BUFFER_DEFAULT_BSIZE; if (!(buf->data = calloc(bsize + 1, 1))) { free(buf); return NULL; } buf->size = bsize + 1; buf->bsize = bsize; buf->flags = flags; if (str && buffer_strcat(buf, str) < 0) { free(buf); return NULL; } return buf; } /* * Concatenate the string into the buffer. */ int buffer_strcat(struct buffer *buf, const char *str) { size_t length; length = strlen(str); if (buffer_grow(buf, length) < 0) return -1; if (buf->flags & BUFFER_FIXED) length = buf->size - buf->length - 1; strncat(buf->data, str, length); buf->length = strlen(buf->data); return 0; } /* * Concatenate the byte pointer into the buffer. */ int buffer_bcat(struct buffer *buf, const void *data, size_t size) { if (buffer_grow(buf, size) < 0) return -1; /* Do not truncate void pointer */ if (buf->flags & BUFFER_FIXED && size > (buf->size - buf->length - 1)) return -1; memcpy(buf->data + buf->length, data, size); buf->length += size; return 0; } /* * Print into the buffer using va_list from stdarg.h */ int buffer_vprintf(struct buffer *buf, const char *fmt, va_list ap) { va_list ap_save; int nb, stop = 0; /* * vsnprintf on windows returns -1 instead of the number of bytes that * should be printed... */ if (buf->flags & BUFFER_AUTO) { do { va_copy(ap_save, ap); nb = vsnprintf(buf->data + buf->length, buf->size - buf->length - 1, fmt, ap_save); if (nb == -1 || nb > strlen(buf->data)) { if (buffer_grow(buf, buf->size + buf->bsize)) return -1; } else stop = 1; } while (stop == 0); } else vsnprintf(buf->data + buf->length, buf->size - buf->length - 1, fmt, ap); va_end(ap_save); return 0; } /* * Use printf(3) functions like to write into the buffer. */ int buffer_printf(struct buffer *buf, const char *fmt, ...) { va_list ap; int status; va_start(ap, fmt); status = buffer_vprintf(buf, fmt, ap); va_end(ap); return status; } /* * Reduce the data buffer to the exact size. Returns -1 on failure. */ int buffer_shrink(struct buffer *buf) { if (!(buf->data = realloc(buf->data, buf->length + 1))) return -1; buf->size = buf->length + 1; return 0; } /* * Returns the buffer data and then free the buffer object. */ char * buffer_end(struct buffer *buf) { char *data; data = buf->data; free(buf); return data; } /* * Reset the struct buffer. */ void buffer_clear(struct buffer *buf) { if (buf->data) free(buf->data); buf->length = 0; buf->size = 0; } void buffer_free(struct buffer *buf) { buffer_clear(buf); free(buf); } static int buffer_grow(struct buffer *buf, size_t needed) { if ((buf->size - buf->length) > needed) return 0; if (buf->flags & BUFFER_AUTO) { while (buf->size - buf->length < needed) buf->size += buf->bsize; if (!(buf->data = realloc(buf->data, buf->size))) return -1; } memset(buf->data + buf->length, 0, buf->size - buf->length); return 0; }