From 7e0b564af9ea4aaa35feced8c6fda6a97c7f8948 Mon Sep 17 00:00:00 2001 From: Gulliver Date: Thu, 11 Sep 2014 20:31:59 +0200 Subject: using only includes from system --- src/html/html.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 src/html/html.c (limited to 'src/html/html.c') diff --git a/src/html/html.c b/src/html/html.c new file mode 100644 index 0000000..ab6fc35 --- /dev/null +++ b/src/html/html.c @@ -0,0 +1,228 @@ +#include +#include +#include +#include +#include + +#include "stmd.h" +#include "debug.h" +#include "html/houdini.h" + +// Functions to convert node_block and inline lists to HTML strings. + +static void escape_html(strbuf *dest, const unsigned char *source, int length) +{ + if (length < 0) + length = strlen((char *)source); + + houdini_escape_html0(dest, source, (size_t)length, 0); +} + +static void escape_href(strbuf *dest, const unsigned char *source, int length) +{ + if (length < 0) + length = strlen((char *)source); + + houdini_escape_href(dest, source, (size_t)length); +} + +static inline void cr(strbuf *html) +{ + if (html->size && html->ptr[html->size - 1] != '\n') + strbuf_putc(html, '\n'); +} + +// Convert an inline list to HTML. Returns 0 on success, and sets result. +static void inlines_to_html(strbuf *html, node_inl* ils) +{ + strbuf scrap = GH_BUF_INIT; + + while(ils != 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, "
\n"); + break; + + case INL_SOFTBREAK: + strbuf_putc(html, '\n'); + break; + + case INL_CODE: + strbuf_puts(html, ""); + escape_html(html, ils->content.literal.data, ils->content.literal.len); + strbuf_puts(html, ""); + break; + + case INL_RAW_HTML: + strbuf_put(html, + ils->content.literal.data, + ils->content.literal.len); + break; + + case INL_LINK: + strbuf_puts(html, "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, "\">"); + inlines_to_html(html, ils->content.inlines); + strbuf_puts(html, ""); + break; + + case INL_IMAGE: + strbuf_puts(html, "content.linkable.url) + escape_href(html, ils->content.linkable.url, -1); + + inlines_to_html(&scrap, ils->content.inlines); + strbuf_puts(html, "\" alt=\""); + if (scrap.size) + escape_html(html, scrap.ptr, scrap.size); + strbuf_clear(&scrap); + + 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, ""); + inlines_to_html(html, ils->content.inlines); + strbuf_puts(html, ""); + break; + + case INL_EMPH: + strbuf_puts(html, ""); + inlines_to_html(html, ils->content.inlines); + strbuf_puts(html, ""); + break; + } + ils = ils->next; + } + + strbuf_free(&scrap); +} + +// Convert a node_block list to HTML. Returns 0 on success, and sets result. +static void blocks_to_html(strbuf *html, node_block *b, bool tight) +{ + struct ListData *data; + + while(b != NULL) { + switch(b->tag) { + case BLOCK_DOCUMENT: + blocks_to_html(html, b->children, false); + break; + + case BLOCK_PARAGRAPH: + if (tight) { + inlines_to_html(html, b->inline_content); + } else { + cr(html); + strbuf_puts(html, "

"); + inlines_to_html(html, b->inline_content); + strbuf_puts(html, "

\n"); + } + break; + + case BLOCK_BQUOTE: + cr(html); + strbuf_puts(html, "
\n"); + blocks_to_html(html, b->children, false); + strbuf_puts(html, "
\n"); + break; + + case BLOCK_LIST_ITEM: + cr(html); + strbuf_puts(html, "
  • "); + blocks_to_html(html, b->children, tight); + strbuf_trim(html); /* TODO: rtrim */ + strbuf_puts(html, "
  • \n"); + break; + + case BLOCK_LIST: + // make sure a list starts at the beginning of the line: + cr(html); + data = &(b->as.list); + + if (data->start > 1) { + strbuf_printf(html, "<%s start=\"%d\">\n", + data->list_type == bullet ? "ul" : "ol", + data->start); + } else { + strbuf_puts(html, data->list_type == bullet ? "
      \n" : "
        \n"); + } + + blocks_to_html(html, b->children, data->tight); + strbuf_puts(html, data->list_type == bullet ? "
    " : ""); + strbuf_putc(html, '\n'); + break; + + case BLOCK_ATX_HEADER: + case BLOCK_SETEXT_HEADER: + cr(html); + strbuf_printf(html, "", b->as.header.level); + inlines_to_html(html, b->inline_content); + strbuf_printf(html, "\n", b->as.header.level); + break; + + case BLOCK_INDENTED_CODE: + case BLOCK_FENCED_CODE: + cr(html); + + strbuf_puts(html, "
    tag == BLOCK_FENCED_CODE) {
    +					strbuf *info = &b->as.code.info;
    +
    +					if (strbuf_len(info) > 0) {
    +						int first_tag = strbuf_strchr(info, ' ', 0);
    +						if (first_tag < 0)
    +							first_tag = strbuf_len(info);
    +
    +						strbuf_puts(html, " class=\"language-");
    +						escape_html(html, info->ptr, first_tag);
    +						strbuf_putc(html, '"');
    +					}
    +				}
    +
    +				strbuf_putc(html, '>');
    +				escape_html(html, b->string_content.ptr, b->string_content.size);
    +				strbuf_puts(html, "
    \n"); + break; + + case BLOCK_HTML: + strbuf_put(html, b->string_content.ptr, b->string_content.size); + break; + + case BLOCK_HRULE: + strbuf_puts(html, "
    \n"); + break; + + case BLOCK_REFERENCE_DEF: + break; + + default: + assert(false); + } + + b = b->next; + } +} + +void stmd_render_html(strbuf *html, node_block *root) +{ + blocks_to_html(html, root, false); +} -- cgit v1.2.3