qiita_marker 0.23.6.2 → 0.23.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -111,13 +111,13 @@ typedef struct cmark_mem {
111
111
  * realloc and free.
112
112
  */
113
113
  CMARK_GFM_EXPORT
114
- cmark_mem *cmark_get_default_mem_allocator();
114
+ cmark_mem *cmark_get_default_mem_allocator(void);
115
115
 
116
116
  /** An arena allocator; uses system calloc to allocate large
117
117
  * slabs of memory. Memory in these slabs is not reused at all.
118
118
  */
119
119
  CMARK_GFM_EXPORT
120
- cmark_mem *cmark_get_arena_mem_allocator();
120
+ cmark_mem *cmark_get_arena_mem_allocator(void);
121
121
 
122
122
  /** Resets the arena allocator, quickly returning all used memory
123
123
  * to the operating system.
@@ -225,6 +225,11 @@ CMARK_GFM_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
225
225
  */
226
226
  CMARK_GFM_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
227
227
 
228
+ /** Returns the footnote reference of 'node', or NULL if 'node' doesn't have a
229
+ * footnote reference.
230
+ */
231
+ CMARK_GFM_EXPORT cmark_node *cmark_node_parent_footnote_def(cmark_node *node);
232
+
228
233
  /**
229
234
  * ## Iterator
230
235
  *
@@ -408,6 +413,17 @@ CMARK_GFM_EXPORT int cmark_node_get_list_tight(cmark_node *node);
408
413
  */
409
414
  CMARK_GFM_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
410
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
+
411
427
  /** Returns the info string from a fenced code block.
412
428
  */
413
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
@@ -10,9 +10,9 @@
10
10
  cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
11
11
  cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
12
12
 
13
- int cmark_version() { return CMARK_GFM_VERSION; }
13
+ int cmark_version(void) { return CMARK_GFM_VERSION; }
14
14
 
15
- const char *cmark_version_string() { return CMARK_GFM_VERSION_STRING; }
15
+ const char *cmark_version_string(void) { return CMARK_GFM_VERSION_STRING; }
16
16
 
17
17
  static void *xcalloc(size_t nmem, size_t size) {
18
18
  void *ptr = calloc(nmem, size);
@@ -38,7 +38,7 @@ static void xfree(void *ptr) {
38
38
 
39
39
  cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, xfree};
40
40
 
41
- cmark_mem *cmark_get_default_mem_allocator() {
41
+ cmark_mem *cmark_get_default_mem_allocator(void) {
42
42
  return &CMARK_DEFAULT_MEM_ALLOCATOR;
43
43
  }
44
44
 
@@ -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
 
@@ -64,10 +64,16 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
64
64
  if (renderer->written_footnote_ix >= renderer->footnote_ix)
65
65
  return false;
66
66
  renderer->written_footnote_ix = renderer->footnote_ix;
67
+ char m[32];
68
+ snprintf(m, sizeof(m), "%d", renderer->written_footnote_ix);
67
69
 
68
70
  cmark_strbuf_puts(html, "<a href=\"#fnref-");
69
71
  houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
70
- cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref aria-label=\"Back to content\">↩</a>");
72
+ cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
73
+ cmark_strbuf_puts(html, m);
74
+ cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
75
+ cmark_strbuf_puts(html, m);
76
+ cmark_strbuf_puts(html, "\">↩</a>");
71
77
 
72
78
  if (node->footnote.def_count > 1)
73
79
  {
@@ -79,7 +85,15 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
79
85
  houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
80
86
  cmark_strbuf_puts(html, "-");
81
87
  cmark_strbuf_puts(html, n);
82
- cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref aria-label=\"Back to content\">↩<sup class=\"footnote-ref\">");
88
+ cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
89
+ cmark_strbuf_puts(html, m);
90
+ cmark_strbuf_puts(html, "-");
91
+ cmark_strbuf_puts(html, n);
92
+ cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
93
+ cmark_strbuf_puts(html, m);
94
+ cmark_strbuf_puts(html, "-");
95
+ cmark_strbuf_puts(html, n);
96
+ cmark_strbuf_puts(html, "\">↩<sup class=\"footnote-ref\">");
83
97
  cmark_strbuf_puts(html, n);
84
98
  cmark_strbuf_puts(html, "</sup></a>");
85
99
  }
@@ -363,10 +377,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
363
377
  break;
364
378
 
365
379
  case CMARK_NODE_STRONG:
366
- if (entering) {
367
- cmark_strbuf_puts(html, "<strong>");
368
- } else {
369
- cmark_strbuf_puts(html, "</strong>");
380
+ if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
381
+ if (entering) {
382
+ cmark_strbuf_puts(html, "<strong>");
383
+ } else {
384
+ cmark_strbuf_puts(html, "</strong>");
385
+ }
370
386
  }
371
387
  break;
372
388
 
@@ -37,7 +37,6 @@ static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99";
37
37
 
38
38
  typedef struct bracket {
39
39
  struct bracket *previous;
40
- struct delimiter *previous_delimiter;
41
40
  cmark_node *inl_text;
42
41
  bufsize_t position;
43
42
  bool image;
@@ -47,9 +46,15 @@ typedef struct bracket {
47
46
  bool in_bracket_image1;
48
47
  } bracket;
49
48
 
49
+ #define FLAG_SKIP_HTML_CDATA (1u << 0)
50
+ #define FLAG_SKIP_HTML_DECLARATION (1u << 1)
51
+ #define FLAG_SKIP_HTML_PI (1u << 2)
52
+ #define FLAG_SKIP_HTML_COMMENT (1u << 3)
53
+
50
54
  typedef struct subject{
51
55
  cmark_mem *mem;
52
56
  cmark_chunk input;
57
+ unsigned flags;
53
58
  int line;
54
59
  bufsize_t pos;
55
60
  int block_offset;
@@ -59,6 +64,7 @@ typedef struct subject{
59
64
  bracket *last_bracket;
60
65
  bufsize_t backticks[MAXBACKTICKS + 1];
61
66
  bool scanned_for_backticks;
67
+ bool no_link_openers;
62
68
  } subject;
63
69
 
64
70
  // Extensions may populate this.
@@ -113,6 +119,24 @@ static cmark_node *make_str_with_entities(subject *subj,
113
119
  }
114
120
  }
115
121
 
122
+ // Like cmark_node_append_child but without costly sanity checks.
123
+ // Assumes that child was newly created.
124
+ static void append_child(cmark_node *node, cmark_node *child) {
125
+ cmark_node *old_last_child = node->last_child;
126
+
127
+ child->next = NULL;
128
+ child->prev = old_last_child;
129
+ child->parent = node;
130
+ node->last_child = child;
131
+
132
+ if (old_last_child) {
133
+ old_last_child->next = child;
134
+ } else {
135
+ // Also set first_child if node previously had no children.
136
+ node->first_child = child;
137
+ }
138
+ }
139
+
116
140
  // Duplicate a chunk by creating a copy of the buffer not by reusing the
117
141
  // buffer like cmark_chunk_dup does.
118
142
  static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
@@ -156,7 +180,7 @@ static CMARK_INLINE cmark_node *make_autolink(subject *subj,
156
180
  link->start_line = link->end_line = subj->line;
157
181
  link->start_column = start_column + 1;
158
182
  link->end_column = end_column + 1;
159
- cmark_node_append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
183
+ append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
160
184
  return link;
161
185
  }
162
186
 
@@ -165,6 +189,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
165
189
  int i;
166
190
  e->mem = mem;
167
191
  e->input = *chunk;
192
+ e->flags = 0;
168
193
  e->line = line_number;
169
194
  e->pos = 0;
170
195
  e->block_offset = block_offset;
@@ -176,6 +201,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
176
201
  e->backticks[i] = 0;
177
202
  }
178
203
  e->scanned_for_backticks = false;
204
+ e->no_link_openers = true;
179
205
  }
