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.

477 lines
13 KiB

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