mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-05 14:24:27 +00:00
Make initial value of git_buf ptr always be a valid empty string.
Taking a page from core git's strbuf, this introduces git_buf_initbuf which is an empty string that is used to initialize the git_buf ptr value even for new buffers. Now the git_buf ptr will always point to a valid NUL-terminated string. This change required jumping through a few hoops for git_buf_grow and git_buf_free to distinguish between a actual allocated buffer and the global initial value. Also, this moves the allocation related functions to be next to each other near the top of buffer.c.
This commit is contained in:
parent
7df41387f5
commit
309113c984
90
src/buffer.c
90
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);
|
||||
@ -114,7 +159,7 @@ void git_buf_printf(git_buf *buf, const char *format, ...)
|
||||
|
||||
const char *git_buf_cstr(git_buf *buf)
|
||||
{
|
||||
return buf->ptr ? buf->ptr : "";
|
||||
return buf->ptr;
|
||||
}
|
||||
|
||||
void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf)
|
||||
@ -135,23 +180,6 @@ void git_buf_copy_cstr(char *data, size_t datasize, git_buf *buf)
|
||||
data[copylen] = '\0';
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
buf->size = 0;
|
||||
if (buf->ptr)
|
||||
*buf->ptr = '\0';
|
||||
}
|
||||
|
||||
void git_buf_consume(git_buf *buf, const char *end)
|
||||
{
|
||||
if (end > buf->ptr && end <= buf->ptr + buf->size) {
|
||||
@ -171,18 +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;
|
||||
char *data = buf->ptr;
|
||||
|
||||
if (buf->ptr == NULL)
|
||||
if (buf->asize <= 0)
|
||||
return NULL;
|
||||
|
||||
assert(buf->asize > buf->size);
|
||||
|
||||
data = buf->ptr;
|
||||
|
||||
buf->ptr = NULL;
|
||||
buf->asize = 0;
|
||||
buf->size = 0;
|
||||
git_buf_init(buf, 0);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -14,8 +14,11 @@ typedef struct {
|
||||
ssize_t asize, size;
|
||||
} git_buf;
|
||||
|
||||
#define GIT_BUF_INIT {NULL, 0, 0}
|
||||
extern char git_buf_initbuf[];
|
||||
|
||||
#define GIT_BUF_INIT { git_buf_initbuf, 0, 0 }
|
||||
|
||||
void git_buf_init(git_buf *buf, size_t initial_size);
|
||||
int git_buf_grow(git_buf *buf, size_t target_size);
|
||||
void git_buf_free(git_buf *buf);
|
||||
void git_buf_swap(git_buf *buf_a, git_buf *buf_b);
|
||||
|
@ -224,10 +224,7 @@ check_buf_append(
|
||||
cl_assert(git_buf_oom(&tgt) == 0);
|
||||
git_buf_puts(&tgt, data_b);
|
||||
cl_assert(git_buf_oom(&tgt) == 0);
|
||||
if (expected_data == NULL)
|
||||
cl_assert(tgt.ptr == NULL);
|
||||
else
|
||||
cl_assert_strequal(expected_data, git_buf_cstr(&tgt));
|
||||
cl_assert_strequal(expected_data, git_buf_cstr(&tgt));
|
||||
cl_assert(tgt.size == expected_size);
|
||||
if (expected_asize > 0)
|
||||
cl_assert(tgt.asize == expected_asize);
|
||||
@ -356,13 +353,13 @@ void test_core_buffer__7(void)
|
||||
b = git_buf_take_cstr(&a);
|
||||
|
||||
cl_assert_strequal("foo", b);
|
||||
cl_assert_strequal(NULL, a.ptr);
|
||||
cl_assert_strequal("", a.ptr);
|
||||
git__free(b);
|
||||
|
||||
b = git_buf_take_cstr(&a);
|
||||
|
||||
cl_assert_strequal(NULL, b);
|
||||
cl_assert_strequal(NULL, a.ptr);
|
||||
cl_assert_strequal("", a.ptr);
|
||||
|
||||
git_buf_free(&a);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user