NeoMutt  2022-04-29-145-g9b6a0e
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 
39 static const int BufferStepSize = 128;
40 
48 struct Buffer *mutt_buffer_init(struct Buffer *buf)
49 {
50  if (!buf)
51  return NULL;
52  memset(buf, 0, sizeof(struct Buffer));
53  return buf;
54 }
55 
63 struct Buffer mutt_buffer_make(size_t size)
64 {
65  struct Buffer buf = { 0 };
66  if (size != 0)
67  {
68  buf.dptr = buf.data = mutt_mem_calloc(1, size);
69  buf.dsize = size;
70  }
71  return buf;
72 }
73 
81 void mutt_buffer_reset(struct Buffer *buf)
82 {
83  if (!buf || !buf->data || (buf->dsize == 0))
84  return;
85  memset(buf->data, 0, buf->dsize);
86  mutt_buffer_seek(buf, 0);
87 }
88 
101 size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
102 {
103  if (!buf || !s)
104  return 0;
105 
106  if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
107  mutt_buffer_alloc(buf, buf->dsize + MAX(BufferStepSize, len + 1));
108 
109  memcpy(buf->dptr, s, len);
110  buf->dptr += len;
111  *(buf->dptr) = '\0';
112  return len;
113 }
114 
123 static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
124 {
125  if (!buf || !fmt)
126  return 0; /* LCOV_EXCL_LINE */
127 
128  mutt_buffer_alloc(buf, 128);
129 
130  int doff = buf->dptr - buf->data;
131  int blen = buf->dsize - doff;
132 
133  va_list ap_retry;
134  va_copy(ap_retry, ap);
135 
136  int len = vsnprintf(buf->dptr, blen, fmt, ap);
137  if (len >= blen)
138  {
139  mutt_buffer_alloc(buf, buf->dsize + len - blen + 1);
140  len = vsnprintf(buf->dptr, len + 1, fmt, ap_retry);
141  }
142  if (len > 0)
143  buf->dptr += len;
144 
145  va_end(ap_retry);
146 
147  return len;
148 }
149 
158 int mutt_buffer_printf(struct Buffer *buf, const char *fmt, ...)
159 {
160  if (!buf || !fmt)
161  return -1;
162 
163  va_list ap;
164 
165  va_start(ap, fmt);
166  mutt_buffer_reset(buf);
167  int len = buffer_printf(buf, fmt, ap);
168  va_end(ap);
169 
170  return len;
171 }
172 
179 void mutt_buffer_fix_dptr(struct Buffer *buf)
180 {
181  if (!buf)
182  return;
183 
184  mutt_buffer_seek(buf, 0);
185 
186  if (buf->data && (buf->dsize > 0))
187  {
188  buf->data[buf->dsize - 1] = '\0';
189  buf->dptr = strchr(buf->data, '\0');
190  }
191 }
192 
201 int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt, ...)
202 {
203  if (!buf || !fmt)
204  return -1;
205 
206  va_list ap;
207 
208  va_start(ap, fmt);
209  int len = buffer_printf(buf, fmt, ap);
210  va_end(ap);
211 
212  return len;
213 }
214 
223 size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
224 {
225  if (!buf || !s)
226  return 0;
227  return mutt_buffer_addstr_n(buf, s, mutt_str_len(s));
228 }
229 
238 size_t mutt_buffer_addch(struct Buffer *buf, char c)
239 {
240  if (!buf)
241  return 0;
242  return mutt_buffer_addstr_n(buf, &c, 1);
243 }
244 
250 bool mutt_buffer_is_empty(const struct Buffer *buf)
251 {
252  if (!buf || !buf->data)
253  return true;
254 
255  return (buf->data[0] == '\0');
256 }
257 
265 void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
266 {
267  if (!buf)
268  return;
269 
270  if (buf->data && (new_size > 0) && (new_size <= buf->dsize))
271  return;
272 
273  const bool was_empty = (buf->dptr == NULL);
274  const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
275 
276  buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
277  mutt_mem_realloc(&buf->data, buf->dsize);
278  mutt_buffer_seek(buf, offset);
279 
280  // Ensures that initially NULL buf->data is properly terminated
281  if (was_empty)
282  {
283  buf->dptr = buf->data;
284  *buf->dptr = '\0';
285  }
286 }
287 
292 void mutt_buffer_dealloc(struct Buffer *buf)
293 {
294  if (!buf || !buf->data)
295  return;
296 
297  buf->dptr = NULL;
298  buf->dsize = 0;
299  FREE(&buf->data);
300 }
301 
310 size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
311 {
312  mutt_buffer_reset(buf);
313  return mutt_buffer_addstr(buf, s);
314 }
315 
325 size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
326 {
327  mutt_buffer_reset(buf);
328  return mutt_buffer_addstr_n(buf, s, len);
329 }
330 
340 size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
341 {
342  mutt_buffer_reset(buf);
343  if (end <= beg)
344  return 0;
345 
346  return mutt_buffer_strcpy_n(buf, beg, end - beg);
347 }
348 
354 size_t mutt_buffer_len(const struct Buffer *buf)
355 {
356  if (!buf || !buf->data || !buf->dptr)
357  return 0;
358 
359  return buf->dptr - buf->data;
360 }
361 
372 size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
373 {
374  if (!buf)
375  return 0;
376 
377  if (!dir)
378  dir = "";
379  if (!fname)
380  fname = "";
381 
382  const bool d_set = (dir[0] != '\0');
383  const bool f_set = (fname[0] != '\0');
384  if (!d_set && !f_set)
385  return 0;
386 
387  const int d_len = strlen(dir);
388  const bool slash = d_set && (dir[d_len - 1] == '/');
389 
390  const char *fmt = "%s/%s";
391  if (!f_set || !d_set || slash)
392  fmt = "%s%s";
393 
394  return mutt_buffer_printf(buf, fmt, dir, fname);
395 }
396 
409 size_t mutt_buffer_concatn_path(struct Buffer *buf, const char *dir,
410  size_t dirlen, const char *fname, size_t fnamelen)
411 {
412  size_t len = 0;
413  mutt_buffer_reset(buf);
414  if (dirlen != 0)
415  len += mutt_buffer_addstr_n(buf, dir, dirlen);
416  if ((dirlen != 0) && (fnamelen != 0))
417  len += mutt_buffer_addch(buf, '/');
418  if (fnamelen != 0)
419  len += mutt_buffer_addstr_n(buf, fname, fnamelen);
420  return len;
421 }
422 
430 char *mutt_buffer_strdup(const struct Buffer *buf)
431 {
432  if (!buf)
433  return NULL;
434 
435  return mutt_str_dup(buf->data);
436 }
437 
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 }
456 
466 void mutt_buffer_seek(struct Buffer *buf, size_t offset)
467 {
468  if (buf)
469  buf->dptr = buf->data + offset;
470 }
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:63
static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:123
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
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:292
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:101
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:354
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:238
size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:340
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:223
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:430
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:179
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:48
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:409
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:201
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:466
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:158
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:445
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:81
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:325
static const int BufferStepSize
Definition: buffer.c:39
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:372
General purpose object for storing and parsing strings.
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
Memory management wrappers.
#define FREE(x)
Definition: memory.h:43
#define ROUND_UP(NUM, STEP)
Definition: memory.h:34
#define MAX(a, b)
Definition: memory.h:30
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
String manipulation functions.
String manipulation buffer.
Definition: buffer.h:34
char * dptr
Current read/write position.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35