From 25429c96f6554ffac415f9d865934b1183f3398e Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 27 May 2016 16:55:16 +0200 Subject: cmark: Implement support for custom allocators --- src/inlines.c | 158 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 77 deletions(-) (limited to 'src/inlines.c') 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) -- cgit v1.2.3