patch [#29651] Add a __str__ Method to Matutils Matrices so print(matrix) Shows Colum...
[blender.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
34 #include <stdarg.h>
35 #include <string.h>
36
37 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.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 DynStr *BLI_dynstr_new(void)
72 {
73         DynStr *ds= MEM_mallocN(sizeof(*ds), "DynStr");
74         ds->elems= ds->last= NULL;
75         ds->curlen= 0;
76         
77         return ds;
78 }
79
80 void BLI_dynstr_append(DynStr *ds, const char *cstr)
81 {
82         DynStrElem *dse= malloc(sizeof(*dse));
83         int cstrlen= strlen(cstr);
84         
85         dse->str= malloc(cstrlen+1);
86         memcpy(dse->str, cstr, cstrlen+1);
87         dse->next= NULL;
88         
89         if (!ds->last)
90                 ds->last= ds->elems= dse;
91         else
92                 ds->last= ds->last->next= dse;
93
94         ds->curlen+= cstrlen;
95 }
96
97 void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len)
98 {
99         DynStrElem *dse= malloc(sizeof(*dse));
100         int cstrlen= BLI_strnlen(cstr, len);
101
102         dse->str= malloc(cstrlen+1);
103         memcpy(dse->str, cstr, cstrlen);
104         dse->str[cstrlen] = '\0';
105         dse->next= NULL;
106
107         if (!ds->last)
108                 ds->last= ds->elems= dse;
109         else
110                 ds->last= ds->last->next= dse;
111
112         ds->curlen+= cstrlen;
113 }
114
115 void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args)
116 {
117         char *message, fixedmessage[256];
118         int len= sizeof(fixedmessage);
119         const int maxlen= 65536;
120         int retval;
121
122         while(1) {
123                 va_list args_cpy;
124                 if(len == sizeof(fixedmessage))
125                         message= fixedmessage;
126                 else
127                         message= MEM_callocN(sizeof(char) * len, "BLI_dynstr_appendf");
128
129                 /* cant reuse the same args, so work on a copy */
130                 va_copy(args_cpy, args);
131                 retval= vsnprintf(message, len, format, args_cpy);
132                 va_end(args_cpy);
133
134                 if(retval == -1) {
135                         /* -1 means not enough space, but on windows it may also mean
136                          * there is a formatting error, so we impose a maximum length */
137                         if(message != fixedmessage)
138                                 MEM_freeN(message);
139                         message= NULL;
140
141                         len *= 2;
142                         if(len > maxlen) {
143                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
144                                 break;
145                         }
146                 }
147                 else if(retval >= len) {
148                         /* in C99 the actual length required is returned */
149                         if(message != fixedmessage)
150                                 MEM_freeN(message);
151                         message= NULL;
152
153                         /* retval doesnt include \0 terminator */
154                         len= retval + 1;
155                 }
156                 else
157                         break;
158         }
159
160         if(message) {
161                 BLI_dynstr_append(ds, message);
162
163                 if(message != fixedmessage)
164                         MEM_freeN(message);
165         }
166 }
167
168 void BLI_dynstr_appendf(DynStr *ds, const char *format, ...)
169 {
170         va_list args;
171         char *message, fixedmessage[256];
172         int len= sizeof(fixedmessage);
173         const int maxlen= 65536;
174         int retval;
175
176         /* note that it's tempting to just call BLI_dynstr_vappendf here
177          * and avoid code duplication, that crashes on some system because
178          * va_start/va_end have to be called for each vsnprintf call */
179
180         while(1) {
181                 if(len == sizeof(fixedmessage))
182                         message= fixedmessage;
183                 else
184                         message= MEM_callocN(sizeof(char)*(len), "BLI_dynstr_appendf");
185
186                 va_start(args, format);
187                 retval= vsnprintf(message, len, format, args);
188                 va_end(args);
189
190                 if(retval == -1) {
191                         /* -1 means not enough space, but on windows it may also mean
192                          * there is a formatting error, so we impose a maximum length */
193                         if(message != fixedmessage)
194                                 MEM_freeN(message);
195                         message= NULL;
196
197                         len *= 2;
198                         if(len > maxlen) {
199                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
200                                 break;
201                         }
202                 }
203                 else if(retval >= len) {
204                         /* in C99 the actual length required is returned */
205                         if(message != fixedmessage)
206                                 MEM_freeN(message);
207                         message= NULL;
208
209                         /* retval doesnt include \0 terminator */
210                         len= retval + 1;
211                 }
212                 else
213                         break;
214         }
215
216         if(message) {
217                 BLI_dynstr_append(ds, message);
218
219                 if(message != fixedmessage)
220                         MEM_freeN(message);
221         }
222 }
223
224 int BLI_dynstr_get_len(DynStr *ds)
225 {
226         return ds->curlen;
227 }
228
229 void BLI_dynstr_get_cstring_ex(DynStr *ds, char *rets)
230 {
231         char *s;
232         DynStrElem *dse;
233
234         for (s= rets, dse= ds->elems; dse; dse= dse->next) {
235                 int slen= strlen(dse->str);
236
237                 memcpy(s, dse->str, slen);
238
239                 s+= slen;
240         }
241         rets[ds->curlen]= '\0';
242 }
243
244 char *BLI_dynstr_get_cstring(DynStr *ds)
245 {
246         char *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring");
247         BLI_dynstr_get_cstring_ex(ds, rets);
248         return rets;
249 }
250
251 void BLI_dynstr_free(DynStr *ds)
252 {
253         DynStrElem *dse;
254         
255         for (dse= ds->elems; dse; ) {
256                 DynStrElem *n= dse->next;
257                 
258                 free(dse->str);
259                 free(dse);
260                 
261                 dse= n;
262         }
263         
264         MEM_freeN(ds);
265 }