#include "k5buf-int.h"
#include <assert.h>
static int ensure_space(struct k5buf *buf, size_t len)
{
size_t new_space;
char *new_data;
if (buf->buftype == ERROR)
return 0;
if (buf->space - 1 - buf->len >= len)
return 1;
if (buf->buftype == FIXED)
goto error_exit;
assert(buf->buftype == DYNAMIC);
new_space = buf->space * 2;
while (new_space <= SPACE_MAX && new_space - buf->len - 1 < len)
new_space *= 2;
if (new_space > SPACE_MAX)
goto error_exit;
new_data = realloc(buf->data, new_space);
if (new_data == NULL)
goto error_exit;
buf->data = new_data;
buf->space = new_space;
return 1;
error_exit:
if (buf->buftype == DYNAMIC) {
free(buf->data);
buf->data = NULL;
}
buf->buftype = ERROR;
return 0;
}
void krb5int_buf_init_fixed(struct k5buf *buf, char *data, size_t space)
{
assert(space > 0);
buf->buftype = FIXED;
buf->data = data;
buf->space = space;
buf->len = 0;
buf->data[0] = '\0';
}
void krb5int_buf_init_dynamic(struct k5buf *buf)
{
buf->buftype = DYNAMIC;
buf->space = DYNAMIC_INITIAL_SIZE;
buf->data = malloc(buf->space);
if (buf->data == NULL) {
buf->buftype = ERROR;
return;
}
buf->len = 0;
buf->data[0] = '\0';
}
void krb5int_buf_add(struct k5buf *buf, const char *data)
{
krb5int_buf_add_len(buf, data, strlen(data));
}
void krb5int_buf_add_len(struct k5buf *buf, const char *data, size_t len)
{
if (!ensure_space(buf, len))
return;
memcpy(buf->data + buf->len, data, len);
buf->len += len;
buf->data[buf->len] = '\0';
}
void krb5int_buf_add_fmt(struct k5buf *buf, const char *fmt, ...)
{
va_list ap;
int r;
size_t remaining;
char *tmp;
if (buf->buftype == ERROR)
return;
remaining = buf->space - buf->len;
if (buf->buftype == FIXED) {
va_start(ap, fmt);
r = vsnprintf(buf->data + buf->len, remaining, fmt, ap);
va_end(ap);
if (SNPRINTF_OVERFLOW(r, remaining))
buf->buftype = ERROR;
else
buf->len += (unsigned int) r;
return;
}
assert(buf->buftype == DYNAMIC);
va_start(ap, fmt);
r = vsnprintf(buf->data + buf->len, remaining, fmt, ap);
va_end(ap);
if (!SNPRINTF_OVERFLOW(r, remaining)) {
buf->len += (unsigned int) r;
return;
}
if (r >= 0) {
if (!ensure_space(buf, r))
return;
remaining = buf->space - buf->len;
va_start(ap, fmt);
r = vsnprintf(buf->data + buf->len, remaining, fmt, ap);
va_end(ap);
if (SNPRINTF_OVERFLOW(r, remaining))
buf->buftype = ERROR;
else
buf->len += (unsigned int) r;
return;
}
va_start(ap, fmt);
r = vasprintf(&tmp, fmt, ap);
va_end(ap);
if (r < 0) {
buf->buftype = ERROR;
return;
}
if (ensure_space(buf, r)) {
memcpy(buf->data + buf->len, tmp, r + 1);
buf->len += r;
}
free(tmp);
}
void krb5int_buf_truncate(struct k5buf *buf, size_t len)
{
if (buf->buftype == ERROR)
return;
assert(len <= buf->len);
buf->len = len;
buf->data[buf->len] = '\0';
}
char *krb5int_buf_data(struct k5buf *buf)
{
return (buf->buftype == ERROR) ? NULL : buf->data;
}
ssize_t krb5int_buf_len(struct k5buf *buf)
{
return (buf->buftype == ERROR) ? -1 : (ssize_t) buf->len;
}
void krb5int_free_buf(struct k5buf *buf)
{
if (buf->buftype == ERROR)
return;
assert(buf->buftype == DYNAMIC);
free(buf->data);
buf->data = NULL;
buf->buftype = ERROR;
}