From 8837f199608ac2e321f75653736747b1e692072f Mon Sep 17 00:00:00 2001 From: Knagis Date: Wed, 8 Oct 2014 11:39:47 +0300 Subject: Implemented stack-based algorithm for matching emphasis --- src/inlines.c | 218 ++++++++++++++++++++++++---------------------------------- 1 file changed, 88 insertions(+), 130 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 71d75e9..589b3c3 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -10,11 +10,19 @@ #include "scanners.h" #include "inlines.h" +typedef struct InlineStack { + inline_stack *previous; + node_inl *first_inline; + int delim_count; + char delim_char; +} inline_stack; + typedef struct Subject { chunk input; int pos; int label_nestlevel; reference_map *refmap; + inline_stack *last_emphasis; } subject; static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); @@ -158,6 +166,7 @@ static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap) e->pos = 0; e->label_nestlevel = 0; e->refmap = refmap; + e->last_emphasis = NULL; chunk_rtrim(&e->input); } @@ -170,6 +179,7 @@ static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap) e->pos = 0; e->label_nestlevel = 0; e->refmap = refmap; + e->last_emphasis = NULL; chunk_rtrim(&e->input); } @@ -262,12 +272,11 @@ static node_inl* handle_backticks(subject *subj) } // Scan ***, **, or * and return number scanned, or 0. -// Don't advance position. +// Advances position. static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close) { int numdelims = 0; char char_before, char_after; - int startpos = subj->pos; char_before = subj->pos == 0 ? '\n' : peek_at(subj, subj->pos - 1); while (peek_char(subj) == c) { @@ -281,135 +290,93 @@ static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close) *can_open = *can_open && !isalnum(char_before); *can_close = *can_close && !isalnum(char_after); } - subj->pos = startpos; return numdelims; } // Parse strong/emph or a fallback. // Assumes the subject has '_' or '*' at the current position. -static node_inl* handle_strong_emph(subject* subj, char c) +static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) { bool can_open, can_close; - node_inl * result = NULL; - node_inl ** last = malloc(sizeof(node_inl *)); - node_inl * new; - node_inl * il; - node_inl * first_head = NULL; - node_inl * first_close = NULL; - int first_close_delims = 0; int numdelims; + int useDelims; + inline_stack * istack; + node_inl * inl; + node_inl * emph; + node_inl * inl_text; + + numdelims = scan_delims(subj, c, &can_open, &can_close); - *last = NULL; + if (can_close) + { + // walk the stack and find a matching opener, if there is one + istack = subj->last_emphasis; + while (true) + { + if (istack == NULL) + goto cannotClose; - numdelims = scan_delims(subj, c, &can_open, &can_close); - subj->pos += numdelims; - - new = make_str(chunk_dup(&subj->input, subj->pos - numdelims, numdelims)); - *last = new; - first_head = new; - result = new; - - if (!can_open || numdelims == 0) { - goto done; - } - - switch (numdelims) { - case 1: - while (true) { - numdelims = scan_delims(subj, c, &can_open, &can_close); - if (numdelims >= 1 && can_close) { - subj->pos += 1; - first_head->tag = INL_EMPH; - chunk_free(&first_head->content.literal); - first_head->content.inlines = first_head->next; - first_head->next = NULL; - goto done; - } else { - if (!parse_inline(subj, last)) { - goto done; - } - } - } - break; - case 2: - while (true) { - numdelims = scan_delims(subj, c, &can_open, &can_close); - if (numdelims >= 2 && can_close) { - subj->pos += 2; - first_head->tag = INL_STRONG; - chunk_free(&first_head->content.literal); - first_head->content.inlines = first_head->next; - first_head->next = NULL; - goto done; - } else { - if (!parse_inline(subj, last)) { - goto done; - } - } - } - break; - case 3: - while (true) { - numdelims = scan_delims(subj, c, &can_open, &can_close); - if (can_close && numdelims >= 1 && numdelims <= 3 && - numdelims != first_close_delims) { - new = make_str(chunk_dup(&subj->input, subj->pos, numdelims)); - append_inlines(*last, new); - *last = new; - if (first_close_delims == 1 && numdelims > 2) { - numdelims = 2; - } else if (first_close_delims == 2) { - numdelims = 1; - } else if (numdelims == 3) { - // If we opened with ***, we interpret it as ** followed by * - // giving us - numdelims = 1; - } - subj->pos += numdelims; - if (first_close) { - first_head->tag = first_close_delims == 1 ? INL_STRONG : INL_EMPH; - chunk_free(&first_head->content.literal); - first_head->content.inlines = - make_inlines(first_close_delims == 1 ? INL_EMPH : INL_STRONG, - first_head->next); - - il = first_head->next; - while (il->next && il->next != first_close) { - il = il->next; - } - il->next = NULL; - - first_head->content.inlines->next = first_close->next; - - il = first_head->content.inlines; - while (il->next && il->next != *last) { - il = il->next; - } - il->next = NULL; - free_inlines(*last); - - first_close->next = NULL; - free_inlines(first_close); - first_head->next = NULL; - goto done; - } else { - first_close = *last; - first_close_delims = numdelims; - } - } else { - if (!parse_inline(subj, last)) { - goto done; - } - } - } - break; - default: - goto done; + if (istack->delim_char == c) + break; + + istack = istack->previous; + } + + // calculate the actual number of delimeters used from this closer + useDelims = istack->delim_count; + if (useDelims == 3) useDelims = numdelims == 3 ? 1 : numdelims; + else if (useDelims > numdelims) useDelims = 1; + + if (istack->delim_count == useDelims) + { + // the opener is completely used up - remove the stack entry and reuse the inline element + inl = istack->first_inline; + inl->tag = useDelims == 1 ? INL_EMPH : INL_STRONG; + chunk_free(&inl->content.literal); + inl->content.inlines = inl->next; + inl->next = NULL; + + subj->last_emphasis = istack->previous; + istack->previous = NULL; + *last = inl; + free(istack); + } + else + { + // the opener will only partially be used - stack entry remains (truncated) and a new inline is added. + inl = istack->first_inline; + istack->delim_count -= useDelims; + inl->content.literal.len = istack->delim_count; + + emph = useDelims == 1 ? make_emph(inl->next) : make_strong(inl->next); + inl->next = emph; + *last = emph; + } + + // if the closer was not fully used, move back a char or two and try again. + if (useDelims < numdelims) + { + subj->pos = subj->pos - numdelims + useDelims; + return handle_strong_emph(subj, c, last); + } + + return make_str(chunk_literal("")); } -done: - free(last); - return result; +cannotClose: + inl_text = make_str(chunk_dup(&subj->input, subj->pos - numdelims, numdelims)); + + if (can_open) + { + istack = (inline_stack*)malloc(sizeof(inline_stack)); + istack->delim_count = numdelims; + istack->delim_char = c; + istack->first_inline = inl_text; + istack->previous = subj->last_emphasis; + subj->last_emphasis = istack; + } + + return inl_text; } // Parse backslash-escape or just a backslash, returning an inline. @@ -828,19 +795,10 @@ static int parse_inline(subject* subj, node_inl ** last) new = handle_pointy_brace(subj); break; case '_': - if (subj->pos > 0) { - unsigned char prev = peek_at(subj, subj->pos - 1); - if (isalnum(prev) || prev == '_') { - new = make_str(chunk_literal("_")); - advance(subj); - break; - } - } - - new = handle_strong_emph(subj, '_'); + new = handle_strong_emph(subj, '_', last); break; case '*': - new = handle_strong_emph(subj, '*'); + new = handle_strong_emph(subj, '*', last); break; case '[': new = handle_left_bracket(subj); -- cgit v1.2.3 From bc78ad0a182bd322552fd081e30e552c18a87455 Mon Sep 17 00:00:00 2001 From: Knagis <> Date: Thu, 9 Oct 2014 07:29:25 -0400 Subject: Modified inline parsing to keep track of two pointers - the head of the list and the tail. --- src/inlines.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 589b3c3..56e4eba 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -11,7 +11,7 @@ #include "inlines.h" typedef struct InlineStack { - inline_stack *previous; + struct InlineStack *previous; node_inl *first_inline; int delim_count; char delim_char; @@ -27,7 +27,7 @@ typedef struct Subject { static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); static node_inl *parse_inlines_while(subject* subj, int (*f)(subject*)); -static int parse_inline(subject* subj, node_inl ** last); +static int parse_inline(subject* subj, node_inl ** first, node_inl ** last); static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap); static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap); @@ -720,8 +720,9 @@ inline static int not_eof(subject* subj) extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) { node_inl* result = NULL; - node_inl** last = &result; - while ((*f)(subj) && parse_inline(subj, last)) { + node_inl** first = &result; + node_inl* last = NULL; + while ((*f)(subj) && parse_inline(subj, first, &last)) { } return result; } @@ -768,7 +769,7 @@ static int subject_find_special_char(subject *subj) // Parse an inline, advancing subject, and add it to last element. // Adjust tail to point to new last element of list. // Return 0 if no inline can be parsed, 1 otherwise. -static int parse_inline(subject* subj, node_inl ** last) +static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) { node_inl* new = NULL; chunk contents; @@ -828,11 +829,18 @@ static int parse_inline(subject* subj, node_inl ** last) new = make_str(contents); } - if (*last == NULL) { + if (*first == NULL) { + *first = new; *last = new; } else { - append_inlines(*last, new); + append_inlines(*first, new); } + + while (new->next) { + new = new->next; + } + *last = new; + return 1; } -- cgit v1.2.3 From 7d7011b918e2783c75d52237887f09bcb1adb62d Mon Sep 17 00:00:00 2001 From: Knagis Date: Thu, 9 Oct 2014 14:34:36 +0300 Subject: Revert "Modified inline parsing to keep track of two pointers - the head of the list and the tail." This reverts commit bc78ad0a182bd322552fd081e30e552c18a87455. --- src/inlines.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 56e4eba..589b3c3 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -11,7 +11,7 @@ #include "inlines.h" typedef struct InlineStack { - struct InlineStack *previous; + inline_stack *previous; node_inl *first_inline; int delim_count; char delim_char; @@ -27,7 +27,7 @@ typedef struct Subject { static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); static node_inl *parse_inlines_while(subject* subj, int (*f)(subject*)); -static int parse_inline(subject* subj, node_inl ** first, node_inl ** last); +static int parse_inline(subject* subj, node_inl ** last); static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap); static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap); @@ -720,9 +720,8 @@ inline static int not_eof(subject* subj) extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) { node_inl* result = NULL; - node_inl** first = &result; - node_inl* last = NULL; - while ((*f)(subj) && parse_inline(subj, first, &last)) { + node_inl** last = &result; + while ((*f)(subj) && parse_inline(subj, last)) { } return result; } @@ -769,7 +768,7 @@ static int subject_find_special_char(subject *subj) // Parse an inline, advancing subject, and add it to last element. // Adjust tail to point to new last element of list. // Return 0 if no inline can be parsed, 1 otherwise. -static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) +static int parse_inline(subject* subj, node_inl ** last) { node_inl* new = NULL; chunk contents; @@ -829,18 +828,11 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) new = make_str(contents); } - if (*first == NULL) { - *first = new; + if (*last == NULL) { *last = new; } else { - append_inlines(*first, new); + append_inlines(*last, new); } - - while (new->next) { - new = new->next; - } - *last = new; - return 1; } -- cgit v1.2.3 From de80806ef51ce89667ebc3f3d1f58bf55d2b370e Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2014 07:36:37 -0400 Subject: Modified inline parsing to keep track of two pointers - the head of the list and the tail. --- src/inlines.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 589b3c3..56e4eba 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -11,7 +11,7 @@ #include "inlines.h" typedef struct InlineStack { - inline_stack *previous; + struct InlineStack *previous; node_inl *first_inline; int delim_count; char delim_char; @@ -27,7 +27,7 @@ typedef struct Subject { static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); static node_inl *parse_inlines_while(subject* subj, int (*f)(subject*)); -static int parse_inline(subject* subj, node_inl ** last); +static int parse_inline(subject* subj, node_inl ** first, node_inl ** last); static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap); static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap); @@ -720,8 +720,9 @@ inline static int not_eof(subject* subj) extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) { node_inl* result = NULL; - node_inl** last = &result; - while ((*f)(subj) && parse_inline(subj, last)) { + node_inl** first = &result; + node_inl* last = NULL; + while ((*f)(subj) && parse_inline(subj, first, &last)) { } return result; } @@ -768,7 +769,7 @@ static int subject_find_special_char(subject *subj) // Parse an inline, advancing subject, and add it to last element. // Adjust tail to point to new last element of list. // Return 0 if no inline can be parsed, 1 otherwise. -static int parse_inline(subject* subj, node_inl ** last) +static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) { node_inl* new = NULL; chunk contents; @@ -828,11 +829,18 @@ static int parse_inline(subject* subj, node_inl ** last) new = make_str(contents); } - if (*last == NULL) { + if (*first == NULL) { + *first = new; *last = new; } else { - append_inlines(*last, new); + append_inlines(*first, new); } + + while (new->next) { + new = new->next; + } + *last = new; + return 1; } -- cgit v1.2.3 From c667b141b84ff73f02202cf7debf37d60e9b3918 Mon Sep 17 00:00:00 2001 From: user Date: Thu, 9 Oct 2014 07:44:11 -0400 Subject: After inline parsing free any remaining InlineStack instances. --- src/inlines.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 56e4eba..e0c1441 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -724,6 +724,15 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) node_inl* last = NULL; while ((*f)(subj) && parse_inline(subj, first, &last)) { } + + inline_stack* istack = subj->last_emphasis; + inline_stack* temp; + while (istack != NULL) { + temp = istack->previous; + free(istack); + istack = temp; + } + return result; } -- cgit v1.2.3 From 93b1ac3408142fb08643de1d94a77384add2fd09 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 18 Oct 2014 21:02:21 -0700 Subject: Reindented c sources. --- src/inlines.c | 219 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 109 insertions(+), 110 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index e0c1441..1eb5056 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -116,26 +116,26 @@ extern void free_inlines(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); - break; - case INL_LINEBREAK: - case INL_SOFTBREAK: - break; - case INL_LINK: - case INL_IMAGE: - free(e->content.linkable.url); - free(e->content.linkable.title); - free_inlines(e->content.linkable.label); - break; - case INL_EMPH: - case INL_STRONG: - free_inlines(e->content.inlines); - break; - default: - break; + case INL_STRING: + case INL_RAW_HTML: + case INL_CODE: + chunk_free(&e->content.literal); + break; + case INL_LINEBREAK: + case INL_SOFTBREAK: + break; + case INL_LINK: + case INL_IMAGE: + free(e->content.linkable.url); + free(e->content.linkable.title); + free_inlines(e->content.linkable.label); + break; + case INL_EMPH: + case INL_STRONG: + free_inlines(e->content.inlines); + break; + default: + break; } next = e->next; free(e); @@ -405,9 +405,9 @@ static node_inl* handle_entity(subject* subj) advance(subj); len = houdini_unescape_ent(&ent, - subj->input.data + subj->pos, - subj->input.len - subj->pos - ); + subj->input.data + subj->pos, + subj->input.len - subj->pos + ); if (len == 0) return make_str(chunk_literal("&")); @@ -480,8 +480,8 @@ unsigned char *clean_title(chunk *title) // remove surrounding quotes if any: if ((first == '\'' && last == '\'') || - (first == '(' && last == ')') || - (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); @@ -509,7 +509,7 @@ static node_inl* handle_pointy_brace(subject* subj) return make_autolink( make_str_with_entities(&contents), contents, 0 - ); + ); } // next try to match an email autolink @@ -519,9 +519,9 @@ static node_inl* handle_pointy_brace(subject* subj) subj->pos += matchlen; return make_autolink( - make_str_with_entities(&contents), - contents, 1 - ); + make_str_with_entities(&contents), + contents, 1 + ); } // finally, try to match an html tag @@ -565,30 +565,30 @@ static int link_label(subject* subj, chunk *raw_label) char c; while ((c = peek_char(subj)) && (c != ']' || nestlevel > 0)) { switch (c) { - case '`': - tmp = handle_backticks(subj); - free_inlines(tmp); - break; - case '<': - tmp = handle_pointy_brace(subj); - free_inlines(tmp); - break; - case '[': // nested [] - nestlevel++; - advance(subj); - break; - case ']': // nested [] - nestlevel--; - advance(subj); - break; - case '\\': - advance(subj); - if (ispunct(peek_char(subj))) { - advance(subj); - } - break; - default: + case '`': + tmp = handle_backticks(subj); + free_inlines(tmp); + break; + case '<': + tmp = handle_pointy_brace(subj); + free_inlines(tmp); + break; + case '[': // nested [] + nestlevel++; + advance(subj); + break; + case ']': // nested [] + nestlevel--; + advance(subj); + break; + case '\\': + advance(subj); + if (ispunct(peek_char(subj))) { advance(subj); + } + break; + default: + advance(subj); } } if (c == ']') { @@ -624,8 +624,8 @@ static node_inl* handle_left_bracket(subject* subj) if (found_label) { if (peek_char(subj) == '(' && - ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && - ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) { + ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && + ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) { // try to parse an explicit link: starturl = subj->pos + 1 + sps; // after ( @@ -651,8 +651,8 @@ static node_inl* handle_left_bracket(subject* subj) subj->pos = endlabel; lab = parse_chunk_inlines(&rawlabel, subj->refmap); result = append_inlines(make_str(chunk_literal("[")), - append_inlines(lab, - make_str(chunk_literal("]")))); + append_inlines(lab, + make_str(chunk_literal("]")))); return result; } } else { @@ -681,7 +681,7 @@ static node_inl* handle_left_bracket(subject* subj) subj->pos = endlabel; lab = parse_chunk_inlines(&rawlabel, subj->refmap); result = append_inlines(make_str(chunk_literal("[")), - append_inlines(lab, make_str(chunk_literal("]")))); + append_inlines(lab, make_str(chunk_literal("]")))); } return result; } @@ -703,8 +703,8 @@ static node_inl* handle_newline(subject *subj) advance(subj); } if (nlpos > 1 && - peek_at(subj, nlpos - 1) == ' ' && - peek_at(subj, nlpos - 2) == ' ') { + peek_at(subj, nlpos - 1) == ' ' && + peek_at(subj, nlpos - 2) == ' ') { return make_linebreak(); } else { return make_softbreak(); @@ -789,67 +789,67 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) return 0; } switch(c){ - case '\n': - new = handle_newline(subj); - break; - case '`': - new = handle_backticks(subj); - break; - case '\\': - new = handle_backslash(subj); - break; - case '&': - new = handle_entity(subj); - break; - case '<': - new = handle_pointy_brace(subj); - break; - case '_': - new = handle_strong_emph(subj, '_', last); - break; - case '*': - new = handle_strong_emph(subj, '*', last); - break; - case '[': + case '\n': + new = handle_newline(subj); + break; + case '`': + new = handle_backticks(subj); + break; + case '\\': + new = handle_backslash(subj); + break; + case '&': + new = handle_entity(subj); + break; + case '<': + new = handle_pointy_brace(subj); + break; + case '_': + new = handle_strong_emph(subj, '_', last); + break; + case '*': + new = handle_strong_emph(subj, '*', last); + break; + case '[': + new = handle_left_bracket(subj); + break; + case '!': + advance(subj); + if (peek_char(subj) == '[') { new = handle_left_bracket(subj); - break; - case '!': - advance(subj); - if (peek_char(subj) == '[') { - new = handle_left_bracket(subj); - if (new != NULL && new->tag == INL_LINK) { - new->tag = INL_IMAGE; - } else { - new = append_inlines(make_str(chunk_literal("!")), new); - } + if (new != NULL && new->tag == INL_LINK) { + new->tag = INL_IMAGE; } else { - new = make_str(chunk_literal("!")); - } - break; - default: - endpos = subject_find_special_char(subj); - contents = chunk_dup(&subj->input, subj->pos, endpos - subj->pos); - subj->pos = endpos; - - // if we're at a newline, strip trailing spaces. - if (peek_char(subj) == '\n') { - chunk_rtrim(&contents); + new = append_inlines(make_str(chunk_literal("!")), new); } + } else { + new = make_str(chunk_literal("!")); + } + break; + default: + endpos = subject_find_special_char(subj); + contents = chunk_dup(&subj->input, subj->pos, endpos - subj->pos); + subj->pos = endpos; + + // if we're at a newline, strip trailing spaces. + if (peek_char(subj) == '\n') { + chunk_rtrim(&contents); + } - new = make_str(contents); + new = make_str(contents); } if (*first == NULL) { - *first = new; + *first = new; *last = new; } else { append_inlines(*first, new); } - + while (new->next) { new = new->next; } - *last = new; - + *last = new; + return 1; } @@ -865,8 +865,8 @@ void spnl(subject* subj) { bool seen_newline = false; while (peek_char(subj) == ' ' || - (!seen_newline && - (seen_newline = peek_char(subj) == '\n'))) { + (!seen_newline && + (seen_newline = peek_char(subj) == '\n'))) { advance(subj); } } @@ -933,4 +933,3 @@ int parse_reference_inline(strbuf *input, reference_map *refmap) reference_create(refmap, &lab, &url, &title); return subj.pos; } - -- cgit v1.2.3 From a50384fac90f89165fd3120b2e5fec39ca4b8ff7 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 18 Oct 2014 21:04:42 -0700 Subject: Don't emit empty str elements in handle_strong_emph. --- src/inlines.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 1eb5056..9fa4a7f 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -360,7 +360,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) return handle_strong_emph(subj, c, last); } - return make_str(chunk_literal("")); + return NULL; // make_str(chunk_literal("")); } cannotClose: @@ -845,8 +845,10 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) append_inlines(*first, new); } - while (new->next) { - new = new->next; + if (new) { + while (new->next) { + new = new->next; + } } *last = new; -- cgit v1.2.3 From db7434f4b164738a3a3fde15b0c610053c9f3a5f Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 18 Oct 2014 22:10:23 -0700 Subject: Fixed performance regression. See discussion under #157. --- src/inlines.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 9fa4a7f..b530c02 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -841,16 +841,10 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) if (*first == NULL) { *first = new; *last = new; - } else { - append_inlines(*first, new); - } - - if (new) { - while (new->next) { - new = new->next; - } + } else if (new) { + append_inlines(*last, new); + *last = new; } - *last = new; return 1; } -- cgit v1.2.3 From 32abf27635068757a084f9a959d21413ab212793 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sat, 18 Oct 2014 23:11:34 -0700 Subject: parse_inline: Correctly move to last inline. --- src/inlines.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index b530c02..10ef834 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -844,6 +844,10 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) } else if (new) { append_inlines(*last, new); *last = new; + while (new->next) { + new = new->next; + *last = new; + } } return 1; -- cgit v1.2.3 From 50cb546d1c603d7444ec09ff52463c2c01212cb2 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 19 Oct 2014 13:07:38 -0700 Subject: Whitespace changes. --- src/inlines.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index 10ef834..f2a1c63 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -304,7 +304,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) node_inl * inl; node_inl * emph; node_inl * inl_text; - + numdelims = scan_delims(subj, c, &can_open, &can_close); if (can_close) @@ -724,7 +724,7 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) node_inl* last = NULL; while ((*f)(subj) && parse_inline(subj, first, &last)) { } - + inline_stack* istack = subj->last_emphasis; inline_stack* temp; while (istack != NULL) { @@ -732,7 +732,7 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) free(istack); istack = temp; } - + return result; } -- cgit v1.2.3 From acfdce9fa8159ec950ec91bd68e8f56b869c0167 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 19 Oct 2014 13:19:11 -0700 Subject: Removed now-undeeded 'first' parameter in parse_inline. --- src/inlines.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index f2a1c63..a6d947c 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -27,7 +27,7 @@ typedef struct Subject { static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); static node_inl *parse_inlines_while(subject* subj, int (*f)(subject*)); -static int parse_inline(subject* subj, node_inl ** first, node_inl ** last); +static int parse_inline(subject* subj, node_inl ** last); static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap); static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap); @@ -720,9 +720,12 @@ inline static int not_eof(subject* subj) extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) { node_inl* result = NULL; - node_inl** first = &result; - node_inl* last = NULL; - while ((*f)(subj) && parse_inline(subj, first, &last)) { + node_inl** last = &result; + node_inl* first = NULL; + while ((*f)(subj) && parse_inline(subj, last)) { + if (!first) { + first = *last; + } } inline_stack* istack = subj->last_emphasis; @@ -733,7 +736,7 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) istack = temp; } - return result; + return first; } node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap) @@ -778,7 +781,7 @@ static int subject_find_special_char(subject *subj) // Parse an inline, advancing subject, and add it to last element. // Adjust tail to point to new last element of list. // Return 0 if no inline can be parsed, 1 otherwise. -static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) +static int parse_inline(subject* subj, node_inl ** last) { node_inl* new = NULL; chunk contents; @@ -838,16 +841,11 @@ static int parse_inline(subject* subj, node_inl ** first, node_inl ** last) new = make_str(contents); } - if (*first == NULL) { - *first = new; + if (*last == NULL) { *last = new; } else if (new) { append_inlines(*last, new); *last = new; - while (new->next) { - new = new->next; - *last = new; - } } return 1; -- cgit v1.2.3 From 751fb7894ccca3a89c4f14cb5c99ff39be957455 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 24 Oct 2014 08:00:05 -0700 Subject: Renamed subj->last_emphasis to subj->emphasis_openers. --- src/inlines.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index a6d947c..a736ec6 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -22,7 +22,7 @@ typedef struct Subject { int pos; int label_nestlevel; reference_map *refmap; - inline_stack *last_emphasis; + inline_stack *emphasis_openers; } subject; static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap); @@ -166,7 +166,7 @@ static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap) e->pos = 0; e->label_nestlevel = 0; e->refmap = refmap; - e->last_emphasis = NULL; + e->emphasis_openers = NULL; chunk_rtrim(&e->input); } @@ -179,7 +179,7 @@ static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap) e->pos = 0; e->label_nestlevel = 0; e->refmap = refmap; - e->last_emphasis = NULL; + e->emphasis_openers = NULL; chunk_rtrim(&e->input); } @@ -310,7 +310,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) if (can_close) { // walk the stack and find a matching opener, if there is one - istack = subj->last_emphasis; + istack = subj->emphasis_openers; while (true) { if (istack == NULL) @@ -336,7 +336,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) inl->content.inlines = inl->next; inl->next = NULL; - subj->last_emphasis = istack->previous; + subj->emphasis_openers = istack->previous; istack->previous = NULL; *last = inl; free(istack); @@ -372,8 +372,8 @@ cannotClose: istack->delim_count = numdelims; istack->delim_char = c; istack->first_inline = inl_text; - istack->previous = subj->last_emphasis; - subj->last_emphasis = istack; + istack->previous = subj->emphasis_openers; + subj->emphasis_openers = istack; } return inl_text; @@ -728,7 +728,7 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*)) } } - inline_stack* istack = subj->last_emphasis; + inline_stack* istack = subj->emphasis_openers; inline_stack* temp; while (istack != NULL) { temp = istack->previous; -- cgit v1.2.3 From 29fbcd6e5715944b458965535bdd5bc302cc0996 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 24 Oct 2014 10:09:30 -0700 Subject: Fixed memory leak by freeing all unused emphasis openers. --- src/inlines.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index a736ec6..d24235a 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -301,6 +301,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) int numdelims; int useDelims; inline_stack * istack; + inline_stack * tempstack; node_inl * inl; node_inl * emph; node_inl * inl_text; @@ -336,10 +337,13 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) inl->content.inlines = inl->next; inl->next = NULL; - subj->emphasis_openers = istack->previous; - istack->previous = NULL; + // remove this opener and all later ones from stack: + while (subj->emphasis_openers != istack->previous) { + tempstack = subj->emphasis_openers; + free(tempstack); + subj->emphasis_openers = subj->emphasis_openers->previous; + } *last = inl; - free(istack); } else { @@ -350,6 +354,15 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) emph = useDelims == 1 ? make_emph(inl->next) : make_strong(inl->next); inl->next = emph; + + // remove all later openers from stack: + while (subj->emphasis_openers != istack) { + tempstack = subj->emphasis_openers; + free(tempstack); + subj->emphasis_openers = subj->emphasis_openers->previous; + } + + *last = emph; } -- cgit v1.2.3 From d6643c7a5b8e5d8836a95c09a06253e43e158726 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Fri, 24 Oct 2014 10:15:50 -0700 Subject: Fixed a memory allocation error. --- src/inlines.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/inlines.c') diff --git a/src/inlines.c b/src/inlines.c index d24235a..07a75f9 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -293,6 +293,16 @@ static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close) return numdelims; } +static void free_openers(subject* subj, inline_stack* istack) +{ + inline_stack * tempstack; + while (subj->emphasis_openers != istack) { + tempstack = subj->emphasis_openers; + subj->emphasis_openers = subj->emphasis_openers->previous; + free(tempstack); + } +} + // Parse strong/emph or a fallback. // Assumes the subject has '_' or '*' at the current position. static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) @@ -301,7 +311,6 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) int numdelims; int useDelims; inline_stack * istack; - inline_stack * tempstack; node_inl * inl; node_inl * emph; node_inl * inl_text; @@ -338,11 +347,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) inl->next = NULL; // remove this opener and all later ones from stack: - while (subj->emphasis_openers != istack->previous) { - tempstack = subj->emphasis_openers; - free(tempstack); - subj->emphasis_openers = subj->emphasis_openers->previous; - } + free_openers(subj, istack->previous); *last = inl; } else @@ -356,12 +361,7 @@ static node_inl* handle_strong_emph(subject* subj, char c, node_inl **last) inl->next = emph; // remove all later openers from stack: - while (subj->emphasis_openers != istack) { - tempstack = subj->emphasis_openers; - free(tempstack); - subj->emphasis_openers = subj->emphasis_openers->previous; - } - + free_openers(subj, istack); *last = emph; } -- cgit v1.2.3