changeset 125:b9723c197038

Add brand new string buffer
author David Demelier <markand@malikania.fr>
date Wed, 07 Mar 2012 09:51:01 +0100
parents 5917096facb9
children 911201e7574f
files buf.c buf.h
diffstat 2 files changed, 313 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buf.c	Wed Mar 07 09:51:01 2012 +0100
@@ -0,0 +1,250 @@
+/*
+ * buf.c -- easy way to manipulate strings
+ *
+ * Copyright (c) 2011, 2012, 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 <string.h>
+
+#include "buf.h"
+
+#define BUF_AVAIL(buf)	((buf)->alsize - (buf)->length - 1)
+#define BUF_SAFE(buf)	(!((buf)->flags & BUF_UNSAFE))
+#define BUF_FIXED(buf)	((buf)->flags & BUF_FIXED)
+#define BUF_AUTO(buf)	(buf->flags == 0)
+
+static void	copy(struct buf *, const void *, size_t);
+static int	grow(struct buf *, size_t);
+
+int
+buf_init(struct buf *buf)
+{
+	/* Set defaults if needed */
+	buf->bsize	= (buf->bsize <= 0) ? BUF_DEFAULT_BSIZE : buf->bsize;
+	buf->alsize	= buf->bsize + 1;
+	buf->malloc	= (buf->malloc == NULL) ? &malloc : buf->malloc;
+	buf->realloc	= (buf->realloc == NULL) ? &realloc : buf->realloc;
+
+	if ((buf->text = buf->malloc(buf->alsize)) == NULL)
+		return -1;
+
+	memset(buf->text, 0, buf->alsize);
+
+	return 0;
+}
+
+/*
+ * This function appends not more than max characters from str.
+ */
+
+int
+buf_ncat(struct buf *buf, const char *str, size_t max)
+{
+	size_t tocopy = max;
+
+	for (tocopy = 0; str[tocopy] != '\0' && tocopy < max; ++tocopy)
+		continue;
+
+	if (BUF_AVAIL(buf) < tocopy) {
+		/* Can't add more */
+		if (BUF_SAFE(buf) && BUF_FIXED(buf))
+			return -1;
+
+		if (BUF_AUTO(buf)) {
+			if (grow(buf, tocopy) < 0)
+				return -1;
+		} else {
+			/* String is unsafe, truncate to the available size */
+			tocopy = BUF_AVAIL(buf);
+		}
+	}
+
+	copy(buf, str, tocopy);
+	
+	return 0;
+}
+
+/*
+ * Append the string str to the end of the string buffer.
+ */
+
+int
+buf_cat(struct buf *buf, const char *str)
+{
+	return buf_ncat(buf, str, strlen(str));
+}
+
+/*
+ * Copy at most max character from str to string buffer.
+ */
+
+int
+buf_ncopy(struct buf *buf, const char *str, size_t max)
+{
+	buf_clear(buf);
+
+	return buf_ncat(buf, str, max);
+}
+
+/*
+ * Copy the string str to the string buffer.
+ */
+
+int
+buf_copy(struct buf *buf, const char *str)
+{
+	return buf_ncopy(buf, str, strlen(str));
+}
+
+/*
+ * Copy the printf(3) like call to the string buffer, this function
+ * returns -1 on fixed safe buffer, otherwise 0 is returned if there
+ * is no allocation failure.
+ */
+
+int
+buf_vprintf(struct buf *buf, const char *fmt, va_list ap)
+{
+	int copied, done = 0;
+
+	if (BUF_FIXED(buf) && BUF_SAFE(buf))
+		return -1;
+
+	buf_clear(buf);
+
+	do {
+		copied = vsnprintf(buf->text, buf->alsize, fmt, ap);
+
+		if (copied > BUF_AVAIL(buf)) {
+			if (BUF_FIXED(buf))
+				done = 1;
+
+			/*
+			 * vsnprintf returns -1 on windows, we need to grow
+			 * the buffer by block size.
+			 */
+			if (grow(buf, buf->alsize + buf->bsize) < 0)
+				return -1;
+		} else {
+			done = 1;
+		}
+	} while (!done);
+
+	return 0;
+}
+
+int
+buf_printf(struct buf *buf, const char *fmt, ...)
+{
+	va_list ap;
+	int rv;
+
+	va_start(ap, fmt);
+	rv = buf_vprintf(buf, fmt, ap);
+	va_end(ap);
+
+	return rv;
+}
+
+/*
+ * Clear the string buffer.
+ */
+
+void
+buf_clear(struct buf *buf)
+{
+	memset(buf->text, 0, buf->alsize);
+
+	buf->length = 0;
+}
+
+void
+buf_free(struct buf *buf)
+{
+	buf_clear(buf);
+
+	free(buf->text);
+	buf->text = NULL;
+}
+
+/*
+ * Valid options that can be set for a buffer :
+ * l -> optional buf block size of type int
+ * m -> malloc function that must matches void * (*malloc)(size_t)
+ * r -> realloc function that must matches void * (*realloc)(void *, size_t)
+ * f -> buffer flags that are OR'ed
+ */
+
+void
+buf_set(struct buf *buf, const char *fmt, ...)
+{
+	va_list ap;
+	const char *p;
+
+	va_start(ap, fmt);
+	for (p = fmt; *p != '\0'; ++p)
+		switch (*p) {
+		case 'l':
+			buf->bsize = va_arg(ap, int);
+			break;
+		case 'm':
+			buf->malloc = va_arg(ap, void *(*)(size_t));
+			break;
+		case 'r':
+			buf->realloc = va_arg(ap, void *(*)(void *, size_t));
+			break;
+		case 'f':
+		case 't':
+			buf->flags = va_arg(ap, int);
+			break;
+		default:
+			break;
+		}
+}
+
+/*
+ * Append to the end of buffer the void ptr of count size.
+ */
+
+static void
+copy(struct buf *buf, const void *ptr, size_t count)
+{
+	memcpy(buf->text + buf->length, ptr, count);
+
+	buf->text[buf->length + count] = '\0';
+	buf->length += count;
+}
+
+/*
+ * Grow the text buffer until the available size fit the needed
+ * size. This function may return -1 on allocation failure.
+ */
+
+static int
+grow(struct buf *buf, size_t needed)
+{
+	while (BUF_AVAIL(buf) <= needed) {
+		buf->text = buf->realloc(buf->text, buf->alsize + buf->bsize);
+	
+		if (buf->text == NULL)
+			return -1;
+
+		buf->alsize += buf->bsize;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buf.h	Wed Mar 07 09:51:01 2012 +0100
@@ -0,0 +1,63 @@
+/*
+ * buf.h -- easy way to manipulate strings
+ *
+ * Copyright (c) 2011, 2012, 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 _BUF_H_
+#define _BUF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#ifndef BUF_DEFAULT_BSIZE
+#define BUF_DEFAULT_BSIZE	128
+#endif
+
+enum {
+	BUF_AUTO	= 0,		/* string grows automatically */
+	BUF_FIXED	= (1 << 0),	/* fixed size string */
+	BUF_UNSAFE	= (1 << 1),	/* string may be truncated */
+};
+
+struct buf {
+	int		flags;	/* string flags */
+	char		*text;	/* string text */
+	size_t		length;	/* string length */
+	size_t		alsize;	/* allocated size */
+	int		bsize;	/* block size (used when growing array) */
+
+	/* Own allocation functions */
+	void * (*malloc)(size_t);
+	void * (*realloc)(void *, size_t);
+};
+
+int	buf_init(struct buf *);
+void	buf_set(struct buf *, const char *, ...);
+int	buf_ncat(struct buf *, const char *, size_t);
+int	buf_cat(struct buf *, const char *);
+int	buf_ncopy(struct buf *, const char *, size_t);
+int	buf_copy(struct buf *, const char *);
+void	buf_clear(struct buf *);
+void	buf_free(struct buf *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BUF_H_ */