[misc] Add VirBuffer as dynamic string building facility.
authorMatthias Bolte <matthias.bolte@googlemail.com>
Sat, 20 Jun 2009 17:52:07 +0000 (19:52 +0200)
committerMatthias Bolte <matthias.bolte@googlemail.com>
Sat, 20 Jun 2009 17:52:07 +0000 (19:52 +0200)
Signed-off-by: Matthias Bolte <matthias.bolte@googlemail.com>

include/libvscmisc/Makefile
include/libvscmisc/buffer.h [new file with mode: 0644]
include/libvscmisc/types.h
misc/Makefile
misc/buffer.c [new file with mode: 0644]

index 26fa9d8..61246a3 100644 (file)
@@ -7,8 +7,8 @@
 
 include ../../config.mk
 
-HEADERS  = assert.h debug.h error.h filesystem.h libvscmisc.h list.h memory.h \
-           string.h types.h
+HEADERS  = assert.h buffer.h debug.h error.h filesystem.h libvscmisc.h list.h \
+           memory.h string.h types.h
 TARGET   = libvscmisc
 
 #
diff --git a/include/libvscmisc/buffer.h b/include/libvscmisc/buffer.h
new file mode 100644 (file)
index 0000000..3a7fd2b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * buffer.h: Library of miscellaneous stuff for other libvsc* libraries
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+/*!
+ * @file
+ */
+
+#ifndef __VSC_MISC__BUFFER_H__
+#define __VSC_MISC__BUFFER_H__
+
+#include "types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+vsc_buffer_init (struct VscBuffer *buffer);
+
+void
+vsc_buffer_append (struct VscBuffer *buffer, const char *string);
+
+void
+vsc_buffer_sprintf (struct VscBuffer *buffer, const char *format, ...);
+
+char *
+vsc_buffer_take (struct VscBuffer *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VSC_MISC__BUFFER_H__ */
index 591bb6c..8d7891b 100644 (file)
@@ -93,6 +93,13 @@ typedef struct VscList * (*VscList_CloneFunction) (struct VscError *error,
 typedef int (*VscList_MatchFunction) (struct VscList *item, void *match_data);
 typedef int (*VscList_FreeFunction) (struct VscList **item);
 
+struct VscBuffer {
+       char *content;
+       size_t allocated;
+       size_t used;
+       int error; // out-of-memory condition
+};
+
 #ifdef __cplusplus
 }
 #endif
index 1a3d9a7..6122573 100644 (file)
@@ -7,7 +7,8 @@
 
 include ../config.mk
 
-OBJS     = assert.o debug.o error.o filesystem.o list.o memory.o string.o
+OBJS     = assert.o buffer.o debug.o error.o filesystem.o list.o memory.o \
+           string.o
 TARGET   = libvscmisc.so
 
 #
diff --git a/misc/buffer.c b/misc/buffer.c
new file mode 100644 (file)
index 0000000..aeb2799
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * buffer.c: Library of miscellaneous stuff for other libvsc* libraries
+ *
+ * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "../include/libvscmisc/assert.h"
+#include "../include/libvscmisc/buffer.h"
+#include "../include/libvscmisc/memory.h"
+
+static int
+_grow (struct VscBuffer *buffer, size_t length)
+{
+       size_t total;
+       char *content;
+
+       VSC__ASSERT (buffer != NULL);
+
+       if (buffer->error) {
+               return -1;
+       }
+
+       if ((length + buffer->used) < buffer->allocated) {
+               return 0;
+       }
+
+       total = buffer->used + length + 512 - (length % 512);
+       content = realloc (buffer->content, total);
+
+       if (content == NULL) {
+               vsc_free (&buffer->content);
+
+               buffer->allocated = 0;
+               buffer->used = 0;
+               buffer->error = TRUE;
+
+               return -1;
+       } else {
+               buffer->content = content;
+               buffer->allocated = total;
+
+               return 0;
+       }
+}
+
+void
+vsc_buffer_init (struct VscBuffer *buffer)
+{
+       VSC__ASSERT (buffer != NULL);
+
+       buffer->content = NULL;
+       buffer->allocated = 0;
+       buffer->used = 0;
+       buffer->error = FALSE;
+}
+
+void
+vsc_buffer_append (struct VscBuffer *buffer, const char *string)
+{
+       size_t length;
+       size_t total;
+
+       VSC__ASSERT (buffer != NULL);
+       VSC__ASSERT (string != NULL);
+
+       if (buffer->error) {
+               return;
+       }
+
+       length = strlen (string);
+       total = buffer->used + length + 2;
+
+       if (total > buffer->allocated) {
+               if (_grow (buffer, total - buffer->used) < 0) {
+                       return;
+               }
+       }
+
+       memcpy (&buffer->content[buffer->used], string, length);
+
+       buffer->used += length;
+       buffer->content[buffer->used] = '\0';
+}
+
+void
+vsc_buffer_sprintf (struct VscBuffer *buffer, const char *format, ...)
+{
+       size_t unused;
+       int length;
+       va_list args, tmp;
+
+       VSC__ASSERT (buffer != NULL);
+       VSC__ASSERT (format != NULL);
+
+       if (buffer->error) {
+               return;
+       }
+
+       if (buffer->allocated == 0) {
+               if (_grow (buffer, 512) < 0) {
+                       return;
+               }
+       }
+
+       unused = buffer->allocated - buffer->used - 1;
+
+       va_start (args, format);
+       va_copy (tmp, args);
+
+       while ((length = vsnprintf (&buffer->content[buffer->used], unused,
+                                   format, tmp)) < 0 ||
+              (size_t) length >= unused - 1) {
+               buffer->content[buffer->used] = '\0';
+
+               va_end (tmp);
+
+               if (_grow (buffer, length) < 0) {
+                       return;
+               }
+
+               unused = buffer->allocated - buffer->used - 1;
+
+               va_copy (tmp, args);
+       }
+
+       va_end (tmp);
+
+       buffer->used += length;
+       buffer->content[buffer->used] = '\0';
+}
+
+char *
+vsc_buffer_take (struct VscBuffer *buffer)
+{
+       char *content = NULL;
+
+       if (buffer->error) {
+               return NULL;
+       }
+
+       content = buffer->content;
+
+       memset (buffer, 0, sizeof (struct VscBuffer));
+
+       return content;
+}