aboutsummaryrefslogtreecommitdiff
path: root/src/cmark.c
blob: 7cc8e5c3b01a15b1bc805d8acab615f734b385f9 (plain)
  1. #include <stdlib.h>
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include "node.h"
  5. #include "references.h"
  6. #include "html/houdini.h"
  7. #include "cmark.h"
  8. #include "buffer.h"
  9. #include "ast.h"
  10. // AST traversal and manipulation functions
  11. cmark_node_block *cmark_block_next(cmark_node_block *current)
  12. {
  13. return current->next;
  14. }
  15. cmark_node_block *cmark_block_previous(cmark_node_block *current)
  16. {
  17. return current->prev;
  18. }
  19. cmark_node_block *cmark_block_parent(cmark_node_block *current)
  20. {
  21. return current->parent;
  22. }
  23. cmark_node_block *cmark_block_children(cmark_node_block *current)
  24. {
  25. return current->children;
  26. }
  27. void cmark_block_insert_before(cmark_node_block *new, cmark_node_block *current)
  28. {
  29. // Find last node in new:
  30. cmark_node_block *new_last = new;
  31. while (new_last->next) {
  32. new_last = new_last->next;
  33. }
  34. new_last->next = current;
  35. current->prev = new_last;
  36. if (current->prev) {
  37. current->prev->next = new;
  38. new->prev = current->prev;
  39. }
  40. }
  41. void cmark_block_insert_after(cmark_node_block *current, cmark_node_block *new)
  42. {
  43. // Find last node in new:
  44. cmark_node_block *new_last = new;
  45. while (new_last->next) {
  46. new_last = new_last->next;
  47. }
  48. if (current->next) {
  49. new_last->next = current->next;
  50. current->next->prev = new_last;
  51. }
  52. current->next = new;
  53. new->prev = current;
  54. }
  55. /* * */
  56. unsigned char *cmark_markdown_to_html(unsigned char *text, int len)
  57. {
  58. cmark_node *blocks;
  59. unsigned char *result;
  60. blocks = cmark_parse_document(text, len);
  61. result = cmark_render_html(blocks);
  62. cmark_free_nodes(blocks);
  63. return result;
  64. }
  65. // Utility function used by cmark_free_nodes
  66. static void splice_into_list(cmark_node* e, cmark_node* children) {
  67. cmark_node * tmp;
  68. if (children) {
  69. tmp = children;
  70. // Find last child
  71. while (tmp->next) {
  72. tmp = tmp->next;
  73. }
  74. // Splice children into list
  75. tmp->next = e->next;
  76. e->next = children;
  77. }
  78. return ;
  79. }
  80. unsigned char *cmark_clean_autolink(chunk *url, int is_email)
  81. {
  82. strbuf buf = GH_BUF_INIT;
  83. chunk_trim(url);
  84. if (url->len == 0)
  85. return NULL;
  86. if (is_email)
  87. strbuf_puts(&buf, "mailto:");
  88. houdini_unescape_html_f(&buf, url->data, url->len);
  89. return strbuf_detach(&buf);
  90. }
  91. // Free a cmark_node list and any children.
  92. void cmark_free_nodes(cmark_node *e)
  93. {
  94. cmark_node *next;
  95. while (e != NULL) {
  96. strbuf_free(&e->string_content);
  97. switch (e->type){
  98. case NODE_FENCED_CODE:
  99. strbuf_free(&e->as.code.info);
  100. break;
  101. case NODE_STRING:
  102. case NODE_INLINE_HTML:
  103. case NODE_INLINE_CODE:
  104. cmark_chunk_free(&e->as.literal);
  105. break;
  106. case NODE_LINK:
  107. case NODE_IMAGE:
  108. free(e->as.link.url);
  109. free(e->as.link.title);
  110. splice_into_list(e, e->as.link.label);
  111. break;
  112. default:
  113. break;
  114. }
  115. if (e->last_child) {
  116. // Splice children into list
  117. e->last_child->next = e->next;
  118. e->next = e->first_child;
  119. }
  120. next = e->next;
  121. free(e);
  122. e = next;
  123. }
  124. }