1 /*
2 dstring.c
3
4 dynamic string buffer functions
5
6 Copyright (C) 2002 Brian Koropoff.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdlib.h>
33 #include <string.h>
34 #include "QF/sys.h"
35 #include "QF/dstring.h"
36
37 #include "compat.h"
38
39 static void *
dstring_alloc(void * data,size_t size)40 dstring_alloc (void *data, size_t size)
41 {
42 return calloc (1, size);
43 }
44
45 static void
dstring_free(void * data,void * ptr)46 dstring_free (void *data, void *ptr)
47 {
48 free (ptr);
49 }
50
51 static void *
dstring_realloc(void * data,void * ptr,size_t size)52 dstring_realloc (void *data, void *ptr, size_t size)
53 {
54 return realloc (ptr, size);
55 }
56
57 VISIBLE dstring_mem_t dstring_default_mem = {
58 dstring_alloc,
59 dstring_free,
60 dstring_realloc,
61 0
62 };
63
64 inline dstring_t *
_dstring_new(dstring_mem_t * mem)65 _dstring_new (dstring_mem_t *mem)
66 {
67 dstring_t *new;
68
69 new = mem->alloc (mem->data, sizeof (dstring_t));
70
71 if (!new)
72 Sys_Error ("dstring_new: Failed to allocate memory.");
73 new->mem = mem;
74 return new;
75 }
76
77 VISIBLE dstring_t *
dstring_new(void)78 dstring_new (void)
79 {
80 return _dstring_new (&dstring_default_mem);
81 }
82
83 VISIBLE void
dstring_delete(dstring_t * dstr)84 dstring_delete (dstring_t *dstr)
85 {
86 if (dstr->str)
87 dstr->mem->free (dstr->mem->data, dstr->str);
88 dstr->mem->free (dstr->mem->data, dstr);
89 }
90
91 VISIBLE inline void
dstring_adjust(dstring_t * dstr)92 dstring_adjust (dstring_t *dstr)
93 {
94 if (dstr->size > dstr->truesize) {
95 dstr->truesize = (dstr->size + 1023) & ~1023;
96 dstr->str = dstr->mem->realloc (dstr->mem->data, dstr->str,
97 dstr->truesize);
98 if (!dstr->str)
99 Sys_Error ("dstring_adjust: Failed to reallocate memory.");
100 }
101 }
102
103 VISIBLE char *
dstring_reserve(dstring_t * dstr,unsigned len)104 dstring_reserve (dstring_t *dstr, unsigned len)
105 {
106 dstr->size += len;
107 dstring_adjust (dstr);
108 return dstr->str + dstr->size - len;
109 }
110
111 VISIBLE void
dstring_copy(dstring_t * dstr,const char * data,unsigned int len)112 dstring_copy (dstring_t *dstr, const char *data, unsigned int len)
113 {
114 dstr->size = len;
115 dstring_adjust (dstr);
116 memcpy (dstr->str, data, len);
117 }
118
119 VISIBLE void
dstring_append(dstring_t * dstr,const char * data,unsigned int len)120 dstring_append (dstring_t *dstr, const char *data, unsigned int len)
121 {
122 unsigned int ins = dstr->size; // Save insertion point
123
124 dstr->size += len;
125 dstring_adjust (dstr);
126 memcpy (dstr->str + ins, data, len);
127 }
128
129 VISIBLE void
dstring_insert(dstring_t * dstr,unsigned int pos,const char * data,unsigned int len)130 dstring_insert (dstring_t *dstr, unsigned int pos, const char *data,
131 unsigned int len)
132 {
133 unsigned int oldsize = dstr->size;
134
135 if (pos > dstr->size)
136 pos = dstr->size;
137 dstr->size += len;
138 dstring_adjust (dstr);
139 memmove (dstr->str + pos + len, dstr->str + pos, oldsize - pos);
140 memcpy (dstr->str + pos, data, len);
141 }
142
143 VISIBLE void
dstring_snip(dstring_t * dstr,unsigned int pos,unsigned int len)144 dstring_snip (dstring_t *dstr, unsigned int pos, unsigned int len)
145 {
146 if (pos > dstr->size)
147 pos = dstr->size;
148 if (pos + len > dstr->size)
149 len = dstr->size - pos;
150 if (!len)
151 return;
152 memmove (dstr->str + pos, dstr->str + pos + len, dstr->size - pos - len);
153 dstr->size -= len;
154 dstring_adjust (dstr);
155 }
156
157 VISIBLE void
dstring_clear(dstring_t * dstr)158 dstring_clear (dstring_t *dstr)
159 {
160 dstr->size = 0;
161 dstring_adjust (dstr);
162 }
163
164 VISIBLE void
dstring_replace(dstring_t * dstr,unsigned int pos,unsigned int rlen,const char * data,unsigned int len)165 dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen,
166 const char *data, unsigned int len)
167 {
168 unsigned int oldsize = dstr->size;
169 if (pos > dstr->size)
170 pos = dstr->size;
171 if (rlen > dstr->size - pos)
172 rlen = dstr->size - pos;
173 if (rlen < len) {
174 dstr->size += len - rlen;
175 dstring_adjust (dstr);
176 memmove (dstr->str + pos + len, dstr->str + pos + rlen,
177 oldsize - (pos + rlen));
178 } else if (rlen > len) {
179 memmove (dstr->str + pos + len, dstr->str + pos + rlen,
180 oldsize - (pos + rlen));
181 dstr->size -= rlen - len;
182 dstring_adjust (dstr);
183 }
184 memcpy (dstr->str + pos, data, len);
185 }
186
187 VISIBLE char *
dstring_freeze(dstring_t * dstr)188 dstring_freeze (dstring_t *dstr)
189 {
190 char *str = dstr->mem->realloc (dstr->mem->data, dstr->str, dstr->size);
191 dstr->mem->free (dstr->mem->data, dstr);
192 return str;
193 }
194
195 VISIBLE inline dstring_t *
_dstring_newstr(dstring_mem_t * mem)196 _dstring_newstr (dstring_mem_t *mem)
197 {
198 dstring_t *new;
199
200 new = mem->alloc (mem->data, sizeof (dstring_t));
201
202 if (!new)
203 Sys_Error ("dstring_newstr: Failed to allocate memory.");
204 new->mem = mem;
205 new->size = 1;
206 dstring_adjust (new);
207 new->str[0] = 0;
208 return new;
209 }
210
211 VISIBLE dstring_t *
dstring_newstr(void)212 dstring_newstr (void)
213 {
214 return _dstring_newstr (&dstring_default_mem);
215 }
216
217 VISIBLE dstring_t *
dstring_strdup(const char * str)218 dstring_strdup (const char *str)
219 {
220 dstring_t *dstr = dstring_new ();
221 dstring_copystr (dstr, str);
222 return dstr;
223 }
224
225 VISIBLE char *
dstring_reservestr(dstring_t * dstr,unsigned len)226 dstring_reservestr (dstring_t *dstr, unsigned len)
227 {
228 int pos = dstr->size;
229 if (pos && !dstr->str[pos - 1])
230 pos--;
231 dstr->size = pos + len + 1;
232 dstring_adjust (dstr);
233 return dstr->str + pos;
234 }
235
236 VISIBLE void
dstring_copystr(dstring_t * dstr,const char * str)237 dstring_copystr (dstring_t *dstr, const char *str)
238 {
239 dstr->size = strlen (str) + 1;
240 dstring_adjust (dstr);
241 strcpy (dstr->str, str);
242 }
243
244 VISIBLE void
dstring_copysubstr(dstring_t * dstr,const char * str,unsigned int len)245 dstring_copysubstr (dstring_t *dstr, const char *str, unsigned int len)
246 {
247 len = strnlen (str, len);
248
249 dstr->size = len + 1;
250 dstring_adjust (dstr);
251 strncpy (dstr->str, str, len);
252 dstr->str[len] = 0;
253 }
254
255 VISIBLE void
dstring_appendstr(dstring_t * dstr,const char * str)256 dstring_appendstr (dstring_t *dstr, const char *str)
257 {
258 unsigned int pos = strnlen (dstr->str, dstr->size);
259 unsigned int len = strlen (str);
260
261 dstr->size = pos + len + 1;
262 dstring_adjust (dstr);
263 strcpy (dstr->str + pos, str);
264 }
265
266 VISIBLE void
dstring_appendsubstr(dstring_t * dstr,const char * str,unsigned int len)267 dstring_appendsubstr (dstring_t *dstr, const char *str, unsigned int len)
268 {
269 unsigned int pos = strnlen (dstr->str, dstr->size);
270
271 len = strnlen (str, len);
272 dstr->size = pos + len + 1;
273 dstring_adjust (dstr);
274 strncpy (dstr->str + pos, str, len);
275 dstr->str[pos + len] = 0;
276 }
277
278 VISIBLE void
dstring_insertstr(dstring_t * dstr,unsigned int pos,const char * str)279 dstring_insertstr (dstring_t *dstr, unsigned int pos, const char *str)
280 {
281 // Don't insert strlen + 1 to achieve concatenation
282 dstring_insert (dstr, pos, str, strlen (str));
283 }
284
285 VISIBLE void
dstring_insertsubstr(dstring_t * dstr,unsigned int pos,const char * str,unsigned int len)286 dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str,
287 unsigned int len)
288 {
289 len = strnlen (str, len);
290
291 dstring_insert (dstr, pos, str, len);
292 }
293
294 VISIBLE void
dstring_clearstr(dstring_t * dstr)295 dstring_clearstr (dstring_t *dstr)
296 {
297 dstr->size = 1;
298 dstring_adjust (dstr);
299 dstr->str[0] = 0;
300 }
301
302 #if defined (HAVE_VA_COPY)
303 # define VA_COPY(a,b) va_copy (a, b)
304 #elif defined (HAVE__VA_COPY)
305 # define VA_COPY(a,b) __va_copy (a, b)
306 #else
307 # define VA_COPY(a,b) memcpy (a, b, sizeof (a))
308 #endif
309
310 static int
_dvsprintf(dstring_t * dstr,int offs,const char * fmt,va_list args)311 _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args)
312 {
313 int size;
314
315 #ifdef VA_LIST_IS_ARRAY
316 va_list tmp_args;
317 VA_COPY (tmp_args, args);
318 #endif
319
320 if (!dstr->truesize)
321 dstring_clearstr (dstr); // Make it a string
322 // Some vsnprintf implementations return -1 on truncation
323 while ((size = vsnprintf (dstr->str + offs, dstr->truesize - offs - 1, fmt,
324 args)) == -1) {
325 dstr->size = (dstr->truesize & ~1023) + 1024;
326 dstring_adjust (dstr);
327 #ifdef VA_LIST_IS_ARRAY
328 VA_COPY (args, tmp_args);
329 #endif
330 }
331 dstr->size = size + offs + 2;
332 // "Proper" implementations return the required size
333 if (dstr->size > dstr->truesize) {
334 dstring_adjust (dstr);
335 #ifdef VA_LIST_IS_ARRAY
336 VA_COPY (args, tmp_args);
337 #endif
338 vsnprintf (dstr->str + offs, dstr->truesize - offs - 1, fmt, args);
339 }
340 dstr->size = size + offs + 1;
341 dstr->str[dstr->size - 1] = 0;
342 return size;
343 }
344
345 VISIBLE int
dvsprintf(dstring_t * dstr,const char * fmt,va_list args)346 dvsprintf (dstring_t *dstr, const char *fmt, va_list args)
347 {
348 return _dvsprintf (dstr, 0, fmt, args);
349 }
350
351 VISIBLE int
dsprintf(dstring_t * dstr,const char * fmt,...)352 dsprintf (dstring_t *dstr, const char *fmt, ...)
353 {
354 va_list args;
355 int ret;
356
357 va_start (args, fmt);
358 ret = _dvsprintf (dstr, 0, fmt, args);
359 va_end (args);
360
361 return ret;
362 }
363
364 VISIBLE int
davsprintf(dstring_t * dstr,const char * fmt,va_list args)365 davsprintf (dstring_t *dstr, const char *fmt, va_list args)
366 {
367 int offs = 0;
368
369 if (dstr->size)
370 offs = dstr->size - 1;
371 return _dvsprintf (dstr, offs, fmt, args);
372 }
373
374 VISIBLE int
dasprintf(dstring_t * dstr,const char * fmt,...)375 dasprintf (dstring_t *dstr, const char *fmt, ...)
376 {
377 va_list args;
378 int ret;
379 int offs = 0;
380
381 if (dstr->size)
382 offs = dstr->size - 1;
383 va_start (args, fmt);
384 ret = _dvsprintf (dstr, offs, fmt, args);
385 va_end (args);
386
387 return ret;
388 }
389