You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

471 lines
13 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2011-2014, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the COPYING file in this distribution for license details.
  7. * ----------------------------------------------------------------------
  8. */
  9. #include <stdarg.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "libcork/core/allocator.h"
  13. #include "libcork/core/types.h"
  14. #include "libcork/ds/buffer.h"
  15. #include "libcork/ds/managed-buffer.h"
  16. #include "libcork/ds/stream.h"
  17. #include "libcork/helpers/errors.h"
  18. void
  19. cork_buffer_init(struct cork_buffer *buffer)
  20. {
  21. buffer->buf = NULL;
  22. buffer->size = 0;
  23. buffer->allocated_size = 0;
  24. }
  25. struct cork_buffer *
  26. cork_buffer_new(void)
  27. {
  28. struct cork_buffer *buffer = cork_new(struct cork_buffer);
  29. cork_buffer_init(buffer);
  30. return buffer;
  31. }
  32. void
  33. cork_buffer_done(struct cork_buffer *buffer)
  34. {
  35. if (buffer->buf != NULL) {
  36. cork_free(buffer->buf, buffer->allocated_size);
  37. buffer->buf = NULL;
  38. }
  39. buffer->size = 0;
  40. buffer->allocated_size = 0;
  41. }
  42. void
  43. cork_buffer_free(struct cork_buffer *buffer)
  44. {
  45. cork_buffer_done(buffer);
  46. cork_delete(struct cork_buffer, buffer);
  47. }
  48. bool
  49. cork_buffer_equal(const struct cork_buffer *buffer1,
  50. const struct cork_buffer *buffer2)
  51. {
  52. if (buffer1 == buffer2) {
  53. return true;
  54. }
  55. if (buffer1->size != buffer2->size) {
  56. return false;
  57. }
  58. return (memcmp(buffer1->buf, buffer2->buf, buffer1->size) == 0);
  59. }
  60. static void
  61. cork_buffer_ensure_size_int(struct cork_buffer *buffer, size_t desired_size)
  62. {
  63. size_t new_size;
  64. if (CORK_LIKELY(buffer->allocated_size >= desired_size)) {
  65. return;
  66. }
  67. /* Make sure we at least double the old size when reallocating. */
  68. new_size = buffer->allocated_size * 2;
  69. if (desired_size > new_size) {
  70. new_size = desired_size;
  71. }
  72. buffer->buf = cork_realloc(buffer->buf, buffer->allocated_size, new_size);
  73. buffer->allocated_size = new_size;
  74. }
  75. void
  76. cork_buffer_ensure_size(struct cork_buffer *buffer, size_t desired_size)
  77. {
  78. cork_buffer_ensure_size_int(buffer, desired_size);
  79. }
  80. void
  81. cork_buffer_clear(struct cork_buffer *buffer)
  82. {
  83. buffer->size = 0;
  84. if (buffer->buf != NULL) {
  85. ((char *) buffer->buf)[0] = '\0';
  86. }
  87. }
  88. void
  89. cork_buffer_truncate(struct cork_buffer *buffer, size_t length)
  90. {
  91. if (buffer->size > length) {
  92. buffer->size = length;
  93. if (length == 0) {
  94. if (buffer->buf != NULL) {
  95. ((char *) buffer->buf)[0] = '\0';
  96. }
  97. } else {
  98. ((char *) buffer->buf)[length] = '\0';
  99. }
  100. }
  101. }
  102. void
  103. cork_buffer_set(struct cork_buffer *buffer, const void *src, size_t length)
  104. {
  105. cork_buffer_ensure_size_int(buffer, length+1);
  106. memcpy(buffer->buf, src, length);
  107. ((char *) buffer->buf)[length] = '\0';
  108. buffer->size = length;
  109. }
  110. void
  111. cork_buffer_append(struct cork_buffer *buffer, const void *src, size_t length)
  112. {
  113. cork_buffer_ensure_size_int(buffer, buffer->size + length + 1);
  114. memcpy(buffer->buf + buffer->size, src, length);
  115. buffer->size += length;
  116. ((char *) buffer->buf)[buffer->size] = '\0';
  117. }
  118. void
  119. cork_buffer_set_string(struct cork_buffer *buffer, const char *str)
  120. {
  121. cork_buffer_set(buffer, str, strlen(str));
  122. }
  123. void
  124. cork_buffer_append_string(struct cork_buffer *buffer, const char *str)
  125. {
  126. cork_buffer_append(buffer, str, strlen(str));
  127. }
  128. void
  129. cork_buffer_append_vprintf(struct cork_buffer *buffer, const char *format,
  130. va_list args)
  131. {
  132. size_t format_size;
  133. va_list args1;
  134. va_copy(args1, args);
  135. format_size = vsnprintf(buffer->buf + buffer->size,
  136. buffer->allocated_size - buffer->size,
  137. format, args1);
  138. va_end(args1);
  139. /* If the first call works, then set buffer->size and return. */
  140. if (format_size < (buffer->allocated_size - buffer->size)) {
  141. buffer->size += format_size;
  142. return;
  143. }
  144. /* If the first call fails, resize buffer and try again. */
  145. cork_buffer_ensure_size_int
  146. (buffer, buffer->allocated_size + format_size + 1);
  147. format_size = vsnprintf(buffer->buf + buffer->size,
  148. buffer->allocated_size - buffer->size,
  149. format, args);
  150. buffer->size += format_size;
  151. }
  152. void
  153. cork_buffer_vprintf(struct cork_buffer *buffer, const char *format,
  154. va_list args)
  155. {
  156. cork_buffer_clear(buffer);
  157. cork_buffer_append_vprintf(buffer, format, args);
  158. }
  159. void
  160. cork_buffer_append_printf(struct cork_buffer *buffer, const char *format, ...)
  161. {
  162. va_list args;
  163. va_start(args, format);
  164. cork_buffer_append_vprintf(buffer, format, args);
  165. va_end(args);
  166. }
  167. void
  168. cork_buffer_printf(struct cork_buffer *buffer, const char *format, ...)
  169. {
  170. va_list args;
  171. va_start(args, format);
  172. cork_buffer_vprintf(buffer, format, args);
  173. va_end(args);
  174. }
  175. void
  176. cork_buffer_append_indent(struct cork_buffer *buffer, size_t indent)
  177. {
  178. cork_buffer_ensure_size_int(buffer, buffer->size + indent + 1);
  179. memset(buffer->buf + buffer->size, ' ', indent);
  180. buffer->size += indent;
  181. ((char *) buffer->buf)[buffer->size] = '\0';
  182. }
  183. /* including space */
  184. #define is_sprint(ch) ((ch) >= 0x20 && (ch) <= 0x7e)
  185. /* not including space */
  186. #define is_print(ch) ((ch) > 0x20 && (ch) <= 0x7e)
  187. #define is_space(ch) \
  188. ((ch) == ' ' || \
  189. (ch) == '\f' || \
  190. (ch) == '\n' || \
  191. (ch) == '\r' || \
  192. (ch) == '\t' || \
  193. (ch) == '\v')
  194. #define to_hex(nybble) \
  195. ((nybble) < 10? '0' + (nybble): 'a' - 10 + (nybble))
  196. void
  197. cork_buffer_append_c_string(struct cork_buffer *dest,
  198. const char *chars, size_t length)
  199. {
  200. size_t i;
  201. cork_buffer_append(dest, "\"", 1);
  202. for (i = 0; i < length; i++) {
  203. char ch = chars[i];
  204. switch (ch) {
  205. case '\"':
  206. cork_buffer_append_literal(dest, "\\\"");
  207. break;
  208. case '\\':
  209. cork_buffer_append_literal(dest, "\\\\");
  210. break;
  211. case '\f':
  212. cork_buffer_append_literal(dest, "\\f");
  213. break;
  214. case '\n':
  215. cork_buffer_append_literal(dest, "\\n");
  216. break;
  217. case '\r':
  218. cork_buffer_append_literal(dest, "\\r");
  219. break;
  220. case '\t':
  221. cork_buffer_append_literal(dest, "\\t");
  222. break;
  223. case '\v':
  224. cork_buffer_append_literal(dest, "\\v");
  225. break;
  226. default:
  227. if (is_sprint(ch)) {
  228. cork_buffer_append(dest, &chars[i], 1);
  229. } else {
  230. uint8_t byte = ch;
  231. cork_buffer_append_printf(dest, "\\x%02" PRIx8, byte);
  232. }
  233. break;
  234. }
  235. }
  236. cork_buffer_append(dest, "\"", 1);
  237. }
  238. void
  239. cork_buffer_append_hex_dump(struct cork_buffer *dest, size_t indent,
  240. const char *chars, size_t length)
  241. {
  242. char hex[3 * 16];
  243. char print[16];
  244. char *curr_hex = hex;
  245. char *curr_print = print;
  246. size_t i;
  247. size_t column = 0;
  248. for (i = 0; i < length; i++) {
  249. char ch = chars[i];
  250. uint8_t u8 = ch;
  251. *curr_hex++ = to_hex(u8 >> 4);
  252. *curr_hex++ = to_hex(u8 & 0x0f);
  253. *curr_hex++ = ' ';
  254. *curr_print++ = is_sprint(ch)? ch: '.';
  255. if (column == 0 && i != 0) {
  256. cork_buffer_append_literal(dest, "\n");
  257. cork_buffer_append_indent(dest, indent);
  258. column++;
  259. } else if (column == 15) {
  260. cork_buffer_append_printf
  261. (dest, "%-48.*s", (int) (curr_hex - hex), hex);
  262. cork_buffer_append_literal(dest, " |");
  263. cork_buffer_append(dest, print, curr_print - print);
  264. cork_buffer_append_literal(dest, "|");
  265. curr_hex = hex;
  266. curr_print = print;
  267. column = 0;
  268. } else {
  269. column++;
  270. }
  271. }
  272. if (column > 0) {
  273. cork_buffer_append_printf(dest, "%-48.*s", (int) (curr_hex - hex), hex);
  274. cork_buffer_append_literal(dest, " |");
  275. cork_buffer_append(dest, print, curr_print - print);
  276. cork_buffer_append_literal(dest, "|");
  277. }
  278. }
  279. void
  280. cork_buffer_append_multiline(struct cork_buffer *dest, size_t indent,
  281. const char *chars, size_t length)
  282. {
  283. size_t i;
  284. for (i = 0; i < length; i++) {
  285. char ch = chars[i];
  286. if (ch == '\n') {
  287. cork_buffer_append_literal(dest, "\n");
  288. cork_buffer_append_indent(dest, indent);
  289. } else {
  290. cork_buffer_append(dest, &chars[i], 1);
  291. }
  292. }
  293. }
  294. void
  295. cork_buffer_append_binary(struct cork_buffer *dest, size_t indent,
  296. const char *chars, size_t length)
  297. {
  298. size_t i;
  299. bool newline = false;
  300. /* If there are any non-printable characters, print out a hex dump */
  301. for (i = 0; i < length; i++) {
  302. if (!is_print(chars[i]) && !is_space(chars[i])) {
  303. cork_buffer_append_literal(dest, "(hex)\n");
  304. cork_buffer_append_indent(dest, indent);
  305. cork_buffer_append_hex_dump(dest, indent, chars, length);
  306. return;
  307. } else if (chars[i] == '\n') {
  308. newline = true;
  309. /* Don't immediately use the multiline format, since there might be
  310. * a non-printable character later on that kicks us over to the hex
  311. * dump format. */
  312. }
  313. }
  314. if (newline) {
  315. cork_buffer_append_literal(dest, "(multiline)\n");
  316. cork_buffer_append_indent(dest, indent);
  317. cork_buffer_append_multiline(dest, indent, chars, length);
  318. } else {
  319. cork_buffer_append(dest, chars, length);
  320. }
  321. }
  322. struct cork_buffer__managed_buffer {
  323. struct cork_managed_buffer parent;
  324. struct cork_buffer *buffer;
  325. };
  326. static void
  327. cork_buffer__managed_free(struct cork_managed_buffer *vself)
  328. {
  329. struct cork_buffer__managed_buffer *self =
  330. cork_container_of(vself, struct cork_buffer__managed_buffer, parent);
  331. cork_buffer_free(self->buffer);
  332. cork_delete(struct cork_buffer__managed_buffer, self);
  333. }
  334. static struct cork_managed_buffer_iface CORK_BUFFER__MANAGED_BUFFER = {
  335. cork_buffer__managed_free
  336. };
  337. struct cork_managed_buffer *
  338. cork_buffer_to_managed_buffer(struct cork_buffer *buffer)
  339. {
  340. struct cork_buffer__managed_buffer *self =
  341. cork_new(struct cork_buffer__managed_buffer);
  342. self->parent.buf = buffer->buf;
  343. self->parent.size = buffer->size;
  344. self->parent.ref_count = 1;
  345. self->parent.iface = &CORK_BUFFER__MANAGED_BUFFER;
  346. self->buffer = buffer;
  347. return &self->parent;
  348. }
  349. int
  350. cork_buffer_to_slice(struct cork_buffer *buffer, struct cork_slice *slice)
  351. {
  352. struct cork_managed_buffer *managed =
  353. cork_buffer_to_managed_buffer(buffer);
  354. /* We don't have to check for NULL; cork_managed_buffer_slice_offset
  355. * will do that for us. */
  356. int rc = cork_managed_buffer_slice_offset(slice, managed, 0);
  357. /* Before returning, drop our reference to the managed buffer. If
  358. * the slicing succeeded, then there will be one remaining reference
  359. * in the slice. If it didn't succeed, this will free the managed
  360. * buffer for us. */
  361. cork_managed_buffer_unref(managed);
  362. return rc;
  363. }
  364. struct cork_buffer__stream_consumer {
  365. struct cork_stream_consumer consumer;
  366. struct cork_buffer *buffer;
  367. };
  368. static int
  369. cork_buffer_stream_consumer_data(struct cork_stream_consumer *consumer,
  370. const void *buf, size_t size,
  371. bool is_first_chunk)
  372. {
  373. struct cork_buffer__stream_consumer *bconsumer = cork_container_of
  374. (consumer, struct cork_buffer__stream_consumer, consumer);
  375. cork_buffer_append(bconsumer->buffer, buf, size);
  376. return 0;
  377. }
  378. static int
  379. cork_buffer_stream_consumer_eof(struct cork_stream_consumer *consumer)
  380. {
  381. return 0;
  382. }
  383. static void
  384. cork_buffer_stream_consumer_free(struct cork_stream_consumer *consumer)
  385. {
  386. struct cork_buffer__stream_consumer *bconsumer =
  387. cork_container_of
  388. (consumer, struct cork_buffer__stream_consumer, consumer);
  389. cork_delete(struct cork_buffer__stream_consumer, bconsumer);
  390. }
  391. struct cork_stream_consumer *
  392. cork_buffer_to_stream_consumer(struct cork_buffer *buffer)
  393. {
  394. struct cork_buffer__stream_consumer *bconsumer =
  395. cork_new(struct cork_buffer__stream_consumer);
  396. bconsumer->consumer.data = cork_buffer_stream_consumer_data;
  397. bconsumer->consumer.eof = cork_buffer_stream_consumer_eof;
  398. bconsumer->consumer.free = cork_buffer_stream_consumer_free;
  399. bconsumer->buffer = buffer;
  400. return &bconsumer->consumer;
  401. }