]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - lib/membuff.c
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
)