NeoMutt  2023-05-17-56-ga67199
Teaching an old dog new tricks
DOXYGEN
buffer.c
Go to the documentation of this file.
1
32#include "config.h"
33#include <stdarg.h>
34#include <stdbool.h>
35#include <stdint.h>
36#include <stdio.h>
37#include <string.h>
38#include "buffer.h"
39#include "exit.h"
40#include "logging2.h"
41#include "memory.h"
42#include "message.h"
43#include "string2.h"
44
46static const int BufferStepSize = 128;
47
55struct Buffer *buf_init(struct Buffer *buf)
56{
57 if (!buf)
58 return NULL;
59 memset(buf, 0, sizeof(struct Buffer));
60 return buf;
61}
62
70struct Buffer buf_make(size_t size)
71{
72 struct Buffer buf = { 0 };
73 if (size != 0)
74 {
75 buf.dptr = buf.data = mutt_mem_calloc(1, size);
76 buf.dsize = size;
77 }
78 return buf;
79}
80
88void buf_reset(struct Buffer *buf)
89{
90 if (!buf || !buf->data || (buf->dsize == 0))
91 return;
92 memset(buf->data, 0, buf->dsize);
93 buf_seek(buf, 0);
94}
95
108size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
109{
110 if (!buf || !s)
111 return 0;
112
113 if (len > (SIZE_MAX - BufferStepSize))
114 {
115 // LCOV_EXCL_START
116 mutt_error(_("Out of memory"));
117 mutt_exit(1);
118 // LCOV_EXCL_STOP
119 }
120
121 if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
122 buf_alloc(buf, buf->dsize + MAX(BufferStepSize, len + 1));
123
124 memcpy(buf->dptr, s, len);
125 buf->dptr += len;
126 *(buf->dptr) = '\0';
127 return len;
128}
129
138static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
139{
140 if (!buf || !fmt)
141 return 0; /* LCOV_EXCL_LINE */
142
143 buf_alloc(buf, 128);
144
145 int doff = buf->dptr - buf->data;
146 int blen = buf->dsize - doff;
147
148 va_list ap_retry;
149 va_copy(ap_retry, ap);
150
151 int len = vsnprintf(buf->dptr, blen, fmt, ap);
152 if (len >= blen)
153 {
154 buf_alloc(buf, buf->dsize + len - blen + 1);
155 len = vsnprintf(buf->dptr, len + 1, fmt, ap_retry);
156 }
157 if (len > 0)
158 buf->dptr += len;
159
160 va_end(ap_retry);
161
162 return len;
163}
164
173int buf_printf(struct Buffer *buf, const char *fmt, ...)
174{
175 if (!buf || !fmt)
176 return -1;
177
178 va_list ap;
179
180 va_start(ap, fmt);
181 buf_reset(buf);
182 int len = buf_vaprintf(buf, fmt, ap);
183 va_end(ap);
184
185 return len;
186}
187
194void buf_fix_dptr(struct Buffer *buf)
195{
196 if (!buf)
197 return;
198
199 buf_seek(buf, 0);
200
201 if (buf->data && (buf->dsize > 0))
202 {
203 buf->data[buf->dsize - 1] = '\0';
204 buf->dptr = strchr(buf->data, '\0');
205 }
206}
207
216int buf_add_printf(struct Buffer *buf, const char *fmt, ...)
217{
218 if (!buf || !fmt)
219 return -1;
220
221 va_list ap;
222
223 va_start(ap, fmt);
224 int len = buf_vaprintf(buf, fmt, ap);
225 va_end(ap);
226
227 return len;
228}
229
238size_t buf_addstr(struct Buffer *buf, const char *s)
239{
240 if (!buf || !s)
241 return 0;
242 return buf_addstr_n(buf, s, mutt_str_len(s));
243}
244
253size_t buf_addch(struct Buffer *buf, char c)
254{
255 if (!buf)
256 return 0;
257 return buf_addstr_n(buf, &c, 1);
258}
259
268size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
269{
270 if (!buf || !s || (*s == '\0'))
271 {
272 return -1;
273 }
274
275 const size_t slen = mutt_str_len(s);
276 const size_t curlen = buf_len(buf);
277 buf_alloc(buf, curlen + slen + 1);
278
279 if (offset > curlen)
280 {
281 for (size_t i = curlen; i < offset; ++i)
282 {
283 buf_addch(buf, ' ');
284 }
285 buf_addstr(buf, s);
286 }
287 else
288 {
289 memmove(buf->data + offset + slen, buf->data + offset, curlen - offset);
290 memcpy(buf->data + offset, s, slen);
291 buf->data[curlen + slen] = '\0';
292 buf->dptr = buf->data + curlen + slen;
293 }
294
295 return buf_len(buf) - curlen;
296}
297
303bool buf_is_empty(const struct Buffer *buf)
304{
305 if (!buf || !buf->data)
306 return true;
307
308 return (buf->data[0] == '\0');
309}
310
316struct Buffer *buf_new(const char *str)
317{
318 struct Buffer *buf = mutt_mem_calloc(1, sizeof(struct Buffer));
319
320 if (str)
321 buf_addstr(buf, str);
322 return buf;
323}
324
329void buf_free(struct Buffer **ptr)
330{
331 if (!ptr || !*ptr)
332 return;
333
334 struct Buffer *buf = *ptr;
335 buf_dealloc(buf);
336
337 FREE(ptr);
338}
339
347void buf_alloc(struct Buffer *buf, size_t new_size)
348{
349 if (!buf)
350 return;
351
352 if (buf->data && (new_size <= buf->dsize))
353 return;
354
355 if (new_size > (SIZE_MAX - BufferStepSize))
356 {
357 // LCOV_EXCL_START
358 mutt_error(_("Out of memory"));
359 mutt_exit(1);
360 // LCOV_EXCL_STOP
361 }
362
363 const bool was_empty = (buf->dptr == NULL);
364 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
365
366 buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
367
368 mutt_mem_realloc(&buf->data, buf->dsize);
369 buf_seek(buf, offset);
370
371 // Ensures that initially NULL buf->data is properly terminated
372 if (was_empty)
373 {
374 buf->dptr = buf->data;
375 *buf->dptr = '\0';
376 }
377}
378
383void buf_dealloc(struct Buffer *buf)
384{
385 if (!buf || !buf->data)
386 return;
387
388 buf->dptr = NULL;
389 buf->dsize = 0;
390 FREE(&buf->data);
391}
392
401size_t buf_strcpy(struct Buffer *buf, const char *s)
402{
403 buf_reset(buf);
404 return buf_addstr(buf, s);
405}
406
416size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
417{
418 buf_reset(buf);
419 return buf_addstr_n(buf, s, len);
420}
421
429{
430 if (!buf)
431 return;
432
434 buf_fix_dptr(buf);
435}
436
446size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
447{
448 buf_reset(buf);
449 if (end <= beg)
450 return 0;
451
452 return buf_strcpy_n(buf, beg, end - beg);
453}
454
460size_t buf_len(const struct Buffer *buf)
461{
462 if (!buf || !buf->data || !buf->dptr)
463 return 0;
464
465 return buf->dptr - buf->data;
466}
467
478size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
479{
480 if (!buf)
481 return 0;
482
483 if (!dir)
484 dir = "";
485 if (!fname)
486 fname = "";
487
488 const bool d_set = (dir[0] != '\0');
489 const bool f_set = (fname[0] != '\0');
490 if (!d_set && !f_set)
491 return 0;
492
493 const int d_len = strlen(dir);
494 const bool slash = d_set && (dir[d_len - 1] == '/');
495
496 const char *fmt = "%s/%s";
497 if (!f_set || !d_set || slash)
498 fmt = "%s%s";
499
500 return buf_printf(buf, fmt, dir, fname);
501}
502
515size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen,
516 const char *fname, size_t fnamelen)
517{
518 size_t len = 0;
519 buf_reset(buf);
520 if (dirlen != 0)
521 len += buf_addstr_n(buf, dir, dirlen);
522 if ((dirlen != 0) && (fnamelen != 0))
523 len += buf_addch(buf, '/');
524 if (fnamelen != 0)
525 len += buf_addstr_n(buf, fname, fnamelen);
526 return len;
527}
528
536char *buf_strdup(const struct Buffer *buf)
537{
538 if (!buf)
539 return NULL;
540
541 return mutt_str_dup(buf->data);
542}
543
551struct Buffer *buf_dup(const struct Buffer *buf)
552{
553 if (!buf)
554 return NULL;
555
556 return buf_new(buf_string(buf));
557}
558
566size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
567{
568 if (!dst)
569 return 0;
570
571 buf_reset(dst);
572 if (!src || !src->data)
573 return 0;
574
575 return buf_addstr_n(dst, src->data, buf_len(src));
576}
577
587void buf_seek(struct Buffer *buf, size_t offset)
588{
589 if (buf && (offset < buf_len(buf)))
590 {
591 buf->dptr = buf->data ? buf->data + offset : NULL;
592 }
593}
594
602const char *buf_find_string(struct Buffer *buf, const char *s)
603{
604 if (!buf || !s)
605 return NULL;
606
607 return strstr(buf->data, s);
608}
609
617const char *buf_find_char(struct Buffer *buf, const char c)
618{
619 if (!buf)
620 return NULL;
621
622 return strchr(buf->data, c);
623}
624
632char buf_at(struct Buffer *buf, size_t offset)
633{
634 if (!buf || (offset > buf_len(buf)))
635 return '\0';
636
637 return buf->data[offset];
638}
639
647bool buf_str_equal(struct Buffer *a, struct Buffer *b)
648{
649 return mutt_str_equal(buf_string(a), buf_string(b));
650}
651
659bool buf_istr_equal(struct Buffer *a, struct Buffer *b)
660{
662}
663
672int buf_coll(struct Buffer *a, struct Buffer *b)
673{
674 return mutt_str_coll(buf_string(a), buf_string(b));
675}
676
683void buf_lower(struct Buffer *buf)
684{
685 if (!buf)
686 return;
687
688 mutt_str_lower(buf->data);
689}
690
697void buf_upper(struct Buffer *buf)
698{
699 if (!buf)
700 return;
701
702 mutt_str_upper(buf->data);
703}
bool buf_istr_equal(struct Buffer *a, struct Buffer *b)
Return if two buffers are equal, case insentive.
Definition: buffer.c:659
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:216
char buf_at(struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:632
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:587
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:108
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:460
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:383
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:88
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:303
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:70
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:194
static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:138
void buf_dequote_comment(struct Buffer *buf)
Un-escape characters in an email address comment.
Definition: buffer.c:428
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:329
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:55
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:416
size_t buf_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:515
const char * buf_find_string(struct Buffer *buf, const char *s)
Return a pointer to a substring found in the buffer.
Definition: buffer.c:602
bool buf_str_equal(struct Buffer *a, struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:647
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:316
void buf_upper(struct Buffer *buf)
Sets a buffer to uppercase.
Definition: buffer.c:697
const char * buf_find_char(struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition: buffer.c:617
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:253
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
int buf_coll(struct Buffer *a, struct Buffer *b)
Collate two strings (compare using locale)
Definition: buffer.c:672
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition: buffer.c:551
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:401
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:566
size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
Add a string in the middle of a buffer.
Definition: buffer.c:268
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:536
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:478
void buf_lower(struct Buffer *buf)
Sets a buffer to lowercase.
Definition: buffer.c:683
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:347
static const int BufferStepSize
When increasing the size of a Buffer, add this much extra space.
Definition: buffer.c:46
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:446
General purpose object for storing and parsing strings.
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:90
Leave the program NOW.
#define mutt_error(...)
Definition: logging2.h:90
Logging Dispatcher.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:241
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
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:810
void mutt_str_dequote_comment(char *str)
Un-escape characters in an email address comment.
Definition: string.c:766
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:251
char * mutt_str_upper(char *str)
Convert all characters in the string to uppercase.
Definition: string.c:408
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:385
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:798
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
int mutt_str_coll(const char *a, const char *b)
Collate two strings (compare using locale), safely.
Definition: string.c:581
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