diff C/buf.c @ 186:d4b8416e9ab1

Move C
author David Demelier <markand@malikania.fr>
date Sat, 23 Nov 2013 16:14:05 +0100
parents buf.c@7f214f26a4c0
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C/buf.c	Sat Nov 23 16:14:05 2013 +0100
@@ -0,0 +1,268 @@
+/*
+ * 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)
+#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, const char *txt)
+{
+	/* Set defaults if needed */
+	buf->chksize	= (buf->chksize <= 0) ? 128 : buf->chksize;
+	buf->alsize	= buf->chksize + 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;
+
+	if (txt != NULL)
+		buf_cat(buf, txt);
+
+	memset(buf->text, 0, buf->alsize);
+
+	return 0;
+}
+
+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->chksize = 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;
+		}
+}
+
+/*
+ * 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) - 1;
+		}
+	}
+
+	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));
+}
+
+/*
+ * Append the caracter c to the end of buffer
+ */
+int
+buf_putc(struct buf *buf, int c)
+{
+	char str[2] = { c, '\0' };
+
+	return buf_ncat(buf, str, 1);
+}
+
+/*
+ * Concatenate 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, rv = 0, done = 0;
+
+	if (BUF_FIXED(buf) && BUF_SAFE(buf))
+		return -1;
+
+	do {
+		copied = vsnprintf(&buf->text[buf->length],
+		    BUF_AVAIL(buf), fmt, ap);
+
+		if (copied >= (signed int)BUF_AVAIL(buf) || copied == -1) {
+			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->chksize) < 0) {
+				done = 1;
+				rv = -1;
+			}
+		} else {
+			done = 1;
+		}
+	} while (!done);
+
+	buf->length = strlen(buf->text);
+
+	return rv;
+}
+
+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;
+}
+
+/*
+ * Realloc the string to it's size and remove useless bytes.
+ */
+int
+buf_trim(struct buf *buf)
+{
+	if ((buf->text = realloc(buf->text, buf->length + 1)) == NULL) {
+		buf->alsize = 0;
+		return -1;
+	}
+
+	buf->alsize = buf->length + 1;
+
+	return 0;
+}
+
+/*
+ * Remove `n' characters from the buffer, a positive value will cut the string
+ * from beginning, negative value will cut from end.
+ */
+void
+buf_cut(struct buf *buf, int start)
+{
+	if ((start > 0 && start >= buf->length) ||
+	    (start < 0 && (int)buf->length + start < 0))
+		return;
+
+	if (start < 0 && (int)buf->length + start >= 0)
+		start = buf->length + start;
+
+	buf->text[start]	= '\0';
+	buf->length		-= buf->length - start;
+}
+
+/*
+ * 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)
+{
+	if (buf != NULL) {
+		buf_clear(buf);
+		free(buf->text);
+
+		buf->text = NULL;
+		buf->alsize = 0;
+	}
+}
+
+/*
+ * 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->chksize);
+	
+		if (buf->text == NULL)
+			return -1;
+
+		buf->alsize += buf->chksize;
+	}
+
+	return 0;
+}