summaryrefslogtreecommitdiff
path: root/src/buffer.c
diff options
context:
space:
mode:
authorVicent Martí <tanoku@gmail.com>2011-11-29 01:39:52 -0800
committerVicent Martí <tanoku@gmail.com>2011-11-29 01:39:52 -0800
commit798dd36c080af364a1405f155d6d3b7aceb5952d (patch)
treed43564395c937b26dc05c81611cdfc874e84160a /src/buffer.c
parent89886d0bbb7e4d3976a684b38151149bad152e39 (diff)
parent679b69c49df2d8c1b9d0d99f4f3a82a0c3975e4c (diff)
downloadlibgit2-798dd36c080af364a1405f155d6d3b7aceb5952d.tar.gz
Merge pull request #499 from arrbee/extend-git-buf
Extend git_buf with new utility functions and unit tests.
Diffstat (limited to 'src/buffer.c')
-rw-r--r--src/buffer.c198
1 files changed, 192 insertions, 6 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 1fb848e46..c56a75598 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -9,7 +9,7 @@
#include <stdarg.h>
#define ENSURE_SIZE(b, d) \
- if ((ssize_t)(d) >= buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\
+ if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\
return;
int git_buf_grow(git_buf *buf, size_t target_size)
@@ -19,6 +19,9 @@ int git_buf_grow(git_buf *buf, size_t target_size)
if (buf->asize < 0)
return GIT_ENOMEM;
+ if (target_size <= (size_t)buf->asize)
+ return GIT_SUCCESS;
+
if (buf->asize == 0)
buf->asize = target_size;
@@ -27,6 +30,9 @@ int git_buf_grow(git_buf *buf, size_t target_size)
while (buf->asize < (int)target_size)
buf->asize = (buf->asize << 1) - (buf->asize >> 1);
+ /* round allocation up to multiple of 8 */
+ buf->asize = (buf->asize + 7) & ~7;
+
new_ptr = git__realloc(buf->ptr, buf->asize);
if (!new_ptr) {
buf->asize = -1;
@@ -42,6 +48,22 @@ int git_buf_oom(const git_buf *buf)
return (buf->asize < 0);
}
+void git_buf_set(git_buf *buf, const char *data, size_t len)
+{
+ if (len == 0 || data == NULL) {
+ git_buf_clear(buf);
+ } else {
+ ENSURE_SIZE(buf, len);
+ memmove(buf->ptr, data, len);
+ buf->size = len;
+ }
+}
+
+void git_buf_sets(git_buf *buf, const char *string)
+{
+ git_buf_set(buf, string, string ? strlen(string) : 0);
+}
+
void git_buf_putc(git_buf *buf, char c)
{
ENSURE_SIZE(buf, buf->size + 1);
@@ -51,12 +73,13 @@ void git_buf_putc(git_buf *buf, char c)
void git_buf_put(git_buf *buf, const char *data, size_t len)
{
ENSURE_SIZE(buf, buf->size + len);
- memcpy(buf->ptr + buf->size, data, len);
+ memmove(buf->ptr + buf->size, data, len);
buf->size += len;
}
void git_buf_puts(git_buf *buf, const char *string)
{
+ assert(string);
git_buf_put(buf, string, strlen(string));
}
@@ -88,7 +111,8 @@ void git_buf_printf(git_buf *buf, const char *format, ...)
const char *git_buf_cstr(git_buf *buf)
{
- if (buf->size + 1 >= buf->asize && git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS)
+ if (buf->size + 1 > buf->asize &&
+ git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS)
return NULL;
buf->ptr[buf->size] = '\0';
@@ -97,7 +121,12 @@ const char *git_buf_cstr(git_buf *buf)
void git_buf_free(git_buf *buf)
{
+ if (!buf) return;
+
git__free(buf->ptr);
+ buf->ptr = NULL;
+ buf->asize = 0;
+ buf->size = 0;
}
void git_buf_clear(git_buf *buf)
@@ -107,7 +136,164 @@ void git_buf_clear(git_buf *buf)
void git_buf_consume(git_buf *buf, const char *end)
{
- size_t consumed = end - buf->ptr;
- memmove(buf->ptr, end, buf->size - consumed);
- buf->size -= consumed;
+ if (end > buf->ptr && end <= buf->ptr + buf->size) {
+ size_t consumed = end - buf->ptr;
+ memmove(buf->ptr, end, buf->size - consumed);
+ buf->size -= consumed;
+ }
+}
+
+void git_buf_swap(git_buf *buf_a, git_buf *buf_b)
+{
+ git_buf t = *buf_a;
+ *buf_a = *buf_b;
+ *buf_b = t;
+}
+
+char *git_buf_take_cstr(git_buf *buf)
+{
+ char *data = NULL;
+
+ if (buf->ptr == NULL)
+ return NULL;
+
+ if (buf->size + 1 > buf->asize &&
+ git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS)
+ return NULL;
+
+ data = buf->ptr;
+ data[buf->size] = '\0';
+
+ buf->ptr = NULL;
+ buf->asize = 0;
+ buf->size = 0;
+
+ return data;
+}
+
+void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
+{
+ /* Make two passes to avoid multiple reallocation */
+
+ va_list ap;
+ int i;
+ size_t total_size = 0;
+ char *out;
+
+ if (buf->size > 0 && buf->ptr[buf->size - 1] != separator)
+ ++total_size; /* space for initial separator */
+
+ va_start(ap, nbuf);
+ for (i = 0; i < nbuf; ++i) {
+ const char* segment;
+ size_t segment_len;
+
+ segment = va_arg(ap, const char *);
+ if (!segment)
+ continue;
+
+ segment_len = strlen(segment);
+ total_size += segment_len;
+ if (segment_len == 0 || segment[segment_len - 1] != separator)
+ ++total_size; /* space for separator */
+ }
+ va_end(ap);
+
+ ENSURE_SIZE(buf, buf->size + total_size);
+
+ out = buf->ptr + buf->size;
+
+ /* append separator to existing buf if needed */
+ if (buf->size > 0 && out[-1] != separator)
+ *out++ = separator;
+
+ va_start(ap, nbuf);
+ for (i = 0; i < nbuf; ++i) {
+ const char* segment;
+ size_t segment_len;
+
+ segment = va_arg(ap, const char *);
+ if (!segment)
+ continue;
+
+ /* skip leading separators */
+ if (out > buf->ptr && out[-1] == separator)
+ while (*segment == separator) segment++;
+
+ /* copy over next buffer */
+ segment_len = strlen(segment);
+ if (segment_len > 0) {
+ memmove(out, segment, segment_len);
+ out += segment_len;
+ }
+
+ /* append trailing separator (except for last item) */
+ if (i < nbuf - 1 && out > buf->ptr && out[-1] != separator)
+ *out++ = separator;
+ }
+ va_end(ap);
+
+ /* set size based on num characters actually written */
+ buf->size = out - buf->ptr;
+}
+
+void git_buf_join(
+ git_buf *buf,
+ char separator,
+ const char *str_a,
+ const char *str_b)
+{
+ size_t add_size = 0;
+ size_t sep_a = 0;
+ size_t strlen_a = 0;
+ size_t sep_b = 0;
+ size_t strlen_b = 0;
+ char *ptr;
+
+ /* calculate string lengths and need for added separators */
+ if (str_a) {
+ while (*str_a == separator) { sep_a = 1; str_a++; }
+ strlen_a = strlen(str_a);
+ }
+ if (str_b) {
+ while (*str_b == separator) { sep_b = 1; str_b++; }
+ strlen_b = strlen(str_b);
+ }
+ if (buf->size > 0) {
+ if (buf->ptr[buf->size - 1] == separator) {
+ sep_a = 0;
+ if (!strlen_a) sep_b = 0;
+ } else if (!strlen_a)
+ sep_b = (str_b != NULL);
+ }
+ if (strlen_a > 0) {
+ if (str_a[strlen_a - 1] == separator)
+ sep_b = 0;
+ else if (str_b)
+ sep_b = 1;
+ }
+
+ add_size = sep_a + strlen_a + sep_b + strlen_b;
+
+ if (!add_size) return;
+
+ ENSURE_SIZE(buf, buf->size + add_size);
+
+ /* concatenate strings */
+ ptr = buf->ptr + buf->size;
+ if (sep_a)
+ *ptr++ = separator;
+ if (strlen_a) {
+ memmove(ptr, str_a, strlen_a);
+ ptr += strlen_a;
+ }
+ if (sep_b)
+ *ptr++ = separator;
+ if (strlen_b) {
+ memmove(ptr, str_b, strlen_b);
+ ptr += strlen_b;
+ }
+
+ /* set size based on num characters actually written */
+ buf->size = ptr - buf->ptr;
}