2 This file is part of GNUnet
3 Copyright (C) 2020 GNUnet e.V.
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.
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.
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/>
18 * @brief Common buffer management functions.
19 * @author Florian Dold
22 #include "gnunet_util_lib.h"
23 #include "gnunet_buffer_lib.h"
26 * Initialize a buffer with the given capacity.
28 * When a buffer is allocated with this function, a warning is logged
29 * when the buffer exceeds the initial capacity.
31 * @param buf the buffer to initialize
32 * @param capacity the capacity (in bytes) to allocate for @a buf
35 GNUNET_buffer_prealloc (struct GNUNET_Buffer *buf, size_t capacity)
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;
48 * Make sure that at least @a n bytes remaining in the buffer.
50 * @param buf buffer to potentially grow
51 * @param n number of bytes that should be available to write
54 GNUNET_buffer_ensure_remaining (struct GNUNET_Buffer *buf, size_t n)
56 size_t new_capacity = buf->position + n;
58 if (new_capacity <= buf->capacity)
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;
66 buf->mem = GNUNET_realloc (buf->mem, new_capacity);
68 buf->mem = GNUNET_malloc (new_capacity);
73 * Write bytes to the buffer.
75 * Grows the buffer if necessary.
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
83 GNUNET_buffer_write (struct GNUNET_Buffer *buf, const char *data, size_t len)
85 GNUNET_buffer_ensure_remaining (buf, len);
86 memcpy (buf->mem + buf->position, data, len);
92 * Write a 0-terminated string to a buffer, excluding the 0-terminator.
94 * @param buf the buffer to write to
95 * @param str the string to write to @a buf
98 GNUNET_buffer_write_str (struct GNUNET_Buffer *buf, const char *str)
100 size_t len = strlen (str);
102 GNUNET_buffer_write (buf, str, len);
107 * Clear the buffer and return the string it contained.
108 * The caller is responsible to eventually #GNUNET_free
109 * the returned string.
111 * The returned string is always 0-terminated.
113 * @param buf the buffer to reap the string from
114 * @returns the buffer contained in the string
117 GNUNET_buffer_reap_str (struct GNUNET_Buffer *buf)
121 /* ensure 0-termination */
122 if ( (0 == buf->position) || ('\0' != buf->mem[buf->position - 1]))
124 GNUNET_buffer_ensure_remaining (buf, 1);
125 buf->mem[buf->position++] = '\0';
128 *buf = (struct GNUNET_Buffer) { 0 };
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.
139 GNUNET_buffer_clear (struct GNUNET_Buffer *buf)
141 GNUNET_free_non_null (buf->mem);
142 *buf = (struct GNUNET_Buffer) { 0 };
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.
151 * @param buf buffer to write to
152 * @param str string containing the new path component
155 GNUNET_buffer_write_path (struct GNUNET_Buffer *buf, const char *str)
157 size_t len = strlen (str);
159 while ( (0 != len) && ('/' == str[0]) )
164 if ( (0 == buf->position) || ('/' != buf->mem[buf->position - 1]) )
166 GNUNET_buffer_ensure_remaining (buf, 1);
167 buf->mem[buf->position++] = '/';
169 GNUNET_buffer_write (buf, str, len);
174 * Write a 0-terminated formatted string to a buffer, excluding the
177 * Grows the buffer if necessary.
179 * @param buf the buffer to write to
180 * @param fmt format string
181 * @param ... format arguments
184 GNUNET_buffer_write_fstr (struct GNUNET_Buffer *buf, const char *fmt, ...)
188 va_start (args, fmt);
189 GNUNET_buffer_write_vfstr (buf, fmt, args);
195 * Write a 0-terminated formatted string to a buffer, excluding the
198 * Grows the buffer if necessary.
200 * @param buf the buffer to write to
201 * @param fmt format string
202 * @param args format argument list
205 GNUNET_buffer_write_vfstr (struct GNUNET_Buffer *buf,
212 va_copy (args2, args);
213 res = vsnprintf (NULL, 0, fmt, args2);
216 GNUNET_assert (res >= 0);
217 GNUNET_buffer_ensure_remaining (buf, res + 1);
219 va_copy (args2, args);
220 res = vsnprintf (buf->mem + buf->position, res + 1, fmt, args2);
223 GNUNET_assert (res >= 0);
224 buf->position += res;
225 GNUNET_assert (buf->position <= buf->capacity);