From c589d7345a311b54d5a642759820a254e129e4ff Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 13 Nov 2014 21:33:40 -0800 Subject: Moved ast-manipulating functions from inlines to ast. --- src/ast.c | 120 +++++++++++++++++++++++++++++++++++++++++++++-------- src/ast.h | 37 ++++++++++++++++- src/inlines.c | 130 +++++++++------------------------------------------------- src/inlines.h | 6 +-- 4 files changed, 158 insertions(+), 135 deletions(-) diff --git a/src/ast.c b/src/ast.c index 2a9ca8f..6e3f0ee 100644 --- a/src/ast.c +++ b/src/ast.c @@ -3,17 +3,18 @@ #include "buffer.h" #include "ast.h" #include "references.h" +#include "html/houdini.h" // Free a node_block list and any children. -void cmark_free_blocks(node_block *e) +void cmark_free_blocks(cmark_node_block *e) { - node_block * next; + cmark_node_block * next; while (e != NULL) { - free_inlines(e->inline_content); + cmark_free_inlines(e->inline_content); strbuf_free(&e->string_content); - if (e->tag == BLOCK_FENCED_CODE) { + if (e->tag == CMARK_BLOCK_FENCED_CODE) { strbuf_free(&e->as.code.info); - } else if (e->tag == BLOCK_DOCUMENT) { + } else if (e->tag == CMARK_BLOCK_DOCUMENT) { reference_map_free(e->as.document.refmap); } if (e->last_child) { @@ -28,8 +29,8 @@ void cmark_free_blocks(node_block *e) } // Utility function used by free_inlines -static void splice_into_list(node_inl* e, node_inl* children) { - node_inl * tmp; +static void splice_into_list(cmark_node_inl* e, node_inl* children) { + cmark_node_inl * tmp; if (children) { tmp = children; // Find last child @@ -45,28 +46,28 @@ static void splice_into_list(node_inl* e, node_inl* children) { // Free an inline list. Avoid recursion to prevent stack overflows // on deeply nested structures. -extern void free_inlines(node_inl* e) +void cmark_free_inlines(cmark_node_inl* e) { node_inl * next; while (e != NULL) { switch (e->tag){ - case INL_STRING: - case INL_RAW_HTML: - case INL_CODE: - chunk_free(&e->content.literal); + case CMARK_INL_STRING: + case CMARK_INL_RAW_HTML: + case CMARK_INL_CODE: + cmark_chunk_free(&e->content.literal); break; - case INL_LINEBREAK: - case INL_SOFTBREAK: + case CMARK_INL_LINEBREAK: + case CMARK_INL_SOFTBREAK: break; - case INL_LINK: - case INL_IMAGE: + case CMARK_INL_LINK: + case CMARK_INL_IMAGE: free(e->content.linkable.url); free(e->content.linkable.title); splice_into_list(e, e->content.linkable.label); break; - case INL_EMPH: - case INL_STRONG: + case CMARK_INL_EMPH: + case CMARK_INL_STRONG: splice_into_list(e, e->content.inlines); break; default: @@ -79,3 +80,86 @@ extern void free_inlines(node_inl* e) e = next; } } + +inline cmark_node_inl *cmark_make_link(cmark_node_inl *label, unsigned char *url, unsigned char *title) +{ + cmark_node_inl* e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = CMARK_INL_LINK; + e->content.linkable.label = label; + e->content.linkable.url = url; + e->content.linkable.title = title; + e->next = NULL; + } + return e; +} + +unsigned char *clean_autolink(chunk *url, int is_email) +{ + strbuf buf = GH_BUF_INIT; + + chunk_trim(url); + + if (url->len == 0) + return NULL; + + if (is_email) + strbuf_puts(&buf, "mailto:"); + + houdini_unescape_html_f(&buf, url->data, url->len); + return strbuf_detach(&buf); +} + +cmark_node_inl* cmark_make_autolink(cmark_node_inl* label, chunk url, int is_email) +{ + return cmark_make_link(label, clean_autolink(&url, is_email), NULL); +} + +inline cmark_node_inl* cmark_make_inlines(int t, cmark_node_inl* contents) +{ + cmark_node_inl * e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->content.inlines = contents; + e->next = NULL; + } + return e; +} + +// Create an inline with a literal string value. +inline cmark_node_inl* cmark_make_literal(int t, cmark_chunk s) +{ + cmark_node_inl * e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->content.literal = s; + e->next = NULL; + } + return e; +} + +// Create an inline with no value. +inline cmark_node_inl* cmark_make_simple(int t) +{ + cmark_node_inl* e = calloc(1, sizeof(*e)); + if(e != NULL) { + e->tag = t; + e->next = NULL; + } + return e; +} + +// Append inline list b to the end of inline list a. +// Return pointer to head of new list. +inline cmark_node_inl* cmark_append_inlines(cmark_node_inl* a, cmark_node_inl* b) +{ + if (a == NULL) { // NULL acts like an empty list + return b; + } + cmark_node_inl* cur = a; + while (cur->next) { + cur = cur->next; + } + cur->next = b; + return a; +} diff --git a/src/ast.h b/src/ast.h index 5c3d298..952be8f 100644 --- a/src/ast.h +++ b/src/ast.h @@ -102,7 +102,27 @@ struct cmark_node_block { typedef struct cmark_node_block cmark_node_block; void cmark_free_blocks(cmark_node_block *e); -void cmark_free_inlines(cmark_node_inl *e); +void cmark_free_inlines(cmark_node_inl* e); +void cmark_free_simple(cmark_node_inl *e); +cmark_node_inl* cmark_append_inlines(cmark_node_inl* a, cmark_node_inl* b); + +cmark_node_inl *cmark_make_link(cmark_node_inl *label, unsigned char *url, unsigned char *title); +cmark_node_inl* cmark_make_autolink(cmark_node_inl* label, cmark_chunk url, int is_email); + +cmark_node_inl* cmark_make_inlines(int t, cmark_node_inl* contents); +cmark_node_inl* cmark_make_literal(int t, cmark_chunk s); +cmark_node_inl* cmark_make_simple(int t); + +// Macros for creating various kinds of simple. +#define cmark_make_str(s) cmark_make_literal(INL_STRING, s) +#define cmark_make_code(s) cmark_make_literal(INL_CODE, s) +#define cmark_make_raw_html(s) cmark_make_literal(INL_RAW_HTML, s) +#define cmark_make_linebreak() cmark_make_simple(INL_LINEBREAK) +#define cmark_make_softbreak() cmark_make_simple(INL_SOFTBREAK) +#define cmark_make_emph(contents) cmark_make_inlines(INL_EMPH, contents) +#define cmark_make_strong(contents) cmark_make_inlines(INL_STRONG, contents) + + #ifndef CMARK_NO_SHORT_NAMES #define node_inl cmark_node_inl @@ -130,8 +150,21 @@ void cmark_free_inlines(cmark_node_inl *e); #define BLOCK_SETEXT_HEADER CMARK_BLOCK_SETEXT_HEADER #define BLOCK_HRULE CMARK_BLOCK_HRULE #define BLOCK_REFERENCE_DEF CMARK_BLOCK_REFERENCE_DEF - #define free_inlines cmark_free_inlines + #define free_simple cmark_free_simple #define free_blocks cmark_free_blocks + #define append_simple cmark_append_simple + #define make_link cmark_make_link + #define make_autolink cmark_make_autolink + #define make_str cmark_make_str + #define make_code cmark_make_code + #define make_raw_html cmark_make_raw_html + #define make_linebreak cmark_make_linebreak + #define make_softbreak cmark_make_softbreak + #define make_emph cmark_make_emph + #define make_strong cmark_make_strong + #define make_simple cmark_make_simple + #define make_simple cmark_make_simple + #define make_simple cmark_make_simple #endif #endif diff --git a/src/inlines.c b/src/inlines.c index 5b7b8ea..78ebaf4 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -8,6 +8,7 @@ #include "html/houdini.h" #include "utf8.h" #include "scanners.h" +#include "ast.h" #include "inlines.h" @@ -50,82 +51,6 @@ static unsigned char *bufdup(const unsigned char *buf) return new; } -static inline node_inl *make_link_(node_inl *label, unsigned char *url, unsigned char *title) -{ - node_inl* e = calloc(1, sizeof(*e)); - if(e != NULL) { - e->tag = INL_LINK; - e->content.linkable.label = label; - e->content.linkable.url = url; - e->content.linkable.title = title; - e->next = NULL; - } - return e; -} - -static inline node_inl* make_autolink(node_inl* label, chunk url, int is_email) -{ - return make_link_(label, clean_autolink(&url, is_email), NULL); -} - -static inline node_inl* make_inlines(int t, node_inl* contents) -{ - node_inl * e = calloc(1, sizeof(*e)); - if(e != NULL) { - e->tag = t; - e->content.inlines = contents; - e->next = NULL; - } - return e; -} - -// Create an inline with a literal string value. -static inline node_inl* make_literal(int t, chunk s) -{ - node_inl * e = calloc(1, sizeof(*e)); - if(e != NULL) { - e->tag = t; - e->content.literal = s; - e->next = NULL; - } - return e; -} - -// Create an inline with no value. -static inline node_inl* make_simple(int t) -{ - node_inl* e = calloc(1, sizeof(*e)); - if(e != NULL) { - e->tag = t; - e->next = NULL; - } - return e; -} - -// Macros for creating various kinds of inlines. -#define make_str(s) make_literal(INL_STRING, s) -#define make_code(s) make_literal(INL_CODE, s) -#define make_raw_html(s) make_literal(INL_RAW_HTML, s) -#define make_linebreak() make_simple(INL_LINEBREAK) -#define make_softbreak() make_simple(INL_SOFTBREAK) -#define make_emph(contents) make_inlines(INL_EMPH, contents) -#define make_strong(contents) make_inlines(INL_STRONG, contents) - -// Append inline list b to the end of inline list a. -// Return pointer to head of new list. -static inline node_inl* append_inlines(node_inl* a, node_inl* b) -{ - if (a == NULL) { // NULL acts like an empty list - return b; - } - node_inl* cur = a; - while (cur->next) { - cur = cur->next; - } - cur->next = b; - return a; -} - static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap) { e->input.data = buffer->ptr; @@ -402,7 +327,7 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) tmp = closer->first_inline; emph->next = tmp->next; tmp->next = NULL; - free_inlines(tmp); + cmark_free_inlines(tmp); // remove closer from stack tempstack = closer->next; remove_delimiter(subj, closer); @@ -492,45 +417,28 @@ unsigned char *clean_url(chunk *url) return strbuf_detach(&buf); } -unsigned char *clean_autolink(chunk *url, int is_email) -{ - strbuf buf = GH_BUF_INIT; - - chunk_trim(url); - - if (url->len == 0) - return NULL; - - if (is_email) - strbuf_puts(&buf, "mailto:"); - - houdini_unescape_html_f(&buf, url->data, url->len); - return strbuf_detach(&buf); -} - -// Clean a title: remove surrounding quotes and remove \ that escape punctuation. unsigned char *clean_title(chunk *title) { - strbuf buf = GH_BUF_INIT; - unsigned char first, last; + strbuf buf = GH_BUF_INIT; + unsigned char first, last; - if (title->len == 0) - return NULL; + if (title->len == 0) + return NULL; - first = title->data[0]; - last = title->data[title->len - 1]; + first = title->data[0]; + last = title->data[title->len - 1]; - // remove surrounding quotes if any: - if ((first == '\'' && last == '\'') || - (first == '(' && last == ')') || - (first == '"' && last == '"')) { - houdini_unescape_html_f(&buf, title->data + 1, title->len - 2); - } else { - houdini_unescape_html_f(&buf, title->data, title->len); - } + // remove surrounding quotes if any: + if ((first == '\'' && last == '\'') || + (first == '(' && last == ')') || + (first == '"' && last == '"')) { + houdini_unescape_html_f(&buf, title->data + 1, title->len - 2); + } else { + houdini_unescape_html_f(&buf, title->data, title->len); + } - strbuf_unescape(&buf); - return strbuf_detach(&buf); + strbuf_unescape(&buf); + return strbuf_detach(&buf); } // Parse an autolink or HTML tag. @@ -880,7 +788,7 @@ static int parse_inline(subject* subj, node_inl ** last) if (*last == NULL) { *last = new; } else if (new) { - append_inlines(*last, new); + cmark_append_inlines(*last, new); *last = new; } diff --git a/src/inlines.h b/src/inlines.h index fa61c8a..57daea2 100644 --- a/src/inlines.h +++ b/src/inlines.h @@ -2,7 +2,6 @@ #define _INLINES_H_ unsigned char *cmark_clean_url(cmark_chunk *url); -unsigned char *cmark_clean_autolink(cmark_chunk *url, int is_email); unsigned char *cmark_clean_title(cmark_chunk *title); cmark_node_inl* cmark_parse_inlines(cmark_strbuf *input, cmark_reference_map *refmap); @@ -10,11 +9,10 @@ cmark_node_inl* cmark_parse_inlines(cmark_strbuf *input, cmark_reference_map *re int cmark_parse_reference_inline(cmark_strbuf *input, cmark_reference_map *refmap); #ifndef CMARK_NO_SHORT_NAMES - #define clean_url cmark_clean_url - #define clean_autolink cmark_clean_autolink - #define clean_title cmark_clean_title #define parse_inlines cmark_parse_inlines #define parse_reference_inline cmark_parse_reference_inline + #define clean_url cmark_clean_url + #define clean_title cmark_clean_title #endif #endif -- cgit v1.2.3