static int rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) { struct html_renderopt *options = opaque; if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size)) return 0; BUFPUTSL(ob, "<a href=\""); if (link && link->size) escape_href(ob, link->data, link->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } if (options->link_attributes) { bufputc(ob, '\"'); options->link_attributes(ob, link, opaque); bufputc(ob, '>'); } else { BUFPUTSL(ob, "\">"); } if (content && content->size) bufput(ob, content->data, content->size); BUFPUTSL(ob, "</a>"); return 1; }
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 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; }
static int rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque) { struct html_renderopt *options = opaque; if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size)) return 0; BUFPUTSL(ob, "<img src=\""); if (link && link->size) escape_href(ob, link->data, link->size); BUFPUTSL(ob, "\" alt=\""); if (alt && alt->size) escape_html(ob, alt->data, alt->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">"); return 1; }
/******************** * GENERIC RENDERER * ********************/ static int rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque) { struct html_renderopt *options = opaque; if (!link || !link->size) return 0; if ((options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size) && type != MKDA_EMAIL) return 0; BUFPUTSL(ob, "<a href=\""); if (type == MKDA_EMAIL) BUFPUTSL(ob, "mailto:"); escape_href(ob, link->data, link->size); if (options->link_attributes) { bufputc(ob, '\"'); options->link_attributes(ob, link, opaque); bufputc(ob, '>'); } else if (options->flags & HTML_NEW_TAB_LINKS) { BUFPUTSL(ob, "\" target=\"_blank\">"); } else { BUFPUTSL(ob, "\">"); } /* * Pretty printing: if we get an email address as * an actual URI, e.g. `mailto:[email protected]`, we don't * want to print the `mailto:` prefix */ if (bufprefix(link, "mailto:") == 0) { escape_html(ob, link->data + 7, link->size - 7); } else { escape_html(ob, link->data, link->size); } BUFPUTSL(ob, "</a>"); return 1; }
static int rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, void *opaque) { hoedown_html_renderer_state *state = 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_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque) { struct html_renderopt *options = opaque; if (!link || !link->size) return 0; BUFPUTSL(ob, "<img src=\""); escape_href(ob, link->data, link->size); BUFPUTSL(ob, "\" alt=\""); if (alt && alt->size) escape_html(ob, alt->data, alt->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); escape_html(ob, title->data, title->size); } bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">"); return 1; }
/******************** * GENERIC RENDERER * ********************/ static int rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autolink type, void *opaque) { hoedown_html_renderer_state *state = opaque; if (!link || !link->size) return 0; if ((state->flags & HOEDOWN_HTML_SAFELINK) != 0 && !hoedown_autolink_is_safe(link->data, link->size) && type != HOEDOWN_AUTOLINK_EMAIL) 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, opaque); hoedown_buffer_putc(ob, '>'); } else { HOEDOWN_BUFPUTSL(ob, "\">"); } /* * Pretty printing: if we get an email address as * an actual URI, e.g. `mailto:[email protected]`, 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 int S_render_node(cmark_node *node, cmark_event_type ev_type, struct render_state *state, int options) { cmark_node *parent; cmark_node *grandparent; cmark_strbuf *html = state->html; char start_header[] = "<h0"; char end_header[] = "</h0"; bool tight; bool entering = (ev_type == CMARK_EVENT_ENTER); if (state->plain == node) { // back at original node state->plain = NULL; } if (state->plain != NULL) { switch(node->type) { case CMARK_NODE_TEXT: case CMARK_NODE_CODE: case CMARK_NODE_INLINE_HTML: escape_html(html, node->as.literal.data, node->as.literal.len); break; case CMARK_NODE_LINEBREAK: case CMARK_NODE_SOFTBREAK: cmark_strbuf_putc(html, ' '); break; default: break; } return 1; } switch (node->type) { case CMARK_NODE_DOCUMENT: break; case CMARK_NODE_BLOCK_QUOTE: if (entering) { cr(html); cmark_strbuf_puts(html, "<blockquote"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, ">\n"); } else { cr(html); cmark_strbuf_puts(html, "</blockquote>\n"); } break; case CMARK_NODE_LIST: { cmark_list_type list_type = node->as.list.list_type; int start = node->as.list.start; if (entering) { cr(html); if (list_type == CMARK_BULLET_LIST) { cmark_strbuf_puts(html, "<ul"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, ">\n"); } else if (start == 1) { cmark_strbuf_puts(html, "<ol"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, ">\n"); } else { cmark_strbuf_printf(html, "<ol start=\"%d\"", start); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, ">\n"); } } else { cmark_strbuf_puts(html, list_type == CMARK_BULLET_LIST ? "</ul>\n" : "</ol>\n"); } break; } case CMARK_NODE_ITEM: if (entering) { cr(html); cmark_strbuf_puts(html, "<li"); S_render_sourcepos(node, html, options); cmark_strbuf_putc(html, '>'); } else { cmark_strbuf_puts(html, "</li>\n"); } break; case CMARK_NODE_HEADER: if (entering) { cr(html); start_header[2] = '0' + node->as.header.level; cmark_strbuf_puts(html, start_header); S_render_sourcepos(node, html, options); cmark_strbuf_putc(html, '>'); } else { end_header[3] = '0' + node->as.header.level; cmark_strbuf_puts(html, end_header); cmark_strbuf_puts(html, ">\n"); } break; case CMARK_NODE_CODE_BLOCK: cr(html); if (!node->as.code.fenced || node->as.code.info.len == 0) { cmark_strbuf_puts(html, "<pre"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, "><code>"); } else { int first_tag = 0; while (first_tag < node->as.code.info.len && node->as.code.info.data[first_tag] != ' ') { first_tag += 1; } cmark_strbuf_puts(html, "<pre"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, "><code class=\"language-"); escape_html(html, node->as.code.info.data, first_tag); cmark_strbuf_puts(html, "\">"); } escape_html(html, node->as.code.literal.data, node->as.code.literal.len); cmark_strbuf_puts(html, "</code></pre>\n"); break; case CMARK_NODE_HTML: cr(html); cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); break; case CMARK_NODE_HRULE: cr(html); cmark_strbuf_puts(html, "<hr"); S_render_sourcepos(node, html, options); cmark_strbuf_puts(html, " />\n"); break; case CMARK_NODE_PARAGRAPH: parent = cmark_node_parent(node); grandparent = cmark_node_parent(parent); if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) { tight = grandparent->as.list.tight; } else { tight = false; } if (!tight) { if (entering) { cr(html); cmark_strbuf_puts(html, "<p"); S_render_sourcepos(node, html, options); cmark_strbuf_putc(html, '>'); } else { cmark_strbuf_puts(html, "</p>\n"); } } break; case CMARK_NODE_TEXT: escape_html(html, node->as.literal.data, node->as.literal.len); break; case CMARK_NODE_LINEBREAK: cmark_strbuf_puts(html, "<br />\n"); break; case CMARK_NODE_SOFTBREAK: if (options & CMARK_OPT_HARDBREAKS) { cmark_strbuf_puts(html, "<br />\n"); } else { cmark_strbuf_putc(html, '\n'); } break; case CMARK_NODE_CODE: cmark_strbuf_puts(html, "<code>"); escape_html(html, node->as.literal.data, node->as.literal.len); cmark_strbuf_puts(html, "</code>"); break; case CMARK_NODE_INLINE_HTML: cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len); break; case CMARK_NODE_STRONG: if (entering) { cmark_strbuf_puts(html, "<strong>"); } else { cmark_strbuf_puts(html, "</strong>"); } break; case CMARK_NODE_EMPH: if (entering) { cmark_strbuf_puts(html, "<em>"); } else { cmark_strbuf_puts(html, "</em>"); } break; case CMARK_NODE_LINK: if (entering) { cmark_strbuf_puts(html, "<a href=\""); if (node->as.link.url) escape_href(html, node->as.link.url, -1); if (node->as.link.title) { cmark_strbuf_puts(html, "\" title=\""); escape_html(html, node->as.link.title, -1); } cmark_strbuf_puts(html, "\">"); } else { cmark_strbuf_puts(html, "</a>"); } break; case CMARK_NODE_IMAGE: if (entering) { cmark_strbuf_puts(html, "<img src=\""); if (node->as.link.url) escape_href(html, node->as.link.url, -1); cmark_strbuf_puts(html, "\" alt=\""); state->plain = node; } else { if (node->as.link.title) { cmark_strbuf_puts(html, "\" title=\""); escape_html(html, node->as.link.title, -1); } cmark_strbuf_puts(html, "\" />"); } break; default: assert(false); break; } // cmark_strbuf_putc(html, 'x'); return 1; }
// Convert an inline list to HTML. Returns 0 on success, and sets result. static void inlines_to_html(strbuf *html, node_inl* ils) { node_inl* children; render_stack* rstack = NULL; while(ils != NULL) { children = NULL; switch(ils->tag) { case INL_STRING: escape_html(html, ils->content.literal.data, ils->content.literal.len); break; case INL_LINEBREAK: strbuf_puts(html, "<br />\n"); break; case INL_SOFTBREAK: strbuf_putc(html, '\n'); break; case INL_CODE: strbuf_puts(html, "<code>"); escape_html(html, ils->content.literal.data, ils->content.literal.len); strbuf_puts(html, "</code>"); break; case INL_RAW_HTML: strbuf_put(html, ils->content.literal.data, ils->content.literal.len); break; case INL_LINK: strbuf_puts(html, "<a href=\""); if (ils->content.linkable.url) escape_href(html, ils->content.linkable.url, -1); if (ils->content.linkable.title) { strbuf_puts(html, "\" title=\""); escape_html(html, ils->content.linkable.title, -1); } strbuf_puts(html, "\">"); children = ils->content.linkable.label; rstack = push_inline(rstack, ils->next, "</a>"); break; case INL_IMAGE: strbuf_puts(html, "<img src=\""); if (ils->content.linkable.url) escape_href(html, ils->content.linkable.url, -1); strbuf_puts(html, "\" alt=\""); inlines_to_plain_html(html, ils->content.inlines); if (ils->content.linkable.title) { strbuf_puts(html, "\" title=\""); escape_html(html, ils->content.linkable.title, -1); } strbuf_puts(html, "\"/>"); break; case INL_STRONG: strbuf_puts(html, "<strong>"); children = ils->content.inlines; rstack = push_inline(rstack, ils->next, "</strong>"); break; case INL_EMPH: strbuf_puts(html, "<em>"); children = ils->content.inlines; rstack = push_inline(rstack, ils->next, "</em>"); break; } if (children) { ils = children; } else { ils = ils->next; } while (ils == NULL && rstack != NULL) { strbuf_puts(html, rstack->literal); ils = rstack->next_sibling.inl; rstack = pop_render_stack(rstack); } } free_render_stack(rstack); }