diff options
-rw-r--r-- | src/inlines.c | 180 | ||||
-rw-r--r-- | src/node.c | 5 |
2 files changed, 90 insertions, 95 deletions
diff --git a/src/inlines.c b/src/inlines.c index 2d26e81..0dcfd72 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -20,8 +20,8 @@ #define make_raw_html(s) make_literal(CMARK_NODE_INLINE_HTML, s) #define make_linebreak() make_simple(CMARK_NODE_LINEBREAK) #define make_softbreak() make_simple(CMARK_NODE_SOFTBREAK) -#define make_emph(contents) make_inlines(CMARK_NODE_EMPH, contents) -#define make_strong(contents) make_inlines(CMARK_NODE_STRONG, contents) +#define make_emph() make_simple(CMARK_NODE_EMPH) +#define make_strong() make_simple(CMARK_NODE_STRONG) typedef struct DelimiterStack { struct DelimiterStack *previous; @@ -41,6 +41,9 @@ typedef struct Subject { delimiter_stack *delimiters; } subject; +static delimiter_stack* +S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer); + static int parse_inline(subject* subj, cmark_node * parent); static void subject_from_buf(subject *e, strbuf *buffer, @@ -83,24 +86,6 @@ static inline cmark_node* make_autolink(cmark_node* label, cmark_chunk url, int return make_link(label, cmark_clean_autolink(&url, is_email), NULL); } -// Setting 'last_child' and the parent of 'contents' is up to the caller. -static inline cmark_node* make_inlines(cmark_node_type t, cmark_node* contents) -{ - cmark_node * e = (cmark_node *)calloc(1, sizeof(*e)); - if(e != NULL) { - e->type = t; - e->first_child = contents; - e->next = NULL; - e->prev = NULL; - e->parent = NULL; - // These fields aren't used for inlines: - e->start_line = 0; - e->start_column = 0; - e->end_line = 0; - } - return e; -} - // Create an inline with a literal string value. static inline cmark_node* make_literal(cmark_node_type t, cmark_chunk s) { @@ -361,9 +346,7 @@ static cmark_node* handle_strong_emph(subject* subj, unsigned char c) static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) { delimiter_stack *closer = subj->delimiters; - delimiter_stack *opener, *tempstack, *nextstack; - int use_delims; - cmark_node *inl, *tmp, *emph; + delimiter_stack *opener; // move back to first relevant delim. while (closer != NULL && closer->previous != stack_bottom) { @@ -384,78 +367,7 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) opener = opener->previous; } if (opener != NULL && opener != stack_bottom) { - // calculate the actual number of delimeters used from this closer - if (closer->delim_count < 3 || opener->delim_count < 3) { - use_delims = closer->delim_count <= opener->delim_count ? - closer->delim_count : opener->delim_count; - } else { // closer and opener both have >= 3 delims - use_delims = closer->delim_count % 2 == 0 ? 2 : 1; - } - - inl = opener->first_inline; - - // remove used delimiters from stack elements and associated inlines. - opener->delim_count -= use_delims; - closer->delim_count -= use_delims; - inl->as.literal.len = opener->delim_count; - closer->first_inline->as.literal.len = closer->delim_count; - - // free delimiters between opener and closer - tempstack = closer->previous; - while (tempstack != NULL && tempstack != opener) { - nextstack = tempstack->previous; - remove_delimiter(subj, tempstack); - tempstack = nextstack; - } - - // create new emph or strong, and splice it in to our inlines - // between the opener and closer - emph = use_delims == 1 ? make_emph(inl->next) : make_strong(inl->next); - emph->next = closer->first_inline; - emph->prev = inl; - emph->parent = inl->parent; - inl->next = emph; - - // if opener has 0 delims, remove it and its associated inline - if (opener->delim_count == 0) { - // replace empty opener inline with emph - chunk_free(&(inl->as.literal)); - inl->type = emph->type; - inl->next = emph->next; - inl->first_child = emph->first_child; - free(emph); - emph = inl; - // remove opener from stack - remove_delimiter(subj, opener); - } - - // fix tree structure - tmp = emph->first_child; - while (tmp->next != NULL && tmp->next != closer->first_inline) { - tmp->parent = emph; - tmp = tmp->next; - } - tmp->parent = emph; - if (tmp->next) { - tmp->next->prev = emph; - } - tmp->next = NULL; - emph->last_child = tmp; - - // if closer has 0 delims, remove it and its associated inline - if (closer->delim_count == 0) { - // remove empty closer inline - tmp = closer->first_inline; - emph->next = tmp->next; - if (tmp->next) { - tmp->next->prev = emph; - } - cmark_node_free(tmp); - // remove closer from stack - tempstack = closer->next; - remove_delimiter(subj, closer); - closer = tempstack; - } + closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } @@ -469,6 +381,84 @@ static void process_emphasis(subject *subj, delimiter_stack *stack_bottom) } } +static delimiter_stack* +S_insert_emph(subject *subj, delimiter_stack *opener, delimiter_stack *closer) +{ + delimiter_stack *tempstack, *nextstack; + int use_delims; + cmark_node *opener_inl = opener->first_inline; + cmark_node *closer_inl = closer->first_inline; + cmark_node *tmp, *emph, *first_child, *last_child; + + // calculate the actual number of delimeters used from this closer + if (closer->delim_count < 3 || opener->delim_count < 3) { + use_delims = closer->delim_count <= opener->delim_count ? + closer->delim_count : opener->delim_count; + } else { // closer and opener both have >= 3 delims + use_delims = closer->delim_count % 2 == 0 ? 2 : 1; + } + + // remove used delimiters from stack elements and associated inlines. + opener->delim_count -= use_delims; + closer->delim_count -= use_delims; + opener_inl->as.literal.len = opener->delim_count; + closer_inl->as.literal.len = closer->delim_count; + + // free delimiters between opener and closer + tempstack = closer->previous; + while (tempstack != NULL && tempstack != opener) { + nextstack = tempstack->previous; + remove_delimiter(subj, tempstack); + tempstack = nextstack; + } + + first_child = opener_inl->next; + last_child = closer_inl->prev; + + // if opener has 0 delims, remove it and its associated inline + if (opener->delim_count == 0) { + // replace empty opener inline with emph + chunk_free(&(opener_inl->as.literal)); + emph = opener_inl; + emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG; + // remove opener from stack + remove_delimiter(subj, opener); + } + else { + // 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->parent = opener_inl->parent; + emph->prev = opener_inl; + opener_inl->next = emph; + } + + // push children below emph + emph->next = closer_inl; + closer_inl->prev = emph; + emph->first_child = first_child; + emph->last_child = last_child; + + // fix children pointers + first_child->prev = NULL; + last_child->next = NULL; + for (tmp = first_child; tmp != NULL; tmp = tmp->next) { + tmp->parent = emph; + } + + // if closer has 0 delims, remove it and its associated inline + if (closer->delim_count == 0) { + // remove empty closer inline + cmark_node_free(closer_inl); + // remove closer from stack + tempstack = closer->next; + remove_delimiter(subj, closer); + closer = tempstack; + } + + return closer; +} + // Parse backslash-escape or just a backslash, returning an inline. static cmark_node* handle_backslash(subject *subj) { @@ -607,6 +607,11 @@ cmark_node_check(cmark_node *node, FILE *out) cur = node; while (true) { if (cur->first_child) { + if (cur->first_child->prev != NULL) { + S_print_error(out, cur->first_child, "prev"); + cur->first_child->prev = NULL; + ++errors; + } if (cur->first_child->parent != cur) { S_print_error(out, cur->first_child, "parent"); cur->first_child->parent = cur; |