Skip to content

Commit 42cfc90

Browse files
authored
Merge pull request #236 from anticomputer/update-to-0.29.0.gfm.10
Release 0.23.9 --> update to 0.29.0.gfm.11
2 parents 94c0af9 + d793fbf commit 42cfc90

16 files changed

+160
-111
lines changed

Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,3 @@ ext/commonmarker/cmark-gfm_export.h: ext/commonmarker/cmark-upstream/build/src/c
2121

2222
ext/commonmarker/cmark-gfm_version.h: ext/commonmarker/cmark-upstream/build/src/cmark-gfm_version.h
2323
cp $< $@
24-
25-
ext/commonmarker/cmark-gfm-extensions_export.h: ext/commonmarker/cmark-upstream/build/extensions/cmark-gfm-extensions_export.h
26-
cp $< $@

ext/commonmarker/blocks.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
#define CODE_INDENT 4
2828
#define TAB_STOP 4
2929

30+
/**
31+
* Very deeply nested lists can cause quadratic performance issues.
32+
* This constant is used in open_new_blocks() to limit the nesting
33+
* depth. It is unlikely that a non-contrived markdown document will
34+
* be nested this deeply.
35+
*/
36+
#define MAX_LIST_DEPTH 100
37+
3038
#ifndef MIN
3139
#define MIN(x, y) ((x < y) ? x : y)
3240
#endif
@@ -1119,10 +1127,11 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
11191127
bool has_content;
11201128
int save_offset;
11211129
int save_column;
1130+
size_t depth = 0;
11221131

11231132
while (cont_type != CMARK_NODE_CODE_BLOCK &&
11241133
cont_type != CMARK_NODE_HTML_BLOCK) {
1125-
1134+
depth++;
11261135
S_find_first_nonspace(parser, input);
11271136
indented = parser->indent >= CODE_INDENT;
11281137

@@ -1224,6 +1233,7 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
12241233
(*container)->internal_offset = matched;
12251234
} else if ((!indented || cont_type == CMARK_NODE_LIST) &&
12261235
parser->indent < 4 &&
1236+
depth < MAX_LIST_DEPTH &&
12271237
(matched = parse_list_marker(
12281238
parser->mem, input, parser->first_nonspace,
12291239
(*container)->type == CMARK_NODE_PARAGRAPH, &data))) {

ext/commonmarker/cmark-gfm.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,17 @@ CMARK_GFM_EXPORT int cmark_node_get_list_tight(cmark_node *node);
413413
*/
414414
CMARK_GFM_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
415415

416+
/**
417+
* Returns item index of 'node'. This is only used when rendering output
418+
* formats such as commonmark, which need to output the index. It is not
419+
* required for formats such as html or latex.
420+
*/
421+
CMARK_GFM_EXPORT int cmark_node_get_item_index(cmark_node *node);
422+
423+
/** Sets item index of 'node'. Returns 1 on success, 0 on failure.
424+
*/
425+
CMARK_GFM_EXPORT int cmark_node_set_item_index(cmark_node *node, int idx);
426+
416427
/** Returns the info string from a fenced code block.
417428
*/
418429
CMARK_GFM_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);

ext/commonmarker/cmark-gfm_version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef CMARK_GFM_VERSION_H
22
#define CMARK_GFM_VERSION_H
33

4-
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 6)
5-
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.6"
4+
#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 11)
5+
#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.11"
66

77
#endif

ext/commonmarker/commonmark.c

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -153,23 +153,8 @@ static bool is_autolink(cmark_node *node) {
153153
link_text->as.literal.len) == 0);
154154
}
155155

