Import improvements from Lanli (and more things)

This commit is contained in:
Xavier Mendez 2014-09-02 19:21:58 +02:00
parent c6238419ff
commit a6b90a7cf7
16 changed files with 457 additions and 399 deletions

View file

@ -1,4 +1,4 @@
CFLAGS = -g -O3 -Wall -Wextra -Wno-unused-parameter -Isrc CFLAGS = -g -O3 -Wall -Wextra -Wno-unused-parameter -Isrc -std=c99
ifneq ($(OS),Windows_NT) ifneq ($(OS),Windows_NT)
CFLAGS += -fPIC CFLAGS += -fPIC

View file

@ -399,20 +399,13 @@ main(int argc, char **argv)
/* reading everything */ /* reading everything */
ib = hoedown_buffer_new(iunit); ib = hoedown_buffer_new(iunit);
if (!ib) {
fprintf(stderr, "Couldn't allocate input buffer.\n");
return 4;
}
while (!feof(in)) { while (!feof(in)) {
if (ferror(in)) { if (ferror(in)) {
fprintf(stderr, "I/O errors found while reading input.\n"); fprintf(stderr, "I/O errors found while reading input.\n");
return 5; return 5;
} }
if (hoedown_buffer_grow(ib, ib->size + iunit) != HOEDOWN_BUF_OK) { hoedown_buffer_grow(ib, ib->size + iunit);
fprintf(stderr, "Couldn't grow input buffer.\n");
return 4;
}
ib->size += fread(ib->data + ib->size, 1, iunit, in); ib->size += fread(ib->data + ib->size, 1, iunit, in);
} }
@ -421,8 +414,8 @@ main(int argc, char **argv)
/* creating the renderer */ /* creating the renderer */
hoedown_renderer *renderer; hoedown_renderer *renderer = NULL;
void (*renderer_free)(hoedown_renderer*); void (*renderer_free)(hoedown_renderer*) = NULL;
switch (renderer_type) { switch (renderer_type) {
case RENDERER_HTML: case RENDERER_HTML:
@ -437,29 +430,12 @@ main(int argc, char **argv)
renderer = null_renderer_new(); renderer = null_renderer_new();
renderer_free = null_renderer_free; renderer_free = null_renderer_free;
break; break;
default:
renderer = NULL;
renderer_free = NULL;
}; };
if (!renderer) {
fprintf(stderr, "Couldn't allocate renderer.\n");
return 4;
}
/* performing markdown rendering */ /* performing markdown rendering */
ob = hoedown_buffer_new(ounit); ob = hoedown_buffer_new(ounit);
if (!ob) {
fprintf(stderr, "Couldn't allocate output buffer.\n");
return 4;
}
document = hoedown_document_new(renderer, extensions, max_nesting); document = hoedown_document_new(renderer, extensions, max_nesting);
if (!document) {
fprintf(stderr, "Couldn't allocate document parser.\n");
return 4;
}
//clock_gettime(CLOCK_MONOTONIC, &start); //clock_gettime(CLOCK_MONOTONIC, &start);
hoedown_document_render(document, ob, ib->data, ib->size); hoedown_document_render(document, ob, ib->data, ib->size);

View file

@ -183,20 +183,13 @@ main(int argc, char **argv)
/* reading everything */ /* reading everything */
ib = hoedown_buffer_new(iunit); ib = hoedown_buffer_new(iunit);
if (!ib) {
fprintf(stderr, "Couldn't allocate input buffer.\n");
return 4;
}
while (!feof(in)) { while (!feof(in)) {
if (ferror(in)) { if (ferror(in)) {
fprintf(stderr, "I/O errors found while reading input.\n"); fprintf(stderr, "I/O errors found while reading input.\n");
return 5; return 5;
} }
if (hoedown_buffer_grow(ib, ib->size + iunit) != HOEDOWN_BUF_OK) { hoedown_buffer_grow(ib, ib->size + iunit);
fprintf(stderr, "Couldn't grow input buffer.\n");
return 4;
}
ib->size += fread(ib->data + ib->size, 1, iunit, in); ib->size += fread(ib->data + ib->size, 1, iunit, in);
} }
@ -206,10 +199,6 @@ main(int argc, char **argv)
/* performing SmartyPants processing */ /* performing SmartyPants processing */
ob = hoedown_buffer_new(ounit); ob = hoedown_buffer_new(ounit);
if (!ob) {
fprintf(stderr, "Couldn't allocate output buffer.\n");
return 4;
}
//clock_gettime(CLOCK_MONOTONIC, &start); //clock_gettime(CLOCK_MONOTONIC, &start);
hoedown_html_smartypants(ob, ib->data, ib->size); hoedown_html_smartypants(ob, ib->data, ib->size);

View file

