aboutsummaryrefslogtreecommitdiff
path: root/src/print.c
blob: 22daeacd7f71e28a4aca0fc13736aa51a9c6fc60 (plain)
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include "cmark.h"
  5. #include "buffer.h"
  6. #include "node.h"
  7. #define INDENT 2
  8. static void print_str(strbuf* buffer, const unsigned char *s, int len)
  9. {
  10. int i;
  11. if (len < 0)
  12. len = strlen((char *)s);
  13. strbuf_putc(buffer, '"');
  14. for (i = 0; i < len; ++i) {
  15. unsigned char c = s[i];
  16. switch (c) {
  17. case '\n':
  18. strbuf_printf(buffer, "\\n");
  19. break;
  20. case '"':
  21. strbuf_printf(buffer, "\\\"");
  22. break;
  23. case '\\':
  24. strbuf_printf(buffer, "\\\\");
  25. break;
  26. default:
  27. strbuf_putc(buffer, (int)c);
  28. }
  29. }
  30. strbuf_putc(buffer, '"');
  31. }
  32. // Prettyprint an inline list, for debugging.
  33. static void render_nodes(strbuf* buffer, cmark_node* node, int indent)
  34. {
  35. int i;
  36. cmark_list *data;
  37. while(node != NULL) {
  38. for (i=0; i < indent; i++) {
  39. strbuf_putc(buffer, ' ');
  40. }
  41. switch(node->type) {
  42. case NODE_DOCUMENT:
  43. break;
  44. case NODE_BLOCK_QUOTE:
  45. strbuf_printf(buffer, "block_quote\n");
  46. break;
  47. case NODE_LIST_ITEM:
  48. strbuf_printf(buffer, "list_item\n");
  49. break;
  50. case NODE_LIST:
  51. data = &(node->as.list);
  52. if (data->list_type == CMARK_ORDERED_LIST) {
  53. strbuf_printf(buffer, "list (type=ordered tight=%s start=%d delim=%s)\n",
  54. (data->tight ? "true" : "false"),
  55. data->start,
  56. (data->delimiter == CMARK_PAREN_DELIM ? "parens" : "period"));
  57. } else {
  58. strbuf_printf(buffer, "list (type=bullet tight=%s bullet_char=%c)\n",
  59. (data->tight ? "true" : "false"),
  60. data->bullet_char);
  61. }
  62. break;
  63. case NODE_HEADER:
  64. strbuf_printf(buffer, "header (level=%d)\n", node->as.header.level);
  65. break;
  66. case NODE_PARAGRAPH:
  67. strbuf_printf(buffer, "paragraph\n");
  68. break;
  69. case NODE_HRULE:
  70. strbuf_printf(buffer, "hrule\n");
  71. break;
  72. case NODE_CODE_BLOCK:
  73. strbuf_printf(buffer, "code_block info=");
  74. print_str(buffer, node->as.code.info.data,
  75. node->as.code.info.len);
  76. strbuf_putc(buffer, ' ');
  77. print_str(buffer, node->as.literal.data,
  78. node->as.literal.len);
  79. strbuf_putc(buffer, '\n');
  80. break;
  81. case NODE_HTML:
  82. strbuf_printf(buffer, "html ");
  83. print_str(buffer, node->as.literal.data,
  84. node->as.literal.len);
  85. strbuf_putc(buffer, '\n');
  86. break;
  87. case NODE_TEXT:
  88. strbuf_printf(buffer, "text ");
  89. print_str(buffer, node->as.literal.data, node->as.literal.len);
  90. strbuf_putc(buffer, '\n');
  91. break;
  92. case NODE_LINEBREAK:
  93. strbuf_printf(buffer, "linebreak\n");
  94. break;
  95. case NODE_SOFTBREAK:
  96. strbuf_printf(buffer, "softbreak\n");
  97. break;
  98. case NODE_CODE:
  99. strbuf_printf(buffer, "code ");
  100. print_str(buffer, node->as.literal.data, node->as.literal.len);
  101. strbuf_putc(buffer, '\n');
  102. break;
  103. case NODE_INLINE_HTML:
  104. strbuf_printf(buffer, "inline_html ");
  105. print_str(buffer, node->as.literal.data, node->as.literal.len);
  106. strbuf_putc(buffer, '\n');
  107. break;
  108. case NODE_LINK:
  109. case NODE_IMAGE:
  110. strbuf_printf(buffer, "%s url=", node->type == NODE_LINK ? "link" : "image");
  111. if (node->as.link.url)
  112. print_str(buffer, node->as.link.url, -1);
  113. if (node->as.link.title) {
  114. strbuf_printf(buffer, " title=");
  115. print_str(buffer, node->as.link.title, -1);
  116. }
  117. strbuf_putc(buffer, '\n');
  118. break;
  119. case NODE_STRONG:
  120. strbuf_printf(buffer, "strong\n");
  121. break;
  122. case NODE_EMPH:
  123. strbuf_printf(buffer, "emph\n");
  124. break;
  125. default:
  126. break;
  127. }
  128. if (node->first_child) { // render children if any
  129. indent += INDENT;
  130. node = node->first_child;
  131. } else if (node->next) { // otherwise render next sibling
  132. node = node->next;
  133. } else {
  134. node = node->parent; // back up to parent
  135. while (node) {
  136. indent -= INDENT;
  137. if (node->next) {
  138. node = node->next;
  139. break;
  140. } else {
  141. node = node->parent;
  142. }
  143. if (!node) {
  144. break;
  145. }
  146. }
  147. }
  148. }
  149. }
  150. char *cmark_render_ast(cmark_node *root)
  151. {
  152. char* result;
  153. strbuf buffer = GH_BUF_INIT;
  154. render_nodes(&buffer, root, -2);
  155. result = (char *)strbuf_detach(&buffer);
  156. strbuf_free(&buffer);
  157. return result;
  158. }