ext/xhtml.c in redcarpet-1.3.3 vs ext/xhtml.c in redcarpet-1.5.0

- old
+ new

@@ -20,13 +20,17 @@ #include <strings.h> #include <stdlib.h> #include <stdio.h> -struct toc_data { - int header_count; - int current_level; +struct xhtml_renderopt { + struct { + int header_count; + int current_level; + } toc_data; + + unsigned int flags; }; static int is_safe_link(const char *link, size_t link_len) { @@ -112,88 +116,107 @@ else lus_attr_escape(ob, link, link_size); BUFPUTSL(ob, "</a>"); } static int -rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, struct mkd_renderopt *options) +rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *opaque) { + struct xhtml_renderopt *options = opaque; + if (!link || !link->size) return 0; - if ((options->flags & RENDER_SAFELINK) != 0 && !is_safe_link(link->data, link->size)) + if ((options->flags & XHTML_SAFELINK) != 0 && !is_safe_link(link->data, link->size)) return 0; rndr_autolink2(ob, link->data, link->size, type); return 1; } static void -rndr_blockcode(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_blockcode(struct buf *ob, struct buf *text, void *opaque) { if (ob->size) bufputc(ob, '\n'); BUFPUTSL(ob, "<pre><code>"); if (text) lus_attr_escape(ob, text->data, text->size); BUFPUTSL(ob, "</code></pre>\n"); } static void -rndr_blockquote(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_blockquote(struct buf *ob, struct buf *text, void *opaque) { BUFPUTSL(ob, "<blockquote>\n"); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "</blockquote>"); } static int -rndr_codespan(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_codespan(struct buf *ob, struct buf *text, void *opaque) { BUFPUTSL(ob, "<code>"); if (text) lus_attr_escape(ob, text->data, text->size); BUFPUTSL(ob, "</code>"); return 1; } static int -rndr_double_emphasis(struct buf *ob, struct buf *text, char c, struct mkd_renderopt *options) +rndr_double_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) { - if (!text || !text->size) return 0; - BUFPUTSL(ob, "<strong>"); - bufput(ob, text->data, text->size); - BUFPUTSL(ob, "</strong>"); + struct xhtml_renderopt *options = opaque; + + if (!text || !text->size) + return 0; + + if (c == '~') { + if (options->flags & XHTML_SKIP_STRIKETHROUGH) + return 0; + + BUFPUTSL(ob, "<span style=\"text-decoration:line-through;\">"); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, "</span>"); + } else { + BUFPUTSL(ob, "<strong>"); + bufput(ob, text->data, text->size); + BUFPUTSL(ob, "</strong>"); + } + return 1; } static int -rndr_emphasis(struct buf *ob, struct buf *text, char c, struct mkd_renderopt *options) +rndr_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) { - if (!text || !text->size) return 0; + if (!text || !text->size || c == '~') return 0; BUFPUTSL(ob, "<em>"); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "</em>"); return 1; } static void -rndr_header(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *options) +rndr_header(struct buf *ob, struct buf *text, int level, void *opaque) { + struct xhtml_renderopt *options = opaque; + if (ob->size) bufputc(ob, '\n'); - if (options->flags & RENDER_TOC) { - struct toc_data *data = options->opaque; - bufprintf(ob, "<a name=\"toc_%d\"></a>", data->header_count++); + if (options->flags & XHTML_TOC) { + bufprintf(ob, "<a name=\"toc_%d\"></a>", options->toc_data.header_count++); } bufprintf(ob, "<h%d>", level); if (text) bufput(ob, text->data, text->size); bufprintf(ob, "</h%d>\n", level); } static int -rndr_link(struct buf *ob, struct buf *link, struct buf *title, struct buf *content, struct mkd_renderopt *options) +rndr_link(struct buf *ob, struct buf *link, struct buf *title, struct buf *content, void *opaque) { - if ((options->flags & RENDER_SAFELINK) != 0 && !is_safe_link(link->data, link->size)) + struct xhtml_renderopt *options = opaque; + + if ((options->flags & XHTML_SAFELINK) != 0 && !is_safe_link(link->data, link->size)) return 0; BUFPUTSL(ob, "<a href=\""); if (link && link->size) lus_attr_escape(ob, link->data, link->size); if (title && title->size) { @@ -204,31 +227,31 @@ BUFPUTSL(ob, "</a>"); return 1; } static void -rndr_list(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *options) +rndr_list(struct buf *ob, struct buf *text, int flags, void *opaque) { if (ob->size) bufputc(ob, '\n'); bufput(ob, flags & MKD_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5); if (text) bufput(ob, text->data, text->size); bufput(ob, flags & MKD_LIST_ORDERED ? "</ol>\n" : "</ul>\n", 6); } static void -rndr_listitem(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *options) +rndr_listitem(struct buf *ob, struct buf *text, int flags, void *opaque) { BUFPUTSL(ob, "<li>"); if (text) { while (text->size && text->data[text->size - 1] == '\n') text->size -= 1; bufput(ob, text->data, text->size); } BUFPUTSL(ob, "</li>\n"); } static void -rndr_paragraph(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_paragraph(struct buf *ob, struct buf *text, void *opaque) { size_t i = 0; if (ob->size) bufputc(ob, '\n'); @@ -243,11 +266,11 @@ BUFPUTSL(ob, "</p>\n"); } } static void -rndr_raw_block(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_raw_block(struct buf *ob, struct buf *text, void *opaque) { size_t org, sz; if (!text) return; sz = text->size; while (sz > 0 && text->data[sz - 1] == '\n') sz -= 1; @@ -258,11 +281,11 @@ bufput(ob, text->data + org, sz - org); bufputc(ob, '\n'); } static int -rndr_triple_emphasis(struct buf *ob, struct buf *text, char c, struct mkd_renderopt *options) +rndr_triple_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<strong><em>"); bufput(ob, text->data, text->size); BUFPUTSL(ob, "</em></strong>"); @@ -273,18 +296,18 @@ /********************** * XHTML 1.0 RENDERER * **********************/ static void -rndr_hrule(struct buf *ob, struct mkd_renderopt *options) +rndr_hrule(struct buf *ob, void *opaque) { if (ob->size) bufputc(ob, '\n'); BUFPUTSL(ob, "<hr />\n"); } static int -rndr_image(struct buf *ob, struct buf *link, struct buf *title, struct buf *alt, struct mkd_renderopt *options) +rndr_image(struct buf *ob, struct buf *link, struct buf *title, struct buf *alt, void *opaque) { if (!link || !link->size) return 0; BUFPUTSL(ob, "<img src=\""); lus_attr_escape(ob, link->data, link->size); BUFPUTSL(ob, "\" alt=\""); @@ -296,31 +319,32 @@ BUFPUTSL(ob, "\" />"); return 1; } static int -rndr_linebreak(struct buf *ob, struct mkd_renderopt *options) +rndr_linebreak(struct buf *ob, void *opaque) { BUFPUTSL(ob, "<br />\n"); return 1; } static int -rndr_raw_html(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_raw_html(struct buf *ob, struct buf *text, void *opaque) { + struct xhtml_renderopt *options = opaque; int escape_html = 0; - if (options->flags & RENDER_SKIP_HTML) + if (options->flags & XHTML_SKIP_HTML) escape_html = 1; - else if ((options->flags & RENDER_SKIP_STYLE) != 0 && is_html_tag(text, "<style>")) + else if ((options->flags & XHTML_SKIP_STYLE) != 0 && is_html_tag(text, "<style>")) escape_html = 1; - else if ((options->flags & RENDER_SKIP_LINKS) != 0 && is_html_tag(text, "<a>")) + else if ((options->flags & XHTML_SKIP_LINKS) != 0 && is_html_tag(text, "<a>")) escape_html = 1; - else if ((options->flags & RENDER_SKIP_IMAGES) != 0 && is_html_tag(text, "<img>")) + else if ((options->flags & XHTML_SKIP_IMAGES) != 0 && is_html_tag(text, "<img>")) escape_html = 1; if (escape_html) lus_attr_escape(ob, text->data, text->size); @@ -328,11 +352,60 @@ bufput(ob, text->data, text->size); return 1; } +static void +rndr_table(struct buf *ob, struct buf *header, struct buf *body, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + BUFPUTSL(ob, "<table><thead>\n"); + if (header) + bufput(ob, header->data, header->size); + BUFPUTSL(ob, "\n</thead><tbody>\n"); + if (body) + bufput(ob, body->data, body->size); + BUFPUTSL(ob, "\n</tbody></table>"); +} +static void +rndr_tablerow(struct buf *ob, struct buf *text, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + BUFPUTSL(ob, "<tr>\n"); + if (text) + bufput(ob, text->data, text->size); + BUFPUTSL(ob, "\n</tr>"); +} + +static void +rndr_tablecell(struct buf *ob, struct buf *text, int align, void *opaque) +{ + if (ob->size) bufputc(ob, '\n'); + switch (align) { + case MKD_TABLE_ALIGN_L: + BUFPUTSL(ob, "<td align=\"left\">"); + break; + + case MKD_TABLE_ALIGN_R: + BUFPUTSL(ob, "<td align=\"right\">"); + break; + + case MKD_TABLE_ALIGN_CENTER: + BUFPUTSL(ob, "<td align=\"center\">"); + break; + + default: + BUFPUTSL(ob, "<td>"); + break; + } + + if (text) + bufput(ob, text->data, text->size); + BUFPUTSL(ob, "</td>"); +} + static struct { char c0; const char *pattern; const char *entity; int skip; @@ -416,17 +489,18 @@ bufputs(ob, ent); return 1; } static void -rndr_normal_text(struct buf *ob, struct buf *text, struct mkd_renderopt *options) +rndr_normal_text(struct buf *ob, struct buf *text, void *opaque) { size_t i; int open_single = 0, open_double = 0, open_tag = 0; + struct xhtml_renderopt *options = opaque; - int autolink = (options->flags & RENDER_AUTOLINK); - int smartypants = (options->flags & RENDER_SMARTYPANTS); + int autolink = (options->flags & XHTML_AUTOLINK); + int smartypants = (options->flags & XHTML_SMARTYPANTS); if (!text) return; if (!autolink && !smartypants) { @@ -561,60 +635,63 @@ bufputc(ob, c); } } static void -toc_header(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *options) +toc_header(struct buf *ob, struct buf *text, int level, void *opaque) { - struct toc_data *data = (struct toc_data *)options->opaque; + struct xhtml_renderopt *options = opaque; - if (level > data->current_level) { + if (level > options->toc_data.current_level) { if (level > 1) BUFPUTSL(ob, "<li>"); BUFPUTSL(ob, "<ul>\n"); } - if (level < data->current_level) { + if (level < options->toc_data.current_level) { BUFPUTSL(ob, "</ul>"); - if (data->current_level > 1) + if (options->toc_data.current_level > 1) BUFPUTSL(ob, "</li>\n"); } - data->current_level = level; + options->toc_data.current_level = level; - bufprintf(ob, "<li><a href=\"#toc_%d\">", data->header_count++); + bufprintf(ob, "<li><a href=\"#toc_%d\">", options->toc_data.header_count++); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "</a></li>\n"); } static void -toc_finalize(struct buf *ob, struct mkd_renderopt *options) +toc_finalize(struct buf *ob, void *opaque) { - struct toc_data *data = (struct toc_data *)options->opaque; + struct xhtml_renderopt *options = opaque; - while (data->current_level > 1) { + while (options->toc_data.current_level > 1) { BUFPUTSL(ob, "</ul></li>\n"); - data->current_level--; + options->toc_data.current_level--; } - if (data->current_level) + if (options->toc_data.current_level) BUFPUTSL(ob, "</ul>\n"); } void -init_toc_renderer(struct mkd_renderer *renderer, int recursion_depth) +init_toc_renderer(struct mkd_renderer *renderer) { static const struct mkd_renderer toc_render = { NULL, NULL, NULL, toc_header, NULL, NULL, NULL, NULL, + NULL, + NULL, + NULL, rndr_autolink, rndr_codespan, rndr_double_emphasis, rndr_emphasis, @@ -628,37 +705,37 @@ NULL, NULL, toc_finalize, - NULL, - - { 0, 0 }, - { 0, 0 }, + "*-~", + NULL }; - memcpy(renderer, &toc_render, sizeof(struct mkd_renderer)); + struct xhtml_renderopt *options; + options = calloc(1, sizeof(struct xhtml_renderopt)); + options->flags = XHTML_TOC; - renderer->parser_options.recursion_depth = recursion_depth; - renderer->render_options.flags = RENDER_TOC; - renderer->render_options.opaque = calloc(1, sizeof(struct toc_data)); + memcpy(renderer, &toc_render, sizeof(struct mkd_renderer)); + renderer->opaque = options; } void -init_xhtml_renderer(struct mkd_renderer *renderer, - unsigned int render_flags, - unsigned int parser_flags, int recursion_depth) +init_xhtml_renderer(struct mkd_renderer *renderer, unsigned int render_flags) { static const struct mkd_renderer renderer_default = { rndr_blockcode, rndr_blockquote, rndr_raw_block, rndr_header, rndr_hrule, rndr_list, rndr_listitem, rndr_paragraph, + rndr_table, + rndr_tablerow, + rndr_tablecell, rndr_autolink, rndr_codespan, rndr_double_emphasis, rndr_emphasis, @@ -672,35 +749,31 @@ rndr_normal_text, NULL, NULL, - "*_", - - { 0, 0 }, - { 0, 0 }, + "*_~", + NULL }; + struct xhtml_renderopt *options; + options = calloc(1, sizeof(struct xhtml_renderopt)); + options->flags = render_flags; + memcpy(renderer, &renderer_default, sizeof(struct mkd_renderer)); + renderer->opaque = options; - if (render_flags & RENDER_SKIP_IMAGES) + if (render_flags & XHTML_SKIP_IMAGES) renderer->image = NULL; - if (render_flags & RENDER_SKIP_LINKS) { + if (render_flags & XHTML_SKIP_LINKS) { renderer->link = NULL; renderer->autolink = NULL; } - - renderer->parser_options.recursion_depth = recursion_depth; - renderer->parser_options.flags = parser_flags; - - renderer->render_options.flags = render_flags; - if (render_flags & RENDER_TOC) - renderer->render_options.opaque = calloc(1, sizeof(struct toc_data)); } void free_renderer(struct mkd_renderer *renderer) { - free(renderer->render_options.opaque); + free(renderer->opaque); }