NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
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 else
323 buf_alloc(buf, 1);
324 return buf;
325}
326
331void buf_free(struct Buffer **ptr)
332{
333 if (!ptr || !*ptr)
334 return;
335
336 struct Buffer *buf = *ptr;
337 buf_dealloc(buf);
338
339 FREE(ptr);
340}
341
349void buf_alloc(struct Buffer *buf, size_t new_size)
350{
351 if (!buf)
352 return;
353
354 if (buf->data && (new_size <= buf->dsize))
355 {
356 // Extra sanity-checking
357 if (!buf->dptr || (buf->dptr < buf->data) || (buf->dptr > (buf->data + buf->dsize)))
358 buf->dptr = buf->data; // LCOV_EXCL_LINE
359 return;
360 }
361
362 if (new_size > (SIZE_MAX - BufferStepSize))
363 {
364 // LCOV_EXCL_START
365 mutt_error(_("Out of memory"));
366 mutt_exit(1);
367 // LCOV_EXCL_STOP
368 }
369
370 const bool was_empty = (buf->dptr == NULL);
371 const size_t offset = (buf->dptr && buf->data) ? (buf->dptr - buf->data) : 0;
372
373 buf->dsize = ROUND_UP(new_size + 1, BufferStepSize);
374
375 mutt_mem_realloc(&buf->data, buf->dsize);
376 buf->dptr = buf->data + offset;
377
378 // Ensures that initially NULL buf->data is properly terminated
379 if (was_empty)
380 {
381 *buf->dptr = '\0';
382 }
383}
384
389void buf_dealloc(struct Buffer *buf)
390{
391 if (!buf || !buf->data)
392 return;
393
394 buf->dptr = NULL;
395 buf->dsize = 0;
396 FREE(&buf->data);
397}
398
407size_t buf_strcpy(struct Buffer *buf, const char *s)
408{
409 buf_reset(buf);
410 return buf_addstr(buf, s);
411}
412
422size_t buf_strcpy_n(struct Buffer *buf, const char *s, size_t len)
423{
424 buf_reset(buf);
425 return buf_addstr_n(buf, s, len);
426}
427
435{
436 if (!buf)
437 return;
438
440 buf_fix_dptr(buf);
441}
442
452size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
453{
454 buf_reset(buf);
455 if (end <= beg)
456 return 0;
457
458 return buf_strcpy_n(buf, beg, end - beg);
459}
460
466size_t buf_len(const struct Buffer *buf)
467{
468 if (!buf || !buf->data || !buf->dptr)
469 return 0;
470
471 return buf->dptr - buf->data;
472}
473
484size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
485{
486 if (!buf)
487 return 0;
488
489 if (!dir)
490 dir = "";
491 if (!fname)
492 fname = "";
493
494 const bool d_set = (dir[0] != '\0');
495 const bool f_set = (fname[0] != '\0');
496 if (!d_set && !f_set)
497 return 0;
498
499 const int d_len = strlen(dir);
500 const bool slash = d_set && (dir[d_len - 1] == '/');
501
502 const char *fmt = "%s/%s";
503 if (!f_set || !d_set || slash)
504 fmt = "%s%s";
505
506 return buf_printf(buf, fmt, dir, fname);
507}
508
521size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen,
522 const char *fname, size_t fnamelen)
523{
524 size_t len = 0;
525 buf_reset(buf);
526 if (dirlen != 0)
527 len += buf_addstr_n(buf, dir, dirlen);
528 if ((dirlen != 0) && (fnamelen != 0))
529 len += buf_addch(buf, '/');
530 if (fnamelen != 0)
531 len += buf_addstr_n(buf, fname, fnamelen);
532 return len;
533}
534
542char *buf_strdup(const struct Buffer *buf)
543{
544 if (!buf)
545 return NULL;
546
547 return mutt_str_dup(buf->data);
548}
549
557struct Buffer *buf_dup(const struct Buffer *buf)
558{
559 if (!buf)
560 return NULL;
561
562 return buf_new(buf_string(buf));
563}
564
572size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
573{
574 if (!dst)
575 return 0;
576
577 buf_reset(dst);
578 if (!src || !src->data)
579 return 0;
580
581 return buf_addstr_n(dst, src->data, buf_len(src));
582}
583
593void buf_seek(struct Buffer *buf, size_t offset)
594{
595 if (buf && (offset < buf_len(buf)))
596 {
597 buf->dptr = buf->data ? buf->data + offset : NULL;
598 }
599}
600
608const char *buf_find_string(const struct Buffer *buf, const char *s)
609{
610 if (!buf || !s)
611 return NULL;
612
613 return strstr(buf->data, s);
614}
615
623const char *buf_find_char(const struct Buffer *buf, const char c)
624{
625 if (!buf)
626 return NULL;
627
628 return strchr(buf->data, c);
629}
630
638char buf_at(const struct Buffer *buf, size_t offset)
639{
640 if (!buf || (offset > buf_len(buf)))
641 return '\0';
642
643 return buf->data[offset];
644}
645
653bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
654{
655 return mutt_str_equal(buf_string(a), buf_string(b));
656}
657
665bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
666{
668}
669
677size_t buf_startswith(const struct Buffer *buf, const char *prefix)
678{
679 return mutt_str_startswith(buf_string(buf), prefix);
680}
681
690int buf_coll(const struct Buffer *a, const struct Buffer *b)
691{
692 return mutt_str_coll(buf_string(a), buf_string(b));
693}
694
701void buf_lower(struct Buffer *buf)
702{
703 if (!buf)
704 return;
705
706 mutt_str_lower(buf->data);
707}
708
715void buf_upper(struct Buffer *buf)
716{
717 if (!buf)
718 return;
719
720 mutt_str_upper(buf->data);
721}
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:173
int buf_coll(const struct Buffer *a, const struct Buffer *b)
Collate two strings (compare using locale)
Definition: buffer.c:690
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:665
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition: buffer.c:216
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition: buffer.c:593
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:466
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:608
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:389
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:434
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:638
void buf_free(struct Buffer **ptr)
Deallocates a buffer.
Definition: buffer.c:331
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:422
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:521
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:715
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
bool buf_str_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal.
Definition: buffer.c:653
struct Buffer * buf_dup(const struct Buffer *buf)
Copy a Buffer into a new allocated buffer.
Definition: buffer.c:557
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:623
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:572
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:542
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:484
void buf_lower(struct Buffer *buf)
Sets a buffer to lowercase.
Definition: buffer.c:701
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:349
static const int BufferStepSize
When increasing the size of a Buffer, add this much extra space.
Definition: buffer.c:46
size_t buf_startswith(const struct Buffer *buf, const char *prefix)
Check whether a buffer starts with a prefix.
Definition: buffer.c:677
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:452
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:93
Leave the program NOW.
#define mutt_error(...)
Definition: logging2.h:92
Logging Dispatcher.
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:228
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:775
void mutt_str_dequote_comment(char *str)
Un-escape characters in an email address comment.
Definition: string.c:731
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:763
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:228
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