aboutsummaryrefslogtreecommitdiff
path: root/src/cmark.c
blob: e7f6899e2a6a800ba81bfe7d9e35d2f0ce891db3 (plain)
  1. #include <stdlib.h>
  2. #include <assert.h>
  3. #include <stdio.h>
  4. #include "references.h"
  5. #include "html/houdini.h"
  6. #include "cmark.h"
  7. #include "buffer.h"
  8. #include "ast.h"
  9. unsigned char *cmark_markdown_to_html(unsigned char *text, int len)
  10. {
  11. node_block *blocks;
  12. unsigned char *result;
  13. blocks = cmark_parse_document(text, len);
  14. result = cmark_render_html(blocks);
  15. cmark_free_blocks(blocks);
  16. return result;
  17. }
  18. // Utility function used by free_inlines
  19. static void splice_into_list(cmark_node_inl* e, node_inl* children) {
  20. cmark_node_inl * tmp;
  21. if (children) {
  22. tmp = children;
  23. // Find last child
  24. while (tmp->next) {
  25. tmp = tmp->next;
  26. }
  27. // Splice children into list
  28. tmp->next = e->next;
  29. e->next = children;
  30. }
  31. return ;
  32. }
  33. // Free an inline list. Avoid recursion to prevent stack overflows
  34. // on deeply nested structures.
  35. void cmark_free_inlines(cmark_node_inl* e)
  36. {
  37. node_inl * next;
  38. while (e != NULL) {
  39. switch (e->tag){
  40. case CMARK_INL_STRING:
  41. case CMARK_INL_RAW_HTML:
  42. case CMARK_INL_CODE:
  43. cmark_chunk_free(&e->content.literal);
  44. break;
  45. case CMARK_INL_LINEBREAK:
  46. case CMARK_INL_SOFTBREAK:
  47. break;
  48. case CMARK_INL_LINK:
  49. case CMARK_INL_IMAGE:
  50. free(e->content.linkable.url);
  51. free(e->content.linkable.title);
  52. splice_into_list(e, e->content.linkable.label);
  53. break;
  54. case CMARK_INL_EMPH:
  55. case CMARK_INL_STRONG:
  56. splice_into_list(e, e->content.inlines);
  57. break;
  58. default:
  59. fprintf(stderr, "[WARN] (%s:%d) Unknown inline tag %d",
  60. __FILE__, __LINE__, e->tag);
  61. break;
  62. }
  63. next = e->next;
  64. free(e);
  65. e = next;
  66. }
  67. }
  68. unsigned char *cmark_clean_autolink(chunk *url, int is_email)
  69. {
  70. strbuf buf = GH_BUF_INIT;
  71. chunk_trim(url);
  72. if (url->len == 0)
  73. return NULL;
  74. if (is_email)
  75. strbuf_puts(&buf, "mailto:");
  76. houdini_unescape_html_f(&buf, url->data, url->len);
  77. return strbuf_detach(&buf);
  78. }
  79. // Free a node_block list and any children.
  80. void cmark_free_blocks(cmark_node_block *e)
  81. {
  82. cmark_node_block * next;
  83. while (e != NULL) {
  84. cmark_free_inlines(e->inline_content);
  85. strbuf_free(&e->string_content);
  86. if (e->tag == CMARK_BLOCK_FENCED_CODE) {
  87. strbuf_free(&e->as.code.info);
  88. } else if (e->tag == CMARK_BLOCK_DOCUMENT) {
  89. reference_map_free(e->as.document.refmap);
  90. }
  91. if (e->last_child) {
  92. // Splice children into list
  93. e->last_child->next = e->next;
  94. e->next = e->children;
  95. }
  96. next = e->next;
  97. free(e);
  98. e = next;
  99. }
  100. }