aboutsummaryrefslogtreecommitdiff
path: root/src/print.c
blob: 9384a0b01448bb0bebbda85dd57b3172e7748ee6 (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.ptr, -1);
  75. strbuf_putc(buffer, ' ');
  76. print_str(buffer, node->string_content.ptr, -1);
  77. strbuf_putc(buffer, '\n');
  78. break;
  79. case NODE_HTML:
  80. strbuf_printf(buffer, "html ");
  81. print_str(buffer, node->string_content.ptr, -1);
  82. strbuf_putc(buffer, '\n');
  83. break;
  84. case NODE_TEXT:
  85. strbuf_printf(buffer, "text ");
  86. print_str(buffer, node->as.literal.data, node->as.literal.len);
  87. strbuf_putc(buffer, '\n');
  88. break;
  89. case NODE_LINEBREAK:
  90. strbuf_printf(buffer, "linebreak\n");
  91. break;
  92. case NODE_SOFTBREAK:
  93. strbuf_printf(buffer, "softbreak\n");
  94. break;
  95. case NODE_INLINE_CODE:
  96. strbuf_printf(buffer, "code ");
  97. print_str(buffer, node->as.literal.data, node->as.literal.len);
  98. strbuf_putc(buffer, '\n');
  99. break;
  100. case NODE_INLINE_HTML:
  101. strbuf_printf(buffer, "inline_html ");
  102. print_str(buffer, node->as.literal.data, node->as.literal.len);
  103. strbuf_putc(buffer, '\n');
  104. break;
  105. case NODE_LINK:
  106. case NODE_IMAGE:
  107. strbuf_printf(buffer, "%s url=", node->type == NODE_LINK ? "link" : "image");
  108. if (node->as.link.url)
  109. print_str(buffer, node->as.link.url, -1);
  110. if (node->as.link.title) {
  111. strbuf_printf(buffer, " title=");
  112. print_str(buffer, node->as.link.title, -1);
  113. }
  114. strbuf_putc(buffer, '\n');
  115. break;
  116. case NODE_STRONG:
  117. strbuf_printf(buffer, "strong\n");
  118. break;
  119. case NODE_EMPH:
  120. strbuf_printf(buffer, "emph\n");
  121. break;
  122. default:
  123. break;
  124. }
  125. if (node->first_child) { // render children if any
  126. indent += INDENT;
  127. node = node->first_child;
  128. } else if (node->next) { // otherwise render next sibling
  129. node = node->next;
  130. } else {
  131. node = node->parent; // back up to parent
  132. while (node) {
  133. indent -= INDENT;
  134. if (node->next) {
  135. node = node->next;
  136. break;
  137. } else {
  138. node = node->parent;
  139. }
  140. if (!node) {
  141. break;
  142. }
  143. }
  144. }
  145. }
  146. }
  147. char *cmark_render_ast(cmark_node *root)
  148. {
  149. char* result;
  150. strbuf buffer = GH_BUF_INIT;
  151. render_nodes(&buffer, root, -2);
  152. result = (char *)strbuf_detach(&buffer);
  153. strbuf_free(&buffer);
  154. return result;
  155. }