Merge from 2.5 r20991 through r21037
[blender.git] / source / blender / blenlib / intern / BLI_dynstr.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Dynamically sized string ADT
29  */
30
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "MEM_guardedalloc.h"
37 #include "BLI_blenlib.h"
38 #include "BLI_dynstr.h"
39
40 #ifdef _WIN32
41 #ifndef vsnprintf
42 #define vsnprintf _vsnprintf
43 #endif
44 #endif
45
46 /***/
47
48 typedef struct DynStrElem DynStrElem;
49 struct DynStrElem {
50         DynStrElem *next;
51         
52         char *str;
53 };
54
55 struct DynStr {
56         DynStrElem *elems, *last;
57         int curlen;
58 };
59
60 /***/
61
62 DynStr *BLI_dynstr_new(void) {
63         DynStr *ds= MEM_mallocN(sizeof(*ds), "DynStr");
64         ds->elems= ds->last= NULL;
65         ds->curlen= 0;
66         
67         return ds;
68 }
69
70 void BLI_dynstr_append(DynStr *ds, const char *cstr) {
71         DynStrElem *dse= malloc(sizeof(*dse));
72         int cstrlen= strlen(cstr);
73         
74         dse->str= malloc(cstrlen+1);
75         memcpy(dse->str, cstr, cstrlen+1);
76         dse->next= NULL;
77         
78         if (!ds->last)
79                 ds->last= ds->elems= dse;
80         else
81                 ds->last= ds->last->next= dse;
82
83         ds->curlen+= cstrlen;
84 }
85
86 void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args)
87 {
88         char *message, fixedmessage[256];
89         int len= 256, maxlen= 65536, retval;
90
91         while(1) {
92                 if(len == sizeof(fixedmessage))
93                         message= fixedmessage;
94                 else
95                         message= MEM_callocN(sizeof(char)*(len+1), "BLI_dynstr_appendf");
96
97                 retval= vsnprintf(message, len, format, args);
98
99                 if(retval == -1) {
100                         /* -1 means not enough space, but on windows it may also mean
101                          * there is a formatting error, so we impose a maximum length */
102                         if(message != fixedmessage)
103                                 MEM_freeN(message);
104                         message= NULL;
105
106                         len *= 2;
107                         if(len > maxlen) {
108                                 fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
109                                 break;
110                         }
111                 }
112                 else if(retval > len) {
113                         /* in C99 the actual length required is returned */
114                         if(message != fixedmessage)
115                                 MEM_freeN(message);
116                         message= NULL;
117
118                         len= retval;
119                 }
120                 else
121                         break;
122         }
123
124         if(message) {
125                 BLI_dynstr_append(ds, message);
126
127                 if(message != fixedmessage)
128                         MEM_freeN(message);
129         }
130 }
131
132 void BLI_dynstr_appendf(DynStr *ds, const char *format, ...)
133 {
134         va_list args;
135         char *message, fixedmessage[256];
136         int len= 256, maxlen= 65536, retval;
137
138         /* note that it's tempting to just call BLI_dynstr_vappendf here
139          * and avoid code duplication, that crashes on some system because
140          * va_start/va_end have to be called for each vsnprintf call */
141
142         while(1) {
143                 if(len == sizeof(fixedmessage))
144                         message= fixedmessage;
145                 else
146                         message= MEM_callocN(sizeof(char)*(len+1), "BLI_dynstr_appendf");
147
148                 va_start(args, format);
149                 retval= vsnprintf(message, len, format, args);
150                 va_end(args);
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                         len= retval;
172                 }
173                 else
174                         break;
175         }
176
177         if(message) {
178                 BLI_dynstr_append(ds, message);
179
180                 if(message != fixedmessage)
181                         MEM_freeN(message);
182         }
183 }
184
185 int BLI_dynstr_get_len(DynStr *ds) {
186         return ds->curlen;
187 }
188
189 char *BLI_dynstr_get_cstring(DynStr *ds) {
190         char *s, *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring");
191         DynStrElem *dse;
192         
193         for (s= rets, dse= ds->elems; dse; dse= dse->next) {
194                 int slen= strlen(dse->str);
195
196                 memcpy(s, dse->str, slen);
197
198                 s+= slen;
199         }
200         rets[ds->curlen]= '\0';
201         
202         return rets;
203 }
204
205 void BLI_dynstr_free(DynStr *ds) {
206         DynStrElem *dse;
207         
208         for (dse= ds->elems; dse; ) {
209                 DynStrElem *n= dse->next;
210                 
211                 free(dse->str);
212                 free(dse);
213                 
214                 dse= n;
215         }
216         
217         MEM_freeN(ds);
218 }