NeoMutt  2022-04-29-249-gaae397
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 <stdint.h>
34#include <stdio.h>
35#include <string.h>
36#include "buffer.h"
37#include "exit.h"
38#include "logging.h"
39#include "memory.h"
40#include "message.h"
41#include "string2.h"
42
43static const int BufferStepSize = 128;
44
52struct Buffer *mutt_buffer_init(struct Buffer *buf)
53{
54 if (!buf)
55 return NULL;
56 memset(buf, 0, sizeof(struct Buffer));
57 return buf;
58}
59
67struct Buffer mutt_buffer_make(size_t size)
68{
69 struct Buffer buf = { 0 };
70 if (size != 0)
71 {
72 buf.dptr = buf.data = mutt_mem_calloc(1, size);
73 buf.dsize = size;
74 }
75 return buf;
76}
77
85void mutt_buffer_reset(struct Buffer *buf)
86{
87 if (!buf || !buf->data || (buf->dsize == 0))
88 return;
89 memset(buf->data, 0, buf->dsize);
90 mutt_buffer_seek(buf, 0);
91}
92
105size_t mutt_buffer_addstr_n(struct Buffer *buf, const char *s, size_t len)
106{
107 if (!buf || !s)
108 return 0;
109
110 if (len > (SIZE_MAX - BufferStepSize))
111 {
112 mutt_error(_("Out of memory"));
113 mutt_exit(1);
114 }
115
116 if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
117 mutt_buffer_alloc(buf, buf->dsize + MAX(BufferStepSize, len + 1));
118
119 memcpy(buf->dptr, s, len);
120 buf->dptr += len;
121 *(buf->dptr) = '\0';
122 return len;
123}
124
133static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
134{
135 if (!buf || !fmt)
136 return 0; /* LCOV_EXCL_LINE */
137
138 mutt_buffer_alloc(buf, 128);
139
140 int doff = buf->dptr - buf->data;
141 int blen = buf->dsize - doff;
142
143 va_list ap_retry;
144 va_copy(ap_retry, ap);
145
146 int len = vsnprintf(buf->dptr, blen, fmt, ap);
147 if (len >= blen)
148 {
149 mutt_buffer_alloc(buf, buf->dsize + len - blen + 1);
150 len = vsnprintf(buf->dptr, len + 1, fmt, ap_retry);
151 }
152 if (len > 0)
153 buf->dptr += len;
154
155 va_end(ap_retry);
156
157 return len;
158}
159
168int mutt_buffer_printf(struct Buffer *buf, const char *fmt, ...)
169{
170 if (!buf || !fmt)
171 return -1;
172
173 va_list ap;
174
175 va_start(ap, fmt);
177 int len = buffer_printf(buf, fmt, ap);
178 va_end(ap);
179
180 return len;
181}
182
190{
191 if (!buf)
192 return;
193
194 mutt_buffer_seek(buf, 0);
195
196 if (buf->data && (buf->dsize > 0))
197 {
198 buf->data[buf->dsize - 1] = '\0';
199 buf->dptr = strchr(buf->data, '\0');
200 }
201}
202
211int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt, ...)
212{
213 if (!buf || !fmt)
214 return -1;
215
216 va_list ap;
217
218 va_start(ap, fmt);
219 int len = buffer_printf(buf, fmt, ap);
220 va_end(ap);
221
222 return len;
223}
224
233size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
234{
235 if (!buf || !s)
236 return 0;
237 return mutt_buffer_addstr_n(buf, s, mutt_str_len(s));
238}
239
248size_t mutt_buffer_addch(struct Buffer *buf, char c)
249{
250 if (!buf)
251 return 0;
252 return mutt_buffer_addstr_n(buf, &c, 1);
253}
254
260bool mutt_buffer_is_empty(const struct Buffer *buf)
261{
262 if (!buf || !buf->data)
263 return true;
264
265 return (buf->data[0] == '\0');
266}
267
275void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
276{
277 if (!buf)
278 return;
279
280 if (buf->data && (new_size <= buf->dsize))
281 return;
282
283 if (new_size > (SIZE_MAX - BufferStepSize))
284 {
285 mutt_error(_("Out of memory"));
286 mutt_exit(1);
287 }
288
289 const bool was_empty = (buf->dptr == NULL);
290 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
291
292 buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
293
294 mutt_mem_realloc(&buf->data, buf->dsize);
295 mutt_buffer_seek(buf, offset);
296
297 // Ensures that initially NULL buf->data is properly terminated
298 if (was_empty)
299 {
300 buf->dptr = buf->data;
301 *buf->dptr = '\0';
302 }
303}
304
310{
311 if (!buf || !buf->data)
312 return;
313
314 buf->dptr = NULL;
315 buf->dsize = 0;
316 FREE(&buf->data);
317}
318
327size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
328{
330 return mutt_buffer_addstr(buf, s);
331}
332
342size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
343{
345 return mutt_buffer_addstr_n(buf, s, len);
346}
347
357size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
358{
360 if (end <= beg)
361 return 0;
362
363 return mutt_buffer_strcpy_n(buf, beg, end - beg);
364}
365
371size_t mutt_buffer_len(const struct Buffer *buf)
372{
373 if (!buf || !buf->data || !buf->dptr)
374 return 0;
375
376 return buf->dptr - buf->data;
377}
378
389size_t mutt_buffer_concat_path(struct Buffer *buf, const char *dir, const char *fname)
390{
391 if (!buf)
392 return 0;
393
394 if (!dir)
395 dir = "";
396 if (!fname)
397 fname = "";
398
399 const bool d_set = (dir[0] != '\0');
400 const bool f_set = (fname[0] != '\0');
401 if (!d_set && !f_set)
402 return 0;
403
404 const int d_len = strlen(dir);
405 const bool slash = d_set && (dir[d_len - 1] == '/');
406
407 const char *fmt = "%s/%s";
408 if (!f_set || !d_set || slash)
409 fmt = "%s%s";
410
411 return mutt_buffer_printf(buf, fmt, dir, fname);
412}
413
426size_t mutt_buffer_concatn_path(struct Buffer *buf, const char *dir,
427 size_t dirlen, const char *fname, size_t fnamelen)
428{
429 size_t len = 0;
431 if (dirlen != 0)
432 len += mutt_buffer_addstr_n(buf, dir, dirlen);
433 if ((dirlen != 0) && (fnamelen != 0))
434 len += mutt_buffer_addch(buf, '/');
435 if (fnamelen != 0)
436 len += mutt_buffer_addstr_n(buf, fname, fnamelen);
437 return len;
438}
439
447char *mutt_buffer_strdup(const struct Buffer *buf)
448{
449 if (!buf)
450 return NULL;
451
452 return mutt_str_dup(buf->data);
453}
454
462size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
463{
464 if (!dst)
465 return 0;
466
468 if (!src || !src->data)
469 return 0;
470
471 return mutt_buffer_addstr_n(dst, src->data, mutt_buffer_len(src));
472}
473
483void mutt_buffer_seek(struct Buffer *buf, size_t offset)
484{
485 if (buf)
486 {
487 buf->dptr = buf->data ? buf->data + offset : NULL;
488 }
489}
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:67
static int buffer_printf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:133
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:275
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:260
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:327
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:309
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:105
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:371
struct Buffer * mutt_buffer_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:52
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:248
size_t mutt_buffer_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:357
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:233
void mutt_buffer_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:189
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:426
int mutt_buffer_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:211
void mutt_buffer_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:483
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:168
size_t mutt_buffer_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:462
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:85
size_t mutt_buffer_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:342
static const int BufferStepSize
Definition: buffer.c:43
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:447
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:389
General purpose object for storing and parsing strings.
Leave the program NOW.
#define mutt_error(...)
Definition: logging.h:87
Logging Dispatcher.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:248
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
Message logging.
#define _(a)
Definition: message.h:28
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:567
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