cleanup: style
[blender-staging.git] / source / blender / blenlib / intern / BLI_dynstr.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * Dynamically sized string ADT
27  */
28
29 /** \file blender/blenlib/intern/BLI_dynstr.c
30  *  \ingroup bli
31  */
32
33 #include <stdlib.h>  /* malloc */
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_string.h"
39 #include "BLI_dynstr.h"
40
41 #ifdef _WIN32
42 #ifndef vsnprintf
43 #define vsnprintf _vsnprintf
44 #endif
45 #endif
46
47 #ifndef va_copy
48 # ifdef __va_copy
49 #  define va_copy(a, b) __va_copy(a, b)
50 # else /* !__va_copy */
51 #  define va_copy(a, b) ((a) = (b))
52 # endif /* __va_copy */
53 #endif /* va_copy */
54
55 /***/
56
57 typedef struct DynStrElem DynStrElem;
58 struct DynStrElem {
59         DynStrElem *next;
60         
61         char *str;
62 };
63
64 struct DynStr {
65         DynStrElem *elems, *last;
66         int curlen;
67 };
68
69 /***/
70
71 /**
72  * Create a new DynStr.
73  *
74  * \return Pointer to a new DynStr.
75  */
76 DynStr *BLI_dynstr_new(void)
77 {
78         DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
79         ds->elems = ds->last = NULL;
80         ds->curlen = 0;
81         
82         return ds;
83 }
84
85 /**
86  * Append a c-string to a DynStr.
87  *
88  * \param ds The DynStr to append to.
89  * \param cstr The c-string to append.
90  */
91 void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
92 {
93         DynStrElem *dse = malloc(sizeof(*dse));
94         int cstrlen = strlen(cstr);
95         
96         dse->str = malloc(cstrlen + 1);
97         memcpy(dse->str, cstr, cstrlen + 1);
98         dse->next = NULL;
99         
100         if (!ds->last)
101                 ds->last = ds->elems = dse;
102         else
103                 ds->last = ds->last->next = dse;
104
105         ds->curlen += cstrlen;
106 }
107
108 /**
109  * Append a length clamped c-string to a DynStr.
110  *
111  * \param ds The DynStr to append to.
112  * \param cstr The c-string to append.
113  * \param len The maximum length of the c-string to copy.
114  */
115 void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
116 {
117         DynStrElem *dse = malloc(sizeof(*dse));
118         int cstrlen = BLI_strnlen(cstr, len);
119
120         dse->str = malloc(cstrlen + 1);
121         memcpy(dse->str, cstr, cstrlen);
122         dse->str[cstrlen] = '\0';
123         dse->next = NULL;
124
125         if (!ds->last)
126                 ds->last = ds->elems = dse;
127         else
128                 ds->last = ds->last->next = dse;
129
130         ds->curlen += cstrlen;
131 }
132
133 void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
134 {
135         char *message, fixedmessage[256];
136         int len = sizeof(fixedmessage);
137         const int maxlen = 65536;
138         int retval;
139
140         while (1) {
141                 va_list args_cpy;
142                 if (len == sizeof(fixedmessage))
143                         message = fixedmessage;
144                 else
145                         message = MEM_callocN(sizeof(char) * len, "BLI_dynstr_appendf");
146
147                 /* cant reuse the same args, so work on a copy */
148                 va_copy(args_cpy, args);
149                 retval = vsnprintf(message, len, format, args_cpy);
150                 va_end(args_cpy);
151
152                 if (retval == -1) {
153                         /* -1 means not enough space, but on windows it may also mean
154                          * there is a formatting error, so we impose a maximum length */
155                         if (message != fixedmessage)
156                                 MEM_freeN(message);
157                         message = NULL;
158
159                         len *= 2;
160                         if (len > maxlen) {
161                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
162                                 break;
163                         }
164                 }
165                 else if (retval >= len) {
166                         /* in C99 the actual length required is returned */
167                         if (message != fixedmessage)
168                                 MEM_freeN(message);
169                         message = NULL;
170
171                         /* retval doesn't include \0 terminator */
172                         len = retval + 1;
173                 }
174                 else
175                         break;
176         }
177
178         if (message) {
179                 BLI_dynstr_append(ds, message);
180
181                 if (message != fixedmessage)
182                         MEM_freeN(message);
183         }
184 }
185
186 /**
187  * Append a c-string to a DynStr, but with formatting like printf.
188  *
189  * \param ds The DynStr to append to.
190  * \param format The printf format string to use.
191  */
192 void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
193 {
194         va_list args;
195         char *message, fixedmessage[256];
196         int len = sizeof(fixedmessage);
197         const int maxlen = 65536;
198         int retval;
199
200         /* note that it's tempting to just call BLI_dynstr_vappendf here
201          * and avoid code duplication, that crashes on some system because
202          * va_start/va_end have to be called for each vsnprintf call */
203
204         while (1) {
205                 if (len == sizeof(fixedmessage))
206                         message = fixedmessage;
207                 else
208                         message = MEM_callocN(sizeof(char) * (len), "BLI_dynstr_appendf");
209
210                 va_start(args, format);
211                 retval = vsnprintf(message, len, format, args);
212                 va_end(args);
213
214                 if (retval == -1) {
215                         /* -1 means not enough space, but on windows it may also mean
216                          * there is a formatting error, so we impose a maximum length */
217                         if (message != fixedmessage)
218                                 MEM_freeN(message);
219                         message = NULL;
220
221                         len *= 2;
222                         if (len > maxlen) {
223                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
224                                 break;
225                         }
226                 }
227                 else if (retval >= len) {
228                         /* in C99 the actual length required is returned */
229                         if (message != fixedmessage)
230                                 MEM_freeN(message);
231                         message = NULL;
232
233                         /* retval doesn't include \0 terminator */
234                         len = retval + 1;
235                 }
236                 else
237                         break;
238         }
239
240         if (message) {
241                 BLI_dynstr_append(ds, message);
242
243                 if (message != fixedmessage)
244                         MEM_freeN(message);
245         }
246 }
247
248 /**
249  * Find the length of a DynStr.
250  *
251  * \param ds The DynStr of interest.
252  * \return The length of \a ds.
253  */
254 int BLI_dynstr_get_len(DynStr *ds)
255 {
256         return ds->curlen;
257 }
258
259 /**
260  * Get a DynStr's contents as a c-string.
261  * <i> The str argument must be allocated to be at
262  * least the size of BLI_dynstr_get_len(ds) + 1. </i>
263  *
264  * \param ds The DynStr of interest.
265  * \param str The string to fill.
266  */
267 void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict rets)
268 {
269         char *s;
270         DynStrElem *dse;
271
272         for (s = rets, dse = ds->elems; dse; dse = dse->next) {
273                 int slen = strlen(dse->str);
274
275                 memcpy(s, dse->str, slen);
276
277                 s += slen;
278         }
279         BLI_assert((s - rets) == ds->curlen);
280         rets[ds->curlen] = '\0';
281 }
282
283 /**
284  * Get a DynStr's contents as a c-string.
285  * <i> The returned c-string should be freed
286  * using MEM_freeN. </i>
287  *
288  * \param ds The DynStr of interest.
289  * \return The contents of \a ds as a c-string.
290  */
291 char *BLI_dynstr_get_cstring(DynStr *ds)
292 {
293         char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
294         BLI_dynstr_get_cstring_ex(ds, rets);
295         return rets;
296 }
297
298 /**
299  * Free the DynStr
300  *
301  * \param ds The DynStr to free.
302  */
303 void BLI_dynstr_free(DynStr *ds)
304 {
305         DynStrElem *dse;
306         
307         for (dse = ds->elems; dse; ) {
308                 DynStrElem *n = dse->next;
309                 
310                 free(dse->str);
311                 free(dse);
312                 
313                 dse = n;
314         }
315         
316         MEM_freeN(ds);
317 }