HTChunk.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /* Chunk handling: Flexible arrays
  2. * ===============================
  3. *
  4. */
  5. #include <HTUtils.h>
  6. #include <HTChunk.h>
  7. #include <LYLeaks.h>
  8. /*
  9. * Initialize a chunk with a certain allocation unit
  10. */
  11. void HTChunkInit(HTChunk *ch, int grow)
  12. {
  13. ch->data = 0;
  14. ch->growby = grow;
  15. ch->size = 0;
  16. ch->allocated = 0;
  17. }
  18. /* Create a chunk with a certain allocation unit
  19. * --------------
  20. */
  21. HTChunk *HTChunkCreate(int grow)
  22. {
  23. HTChunk *ch = typecalloc(HTChunk);
  24. if (ch == NULL)
  25. outofmem(__FILE__, "creation of chunk");
  26. HTChunkInit(ch, grow);
  27. return ch;
  28. }
  29. HTChunk *HTChunkCreateMayFail(int grow, int failok)
  30. {
  31. HTChunk *ch = typecalloc(HTChunk);
  32. if (ch == NULL) {
  33. if (!failok) {
  34. outofmem(__FILE__, "creation of chunk");
  35. } else {
  36. return ch;
  37. }
  38. }
  39. HTChunkInit(ch, grow);
  40. ch->failok = failok;
  41. return ch;
  42. }
  43. /* Create a chunk with a certain allocation unit and ensured size
  44. * --------------
  45. */
  46. HTChunk *HTChunkCreate2(int grow, size_t needed)
  47. {
  48. HTChunk *ch = typecalloc(HTChunk);
  49. if (ch == NULL)
  50. outofmem(__FILE__, "HTChunkCreate2");
  51. HTChunkInit(ch, grow);
  52. if (needed > 0) {
  53. ch->allocated = needed - 1 - ((needed - 1) % ch->growby)
  54. + ch->growby; /* Round up */
  55. CTRACE((tfp, "HTChunkCreate2: requested %d, allocate %d\n",
  56. (int) needed, ch->allocated));
  57. ch->data = typecallocn(char, ch->allocated);
  58. if (!ch->data)
  59. outofmem(__FILE__, "HTChunkCreate2 data");
  60. }
  61. return ch;
  62. }
  63. /* Clear a chunk of all data
  64. * --------------------------
  65. */
  66. void HTChunkClear(HTChunk *ch)
  67. {
  68. FREE(ch->data);
  69. ch->size = 0;
  70. ch->allocated = 0;
  71. }
  72. /* Free a chunk (and it's chain, if any)
  73. * -------------------------------------
  74. */
  75. void HTChunkFree(HTChunk *ch)
  76. {
  77. HTChunk *next;
  78. do {
  79. next = ch->next;
  80. FREE(ch->data);
  81. FREE(ch);
  82. ch = next;
  83. } while (ch != NULL);
  84. }
  85. /* Realloc the chunk
  86. * -----------------
  87. */
  88. BOOL HTChunkRealloc(HTChunk *ch, int growby)
  89. {
  90. char *data;
  91. ch->allocated = ch->allocated + growby;
  92. data = (ch->data
  93. ? (char *) realloc(ch->data, ch->allocated)
  94. : typecallocn(char, ch->allocated));
  95. if (data) {
  96. ch->data = data;
  97. } else if (ch->failok) {
  98. HTChunkClear(ch); /* allocation failed, clear all data - kw */
  99. return FALSE; /* caller should check ch->allocated - kw */
  100. } else {
  101. outofmem(__FILE__, "HTChunkRealloc");
  102. }
  103. return TRUE;
  104. }
  105. /* Append a character
  106. * ------------------
  107. */
  108. void HTChunkPutc(HTChunk *ch, char c)
  109. {
  110. if (ch->size >= ch->allocated) {
  111. if (!HTChunkRealloc(ch, ch->growby))
  112. return;
  113. }
  114. ch->data[ch->size++] = c;
  115. }
  116. /* like above but no realloc: extend to another chunk if necessary */
  117. HTChunk *HTChunkPutc2(HTChunk *ch, char c)
  118. {
  119. if (ch->size >= ch->allocated) {
  120. HTChunk *chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
  121. ch->next = chunk;
  122. HTChunkPutc(chunk, c);
  123. return chunk;
  124. }
  125. ch->data[ch->size++] = c;
  126. return ch;
  127. }
  128. /* Ensure a certain size
  129. * ---------------------
  130. */
  131. void HTChunkEnsure(HTChunk *ch, int needed)
  132. {
  133. if (needed <= ch->allocated)
  134. return;
  135. ch->allocated = needed - 1 - ((needed - 1) % ch->growby)
  136. + ch->growby; /* Round up */
  137. ch->data = (ch->data
  138. ? (char *) realloc(ch->data, ch->allocated)
  139. : typecallocn(char, ch->allocated));
  140. if (ch->data == NULL)
  141. outofmem(__FILE__, "HTChunkEnsure");
  142. }
  143. /*
  144. * Append a block of characters.
  145. */
  146. void HTChunkPutb(HTChunk *ch, const char *b, int l)
  147. {
  148. if (l <= 0)
  149. return;
  150. if (ch->size + l > ch->allocated) {
  151. int growby = l - (l % ch->growby) + ch->growby; /* Round up */
  152. if (!HTChunkRealloc(ch, growby))
  153. return;
  154. }
  155. memcpy(ch->data + ch->size, b, l);
  156. ch->size += l;
  157. }
  158. /* like above but no realloc: extend to another chunk if necessary */
  159. HTChunk *HTChunkPutb2(HTChunk *ch, const char *b, int l)
  160. {
  161. if (l <= 0)
  162. return ch;
  163. if (ch->size + l > ch->allocated) {
  164. HTChunk *chunk;
  165. int m = ch->allocated - ch->size;
  166. memcpy(ch->data + ch->size, b, m);
  167. ch->size += m;
  168. chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
  169. ch->next = chunk;
  170. HTChunkPutb(chunk, b + m, l - m);
  171. return chunk;
  172. }
  173. memcpy(ch->data + ch->size, b, l);
  174. ch->size += l;
  175. return ch;
  176. }
  177. #define PUTC(code) ch->data[ch->size++] = (char)(code)
  178. #define PUTC2(code) ch->data[ch->size++] = (char)(0x80|(0x3f &(code)))
  179. /*
  180. * Append a character encoded as UTF-8.
  181. */
  182. void HTChunkPutUtf8Char(HTChunk *ch, UCode_t code)
  183. {
  184. int utflen;
  185. if (TOASCII(code) < 128)
  186. utflen = 1;
  187. else if (code < 0x800L) {
  188. utflen = 2;
  189. } else if (code < 0x10000L) {
  190. utflen = 3;
  191. } else if (code < 0x200000L) {
  192. utflen = 4;
  193. } else if (code < 0x4000000L) {
  194. utflen = 5;
  195. } else if (code <= 0x7fffffffL) {
  196. utflen = 6;
  197. } else
  198. utflen = 0;
  199. if (ch->size + utflen > ch->allocated) {
  200. int growby = (ch->growby >= utflen) ? ch->growby : utflen;
  201. if (!HTChunkRealloc(ch, growby))
  202. return;
  203. }
  204. switch (utflen) {
  205. case 0:
  206. return;
  207. case 1:
  208. ch->data[ch->size++] = (char) code;
  209. return;
  210. case 2:
  211. PUTC(0xc0 | (code >> 6));
  212. break;
  213. case 3:
  214. PUTC(0xe0 | (code >> 12));
  215. break;
  216. case 4:
  217. PUTC(0xf0 | (code >> 18));
  218. break;
  219. case 5:
  220. PUTC(0xf8 | (code >> 24));
  221. break;
  222. case 6:
  223. PUTC(0xfc | (code >> 30));
  224. break;
  225. }
  226. switch (utflen) {
  227. case 6:
  228. PUTC2(code >> 24);
  229. /* FALLTHRU */
  230. case 5:
  231. PUTC2(code >> 18);
  232. /* FALLTHRU */
  233. case 4:
  234. PUTC2(code >> 12);
  235. /* FALLTHRU */
  236. case 3:
  237. PUTC2(code >> 6);
  238. /* FALLTHRU */
  239. case 2:
  240. PUTC2(code);
  241. break;
  242. }
  243. }
  244. /* Terminate a chunk
  245. * -----------------
  246. */
  247. void HTChunkTerminate(HTChunk *ch)
  248. {
  249. HTChunkPutc(ch, (char) 0);
  250. }
  251. /* Append a string
  252. * ---------------
  253. */
  254. void HTChunkPuts(HTChunk *ch, const char *s)
  255. {
  256. const char *p;
  257. if (s != NULL) {
  258. for (p = s; *p; p++) {
  259. if (ch->size >= ch->allocated) {
  260. if (!HTChunkRealloc(ch, ch->growby))
  261. return;
  262. }
  263. ch->data[ch->size++] = *p;
  264. }
  265. }
  266. }
  267. /* like above but no realloc: extend to another chunk if necessary */
  268. HTChunk *HTChunkPuts2(HTChunk *ch, const char *s)
  269. {
  270. const char *p;
  271. if (s != NULL) {
  272. for (p = s; *p; p++) {
  273. if (ch->size >= ch->allocated) {
  274. HTChunk *chunk = HTChunkCreateMayFail(ch->growby, ch->failok);
  275. ch->next = chunk;
  276. HTChunkPuts(chunk, p);
  277. return chunk;
  278. }
  279. ch->data[ch->size++] = *p;
  280. }
  281. }
  282. return ch;
  283. }