156-
// if node is a block node, returns node.
157-
// otherwise returns first block-level node that is an ancestor of node.
158-
// if there is no block-level ancestor, returns NULL.
159-
static cmark_node *get_containing_block(cmark_node *node) {
160-
while (node) {
161-
if (CMARK_NODE_BLOCK_P(node)) {
162-
return node;
163-
} else {
164-
node = node->parent;
165-
}
166-
}
167-
return NULL;
168-
}
169-
170156
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
171157
cmark_event_type ev_type, int options) {
172-
cmark_node *tmp;
173158
int list_number;
174159
cmark_delim_type list_delim;
175160
int numticks;
@@ -189,14 +174,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
189174
// Don't adjust tight list status til we've started the list.
190175
// Otherwise we loose the blank line between a paragraph and
191176
// a following list.
192-
if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
193-
tmp = get_containing_block(node);
194-
renderer->in_tight_list_item =
195-
tmp && // tmp might be NULL if there is no containing block
196-
((tmp->type == CMARK_NODE_ITEM &&
197-
cmark_node_get_list_tight(tmp->parent)) ||
198-
(tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
199-
cmark_node_get_list_tight(tmp->parent->parent)));
177+
if (entering) {
178+
if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
179+
renderer->in_tight_list_item = node->parent->parent->as.list.tight;
180+
}
181+
} else {
182+
if (node->type == CMARK_NODE_LIST) {
183+
renderer->in_tight_list_item =
184+
node->parent &&
185+
node->parent->type == CMARK_NODE_ITEM &&
186+
node->parent->parent->as.list.tight;
187+
}
200188
}
201189

202190
if (node->extension && node->extension->commonmark_render_func) {
@@ -234,13 +222,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
234222
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
235223
marker_width = 4;
236224
} else {
237-
list_number = cmark_node_get_list_start(node->parent);
225+
list_number = cmark_node_get_item_index(node);
238226
list_delim = cmark_node_get_list_delim(node->parent);
239-
tmp = node;
240-
while (tmp->prev) {
241-
tmp = tmp->prev;
242-
list_number += 1;
243-
}
244227
// we ensure a width of at least 4 so
245228
// we get nice transition from single digits
246229
// to double
@@ -405,10 +388,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
405388
break;
406389

407390
case CMARK_NODE_STRONG:
408-
if (entering) {
409-
LIT("**");
410-
} else {
411-
LIT("**");
391+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
392+
if (entering) {
393+
LIT("**");
394+
} else {
395+
LIT("**");
396+
}
412397
}
413398
break;
414399

ext/commonmarker/html.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
364364
break;
365365

366366
case CMARK_NODE_STRONG:
367-
if (entering) {
368-
cmark_strbuf_puts(html, "<strong>");
369-
} else {
370-
cmark_strbuf_puts(html, "</strong>");
367+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
368+
if (entering) {
369+
cmark_strbuf_puts(html, "<strong>");
370+
} else {
371+
cmark_strbuf_puts(html, "</strong>");
372+
}
371373
}
372374
break;
373375

ext/commonmarker/latex.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
385385
break;
386386

387387
case CMARK_NODE_STRONG:
388-
if (entering) {
389-
LIT("\\textbf{");
390-
} else {
391-
LIT("}");
388+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
389+
if (entering) {
390+
LIT("\\textbf{");
391+
} else {
392+
LIT("}");
393+
}
392394
}
393395
break;
394396

ext/commonmarker/man.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ static void S_outc(cmark_renderer *renderer, cmark_node *node,
7474

7575
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
7676
cmark_event_type ev_type, int options) {
77-
cmark_node *tmp;
7877
int list_number;
7978
bool entering = (ev_type == CMARK_EVENT_ENTER);
8079
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
@@ -123,12 +122,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
123122
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
124123
LIT("\\[bu] 2");
125124
} else {
126-
list_number = cmark_node_get_list_start(node->parent);
127-
tmp = node;
128-
while (tmp->prev) {
129-
tmp = tmp->prev;
130-
list_number += 1;
131-
}
125+
list_number = cmark_node_get_item_index(node);
132126
char list_number_s[LIST_NUMBER_SIZE];
133127
snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number);
134128
LIT(list_number_s);
@@ -225,10 +219,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
225219
break;
226220

227221
case CMARK_NODE_STRONG:
228-
if (entering) {
229-
LIT("\\f[B]");
230-
} else {
231-
LIT("\\f[]");
222+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
223+
if (entering) {
224+
LIT("\\f[B]");
225+
} else {
226+
LIT("\\f[]");
227+
}
232228
}
233229
break;
234230

ext/commonmarker/node.c

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@
55
#include "node.h"
66
#include "syntax_extension.h"
77

8+
/**
9+
* Expensive safety checks are off by default, but can be enabled
10+
* by calling cmark_enable_safety_checks().
11+
*/
12+
static bool enable_safety_checks = false;
13+
14+
void cmark_enable_safety_checks(bool enable) {
15+
enable_safety_checks = enable;
16+
}
17+
818
static void S_node_unlink(cmark_node *node);
919

1020
#define NODE_MEM(node) cmark_node_mem(node)
@@ -29,7 +39,7 @@ void cmark_register_node_flag(cmark_node_internal_flags *flags) {
2939
nextflag <<= 1;
3040
}
3141

32-
void cmark_init_standard_node_flags() {}
42+
void cmark_init_standard_node_flags(void) {}
3343

3444
bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
3545
if (child_type == CMARK_NODE_DOCUMENT) {
@@ -70,23 +80,23 @@ bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
7080
}
7181

7282
static bool S_can_contain(cmark_node *node, cmark_node *child) {
73-
cmark_node *cur;
74-
7583
if (node == NULL || child == NULL) {
7684
return false;
7785
}
7886
if (NODE_MEM(node) != NODE_MEM(child)) {
7987
return 0;
8088
}
8189

82-
// Verify that child is not an ancestor of node or equal to node.
83-
cur = node;
84-
do {
85-
if (cur == child) {
86-
return false;
87-
}
88-
cur = cur->parent;
89-
} while (cur != NULL);
90+
if (enable_safety_checks) {
91+
// Verify that child is not an ancestor of node or equal to node.
92+
cmark_node *cur = node;
93+
do {
94+
if (cur == child) {
95+
return false;
96+
}
97+
cur = cur->parent;
98+
} while (cur != NULL);
99+
}
90100

91101
return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
92102
}
@@ -554,6 +564,31 @@ int cmark_node_set_list_tight(cmark_node *node, int tight) {
554564
}
555565
}
556566

