NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
buffer.c
Go to the documentation of this file.
1
27
36
37#include "config.h"
38#include <stdarg.h>
39#include <stdbool.h>
40#include <stdio.h>
41#include <string.h>
42#include "buffer.h"
43#include "exit.h"
44#include "logging2.h"
45#include "memory.h"
46#include "message.h"
47#include "string2.h"
48
54static size_t buf_step_size(size_t size)
55{
56 if (size <= 16)
57 return 16;
58 if (size <= 32)
59 return 32;
60 if (size <= 64)
61 return 64;
62 if (size <= 128)
63 return 128;
64 return ROUND_UP(size, 128);
65}
66
74struct Buffer *buf_init(struct Buffer *buf)
75{
76 if (!buf)
77 return NULL;
78 memset(buf, 0, sizeof(struct Buffer));
79 return buf;
80}
81
89void buf_reset(struct Buffer *buf)
90{
91 if (!buf || !buf->data || (buf->dsize == 0))
92 return;
93 memset(buf->data, 0, buf->dsize);
94 buf_seek(buf, 0);
95}
96
109size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
110{
111 if (!buf || !s)
112 return 0;
113
114 if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
115 {
116 buf_alloc(buf, buf->dsize + len);
117 }
118
119 memcpy(buf->dptr, s, len);
120 buf->dptr += len;
121 *(buf->dptr) = '\0';
122 return len;
123}
124
133static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
134{
135 if (!buf || !fmt)
136 return 0; /* LCOV_EXCL_LINE */
137
138 buf_alloc(buf, 128);
139
140 size_t doff = buf->dptr - buf->data;
141 size_t blen = buf->dsize - doff;
142
143 va_list ap_retry = { 0 };
144 va_copy(ap_retry, ap);
145
146 int len = vsnprintf(buf->dptr, blen, fmt, ap);
147 if (len >= (int) blen)
148 {
149 buf_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 buf_printf(struct Buffer *buf, const char *fmt, ...)
169{
170 if (!buf || !fmt)
171 return -1;
172
173 va_list ap = { 0 };
174
175 va_start(ap, fmt);
176 buf_reset(buf);
177 int len = buf_vaprintf(buf, fmt, ap);
178 va_end(ap);
179
180 return len;
181}
182
189void buf_fix_dptr(struct Buffer *buf)
190{
191 if (!buf)
192 return;
193
194 buf_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 buf_add_printf(struct Buffer *buf, const char *fmt, ...)
212{
213 if (!buf || !fmt)
214 return -1;
215
216 va_list ap = { 0 };
217
218 va_start(ap, fmt);
219 int len = buf_vaprintf(buf, fmt, ap);
220 va_end(ap);
221
222 return len;
223}
224
233size_t buf_addstr(struct Buffer *buf, const char *s)
234{
235 if (!buf || !s)
236 return 0;
237 return buf_addstr_n(buf, s, mutt_str_len(s));
238}
239
248size_t buf_addch(struct Buffer *buf, char c)
249{
250 if (!buf)
251 return 0;
252 return buf_addstr_n(buf, &c, 1);
253}
254
263size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
264{
265 if (!buf || !s || (*s == '\0'))
266 {
267 return -1;
268 }
269
270 const size_t slen = mutt_str_len(s);
271 const size_t curlen = buf_len(buf);
272 buf_alloc(buf, curlen + slen + 1);
273
274 if (offset > curlen)
275 {
276 for (size_t i = curlen; i < offset; i++)
277 {
278 buf_addch(buf, ' ');
279 }
280 buf_addstr(buf, s);
281 }
282 else
283 {
284 memmove(buf->data + offset + slen, buf->data + offset, curlen - offset);
285 memcpy(buf->data + offset, s, slen);
286 buf->data[curlen + slen] = '\0';
287 buf->dptr = buf->data + curlen + slen;
288 }
289
290 return buf_len(buf) - curlen;
291}
292
298bool buf_is_empty(const struct Buffer *buf)
299{
300 if (!buf || !buf->data)
301 return true;
302
303 return (buf_at(buf, 0) == '\0');
304}
305
311struct Buffer *buf_new(const char *str)
312{
313 struct Buffer *buf = MUTT_MEM_CALLOC(1, struct Buffer);
314
315 if (str)
316 buf_addstr(buf, str);
317 else
318 buf_alloc(buf, 1);
319 return buf;
320}
321
326void buf_free(struct Buffer **ptr)
327{
328 if (!ptr || !*ptr)
329 return;
330
331 struct Buffer *buf = *ptr;
332 buf_dealloc(buf);
333
334 FREE(ptr);
335}
336
342void buf_alloc(struct Buffer *buf, size_t new_size)
343{
344 if (!buf)
345 return;
346
347 if (buf->data && (new_size <= buf->dsize))
348 {
349 // Extra sanity-checking
350 if (!buf->dptr || (buf->dptr < buf->data) || (buf->dptr > (buf->data + buf->dsize)))
351 buf->dptr = buf->data; // LCOV_EXCL_LINE
352 return;
353 }
354
355 const size_t dsize = buf_step_size(new_size + 1);
356 if (dsize <= new_size)
357 {
358 // LCOV_EXCL_START
359 mutt_error(_("Out of memory"));
360 mutt_exit(1);
361 // LCOV_EXCL_STOP
362 }
363
364 const bool was_empty = (buf->dptr == NULL);
365 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
366
367 buf->dsize = dsize;
368
369 MUTT_MEM_REALLOC(&buf->data, buf->dsize, char);
370 buf->dptr = buf->data + offset;
371
372 // Ensures that initially NULL buf->data is properly terminated
373 if (was_empty)
374 {
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 if (!buf)
404 return 0;
405
406 buf_reset(buf);
407 if (!s)
408 return 0;
409
410 return buf_addstr(buf, s);
411}
412
422size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
423{
424 if (!buf)
425 return 0;
426
427 buf_reset(buf);
428 if (!s)
429 return 0;
430
431 return buf_addstr_n(buf, s, len);
432}
433
441{
442 if (!buf || !buf->data || (buf->dsize == 0))
443 return;
444
445 buf_seek(buf, 0);
446
447 char *s = buf->data;
448 for (; *buf->dptr; buf->dptr++)
449 {
450 if (*buf->dptr == '\\')
451 {
452 if (!*++buf->dptr)
453 break; /* error? */
454 *s++ = *buf->dptr;
455 }
456 else if (*buf->dptr != '\"')
457 {
458 if (s != buf->dptr)
459 *s = *buf->dptr;
460 s++;
461 }
462 }
463 *s = '\0';
464
465 buf_fix_dptr(buf);
466}
467
477size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
478{
479 if (!buf)
480 return 0;
481
482 buf_reset(buf);
483 if (!beg || !end)
484 return 0;
485
486 if (end <= beg)
487 return 0;
488
489 return buf_strcpy_n(buf, beg, end - beg);
490}
491
497size_t buf_len(const struct Buffer *buf)
498{
499 if (!buf || !buf->data || !buf->dptr)
500 return 0;
501
502 return buf->dptr - buf->data;
503}
504
515size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
516{
517 if (!buf)
518 return 0;
519
520 if (!dir)
521 dir = "";
522 if (!fname)
523 fname = "";
524
525 const bool d_set = (dir[0] != '\0');
526 const bool f_set = (fname[0] != '\0');
527 if (!d_set && !f_set)
528 return 0;
529
530 const size_t d_len = strlen(dir);
531 const bool slash = d_set && (dir[d_len - 1] == '/');
532
533 const char *fmt = "%s/%s";
534 if (!f_set || !d_set || slash)
535 fmt = "%s%s";
536
537 return buf_printf(buf, fmt, dir, fname);
538}
539
552size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen,
553 const char *fname, size_t fnamelen)
554{
555 if (!buf)
556 return 0;
557
558 buf_reset(buf);
559
560 size_t len = 0;
561 if (dirlen != 0)
562 len += buf_addstr_n(buf, dir, dirlen);
563 if ((dirlen != 0) && (fnamelen != 0))
564 len += buf_addch(buf, '/');
565 if (fnamelen != 0)
566 len += buf_addstr_n(buf, fname, fnamelen);
567 return len;
568}
569
577char *buf_strdup(const struct Buffer *buf)
578{
579 if (!buf)
580 return NULL;
581
582 return mutt_str_dup(buf->data);
583}
584
592struct Buffer *buf_dup(const struct Buffer *buf)
593{
594 if (!buf)
595 return NULL;
596
597 return buf_new(buf_string(buf));
598}
599
607size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
608{
609 if (!dst)
610 return 0;
611
612 buf_reset(dst);
613 if (!src || !src->data)
614 return 0;
615
616 return buf_addstr_n(dst, src->data, buf_len(src));
617}
618
628void buf_seek(struct Buffer *buf, size_t offset)
629{
630 if (!buf || !buf->data)
631 return;
632
633 if (offset < buf->dsize)
634 buf->dptr = buf->data + offset;
635}
636
644const char *buf_find_string(const struct Buffer *buf, const char *s)
645{
646 if (!buf || !buf->data || !s)
647 return NULL;
648
649 return strstr(buf->data, s);
650}
651
659const char *buf_find_char(const struct Buffer *buf, const char c)
660{
661 if (!buf || !buf->data)
662 return NULL;
663
664 return strchr(buf->data, c);
665}
666
674char buf_at(const struct Buffer *buf, size_t offset)
675{
676 if (!buf || !buf->data || (offset > buf_len(buf)))
677 return '\0';
678
679 return buf->data[offset];
680}
681
689bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
690{
691 return mutt_str_equal(buf_string(a), buf_string(b));
692}
693
701bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
702{
704}
705
713size_t buf_startswith(const struct Buffer *buf, const char *prefix)
714{
715 if (!buf || !prefix)
716 return 0;
717
718 return mutt_str_startswith(buf_string(buf), prefix);
719}
720
729int buf_coll(const struct Buffer *a, const struct Buffer *b)
730{
731 return mutt_str_coll(buf_string(a), buf_string(b));
732}
733
740void buf_lower(struct Buffer *buf)
741{
742 if (!buf || !buf->data)
743 return;
744
745 mutt_str_lower(buf->data);
746}
747
754void buf_join_str(struct Buffer *buf, const char *str, char sep)
755{
756 if (!buf || !str)
757 return;
758
759 if (!buf_is_empty(buf) && mutt_str_len(str))
760 buf_addch(buf, sep);
761
762 buf_addstr(buf, str);
763}
764
774void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
775{
776 if (!buf || !buf->data || !str)
777 return;
778
779 size_t slen = buf_len(buf);
780 if (pos > slen)
781 return;
782 if (len > slen - pos)
783 len = slen - pos;
784
785 size_t rlen = mutt_str_len(str);
786 size_t new_size = slen - len + rlen + 1;
787 if (new_size > buf->dsize)
788 buf_alloc(buf, new_size);
789
790 memmove(buf->data + pos + rlen, buf->data + pos + len, slen - pos - len + 1);
791 memcpy(buf->data + pos, str, rlen);
792
793 buf_fix_dptr(buf);
794}
795
805const char *buf_rfind(const struct Buffer *buf, const char *str)
806{
807 if (buf_is_empty(buf) || !str || (*str == '\0'))
808 return NULL;
809
810 size_t len = strlen(str);
811 size_t slen = buf_len(buf);
812 if (len > slen)
813 return NULL;
814
815 const char *end = buf->data + slen - len;
816
817 for (const char *p = end; p >= buf->data; p--)
818 {
819 for (size_t i = 0; i < len; i++)
820 {
821 if (p[i] != str[i])
822 goto next;
823 }
824 return p;
825
826 next:;
827 }
828 return NULL;
829}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
int buf_coll(const struct Buffer *a, const struct Buffer *b)
Collate two strings (compare using locale)
Definition buffer.c:729
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition buffer.c:701
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:211
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition buffer.c:628
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:109
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
const char * buf_find_string(const struct Buffer *buf, const char *s)
Return a pointer to a substring found in the buffer.
Definition buffer.c:644
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:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:189
static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition buffer.c:133
void buf_dequote_comment(struct Buffer *buf)
Un-escape characters in an email address comment.
Definition buffer.c:440
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:674
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition buffer.c:326
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Replace part of a string.
Definition buffer.c:774
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition buffer.c:74
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition buffer.c:422
static size_t buf_step_size(size_t size)
Decide how much memory to allocate.
Definition buffer.c:54
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:552
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition buffer.c:311
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition buffer.c:248
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition buffer.c:233
void buf_join_str(struct Buffer *buf, const char *str, char sep)
Join a buffer with a string separated by sep.
Definition buffer.c:754
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition buffer.c:689
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition buffer.c:805
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition buffer.c:592
const char * buf_find_char(const struct Buffer *buf, const char c)
Return a pointer to a char found in the buffer.
Definition buffer.c:659
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:607
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:263
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition buffer.c:515
void buf_lower(struct Buffer *buf)
Sets a buffer to lowercase.
Definition buffer.c:740
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
size_t buf_startswith(const struct Buffer *buf, const char *prefix)
Check whether a buffer starts with a prefix.
Definition buffer.c:713
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition buffer.c:477
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:96
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition exit.c:41
Leave the program NOW.
#define mutt_error(...)
Definition logging2.h:94
Logging Dispatcher.
Memory management wrappers.
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define ROUND_UP(NUM, STEP)
Round up NUM to the nearest multiple of STEP.
Definition memory.h:46
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
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:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition string.c:317
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
int mutt_str_coll(const char *a, const char *b)
Collate two strings (compare using locale), safely.
Definition string.c:516
String manipulation functions.
String manipulation buffer.
Definition buffer.h:36
char * dptr
Current read/write position.
Definition buffer.h:38
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37