aboutsummaryrefslogtreecommitdiff
path: root/src/util/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/buffer.c')
-rw-r--r--src/util/buffer.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/util/buffer.c b/src/util/buffer.c
new file mode 100644
index 000000000..d89565d68
--- /dev/null
+++ b/src/util/buffer.c
@@ -0,0 +1,226 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU Affero General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
12
13 You should have received a copy of the GNU Affero General Public License along with
14 GNUnet; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15*/
16/**
17 * @file buffer.c
18 * @brief Common buffer management functions.
19 * @author Florian Dold
20 */
21#include "platform.h"
22#include "gnunet_util_lib.h"
23#include "gnunet_buffer_lib.h"
24
25/**
26 * Initialize a buffer with the given capacity.
27 *
28 * When a buffer is allocated with this function, a warning is logged
29 * when the buffer exceeds the initial capacity.
30 *
31 * @param buf the buffer to initialize
32 * @param capacity the capacity (in bytes) to allocate for @a buf
33 */
34void
35GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf, size_t capacity)
36{
37 /* Buffer should be zero-initialized */
38 GNUNET_assert (0 == buf->mem);
39 GNUNET_assert (0 == buf->capacity);
40 GNUNET_assert (0 == buf->position);
41 buf->mem = GNUNET_malloc (capacity);
42 buf->capacity = capacity;
43 buf->warn_grow = GNUNET_YES;
44}
45
46
47/**
48 * Make sure that at least @a n bytes remaining in the buffer.
49 *
50 * @param buf buffer to potentially grow
51 * @param n number of bytes that should be available to write
52 */
53void
54GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf, size_t n)
55{
56 size_t new_capacity = buf->position + n;
57
58 if (new_capacity <= buf->capacity)
59 return;
60 /* warn if calculation of expected size was wrong */
61 GNUNET_break (GNUNET_YES != buf->warn_grow);
62 if (new_capacity < buf->capacity * 2)
63 new_capacity = buf->capacity * 2;
64 buf->capacity = new_capacity;
65 if (NULL != buf->mem)
66 buf->mem = GNUNET_realloc (buf->mem, new_capacity);
67 else
68 buf->mem = GNUNET_malloc (new_capacity);
69}
70
71
72/**
73 * Write bytes to the buffer.
74 *
75 * Grows the buffer if necessary.
76 *
77 * @param buf buffer to write to
78 * @param data data to read from
79 * @param len number of bytes to copy from @a data to @a buf
80 *
81 */
82void
83GNUNET_buffer_write (struct GNUNET_Buffer *buf, const char *data, size_t len)
84{
85 GNUNET_buffer_ensure_remaining (buf, len);
86 memcpy (buf->mem + buf->position, data, len);
87 buf->position += len;
88}
89
90
91/**
92 * Write a 0-terminated string to a buffer, excluding the 0-terminator.
93 *
94 * @param buf the buffer to write to
95 * @param str the string to write to @a buf
96 */
97void
98GNUNET_buffer_write_str (struct GNUNET_Buffer *buf, const char *str)
99{
100 size_t len = strlen (str);
101
102 GNUNET_buffer_write (buf, str, len);
103}
104
105
106/**
107 * Clear the buffer and return the string it contained.
108 * The caller is responsible to eventually #GNUNET_free
109 * the returned string.
110 *
111 * The returned string is always 0-terminated.
112 *
113 * @param buf the buffer to reap the string from
114 * @returns the buffer contained in the string
115 */
116char *
117GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf)
118{
119 char *res;
120
121 /* ensure 0-termination */
122 if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1]))
123 {
124 GNUNET_buffer_ensure_remaining (buf, 1);
125 buf->mem[buf->position++] = '\0';
126 }
127 res = buf->mem;
128 *buf = (struct GNUNET_Buffer) { 0 };
129 return res;
130}
131
132
133/**
134 * Free the backing memory of the given buffer.
135 * Does not free the memory of the buffer control structure,
136 * which is typically stack-allocated.
137 */
138void
139GNUNET_buffer_clear (struct GNUNET_Buffer *buf)
140{
141 GNUNET_free_non_null (buf->mem);
142 *buf = (struct GNUNET_Buffer) { 0 };
143}
144
145
146/**
147 * Write a path component to a buffer, ensuring that
148 * there is exactly one slash between the previous contents
149 * of the buffer and the new string.
150 *
151 * @param buf buffer to write to
152 * @param str string containing the new path component
153 */
154void
155GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str)
156{
157 size_t len = strlen (str);
158
159 while ( (0 != len) && ('/' == str[0]) )
160 {
161 str++;
162 len--;
163 }
164 if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) )
165 {
166 GNUNET_buffer_ensure_remaining (buf, 1);
167 buf->mem[buf->position++] = '/';
168 }
169 GNUNET_buffer_write (buf, str, len);
170}
171
172
173/**
174 * Write a 0-terminated formatted string to a buffer, excluding the
175 * 0-terminator.
176 *
177 * Grows the buffer if necessary.
178 *
179 * @param buf the buffer to write to
180 * @param fmt format string
181 * @param ... format arguments
182 */
183void
184GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
185{
186 va_list args;
187
188 va_start (args, fmt);
189 GNUNET_buffer_write_vfstr (buf, fmt, args);
190 va_end (args);
191}
192
193
194/**
195 * Write a 0-terminated formatted string to a buffer, excluding the
196 * 0-terminator.
197 *
198 * Grows the buffer if necessary.
199 *
200 * @param buf the buffer to write to
201 * @param fmt format string
202 * @param args format argument list
203 */
204void
205GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf,
206 const char *fmt,
207 va_list args)
208{
209 int res;
210 va_list args2;
211
212 va_copy (args2, args);
213 res = vsnprintf (NULL, 0, fmt, args2);
214 va_end (args2);
215
216 GNUNET_assert (res >= 0);
217 GNUNET_buffer_ensure_remaining (buf, res + 1);
218
219 va_copy (args2, args);
220 res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2);
221 va_end (args2);
222
223 GNUNET_assert (res >= 0);
224 buf->position += res;
225 GNUNET_assert (buf->position <= buf->capacity);
226}