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>
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.
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.
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.
29 static size_t BufferPoolCount = 0;
30 static size_t BufferPoolLen = 0;
31 static BUFFER **BufferPool = NULL;
34 /* Creates and initializes a BUFFER */
35 BUFFER *mutt_buffer_new (void)
39 b = safe_malloc (sizeof(BUFFER));
46 /* Initialize a new BUFFER */
47 BUFFER *mutt_buffer_init (BUFFER *b)
49 memset (b, 0, sizeof(BUFFER));
53 void mutt_buffer_free (BUFFER **p)
59 /* dptr is just an offset to data and shouldn't be freed */
60 FREE (p); /* __FREE_CHECKED__ */
63 void mutt_buffer_clear (BUFFER *b)
70 /* Creates and initializes a BUFFER by copying the seed string. */
71 BUFFER *mutt_buffer_from (char *seed)
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;
85 size_t mutt_buffer_len (BUFFER *buf)
87 return buf->dptr - buf->data;
90 /* Increases the allocated size of the buffer */
91 void mutt_buffer_increase_size (BUFFER *buf, size_t new_size)
95 if (buf->dsize < new_size)
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. */
106 /* Ensure buffer->dptr points to the end of the buffer. */
107 void mutt_buffer_fix_dptr (BUFFER *buf)
109 buf->dptr = buf->data;
113 buf->data[buf->dsize - 1] = '\0';
114 buf->dptr = strchr (buf->data, '\0');
118 static int _mutt_buffer_add_printf (BUFFER* buf, const char* fmt, va_list ap)
123 va_copy (ap_retry, ap);
126 buf->dptr = buf->data;
128 doff = buf->dptr - buf->data;
129 blen = buf->dsize - doff;
130 /* solaris 9 vsnprintf barfs when blen is 0 */
134 mutt_buffer_increase_size (buf, buf->dsize + blen);
136 if ((len = vsnprintf (buf->dptr, blen, fmt, ap)) >= blen)
141 mutt_buffer_increase_size (buf, buf->dsize + blen);
142 len = vsnprintf (buf->dptr, len, fmt, ap_retry);
152 int mutt_buffer_printf (BUFFER* buf, const char* fmt, ...)
158 mutt_buffer_clear (buf);
159 rv = _mutt_buffer_add_printf (buf, fmt, ap);
165 int mutt_buffer_add_printf (BUFFER* buf, const char* fmt, ...)
171 rv = _mutt_buffer_add_printf (buf, fmt, ap);
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 */
180 void mutt_buffer_addstr_n (BUFFER* buf, const char* s, size_t len)
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);
189 void mutt_buffer_addstr (BUFFER* buf, const char* s)
191 mutt_buffer_addstr_n (buf, s, mutt_strlen (s));
194 void mutt_buffer_addch (BUFFER* buf, char c)
196 mutt_buffer_addstr_n (buf, &c, 1);
199 void mutt_buffer_strcpy (BUFFER *buf, const char *s)
201 mutt_buffer_clear (buf);
202 mutt_buffer_addstr (buf, s);
205 void mutt_buffer_strcpy_n (BUFFER *buf, const char *s, size_t len)
207 mutt_buffer_clear (buf);
208 mutt_buffer_addstr_n (buf, s, len);
211 void mutt_buffer_substrcpy (BUFFER *buf, const char *beg, const char *end)
213 mutt_buffer_clear (buf);
215 mutt_buffer_strcpy_n (buf, beg, end - beg);
218 static void increase_buffer_pool (void)
223 safe_realloc (&BufferPool, BufferPoolLen * sizeof (BUFFER *));
224 while (BufferPoolCount < 5)
226 newbuf = mutt_buffer_new ();
227 mutt_buffer_increase_size (newbuf, LONG_STRING);
228 mutt_buffer_clear (newbuf);
229 BufferPool[BufferPoolCount++] = newbuf;
233 void mutt_buffer_pool_init (void)
235 increase_buffer_pool ();
238 void mutt_buffer_pool_free (void)
240 dprint (1, (debugfile,
241 "mutt_buffer_pool_free: %zu of %zu returned to pool\n",
242 BufferPoolCount, BufferPoolLen));
244 while (BufferPoolCount)
245 mutt_buffer_free (&BufferPool[--BufferPoolCount]);
250 BUFFER *mutt_buffer_pool_get (void)
252 if (!BufferPoolCount)
253 increase_buffer_pool ();
254 return BufferPool[--BufferPoolCount];
257 void mutt_buffer_pool_release (BUFFER **pbuf)
264 if (BufferPoolCount >= BufferPoolLen)
266 dprint (1, (debugfile, "Internal buffer pool error\n"));
267 mutt_buffer_free (pbuf);
272 if (buf->dsize > LONG_STRING*2)
274 buf->dsize = LONG_STRING;
275 safe_realloc (&buf->data, buf->dsize);
277 mutt_buffer_clear (buf);
279 BufferPool[BufferPoolCount++] = buf;