1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
6 * Copyright (c) 1992 Simon Glass
14 void membuff_purge(struct membuff *mb)
16 /* set mb->head and mb->tail so the buffers look empty */
21 static int membuff_putrawflex(struct membuff *mb, int maxlen, bool update,
22 char ***data, int *offsetp)
26 /* always write to 'mb->head' */
27 assert(data && offsetp);
29 *offsetp = mb->head - mb->start;
31 /* if there is no buffer, we can do nothing */
36 * if head is ahead of tail, we can write from head until the end of
39 if (mb->head >= mb->tail) {
40 /* work out how many bytes can fit here */
41 len = mb->end - mb->head - 1;
42 if (maxlen >= 0 && len > maxlen)
45 /* update the head pointer to mark these bytes as written */
50 * if the tail isn't at start of the buffer, then we can
51 * write one more byte right at the end
53 if ((maxlen < 0 || len < maxlen) && mb->tail != mb->start) {
59 /* otherwise now we can write until head almost reaches tail */
61 /* work out how many bytes can fit here */
62 len = mb->tail - mb->head - 1;
63 if (maxlen >= 0 && len > maxlen)
66 /* update the head pointer to mark these bytes as written */
71 /* return the number of bytes which can be/must be written */
75 int membuff_putraw(struct membuff *mb, int maxlen, bool update, char **data)
81 size = membuff_putrawflex(mb, maxlen, update, &datap, &offset);
82 *data = *datap + offset;
87 bool membuff_putbyte(struct membuff *mb, int ch)
91 if (membuff_putraw(mb, 1, true, &data) != 1)
98 int membuff_getraw(struct membuff *mb, int maxlen, bool update, char **data)
102 /* assume for now there is no data to get */
106 * in this case head is ahead of tail, so we must return data between
109 if (mb->head > mb->tail) {
110 /* work out the amount of data */
112 len = mb->head - mb->tail;
114 /* check it isn't too much */
115 if (maxlen >= 0 && len > maxlen)
118 /* & mark it as read from the buffer */
124 * if head is before tail, then we have data between 'tail' and 'end'
125 * and some more data between 'start' and 'head'(which we can't
128 else if (mb->head < mb->tail) {
129 /* work out the amount of data */
131 len = mb->end - mb->tail;
132 if (maxlen >= 0 && len > maxlen)
136 if (mb->tail == mb->end)
137 mb->tail = mb->start;
141 debug("getraw: maxlen=%d, update=%d, head=%d, tail=%d, data=%d, len=%d",
142 maxlen, update, (int)(mb->head - mb->start),
143 (int)(mb->tail - mb->start), (int)(*data - mb->start), len);
145 /* return the number of bytes we found */
149 int membuff_getbyte(struct membuff *mb)
153 return membuff_getraw(mb, 1, true, &data) != 1 ? -1 : *(uint8_t *)data;
156 int membuff_peekbyte(struct membuff *mb)
160 return membuff_getraw(mb, 1, false, &data) != 1 ? -1 : *(uint8_t *)data;
163 int membuff_get(struct membuff *mb, char *buff, int maxlen)
165 char *data = 0, *buffptr = buff;
169 * do this in up to two lots(see GetRaw for why) stopping when there
172 for (i = 0; len && i < 2; i++) {
173 /* get a pointer to the data available */
174 len = membuff_getraw(mb, maxlen, true, &data);
176 /* copy it into the buffer */
177 memcpy(buffptr, data, len);
182 /* return the number of bytes read */
183 return buffptr - buff;
186 int membuff_put(struct membuff *mb, const char *buff, int length)
189 int towrite, i, written;
191 for (i = written = 0; i < 2; i++) {
192 /* ask where some data can be written */
193 towrite = membuff_putraw(mb, length, true, &data);
195 /* and write it, updating the bytes length */
196 memcpy(data, buff, towrite);
202 /* return the number of bytes written */
206 bool membuff_isempty(struct membuff *mb)
208 return mb->head == mb->tail;
211 int membuff_avail(struct membuff *mb)
217 /* make a copy of this buffer's control data */
220 /* now read everything out of the copied buffer */
221 for (i = avail = 0; i < 2; i++)
222 avail += membuff_getraw(©, -1, true, &data);
224 /* and return how much we read */
228 int membuff_size(struct membuff *mb)
230 return mb->end - mb->start;
233 bool membuff_makecontig(struct membuff *mb)
235 int topsize, botsize;
237 debug("makecontig: head=%d, tail=%d, size=%d",
238 (int)(mb->head - mb->start), (int)(mb->tail - mb->start),
239 (int)(mb->end - mb->start));
242 * first we move anything at the start of the buffer into the correct
243 * place some way along
245 if (mb->tail > mb->head) {
247 * the data is split into two parts, from 0 to ->head and
248 * from ->tail to ->end. We move the stuff from 0 to ->head
249 * up to make space for the other data before it
251 topsize = mb->end - mb->tail;
252 botsize = mb->head - mb->start;
255 * must move data at bottom up by 'topsize' bytes - check if
258 if (mb->head + topsize >= mb->tail)
260 memmove(mb->start + topsize, mb->start, botsize);
261 debug(" - memmove(%d, %d, %d)", topsize, 0, botsize);
263 /* nothing at the start, so skip that step */
265 topsize = mb->head - mb->tail;
269 /* now move data at top down to the bottom */
270 memcpy(mb->start, mb->tail, topsize);
271 debug(" - memcpy(%d, %d, %d)", 0, (int)(mb->tail - mb->start), topsize);
273 /* adjust pointers */
274 mb->tail = mb->start;
275 mb->head = mb->start + topsize + botsize;
277 debug(" - head=%d, tail=%d", (int)(mb->head - mb->start),
278 (int)(mb->tail - mb->start));
284 int membuff_free(struct membuff *mb)
286 return mb->end == mb->start ? 0 :
287 (mb->end - mb->start) - 1 - membuff_avail(mb);
290 int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch)
292 int len; /* number of bytes read (!= string length) */
297 end = mb->head >= mb->tail ? mb->head : mb->end;
298 for (len = 0, s = mb->tail; s < end && len < maxlen - 1; str++) {
301 if (*str == '\n' || *str < minch) {
305 if (s == end && mb->tail > mb->head) {
311 /* couldn't get the whole string */
318 /* terminate the string, update the membuff and return success */
320 mb->tail = s == mb->end ? mb->start : s;
325 int membuff_extend_by(struct membuff *mb, int by, int max)
327 int oldhead, oldtail;
331 /* double the buffer size until it is big enough */
333 for (orig = mb->end - mb->start, size = orig; size < orig + by;)
336 size = min(size, max);
339 /* if we're already at maximum, give up */
343 oldhead = mb->head - mb->start;
344 oldtail = mb->tail - mb->start;
345 ptr = realloc(mb->start, size);
349 mb->head = mb->start + oldhead;
350 mb->tail = mb->start + oldtail;
352 if (mb->head < mb->tail) {
353 memmove(mb->tail + by, mb->tail, orig - oldtail);
356 mb->end = mb->start + size;
361 void membuff_init(struct membuff *mb, char *buff, int size)
364 mb->end = mb->start + size;
368 int membuff_new(struct membuff *mb, int size)
370 mb->start = malloc(size);
374 membuff_init(mb, mb->start, size);
378 void membuff_uninit(struct membuff *mb)
385 void membuff_dispose(struct membuff *mb)