static int toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque) { if (content && content->size) bufput(ob, content->data, content->size); return 1; }
void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure) { size_t i = 0, org, esc = 0; bufgrow(ob, ESCAPE_GROW_FACTOR(size)); while (i < size) { org = i; while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i >= size) break; /* The forward slash is only escaped in secure mode */ if (src[i] == '/' && !secure) { bufputc(ob, '/'); } else { bufputs(ob, HTML_ESCAPES[esc]); } i++; } }
static int rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque) { struct html_renderopt *options = 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((options->flags & HTML_ESCAPE) != 0) { escape_html(ob, text->data, text->size); return 1; } if ((options->flags & HTML_SKIP_HTML) != 0) return 1; if ((options->flags & HTML_SKIP_STYLE) != 0 && sdhtml_is_tag(text->data, text->size, "style")) return 1; if ((options->flags & HTML_SKIP_LINKS) != 0 && sdhtml_is_tag(text->data, text->size, "a")) return 1; if ((options->flags & HTML_SKIP_IMAGES) != 0 && sdhtml_is_tag(text->data, text->size, "img")) return 1; bufput(ob, text->data, text->size); return 1; }
static void rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque) { if (flags & MKD_TABLE_HEADER) { BUFPUTSL(ob, "<th"); } else { BUFPUTSL(ob, "<td"); } switch (flags & MKD_TABLE_ALIGNMASK) { case MKD_TABLE_ALIGN_CENTER: BUFPUTSL(ob, " style=\"text-align: center\">"); break; case MKD_TABLE_ALIGN_L: BUFPUTSL(ob, " style=\"text-align: left\">"); break; case MKD_TABLE_ALIGN_R: BUFPUTSL(ob, " style=\"text-align: right\">"); break; default: BUFPUTSL(ob, ">"); } if (text) bufput(ob, text->data, text->size); if (flags & MKD_TABLE_HEADER) { BUFPUTSL(ob, "</th>\n"); } else { BUFPUTSL(ob, "</td>\n"); } }
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; }
/* build_ref_id • collapse whitespace from input text to make it a ref id */ static int build_ref_id(struct buf *id, const char *data, size_t size) { size_t beg, i; /* skip leading whitespace */ while (size > 0 && (data[0] == ' ' || data[0] == '\t' || data[0] == '\n')) { data += 1; size -= 1; } /* skip trailing whitespace */ while (size > 0 && (data[size - 1] == ' ' || data[size - 1] == '\t' || data[size - 1] == '\n')) size -= 1; if (size == 0) return -1; /* making the ref id */ i = 0; id->size = 0; while (i < size) { /* copy non-whitespace into the output buffer */ beg = i; while (i < size && !(data[i] == ' ' || data[i] == '\t' || data[i] == '\n')) i += 1; bufput(id, data + beg, i - beg); /* add a single space and skip all consecutive whitespace */ if (i < size) bufputc(id, ' '); while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n')) i += 1; } return 0; }
/* parse_blockquote • hanldes parsing of a block-level code fragment */ static size_t parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t beg, end, pre; struct buf *work = new_work_buffer(rndr); beg = 0; while (beg < size) { for (end = beg + 1; end < size && data[end - 1] != '\n'; end += 1); pre = prefix_code(data + beg, end - beg); if (pre) beg += pre; /* skipping prefix */ else if (!is_empty(data + beg, end - beg)) /* non-empty non-prefixed line breaks the pre */ break; if (beg < end) { /* verbatim copy to the working buffer, escaping entities */ if (is_empty(data + beg, end - beg)) bufputc(work, '\n'); else bufput(work, data + beg, end - beg); } beg = end; } while (work->size && work->data[work->size - 1] == '\n') work->size -= 1; bufputc(work, '\n'); if (rndr->make.blockcode) rndr->make.blockcode(ob, work, rndr->make.opaque); release_work_buffer(rndr, work); return beg; }
size_t sd_autolink__www( size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size, unsigned int flags) { size_t link_end; if (offset > 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, flags); if (link_end == 0) return 0; while (link_end < size && !isspace(data[link_end])) link_end++; link_end = autolink_delim(data, link_end, offset, size); if (link_end == 0) return 0; bufput(link, data, link_end); *rewind_p = 0; return (int)link_end; }
static int latex_image(struct buf *ob, struct buf *link, struct buf *title, struct buf *alt, void *opaque) { if (!link || !link->size) return 0; BUFPUTSL(ob, "\\includegraphics{"); bufput(ob, link->data, link->size); BUFPUTSL(ob, "}"); 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; }
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_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_blockquote(struct buf *ob, const 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 void rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque) { BUFPUTSL(ob, "<tr>\n"); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "</tr>\n"); }
size_t sd_autolink__subreddit(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size) { size_t link_end; if (size < 3) return 0; /* make sure this / is part of /r/ */ if (strncasecmp((char*)data, "/r/", 3) != 0) return 0; link_end = strlen("/r/"); do { size_t start = link_end; int max_length = 24; /* special case: /r/reddit.com (only subreddit containing '.'). */ if ( size >= link_end+10 && strncasecmp((char*)data+link_end, "reddit.com", 10) == 0 ) { link_end += 10; /* Make sure there are no trailing characters (don't do * any autolinking for /r/reddit.commission) */ max_length = 10; } /* If not a special case, verify it begins with (t:)?[A-Za-z0-9] */ else { /* support autolinking to timereddits, /r/t:when (1 April 2012) */ if ( size > link_end+2 && strncasecmp((char*)data+link_end, "t:", 2) == 0 ) link_end += 2; /* Jump over the 't:' */ /* the first character of a subreddit name must be a letter or digit */ if (!isalnum(data[link_end])) return 0; link_end += 1; } /* consume valid characters ([A-Za-z0-9_]) until we run out */ while (link_end < size && (isalnum(data[link_end]) || data[link_end] == '_')) link_end++; /* valid subreddit names are between 3 and 21 characters, with * some subreddits having 2-character names. Don't bother with * autolinking for anything outside this length range. * (chksrname function in reddit/.../validator.py) */ if ( link_end-start < 2 || link_end-start > max_length ) return 0; /* If we are linking to a multireddit, continue */ } while ( link_end < size && data[link_end] == '+' && link_end++ ); /* make the link */ bufput(link, data, link_end); *rewind_p = 0; return link_end; }
static int rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<b><i>"); bufput(ob, text->data, text->size); BUFPUTSL(ob, "</i></b>"); return 1; }
static int rndr_superscript(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<sup>"); bufput(ob, text->data, text->size); BUFPUTSL(ob, "</sup>"); return 1; }
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 int rndr_link(struct buf *ob, struct buf *link, struct buf *title, struct buf *content, void *opaque) { struct html_renderopt *options = opaque; if ((options->flags & HTML_SAFELINK) != 0 && !is_safe_link(link->data, link->size)) return 0; BUFPUTSL(ob, "<a href=\""); if (link && link->size) bufput(ob, link->data, link->size); if (title && title->size) { BUFPUTSL(ob, "\" title=\""); attr_escape(ob, title->data, title->size); } BUFPUTSL(ob, "\">"); if (content && content->size) bufput(ob, content->data, content->size); BUFPUTSL(ob, "</a>"); return 1; }
/** * Ruby code */ static void autolink_callback(struct buf *link_text, const struct buf *link, void *block) { VALUE rb_link, rb_link_text; rb_link = rb_str_new(link->data, link->size); rb_link_text = rb_funcall((VALUE)block, rb_intern("call"), 1, rb_link); Check_Type(rb_link_text, T_STRING); bufput(link_text, RSTRING_PTR(rb_link_text), RSTRING_LEN(rb_link_text)); }
static void latex_entity(struct buf *ob, struct buf *entity, void *opaque) { const char *rendered = entity2latex(entity); if (rendered) bufputs(ob, rendered); else { BUFPUTSL(ob, "\\texttt{"); bufput(ob, entity->data, entity->size); BUFPUTSL(ob, "}"); } }
void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size) { size_t i = 0, org, ch; bufgrow(ob, ESCAPE_GROW_FACTOR(size)); while (i < size) { org = i; while (i < size && JS_ESCAPE[src[i]] == 0) i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i >= size) break; ch = src[i]; switch (ch) { case '/': /* * Escape only if preceded by a lt */ if (i && src[i - 1] == '<') bufputc(ob, '\\'); bufputc(ob, ch); break; case '\r': /* * Escape as \n, and skip the next \n if it's there */ if (i + 1 < size && src[i + 1] == '\n') i++; case '\n': /* * Escape actually as '\','n', not as '\', '\n' */ ch = 'n'; default: /* * Normal escaping */ bufputc(ob, '\\'); bufputc(ob, ch); break; } i++; } }
static void rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque) { struct html_renderopt *options = opaque; size_t i = 0; if (ob->size) bufputc(ob, '\n'); if (!text || !text->size) return; while (i < text->size && isspace(text->data[i])) i++; if (i == text->size) return; BUFPUTSL(ob, "<p>"); if (options->flags & HTML_HARD_WRAP) { size_t org; while (i < text->size) { org = i; while (i < text->size && text->data[i] != '\n') i++; if (i > org) bufput(ob, text->data + org, i - org); /* * do not insert a line break if this newline * is the last character on the paragraph */ if (i >= text->size - 1) break; rndr_linebreak(ob, opaque); i++; } } else { bufput(ob, &text->data[i], text->size - i); } BUFPUTSL(ob, "</p>\n"); }
static void rndr_paragraph(struct buf *ob, struct buf *text, void *opaque) { struct xhtml_renderopt *options = opaque; size_t i = 0; if (ob->size) bufputc(ob, '\n'); if (!text || !text->size) return; while (i < text->size && isspace(text->data[i])) i++; if (i == text->size) return; BUFPUTSL(ob, "<p>"); if (options->flags & XHTML_HARD_WRAP) { size_t org; while (i < text->size) { org = i; while (i < text->size && text->data[i] != '\n') i++; if (i > org) bufput(ob, text->data + org, i - org); if (i >= text->size) break; BUFPUTSL(ob, "<br/>\n"); i++; } } else { bufput(ob, &text->data[i], text->size - i); } BUFPUTSL(ob, "</p>\n"); /* Close any open quotes at the end of the paragraph */ options->quotes.in_squote = 0; options->quotes.in_dquote = 0; }
static int rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<del>"); bufput(ob, text->data, text->size); BUFPUTSL(ob, "</del>"); return 1; }
static int rndr_displayedmath(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "\\["); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "\\]"); return 1; }
static int rndr_inlinemath(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "\\("); if (text) bufput(ob, text->data, text->size); BUFPUTSL(ob, "\\)"); return 1; }
size_t sd_autolink__email( size_t *rewind_p, struct buf *link, uint8_t *data, size_t max_rewind, size_t size, unsigned int flags) { size_t link_end, rewind; int nb = 0, np = 0; for (rewind = 0; rewind < max_rewind; ++rewind) { uint8_t c = data[-rewind - 1]; if (isalnum(c)) continue; if (strchr(".+-_", c) != NULL) continue; break; } if (rewind == 0) return 0; for (link_end = 0; link_end < size; ++link_end) { uint8_t c = data[link_end]; if (isalnum(c)) continue; if (c == '@') nb++; else if (c == '.' && link_end < size - 1) np++; else if (c != '-' && c != '_') break; } if (link_end < 2 || nb != 1 || np == 0) return 0; link_end = autolink_delim(data, link_end, max_rewind, size); if (link_end == 0) return 0; bufput(link, data - rewind, link_end + rewind); *rewind_p = rewind; return link_end; }
/* get_link_ref • extract referenced link and title from id */ static int get_link_ref(struct render *rndr, struct buf *link, struct buf *title, char * data, size_t size) { struct link_ref *lr; /* find the link from its id (stored temporarily in link) */ link->size = 0; if (build_ref_id(link, data, size) < 0) return -1; lr = arr_sorted_find(&rndr->refs, link, cmp_link_ref); if (!lr) return -1; /* fill the output buffers */ link->size = 0; if (lr->link) bufput(link, lr->link->data, lr->link->size); title->size = 0; if (lr->title) bufput(title, lr->title->data, lr->title->size); return 0; }
static int rndr_quote(struct buf *ob, const struct buf *text, void *opaque) { if (!text || !text->size) return 0; BUFPUTSL(ob, "<q>"); bufput(ob, text->data, text->size); BUFPUTSL(ob, "</q>"); return 1; }