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
15 void membuff_purge(struct membuff *mb)
17 /* set mb->head and mb->tail so the buffers look empty */
22 static int membuff_putrawflex(struct membuff *mb, int maxlen, bool update,
23 char ***data, int *offsetp)
27 /* always write to 'mb->head' */
28 assert(data && offsetp);
30 *offsetp = mb->head - mb->start;
32 /* if there is no buffer, we can do nothing */
37 * if head is ahead of tail, we can write from head until the end of
40 if (mb->head >= mb->tail) {
41 /* work out how many bytes can fit here */
42 len = mb->end - mb->head - 1;
43 if (maxlen >= 0 && len > maxlen)
46 /* update the head pointer to mark these bytes as written */
51 * if the tail isn't at start of the buffer, then we can
52 * write one more byte right at the end
54 if ((maxlen < 0 || len < maxlen) && mb->tail != mb->start) {
60 /* otherwise now we can write until head almost reaches tail */
62 /* work out how many bytes can fit here */
63 len = mb->tail - mb->head - 1;
64 if (maxlen >= 0 && len > maxlen)
67 /* update the head pointer to mark these bytes as written */
72 /* return the number of bytes which can be/must be written */
76 int membuff_putraw(struct membuff *mb, int maxlen, bool update, char **data)
82 size = membuff_putrawflex(mb, maxlen, update, &datap, &offset);
83 *data = *datap + offset;
88 bool membuff_putbyte(struct membuff *mb, int ch)
92 if (membuff_putraw(mb, 1, true, &data) != 1)
99 int membuff_getraw(struct membuff *mb, int maxlen, bool update, char **data)
103 /* assume for now there is no data to get */
107 * in this case head is ahead of tail, so we must return data between
110 if (mb->head > mb->tail) {
111 /* work out the amount of data */
113 len = mb->head - mb->tail;
115 /* check it isn't too much */
116 if (maxlen >= 0 && len > maxlen)
119 /* & mark it as read from the buffer */
125 * if head is before tail, then we have data between 'tail' and 'end'
126 * and some more data between 'start' and 'head'(which we can't
129 else if (mb->head < mb->tail) {
130 /* work out the amount of data */
132 len = mb->end - mb->tail;
133 if (maxlen >= 0 && len > maxlen)
137 if (mb->tail == mb->end)
138 mb->tail = mb->start;
142 debug("getraw: maxlen=%d, update=%d, head=%d, tail=%d, data=%d, len=%d",
143 maxlen, update, (int)(mb->head - mb->start),
144 (int)(mb->tail - mb->start), (int)(*data - mb->start), len);
146 /* return the number of bytes we found */
150 int membuff_getbyte(struct membuff *mb)
154 return membuff_getraw(mb, 1, true, &data) != 1 ? -1 : *(uint8_t *)data;
157 int membuff_peekbyte(struct membuff *mb)
161 return membuff_getraw(mb, 1, false, &data) != 1 ? -1 : *(uint8_t *)data;
164 int membuff_get(struct membuff *mb, char *buff, int maxlen)
166 char *data = 0, *buffptr = buff;
170 * do this in up to two lots(see GetRaw for why) stopping when there
173 for (i = 0; len && i < 2; i++) {
174 /* get a pointer to the data available */
175 len = membuff_getraw(mb, maxlen, true, &data);
177 /* copy it into the buffer */
178 memcpy(buffptr, data, len);
183 /* return the number of bytes read */
184 return buffptr - buff;
187 int membuff_put(struct membuff *mb, const char *buff, int length)
190 int towrite, i, written;
192 for (i = written = 0; i < 2; i++) {
193 /* ask where some data can be written */
194 towrite = membuff_putraw(mb, length, true, &data);
196 /* and write it, updating the bytes length */
197 memcpy(data, buff, towrite);
203 /* return the number of bytes written */
207 bool membuff_isempty(struct membuff *mb)
209 return mb->head == mb->tail;
212 int membuff_avail(struct membuff *mb)
218 /* make a copy of this buffer's control data */
221 /* now read everything out of the copied buffer */
222 for (i = avail = 0; i < 2; i++)
223 avail += membuff_getraw(©, -1, true, &data);
225 /* and return how much we read */
229 int membuff_size(struct membuff *mb)
231 return mb->end - mb->start;
234 bool membuff_makecontig(struct membuff *mb)
236 int topsize, botsize;
238 debug("makecontig: head=%d, tail=%d, size=%d",
239 (int)(mb->head - mb->start), (int)(mb->tail - mb->start),
240 (int)(mb->end - mb->start));
243 * first we move anything at the start of the buffer into the correct
244 * place some way along
246 if (mb->tail > mb->head) {
248 * the data is split into two parts, from 0 to ->head and
249 * from ->tail to ->end. We move the stuff from 0 to ->head
250 * up to make space for the other data before it
252 topsize = mb->end - mb->tail;
253 botsize = mb->head - mb->start;
256 * must move data at bottom up by 'topsize' bytes - check if
259 if (mb->head + topsize >= mb->tail)
261 memmove(mb->start + topsize, mb->start, botsize);
262 debug(" - memmove(%d, %d, %d)", topsize, 0, botsize);
264 /* nothing at the start, so skip that step */
266 topsize = mb->head - mb->tail;
270 /* now move data at top down to the bottom */
271 memcpy(mb->start, mb->tail, topsize);
272 debug(" - memcpy(%d, %d, %d)", 0, (int)(mb->tail - mb->start), topsize);
274 /* adjust pointers */
275 mb->tail = mb->start;
276 mb->head = mb->start + topsize + botsize;
278 debug(" - head=%d, tail=%d", (int)(mb->head - mb->start),
279 (int)(mb->tail - mb->start));
285 int membuff_free(struct membuff *mb)
287 return mb->end == mb->start ? 0 :
288 (mb->end - mb->start) - 1 - membuff_avail(mb);
291 int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch)
293 int len; /* number of bytes read (!= string length) */
298 end = mb->head >= mb->tail ? mb->head : mb->end;
299 for (len = 0, s = mb->tail; s < end && len < maxlen - 1; str++) {
302 if (*str == '\n' || *str < minch) {
306 if (s == end && mb->tail > mb->head) {
312 /* couldn't get the whole string */
319 /* terminate the string, update the membuff and return success */
321 mb->tail = s == mb->end ? mb->start : s;
326 int membuff_extend_by(struct membuff *mb, int by, int max)
328 int oldhead, oldtail;
332 /* double the buffer size until it is big enough */
334 for (orig = mb->end - mb->start, size = orig; size < orig + by;)
337 size = min(size, max);
340 /* if we're already at maximum, give up */
344 oldhead = mb->head - mb->start;
345 oldtail = mb->tail - mb->start;
346 ptr = realloc(mb->start, size);
350 mb->head = mb->start + oldhead;
351 mb->tail = mb->start + oldtail;
353 if (mb->head < mb->tail) {
354 memmove(mb->tail + by, mb->tail, orig - oldtail);
357 mb->end = mb->start + size;
362 void membuff_init(struct membuff *mb, char *buff, int size)
365 mb->end = mb->start + size;
369 int membuff_new(struct membuff *mb, int size)
371 mb->start = malloc(size);
375 membuff_init(mb, mb->start, size);
379 void membuff_uninit(struct membuff *mb)
386 void membuff_dispose(struct membuff *mb)