Files
libucore/src/dstr.c
T
Nils O. Selåsdal 9416c58457 Check snprintf for -1
2015-11-25 09:40:21 +01:00

304 lines
5.5 KiB
C

#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include "ucore/dstr.h"
#include "ucore/utils.h"
void uc_dstr_init(struct DStr *str)
{
str->len = 0;
str->allocated = 0;
str->str = NULL;
}
int uc_dstr_init_str(struct DStr *str, const char *init)
{
uc_dstr_init(str);
return uc_dstr_append_str(str, init);
}
int uc_dstr_init_str_sz(struct DStr *str, const char *init, size_t len)
{
uc_dstr_init(str);
return uc_dstr_append_str_sz(str, init, len);
}
void uc_dstr_destroy(struct DStr *str)
{
#ifdef DEBUG
if (str->str) {
memset(str->str, 0xcc, str->allocated);
}
str->len = -1;
str->allocated = -1;
#endif
free(str->str);
}
int uc_dstr_copy(struct DStr *dest, const struct DStr *src)
{
char *s;
uc_dstr_init(dest);
if (src->allocated == 0) {
return 0;
}
s = uc_dstr_put(dest, src->len);
if (s == NULL) {
return -1;
}
//+1 to copy a potential nul terminator, uc_dstr_put
//guarantees we have room for it.
memcpy(s, src->str, UC_MIN(src->len + 1, src->allocated));
return 0;
}
size_t uc_dstr_available(const struct DStr *str)
{
return str->allocated - str->len;
}
int uc_dstr_ensure(struct DStr *str, size_t total)
{
if (str->allocated < total) {
//allocate a minimum no. of bytes, and one
//additional for the common case of nul terminating
//the string
size_t new_len = UC_MAX(7U, total) + 1;
char *new_str = realloc(str->str, new_len);
if (new_str == NULL) {
return -1;
}
str->str = new_str;
str->allocated = new_len;
}
return 0;
}
void uc_dstr_reset(struct DStr *str)
{
str->len = 0;
#ifdef DEBUG
if (str->str) {
memset(str->str, 0xcc, str->allocated);
}
#endif
}
void uc_dstr_terminate(struct DStr *str)
{
uc_dstr_ensure(str, str->len + 1);
str->str[str->len] = 0;
}
char *uc_dstr_str(struct DStr *str)
{
uc_dstr_terminate(str);
return str->str;
}
char *uc_dstr_put(struct DStr *str, size_t len)
{
char *start;
if (uc_dstr_ensure(str, str->len + len) != 0) {
return NULL;
}
start = str->str + str->len;
str->len += len;
return start;
}
size_t uc_dstr_append_str_filter(struct DStr *str, const char *restrict s, int (*is_x)(int c))
{
size_t len = strlen(s);
size_t i;
size_t idx = 0;
if (uc_dstr_ensure(str, str->len + len) != 0) {
return 0;
}
for (i = 0; i < len; i++) {
if (is_x(s[i])) {
str->str[str->len + idx]= s[i];
idx++;
}
}
str->len += idx;
return idx;
}
int uc_dstr_append_str_sz(struct DStr *str, const char *restrict s, size_t len)
{
char *start = uc_dstr_put(str, len);
if (start == NULL) {
return -1;
}
memcpy(start, s, len);
return 0;
}
int uc_dstr_append_str(struct DStr *str, const char *restrict s)
{
size_t len = strlen(s);
return uc_dstr_append_str_sz(str, s ,len);
}
int uc_dstr_append_char(struct DStr *str, char c)
{
char *start = uc_dstr_put(str, 1);
if (start == NULL) {
return -1;
}
*start = c;
return 0;
}
void uc_dstr_own(struct DStr *str, char *restrict s)
{
size_t len = strlen(s);
if (str->str) {
free(str->str);
}
str->len = len;
str->allocated = len + 1;
str->str = s;
}
char *uc_dstr_steal(struct DStr *str)
{
char *s = str->str;
uc_dstr_init(str);
return s;
}
void uc_str_swap(struct DStr *restrict a, struct DStr *restrict b)
{
struct DStr tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
size_t uc_dstr_replace(struct DStr *str, char f, char r)
{
size_t i;
size_t count = 0;
if (str->len == 0) {
return 0;
}
for (i = 0; i < str->len; i++) {
if (str->str[i] == f) {
str->str[i] = r;
count++;
}
}
return count;
}
void uc_dstr_trim(struct DStr *str)
{
size_t spaces;
static const char whitespace[] = " \t\n\v\f\r";
uc_dstr_terminate(str);
//spaces at the start
spaces = strspn(str->str, whitespace);
if (spaces > 0) {
memmove(str->str, str->str + spaces, str->len - spaces);
str->len -= spaces;
}
//spaces at the end
if (str->len > 0) {
size_t idx = str->len - 1;
do {
if (strchr(whitespace, str->str[idx]) == NULL) {
break;
} else {
str->len--;
idx--;
}
} while (idx != 0);
}
}
int uc_dstr_sprintf(struct DStr *str, const char *restrict fmt, ...)
{
va_list ap;
int rc;
va_start(ap, fmt);
rc = uc_dstr_vsprintf(str, fmt, ap);
va_end(ap);
return rc;
}
int uc_dstr_vsprintf(struct DStr *str, const char *restrict fmt, va_list ap_)
{
va_list ap;
int rc;
int available;
int needed;
rc = uc_dstr_ensure(str, str->len + 1);
if (rc != 0) {
return -1;
}
available = uc_dstr_available(str);
va_copy(ap, ap_);
needed = vsnprintf(str->str + str->len, available, fmt, ap);
va_end(ap);
if (needed < 0) {
return needed;
}
if (needed >= available) {
rc = uc_dstr_ensure(str, str->len + needed + 1);
if (rc != 0) {
return -1;
}
available = uc_dstr_available(str);
va_copy(ap, ap_);
needed = vsnprintf(str->str + str->len, available, fmt, ap);
va_end(ap);
}
str->len += needed;
return needed;
}