mutt stable branch with some hacks
at jcs 282 lines 6.3 kB view raw
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}