// retoor <retoor@molodetz.nl>
#include "string.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct string_t {
char *data;
size_t length;
size_t capacity;
};
static const size_t DEFAULT_CAPACITY = 32;
string_handle string_create(const char *str) {
if (!str) return string_create_empty();
return string_create_n(str, strlen(str));
}
string_handle string_create_empty(void) {
struct string_t *s = calloc(1, sizeof(struct string_t));
if (!s) return NULL;
s->data = malloc(DEFAULT_CAPACITY);
if (!s->data) {
free(s);
return NULL;
}
s->data[0] = '\0';
s->length = 0;
s->capacity = DEFAULT_CAPACITY;
return s;
}
string_handle string_create_n(const char *str, size_t len) {
if (!str) return string_create_empty();
if (len == 0) return string_create_empty();
struct string_t *s = malloc(sizeof(struct string_t));
if (!s) return NULL;
s->capacity = len + 1;
if (s->capacity < DEFAULT_CAPACITY) s->capacity = DEFAULT_CAPACITY;
s->data = malloc(s->capacity);
if (!s->data) {
free(s);
return NULL;
}
memcpy(s->data, str, len);
s->data[len] = '\0';
s->length = len;
return s;
}
string_handle string_format(const char *fmt, ...) {
if (!fmt) return string_create_empty();
va_list args, args_copy;
va_start(args, fmt);
va_copy(args_copy, args);
int len = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
if (len < 0) {
va_end(args);
return string_create_empty();
}
struct string_t *s = malloc(sizeof(struct string_t));
if (!s) {
va_end(args);
return NULL;
}
s->capacity = (size_t)len + 1;
s->data = malloc(s->capacity);
if (!s->data) {
free(s);
va_end(args);
return NULL;
}
vsnprintf(s->data, s->capacity, fmt, args);
s->length = (size_t)len;
va_end(args);
return s;
}
string_handle string_clone(const char *str) {
return string_create(str);
}
string_handle string_clone_handle(string_handle s) {
if (!s) return NULL;
return string_create_n(s->data, s->length);
}
string_handle string_concat(const char *a, const char *b) {
if (!a) return string_create(b);
if (!b) return string_create(a);
size_t len_a = strlen(a);
size_t len_b = strlen(b);
struct string_t *s = malloc(sizeof(struct string_t));
if (!s) return NULL;
s->length = len_a + len_b;
s->capacity = s->length + 1;
s->data = malloc(s->capacity);
if (!s->data) {
free(s);
return NULL;
}
memcpy(s->data, a, len_a);
memcpy(s->data + len_a, b, len_b);
s->data[s->length] = '\0';
return s;
}
string_handle string_concat_handle(string_handle a, const char *b) {
if (!a) return string_create(b);
if (!b) return string_clone_handle(a);
size_t len_b = strlen(b);
size_t new_len = a->length + len_b;
if (new_len + 1 > a->capacity) {
size_t new_capacity = a->capacity * 2;
while (new_capacity < new_len + 1) new_capacity *= 2;
char *new_data = realloc(a->data, new_capacity);
if (!new_data) return NULL;
a->data = new_data;
a->capacity = new_capacity;
}
memcpy(a->data + a->length, b, len_b);
a->length = new_len;
a->data[a->length] = '\0';
return a;
}
void string_append(string_handle s, const char *str) {
if (!s || !str) return;
string_append_n(s, str, strlen(str));
}
void string_append_n(string_handle s, const char *str, size_t len) {
if (!s || !str || len == 0) return;
if (s->length + len + 1 > s->capacity) {
size_t new_capacity = s->capacity;
while (new_capacity < s->length + len + 1) new_capacity *= 2;
char *new_data = realloc(s->data, new_capacity);
if (!new_data) return;
s->data = new_data;
s->capacity = new_capacity;
}
memcpy(s->data + s->length, str, len);
s->length += len;
s->data[s->length] = '\0';
}
void string_appendf(string_handle s, const char *fmt, ...) {
if (!s || !fmt) return;
va_list args;
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (len < 0) return;
if (s->length + (size_t)len + 1 > s->capacity) {
size_t new_capacity = s->capacity;
while (new_capacity < s->length + (size_t)len + 1) new_capacity *= 2;
char *new_data = realloc(s->data, new_capacity);
if (!new_data) return;
s->data = new_data;
s->capacity = new_capacity;
}
va_start(args, fmt);
vsnprintf(s->data + s->length, s->capacity - s->length, fmt, args);
s->length += (size_t)len;
va_end(args);
}
void string_append_handle(string_handle dest, string_handle src) {
if (!dest || !src) return;
string_append_n(dest, src->data, src->length);
}
size_t string_length(string_handle s) {
return s ? s->length : 0;
}
size_t string_capacity(string_handle s) {
return s ? s->capacity : 0;
}
const char *string_c_str(string_handle s) {
return s ? s->data : "";
}
char *string_release(string_handle s) {
if (!s) return NULL;
char *data = s->data;
free(s);
return data;
}
bool string_equals(string_handle a, string_handle b) {
if (!a && !b) return true;
if (!a || !b) return false;
if (a->length != b->length) return false;
return memcmp(a->data, b->data, a->length) == 0;
}
bool string_equals_c_str(string_handle s, const char *str) {
if (!s && !str) return true;
if (!s || !str) return false;
return strcmp(s->data, str) == 0;
}
bool string_is_empty(string_handle s) {
return !s || s->length == 0;
}
void string_clear(string_handle s) {
if (!s) return;
s->length = 0;
if (s->data) s->data[0] = '\0';
}
void string_destroy(string_handle s) {
if (!s) return;
if (s->data) free(s->data);
free(s);
}