@ -10,21 +10,20 @@
#endif #endif
int 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 size_t valid_uris_count = 6;
static const char *valid_uris[] = { 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 (size_t i = 0; i < valid_uris_count; ++i) {
size_t len = valid_uris_size[i];
for (i = 0; i < valid_uris_count; ++i) { if (size > len &&
size_t len = strlen(valid_uris[i]); strncasecmp((char *)data, valid_uris[i], len) == 0 &&
isalnum(data[len]))
if (link_len > len &&
strncasecmp((char *)link, valid_uris[i], len) == 0 &&
isalnum(link[len]))
return 1; return 1;
} }

View file

@ -9,24 +9,35 @@
extern "C" { extern "C" {
#endif #endif
enum {
/*************
* CONSTANTS *
*************/
typedef enum hoedown_autolink_flags {
HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0) HOEDOWN_AUTOLINK_SHORT_DOMAINS = (1 << 0)
}; } hoedown_autolink_flags;
int
hoedown_autolink_is_safe(const uint8_t *link, size_t link_len);
size_t /*************
hoedown_autolink__www(size_t *rewind_p, hoedown_buffer *link, * FUNCTIONS *
uint8_t *data, size_t offset, size_t size, unsigned int flags); *************/
size_t /* hoedown_autolink_is_safe: verify that a URL has a safe protocol */
hoedown_autolink__email(size_t *rewind_p, hoedown_buffer *link, int hoedown_autolink_is_safe(const uint8_t *data, size_t size);
uint8_t *data, size_t offset, size_t size, unsigned int flags);
/* 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);
/* 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);
/* 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 #ifdef __cplusplus
} }

View file

@ -5,7 +5,6 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
/* hoedown_buffer_init: initialize a buffer with custom allocators */
void void
hoedown_buffer_init( hoedown_buffer_init(
hoedown_buffer *buf, hoedown_buffer *buf,
@ -14,8 +13,7 @@ hoedown_buffer_init(
hoedown_free_callback data_free, hoedown_free_callback data_free,
hoedown_free_callback buffer_free) hoedown_free_callback buffer_free)
{ {
if (!buf) assert(buf);
return;
buf->data = NULL; buf->data = NULL;
buf->size = buf->asize = 0; buf->size = buf->asize = 0;
@ -25,21 +23,18 @@ hoedown_buffer_init(
buf->buffer_free = buffer_free; buf->buffer_free = buffer_free;
} }
/* hoedown_buffer_new: allocation of a new buffer */
hoedown_buffer * hoedown_buffer *
hoedown_buffer_new(size_t unit) hoedown_buffer_new(size_t unit)
{ {
hoedown_buffer *ret = malloc(sizeof (hoedown_buffer)); hoedown_buffer *ret = hoedown_malloc(sizeof (hoedown_buffer));
hoedown_buffer_init(ret, unit, realloc, free, free); hoedown_buffer_init(ret, unit, hoedown_realloc, free, free);
return ret; return ret;
} }
/* hoedown_buffer_free: decrease the reference count and free the buffer if needed */
void void
hoedown_buffer_free(hoedown_buffer *buf) hoedown_buffer_free(hoedown_buffer *buf)
{ {
if (!buf) if (!buf) return;
return;
buf->data_free(buf->data); buf->data_free(buf->data);
@ -47,84 +42,104 @@ hoedown_buffer_free(hoedown_buffer *buf)
buf->buffer_free(buf); buf->buffer_free(buf);
} }
/* hoedown_buffer_reset: frees internal data of the buffer */
void void
hoedown_buffer_reset(hoedown_buffer *buf) hoedown_buffer_reset(hoedown_buffer *buf)
{ {
if (!buf) assert(buf && buf->unit);
return;
buf->data_free(buf->data); buf->data_free(buf->data);
buf->data = NULL; buf->data = NULL;
buf->size = buf->asize = 0; buf->size = buf->asize = 0;
} }
/* hoedown_buffer_grow: increasing the allocated size to the given value */ void
int
hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz) hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz)
{ {
size_t neoasz; size_t neoasz;
void *neodata;
assert(buf && buf->unit); assert(buf && buf->unit);
if (buf->asize >= neosz) if (buf->asize >= neosz)
return HOEDOWN_BUF_OK; return;
neoasz = buf->asize + buf->unit; neoasz = buf->asize + buf->unit;
while (neoasz < neosz) while (neoasz < neosz)
neoasz += buf->unit; neoasz += buf->unit;
neodata = buf->data_realloc(buf->data, neoasz); buf->data = buf->data_realloc(buf->data, neoasz);
if (!neodata)
return HOEDOWN_BUF_ENOMEM;
buf->data = neodata;
buf->asize = neoasz; buf->asize = neoasz;
return HOEDOWN_BUF_OK;
} }
/* hoedown_buffer_put: appends raw data to a buffer */
void 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); assert(buf && buf->unit);
if (buf->size + len > buf->asize && hoedown_buffer_grow(buf, buf->size + len) < 0) if (buf->size + size > buf->asize)
return; hoedown_buffer_grow(buf, buf->size + size);
memcpy(buf->data + buf->size, data, len); memcpy(buf->data + buf->size, data, size);
buf->size += len; buf->size += size;
} }
/* hoedown_buffer_puts: appends a NUL-terminated string to a buffer */
void void
hoedown_buffer_puts(hoedown_buffer *buf, const char *str) 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 void
hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c) hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c)
{ {
assert(buf && buf->unit); assert(buf && buf->unit);
if (buf->size + 1 > buf->asize && hoedown_buffer_grow(buf, buf->size + 1) < 0) if (buf->size >= buf->asize)
return; hoedown_buffer_grow(buf, buf->size + 1);
buf->data[buf->size] = c; buf->data[buf->size] = c;
buf->size += 1; buf->size += 1;
} }
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;
size_t i = 0;
while (i < size && buf->data[i] == data[i]) i++;
return i == size;
}
int
hoedown_buffer_eqs(const hoedown_buffer *buf, const char *str)
{
return hoedown_buffer_eq(buf, (const uint8_t *)str, strlen(str));
}
int int
hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix) hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
{ {
size_t i;
assert(buf && buf->unit); assert(buf && buf->unit);
for (i = 0; i < buf->size; ++i) { for (size_t i = 0; i < buf->size; ++i) {
if (prefix[i] == 0) if (prefix[i] == 0)
return 0; return 0;
@ -135,22 +150,20 @@ hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix)
return 0; return 0;
} }
/* hoedown_buffer_slurp: removes a given number of bytes from the head of the array */
void void
hoedown_buffer_slurp(hoedown_buffer *buf, size_t len) hoedown_buffer_slurp(hoedown_buffer *buf, size_t size)
{ {
assert(buf && buf->unit); assert(buf && buf->unit);
if (len >= buf->size) { if (size >= buf->size) {
buf->size = 0; buf->size = 0;
return; return;
} }
buf->size -= len; buf->size -= size;
memmove(buf->data, buf->data + len, buf->size); memmove(buf->data, buf->data + size, buf->size);
} }
/* hoedown_buffer_cstr: NULL-termination of the string array */
const char * const char *
hoedown_buffer_cstr(hoedown_buffer *buf) hoedown_buffer_cstr(hoedown_buffer *buf)
{ {
@ -159,15 +172,12 @@ hoedown_buffer_cstr(hoedown_buffer *buf)
if (buf->size < buf->asize && buf->data[buf->size] == 0) if (buf->size < buf->asize && buf->data[buf->size] == 0)
return (char *)buf->data; return (char *)buf->data;
if (buf->size + 1 <= buf->asize || hoedown_buffer_grow(buf, buf->size + 1) == 0) { hoedown_buffer_grow(buf, buf->size + 1);
buf->data[buf->size] = 0; buf->data[buf->size] = 0;
return (char *)buf->data;
}
return NULL; return (char *)buf->data;
} }
/* hoedown_buffer_printf: formatted printing to a buffer */
void void
hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
{ {
@ -176,9 +186,9 @@ hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
assert(buf && buf->unit); assert(buf && buf->unit);
if (buf->size >= buf->asize && hoedown_buffer_grow(buf, buf->size + 1) < 0) if (buf->size >= buf->asize)
return; hoedown_buffer_grow(buf, buf->size + 1);
va_start(ap, fmt); va_start(ap, fmt);
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
va_end(ap); va_end(ap);
@ -194,8 +204,7 @@ hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...)
} }
if ((size_t)n >= buf->asize - buf->size) { if ((size_t)n >= buf->asize - buf->size) {
if (hoedown_buffer_grow(buf, buf->size + n + 1) < 0) hoedown_buffer_grow(buf, buf->size + n + 1);
return;
va_start(ap, fmt); va_start(ap, fmt);
n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); n = vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);

View file

