commonmarker 0.23.8 → 0.23.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of commonmarker might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5720fe7353e4f737164cc06dd97f54d8e203342bcaf2267b77e26231122ef65
4
- data.tar.gz: 1b929f138c087ce5da68ad0cdf61701ef0521db9e5d13c973b0ae81ea3c25bb1
3
+ metadata.gz: e13ce6bba89ae75cedfa740776ebacf43cc4c304f576aff0d5d795c5b9264e83
4
+ data.tar.gz: '03805285731cd7a7ddf1b856f572a3625c513d346f3e6fce7805d49a75a8c975'
5
5
  SHA512:
6
- metadata.gz: 2867a5effac7f5a52f1f850e8c9f9f4257105e14fafd34ea5bb688bf98357aa15aece3e55cc8df27df219624493d41e34a715dba4f631b2618e294dee30e61a7
7
- data.tar.gz: 938dfa5d2335d7ec2f9ee330b2d1c502c6c95809f8835ee1b6e1ba9c9bce13e5e73315f7add0feab39e229085266e416c8865f77b66731f915aeee78e87eb5ac
6
+ metadata.gz: daffcc63f38700d806bbc9fa586fdb27855aec89b9fa7a6277accccabff40cb0adfd9e469eec2d992a540b038b5348e2b275b25d191cd1ee4ce38ccdc9a2094a
7
+ data.tar.gz: bef345d402340ace137b25ba5c0c78255252d347f5f637cfb3dff4c0407b554da958a7a9c14893dee523fd203c4b0ce5f2a5a696cdf83051eb5985aa4e116bab
@@ -27,6 +27,14 @@
27
27
  #define CODE_INDENT 4
28
28
  #define TAB_STOP 4
29
29
 
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
+
30
38
  #ifndef MIN
31
39
  #define MIN(x, y) ((x < y) ? x : y)
32
40
  #endif
@@ -1119,10 +1127,11 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
1119
1127
  bool has_content;
1120
1128
  int save_offset;
1121
1129
  int save_column;
1130
+ size_t depth = 0;
1122
1131
 
1123
1132
  while (cont_type != CMARK_NODE_CODE_BLOCK &&
1124
1133
  cont_type != CMARK_NODE_HTML_BLOCK) {
1125
-
1134
+ depth++;
1126
1135
  S_find_first_nonspace(parser, input);
1127
1136
  indented = parser->indent >= CODE_INDENT;
1128
1137
 
@@ -1224,6 +1233,7 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
1224
1233
  (*container)->internal_offset = matched;
1225
1234
  } else if ((!indented || cont_type == CMARK_NODE_LIST) &&
1226
1235
  parser->indent < 4 &&
1236
+ depth < MAX_LIST_DEPTH &&
1227
1237
  (matched = parse_list_marker(
1228
1238
  parser->mem, input, parser->first_nonspace,
1229
1239
  (*container)->type == CMARK_NODE_PARAGRAPH, &data))) {
@@ -413,6 +413,17 @@ CMARK_GFM_EXPORT int cmark_node_get_list_tight(cmark_node *node);
413
413
  */
414
414
  CMARK_GFM_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
415
415
 
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
+
416
427
  /** Returns the info string from a fenced code block.
417
428
  */
418
429
  CMARK_GFM_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
@@ -1,7 +1,7 @@
1
1
  #ifndef CMARK_GFM_VERSION_H
2
2
  #define CMARK_GFM_VERSION_H
3
3
 
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"
6
6
 
7
7
  #endif
@@ -153,23 +153,8 @@ static bool is_autolink(cmark_node *node) {
153
153
  link_text->as.literal.len) == 0);
154
154
  }
155
155
 
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
-
170
156
  static int S_render_node(cmark_renderer *renderer, cmark_node *node,
171
157
  cmark_event_type ev_type, int options) {
172
- cmark_node *tmp;
173
158
  int list_number;
174
159
  cmark_delim_type list_delim;
175
160
  int numticks;
@@ -189,14 +174,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
189
174
  // Don't adjust tight list status til we've started the list.
190
175
  // Otherwise we loose the blank line between a paragraph and
191
176
  // 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
+ }
200
188
  }
201
189
 
202
190
  if (node->extension && node->extension->commonmark_render_func) {
@@ -234,13 +222,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
234
222
  if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
235
223
  marker_width = 4;
236
224
  } else {
237
- list_number = cmark_node_get_list_start(node->parent);
225
+ list_number = cmark_node_get_item_index(node);
238
226
  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
- }
244
227
  // we ensure a width of at least 4 so
245
228
  // we get nice transition from single digits
246
229
  // to double
