summaryrefslogtreecommitdiff
path: root/src/ast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast.c')
-rw-r--r--src/ast.c53
1 files changed, 52 insertions, 1 deletions
diff --git a/src/ast.c b/src/ast.c
index 8ccf184..2a9ca8f 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -2,7 +2,6 @@
#include <stdio.h>
#include "buffer.h"
#include "ast.h"
-#include "inlines.h"
#include "references.h"
// Free a node_block list and any children.
@@ -28,3 +27,55 @@ void cmark_free_blocks(node_block *e)
}
}
+// Utility function used by free_inlines
+static void splice_into_list(node_inl* e, node_inl* children) {
+ node_inl * tmp;
+ if (children) {
+ tmp = children;
+ // Find last child
+ while (tmp->next) {
+ tmp = tmp->next;
+ }
+ // Splice children into list
+ tmp->next = e->next;
+ e->next = children;
+ }
+ return ;
+}
+
+// Free an inline list. Avoid recursion to prevent stack overflows
+// on deeply nested structures.
+extern void free_inlines(node_inl* e)
+{
+ node_inl * next;
+
+ while (e != NULL) {
+ switch (e->tag){
+ case INL_STRING:
+ case INL_RAW_HTML:
+ case INL_CODE:
+ chunk_free(&e->content.literal);
+ break;
+ case INL_LINEBREAK:
+ case INL_SOFTBREAK:
+ break;
+ case INL_LINK:
+ case INL_IMAGE:
+ free(e->content.linkable.url);
+ free(e->content.linkable.title);
+ splice_into_list(e, e->content.linkable.label);
+ break;
+ case INL_EMPH:
+ case INL_STRONG:
+ splice_into_list(e, e->content.inlines);
+ break;
+ default:
+ fprintf(stderr, "[WARN] (%s:%d) Unknown inline tag %d",
+ __FILE__, __LINE__, e->tag);
+ break;
+ }
+ next = e->next;
+ free(e);
+ e = next;
+ }
+}