diff options
| author | Vicent Martà <tanoku@gmail.com> | 2011-11-30 11:02:34 -0800 |
|---|---|---|
| committer | Vicent Martà <tanoku@gmail.com> | 2011-11-30 11:02:34 -0800 |
| commit | f5f048265800659aa6f495c05eb99e1b76a713e2 (patch) | |
| tree | 63fb56773ea31214c1107dfa33dbecceec2b4c1c /src/buffer.c | |
| parent | fc88a8d321541165b52d2cdb27753bab76870321 (diff) | |
| parent | 309113c984c1f3157659dc1174e5d4218f610ae4 (diff) | |
| download | libgit2-f5f048265800659aa6f495c05eb99e1b76a713e2.tar.gz | |
Merge pull request #503 from arrbee/git-buf-always-cstr
Make git_buf functions always maintain a valid cstr
Diffstat (limited to 'src/buffer.c')
| -rw-r--r-- | src/buffer.c | 118 |
1 files changed, 79 insertions, 39 deletions
diff --git a/src/buffer.c b/src/buffer.c index c56a75598..3dff813e3 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -8,13 +8,29 @@ #include "posix.h" #include <stdarg.h> +/* Used as default value for git_buf->ptr so that people can always + * assume ptr is non-NULL and zero terminated even for new git_bufs. + */ +char git_buf_initbuf[1]; + #define ENSURE_SIZE(b, d) \ if ((ssize_t)(d) > buf->asize && git_buf_grow(b, (d)) < GIT_SUCCESS)\ return; +void git_buf_init(git_buf *buf, size_t initial_size) +{ + buf->asize = 0; + buf->size = 0; + buf->ptr = git_buf_initbuf; + + if (initial_size) + git_buf_grow(buf, initial_size); +} + int git_buf_grow(git_buf *buf, size_t target_size) { char *new_ptr; + size_t new_size; if (buf->asize < 0) return GIT_ENOMEM; @@ -22,27 +38,56 @@ int git_buf_grow(git_buf *buf, size_t target_size) if (target_size <= (size_t)buf->asize) return GIT_SUCCESS; - if (buf->asize == 0) - buf->asize = target_size; + if (buf->asize == 0) { + new_size = target_size; + new_ptr = NULL; + } else { + new_size = (size_t)buf->asize; + new_ptr = buf->ptr; + } /* grow the buffer size by 1.5, until it's big enough * to fit our target size */ - while (buf->asize < (int)target_size) - buf->asize = (buf->asize << 1) - (buf->asize >> 1); + while (new_size < target_size) + new_size = (new_size << 1) - (new_size >> 1); /* round allocation up to multiple of 8 */ - buf->asize = (buf->asize + 7) & ~7; + new_size = (new_size + 7) & ~7; - new_ptr = git__realloc(buf->ptr, buf->asize); + new_ptr = git__realloc(new_ptr, new_size); if (!new_ptr) { buf->asize = -1; return GIT_ENOMEM; } - buf->ptr = new_ptr; + buf->asize = new_size; + buf->ptr = new_ptr; + + /* truncate the existing buffer size if necessary */ + if (buf->size >= buf->asize) + buf->size = buf->asize - 1; + buf->ptr[buf->size] = '\0'; + return GIT_SUCCESS; } +void git_buf_free(git_buf *buf) +{ + if (!buf) return; + + if (buf->ptr != git_buf_initbuf) + git__free(buf->ptr); + + git_buf_init(buf, 0); +} + +void git_buf_clear(git_buf *buf) +{ + buf->size = 0; + if (buf->asize > 0) + buf->ptr[0] = '\0'; +} + int git_buf_oom(const git_buf *buf) { return (buf->asize < 0); @@ -53,9 +98,10 @@ 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); + ENSURE_SIZE(buf, len + 1); memmove(buf->ptr, data, len); buf->size = len; + buf->ptr[buf->size] = '\0'; } } @@ -66,15 +112,17 @@ void git_buf_sets(git_buf *buf, const char *string) void git_buf_putc(git_buf *buf, char c) { - ENSURE_SIZE(buf, buf->size + 1); + ENSURE_SIZE(buf, buf->size + 2); buf->ptr[buf->size++] = c; + buf->ptr[buf->size] = '\0'; } void git_buf_put(git_buf *buf, const char *data, size_t len) { - ENSURE_SIZE(buf, buf->size + len); + ENSURE_SIZE(buf, buf->size + len + 1); memmove(buf->ptr + buf->size, data, len); buf->size += len; + buf->ptr[buf->size] = '\0'; } void git_buf_puts(git_buf *buf, const char *string) @@ -111,27 +159,25 @@ 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) - return NULL; - - buf->ptr[buf->size] = '\0'; return buf->ptr; } -void git_buf_free(git_buf *buf) +void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf) { - if (!buf) return; + size_t copylen; - git__free(buf->ptr); - buf->ptr = NULL; - buf->asize = 0; - buf->size = 0; -} + assert(data && datasize); -void git_buf_clear(git_buf *buf) -{ - buf->size = 0; + data[0] = '\0'; + + if (buf->size == 0 || buf->asize <= 0) + return; + + copylen = buf->size; + if (copylen > datasize - 1) + copylen = datasize - 1; + memmove(data, buf->ptr, copylen); + data[copylen] = '\0'; } void git_buf_consume(git_buf *buf, const char *end) @@ -140,6 +186,7 @@ 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; + buf->ptr[buf->size] = '\0'; } } @@ -152,21 +199,12 @@ void git_buf_swap(git_buf *buf_a, git_buf *buf_b) char *git_buf_take_cstr(git_buf *buf) { - char *data = NULL; - - if (buf->ptr == NULL) - return NULL; + char *data = buf->ptr; - if (buf->size + 1 > buf->asize && - git_buf_grow(buf, buf->size + 1) < GIT_SUCCESS) + if (buf->asize <= 0) return NULL; - data = buf->ptr; - data[buf->size] = '\0'; - - buf->ptr = NULL; - buf->asize = 0; - buf->size = 0; + git_buf_init(buf, 0); return data; } @@ -199,7 +237,7 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) } va_end(ap); - ENSURE_SIZE(buf, buf->size + total_size); + ENSURE_SIZE(buf, buf->size + total_size + 1); out = buf->ptr + buf->size; @@ -235,6 +273,7 @@ void git_buf_join_n(git_buf *buf, char separator, int nbuf, ...) /* set size based on num characters actually written */ buf->size = out - buf->ptr; + buf->ptr[buf->size] = '\0'; } void git_buf_join( @@ -277,7 +316,7 @@ void git_buf_join( if (!add_size) return; - ENSURE_SIZE(buf, buf->size + add_size); + ENSURE_SIZE(buf, buf->size + add_size + 1); /* concatenate strings */ ptr = buf->ptr + buf->size; @@ -296,4 +335,5 @@ void git_buf_join( /* set size based on num characters actually written */ buf->size = ptr - buf->ptr; + buf->ptr[buf->size] = '\0'; } |
