membuff.c 8.3 KB

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