Blender  V3.3
BLI_dynstr.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
9 #include <stdio.h>
10 #include <stdlib.h> /* malloc */
11 #include <string.h>
12 
13 #include "BLI_dynstr.h"
14 #include "BLI_memarena.h"
15 #include "BLI_string.h"
16 #include "BLI_utildefines.h"
17 #include "MEM_guardedalloc.h"
18 
19 #ifdef _WIN32
20 # ifndef vsnprintf
21 # define vsnprintf _vsnprintf
22 # endif
23 #endif
24 
25 #ifndef va_copy
26 # ifdef __va_copy
27 # define va_copy(a, b) __va_copy(a, b)
28 # else /* !__va_copy */
29 # define va_copy(a, b) ((a) = (b))
30 # endif /* __va_copy */
31 #endif /* va_copy */
32 
33 /***/
34 
35 typedef struct DynStrElem DynStrElem;
36 struct DynStrElem {
38 
39  char *str;
40 };
41 
42 struct DynStr {
44  int curlen;
46 };
47 
48 /***/
49 
51 {
52  DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
53  ds->elems = ds->last = NULL;
54  ds->curlen = 0;
55  ds->memarena = NULL;
56 
57  return ds;
58 }
59 
61 {
62  DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
63  ds->elems = ds->last = NULL;
64  ds->curlen = 0;
66 
67  return ds;
68 }
69 
70 BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
71 {
72  return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
73 }
74 
75 void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
76 {
77  DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
78  int cstrlen = strlen(cstr);
79 
80  dse->str = dynstr_alloc(ds, cstrlen + 1);
81  memcpy(dse->str, cstr, cstrlen + 1);
82  dse->next = NULL;
83 
84  if (!ds->last) {
85  ds->last = ds->elems = dse;
86  }
87  else {
88  ds->last = ds->last->next = dse;
89  }
90 
91  ds->curlen += cstrlen;
92 }
93 
94 void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
95 {
96  DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
97  int cstrlen = BLI_strnlen(cstr, len);
98 
99  dse->str = dynstr_alloc(ds, cstrlen + 1);
100  memcpy(dse->str, cstr, cstrlen);
101  dse->str[cstrlen] = '\0';
102  dse->next = NULL;
103 
104  if (!ds->last) {
105  ds->last = ds->elems = dse;
106  }
107  else {
108  ds->last = ds->last->next = dse;
109  }
110 
111  ds->curlen += cstrlen;
112 }
113 
114 void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
115 {
116  char *message, fixedmessage[256];
117  int len = sizeof(fixedmessage);
118  const int maxlen = 65536;
119  int retval;
120 
121  while (1) {
122  va_list args_cpy;
123  if (len == sizeof(fixedmessage)) {
124  message = fixedmessage;
125  }
126  else {
127  message = MEM_callocN(sizeof(char) * len, "BLI_dynstr_appendf");
128  }
129 
130  /* can't reuse the same args, so work on a copy */
131  va_copy(args_cpy, args);
132  retval = vsnprintf(message, len, format, args_cpy);
133  va_end(args_cpy);
134 
135  if (retval == -1) {
136  /* -1 means not enough space, but on windows it may also mean
137  * there is a formatting error, so we impose a maximum length */
138  if (message != fixedmessage) {
139  MEM_freeN(message);
140  }
141  message = NULL;
142 
143  len *= 2;
144  if (len > maxlen) {
145  fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
146  break;
147  }
148  }
149  else if (retval >= len) {
150  /* in C99 the actual length required is returned */
151  if (message != fixedmessage) {
152  MEM_freeN(message);
153  }
154  message = NULL;
155 
156  /* retval doesn't include \0 terminator */
157  len = retval + 1;
158  }
159  else {
160  break;
161  }
162  }
163 
164  if (message) {
165  BLI_dynstr_append(ds, message);
166 
167  if (message != fixedmessage) {
168  MEM_freeN(message);
169  }
170  }
171 }
172 
173 void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
174 {
175  va_list args;
176  char *message, fixedmessage[256];
177  int len = sizeof(fixedmessage);
178  const int maxlen = 65536;
179  int retval;
180 
181  /* note that it's tempting to just call BLI_dynstr_vappendf here
182  * and avoid code duplication, that crashes on some system because
183  * va_start/va_end have to be called for each vsnprintf call */
184 
185  while (1) {
186  if (len == sizeof(fixedmessage)) {
187  message = fixedmessage;
188  }
189  else {
190  message = MEM_callocN(sizeof(char) * (len), "BLI_dynstr_appendf");
191  }
192 
193  va_start(args, format);
194  retval = vsnprintf(message, len, format, args);
195  va_end(args);
196 
197  if (retval == -1) {
198  /* -1 means not enough space, but on windows it may also mean
199  * there is a formatting error, so we impose a maximum length */
200  if (message != fixedmessage) {
201  MEM_freeN(message);
202  }
203  message = NULL;
204 
205  len *= 2;
206  if (len > maxlen) {
207  fprintf(stderr, "BLI_dynstr_append text too long or format error.\n");
208  break;
209  }
210  }
211  else if (retval >= len) {
212  /* in C99 the actual length required is returned */
213  if (message != fixedmessage) {
214  MEM_freeN(message);
215  }
216  message = NULL;
217 
218  /* retval doesn't include \0 terminator */
219  len = retval + 1;
220  }
221  else {
222  break;
223  }
224  }
225 
226  if (message) {
227  BLI_dynstr_append(ds, message);
228 
229  if (message != fixedmessage) {
230  MEM_freeN(message);
231  }
232  }
233 }
234 
236 {
237  return ds->curlen;
238 }
239 
240 void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
241 {
242  char *s;
243  const DynStrElem *dse;
244 
245  for (s = rets, dse = ds->elems; dse; dse = dse->next) {
246  int slen = strlen(dse->str);
247 
248  memcpy(s, dse->str, slen);
249 
250  s += slen;
251  }
252  BLI_assert((s - rets) == ds->curlen);
253  rets[ds->curlen] = '\0';
254 }
255 
257 {
258  char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
259  BLI_dynstr_get_cstring_ex(ds, rets);
260  return rets;
261 }
262 
264 {
265  if (ds->memarena) {
267  }
268  else {
269  for (DynStrElem *dse_next, *dse = ds->elems; dse; dse = dse_next) {
270  dse_next = dse->next;
271 
272  free(dse->str);
273  free(dse);
274  }
275  }
276 
277  ds->elems = ds->last = NULL;
278  ds->curlen = 0;
279 }
280 
282 {
283  if (ds->memarena) {
285  }
286  else {
287  BLI_dynstr_clear(ds);
288  }
289 
290  MEM_freeN(ds);
291 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...)
Definition: BLI_dynstr.c:173
void BLI_dynstr_free(DynStr *ds)
Definition: BLI_dynstr.c:281
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
Definition: BLI_dynstr.c:94
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
Definition: BLI_dynstr.c:240
#define va_copy(a, b)
Definition: BLI_dynstr.c:29
void BLI_dynstr_clear(DynStr *ds)
Definition: BLI_dynstr.c:263
BLI_INLINE void * dynstr_alloc(DynStr *__restrict ds, size_t size)
Definition: BLI_dynstr.c:70
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
Definition: BLI_dynstr.c:75
char * BLI_dynstr_get_cstring(const DynStr *ds)
Definition: BLI_dynstr.c:256
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
Definition: BLI_dynstr.c:114
DynStr * BLI_dynstr_new_memarena(void)
Definition: BLI_dynstr.c:60
int BLI_dynstr_get_len(const DynStr *ds)
Definition: BLI_dynstr.c:235
DynStr * BLI_dynstr_new(void)
Definition: BLI_dynstr.c:50
A dynamically sized string ADT.
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:20
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:116
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:208
size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:899
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
int len
Definition: draw_manager.c:108
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
DynStrElem * next
Definition: BLI_dynstr.c:37
char * str
Definition: BLI_dynstr.c:39
MemArena * memarena
Definition: BLI_dynstr.c:45
DynStrElem * last
Definition: BLI_dynstr.c:43
int curlen
Definition: BLI_dynstr.c:44
DynStrElem * elems
Definition: BLI_dynstr.c:43