membuff.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2015 Google, Inc
  4. * Written by Simon Glass <sjg@chromium.org>
  5. *
  6. * Copyright (c) 1992 Simon Glass
  7. */
  8. #include <common.h>
  9. #include <errno.h>
  10. #include <malloc.h>
  11. #include "membuff.h"
  12. void membuff_purge(struct membuff *mb)
  13. {
  14. /* set mb->head and mb->tail so the buffers look empty */
  15. mb->head = mb->start;
  16. mb->tail = mb->start;
  17. }
  18. static int membuff_putrawflex(struct membuff *mb, int maxlen, bool update,
  19. char ***data, int *offsetp)
  20. {
  21. int len;
  22. /* always write to 'mb->head' */
  23. assert(data && offsetp);
  24. *data = &mb->start;
  25. *offsetp = mb->head - mb->start;
  26. /* if there is no buffer, we can do nothing */
  27. if (!mb->start)
  28. return 0;
  29. /*
  30. * if head is ahead of tail, we can write from head until the end of
  31. * the buffer
  32. */
  33. if (mb->head >= mb->tail) {
  34. /* work out how many bytes can fit here */
  35. len = mb->end - mb->head - 1;
  36. if (maxlen >= 0 && len > maxlen)
  37. len = maxlen;
  38. /* update the head pointer to mark these bytes as written */
  39. if (update)
  40. mb->head += len;
  41. /*
  42. * if the tail isn't at start of the buffer, then we can
  43. * write one more byte right at the end
  44. */
  45. if ((maxlen < 0 || len < maxlen) && mb->tail != mb->start) {
  46. len++;
  47. if (update)
  48. mb->head = mb->start;
  49. }
  50. /* otherwise now we can write until head almost reaches tail */
  51. } else {
  52. /* work out how many bytes can fit here */
  53. len = mb->tail - mb->head - 1;
  54. if (maxlen >= 0 && len > maxlen)
  55. len = maxlen;
  56. /* update the head pointer to mark these bytes as written */
  57. if (update)
  58. mb->head += len;
  59. }
  60. /* return the number of bytes which can be/must be written */
  61. return len;
  62. }
  63. int membuff_putraw(struct membuff *mb, int maxlen, bool update, char **data)
  64. {
  65. char **datap;
  66. int offset;
  67. int size;
  68. size = membuff_putrawflex(mb, maxlen, update, &datap, &offset);
  69. *data = *datap + offset;
  70. return size;
  71. }
  72. bool membuff_putbyte(struct membuff *mb, int ch)
  73. {
  74. char *data;
  75. if (membuff_putraw(mb, 1, true, &data) != 1)
  76. return false;
  77. *data = ch;
  78. return true;
  79. }
  80. int membuff_getraw(struct membuff *mb, int maxlen, bool update, char **data)
  81. {
  82. int len;
  83. /* assume for now there is no data to get */
  84. len = 0;
  85. /*
  86. * in this case head is ahead of tail, so we must return data between
  87. *'tail' and 'head'
  88. */
  89. if (mb->head > mb->tail) {
  90. /* work out the amount of data */
  91. *data = mb->tail;
  92. len = mb->head - mb->tail;
  93. /* check it isn't too much */
  94. if (maxlen >= 0 && len > maxlen)
  95. len = maxlen;
  96. /* & mark it as read from the buffer */
  97. if (update)
  98. mb->tail += len;
  99. }
  100. /*
  101. * if head is before tail, then we have data between 'tail' and 'end'
  102. * and some more data between 'start' and 'head'(which we can't
  103. * return this time
  104. */
  105. else if (mb->head < mb->tail) {
  106. /* work out the amount of data */
  107. *data = mb->tail;
  108. len = mb->end - mb->tail;
  109. if (maxlen >= 0 && len > maxlen)
  110. len = maxlen;
  111. if (update) {
  112. mb->tail += len;
  113. if (mb->tail == mb->end)
  114. mb->tail = mb->start;
  115. }
  116. }
  117. debug("getraw: maxlen=%d, update=%d, head=%d, tail=%d, data=%d, len=%d",
  118. maxlen, update, (int)(mb->head - mb->start),
  119. (int)(mb->tail - mb->start), (int)(*data - mb->start), len);
  120. /* return the number of bytes we found */
  121. return len;
  122. }
  123. int membuff_getbyte(struct membuff *mb)
  124. {
  125. char *data = 0;
  126. return membuff_getraw(mb, 1, true, &data) != 1 ? -1 : *(uint8_t *)data;
  127. }
  128. int membuff_peekbyte(struct membuff *mb)
  129. {
  130. char *data = 0;
  131. return membuff_getraw(mb, 1, false, &data) != 1 ? -1 : *(uint8_t *)data;
  132. }
  133. int membuff_get(struct membuff *mb, char *buff, int maxlen)
  134. {
  135. char *data = 0, *buffptr = buff;
  136. int len = 1, i;
  137. /*
  138. * do this in up to two lots(see GetRaw for why) stopping when there
  139. * is no more data
  140. */
  141. for (i = 0; len && i < 2; i++) {
  142. /* get a pointer to the data available */
  143. len = membuff_getraw(mb, maxlen, true, &data);
  144. /* copy it into the buffer */
  145. memcpy(buffptr, data, len);
  146. buffptr += len;
  147. maxlen -= len;
  148. }
  149. /* return the number of bytes read */
  150. return buffptr - buff;
  151. }
  152. int membuff_put(struct membuff *mb, const char *buff, int length)
  153. {
  154. char *data;
  155. int towrite, i, written;
  156. for (i = written = 0; i < 2; i++) {
  157. /* ask where some data can be written */
  158. towrite = membuff_putraw(mb, length, true, &data);
  159. /* and write it, updating the bytes length */
  160. memcpy(data, buff, towrite);
  161. written += towrite;
  162. buff += towrite;
  163. length -= towrite;
  164. }
  165. /* return the number of bytes written */
  166. return written;
  167. }
  168. bool membuff_isempty(struct membuff *mb)
  169. {
  170. return mb->head == mb->tail;
  171. }
  172. int membuff_avail(struct membuff *mb)
  173. {
  174. struct membuff copy;
  175. int i, avail;
  176. char *data = 0;
  177. /* make a copy of this buffer's control data */
  178. copy = *mb;
  179. /* now read everything out of the copied buffer */
  180. for (i = avail = 0; i < 2; i++)
  181. avail += membuff_getraw(&copy, -1, true, &data);
  182. /* and return how much we read */
  183. return avail;
  184. }
  185. int membuff_size(struct membuff *mb)
  186. {
  187. return mb->end - mb->start;
  188. }
  189. bool membuff_makecontig(struct membuff *mb)
  190. {
  191. int topsize, botsize;
  192. debug("makecontig: head=%d, tail=%d, size=%d",
  193. (int)(mb->head - mb->start), (int)(mb->tail - mb->start),
  194. (int)(mb->end - mb->start));
  195. /*
  196. * first we move anything at the start of the buffer into the correct
  197. * place some way along
  198. */
  199. if (mb->tail > mb->head) {
  200. /*
  201. * the data is split into two parts, from 0 to ->head and
  202. * from ->tail to ->end. We move the stuff from 0 to ->head
  203. * up to make space for the other data before it
  204. */
  205. topsize = mb->end - mb->tail;
  206. botsize = mb->head - mb->start;
  207. /*
  208. * must move data at bottom up by 'topsize' bytes - check if
  209. * there's room
  210. */
  211. if (mb->head + topsize >= mb->tail)
  212. return false;
  213. memmove(mb->start + topsize, mb->start, botsize);
  214. debug(" - memmove(%d, %d, %d)", topsize, 0, botsize);
  215. /* nothing at the start, so skip that step */
  216. } else {
  217. topsize = mb->head - mb->tail;
  218. botsize = 0;
  219. }
  220. /* now move data at top down to the bottom */
  221. memcpy(mb->start, mb->tail, topsize);
  222. debug(" - memcpy(%d, %d, %d)", 0, (int)(mb->tail - mb->start), topsize);
  223. /* adjust pointers */
  224. mb->tail = mb->start;
  225. mb->head = mb->start + topsize + botsize;
  226. debug(" - head=%d, tail=%d", (int)(mb->head - mb->start),
  227. (int)(mb->tail - mb->start));
  228. /* all ok */
  229. return true;
  230. }
  231. int membuff_free(struct membuff *mb)
  232. {
  233. return mb->end == mb->start ? 0 :
  234. (mb->end - mb->start) - 1 - membuff_avail(mb);
  235. }
  236. int membuff_readline(struct membuff *mb, char *str, int maxlen, int minch)
  237. {
  238. int len; /* number of bytes read (!= string length) */
  239. char *s, *end;
  240. bool ok = false;
  241. char *orig = str;
  242. end = mb->head >= mb->tail ? mb->head : mb->end;
  243. for (len = 0, s = mb->tail; s < end && len < maxlen - 1; str++) {
  244. *str = *s++;
  245. len++;
  246. if (*str == '\n' || *str < minch) {
  247. ok = true;
  248. break;
  249. }
  250. if (s == end && mb->tail > mb->head) {
  251. s = mb->start;
  252. end = mb->head;
  253. }
  254. }
  255. /* couldn't get the whole string */
  256. if (!ok) {
  257. if (maxlen)
  258. *orig = '\0';
  259. return 0;
  260. }
  261. /* terminate the string, update the membuff and return success */
  262. *str = '\0';
  263. mb->tail = s == mb->end ? mb->start : s;
  264. return len;
  265. }
  266. int membuff_extend_by(struct membuff *mb, int by, int max)
  267. {
  268. int oldhead, oldtail;
  269. int size, orig;
  270. char *ptr;
  271. /* double the buffer size until it is big enough */
  272. assert(by >= 0);
  273. for (orig = mb->end - mb->start, size = orig; size < orig + by;)
  274. size *= 2;
  275. if (max != -1)
  276. size = min(size, max);
  277. by = size - orig;
  278. /* if we're already at maximum, give up */
  279. if (by <= 0)
  280. return -E2BIG;
  281. oldhead = mb->head - mb->start;
  282. oldtail = mb->tail - mb->start;
  283. ptr = realloc(mb->start, size);
  284. if (!ptr)
  285. return -ENOMEM;
  286. mb->start = ptr;
  287. mb->head = mb->start + oldhead;
  288. mb->tail = mb->start + oldtail;
  289. if (mb->head < mb->tail) {
  290. memmove(mb->tail + by, mb->tail, orig - oldtail);
  291. mb->tail += by;
  292. }
  293. mb->end = mb->start + size;
  294. return 0;
  295. }
  296. void membuff_init(struct membuff *mb, char *buff, int size)
  297. {
  298. mb->start = buff;
  299. mb->end = mb->start + size;
  300. membuff_purge(mb);
  301. }
  302. int membuff_new(struct membuff *mb, int size)
  303. {
  304. mb->start = malloc(size);
  305. if (!mb->start)
  306. return -ENOMEM;
  307. membuff_init(mb, mb->start, size);
  308. return 0;
  309. }
  310. void membuff_uninit(struct membuff *mb)
  311. {
  312. mb->end = NULL;
  313. mb->start = NULL;
  314. membuff_purge(mb);
  315. }
  316. void membuff_dispose(struct membuff *mb)
  317. {
  318. free(&mb->start);
  319. membuff_uninit(mb);
  320. }