]> granicus.if.org Git - mutt/blob - buffer.c
Convert pgp_app_handler to use buffer pool.
[mutt] / buffer.c
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
29 static size_t BufferPoolCount = 0;
30 static size_t BufferPoolLen  = 0;
31 static BUFFER **BufferPool = NULL;
32
33
34 /* Creates and initializes a BUFFER */
35 BUFFER *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 */
47 BUFFER *mutt_buffer_init (BUFFER *b)
48 {
49   memset (b, 0, sizeof(BUFFER));
50   return b;
51 }
52
53 void 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
63 void 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. */
71 BUFFER *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
85 size_t mutt_buffer_len (BUFFER *buf)
86 {
87   return buf->dptr - buf->data;
88 }
89
90 /* Increases the allocated size of the buffer */
91 void 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. */
107 void 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
118 static 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
152 int 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
165 int 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 */
180 void 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
189 void mutt_buffer_addstr (BUFFER* buf, const char* s)
190 {
191   mutt_buffer_addstr_n (buf, s, mutt_strlen (s));
192 }
193
194 void mutt_buffer_addch (BUFFER* buf, char c)
195 {
196   mutt_buffer_addstr_n (buf, &c, 1);
197 }
198
199 void mutt_buffer_strcpy (BUFFER *buf, const char *s)
200 {
201   mutt_buffer_clear (buf);
202   mutt_buffer_addstr (buf, s);
203 }
204
205 void 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
211 void 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
218 static 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
233 void mutt_buffer_pool_init (void)
234 {
235   increase_buffer_pool ();
236 }
237
238 void 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
250 BUFFER *mutt_buffer_pool_get (void)
251 {
252   if (!BufferPoolCount)
253     increase_buffer_pool ();
254   return BufferPool[--BufferPoolCount];
255 }
256
257 void 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 }