about summary refs log tree commit diff stats
path: root/wrapperhelper/src/cstring.c
blob: b38a43e6262ee0e3c5546bc6cb3dd68539cead79 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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;
}