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