@@ -405,10 +388,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
405
388
  break;
406
389
 
407
390
  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
+ }
412
397
  }
413
398
  break;
414
399
 
@@ -364,10 +364,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
364
364
  break;
365
365
 
366
366
  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
+ }
371
373
  }
372
374
  break;
373
375
 
@@ -385,10 +385,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
385
385
  break;
386
386
 
387
387
  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
+ }
392
394
  }
393
395
  break;
394
396
 
@@ -74,7 +74,6 @@ static void S_outc(cmark_renderer *renderer, cmark_node *node,
74
74
 
75
75
  static int S_render_node(cmark_renderer *renderer, cmark_node *node,
76
76
  cmark_event_type ev_type, int options) {
77
- cmark_node *tmp;
78
77
  int list_number;
79
78
  bool entering = (ev_type == CMARK_EVENT_ENTER);
80
79
  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,
123
122
  if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
124
123
  LIT("\\[bu] 2");
125
124
  } 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);
132
126
  char list_number_s[LIST_NUMBER_SIZE];
133
127
  snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number);
134
128
  LIT(list_number_s);
@@ -225,10 +219,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
225
219
  break;
226
220
 
227
221
  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
+ }
232
228
  }
233
229
  break;
234
230
 
@@ -5,6 +5,16 @@
5
5
  #include "node.h"
6
6
  #include "syntax_extension.h"
7
7
 
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
+
8
18
  static void S_node_unlink(cmark_node *node);
9
19
 
10
20
  #define NODE_MEM(node) cmark_node_mem(node)
@@ -29,7 +39,7 @@ void cmark_register_node_flag(cmark_node_internal_flags *flags) {
29
39
  nextflag <<= 1;
30
40
  }
31
41
 
32
- void cmark_init_standard_node_flags() {}
42
+ void cmark_init_standard_node_flags(void) {}
33
43
 
34
44
  bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
35
45
  if (child_type == CMARK_NODE_DOCUMENT) {
@@ -70,8 +80,6 @@ bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
70
80
  }
71
81
 
72
82
  static bool S_can_contain(cmark_node *node, cmark_node *child) {
73
- cmark_node *cur;
74
-
75
83
  if (node == NULL || child == NULL) {
76
84
  return false;
77
85
  }
@@ -79,14 +87,16 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
79
87
  return 0;
80
88
  }
81
89
 
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
+ }
90
100
 
91
101
  return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
92
102
  }
@@ -554,6 +564,31 @@ int cmark_node_set_list_tight(cmark_node *node, int tight) {
554
564
  }
555
565
  }
