about summary refs log tree commit diff stats
path: root/wrapperhelper/src/cstring.c
diff options
context:
space:
mode:
Diffstat (limited to 'wrapperhelper/src/cstring.c')
-rw-r--r--wrapperhelper/src/cstring.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/wrapperhelper/src/cstring.c b/wrapperhelper/src/cstring.c
new file mode 100644
index 00000000..b38a43e6
--- /dev/null
+++ b/wrapperhelper/src/cstring.c
@@ -0,0 +1,115 @@
+#include "cstring.h"
+
+#include <string.h>
+
+#define STRING_MIN_CAP 8
+
+string_t *string_new(void) {
+	string_t *ret = malloc(sizeof(*ret));
+	if (!ret) return NULL;
+	char *buf = malloc(sizeof(char));
+	if (!buf) {
+		free(ret);
+		return NULL;
+	}
+	buf[0] = '\0';
+	ret->ssize = ret->scap = 0; ret->buf = buf;
+	return ret;
+}
+
+string_t *string_new_cap(size_t cap) {
+	string_t *ret = malloc(sizeof(*ret));
+	if (!ret) return NULL;
+	cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
+	ret->buf = malloc((cap + 1) * sizeof(char));
+	if (!ret->buf) {
+		free(ret);
+		return NULL;
+	}
+	ret->buf[0] = '\0';
+	ret->scap = cap;
+	ret->ssize = 0;
+	return ret;
+}
+
+int string_reserve(string_t *s, size_t cap) {
+	size_t new_cap = (cap < STRING_MIN_CAP) ? STRING_MIN_CAP : cap;
+	if (new_cap <= s->scap) return 1;
+	
+	void *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
+	if (!new_buf) return 0;
+	s->buf = new_buf;
+	s->scap = new_cap;
+	return 1;
+}
+
+void string_del(string_t *s) {
+	if (s->buf) free(s->buf);
+	free(s);
+}
+
+char *string_steal(string_t *s) {
+	char *ret = s->buf;
+	free(s);
+	return ret;
+}
+
+int string_add_char(string_t *s, char elem) {
+	if (s->ssize >= s->scap) {
+		size_t new_cap = (s->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap * 2;
+		char *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
+		if (!new_buf) return 0;
+		s->buf = new_buf;
+		s->scap = new_cap;
+	}
+	s->buf[s->ssize++] = elem;
+	s->buf[s->ssize] = '\0';
+	return 1;
+}
+
+int string_add_string(string_t *s1, string_t *s2) {
+	if (s1->ssize + s2->ssize > s1->scap) {
+		size_t new_cap = (s1->scap < STRING_MIN_CAP) ? STRING_MIN_CAP : s1->scap * 2;
+		while (s1->ssize + s2->ssize > new_cap) {
+			new_cap = new_cap * 2;
+		}
+		char *new_buf = realloc(s1->buf, sizeof(char) * (new_cap + 1));
+		if (!new_buf) return 0;
+		s1->buf = new_buf;
+		s1->scap = new_cap;
+	}
+	memcpy(s1->buf + s1->ssize, s2->buf, s2->ssize);
+	s1->ssize += s2->ssize;
+	s1->buf[s1->ssize] = '\0';
+	return 1;
+}
+
+void string_pop(string_t *s) {
+	if (!s->ssize) return;
+	s->buf[--s->ssize] = '\0';
+	if (s->ssize < s->scap / 4) {
+		size_t new_cap = (s->scap / 2 < STRING_MIN_CAP) ? STRING_MIN_CAP : s->scap / 2;
+		if (new_cap == s->scap) return;
+		void *new_buf = realloc(s->buf, sizeof(char) * (new_cap + 1));
+		if (!new_buf) return; // We don't really care if the realloc fails, we just need to not update anything
+		s->buf = new_buf;
+		s->scap = new_cap;
+	}
+}
+
+string_t *string_dup(string_t const *s) {
+	string_t *ret = string_new_cap(s->ssize);
+	if (!ret) return NULL;
+	memcpy(ret->buf, s->buf, s->ssize + 1);
+	ret->ssize = s->ssize;
+	return ret;
+}
+
+string_t *string_concat(string_t const *l, string_t const *r) {
+	string_t *ret = string_new_cap(l->ssize + r->ssize);
+	if (!ret) return NULL;
+	memcpy(ret->buf, l->buf, l->ssize);
+	memcpy(ret->buf + l->ssize, r->buf, r->ssize);
+	ret->buf[ret->ssize] = '\0';
+	return ret;
+}