@ -3,9 +3,11 @@
#ifndef HOEDOWN_BUFFER_H #ifndef HOEDOWN_BUFFER_H
#define HOEDOWN_BUFFER_H #define HOEDOWN_BUFFER_H
#include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -16,15 +18,14 @@ extern "C" {
#define inline __inline #define inline __inline
#endif #endif
typedef enum {
HOEDOWN_BUF_OK = 0, /*********
HOEDOWN_BUF_ENOMEM = -1 * TYPES *
} hoedown_buferror_t; *********/
typedef void *(*hoedown_realloc_callback)(void *, size_t); typedef void *(*hoedown_realloc_callback)(void *, size_t);
typedef void (*hoedown_free_callback)(void *); typedef void (*hoedown_free_callback)(void *);
/* hoedown_buffer: character array buffer */
struct hoedown_buffer { struct hoedown_buffer {
uint8_t *data; /* actual character data */ uint8_t *data; /* actual character data */
size_t size; /* size of the string */ size_t size; /* size of the string */
@ -35,12 +36,29 @@ struct hoedown_buffer {
hoedown_free_callback data_free; hoedown_free_callback data_free;
hoedown_free_callback buffer_free; hoedown_free_callback buffer_free;
}; };
typedef struct hoedown_buffer hoedown_buffer; typedef struct hoedown_buffer hoedown_buffer;
/* HOEDOWN_BUFPUTSL: optimized hoedown_buffer_puts of a string literal */ /* malloc / realloc / calloc wrappers */
#define HOEDOWN_BUFPUTSL(output, literal) \ #define HOEDOWN_ALLOC_WRAPPER(sig, call) \
hoedown_buffer_put(output, literal, sizeof(literal) - 1) static inline void *hoedown_##sig __attribute__ ((malloc)); \
static inline void *hoedown_##sig { \
void *ret = call; \
if (!ret) { \
fprintf(stderr, "Allocation failed.\n"); \
abort(); \
} \
return ret; \
}
/*************
* FUNCTIONS *
*************/
/* allocation wrappers */
HOEDOWN_ALLOC_WRAPPER(malloc(size_t size), malloc(size));
HOEDOWN_ALLOC_WRAPPER(calloc(size_t nmemb, size_t size), calloc(nmemb, size));
HOEDOWN_ALLOC_WRAPPER(realloc(void *ptr, size_t size), realloc(ptr, size));
/* hoedown_buffer_init: initialize a buffer with custom allocators */ /* hoedown_buffer_init: initialize a buffer with custom allocators */
void hoedown_buffer_init( void hoedown_buffer_init(
@ -51,32 +69,41 @@ void hoedown_buffer_init(
hoedown_free_callback buffer_free hoedown_free_callback buffer_free
); );
/* hoedown_buffer_new: allocation of a new buffer */ /* hoedown_buffer_new: allocate a new buffer */
hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc)); hoedown_buffer *hoedown_buffer_new(size_t unit) __attribute__ ((malloc));
/* hoedown_buffer_free: decrease the reference count and free the buffer if needed */ /* hoedown_buffer_reset: free internal data of the buffer */
void hoedown_buffer_free(hoedown_buffer *buf);
/* hoedown_buffer_reset: frees internal data of the buffer */
void hoedown_buffer_reset(hoedown_buffer *buf); void hoedown_buffer_reset(hoedown_buffer *buf);
/* hoedown_buffer_grow: increasing the allocated size to the given value */ /* hoedown_buffer_grow: increase the allocated size to the given value */
int hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz); void hoedown_buffer_grow(hoedown_buffer *buf, size_t neosz);
/* hoedown_buffer_put: appends raw data to a buffer */ /* hoedown_buffer_put: append raw data to a buffer */
void hoedown_buffer_put(hoedown_buffer *buf, const void *data, size_t len); 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); 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); void hoedown_buffer_putc(hoedown_buffer *buf, uint8_t c);
/* 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 */ /* hoedown_buffer_prefix: compare the beginning of a buffer with a string */
int hoedown_buffer_prefix(const hoedown_buffer *buf, const char *prefix); 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 */ /* hoedown_buffer_slurp: remove a given number of bytes from the head of the buffer */
void hoedown_buffer_slurp(hoedown_buffer *buf, size_t len); void hoedown_buffer_slurp(hoedown_buffer *buf, size_t size);
/* hoedown_buffer_cstr: NUL-termination of the string array (making a C-string) */ /* hoedown_buffer_cstr: NUL-termination of the string array (making a C-string) */
const char *hoedown_buffer_cstr(hoedown_buffer *buf); const char *hoedown_buffer_cstr(hoedown_buffer *buf);
@ -84,6 +111,23 @@ const char *hoedown_buffer_cstr(hoedown_buffer *buf);
/* hoedown_buffer_printf: formatted printing to a buffer */ /* hoedown_buffer_printf: formatted printing to a buffer */
void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void hoedown_buffer_printf(hoedown_buffer *buf, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
/* 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -1,5 +1,3 @@
/* document.c - generic markdown parser */
#include "document.h" #include "document.h"
#include <assert.h> #include <assert.h>
@ -120,7 +118,7 @@ struct hoedown_document {
struct footnote_list footnotes_used; struct footnote_list footnotes_used;
uint8_t active_char[256]; uint8_t active_char[256];
hoedown_stack work_bufs[2]; hoedown_stack work_bufs[2];
unsigned int ext_flags; hoedown_extensions ext_flags;
size_t max_nesting; size_t max_nesting;
int in_link_body; int in_link_body;
}; };
@ -191,10 +189,7 @@ add_link_ref(
struct link_ref **references, struct link_ref **references,
const uint8_t *name, size_t name_size) const uint8_t *name, size_t name_size)
{ {
struct link_ref *ref = calloc(1, sizeof(struct link_ref)); struct link_ref *ref = hoedown_calloc(1, sizeof(struct link_ref));
if (!ref)
return NULL;
ref->id = hash_link_ref(name, name_size); ref->id = hash_link_ref(name, name_size);
ref->next = references[ref->id % REF_TABLE_SIZE]; ref->next = references[ref->id % REF_TABLE_SIZE];
@ -243,9 +238,7 @@ free_link_refs(struct link_ref **references)
static struct footnote_ref * static struct footnote_ref *
create_footnote_ref(struct footnote_list *list, const uint8_t *name, size_t name_size) 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)); struct footnote_ref *ref = hoedown_calloc(1, sizeof(struct footnote_ref));
if (!ref)
return NULL;
ref->id = hash_link_ref(name, name_size); ref->id = hash_link_ref(name, name_size);
@ -255,7 +248,7 @@ create_footnote_ref(struct footnote_list *list, const uint8_t *name, size_t name
static int static int
add_footnote_ref(struct footnote_list *list, struct footnote_ref *ref) 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) if (!item)
return 0; return 0;
item->ref = ref; item->ref = ref;
@ -388,7 +381,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 */ /* tag_length • returns the length of the given tag, or 0 is it's not valid */
static size_t 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; size_t i, j;
@ -453,8 +446,8 @@ static void
parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size)
{ {
size_t i = 0, end = 0; size_t i = 0, end = 0;
uint8_t action = 0;
hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL };
uint8_t *active_char = doc->active_char;
if (doc->work_bufs[BUFFER_SPAN].size + if (doc->work_bufs[BUFFER_SPAN].size +
doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting) doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting)
@ -462,9 +455,8 @@ parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t si
while (i < size) { while (i < size) {
/* copying inactive chars into the output */ /* 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++; end++;
}
if (doc->md.normal_text) { if (doc->md.normal_text) {
work.data = data + i; work.data = data + i;
@ -477,7 +469,7 @@ parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t si
if (end >= size) break; if (end >= size) break;
i = end; 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, size - i);
if (!end) /* no action from the callback */ if (!end) /* no action from the callback */
end = i + 1; end = i + 1;
else { else {
@ -907,7 +899,7 @@ char_entity(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off
static size_t static size_t
char_langle_tag(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) 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_autolink_type altype = HOEDOWN_AUTOLINK_NONE;
size_t end = tag_length(data, size, &altype); size_t end = tag_length(data, size, &altype);
hoedown_buffer work = { data, end, 0, 0, NULL, NULL, NULL }; hoedown_buffer work = { data, end, 0, 0, NULL, NULL, NULL };
int ret = 0; int ret = 0;
@ -1744,7 +1736,7 @@ parse_blockcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* parse_listitem • parsing of a single list item */ /* parse_listitem • parsing of a single list item */
/* assuming initial prefix is already removed */ /* assuming initial prefix is already removed */
static size_t 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_listflags *flags)
{ {
hoedown_buffer *work = 0, *inter = 0; hoedown_buffer *work = 0, *inter = 0;
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
@ -1881,7 +1873,7 @@ parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t
/* parse_list • parsing ordered or unordered list block */ /* parse_list • parsing ordered or unordered list block */
static size_t 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_listflags flags)
{ {
hoedown_buffer *work = 0; hoedown_buffer *work = 0;
size_t i = 0, j; size_t i = 0, j;
@ -2044,7 +2036,7 @@ htmlblock_find_end_strict(
while (i < size && data[i] != '\n') i++; while (i < size && data[i] != '\n') i++;
if (i < size) i++; if (i < size) i++;
if (i == mark) return 0; if (i == mark) return 0;
if (data[mark] == ' ' && mark > 0) continue; if (data[mark] == ' ' && mark > 0) continue;
mark += htmlblock_find_end(tag, tag_len, doc, data + mark, i - mark); mark += htmlblock_find_end(tag, tag_len, doc, data + mark, i - mark);
if (mark == i && (is_empty(data + i, size - i) || i >= size)) break; if (mark == i && (is_empty(data + i, size - i) || i >= size)) break;
@ -2144,8 +2136,8 @@ parse_table_row(
uint8_t *data, uint8_t *data,
size_t size, size_t size,
size_t columns, size_t columns,
int *col_data, hoedown_tableflags *col_data,
int header_flag) hoedown_tableflags header_flag)
{ {
size_t i = 0, col; size_t i = 0, col;
hoedown_buffer *row_work = 0; hoedown_buffer *row_work = 0;
@ -2201,7 +2193,7 @@ parse_table_header(
uint8_t *data, uint8_t *data,
size_t size, size_t size,
size_t *columns, size_t *columns,
int **column_data) hoedown_tableflags **column_data)
{ {
int pipes; int pipes;
size_t i = 0, col, header_end, under_end; size_t i = 0, col, header_end, under_end;
@ -2229,7 +2221,7 @@ parse_table_header(
return 0; return 0;
*columns = pipes + 1; *columns = pipes + 1;
*column_data = calloc(*columns, sizeof(int)); *column_data = hoedown_calloc(*columns, sizeof(hoedown_tableflags));
/* Parse the header underline */ /* Parse the header underline */
i++; i++;
@ -2299,7 +2291,7 @@ parse_table(
hoedown_buffer *body_work = 0; hoedown_buffer *body_work = 0;
size_t columns; size_t columns;
int *col_data = NULL; hoedown_tableflags *col_data = NULL;
header_work = newbuf(doc, BUFFER_SPAN); header_work = newbuf(doc, BUFFER_SPAN);
body_work = newbuf(doc, BUFFER_BLOCK); body_work = newbuf(doc, BUFFER_BLOCK);
@ -2489,7 +2481,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); hoedown_buffer_put(contents, data + start + ind, i - start - ind);
/* add carriage return */ /* add carriage return */
if (i < end) { if (i < end) {
hoedown_buffer_put(contents, "\n", 1); hoedown_buffer_putc(contents, '\n');
if (i < end && (data[i] == '\n' || data[i] == '\r')) { if (i < end && (data[i] == '\n' || data[i] == '\r')) {
i++; i++;
if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++; if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++;
@ -2662,21 +2654,18 @@ static void expand_tabs(hoedown_buffer *ob, const uint8_t *line, size_t size)
hoedown_document * hoedown_document *
hoedown_document_new( hoedown_document_new(
const hoedown_renderer *renderer, const hoedown_renderer *renderer,
unsigned int extensions, hoedown_extensions extensions,
size_t max_nesting) size_t max_nesting)
{ {
hoedown_document *doc = NULL; hoedown_document *doc = NULL;
assert(max_nesting > 0 && renderer); assert(max_nesting > 0 && renderer);
doc = malloc(sizeof(hoedown_document)); doc = hoedown_malloc(sizeof(hoedown_document));
if (!doc)
return NULL;
memcpy(&doc->md, renderer, sizeof(hoedown_renderer)); memcpy(&doc->md, renderer, sizeof(hoedown_renderer));
hoedown_stack_new(&doc->work_bufs[BUFFER_BLOCK], 4); hoedown_stack_init(&doc->work_bufs[BUFFER_BLOCK], 4);
hoedown_stack_new(&doc->work_bufs[BUFFER_SPAN], 8); hoedown_stack_init(&doc->work_bufs[BUFFER_SPAN], 8);
memset(doc->active_char, 0x0, 256); memset(doc->active_char, 0x0, 256);
@ -2723,7 +2712,7 @@ hoedown_document_new(
} }
void 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}; static const uint8_t UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
@ -2733,11 +2722,9 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
int footnotes_enabled; int footnotes_enabled;
text = hoedown_buffer_new(64); text = hoedown_buffer_new(64);
if (!text)
return;
/* Preallocate enough space for our buffer to avoid expanding while copying */ /* 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 */ /* reset the references table */
memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
@ -2755,26 +2742,26 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
/* Skip a possible UTF-8 BOM, even though the Unicode standard /* Skip a possible UTF-8 BOM, even though the Unicode standard
* discourages having these in UTF-8 documents */ * 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; beg += 3;
while (beg < doc_size) /* iterating over lines */ while (beg < size) /* iterating over lines */
if (footnotes_enabled && is_footnote(document, beg, doc_size, &end, &doc->footnotes_found)) if (footnotes_enabled && is_footnote(data, beg, size, &end, &doc->footnotes_found))
beg = end; 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; beg = end;
else { /* skipping to the next line */ else { /* skipping to the next line */
end = beg; end = beg;
while (end < doc_size && document[end] != '\n' && document[end] != '\r') while (end < size && data[end] != '\n' && data[end] != '\r')
end++; end++;
/* adding the line body if present */ /* adding the line body if present */
if (end > beg) 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 */ /* 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'); hoedown_buffer_putc(text, '\n');
end++; end++;
} }
@ -2817,38 +2804,36 @@ hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t
} }
void 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; size_t i = 0, mark;
hoedown_buffer *text = hoedown_buffer_new(64); hoedown_buffer *text = hoedown_buffer_new(64);
if (!text)
return;
/* reset the references table */ /* reset the references table */
memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
/* first pass: convert all spacing to spaces */ /* first pass: expand tabs and process newlines */
hoedown_buffer_grow(text, doc_size); hoedown_buffer_grow(text, size);
while (1) { while (1) {
mark = i; mark = i;
while (i < doc_size && document[i] != '\n' && document[i] != '\r') while (i < size && data[i] != '\n' && data[i] != '\r')
i++; i++;
expand_tabs(text, document + mark, i - mark); expand_tabs(text, data + mark, i - mark);
if (i >= doc_size) if (i >= size)
break; 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 */ /* 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'); hoedown_buffer_putc(text, '\n');
i++; i++;
} }
} }
/* second pass: actual rendering */ /* second pass: actual rendering */
hoedown_buffer_grow(ob, doc_size + (doc_size >> 1)); hoedown_buffer_grow(ob, text->size + (text->size >> 1));
parse_inline(ob, doc, text->data, text->size); parse_inline(ob, doc, text->data, text->size);
/* clean-up */ /* clean-up */
@ -2869,8 +2854,8 @@ hoedown_document_free(hoedown_document *doc)
for (i = 0; i < (size_t)doc->work_bufs[BUFFER_BLOCK].asize; ++i) for (i = 0; i < (size_t)doc->work_bufs[BUFFER_BLOCK].asize; ++i)
hoedown_buffer_free(doc->work_bufs[BUFFER_BLOCK].item[i]); hoedown_buffer_free(doc->work_bufs[BUFFER_BLOCK].item[i]);
hoedown_stack_free(&doc->work_bufs[BUFFER_SPAN]); hoedown_stack_reset(&doc->work_bufs[BUFFER_SPAN]);
hoedown_stack_free(&doc->work_bufs[BUFFER_BLOCK]); hoedown_stack_reset(&doc->work_bufs[BUFFER_BLOCK]);
free(doc); free(doc);
} }

View file

@ -10,11 +10,12 @@
extern "C" { extern "C" {
#endif #endif
/*********
* FLAGS *
*********/
enum hoedown_extensions { /*************
* CONSTANTS *
*************/
typedef enum hoedown_extensions {
/* block-level extensions */ /* block-level extensions */
HOEDOWN_EXT_TABLES = (1 << 0), HOEDOWN_EXT_TABLES = (1 << 0),
HOEDOWN_EXT_FENCED_CODE = (1 << 1), HOEDOWN_EXT_FENCED_CODE = (1 << 1),
@ -35,7 +36,7 @@ enum hoedown_extensions {
/* negative flags */ /* negative flags */
HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 12) HOEDOWN_EXT_DISABLE_INDENTED_CODE = (1 << 12)
}; } hoedown_extensions;
#define HOEDOWN_EXT_BLOCK (\ #define HOEDOWN_EXT_BLOCK (\
HOEDOWN_EXT_TABLES |\ HOEDOWN_EXT_TABLES |\
@ -58,30 +59,29 @@ enum hoedown_extensions {
#define HOEDOWN_EXT_NEGATIVE (\ #define HOEDOWN_EXT_NEGATIVE (\
HOEDOWN_EXT_DISABLE_INDENTED_CODE ) HOEDOWN_EXT_DISABLE_INDENTED_CODE )
/* list/listitem flags */ typedef enum hoedown_listflags {
enum hoedown_listflags {
HOEDOWN_LIST_ORDERED = (1 << 0), HOEDOWN_LIST_ORDERED = (1 << 0),
HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */ HOEDOWN_LI_BLOCK = (1 << 1) /* <li> containing block data */
}; } hoedown_listflags;
enum hoedown_tableflags { typedef enum hoedown_tableflags {
HOEDOWN_TABLE_ALIGN_LEFT = 1, HOEDOWN_TABLE_ALIGN_LEFT = 1,
HOEDOWN_TABLE_ALIGN_RIGHT = 2, HOEDOWN_TABLE_ALIGN_RIGHT = 2,
HOEDOWN_TABLE_ALIGN_CENTER = 3, HOEDOWN_TABLE_ALIGN_CENTER = 3,
HOEDOWN_TABLE_ALIGNMASK = 3, HOEDOWN_TABLE_ALIGNMASK = 3,
HOEDOWN_TABLE_HEADER = 4 HOEDOWN_TABLE_HEADER = 4
}; } hoedown_tableflags;
/* hoedown_autolink - type of autolink */ typedef enum hoedown_autolink_type {
enum hoedown_autolink {
HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/ HOEDOWN_AUTOLINK_NONE, /* used internally when it is not an autolink*/
HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */ HOEDOWN_AUTOLINK_NORMAL, /* normal http/http/ftp/mailto/etc link */
HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */ HOEDOWN_AUTOLINK_EMAIL /* e-mail link without explit mailto: */
}; } hoedown_autolink_type;
/********************
* TYPE DEFINITIONS * /*********
********************/ * TYPES *
*********/
/* hoedown_renderer - functions for rendering parsed data */ /* hoedown_renderer - functions for rendering parsed data */
struct hoedown_renderer { struct hoedown_renderer {
@ -94,17 +94,17 @@ struct hoedown_renderer {
void (*blockhtml)(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 (*header)(hoedown_buffer *ob, const hoedown_buffer *text, int level, void *opaque);
void (*hrule)(hoedown_buffer *ob, void *opaque); void (*hrule)(hoedown_buffer *ob, void *opaque);
void (*list)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque); void (*list)(hoedown_buffer *ob, const hoedown_buffer *text, hoedown_listflags flags, void *opaque);
void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque); void (*listitem)(hoedown_buffer *ob, const hoedown_buffer *text, hoedown_listflags flags, void *opaque);
void (*paragraph)(hoedown_buffer *ob, const hoedown_buffer *text, 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)(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_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 (*table_cell)(hoedown_buffer *ob, const hoedown_buffer *text, hoedown_tableflags flags, void *opaque);
void (*footnotes)(hoedown_buffer *ob, const hoedown_buffer *text, 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 (*footnote_def)(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int num, void *opaque);
/* span level callbacks - NULL or return 0 prints the span verbatim */ /* 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 (*autolink)(hoedown_buffer *ob, const hoedown_buffer *link, hoedown_autolink_type type, void *opaque);
int (*codespan)(hoedown_buffer *ob, const hoedown_buffer *text, 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 (*double_emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque); int (*emphasis)(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque);
@ -128,31 +128,32 @@ struct hoedown_renderer {
void (*doc_header)(hoedown_buffer *ob, void *opaque); void (*doc_header)(hoedown_buffer *ob, void *opaque);
void (*doc_footer)(hoedown_buffer *ob, void *opaque); void (*doc_footer)(hoedown_buffer *ob, void *opaque);
}; };
typedef struct hoedown_renderer hoedown_renderer; typedef struct hoedown_renderer hoedown_renderer;
struct hoedown_document; struct hoedown_document;
typedef struct hoedown_document hoedown_document; typedef struct hoedown_document hoedown_document;
/**********************
* EXPORTED FUNCTIONS *
**********************/
extern hoedown_document * /*************
hoedown_document_new( * FUNCTIONS *
*************/
/* hoedown_document_new: allocate a new document processor instance */
hoedown_document *hoedown_document_new(
const hoedown_renderer *renderer, const hoedown_renderer *renderer,
unsigned int extensions, hoedown_extensions extensions,
size_t max_nesting); size_t max_nesting
) __attribute__ ((malloc));
extern void /* hoedown_document_render: render regular Markdown using the document processor */
hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size); void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size);
extern void /* hoedown_document_render_inline: render inline Markdown using the document processor */
hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *document, size_t doc_size); void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t 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 #ifdef __cplusplus
} }

View file

@ -4,6 +4,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.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: * The following characters will not be escaped:
* *
@ -17,7 +22,7 @@
* *
* We asume (lazily) that any RESERVED char that * We asume (lazily) that any RESERVED char that
* appears inside an URL is actually meant to * 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. * component/separator) and hence needs no escaping.
* *
* There are two exceptions: the chacters & (amp) * There are two exceptions: the chacters & (amp)
@ -30,58 +35,56 @@
* *
*/ */
static const uint8_t HREF_SAFE[UINT8_MAX+1] = { 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, 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 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 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"; static const char hex_chars[] = "0123456789ABCDEF";
size_t i = 0, org; size_t i = 0, mark;
char hex_str[3]; char hex_str[3];
hex_str[0] = '%'; hex_str[0] = '%';
while (i < size) { while (i < size) {
org = i; mark = i;
while (i < size && HREF_SAFE[src[i]] != 0) while (i < size && HREF_SAFE[data[i]] != 0)
i++; i++;
if (i > org) { /* Optimization for cases when there's nothing to escape */
if (org == 0) { if (mark == 0 && i >= size) {
if (i >= size) { hoedown_buffer_put(ob, data, size);
hoedown_buffer_put(ob, src, size); return;
return; }
}
} if (i > mark) {
hoedown_buffer_put(ob, data + mark, i - mark);
hoedown_buffer_put(ob, src + org, i - org);
} }
/* escaping */ /* escaping */
if (i >= size) if (i >= size)
break; break;
switch (src[i]) { switch (data[i]) {
/* amp appears all the time in URLs, but needs /* amp appears all the time in URLs, but needs
* HTML-entity escaping to be inside an href */ * HTML-entity escaping to be inside an href */
case '&': case '&':
HOEDOWN_BUFPUTSL(ob, "&amp;"); HOEDOWN_BUFPUTSL(ob, "&amp;");
break; break;
@ -91,7 +94,7 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
case '\'': case '\'':
HOEDOWN_BUFPUTSL(ob, "&#x27;"); HOEDOWN_BUFPUTSL(ob, "&#x27;");
break; break;
/* the space can be escaped to %20 or a plus /* the space can be escaped to %20 or a plus
* sign. we're going with the generic escape * sign. we're going with the generic escape
* for now. the plus thing is more commonly seen * for now. the plus thing is more commonly seen
@ -104,15 +107,16 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
/* every other character goes with a %XX escaping */ /* every other character goes with a %XX escaping */
default: default:
hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; hex_str[1] = hex_chars[(data[i] >> 4) & 0xF];
hex_str[2] = hex_chars[src[i] & 0xF]; hex_str[2] = hex_chars[data[i] & 0xF];
hoedown_buffer_put(ob, hex_str, 3); hoedown_buffer_put(ob, (uint8_t *)hex_str, 3);
} }
i++; i++;
} }
} }
/** /**
* According to the OWASP rules: * According to the OWASP rules:
* *
@ -125,21 +129,21 @@ hoedown_escape_href(hoedown_buffer *ob, const uint8_t *src, size_t size)
* *
*/ */
static const uint8_t HTML_ESCAPE_TABLE[UINT8_MAX+1] = { 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, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}; };
@ -154,36 +158,30 @@ static const char *HTML_ESCAPES[] = {
}; };
void 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; size_t i = 0, mark;
while (i < size) { while (1) {
org = i; mark = i;
while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) while (i < size && HTML_ESCAPE_TABLE[data[i]] == 0) i++;
i++;
if (i > org) { /* Optimization for cases where there's nothing to escape */
if (org == 0) { if (mark == 0 && i >= size) {
if (i >= size) { hoedown_buffer_put(ob, data, size);
hoedown_buffer_put(ob, src, size); return;
return;
}
}
hoedown_buffer_put(ob, src + org, i - org);
} }
/* escaping */ if (likely(i > mark))
if (i >= size) hoedown_buffer_put(ob, data + mark, i - mark);
break;
if (i >= size) break;
/* The forward slash is only escaped in secure mode */ /* The forward slash is only escaped in secure mode */
if (src[i] == '/' && !secure) { if (!secure && data[i] == '/') {
hoedown_buffer_putc(ob, '/'); hoedown_buffer_putc(ob, '/');
} else { } else {
hoedown_buffer_puts(ob, HTML_ESCAPES[esc]); hoedown_buffer_puts(ob, HTML_ESCAPES[HTML_ESCAPE_TABLE[data[i]]]);
} }
i++; i++;

View file

@ -9,8 +9,17 @@
extern "C" { extern "C" {
#endif #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 #ifdef __cplusplus
} }

View file

@ -9,34 +9,34 @@
#define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML) #define USE_XHTML(opt) (opt->flags & HOEDOWN_HTML_USE_XHTML)
int hoedown_html_tag
hoedown_html_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname) hoedown_html_is_tag(const uint8_t *data, size_t size, const char *tagname)
{ {
size_t i; size_t i;
int closed = 0; int closed = 0;
if (tag_size < 3 || tag_data[0] != '<') if (size < 3 || data[0] != '<')
return HOEDOWN_HTML_TAG_NONE; return HOEDOWN_HTML_TAG_NONE;
i = 1; i = 1;
if (tag_data[i] == '/') { if (data[i] == '/') {
closed = 1; closed = 1;
i++; i++;
} }
for (; i < tag_size; ++i, ++tagname) { for (; i < size; ++i, ++tagname) {
if (*tagname == 0) if (*tagname == 0)
break; break;
if (tag_data[i] != *tagname) if (data[i] != *tagname)
return HOEDOWN_HTML_TAG_NONE; return HOEDOWN_HTML_TAG_NONE;
} }
if (i == tag_size) if (i == size)
return HOEDOWN_HTML_TAG_NONE; 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 closed ? HOEDOWN_HTML_TAG_CLOSE : HOEDOWN_HTML_TAG_OPEN;
return HOEDOWN_HTML_TAG_NONE; return HOEDOWN_HTML_TAG_NONE;
@ -56,7 +56,7 @@ static inline void escape_href(hoedown_buffer *ob, const uint8_t *source, size_t
* GENERIC RENDERER * * GENERIC RENDERER *
********************/ ********************/
static int 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, void *opaque)
{ {
hoedown_html_renderer_state *state = opaque; hoedown_html_renderer_state *state = opaque;
@ -268,9 +268,9 @@ static void
rndr_list(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque) rndr_list(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque)
{ {
if (ob->size) hoedown_buffer_putc(ob, '\n'); if (ob->size) hoedown_buffer_putc(ob, '\n');
hoedown_buffer_put(ob, flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5); hoedown_buffer_put(ob, (uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "<ol>\n" : "<ul>\n"), 5);
if (text) hoedown_buffer_put(ob, text->data, text->size); 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, (uint8_t *)(flags & HOEDOWN_LIST_ORDERED ? "</ol>\n" : "</ul>\n"), 6);
} }
static void static void
@ -428,7 +428,7 @@ rndr_tablerow(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
} }
static void static void
rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int flags, void *opaque) rndr_tablecell(hoedown_buffer *ob, const hoedown_buffer *text, hoedown_tableflags flags, void *opaque)
{ {
if (flags & HOEDOWN_TABLE_HEADER) { if (flags & HOEDOWN_TABLE_HEADER) {
HOEDOWN_BUFPUTSL(ob, "<th"); HOEDOWN_BUFPUTSL(ob, "<th");
@ -489,10 +489,10 @@ rndr_footnotes(hoedown_buffer *ob, const hoedown_buffer *text, void *opaque)
HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n"); HOEDOWN_BUFPUTSL(ob, "<div class=\"footnotes\">\n");
hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n"); hoedown_buffer_puts(ob, USE_XHTML(state) ? "<hr/>\n" : "<hr>\n");
HOEDOWN_BUFPUTSL(ob, "<ol>\n"); HOEDOWN_BUFPUTSL(ob, "<ol>\n");
if (text) if (text)
hoedown_buffer_put(ob, text->data, text->size); hoedown_buffer_put(ob, text->data, text->size);
HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n"); HOEDOWN_BUFPUTSL(ob, "\n</ol>\n</div>\n");
} }
@ -501,7 +501,7 @@ rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int n
{ {
size_t i = 0; size_t i = 0;
int pfound = 0; int pfound = 0;
/* insert anchor at the end of first paragraph block */ /* insert anchor at the end of first paragraph block */
if (text) { if (text) {
while ((i+3) < text->size) { while ((i+3) < text->size) {
@ -514,7 +514,7 @@ rndr_footnote_def(hoedown_buffer *ob, const hoedown_buffer *text, unsigned int n
break; break;
} }
} }
hoedown_buffer_printf(ob, "\n<li id=\"fn%d\">\n", num); hoedown_buffer_printf(ob, "\n<li id=\"fn%d\">\n", num);
if (pfound) { if (pfound) {
hoedown_buffer_put(ob, text->data, i); hoedown_buffer_put(ob, text->data, i);
@ -634,23 +634,15 @@ hoedown_html_toc_renderer_new(int nesting_level)
hoedown_renderer *renderer; hoedown_renderer *renderer;
/* Prepare the state pointer */ /* Prepare the state pointer */
state = malloc(sizeof(hoedown_html_renderer_state)); state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
if (!state)
return NULL;
memset(state, 0x0, sizeof(hoedown_html_renderer_state)); memset(state, 0x0, sizeof(hoedown_html_renderer_state));
state->toc_data.nesting_level = nesting_level; state->toc_data.nesting_level = nesting_level;
/* Prepare the renderer */ /* Prepare the renderer */
renderer = malloc(sizeof(hoedown_renderer)); renderer = hoedown_malloc(sizeof(hoedown_renderer));
if (!renderer) {
free(state);
return NULL;
}
memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
renderer->opaque = state; renderer->opaque = state;
return renderer; return renderer;
} }
@ -658,7 +650,7 @@ hoedown_html_toc_renderer_new(int nesting_level)
hoedown_renderer * hoedown_renderer *
hoedown_html_renderer_new(unsigned int render_flags, int nesting_level) hoedown_html_renderer_new(unsigned int render_flags, int nesting_level)
{ {
static const hoedown_renderer cb_default = { static const hoedown_renderer cb_default = {
NULL, NULL,
rndr_blockcode, rndr_blockcode,
@ -702,27 +694,19 @@ hoedown_html_renderer_new(unsigned int render_flags, int nesting_level)
hoedown_renderer *renderer; hoedown_renderer *renderer;
/* Prepare the state pointer */ /* Prepare the state pointer */
state = malloc(sizeof(hoedown_html_renderer_state)); state = hoedown_malloc(sizeof(hoedown_html_renderer_state));
if (!state)
return NULL;
memset(state, 0x0, sizeof(hoedown_html_renderer_state)); memset(state, 0x0, sizeof(hoedown_html_renderer_state));
state->flags = render_flags; state->flags = render_flags;
state->toc_data.nesting_level = nesting_level; state->toc_data.nesting_level = nesting_level;
/* Prepare the renderer */ /* Prepare the renderer */
renderer = malloc(sizeof(hoedown_renderer)); renderer = hoedown_malloc(sizeof(hoedown_renderer));
if (!renderer) {
free(state);
return NULL;
}
memcpy(renderer, &cb_default, sizeof(hoedown_renderer)); memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE) if (render_flags & HOEDOWN_HTML_SKIP_HTML || render_flags & HOEDOWN_HTML_ESCAPE)
renderer->blockhtml = NULL; renderer->blockhtml = NULL;
renderer->opaque = state; renderer->opaque = state;
return renderer; return renderer;
} }

View file

@ -1,17 +1,21 @@
/* html.h - HTML renderer */ /* html.h - HTML renderer and utilities */
#ifndef HOEDOWN_HTML_H #ifndef HOEDOWN_HTML_H
#define HOEDOWN_HTML_H #define HOEDOWN_HTML_H
#include "document.h" #include "document.h"
#include "buffer.h" #include "buffer.h"
#include <stdlib.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
typedef enum {
/*************
* CONSTANTS *
*************/
typedef enum hoedown_html_flags {
HOEDOWN_HTML_SKIP_HTML = (1 << 0), HOEDOWN_HTML_SKIP_HTML = (1 << 0),
HOEDOWN_HTML_ESCAPE = (1 << 1), HOEDOWN_HTML_ESCAPE = (1 << 1),
HOEDOWN_HTML_SAFELINK = (1 << 2), HOEDOWN_HTML_SAFELINK = (1 << 2),
@ -19,12 +23,17 @@ typedef enum {
HOEDOWN_HTML_USE_XHTML = (1 << 4) HOEDOWN_HTML_USE_XHTML = (1 << 4)
} hoedown_html_flags; } hoedown_html_flags;
typedef enum { typedef enum hoedown_html_tag {
HOEDOWN_HTML_TAG_NONE = 0, HOEDOWN_HTML_TAG_NONE = 0,
HOEDOWN_HTML_TAG_OPEN, HOEDOWN_HTML_TAG_OPEN,
HOEDOWN_HTML_TAG_CLOSE HOEDOWN_HTML_TAG_CLOSE
} hoedown_html_tag; } hoedown_html_tag;
/*********
* TYPES *
*********/
struct hoedown_html_renderer_state { struct hoedown_html_renderer_state {
void *opaque; void *opaque;
@ -35,28 +44,39 @@ struct hoedown_html_renderer_state {
int nesting_level; int nesting_level;
} toc_data; } toc_data;
unsigned int flags; hoedown_html_flags flags;
/* extra callbacks */ /* extra callbacks */
void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, void *self); void (*link_attributes)(hoedown_buffer *ob, const hoedown_buffer *url, void *self);
}; };
typedef struct hoedown_html_renderer_state hoedown_html_renderer_state; 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 *
*************/
extern hoedown_renderer * /* hoedown_html_smartypants: process an HTML snippet using SmartyPants for smart punctuation */
hoedown_html_toc_renderer_new(int nesting_level); void hoedown_html_smartypants(hoedown_buffer *ob, const uint8_t *data, size_t size);
extern void /* hoedown_html_is_tag: checks if data starts with a specific tag, returns the tag type or NONE */
hoedown_html_renderer_free(hoedown_renderer *renderer); 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));
/* 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));
/* 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 #ifdef __cplusplus
} }

View file

@ -1,25 +1,29 @@
#include "stack.h" #include "stack.h"
#include <string.h> #include "buffer.h"
int #include <stdlib.h>
hoedown_stack_new(hoedown_stack *st, size_t initial_size) #include <string.h>
#include <assert.h>
void
hoedown_stack_init(hoedown_stack *st, size_t initial_size)
{ {
assert(st);
st->item = NULL; st->item = NULL;
st->size = 0; st->size = st->asize = 0;
st->asize = 0;
if (!initial_size) if (!initial_size)
initial_size = 8; initial_size = 8;
return hoedown_stack_grow(st, initial_size); hoedown_stack_grow(st, initial_size);
} }
void void
hoedown_stack_free(hoedown_stack *st) hoedown_stack_reset(hoedown_stack *st)
{ {
if (!st) assert(st);
return;
free(st->item); free(st->item);
@ -28,43 +32,38 @@ hoedown_stack_free(hoedown_stack *st)
st->asize = 0; st->asize = 0;
} }
int void
hoedown_stack_grow(hoedown_stack *st, size_t new_size) hoedown_stack_grow(hoedown_stack *st, size_t neosz)
{ {
void **new_st; assert(st);
if (st->asize >= new_size) if (st->asize >= neosz)
return 0; return;
new_st = realloc(st->item, new_size * sizeof(void *)); st->item = hoedown_realloc(st->item, neosz * sizeof(void *));
if (new_st == NULL) memset(st->item + st->asize, 0x0, (neosz - st->asize) * sizeof(void *));
return -1; st->asize = neosz;
memset(new_st + st->asize, 0x0, if (st->size > neosz)
(new_size - st->asize) * sizeof(void *)); st->size = neosz;
st->item = new_st;
st->asize = new_size;
if (st->size > new_size)
st->size = new_size;
return 0;
} }
int void
hoedown_stack_push(hoedown_stack *st, void *item) hoedown_stack_push(hoedown_stack *st, void *item)
{ {
if (hoedown_stack_grow(st, st->size * 2) < 0) assert(st);
return -1;
if (st->size >= st->asize)
hoedown_stack_grow(st, (st->size + 1) * 2);
st->item[st->size++] = item; st->item[st->size++] = item;
return 0;
} }
void * void *
hoedown_stack_pop(hoedown_stack *st) hoedown_stack_pop(hoedown_stack *st)
{ {
assert(st);
if (!st->size) if (!st->size)
return NULL; return NULL;
@ -72,8 +71,10 @@ hoedown_stack_pop(hoedown_stack *st)
} }
void * void *
hoedown_stack_top(hoedown_stack *st) hoedown_stack_top(const hoedown_stack *st)
{ {
assert(st);
if (!st->size) if (!st->size)
return NULL; return NULL;

View file

@ -3,26 +3,47 @@
#ifndef HOEDOWN_STACK_H #ifndef HOEDOWN_STACK_H
#define HOEDOWN_STACK_H #define HOEDOWN_STACK_H
#include <stdlib.h> #include <stddef.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*********
* TYPES *
*********/
struct hoedown_stack { struct hoedown_stack {
void **item; void **item;
size_t size; size_t size;
size_t asize; size_t asize;
}; };
typedef struct hoedown_stack hoedown_stack; 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); * FUNCTIONS *
int hoedown_stack_push(hoedown_stack *, void *); *************/
void *hoedown_stack_pop(hoedown_stack *);
void *hoedown_stack_top(hoedown_stack *); /* hoedown_stack_init: initialize a stack */
void hoedown_stack_init(hoedown_stack *st, size_t initial_size);
/* hoedown_stack_reset: free internal data of the stack */
void hoedown_stack_reset(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 #ifdef __cplusplus
} }

View file

@ -7,13 +7,24 @@
extern "C" { extern "C" {
#endif #endif
/*************
* CONSTANTS *
*************/
#define HOEDOWN_VERSION "2.0.0" #define HOEDOWN_VERSION "2.0.0"
#define HOEDOWN_VERSION_MAJOR 2 #define HOEDOWN_VERSION_MAJOR 2
#define HOEDOWN_VERSION_MINOR 0 #define HOEDOWN_VERSION_MINOR 0
#define HOEDOWN_VERSION_REVISION 0 #define HOEDOWN_VERSION_REVISION 0
extern void
hoedown_version(int *major, int *minor, int *revision); /*************
* FUNCTIONS *
*************/
/* hoedown_version: retrieve Hoedown's version numbers */
void hoedown_version(int *major, int *minor, int *revision);
#ifdef __cplusplus #ifdef __cplusplus
} }