]>
git.ipfire.org Git - people/ms/u-boot.git/blob - lib/membuff.c
2 * Copyright (c) 2015 Google, Inc
3 * Written by Simon Glass <sjg@chromium.org>
5 * Copyright (c) 1992 Simon Glass
7 * SPDX-License-Identifier: GPL-2.0+
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
)