sundown 0.4.1.2 → 0.4.2
raw patch · 9 files changed
+325/−161 lines, 9 files
Files
- cbits/autolink.c +45/−9
- cbits/autolink.h +22/−7
- cbits/buffer.c +2/−0
- cbits/buffer.h +8/−0
- cbits/markdown.c +175/−87
- cbits/markdown.h +13/−5
- cbits/stack.h +8/−0
- src/Text/Sundown/Markdown/Foreign.hsc +18/−17
- sundown.cabal +34/−36
cbits/autolink.c view
@@ -15,12 +15,17 @@ */ #include "buffer.h"+#include "autolink.h" #include <string.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> +#if defined(_WIN32)+#define strncasecmp _strnicmp+#endif+ int sd_autolink_issafe(const uint8_t *link, size_t link_len) {@@ -128,7 +133,7 @@ } static size_t-check_domain(uint8_t *data, size_t size)+check_domain(uint8_t *data, size_t size, int allow_short) { size_t i, np = 0; @@ -140,13 +145,27 @@ else if (!isalnum(data[i]) && data[i] != '-') break; } - /* a valid domain needs to have at least a dot.- * that's as far as we get */- return np ? i : 0;+ if (allow_short) {+ /* We don't need a valid domain in the strict sense (with+ * least one dot; so just make sure it's composed of valid+ * domain characters and return the length of the the valid+ * sequence. */+ return i;+ } else {+ /* a valid domain needs to have at least a dot.+ * that's as far as we get */+ return np ? i : 0;+ } } size_t-sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)+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; @@ -156,7 +175,7 @@ if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0) return 0; - link_end = check_domain(data, size);+ link_end = check_domain(data, size, 0); if (link_end == 0) return 0;@@ -176,7 +195,13 @@ } size_t-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)+sd_autolink__email(+ size_t *rewind_p,+ struct buf *link,+ uint8_t *data,+ size_t offset,+ size_t size,+ unsigned int flags) { size_t link_end, rewind; int nb = 0, np = 0;@@ -225,7 +250,13 @@ } size_t-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)+sd_autolink__url(+ size_t *rewind_p,+ struct buf *link,+ uint8_t *data,+ size_t offset,+ size_t size,+ unsigned int flags) { size_t link_end, rewind = 0, domain_len; @@ -237,9 +268,14 @@ if (!sd_autolink_issafe(data - rewind, size + rewind)) return 0;+ link_end = strlen("://"); - domain_len = check_domain(data + link_end, size - link_end);+ domain_len = check_domain(+ data + link_end,+ size - link_end,+ flags & SD_AUTOLINK_SHORT_DOMAINS);+ if (domain_len == 0) return 0;
cbits/autolink.h view
@@ -19,17 +19,32 @@ #include "buffer.h" -extern int+#ifdef __cplusplus+extern "C" {+#endif++enum {+ SD_AUTOLINK_SHORT_DOMAINS = (1 << 0),+};++int sd_autolink_issafe(const uint8_t *link, size_t link_len); -extern size_t-sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);+size_t+sd_autolink__www(size_t *rewind_p, struct buf *link,+ uint8_t *data, size_t offset, size_t size, unsigned int flags); -extern size_t-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);+size_t+sd_autolink__email(size_t *rewind_p, struct buf *link,+ uint8_t *data, size_t offset, size_t size, unsigned int flags); -extern size_t-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);+size_t+sd_autolink__url(size_t *rewind_p, struct buf *link,+ uint8_t *data, size_t offset, size_t size, unsigned int flags);++#ifdef __cplusplus+}+#endif #endif
cbits/buffer.c view
@@ -127,7 +127,9 @@ if (n < 0) { #ifdef _MSC_VER+ va_start(ap, fmt); n = _vscprintf(fmt, ap);+ va_end(ap); #else return; #endif
cbits/buffer.h view
@@ -22,6 +22,10 @@ #include <stdarg.h> #include <stdint.h> +#ifdef __cplusplus+extern "C" {+#endif+ #if defined(_MSC_VER) #define __attribute__(x) #define inline@@ -84,5 +88,9 @@ /* bufprintf: formatted printing to a buffer */ void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));++#ifdef __cplusplus+}+#endif #endif
cbits/markdown.c view
@@ -25,6 +25,10 @@ #include <ctype.h> #include <stdio.h> +#if defined(_WIN32)+#define strncasecmp _strnicmp+#endif+ #define REF_TABLE_SIZE 8 #define BUFFER_BLOCK 0@@ -767,7 +771,7 @@ link = rndr_newbuf(rndr, BUFFER_SPAN); - if ((link_len = sd_autolink__www(&rewind, link, data, offset, size)) > 0) {+ if ((link_len = sd_autolink__www(&rewind, link, data, offset, size, 0)) > 0) { link_url = rndr_newbuf(rndr, BUFFER_SPAN); BUFPUTSL(link_url, "http://"); bufput(link_url, link->data, link->size);@@ -799,7 +803,7 @@ link = rndr_newbuf(rndr, BUFFER_SPAN); - if ((link_len = sd_autolink__email(&rewind, link, data, offset, size)) > 0) {+ if ((link_len = sd_autolink__email(&rewind, link, data, offset, size, 0)) > 0) { ob->size -= rewind; rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque); }@@ -819,7 +823,7 @@ link = rndr_newbuf(rndr, BUFFER_SPAN); - if ((link_len = sd_autolink__url(&rewind, link, data, offset, size)) > 0) {+ if ((link_len = sd_autolink__url(&rewind, link, data, offset, size, 0)) > 0) { ob->size -= rewind; rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque); }@@ -1150,9 +1154,10 @@ return n >= 3; } -/* check if a line is a code fence; return its size if it is */+/* check if a line begins with a code fence; return the+ * width of the code fence */ static size_t-is_codefence(uint8_t *data, size_t size, struct buf *syntax)+prefix_codefence(uint8_t *data, size_t size) { size_t i = 0, n = 0; uint8_t c;@@ -1177,43 +1182,56 @@ if (n < 3) return 0; - if (syntax != NULL) {- size_t syn = 0;+ return i;+} - while (i < size && data[i] == ' ')- i++;+/* check if a line is a code fence; return its size if it is */+static size_t+is_codefence(uint8_t *data, size_t size, struct buf *syntax)+{+ size_t i = 0, syn_len = 0;+ uint8_t *syn_start; - syntax->data = data + i;+ i = prefix_codefence(data, size);+ if (i == 0)+ return 0; - if (i < size && data[i] == '{') {- i++; syntax->data++;+ while (i < size && data[i] == ' ')+ i++; - while (i < size && data[i] != '}' && data[i] != '\n') {- syn++; i++;- }+ syn_start = data + i; - if (i == size || data[i] != '}')- return 0;+ if (i < size && data[i] == '{') {+ i++; syn_start++; - /* strip all whitespace at the beginning and the end- * of the {} block */- while (syn > 0 && _isspace(syntax->data[0])) {- syntax->data++; syn--;- }+ while (i < size && data[i] != '}' && data[i] != '\n') {+ syn_len++; i++;+ } - while (syn > 0 && _isspace(syntax->data[syn - 1]))- syn--;+ if (i == size || data[i] != '}')+ return 0; - i++;- } else {- while (i < size && !_isspace(data[i])) {- syn++; i++;- }+ /* strip all whitespace at the beginning and the end+ * of the {} block */+ while (syn_len > 0 && _isspace(syn_start[0])) {+ syn_start++; syn_len--; } - syntax->size = syn;+ while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))+ syn_len--;++ i++;+ } else {+ while (i < size && !_isspace(data[i])) {+ syn_len++; i++;+ } } + if (syntax) {+ syntax->data = syn_start;+ syntax->size = syn_len;+ }+ while (i < size && data[i] != '\n') { if (!_isspace(data[i])) return 0;@@ -1416,19 +1434,48 @@ while (i < size) { for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; - if (is_empty(data + i, size - i) || (level = is_headerline(data + i, size - i)) != 0)+ if (is_empty(data + i, size - i)) break; - if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) {- if (data[i] == '<' && rndr->cb.blockhtml && parse_htmlblock(ob, rndr, data + i, size - i, 0)) {+ if ((level = is_headerline(data + i, size - i)) != 0)+ break;++ if (is_atxheader(rndr, data + i, size - i) ||+ is_hrule(data + i, size - i) ||+ prefix_quote(data + i, size - i)) {+ end = i;+ break;+ }++ /*+ * Early termination of a paragraph with the same logic+ * as Markdown 1.0.0. If this logic is applied, the+ * Markdown 1.0.3 test suite won't pass cleanly+ *+ * :: If the first character in a new line is not a letter,+ * let's check to see if there's some kind of block starting+ * here+ */+ if ((rndr->ext_flags & MKDEXT_LAX_SPACING) && !isalnum(data[i])) {+ if (prefix_oli(data + i, size - i) ||+ prefix_uli(data + i, size - i)) { end = i; break; }- } - if (is_atxheader(rndr, data + i, size - i) || is_hrule(data + i, size - i)) {- end = i;- break;+ /* see if an html block starts here */+ if (data[i] == '<' && rndr->cb.blockhtml &&+ parse_htmlblock(ob, rndr, data + i, size - i, 0)) {+ end = i;+ break;+ }++ /* see if a code fence starts here */+ if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 &&+ is_codefence(data + i, size - i, NULL) != 0) {+ end = i;+ break;+ } } i = end;@@ -1500,9 +1547,10 @@ while (beg < size) { size_t fence_end;+ struct buf fence_trail = { 0, 0, 0, 0 }; - fence_end = is_codefence(data + beg, size - beg, NULL);- if (fence_end != 0) {+ fence_end = is_codefence(data + beg, size - beg, &fence_trail);+ if (fence_end != 0 && fence_trail.size == 0) { beg += fence_end; break; }@@ -1577,8 +1625,7 @@ { struct buf *work = 0, *inter = 0; size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;- int in_empty = 0, has_inside_empty = 0;- size_t has_next_uli, has_next_oli;+ int in_empty = 0, has_inside_empty = 0, in_fence = 0; /* keeping track of the first indentation prefix */ while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')@@ -1606,6 +1653,8 @@ /* process the following lines */ while (beg < size) {+ size_t has_next_uli = 0, has_next_oli = 0;+ end++; while (end < size && data[end - 1] != '\n')@@ -1625,9 +1674,18 @@ pre = i; - has_next_uli = prefix_uli(data + beg + i, end - beg - i);- has_next_oli = prefix_oli(data + beg + i, end - beg - i);+ if (rndr->ext_flags & MKDEXT_FENCED_CODE) {+ if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)+ in_fence = !in_fence;+ } + /* Only check for new list items if we are **not** inside+ * a fenced code block */+ if (!in_fence) {+ has_next_uli = prefix_uli(data + beg + i, end - beg - i);+ has_next_oli = prefix_oli(data + beg + i, end - beg - i);+ }+ /* checking for ul/ol switch */ if (in_empty && ( ((*flags & MKD_LIST_ORDERED) && has_next_uli) ||@@ -1647,10 +1705,12 @@ if (!sublist) sublist = work->size; }- /* joining only indented stuff after empty lines */- else if (in_empty && i < 4) {- *flags |= MKD_LI_END;- break;+ /* joining only indented stuff after empty lines;+ * note that now we only require 1 space of indentation+ * to continue a list */+ else if (in_empty && pre == 0) {+ *flags |= MKD_LI_END;+ break; } else if (in_empty) { bufputc(work, '\n');@@ -1758,7 +1818,12 @@ /* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */ /* returns the length on match, 0 otherwise */ static size_t-htmlblock_end(const char *tag, size_t tag_len, struct sd_markdown *rndr, uint8_t *data, size_t size)+htmlblock_end_tag(+ const char *tag,+ size_t tag_len,+ struct sd_markdown *rndr,+ uint8_t *data,+ size_t size) { size_t i, w; @@ -1776,25 +1841,60 @@ i += w; w = 0; - if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) {- if (i < size)- w = is_empty(data + i, size - i);- } else {- if (i < size && (w = is_empty(data + i, size - i)) == 0)- return 0; /* non-blank line after tag line */- }+ if (i < size)+ w = is_empty(data + i, size - i); return i + w; } +static size_t+htmlblock_end(const char *curtag,+ struct sd_markdown *rndr,+ uint8_t *data,+ size_t size,+ int start_of_line)+{+ size_t tag_size = strlen(curtag);+ size_t i = 1, end_tag;+ int block_lines = 0; + while (i < size) {+ i++;+ while (i < size && !(data[i - 1] == '<' && data[i] == '/')) {+ if (data[i] == '\n')+ block_lines++;++ i++;+ }++ /* If we are only looking for unindented tags, skip the tag+ * if it doesn't follow a newline.+ *+ * The only exception to this is if the tag is still on the+ * initial line; in that case it still counts as a closing+ * tag+ */+ if (start_of_line && block_lines > 0 && data[i - 2] != '\n')+ continue;++ if (i + 2 + tag_size >= size)+ break;++ end_tag = htmlblock_end_tag(curtag, tag_size, rndr, data + i - 1, size - i + 1);+ if (end_tag)+ return i + end_tag - 1;+ }++ return 0;+}++ /* parse_htmlblock • parsing of inline HTML block */ static size_t parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render) {- size_t i, j = 0;+ size_t i, j = 0, tag_end; const char *curtag = NULL;- int found; struct buf work = { data, 0, 0, 0 }; /* identification of the opening tag */@@ -1855,40 +1955,23 @@ /* looking for an unindented matching closing tag */ /* followed by a blank line */- i = 1;- found = 0;+ tag_end = htmlblock_end(curtag, rndr, data, size, 1); /* if not found, trying a second pass looking for indented match */ /* but not if tag is "ins" or "del" (following original Markdown.pl) */- if (strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {- size_t tag_size = strlen(curtag);- i = 1;- while (i < size) {- i++;- while (i < size && !(data[i - 1] == '<' && data[i] == '/'))- i++;-- if (i + 2 + tag_size >= size)- break;-- j = htmlblock_end(curtag, tag_size, rndr, data + i - 1, size - i + 1);-- if (j) {- i += j - 1;- found = 1;- break;- }- }+ if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) {+ tag_end = htmlblock_end(curtag, rndr, data, size, 0); } - if (!found) return 0;+ if (!tag_end)+ return 0; /* the end of the block has been found */- work.size = i;+ work.size = tag_end; if (do_render && rndr->cb.blockhtml) rndr->cb.blockhtml(ob, &work, rndr->opaque); - return i;+ return tag_end; } static void@@ -1970,10 +2053,13 @@ header_end = i; + while (header_end > 0 && _isspace(data[header_end - 1]))+ header_end--;+ if (data[0] == '|') pipes--; - if (i > 2 && data[i - 1] == '|')+ if (header_end && data[header_end - 1] == '|') pipes--; *columns = pipes + 1;@@ -2247,8 +2333,8 @@ line_end = title_end; title_end = i; } } - if (!line_end)- return 0; /* garbage after the link */+ if (!line_end || link_end == link_offset)+ return 0; /* garbage after the link empty link */ /* a valid ref has been found, filling-in return structures */ if (last)@@ -2258,6 +2344,8 @@ struct link_ref *ref; ref = add_link_ref(refs, data + id_offset, id_end - id_offset);+ if (!ref)+ return 0; ref->link = bufnew(link_end - link_offset); bufput(ref->link, data + link_offset, link_end - link_offset);@@ -2455,9 +2543,9 @@ void sd_version(int *ver_major, int *ver_minor, int *ver_revision) {- *ver_major = UPSKIRT_VER_MAJOR;- *ver_minor = UPSKIRT_VER_MINOR;- *ver_revision = UPSKIRT_VER_REVISION;+ *ver_major = SUNDOWN_VER_MAJOR;+ *ver_minor = SUNDOWN_VER_MINOR;+ *ver_revision = SUNDOWN_VER_REVISION; } /* vim: set filetype=c: */
cbits/markdown.h view
@@ -22,11 +22,15 @@ #include "buffer.h" #include "autolink.h" -#define UPSKIRT_VERSION "1.15.2"-#define UPSKIRT_VER_MAJOR 1-#define UPSKIRT_VER_MINOR 15-#define UPSKIRT_VER_REVISION 2+#ifdef __cplusplus+extern "C" {+#endif +#define SUNDOWN_VERSION "1.16.0"+#define SUNDOWN_VER_MAJOR 1+#define SUNDOWN_VER_MINOR 16+#define SUNDOWN_VER_REVISION 0+ /******************** * TYPE DEFINITIONS * ********************/@@ -52,9 +56,9 @@ MKDEXT_FENCED_CODE = (1 << 2), MKDEXT_AUTOLINK = (1 << 3), MKDEXT_STRIKETHROUGH = (1 << 4),- MKDEXT_LAX_HTML_BLOCKS = (1 << 5), MKDEXT_SPACE_HEADERS = (1 << 6), MKDEXT_SUPERSCRIPT = (1 << 7),+ MKDEXT_LAX_SPACING = (1 << 8), }; /* sd_callbacks - functions for rendering parsed data */@@ -124,6 +128,10 @@ extern void sd_version(int *major, int *minor, int *revision);++#ifdef __cplusplus+}+#endif #endif
cbits/stack.h view
@@ -3,6 +3,10 @@ #include <stdlib.h> +#ifdef __cplusplus+extern "C" {+#endif+ struct stack { void **item; size_t size;@@ -17,5 +21,9 @@ void *stack_pop(struct stack *); void *stack_top(struct stack *);++#ifdef __cplusplus+}+#endif #endif
src/Text/Sundown/Markdown/Foreign.hsc view
@@ -17,22 +17,23 @@ #include "markdown.h" -- | A set of switches to enable or disable markdown features.-data Extensions = Extensions { extNoIntraEmphasis :: Bool -- ^ Turn off underscores insode a word- -- does designating emphasis.- , extTables :: Bool- , extFencedCode :: Bool -- ^ Turns on a non-indentation form of- -- code-blocks, by blocking off a regionwith ~- -- or \`.- , extAutolink :: Bool -- ^ Turn things that look like URLs and email- -- addresses into links- , extStrikethrough :: Bool -- ^ Surround text with `~` to designate it- -- as struck through- , extLaxHtmlBlocks :: Bool -- ^ Allow HTML markup inside of paragraphs,- -- instead requireing tags to be on separate- -- lines- , extSpaceHeaders :: Bool- , extSuperscript :: Bool- }+data Extensions = Extensions+ { extNoIntraEmphasis :: Bool+ -- ^ Turn off underscores insode a word does designating emphasis.+ , extTables :: Bool+ , extFencedCode :: Bool+ -- ^ Turns on a non-indentation form of code-blocks, by blocking off a+ -- regionwith ~ or \`.+ , extAutolink :: Bool+ -- ^ Turn things that look like URLs and email addresses into links+ , extStrikethrough :: Bool+ -- ^ Surround text with `~` to designate it as struck through+ , extSpaceHeaders :: Bool+ , extSuperscript :: Bool+ , extLaxSpacing :: Bool+ -- ^ Allow blocks inside of paragraphs, instead requireing tags to be on+ -- separate lines+ } instance Flag Extensions where flagIndexes exts = [ (#{const MKDEXT_NO_INTRA_EMPHASIS}, extNoIntraEmphasis exts)@@ -40,9 +41,9 @@ , (#{const MKDEXT_FENCED_CODE}, extFencedCode exts) , (#{const MKDEXT_AUTOLINK}, extAutolink exts) , (#{const MKDEXT_STRIKETHROUGH}, extStrikethrough exts)- , (#{const MKDEXT_LAX_HTML_BLOCKS}, extLaxHtmlBlocks exts) , (#{const MKDEXT_SPACE_HEADERS}, extSpaceHeaders exts) , (#{const MKDEXT_SUPERSCRIPT}, extSuperscript exts)+ , (#{const MKDEXT_LAX_SPACING}, extLaxSpacing exts) ]
sundown.cabal view
@@ -1,49 +1,47 @@-Cabal-version: >= 1.6-Name: sundown-Version: 0.4.1.2-Author: Francesco Mazzoli (f@mazzo.li)-Maintainer: Francesco Mazzoli (f@mazzo.li)-Build-Type: Simple-License: PublicDomain-Build-Type: Simple-Category: Foreign binding, Text-Synopsis: Bindings to the sundown markdown library-Tested-With: GHC==7.2.2-Homepage: https://github.com/bitonic/sundown-Bug-Reports: https://github.com/bitonic/sundown/issues+Cabal-version: >= 1.6+Name: sundown+Version: 0.4.2+Author: Francesco Mazzoli (f@mazzo.li)+Maintainer: Francesco Mazzoli (f@mazzo.li)+Build-Type: Simple+License: PublicDomain+Build-Type: Simple+Category: Foreign binding, Text+Synopsis: Bindings to the sundown markdown library+Tested-With: GHC==7.4.2, GHC==7.2.2, GHC==7.0.4, GHC==6.12.3+Homepage: https://github.com/bitonic/sundown+Bug-Reports: https://github.com/bitonic/sundown/issues Description:- Bindings to the github fork of sundown, a nice C markdown library:- <https://github.com/tanoku/sundown>+ Bindings to GitHub's C markdown library: <https://github.com/tanoku/sundown> source-repository head type: git location: git://github.com/bitonic/sundown.git Library- Hs-Source-Dirs: src-- Build-Depends: base >= 3 && < 5- , bytestring-- GHC-Options: -Wall -O2 -fno-cse-- Extensions: ForeignFunctionInterface, EmptyDataDecls+ Hs-Source-Dirs: src+ Build-Depends: base >= 3 && < 5, bytestring+ GHC-Options: -Wall -O2 -fno-cse+ Extensions: ForeignFunctionInterface, EmptyDataDecls - Exposed-Modules: Text.Sundown- , Text.Sundown.Markdown- , Text.Sundown.Renderers.Html+ Exposed-Modules: Text.Sundown,+ Text.Sundown.Markdown,+ Text.Sundown.Renderers.Html - Other-Modules: Text.Sundown.Buffer.Foreign- , Text.Sundown.Renderers.Html.Foreign- , Text.Sundown.Flag- , Text.Sundown.Markdown.Foreign+ Other-Modules: Text.Sundown.Buffer.Foreign,+ Text.Sundown.Renderers.Html.Foreign,+ Text.Sundown.Flag,+ Text.Sundown.Markdown.Foreign - C-Sources: cbits/autolink.c, cbits/buffer.c, cbits/houdini_href_e.c,- cbits/houdini_html_e.c, cbits/html.c, cbits/html_smartypants.c,- cbits/markdown.c, cbits/stack.c+ C-Sources: cbits/autolink.c, cbits/buffer.c,+ cbits/houdini_href_e.c, cbits/houdini_html_e.c,+ cbits/html.c, cbits/html_smartypants.c,+ cbits/markdown.c, cbits/stack.c - Include-Dirs: cbits+ Include-Dirs: cbits - Includes: autolink.h, buffer.h, html.h, html_blocks.h, markdown.h, stack.h+ Includes: autolink.h, buffer.h, html.h, html_blocks.h, markdown.h,+ stack.h - Install-includes: autolink.h, buffer.h, houdini.h, html.h, html_blocks.h, markdown.h, stack.h+ Install-includes: autolink.h, buffer.h, houdini.h, html.h, html_blocks.h,+ markdown.h, stack.h