NeoMutt  2024-02-01-35-geee02f
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 <stdarg.h>
39#include <stdbool.h>
40#include <stdint.h>
41#include <stdio.h>
42#include <string.h>
43#include "buffer.h"
44#include "exit.h"
45#include "logging2.h"
46#include "memory.h"
47#include "message.h"
48#include "string2.h"
49
51static const int BufferStepSize = 128;
52
60struct Buffer *buf_init(struct Buffer *buf)
61{
62 if (!buf)
63 return NULL;
64 memset(buf, 0, sizeof(struct Buffer));
65 return buf;
66}
67
75struct Buffer buf_make(size_t size)
76{
77 struct Buffer buf = { 0 };
78 if (size != 0)
79 {
80 buf.dptr = buf.data = mutt_mem_calloc(1, size);
81 buf.dsize = size;
82 }
83 return buf;
84}
85
93void buf_reset(struct Buffer *buf)
94{
95 if (!buf || !buf->data || (buf->dsize == 0))
96 return;
97 memset(buf->data, 0, buf->dsize);
98 buf_seek(buf, 0);
99}
100
113size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
114{
115 if (!buf || !s)
116 return 0;
117
118 if (len > (SIZE_MAX - BufferStepSize))
119 {
120 // LCOV_EXCL_START
121 mutt_error(_("Out of memory"));
122 mutt_exit(1);
123 // LCOV_EXCL_STOP
124 }
125
126 if (!buf->data || !buf->dptr || ((buf->dptr + len + 1) > (buf->data + buf->dsize)))
127 buf_alloc(buf, buf->dsize + MAX(BufferStepSize, len + 1));
128
129 memcpy(buf->dptr, s, len);
130 buf->dptr += len;
131 *(buf->dptr) = '\0';
132 return len;
133}
134
143static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
144{
145 if (!buf || !fmt)
146 return 0; /* LCOV_EXCL_LINE */
147
148 buf_alloc(buf, 128);
149
150 int doff = buf->dptr - buf->data;
151 int blen = buf->dsize - doff;
152
153 va_list ap_retry;
154 va_copy(ap_retry, ap);
155
156 int len = vsnprintf(buf->dptr, blen, fmt, ap);
157 if (len >= blen)
158 {
159 buf_alloc(buf, buf->dsize + len - blen + 1);
160 len = vsnprintf(buf->dptr, len + 1, fmt, ap_retry);
161 }
162 if (len > 0)
163 buf->dptr += len;
164
165 va_end(ap_retry);
166
167 return len;
168}
169
178int buf_printf(struct Buffer *buf, const char *fmt, ...)
179{
180 if (!buf || !fmt)
181 return -1;
182
183 va_list ap;
184
185 va_start(ap, fmt);
186 buf_reset(buf);
187 int len = buf_vaprintf(buf, fmt, ap);
188 va_end(ap);
189
190 return len;
191}
192
199void buf_fix_dptr(struct Buffer *buf)
200{
201 if (!buf)
202 return;
203
204 buf_seek(buf, 0);
205
206 if (buf->data && (buf->dsize > 0))
207 {
208 buf->data[buf->dsize - 1] = '\0';
209 buf->dptr = strchr(buf->data, '\0');
210 }
211}
212
221int buf_add_printf(struct Buffer *buf, const char *fmt, ...)
222{
223 if (!buf || !fmt)
224 return -1;
225
226 va_list ap;
227
228 va_start(ap, fmt);
229 int len = buf_vaprintf(buf, fmt, ap);
230 va_end(ap);
231
232 return len;
233}
234
243size_t buf_addstr(struct Buffer *buf, const char *s)
244{
245 if (!buf || !s)
246 return 0;
247 return buf_addstr_n(buf, s, mutt_str_len(s));
248}
249
258size_t buf_addch(struct Buffer *buf, char c)
259{
260 if (!buf)
261 return 0;
262 return buf_addstr_n(buf, &c, 1);
263}
264
273size_t buf_insert(struct Buffer *buf, size_t offset, const char *s)
274{
275 if (!buf || !s || (*s == '\0'))
276 {
277 return -1;
278 }
279
280 const size_t slen = mutt_str_len(s);
281 const size_t curlen = buf_len(buf);
282 buf_alloc(buf, curlen + slen + 1);
283
284 if (offset > curlen)
285 {
286 for (size_t i = curlen; i < offset; ++i)
287 {
288 buf_addch(buf, ' ');
289 }
290 buf_addstr(buf, s);
291 }
292 else
293 {
294 memmove(buf->data + offset + slen, buf->data + offset, curlen - offset);
295 memcpy(buf->data + offset, s, slen);
296 buf->data[curlen + slen] = '\0';
297 buf->dptr = buf->data + curlen + slen;
298 }
299
300 return buf_len(buf) - curlen;
301}
302
308bool buf_is_empty(const struct Buffer *buf)
309{
310 if (!buf || !buf->data)
311 return true;
312
313 return (buf->data[0] == '\0');
314}
315
321struct Buffer *buf_new(const char *str)
322{
323 struct Buffer *buf = mutt_mem_calloc(1, sizeof(struct Buffer));
324
325 if (str)
326 buf_addstr(buf, str);
327 else
328 buf_alloc(buf, 1);
329 return buf;
330}
331
336void buf_free(struct Buffer **ptr)
337{
338 if (!ptr || !*ptr)
339 return;
340
341 struct Buffer *buf = *ptr;
342 buf_dealloc(buf);
343
344 FREE(ptr);
345}
346
354void buf_alloc(struct Buffer *buf, size_t new_size)
355{
356 if (!buf)
357 return;
358
359 if (buf->data && (new_size <= buf->dsize))
360 {
361 // Extra sanity-checking
362 if (!buf->dptr || (buf->dptr < buf->data) || (buf->dptr > (buf->data + buf->dsize)))
363 buf->dptr = buf->data; // LCOV_EXCL_LINE
364 return;
365 }
366
367 if (new_size > (SIZE_MAX - BufferStepSize))
368 {
369 // LCOV_EXCL_START
370 mutt_error(_("Out of memory"));
371 mutt_exit(1);
372 // LCOV_EXCL_STOP
373 }
374
375 const bool was_empty = (buf->dptr == NULL);
376 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
377
378 buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
379
380 mutt_mem_realloc(&buf->data, buf->dsize);
381 buf->dptr = buf->data + offset;
382
383 // Ensures that initially NULL buf->data is properly terminated
384 if (was_empty)
385 {
386 *buf->dptr = '\0';
387 }
388}
389
394void buf_dealloc(struct Buffer *buf)
395{
396 if (!buf || !buf->data)
397 return;
398
399 buf->dptr = NULL;
400 buf->dsize = 0;
401 FREE(&buf->data);
402}
403
412size_t buf_strcpy(struct Buffer *buf, const char *s)
413{
414 if (!buf)
415 return 0;
416
417 buf_reset(buf);
418 if (!s)
419 return 0;
420
421 return buf_addstr(buf, s);
422}
423
433size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
434{
435 if (!buf)
436 return 0;
437
438 buf_reset(buf);
439 if (!s)
440 return 0;
441
442 return buf_addstr_n(buf, s, len);
443}
444
452{
453 if (!buf || !buf->data || (buf->dsize == 0))
454 return;
455
456 buf_seek(buf, 0);
457
458 char *s = buf->data;
459 for (; *buf->dptr; buf->dptr++)
460 {
461 if (*buf->dptr == '\\')
462 {
463 if (!*++buf->dptr)
464 break; /* error? */
465 *s++ = *buf->dptr;
466 }
467 else if (*buf->dptr != '\"')
468 {
469 if (s != buf->dptr)
470 *s = *buf->dptr;
471 s++;
472 }
473 }
474 *s = '\0';
475
476 buf_fix_dptr(buf);
477}
478
488size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
489{
490 if (!buf)
491 return 0;
492
493 buf_reset(buf);
494 if (!beg || !end)
495 return 0;
496
497 if (end <= beg)
498 return 0;
499
500 return buf_strcpy_n(buf, beg, end - beg);
501}
502
508size_t buf_len(const struct Buffer *buf)
509{
510 if (!buf || !buf->data || !buf->dptr)
511 return 0;
512
513 return buf->dptr - buf->data;
514}
515
526size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
527{
528 if (!buf)
529 return 0;
530
531 if (!dir)
532 dir = "";
533 if (!fname)
534 fname = "";
535
536 const bool d_set = (dir[0] != '\0');
537 const bool f_set = (fname[0] != '\0');
538 if (!d_set && !f_set)
539 return 0;
540
541 const int d_len = strlen(dir);
542 const bool slash = d_set && (dir[d_len - 1] == '/');
543
544 const char *fmt = "%s/%s";
545 if (!f_set || !d_set || slash)
546 fmt = "%s%s";
547
548 return buf_printf(buf, fmt, dir, fname);
549}
550
563size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen,
564 const char *fname, size_t fnamelen)
565{
566 if (!buf)
567 return 0;
568
569 buf_reset(buf);
570
571 size_t len = 0;
572 if (dirlen != 0)
573 len += buf_addstr_n(buf, dir, dirlen);
574 if ((dirlen != 0) && (fnamelen != 0))
575 len += buf_addch(buf, '/');
576 if (fnamelen != 0)
577 len += buf_addstr_n(buf, fname, fnamelen);
578 return len;
579}
580
588char *buf_strdup(const struct Buffer *buf)
589{
590 if (!buf)
591 return NULL;
592
593 return mutt_str_dup(buf->data);
594}
595
603struct Buffer *buf_dup(const struct Buffer *buf)
604{
605 if (!buf)
606 return NULL;
607
608 return buf_new(buf_string(buf));
609}
610
618size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
619{
620 if (!dst)
621 return 0;
622
623 buf_reset(dst);
624 if (!src || !src->data)
625 return 0;
626
627 return buf_addstr_n(dst, src->data, buf_len(src));
628}
629
639void buf_seek(struct Buffer *buf, size_t offset)
640{
641 if (!buf)
642 return;
643
644 if ((offset < buf_len(buf)))
645 {
646 buf->dptr = buf->data ? buf->data + offset : NULL;
647 }
648}
649
657const char *buf_find_string(const struct Buffer *buf, const char *s)
658{
659 if (!buf || !s)
660 return NULL;
661
662 return strstr(buf->data, s);
663}
664
672const char *buf_find_char(const struct Buffer *buf, const char c)
673{
674 if (!buf)
675 return NULL;
676
677 return strchr(buf->data, c);
678}
679
687char buf_at(const struct Buffer *buf, size_t offset)
688{
689 if (!buf || (offset > buf_len(buf)))
690 return '\0';
691
692 return buf->data[offset];
693}
694
702bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
703{
704 return mutt_str_equal(buf_string(a), buf_string(b));
705}
706
714bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
715{
717}
718
726size_t buf_startswith(const struct Buffer *buf, const char *prefix)
727{
728 if (!buf || !prefix)
729 return 0;
730
731 return mutt_str_startswith(buf_string(buf), prefix);
732}
733
742int buf_coll(const struct Buffer *a, const struct Buffer *b)
743{
744 return mutt_str_coll(buf_string(a), buf_string(b));
745}
746
753void buf_lower(struct Buffer *buf)
754{
755 if (!buf)
756 return;
757
758 mutt_str_lower(buf->data);
759}
760
767void buf_join_str(struct Buffer *buf, const char *str, char sep)
768{
769 if (!buf || !str)
770 return;
771
772 if (!buf_is_empty(buf) && mutt_str_len(str))
773 buf_addch(buf, sep);
774
775 buf_addstr(buf, str);
776}
777
778/*
779 * buf_inline_replace - Replace part of a string
780 * @param buf Buffer to modify
781 * @param pos Starting position of string to overwrite
782 * @param len Length of string to overwrite
783 * @param str Replacement string
784 *
785 * String (`11XXXOOOOOO`, 2, 3, `YYYY`) becomes `11YYYY000000`
786 */
787void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
788{
789 if (!buf || !str)
790 return;
791
792 size_t olen = buf->dsize;
793 size_t rlen = mutt_str_len(str);
794
795 size_t new_size = buf->dsize - len + rlen + 1;
796 if (new_size > buf->dsize)
797 buf_alloc(buf, new_size);
798
799 memmove(buf->data + pos + rlen, buf->data + pos + len, olen - pos - len);
800 memmove(buf->data + pos, str, rlen);
801
802 buf_fix_dptr(buf);
803}
804
814const char *buf_rfind(const struct Buffer *buf, const char *str)
815{
816 if (buf_is_empty(buf) || !str)
817 return NULL;
818
819 int len = strlen(str);
820 const char *end = buf->data + buf->dsize - len;
821
822 for (const char *p = end; p >= buf->data; --p)
823 {
824 for (size_t i = 0; i < len; i++)
825 {
826 if (p[i] != str[i])
827 goto next;
828 }
829 return p;
830
831 next:;
832 }
833 return NULL;
834}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:178
int buf_coll(const struct Buffer *a, const struct Buffer *b)
Collate two strings (compare using locale)
Definition: buffer.c:742
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:714
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:221
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:639
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:113
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:508
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:657
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:394
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:93
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:308
struct Buffer buf_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:75
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:199
static int buf_vaprintf(struct Buffer *buf, const char *fmt, va_list ap)
Format a string into a Buffer.
Definition: buffer.c:143
void buf_dequote_comment(struct Buffer *buf)
Un-escape characters in an email address comment.
Definition: buffer.c:451
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:687
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:336
void buf_inline_replace(struct Buffer *buf, size_t pos, size_t len, const char *str)
Definition: buffer.c:787
struct Buffer * buf_init(struct Buffer *buf)
Initialise a new Buffer.
Definition: buffer.c:60
size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
Copy a string into a Buffer.
Definition: buffer.c:433
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:563
struct Buffer * buf_new(const char *str)
Allocate a new Buffer.
Definition: buffer.c:321
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:258
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:243
void buf_join_str(struct Buffer *buf, const char *str, char sep)
Join a buffer with a string separated by sep.
Definition: buffer.c:767
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:702
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition: buffer.c:814
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition: buffer.c:603
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:672
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:412
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:618
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:273
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:588
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:526
void buf_lower(struct Buffer *buf)
Sets a buffer to lowercase.
Definition: buffer.c:753
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:354
static const int BufferStepSize
When increasing the size of a Buffer, add this much extra space.
Definition: buffer.c:51
size_t buf_startswith(const struct Buffer *buf, const char *prefix)
Check whether a buffer starts with a prefix.
Definition: buffer.c:726
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:488
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:97
Leave the program NOW.
#define mutt_error(...)
Definition: logging2.h:92
Logging Dispatcher.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:231
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: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:721
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:362
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:709
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:545
int mutt_str_coll(const char *a, const char *b)
Collate two strings (compare using locale), safely.
Definition: string.c:558
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