taisei/src/util/strbuf.c
2024-08-30 11:52:47 +02:00

94 lines
2.4 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "strbuf.h"
#include "util/miscmath.h"
#include <stdio.h>
int strbuf_printf(StringBuffer *strbuf, const char *format, ...) {
va_list va;
va_start(va, format);
int r = strbuf_vprintf(strbuf, format, va);
va_end(va);
return r;
}
static size_t strbuf_size_available(StringBuffer *strbuf) {
ptrdiff_t offset = strbuf->pos - strbuf->start;
assume_nolog(offset >= 0);
ptrdiff_t size_available = strbuf->buf_size - offset;
assume_nolog(size_available >= 0);
return size_available;
}
static size_t strbuf_reserve(StringBuffer *strbuf, size_t size_required) {
size_t size_available = strbuf_size_available(strbuf);
if(size_required >= size_available) {
ptrdiff_t offset = strbuf->pos - strbuf->start;
size_t new_size = topow2_u64(strbuf->buf_size + (size_required - size_available + 1));
strbuf->start = mem_realloc(strbuf->start, new_size);
strbuf->pos = strbuf->start + offset;
strbuf->buf_size = new_size;
size_available = new_size - offset;
}
return size_available;
}
int strbuf_vprintf(StringBuffer *strbuf, const char *format, va_list args) {
size_t size_available = strbuf_size_available(strbuf);
va_list args_copy;
va_copy(args_copy, args);
int size_required = vsnprintf(strbuf->pos, size_available, format, args_copy);
va_end(args_copy);
if(size_required >= size_available) {
size_available = strbuf_reserve(strbuf, size_required);
va_copy(args_copy, args);
size_required = vsnprintf(strbuf->pos, size_available, format, args_copy);
va_end(args_copy);
assume_nolog(size_required < size_available);
}
strbuf->pos += size_required;
assume_nolog(*strbuf->pos == 0);
return size_required;
}
int strbuf_ncat(StringBuffer *strbuf, size_t datasize, const char data[]) {
if(UNLIKELY(!datasize)) {
return 0;
}
assert(datasize < INT32_MAX);
strbuf_reserve(strbuf, datasize + 1);
assert_nolog(strbuf_size_available(strbuf) >= datasize + 1);
memcpy(strbuf->pos, data, datasize);
strbuf->pos += datasize;
*strbuf->pos = 0;
return datasize;
}
void strbuf_clear(StringBuffer *strbuf) {
strbuf->pos = strbuf->start;
if(strbuf->start) {
*strbuf->pos = 0;
}
}
void strbuf_free(StringBuffer *strbuf) {
mem_free(strbuf->start);
memset(strbuf, 0, sizeof(*strbuf));
}