180
206
 
181
207
  static CMARK_INLINE int isbacktick(int c) { return (c == '`'); }
@@ -515,6 +541,7 @@ static void push_delimiter(subject *subj, unsigned char c, bool can_open,
515
541
  delim->can_open = can_open;
516
542
  delim->can_close = can_close;
517
543
  delim->inl_text = inl_text;
544
+ delim->position = subj->pos;
518
545
  delim->length = inl_text->as.literal.len;
519
546
  delim->previous = subj->last_delim;
520
547
  delim->next = NULL;
@@ -535,7 +562,6 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
535
562
  b->active = true;
536
563
  b->inl_text = inl_text;
537
564
  b->previous = subj->last_bracket;
538
- b->previous_delimiter = subj->last_delim;
539
565
  b->position = subj->pos;
540
566
  b->bracket_after = false;
541
567
  if (image) {
@@ -544,6 +570,9 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
544
570
  b->in_bracket_image0 = true;
545
571
  }
546
572
  subj->last_bracket = b;
573
+ if (!image) {
574
+ subj->no_link_openers = false;
575
+ }
547
576
  }
548
577
 
549
578
  // Assumes the subject has a c at the current position.
@@ -651,12 +680,13 @@ static cmark_syntax_extension *get_extension_for_special_char(cmark_parser *pars
651
680
  return NULL;
652
681
  }
