src/utils_strbuf.[ch]: Add string buffer utility.
[collectd.git] / src / utils_strbuf.c
diff --git a/src/utils_strbuf.c b/src/utils_strbuf.c
new file mode 100644 (file)
index 0000000..408c4ef
--- /dev/null
@@ -0,0 +1,120 @@
+/**
+ * collectd - src/utils_strbuf.c
+ * Copyright (C) 2018  Florian Forster
+ *
+ * MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Florian Forster <octo at collectd.org>
+ **/
+
+#include "utils_strbuf.h"
+#include "collectd.h"
+
+#include <stdarg.h>
+
+strbuf_t *strbuf_create(size_t sz) /* {{{ */
+{
+  strbuf_t *buf;
+
+  buf = malloc(sizeof(*buf));
+  if (buf == NULL)
+    return NULL;
+  memset(buf, 0, sizeof(*buf));
+
+  buf->buffer = malloc(sz);
+  if (buf->buffer == NULL) {
+    free(buf);
+    return NULL;
+  }
+  memset(buf->buffer, 0, sz);
+
+  buf->free = sz;
+  buf->used = 0;
+
+  return buf;
+} /* }}} int strbuf_t *strbuf_create */
+
+void strbuf_destroy(strbuf_t *buf) /* {{{ */
+{
+  if (buf == NULL)
+    return;
+
+  free(buf->buffer);
+  free(buf);
+} /* }}} void strbuf_destroy */
+
+void strbuf_reset(strbuf_t *buf) /* {{{ */
+{
+  buf->free += buf->used;
+  buf->used = 0;
+  buf->buffer[0] = 0;
+} /* }}} void strbuf_reset */
+
+int strbuf_add(strbuf_t *buf, char const *str) /* {{{ */
+{
+  char *base = buf->buffer + buf->used;
+  size_t len = strlen(str);
+
+  if (len >= buf->free)
+    return ENOMEM;
+
+  /* len+1 so copied memory includes the trailing nil. */
+  memcpy(base, str, len + 1);
+  buf->free -= len;
+  buf->used += len;
+
+  assert(buf->buffer[buf->used] == 0);
+
+  return 0;
+} /* }}} int strbuf_add */
+
+__attribute__((format(printf, 2, 3))) int
+strbuf_addf(strbuf_t *buf, char const *format, ...) /* {{{ */
+{
+  va_list ap;
+  char *base = buf->buffer + buf->used;
+  int status;
+  size_t len;
+
+  va_start(ap, format);
+  status = vsnprintf(base, buf->free, format, ap);
+  va_end(ap);
+
+  if (status < 0)
+    return status;
+
+  len = (size_t)status;
+  if (len >= buf->free) /* truncated */
+  {
+    base[0] = 0; /* make sure buffer appears unmodified. */
+    return ENOMEM;
+  }
+
+  buf->free -= len;
+  buf->used += len;
+
+  assert(buf->buffer[buf->used] == 0);
+
+  return 0;
+} /* }}} int strbuf_addf */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */