From 097fe8ea6fb25df68077c25c08f29fb57a9d2bd6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 30 Dec 2013 20:20:28 +0100 Subject: 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). --- bstr/bstr.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ bstr/bstr.h | 8 ++++++++ 2 files changed, 59 insertions(+) (limited to 'bstr') 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 #include #include +#include #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); -- cgit v1.2.3