653
682
 
654
- static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *stack_bottom) {
655
- delimiter *closer = subj->last_delim;
683
+ static void process_emphasis(cmark_parser *parser, subject *subj, bufsize_t stack_bottom) {
684
+ delimiter *candidate;
685
+ delimiter *closer = NULL;
656
686
  delimiter *opener;
657
687
  delimiter *old_closer;
658
688
  bool opener_found;
659
- delimiter *openers_bottom[3][128];
689
+ bufsize_t openers_bottom[3][128];
660
690
  int i;
661
691
 
662
692
  // initialize openers_bottom:
@@ -669,8 +699,10 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
669
699
  }
670
700
 
671
701
  // move back to first relevant delim.
672
- while (closer != NULL && closer->previous != stack_bottom) {
673
- closer = closer->previous;
702
+ candidate = subj->last_delim;
703
+ while (candidate != NULL && candidate->position >= stack_bottom) {
704
+ closer = candidate;
705
+ candidate = candidate->previous;
674
706
  }
675
707
 
676
708
  // now move forward, looking for closers, and handling each
@@ -680,8 +712,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
680
712
  // Now look backwards for first matching opener:
681
713
  opener = closer->previous;
682
714
  opener_found = false;
683
- while (opener != NULL && opener != stack_bottom &&
684
- opener != openers_bottom[closer->length % 3][closer->delim_char]) {
715
+ while (opener != NULL && opener->position >= stack_bottom &&
716
+ opener->position >= openers_bottom[closer->length % 3][closer->delim_char]) {
685
717
  if (opener->can_open && opener->delim_char == closer->delim_char) {
686
718
  // interior closer of size 2 can't match opener of size 1
687
719
  // or of size 1 can't match 2
@@ -707,27 +739,29 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
707
739
  } else {
708
740
  closer = closer->next;
709
741
  }
710
- } else if (closer->delim_char == '\'') {
742
+ } else if (closer->delim_char == '\'' || closer->delim_char == '"') {
711
743
  cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
712
- closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE);
713
- if (opener_found) {
714
- cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
715
- opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE);
744
+ if (closer->delim_char == '\'') {
745
+ closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE);
746
+ } else {
747
+ closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
716
748
  }
717
749
  closer = closer->next;
718
- } else if (closer->delim_char == '"') {
719
- cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
720
- closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
721
750
  if (opener_found) {
722
751
  cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
723
- opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE);
752
+ if (old_closer->delim_char == '\'') {
753
+ opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE);
754
+ } else {
755
+ opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE);
756
+ }
757
+ remove_delimiter(subj, opener);
758
+ remove_delimiter(subj, old_closer);
724
759
  }
725
- closer = closer->next;
726
760
  }
727
761
  if (!opener_found) {
728
762
  // set lower bound for future searches for openers
729
763
  openers_bottom[old_closer->length % 3][old_closer->delim_char] =
730
- old_closer->previous;
764
+ old_closer->position;
731
765
  if (!old_closer->can_open) {
732
766
  // we can remove a closer that can't be an
733
767
  // opener, once we've seen there's no
@@ -740,7 +774,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
740
774
  }
741
775
  }
742
776
  // free all delimiters in list until stack_bottom:
743
- while (subj->last_delim != NULL && subj->last_delim != stack_bottom) {
777
+ while (subj->last_delim != NULL &&
778
+ subj->last_delim->position >= stack_bottom) {
744
779
  remove_delimiter(subj, subj->last_delim);
745
780
  }
746
781
  }
@@ -779,7 +814,8 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
779
814
  tmp = opener_inl->next;
780
815
  while (tmp && tmp != closer_inl) {
781
816
  tmpnext = tmp->next;
782
- cmark_node_append_child(emph, tmp);
817
+ cmark_node_unlink(tmp);
818
+ append_child(emph, tmp);
783
819
  tmp = tmpnext;
784
820
  }
785
821
  cmark_node_insert_after(opener_inl, emph);
@@ -910,7 +946,63 @@ static cmark_node *handle_pointy_brace(subject *subj, int options) {
910
946
  }
911
947
 
912
948
  // finally, try to match an html tag
