More buffer functions.
[apps/madmutt.git] / lib-lib / buffer.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or (at
5  *  your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful, but
8  *  WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
15  *  MA 02110-1301, USA.
16  *
17  *  Copyright © 2006 Pierre Habouzit
18  */
19
20 /*
21  * Copyright notice from original mutt:
22  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
23  *
24  * This file is part of mutt-ng, see http://www.muttng.org/.
25  * It's licensed under the GNU General Public License,
26  * please see the file GPL in the top level source directory.
27  */
28
29 #include "lib-lib.h"
30
31 void buffer_splice(buffer_t *buf, ssize_t pos, ssize_t len,
32                    const void *data, ssize_t dlen)
33 {
34     if (dlen >= len)
35         buffer_extend(buf, dlen - len);
36     memmove(buf->data + pos + dlen,
37             buf->data + pos + len,
38             buf->len - pos - len);
39     memcpy(buf->data + pos, data, dlen);
40     buffer_setlen(buf, buf->len + dlen - len);
41 }
42
43 ssize_t buffer_addvf(buffer_t *buf, const char *fmt, va_list args)
44 {
45     ssize_t len;
46     va_list ap;
47
48     va_copy(ap, args);
49     buffer_ensure(buf, BUFSIZ);
50
51     len = vsnprintf(buf->data + buf->len, buf->size - buf->len, fmt, args);
52     if (len < 0)
53         return len;
54     if (len >= buf->size - buf->len) {
55         buffer_ensure(buf, len);
56         vsnprintf(buf->data + buf->len, buf->size - buf->len, fmt, ap);
57     }
58     buf->len += len;
59     buf->data[buf->len] = '\0';
60
61     return len;
62 }
63
64 ssize_t buffer_addf(buffer_t *buf, const char *fmt, ...)
65 {
66     ssize_t res;
67     va_list args;
68     va_start(args, fmt);
69     res = buffer_addvf(buf, fmt, args);
70     va_end(args);
71     return res;
72 }
73 /****** LEGACY BUFFERS *******/
74
75 /*
76  * Creates and initializes a BUFFER*. If passed an existing BUFFER*,
77  * just initializes. Frees anything already in the buffer.
78  *
79  * Disregards the 'destroy' flag, which seems reserved for caller.
80  * This is bad, but there's no apparent protocol for it.
81  */
82 BUFFER *mutt_buffer_init(BUFFER *b)
83 {
84     if (!b) {
85         b = p_new(BUFFER, 1);
86     }
87     p_delete(&b->data);
88     p_clear(b, 1);
89     return b;
90 }
91
92 /*
93  * Creates and initializes a BUFFER*. If passed an existing BUFFER*,
94  * just initializes. Frees anything already in the buffer. Copies in
95  * the seed string.
96  *
97  * Disregards the 'destroy' flag, which seems reserved for caller.
98  * This is bad, but there's no apparent protocol for it.
99  */
100 BUFFER *mutt_buffer_from(BUFFER * b, const char *seed)
101 {
102     if (!seed)
103         return NULL;
104
105     b = mutt_buffer_init(b);
106     b->dsize = m_strlen(seed);
107     b->data  = m_strdup(seed);
108     b->dptr  = (char *)b->data + b->dsize;
109     return b;
110 }
111
112 void mutt_buffer_free(BUFFER **p)
113 {
114     if (p && *p) {
115         p_delete(&(*p)->data);
116         p_delete(p);
117     }
118 }
119
120 /* dynamically grows a BUFFER to accomodate s, in increments of 128 bytes.
121  * Always one byte bigger than necessary for the null terminator, and
122  * the buffer is always null-terminated */
123 void mutt_buffer_add(BUFFER *buf, const char *s, ssize_t len)
124 {
125     size_t offset;
126
127     if (buf->dptr + len + 1 > buf->data + buf->dsize) {
128         offset = buf->dptr - buf->data;
129         buf->dsize += ((len + 1 + 127) & ~127);
130         p_realloc(&buf->data, buf->dsize);
131         buf->dptr = buf->data + offset;
132     }
133     memcpy(buf->dptr, s, len);
134     buf->dptr += len;
135     *buf->dptr = '\0';
136 }
137