567+
int cmark_node_get_item_index(cmark_node *node) {
568+
if (node == NULL) {
569+
return 0;
570+
}
571+
572+
if (node->type == CMARK_NODE_ITEM) {
573+
return node->as.list.start;
574+
} else {
575+
return 0;
576+
}
577+
}
578+
579+
int cmark_node_set_item_index(cmark_node *node, int idx) {
580+
if (node == NULL || idx < 0) {
581+
return 0;
582+
}
583+
584+
if (node->type == CMARK_NODE_ITEM) {
585+
node->as.list.start = idx;
586+
return 1;
587+
} else {
588+
return 0;
589+
}
590+
}
591+
557592
const char *cmark_node_get_fence_info(cmark_node *node) {
558593
if (node == NULL) {
559594
return NULL;

ext/commonmarker/node.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ struct cmark_node {
8282

8383
cmark_syntax_extension *extension;
8484

85+
/**
86+
* Used during cmark_render() to cache the most recent non-NULL
87+
* extension, if you go up the parent chain like this:
88+
*
89+
* node->parent->...parent->extension
90+
*/
91+
cmark_syntax_extension *ancestor_extension;
92+
8593
union {
8694
int ref_ix;
8795
int def_count;
@@ -119,7 +127,7 @@ void cmark_register_node_flag(cmark_node_internal_flags *flags);
119127
* library. It is now a no-op.
120128
*/
121129
CMARK_GFM_EXPORT
122-
void cmark_init_standard_node_flags();
130+
void cmark_init_standard_node_flags(void);
123131

124132
static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
125133
return node->content.mem;
@@ -144,6 +152,13 @@ static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
144152

145153
CMARK_GFM_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
146154

155+
/**
156+
* Enable (or disable) extra safety checks. These extra checks cause
157+
* extra performance overhead (in some cases quadratic), so they are only
158+
* intended to be used during testing.
159+
*/
160+
CMARK_GFM_EXPORT void cmark_enable_safety_checks(bool enable);
161+
147162
#ifdef __cplusplus
148163
}
149164
#endif

0 commit comments

Comments
 (0)