913
- matchlen = scan_html_tag(&subj->input, subj->pos);
949
+ if (subj->pos + 2 <= subj->input.len) {
950
+ int c = subj->input.data[subj->pos];
951
+ if (c == '!' && (subj->flags & FLAG_SKIP_HTML_COMMENT) == 0) {
952
+ c = subj->input.data[subj->pos+1];
953
+ if (c == '-' && subj->input.data[subj->pos+2] == '-') {
954
+ if (subj->input.data[subj->pos+3] == '>') {
955
+ matchlen = 4;
956
+ } else if (subj->input.data[subj->pos+3] == '-' &&
957
+ subj->input.data[subj->pos+4] == '>') {
958
+ matchlen = 5;
959
+ } else {
960
+ matchlen = scan_html_comment(&subj->input, subj->pos + 1);
961
+ if (matchlen > 0) {
962
+ matchlen += 1; // prefix "<"
963
+ } else { // no match through end of input: set a flag so
964
+ // we don't reparse looking for -->:
965
+ subj->flags |= FLAG_SKIP_HTML_COMMENT;
966
+ }
967
+ }
968
+ } else if (c == '[') {
969
+ if ((subj->flags & FLAG_SKIP_HTML_CDATA) == 0) {
970
+ matchlen = scan_html_cdata(&subj->input, subj->pos + 2);
971
+ if (matchlen > 0) {
972
+ // The regex doesn't require the final "]]>". But if we're not at
973
+ // the end of input, it must come after the match. Otherwise,
974
+ // disable subsequent scans to avoid quadratic behavior.
975
+ matchlen += 5; // prefix "![", suffix "]]>"
976
+ if (subj->pos + matchlen > subj->input.len) {
977
+ subj->flags |= FLAG_SKIP_HTML_CDATA;
978
+ matchlen = 0;
979
+ }
980
+ }
981
+ }
982
+ } else if ((subj->flags & FLAG_SKIP_HTML_DECLARATION) == 0) {
983
+ matchlen = scan_html_declaration(&subj->input, subj->pos + 1);
984
+ if (matchlen > 0) {
985
+ matchlen += 2; // prefix "!", suffix ">"
986
+ if (subj->pos + matchlen > subj->input.len) {
987
+ subj->flags |= FLAG_SKIP_HTML_DECLARATION;
988
+ matchlen = 0;
989
+ }
990
+ }
991
+ }
992
+ } else if (c == '?') {
993
+ if ((subj->flags & FLAG_SKIP_HTML_PI) == 0) {
994
+ // Note that we allow an empty match.
995
+ matchlen = scan_html_pi(&subj->input, subj->pos + 1);
996
+ matchlen += 3; // prefix "?", suffix "?>"
997
+ if (subj->pos + matchlen > subj->input.len) {
998
+ subj->flags |= FLAG_SKIP_HTML_PI;
999
+ matchlen = 0;
1000
+ }
1001
+ }
1002
+ } else {
1003
+ matchlen = scan_html_tag(&subj->input, subj->pos);
1004
+ }
1005
+ }
914
1006
  if (matchlen > 0) {
915
1007
  contents = cmark_chunk_dup(&subj->input, subj->pos - 1, matchlen + 1);
916
1008
  subj->pos += matchlen;
@@ -1076,16 +1168,16 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
1076
1168
  return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
1077
1169
  }
1078
1170
 
