Skip to content
Browse files

Merge remote-tracking branch 'x3ro/update-sundown'

  • Loading branch information...
2 parents 624e5cb + 25bed5a commit c2ed450a68b50b1350ee21507bddf7e140b30018 @vmg committed Oct 10, 2012
View
1 .gitignore
@@ -0,0 +1 @@
+lib/redcarpet.bundle
View
2 .travis.yml
@@ -6,7 +6,5 @@ rvm:
- ruby-head
- ree
-gemfile: Gemfile.ci
-
notifications:
email: false
View
2 Gemfile
@@ -0,0 +1,2 @@
+source :rubygems
+gemspec
View
3 Gemfile.ci
@@ -1,3 +0,0 @@
-source "http://rubygems.org"
-gem "nokogiri"
-gem "rake-compiler"
View
20 Gemfile.lock
@@ -0,0 +1,20 @@
+PATH
+ remote: .
+ specs:
+ redcarpet (2.1.1)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ nokogiri (1.5.5)
+ rake (0.9.2.2)
+ rake-compiler (0.8.1)
+ rake
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ nokogiri
+ rake-compiler
+ redcarpet!
View
12 README.markdown
@@ -9,14 +9,14 @@ case since version 2 -- it now has its own API, but retains the old name. Yes,
that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
versions.
-Redcarpet is powered by the [Sundown](https://www.github.com/tanoku/sundown)
+Redcarpet is powered by the [Sundown](https://www.github.com/vmg/sundown)
library. You might want to find out more about Sundown to see what makes this
Ruby library so awesome.
This library is written by people
-------------------------------------------------------
-Redcarpet 2 has been rewritten from scratch by Vicent Martí (@tanoku). Why
+Redcarpet 2 has been rewritten from scratch by Vicent Martí (@vmg). Why
are you not following me on Twitter?
Redcarpet would not be possible without the Sundown library and its authors
@@ -32,7 +32,7 @@ extensions, but the parser is standalone and requires no installed libraries.
The Redcarpet source (including Sundown as a submodule) is available at GitHub:
- $ git clone git://github.com/tanoku/redcarpet.git
+ $ git clone git://github.com/vmg/redcarpet.git
And it's like *really* simple to use
------------------------------------
@@ -78,7 +78,7 @@ settings, and reused between parses.
Two `~` characters mark the start of a strikethrough,
e.g. `this is ~~good~~ bad`
- :lax_html_blocks - HTML blocks do not require to be surrounded
+ :lax_spacing - HTML blocks do not require to be surrounded
by an empty line as in the Markdown standard.
:space_after_headers - A space is always required between the
@@ -311,6 +311,10 @@ that's a maintance nightmare and won't work.
On a related topic: if your Markdown gem has a `lib/markdown.rb` file that
monkeypatches the Markdown class, you're a terrible human being. Just saying.
+Testing
+-------
+Tests run a lot faster without `bundle exec` :)
+
Boring legal stuff
------------------
View
264 ext/redcarpet/autolink.c
@@ -1,264 +0,0 @@
-/*
- * Copyright (c) 2011, Vicent Marti
- *
- * 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 "buffer.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)
-{
- static const size_t valid_uris_count = 5;
- static const char *valid_uris[] = {
- "/", "http://", "https://", "ftp://", "mailto:"
- };
-
- size_t i;
-
- for (i = 0; i < valid_uris_count; ++i) {
- size_t len = strlen(valid_uris[i]);
-
- if (link_len > len &&
- strncasecmp((char *)link, valid_uris[i], len) == 0 &&
- isalnum(link[len]))
- return 1;
- }
-
- return 0;
-}
-
-static size_t
-autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
-{
- uint8_t cclose, copen = 0;
- size_t i;
-
- for (i = 0; i < link_end; ++i)
- if (data[i] == '<') {
- link_end = i;
- break;
- }
-
- while (link_end > 0) {
- if (strchr("?!.,", data[link_end - 1]) != NULL)
- link_end--;
-
- else if (data[link_end - 1] == ';') {
- size_t new_end = link_end - 2;
-
- while (new_end > 0 && isalpha(data[new_end]))
- new_end--;
-
- if (new_end < link_end - 2 && data[new_end] == '&')
- link_end = new_end;
- else
- link_end--;
- }
- else break;
- }
-
- if (link_end == 0)
- return 0;
-
- cclose = data[link_end - 1];
-
- switch (cclose) {
- case '"': copen = '"'; break;
- case '\'': copen = '\''; break;
- case ')': copen = '('; break;
- case ']': copen = '['; break;
- case '}': copen = '{'; break;
- }
-
- if (copen != 0) {
- size_t closing = 0;
- size_t opening = 0;
- size_t i = 0;
-
- /* Try to close the final punctuation sign in this same line;
- * if we managed to close it outside of the URL, that means that it's
- * not part of the URL. If it closes inside the URL, that means it
- * is part of the URL.
- *
- * Examples:
- *
- * foo http://www.pokemon.com/Pikachu_(Electric) bar
- * => http://www.pokemon.com/Pikachu_(Electric)
- *
- * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
- * => http://www.pokemon.com/Pikachu_(Electric)
- *
- * foo http://www.pokemon.com/Pikachu_(Electric)) bar
- * => http://www.pokemon.com/Pikachu_(Electric))
- *
- * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
- * => foo http://www.pokemon.com/Pikachu_(Electric)
- */
-
- while (i < link_end) {
- if (data[i] == copen)
- opening++;
- else if (data[i] == cclose)
- closing++;
-
- i++;
- }
-
- if (closing != opening)
- link_end--;
- }
-
- return link_end;
-}
-
-static size_t
-check_domain(uint8_t *data, size_t size)
-{
- size_t i, np = 0;
-
- if (!isalnum(data[0]))
- return 0;
-
- for (i = 1; i < size - 1; ++i) {
- if (data[i] == '.') np++;
- 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;
-}
-
-size_t
-sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
-{
- 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);
-
- 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;
-}
-
-size_t
-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
-{
- size_t link_end, rewind;
- int nb = 0, np = 0;
-
- for (rewind = 0; rewind < offset; ++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, offset, size);
-
- if (link_end == 0)
- return 0;
-
- bufput(link, data - rewind, link_end + rewind);
- *rewind_p = rewind;
-
- return link_end;
-}
-
-size_t
-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
-{
- size_t link_end, rewind = 0, domain_len;
-
- if (size < 4 || data[1] != '/' || data[2] != '/')
- return 0;
-
- while (rewind < offset && isalpha(data[-rewind - 1]))
- rewind++;
-
- if (!sd_autolink_issafe(data - rewind, size + rewind))
- return 0;
- link_end = strlen("://");
-
- domain_len = check_domain(data + link_end, size - link_end);
- if (domain_len == 0)
- return 0;
-
- link_end += domain_len;
- 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 - rewind, link_end + rewind);
- *rewind_p = rewind;
-
- return link_end;
-}
-
View
1 ext/redcarpet/autolink.c
View
36 ext/redcarpet/autolink.h
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2011, Vicent Marti
- *
- * 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.
- */
-
-#ifndef UPSKIRT_AUTOLINK_H
-#define UPSKIRT_AUTOLINK_H
-
-#include "buffer.h"
-
-extern 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);
-
-extern size_t
-sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
-
-extern size_t
-sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
-
-#endif
-
-/* vim: set filetype=c: */
View
1 ext/redcarpet/autolink.h
View
223 ext/redcarpet/buffer.c
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2008, Natacha Porté
- * Copyright (c) 2011, Vicent Martí
- *
- * 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.
- */
-
-#define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb
-
-#include "buffer.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-/* MSVC compat */
-#if defined(_MSC_VER)
-# define _buf_vsnprintf _vsnprintf
-#else
-# define _buf_vsnprintf vsnprintf
-#endif
-
-int
-bufprefix(const struct buf *buf, const char *prefix)
-{
- size_t i;
- assert(buf && buf->unit);
-
- for (i = 0; i < buf->size; ++i) {
- if (prefix[i] == 0)
- return 0;
-
- if (buf->data[i] != prefix[i])
- return buf->data[i] - prefix[i];
- }
-
- return 0;
-}
-
-/* bufgrow: increasing the allocated size to the given value */
-int
-bufgrow(struct buf *buf, size_t neosz)
-{
- size_t neoasz;
- void *neodata;
-
- assert(buf && buf->unit);
-
- if (neosz > BUFFER_MAX_ALLOC_SIZE)
- return BUF_ENOMEM;
-
- if (buf->asize >= neosz)
- return BUF_OK;
-
- neoasz = buf->asize + buf->unit;
- while (neoasz < neosz)
- neoasz += buf->unit;
-
- neodata = realloc(buf->data, neoasz);
- if (!neodata)
- return BUF_ENOMEM;
-
- buf->data = neodata;
- buf->asize = neoasz;
- return BUF_OK;
-}
-
-
-/* bufnew: allocation of a new buffer */
-struct buf *
-bufnew(size_t unit)
-{
- struct buf *ret;
- ret = malloc(sizeof (struct buf));
-
- if (ret) {
- ret->data = 0;
- ret->size = ret->asize = 0;
- ret->unit = unit;
- }
- return ret;
-}
-
-/* bufnullterm: NULL-termination of the string array */
-const char *
-bufcstr(struct buf *buf)
-{
- assert(buf && buf->unit);
-
- if (buf->size < buf->asize && buf->data[buf->size] == 0)
- return (char *)buf->data;
-
- if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) {
- buf->data[buf->size] = 0;
- return (char *)buf->data;
- }
-
- return NULL;
-}
-
-/* bufprintf: formatted printing to a buffer */
-void
-bufprintf(struct buf *buf, const char *fmt, ...)
-{
- va_list ap;
- int n;
-
- assert(buf && buf->unit);
-
- if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0)
- return;
-
- va_start(ap, fmt);
- n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
- va_end(ap);
-
- if (n < 0) {
-#ifdef _MSC_VER
- n = _vscprintf(fmt, ap);
-#else
- return;
-#endif
- }
-
- if ((size_t)n >= buf->asize - buf->size) {
- if (bufgrow(buf, buf->size + n + 1) < 0)
- return;
-
- va_start(ap, fmt);
- n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
- va_end(ap);
- }
-
- if (n < 0)
- return;
-
- buf->size += n;
-}
-
-/* bufput: appends raw data to a buffer */
-void
-bufput(struct buf *buf, const void *data, size_t len)
-{
- assert(buf && buf->unit);
-
- if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0)
- return;
-
- memcpy(buf->data + buf->size, data, len);
- buf->size += len;
-}
-
-/* bufputs: appends a NUL-terminated string to a buffer */
-void
-bufputs(struct buf *buf, const char *str)
-{
- bufput(buf, str, strlen(str));
-}
-
-
-/* bufputc: appends a single uint8_t to a buffer */
-void
-bufputc(struct buf *buf, int c)
-{
- assert(buf && buf->unit);
-
- if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0)
- return;
-
- buf->data[buf->size] = c;
- buf->size += 1;
-}
-
-/* bufrelease: decrease the reference count and free the buffer if needed */
-void
-bufrelease(struct buf *buf)
-{
- if (!buf)
- return;
-
- free(buf->data);
- free(buf);
-}
-
-
-/* bufreset: frees internal data of the buffer */
-void
-bufreset(struct buf *buf)
-{
- if (!buf)
- return;
-
- free(buf->data);
- buf->data = NULL;
- buf->size = buf->asize = 0;
-}
-
-/* bufslurp: removes a given number of bytes from the head of the array */
-void
-bufslurp(struct buf *buf, size_t len)
-{
- assert(buf && buf->unit);
-
- if (len >= buf->size) {
- buf->size = 0;
- return;
- }
-
- buf->size -= len;
- memmove(buf->data, buf->data + len, buf->size);
-}
-
View
1 ext/redcarpet/buffer.c
View
88 ext/redcarpet/buffer.h
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2008, Natacha Porté
- * Copyright (c) 2011, Vicent Martí
- *
- * 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.
- */
-
-#ifndef BUFFER_H__
-#define BUFFER_H__
-
-#include <stddef.h>
-#include <stdarg.h>
-#include <stdint.h>
-
-#if defined(_MSC_VER)
-#define __attribute__(x)
-#define inline
-#endif
-
-typedef enum {
- BUF_OK = 0,
- BUF_ENOMEM = -1,
-} buferror_t;
-
-/* struct buf: character array buffer */
-struct buf {
- uint8_t *data; /* actual character data */
- size_t size; /* size of the string */
- size_t asize; /* allocated size (0 = volatile buffer) */
- size_t unit; /* reallocation unit size (0 = read-only buffer) */
-};
-
-/* CONST_BUF: global buffer from a string litteral */
-#define BUF_STATIC(string) \
- { (uint8_t *)string, sizeof string -1, sizeof string, 0, 0 }
-
-/* VOLATILE_BUF: macro for creating a volatile buffer on the stack */
-#define BUF_VOLATILE(strname) \
- { (uint8_t *)strname, strlen(strname), 0, 0, 0 }
-
-/* BUFPUTSL: optimized bufputs of a string litteral */
-#define BUFPUTSL(output, literal) \
- bufput(output, literal, sizeof literal - 1)
-
-/* bufgrow: increasing the allocated size to the given value */
-int bufgrow(struct buf *, size_t);
-
-/* bufnew: allocation of a new buffer */
-struct buf *bufnew(size_t) __attribute__ ((malloc));
-
-/* bufnullterm: NUL-termination of the string array (making a C-string) */
-const char *bufcstr(struct buf *);
-
-/* bufprefix: compare the beginning of a buffer with a string */
-int bufprefix(const struct buf *buf, const char *prefix);
-
-/* bufput: appends raw data to a buffer */
-void bufput(struct buf *, const void *, size_t);
-
-/* bufputs: appends a NUL-terminated string to a buffer */
-void bufputs(struct buf *, const char *);
-
-/* bufputc: appends a single char to a buffer */
-void bufputc(struct buf *, int);
-
-/* bufrelease: decrease the reference count and free the buffer if needed */
-void bufrelease(struct buf *);
-
-/* bufreset: frees internal data of the buffer */
-void bufreset(struct buf *);
-
-/* bufslurp: removes a given number of bytes from the head of the array */
-void bufslurp(struct buf *, size_t);
-
-/* bufprintf: formatted printing to a buffer */
-void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
-
-#endif
View
1 ext/redcarpet/buffer.h
View
1 ext/redcarpet/html_blocks.h
View
206 ext/redcarpet/html_blocks.h
@@ -1,206 +0,0 @@
-/* C code produced by gperf version 3.0.3 */
-/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
-/* Computed positions: -k'1-2' */
-
-#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
- && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
- && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
- && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
- && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
- && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
- && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
- && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
- && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
- && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
- && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
- && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
- && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
- && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
- && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
- && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
- && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
- && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
- && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
- && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
- && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
- && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
- && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
-/* The character set is not based on ISO-646. */
-error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
-#endif
-
-/* maximum key range = 37, duplicates = 0 */
-
-#ifndef GPERF_DOWNCASE
-#define GPERF_DOWNCASE 1
-static unsigned char gperf_downcase[256] =
- {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
- 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
- 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
- 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
- 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
- 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
- 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
- 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
- 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
- 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
- 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
- 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
- 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
- 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
- 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
- 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
- 255
- };
-#endif
-
-#ifndef GPERF_CASE_STRNCMP
-#define GPERF_CASE_STRNCMP 1
-static int
-gperf_case_strncmp (s1, s2, n)
- register const char *s1;
- register const char *s2;
- register unsigned int n;
-{
- for (; n > 0;)
- {
- unsigned char c1 = gperf_downcase[(unsigned char)*s1++];
- unsigned char c2 = gperf_downcase[(unsigned char)*s2++];
- if (c1 != 0 && c1 == c2)
- {
- n--;
- continue;
- }
- return (int)c1 - (int)c2;
- }
- return 0;
-}
-#endif
-
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
-inline
-#endif
-#endif
-static unsigned int
-hash_block_tag (str, len)
- register const char *str;
- register unsigned int len;
-{
- static const unsigned char asso_values[] =
- {
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 8, 30, 25, 20, 15, 10, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 0, 38, 0, 38,
- 5, 5, 5, 15, 0, 38, 38, 0, 15, 10,
- 0, 38, 38, 15, 0, 5, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 0, 38,
- 0, 38, 5, 5, 5, 15, 0, 38, 38, 0,
- 15, 10, 0, 38, 38, 15, 0, 5, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38
- };
- register int hval = len;
-
- switch (hval)
- {
- default:
- hval += asso_values[(unsigned char)str[1]+1];
- /*FALLTHROUGH*/
- case 1:
- hval += asso_values[(unsigned char)str[0]];
- break;
- }
- return hval;
-}
-
-#ifdef __GNUC__
-__inline
-#ifdef __GNUC_STDC_INLINE__
-__attribute__ ((__gnu_inline__))
-#endif
-#endif
-const char *
-find_block_tag (str, len)
- register const char *str;
- register unsigned int len;
-{
- enum
- {
- TOTAL_KEYWORDS = 24,
- MIN_WORD_LENGTH = 1,
- MAX_WORD_LENGTH = 10,
- MIN_HASH_VALUE = 1,
- MAX_HASH_VALUE = 37
- };
-
- static const char * const wordlist[] =
- {
- "",
- "p",
- "dl",
- "div",
- "math",
- "table",
- "",
- "ul",
- "del",
- "form",
- "blockquote",
- "figure",
- "ol",
- "fieldset",
- "",
- "h1",
- "",
- "h6",
- "pre",
- "", "",
- "script",
- "h5",
- "noscript",
- "",
- "style",
- "iframe",
- "h4",
- "ins",
- "", "", "",
- "h3",
- "", "", "", "",
- "h2"
- };
-
- if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
- {
- register int key = hash_block_tag (str, len);
-
- if (key <= MAX_HASH_VALUE && key >= 0)
- {
- register const char *s = wordlist[key];
-
- if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0')
- return s;
- }
- }
- return 0;
-}
View
2,505 ext/redcarpet/markdown.c
@@ -1,2505 +0,0 @@
-/* markdown.c - generic markdown parser */
-
-/*
- * Copyright (c) 2009, Natacha Porté
- * Copyright (c) 2011, Vicent Marti
- *
- * 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 "markdown.h"
-#include "stack.h"
-
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
-
-#if defined(_WIN32)
-#define strncasecmp _strnicmp
-#endif
-
-#define REF_TABLE_SIZE 8
-
-#define BUFFER_BLOCK 0
-#define BUFFER_SPAN 1
-
-#define MKD_LI_END 8 /* internal list flag */
-
-#define gperf_case_strncmp(s1, s2, n) strncasecmp(s1, s2, n)
-#define GPERF_DOWNCASE 1
-#define GPERF_CASE_STRNCMP 1
-#include "html_blocks.h"
-
-/***************
- * LOCAL TYPES *
- ***************/
-
-/* link_ref: reference to a link */
-struct link_ref {
- unsigned int id;
-
- struct buf *link;
- struct buf *title;
-
- struct link_ref *next;
-};
-
-/* char_trigger: function pointer to render active chars */
-/* returns the number of chars taken care of */
-/* data is the pointer of the beginning of the span */
-/* offset is the number of valid chars before data */
-struct sd_markdown;
-typedef size_t
-(*char_trigger)(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-
-static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-static size_t char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
-
-enum markdown_char_t {
- MD_CHAR_NONE = 0,
- MD_CHAR_EMPHASIS,
- MD_CHAR_CODESPAN,
- MD_CHAR_LINEBREAK,
- MD_CHAR_LINK,
- MD_CHAR_LANGLE,
- MD_CHAR_ESCAPE,
- MD_CHAR_ENTITITY,
- MD_CHAR_AUTOLINK_URL,
- MD_CHAR_AUTOLINK_EMAIL,
- MD_CHAR_AUTOLINK_WWW,
- MD_CHAR_SUPERSCRIPT,
-};
-
-static char_trigger markdown_char_ptrs[] = {
- NULL,
- &char_emphasis,
- &char_codespan,
- &char_linebreak,
- &char_link,
- &char_langle_tag,
- &char_escape,
- &char_entity,
- &char_autolink_url,
- &char_autolink_email,
- &char_autolink_www,
- &char_superscript,
-};
-
-/* render • structure containing one particular render */
-struct sd_markdown {
- struct sd_callbacks cb;
- void *opaque;
-
- struct link_ref *refs[REF_TABLE_SIZE];
- uint8_t active_char[256];
- struct stack work_bufs[2];
- unsigned int ext_flags;
- size_t max_nesting;
- int in_link_body;
-};
-
-/***************************
- * HELPER FUNCTIONS *
- ***************************/
-
-static inline struct buf *
-rndr_newbuf(struct sd_markdown *rndr, int type)
-{
- static const size_t buf_size[2] = {256, 64};
- struct buf *work = NULL;
- struct stack *pool = &rndr->work_bufs[type];
-
- if (pool->size < pool->asize &&
- pool->item[pool->size] != NULL) {
- work = pool->item[pool->size++];
- work->size = 0;
- } else {
- work = bufnew(buf_size[type]);
- stack_push(pool, work);
- }
-
- return work;
-}
-
-static inline void
-rndr_popbuf(struct sd_markdown *rndr, int type)
-{
- rndr->work_bufs[type].size--;
-}
-
-static void
-unscape_text(struct buf *ob, struct buf *src)
-{
- size_t i = 0, org;
- while (i < src->size) {
- org = i;
- while (i < src->size && src->data[i] != '\\')
- i++;
-
- if (i > org)
- bufput(ob, src->data + org, i - org);
-
- if (i + 1 >= src->size)
- break;
-
- bufputc(ob, src->data[i + 1]);
- i += 2;
- }
-}
-
-static unsigned int
-hash_link_ref(const uint8_t *link_ref, size_t length)
-{
- size_t i;
- unsigned int hash = 0;
-
- for (i = 0; i < length; ++i)
- hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash;
-
- return hash;
-}
-
-static struct link_ref *
-add_link_ref(
- struct link_ref **references,
- const uint8_t *name, size_t name_size)
-{
- struct link_ref *ref = calloc(1, sizeof(struct link_ref));
-
- if (!ref)
- return NULL;
-
- ref->id = hash_link_ref(name, name_size);
- ref->next = references[ref->id % REF_TABLE_SIZE];
-
- references[ref->id % REF_TABLE_SIZE] = ref;
- return ref;
-}
-
-static struct link_ref *
-find_link_ref(struct link_ref **references, uint8_t *name, size_t length)
-{
- unsigned int hash = hash_link_ref(name, length);
- struct link_ref *ref = NULL;
-
- ref = references[hash % REF_TABLE_SIZE];
-
- while (ref != NULL) {
- if (ref->id == hash)
- return ref;
-
- ref = ref->next;
- }
-
- return NULL;
-}
-
-static void
-free_link_refs(struct link_ref **references)
-{
- size_t i;
-
- for (i = 0; i < REF_TABLE_SIZE; ++i) {
- struct link_ref *r = references[i];
- struct link_ref *next;
-
- while (r) {
- next = r->next;
- bufrelease(r->link);
- bufrelease(r->title);
- free(r);
- r = next;
- }
- }
-}
-
-/*
- * Check whether a char is a Markdown space.
-
- * Right now we only consider spaces the actual
- * space and a newline: tabs and carriage returns
- * are filtered out during the preprocessing phase.
- *
- * If we wanted to actually be UTF-8 compliant, we
- * should instead extract an Unicode codepoint from
- * this character and check for space properties.
- */
-static inline int
-_isspace(int c)
-{
- return c == ' ' || c == '\n';
-}
-
-/****************************
- * INLINE PARSING FUNCTIONS *
- ****************************/
-
-/* is_mail_autolink • looks for the address part of a mail autolink and '>' */
-/* this is less strict than the original markdown e-mail address matching */
-static size_t
-is_mail_autolink(uint8_t *data, size_t size)
-{
- size_t i = 0, nb = 0;
-
- /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */
- for (i = 0; i < size; ++i) {
- if (isalnum(data[i]))
- continue;
-
- switch (data[i]) {
- case '@':
- nb++;
-
- case '-':
- case '.':
- case '_':
- break;
-
- case '>':
- return (nb == 1) ? i + 1 : 0;
-
- default:
- return 0;
- }
- }
-
- return 0;
-}
-
-/* tag_length • returns the length of the given tag, or 0 is it's not valid */
-static size_t
-tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink)
-{
- size_t i, j;
-
- /* a valid tag can't be shorter than 3 chars */
- if (size < 3) return 0;
-
- /* begins with a '<' optionally followed by '/', followed by letter or number */
- if (data[0] != '<') return 0;
- i = (data[1] == '/') ? 2 : 1;
-
- if (!isalnum(data[i]))
- return 0;
-
- /* scheme test */
- *autolink = MKDA_NOT_AUTOLINK;
-
- /* try to find the beginning of an URI */
- while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-'))
- i++;
-
- if (i > 1 && data[i] == '@') {
- if ((j = is_mail_autolink(data + i, size - i)) != 0) {
- *autolink = MKDA_EMAIL;
- return i + j;
- }
- }
-
- if (i > 2 && data[i] == ':') {
- *autolink = MKDA_NORMAL;
- i++;
- }
-
- /* completing autolink test: no whitespace or ' or " */
- if (i >= size)
- *autolink = MKDA_NOT_AUTOLINK;
-
- else if (*autolink) {
- j = i;
-
- while (i < size) {
- if (data[i] == '\\') i += 2;
- else if (data[i] == '>' || data[i] == '\'' ||
- data[i] == '"' || data[i] == ' ' || data[i] == '\n')
- break;
- else i++;
- }
-
- if (i >= size) return 0;
- if (i > j && data[i] == '>') return i + 1;
- /* one of the forbidden chars has been found */
- *autolink = MKDA_NOT_AUTOLINK;
- }
-
- /* looking for sometinhg looking like a tag end */
- while (i < size && data[i] != '>') i++;
- if (i >= size) return 0;
- return i + 1;
-}
-
-/* parse_inline • parses inline markdown elements */
-static void
-parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
-{
- size_t i = 0, end = 0;
- uint8_t action = 0;
- struct buf work = { 0, 0, 0, 0 };
-
- if (rndr->work_bufs[BUFFER_SPAN].size +
- rndr->work_bufs[BUFFER_BLOCK].size > rndr->max_nesting)
- return;
-
- while (i < size) {
- /* copying inactive chars into the output */
- while (end < size && (action = rndr->active_char[data[end]]) == 0) {
- end++;
- }
-
- if (rndr->cb.normal_text) {
- work.data = data + i;
- work.size = end - i;
- rndr->cb.normal_text(ob, &work, rndr->opaque);
- }
- else
- bufput(ob, data + i, end - i);
-
- if (end >= size) break;
- i = end;
-
- end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i);
- if (!end) /* no action from the callback */
- end = i + 1;
- else {
- i += end;
- end = i;
- }
- }
-}
-
-/* find_emph_char • looks for the next emph uint8_t, skipping other constructs */
-static size_t
-find_emph_char(uint8_t *data, size_t size, uint8_t c)
-{
- size_t i = 1;
-
- while (i < size) {
- while (i < size && data[i] != c && data[i] != '`' && data[i] != '[')
- i++;
-
- if (i == size)
- return 0;
-
- if (data[i] == c)
- return i;
-
- /* not counting escaped chars */
- if (i && data[i - 1] == '\\') {
- i++; continue;
- }
-
- if (data[i] == '`') {
- size_t span_nb = 0, bt;
- size_t tmp_i = 0;
-
- /* counting the number of opening backticks */
- while (i < size && data[i] == '`') {
- i++; span_nb++;
- }
-
- if (i >= size) return 0;
-
- /* finding the matching closing sequence */
- bt = 0;
- while (i < size && bt < span_nb) {
- if (!tmp_i && data[i] == c) tmp_i = i;
- if (data[i] == '`') bt++;
- else bt = 0;
- i++;
- }
-
- if (i >= size) return tmp_i;
- }
- /* skipping a link */
- else if (data[i] == '[') {
- size_t tmp_i = 0;
- uint8_t cc;
-
- i++;
- while (i < size && data[i] != ']') {
- if (!tmp_i && data[i] == c) tmp_i = i;
- i++;
- }
-
- i++;
- while (i < size && (data[i] == ' ' || data[i] == '\n'))
- i++;
-
- if (i >= size)
- return tmp_i;
-
- switch (data[i]) {
- case '[':
- cc = ']'; break;
-
- case '(':
- cc = ')'; break;
-
- default:
- if (tmp_i)
- return tmp_i;
- else
- continue;
- }
-
- i++;
- while (i < size && data[i] != cc) {
- if (!tmp_i && data[i] == c) tmp_i = i;
- i++;
- }
-
- if (i >= size)
- return tmp_i;
-
- i++;
- }
- }
-
- return 0;
-}
-
-/* parse_emph1 • parsing single emphase */
-/* closed by a symbol not preceded by whitespace and not followed by symbol */
-static size_t
-parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c)
-{
- size_t i = 0, len;
- struct buf *work = 0;
- int r;
-
- if (!rndr->cb.emphasis) return 0;
-
- /* skipping one symbol if coming from emph3 */
- if (size > 1 && data[0] == c && data[1] == c) i = 1;
-
- while (i < size) {
- len = find_emph_char(data + i, size - i, c);
- if (!len) return 0;
- i += len;
- if (i >= size) return 0;
-
- if (data[i] == c && !_isspace(data[i - 1])) {
-
- if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
- if (!(i + 1 == size || _isspace(data[i + 1]) || ispunct(data[i + 1])))
- continue;
- }
-
- work = rndr_newbuf(rndr, BUFFER_SPAN);
- parse_inline(work, rndr, data, i);
- r = rndr->cb.emphasis(ob, work, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
- return r ? i + 1 : 0;
- }
- }
-
- return 0;
-}
-
-/* parse_emph2 • parsing single emphase */
-static size_t
-parse_emph2(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c)
-{
- int (*render_method)(struct buf *ob, const struct buf *text, void *opaque);
- size_t i = 0, len;
- struct buf *work = 0;
- int r;
-
- render_method = (c == '~') ? rndr->cb.strikethrough : rndr->cb.double_emphasis;
-
- if (!render_method)
- return 0;
-
- while (i < size) {
- len = find_emph_char(data + i, size - i, c);
- if (!len) return 0;
- i += len;
-
- if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) {
- work = rndr_newbuf(rndr, BUFFER_SPAN);
- parse_inline(work, rndr, data, i);
- r = render_method(ob, work, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
- return r ? i + 2 : 0;
- }
- i++;
- }
- return 0;
-}
-
-/* parse_emph3 • parsing single emphase */
-/* finds the first closing tag, and delegates to the other emph */
-static size_t
-parse_emph3(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, uint8_t c)
-{
- size_t i = 0, len;
- int r;
-
- while (i < size) {
- len = find_emph_char(data + i, size - i, c);
- if (!len) return 0;
- i += len;
-
- /* skip whitespace preceded symbols */
- if (data[i] != c || _isspace(data[i - 1]))
- continue;
-
- if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->cb.triple_emphasis) {
- /* triple symbol found */
- struct buf *work = rndr_newbuf(rndr, BUFFER_SPAN);
-
- parse_inline(work, rndr, data, i);
- r = rndr->cb.triple_emphasis(ob, work, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
- return r ? i + 3 : 0;
-
- } else if (i + 1 < size && data[i + 1] == c) {
- /* double symbol found, handing over to emph1 */
- len = parse_emph1(ob, rndr, data - 2, size + 2, c);
- if (!len) return 0;
- else return len - 2;
-
- } else {
- /* single symbol found, handing over to emph2 */
- len = parse_emph2(ob, rndr, data - 1, size + 1, c);
- if (!len) return 0;
- else return len - 1;
- }
- }
- return 0;
-}
-
-/* char_emphasis • single and double emphasis parsing */
-static size_t
-char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- uint8_t c = data[0];
- size_t ret;
-
- if (size > 2 && data[1] != c) {
- /* whitespace cannot follow an opening emphasis;
- * strikethrough only takes two characters '~~' */
- if (c == '~' || _isspace(data[1]) || (ret = parse_emph1(ob, rndr, data + 1, size - 1, c)) == 0)
- return 0;
-
- return ret + 1;
- }
-
- if (size > 3 && data[1] == c && data[2] != c) {
- if (_isspace(data[2]) || (ret = parse_emph2(ob, rndr, data + 2, size - 2, c)) == 0)
- return 0;
-
- return ret + 2;
- }
-
- if (size > 4 && data[1] == c && data[2] == c && data[3] != c) {
- if (c == '~' || _isspace(data[3]) || (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0)
- return 0;
-
- return ret + 3;
- }
-
- return 0;
-}
-
-
-/* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */
-static size_t
-char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- if (offset < 2 || data[-1] != ' ' || data[-2] != ' ')
- return 0;
-
- /* removing the last space from ob and rendering */
- while (ob->size && ob->data[ob->size - 1] == ' ')
- ob->size--;
-
- return rndr->cb.linebreak(ob, rndr->opaque) ? 1 : 0;
-}
-
-
-/* char_codespan • '`' parsing a code span (assuming codespan != 0) */
-static size_t
-char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- size_t end, nb = 0, i, f_begin, f_end;
-
- /* counting the number of backticks in the delimiter */
- while (nb < size && data[nb] == '`')
- nb++;
-
- /* finding the next delimiter */
- i = 0;
- for (end = nb; end < size && i < nb; end++) {
- if (data[end] == '`') i++;
- else i = 0;
- }
-
- if (i < nb && end >= size)
- return 0; /* no matching delimiter */
-
- /* trimming outside whitespaces */
- f_begin = nb;
- while (f_begin < end && data[f_begin] == ' ')
- f_begin++;
-
- f_end = end - nb;
- while (f_end > nb && data[f_end-1] == ' ')
- f_end--;
-
- /* real code span */
- if (f_begin < f_end) {
- struct buf work = { data + f_begin, f_end - f_begin, 0, 0 };
- if (!rndr->cb.codespan(ob, &work, rndr->opaque))
- end = 0;
- } else {
- if (!rndr->cb.codespan(ob, 0, rndr->opaque))
- end = 0;
- }
-
- return end;
-}
-
-
-/* char_escape • '\\' backslash escape */
-static size_t
-char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~";
- struct buf work = { 0, 0, 0, 0 };
-
- if (size > 1) {
- if (strchr(escape_chars, data[1]) == NULL)
- return 0;
-
- if (rndr->cb.normal_text) {
- work.data = data + 1;
- work.size = 1;
- rndr->cb.normal_text(ob, &work, rndr->opaque);
- }
- else bufputc(ob, data[1]);
- } else if (size == 1) {
- bufputc(ob, data[0]);
- }
-
- return 2;
-}
-
-/* char_entity • '&' escaped when it doesn't belong to an entity */
-/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */
-static size_t
-char_entity(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- size_t end = 1;
- struct buf work = { 0, 0, 0, 0 };
-
- if (end < size && data[end] == '#')
- end++;
-
- while (end < size && isalnum(data[end]))
- end++;
-
- if (end < size && data[end] == ';')
- end++; /* real entity */
- else
- return 0; /* lone '&' */
-
- if (rndr->cb.entity) {
- work.data = data;
- work.size = end;
- rndr->cb.entity(ob, &work, rndr->opaque);
- }
- else bufput(ob, data, end);
-
- return end;
-}
-
-/* char_langle_tag • '<' when tags or autolinks are allowed */
-static size_t
-char_langle_tag(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- enum mkd_autolink altype = MKDA_NOT_AUTOLINK;
- size_t end = tag_length(data, size, &altype);
- struct buf work = { data, end, 0, 0 };
- int ret = 0;
-
- if (end > 2) {
- if (rndr->cb.autolink && altype != MKDA_NOT_AUTOLINK) {
- struct buf *u_link = rndr_newbuf(rndr, BUFFER_SPAN);
- work.data = data + 1;
- work.size = end - 2;
- unscape_text(u_link, &work);
- ret = rndr->cb.autolink(ob, u_link, altype, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
- }
- else if (rndr->cb.raw_html_tag)
- ret = rndr->cb.raw_html_tag(ob, &work, rndr->opaque);
- }
-
- if (!ret) return 0;
- else return end;
-}
-
-static size_t
-char_autolink_www(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- struct buf *link, *link_url, *link_text;
- size_t link_len, rewind;
-
- if (!rndr->cb.link || rndr->in_link_body)
- return 0;
-
- link = rndr_newbuf(rndr, BUFFER_SPAN);
-
- if ((link_len = sd_autolink__www(&rewind, link, data, offset, size)) > 0) {
- link_url = rndr_newbuf(rndr, BUFFER_SPAN);
- BUFPUTSL(link_url, "http://");
- bufput(link_url, link->data, link->size);
-
- ob->size -= rewind;
- if (rndr->cb.normal_text) {
- link_text = rndr_newbuf(rndr, BUFFER_SPAN);
- rndr->cb.normal_text(link_text, link, rndr->opaque);
- rndr->cb.link(ob, link_url, NULL, link_text, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
- } else {
- rndr->cb.link(ob, link_url, NULL, link, rndr->opaque);
- }
- rndr_popbuf(rndr, BUFFER_SPAN);
- }
-
- rndr_popbuf(rndr, BUFFER_SPAN);
- return link_len;
-}
-
-static size_t
-char_autolink_email(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- struct buf *link;
- size_t link_len, rewind;
-
- if (!rndr->cb.autolink || rndr->in_link_body)
- return 0;
-
- link = rndr_newbuf(rndr, BUFFER_SPAN);
-
- if ((link_len = sd_autolink__email(&rewind, link, data, offset, size)) > 0) {
- ob->size -= rewind;
- rndr->cb.autolink(ob, link, MKDA_EMAIL, rndr->opaque);
- }
-
- rndr_popbuf(rndr, BUFFER_SPAN);
- return link_len;
-}
-
-static size_t
-char_autolink_url(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- struct buf *link;
- size_t link_len, rewind;
-
- if (!rndr->cb.autolink || rndr->in_link_body)
- return 0;
-
- link = rndr_newbuf(rndr, BUFFER_SPAN);
-
- if ((link_len = sd_autolink__url(&rewind, link, data, offset, size)) > 0) {
- ob->size -= rewind;
- rndr->cb.autolink(ob, link, MKDA_NORMAL, rndr->opaque);
- }
-
- rndr_popbuf(rndr, BUFFER_SPAN);
- return link_len;
-}
-
-/* char_link • '[': parsing a link or an image */
-static size_t
-char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- int is_img = (offset && data[-1] == '!'), level;
- size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0;
- struct buf *content = 0;
- struct buf *link = 0;
- struct buf *title = 0;
- struct buf *u_link = 0;
- size_t org_work_size = rndr->work_bufs[BUFFER_SPAN].size;
- int text_has_nl = 0, ret = 0;
- int in_title = 0, qtype = 0;
-
- /* checking whether the correct renderer exists */
- if ((is_img && !rndr->cb.image) || (!is_img && !rndr->cb.link))
- goto cleanup;
-
- /* looking for the matching closing bracket */
- for (level = 1; i < size; i++) {
- if (data[i] == '\n')
- text_has_nl = 1;
-
- else if (data[i - 1] == '\\')
- continue;
-
- else if (data[i] == '[')
- level++;
-
- else if (data[i] == ']') {
- level--;
- if (level <= 0)
- break;
- }
- }
-
- if (i >= size)
- goto cleanup;
-
- txt_e = i;
- i++;
-
- /* skip any amount of whitespace or newline */
- /* (this is much more laxist than original markdown syntax) */
- while (i < size && _isspace(data[i]))
- i++;
-
- /* inline style link */
- if (i < size && data[i] == '(') {
- /* skipping initial whitespace */
- i++;
-
- while (i < size && _isspace(data[i]))
- i++;
-
- link_b = i;
-
- /* looking for link end: ' " ) */
- while (i < size) {
- if (data[i] == '\\') i += 2;
- else if (data[i] == ')') break;
- else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break;
- else i++;
- }
-
- if (i >= size) goto cleanup;
- link_e = i;
-
- /* looking for title end if present */
- if (data[i] == '\'' || data[i] == '"') {
- qtype = data[i];
- in_title = 1;
- i++;
- title_b = i;
-
- while (i < size) {
- if (data[i] == '\\') i += 2;
- else if (data[i] == qtype) {in_title = 0; i++;}
- else if ((data[i] == ')') && !in_title) break;
- else i++;
- }
-
- if (i >= size) goto cleanup;
-
- /* skipping whitespaces after title */
- title_e = i - 1;
- while (title_e > title_b && _isspace(data[title_e]))
- title_e--;
-
- /* checking for closing quote presence */
- if (data[title_e] != '\'' && data[title_e] != '"') {
- title_b = title_e = 0;
- link_e = i;
- }
- }
-
- /* remove whitespace at the end of the link */
- while (link_e > link_b && _isspace(data[link_e - 1]))
- link_e--;
-
- /* remove optional angle brackets around the link */
- if (data[link_b] == '<') link_b++;
- if (data[link_e - 1] == '>') link_e--;
-
- /* building escaped link and title */
- if (link_e > link_b) {
- link = rndr_newbuf(rndr, BUFFER_SPAN);
- bufput(link, data + link_b, link_e - link_b);
- }
-
- if (title_e > title_b) {
- title = rndr_newbuf(rndr, BUFFER_SPAN);
- bufput(title, data + title_b, title_e - title_b);
- }
-
- i++;
- }
-
- /* reference style link */
- else if (i < size && data[i] == '[') {
- struct buf id = { 0, 0, 0, 0 };
- struct link_ref *lr;
-
- /* looking for the id */
- i++;
- link_b = i;
- while (i < size && data[i] != ']') i++;
- if (i >= size) goto cleanup;
- link_e = i;
-
- /* finding the link_ref */
- if (link_b == link_e) {
- if (text_has_nl) {
- struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN);
- size_t j;
-
- for (j = 1; j < txt_e; j++) {
- if (data[j] != '\n')
- bufputc(b, data[j]);
- else if (data[j - 1] != ' ')
- bufputc(b, ' ');
- }
-
- id.data = b->data;
- id.size = b->size;
- } else {
- id.data = data + 1;
- id.size = txt_e - 1;
- }
- } else {
- id.data = data + link_b;
- id.size = link_e - link_b;
- }
-
- lr = find_link_ref(rndr->refs, id.data, id.size);
- if (!lr)
- goto cleanup;
-
- /* keeping link and title from link_ref */
- link = lr->link;
- title = lr->title;
- i++;
- }
-
- /* shortcut reference style link */
- else {
- struct buf id = { 0, 0, 0, 0 };
- struct link_ref *lr;
-
- /* crafting the id */
- if (text_has_nl) {
- struct buf *b = rndr_newbuf(rndr, BUFFER_SPAN);
- size_t j;
-
- for (j = 1; j < txt_e; j++) {
- if (data[j] != '\n')
- bufputc(b, data[j]);
- else if (data[j - 1] != ' ')
- bufputc(b, ' ');
- }
-
- id.data = b->data;
- id.size = b->size;
- } else {
- id.data = data + 1;
- id.size = txt_e - 1;
- }
-
- /* finding the link_ref */
- lr = find_link_ref(rndr->refs, id.data, id.size);
- if (!lr)
- goto cleanup;
-
- /* keeping link and title from link_ref */
- link = lr->link;
- title = lr->title;
-
- /* rewinding the whitespace */
- i = txt_e + 1;
- }
-
- /* building content: img alt is escaped, link content is parsed */
- if (txt_e > 1) {
- content = rndr_newbuf(rndr, BUFFER_SPAN);
- if (is_img) {
- bufput(content, data + 1, txt_e - 1);
- } else {
- /* disable autolinking when parsing inline the
- * content of a link */
- rndr->in_link_body = 1;
- parse_inline(content, rndr, data + 1, txt_e - 1);
- rndr->in_link_body = 0;
- }
- }
-
- if (link) {
- u_link = rndr_newbuf(rndr, BUFFER_SPAN);
- unscape_text(u_link, link);
- }
-
- /* calling the relevant rendering function */
- if (is_img) {
- if (ob->size && ob->data[ob->size - 1] == '!')
- ob->size -= 1;
-
- ret = rndr->cb.image(ob, u_link, title, content, rndr->opaque);
- } else {
- ret = rndr->cb.link(ob, u_link, title, content, rndr->opaque);
- }
-
- /* cleanup */
-cleanup:
- rndr->work_bufs[BUFFER_SPAN].size = (int)org_work_size;
- return ret ? i : 0;
-}
-
-static size_t
-char_superscript(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
-{
- size_t sup_start, sup_len;
- struct buf *sup;
-
- if (!rndr->cb.superscript)
- return 0;
-
- if (size < 2)
- return 0;
-
- if (data[1] == '(') {
- sup_start = sup_len = 2;
-
- while (sup_len < size && data[sup_len] != ')' && data[sup_len - 1] != '\\')
- sup_len++;
-
- if (sup_len == size)
- return 0;
- } else {
- sup_start = sup_len = 1;
-
- while (sup_len < size && !_isspace(data[sup_len]))
- sup_len++;
- }
-
- if (sup_len - sup_start == 0)
- return (sup_start == 2) ? 3 : 0;
-
- sup = rndr_newbuf(rndr, BUFFER_SPAN);
- parse_inline(sup, rndr, data + sup_start, sup_len - sup_start);
- rndr->cb.superscript(ob, sup, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_SPAN);
-
- return (sup_start == 2) ? sup_len + 1 : sup_len;
-}
-
-/*********************************
- * BLOCK-LEVEL PARSING FUNCTIONS *
- *********************************/
-
-/* is_empty • returns the line length when it is empty, 0 otherwise */
-static size_t
-is_empty(uint8_t *data, size_t size)
-{
- size_t i;
-
- for (i = 0; i < size && data[i] != '\n'; i++)
- if (data[i] != ' ')
- return 0;
-
- return i + 1;
-}
-
-/* is_hrule • returns whether a line is a horizontal rule */
-static int
-is_hrule(uint8_t *data, size_t size)
-{
- size_t i = 0, n = 0;
- uint8_t c;
-
- /* skipping initial spaces */
- if (size < 3) return 0;
- if (data[0] == ' ') { i++;
- if (data[1] == ' ') { i++;
- if (data[2] == ' ') { i++; } } }
-
- /* looking at the hrule uint8_t */
- if (i + 2 >= size
- || (data[i] != '*' && data[i] != '-' && data[i] != '_'))
- return 0;
- c = data[i];
-
- /* the whole line must be the char or whitespace */
- while (i < size && data[i] != '\n') {
- if (data[i] == c) n++;
- else if (data[i] != ' ')
- return 0;
-
- i++;
- }
-
- return n >= 3;
-}
-
-/* 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, n = 0;
- uint8_t c;
-
- /* skipping initial spaces */
- if (size < 3) return 0;
- if (data[0] == ' ') { i++;
- if (data[1] == ' ') { i++;
- if (data[2] == ' ') { i++; } } }
-
- /* looking at the hrule uint8_t */
- if (i + 2 >= size || !(data[i] == '~' || data[i] == '`'))
- return 0;
-
- c = data[i];
-
- /* the whole line must be the uint8_t or whitespace */
- while (i < size && data[i] == c) {
- n++; i++;
- }
-
- if (n < 3)
- return 0;
-
- if (syntax != NULL) {
- size_t syn = 0;
-
- while (i < size && data[i] == ' ')
- i++;
-
- syntax->data = data + i;
-
- if (i < size && data[i] == '{') {
- i++; syntax->data++;
-
- while (i < size && data[i] != '}' && data[i] != '\n') {
- syn++; i++;
- }
-
- if (i == size || data[i] != '}')
- return 0;
-
- /* strip all whitespace at the beginning and the end
- * of the {} block */
- while (syn > 0 && _isspace(syntax->data[0])) {
- syntax->data++; syn--;
- }
-
- while (syn > 0 && _isspace(syntax->data[syn - 1]))
- syn--;
-
- i++;
- } else {
- while (i < size && !_isspace(data[i])) {
- syn++; i++;
- }
- }
-
- syntax->size = syn;
- }
-
- while (i < size && data[i] != '\n') {
- if (!_isspace(data[i]))
- return 0;
-
- i++;
- }
-
- return i + 1;
-}
-
-/* is_atxheader • returns whether the line is a hash-prefixed header */
-static int
-is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size)
-{
- if (data[0] != '#')
- return 0;
-
- if (rndr->ext_flags & MKDEXT_SPACE_HEADERS) {
- size_t level = 0;
-
- while (level < size && level < 6 && data[level] == '#')
- level++;
-
- if (level < size && data[level] != ' ')
- return 0;
- }
-
- return 1;
-}
-
-/* is_headerline • returns whether the line is a setext-style hdr underline */
-static int
-is_headerline(uint8_t *data, size_t size)
-{
- size_t i = 0;
-
- /* test of level 1 header */
- if (data[i] == '=') {
- for (i = 1; i < size && data[i] == '='; i++);
- while (i < size && data[i] == ' ') i++;
- return (i >= size || data[i] == '\n') ? 1 : 0; }
-
- /* test of level 2 header */
- if (data[i] == '-') {
- for (i = 1; i < size && data[i] == '-'; i++);
- while (i < size && data[i] == ' ') i++;
- return (i >= size || data[i] == '\n') ? 2 : 0; }
-
- return 0;
-}
-
-static int
-is_next_headerline(uint8_t *data, size_t size)
-{
- size_t i = 0;
-
- while (i < size && data[i] != '\n')
- i++;
-
- if (++i >= size)
- return 0;
-
- return is_headerline(data + i, size - i);
-}
-
-/* prefix_quote • returns blockquote prefix length */
-static size_t
-prefix_quote(uint8_t *data, size_t size)
-{
- size_t i = 0;
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
-
- if (i < size && data[i] == '>') {
- if (i + 1 < size && data[i + 1] == ' ')
- return i + 2;
-
- return i + 1;
- }
-
- return 0;
-}
-
-/* prefix_code • returns prefix length for block code*/
-static size_t
-prefix_code(uint8_t *data, size_t size)
-{
- if (size > 3 && data[0] == ' ' && data[1] == ' '
- && data[2] == ' ' && data[3] == ' ') return 4;
-
- return 0;
-}
-
-/* prefix_oli • returns ordered list item prefix */
-static size_t
-prefix_oli(uint8_t *data, size_t size)
-{
- size_t i = 0;
-
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
-
- if (i >= size || data[i] < '0' || data[i] > '9')
- return 0;
-
- while (i < size && data[i] >= '0' && data[i] <= '9')
- i++;
-
- if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ')
- return 0;
-
- if (is_next_headerline(data + i, size - i))
- return 0;
-
- return i + 2;
-}
-
-/* prefix_uli • returns ordered list item prefix */
-static size_t
-prefix_uli(uint8_t *data, size_t size)
-{
- size_t i = 0;
-
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
- if (i < size && data[i] == ' ') i++;
-
- if (i + 1 >= size ||
- (data[i] != '*' && data[i] != '+' && data[i] != '-') ||
- data[i + 1] != ' ')
- return 0;
-
- if (is_next_headerline(data + i, size - i))
- return 0;
-
- return i + 2;
-}
-
-
-/* parse_block • parsing of one block, returning next uint8_t to parse */
-static void parse_block(struct buf *ob, struct sd_markdown *rndr,
- uint8_t *data, size_t size);
-
-
-/* parse_blockquote • handles parsing of a blockquote fragment */
-static size_t
-parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
-{
- size_t beg, end = 0, pre, work_size = 0;
- uint8_t *work_data = 0;
- struct buf *out = 0;
-
- out = rndr_newbuf(rndr, BUFFER_BLOCK);
- beg = 0;
- while (beg < size) {
- for (end = beg + 1; end < size && data[end - 1] != '\n'; end++);
-
- pre = prefix_quote(data + beg, end - beg);
-
- if (pre)
- beg += pre; /* skipping prefix */
-
- /* empty line followed by non-quote line */
- else if (is_empty(data + beg, end - beg) &&
- (end >= size || (prefix_quote(data + end, size - end) == 0 &&
- !is_empty(data + end, size - end))))
- break;
-
- if (beg < end) { /* copy into the in-place working buffer */
- /* bufput(work, data + beg, end - beg); */
- if (!work_data)
- work_data = data + beg;
- else if (data + beg != work_data + work_size)
- memmove(work_data + work_size, data + beg, end - beg);
- work_size += end - beg;
- }
- beg = end;
- }
-
- parse_block(out, rndr, work_data, work_size);
- if (rndr->cb.blockquote)
- rndr->cb.blockquote(ob, out, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_BLOCK);
- return end;
-}
-
-static size_t
-parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render);
-
-/* parse_blockquote • handles parsing of a regular paragraph */
-static size_t
-parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
-{
- size_t i = 0, end = 0;
- int level = 0;
- struct buf work = { data, 0, 0, 0 };
-
- while (i < size) {
- for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */;
-
- if (is_empty(data + i, size - i))
- break;
-
- if ((level = is_headerline(data + i, size - i)) != 0)
- break;
-
- if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) {
- if (data[i] == '<' && rndr->cb.blockhtml && parse_htmlblock(ob, rndr, data + i, size - i, 0)) {
- end = i;
- break;
- }
- }
-
- if (is_atxheader(rndr, data + i, size - i) ||
- is_hrule(data + i, size - i) ||
- prefix_quote(data + i, size - i)) {
- end = i;
- break;
- }
-
- i = end;
- }
-
- work.size = i;
- while (work.size && data[work.size - 1] == '\n')
- work.size--;
-
- if (!level) {
- struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK);
- parse_inline(tmp, rndr, work.data, work.size);
- if (rndr->cb.paragraph)
- rndr->cb.paragraph(ob, tmp, rndr->opaque);
- rndr_popbuf(rndr, BUFFER_BLOCK);
- } else {
- struct buf *header_work;
-
- if (work.size) {
- size_t beg;
- i = work.size;
- work.size -= 1;
-
- while (work.size && data[work.size] != '\n')
- work.size -= 1;
-
- beg = work.size + 1;
- while (work.size && data[work.size - 1] == '\n')
- work.size -= 1;
-
- if (work.size > 0) {
- struct buf *tmp = rndr_newbuf(rndr, BUFFER_BLOCK);
- parse_inline(tmp, rndr, work.data, work.size);
-
- if (rndr->cb.paragraph)
- rndr->cb.paragraph(ob, tmp, rndr->opaque);
-
- rndr_popbuf(rndr, BUFFER_BLOCK);
- work.data += beg;
- work.size = i - beg;
- }
- else work.size = i;
- }
-
- header_work = rndr