diff options
author | Vicent Martà <tanoku@gmail.com> | 2011-11-29 01:39:52 -0800 |
---|---|---|
committer | Vicent Martà <tanoku@gmail.com> | 2011-11-29 01:39:52 -0800 |
commit | 798dd36c080af364a1405f155d6d3b7aceb5952d (patch) | |
tree | d43564395c937b26dc05c81611cdfc874e84160a /src/buffer.c | |
parent | 89886d0bbb7e4d3976a684b38151149bad152e39 (diff) | |
parent | 679b69c49df2d8c1b9d0d99f4f3a82a0c3975e4c (diff) | |
download | libgit2-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.c | 198 |
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; } |