use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / util / buffer.c
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  */
34 void
35 GNUNET_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  */
53 void
54 GNUNET_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  */
82 void
83 GNUNET_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  */
97 void
98 GNUNET_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  */
116 char *
117 GNUNET_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  */
138 void
139 GNUNET_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  */
154 void
155 GNUNET_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  */
183 void
184 GNUNET_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  */
204 void
205 GNUNET_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 }