1 #include "iwxstr.h"
2 #include "iwlog.h"
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <errno.h>
8
9 // Default IWXSTR initial size
10 #ifndef IWXSTR_AUNIT
11 #define IWXSTR_AUNIT 16
12 #endif
13
14 struct _IWXSTR {
15 char *ptr; /**< Data buffer */
16 size_t size; /**< Actual data size */
17 size_t asize; /**< Allocated buffer size */
18 void (*user_data_free_fn)(void*);
19 void *user_data;
20 };
21
iwxstr_new2(size_t siz)22 IWXSTR* iwxstr_new2(size_t siz) {
23 if (!siz) {
24 siz = IWXSTR_AUNIT;
25 }
26 IWXSTR *xstr = malloc(sizeof(*xstr));
27 if (!xstr) {
28 return 0;
29 }
30 xstr->ptr = malloc(siz);
31 if (!xstr->ptr) {
32 free(xstr);
33 return 0;
34 }
35 xstr->user_data = 0;
36 xstr->user_data_free_fn = 0;
37 xstr->size = 0;
38 xstr->asize = siz;
39 xstr->ptr[0] = '\0';
40 return xstr;
41 }
42
iwxstr_new(void)43 IWXSTR* iwxstr_new(void) {
44 return iwxstr_new2(IWXSTR_AUNIT);
45 }
46
iwxstr_new_clone(const IWXSTR * xstr)47 IWXSTR* iwxstr_new_clone(const IWXSTR *xstr) {
48 IWXSTR *ret = malloc(sizeof(*ret));
49 if (!ret) {
50 return 0;
51 }
52 ret->user_data = 0;
53 ret->user_data_free_fn = 0;
54 ret->size = xstr->size;
55 ret->asize = xstr->asize;
56 ret->ptr = malloc(xstr->asize);
57 if (!ret->ptr) {
58 free(ret);
59 return 0;
60 }
61 if (xstr->size) {
62 memcpy(ret->ptr, xstr->ptr, xstr->size);
63 }
64 return ret;
65 }
66
iwxstr_wrap(char * buf,size_t size,size_t asize)67 IWXSTR* iwxstr_wrap(char *buf, size_t size, size_t asize) {
68 IWXSTR *xstr = malloc(sizeof(*xstr));
69 if (!xstr) {
70 return 0;
71 }
72 xstr->user_data = 0;
73 xstr->user_data_free_fn = 0;
74 xstr->size = size;
75 xstr->asize = asize;
76 xstr->ptr = buf;
77
78 if (size >= asize) {
79 xstr->ptr = realloc(buf, size + 1);
80 if (!xstr->ptr) {
81 free(xstr);
82 return 0;
83 }
84 xstr->asize = size + 1;
85 }
86 xstr->ptr[size] = '\0';
87 return xstr;
88 }
89
iwxstr_destroy(IWXSTR * xstr)90 void iwxstr_destroy(IWXSTR *xstr) {
91 if (!xstr) {
92 return;
93 }
94 if (xstr->user_data_free_fn) {
95 xstr->user_data_free_fn(xstr->user_data);
96 }
97 free(xstr->ptr);
98 free(xstr);
99 }
100
iwxstr_destroy_keep_ptr(IWXSTR * xstr)101 char* iwxstr_destroy_keep_ptr(IWXSTR *xstr) {
102 if (!xstr) {
103 return 0;
104 }
105 char *ptr = xstr->ptr;
106 if (xstr->user_data_free_fn) {
107 xstr->user_data_free_fn(xstr->user_data);
108 }
109 free(xstr);
110 return ptr;
111 }
112
iwxstr_clear(IWXSTR * xstr)113 void iwxstr_clear(IWXSTR *xstr) {
114 assert(xstr);
115 xstr->size = 0;
116 xstr->ptr[0] = '\0';
117 }
118
iwxstr_cat(IWXSTR * xstr,const void * buf,size_t size)119 iwrc iwxstr_cat(IWXSTR *xstr, const void *buf, size_t size) {
120 size_t nsize = xstr->size + size + 1;
121 if (xstr->asize < nsize) {
122 while (xstr->asize < nsize) {
123 xstr->asize <<= 1;
124 if (xstr->asize < nsize) {
125 xstr->asize = nsize;
126 }
127 }
128 char *ptr = realloc(xstr->ptr, xstr->asize);
129 if (!ptr) {
130 return IW_ERROR_ALLOC;
131 }
132 xstr->ptr = ptr;
133 }
134 memcpy(xstr->ptr + xstr->size, buf, size);
135 xstr->size += size;
136 xstr->ptr[xstr->size] = '\0';
137 return IW_OK;
138 }
139
iwxstr_set_size(IWXSTR * xstr,size_t size)140 iwrc iwxstr_set_size(IWXSTR *xstr, size_t size) {
141 size_t nsize = size + 1;
142 if (xstr->asize < nsize) {
143 while (xstr->asize < nsize) {
144 xstr->asize <<= 1;
145 if (xstr->asize < nsize) {
146 xstr->asize = nsize;
147 }
148 }
149 char *ptr = realloc(xstr->ptr, xstr->asize);
150 if (!ptr) {
151 return IW_ERROR_ALLOC;
152 }
153 xstr->ptr = ptr;
154 }
155 xstr->size = size;
156 return IW_OK;
157 }
158
iwxstr_cat2(IWXSTR * xstr,const char * buf)159 iwrc iwxstr_cat2(IWXSTR *xstr, const char *buf) {
160 return buf ? iwxstr_cat(xstr, buf, strlen(buf)) : 0;
161 }
162
iwxstr_unshift(IWXSTR * xstr,const void * buf,size_t size)163 iwrc iwxstr_unshift(IWXSTR *xstr, const void *buf, size_t size) {
164 size_t nsize = xstr->size + size + 1;
165 if (xstr->asize < nsize) {
166 while (xstr->asize < nsize) {
167 xstr->asize <<= 1;
168 if (xstr->asize < nsize) {
169 xstr->asize = nsize;
170 }
171 }
172 char *ptr = realloc(xstr->ptr, xstr->asize);
173 if (!ptr) {
174 return IW_ERROR_ALLOC;
175 }
176 xstr->ptr = ptr;
177 }
178 if (xstr->size) {
179 // shift to right
180 memmove(xstr->ptr + size, xstr->ptr, xstr->size);
181 }
182 memcpy(xstr->ptr, buf, size);
183 xstr->size += size;
184 xstr->ptr[xstr->size] = '\0';
185 return IW_OK;
186 }
187
iwxstr_shift(IWXSTR * xstr,size_t shift_size)188 void iwxstr_shift(IWXSTR *xstr, size_t shift_size) {
189 if (shift_size == 0) {
190 return;
191 }
192 if (shift_size > xstr->size) {
193 shift_size = xstr->size;
194 }
195 if (xstr->size > shift_size) {
196 memmove(xstr->ptr, xstr->ptr + shift_size, xstr->size - shift_size);
197 }
198 xstr->size -= shift_size;
199 xstr->ptr[xstr->size] = '\0';
200 }
201
iwxstr_pop(IWXSTR * xstr,size_t pop_size)202 void iwxstr_pop(IWXSTR *xstr, size_t pop_size) {
203 if (pop_size == 0) {
204 return;
205 }
206 if (pop_size > xstr->size) {
207 pop_size = xstr->size;
208 }
209 xstr->size -= pop_size;
210 xstr->ptr[xstr->size] = '\0';
211 }
212
iwxstr_insert(IWXSTR * xstr,size_t pos,const void * buf,size_t size)213 iwrc iwxstr_insert(IWXSTR *xstr, size_t pos, const void *buf, size_t size) {
214 if (pos > xstr->size) {
215 return IW_ERROR_OUT_OF_BOUNDS;
216 }
217 if (size == 0) {
218 return 0;
219 }
220 size_t nsize = xstr->size + size + 1;
221 if (xstr->asize < nsize) {
222 while (xstr->asize < nsize) {
223 xstr->asize <<= 1;
224 if (xstr->asize < nsize) {
225 xstr->asize = nsize;
226 }
227 }
228 char *ptr = realloc(xstr->ptr, xstr->asize);
229 if (!ptr) {
230 return IW_ERROR_ALLOC;
231 }
232 xstr->ptr = ptr;
233 }
234 memmove(xstr->ptr + pos + size, xstr->ptr + pos, xstr->size - pos + 1 /* \0 */);
235 memcpy(xstr->ptr + pos, buf, size);
236 xstr->size += size;
237 return IW_OK;
238 }
239
iwxstr_insert_vaprintf(IWXSTR * xstr,size_t pos,const char * format,va_list va)240 iwrc iwxstr_insert_vaprintf(IWXSTR *xstr, size_t pos, const char *format, va_list va) {
241 iwrc rc = 0;
242 char buf[1024];
243 va_list cva;
244 va_copy(cva, va);
245 char *wp = buf;
246 int len = vsnprintf(wp, sizeof(buf), format, va);
247 if (len >= sizeof(buf)) {
248 RCA(wp = malloc(len + 1), finish);
249 len = vsnprintf(wp, len + 1, format, cva);
250 if (len < 0) {
251 rc = IW_ERROR_FAIL;
252 goto finish;
253 }
254 }
255 rc = iwxstr_insert(xstr, pos, wp, len);
256
257 finish:
258 va_end(cva);
259 if (wp != buf) {
260 free(wp);
261 }
262 return rc;
263 }
264
iwxstr_insert_printf(IWXSTR * xstr,size_t pos,const char * format,...)265 iwrc iwxstr_insert_printf(IWXSTR *xstr, size_t pos, const char *format, ...) {
266 va_list ap;
267 va_start(ap, format);
268 iwrc rc = iwxstr_insert_vaprintf(xstr, pos, format, ap);
269 va_end(ap);
270 return rc;
271 }
272
iwxstr_vaprintf(IWXSTR * xstr,const char * format,va_list va)273 iwrc iwxstr_vaprintf(IWXSTR *xstr, const char *format, va_list va) {
274 iwrc rc = 0;
275 char buf[1024];
276 va_list cva;
277 va_copy(cva, va);
278 char *wp = buf;
279 int len = vsnprintf(wp, sizeof(buf), format, va);
280 if (len >= sizeof(buf)) {
281 RCA(wp = malloc(len + 1), finish);
282 len = vsnprintf(wp, len + 1, format, cva);
283 if (len < 0) {
284 rc = IW_ERROR_FAIL;
285 goto finish;
286 }
287 }
288 rc = iwxstr_cat(xstr, wp, len);
289
290 finish:
291 va_end(cva);
292 if (wp != buf) {
293 free(wp);
294 }
295 return rc;
296 }
297
iwxstr_printf(IWXSTR * xstr,const char * format,...)298 iwrc iwxstr_printf(IWXSTR *xstr, const char *format, ...) {
299 va_list ap;
300 va_start(ap, format);
301 iwrc rc = iwxstr_vaprintf(xstr, format, ap);
302 va_end(ap);
303 return rc;
304 }
305
iwxstr_new_printf(const char * format,...)306 IWXSTR* iwxstr_new_printf(const char *format, ...) {
307 IWXSTR *xstr = iwxstr_new();
308 if (!xstr) {
309 return 0;
310 }
311 va_list ap;
312 va_start(ap, format);
313 iwrc rc = iwxstr_vaprintf(xstr, format, ap);
314 va_end(ap);
315 if (rc) {
316 iwxstr_destroy(xstr);
317 return 0;
318 }
319 return xstr;
320 }
321
iwxstr_ptr(IWXSTR * xstr)322 char* iwxstr_ptr(IWXSTR *xstr) {
323 return xstr->ptr;
324 }
325
iwxstr_size(IWXSTR * xstr)326 size_t iwxstr_size(IWXSTR *xstr) {
327 return xstr->size;
328 }
329
iwxstr_asize(IWXSTR * xstr)330 size_t iwxstr_asize(IWXSTR *xstr) {
331 return xstr->asize;
332 }
333
iwxstr_user_data_set(IWXSTR * xstr,void * data,void (* free_fn)(void *))334 void iwxstr_user_data_set(IWXSTR *xstr, void *data, void (*free_fn)(void*)) {
335 if (xstr->user_data_free_fn) {
336 xstr->user_data_free_fn(xstr->user_data);
337 }
338 xstr->user_data = data;
339 xstr->user_data_free_fn = free_fn;
340 }
341
iwxstr_user_data_get(IWXSTR * xstr)342 void* iwxstr_user_data_get(IWXSTR *xstr) {
343 return xstr->user_data;
344 }
345
iwxstr_user_data_detach(IWXSTR * xstr)346 void* iwxstr_user_data_detach(IWXSTR *xstr) {
347 xstr->user_data_free_fn = 0;
348 return xstr->user_data;
349 }
350