mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2002,2010,2013 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 2004 g10 Code GmbH
4 * Copyright (C) 2018 Kevin J. McCarthy <kevin@8t8.us>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (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
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#if HAVE_CONFIG_H
22# include "config.h"
23#endif
24
25#include "mutt.h"
26#include "buffer.h"
27
28
29static size_t BufferPoolCount = 0;
30static size_t BufferPoolLen = 0;
31static BUFFER **BufferPool = NULL;
32
33
34/* Creates and initializes a BUFFER */
35BUFFER *mutt_buffer_new (void)
36{
37 BUFFER *b;
38
39 b = safe_malloc (sizeof(BUFFER));
40
41 mutt_buffer_init (b);
42
43 return b;
44}
45
46/* Initialize a new BUFFER */
47BUFFER *mutt_buffer_init (BUFFER *b)
48{
49 memset (b, 0, sizeof(BUFFER));
50 return b;
51}
52
53void mutt_buffer_free (BUFFER **p)
54{
55 if (!p || !*p)
56 return;
57
58 FREE (&(*p)->data);
59 /* dptr is just an offset to data and shouldn't be freed */
60 FREE (p); /* __FREE_CHECKED__ */
61}
62
63void mutt_buffer_clear (BUFFER *b)
64{
65 b->dptr = b->data;
66 if (b->dptr)
67 *(b->dptr) = '\0';
68}
69
70/* Creates and initializes a BUFFER by copying the seed string. */
71BUFFER *mutt_buffer_from (char *seed)
72{
73 BUFFER *b;
74
75 if (!seed)
76 return NULL;
77
78 b = mutt_buffer_new ();
79 b->data = safe_strdup (seed);
80 b->dsize = mutt_strlen (seed);
81 b->dptr = (char *) b->data + b->dsize;
82 return b;
83}
84
85size_t mutt_buffer_len (BUFFER *buf)
86{
87 return buf->dptr - buf->data;
88}
89
90/* Increases the allocated size of the buffer */
91void mutt_buffer_increase_size (BUFFER *buf, size_t new_size)
92{
93 size_t offset;
94
95 if (buf->dsize < new_size)
96 {
97 offset = buf->dptr - buf->data;
98 buf->dsize = new_size;
99 safe_realloc (&buf->data, buf->dsize);
100 buf->dptr = buf->data + offset;
101 /* This ensures an initially NULL buf->data is now properly terminated. */
102 *(buf->dptr) = '\0';
103 }
104}
105
106/* Ensure buffer->dptr points to the end of the buffer. */
107void mutt_buffer_fix_dptr (BUFFER *buf)
108{
109 buf->dptr = buf->data;
110
111 if (buf->data)
112 {
113 buf->data[buf->dsize - 1] = '\0';
114 buf->dptr = strchr (buf->data, '\0');
115 }
116}
117
118static int _mutt_buffer_add_printf (BUFFER* buf, const char* fmt, va_list ap)
119{
120 va_list ap_retry;
121 int len, blen, doff;
122
123 va_copy (ap_retry, ap);
124
125 if (!buf->dptr)
126 buf->dptr = buf->data;
127
128 doff = buf->dptr - buf->data;
129 blen = buf->dsize - doff;
130 /* solaris 9 vsnprintf barfs when blen is 0 */
131 if (!blen)
132 {
133 blen = 128;
134 mutt_buffer_increase_size (buf, buf->dsize + blen);
135 }
136 if ((len = vsnprintf (buf->dptr, blen, fmt, ap)) >= blen)
137 {
138 blen = ++len - blen;
139 if (blen < 128)
140 blen = 128;
141 mutt_buffer_increase_size (buf, buf->dsize + blen);
142 len = vsnprintf (buf->dptr, len, fmt, ap_retry);
143 }
144 if (len > 0)
145 buf->dptr += len;
146
147 va_end (ap_retry);
148
149 return len;
150}
151
152int mutt_buffer_printf (BUFFER* buf, const char* fmt, ...)
153{
154 va_list ap;
155 int rv;
156
157 va_start (ap, fmt);
158 mutt_buffer_clear (buf);
159 rv = _mutt_buffer_add_printf (buf, fmt, ap);
160 va_end (ap);
161
162 return rv;
163}
164
165int mutt_buffer_add_printf (BUFFER* buf, const char* fmt, ...)
166{
167 va_list ap;
168 int rv;
169
170 va_start (ap, fmt);
171 rv = _mutt_buffer_add_printf (buf, fmt, ap);
172 va_end (ap);
173
174 return rv;
175}
176
177/* Dynamically grows a BUFFER to accommodate s, in increments of 128 bytes.
178 * Always one byte bigger than necessary for the null terminator, and
179 * the buffer is always null-terminated */
180void mutt_buffer_addstr_n (BUFFER* buf, const char* s, size_t len)
181{
182 if (buf->dptr + len + 1 > buf->data + buf->dsize)
183 mutt_buffer_increase_size (buf, buf->dsize + (len < 128 ? 128 : len + 1));
184 memcpy (buf->dptr, s, len);
185 buf->dptr += len;
186 *(buf->dptr) = '\0';
187}
188
189void mutt_buffer_addstr (BUFFER* buf, const char* s)
190{
191 mutt_buffer_addstr_n (buf, s, mutt_strlen (s));
192}
193
194void mutt_buffer_addch (BUFFER* buf, char c)
195{
196 mutt_buffer_addstr_n (buf, &c, 1);
197}
198
199void mutt_buffer_strcpy (BUFFER *buf, const char *s)
200{
201 mutt_buffer_clear (buf);
202 mutt_buffer_addstr (buf, s);
203}
204
205void mutt_buffer_strcpy_n (BUFFER *buf, const char *s, size_t len)
206{
207 mutt_buffer_clear (buf);
208 mutt_buffer_addstr_n (buf, s, len);
209}
210
211void mutt_buffer_substrcpy (BUFFER *buf, const char *beg, const char *end)
212{
213 mutt_buffer_clear (buf);
214 if (end > beg)
215 mutt_buffer_strcpy_n (buf, beg, end - beg);
216}
217
218static void increase_buffer_pool (void)
219{
220 BUFFER *newbuf;
221
222 BufferPoolLen += 5;
223 safe_realloc (&BufferPool, BufferPoolLen * sizeof (BUFFER *));
224 while (BufferPoolCount < 5)
225 {
226 newbuf = mutt_buffer_new ();
227 mutt_buffer_increase_size (newbuf, LONG_STRING);
228 mutt_buffer_clear (newbuf);
229 BufferPool[BufferPoolCount++] = newbuf;
230 }
231}
232
233void mutt_buffer_pool_init (void)
234{
235 increase_buffer_pool ();
236}
237
238void mutt_buffer_pool_free (void)
239{
240 dprint (1, (debugfile,
241 "mutt_buffer_pool_free: %zu of %zu returned to pool\n",
242 BufferPoolCount, BufferPoolLen));
243
244 while (BufferPoolCount)
245 mutt_buffer_free (&BufferPool[--BufferPoolCount]);
246 FREE (&BufferPool);
247 BufferPoolLen = 0;
248}
249
250BUFFER *mutt_buffer_pool_get (void)
251{
252 if (!BufferPoolCount)
253 increase_buffer_pool ();
254 return BufferPool[--BufferPoolCount];
255}
256
257void mutt_buffer_pool_release (BUFFER **pbuf)
258{
259 BUFFER *buf;
260
261 if (!pbuf || !*pbuf)
262 return;
263
264 if (BufferPoolCount >= BufferPoolLen)
265 {
266 dprint (1, (debugfile, "Internal buffer pool error\n"));
267 mutt_buffer_free (pbuf);
268 return;
269 }
270
271 buf = *pbuf;
272 if (buf->dsize > LONG_STRING*2)
273 {
274 buf->dsize = LONG_STRING;
275 safe_realloc (&buf->data, buf->dsize);
276 }
277 mutt_buffer_clear (buf);
278 buf->destroy = 0;
279 BufferPool[BufferPoolCount++] = buf;
280
281 *pbuf = NULL;
282}