Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #include "html.h" | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <ctype.h> | |
| #include "escape.h" | |
| #define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML) | |
| hoedown_html_tag | |
| hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname) | |
| { | |
| size_t i; | |
| int closed = 0; | |
| if (size < 3 || data[0] != '<') | |
| return HOEDOWN_HTML_TAG_NONE; | |
| i = 1; | |
| if (data[i] == '/') { | |
| closed = 1; | |
| i++; | |
| } | |
| for (; i < size; ++i, ++tagname) { | |
| if (*tagname == 0) | |
| break; | |
| if (data[i] != *tagname) | |
| return HOEDOWN_HTML_TAG_NONE; | |
| } | |
| if (i == size) | |
| return HOEDOWN_HTML_TAG_NONE; | |
| if (isspace(data[i]) || data[i] == '>') | |
| return closed ? HOEDOWN_HTML_TAG_CLOSE : HOEDOWN_HTML_TAG_OPEN; | |
| return HOEDOWN_HTML_TAG_NONE; | |
| } | |
| static void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length) | |
| { | |
| hoedown_escape_html(ob, source, length, 0); | |
| } | |
| static void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length) | |
| { | |
| hoedown_escape_href(ob, source, length); | |
| } | |
| /******************** | |
| * GENERIC RENDERER * | |
| ********************/ | |
| static int | |
| rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (!link || !link->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<a href=\""); | |
| if (type == HOEDOWN_AUTOLINK_EMAIL) | |
| HOEDOWN_BUFPUTSL(ob, "mailto:"); | |
| escape_href(ob, link->data, link->size); | |
| if (state->link_attributes) { | |
| hoedown_buffer_putc(ob, '\"'); | |
| state->link_attributes(ob, link, data); | |
| hoedown_buffer_putc(ob, '>'); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob, "\">"); | |
| } | |
| /* | |
| * Pretty printing: if we get an email address as | |
| * an actual URI, e.g. `mailto:foo@bar.com`, we don't | |
| * want to print the `mailto:` prefix | |
| */ | |
| if (hoedown_buffer_prefix(link, "mailto:") == 0) { | |
| escape_html(ob, link->data + 7, link->size - 7); | |
| } else { | |
| escape_html(ob, link->data, link->size); | |
| } | |
| HOEDOWN_BUFPUTSL(ob, "</a>"); | |
| return 1; | |
| } | |
| static void | |
| rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| if (lang) { | |
| HOEDOWN_BUFPUTSL(ob, "<pre><code class=\"language-"); | |
| escape_html(ob, lang->data, lang->size); | |
| HOEDOWN_BUFPUTSL(ob, "\">"); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob, "<pre><code>"); | |
| } | |
| if (text) | |
| escape_html(ob, text->data, text->size); | |
| HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); | |
| } | |
| static void | |
| rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| HOEDOWN_BUFPUTSL(ob, "<blockquote>\n"); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</blockquote>\n"); | |
| } | |
| static int | |
| rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) | |
| { | |
| HOEDOWN_BUFPUTSL(ob, "<code>"); | |
| if (text) escape_html(ob, text->data, text->size); | |
| HOEDOWN_BUFPUTSL(ob, "</code>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<del>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</del>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<strong>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</strong>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<em>"); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</em>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_underline(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<u>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</u>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<mark>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</mark>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_quote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) | |
| return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<q>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</q>"); | |
| return 1; | |
| } | |
| static int | |
| rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| hoedown_buffer_puts(ob, USE_XHTML(state) ? "<br/>\n" : "<br>\n"); | |
| return 1; | |
| } | |
| static void | |
| rndr_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (ob->size) | |
| hoedown_buffer_putc(ob, '\n'); | |
| if (level <= state->toc_data.nesting_level) | |
| hoedown_buffer_printf(ob, "<h%d id=\"toc_%d\">", level, state->toc_data.header_count++); | |
| else | |
| hoedown_buffer_printf(ob, "<h%d>", level); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| hoedown_buffer_printf(ob, "</h%d>\n", level); | |
| } | |
| static int | |
| rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| HOEDOWN_BUFPUTSL(ob, "<a href=\""); | |
| if (link && link->size) | |
| escape_href(ob, link->data, link->size); | |
| if (title && title->size) { | |
| HOEDOWN_BUFPUTSL(ob, "\" title=\""); | |
| escape_html(ob, title->data, title->size); | |
| } | |
| if (state->link_attributes) { | |
| hoedown_buffer_putc(ob, '\"'); | |
| state->link_attributes(ob, link, data); | |
| hoedown_buffer_putc(ob, '>'); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob, "\">"); | |
| } | |
| if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</a>"); | |
| return 1; | |
| } | |
| static void | |
| rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n"), 5); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n"), 6); | |
| } | |
| static void | |
| rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data) | |
| { | |
| HOEDOWN_BUFPUTSL(ob, "<li>"); | |
| if (content) { | |
| size_t size = content->size; | |
| while (size && content->data[size - 1] == '\n') | |
| size--; | |
| hoedown_buffer_put(ob, content->data, size); | |
| } | |
| HOEDOWN_BUFPUTSL(ob, "</li>\n"); | |
| } | |
| static void | |
| rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| size_t i = 0; | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| if (!content || !content->size) | |
| return; | |
| while (i < content->size && isspace(content->data[i])) i++; | |
| if (i == content->size) | |
| return; | |
| HOEDOWN_BUFPUTSL(ob, "<p>"); | |
| if (state->flags & HOEDOWN_HTML_HARD_WRAP) { | |
| size_t org; | |
| while (i < content->size) { | |
| org = i; | |
| while (i < content->size && content->data[i] != '\n') | |
| i++; | |
| if (i > org) | |
| hoedown_buffer_put(ob, content->data + org, i - org); | |
| /* | |
| * do not insert a line break if this newline | |
| * is the last character on the paragraph | |
| */ | |
| if (i >= content->size - 1) | |
| break; | |
| rndr_linebreak(ob, data); | |
| i++; | |
| } | |
| } else { | |
| hoedown_buffer_put(ob, content->data + i, content->size - i); | |
| } | |
| HOEDOWN_BUFPUTSL(ob, "</p>\n"); | |
| } | |
| static void | |
| rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) | |
| { | |
| size_t org, sz; | |
| if (!text) | |
| return; | |
| /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */ | |
| sz = text->size; | |
| while (sz > 0 && text->data[sz - 1] == '\n') | |
| sz--; | |
| org = 0; | |
| while (org < sz && text->data[org] == '\n') | |
| org++; | |
| if (org >= sz) | |
| return; | |
| if (ob->size) | |
| hoedown_buffer_putc(ob, '\n'); | |
| hoedown_buffer_put(ob, text->data + org, sz - org); | |
| hoedown_buffer_putc(ob, '\n'); | |
| } | |
| static int | |
| rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<strong><em>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</em></strong>"); | |
| return 1; | |
| } | |
| static void | |
| rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); | |
| } | |
| static int | |
| rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (!link || !link->size) return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<img src=\""); | |
| escape_href(ob, link->data, link->size); | |
| HOEDOWN_BUFPUTSL(ob, "\" alt=\""); | |
| if (alt && alt->size) | |
| escape_html(ob, alt->data, alt->size); | |
| if (title && title->size) { | |
| HOEDOWN_BUFPUTSL(ob, "\" title=\""); | |
| escape_html(ob, title->data, title->size); } | |
| hoedown_buffer_puts(ob, USE_XHTML(state) ? "\"/>" : "\">"); | |
| return 1; | |
| } | |
| static int | |
| rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| /* ESCAPE overrides SKIP_HTML. It doesn't look to see if | |
| * there are any valid tags, just escapes all of them. */ | |
| if((state->flags & HOEDOWN_HTML_ESCAPE) != 0) { | |
| escape_html(ob, text->data, text->size); | |
| return 1; | |
| } | |
| if ((state->flags & HOEDOWN_HTML_SKIP_HTML) != 0) | |
| return 1; | |
| hoedown_buffer_put(ob, text->data, text->size); | |
| return 1; | |
| } | |
| static void | |
| rndr_table(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| HOEDOWN_BUFPUTSL(ob, "<table>\n"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</table>\n"); | |
| } | |
| static void | |
| rndr_table_header(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| HOEDOWN_BUFPUTSL(ob, "<thead>\n"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</thead>\n"); | |
| } | |
| static void | |
| rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| HOEDOWN_BUFPUTSL(ob, "<tbody>\n"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</tbody>\n"); | |
| } | |
| static void | |
| rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| HOEDOWN_BUFPUTSL(ob, "<tr>\n"); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</tr>\n"); | |
| } | |
| static void | |
| rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data) | |
| { | |
| if (flags & HOEDOWN_TABLE_HEADER) { | |
| HOEDOWN_BUFPUTSL(ob, "<th"); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob, "<td"); | |
| } | |
| switch (flags & HOEDOWN_TABLE_ALIGNMASK) { | |
| case HOEDOWN_TABLE_ALIGN_CENTER: | |
| HOEDOWN_BUFPUTSL(ob, " style=\"text-align: center\">"); | |
| break; | |
| case HOEDOWN_TABLE_ALIGN_LEFT: | |
| HOEDOWN_BUFPUTSL(ob, " style=\"text-align: left\">"); | |
| break; | |
| case HOEDOWN_TABLE_ALIGN_RIGHT: | |
| HOEDOWN_BUFPUTSL(ob, " style=\"text-align: right\">"); | |
| break; | |
| default: | |
| HOEDOWN_BUFPUTSL(ob, ">"); | |
| } | |
| if (content) | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| if (flags & HOEDOWN_TABLE_HEADER) { | |
| HOEDOWN_BUFPUTSL(ob, "</th>\n"); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob, "</td>\n"); | |
| } | |
| } | |
| static int | |
| rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (!content || !content->size) return 0; | |
| HOEDOWN_BUFPUTSL(ob, "<sup>"); | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</sup>"); | |
| return 1; | |
| } | |
| static void | |
| rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| if (content) | |
| escape_html(ob, content->data, content->size); | |
| } | |
| static void | |
| rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (ob->size) hoedown_buffer_putc(ob, '\n'); | |
| HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n"); | |
| hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); | |
| HOEDOWN_BUFPUTSL(ob, "<ol>\n"); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n"); | |
| } | |
| static void | |
| rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data) | |
| { | |
| size_t i = 0; | |
| int pfound = 0; | |
| /* insert anchor at the end of first paragraph block */ | |
| if (content) { | |
| while ((i+3) < content->size) { | |
| if (content->data[i++] != '<') continue; | |
| if (content->data[i++] != '/') continue; | |
| if (content->data[i++] != 'p' && content->data[i] != 'P') continue; | |
| if (content->data[i] != '>') continue; | |
| i -= 3; | |
| pfound = 1; | |
| break; | |
| } | |
| } | |
| hoedown_buffer_printf(ob, "\n<li id=\"fn%d\">\n", num); | |
| if (pfound) { | |
| hoedown_buffer_put(ob, content->data, i); | |
| hoedown_buffer_printf(ob, " <a href=\"#fnref%d\" rev=\"footnote\">↩</a>", num); | |
| hoedown_buffer_put(ob, content->data + i, content->size - i); | |
| } else if (content) { | |
| hoedown_buffer_put(ob, content->data, content->size); | |
| } | |
| HOEDOWN_BUFPUTSL(ob, "</li>\n"); | |
| } | |
| static int | |
| rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data) | |
| { | |
| hoedown_buffer_printf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num); | |
| return 1; | |
| } | |
| static int | |
| rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data) | |
| { | |
| hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "\\("), 2); | |
| escape_html(ob, text->data, text->size); | |
| hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "\\)"), 2); | |
| return 1; | |
| } | |
| static void | |
| toc_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state = data->opaque; | |
| if (level <= state->toc_data.nesting_level) { | |
| /* set the level offset if this is the first header | |
| * we're parsing for the document */ | |
| if (state->toc_data.current_level == 0) | |
| state->toc_data.level_offset = level - 1; | |
| level -= state->toc_data.level_offset; | |
| if (level > state->toc_data.current_level) { | |
| while (level > state->toc_data.current_level) { | |
| HOEDOWN_BUFPUTSL(ob, "<ul>\n<li>\n"); | |
| state->toc_data.current_level++; | |
| } | |
| } else if (level < state->toc_data.current_level) { | |
| HOEDOWN_BUFPUTSL(ob, "</li>\n"); | |
| while (level < state->toc_data.current_level) { | |
| HOEDOWN_BUFPUTSL(ob, "</ul>\n</li>\n"); | |
| state->toc_data.current_level--; | |
| } | |
| HOEDOWN_BUFPUTSL(ob,"<li>\n"); | |
| } else { | |
| HOEDOWN_BUFPUTSL(ob,"</li>\n<li>\n"); | |
| } | |
| hoedown_buffer_printf(ob, "<a href=\"#toc_%d\">", state->toc_data.header_count++); | |
| if (content) hoedown_buffer_put(ob, content->data, content->size); | |
| HOEDOWN_BUFPUTSL(ob, "</a>\n"); | |
| } | |
| } | |
| static int | |
| toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data) | |
| { | |
| if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); | |
| return 1; | |
| } | |
| static void | |
| toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data) | |
| { | |
| hoedown_html_renderer_state *state; | |
| if (inline_render) | |
| return; | |
| state = data->opaque; | |
| while (state->toc_data.current_level > 0) { | |
| HOEDOWN_BUFPUTSL(ob, "</li>\n</ul>\n"); | |
| state->toc_data.current_level--; | |
| } | |
| state->toc_data.header_count = 0; | |
| } | |
| hoedown_renderer * | |
| hoedown_html_toc_renderer_new(int nesting_level) | |
| { | |
| static const hoedown_renderer cb_default = { | |
| NULL, | |
| NULL, | |
| NULL, | |
| toc_header, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| rndr_codespan, | |
| rndr_double_emphasis, | |
| rndr_emphasis, | |
| rndr_underline, | |
| rndr_highlight, | |
| rndr_quote, | |
| NULL, | |
| NULL, | |
| toc_link, | |
| rndr_triple_emphasis, | |
| rndr_strikethrough, | |
| rndr_superscript, | |
| NULL, | |
| NULL, | |
| NULL, | |
| NULL, | |
| rndr_normal_text, | |
| NULL, | |
| toc_finalize | |
| }; | |
| hoedown_html_renderer_state *state; | |
| hoedown_renderer *renderer; | |
| /* Prepare the state pointer */ | |
| state = hoedown_malloc(sizeof(hoedown_html_renderer_state)); | |
| memset(state, 0x0, sizeof(hoedown_html_renderer_state)); | |
| state->toc_data.nesting_level = nesting_level; | |
| /* Prepare the renderer */ | |
| renderer = hoedown_malloc(sizeof(hoedown_renderer)); | |
| memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); | |
| renderer->opaque = state; | |
| return renderer; | |
| } | |
| hoedown_renderer * | |
| hoedown_html_renderer_new(hoedown_html_flags render_flags, int nesting_level) | |
| { | |
| static const hoedown_renderer cb_default = { | |
| NULL, | |
| rndr_blockcode, | |
| rndr_blockquote, | |
| rndr_header, | |
| rndr_hrule, | |
| rndr_list, | |
| rndr_listitem, | |
| rndr_paragraph, | |
| rndr_table, | |
| rndr_table_header, | |
| rndr_table_body, | |
| rndr_tablerow, | |
| rndr_tablecell, | |
| rndr_footnotes, | |
| rndr_footnote_def, | |
| rndr_raw_block, | |
| rndr_autolink, | |
| rndr_codespan, | |
| rndr_double_emphasis, | |
| rndr_emphasis, | |
| rndr_underline, | |
| rndr_highlight, | |
| rndr_quote, | |
| rndr_image, | |
| rndr_linebreak, | |
| rndr_link, | |
| rndr_triple_emphasis, | |
| rndr_strikethrough, | |
| rndr_superscript, | |
| rndr_footnote_ref, | |
| rndr_math, | |
| rndr_raw_html, | |
| NULL, | |
| rndr_normal_text, | |
| NULL, | |
| NULL | |
| }; | |
| hoedown_html_renderer_state *state; | |
| hoedown_renderer *renderer; | |
| /* Prepare the state pointer */ | |
| state = hoedown_malloc(sizeof(hoedown_html_renderer_state)); | |
| memset(state, 0x0, sizeof(hoedown_html_renderer_state)); | |
| state->flags = render_flags; | |
| state->toc_data.nesting_level = nesting_level; | |
| /* Prepare the renderer */ | |
| renderer = hoedown_malloc(sizeof(hoedown_renderer)); | |
| memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); | |
| if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE) | |
| renderer->blockhtml = NULL; | |
| renderer->opaque = state; | |
| return renderer; | |
| } | |
| void | |
| hoedown_html_renderer_free(hoedown_renderer *renderer) | |
| { | |
| free(renderer->opaque); | |
| free(renderer); | |
| } |