1 /*
2 * Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #pragma once
18
19 #include <string.h>
20 #include <stdarg.h>
21 #include "c99defs.h"
22 #include "bmem.h"
23
24 /*
25 * Dynamic string
26 *
27 * Helper struct/functions for dynamically sizing string buffers.
28 */
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 struct strref;
35
36 struct dstr {
37 char *array;
38 size_t len; /* number of characters, excluding null terminator */
39 size_t capacity;
40 };
41
42 #ifndef _MSC_VER
43 #define PRINTFATTR(f, a) __attribute__((__format__(__printf__, f, a)))
44 #else
45 #define PRINTFATTR(f, a)
46 #endif
47
48 EXPORT int astrcmpi(const char *str1, const char *str2);
49 EXPORT int wstrcmpi(const wchar_t *str1, const wchar_t *str2);
50 EXPORT int astrcmp_n(const char *str1, const char *str2, size_t n);
51 EXPORT int wstrcmp_n(const wchar_t *str1, const wchar_t *str2, size_t n);
52 EXPORT int astrcmpi_n(const char *str1, const char *str2, size_t n);
53 EXPORT int wstrcmpi_n(const wchar_t *str1, const wchar_t *str2, size_t n);
54
55 EXPORT char *astrstri(const char *str, const char *find);
56 EXPORT wchar_t *wstrstri(const wchar_t *str, const wchar_t *find);
57
58 EXPORT char *strdepad(char *str);
59 EXPORT wchar_t *wcsdepad(wchar_t *str);
60
61 EXPORT char **strlist_split(const char *str, char split_ch, bool include_empty);
62 EXPORT void strlist_free(char **strlist);
63
64 static inline void dstr_init(struct dstr *dst);
65 static inline void dstr_init_move(struct dstr *dst, struct dstr *src);
66 static inline void dstr_init_move_array(struct dstr *dst, char *str);
67 static inline void dstr_init_copy(struct dstr *dst, const char *src);
68 static inline void dstr_init_copy_dstr(struct dstr *dst,
69 const struct dstr *src);
70 EXPORT void dstr_init_copy_strref(struct dstr *dst, const struct strref *src);
71
72 static inline void dstr_free(struct dstr *dst);
73 static inline void dstr_array_free(struct dstr *array, const size_t count);
74
75 static inline void dstr_move(struct dstr *dst, struct dstr *src);
76 static inline void dstr_move_array(struct dstr *dst, char *str);
77
78 EXPORT void dstr_copy(struct dstr *dst, const char *array);
79 static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src);
80 EXPORT void dstr_copy_strref(struct dstr *dst, const struct strref *src);
81
82 EXPORT void dstr_ncopy(struct dstr *dst, const char *array, const size_t len);
83 EXPORT void dstr_ncopy_dstr(struct dstr *dst, const struct dstr *src,
84 const size_t len);
85
86 static inline void dstr_resize(struct dstr *dst, const size_t num);
87 static inline void dstr_reserve(struct dstr *dst, const size_t num);
88
89 static inline bool dstr_is_empty(const struct dstr *str);
90
91 static inline void dstr_cat(struct dstr *dst, const char *array);
92 EXPORT void dstr_cat_dstr(struct dstr *dst, const struct dstr *str);
93 EXPORT void dstr_cat_strref(struct dstr *dst, const struct strref *str);
94
95 static inline void dstr_cat_ch(struct dstr *dst, char ch);
96
97 EXPORT void dstr_ncat(struct dstr *dst, const char *array, const size_t len);
98 EXPORT void dstr_ncat_dstr(struct dstr *dst, const struct dstr *str,
99 const size_t len);
100
101 EXPORT void dstr_insert(struct dstr *dst, const size_t idx, const char *array);
102 EXPORT void dstr_insert_dstr(struct dstr *dst, const size_t idx,
103 const struct dstr *str);
104 EXPORT void dstr_insert_ch(struct dstr *dst, const size_t idx, const char ch);
105
106 EXPORT void dstr_remove(struct dstr *dst, const size_t idx, const size_t count);
107
108 PRINTFATTR(2, 3)
109 EXPORT void dstr_printf(struct dstr *dst, const char *format, ...);
110 PRINTFATTR(2, 3)
111 EXPORT void dstr_catf(struct dstr *dst, const char *format, ...);
112
113 EXPORT void dstr_vprintf(struct dstr *dst, const char *format, va_list args);
114 EXPORT void dstr_vcatf(struct dstr *dst, const char *format, va_list args);
115
116 EXPORT void dstr_safe_printf(struct dstr *dst, const char *format,
117 const char *val1, const char *val2,
118 const char *val3, const char *val4);
119
120 static inline const char *dstr_find_i(const struct dstr *str, const char *find);
121 static inline const char *dstr_find(const struct dstr *str, const char *find);
122
123 EXPORT void dstr_replace(struct dstr *str, const char *find,
124 const char *replace);
125
126 static inline int dstr_cmp(const struct dstr *str1, const char *str2);
127 static inline int dstr_cmpi(const struct dstr *str1, const char *str2);
128 static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
129 const size_t n);
130 static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
131 const size_t n);
132
133 EXPORT void dstr_depad(struct dstr *dst);
134
135 EXPORT void dstr_left(struct dstr *dst, const struct dstr *str,
136 const size_t pos);
137 EXPORT void dstr_mid(struct dstr *dst, const struct dstr *str,
138 const size_t start, const size_t count);
139 EXPORT void dstr_right(struct dstr *dst, const struct dstr *str,
140 const size_t pos);
141
142 static inline char dstr_end(const struct dstr *str);
143
144 EXPORT void dstr_from_mbs(struct dstr *dst, const char *mbstr);
145 EXPORT char *dstr_to_mbs(const struct dstr *str);
146 EXPORT void dstr_from_wcs(struct dstr *dst, const wchar_t *wstr);
147 EXPORT wchar_t *dstr_to_wcs(const struct dstr *str);
148
149 EXPORT void dstr_to_upper(struct dstr *str);
150 EXPORT void dstr_to_lower(struct dstr *str);
151
152 #undef PRINTFATTR
153
154 /* ------------------------------------------------------------------------- */
155
dstr_init(struct dstr * dst)156 static inline void dstr_init(struct dstr *dst)
157 {
158 dst->array = NULL;
159 dst->len = 0;
160 dst->capacity = 0;
161 }
162
dstr_init_move_array(struct dstr * dst,char * str)163 static inline void dstr_init_move_array(struct dstr *dst, char *str)
164 {
165 dst->array = str;
166 dst->len = (!str) ? 0 : strlen(str);
167 dst->capacity = dst->len + 1;
168 }
169
dstr_init_move(struct dstr * dst,struct dstr * src)170 static inline void dstr_init_move(struct dstr *dst, struct dstr *src)
171 {
172 *dst = *src;
173 dstr_init(src);
174 }
175
dstr_init_copy(struct dstr * dst,const char * str)176 static inline void dstr_init_copy(struct dstr *dst, const char *str)
177 {
178 dstr_init(dst);
179 dstr_copy(dst, str);
180 }
181
dstr_init_copy_dstr(struct dstr * dst,const struct dstr * src)182 static inline void dstr_init_copy_dstr(struct dstr *dst, const struct dstr *src)
183 {
184 dstr_init(dst);
185 dstr_copy_dstr(dst, src);
186 }
187
dstr_free(struct dstr * dst)188 static inline void dstr_free(struct dstr *dst)
189 {
190 bfree(dst->array);
191 dst->array = NULL;
192 dst->len = 0;
193 dst->capacity = 0;
194 }
195
dstr_array_free(struct dstr * array,const size_t count)196 static inline void dstr_array_free(struct dstr *array, const size_t count)
197 {
198 size_t i;
199 for (i = 0; i < count; i++)
200 dstr_free(array + i);
201 }
202
dstr_move_array(struct dstr * dst,char * str)203 static inline void dstr_move_array(struct dstr *dst, char *str)
204 {
205 dstr_free(dst);
206 dst->array = str;
207 dst->len = (!str) ? 0 : strlen(str);
208 dst->capacity = dst->len + 1;
209 }
210
dstr_move(struct dstr * dst,struct dstr * src)211 static inline void dstr_move(struct dstr *dst, struct dstr *src)
212 {
213 dstr_free(dst);
214 dstr_init_move(dst, src);
215 }
216
dstr_ensure_capacity(struct dstr * dst,const size_t new_size)217 static inline void dstr_ensure_capacity(struct dstr *dst, const size_t new_size)
218 {
219 size_t new_cap;
220 if (new_size <= dst->capacity)
221 return;
222
223 new_cap = (!dst->capacity) ? new_size : dst->capacity * 2;
224 if (new_size > new_cap)
225 new_cap = new_size;
226 dst->array = (char *)brealloc(dst->array, new_cap);
227 dst->capacity = new_cap;
228 }
229
dstr_copy_dstr(struct dstr * dst,const struct dstr * src)230 static inline void dstr_copy_dstr(struct dstr *dst, const struct dstr *src)
231 {
232 dstr_free(dst);
233
234 if (src->len) {
235 dstr_ensure_capacity(dst, src->len + 1);
236 memcpy(dst->array, src->array, src->len + 1);
237 dst->len = src->len;
238 }
239 }
240
dstr_reserve(struct dstr * dst,const size_t capacity)241 static inline void dstr_reserve(struct dstr *dst, const size_t capacity)
242 {
243 if (capacity == 0 || capacity <= dst->len)
244 return;
245
246 dst->array = (char *)brealloc(dst->array, capacity);
247 dst->capacity = capacity;
248 }
249
dstr_resize(struct dstr * dst,const size_t num)250 static inline void dstr_resize(struct dstr *dst, const size_t num)
251 {
252 if (!num) {
253 dstr_free(dst);
254 return;
255 }
256
257 dstr_ensure_capacity(dst, num + 1);
258 dst->array[num] = 0;
259 dst->len = num;
260 }
261
dstr_is_empty(const struct dstr * str)262 static inline bool dstr_is_empty(const struct dstr *str)
263 {
264 if (!str->array || !str->len)
265 return true;
266 if (!*str->array)
267 return true;
268
269 return false;
270 }
271
dstr_cat(struct dstr * dst,const char * array)272 static inline void dstr_cat(struct dstr *dst, const char *array)
273 {
274 size_t len;
275 if (!array || !*array)
276 return;
277
278 len = strlen(array);
279 dstr_ncat(dst, array, len);
280 }
281
dstr_cat_ch(struct dstr * dst,char ch)282 static inline void dstr_cat_ch(struct dstr *dst, char ch)
283 {
284 dstr_ensure_capacity(dst, ++dst->len + 1);
285 dst->array[dst->len - 1] = ch;
286 dst->array[dst->len] = 0;
287 }
288
dstr_find_i(const struct dstr * str,const char * find)289 static inline const char *dstr_find_i(const struct dstr *str, const char *find)
290 {
291 return astrstri(str->array, find);
292 }
293
dstr_find(const struct dstr * str,const char * find)294 static inline const char *dstr_find(const struct dstr *str, const char *find)
295 {
296 return strstr(str->array, find);
297 }
298
dstr_cmp(const struct dstr * str1,const char * str2)299 static inline int dstr_cmp(const struct dstr *str1, const char *str2)
300 {
301 return strcmp(str1->array, str2);
302 }
303
dstr_cmpi(const struct dstr * str1,const char * str2)304 static inline int dstr_cmpi(const struct dstr *str1, const char *str2)
305 {
306 return astrcmpi(str1->array, str2);
307 }
308
dstr_ncmp(const struct dstr * str1,const char * str2,const size_t n)309 static inline int dstr_ncmp(const struct dstr *str1, const char *str2,
310 const size_t n)
311 {
312 return astrcmp_n(str1->array, str2, n);
313 }
314
dstr_ncmpi(const struct dstr * str1,const char * str2,const size_t n)315 static inline int dstr_ncmpi(const struct dstr *str1, const char *str2,
316 const size_t n)
317 {
318 return astrcmpi_n(str1->array, str2, n);
319 }
320
dstr_end(const struct dstr * str)321 static inline char dstr_end(const struct dstr *str)
322 {
323 if (dstr_is_empty(str))
324 return 0;
325
326 return str->array[str->len - 1];
327 }
328
329 #ifdef __cplusplus
330 }
331 #endif
332