Skip to content

Commit 969e27e

Browse files
authored
updated cmark-gfm from 0.29.0.gfm.9 to .13; bumped up version to 1.9.2 (#30)
1 parent 89c6ddc commit 969e27e

File tree

15 files changed

+251
-151
lines changed

15 files changed

+251
-151
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: commonmark
22
Type: Package
33
Title: High Performance CommonMark and Github Markdown Rendering in R
4-
Version: 1.9.1
4+
Version: 1.9.2
55
Authors@R: c(
66
person("Jeroen", "Ooms", ,"jeroen@berkeley.edu", role = c("aut", "cre"),
77
comment = c(ORCID = "0000-0002-4035-0289")),

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
1.9.2
2+
- Update libcmark-gfm to 0.29.0.gfm.13
3+
14
1.9.0
25
- Add parameter 'footnotes' to enable footnote parsing
36
- Update libcmark-gfm to 0.29.0.gfm.9

src/cmark/blocks.c

Lines changed: 15 additions & 3 deletions
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

@@ -1208,22 +1217,25 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
12081217
parser->first_nonspace + 1);
12091218
S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
12101219
} else if (!indented &&
1211-
parser->options & CMARK_OPT_FOOTNOTES &&
1220+
(parser->options & CMARK_OPT_FOOTNOTES) &&
1221+
depth < MAX_LIST_DEPTH &&
12121222
(matched = scan_footnote_definition(input, parser->first_nonspace))) {
12131223
cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2);
1214-
cmark_chunk_to_cstr(parser->mem, &c);
12151224

12161225
while (c.data[c.len - 1] != ']')
12171226
--c.len;
12181227
--c.len;
12191228

1229+
cmark_chunk_to_cstr(parser->mem, &c);
1230+
12201231
S_advance_offset(parser, input, parser->first_nonspace + matched - parser->offset, false);
12211232
*container = add_child(parser, *container, CMARK_NODE_FOOTNOTE_DEFINITION, parser->first_nonspace + matched + 1);
12221233
(*container)->as.literal = c;
12231234

12241235
(*container)->internal_offset = matched;
12251236
} else if ((!indented || cont_type == CMARK_NODE_LIST) &&
12261237
parser->indent < 4 &&
1238+
depth < MAX_LIST_DEPTH &&
12271239
(matched = parse_list_marker(
12281240
parser->mem, input, parser->first_nonspace,
12291241
(*container)->type == CMARK_NODE_PARAGRAPH, &data))) {

src/cmark/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);

src/cmark/commonmark.c

Lines changed: 19 additions & 34 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;
@@ -180,7 +165,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
180165
char fencechar[2] = {'\0', '\0'};
181166
size_t info_len, code_len;
182167
char listmarker[LISTMARKER_SIZE];
183-
char *emph_delim;
168+
const char *emph_delim;
184169
bool first_in_list_item;
185170
bufsize_t marker_width;
186171
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options) &&
@@ -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

src/cmark/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

src/cmark/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

src/cmark/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

src/cmark/node.c

Lines changed: 46 additions & 10 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)
@@ -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
}
@@ -367,6 +377,7 @@ const char *cmark_node_get_literal(cmark_node *node) {
367377
case CMARK_NODE_HTML_INLINE:
368378
case CMARK_NODE_CODE:
369379
case CMARK_NODE_FOOTNOTE_REFERENCE:
380+
case CMARK_NODE_FOOTNOTE_DEFINITION:
370381
return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.literal);
371382

372383
case CMARK_NODE_CODE_BLOCK:
@@ -554,6 +565,31 @@ int cmark_node_set_list_tight(cmark_node *node, int tight) {
554565
}
555566
}
556567

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

src/cmark/node.h

Lines changed: 16 additions & 0 deletions
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;
@@ -97,6 +105,7 @@ struct cmark_node {
97105
cmark_link link;
98106
cmark_custom custom;
99107
int html_block_type;
108+
int cell_index; // For keeping track of TABLE_CELL table alignments
100109
void *opaque;
101110
} as;
102111
};
@@ -144,6 +153,13 @@ static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
144153

145154
CMARK_GFM_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
146155

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

0 commit comments

Comments
 (0)