Repository navigation
Expand file tree
/
Copy pathstring.cpp
More file actions
240 lines (208 loc) · 5.83 KB
/
Copy pathstring.cpp
File metadata and controls
240 lines (208 loc) · 5.83 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include <assert.h>
#include "string.h"
// Header size in bytes (4 for bufsize, 4 for string length)
#define HEADER_SIZE 8
#define NUL_SIZE 1
// How many bytes to overgrow the buffer with when it needs to expand.
// The current value choosen completely arbitrarily.
#define BUFFER_OVERGROW 64
// NOTE(christoffer) See note about casting to void * in string.h
#define _get_bufsize(str) (*((u32*)((void*)(str - HEADER_SIZE))))
#define _set_bufsize(str, bufsize) (*((u32*)(void*)((str - HEADER_SIZE))) = bufsize)
/**
* A String implementation where the buffer size and the string length are prepended to the
* content buffer.
*
* These functions all return a pointer to the content, so that it can be used with any
* other function that expects a cstring.
*
* [ buffer_size (4 bytes) ][ string length (4 bytes) ][ content (buffer_size bytes)
* ^ pointer returned to caller
*/
u32 cstrlen(const char* cstr)
{
u32 nul_offset = 0;
while (*(cstr + nul_offset++))
;
return nul_offset - 1;
}
void cstrcpy(char* dest, const char* src)
{
while ((*(dest++) = *(src++)))
;
}
void cstrcat(char* dest, const char* src)
{
while (*(dest++))
; // seek to %nul
dest--; // backtrack to overwrite the %nul
while ((*(dest++) = *(src++)))
; // copy until (including) src %nul
}
String
string_new()
{
u32 bufsize = HEADER_SIZE + NUL_SIZE;
char* buf = ALLOC(char, bufsize);
assert(buf);
String string = (String)(buf + HEADER_SIZE);
_set_bufsize(string, bufsize);
string_clear(string);
return string;
}
String
string_new(const char* content)
{
u32 content_len = cstrlen(content);
u32 req_bufsize = HEADER_SIZE + content_len + NUL_SIZE;
char* buf = ALLOC(char, req_bufsize);
assert(buf);
String string = (String)(buf + HEADER_SIZE);
cstrcpy(string, content);
*(string + content_len) = '\0';
_set_bufsize(string, req_bufsize);
set_string_len(string, content_len);
return string;
}
void string_clear(String string)
{
set_string_len(string, 0);
*string = '\0';
}
void string_free(String string)
{
if (string) {
char* bufptr = ((char*)string) - HEADER_SIZE;
free(bufptr);
}
}
String
string_resizebuf(String string, u32 new_bufsize)
{
char* bufptr = string - HEADER_SIZE;
u32 cur_bufsize = _get_bufsize(string);
if (new_bufsize == cur_bufsize) {
// Optimization, noop if we don't need resize
return string;
}
// Resize buffer and write the new buffer size
bufptr = (char*)realloc(bufptr, new_bufsize);
assert(bufptr);
string = bufptr + HEADER_SIZE;
_set_bufsize(string, new_bufsize);
// If we shrunk the buffer, make sure that it ends with a %nul and that the new length is corrected
if (new_bufsize < cur_bufsize) {
u32 new_len = new_bufsize - HEADER_SIZE - NUL_SIZE;
*(string + new_len) = '\0';
set_string_len(string, new_len);
}
return string;
}
String
string_ensure_fits_len(String string, u32 at_least_length)
{
u32 curlen = string_len(string);
if (curlen < at_least_length) {
u32 req_bufsize = at_least_length + HEADER_SIZE + NUL_SIZE;
string = string_resizebuf(string, req_bufsize + BUFFER_OVERGROW);
}
return string;
}
String
string_append(String string, const char* content)
{
u32 cur_len = string_len(string);
u32 new_len = cur_len + cstrlen(content);
string = string_ensure_fits_len(string, new_len);
cstrcat(string, content);
*(string + new_len) = '\0';
set_string_len(string, new_len);
return string;
}
String
string_append(String string, const char chr)
{
u32 cur_len = string_len(string);
u32 new_len = cur_len + 1;
string = string_ensure_fits_len(string, new_len);
string[cur_len] = chr;
string[new_len] = '\0';
set_string_len(string, new_len);
return string;
}
String
string_copy(String string, const char* content, u32 count)
{
u32 content_len = cstrlen(content);
u32 new_len = content_len < count ? content_len : count;
string = string_ensure_fits_len(string, new_len);
u32 copied_len = 0;
char* dest = string;
while (*content && (copied_len < new_len)) {
*(dest++) = *(content++);
copied_len++;
}
*dest = '\0';
set_string_len(string, copied_len);
return string;
}
String
string_copy(String string, const char* content)
{
u32 bytelimit = cstrlen(content);
String result = string_copy(string, content, bytelimit);
return result;
}
StringList*
string_list_add_front_dup(StringList* list, const char* content)
{
StringList* node = ALLOC(StringList, 1);
node->string = string_new(content);
node->next = list;
return node;
}
bool string_list_contains(StringList* list, const char* value)
{
while (list) {
if (string_eq(list->string, value)) {
return true;
}
list = list->next;
}
return false;
}
void string_list_free(StringList* list)
{
while (list) {
StringList* dead = list;
list = list->next;
string_free(dead->string);
free(dead);
}
}
bool string_eq(const char* a, const char* b)
{
// Break immidiately if we didn't get strings, or if the first char doesn't match
if ((!a || !b) || (*a != *b)) {
return false;
}
// Loop while both of the strings are equal, and both of them have a value.
while ((*a && *b) && (*a == *b)) {
a++;
b++;
}
// The only case where the strings are equal is if they're both depleted at the same time
return !(*a || *b);
}
bool string_starts_with(const char* string, const char* substring)
{
if (!string || !substring) {
return false;
}
do {
if (*string != *substring) {
return false;
}
} while (*(++substring) && *(++string));
return true;
}