1079
- if (!opener->active) {
1171
+ // If we got here, we matched a potential link/image text.
1172
+ // Now we check to see if it's a link/image.
1173
+ is_image = opener->image;
1174
+
1175
+ if (!is_image && subj->no_link_openers) {
1080
1176
  // take delimiter off stack
1081
1177
  pop_bracket(subj);
1082
1178
  return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
1083
1179
  }
1084
1180
 
1085
- // If we got here, we matched a potential link/image text.
1086
- // Now we check to see if it's a link/image.
1087
- is_image = opener->image;
1088
-
1089
1181
  after_link_text_pos = subj->pos;
1090
1182
 
1091
1183
  // First, look for an inline link.
@@ -1204,7 +1296,7 @@ noMatch:
1204
1296
  // being replacing the opening '[' text node with a `^footnote-ref]` node.
1205
1297
  cmark_node_insert_before(opener->inl_text, fnref);
1206
1298
 
1207
- process_emphasis(parser, subj, opener->previous_delimiter);
1299
+ process_emphasis(parser, subj, opener->position);
1208
1300
  // sometimes, the footnote reference text gets parsed into multiple nodes
1209
1301
  // i.e. '[^example]' parsed into '[', '^exam', 'ple]'.
1210
1302
  // this happens for ex with the autolink extension. when the autolinker
@@ -1249,42 +1341,22 @@ match:
1249
1341
  tmp = opener->inl_text->next;
1250
1342
  while (tmp) {
1251
1343
  tmpnext = tmp->next;
1252
- cmark_node_append_child(inl, tmp);
1344
+ cmark_node_unlink(tmp);
1345
+ append_child(inl, tmp);
1253
1346
  tmp = tmpnext;
1254
1347
  }
1255
1348
 
1256
1349
  // Free the bracket [:
1257
1350
  cmark_node_free(opener->inl_text);
1258
1351
 
1259
- process_emphasis(parser, subj, opener->previous_delimiter);
1352
+ process_emphasis(parser, subj, opener->position);
1260
1353
  pop_bracket(subj);
1261
1354
 
1262
- // Now, if we have a link, we also want to deactivate earlier link
1263
- // delimiters. (This code can be removed if we decide to allow links
1355
+ // Now, if we have a link, we also want to deactivate links until
1356
+ // we get a new opener. (This code can be removed if we decide to allow links
1264
1357
  // inside links.)
1265
1358
  if (!is_image) {
1266
- opener = subj->last_bracket;
1267
- while (opener != NULL) {
1268
- if (!opener->image) {
1269
- if (!opener->active) {
1270
- break;
1271
- } else {
1272
- opener->active = false;
1273
- }
1274
- }
1275
- opener = opener->previous;
1276
- }
1277
- bool in_bracket_image1 = false;
1278
- if (opener) {
1279
- in_bracket_image1 = opener->in_bracket_image1;
1280
- }
1281
- bracket *opener2 = subj->last_bracket;
1282
- while (opener2 != opener) {
1283
- if (opener2->image) {
1284
- opener2->in_bracket_image1 = in_bracket_image1;
1285
- }
1286
- opener2 = opener2->previous;
1287
- }
1359
+ subj->no_link_openers = true;
1288
1360
  }
1289
1361
 
1290
1362
  return NULL;
@@ -1463,7 +1535,7 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
1463
1535
  new_inl = make_str(subj, startpos, endpos - 1, contents);
1464
1536
  }
1465
1537
  if (new_inl != NULL) {
1466
- cmark_node_append_child(parent, new_inl);
1538
+ append_child(parent, new_inl);
1467
1539
  }
1468
1540
 
1469
1541
  return 1;
@@ -1482,7 +1554,7 @@ void cmark_parse_inlines(cmark_parser *parser,
1482
1554
  while (!is_eof(&subj) && parse_inline(parser, &subj, parent, options))
1483
1555
  ;
1484
1556
 
1485
- process_emphasis(parser, &subj, NULL);
1557
+ process_emphasis(parser, &subj, 0);
1486
1558
  // free bracket and delim stack
1487
1559
  while (subj.last_delim) {
1488
1560
  remove_delimiter(&subj, subj.last_delim);
@@ -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
 
@@ -51,7 +51,7 @@ refsearch(const void *label, const void *p2) {
51
51
  }
52
52
 
53
53
  static void sort_map(cmark_map *map) {
54
- unsigned int i = 0, last = 0, size = map->size;
54
+ size_t i = 0, last = 0, size = map->size;
55
55
  cmark_map_entry *r = map->refs, **sorted = NULL;
56
56
 
57
57
  sorted = (cmark_map_entry **)map->mem->calloc(size, sizeof(cmark_map_entry *));
@@ -73,6 +73,7 @@ static void sort_map(cmark_map *map) {
73
73
 
74
74
  cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label) {
75
75
  cmark_map_entry **ref = NULL;
76
+ cmark_map_entry *r = NULL;
76
77
  unsigned char *norm;
77
78
 
78
79
  if (label->len < 1 || label->len > MAX_LINK_LABEL_LENGTH)
@@ -91,10 +92,15 @@ cmark_map_entry *cmark_map_lookup(cmark_map *map, cmark_chunk *label) {
91
92
  ref = (cmark_map_entry **)bsearch(norm, map->sorted, map->size, sizeof(cmark_map_entry *), refsearch);
92
93
  map->mem->free(norm);
93
94
 
94
- if (!ref)
95
- return NULL;
95
+ if (ref != NULL) {
96
+ r = ref[0];
97
+ /* Check for expansion limit */
98
+ if (r->size > map->max_ref_size - map->ref_size)
99
+ return NULL;
100
+ map->ref_size += r->size;
101
+ }
96
102
 
97
- return ref[0];
103
+ return r;
98
104
  }
99
105
 
100
106
  void cmark_map_free(cmark_map *map) {
@@ -118,5 +124,6 @@ cmark_map *cmark_map_new(cmark_mem *mem, cmark_map_free_f free) {
118
124
  cmark_map *map = (cmark_map *)mem->calloc(1, sizeof(cmark_map));
119
125
  map->mem = mem;
120
126
  map->free = free;
127
+ map->max_ref_size = UINT_MAX;
121
128
  return map;
122
129
  }