NeoMutt  2024-10-02-37-gfa9146
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
buffer.c
Go to the documentation of this file.
1
37#include "config.h"
38#include <errno.h>
39#include <stdarg.h>
40#include <stdbool.h>
41#include <stdint.h>
42#include <stdio.h>
43#include <string.h>
44#include "buffer.h"
45#include "exit.h"
46#include "logging2.h"
47#include "memory.h"
48#include "message.h"
49#include "string2.h"
50
52static const int BufferStepSize = 128;
53
61struct Buffer *buf_init(struct Buffer *buf)
62{
63 if (!buf)
64 return NULL;
65 memset(buf, 0, sizeof(struct Buffer));
66 return buf;
67}
68
76void buf_reset(struct Buffer *buf)
77{
78 if (!buf || !buf->data || (buf->dsize == 0))
79 return;
80 memset(buf->data, 0, buf->dsize);
81 buf_seek(buf, 0);
82}
83
96size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
97{
98 if (!buf || !s)
99 return 0;
100
101 if (len > (SIZE_MAX - BufferStepSize))
102 {
103 // LCOV_EXCL_START
104 mutt_error("%s", strerror(ENOMEM));
105 mutt_exit(1);
106 // LCOV_EXCL_STOP
107 }
108
109 if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
110 buf_alloc(buf, buf->dsize + MAX(BufferStepSize, len + 1));
111
112 memcpy(buf->dptr, s, len);
113 buf->dptr += len;
114 *(buf->dptr) = '\0';
115 return len;
116}
117
126static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
127{
128 if (!buf || !fmt)
129 return 0; /* LCOV_EXCL_LINE */
130
131 buf_alloc(buf, 128);
132
133 int doff = buf->dptr - buf->data;
134 int blen = buf->dsize - doff;
135
136 va_list ap_retry;
137 va_copy(ap_retry, ap);
138
139 int len = vsnprintf(buf->dptr, blen, fmt, ap);
140 if (len >= blen)
141 {
142 buf_alloc(buf, buf->dsize + len - blen + 1);
143 len = vsnprintf(buf->dptr, len + 1, fmt, ap_retry);
144 }
145 if (len > 0)
146 buf->dptr += len;
147
148 va_end(ap_retry);
149
150 return len;
151}
152
161int buf_printf(struct Buffer *buf, const char *fmt, ...)
162{
163 if (!buf || !fmt)
164 return -1;
165
166 va_list ap;
167
168 va_start(ap, fmt);
169 buf_reset(buf);
170 int len = buf_vaprintf(buf, fmt, ap);
171 va_end(ap);
172
173 return len;
174}
175
182void buf_fix_dptr(struct Buffer *buf)
183{
184 if (!buf)
185 return;
186
187 buf_seek(buf, 0);
188
189 if (buf->data && (buf->dsize > 0))
190 {
191 buf->data[buf->dsize - 1] = '\0';
192 buf->dptr = strchr(buf->data, '\0');
193 }
194}
195
204int buf_add_printf(struct Buffer *buf, const char *fmt, ...)
205{
206 if (!buf || !fmt)
207 return -1;
208
209 va_list ap;
210
211 va_start(ap, fmt);
212 int len = buf_vaprintf(buf, fmt, ap);
213 va_end(ap);
214
215 return len;
216}
217
226size_t buf_addstr(struct Buffer *buf, const char *s)
227{
228 if (!buf || !s)
229 return 0;
230 return buf_addstr_n(buf, s, mutt_str_len(s));
231}
232
241size_t buf_addch(struct Buffer *buf, char c)
242{
243 if (!buf)
244 return 0;
245 return buf_addstr_n(buf, &c, 1);
246}
247
256size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
257{
258 if (!buf || !s || (*s == '\0'))
259 {
260 return -1;
261 }
262
263 const size_t slen = mutt_str_len(s);
264 const size_t curlen = buf_len(buf);
265 buf_alloc(buf, curlen + slen + 1);
266
267 if (offset > curlen)
268 {
269 for (size_t i = curlen; i < offset; ++i)
270 {
271 buf_addch(buf, ' ');
272 }
273 buf_addstr(buf, s);
274 }
275 else
276 {
277 memmove(buf->data + offset + slen, buf->data + offset, curlen - offset);
278 memcpy(buf->data + offset, s, slen);
279 buf->data[curlen + slen] = '\0';
280 buf->dptr = buf->data + curlen + slen;
281 }
282
283 return buf_len(buf) - curlen;
284}
285
291bool buf_is_empty(const struct Buffer *buf)
292{
293 if (!buf || !buf->data)
294 return true;
295
296 return (buf->data[0] == '\0');
297}
298
304struct Buffer *buf_new(const char *str)
305{
306 struct Buffer *buf = mutt_mem_calloc(1, sizeof(struct Buffer));
307
308 if (str)
309 buf_addstr(buf, str);
310 else
311 buf_alloc(buf, 1);
312 return buf;
313}
314
319void buf_free(struct Buffer **ptr)
320{
321 if (!ptr || !*ptr)
322 return;
323
324 struct Buffer *buf = *ptr;
325 buf_dealloc(buf);
326
327 FREE(ptr);
328}
329
337void buf_alloc(struct Buffer *buf, size_t new_size)
338{
339 if (!buf)
340 return;
341
342 if (buf->data && (new_size <= buf->dsize))
343 {
344 // Extra sanity-checking
345 if (!buf->dptr || (buf->dptr < buf->data) || (buf->dptr > (buf->data + buf->dsize)))
346 buf->dptr = buf->data; // LCOV_EXCL_LINE
347 return;
348 }
349
350 if (new_size > (SIZE_MAX - BufferStepSize))
351 {
352 // LCOV_EXCL_START
353 mutt_error(_("Out of memory"));
354 mutt_exit(1);
355 // LCOV_EXCL_STOP
356 }
357
358 const bool was_empty = (buf->dptr == NULL);
359 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
360
361 buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
362
363 mutt_mem_realloc(&buf->data, buf->dsize);
364 buf->dptr = buf->data + offset;
365
366 // Ensures that initially NULL buf->data is properly terminated
367 if (was_empty)
368 {
369 *buf->dptr = '\0';
370 }
371}
372
377void buf_dealloc(struct Buffer *buf)
378{
379 if (!buf || !buf->data)
380 return;
381
382 buf->dptr = NULL;
383 buf->dsize = 0;
384 FREE(&buf->data);
385}
386
395size_t buf_strcpy(struct Buffer *buf, const char *s)
396{
397 if (!buf)
398 return 0;
399
400 buf_reset(buf);
401 if (!s)
402 return 0;
403
404 return buf_addstr(buf, s);
405}
406
416size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
417{
418 if (!buf)
419 return 0;
420
421 buf_reset(buf);
422 if (!s)
423 return 0;
424
425 return buf_addstr_n(buf, s, len);
426}
427
435{
436 if (!buf || !buf->data || (buf->dsize == 0))
437 return;
438
439 buf_seek(buf, 0);
440
441 char *s = buf->data;
442 for (; *buf->dptr; buf->dptr++)
443 {
444 if (*buf->dptr == '\\')
445 {
446 if (!*++buf->dptr)
447 break; /* error? */
448 *s++ = *buf->dptr;
449 }
450 else if (*buf->dptr != '\"')
451 {
452 if (s != buf->dptr)
453 *s = *buf->dptr;
454 s++;
455 }
456 }
457 *s = '\0';
458
459 buf_fix_dptr(buf);
460}
461
471size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
472{
473 if (!buf)
474 return 0;
475
476 buf_reset(buf);
477 if (!beg || !end)
478 return 0;
479
480 if (end <= beg)
481 return 0;
482
483 return buf_strcpy_n(buf, beg, end - beg);
484}
485
491size_t buf_len(const struct Buffer *buf)
492{
493 if (!buf || !buf->data || !buf->dptr)
494 return 0;
495
496 return buf->dptr - buf->data;
497}
498
509size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
510{
511 if (!buf)
512 return 0;
513
514 if (!dir)
515 dir = "";
516 if (!fname)
517 fname = "";
518
519 const bool d_set = (dir[0] != '\0');
520 const bool f_set = (fname[0] != '\0');
521 if (!d_set && !f_set)
522 return 0;
523
524 const int d_len = strlen(dir);
525 const bool slash = d_set && (dir[d_len - 1] == '/');
526
527 const char *fmt = "%s/%s";
528 if (!f_set || !d_set || slash)
529 fmt = "%s%s";
530
531 return buf_printf(buf, fmt, dir, fname);
532}
533
546size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen,
547 const char *fname, size_t fnamelen)
548{
549 if (!buf)
550 return 0;
551
552 buf_reset(buf);
553
554 size_t len = 0;
555 if (dirlen != 0)
556 len += buf_addstr_n(buf, dir, dirlen);
557 if ((dirlen != 0) && (fnamelen != 0))
558 len += buf_addch(buf, '/');
559 if (fnamelen != 0)
560 len += buf_addstr_n(buf, fname, fnamelen);
561 return len;
562}
563
571char *buf_strdup(const struct Buffer *buf)
572{
573 if (!buf)
574 return NULL;
575
576 return mutt_str_dup(buf->data);
577}
578
586struct Buffer *buf_dup(const struct Buffer *buf)
587{
588 if (!buf)
589 return NULL;
590
591 return buf_new(buf_string(buf));
592}
593
601size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
602{
603 if (!dst)
604 return 0;
605
606 buf_reset(dst);
607 if (!src || !src->data)
608 return 0;
609
610 return buf_addstr_n(dst, src->data, buf_len(src));
611}
612
622void buf_seek(struct Buffer *buf, size_t offset)
623{
624 if (!buf)
625 return;
626
627 if ((offset < buf_len(buf)))
628 {
629 buf->dptr = buf->data ? buf->data + offset : NULL;
630 }
631}
632
640const char *buf_find_string(const struct Buffer *buf, const char *s)
641{
642 if (!buf || !s)
643 return NULL;
644
645 return strstr(buf->data, s);
646}
647
655const char *buf_find_char(const struct Buffer *buf, const char c)
656{
657 if (!buf)
658 return NULL;
659
660 return strchr(buf->data, c);
661}
662
670char buf_at(const struct Buffer *buf, size_t offset)
671{
672 if (!buf || (offset > buf_len(buf)))
673 return '\0';
674
675 return buf->data[offset];
676}
677
685bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
686{
687 return mutt_str_equal(buf_string(a), buf_string(b));
688}
689
697bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
698{
700}
701
709size_t buf_startswith(const struct Buffer *buf, const char *prefix)
710{
711 if (!buf || !prefix)
712 return 0;
713
714 return mutt_str_startswith(buf_string(buf), prefix);
715}
716
725int buf_coll(const struct Buffer *a, const struct Buffer *b)
726{
727 return mutt_str_coll(buf_string(a), buf_string(b));
728}
729
736void buf_lower(struct Buffer *buf)
737{
738 if (!buf)
739 return;
740
741 mutt_str_lower(buf->data);
742}
743
750void buf_join_str(struct Buffer *buf, const char *str, char sep)
751{
752 if (!buf || !str)
753 return;
754
755 if (!buf_is_empty(buf) && mutt_str_len(str))
756 buf_addch(buf, sep);
757
758 buf_addstr(buf, str);
759}
760
761/*
762 * buf_inline_replace - Replace part of a string
763 * @param buf Buffer to modify
764 * @param pos Starting position of string to overwrite
765 * @param len Length of string to overwrite
766 * @param str Replacement string
767 *
768 * String (`11XXXOOOOOO`, 2, 3, `YYYY`) becomes `11YYYY000000`
769 */
770void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
771{
772 if (!buf || !str)
773 return;
774
775 size_t olen = buf->dsize;
776 size_t rlen = mutt_str_len(str);
777
778 size_t new_size = buf->dsize - len + rlen + 1;
779 if (new_size > buf->dsize)
780 buf_alloc(buf, new_size);
781
782 memmove(buf->data + pos + rlen, buf->data + pos + len, olen - pos - len);
783 memmove(buf->data + pos, str, rlen);
784
785 buf_fix_dptr(buf);
786}
787
797const char *buf_rfind(const struct Buffer *buf, const char *str)
798{
799 if (buf_is_empty(buf) || !str)
800 return NULL;
801
802 int len = strlen(str);
803 const char *end = buf->data + buf->dsize - len;
804
805 for (const char *p = end; p >= buf->data; --p)
806 {
807 for (size_t i = 0; i < len; i++)
808 {
809 if (p[i] != str[i])
810 goto next;
811 }
812 return p;
813
814 next:;
815 }
816 return NULL;
817}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:161
int buf_coll(const struct Buffer *a, const struct Buffer *b)
Collate two strings (compare using locale)
Definition: buffer.c:725
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:697
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:204
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:622
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:96
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
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:640
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:377
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:182
static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:126
void buf_dequote_comment(struct Buffer *buf)
Un-escape characters in an email address comment.
Definition: buffer.c:434
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:670
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:319
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Definition: buffer.c:770
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:61
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:546
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:304
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
void buf_join_str(struct Buffer *buf, const char *str, char sep)
Join a buffer with a string separated by sep.
Definition: buffer.c:750
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:685
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition: buffer.c:797
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition: buffer.c:586
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:655
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
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:256
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:509
void buf_lower(struct Buffer *buf)
Sets a buffer to lowercase.
Definition: buffer.c:736
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:337
static const int BufferStepSize
When increasing the size of a Buffer, add this much extra space.
Definition: buffer.c:52
size_t buf_startswith(const struct Buffer *buf, const char *prefix)
Check whether a buffer starts with a prefix.
Definition: buffer.c:709
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:471
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
Leave the program NOW.
#define mutt_error(...)
Definition: logging2.h:92
Logging Dispatcher.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:269
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:115
Memory management wrappers.
#define FREE(x)
Definition: memory.h:45
#define ROUND_UP(NUM, STEP)
Definition: memory.h:36
#define MAX(a, b)
Definition: memory.h:31
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:672
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:313
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
int mutt_str_coll(const char *a, const char *b)
Collate two strings (compare using locale), safely.
Definition: string.c:509
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