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