buffer.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. * This component and the accompanying materials are made available
  5. * under the terms of the License "Eclipse Public License v1.0"
  6. * which accompanies this distribution, and is available
  7. * at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. *
  9. * Initial Contributors:
  10. * Nokia Corporation - initial contribution.
  11. *
  12. * Contributors:
  13. *
  14. * Description:
  15. * Expanding text buffer
  16. *
  17. */
  18. #include <malloc.h>
  19. #include "buffer.h"
  20. #include <string.h>
  21. /* efficient allocation unit: */
  22. #define ALLOCSIZE 4096
  23. #define INITIALBLOCKCOUNT 128
  24. byteblock *buffer_newblock(buffer *b, unsigned int size)
  25. {
  26. byteblock *bb;
  27. if (!b)
  28. return NULL;
  29. b->lastblock++;
  30. if (b->lastblock == b->maxblocks)
  31. {
  32. byteblock **nbb = (byteblock **)realloc(b->blocks, sizeof(byteblock *) * (b->maxblocks + INITIALBLOCKCOUNT));
  33. if (!nbb)
  34. return NULL;
  35. b->blocks = nbb;
  36. b->maxblocks += INITIALBLOCKCOUNT;
  37. }
  38. bb = malloc(sizeof(byteblock) + size-1);
  39. if (!bb)
  40. {
  41. return NULL;
  42. }
  43. b->blocks[b->lastblock] = bb;
  44. bb->fill = 0;
  45. bb->size = size;
  46. return bb;
  47. }
  48. buffer *buffer_new(void)
  49. {
  50. buffer *b = malloc(sizeof(buffer));
  51. if (b)
  52. {
  53. b->lastblock = -1; /* no blocks as yet */
  54. b->maxblocks = INITIALBLOCKCOUNT;
  55. b->blocks = (byteblock **)malloc(sizeof(byteblock *) * b->maxblocks);
  56. if (!b->blocks)
  57. {
  58. free(b);
  59. return NULL;
  60. }
  61. buffer_newblock(b, ALLOCSIZE);
  62. }
  63. return b;
  64. }
  65. char *buffer_append(buffer *b, char *bytes, unsigned int size)
  66. {
  67. if (!b || !bytes)
  68. return NULL;
  69. char *space = buffer_makespace(b, size);
  70. if (!space)
  71. return NULL;
  72. memcpy(space, bytes, size);
  73. buffer_usespace(b, size);
  74. return space;
  75. }
  76. char *buffer_prepend(buffer *b, char *bytes, unsigned int size)
  77. {
  78. byteblock *bb;
  79. if (!b || !bytes)
  80. return NULL;
  81. bb = buffer_newblock(b, size);
  82. /* cheat by moving the new block from the end to the start. */
  83. bb = b->blocks[b->lastblock];
  84. if (b->lastblock != 0)
  85. {
  86. memmove(b->blocks+1, b->blocks, sizeof(byteblock *) * b->lastblock );
  87. b->blocks[0] = bb;
  88. }
  89. memcpy(&(b->blocks[0]->byte0), bytes, size);
  90. b->blocks[0]->fill = size;
  91. return &(b->blocks[0]->byte0);
  92. }
  93. /* Allocate memory at the end of the buffer (if there isn't
  94. * enough already) so that the user can append at least that
  95. * many bytes without overrunning the buffer. This is useful
  96. * where one may not know in advance how many bytes are to be
  97. * added (e.g. reading from a socket) but one does know the
  98. * upper limit.
  99. */
  100. char *buffer_makespace(buffer *b, unsigned int size)
  101. {
  102. byteblock *bb;
  103. byteblock *last;
  104. if (!b)
  105. return NULL;
  106. last = b->blocks[b->lastblock];
  107. if (last->size - last->fill > size)
  108. return (&last->byte0 + last->fill);
  109. if (size > ALLOCSIZE)
  110. {
  111. bb = buffer_newblock(b, size);
  112. } else {
  113. bb = buffer_newblock(b, ALLOCSIZE);
  114. }
  115. if (!bb)
  116. return NULL;
  117. return &bb->byte0;
  118. }
  119. void buffer_usespace(buffer *b, unsigned int nbytes)
  120. {
  121. byteblock *last;
  122. if (!b)
  123. return;
  124. last = b->blocks[b->lastblock];
  125. if (last->fill + nbytes < last->size)
  126. last->fill += nbytes;
  127. else
  128. last->fill = last->size; /* really an error - no exceptions though. */
  129. }
  130. byteblock *buffer_getbytes(buffer *b, unsigned int *iterator)
  131. {
  132. if (!b)
  133. return NULL;
  134. if (*iterator > b->lastblock)
  135. return NULL;
  136. return b->blocks[(*iterator)++];
  137. }
  138. void buffer_free(buffer **b)
  139. {
  140. int i;
  141. buffer *bf;
  142. if (!b || !*b)
  143. return;
  144. bf=*b;
  145. if (bf->blocks)
  146. {
  147. for (i=0; i <= bf->lastblock; i++)
  148. {
  149. if (bf->blocks[i])
  150. free(bf->blocks[i]);
  151. }
  152. free(bf->blocks);
  153. }
  154. free(bf);
  155. *b = NULL;
  156. }