summaryrefslogtreecommitdiff
path: root/src/buffer.c
diff options
context:
space:
mode:
authorVicent Martí <tanoku@gmail.com>2011-11-30 11:02:34 -0800
committerVicent Martí <tanoku@gmail.com>2011-11-30 11:02:34 -0800
commitf5f048265800659aa6f495c05eb99e1b76a713e2 (patch)
tree63fb56773ea31214c1107dfa33dbecceec2b4c1c /src/buffer.c
parentfc88a8d321541165b52d2cdb27753bab76870321 (diff)
parent309113c984c1f3157659dc1174e5d4218f610ae4 (diff)
downloadlibgit2-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.c118
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';
}