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 */