diff options
author | John MacFarlane <jgm@berkeley.edu> | 2014-11-13 22:42:18 -0800 |
---|---|---|
committer | John MacFarlane <jgm@berkeley.edu> | 2014-11-13 22:42:18 -0800 |
commit | 549c5dbd45c20fa30f42cd70b734e6447af3f1ba (patch) | |
tree | 92c87f26e66612af6c0ff225c6cc8f219dde695e /src/cmark.c | |
parent | 9ba42f1a8b93237ea4bfc05f29972c3c3922ebaa (diff) |
Removed ast modules, moved these defs back to cmark.h.
Diffstat (limited to 'src/cmark.c')
-rw-r--r-- | src/cmark.c | 163 |
1 files changed, 162 insertions, 1 deletions
diff --git a/src/cmark.c b/src/cmark.c index 8f5c4e8..eacf411 100644 --- a/src/cmark.c +++ b/src/cmark.c @@ -1,7 +1,9 @@ #include <stdlib.h> #include <assert.h> #include <stdio.h> - +#include <stdbool.h> +#include "references.h" +#include "html/houdini.h" #include "cmark.h" #include "buffer.h" @@ -21,3 +23,162 @@ extern unsigned char *cmark_markdown_to_html(unsigned char *text, int len) return result; } + +// Free a node_block list and any children. +void cmark_free_blocks(cmark_node_block *e) +{ + cmark_node_block * next; + while (e != NULL) { + cmark_free_inlines(e->inline_content); + strbuf_free(&e->string_content); + if (e->tag == CMARK_BLOCK_FENCED_CODE) { + strbuf_free(&e->as.code.info); + } else if (e->tag == CMARK_BLOCK_DOCUMENT) { + reference_map_free(e->as.document.refmap); + } + if (e->last_child) { + // Splice children into list + e->last_child->next = e->next; + e->next = e->children; + } + next = e->next; + free(e); + e = next; + } +} + +// Utility function used by free_inlines +static void splice_into_list(cmark_node_inl* e, node_inl* children) { + cmark_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. +void cmark_free_inlines(cmark_node_inl* e) +{ + node_inl * next; + + while (e != NULL) { + switch (e->tag){ + case CMARK_INL_STRING: + case CMARK_INL_RAW_HTML: + case CMARK_INL_CODE: + cmark_chunk_free(&e->content.literal); + break; + case CMARK_INL_LINEBREAK: + case CMARK_INL_SOFTBREAK: + break; + case CMARK_INL_LINK: + case CMARK_INL_IMAGE: + free(e->content.linkable.url); + free(e->content.linkable.title); + splice_into_list(e, e->content.linkable.label); + break; + case CMARK_INL_EMPH: + case CMARK_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; + } +} + +inline cmark_node_inl *cmark_make_link(cmark_node_inl *label, unsigned char *url, unsigned char *title) +{ + cmark_node_inl* e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = CMARK_INL_LINK; + e->content.linkable.label = label; + e->content.linkable.url = url; + e->content.linkable.title = title; + e->next = NULL; + } + return e; +} + +unsigned char *clean_autolink(chunk *url, int is_email) +{ + strbuf buf = GH_BUF_INIT; + + chunk_trim(url); + + if (url->len == 0) + return NULL; + + if (is_email) + strbuf_puts(&buf, "mailto:"); + + houdini_unescape_html_f(&buf, url->data, url->len); + return strbuf_detach(&buf); +} + +cmark_node_inl* cmark_make_autolink(cmark_node_inl* label, chunk url, int is_email) +{ + return cmark_make_link(label, clean_autolink(&url, is_email), NULL); +} + +inline cmark_node_inl* cmark_make_inlines(int t, cmark_node_inl* contents) +{ + cmark_node_inl * e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->content.inlines = contents; + e->next = NULL; + } + return e; +} + +// Create an inline with a literal string value. +inline cmark_node_inl* cmark_make_literal(int t, cmark_chunk s) +{ + cmark_node_inl * e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->content.literal = s; + e->next = NULL; + } + return e; +} + +// Create an inline with no value. +inline cmark_node_inl* cmark_make_simple(int t) +{ + cmark_node_inl* e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->next = NULL; + } + return e; +} + +// Append inline list b to the end of inline list a. +// Return pointer to head of new list. +inline cmark_node_inl* cmark_append_inlines(cmark_node_inl* a, cmark_node_inl* b) +{ + if (a == NULL) { // NULL acts like an empty list + return b; + } + cmark_node_inl* cur = a; + while (cur->next) { + cur = cur->next; + } + cur->next = b; + return a; +} |