static void rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int num, void *opaque) { size_t i = 0; int pfound = 0; /* insert anchor at the end of first paragraph block */ if (text) { while ((i+3) < text->size) { if (text->data[i++] != '<') continue; if (text->data[i++] != '/') continue; if (text->data[i++] != 'p' && text->data[i] != 'P') continue; if (text->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, text->data, i); hoedown_buffer_printf(ob, " <a href=\"#fnref%d\" rev=\"footnote\">↩</a>", num); hoedown_buffer_put(ob, text->data + i, text->size - i); } else if (text) { hoedown_buffer_put(ob, text->data, text->size); } HOEDOWN_BUFPUTSL(ob, "</li>\n"); }
void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure) { size_t i = 0, mark; while (1) { mark = i; while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++; /* Optimization for cases where there's nothing to escape */ if (mark == 0 && i >= size) { hoedown_buffer_put(ob, data, size); return; } if (likely(i > mark)) hoedown_buffer_put(ob, data + mark, i - mark); if (i >= size) break; /* The forward slash is only escaped in secure mode */ if (!secure && data[i] == '/') { hoedown_buffer_putc(ob, '/'); } else { hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]); } i++; } }
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 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_list(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5); if (text) hoedown_buffer_put(ob, text->data, text->size); hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n", 6); }
static void rndr_table(hoedown_buffer *ob, const hoedown_buffer *header, const hoedown_buffer *body, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<table><thead>\n"); if (header) hoedown_buffer_put(ob, header->data, header->size); HOEDOWN_BUFPUTSL(ob, "</thead><tbody>\n"); if (body) hoedown_buffer_put(ob, body->data, body->size); HOEDOWN_BUFPUTSL(ob, "</tbody></table>\n"); }
// Supports task list syntax if HOEDOWN_HTML_USE_TASK_LIST is on. // Implementation based on hoextdown. void hoedown_patch_render_listitem( hoedown_buffer *ob, const hoedown_buffer *text, hoedown_list_flags flags, const hoedown_renderer_data *data) { if (text) { hoedown_html_renderer_state *state = data->opaque; size_t offset = 0; if (flags & HOEDOWN_LI_BLOCK) offset = 3; // Do task list checkbox ([x] or [ ]). if (USE_TASK_LIST(state) && text->size >= 3) { if (strncmp((char *)(text->data + offset), "[ ]", 3) == 0) { HOEDOWN_BUFPUTSL(ob, "<li class=\"task-list-item\">"); hoedown_buffer_put(ob, text->data, offset); if (USE_XHTML(state)) HOEDOWN_BUFPUTSL(ob, "<input type=\"checkbox\" />"); else HOEDOWN_BUFPUTSL(ob, "<input type=\"checkbox\">"); offset += 3; } else if (strncmp((char *)(text->data + offset), "[x]", 3) == 0) { HOEDOWN_BUFPUTSL(ob, "<li class=\"task-list-item\">"); hoedown_buffer_put(ob, text->data, offset); if (USE_XHTML(state)) HOEDOWN_BUFPUTSL(ob, "<input type=\"checkbox\" checked />"); else HOEDOWN_BUFPUTSL(ob, "<input type=\"checkbox\" checked>"); offset += 3; } else { HOEDOWN_BUFPUTSL(ob, "<li>"); offset = 0; } } else { HOEDOWN_BUFPUTSL(ob, "<li>"); offset = 0; } size_t size = text->size; while (size && text->data[size - offset - 1] == '\n') size--; hoedown_buffer_put(ob, text->data + offset, size - offset); } HOEDOWN_BUFPUTSL(ob, "</li>\n"); }
static void rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data) { const hoedown_buffer *id; id = hoedown_document_footnote_id(((hoedown_context_test_renderer_state*) data->opaque)->doc); if (id) { hoedown_buffer_puts(ob, "id: "); hoedown_buffer_put(ob, id->data, id->size); } hoedown_buffer_putc(ob, ' '); if (content) hoedown_buffer_put(ob, content->data, content->size); }
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_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_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 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"); } }
size_t hoedown_autolink__www( size_t *rewind_p, hoedown_buffer *link, uint8_t *data, size_t max_rewind, size_t size, unsigned int flags) { size_t link_end; if (max_rewind > 0 && !ispunct(data[-1]) && !isspace(data[-1])) return 0; if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) return 0; link_end = check_domain(data, size, 0); if (link_end == 0) return 0; while (link_end < size && !isspace(data[link_end])) link_end++; link_end = autolink_delim(data, link_end, max_rewind, size); if (link_end == 0) return 0; hoedown_buffer_put(link, data, link_end); *rewind_p = 0; return (int)link_end; }
static int rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *attr, const hoedown_renderer_data *data) { const hoedown_buffer *id; hoedown_link_type link_type; id = hoedown_document_link_id(((hoedown_context_test_renderer_state*) data->opaque)->doc); hoedown_buffer_puts(ob, "id: "); if (id) hoedown_buffer_put(ob, id->data, id->size); else hoedown_buffer_puts(ob, "no id"); hoedown_buffer_putc(ob, ' '); link_type = hoedown_document_link_type(((hoedown_context_test_renderer_state*) data->opaque)->doc); switch (link_type) { case HOEDOWN_LINK_INLINE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_INLINE"); break; case HOEDOWN_LINK_REFERENCE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_REFERENCE"); break; case HOEDOWN_LINK_EMPTY_REFERENCE: hoedown_buffer_puts(ob, "HOEDOWN_LINK_EMPTY_REFERENCE"); break; case HOEDOWN_LINK_SHORTCUT: hoedown_buffer_puts(ob, "HOEDOWN_LINK_SHORTCUT"); break; default: break; } return 1; }
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 toc_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque) { if (content && content->size) hoedown_buffer_put(ob, content->data, content->size); return 1; }
static void rndr_test_link_attributes(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data) { hoedown_buffer_puts(ob, " data-url=\""); hoedown_buffer_put(ob, url->data, url->size); hoedown_buffer_putc(ob, '\"'); }
static int rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { hoedown_html_renderer_state *state = opaque; /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES * It doens't see if there are any valid tags, just escape 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; if ((state->flags & HOEDOWN_HTML_SKIP_STYLE) != 0 && hoedown_html_is_tag(text->data, text->size, "style")) return 1; if ((state->flags & HOEDOWN_HTML_SKIP_LINKS) != 0 && hoedown_html_is_tag(text->data, text->size, "a")) return 1; if ((state->flags & HOEDOWN_HTML_SKIP_IMAGES) != 0 && hoedown_html_is_tag(text->data, text->size, "img")) return 1; hoedown_buffer_put(ob, text->data, text->size); return 1; }
static void rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque) { 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 (text) hoedown_buffer_put(ob, text->data, text->size); if (flags & HOEDOWN_TABLE_HEADER) { HOEDOWN_BUFPUTSL(ob, "</th>\n"); } else { HOEDOWN_BUFPUTSL(ob, "</td>\n"); } }
static int rndr_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque) { hoedown_html_renderer_state *state = opaque; if (link != NULL && (state->flags & HOEDOWN_HTML_SAFELINK) != 0 && !hoedown_autolink_is_safe(link->data, link->size)) return 0; 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, opaque); 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; }
// rndr_blockcode from HEAD. The "language-" prefix in class in needed to make // the HTML compatible with Prism. void hoedown_patch_render_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'); hoedown_html_renderer_state *state = data->opaque; hoedown_buffer *front = NULL; hoedown_buffer *back = NULL; if (lang && USE_BLOCKCODE_INFORMATION(state)) { front = hoedown_buffer_new(lang->size); back = hoedown_buffer_new(lang->size); hoedown_buffer *current = front; for (size_t i = 0; i < lang->size; i++) { uint8_t c = lang->data[i]; if (current == front && c == ':') current = back; else hoedown_buffer_putc(current, c); } lang = front; } HOEDOWN_BUFPUTSL(ob, "<pre"); if (state->flags & HOEDOWN_HTML_BLOCKCODE_LINE_NUMBERS) HOEDOWN_BUFPUTSL(ob, " class=\"line-numbers\""); if (back && back->size) { HOEDOWN_BUFPUTSL(ob, " data-information=\""); hoedown_buffer_put(ob, back->data, back->size); HOEDOWN_BUFPUTSL(ob, "\""); } HOEDOWN_BUFPUTSL(ob, "><code class=\"language-"); if (lang && lang->size) hoedown_escape_html(ob, lang->data, lang->size, 0); else HOEDOWN_BUFPUTSL(ob, "none"); HOEDOWN_BUFPUTSL(ob, "\">"); if (text) { // Remove last newline to prevent prism from adding a blank line at the // end of code blocks. size_t size = text->size; if (size > 0 && text->data[size - 1] == '\n') size--; hoedown_escape_html(ob, text->data, size, 0); } HOEDOWN_BUFPUTSL(ob, "</code></pre>\n"); hoedown_buffer_free(front); hoedown_buffer_free(back); }
static void rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { HOEDOWN_BUFPUTSL(ob, "<tr>\n"); if (text) hoedown_buffer_put(ob, text->data, text->size); HOEDOWN_BUFPUTSL(ob, "</tr>\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 void rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { if (ob->size) hoedown_buffer_putc(ob, '\n'); HOEDOWN_BUFPUTSL(ob, "<blockquote>\n"); if (text) hoedown_buffer_put(ob, text->data, text->size); HOEDOWN_BUFPUTSL(ob, "</blockquote>\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 int rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { if (!text || !text->size) return 0; HOEDOWN_BUFPUTSL(ob, "<sup>"); hoedown_buffer_put(ob, text->data, text->size); HOEDOWN_BUFPUTSL(ob, "</sup>"); return 1; }
static int rndr_emphasis(struct hoedown_buffer *ob, const struct hoedown_buffer *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<em>"); if (text) hoedown_buffer_put(ob, text->data, text->size); BUFPUTSL(ob, "</em>"); return 1; }
static int rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque) { if (!text || !text->size) return 0; HOEDOWN_BUFPUTSL(ob, "<strong><em>"); hoedown_buffer_put(ob, text->data, text->size); HOEDOWN_BUFPUTSL(ob, "</em></strong>"); return 1; }
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 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; }