summaryrefslogtreecommitdiffstats
path: root/bstr
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-30 20:20:28 +0100
committerwm4 <wm4@nowhere>2013-12-30 22:49:50 +0100
commit097fe8ea6fb25df68077c25c08f29fb57a9d2bd6 (patch)
tree2c25042f0484fbdcec73f0c815af14828d7f164c /bstr
parent56ce2a39be53be9b06ba815c56d768d0e45f3ac3 (diff)
downloadmpv-097fe8ea6fb25df68077c25c08f29fb57a9d2bd6.tar.bz2
mpv-097fe8ea6fb25df68077c25c08f29fb57a9d2bd6.tar.xz
bstr: add bstr_xappend function
Apparently this can be really useful when being paranoid and trying to avoid too much malloc/realloc, since it can be used to appending into a buffer (with transparent realloc only if the buffer is too small).
Diffstat (limited to 'bstr')
-rw-r--r--bstr/bstr.c51
-rw-r--r--bstr/bstr.h8
2 files changed, 59 insertions, 0 deletions
diff --git a/bstr/bstr.c b/bstr/bstr.c
index 65ae928d31..730b7474b8 100644
--- a/bstr/bstr.c
+++ b/bstr/bstr.c
@@ -356,6 +356,57 @@ struct bstr bstr_sanitize_utf8_latin1(void *talloc_ctx, struct bstr s)
return new;
}
+static void resize_append(void *talloc_ctx, bstr *s, size_t append_min)
+{
+ size_t size = talloc_get_size(s->start);
+ assert(s->len <= size);
+ if (append_min > size - s->len) {
+ if (append_min < size)
+ append_min = size; // preallocate in power of 2s
+ s->start = talloc_realloc_size(talloc_ctx, s->start, size + append_min);
+ }
+}
+
+// Append the string, so that *s = *s + append. s->start is expected to be
+// a talloc allocation (which can be realloced) or NULL.
+// This function will always implicitly append a \0 after the new string for
+// convenience.
+// talloc_ctx will be used as parent context, if s->start is NULL.
+void bstr_xappend(void *talloc_ctx, bstr *s, bstr append)
+{
+ resize_append(talloc_ctx, s, append.len + 1);
+ memcpy(s->start + s->len, append.start, append.len);
+ s->len += append.len;
+ s->start[s->len] = '\0';
+}
+
+void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ bstr_xappend_vasprintf(talloc_ctx, s, fmt, ap);
+ va_end(ap);
+}
+
+// Exactly as bstr_xappend(), but with a formatted string.
+void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt,
+ va_list ap)
+{
+ int size;
+ va_list copy;
+ va_copy(copy, ap);
+ char c;
+ size = vsnprintf(&c, 1, fmt, copy);
+ va_end(copy);
+
+ if (size < 0)
+ abort();
+
+ resize_append(talloc_ctx, s, size + 1);
+ vsnprintf(s->start + s->len, size + 1, fmt, ap);
+ s->len += size;
+}
+
bool bstr_case_startswith(struct bstr s, struct bstr prefix)
{
struct bstr start = bstr_splice(s, 0, prefix.len);
diff --git a/bstr/bstr.h b/bstr/bstr.h
index 67e85655c4..71d5d473c4 100644
--- a/bstr/bstr.h
+++ b/bstr/bstr.h
@@ -23,8 +23,10 @@
#include <stddef.h>
#include <string.h>
#include <stdbool.h>
+#include <stdarg.h>
#include "talloc.h"
+#include "compat/compiler.h"
/* NOTE: 'len' is size_t, but most string-handling functions below assume
* that input size has been sanity checked and len fits in an int.
@@ -118,6 +120,12 @@ struct bstr bstr_getline(struct bstr str, struct bstr *rest);
// and will remove the trailing \n or \r\n sequence.
struct bstr bstr_strip_linebreaks(struct bstr str);
+void bstr_xappend(void *talloc_ctx, bstr *s, bstr append);
+void bstr_xappend_asprintf(void *talloc_ctx, bstr *s, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(3, 4);
+void bstr_xappend_vasprintf(void *talloc_ctx, bstr *s, const char *fmt, va_list va)
+ PRINTF_ATTRIBUTE(3, 0);
+
// If s starts with prefix, return true and return the rest of the string in s.
bool bstr_eatstart(struct bstr *s, struct bstr prefix);