556
566
 
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
+
557
592
  const char *cmark_node_get_fence_info(cmark_node *node) {
558
593
  if (node == NULL) {
559
594
  return NULL;
@@ -82,6 +82,14 @@ struct cmark_node {
82
82
 
83
83
  cmark_syntax_extension *extension;
84
84
 
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
+
85
93
  union {
86
94
  int ref_ix;
87
95
  int def_count;
@@ -119,7 +127,7 @@ void cmark_register_node_flag(cmark_node_internal_flags *flags);
119
127
  * library. It is now a no-op.
120
128
  */
121
129
  CMARK_GFM_EXPORT
122
- void cmark_init_standard_node_flags();
130
+ void cmark_init_standard_node_flags(void);
123
131
 
124
132
  static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
125
133
  return node->content.mem;
@@ -144,6 +152,13 @@ static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
144
152
 
145
153
  CMARK_GFM_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
146
154
 
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
+
147
162
  #ifdef __cplusplus
148
163
  }
149
164
  #endif
@@ -16,23 +16,8 @@ static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_node *node,
16
16
  cmark_render_code_point(renderer, c);
17
17
  }
18
18
 
19
- // if node is a block node, returns node.
20
- // otherwise returns first block-level node that is an ancestor of node.
21
- // if there is no block-level ancestor, returns NULL.
22
- static cmark_node *get_containing_block(cmark_node *node) {
23
- while (node) {
24
- if (CMARK_NODE_BLOCK_P(node)) {
25
- return node;
26
- } else {
27
- node = node->parent;
28
- }
29
- }
30
- return NULL;
31
- }
32
-
33
19
  static int S_render_node(cmark_renderer *renderer, cmark_node *node,
34
20
  cmark_event_type ev_type, int options) {
35
- cmark_node *tmp;
36
21
  int list_number;
37
22
  cmark_delim_type list_delim;
38
23
  int i;
@@ -46,14 +31,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
46
31
  // Don't adjust tight list status til we've started the list.
47
32
  // Otherwise we loose the blank line between a paragraph and
48
33
  // a following list.
49
- if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
50
- tmp = get_containing_block(node);
51
- renderer->in_tight_list_item =
52
- tmp && // tmp might be NULL if there is no containing block
53
- ((tmp->type == CMARK_NODE_ITEM &&
54
- cmark_node_get_list_tight(tmp->parent)) ||
55
- (tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
56
- cmark_node_get_list_tight(tmp->parent->parent)));
34
+ if (entering) {
35
+ if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
36
+ renderer->in_tight_list_item = node->parent->parent->as.list.tight;
37
+ }
38
+ } else {
39
+ if (node->type == CMARK_NODE_LIST) {
40
+ renderer->in_tight_list_item =
41
+ node->parent &&
42
+ node->parent->type == CMARK_NODE_ITEM &&
43
+ node->parent->parent->as.list.tight;
44
+ }
57
45
  }
58
46
 
59
47
  if (node->extension && node->extension->plaintext_render_func) {
@@ -79,13 +67,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
79
67
  if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
80
68
  marker_width = 4;
81
69
  } else {
82
- list_number = cmark_node_get_list_start(node->parent);
70
+ list_number = cmark_node_get_item_index(node);
83
71
  list_delim = cmark_node_get_list_delim(node->parent);
84
- tmp = node;
85
- while (tmp->prev) {
86
- tmp = tmp->prev;
87
- list_number += 1;
88
- }
89
72
  // we ensure a width of at least 4 so
90
73
  // we get nice transition from single digits
91
74
  // to double
@@ -31,13 +31,7 @@ static void S_out(cmark_renderer *renderer, cmark_node *node,
31
31
  cmark_chunk remainder = cmark_chunk_literal("");
32
32
  int k = renderer->buffer->size - 1;
33
33
 
34
- cmark_syntax_extension *ext = NULL;
35
- cmark_node *n = node;
36
- while (n && !ext) {
37
- ext = n->extension;
38
- if (!ext)
39
- n = n->parent;
40
- }
34
+ cmark_syntax_extension *ext = node->ancestor_extension;
41
35
  if (ext && !ext->commonmark_escape_func)
42
36
  ext = NULL;
43
37
 
@@ -182,6 +176,20 @@ char *cmark_render(cmark_mem *mem, cmark_node *root, int options, int width,
182
176
 
183
177
  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
184
178
  cur = cmark_iter_get_node(iter);
179
+ if (cur->extension) {
180
+ cur->ancestor_extension = cur->extension;
181
+ } else if (cur->parent) {
182
+ cur->ancestor_extension = cur->parent->ancestor_extension;
183
+ }
184
+ if (cur->type == CMARK_NODE_ITEM) {
185
+ // Calculate the list item's index, for the benefit of output formats
186
+ // like commonmark and plaintext.
187
+ if (cur->prev) {
188
+ cmark_node_set_item_index(cur, 1 + cmark_node_get_item_index(cur->prev));
189
+ } else {
190
+ cmark_node_set_item_index(cur, cmark_node_get_list_start(cur->parent));
191
+ }
192
+ }
185
193
  if (!render_node(&renderer, cur, ev_type, options)) {
186
194
  // a false value causes us to skip processing
187
195
  // the node's contents. this is used for
@@ -11,6 +11,7 @@
11
11
  #include "syntax_extension.h"
12
12
 
13
13
  #define BUFFER_SIZE 100
14
+ #define MAX_INDENT 40
14
15
 
15
16
  // Functions to convert cmark_nodes to XML strings.
16
17
 
@@ -26,7 +27,7 @@ struct render_state {
26
27
 
27
28
  static CMARK_INLINE void indent(struct render_state *state) {
28
29
  int i;
29
- for (i = 0; i < state->indent; i++) {
30
+ for (i = 0; i < state->indent && i < MAX_INDENT; i++) {
30
31
  cmark_strbuf_putc(state->xml, ' ');
31
32
  }
32
33
  }
@@ -129,8 +129,12 @@ module CommonMarker
129
129
  out("<em>", :children, "</em>")
130
130
  end
131
131
 
132
- def strong(_)
133
- out("<strong>", :children, "</strong>")
132
+ def strong(node)
133
+ if node.parent&.type == :strong
134
+ out(:children)
135
+ else
136
+ out("<strong>", :children, "</strong>")
137
+ end
134
138
  end
135
139
 
136
140
  def link(node)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CommonMarker
4
- VERSION = "0.23.8"
4
+ VERSION = "0.23.9"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commonmarker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.8
4
+ version: 0.23.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-01-31 00:00:00.000000000 Z
12
+ date: 2023-04-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: awesome_print