NeoMutt  2019-11-11
Teaching an old dog new tricks
DOXYGEN
buffer.c
Go to the documentation of this file.
1 
30 #include "config.h"
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include "buffer.h"
36 #include "memory.h"
37 #include "string2.h"
38 
46 struct Buffer *mutt_buffer_init(struct Buffer *buf)
47 {
48  if (!buf)
49  return NULL;
50  memset(buf, 0, sizeof(struct Buffer));
51  return buf;
52 }
53 
61 struct Buffer mutt_buffer_make(size_t size)
62 {
63  struct Buffer buf = { 0 };
64  if (size != 0)
65  {
66  buf.dptr = buf.data = mutt_mem_calloc(1, size);
67  buf.dsize = size;
68  }
69  return buf;
70 }
71 
79 void mutt_buffer_reset(struct Buffer *buf)
80 {
81  if (!buf || !buf->data || (buf->dsize == 0))
82  return;
83  memset(buf->data, 0, buf->dsize);
84  buf->dptr = buf->data;
85 }
86 
99 size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
100 {
101  if (!buf || !s)
102  return 0;
103 
104  if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
105  mutt_buffer_alloc(buf, buf->dsize + MAX(128, len + 1));
106 
107  memcpy(buf->dptr, s, len);
108  buf->dptr += len;
109  *(buf->dptr) = '\0';
110  return len;
111 }
112 
121 static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
122 {
123  if (!buf || !fmt)
124  return 0; /* LCOV_EXCL_LINE */
125 
126  if (!buf->data || !buf->dptr || (buf->dsize < 128))
127  mutt_buffer_alloc(buf, 128);
128 
129  int doff = buf->dptr - buf->data;
130  int blen = buf->dsize - doff;
131 
132  va_list ap_retry;
133  va_copy(ap_retry, ap);
134 
135  int len = vsnprintf(buf->dptr, blen, fmt, ap);
136  if (len >= blen)
137  {
138  blen = ++len - blen;
139  if (blen < 128)
140  blen = 128;
141  mutt_buffer_alloc(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 
160 int mutt_buffer_printf(struct Buffer *buf, const char *fmt, ...)
161 {
162  if (!buf || !fmt)
163  return -1;
164 
165  va_list ap;
166 
167  va_start(ap, fmt);
168  mutt_buffer_reset(buf);
169  int len = buffer_printf(buf, fmt, ap);
170  va_end(ap);
171 
172  return len;
173 }
174 
181 void mutt_buffer_fix_dptr(struct Buffer *buf)
182 {
183  if (!buf)
184  return;
185 
186  buf->dptr = buf->data;
187 
188  if (buf->data && (buf->dsize > 0))
189  {
190  buf->data[buf->dsize - 1] = '\0';
191  buf->dptr = strchr(buf->data, '\0');
192  }
193 }
194 
203 int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt, ...)
204 {
205  if (!buf || !fmt)
206  return -1;
207 
208  va_list ap;
209 
210  va_start(ap, fmt);
211  int len = buffer_printf(buf, fmt, ap);
212  va_end(ap);
213 
214  return len;
215 }
216 
225 size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
226 {
227  if (!buf || !s)
228  return 0;
229  return mutt_buffer_addstr_n(buf, s, mutt_str_strlen(s));
230 }
231 
240 size_t mutt_buffer_addch(struct Buffer *buf, char c)
241 {
242  if (!buf)
243  return 0;
244  return mutt_buffer_addstr_n(buf, &c, 1);
245 }
246 
252 bool mutt_buffer_is_empty(const struct Buffer *buf)
253 {
254  if (!buf || !buf->data)
255  return true;
256 
257  return (buf->data[0] == '\0');
258 }
259 
265 void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
266 {
267  if (!buf)
268  {
269  return;
270  }
271 
272  if (!buf->dptr)
273  {
274  buf->dptr = buf->data;
275  }
276 
277  if ((new_size > buf->dsize) || !buf->data)
278  {
279  size_t offset = (buf->dptr && buf->data) ? buf->dptr - buf->data : 0;
280 
281  buf->dsize = new_size;
282  mutt_mem_realloc(&buf->data, buf->dsize);
283  buf->dptr = buf->data + offset;
284  /* This ensures an initially NULL buf->data is now properly terminated. */
285  if (buf->dptr)
286  *buf->dptr = '\0';
287  }
288 }
289 
294 void mutt_buffer_dealloc(struct Buffer *buf)
295 {
296  if (!buf || !buf->data)
297  return;
298 
299  buf->dptr = NULL;
300  buf->dsize = 0;
301  FREE(&buf->data);
302 }
303 
312 size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
313 {
314  mutt_buffer_reset(buf);
315  return mutt_buffer_addstr(buf, s);
316 }
317 
327 size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
328 {
329  mutt_buffer_reset(buf);
330  return mutt_buffer_addstr_n(buf, s, len);
331 }
332 
342 size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
343 {
344  mutt_buffer_reset(buf);
345  if (end <= beg)
346  return 0;
347 
348  return mutt_buffer_strcpy_n(buf, beg, end - beg);
349 }
350 
356 size_t mutt_buffer_len(const struct Buffer *buf)
357 {
358  if (!buf || !buf->data || !buf->dptr)
359  return 0;
360 
361  return buf->dptr - buf->data;
362 }
363 
374 size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
375 {
376  if (!buf)
377  return 0;
378 
379  if (!dir)
380  dir = "";
381  if (!fname)
382  fname = "";
383 
384  const bool d_set = (dir[0] != '\0');
385  const bool f_set = (fname[0] != '\0');
386  if (!d_set && !f_set)
387  return 0;
388 
389  const int d_len = strlen(dir);
390  const bool slash = d_set && (dir[d_len - 1] == '/');
391 
392  const char *fmt = "%s/%s";
393  if (!f_set || !d_set || slash)
394  fmt = "%s%s";
395 
396  return mutt_buffer_printf(buf, fmt, dir, fname);
397 }
398 
411 size_t mutt_buffer_concatn_path(struct Buffer *buf, const char *dir,
412  size_t dirlen, const char *fname, size_t fnamelen)
413 {
414  size_t len = 0;
415  mutt_buffer_reset(buf);
416  if (dirlen != 0)
417  len += mutt_buffer_addstr_n(buf, dir, dirlen);
418  if ((dirlen != 0) && (fnamelen != 0))
419  len += mutt_buffer_addch(buf, '/');
420  if (fnamelen != 0)
421  len += mutt_buffer_addstr_n(buf, fname, fnamelen);
422  return len;
423 }
424 
432 char *mutt_buffer_strdup(struct Buffer *buf)
433 {
434  if (!buf)
435  return NULL;
436 
437  return mutt_str_strdup(buf->data);
438 }
439 
445 size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
446 {
447  if (!dst)
448  return 0;
449 
450  mutt_buffer_reset(dst);
451  if (!src || !src->data)
452  return 0;
453 
454  return mutt_buffer_addstr_n(dst, src->data, mutt_buffer_len(src));
455 }
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
Memory management wrappers.
static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:121
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer&#39;s contents to another Buffer.
Definition: buffer.c:445
size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:342
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
String manipulation buffer.
Definition: buffer.h:33
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:666
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
String manipulation functions.
#define MAX(a, b)
Definition: memory.h:30
size_t dsize
Length of data.
Definition: buffer.h:37
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:203
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:181
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:327
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:99
char * data
Pointer to data.
Definition: buffer.h:35
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
size_t mutt_buffer_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen, const char *fname, size_t fnamelen)
Join a directory name and a filename.
Definition: buffer.c:411
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
General purpose object for storing and parsing strings.
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
#define FREE(x)
Definition: memory.h:40
size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:374
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:46
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265