summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/autolink.c18
-rw-r--r--src/autolink.h37
-rw-r--r--src/buffer.c205
-rw-r--r--src/buffer.h85
-rw-r--r--src/document.c398
-rw-r--r--src/document.h154
-rw-r--r--src/escape.c143
-rw-r--r--src/escape.h13
-rw-r--r--src/html.c346
-rw-r--r--src/html.h59
-rw-r--r--src/html_smartypants.c12
-rw-r--r--src/stack.c66
-rw-r--r--src/stack.h37
-rw-r--r--src/version.c8
-rw-r--r--src/version.h21
15 files changed, 933 insertions, 669 deletions
diff --git a/src/autolink.c b/src/autolink.c
index f2245cb..e7019fd 100644
--- a/src/autolink.c
+++ b/src/autolink.c
@@ -5,26 +5,28 @@
#include <stdio.h>
#include <ctype.h>
-#ifdef _MSC_VER
+#ifndef _MSC_VER
+#include <strings.h>
+#else
#define strncasecmp _strnicmp
#endif
int
-hoedown_autolink_is_safe(const uint8_t *link, size_t link_len)
+hoedown_autolink_is_safe(const uint8_t *data, size_t size)
{
static const size_t valid_uris_count = 6;
static const char *valid_uris[] = {
- "#", "/", "http://", "https://", "ftp://", "mailto:"
+ "http://", "https://", "/", "#", "ftp://", "mailto:"
};
-
+ static const size_t valid_uris_size[] = { 7, 8, 1, 1, 6, 7 };
size_t i;
for (i = 0; i < valid_uris_count; ++i) {
- size_t len = strlen(valid_uris[i]);
+ size_t len = valid_uris_size[i];
- if (link_len > len &&
- strncasecmp((char *)link, valid_uris[i], len) == 0 &&
- isalnum(link[len]))
+ if (size > len &&
+ strncasecmp((char *)data, valid_uris[i], len) == 0 &&
+ isalnum(data[len]))
return 1;
}
diff --git a/src/autolink.h b/src/autolink.h
index 8860ee2..528885c 100644
--- a/src/autolink.h
+++ b/src/autolink.h
@@ -9,24 +9,35 @@
extern "C" {
#endif
-enum {
+
+/*************
+ * CONSTANTS *
+ *************/
+
+typedef enum hoedown_autolink_flags {
HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0)
-};
+} hoedown_autolink_flags;
+
+
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* hoedown_autolink_is_safe: verify that a URL has a safe protocol */
+int hoedown_autolink_is_safe(const uint8_t *data, size_t size);
-int
-hoedown_autolink_is_safe(const uint8_t *link, size_t link_len);
+/* hoedown_autolink__www: search for the next www link in data */
+size_t hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link,
+ uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
-size_t
-hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link,
- uint8_t *data, size_t offset, size_t size, unsigned int flags);
+/* hoedown_autolink__email: search for the next email in data */
+size_t hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link,
+ uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
-size_t
-hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link,
- uint8_t *data, size_t offset, size_t size, unsigned int flags);
+/* hoedown_autolink__url: search for the next URL in data */
+size_t hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link,
+ uint8_t *data, size_t offset, size_t size, hoedown_autolink_flags flags);
-size_t
-hoedown_autolink__url(size_t *rewind_p, hoedown_buffer *link,
- uint8_t *data, size_t offset, size_t size, unsigned int flags);
#ifdef __cplusplus
}
diff --git a/src/buffer.c b/src/buffer.c
index 1ab9eac..af77b70 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5,7 +5,45 @@
#include <string.h>
#include <assert.h>
-/* hoedown_buffer_init: initialize a buffer with custom allocators */
+void *
+hoedown_malloc(size_t size)
+{
+ void *ret = malloc(size);
+
+ if (!ret) {
+ fprintf(stderr, "Allocation failed.\n");
+ abort();
+ }
+
+ return ret;
+}
+
+void *
+hoedown_calloc(size_t nmemb, size_t size)
+{
+ void *ret = calloc(nmemb, size);
+
+ if (!ret) {
+ fprintf(stderr, "Allocation failed.\n");
+ abort();
+ }
+
+ return ret;
+}
+
+void *
+hoedown_realloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+
+ if (!ret) {
+ fprintf(stderr, "Allocation failed.\n");
+ abort();
+ }
+
+ return ret;
+}
+
void
hoedown_buffer_init(
hoedown_buffer *buf,
@@ -14,8 +52,7 @@ hoedown_buffer_init(
hoedown_free_callback data_free,
hoedown_free_callback buffer_free)
{
- if (!buf)
- return;
+ assert(buf);
buf->data = NULL;
buf->size = buf->asize = 0;
@@ -25,21 +62,26 @@ hoedown_buffer_init(
buf->buffer_free = buffer_free;
}
-/* hoedown_buffer_new: allocation of a new buffer */
+void
+hoedown_buffer_uninit(hoedown_buffer *buf)
+{
+ assert(buf && buf->unit);
+ buf->data_free(buf->data);
+}
+
hoedown_buffer *
hoedown_buffer_new(size_t unit)
{
- hoedown_buffer *ret = malloc(sizeof (hoedown_buffer));
- hoedown_buffer_init(ret, unit, realloc, free, free);
+ hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer));
+ hoedown_buffer_init(ret, unit, hoedown_realloc, free, free);
return ret;
}
-/* hoedown_buffer_free: decrease the reference count and free the buffer if needed */
void
hoedown_buffer_free(hoedown_buffer *buf)
{
- if (!buf)
- return;
+ if (!buf) return;
+ assert(buf && buf->unit);
buf->data_free(buf->data);
@@ -47,82 +89,111 @@ hoedown_buffer_free(hoedown_buffer *buf)
buf->buffer_free(buf);
}
-/* hoedown_buffer_reset: frees internal data of the buffer */
void
hoedown_buffer_reset(hoedown_buffer *buf)
{
- if (!buf)
- return;
+ assert(buf && buf->unit);
buf->data_free(buf->data);
buf->data = NULL;
buf->size = buf->asize = 0;
}
-/* hoedown_buffer_grow: increasing the allocated size to the given value */
-int
+void
hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz)
{
size_t neoasz;
- void *neodata;
-
assert(buf && buf->unit);
if (buf->asize >= neosz)
- return HOEDOWN_BUF_OK;
+ return;
neoasz = buf->asize + buf->unit;
while (neoasz < neosz)
neoasz += buf->unit;
- neodata = buf->data_realloc(buf->data, neoasz);
- if (!neodata)
- return HOEDOWN_BUF_ENOMEM;
-
- buf->data = neodata;
+ buf->data = buf->data_realloc(buf->data, neoasz);
buf->asize = neoasz;
- return HOEDOWN_BUF_OK;
}
-/* hoedown_buffer_put: appends raw data to a buffer */
void
-hoedown_buffer_put(hoedown_buffer *buf, const void *data, size_t len)
+hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size)
{
assert(buf && buf->unit);
- if (buf->size + len > buf->asize && hoedown_buffer_grow(buf, buf->size + len) < 0)
- return;
+ if (buf->size + size > buf->asize)
+ hoedown_buffer_grow(buf, buf->size + size);
- memcpy(buf->data + buf->size, data, len);
- buf->size += len;
+ memcpy(buf->data + buf->size, data, size);
+ buf->size += size;
}
-/* hoedown_buffer_puts: appends a NUL-terminated string to a buffer */
void
hoedown_buffer_puts(hoedown_buffer *buf, const char *str)
{
- hoedown_buffer_put(buf, str, strlen(str));
+ hoedown_buffer_put(buf, (const uint8_t *)str, strlen(str));
}
-
-/* hoedown_buffer_putc: appends a single uint8_t to a buffer */
void
hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c)
{
assert(buf && buf->unit);
- if (buf->size + 1 > buf->asize && hoedown_buffer_grow(buf, buf->size + 1) < 0)
- return;
+ if (buf->size >= buf->asize)
+ hoedown_buffer_grow(buf, buf->size + 1);
buf->data[buf->size] = c;
buf->size += 1;
}
int
+hoedown_buffer_putf(hoedown_buffer *buf, FILE *file)
+{
+ assert(buf && buf->unit);
+
+ while (!(feof(file) || ferror(file))) {
+ hoedown_buffer_grow(buf, buf->size + buf->unit);
+ buf->size += fread(buf->data + buf->size, 1, buf->unit, file);
+ }
+
+ return ferror(file);
+}
+
+void
+hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size)
+{
+ assert(buf && buf->unit);
+
+ if (size > buf->asize)
+ hoedown_buffer_grow(buf, size);
+
+ memcpy(buf->data, data, size);
+ buf->size = size;
+}
+
+void
+hoedown_buffer_sets(hoedown_buffer *buf, const char *str)
+{
+ hoedown_buffer_set(buf, (const uint8_t *)str, strlen(str));
+}
+
+int
+hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size)
+{
+ if (buf->size != size) return 0;
+ return memcmp(buf->data, data, size) == 0;
+}
+
+int
+hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str)
+{
+ return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str));
+}
+
+int
hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
{
size_t i;
- assert(buf && buf->unit);
for (i = 0; i < buf->size; ++i) {
if (prefix[i] == 0)
@@ -135,22 +206,20 @@ hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
return 0;
}
-/* hoedown_buffer_slurp: removes a given number of bytes from the head of the array */
void
-hoedown_buffer_slurp(hoedown_buffer *buf, size_t len)
+hoedown_buffer_slurp(hoedown_buffer *buf, size_t size)
{
assert(buf && buf->unit);
- if (len >= buf->size) {
+ if (size >= buf->size) {
buf->size = 0;
return;
}
- buf->size -= len;
- memmove(buf->data, buf->data + len, buf->size);
+ buf->size -= size;
+ memmove(buf->data, buf->data + size, buf->size);
}
-/* hoedown_buffer_cstr: NULL-termination of the string array */
const char *
hoedown_buffer_cstr(hoedown_buffer *buf)
{
@@ -159,15 +228,12 @@ hoedown_buffer_cstr(hoedown_buffer *buf)
if (buf->size < buf->asize && buf->data[buf->size] == 0)
return (char *)buf->data;
- if (buf->size + 1 <= buf->asize || hoedown_buffer_grow(buf, buf->size + 1) == 0) {
- buf->data[buf->size] = 0;
- return (char *)buf->data;
- }
+ hoedown_buffer_grow(buf, buf->size + 1);
+ buf->data[buf->size] = 0;
- return NULL;
+ return (char *)buf->data;
}
-/* hoedown_buffer_printf: formatted printing to a buffer */
void
hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
{
@@ -176,9 +242,9 @@ hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
assert(buf && buf->unit);
- if (buf->size >= buf->asize && hoedown_buffer_grow(buf, buf->size + 1) < 0)
- return;
-
+ if (buf->size >= buf->asize)
+ hoedown_buffer_grow(buf, buf->size + 1);
+
va_start(ap, fmt);
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
va_end(ap);
@@ -194,8 +260,7 @@ hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
}
if ((size_t)n >= buf->asize - buf->size) {
- if (hoedown_buffer_grow(buf, buf->size + n + 1) < 0)
- return;
+ hoedown_buffer_grow(buf, buf->size + n + 1);
va_start(ap, fmt);
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
@@ -207,3 +272,37 @@ hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
buf->size += n;
}
+
+void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int c) {
+ unsigned char unichar[4];
+
+ assert(buf && buf->unit);
+
+ if (c < 0x80) {
+ hoedown_buffer_putc(buf, c);
+ }
+ else if (c < 0x800) {
+ unichar[0] = 192 + (c / 64);
+ unichar[1] = 128 + (c % 64);
+ hoedown_buffer_put(buf, unichar, 2);
+ }
+ else if (c - 0xd800u < 0x800) {
+ HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
+ }
+ else if (c < 0x10000) {
+ unichar[0] = 224 + (c / 4096);
+ unichar[1] = 128 + (c / 64) % 64;
+ unichar[2] = 128 + (c % 64);
+ hoedown_buffer_put(buf, unichar, 3);
+ }
+ else if (c < 0x110000) {
+ unichar[0] = 240 + (c / 262144);
+ unichar[1] = 128 + (c / 4096) % 64;
+ unichar[2] = 128 + (c / 64) % 64;
+ unichar[3] = 128 + (c % 64);
+ hoedown_buffer_put(buf, unichar, 4);
+ }
+ else {
+ HOEDOWN_BUFPUTSL(buf, "\xef\xbf\xbd");
+ }
+}
diff --git a/src/buffer.h b/src/buffer.h
index 8ba3683..d7703f8 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -3,9 +3,11 @@
#ifndef HOEDOWN_BUFFER_H
#define HOEDOWN_BUFFER_H
+#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdint.h>
+#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
@@ -14,17 +16,17 @@ extern "C" {
#if defined(_MSC_VER)
#define __attribute__(x)
#define inline __inline
+#define __builtin_expect(x,n) x
#endif
-typedef enum {
- HOEDOWN_BUF_OK = 0,
- HOEDOWN_BUF_ENOMEM = -1
-} hoedown_buferror_t;
+
+/*********
+ * TYPES *
+ *********/
typedef void *(*hoedown_realloc_callback)(void *, size_t);
typedef void (*hoedown_free_callback)(void *);
-/* hoedown_buffer: character array buffer */
struct hoedown_buffer {
uint8_t *data; /* actual character data */
size_t size; /* size of the string */
@@ -38,9 +40,15 @@ struct hoedown_buffer {
typedef struct hoedown_buffer hoedown_buffer;
-/* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */
-#define HOEDOWN_BUFPUTSL(output, literal) \
- hoedown_buffer_put(output, literal, sizeof(literal) - 1)
+
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* allocation wrappers */
+void *hoedown_malloc(size_t size) __attribute__ ((malloc));
+void *hoedown_calloc(size_t nmemb, size_t size) __attribute__ ((malloc));
+void *hoedown_realloc(void *ptr, size_t size) __attribute__ ((malloc));
/* hoedown_buffer_init: initialize a buffer with custom allocators */
void hoedown_buffer_init(
@@ -51,32 +59,47 @@ void hoedown_buffer_init(
hoedown_free_callback buffer_free
);
-/* hoedown_buffer_new: allocation of a new buffer */
-hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc));
+/* hoedown_buffer_uninit: uninitialize an existing buffer */
+void hoedown_buffer_uninit(hoedown_buffer *buf);
-/* hoedown_buffer_free: decrease the reference count and free the buffer if needed */
-void hoedown_buffer_free(hoedown_buffer *buf);
+/* hoedown_buffer_new: allocate a new buffer */
+hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc));
-/* hoedown_buffer_reset: frees internal data of the buffer */
+/* hoedown_buffer_reset: free internal data of the buffer */
void hoedown_buffer_reset(hoedown_buffer *buf);
-/* hoedown_buffer_grow: increasing the allocated size to the given value */
-int hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz);
+/* hoedown_buffer_grow: increase the allocated size to the given value */
+void hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz);
-/* hoedown_buffer_put: appends raw data to a buffer */
-void hoedown_buffer_put(hoedown_buffer *buf, const void *data, size_t len);
+/* hoedown_buffer_put: append raw data to a buffer */
+void hoedown_buffer_put(hoedown_buffer *buf, const uint8_t *data, size_t size);
-/* hoedown_buffer_puts: appends a NUL-terminated string to a buffer */
+/* hoedown_buffer_puts: append a NUL-terminated string to a buffer */
void hoedown_buffer_puts(hoedown_buffer *buf, const char *str);
-/* hoedown_buffer_putc: appends a single char to a buffer */
+/* hoedown_buffer_putc: append a single char to a buffer */
void hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c);
+/* hoedown_buffer_putf: read from a file and append to a buffer, until EOF or error */
+int hoedown_buffer_putf(hoedown_buffer *buf, FILE* file);
+
+/* hoedown_buffer_set: replace the buffer's contents with raw data */
+void hoedown_buffer_set(hoedown_buffer *buf, const uint8_t *data, size_t size);
+
+/* hoedown_buffer_sets: replace the buffer's contents with a NUL-terminated string */
+void hoedown_buffer_sets(hoedown_buffer *buf, const char *str);
+
+/* hoedown_buffer_eq: compare a buffer's data with other data for equality */
+int hoedown_buffer_eq(const hoedown_buffer *buf, const uint8_t *data, size_t size);
+
+/* hoedown_buffer_eq: compare a buffer's data with NUL-terminated string for equality */
+int hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str);
+
/* hoedown_buffer_prefix: compare the beginning of a buffer with a string */
int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix);
-/* hoedown_buffer_slurp: removes a given number of bytes from the head of the array */
-void hoedown_buffer_slurp(hoedown_buffer *buf, size_t len);
+/* hoedown_buffer_slurp: remove a given number of bytes from the head of the buffer */
+void hoedown_buffer_slurp(hoedown_buffer *buf, size_t size);
/* hoedown_buffer_cstr: NUL-termination of the string array (making a C-string) */
const char *hoedown_buffer_cstr(hoedown_buffer *buf);
@@ -84,6 +107,26 @@ const char *hoedown_buffer_cstr(hoedown_buffer *buf);
/* hoedown_buffer_printf: formatted printing to a buffer */
void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+/* hoedown_buffer_put_utf8: put a Unicode character encoded as UTF-8 */
+void hoedown_buffer_put_utf8(hoedown_buffer *buf, unsigned int codepoint);
+
+/* hoedown_buffer_free: free the buffer */
+void hoedown_buffer_free(hoedown_buffer *buf);
+
+
+/* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */
+#define HOEDOWN_BUFPUTSL(output, literal) \
+ hoedown_buffer_put(output, (const uint8_t *)literal, sizeof(literal) - 1)
+
+/* HOEDOWN_BUFSETSL: optimized hoedown_buffer_sets of a string literal */
+#define HOEDOWN_BUFSETSL(output, literal) \
+ hoedown_buffer_set(output, (const uint8_t *)literal, sizeof(literal) - 1)
+
+/* HOEDOWN_BUFEQSL: optimized hoedown_buffer_eqs of a string literal */
+#define HOEDOWN_BUFEQSL(output, literal) \
+ hoedown_buffer_eq(output, (const uint8_t *)literal, sizeof(literal) - 1)
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/document.c b/src/document.c
index acf2572..ee0102f 100644
--- a/src/document.c
+++ b/src/document.c
@@ -1,5 +1,3 @@
-/* document.c - generic markdown parser */
-
#include "document.h"
#include <assert.h>
@@ -9,7 +7,9 @@
#include "stack.h"
-#ifdef _MSC_VER
+#ifndef _MSC_VER
+#include <strings.h>
+#else
#define strncasecmp _strnicmp
#endif
@@ -88,7 +88,7 @@ enum markdown_char_t {
MD_CHAR_LINK,
MD_CHAR_LANGLE,
MD_CHAR_ESCAPE,
- MD_CHAR_ENTITITY,
+ MD_CHAR_ENTITY,
MD_CHAR_AUTOLINK_URL,
MD_CHAR_AUTOLINK_EMAIL,
MD_CHAR_AUTOLINK_WWW,
@@ -114,16 +114,16 @@ static char_trigger markdown_char_ptrs[] = {
&char_math
};
-/* render • structure containing state for a parser instance */
struct hoedown_document {
hoedown_renderer md;
+ hoedown_renderer_data data;
struct link_ref *refs[REF_TABLE_SIZE];
struct footnote_list footnotes_found;
struct footnote_list footnotes_used;
uint8_t active_char[256];
hoedown_stack work_bufs[2];
- unsigned int ext_flags;
+ hoedown_extensions ext_flags;
size_t max_nesting;
int in_link_body;
};
@@ -132,7 +132,7 @@ struct hoedown_document {
* HELPER FUNCTIONS *
***************************/
-static inline hoedown_buffer *
+static hoedown_buffer *
newbuf(hoedown_document *doc, int type)
{
static const size_t buf_size[2] = {256, 64};
@@ -151,7 +151,7 @@ newbuf(hoedown_document *doc, int type)
return work;
}
-static inline void
+static void
popbuf(hoedown_document *doc, int type)
{
doc->work_bufs[type].size--;
@@ -194,10 +194,7 @@ 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;
+ struct link_ref *ref = hoedown_calloc(1, sizeof(struct link_ref));
ref->id = hash_link_ref(name, name_size);
ref->next = references[ref->id % REF_TABLE_SIZE];
@@ -246,9 +243,7 @@ free_link_refs(struct link_ref **references)
static struct footnote_ref *
create_footnote_ref(struct footnote_list *list, const uint8_t *name, size_t name_size)
{
- struct footnote_ref *ref = calloc(1, sizeof(struct footnote_ref));
- if (!ref)
- return NULL;
+ struct footnote_ref *ref = hoedown_calloc(1, sizeof(struct footnote_ref));
ref->id = hash_link_ref(name, name_size);
@@ -258,7 +253,7 @@ create_footnote_ref(struct footnote_list *list, const uint8_t *name, size_t name
static int
add_footnote_ref(struct footnote_list *list, struct footnote_ref *ref)
{
- struct footnote_item *item = calloc(1, sizeof(struct footnote_item));
+ struct footnote_item *item = hoedown_calloc(1, sizeof(struct footnote_item));
if (!item)
return 0;
item->ref = ref;
@@ -325,14 +320,14 @@ free_footnote_list(struct footnote_list *list, int free_refs)
* should instead extract an Unicode codepoint from
* this character and check for space properties.
*/
-static inline int
+static int
_isspace(int c)
{
return c == ' ' || c == '\n';
}
/* is_empty_all: verify that all the data is spacing */
-static inline int
+static int
is_empty_all(const uint8_t *data, size_t size)
{
size_t i = 0;
@@ -344,7 +339,7 @@ is_empty_all(const uint8_t *data, size_t size)
* Replace all spacing characters in data with spaces. As a special
* case, this collapses a newline with the previous space, if possible.
*/
-static inline void
+static void
replace_spacing(hoedown_buffer *ob, const uint8_t *data, size_t size)
{
size_t i = 0, mark;
@@ -400,7 +395,7 @@ is_mail_autolink(uint8_t *data, size_t size)
/* 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 hoedown_autolink *autolink)
+tag_length(uint8_t *data, size_t size, hoedown_autolink_type *autolink)
{
size_t i, j;
@@ -454,7 +449,7 @@ tag_length(uint8_t *data, size_t size, enum hoedown_autolink *autolink)
*autolink = HOEDOWN_AUTOLINK_NONE;
}
- /* looking for sometinhg looking like a tag end */
+ /* looking for something looking like a tag end */
while (i < size && data[i] != '>') i++;
if (i >= size) return 0;
return i + 1;
@@ -464,9 +459,9 @@ tag_length(uint8_t *data, size_t size, enum hoedown_autolink *autolink)
static void
parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size)
{
- size_t i = 0, end = 0;
- uint8_t action = 0;
+ size_t i = 0, end = 0, consumed = 0;
hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL };
+ uint8_t *active_char = doc->active_char;
if (doc->work_bufs[BUFFER_SPAN].size +
doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting)
@@ -474,14 +469,13 @@ parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t si
while (i < size) {
/* copying inactive chars into the output */
- while (end < size && (action = doc->active_char[data[end]]) == 0) {
+ while (end < size && active_char[data[end]] == 0)
end++;
- }
if (doc->md.normal_text) {
work.data = data + i;
work.size = end - i;
- doc->md.normal_text(ob, &work, doc->md.opaque);
+ doc->md.normal_text(ob, &work, &doc->data);
}
else
hoedown_buffer_put(ob, data + i, end - i);
@@ -489,12 +483,13 @@ parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t si
if (end >= size) break;
i = end;
- end = markdown_char_ptrs[(int)action](ob, doc, data + i, i, size - i);
+ end = markdown_char_ptrs[ (int)active_char[data[end]] ](ob, doc, data + i, i - consumed, size - i);
if (!end) /* no action from the callback */
end = i + 1;
else {
i += end;
end = i;
+ consumed = i;
}
}
}
@@ -554,7 +549,7 @@ find_emph_char(uint8_t *data, size_t size, uint8_t c)
}
/* not a well-formed codespan; use found matching emph char */
- if (i >= size) return tmp_i;
+ if (bt < span_nb && i >= size) return tmp_i;
}
/* skipping a link */
else if (data[i] == '[') {
@@ -633,9 +628,9 @@ parse_emph1(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz
parse_inline(work, doc, data, i);
if (doc->ext_flags & HOEDOWN_EXT_UNDERLINE && c == '_')
- r = doc->md.underline(ob, work, doc->md.opaque);
+ r = doc->md.underline(ob, work, &doc->data);
else
- r = doc->md.emphasis(ob, work, doc->md.opaque);
+ r = doc->md.emphasis(ob, work, &doc->data);
popbuf(doc, BUFFER_SPAN);
return r ? i + 1 : 0;
@@ -663,11 +658,11 @@ parse_emph2(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz
parse_inline(work, doc, data, i);
if (c == '~')
- r = doc->md.strikethrough(ob, work, doc->md.opaque);
+ r = doc->md.strikethrough(ob, work, &doc->data);
else if (c == '=')
- r = doc->md.highlight(ob, work, doc->md.opaque);
+ r = doc->md.highlight(ob, work, &doc->data);
else
- r = doc->md.double_emphasis(ob, work, doc->md.opaque);
+ r = doc->md.double_emphasis(ob, work, &doc->data);
popbuf(doc, BUFFER_SPAN);
return r ? i + 2 : 0;
@@ -699,7 +694,7 @@ parse_emph3(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz
hoedown_buffer *work = newbuf(doc, BUFFER_SPAN);
parse_inline(work, doc, data, i);
- r = doc->md.triple_emphasis(ob, work, doc->md.opaque);
+ r = doc->md.triple_emphasis(ob, work, &doc->data);
popbuf(doc, BUFFER_SPAN);
return r ? i + 3 : 0;
@@ -723,36 +718,41 @@ parse_emph3(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz
static size_t
parse_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size, const char *end, size_t delimsz, int displaymode)
{
+ hoedown_buffer text = { NULL, 0, 0, 0, NULL, NULL, NULL };
size_t i = delimsz;
- if (!doc->md.math) return 0;
+
+ if (!doc->md.math)
+ return 0;
/* find ending delimiter */
while (1) {
- while (i < size && data[i] != (uint8_t)end[0]) i++;
- if (i >= size) return 0;
+ while (i < size && data[i] != (uint8_t)end[0])
+ i++;
+
+ if (i >= size)
+ return 0;
if (!is_escaped(data, i) && !(i + delimsz > size)
&& memcmp(data + i, end, delimsz) == 0)
break;
+
i++;
}
/* prepare buffers */
- hoedown_buffer text = { data + delimsz, i - delimsz, 0, 0, NULL, NULL, NULL };
-
- /* enforce spacing around the span */
- i += delimsz;
- if (offset && !_isspace(data[-1])) return 0;
- if (i < size && !_isspace(data[i])) return 0;
+ text.data = data + delimsz;
+ text.size = i - delimsz;
/* if this is a $$ and MATH_EXPLICIT is not active,
- * guess wether displaymode should be enabled from the context */
+ * guess whether displaymode should be enabled from the context */
+ i += delimsz;
if (delimsz == 2 && !(doc->ext_flags & HOEDOWN_EXT_MATH_EXPLICIT))
displaymode = is_empty_all(data - offset, offset) && is_empty_all(data + i, size - i);
/* call callback */
- if (doc->md.math(ob, &text, displaymode, doc->md.opaque))
+ if (doc->md.math(ob, &text, displaymode, &doc->data))
return i;
+
return 0;
}
@@ -806,7 +806,7 @@ char_linebreak(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
while (ob->size && ob->data[ob->size - 1] == ' ')
ob->size--;
- return doc->md.linebreak(ob, doc->md.opaque) ? 1 : 0;
+ return doc->md.linebreak(ob, &doc->data) ? 1 : 0;
}
@@ -814,6 +814,7 @@ char_linebreak(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
static size_t
char_codespan(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size)
{
+ hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL };
size_t end, nb = 0, i, f_begin, f_end;
/* counting the number of backticks in the delimiter */
@@ -841,11 +842,13 @@ char_codespan(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t o
/* real code span */
if (f_begin < f_end) {
- hoedown_buffer work = { data + f_begin, f_end - f_begin, 0, 0, NULL, NULL, NULL };
- if (!doc->md.codespan(ob, &work, doc->md.opaque))
+ work.data = data + f_begin;
+ work.size = f_end - f_begin;
+
+ if (!doc->md.codespan(ob, &work, &doc->data))
end = 0;
} else {
- if (!doc->md.codespan(ob, 0, doc->md.opaque))
+ if (!doc->md.codespan(ob, 0, &doc->data))
end = 0;
}
@@ -887,11 +890,11 @@ char_quote(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offs
hoedown_buffer *work = newbuf(doc, BUFFER_SPAN);
parse_inline(work, doc, data + f_begin, f_end - f_begin);
- if (!doc->md.quote(ob, work, doc->md.opaque))
+ if (!doc->md.quote(ob, work, &doc->data))
end = 0;
popbuf(doc, BUFFER_SPAN);
} else {
- if (!doc->md.quote(ob, 0, doc->md.opaque))
+ if (!doc->md.quote(ob, 0, &doc->data))
end = 0;
}
@@ -921,7 +924,7 @@ char_escape(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off
if (doc->md.normal_text) {
work.data = data + 1;
work.size = 1;
- doc->md.normal_text(ob, &work, doc->md.opaque);
+ doc->md.normal_text(ob, &work, &doc->data);
}
else hoedown_buffer_putc(ob, data[1]);
} else if (size == 1) {
@@ -953,7 +956,7 @@ char_entity(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off
if (doc->md.entity) {
work.data = data;
work.size = end;
- doc->md.entity(ob, &work, doc->md.opaque);
+ doc->md.entity(ob, &work, &doc->data);
}
else hoedown_buffer_put(ob, data, end);
@@ -964,22 +967,25 @@ char_entity(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off
static size_t
char_langle_tag(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size)
{
- enum hoedown_autolink altype = HOEDOWN_AUTOLINK_NONE;
+ hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL };
+ hoedown_autolink_type altype = HOEDOWN_AUTOLINK_NONE;
size_t end = tag_length(data, size, &altype);
- hoedown_buffer work = { data, end, 0, 0, NULL, NULL, NULL };
int ret = 0;
+ work.data = data;
+ work.size = end;
+
if (end > 2) {
if (doc->md.autolink && altype != HOEDOWN_AUTOLINK_NONE) {
hoedown_buffer *u_link = newbuf(doc, BUFFER_SPAN);
work.data = data + 1;
work.size = end - 2;
unscape_text(u_link, &work);
- ret = doc->md.autolink(ob, u_link, altype, doc->md.opaque);
+ ret = doc->md.autolink(ob, u_link, altype, &doc->data);
popbuf(doc, BUFFER_SPAN);
}
- else if (doc->md.raw_html_tag)
- ret = doc->md.raw_html_tag(ob, &work, doc->md.opaque);
+ else if (doc->md.raw_html)
+ ret = doc->md.raw_html(ob, &work, &doc->data);
}
if (!ret) return 0;
@@ -1002,14 +1008,18 @@ char_autolink_www(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size
HOEDOWN_BUFPUTSL(link_url, "http://");
hoedown_buffer_put(link_url, link->data, link->size);
- ob->size -= rewind;
+ if (ob->size > rewind)
+ ob->size -= rewind;
+ else
+ ob->size = 0;
+
if (doc->md.normal_text) {
link_text = newbuf(doc, BUFFER_SPAN);
- doc->md.normal_text(link_text, link, doc->md.opaque);
- doc->md.link(ob, link_url, NULL, link_text, doc->md.opaque);
+ doc->md.normal_text(link_text, link, &doc->data);
+ doc->md.link(ob, link_text, link_url, NULL, &doc->data);
popbuf(doc, BUFFER_SPAN);
} else {
- doc->md.link(ob, link_url, NULL, link, doc->md.opaque);
+ doc->md.link(ob, link, link_url, NULL, &doc->data);
}
popbuf(doc, BUFFER_SPAN);
}
@@ -1030,8 +1040,12 @@ char_autolink_email(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, si
link = newbuf(doc, BUFFER_SPAN);
if ((link_len = hoedown_autolink__email(&rewind, link, data, offset, size, 0)) > 0) {
- ob->size -= rewind;
- doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_EMAIL, doc->md.opaque);
+ if (ob->size > rewind)
+ ob->size -= rewind;
+ else
+ ob->size = 0;
+
+ doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_EMAIL, &doc->data);
}
popbuf(doc, BUFFER_SPAN);
@@ -1050,8 +1064,12 @@ char_autolink_url(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size
link = newbuf(doc, BUFFER_SPAN);
if ((link_len = hoedown_autolink__url(&rewind, link, data, offset, size, 0)) > 0) {
- ob->size -= rewind;
- doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_NORMAL, doc->md.opaque);
+ if (ob->size > rewind)
+ ob->size -= rewind;
+ else
+ ob->size = 0;
+
+ doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_NORMAL, &doc->data);
}
popbuf(doc, BUFFER_SPAN);
@@ -1106,7 +1124,7 @@ char_link(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offse
/* render */
if (doc->md.footnote_ref)
- ret = doc->md.footnote_ref(ob, fr->num, doc->md.opaque);
+ ret = doc->md.footnote_ref(ob, fr->num, &doc->data);
}
goto cleanup;
@@ -1181,8 +1199,10 @@ char_link(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offse
link_e--;
/* remove optional angle brackets around the link */
- if (data[link_b] == '<') link_b++;
- if (data[link_e - 1] == '>') link_e--;
+ if (data[link_b] == '<' && data[link_e - 1] == '>') {
+ link_b++;
+ link_e--;
+ }
/* building escaped link and title */
if (link_e > link_b) {
@@ -1271,9 +1291,9 @@ char_link(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offse
if (ob->size && ob->data[ob->size - 1] == '!')
ob->size -= 1;
- ret = doc->md.image(ob, u_link, title, content, doc->md.opaque);
+ ret = doc->md.image(ob, u_link, title, content, &doc->data);
} else {
- ret = doc->md.link(ob, u_link, title, content, doc->md.opaque);
+ ret = doc->md.link(ob, content, u_link, title, &doc->data);
}
/* cleanup */
@@ -1312,7 +1332,7 @@ char_superscript(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_
sup = newbuf(doc, BUFFER_SPAN);
parse_inline(sup, doc, data + sup_start, sup_len - sup_start);
- doc->md.superscript(ob, sup, doc->md.opaque);
+ doc->md.superscript(ob, sup, &doc->data);
popbuf(doc, BUFFER_SPAN);
return (sup_start == 2) ? sup_len + 1 : sup_len;
@@ -1616,7 +1636,7 @@ parse_blockquote(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_
parse_block(out, doc, work_data, work_size);
if (doc->md.blockquote)
- doc->md.blockquote(ob, out, doc->md.opaque);
+ doc->md.blockquote(ob, out, &doc->data);
popbuf(doc, BUFFER_BLOCK);
return end;
}
@@ -1628,9 +1648,11 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
static size_t
parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size)
{
+ hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL };
size_t i = 0, end = 0;
int level = 0;
- hoedown_buffer work = { data, 0, 0, 0, NULL, NULL, NULL };
+
+ work.data = data;
while (i < size) {
for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */;
@@ -1648,37 +1670,6 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
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 ((doc->ext_flags & HOEDOWN_EXT_LAX_SPACING) && !isalnum(data[i])) {
- if (prefix_oli(data + i, size - i) ||
- prefix_uli(data + i, size - i)) {
- end = i;
- break;
- }
-
- /* see if an html block starts here */
- if (data[i] == '<' && doc->md.blockhtml &&
- parse_htmlblock(ob, doc, data + i, size - i, 0)) {
- end = i;
- break;
- }
-
- /* see if a code fence starts here */
- if ((doc->ext_flags & HOEDOWN_EXT_FENCED_CODE) != 0 &&
- is_codefence(data + i, size - i, NULL, NULL)) {
- end = i;
- break;
- }
- }
-
i = end;
}
@@ -1690,7 +1681,7 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
hoedown_buffer *tmp = newbuf(doc, BUFFER_BLOCK);
parse_inline(tmp, doc, work.data, work.size);
if (doc->md.paragraph)
- doc->md.paragraph(ob, tmp, doc->md.opaque);
+ doc->md.paragraph(ob, tmp, &doc->data);
popbuf(doc, BUFFER_BLOCK);
} else {
hoedown_buffer *header_work;
@@ -1712,7 +1703,7 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
parse_inline(tmp, doc, work.data, work.size);
if (doc->md.paragraph)
- doc->md.paragraph(ob, tmp, doc->md.opaque);
+ doc->md.paragraph(ob, tmp, &doc->data);
popbuf(doc, BUFFER_BLOCK);
work.data += beg;
@@ -1725,7 +1716,7 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
parse_inline(header_work, doc, work.data, work.size);
if (doc->md.header)
- doc->md.header(ob, header_work, (int)level, doc->md.opaque);
+ doc->md.header(ob, header_work, (int)level, &doc->data);
popbuf(doc, BUFFER_SPAN);
}
@@ -1737,23 +1728,27 @@ parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
static size_t
parse_fencedcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size)
{
+ hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL };
+ hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL };
size_t i = 0, text_start, line_start;
size_t w, w2;
size_t width, width2;
uint8_t chr, chr2;
- hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL };
- hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL };
- // parse codefence line
- while (i < size && data[i] != '\n') i++;
+ /* parse codefence line */
+ while (i < size && data[i] != '\n')
+ i++;
+
w = parse_codefence(data, i, &lang, &width, &chr);
- if (!w) return 0;
+ if (!w)
+ return 0;
- // search for end
+ /* search for end */
i++;
text_start = i;
while ((line_start = i) < size) {
- while (i < size && data[i] != '\n') i++;
+ while (i < size && data[i] != '\n')
+ i++;
w2 = is_codefence(data + line_start, i - line_start, &width2, &chr2);
if (w == w2 && width == width2 && chr == chr2 &&
@@ -1762,11 +1757,12 @@ parse_fencedcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_
i++;
}
+
text.data = data + text_start;
text.size = line_start - text_start;
if (doc->md.blockcode)
- doc->md.blockcode(ob, text.size ? &text : NULL, lang.size ? &lang : NULL, doc->md.opaque);
+ doc->md.blockcode(ob, text.size ? &text : NULL, lang.size ? &lang : NULL, &doc->data);
return i;
}
@@ -1806,7 +1802,7 @@ parse_blockcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
hoedown_buffer_putc(work, '\n');
if (doc->md.blockcode)
- doc->md.blockcode(ob, work, NULL, doc->md.opaque);
+ doc->md.blockcode(ob, work, NULL, &doc->data);
popbuf(doc, BUFFER_BLOCK);
return beg;
@@ -1815,7 +1811,7 @@ parse_blockcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* parse_listitem • parsing of a single list item */
/* assuming initial prefix is already removed */
static size_t
-parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, int *flags)
+parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, hoedown_list_flags *flags)
{
hoedown_buffer *work = 0, *inter = 0;
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
@@ -1942,7 +1938,7 @@ parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* render of li itself */
if (doc->md.listitem)
- doc->md.listitem(ob, inter, *flags, doc->md.opaque);
+ doc->md.listitem(ob, inter, *flags, &doc->data);
popbuf(doc, BUFFER_SPAN);
popbuf(doc, BUFFER_SPAN);
@@ -1952,7 +1948,7 @@ parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* parse_list • parsing ordered or unordered list block */
static size_t
-parse_list(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, int flags)
+parse_list(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, hoedown_list_flags flags)
{
hoedown_buffer *work = 0;
size_t i = 0, j;
@@ -1968,7 +1964,7 @@ parse_list(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size
}
if (doc->md.list)
- doc->md.list(ob, work, flags, doc->md.opaque);
+ doc->md.list(ob, work, flags, &doc->data);
popbuf(doc, BUFFER_BLOCK);
return i;
}
@@ -2000,7 +1996,7 @@ parse_atxheader(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
parse_inline(work, doc, data + i, end - i);
if (doc->md.header)
- doc->md.header(ob, work, (int)level, doc->md.opaque);
+ doc->md.header(ob, work, (int)level, &doc->data);
popbuf(doc, BUFFER_SPAN);
}
@@ -2018,7 +2014,7 @@ parse_footnote_def(hoedown_buffer *ob, hoedown_document *doc, unsigned int num,
parse_block(work, doc, data, size);
if (doc->md.footnote_def)
- doc->md.footnote_def(ob, work, num, doc->md.opaque);
+ doc->md.footnote_def(ob, work, num, &doc->data);
popbuf(doc, BUFFER_SPAN);
}
@@ -2043,14 +2039,14 @@ parse_footnote_list(hoedown_buffer *ob, hoedown_document *doc, struct footnote_l
}
if (doc->md.footnotes)
- doc->md.footnotes(ob, work, doc->md.opaque);
+ doc->md.footnotes(ob, work, &doc->data);
popbuf(doc, BUFFER_BLOCK);
}
/* htmlblock_is_end • check for end of HTML block : </tag>( *)\n */
/* returns tag length on match, 0 otherwise */
/* assumes data starts with "<" */
-static inline size_t
+static size_t
htmlblock_is_end(
const char *tag,
size_t tag_len,
@@ -2115,7 +2111,7 @@ htmlblock_find_end_strict(
while (i < size && data[i] != '\n') i++;
if (i < size) i++;
if (i == mark) return 0;
-
+
if (data[mark] == ' ' && mark > 0) continue;
mark += htmlblock_find_end(tag, tag_len, doc, data + mark, i - mark);
if (mark == i && (is_empty(data + i, size - i) || i >= size)) break;
@@ -2128,9 +2124,11 @@ htmlblock_find_end_strict(
static size_t
parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, int do_render)
{
- size_t i, j = 0, tag_end;
+ hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL };
+ size_t i, j = 0, tag_len, tag_end;
const char *curtag = NULL;
- hoedown_buffer work = { data, 0, 0, 0, NULL, NULL, NULL };
+
+ work.data = data;
/* identification of the opening tag */
if (size < 2 || data[0] != '<')
@@ -2161,7 +2159,7 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
if (j) {
work.size = i + j;
if (do_render && doc->md.blockhtml)
- doc->md.blockhtml(ob, &work, doc->md.opaque);
+ doc->md.blockhtml(ob, &work, &doc->data);
return work.size;
}
}
@@ -2178,7 +2176,7 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
if (j) {
work.size = i + j;
if (do_render && doc->md.blockhtml)
- doc->md.blockhtml(ob, &work, doc->md.opaque);
+ doc->md.blockhtml(ob, &work, &doc->data);
return work.size;
}
}
@@ -2189,7 +2187,7 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
}
/* looking for a matching closing tag in strict mode */
- size_t tag_len = strlen(curtag);
+ tag_len = strlen(curtag);
tag_end = htmlblock_find_end_strict(curtag, tag_len, doc, data, size);
/* if not found, trying a second pass looking for indented match */
@@ -2203,7 +2201,7 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* the end of the block has been found */
work.size = tag_end;
if (do_render && doc->md.blockhtml)
- doc->md.blockhtml(ob, &work, doc->md.opaque);
+ doc->md.blockhtml(ob, &work, &doc->data);
return tag_end;
}
@@ -2215,10 +2213,10 @@ parse_table_row(
uint8_t *data,
size_t size,
size_t columns,
- int *col_data,
- int header_flag)
+ hoedown_table_flags *col_data,
+ hoedown_table_flags header_flag)
{
- size_t i = 0, col;
+ size_t i = 0, col, len;
hoedown_buffer *row_work = 0;
if (!doc->md.table_cell || !doc->md.table_row)
@@ -2240,8 +2238,16 @@ parse_table_row(
cell_start = i;
- size_t len = find_emph_char(data + i, size - i, '|');
- i += len ? len : size - i;
+ len = find_emph_char(data + i, size - i, '|');
+
+ /* Two possibilities for len == 0:
+ 1) No more pipe char found in the current line.
+ 2) The next pipe is right after the current one, i.e. empty cell.
+ For case 1, we skip to the end of line; for case 2 we just continue.
+ */
+ if (len == 0 && i < size && data[i] != '|')
+ len = size - i;
+ i += len;
cell_end = i - 1;
@@ -2249,7 +2255,7 @@ parse_table_row(
cell_end--;
parse_inline(cell_work, doc, data + cell_start, 1 + cell_end - cell_start);
- doc->md.table_cell(row_work, cell_work, col_data[col] | header_flag, doc->md.opaque);
+ doc->md.table_cell(row_work, cell_work, col_data[col] | header_flag, &doc->data);
popbuf(doc, BUFFER_SPAN);
i++;
@@ -2257,10 +2263,10 @@ parse_table_row(
for (; col < columns; ++col) {
hoedown_buffer empty_cell = { 0, 0, 0, 0, NULL, NULL, NULL };
- doc->md.table_cell(row_work, &empty_cell, col_data[col] | header_flag, doc->md.opaque);
+ doc->md.table_cell(row_work, &empty_cell, col_data[col] | header_flag, &doc->data);
}
- doc->md.table_row(ob, row_work, doc->md.opaque);
+ doc->md.table_row(ob, row_work, &doc->data);
popbuf(doc, BUFFER_SPAN);
}
@@ -2272,7 +2278,7 @@ parse_table_header(
uint8_t *data,
size_t size,
size_t *columns,
- int **column_data)
+ hoedown_table_flags **column_data)
{
int pipes;
size_t i = 0, col, header_end, under_end;
@@ -2300,7 +2306,7 @@ parse_table_header(
return 0;
*columns = pipes + 1;
- *column_data = calloc(*columns, sizeof(int));
+ *column_data = hoedown_calloc(*columns, sizeof(hoedown_table_flags));
/* Parse the header underline */
i++;
@@ -2366,12 +2372,14 @@ parse_table(
{
size_t i;
+ hoedown_buffer *work = 0;
hoedown_buffer *header_work = 0;
hoedown_buffer *body_work = 0;
size_t columns;
- int *col_data = NULL;
+ hoedown_table_flags *col_data = NULL;
+ work = newbuf(doc, BUFFER_BLOCK);
header_work = newbuf(doc, BUFFER_SPAN);
body_work = newbuf(doc, BUFFER_BLOCK);
@@ -2405,13 +2413,20 @@ parse_table(
i++;
}
+ if (doc->md.table_header)
+ doc->md.table_header(work, header_work, &doc->data);
+
+ if (doc->md.table_body)
+ doc->md.table_body(work, body_work, &doc->data);
+
if (doc->md.table)
- doc->md.table(ob, header_work, body_work, doc->md.opaque);
+ doc->md.table(ob, work, &doc->data);
}
free(col_data);
popbuf(doc, BUFFER_SPAN);
popbuf(doc, BUFFER_BLOCK);
+ popbuf(doc, BUFFER_BLOCK);
return i;
}
@@ -2443,7 +2458,7 @@ parse_block(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz
else if (is_hrule(txt_data, end)) {
if (doc->md.hrule)
- doc->md.hrule(ob, doc->md.opaque);
+ doc->md.hrule(ob, &doc->data);
while (beg < size && data[beg] != '\n')
beg++;
@@ -2523,7 +2538,7 @@ is_footnote(const uint8_t *data, size_t beg, size_t end, size_t *last, struct fo
start = i;
- /* process lines similiar to a list item */
+ /* process lines similar to a list item */
while (i < end) {
while (i < end && data[i] != '\n' && data[i] != '\r') i++;
@@ -2560,7 +2575,7 @@ is_footnote(const uint8_t *data, size_t beg, size_t end, size_t *last, struct fo
hoedown_buffer_put(contents, data + start + ind, i - start - ind);
/* add carriage return */
if (i < end) {
- hoedown_buffer_put(contents, "\n", 1);
+ hoedown_buffer_putc(contents, '\n');
if (i < end && (data[i] == '\n' || data[i] == '\r')) {
i++;
if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++;
@@ -2703,13 +2718,22 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
static void expand_tabs(hoedown_buffer *ob, const uint8_t *line, size_t size)
{
+ /* This code makes two assumptions:
+ * - Input is valid UTF-8. (Any byte with top two bits 10 is skipped,
+ * whether or not it is a valid UTF-8 continuation byte.)
+ * - Input contains no combining characters. (Combining characters
+ * should be skipped but are not.)
+ */
size_t i = 0, tab = 0;
while (i < size) {
size_t org = i;
while (i < size && line[i] != '\t') {
- i++; tab++;
+ /* ignore UTF-8 continuation bytes */
+ if ((line[i] & 0xc0) != 0x80)
+ tab++;
+ i++;
}
if (i > org)
@@ -2733,24 +2757,27 @@ static void expand_tabs(hoedown_buffer *ob, const uint8_t *line, size_t size)
hoedown_document *
hoedown_document_new(
const hoedown_renderer *renderer,
- unsigned int extensions,
+ hoedown_extensions extensions,
size_t max_nesting)
{
hoedown_document *doc = NULL;
assert(max_nesting > 0 && renderer);
- doc = malloc(sizeof(hoedown_document));
- if (!doc)
- return NULL;
-
+ doc = hoedown_malloc(sizeof(hoedown_document));
memcpy(&doc->md, renderer, sizeof(hoedown_renderer));
- hoedown_stack_new(&doc->work_bufs[BUFFER_BLOCK], 4);
- hoedown_stack_new(&doc->work_bufs[BUFFER_SPAN], 8);
+ doc->data.opaque = renderer->opaque;
+
+ hoedown_stack_init(&doc->work_bufs[BUFFER_BLOCK], 4);
+ hoedown_stack_init(&doc->work_bufs[BUFFER_SPAN], 8);
memset(doc->active_char, 0x0, 256);
+ if (extensions & HOEDOWN_EXT_UNDERLINE && doc->md.underline) {
+ doc->active_char['_'] = MD_CHAR_EMPHASIS;
+ }
+
if (doc->md.emphasis || doc->md.double_emphasis || doc->md.triple_emphasis) {
doc->active_char['*'] = MD_CHAR_EMPHASIS;
doc->active_char['_'] = MD_CHAR_EMPHASIS;
@@ -2766,12 +2793,12 @@ hoedown_document_new(
if (doc->md.linebreak)
doc->active_char['\n'] = MD_CHAR_LINEBREAK;
- if (doc->md.image || doc->md.link)
+ if (doc->md.image || doc->md.link || doc->md.footnotes || doc->md.footnote_ref)
doc->active_char['['] = MD_CHAR_LINK;
doc->active_char['<'] = MD_CHAR_LANGLE;
doc->active_char['\\'] = MD_CHAR_ESCAPE;
- doc->active_char['&'] = MD_CHAR_ENTITITY;
+ doc->active_char['&'] = MD_CHAR_ENTITY;
if (extensions & HOEDOWN_EXT_AUTOLINK) {
doc->active_char[':'] = MD_CHAR_AUTOLINK_URL;
@@ -2797,7 +2824,7 @@ hoedown_document_new(
}
void
-hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size)
+hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size)
{
static const uint8_t UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
@@ -2807,11 +2834,9 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
int footnotes_enabled;
text = hoedown_buffer_new(64);
- if (!text)
- return;
/* Preallocate enough space for our buffer to avoid expanding while copying */
- hoedown_buffer_grow(text, doc_size);
+ hoedown_buffer_grow(text, size);
/* reset the references table */
memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
@@ -2829,26 +2854,26 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
/* Skip a possible UTF-8 BOM, even though the Unicode standard
* discourages having these in UTF-8 documents */
- if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0)
+ if (size >= 3 && memcmp(data, UTF8_BOM, 3) == 0)
beg += 3;
- while (beg < doc_size) /* iterating over lines */
- if (footnotes_enabled && is_footnote(document, beg, doc_size, &end, &doc->footnotes_found))
+ while (beg < size) /* iterating over lines */
+ if (footnotes_enabled && is_footnote(data, beg, size, &end, &doc->footnotes_found))
beg = end;
- else if (is_ref(document, beg, doc_size, &end, doc->refs))
+ else if (is_ref(data, beg, size, &end, doc->refs))
beg = end;
else { /* skipping to the next line */
end = beg;
- while (end < doc_size && document[end] != '\n' && document[end] != '\r')
+ while (end < size && data[end] != '\n' && data[end] != '\r')
end++;
/* adding the line body if present */
if (end > beg)
- expand_tabs(text, document + beg, end - beg);
+ expand_tabs(text, data + beg, end - beg);
- while (end < doc_size && (document[end] == '\n' || document[end] == '\r')) {
+ while (end < size && (data[end] == '\n' || data[end] == '\r')) {
/* add one \n per newline */
- if (document[end] == '\n' || (end + 1 < doc_size && document[end + 1] != '\n'))
+ if (data[end] == '\n' || (end + 1 < size && data[end + 1] != '\n'))
hoedown_buffer_putc(text, '\n');
end++;
}
@@ -2861,7 +2886,7 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
/* second pass: actual rendering */
if (doc->md.doc_header)
- doc->md.doc_header(ob, doc->md.opaque);
+ doc->md.doc_header(ob, 0, &doc->data);
if (text->size) {
/* adding a final newline if not already present */
@@ -2876,7 +2901,7 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
parse_footnote_list(ob, doc, &doc->footnotes_used);
if (doc->md.doc_footer)
- doc->md.doc_footer(ob, doc->md.opaque);
+ doc->md.doc_footer(ob, 0, &doc->data);
/* clean-up */
hoedown_buffer_free(text);
@@ -2891,40 +2916,45 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
}
void
-hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size)
+hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size)
{
size_t i = 0, mark;
hoedown_buffer *text = hoedown_buffer_new(64);
- if (!text)
- return;
/* reset the references table */
memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
- /* first pass: convert all spacing to spaces */
- hoedown_buffer_grow(text, doc_size);
+ /* first pass: expand tabs and process newlines */
+ hoedown_buffer_grow(text, size);
while (1) {
mark = i;
- while (i < doc_size && document[i] != '\n' && document[i] != '\r')
+ while (i < size && data[i] != '\n' && data[i] != '\r')
i++;
- expand_tabs(text, document + mark, i - mark);
+ expand_tabs(text, data + mark, i - mark);
- if (i >= doc_size)
+ if (i >= size)
break;
- while (i < doc_size && (document[i] == '\n' || document[i] == '\r')) {
+ while (i < size && (data[i] == '\n' || data[i] == '\r')) {
/* add one \n per newline */
- if (document[i] == '\n' || (i + 1 < doc_size && document[i + 1] != '\n'))
+ if (data[i] == '\n' || (i + 1 < size && data[i + 1] != '\n'))
hoedown_buffer_putc(text, '\n');
i++;
}
}
/* second pass: actual rendering */
- hoedown_buffer_grow(ob, doc_size + (doc_size >> 1));
+ hoedown_buffer_grow(ob, text->size + (text->size >> 1));
+
+ if (doc->md.doc_header)
+ doc->md.doc_header(ob, 1, &doc->data);
+
parse_inline(ob, doc, text->data, text->size);
+ if (doc->md.doc_footer)
+ doc->md.doc_footer(ob, 1, &doc->data);
+
/* clean-up */
hoedown_buffer_free(text);
@@ -2943,8 +2973,8 @@ hoedown_document_free(hoedown_document *doc)
for (i = 0; i < (size_t)doc->work_bufs[BUFFER_BLOCK].asize; ++i)
hoedown_buffer_free(doc->work_bufs[BUFFER_BLOCK].item[i]);
- hoedown_stack_free(&doc->work_bufs[BUFFER_SPAN]);
- hoedown_stack_free(&doc->work_bufs[BUFFER_BLOCK]);
+ hoedown_stack_uninit(&doc->work_bufs[BUFFER_SPAN]);
+ hoedown_stack_uninit(&doc->work_bufs[BUFFER_BLOCK]);
free(doc);
}
diff --git a/src/document.h b/src/document.h
index 4547972..a8178fe 100644
--- a/src/document.h
+++ b/src/document.h
@@ -10,11 +10,12 @@
extern "C" {
#endif
-/*********
- * FLAGS *
- *********/
-enum hoedown_extensions {
+/*************
+ * CONSTANTS *
+ *************/
+
+typedef enum hoedown_extensions {
/* block-level extensions */
HOEDOWN_EXT_TABLES = (1 << 0),
HOEDOWN_EXT_FENCED_CODE = (1 << 1),
@@ -27,17 +28,16 @@ enum hoedown_extensions {
HOEDOWN_EXT_HIGHLIGHT = (1 << 6),
HOEDOWN_EXT_QUOTE = (1 << 7),
HOEDOWN_EXT_SUPERSCRIPT = (1 << 8),
- HOEDOWN_EXT_MATH = (1 << 13),
+ HOEDOWN_EXT_MATH = (1 << 9),
/* other flags */
- HOEDOWN_EXT_LAX_SPACING = (1 << 9),
- HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 10),
- HOEDOWN_EXT_SPACE_HEADERS = (1 << 11),
- HOEDOWN_EXT_MATH_EXPLICIT = (1 << 14),
+ HOEDOWN_EXT_NO_INTRA_EMPHASIS = (1 << 11),
+ HOEDOWN_EXT_SPACE_HEADERS = (1 << 12),
+ HOEDOWN_EXT_MATH_EXPLICIT = (1 << 13),
/* negative flags */
- HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 12)
-};
+ HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 14)
+} hoedown_extensions;
#define HOEDOWN_EXT_BLOCK (\
HOEDOWN_EXT_TABLES |\
@@ -54,7 +54,6 @@ enum hoedown_extensions {
HOEDOWN_EXT_MATH )
#define HOEDOWN_EXT_FLAGS (\
- HOEDOWN_EXT_LAX_SPACING |\
HOEDOWN_EXT_NO_INTRA_EMPHASIS |\
HOEDOWN_EXT_SPACE_HEADERS |\
HOEDOWN_EXT_MATH_EXPLICIT )
@@ -62,30 +61,37 @@ enum hoedown_extensions {
#define HOEDOWN_EXT_NEGATIVE (\
HOEDOWN_EXT_DISABLE_INDENTED_CODE )
-/* list/listitem flags */
-enum hoedown_listflags {
+typedef enum hoedown_list_flags {
HOEDOWN_LIST_ORDERED = (1 << 0),
HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */
-};
+} hoedown_list_flags;
-enum hoedown_tableflags {
+typedef enum hoedown_table_flags {
HOEDOWN_TABLE_ALIGN_LEFT = 1,
HOEDOWN_TABLE_ALIGN_RIGHT = 2,
HOEDOWN_TABLE_ALIGN_CENTER = 3,
HOEDOWN_TABLE_ALIGNMASK = 3,
HOEDOWN_TABLE_HEADER = 4
-};
+} hoedown_table_flags;
-/* hoedown_autolink - type of autolink */
-enum hoedown_autolink {
+typedef enum hoedown_autolink_type {
HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/
HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */
HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */
-};
+} hoedown_autolink_type;
-/********************
- * TYPE DEFINITIONS *
- ********************/
+
+/*********
+ * TYPES *
+ *********/
+
+struct hoedown_document;
+typedef struct hoedown_document hoedown_document;
+
+struct hoedown_renderer_data {
+ void *opaque;
+};
+typedef struct hoedown_renderer_data hoedown_renderer_data;
/* hoedown_renderer - functions for rendering parsed data */
struct hoedown_renderer {
@@ -93,71 +99,71 @@ struct hoedown_renderer {
void *opaque;
/* block level callbacks - NULL skips the block */
- void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, void *opaque);
- void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- void (*blockhtml)(hoedown_buffer *ob,const hoedown_buffer *text, void *opaque);
- void (*header)(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaque);
- void (*hrule)(hoedown_buffer *ob, void *opaque);
- void (*list)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque);
- void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque);
- void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- void (*table)(hoedown_buffer *ob, const hoedown_buffer *header, const hoedown_buffer *body, void *opaque);
- void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque);
- void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int num, void *opaque);
+ void (*blockcode)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data);
+ void (*blockquote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*header)(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data);
+ void (*hrule)(hoedown_buffer *ob, const hoedown_renderer_data *data);
+ void (*list)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
+ void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data);
+ void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*table)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*table_header)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*table_body)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*table_row)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data);
+ void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ void (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data);
+ void (*blockhtml)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
/* span level callbacks - NULL or return 0 prints the span verbatim */
- int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autolink type, void *opaque);
- int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*underline)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*quote)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, void *opaque);
- int (*linebreak)(hoedown_buffer *ob, void *opaque);
- int (*link)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque);
- int (*raw_html_tag)(hoedown_buffer *ob, const hoedown_buffer *tag, void *opaque);
- int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
- int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, void *opaque);
- int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, void *opaque);
+ int (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data);
+ int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
+ int (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*underline)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*highlight)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*quote)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*image)(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data);
+ int (*linebreak)(hoedown_buffer *ob, const hoedown_renderer_data *data);
+ int (*link)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data);
+ int (*triple_emphasis)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*strikethrough)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*superscript)(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data);
+ int (*footnote_ref)(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data);
+ int (*math)(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data);
+ int (*raw_html)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
/* low level callbacks - NULL copies input directly into the output */
- void (*entity)(hoedown_buffer *ob, const hoedown_buffer *entity, void *opaque);
- void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
+ void (*entity)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
+ void (*normal_text)(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data);
- /* header and footer */
- void (*doc_header)(hoedown_buffer *ob, void *opaque);
- void (*doc_footer)(hoedown_buffer *ob, void *opaque);
+ /* miscellaneous callbacks */
+ void (*doc_header)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
+ void (*doc_footer)(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data);
};
-
typedef struct hoedown_renderer hoedown_renderer;
-struct hoedown_document;
-typedef struct hoedown_document hoedown_document;
+/*************
+ * FUNCTIONS *
+ *************/
-/**********************
- * EXPORTED FUNCTIONS *
- **********************/
-
-extern hoedown_document *
-hoedown_document_new(
+/* hoedown_document_new: allocate a new document processor instance */
+hoedown_document *hoedown_document_new(
const hoedown_renderer *renderer,
- unsigned int extensions,
- size_t max_nesting);
+ hoedown_extensions extensions,
+ size_t max_nesting
+) __attribute__ ((malloc));
+
+/* hoedown_document_render: render regular Markdown using the document processor */
+void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size);
-extern void
-hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size);
+/* hoedown_document_render_inline: render inline Markdown using the document processor */
+void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size);
-extern void
-hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size);
+/* hoedown_document_free: deallocate a document processor instance */
+void hoedown_document_free(hoedown_document *doc);
-extern void
-hoedown_document_free(hoedown_document *doc);
#ifdef __cplusplus
}
diff --git a/src/escape.c b/src/escape.c
index 749eb75..122c6ec 100644
--- a/src/escape.c
+++ b/src/escape.c
@@ -4,6 +4,11 @@
#include <stdio.h>
#include <string.h>
+
+#define likely(x) __builtin_expect((x),1)
+#define unlikely(x) __builtin_expect((x),0)
+
+
/*
* The following characters will not be escaped:
*
@@ -15,9 +20,9 @@
* - The characters which are *not* safe to be in
* an URL because they are RESERVED characters.
*
- * We asume (lazily) that any RESERVED char that
+ * We assume (lazily) that any RESERVED char that
* appears inside an URL is actually meant to
- * have its native function (i.e. as an URL
+ * have its native function (i.e. as an URL
* component/separator) and hence needs no escaping.
*
* There are two exceptions: the chacters & (amp)
@@ -30,58 +35,55 @@
*
*/
static const uint8_t HREF_SAFE[UINT8_MAX+1] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
void
-hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
+hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size)
{
static const char hex_chars[] = "0123456789ABCDEF";
- size_t i = 0, org;
+ size_t i = 0, mark;
char hex_str[3];
hex_str[0] = '%';
while (i < size) {
- org = i;
- while (i < size && HREF_SAFE[src[i]] != 0)
- i++;
+ mark = i;
+ while (i < size && HREF_SAFE[data[i]]) i++;
- if (i > org) {
- if (org == 0) {
- if (i >= size) {
- hoedown_buffer_put(ob, src, size);
- return;
- }
-
- }
+ /* Optimization for cases where there's nothing to escape */
+ if (mark == 0 && i >= size) {
+ hoedown_buffer_put(ob, data, size);
+ return;
+ }
- hoedown_buffer_put(ob, src + org, i - org);
+ if (likely(i > mark)) {
+ hoedown_buffer_put(ob, data + mark, i - mark);
}
/* escaping */
if (i >= size)
break;
- switch (src[i]) {
+ switch (data[i]) {
/* amp appears all the time in URLs, but needs
* HTML-entity escaping to be inside an href */
- case '&':
+ case '&':
HOEDOWN_BUFPUTSL(ob, "&amp;");
break;
@@ -91,7 +93,7 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
case '\'':
HOEDOWN_BUFPUTSL(ob, "&#x27;");
break;
-
+
/* the space can be escaped to %20 or a plus
* sign. we're going with the generic escape
* for now. the plus thing is more commonly seen
@@ -104,15 +106,16 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
/* every other character goes with a %XX escaping */
default:
- hex_str[1] = hex_chars[(src[i] >> 4) & 0xF];
- hex_str[2] = hex_chars[src[i] & 0xF];
- hoedown_buffer_put(ob, hex_str, 3);
+ hex_str[1] = hex_chars[(data[i] >> 4) & 0xF];
+ hex_str[2] = hex_chars[data[i] & 0xF];
+ hoedown_buffer_put(ob, (uint8_t *)hex_str, 3);
}
i++;
}
}
+
/**
* According to the OWASP rules:
*
@@ -125,21 +128,21 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
*
*/
static const uint8_t HTML_ESCAPE_TABLE[UINT8_MAX+1] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
@@ -154,36 +157,30 @@ static const char *HTML_ESCAPES[] = {
};
void
-hoedown_escape_html(hoedown_buffer *ob, const uint8_t *src, size_t size, int secure)
+hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure)
{
- size_t i = 0, org, esc = 0;
-
- while (i < size) {
- org = i;
- while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)
- i++;
-
- if (i > org) {
- if (org == 0) {
- if (i >= size) {
- hoedown_buffer_put(ob, src, size);
- return;
- }
+ size_t i = 0, mark;
- }
+ while (1) {
+ mark = i;
+ while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++;
- hoedown_buffer_put(ob, src + org, i - org);
+ /* Optimization for cases where there's nothing to escape */
+ if (mark == 0 && i >= size) {
+ hoedown_buffer_put(ob, data, size);
+ return;
}
- /* escaping */
- if (i >= size)
- break;
+ if (likely(i > mark))
+ hoedown_buffer_put(ob, data + mark, i - mark);
+
+ if (i >= size) break;
/* The forward slash is only escaped in secure mode */
- if (src[i] == '/' && !secure) {
+ if (!secure && data[i] == '/') {
hoedown_buffer_putc(ob, '/');
} else {
- hoedown_buffer_puts(ob, HTML_ESCAPES[esc]);
+ hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]);
}
i++;
diff --git a/src/escape.h b/src/escape.h
index 95be860..d7659c2 100644
--- a/src/escape.h
+++ b/src/escape.h
@@ -9,8 +9,17 @@
extern "C" {
#endif
-extern void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *src, size_t size, int secure);
-extern void hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size);
+
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* hoedown_escape_href: escape (part of) a URL inside HTML */
+void hoedown_escape_href(hoedown_buffer *ob, const uint8_t *data, size_t size);
+
+/* hoedown_escape_html: escape HTML */
+void hoedown_escape_html(hoedown_buffer *ob, const uint8_t *data, size_t size, int secure);
+
#ifdef __cplusplus
}
diff --git a/src/html.c b/src/html.c
index 1c65578..b5101c1 100644
--- a/src/html.c
+++ b/src/html.c
@@ -9,45 +9,45 @@
#define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML)
-int
-hoedown_html_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname)
+hoedown_html_tag
+hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname)
{
size_t i;
int closed = 0;
- if (tag_size < 3 || tag_data[0] != '<')
+ if (size < 3 || data[0] != '<')
return HOEDOWN_HTML_TAG_NONE;
i = 1;
- if (tag_data[i] == '/') {
+ if (data[i] == '/') {
closed = 1;
i++;
}
- for (; i < tag_size; ++i, ++tagname) {
+ for (; i < size; ++i, ++tagname) {
if (*tagname == 0)
break;
- if (tag_data[i] != *tagname)
+ if (data[i] != *tagname)
return HOEDOWN_HTML_TAG_NONE;
}
- if (i == tag_size)
+ if (i == size)
return HOEDOWN_HTML_TAG_NONE;
- if (isspace(tag_data[i]) || tag_data[i] == '>')
+ if (isspace(data[i]) || data[i] == '>')
return closed ? HOEDOWN_HTML_TAG_CLOSE : HOEDOWN_HTML_TAG_OPEN;
return HOEDOWN_HTML_TAG_NONE;
}
-static inline void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length)
+static void escape_html(hoedown_buffer *ob, const uint8_t *source, size_t length)
{
hoedown_escape_html(ob, source, length, 0);
}
-static inline void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length)
+static void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t length)
{
hoedown_escape_href(ob, source, length);
}
@@ -56,18 +56,13 @@ static inline void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t
* GENERIC RENDERER *
********************/
static int
-rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autolink type, void *opaque)
+rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (!link || !link->size)
return 0;
- if ((state->flags & HOEDOWN_HTML_SAFELINK) != 0 &&
- !hoedown_autolink_is_safe(link->data, link->size) &&
- type != HOEDOWN_AUTOLINK_EMAIL)
- return 0;
-
HOEDOWN_BUFPUTSL(ob, "<a href=\"");
if (type == HOEDOWN_AUTOLINK_EMAIL)
HOEDOWN_BUFPUTSL(ob, "mailto:");
@@ -75,7 +70,7 @@ rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autol
if (state->link_attributes) {
hoedown_buffer_putc(ob, '\"');
- state->link_attributes(ob, link, opaque);
+ state->link_attributes(ob, link, data);
hoedown_buffer_putc(ob, '>');
} else {
HOEDOWN_BUFPUTSL(ob, "\">");
@@ -98,7 +93,7 @@ rndr_autolink(hoedown_buffer *ob, const hoedown_buffer *link, enum hoedown_autol
}
static void
-rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, void *opaque)
+rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buffer *lang, const hoedown_renderer_data *data)
{
if (ob->size) hoedown_buffer_putc(ob, '\n');
@@ -117,16 +112,16 @@ rndr_blockcode(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_buf
}
static void
-rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_blockquote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
if (ob->size) hoedown_buffer_putc(ob, '\n');
HOEDOWN_BUFPUTSL(ob, "<blockquote>\n");
- if (text) hoedown_buffer_put(ob, text->data, text->size);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</blockquote>\n");
}
static int
-rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
{
HOEDOWN_BUFPUTSL(ob, "<code>");
if (text) escape_html(ob, text->data, text->size);
@@ -135,91 +130,91 @@ rndr_codespan(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
}
static int
-rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_strikethrough(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size)
+ if (!content || !content->size)
return 0;
HOEDOWN_BUFPUTSL(ob, "<del>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</del>");
return 1;
}
static int
-rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_double_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size)
+ if (!content || !content->size)
return 0;
HOEDOWN_BUFPUTSL(ob, "<strong>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</strong>");
return 1;
}
static int
-rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size) return 0;
+ if (!content || !content->size) return 0;
HOEDOWN_BUFPUTSL(ob, "<em>");
- if (text) hoedown_buffer_put(ob, text->data, text->size);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</em>");
return 1;
}
static int
-rndr_underline(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_underline(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size)
+ if (!content || !content->size)
return 0;
HOEDOWN_BUFPUTSL(ob, "<u>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</u>");
return 1;
}
static int
-rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_highlight(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size)
+ if (!content || !content->size)
return 0;
HOEDOWN_BUFPUTSL(ob, "<mark>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</mark>");
return 1;
}
static int
-rndr_quote(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_quote(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size)
+ if (!content || !content->size)
return 0;
HOEDOWN_BUFPUTSL(ob, "<q>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</q>");
return 1;
}
static int
-rndr_linebreak(hoedown_buffer *ob, void *opaque)
+rndr_linebreak(hoedown_buffer *ob, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<br/>\n" : "<br>\n");
return 1;
}
static void
-rndr_header(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaque)
+rndr_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (ob->size)
hoedown_buffer_putc(ob, '\n');
@@ -229,17 +224,14 @@ rndr_header(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opa
else
hoedown_buffer_printf(ob, "<h%d>", level);
- if (text) hoedown_buffer_put(ob, text->data, text->size);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
hoedown_buffer_printf(ob, "</h%d>\n", level);
}
static int
-rndr_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque)
+rndr_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
-
- if (link != NULL && (state->flags & HOEDOWN_HTML_SAFELINK) != 0 && !hoedown_autolink_is_safe(link->data, link->size))
- return 0;
+ hoedown_html_renderer_state *state = data->opaque;
HOEDOWN_BUFPUTSL(ob, "<a href=\"");
@@ -253,7 +245,7 @@ rndr_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *
if (state->link_attributes) {
hoedown_buffer_putc(ob, '\"');
- state->link_attributes(ob, link, opaque);
+ state->link_attributes(ob, link, data);
hoedown_buffer_putc(ob, '>');
} else {
HOEDOWN_BUFPUTSL(ob, "\">");
@@ -265,110 +257,120 @@ rndr_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *
}
static void
-rndr_list(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque)
+rndr_list(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
{
if (ob->size) hoedown_buffer_putc(ob, '\n');
- hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5);
- if (text) hoedown_buffer_put(ob, text->data, text->size);
- hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n", 6);
+ hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n"), 5);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
+ hoedown_buffer_put(ob, (const uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n"), 6);
}
static void
-rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque)
+rndr_listitem(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_list_flags flags, const hoedown_renderer_data *data)
{
HOEDOWN_BUFPUTSL(ob, "<li>");
- if (text) {
- size_t size = text->size;
- while (size && text->data[size - 1] == '\n')
+ if (content) {
+ size_t size = content->size;
+ while (size && content->data[size - 1] == '\n')
size--;
- hoedown_buffer_put(ob, text->data, size);
+ hoedown_buffer_put(ob, content->data, size);
}
HOEDOWN_BUFPUTSL(ob, "</li>\n");
}
static void
-rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_paragraph(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
size_t i = 0;
if (ob->size) hoedown_buffer_putc(ob, '\n');
- if (!text || !text->size)
+ if (!content || !content->size)
return;
- while (i < text->size && isspace(text->data[i])) i++;
+ while (i < content->size && isspace(content->data[i])) i++;
- if (i == text->size)
+ if (i == content->size)
return;
HOEDOWN_BUFPUTSL(ob, "<p>");
if (state->flags & HOEDOWN_HTML_HARD_WRAP) {
size_t org;
- while (i < text->size) {
+ while (i < content->size) {
org = i;
- while (i < text->size && text->data[i] != '\n')
+ while (i < content->size && content->data[i] != '\n')
i++;
if (i > org)
- hoedown_buffer_put(ob, text->data + org, i - org);
+ hoedown_buffer_put(ob, content->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)
+ if (i >= content->size - 1)
break;
- rndr_linebreak(ob, opaque);
+ rndr_linebreak(ob, data);
i++;
}
} else {
- hoedown_buffer_put(ob, &text->data[i], text->size - i);
+ hoedown_buffer_put(ob, content->data + i, content->size - i);
}
HOEDOWN_BUFPUTSL(ob, "</p>\n");
}
static void
-rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_raw_block(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
{
size_t org, sz;
- if (!text) return;
- //FIXME: do we *really* need to trim the HTML?
- //how does that make a difference?
+
+ if (!text)
+ return;
+
+ /* FIXME: Do we *really* need to trim the HTML? How does that make a difference? */
sz = text->size;
- while (sz > 0 && text->data[sz - 1] == '\n') sz--;
+ while (sz > 0 && text->data[sz - 1] == '\n')
+ sz--;
+
org = 0;
- while (org < sz && text->data[org] == '\n') org++;
- if (org >= sz) return;
- if (ob->size) hoedown_buffer_putc(ob, '\n');
+ while (org < sz && text->data[org] == '\n')
+ org++;
+
+ if (org >= sz)
+ return;
+
+ if (ob->size)
+ hoedown_buffer_putc(ob, '\n');
+
hoedown_buffer_put(ob, text->data + org, sz - org);
hoedown_buffer_putc(ob, '\n');
}
static int
-rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_triple_emphasis(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size) return 0;
+ if (!content || !content->size) return 0;
HOEDOWN_BUFPUTSL(ob, "<strong><em>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</em></strong>");
return 1;
}
static void
-rndr_hrule(hoedown_buffer *ob, void *opaque)
+rndr_hrule(hoedown_buffer *ob, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (ob->size) hoedown_buffer_putc(ob, '\n');
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n");
}
static int
-rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, void *opaque)
+rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *alt, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (!link || !link->size) return 0;
HOEDOWN_BUFPUTSL(ob, "<img src=\"");
@@ -387,9 +389,9 @@ rndr_image(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer
}
static int
-rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
/* ESCAPE overrides SKIP_HTML. It doesn't look to see if
* there are any valid tags, just escapes all of them. */
@@ -406,29 +408,42 @@ rndr_raw_html(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
}
static void
-rndr_table(hoedown_buffer *ob, const hoedown_buffer *header, const hoedown_buffer *body, void *opaque)
+rndr_table(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (ob->size) hoedown_buffer_putc(ob, '\n');
- HOEDOWN_BUFPUTSL(ob, "<table><thead>\n");
- if (header)
- hoedown_buffer_put(ob, header->data, header->size);
- HOEDOWN_BUFPUTSL(ob, "</thead><tbody>\n");
- if (body)
- hoedown_buffer_put(ob, body->data, body->size);
- HOEDOWN_BUFPUTSL(ob, "</tbody></table>\n");
+ if (ob->size) hoedown_buffer_putc(ob, '\n');
+ HOEDOWN_BUFPUTSL(ob, "<table>\n");
+ hoedown_buffer_put(ob, content->data, content->size);
+ HOEDOWN_BUFPUTSL(ob, "</table>\n");
}
static void
-rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_table_header(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
+{
+ if (ob->size) hoedown_buffer_putc(ob, '\n');
+ HOEDOWN_BUFPUTSL(ob, "<thead>\n");
+ hoedown_buffer_put(ob, content->data, content->size);
+ HOEDOWN_BUFPUTSL(ob, "</thead>\n");
+}
+
+static void
+rndr_table_body(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
+{
+ if (ob->size) hoedown_buffer_putc(ob, '\n');
+ HOEDOWN_BUFPUTSL(ob, "<tbody>\n");
+ hoedown_buffer_put(ob, content->data, content->size);
+ HOEDOWN_BUFPUTSL(ob, "</tbody>\n");
+}
+
+static void
+rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
HOEDOWN_BUFPUTSL(ob, "<tr>\n");
- if (text)
- hoedown_buffer_put(ob, text->data, text->size);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</tr>\n");
}
static void
-rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque)
+rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *content, hoedown_table_flags flags, const hoedown_renderer_data *data)
{
if (flags & HOEDOWN_TABLE_HEADER) {
HOEDOWN_BUFPUTSL(ob, "<th");
@@ -453,8 +468,8 @@ rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flag
HOEDOWN_BUFPUTSL(ob, ">");
}
- if (text)
- hoedown_buffer_put(ob, text->data, text->size);
+ if (content)
+ hoedown_buffer_put(ob, content->data, content->size);
if (flags & HOEDOWN_TABLE_HEADER) {
HOEDOWN_BUFPUTSL(ob, "</th>\n");
@@ -464,88 +479,87 @@ rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flag
}
static int
-rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_superscript(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (!text || !text->size) return 0;
+ if (!content || !content->size) return 0;
HOEDOWN_BUFPUTSL(ob, "<sup>");
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</sup>");
return 1;
}
static void
-rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_normal_text(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- if (text)
- escape_html(ob, text->data, text->size);
+ if (content)
+ escape_html(ob, content->data, content->size);
}
static void
-rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
+rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (ob->size) hoedown_buffer_putc(ob, '\n');
HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n");
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n");
HOEDOWN_BUFPUTSL(ob, "<ol>\n");
-
- if (text)
- hoedown_buffer_put(ob, text->data, text->size);
-
+
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
+
HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n");
}
static void
-rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int num, void *opaque)
+rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *content, unsigned int num, const hoedown_renderer_data *data)
{
size_t i = 0;
int pfound = 0;
-
+
/* insert anchor at the end of first paragraph block */
- if (text) {
- while ((i+3) < text->size) {
- if (text->data[i++] != '<') continue;
- if (text->data[i++] != '/') continue;
- if (text->data[i++] != 'p' && text->data[i] != 'P') continue;
- if (text->data[i] != '>') continue;
+ if (content) {
+ while ((i+3) < content->size) {
+ if (content->data[i++] != '<') continue;
+ if (content->data[i++] != '/') continue;
+ if (content->data[i++] != 'p' && content->data[i] != 'P') continue;
+ if (content->data[i] != '>') continue;
i -= 3;
pfound = 1;
break;
}
}
-
+
hoedown_buffer_printf(ob, "\n<li id=\"fn%d\">\n", num);
if (pfound) {
- hoedown_buffer_put(ob, text->data, i);
+ hoedown_buffer_put(ob, content->data, i);
hoedown_buffer_printf(ob, "&nbsp;<a href=\"#fnref%d\" rev=\"footnote\">&#8617;</a>", num);
- hoedown_buffer_put(ob, text->data + i, text->size - i);
- } else if (text) {
- hoedown_buffer_put(ob, text->data, text->size);
+ hoedown_buffer_put(ob, content->data + i, content->size - i);
+ } else if (content) {
+ hoedown_buffer_put(ob, content->data, content->size);
}
HOEDOWN_BUFPUTSL(ob, "</li>\n");
}
static int
-rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, void *opaque)
+rndr_footnote_ref(hoedown_buffer *ob, unsigned int num, const hoedown_renderer_data *data)
{
hoedown_buffer_printf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num);
return 1;
}
static int
-rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, void *opaque)
+rndr_math(hoedown_buffer *ob, const hoedown_buffer *text, int displaymode, const hoedown_renderer_data *data)
{
- hoedown_buffer_put(ob, displaymode ? "\\[" : "\\(", 2);
+ hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "\\("), 2);
escape_html(ob, text->data, text->size);
- hoedown_buffer_put(ob, displaymode ? "\\]" : "\\)", 2);
+ hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "\\)"), 2);
return 1;
}
static void
-toc_header(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaque)
+toc_header(hoedown_buffer *ob, const hoedown_buffer *content, int level, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state = data->opaque;
if (level <= state->toc_data.nesting_level) {
/* set the level offset if this is the first header
@@ -572,28 +586,34 @@ toc_header(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaq
}
hoedown_buffer_printf(ob, "<a href=\"#toc_%d\">", state->toc_data.header_count++);
- if (text) escape_html(ob, text->data, text->size);
+ if (content) hoedown_buffer_put(ob, content->data, content->size);
HOEDOWN_BUFPUTSL(ob, "</a>\n");
}
}
static int
-toc_link(hoedown_buffer *ob, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_buffer *content, void *opaque)
+toc_link(hoedown_buffer *ob, const hoedown_buffer *content, const hoedown_buffer *link, const hoedown_buffer *title, const hoedown_renderer_data *data)
{
- if (content && content->size)
- hoedown_buffer_put(ob, content->data, content->size);
+ if (content && content->size) hoedown_buffer_put(ob, content->data, content->size);
return 1;
}
static void
-toc_finalize(hoedown_buffer *ob, void *opaque)
+toc_finalize(hoedown_buffer *ob, int inline_render, const hoedown_renderer_data *data)
{
- hoedown_html_renderer_state *state = opaque;
+ hoedown_html_renderer_state *state;
+
+ if (inline_render)
+ return;
+
+ state = data->opaque;
while (state->toc_data.current_level > 0) {
HOEDOWN_BUFPUTSL(ob, "</li>\n</ul>\n");
state->toc_data.current_level--;
}
+
+ state->toc_data.header_count = 0;
}
hoedown_renderer *
@@ -604,7 +624,6 @@ hoedown_html_toc_renderer_new(int nesting_level)
NULL,
NULL,
- NULL,
toc_header,
NULL,
NULL,
@@ -615,6 +634,9 @@ hoedown_html_toc_renderer_new(int nesting_level)
NULL,
NULL,
NULL,
+ NULL,
+ NULL,
+ NULL,
NULL,
rndr_codespan,
@@ -626,15 +648,15 @@ hoedown_html_toc_renderer_new(int nesting_level)
NULL,
NULL,
toc_link,
- NULL,
rndr_triple_emphasis,
rndr_strikethrough,
rndr_superscript,
NULL,
NULL,
-
NULL,
+
NULL,
+ rndr_normal_text,
NULL,
toc_finalize
@@ -644,46 +666,40 @@ hoedown_html_toc_renderer_new(int nesting_level)
hoedown_renderer *renderer;
/* Prepare the state pointer */
- state = malloc(sizeof(hoedown_html_renderer_state));
- if (!state)
- return NULL;
-
+ state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
memset(state, 0x0, sizeof(hoedown_html_renderer_state));
state->toc_data.nesting_level = nesting_level;
/* Prepare the renderer */
- renderer = malloc(sizeof(hoedown_renderer));
- if (!renderer) {
- free(state);
- return NULL;
- }
-
+ renderer = hoedown_malloc(sizeof(hoedown_renderer));
memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
-
+
renderer->opaque = state;
return renderer;
}
hoedown_renderer *
-hoedown_html_renderer_new(unsigned int render_flags, int nesting_level)
+hoedown_html_renderer_new(hoedown_html_flags render_flags, int nesting_level)
{
- static const hoedown_renderer cb_default = {
+ static const hoedown_renderer cb_default = {
NULL,
rndr_blockcode,
rndr_blockquote,
- rndr_raw_block,
rndr_header,
rndr_hrule,
rndr_list,
rndr_listitem,
rndr_paragraph,
rndr_table,
+ rndr_table_header,
+ rndr_table_body,
rndr_tablerow,
rndr_tablecell,
rndr_footnotes,
rndr_footnote_def,
+ rndr_raw_block,
rndr_autolink,
rndr_codespan,
@@ -695,12 +711,12 @@ hoedown_html_renderer_new(unsigned int render_flags, int nesting_level)
rndr_image,
rndr_linebreak,
rndr_link,
- rndr_raw_html,
rndr_triple_emphasis,
rndr_strikethrough,
rndr_superscript,
rndr_footnote_ref,
rndr_math,
+ rndr_raw_html,
NULL,
rndr_normal_text,
@@ -713,27 +729,19 @@ hoedown_html_renderer_new(unsigned int render_flags, int nesting_level)
hoedown_renderer *renderer;
/* Prepare the state pointer */
- state = malloc(sizeof(hoedown_html_renderer_state));
- if (!state)
- return NULL;
-
+ state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
memset(state, 0x0, sizeof(hoedown_html_renderer_state));
state->flags = render_flags;
state->toc_data.nesting_level = nesting_level;
/* Prepare the renderer */
- renderer = malloc(sizeof(hoedown_renderer));
- if (!renderer) {
- free(state);
- return NULL;
- }
-
+ renderer = hoedown_malloc(sizeof(hoedown_renderer));
memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE)
renderer->blockhtml = NULL;
-
+
renderer->opaque = state;
return renderer;
}
diff --git a/src/html.h b/src/html.h
index 46b424b..e46e7fd 100644
--- a/src/html.h
+++ b/src/html.h
@@ -1,30 +1,38 @@
-/* html.h - HTML renderer */
+/* html.h - HTML renderer and utilities */
#ifndef HOEDOWN_HTML_H
#define HOEDOWN_HTML_H
#include "document.h"
#include "buffer.h"
-#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
-typedef enum {
+
+/*************
+ * CONSTANTS *
+ *************/
+
+typedef enum hoedown_html_flags {
HOEDOWN_HTML_SKIP_HTML = (1 << 0),
HOEDOWN_HTML_ESCAPE = (1 << 1),
- HOEDOWN_HTML_SAFELINK = (1 << 2),
- HOEDOWN_HTML_HARD_WRAP = (1 << 3),
- HOEDOWN_HTML_USE_XHTML = (1 << 4)
+ HOEDOWN_HTML_HARD_WRAP = (1 << 2),
+ HOEDOWN_HTML_USE_XHTML = (1 << 3)
} hoedown_html_flags;
-typedef enum {
+typedef enum hoedown_html_tag {
HOEDOWN_HTML_TAG_NONE = 0,
HOEDOWN_HTML_TAG_OPEN,
HOEDOWN_HTML_TAG_CLOSE
} hoedown_html_tag;
+
+/*********
+ * TYPES *
+ *********/
+
struct hoedown_html_renderer_state {
void *opaque;
@@ -35,28 +43,39 @@ struct hoedown_html_renderer_state {
int nesting_level;
} toc_data;
- unsigned int flags;
+ hoedown_html_flags flags;
/* extra callbacks */
- void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, void *self);
+ void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, const hoedown_renderer_data *data);
};
-
typedef struct hoedown_html_renderer_state hoedown_html_renderer_state;
-int
-hoedown_html_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname);
-extern hoedown_renderer *
-hoedown_html_renderer_new(unsigned int render_flags, int nesting_level);
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* hoedown_html_smartypants: process an HTML snippet using SmartyPants for smart punctuation */
+void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size);
+
+/* hoedown_html_is_tag: checks if data starts with a specific tag, returns the tag type or NONE */
+hoedown_html_tag hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname);
+
+
+/* hoedown_html_renderer_new: allocates a regular HTML renderer */
+hoedown_renderer *hoedown_html_renderer_new(
+ hoedown_html_flags render_flags,
+ int nesting_level
+) __attribute__ ((malloc));
-extern hoedown_renderer *
-hoedown_html_toc_renderer_new(int nesting_level);
+/* hoedown_html_toc_renderer_new: like hoedown_html_renderer_new, but the returned renderer produces the Table of Contents */
+hoedown_renderer *hoedown_html_toc_renderer_new(
+ int nesting_level
+) __attribute__ ((malloc));
-extern void
-hoedown_html_renderer_free(hoedown_renderer *renderer);
+/* hoedown_html_renderer_free: deallocate an HTML renderer */
+void hoedown_html_renderer_free(hoedown_renderer *renderer);
-extern void
-hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *text, size_t size);
#ifdef __cplusplus
}
diff --git a/src/html_smartypants.c b/src/html_smartypants.c
index 9f9dcf0..b0904da 100644
--- a/src/html_smartypants.c
+++ b/src/html_smartypants.c
@@ -60,7 +60,7 @@ static const uint8_t smartypants_cb_chars[UINT8_MAX+1] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
-static inline int
+static int
word_boundary(uint8_t c)
{
return c == 0 || isspace(c) || ispunct(c);
@@ -313,6 +313,16 @@ smartypants_cb__ltag(hoedown_buffer *ob, struct smartypants_data *smrt, uint8_t
size_t tag, i = 0;
+ /* This is a comment. Copy everything verbatim until --> or EOF is seen. */
+ if (i + 4 < size && memcmp(text, "<!--", 4) == 0) {
+ i += 4;
+ while (i + 3 < size && memcmp(text + i, "-->", 3) != 0)
+ i++;
+ i += 3;
+ hoedown_buffer_put(ob, text, i + 1);
+ return i;
+ }
+
while (i < size && text[i] != '>')
i++;
diff --git a/src/stack.c b/src/stack.c
index d0dea29..5c6102c 100644
--- a/src/stack.c
+++ b/src/stack.c
@@ -1,70 +1,66 @@
#include "stack.h"
+#include "buffer.h"
+
+#include <stdlib.h>
#include <string.h>
+#include <assert.h>
-int
-hoedown_stack_new(hoedown_stack *st, size_t initial_size)
+void
+hoedown_stack_init(hoedown_stack *st, size_t initial_size)
{
+ assert(st);
+
st->item = NULL;
- st->size = 0;
- st->asize = 0;
+ st->size = st->asize = 0;
if (!initial_size)
initial_size = 8;
- return hoedown_stack_grow(st, initial_size);
+ hoedown_stack_grow(st, initial_size);
}
void
-hoedown_stack_free(hoedown_stack *st)
+hoedown_stack_uninit(hoedown_stack *st)
{
- if (!st)
- return;
+ assert(st);
free(st->item);
-
- st->item = NULL;
- st->size = 0;
- st->asize = 0;
}
-int
-hoedown_stack_grow(hoedown_stack *st, size_t new_size)
+void
+hoedown_stack_grow(hoedown_stack *st, size_t neosz)
{
- void **new_st;
+ assert(st);
- if (st->asize >= new_size)
- return 0;
-
- new_st = realloc(st->item, new_size * sizeof(void *));
- if (new_st == NULL)
- return -1;
-
- memset(new_st + st->asize, 0x0,
- (new_size - st->asize) * sizeof(void *));
+ if (st->asize >= neosz)
+ return;
- st->item = new_st;
- st->asize = new_size;
+ st->item = hoedown_realloc(st->item, neosz * sizeof(void *));
+ memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *));
- if (st->size > new_size)
- st->size = new_size;
+ st->asize = neosz;
- return 0;
+ if (st->size > neosz)
+ st->size = neosz;
}
-int
+void
hoedown_stack_push(hoedown_stack *st, void *item)
{
- if (hoedown_stack_grow(st, st->size * 2) < 0)
- return -1;
+ assert(st);
+
+ if (st->size >= st->asize)
+ hoedown_stack_grow(st, st->size * 2);
st->item[st->size++] = item;
- return 0;
}
void *
hoedown_stack_pop(hoedown_stack *st)
{
+ assert(st);
+
if (!st->size)
return NULL;
@@ -72,8 +68,10 @@ hoedown_stack_pop(hoedown_stack *st)
}
void *
-hoedown_stack_top(hoedown_stack *st)
+hoedown_stack_top(const hoedown_stack *st)
{
+ assert(st);
+
if (!st->size)
return NULL;
diff --git a/src/stack.h b/src/stack.h
index 9063592..bf9b439 100644
--- a/src/stack.h
+++ b/src/stack.h
@@ -3,26 +3,47 @@
#ifndef HOEDOWN_STACK_H
#define HOEDOWN_STACK_H
-#include <stdlib.h>
+#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
+
+/*********
+ * TYPES *
+ *********/
+
struct hoedown_stack {
void **item;
size_t size;
size_t asize;
};
-
typedef struct hoedown_stack hoedown_stack;
-int hoedown_stack_new(hoedown_stack *, size_t);
-void hoedown_stack_free(hoedown_stack *);
-int hoedown_stack_grow(hoedown_stack *, size_t);
-int hoedown_stack_push(hoedown_stack *, void *);
-void *hoedown_stack_pop(hoedown_stack *);
-void *hoedown_stack_top(hoedown_stack *);
+
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* hoedown_stack_init: initialize a stack */
+void hoedown_stack_init(hoedown_stack *st, size_t initial_size);
+
+/* hoedown_stack_uninit: free internal data of the stack */
+void hoedown_stack_uninit(hoedown_stack *st);
+
+/* hoedown_stack_grow: increase the allocated size to the given value */
+void hoedown_stack_grow(hoedown_stack *st, size_t neosz);
+
+/* hoedown_stack_push: push an item to the top of the stack */
+void hoedown_stack_push(hoedown_stack *st, void *item);
+
+/* hoedown_stack_pop: retrieve and remove the item at the top of the stack */
+void *hoedown_stack_pop(hoedown_stack *st);
+
+/* hoedown_stack_top: retrieve the item at the top of the stack */
+void *hoedown_stack_top(const hoedown_stack *st);
+
#ifdef __cplusplus
}
diff --git a/src/version.c b/src/version.c
index 73a70bc..744209b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -1,9 +1,9 @@
#include "version.h"
void
-hoedown_version(int *ver_major, int *ver_minor, int *ver_revision)
+hoedown_version(int *major, int *minor, int *revision)
{
- *ver_major = HOEDOWN_VERSION_MAJOR;
- *ver_minor = HOEDOWN_VERSION_MINOR;
- *ver_revision = HOEDOWN_VERSION_REVISION;
+ *major = HOEDOWN_VERSION_MAJOR;
+ *minor = HOEDOWN_VERSION_MINOR;
+ *revision = HOEDOWN_VERSION_REVISION;
}
diff --git a/src/version.h b/src/version.h
index 3971658..d3247b6 100644
--- a/src/version.h
+++ b/src/version.h
@@ -7,13 +7,24 @@
extern "C" {
#endif
-#define HOEDOWN_VERSION "2.0.0"
-#define HOEDOWN_VERSION_MAJOR 2
+
+/*************
+ * CONSTANTS *
+ *************/
+
+#define HOEDOWN_VERSION "3.0.5"
+#define HOEDOWN_VERSION_MAJOR 3
#define HOEDOWN_VERSION_MINOR 0
-#define HOEDOWN_VERSION_REVISION 0
+#define HOEDOWN_VERSION_REVISION 5
+
+
+/*************
+ * FUNCTIONS *
+ *************/
+
+/* hoedown_version: retrieve Hoedown's version numbers */
+void hoedown_version(int *major, int *minor, int *revision);
-extern void
-hoedown_version(int *major, int *minor, int *revision);
#ifdef __cplusplus
}