summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/man3/cmark.381
-rw-r--r--src/blocks.c110
-rw-r--r--src/buffer.c19
-rw-r--r--src/buffer.h9
-rw-r--r--src/chunk.h17
-rw-r--r--src/cmark.c30
-rw-r--r--src/cmark.h38
-rw-r--r--src/html.c2
-rw-r--r--src/inlines.c158
-rw-r--r--src/inlines.h8
-rw-r--r--src/iterator.c10
-rw-r--r--src/iterator.h2
-rw-r--r--src/main.c2
-rw-r--r--src/memory.h12
-rw-r--r--src/node.c63
-rw-r--r--src/node.h10
-rw-r--r--src/parser.h2
-rwxr-xr-xsrc/references.c35
-rw-r--r--src/references.h4
-rw-r--r--src/render.c12
-rw-r--r--src/render.h2
-rw-r--r--src/xml.c2
22 files changed, 343 insertions, 285 deletions
diff --git a/man/man3/cmark.3 b/man/man3/cmark.3
index 5642e59..ca304e6 100644
--- a/man/man3/cmark.3
+++ b/man/man3/cmark.3
@@ -1,4 +1,4 @@
-.TH cmark 3 "May 14, 2016" "LOCAL" "Library Functions Manual"
+.TH cmark 3 "June 02, 2016" "LOCAL" "Library Functions Manual"
.SH
NAME
.PP
@@ -15,7 +15,7 @@ Simple Interface
.PP
Convert \f[I]text\f[] (assumed to be a UTF\-8 encoded string with length
\f[I]len\f[]) from CommonMark Markdown to HTML, returning a
-null\-terminated, UTF\-8\-encoded string. It is the caller's
+null\-terminated, UTF\-8\-encoded string. It is the caller\[cq]s
responsibility to free the returned buffer.
.SS
@@ -96,6 +96,25 @@ typedef enum {
.SS
+Custom memory allocator support
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef struct cmark_mem {
+ void *(*calloc)(size_t, size_t);
+ void (*free)(void *);
+} cmark_mem;
+.RE
+\f[]
+.fi
+
+.PP
+Defines the memory allocation functions to be used by CMark when parsing
+and allocating a document tree
+
+.SS
Creating and Destroying Nodes
.PP
@@ -103,8 +122,15 @@ Creating and Destroying Nodes
.PP
Creates a new node of type \f[I]type\f[]. Note that the node may have
-other required properties, which it is the caller's responsibility to
-assign.
+other required properties, which it is the caller\[cq]s responsibility
+to assign.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_new2\f[](\fIcmark_node_type type\f[], \fIcmark_mem *mem\f[])
+
+.PP
+Same as \f[C]cmark_node_new\f[], but explicitly listing the memory
+allocator used to allocate the node
.PP
\fIvoid\f[] \fBcmark_node_free\f[](\fIcmark_node *node\f[])
@@ -378,7 +404,8 @@ Returns 1 if \f[I]node\f[] is a tight list, 0 otherwise.
\fIint\f[] \fBcmark_node_set_list_tight\f[](\fIcmark_node *node\f[], \fIint tight\f[])
.PP
-Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
+Sets the \[lq]tightness\[rq] of a list. Returns 1 on success, 0 on
+failure.
.PP
\fIconst char *\f[] \fBcmark_node_get_fence_info\f[](\fIcmark_node *node\f[])
@@ -425,31 +452,31 @@ on failure.
\fIconst char *\f[] \fBcmark_node_get_on_enter\f[](\fIcmark_node *node\f[])
.PP
-Returns the literal "on enter" text for a custom \f[I]node\f[], or an
-empty string if no on_enter is set.
+Returns the literal \[lq]on enter\[rq] text for a custom \f[I]node\f[],
+or an empty string if no on_enter is set.
.PP
\fIint\f[] \fBcmark_node_set_on_enter\f[](\fIcmark_node *node\f[], \fIconst char *on_enter\f[])
.PP
-Sets the literal text to render "on enter" for a custom \f[I]node\f[].
-Any children of the node will be rendered after this text. Returns 1 on
-success 0 on failure.
+Sets the literal text to render \[lq]on enter\[rq] for a custom
+\f[I]node\f[]. Any children of the node will be rendered after this
+text. Returns 1 on success 0 on failure.
.PP
\fIconst char *\f[] \fBcmark_node_get_on_exit\f[](\fIcmark_node *node\f[])
.PP
-Returns the literal "on exit" text for a custom \f[I]node\f[], or an
-empty string if no on_exit is set.
+Returns the literal \[lq]on exit\[rq] text for a custom \f[I]node\f[],
+or an empty string if no on_exit is set.
.PP
\fIint\f[] \fBcmark_node_set_on_exit\f[](\fIcmark_node *node\f[], \fIconst char *on_exit\f[])
.PP
-Sets the literal text to render "on exit" for a custom \f[I]node\f[].
-Any children of the node will be rendered before this text. Returns 1 on
-success 0 on failure.
+Sets the literal text to render \[lq]on exit\[rq] for a custom
+\f[I]node\f[]. Any children of the node will be rendered before this
+text. Returns 1 on success 0 on failure.
.PP
\fIint\f[] \fBcmark_node_get_start_line\f[](\fIcmark_node *node\f[])
@@ -563,6 +590,12 @@ cmark_parser_free(parser);
Creates a new parser object.
.PP
+\fIcmark_parser *\f[] \fBcmark_parser_new2\f[](\fIint options\f[], \fIcmark_mem *mem\f[])
+
+.PP
+Creates a new parser object with the given memory allocator
+
+.PP
\fIvoid\f[] \fBcmark_parser_free\f[](\fIcmark_parser *parser\f[])
.PP
@@ -604,36 +637,36 @@ Rendering
\fIchar *\f[] \fBcmark_render_xml\f[](\fIcmark_node *root\f[], \fIint options\f[])
.PP
-Render a \f[I]node\f[] tree as XML. It is the caller's responsibility to
-free the returned buffer.
+Render a \f[I]node\f[] tree as XML. It is the caller\[cq]s
+responsibility to free the returned buffer.
.PP
\fIchar *\f[] \fBcmark_render_html\f[](\fIcmark_node *root\f[], \fIint options\f[])
.PP
Render a \f[I]node\f[] tree as an HTML fragment. It is up to the user to
-add an appropriate header and footer. It is the caller's responsibility
-to free the returned buffer.
+add an appropriate header and footer. It is the caller\[cq]s
+responsibility to free the returned buffer.
.PP
\fIchar *\f[] \fBcmark_render_man\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
.PP
Render a \f[I]node\f[] tree as a groff man page, without the header. It
-is the caller's responsibility to free the returned buffer.
+is the caller\[cq]s responsibility to free the returned buffer.
.PP
\fIchar *\f[] \fBcmark_render_commonmark\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
.PP
-Render a \f[I]node\f[] tree as a commonmark document. It is the caller's
-responsibility to free the returned buffer.
+Render a \f[I]node\f[] tree as a commonmark document. It is the
+caller\[cq]s responsibility to free the returned buffer.
.PP
\fIchar *\f[] \fBcmark_render_latex\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
.PP
-Render a \f[I]node\f[] tree as a LaTeX document. It is the caller's
+Render a \f[I]node\f[] tree as a LaTeX document. It is the caller\[cq]s
responsibility to free the returned buffer.
.SS
@@ -744,7 +777,7 @@ with the replacement character U+FFFD.
.fi
.PP
-Convert straight quotes to curly, \-\-\- to em dashes, \-\- to en
+Convert straight quotes to curly, \[em] to em dashes, \[en] to en
dashes.
.SS
diff --git a/src/blocks.c b/src/blocks.c
index 07eacc6..ef1790e 100644
--- a/src/blocks.c
+++ b/src/blocks.c
@@ -44,36 +44,38 @@ static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
bufsize_t bytes);
-static cmark_node *make_block(cmark_node_type tag, int start_line,
+static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag, int start_line,
int start_column) {
cmark_node *e;
- e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+ e = (cmark_node *)mem->calloc(1, sizeof(*e));
+ cmark_strbuf_init(mem, &e->content, 32);
e->type = tag;
e->open = true;
e->start_line = start_line;
e->start_column = start_column;
e->end_line = start_line;
- cmark_strbuf_init(&e->string_content, 32);
return e;
}
// Create a root document node.
-static cmark_node *make_document() {
- cmark_node *e = make_block(CMARK_NODE_DOCUMENT, 1, 1);
+static cmark_node *make_document(cmark_mem *mem) {
+ cmark_node *e = make_block(mem, CMARK_NODE_DOCUMENT, 1, 1);
return e;
}
-cmark_parser *cmark_parser_new(int options) {
- cmark_parser *parser = (cmark_parser *)cmark_calloc(1, sizeof(cmark_parser));
- cmark_node *document = make_document();
- cmark_strbuf *line = (cmark_strbuf *)cmark_calloc(1, sizeof(cmark_strbuf));
- cmark_strbuf *buf = (cmark_strbuf *)cmark_calloc(1, sizeof(cmark_strbuf));
- cmark_strbuf_init(line, 256);
- cmark_strbuf_init(buf, 0);
-
- parser->refmap = cmark_reference_map_new();
+cmark_parser *cmark_parser_new2(int options, cmark_mem *mem) {
+ cmark_parser *parser = mem->calloc(1, sizeof(cmark_parser));
+ parser->mem = mem;
+
+ cmark_node *document = make_document(mem);
+ cmark_strbuf *line = mem->calloc(1, sizeof(cmark_strbuf));
+ cmark_strbuf *buf = mem->calloc(1, sizeof(cmark_strbuf));
+ cmark_strbuf_init(mem, line, 256);
+ cmark_strbuf_init(mem, buf, 0);
+
+ parser->refmap = cmark_reference_map_new(mem);
parser->root = document;
parser->current = document;
parser->line_number = 0;
@@ -93,13 +95,30 @@ cmark_parser *cmark_parser_new(int options) {
return parser;
}
+static void *xcalloc(size_t nmem, size_t size) {
+ void *ptr = calloc(nmem, size);
+ if (!ptr) abort();
+ return ptr;
+}
+
+static void xfree(void *ptr) {
+ free(ptr);
+}
+
+cmark_mem DEFAULT_MEM_ALLOCATOR = { xcalloc, xfree };
+
+cmark_parser *cmark_parser_new(int options) {
+ return cmark_parser_new2(options, &DEFAULT_MEM_ALLOCATOR);
+}
+
void cmark_parser_free(cmark_parser *parser) {
+ cmark_mem *mem = parser->mem;
cmark_strbuf_free(parser->curline);
- free(parser->curline);
+ mem->free(parser->curline);
cmark_strbuf_free(parser->linebuf);
- free(parser->linebuf);
+ mem->free(parser->linebuf);
cmark_reference_map_free(parser->refmap);
- free(parser);
+ mem->free(parser);
}
static cmark_node *finalize(cmark_parser *parser, cmark_node *b);
@@ -153,10 +172,10 @@ static void add_line(cmark_node *node, cmark_chunk *ch, cmark_parser *parser) {
// add space characters:
chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
for (i = 0; i < chars_to_tab; i++) {
- cmark_strbuf_putc(&node->string_content, ' ');
+ cmark_strbuf_putc(&node->content, ' ');
}
}
- cmark_strbuf_put(&node->string_content, ch->data + parser->offset,
+ cmark_strbuf_put(&node->content, ch->data + parser->offset,
ch->len - parser->offset);
}
@@ -229,7 +248,6 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
cmark_node *parent;
parent = b->parent;
-
assert(b->open); // shouldn't call finalize on closed blocks
b->open = false;
@@ -251,15 +269,17 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
b->end_column = parser->last_line_length;
}
+ cmark_strbuf *node_content = &b->content;
+
switch (b->type) {
case CMARK_NODE_PARAGRAPH:
- while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
- (pos = cmark_parse_reference_inline(&b->string_content,
+ while (cmark_strbuf_at(node_content, 0) == '[' &&
+ (pos = cmark_parse_reference_inline(parser->mem, node_content,
parser->refmap))) {
- cmark_strbuf_drop(&b->string_content, pos);
+ cmark_strbuf_drop(node_content, pos);
}
- if (is_blank(&b->string_content, 0)) {
+ if (is_blank(node_content, 0)) {
// remove blank node (former reference def)
cmark_node_free(b);
}
@@ -267,34 +287,33 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
case CMARK_NODE_CODE_BLOCK:
if (!b->as.code.fenced) { // indented code
- remove_trailing_blank_lines(&b->string_content);
- cmark_strbuf_putc(&b->string_content, '\n');
+ remove_trailing_blank_lines(node_content);
+ cmark_strbuf_putc(node_content, '\n');
} else {
-
// first line of contents becomes info
- for (pos = 0; pos < b->string_content.size; ++pos) {
- if (S_is_line_end_char(b->string_content.ptr[pos]))
+ for (pos = 0; pos < node_content->size; ++pos) {
+ if (S_is_line_end_char(node_content->ptr[pos]))
break;
}
- assert(pos < b->string_content.size);
+ assert(pos < node_content->size);
- cmark_strbuf tmp = GH_BUF_INIT;
- houdini_unescape_html_f(&tmp, b->string_content.ptr, pos);
+ cmark_strbuf tmp = CMARK_BUF_INIT(parser->mem);
+ houdini_unescape_html_f(&tmp, node_content->ptr, pos);
cmark_strbuf_trim(&tmp);
cmark_strbuf_unescape(&tmp);
b->as.code.info = cmark_chunk_buf_detach(&tmp);
- if (b->string_content.ptr[pos] == '\r')
+ if (node_content->ptr[pos] == '\r')
pos += 1;
- if (b->string_content.ptr[pos] == '\n')
+ if (node_content->ptr[pos] == '\n')
pos += 1;
- cmark_strbuf_drop(&b->string_content, pos);
+ cmark_strbuf_drop(node_content, pos);
}
- b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
+ b->as.code.literal = cmark_chunk_buf_detach(node_content);
break;
case CMARK_NODE_HTML_BLOCK:
- b->as.literal = cmark_chunk_buf_detach(&b->string_content);
+ b->as.literal = cmark_chunk_buf_detach(node_content);
break;
case CMARK_NODE_LIST: // determine tight/loose status
@@ -328,6 +347,7 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
default:
break;
}
+
return parent;
}
@@ -342,7 +362,7 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
parent = finalize(parser, parent);
}
- cmark_node *child = make_block(block_type, parser->line_number, start_column);
+ cmark_node *child = make_block(parser->mem, block_type, parser->line_number, start_column);
child->parent = parent;
if (parent->last_child) {
@@ -358,7 +378,7 @@ static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
// Walk through node and all children, recursively, parsing
// string content into inline content where appropriate.
-static void process_inlines(cmark_node *root, cmark_reference_map *refmap,
+static void process_inlines(cmark_mem *mem, cmark_node *root, cmark_reference_map *refmap,
int options) {
cmark_iter *iter = cmark_iter_new(root);
cmark_node *cur;
@@ -368,7 +388,7 @@ static void process_inlines(cmark_node *root, cmark_reference_map *refmap,
cur = cmark_iter_get_node(iter);
if (ev_type == CMARK_EVENT_ENTER) {
if (contains_inlines(cur->type)) {
- cmark_parse_inlines(cur, refmap, options);
+ cmark_parse_inlines(mem, cur, refmap, options);
}
}
}
@@ -379,7 +399,7 @@ static void process_inlines(cmark_node *root, cmark_reference_map *refmap,
// Attempts to parse a list item marker (bullet or enumerated).
// On success, returns length of the marker, and populates
// data with the details. On failure, returns 0.
-static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
+static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input, bufsize_t pos,
cmark_list **dataptr) {
unsigned char c;
bufsize_t startpos;
@@ -393,7 +413,7 @@ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
if (!cmark_isspace(peek_at(input, pos))) {
return 0;
}
- data = (cmark_list *)cmark_calloc(1, sizeof(*data));
+ data = (cmark_list *)mem->calloc(1, sizeof(*data));
data->marker_offset = 0; // will be adjusted later
data->list_type = CMARK_BULLET_LIST;
data->bullet_char = c;
@@ -419,7 +439,7 @@ static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
if (!cmark_isspace(peek_at(input, pos))) {
return 0;
}
- data = (cmark_list *)cmark_calloc(1, sizeof(*data));
+ data = (cmark_list *)mem->calloc(1, sizeof(*data));
data->marker_offset = 0; // will be adjusted later
data->list_type = CMARK_ORDERED_LIST;
data->bullet_char = 0;
@@ -451,7 +471,7 @@ static cmark_node *finalize_document(cmark_parser *parser) {
}
finalize(parser, parser->root);
- process_inlines(parser->root, parser->refmap, parser->options);
+ process_inlines(parser->mem, parser->root, parser->refmap, parser->options);
return parser->root;
}
@@ -899,7 +919,7 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
parser->first_nonspace + 1);
S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
} else if ((matched =
- parse_list_marker(input, parser->first_nonspace, &data)) &&
+ parse_list_marker(parser->mem, input, parser->first_nonspace, &data)) &&
(!indented || cont_type == CMARK_NODE_LIST)) {
// Note that we can have new list items starting with >= 4
// spaces indent, as long as the list container is still open.
diff --git a/src/buffer.c b/src/buffer.c
index 2ac3b04..b879f0c 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -21,7 +21,8 @@ unsigned char cmark_strbuf__initbuf[1];
#define MIN(x, y) ((x < y) ? x : y)
#endif
-void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size) {
+void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, bufsize_t initial_size) {
+ buf->mem = mem;
buf->asize = 0;
buf->size = 0;
buf->ptr = cmark_strbuf__initbuf;
@@ -41,7 +42,7 @@ void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
return;
if (target_size > (bufsize_t)(SIZE_MAX / 4))
- cmark_trigger_oom();
+ abort();
/* Oversize the buffer by 50% to guarantee amortized linear time
* complexity on append operations. */
@@ -49,7 +50,11 @@ void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
new_size += 1;
new_size = (new_size + 7) & ~7;
- unsigned char *new_ptr = cmark_realloc(buf->asize ? buf->ptr : NULL, new_size);
+ unsigned char *new_ptr = buf->mem->calloc(new_size, 1);
+ if (buf->ptr != cmark_strbuf__initbuf) {
+ memcpy(new_ptr, buf->ptr, buf->size);
+ buf->mem->free(buf->ptr);
+ }
buf->asize = new_size;
buf->ptr = new_ptr;
@@ -62,9 +67,9 @@ void cmark_strbuf_free(cmark_strbuf *buf) {
return;
if (buf->ptr != cmark_strbuf__initbuf)
- free(buf->ptr);
+ buf->mem->free(buf->ptr);
- cmark_strbuf_init(buf, 0);
+ cmark_strbuf_init(buf->mem, buf, 0);
}
void cmark_strbuf_clear(cmark_strbuf *buf) {
@@ -147,10 +152,10 @@ unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
if (buf->asize == 0) {
/* return an empty string */
- return cmark_calloc(1, 1);
+ return buf->mem->calloc(1, 1);
}
- cmark_strbuf_init(buf, 0);
+ cmark_strbuf_init(buf->mem, buf, 0);
return data;
}
diff --git a/src/buffer.h b/src/buffer.h
index 89328ac..96b2704 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -7,6 +7,7 @@
#include <limits.h>
#include <stdbool.h>
#include "config.h"
+#include "cmark.h"
#ifdef __cplusplus
extern "C" {
@@ -15,22 +16,22 @@ extern "C" {
typedef ssize_t bufsize_t;
typedef struct {
+ cmark_mem *mem;
unsigned char *ptr;
bufsize_t asize, size;
} cmark_strbuf;
extern unsigned char cmark_strbuf__initbuf[];
-#define GH_BUF_INIT \
- { cmark_strbuf__initbuf, 0, 0 }
+#define CMARK_BUF_INIT(mem) {mem, cmark_strbuf__initbuf, 0, 0}
/**
* Initialize a cmark_strbuf structure.
*
- * For the cases where GH_BUF_INIT cannot be used to do static
+ * For the cases where CMARK_BUF_INIT cannot be used to do static
* initialization.
*/
-void cmark_strbuf_init(cmark_strbuf *buf, bufsize_t initial_size);
+void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf, bufsize_t initial_size);
/**
* Grow the buffer to hold at least `target_size` bytes.
diff --git a/src/chunk.h b/src/chunk.h
index acceaa1..4dfc698 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -4,9 +4,10 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
+#include "cmark.h"
+#include "buffer.h"
#include "memory.h"
#include "cmark_ctype.h"
-#include "buffer.h"
#define CMARK_CHUNK_EMPTY \
{ NULL, 0, 0 }
@@ -17,9 +18,9 @@ typedef struct {
bufsize_t alloc; // also implies a NULL-terminated string
} cmark_chunk;
-static CMARK_INLINE void cmark_chunk_free(cmark_chunk *c) {
+static CMARK_INLINE void cmark_chunk_free(cmark_mem *mem, cmark_chunk *c) {
if (c->alloc)
- free(c->data);
+ mem->free(c->data);
c->data = NULL;
c->alloc = 0;
@@ -56,13 +57,13 @@ static CMARK_INLINE bufsize_t
return p ? (bufsize_t)(p - ch->data) : ch->len;
}
-static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_chunk *c) {
+static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_mem *mem, cmark_chunk *c) {
unsigned char *str;
if (c->alloc) {
return (char *)c->data;
}
- str = (unsigned char *)cmark_calloc(c->len + 1, 1);
+ str = (unsigned char *)mem->calloc(c->len + 1, 1);
if (c->len > 0) {
memcpy(str, c->data, c->len);
}
@@ -73,9 +74,9 @@ static CMARK_INLINE const char *cmark_chunk_to_cstr(cmark_chunk *c) {
return (char *)str;
}
-static CMARK_INLINE void cmark_chunk_set_cstr(cmark_chunk *c, const char *str) {
+static CMARK_INLINE void cmark_chunk_set_cstr(cmark_mem *mem, cmark_chunk *c, const char *str) {
if (c->alloc) {
- free(c->data);
+ mem->free(c->data);
}
if (str == NULL) {
c->len = 0;
@@ -83,7 +84,7 @@ static CMARK_INLINE void cmark_chunk_set_cstr(cmark_chunk *c, const char *str) {
c->alloc = 0;
} else {
c->len = strlen(str);
- c->data = (unsigned char *)cmark_calloc(c->len + 1, 1);
+ c->data = (unsigned char *)mem->calloc(c->len + 1, 1);
c->alloc = 1;
memcpy(c->data, str, c->len + 1);
}
diff --git a/src/cmark.c b/src/cmark.c
index 3288308..3491199 100644
--- a/src/cmark.c
+++ b/src/cmark.c
@@ -10,36 +10,6 @@ int cmark_version() { return CMARK_VERSION; }
const char *cmark_version_string() { return CMARK_VERSION_STRING; }
-void (*_cmark_on_oom)(void) = NULL;
-
-void cmark_trigger_oom(void)
-{
- if (_cmark_on_oom)
- _cmark_on_oom();
- abort();
-}
-
-void cmark_set_oom_handler(void (*handler)(void))
-{
- _cmark_on_oom = handler;
-}
-
-void *cmark_calloc(size_t nmem, size_t size)
-{
- void *ptr = calloc(nmem, size);
- if (!ptr)
- cmark_trigger_oom();
- return ptr;
-}
-
-void *cmark_realloc(void *ptr, size_t size)
-{
- void *ptr_new = realloc(ptr, size);
- if (!ptr_new)
- cmark_trigger_oom();
- return ptr_new;
-}
-
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
cmark_node *doc;
char *result;
diff --git a/src/cmark.h b/src/cmark.h
index a43011b..293919d 100644
--- a/src/cmark.h
+++ b/src/cmark.h
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <cmark_export.h>
#include <cmark_version.h>
+#include "memory.h"
#ifdef __cplusplus
extern "C" {
@@ -88,6 +89,19 @@ typedef struct cmark_parser cmark_parser;
typedef struct cmark_iter cmark_iter;
/**
+ * ## Custom memory allocator support
+ */
+
+/** Defines the memory allocation functions to be used by CMark
+ * when parsing and allocating a document tree
+ */
+typedef struct cmark_mem {
+ void *(*calloc)(size_t, size_t);
+ void (*free)(void *);
+} cmark_mem;
+
+
+/**
* ## Creating and Destroying Nodes
*/
@@ -97,6 +111,11 @@ typedef struct cmark_iter cmark_iter;
*/
CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
+/** Same as `cmark_node_new`, but explicitly listing the memory
+ * allocator used to allocate the node
+ */
+CMARK_EXPORT cmark_node *cmark_node_new2(cmark_node_type type, cmark_mem *mem);
+
/** Frees the memory allocated for a node and any children.
*/
CMARK_EXPORT void cmark_node_free(cmark_node *node);
@@ -437,6 +456,11 @@ CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
CMARK_EXPORT
cmark_parser *cmark_parser_new(int options);
+/** Creates a new parser object with the given memory allocator
+ */
+CMARK_EXPORT
+cmark_parser *cmark_parser_new2(int options, cmark_mem *mem);
+
/** Frees memory allocated for a parser object.
*/
CMARK_EXPORT
@@ -573,20 +597,6 @@ int cmark_version();
CMARK_EXPORT
const char *cmark_version_string();
-/** Set the callback function that will be issued whenever the
- * library hits an out of memory situation.
- *
- * This can happen when the heap memory allocator fails to allocate
- * a block of memory, or when the index of an in-memory buffer overflows
- *
- * If no OOM handler is set, the library will call `abort` and
- * terminate itself and the running process. If the custom OOM handler
- * you set does return (i.e. it does not gracefully terminate the
- * application), the behavior of the library will be unspecified.
- */
-CMARK_EXPORT
-void cmark_set_oom_handler(void (*handler)(void));
-
/** # AUTHORS
*
* John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
diff --git a/src/html.c b/src/html.c
index c2267cb..a680e4a 100644
--- a/src/html.c
+++ b/src/html.c
@@ -324,7 +324,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
char *cmark_render_html(cmark_node *root, int options) {
char *result;
- cmark_strbuf html = GH_BUF_INIT;
+ cmark_strbuf html = CMARK_BUF_INIT(cmark_node_mem(root));
cmark_event_type ev_type;
cmark_node *cur;
struct render_state state = {&html, NULL};
diff --git a/src/inlines.c b/src/inlines.c
index f2e7cf1..8f18e6c 100644
--- a/src/inlines.c
+++ b/src/inlines.c
@@ -22,13 +22,13 @@ static const char *LEFTSINGLEQUOTE = "\xE2\x80\x98";
static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99";
// Macros for creating various kinds of simple.
-#define make_str(s) make_literal(CMARK_NODE_TEXT, s)
-#define make_code(s) make_literal(CMARK_NODE_CODE, s)
-#define make_raw_html(s) make_literal(CMARK_NODE_HTML_INLINE, s)
-#define make_linebreak() make_simple(CMARK_NODE_LINEBREAK)
-#define make_softbreak() make_simple(CMARK_NODE_SOFTBREAK)
-#define make_emph() make_simple(CMARK_NODE_EMPH)
-#define make_strong() make_simple(CMARK_NODE_STRONG)
+#define make_str(mem, s) make_literal(mem, CMARK_NODE_TEXT, s)
+#define make_code(mem, s) make_literal(mem, CMARK_NODE_CODE, s)
+#define make_raw_html(mem, s) make_literal(mem, CMARK_NODE_HTML_INLINE, s)
+#define make_linebreak(mem) make_simple(mem, CMARK_NODE_LINEBREAK)
+#define make_softbreak(mem) make_simple(mem, CMARK_NODE_SOFTBREAK)
+#define make_emph(mem) make_simple(mem, CMARK_NODE_EMPH)
+#define make_strong(mem) make_simple(mem, CMARK_NODE_STRONG)
typedef struct delimiter {
struct delimiter *previous;
@@ -42,6 +42,7 @@ typedef struct delimiter {
} delimiter;
typedef struct {
+ cmark_mem *mem;
cmark_chunk input;
bufsize_t pos;
cmark_reference_map *refmap;
@@ -57,44 +58,46 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
static int parse_inline(subject *subj, cmark_node *parent, int options);
-static void subject_from_buf(subject *e, cmark_strbuf *buffer,
+static void subject_from_buf(cmark_mem *mem, subject *e, cmark_strbuf *buffer,
cmark_reference_map *refmap);
static bufsize_t subject_find_special_char(subject *subj, int options);
// Create an inline with a literal string value.
-static CMARK_INLINE cmark_node *make_literal(cmark_node_type t, cmark_chunk s) {
- cmark_node *e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+static CMARK_INLINE cmark_node *make_literal(cmark_mem *mem, cmark_node_type t, cmark_chunk s) {
+ cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e));
+ cmark_strbuf_init(mem, &e->content, 0);
e->type = t;
e->as.literal = s;
return e;
}
// Create an inline with no value.
-static CMARK_INLINE cmark_node *make_simple(cmark_node_type t) {
- cmark_node *e = (cmark_node *)cmark_calloc(1, sizeof(*e));
+static CMARK_INLINE cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) {
+ cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e));
+ cmark_strbuf_init(mem, &e->content, 0);
e->type = t;
return e;
}
// Like make_str, but parses entities.
-static cmark_node *make_str_with_entities(cmark_chunk *content) {
- cmark_strbuf unescaped = GH_BUF_INIT;
+static cmark_node *make_str_with_entities(cmark_mem *mem, cmark_chunk *content) {
+ cmark_strbuf unescaped = CMARK_BUF_INIT(mem);
if (houdini_unescape_html(&unescaped, content->data, content->len)) {
- return make_str(cmark_chunk_buf_detach(&unescaped));
+ return make_str(mem, cmark_chunk_buf_detach(&unescaped));
} else {
- return make_str(*content);
+ return make_str(mem, *content);
}
}
// Duplicate a chunk by creating a copy of the buffer not by reusing the
// buffer like cmark_chunk_dup does.
-static cmark_chunk chunk_clone(cmark_chunk *src) {
+static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
cmark_chunk c;
bufsize_t len = src->len;
c.len = len;
- c.data = (unsigned char *)cmark_calloc(len + 1, 1);
+ c.data = (unsigned char *)mem->calloc(len + 1, 1);
c.alloc = 1;
memcpy(c.data, src->data, len);
c.data[len] = '\0';
@@ -102,8 +105,8 @@ static cmark_chunk chunk_clone(cmark_chunk *src) {
return c;
}
-static cmark_chunk cmark_clean_autolink(cmark_chunk *url, int is_email) {
- cmark_strbuf buf = GH_BUF_INIT;
+static cmark_chunk cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url, int is_email) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
cmark_chunk_trim(url);
@@ -119,16 +122,17 @@ static cmark_chunk cmark_clean_autolink(cmark_chunk *url, int is_email) {
return cmark_chunk_buf_detach(&buf);
}
-static CMARK_INLINE cmark_node *make_autolink(cmark_chunk url, int is_email) {
- cmark_node *link = make_simple(CMARK_NODE_LINK);
- link->as.link.url = cmark_clean_autolink(&url, is_email);
+static CMARK_INLINE cmark_node *make_autolink(cmark_mem *mem, cmark_chunk url, int is_email) {
+ cmark_node *link = make_simple(mem, CMARK_NODE_LINK);
+ link->as.link.url = cmark_clean_autolink(mem, &url, is_email);
link->as.link.title = cmark_chunk_literal("");
- cmark_node_append_child(link, make_str_with_entities(&url));
+ cmark_node_append_child(link, make_str_with_entities(mem, &url));
return link;
}
-static void subject_from_buf(subject *e, cmark_strbuf *buffer,
+static void subject_from_buf(cmark_mem *mem, subject *e, cmark_strbuf *buffer,
cmark_reference_map *refmap) {
+ e->mem = mem;
e->input.data = buffer->ptr;
e->input.len = buffer->size;
e->input.alloc = 0;
@@ -229,16 +233,16 @@ static cmark_node *handle_backticks(subject *subj) {
if (endpos == 0) { // not found
subj->pos = startpos; // rewind
- return make_str(openticks);
+ return make_str(subj->mem, openticks);
} else {
- cmark_strbuf buf = GH_BUF_INIT;
+ cmark_strbuf buf = CMARK_BUF_INIT(subj->mem);
cmark_strbuf_set(&buf, subj->input.data + startpos,
endpos - startpos - openticks.len);
cmark_strbuf_trim(&buf);
cmark_strbuf_normalize_whitespace(&buf);
- return make_code(cmark_chunk_buf_detach(&buf));
+ return make_code(subj->mem, cmark_chunk_buf_detach(&buf));
}
}
@@ -340,7 +344,7 @@ static void remove_delimiter(subject *subj, delimiter *delim) {
static void push_delimiter(subject *subj, unsigned char c, bool can_open,
bool can_close, cmark_node *inl_text) {
- delimiter *delim = (delimiter *)cmark_calloc(1, sizeof(delimiter));
+ delimiter *delim = (delimiter *)subj->mem->calloc(1, sizeof(delimiter));
delim->delim_char = c;
delim->can_open = can_open;
delim->can_close = can_close;
@@ -373,7 +377,7 @@ static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart) {
contents = cmark_chunk_dup(&subj->input, subj->pos - numdelims, numdelims);
}
- inl_text = make_str(contents);
+ inl_text = make_str(subj->mem, contents);
if ((can_open || can_close) && (!(c == '\'' || c == '"') || smart)) {
push_delimiter(subj, c, can_open, can_close, inl_text);
@@ -389,7 +393,7 @@ static cmark_node *handle_hyphen(subject *subj, bool smart) {
advance(subj);
if (!smart || peek_char(subj) != '-') {
- return make_str(cmark_chunk_literal("-"));
+ return make_str(subj->mem, cmark_chunk_literal("-"));
}
while (smart && peek_char(subj) == '-') {
@@ -400,7 +404,7 @@ static cmark_node *handle_hyphen(subject *subj, bool smart) {
int en_count = 0;
int em_count = 0;
int i;
- cmark_strbuf buf = GH_BUF_INIT;
+ cmark_strbuf buf = CMARK_BUF_INIT(subj->mem);
if (numhyphens % 3 == 0) { // if divisible by 3, use all em dashes
em_count = numhyphens / 3;
@@ -422,7 +426,7 @@ static cmark_node *handle_hyphen(subject *subj, bool smart) {
cmark_strbuf_puts(&buf, ENDASH);
}
- return make_str(cmark_chunk_buf_detach(&buf));
+ return make_str(subj->mem, cmark_chunk_buf_detach(&buf));
}
// Assumes we have a period at the current position.
@@ -432,12 +436,12 @@ static cmark_node *handle_period(subject *subj, bool smart) {
advance(subj);
if (peek_char(subj) == '.') {
advance(subj);
- return make_str(cmark_chunk_literal(ELLIPSES));
+ return make_str(subj->mem, cmark_chunk_literal(ELLIPSES));
} else {
- return make_str(cmark_chunk_literal(".."));
+ return make_str(subj->mem, cmark_chunk_literal(".."));
}
} else {
- return make_str(cmark_chunk_literal("."));
+ return make_str(subj->mem, cmark_chunk_literal("."));
}
}
@@ -483,18 +487,18 @@ static void process_emphasis(subject *subj, delimiter *stack_bottom) {
closer = closer->next;
}
} else if (closer->delim_char == '\'') {
- cmark_chunk_free(&closer->inl_text->as.literal);
+ cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE);
if (opener_found) {
- cmark_chunk_free(&opener->inl_text->as.literal);
+ cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE);
}
closer = closer->next;
} else if (closer->delim_char == '"') {
- cmark_chunk_free(&closer->inl_text->as.literal);
+ cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
if (opener_found) {
- cmark_chunk_free(&opener->inl_text->as.literal);
+ cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE);
}
closer = closer->next;
@@ -553,7 +557,7 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
// create new emph or strong, and splice it in to our inlines
// between the opener and closer
- emph = use_delims == 1 ? make_emph() : make_strong();
+ emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem);
tmp = opener_inl->next;
while (tmp && tmp != closer_inl) {
@@ -589,18 +593,18 @@ static cmark_node *handle_backslash(subject *subj) {
if (cmark_ispunct(
nextchar)) { // only ascii symbols and newline can be escaped
advance(subj);
- return make_str(cmark_chunk_dup(&subj->input, subj->pos - 1, 1));
+ return make_str(subj->mem, cmark_chunk_dup(&subj->input, subj->pos - 1, 1));
} else if (!is_eof(subj) && skip_line_end(subj)) {
- return make_linebreak();
+ return make_linebreak(subj->mem);
} else {
- return make_str(cmark_chunk_literal("\\"));
+ return make_str(subj->mem, cmark_chunk_literal("\\"));
}
}
// Parse an entity or a regular "&" string.
// Assumes the subject has an '&' character at the current position.
static cmark_node *handle_entity(subject *subj) {
- cmark_strbuf ent = GH_BUF_INIT;
+ cmark_strbuf ent = CMARK_BUF_INIT(subj->mem);
bufsize_t len;
advance(subj);
@@ -609,16 +613,16 @@ static cmark_node *handle_entity(subject *subj) {
subj->input.len - subj->pos);
if (len == 0)
- return make_str(cmark_chunk_literal("&"));
+ return make_str(subj->mem, cmark_chunk_literal("&"));
subj->pos += len;
- return make_str(cmark_chunk_buf_detach(&ent));
+ return make_str(subj->mem, cmark_chunk_buf_detach(&ent));
}
// Clean a URL: remove surrounding whitespace and surrounding <>,
// and remove \ that escape punctuation.
-cmark_chunk cmark_clean_url(cmark_chunk *url) {
- cmark_strbuf buf = GH_BUF_INIT;
+cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
cmark_chunk_trim(url);
@@ -637,8 +641,8 @@ cmark_chunk cmark_clean_url(cmark_chunk *url) {
return cmark_chunk_buf_detach(&buf);
}
-cmark_chunk cmark_clean_title(cmark_chunk *title) {
- cmark_strbuf buf = GH_BUF_INIT;
+cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
unsigned char first, last;
if (title->len == 0) {
@@ -675,7 +679,7 @@ static cmark_node *handle_pointy_brace(subject *subj) {
contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1);
subj->pos += matchlen;
- return make_autolink(contents, 0);
+ return make_autolink(subj->mem, contents, 0);
}
// next try to match an email autolink
@@ -684,7 +688,7 @@ static cmark_node *handle_pointy_brace(subject *subj) {
contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1);
subj->pos += matchlen;
- return make_autolink(contents, 1);
+ return make_autolink(subj->mem, contents, 1);
}
// finally, try to match an html tag
@@ -692,11 +696,11 @@ static cmark_node *handle_pointy_brace(subject *subj) {
if (matchlen > 0) {
contents = cmark_chunk_dup(&subj->input, subj->pos - 1, matchlen + 1);
subj->pos += matchlen;
- return make_raw_html(contents);
+ return make_raw_html(subj->mem, contents);
}
// if nothing matches, just return the opening <:
- return make_str(cmark_chunk_literal("<"));
+ return make_str(subj->mem, cmark_chunk_literal("<"));
}
// Parse a link label. Returns 1 if successful.
@@ -774,13 +778,13 @@ static cmark_node *handle_close_bracket(subject *subj) {
}
if (opener == NULL) {
- return make_str(cmark_chunk_literal("]"));
+ return make_str(subj->mem, cmark_chunk_literal("]"));
}
if (!opener->active) {
// take delimiter off stack
remove_delimiter(subj, opener);
- return make_str(cmark_chunk_literal("]"));
+ return make_str(subj->mem, cmark_chunk_literal("]"));
}
// If we got here, we matched a potential link/image text.
@@ -811,10 +815,10 @@ static cmark_node *handle_close_bracket(subject *subj) {
url_chunk = cmark_chunk_dup(&subj->input, starturl, endurl - starturl);
title_chunk =
cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle);
- url = cmark_clean_url(&url_chunk);
- title = cmark_clean_title(&title_chunk);
- cmark_chunk_free(&url_chunk);
- cmark_chunk_free(&title_chunk);
+ url = cmark_clean_url(subj->mem, &url_chunk);
+ title = cmark_clean_title(subj->mem, &title_chunk);
+ cmark_chunk_free(subj->mem, &url_chunk);
+ cmark_chunk_free(subj->mem, &title_chunk);
goto match;
} else {
@@ -827,7 +831,7 @@ static cmark_node *handle_close_bracket(subject *subj) {
raw_label = cmark_chunk_literal("");
found_label = link_label(subj, &raw_label);
if (!found_label || raw_label.len == 0) {
- cmark_chunk_free(&raw_label);
+ cmark_chunk_free(subj->mem, &raw_label);
raw_label = cmark_chunk_dup(&subj->input, opener->position,
initial_pos - opener->position - 1);
}
@@ -839,11 +843,11 @@ static cmark_node *handle_close_bracket(subject *subj) {
}
ref = cmark_reference_lookup(subj->refmap, &raw_label);
- cmark_chunk_free(&raw_label);
+ cmark_chunk_free(subj->mem, &raw_label);
if (ref != NULL) { // found
- url = chunk_clone(&ref->url);
- title = chunk_clone(&ref->title);
+ url = chunk_clone(subj->mem, &ref->url);
+ title = chunk_clone(subj->mem, &ref->title);
goto match;
} else {
goto noMatch;
@@ -853,10 +857,10 @@ noMatch:
// If we fall through to here, it means we didn't match a link:
remove_delimiter(subj, opener); // remove this opener from delimiter list
subj->pos = initial_pos;
- return make_str(cmark_chunk_literal("]"));
+ return make_str(subj->mem, cmark_chunk_literal("]"));
match:
- inl = make_simple(is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK);
+ inl = make_simple(subj->mem, is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK);
inl->as.link.url = url;
inl->as.link.title = title;
cmark_node_insert_before(opener->inl_text, inl);
@@ -909,9 +913,9 @@ static cmark_node *handle_newline(subject *subj) {
skip_spaces(subj);
if (nlpos > 1 && peek_at(subj, nlpos - 1) == ' ' &&
peek_at(subj, nlpos - 2) == ' ') {
- return make_linebreak();
+ return make_linebreak(subj->mem);
} else {
- return make_softbreak();
+ return make_softbreak(subj->mem);
}
}
@@ -1000,7 +1004,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
break;
case '[':
advance(subj);
- new_inl = make_str(cmark_chunk_literal("["));
+ new_inl = make_str(subj->mem, cmark_chunk_literal("["));
push_delimiter(subj, '[', true, false, new_inl);
break;
case ']':
@@ -1010,10 +1014,10 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
advance(subj);
if (peek_char(subj) == '[') {
advance(subj);
- new_inl = make_str(cmark_chunk_literal("!["));
+ new_inl = make_str(subj->mem, cmark_chunk_literal("!["));
push_delimiter(subj, '!', false, true, new_inl);
} else {
- new_inl = make_str(cmark_chunk_literal("!"));
+ new_inl = make_str(subj->mem, cmark_chunk_literal("!"));
}
break;
default:
@@ -1026,7 +1030,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
cmark_chunk_rtrim(&contents);
}
- new_inl = make_str(contents);
+ new_inl = make_str(subj->mem, contents);
}
if (new_inl != NULL) {
cmark_node_append_child(parent, new_inl);
@@ -1036,10 +1040,10 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
}
// Parse inlines from parent's string_content, adding as children of parent.
-extern void cmark_parse_inlines(cmark_node *parent, cmark_reference_map *refmap,
+extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, cmark_reference_map *refmap,
int options) {
subject subj;
- subject_from_buf(&subj, &parent->string_content, refmap);
+ subject_from_buf(mem, &subj, &parent->content, refmap);
cmark_chunk_rtrim(&subj.input);
while (!is_eof(&subj) && parse_inline(&subj, parent, options))
@@ -1060,7 +1064,7 @@ static void spnl(subject *subj) {
// Modify refmap if a reference is encountered.
// Return 0 if no reference found, otherwise position of subject
// after reference is parsed.
-bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
+bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_strbuf *input,
cmark_reference_map *refmap) {
subject subj;
@@ -1071,7 +1075,7 @@ bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
bufsize_t matchlen = 0;
bufsize_t beforetitle;
- subject_from_buf(&subj, input, NULL);
+ subject_from_buf(mem, &subj, input, NULL);
// parse label:
if (!link_label(&subj, &lab) || lab.len == 0)
diff --git a/src/inlines.h b/src/inlines.h
index 7e7ee45..cbe7830 100644
--- a/src/inlines.h
+++ b/src/inlines.h
@@ -5,13 +5,13 @@
extern "C" {
#endif
-cmark_chunk cmark_clean_url(cmark_chunk *url);
-cmark_chunk cmark_clean_title(cmark_chunk *title);
+cmark_chunk cmark_clean_url(cmark_mem *mem, cmark_chunk *url);
+cmark_chunk cmark_clean_title(cmark_mem *mem, cmark_chunk *title);
-void cmark_parse_inlines(cmark_node *parent, cmark_reference_map *refmap,
+void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, cmark_reference_map *refmap,
int options);
-bufsize_t cmark_parse_reference_inline(cmark_strbuf *input,
+bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_strbuf *input,
cmark_reference_map *refmap);
#ifdef __cplusplus
diff --git a/src/iterator.c b/src/iterator.c
index 40287f5..24423a2 100644
--- a/src/iterator.c
+++ b/src/iterator.c
@@ -16,7 +16,9 @@ cmark_iter *cmark_iter_new(cmark_node *root) {
if (root == NULL) {
return NULL;
}
- cmark_iter *iter = (cmark_iter *)cmark_calloc(1, sizeof(cmark_iter));
+ cmark_mem *mem = root->content.mem;
+ cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter));
+ iter->mem = mem;
iter->root = root;
iter->cur.ev_type = CMARK_EVENT_NONE;
iter->cur.node = NULL;
@@ -25,7 +27,7 @@ cmark_iter *cmark_iter_new(cmark_node *root) {
return iter;
}
-void cmark_iter_free(cmark_iter *iter) { free(iter); }
+void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
static bool S_is_leaf(cmark_node *node) {
return ((1 << node->type) & S_leaf_mask) != 0;
@@ -90,7 +92,7 @@ void cmark_consolidate_text_nodes(cmark_node *root) {
return;
}
cmark_iter *iter = cmark_iter_new(root);
- cmark_strbuf buf = GH_BUF_INIT;
+ cmark_strbuf buf = CMARK_BUF_INIT(iter->mem);
cmark_event_type ev_type;
cmark_node *cur, *tmp, *next;
@@ -108,7 +110,7 @@ void cmark_consolidate_text_nodes(cmark_node *root) {
cmark_node_free(tmp);
tmp = next;
}
- cmark_chunk_free(&cur->as.literal);
+ cmark_chunk_free(iter->mem, &cur->as.literal);
cur->as.literal = cmark_chunk_buf_detach(&buf);
}
}
diff --git a/src/iterator.h b/src/iterator.h
index 9c6bca6..fc745df 100644
--- a/src/iterator.h
+++ b/src/iterator.h
@@ -6,6 +6,7 @@ extern "C" {
#endif
#include "cmark.h"
+#include "memory.h"
typedef struct {
cmark_event_type ev_type;
@@ -13,6 +14,7 @@ typedef struct {
} cmark_iter_state;
struct cmark_iter {
+ cmark_mem *mem;
cmark_node *root;
cmark_iter_state cur;
cmark_iter_state next;
diff --git a/src/main.c b/src/main.c
index 5ea4b61..88a4f32 100644
--- a/src/main.c
+++ b/src/main.c
@@ -81,7 +81,7 @@ int main(int argc, char *argv[]) {
_setmode(_fileno(stdout), _O_BINARY);
#endif
- files = (int *)cmark_calloc(argc, sizeof(*files));
+ files = (int *)calloc(argc, sizeof(*files));
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0) {
diff --git a/src/memory.h b/src/memory.h
deleted file mode 100644
index f05d566..0000000
--- a/src/memory.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef CMARK_MEM_H
-#define CMARK_MEM_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void *cmark_calloc(size_t nmem, size_t size);
-void *cmark_realloc(void *ptr, size_t size);
-void cmark_trigger_oom(void);
-
-#endif
diff --git a/src/node.c b/src/node.c
index 30cd69f..fee919d 100644
--- a/src/node.c
+++ b/src/node.c
@@ -6,6 +6,8 @@
static void S_node_unlink(cmark_node *node);
+#define NODE_MEM(node) cmark_node_mem(node)
+
static CMARK_INLINE bool S_is_block(cmark_node *node) {
if (node == NULL) {
return false;
@@ -28,6 +30,9 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
if (node == NULL || child == NULL) {
return false;
}
+ if (NODE_MEM(node) != NODE_MEM(child)) {
+ return 0;
+ }
// Verify that child is not an ancestor of node or equal to node.
cur = node;
@@ -70,8 +75,9 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
return false;
}
-cmark_node *cmark_node_new(cmark_node_type type) {
- cmark_node *node = (cmark_node *)cmark_calloc(1, sizeof(*node));
+cmark_node *cmark_node_new2(cmark_node_type type, cmark_mem *mem) {
+ cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node));
+ cmark_strbuf_init(mem, &node->content, 0);
node->type = type;
switch (node->type) {
@@ -94,33 +100,36 @@ cmark_node *cmark_node_new(cmark_node_type type) {
return node;
}
+cmark_node *cmark_node_new(cmark_node_type type) {
+ extern cmark_mem DEFAULT_MEM_ALLOCATOR;
+ return cmark_node_new2(type, &DEFAULT_MEM_ALLOCATOR);
+}
+
// Free a cmark_node list and any children.
static void S_free_nodes(cmark_node *e) {
cmark_node *next;
while (e != NULL) {
- if (S_is_block(e)) {
- cmark_strbuf_free(&e->string_content);
- }
+ cmark_strbuf_free(&e->content);
switch (e->type) {
case CMARK_NODE_CODE_BLOCK:
- cmark_chunk_free(&e->as.code.info);
- cmark_chunk_free(&e->as.code.literal);
+ cmark_chunk_free(NODE_MEM(e), &e->as.code.info);
+ cmark_chunk_free(NODE_MEM(e), &e->as.code.literal);
break;
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
case CMARK_NODE_HTML_BLOCK:
- cmark_chunk_free(&e->as.literal);
+ cmark_chunk_free(NODE_MEM(e), &e->as.literal);
break;
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
- cmark_chunk_free(&e->as.link.url);
- cmark_chunk_free(&e->as.link.title);
+ cmark_chunk_free(NODE_MEM(e), &e->as.link.url);
+ cmark_chunk_free(NODE_MEM(e), &e->as.link.title);
break;
case CMARK_NODE_CUSTOM_BLOCK:
case CMARK_NODE_CUSTOM_INLINE:
- cmark_chunk_free(&e->as.custom.on_enter);
- cmark_chunk_free(&e->as.custom.on_exit);
+ cmark_chunk_free(NODE_MEM(e), &e->as.custom.on_enter);
+ cmark_chunk_free(NODE_MEM(e), &e->as.custom.on_exit);
break;
default:
break;
@@ -131,7 +140,7 @@ static void S_free_nodes(cmark_node *e) {
e->next = e->first_child;
}
next = e->next;
- free(e);
+ NODE_MEM(e)->free(e);
e = next;
}
}
@@ -269,10 +278,10 @@ const char *cmark_node_get_literal(cmark_node *node) {
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
- return cmark_chunk_to_cstr(&node->as.literal);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.literal);
case CMARK_NODE_CODE_BLOCK:
- return cmark_chunk_to_cstr(&node->as.code.literal);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.code.literal);
default:
break;
@@ -291,11 +300,11 @@ int cmark_node_set_literal(cmark_node *node, const char *content) {
case CMARK_NODE_TEXT:
case CMARK_NODE_HTML_INLINE:
case CMARK_NODE_CODE:
- cmark_chunk_set_cstr(&node->as.literal, content);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.literal, content);
return 1;
case CMARK_NODE_CODE_BLOCK:
- cmark_chunk_set_cstr(&node->as.code.literal, content);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.code.literal, content);
return 1;
default:
@@ -452,7 +461,7 @@ const char *cmark_node_get_fence_info(cmark_node *node) {
}
if (node->type == CMARK_NODE_CODE_BLOCK) {
- return cmark_chunk_to_cstr(&node->as.code.info);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.code.info);
} else {
return NULL;
}
@@ -464,7 +473,7 @@ int cmark_node_set_fence_info(cmark_node *node, const char *info) {
}
if (node->type == CMARK_NODE_CODE_BLOCK) {
- cmark_chunk_set_cstr(&node->as.code.info, info);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.code.info, info);
return 1;
} else {
return 0;
@@ -479,7 +488,7 @@ const char *cmark_node_get_url(cmark_node *node) {
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
- return cmark_chunk_to_cstr(&node->as.link.url);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.link.url);
default:
break;
}
@@ -495,7 +504,7 @@ int cmark_node_set_url(cmark_node *node, const char *url) {
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
- cmark_chunk_set_cstr(&node->as.link.url, url);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.link.url, url);
return 1;
default:
break;
@@ -512,7 +521,7 @@ const char *cmark_node_get_title(cmark_node *node) {
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
- return cmark_chunk_to_cstr(&node->as.link.title);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.link.title);
default:
break;
}
@@ -528,7 +537,7 @@ int cmark_node_set_title(cmark_node *node, const char *title) {
switch (node->type) {
case CMARK_NODE_LINK:
case CMARK_NODE_IMAGE:
- cmark_chunk_set_cstr(&node->as.link.title, title);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.link.title, title);
return 1;
default:
break;
@@ -545,7 +554,7 @@ const char *cmark_node_get_on_enter(cmark_node *node) {
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
- return cmark_chunk_to_cstr(&node->as.custom.on_enter);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.custom.on_enter);
default:
break;
}
@@ -561,7 +570,7 @@ int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
- cmark_chunk_set_cstr(&node->as.custom.on_enter, on_enter);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.custom.on_enter, on_enter);
return 1;
default:
break;
@@ -578,7 +587,7 @@ const char *cmark_node_get_on_exit(cmark_node *node) {
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
- return cmark_chunk_to_cstr(&node->as.custom.on_exit);
+ return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.custom.on_exit);
default:
break;
}
@@ -594,7 +603,7 @@ int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
switch (node->type) {
case CMARK_NODE_CUSTOM_INLINE:
case CMARK_NODE_CUSTOM_BLOCK:
- cmark_chunk_set_cstr(&node->as.custom.on_exit, on_exit);
+ cmark_chunk_set_cstr(NODE_MEM(node), &node->as.custom.on_exit, on_exit);
return 1;
default:
break;
diff --git a/src/node.h b/src/node.h
index 397d8e3..1fff990 100644
--- a/src/node.h
+++ b/src/node.h
@@ -48,6 +48,8 @@ typedef struct {
} cmark_custom;
struct cmark_node {
+ cmark_strbuf content;
+
struct cmark_node *next;
struct cmark_node *prev;
struct cmark_node *parent;
@@ -62,11 +64,8 @@ struct cmark_node {
int end_column;
cmark_node_type type;
-
- bool open;
bool last_line_blank;
-
- cmark_strbuf string_content;
+ bool open;
union {
cmark_chunk literal;
@@ -79,6 +78,9 @@ struct cmark_node {
} as;
};
+static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
+ return node->content.mem;
+}
CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
#ifdef __cplusplus
diff --git a/src/parser.h b/src/parser.h
index ab21d0f..1309420 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -4,6 +4,7 @@
#include <stdio.h>
#include "node.h"
#include "buffer.h"
+#include "memory.h"
#ifdef __cplusplus
extern "C" {
@@ -12,6 +13,7 @@ extern "C" {
#define MAX_LINK_LABEL_LENGTH 1000
struct cmark_parser {
+ struct cmark_mem *mem;
struct cmark_reference_map *refmap;
struct cmark_node *root;
struct cmark_node *current;
diff --git a/src/references.c b/src/references.c
index 168bd89..235e0af 100755
--- a/src/references.c
+++ b/src/references.c
@@ -14,12 +14,13 @@ static unsigned int refhash(const unsigned char *link_ref) {
return hash;
}
-static void reference_free(cmark_reference *ref) {
+static void reference_free(cmark_reference_map *map, cmark_reference *ref) {
+ cmark_mem *mem = map->mem;
if (ref != NULL) {
- free(ref->label);
- cmark_chunk_free(&ref->url);
- cmark_chunk_free(&ref->title);
- free(ref);
+ mem->free(ref->label);
+ cmark_chunk_free(mem, &ref->url);
+ cmark_chunk_free(mem, &ref->title);
+ mem->free(ref);
}
}
@@ -27,8 +28,8 @@ static void reference_free(cmark_reference *ref) {
// remove leading/trailing whitespace, case fold
// Return NULL if the reference name is actually empty (i.e. composed
// solely from whitespace)
-static unsigned char *normalize_reference(cmark_chunk *ref) {
- cmark_strbuf normalized = GH_BUF_INIT;
+static unsigned char *normalize_reference(cmark_mem *mem, cmark_chunk *ref) {
+ cmark_strbuf normalized = CMARK_BUF_INIT(mem);
unsigned char *result;
if (ref == NULL)
@@ -57,7 +58,7 @@ static void add_reference(cmark_reference_map *map, cmark_reference *ref) {
while (t) {
if (t->hash == ref->hash && !strcmp((char *)t->label, (char *)ref->label)) {
- reference_free(ref);
+ reference_free(map, ref);
return;
}
@@ -70,17 +71,17 @@ static void add_reference(cmark_reference_map *map, cmark_reference *ref) {
void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
cmark_chunk *url, cmark_chunk *title) {
cmark_reference *ref;
- unsigned char *reflabel = normalize_reference(label);
+ unsigned char *reflabel = normalize_reference(map->mem, label);
/* empty reference name, or composed from only whitespace */
if (reflabel == NULL)
return;
- ref = (cmark_reference *)cmark_calloc(1, sizeof(*ref));
+ ref = (cmark_reference *)map->mem->calloc(1, sizeof(*ref));
ref->label = reflabel;
ref->hash = refhash(ref->label);
- ref->url = cmark_clean_url(url);
- ref->title = cmark_clean_title(title);
+ ref->url = cmark_clean_url(map->mem, url);
+ ref->title = cmark_clean_title(map->mem, title);
ref->next = NULL;
add_reference(map, ref);
@@ -100,7 +101,7 @@ cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
if (map == NULL)
return NULL;
- norm = normalize_reference(label);
+ norm = normalize_reference(map->mem, label);
if (norm == NULL)
return NULL;
@@ -129,7 +130,7 @@ void cmark_reference_map_free(cmark_reference_map *map) {
while (ref) {
next = ref->next;
- reference_free(ref);
+ reference_free(map, ref);
ref = next;
}
}
@@ -137,6 +138,8 @@ void cmark_reference_map_free(cmark_reference_map *map) {
free(map);
}
-cmark_reference_map *cmark_reference_map_new(void) {
- return (cmark_reference_map *)cmark_calloc(1, sizeof(cmark_reference_map));
+cmark_reference_map *cmark_reference_map_new(cmark_mem *mem) {
+ cmark_reference_map *map = mem->calloc(1, sizeof(cmark_reference_map));
+ map->mem = mem;
+ return map;
}
diff --git a/src/references.h b/src/references.h
index 310ff9f..f075bbb 100644
--- a/src/references.h
+++ b/src/references.h
@@ -1,6 +1,7 @@
#ifndef CMARK_REFERENCES_H
#define CMARK_REFERENCES_H
+#include "memory.h"
#include "chunk.h"
#ifdef __cplusplus
@@ -20,12 +21,13 @@ struct cmark_reference {
typedef struct cmark_reference cmark_reference;
struct cmark_reference_map {
+ cmark_mem *mem;
cmark_reference *table[REFMAP_SIZE];
};
typedef struct cmark_reference_map cmark_reference_map;
-cmark_reference_map *cmark_reference_map_new(void);
+cmark_reference_map *cmark_reference_map_new(cmark_mem *mem);
void cmark_reference_map_free(cmark_reference_map *map);
cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
cmark_chunk *label);
diff --git a/src/render.c b/src/render.c
index b1ed2e4..0f88007 100644
--- a/src/render.c
+++ b/src/render.c
@@ -4,6 +4,7 @@
#include "cmark.h"
#include "utf8.h"
#include "render.h"
+#include "node.h"
static CMARK_INLINE void S_cr(cmark_renderer *renderer) {
if (renderer->need_cr < 1) {
@@ -108,7 +109,7 @@ static void S_out(cmark_renderer *renderer, const char *source, bool wrap,
!renderer->begin_line && renderer->last_breakable > 0) {
// copy from last_breakable to remainder
- cmark_chunk_set_cstr(&remainder, (char *)renderer->buffer->ptr +
+ cmark_chunk_set_cstr(renderer->mem, &remainder, (char *)renderer->buffer->ptr +
renderer->last_breakable + 1);
// truncate at last_breakable
cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
@@ -118,7 +119,7 @@ static void S_out(cmark_renderer *renderer, const char *source, bool wrap,
renderer->prefix->size);
cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len);
renderer->column = renderer->prefix->size + remainder.len;
- cmark_chunk_free(&remainder);
+ cmark_chunk_free(renderer->mem, &remainder);
renderer->last_breakable = 0;
renderer->begin_line = false;
renderer->begin_content = false;
@@ -146,14 +147,15 @@ char *cmark_render(cmark_node *root, int options, int width,
int (*render_node)(cmark_renderer *renderer,
cmark_node *node,
cmark_event_type ev_type, int options)) {
- cmark_strbuf pref = GH_BUF_INIT;
- cmark_strbuf buf = GH_BUF_INIT;
+ cmark_mem *mem = cmark_node_mem(root);
+ cmark_strbuf pref = CMARK_BUF_INIT(mem);
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
cmark_node *cur;
cmark_event_type ev_type;
char *result;
cmark_iter *iter = cmark_iter_new(root);
- cmark_renderer renderer = {&buf, &pref, 0, width, 0,
+ cmark_renderer renderer = {mem, &buf, &pref, 0, width, 0,
0, true, true, false, false,
outc, S_cr, S_blankline, S_out};
diff --git a/src/render.h b/src/render.h
index c3acf6b..35eb0a6 100644
--- a/src/render.h
+++ b/src/render.h
@@ -8,10 +8,12 @@ extern "C" {
#include <stdlib.h>
#include "buffer.h"
#include "chunk.h"
+#include "memory.h"
typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping;
struct cmark_renderer {
+ cmark_mem *mem;
cmark_strbuf *buffer;
cmark_strbuf *prefix;
int column;
diff --git a/src/xml.c b/src/xml.c
index 12bd629..4898cd2 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -149,7 +149,7 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
char *cmark_render_xml(cmark_node *root, int options) {
char *result;
- cmark_strbuf xml = GH_BUF_INIT;
+ cmark_strbuf xml = CMARK_BUF_INIT(cmark_node_mem(root));
cmark_event_type ev_type;
cmark_node *cur;
struct render_state state = {&xml, 0};