Skip to content

Commit aa73711

Browse files
Early-terminate the loop in check_open_blocks when the current line is blank.
1 parent c72487d commit aa73711

File tree

2 files changed

+39
-3
lines changed

2 files changed

+39
-3
lines changed

src/blocks.c

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,11 @@ static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
409409
// in parser. (Used to check that the counts in parser, which are updated incrementally, are
410410
// correct.)
411411
bool check_open_block_counts(cmark_parser *parser) {
412-
cmark_parser tmp_parser = {0}; // Only used for its open_block_counts field.
412+
cmark_parser tmp_parser = {0}; // Only used for its open_block_counts and total_open_blocks fields.
413413
add_open_block_counts(&tmp_parser, parser->root);
414-
return memcmp(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts)) == 0;
414+
return
415+
tmp_parser.total_open_blocks == parser->total_open_blocks &&
416+
memcmp(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts)) == 0;
415417
}
416418

417419
// Add a node as child of another. Return pointer to child.
@@ -1082,10 +1084,14 @@ static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
10821084
*all_matched = false;
10831085
cmark_node *container = parser->root;
10841086
cmark_node_type cont_type;
1087+
cmark_parser tmp_parser; // Only used for its open_block_counts and total_open_blocks fields.
1088+
memcpy(tmp_parser.open_block_counts, parser->open_block_counts, sizeof(parser->open_block_counts));
1089+
tmp_parser.total_open_blocks = parser->total_open_blocks;
10851090

10861091
assert(check_open_block_counts(parser));
10871092

10881093
while (S_last_child_is_open(container)) {
1094+
decr_open_block_count(&tmp_parser, S_type(container));
10891095
container = container->last_child;
10901096
cont_type = S_type(container);
10911097

@@ -1097,6 +1103,26 @@ static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
10971103
continue;
10981104
}
10991105

1106+
if (parser->blank) {
1107+
const size_t n_list = read_open_block_count(&tmp_parser, CMARK_NODE_LIST);
1108+
const size_t n_item = read_open_block_count(&tmp_parser, CMARK_NODE_ITEM);
1109+
const size_t n_para = read_open_block_count(&tmp_parser, CMARK_NODE_PARAGRAPH);
1110+
if (n_list + n_item + n_para == tmp_parser.total_open_blocks) {
1111+
if (parser->current->flags & CMARK_NODE__OPEN_BLOCK) {
1112+
if (S_type(parser->current) == CMARK_NODE_PARAGRAPH) {
1113+
container = parser->current;
1114+
goto done;
1115+
}
1116+
if (S_type(parser->current) == CMARK_NODE_ITEM) {
1117+
if (parser->current->flags & CMARK_NODE__OPEN) {
1118+
container = parser->current;
1119+
cont_type = S_type(container);
1120+
}
1121+
}
1122+
}
1123+
}
1124+
}
1125+
11001126
switch (cont_type) {
11011127
case CMARK_NODE_BLOCK_QUOTE:
11021128
if (!parse_block_quote_prefix(parser, input))
@@ -1387,7 +1413,7 @@ static void add_text_to_container(cmark_parser *parser, cmark_node *container,
13871413
S_set_last_line_blank(container, last_line_blank);
13881414

13891415
tmp = container;
1390-
while (tmp->parent) {
1416+
while (tmp->parent && S_last_line_blank(tmp->parent)) {
13911417
S_set_last_line_blank(tmp->parent, false);
13921418
tmp = tmp->parent;
13931419
}

src/parser.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,29 @@ struct cmark_parser {
6666
* For example, CMARK_NODE_LIST (0x8003) is stored at offset 2.
6767
*/
6868
size_t open_block_counts[CMARK_NODE_TYPE_BLOCK_LIMIT];
69+
size_t total_open_blocks;
6970
};
7071

7172
static CMARK_INLINE void incr_open_block_count(cmark_parser *parser, cmark_node_type type) {
7273
assert(type > CMARK_NODE_TYPE_BLOCK);
7374
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
7475
parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1]++;
76+
parser->total_open_blocks++;
7577
}
7678

7779
static CMARK_INLINE void decr_open_block_count(cmark_parser *parser, cmark_node_type type) {
7880
assert(type > CMARK_NODE_TYPE_BLOCK);
7981
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
8082
assert(parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1] > 0);
8183
parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1]--;
84+
assert(parser->total_open_blocks > 0);
85+
parser->total_open_blocks--;
86+
}
87+
88+
static CMARK_INLINE size_t read_open_block_count(cmark_parser *parser, cmark_node_type type) {
89+
assert(type > CMARK_NODE_TYPE_BLOCK);
90+
assert(type <= CMARK_NODE_TYPE_BLOCK + CMARK_NODE_TYPE_BLOCK_LIMIT);
91+
return parser->open_block_counts[type - CMARK_NODE_TYPE_BLOCK - 1];
8292
}
8393

8494
#ifdef __cplusplus

0 commit comments

Comments
 (0)