mirror of
https://github.com/richgel999/ufo_data.git
synced 2024-12-27 16:39:31 -05:00
705 lines
18 KiB
C
705 lines
18 KiB
C
/* renderers.h - example markdown renderers */
|
|
|
|
/*
|
|
* Copyright (c) 2009, Natacha Porté
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include "renderers.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#include <string.h>
|
|
#define strncasecmp _strnicmp
|
|
#pragma warning (disable:4100)
|
|
#else
|
|
#include <strings.h>
|
|
#endif
|
|
|
|
|
|
/*****************************
|
|
* EXPORTED HELPER FUNCTIONS *
|
|
*****************************/
|
|
|
|
/* lus_attr_escape • copy the buffer entity-escaping '<', '>', '&' and '"' */
|
|
void
|
|
lus_attr_escape(struct buf *ob, const char *src, size_t size) {
|
|
size_t i = 0, org;
|
|
while (i < size) {
|
|
/* copying directly unescaped characters */
|
|
org = i;
|
|
while (i < size && src[i] != '<' && src[i] != '>'
|
|
&& src[i] != '&' && src[i] != '"')
|
|
i += 1;
|
|
if (i > org) bufput(ob, src + org, i - org);
|
|
|
|
/* escaping */
|
|
if (i >= size) break;
|
|
else if (src[i] == '<') BUFPUTSL(ob, "<");
|
|
else if (src[i] == '>') BUFPUTSL(ob, ">");
|
|
else if (src[i] == '&') BUFPUTSL(ob, "&");
|
|
else if (src[i] == '"') BUFPUTSL(ob, """);
|
|
i += 1; } }
|
|
|
|
|
|
/* lus_body_escape • copy the buffer entity-escaping '<', '>' and '&' */
|
|
void
|
|
lus_body_escape(struct buf *ob, const char *src, size_t size) {
|
|
size_t i = 0, org;
|
|
while (i < size) {
|
|
/* copying directly unescaped characters */
|
|
org = i;
|
|
while (i < size && src[i] != '<' && src[i] != '>'
|
|
&& src[i] != '&')
|
|
i += 1;
|
|
if (i > org) bufput(ob, src + org, i - org);
|
|
|
|
/* escaping */
|
|
if (i >= size) break;
|
|
else if (src[i] == '<') BUFPUTSL(ob, "<");
|
|
else if (src[i] == '>') BUFPUTSL(ob, ">");
|
|
else if (src[i] == '&') BUFPUTSL(ob, "&");
|
|
i += 1; } }
|
|
|
|
|
|
|
|
/********************
|
|
* GENERIC RENDERER *
|
|
********************/
|
|
|
|
static int
|
|
rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type,
|
|
void *opaque) {
|
|
if (!link || !link->size) return 0;
|
|
BUFPUTSL(ob, "<a href=\"");
|
|
if (type == MKDA_IMPLICIT_EMAIL) BUFPUTSL(ob, "mailto:");
|
|
lus_attr_escape(ob, link->data, link->size);
|
|
BUFPUTSL(ob, "\">");
|
|
if (type == MKDA_EXPLICIT_EMAIL && link->size > 7)
|
|
lus_body_escape(ob, link->data + 7, link->size - 7);
|
|
else lus_body_escape(ob, link->data, link->size);
|
|
BUFPUTSL(ob, "</a>");
|
|
return 1; }
|
|
|
|
static void
|
|
rndr_blockcode(struct buf *ob, struct buf *text, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<pre><code>");
|
|
if (text) lus_body_escape(ob, text->data, text->size);
|
|
BUFPUTSL(ob, "</code></pre>\n"); }
|
|
|
|
static void
|
|
rndr_blockquote(struct buf *ob, struct buf *text, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<blockquote>\n");
|
|
if (text) bufput(ob, text->data, text->size);
|
|
BUFPUTSL(ob, "</blockquote>\n"); }
|
|
|
|
static int
|
|
rndr_codespan(struct buf *ob, struct buf *text, void *opaque) {
|
|
BUFPUTSL(ob, "<code>");
|
|
if (text) lus_body_escape(ob, text->data, text->size);
|
|
BUFPUTSL(ob, "</code>");
|
|
return 1; }
|
|
|
|
static int
|
|
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>");
|
|
return 1; }
|
|
|
|
static int
|
|
rndr_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) {
|
|
if (!text || !text->size) 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, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
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, void *opaque) {
|
|
BUFPUTSL(ob, "<a href=\"");
|
|
if (link && link->size) lus_attr_escape(ob, link->data, link->size);
|
|
if (title && title->size) {
|
|
BUFPUTSL(ob, "\" title=\"");
|
|
lus_attr_escape(ob, title->data, title->size); }
|
|
BUFPUTSL(ob, "\">");
|
|
if (content && content->size) bufput(ob, content->data, content->size);
|
|
BUFPUTSL(ob, "</a>");
|
|
return 1; }
|
|
|
|
static void
|
|
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, 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_normal_text(struct buf *ob, struct buf *text, void *opaque) {
|
|
if (text) lus_body_escape(ob, text->data, text->size); }
|
|
|
|
static void
|
|
rndr_paragraph(struct buf *ob, struct buf *text, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<p>");
|
|
if (text) bufput(ob, text->data, text->size);
|
|
BUFPUTSL(ob, "</p>\n"); }
|
|
|
|
static void
|
|
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;
|
|
org = 0;
|
|
while (org < sz && text->data[org] == '\n') org += 1;
|
|
if (org >= sz) return;
|
|
if (ob->size) bufputc(ob, '\n');
|
|
bufput(ob, text->data + org, sz - org);
|
|
bufputc(ob, '\n'); }
|
|
|
|
static int
|
|
rndr_raw_inline(struct buf *ob, struct buf *text, void *opaque) {
|
|
bufput(ob, text->data, text->size);
|
|
return 1; }
|
|
|
|
static int
|
|
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>");
|
|
return 1; }
|
|
|
|
|
|
|
|
/*******************
|
|
* HTML 4 RENDERER *
|
|
*******************/
|
|
|
|
static void
|
|
html_hrule(struct buf *ob, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<hr>\n"); }
|
|
|
|
static int
|
|
html_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=\"");
|
|
if (alt && alt->size)
|
|
lus_attr_escape(ob, alt->data, alt->size);
|
|
if (title && title->size) {
|
|
BUFPUTSL(ob, "\" title=\"");
|
|
lus_attr_escape(ob, title->data, title->size); }
|
|
BUFPUTSL(ob, "\">");
|
|
return 1; }
|
|
|
|
static int
|
|
html_linebreak(struct buf *ob, void *opaque) {
|
|
BUFPUTSL(ob, "<br>\n");
|
|
return 1; }
|
|
|
|
|
|
/* exported renderer structure */
|
|
const struct mkd_renderer mkd_html = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
rndr_blockquote,
|
|
rndr_raw_block,
|
|
rndr_header,
|
|
html_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
rndr_paragraph,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
rndr_double_emphasis,
|
|
rndr_emphasis,
|
|
html_image,
|
|
html_linebreak,
|
|
rndr_link,
|
|
rndr_raw_inline,
|
|
rndr_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_",
|
|
NULL };
|
|
|
|
|
|
|
|
/**********************
|
|
* XHTML 1.0 RENDERER *
|
|
**********************/
|
|
|
|
static void
|
|
xhtml_hrule(struct buf *ob, void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<hr />\n"); }
|
|
|
|
static int
|
|
xhtml_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=\"");
|
|
if (alt && alt->size)
|
|
lus_attr_escape(ob, alt->data, alt->size);
|
|
if (title && title->size) {
|
|
BUFPUTSL(ob, "\" title=\"");
|
|
lus_attr_escape(ob, title->data, title->size); }
|
|
BUFPUTSL(ob, "\" />");
|
|
return 1; }
|
|
|
|
static int
|
|
xhtml_linebreak(struct buf *ob, void *opaque) {
|
|
BUFPUTSL(ob, "<br />\n");
|
|
return 1; }
|
|
|
|
|
|
/* exported renderer structure */
|
|
const struct mkd_renderer mkd_xhtml = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
rndr_blockquote,
|
|
rndr_raw_block,
|
|
rndr_header,
|
|
xhtml_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
rndr_paragraph,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
rndr_double_emphasis,
|
|
rndr_emphasis,
|
|
xhtml_image,
|
|
xhtml_linebreak,
|
|
rndr_link,
|
|
rndr_raw_inline,
|
|
rndr_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_",
|
|
NULL };
|
|
|
|
|
|
|
|
/**********************
|
|
* DISCOUNT RENDERERS *
|
|
**********************/
|
|
|
|
static int
|
|
print_link_wxh(struct buf *ob, struct buf *link) {
|
|
size_t eq, ex, end;
|
|
if (link->size < 1) return 0;
|
|
eq = link->size - 1;
|
|
while (eq > 0 && (link->data[eq - 1] != ' ' || link->data[eq] != '='))
|
|
eq -= 1;
|
|
if (!eq) return 0;
|
|
ex = eq + 1;
|
|
while (ex < link->size
|
|
&& link->data[ex] >= '0' && link->data[ex] <= '9')
|
|
ex += 1;
|
|
if (ex >= link->size || ex == eq + 1 || link->data[ex] != 'x') return 0;
|
|
end = ex + 1;
|
|
while (end < link->size
|
|
&& link->data[end] >= '0' && link->data[end] <= '9')
|
|
end += 1;
|
|
if (end == ex + 1) return 0;
|
|
/* everything is fine, proceeding to actual printing */
|
|
lus_attr_escape(ob, link->data, eq - 1);
|
|
BUFPUTSL(ob, "\" width=");
|
|
bufput(ob, link->data + eq + 1, ex - eq - 1);
|
|
BUFPUTSL(ob, " height=");
|
|
bufput(ob, link->data + ex + 1, end - ex - 1);
|
|
return 1; }
|
|
|
|
static int
|
|
discount_image(struct buf *ob, struct buf *link, struct buf *title,
|
|
struct buf *alt, int xhtml) {
|
|
if (!link || !link->size) return 0;
|
|
BUFPUTSL(ob, "<img src=\"");
|
|
if (!print_link_wxh(ob, link)) {
|
|
lus_attr_escape(ob, link->data, link->size);
|
|
bufputc(ob, '"'); }
|
|
BUFPUTSL(ob, " alt=\"");
|
|
if (alt && alt->size)
|
|
lus_attr_escape(ob, alt->data, alt->size);
|
|
if (title && title->size) {
|
|
BUFPUTSL(ob, "\" title=\"");
|
|
lus_attr_escape(ob, title->data, title->size); }
|
|
bufputs(ob, xhtml ? "\" />" : "\">");
|
|
return 1; }
|
|
|
|
static int
|
|
html_discount_image(struct buf *ob, struct buf *link, struct buf *title,
|
|
struct buf *alt, void *opaque) {
|
|
return discount_image(ob, link, title, alt, 0); }
|
|
|
|
static int
|
|
xhtml_discount_image(struct buf *ob, struct buf *link, struct buf *title,
|
|
struct buf *alt, void *opaque) {
|
|
return discount_image(ob, link, title, alt, 1); }
|
|
|
|
static int
|
|
discount_link(struct buf *ob, struct buf *link, struct buf *title,
|
|
struct buf *content, void *opaque) {
|
|
if (!link) return rndr_link(ob, link, title, content, opaque);
|
|
else if (link->size > 5 && !strncasecmp(link->data, "abbr:", 5)) {
|
|
BUFPUTSL(ob, "<abbr title=\"");
|
|
lus_attr_escape(ob, link->data + 5, link->size - 5);
|
|
BUFPUTSL(ob, "\">");
|
|
bufput(ob, content->data, content->size);
|
|
BUFPUTSL(ob, "</abbr>");
|
|
return 1; }
|
|
else if (link->size > 6 && !strncasecmp(link->data, "class:", 6)) {
|
|
BUFPUTSL(ob, "<span class=\"");
|
|
lus_attr_escape(ob, link->data + 6, link->size - 6);
|
|
BUFPUTSL(ob, "\">");
|
|
bufput(ob, content->data, content->size);
|
|
BUFPUTSL(ob, "</span>");
|
|
return 1; }
|
|
else if (link->size > 3 && !strncasecmp(link->data, "id:", 3)) {
|
|
BUFPUTSL(ob, "<span id=\"");
|
|
lus_attr_escape(ob, link->data + 3, link->size - 3);
|
|
BUFPUTSL(ob, "\">");
|
|
bufput(ob, content->data, content->size);
|
|
BUFPUTSL(ob, "</span>");
|
|
return 1; }
|
|
else if (link->size > 4 && !strncasecmp(link->data, "raw:", 4)) {
|
|
bufput(ob, link->data + 4, link->size - 4);
|
|
return 1; }
|
|
return rndr_link(ob, link, title, content, opaque); }
|
|
|
|
static void
|
|
discount_blockquote(struct buf *ob, struct buf *text, void *opaque) {
|
|
size_t i = 5, size = text->size;
|
|
char *data = text->data;
|
|
if (text->size < 5 || strncasecmp(text->data, "<p>%", 4)) {
|
|
rndr_blockquote(ob, text, opaque);
|
|
return; }
|
|
while (i < size && data[i] != '\n' && data[i] != '%')
|
|
i += 1;
|
|
if (i >= size || data[i] != '%') {
|
|
rndr_blockquote(ob, text, opaque);
|
|
return; }
|
|
BUFPUTSL(ob, "<div class=\"");
|
|
bufput(ob, text->data + 4, i - 4);
|
|
BUFPUTSL(ob, "\"><p>");
|
|
i += 1;
|
|
if (i + 4 >= text->size && !strncasecmp(text->data + i, "</p>", 4)) {
|
|
size_t old_i = i;
|
|
i += 4;
|
|
while (i + 3 < text->size
|
|
&& (data[i] != '<' || data[i + 1] != 'p' || data[i + 2] != '>'))
|
|
i += 1;
|
|
if (i + 3 >= text->size) i = old_i; }
|
|
bufput(ob, text->data + i, text->size - i);
|
|
BUFPUTSL(ob, "</div>\n"); }
|
|
|
|
static void
|
|
discount_table(struct buf *ob, struct buf *head_row, struct buf *rows,
|
|
void *opaque) {
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<table>\n");
|
|
if (head_row) {
|
|
BUFPUTSL(ob, "<thead>\n");
|
|
bufput(ob, head_row->data, head_row->size);
|
|
BUFPUTSL(ob, "</thead>\n<tbody>\n"); }
|
|
if (rows)
|
|
bufput(ob, rows->data, rows->size);
|
|
if (head_row)
|
|
BUFPUTSL(ob, "</tbody>\n");
|
|
BUFPUTSL(ob, "</table>\n"); }
|
|
|
|
static void
|
|
discount_table_row(struct buf *ob, struct buf *cells, int flags, void *opaque){
|
|
(void)flags;
|
|
BUFPUTSL(ob, " <tr>\n");
|
|
if (cells) bufput(ob, cells->data, cells->size);
|
|
BUFPUTSL(ob, " </tr>\n"); }
|
|
|
|
static void
|
|
discount_table_cell(struct buf *ob, struct buf *text, int flags, void *opaque){
|
|
if (flags & MKD_CELL_HEAD)
|
|
BUFPUTSL(ob, " <th");
|
|
else
|
|
BUFPUTSL(ob, " <td");
|
|
switch (flags & MKD_CELL_ALIGN_MASK) {
|
|
case MKD_CELL_ALIGN_LEFT:
|
|
BUFPUTSL(ob, " align=\"left\"");
|
|
break;
|
|
case MKD_CELL_ALIGN_RIGHT:
|
|
BUFPUTSL(ob, " align=\"right\"");
|
|
break;
|
|
case MKD_CELL_ALIGN_CENTER:
|
|
BUFPUTSL(ob, " align=\"center\"");
|
|
break; }
|
|
bufputc(ob, '>');
|
|
if (text) bufput(ob, text->data, text->size);
|
|
if (flags & MKD_CELL_HEAD)
|
|
BUFPUTSL(ob, "</th>\n");
|
|
else
|
|
BUFPUTSL(ob, "</td>\n"); }
|
|
|
|
/* exported renderer structures */
|
|
const struct mkd_renderer discount_html = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
discount_blockquote,
|
|
rndr_raw_block,
|
|
rndr_header,
|
|
html_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
rndr_paragraph,
|
|
discount_table,
|
|
discount_table_cell,
|
|
discount_table_row,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
rndr_double_emphasis,
|
|
rndr_emphasis,
|
|
html_discount_image,
|
|
html_linebreak,
|
|
discount_link,
|
|
rndr_raw_inline,
|
|
rndr_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_",
|
|
NULL };
|
|
const struct mkd_renderer discount_xhtml = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
discount_blockquote,
|
|
rndr_raw_block,
|
|
rndr_header,
|
|
xhtml_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
rndr_paragraph,
|
|
discount_table,
|
|
discount_table_cell,
|
|
discount_table_row,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
rndr_double_emphasis,
|
|
rndr_emphasis,
|
|
xhtml_discount_image,
|
|
xhtml_linebreak,
|
|
discount_link,
|
|
rndr_raw_inline,
|
|
rndr_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_",
|
|
NULL };
|
|
|
|
|
|
/****************************
|
|
* NATACHA'S OWN EXTENSIONS *
|
|
****************************/
|
|
|
|
static void
|
|
nat_span(struct buf *ob, struct buf *text, char *tag) {
|
|
bufprintf(ob, "<%s>", tag);
|
|
bufput(ob, text->data, text->size);
|
|
bufprintf(ob, "</%s>", tag); }
|
|
|
|
static int
|
|
nat_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) {
|
|
if (!text || !text->size || c == '+' || c == '-') return 0;
|
|
if (c == '|') nat_span(ob, text, "span");
|
|
else nat_span(ob, text, "em");
|
|
return 1; }
|
|
|
|
static int
|
|
nat_double_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) {
|
|
if (!text || !text->size || c == '|') return 0;
|
|
if (c == '+') nat_span(ob, text, "ins");
|
|
else if (c == '-') nat_span(ob, text, "del");
|
|
else nat_span(ob, text, "strong");
|
|
return 1; }
|
|
|
|
static int
|
|
nat_triple_emphasis(struct buf *ob, struct buf *text, char c, void *opaque) {
|
|
if (!text || !text->size || c == '+' || c == '-' || c == '|') return 0;
|
|
BUFPUTSL(ob, "<strong><em>");
|
|
bufput(ob, text->data, text->size);
|
|
BUFPUTSL(ob, "</em></strong>");
|
|
return 1; }
|
|
|
|
static void
|
|
nat_header(struct buf *ob, struct buf *text, int level, void *opaque) {
|
|
size_t i = 0;
|
|
if (ob->size) bufputc(ob, '\n');
|
|
while (i < text->size && (text->data[i] == '-' || text->data[i] == '_'
|
|
|| text->data[i] == '.' || text->data[i] == ':'
|
|
|| (text->data[i] >= 'a' && text->data[i] <= 'z')
|
|
|| (text->data[i] >= 'A' && text->data[i] <= 'Z')
|
|
|| (text->data[i] >= '0' && text->data[i] <= '9')))
|
|
i += 1;
|
|
bufprintf(ob, "<h%d", level);
|
|
if (i < text->size && text->data[i] == '#') {
|
|
bufprintf(ob, " id=\"%.*s\">", (int)i, text->data);
|
|
i += 1; }
|
|
else {
|
|
bufputc(ob, '>');
|
|
i = 0; }
|
|
bufput(ob, text->data + i, text->size - i);
|
|
bufprintf(ob, "</h%d>\n", level); }
|
|
|
|
static void
|
|
nat_paragraph(struct buf *ob, struct buf *text, void *opaque) {
|
|
size_t i = 0;
|
|
if (ob->size) bufputc(ob, '\n');
|
|
BUFPUTSL(ob, "<p");
|
|
if (text && text->size && text->data[0] == '(') {
|
|
i = 1;
|
|
while (i < text->size && (text->data[i] == ' '
|
|
/* this seems to be a bit more restrictive than */
|
|
/* what is allowed for class names */
|
|
|| (text->data[i] >= 'a' && text->data[i] <= 'z')
|
|
|| (text->data[i] >= 'A' && text->data[i] <= 'Z')
|
|
|| (text->data[i] >= '0' && text->data[i] <= '9')))
|
|
i += 1;
|
|
if (i < text->size && text->data[i] == ')') {
|
|
bufprintf(ob, " class=\"%.*s\"",
|
|
(int)(i - 1), text->data + 1);
|
|
i += 1; }
|
|
else i = 0; }
|
|
bufputc(ob, '>');
|
|
if (text) bufput(ob, text->data + i, text->size - i);
|
|
BUFPUTSL(ob, "</p>\n"); }
|
|
|
|
|
|
/* exported renderer structures */
|
|
const struct mkd_renderer nat_html = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
discount_blockquote,
|
|
rndr_raw_block,
|
|
nat_header,
|
|
html_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
nat_paragraph,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
nat_double_emphasis,
|
|
nat_emphasis,
|
|
html_discount_image,
|
|
html_linebreak,
|
|
discount_link,
|
|
rndr_raw_inline,
|
|
nat_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_-+|",
|
|
NULL };
|
|
const struct mkd_renderer nat_xhtml = {
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_blockcode,
|
|
discount_blockquote,
|
|
rndr_raw_block,
|
|
nat_header,
|
|
xhtml_hrule,
|
|
rndr_list,
|
|
rndr_listitem,
|
|
nat_paragraph,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
|
|
rndr_autolink,
|
|
rndr_codespan,
|
|
nat_double_emphasis,
|
|
nat_emphasis,
|
|
xhtml_discount_image,
|
|
xhtml_linebreak,
|
|
discount_link,
|
|
rndr_raw_inline,
|
|
nat_triple_emphasis,
|
|
|
|
NULL,
|
|
rndr_normal_text,
|
|
|
|
64,
|
|
"*_-+|",
|
|
NULL };
|