Mercurial > code
changeset 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 |
files | buffer.c buffer.h |
diffstat | 2 files changed, 274 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buffer.c Mon Sep 05 23:01:29 2011 +0200 @@ -0,0 +1,224 @@ +/* + * 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/buffer.h Mon Sep 05 23:01:29 2011 +0200 @@ -0,0 +1,50 @@ +/* + * buffer.h -- 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. + */ + +#ifndef HAVE_BUFFER_H +#define HAVE_BUFFER_H + +#define BUFFER_DEFAULT_BSIZE 512 + +#include <stdarg.h> + +struct buffer { + char *data; /* string buffer */ + size_t length; /* string's length */ + size_t size; /* current size */ + size_t bsize; /* block size */ + +#define BUFFER_AUTO 0x00000001 +#define BUFFER_FIXED 0x00000010 + int flags; /* buffer's flags (default AUTO) */ +}; + +struct buffer *buffer_new(const char *, size_t, int); +#define buffer_new_auto(size) buffer_new(NULL, size, BUFFER_AUTO) +#define buffer_new_fixed(max) buffer_new(NULL, max, BUFFER_FIXED) + +int buffer_strcat(struct buffer *, const char *); +int buffer_bcat(struct buffer *, const void *, size_t); +int buffer_vprintf(struct buffer *, const char *, va_list); +int buffer_printf(struct buffer *, const char *, ...); +int buffer_shrink(struct buffer *); +char *buffer_end(struct buffer *); +void buffer_clear(struct buffer *); +void buffer_free(struct buffer *); + +#endif /* HAVE_BUFFER_H */