2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323...
[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
136         va_start(args, format);
137         BLI_dynstr_vappendf(ds, format, args);
138         va_end(args);
139 }
140
141 int BLI_dynstr_get_len(DynStr *ds) {
142         return ds->curlen;
143 }
144
145 char *BLI_dynstr_get_cstring(DynStr *ds) {
146         char *s, *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring");
147         DynStrElem *dse;
148         
149         for (s= rets, dse= ds->elems; dse; dse= dse->next) {
150                 int slen= strlen(dse->str);
151
152                 memcpy(s, dse->str, slen);
153
154                 s+= slen;
155         }
156         rets[ds->curlen]= '\0';
157         
158         return rets;
159 }
160
161 void BLI_dynstr_free(DynStr *ds) {
162         DynStrElem *dse;
163         
164         for (dse= ds->elems; dse; ) {
165                 DynStrElem *n= dse->next;
166                 
167                 free(dse->str);
168                 free(dse);
169                 
170                 dse= n;
171         }
172         
173         MEM_freeN(ds);
174 }