commonmarker 0.23.6 → 0.23.8
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 +4 -4
- data/ext/commonmarker/arena.c +9 -8
- data/ext/commonmarker/autolink.c +207 -155
- data/ext/commonmarker/blocks.c +14 -0
- data/ext/commonmarker/cmark-gfm-core-extensions.h +11 -11
- data/ext/commonmarker/cmark-gfm-extension_api.h +1 -0
- data/ext/commonmarker/cmark-gfm.h +7 -2
- data/ext/commonmarker/cmark.c +3 -3
- data/ext/commonmarker/commonmarker.c +1 -0
- data/ext/commonmarker/html.c +16 -2
- data/ext/commonmarker/inlines.c +130 -58
- data/ext/commonmarker/map.c +11 -4
- data/ext/commonmarker/map.h +5 -2
- data/ext/commonmarker/node.c +30 -0
- data/ext/commonmarker/node.h +27 -1
- data/ext/commonmarker/parser.h +1 -0
- data/ext/commonmarker/references.c +1 -0
- data/ext/commonmarker/scanners.c +13916 -10368
- data/ext/commonmarker/scanners.h +8 -0
- data/ext/commonmarker/strikethrough.c +1 -1
- data/ext/commonmarker/table.c +59 -35
- data/lib/commonmarker/config.rb +15 -13
- data/lib/commonmarker/renderer.rb +1 -1
- data/lib/commonmarker/version.rb +1 -1
- data/lib/commonmarker.rb +27 -25
- metadata +7 -7
data/ext/commonmarker/html.c
CHANGED
@@ -63,10 +63,16 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
|
|
63
63
|
if (renderer->written_footnote_ix >= renderer->footnote_ix)
|
64
64
|
return false;
|
65
65
|
renderer->written_footnote_ix = renderer->footnote_ix;
|
66
|
+
char m[32];
|
67
|
+
snprintf(m, sizeof(m), "%d", renderer->written_footnote_ix);
|
66
68
|
|
67
69
|
cmark_strbuf_puts(html, "<a href=\"#fnref-");
|
68
70
|
houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
|
69
|
-
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref
|
71
|
+
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
|
72
|
+
cmark_strbuf_puts(html, m);
|
73
|
+
cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
|
74
|
+
cmark_strbuf_puts(html, m);
|
75
|
+
cmark_strbuf_puts(html, "\">↩</a>");
|
70
76
|
|
71
77
|
if (node->footnote.def_count > 1)
|
72
78
|
{
|
@@ -78,7 +84,15 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
|
|
78
84
|
houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
|
79
85
|
cmark_strbuf_puts(html, "-");
|
80
86
|
cmark_strbuf_puts(html, n);
|
81
|
-
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref
|
87
|
+
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
|
88
|
+
cmark_strbuf_puts(html, m);
|
89
|
+
cmark_strbuf_puts(html, "-");
|
90
|
+
cmark_strbuf_puts(html, n);
|
91
|
+
cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
|
92
|
+
cmark_strbuf_puts(html, m);
|
93
|
+
cmark_strbuf_puts(html, "-");
|
94
|
+
cmark_strbuf_puts(html, n);
|
95
|
+
cmark_strbuf_puts(html, "\">↩<sup class=\"footnote-ref\">");
|
82
96
|
cmark_strbuf_puts(html, n);
|
83
97
|
cmark_strbuf_puts(html, "</sup></a>");
|
84
98
|
}
|
data/ext/commonmarker/inlines.c
CHANGED
@@ -35,7 +35,6 @@ static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99";
|
|
35
35
|
|
36
36
|
typedef struct bracket {
|
37
37
|
struct bracket *previous;
|
38
|
-
struct delimiter *previous_delimiter;
|
39
38
|
cmark_node *inl_text;
|
40
39
|
bufsize_t position;
|
41
40
|
bool image;
|
@@ -45,9 +44,15 @@ typedef struct bracket {
|
|
45
44
|
bool in_bracket_image1;
|
46
45
|
} bracket;
|
47
46
|
|
47
|
+
#define FLAG_SKIP_HTML_CDATA (1u << 0)
|
48
|
+
#define FLAG_SKIP_HTML_DECLARATION (1u << 1)
|
49
|
+
#define FLAG_SKIP_HTML_PI (1u << 2)
|
50
|
+
#define FLAG_SKIP_HTML_COMMENT (1u << 3)
|
51
|
+
|
48
52
|
typedef struct subject{
|
49
53
|
cmark_mem *mem;
|
50
54
|
cmark_chunk input;
|
55
|
+
unsigned flags;
|
51
56
|
int line;
|
52
57
|
bufsize_t pos;
|
53
58
|
int block_offset;
|
@@ -57,6 +62,7 @@ typedef struct subject{
|
|
57
62
|
bracket *last_bracket;
|
58
63
|
bufsize_t backticks[MAXBACKTICKS + 1];
|
59
64
|
bool scanned_for_backticks;
|
65
|
+
bool no_link_openers;
|
60
66
|
} subject;
|
61
67
|
|
62
68
|
// Extensions may populate this.
|
@@ -111,6 +117,24 @@ static cmark_node *make_str_with_entities(subject *subj,
|
|
111
117
|
}
|
112
118
|
}
|
113
119
|
|
120
|
+
// Like cmark_node_append_child but without costly sanity checks.
|
121
|
+
// Assumes that child was newly created.
|
122
|
+
static void append_child(cmark_node *node, cmark_node *child) {
|
123
|
+
cmark_node *old_last_child = node->last_child;
|
124
|
+
|
125
|
+
child->next = NULL;
|
126
|
+
child->prev = old_last_child;
|
127
|
+
child->parent = node;
|
128
|
+
node->last_child = child;
|
129
|
+
|
130
|
+
if (old_last_child) {
|
131
|
+
old_last_child->next = child;
|
132
|
+
} else {
|
133
|
+
// Also set first_child if node previously had no children.
|
134
|
+
node->first_child = child;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
114
138
|
// Duplicate a chunk by creating a copy of the buffer not by reusing the
|
115
139
|
// buffer like cmark_chunk_dup does.
|
116
140
|
static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
|
@@ -154,7 +178,7 @@ static CMARK_INLINE cmark_node *make_autolink(subject *subj,
|
|
154
178
|
link->start_line = link->end_line = subj->line;
|
155
179
|
link->start_column = start_column + 1;
|
156
180
|
link->end_column = end_column + 1;
|
157
|
-
|
181
|
+
append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
|
158
182
|
return link;
|
159
183
|
}
|
160
184
|
|
@@ -163,6 +187,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
|
|
163
187
|
int i;
|
164
188
|
e->mem = mem;
|
165
189
|
e->input = *chunk;
|
190
|
+
e->flags = 0;
|
166
191
|
e->line = line_number;
|
167
192
|
e->pos = 0;
|
168
193
|
e->block_offset = block_offset;
|
@@ -174,6 +199,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
|
|
174
199
|
e->backticks[i] = 0;
|
175
200
|
}
|
176
201
|
e->scanned_for_backticks = false;
|
202
|
+
e->no_link_openers = true;
|
177
203
|
}
|
178
204
|
|
179
205
|
static CMARK_INLINE int isbacktick(int c) { return (c == '`'); }
|
@@ -505,6 +531,7 @@ static void push_delimiter(subject *subj, unsigned char c, bool can_open,
|
|
505
531
|
delim->can_open = can_open;
|
506
532
|
delim->can_close = can_close;
|
507
533
|
delim->inl_text = inl_text;
|
534
|
+
delim->position = subj->pos;
|
508
535
|
delim->length = inl_text->as.literal.len;
|
509
536
|
delim->previous = subj->last_delim;
|
510
537
|
delim->next = NULL;
|
@@ -525,7 +552,6 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
|
|
525
552
|
b->active = true;
|
526
553
|
b->inl_text = inl_text;
|
527
554
|
b->previous = subj->last_bracket;
|
528
|
-
b->previous_delimiter = subj->last_delim;
|
529
555
|
b->position = subj->pos;
|
530
556
|
b->bracket_after = false;
|
531
557
|
if (image) {
|
@@ -534,6 +560,9 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
|
|
534
560
|
b->in_bracket_image0 = true;
|
535
561
|
}
|
536
562
|
subj->last_bracket = b;
|
563
|
+
if (!image) {
|
564
|
+
subj->no_link_openers = false;
|
565
|
+
}
|
537
566
|
}
|
538
567
|
|
539
568
|
// Assumes the subject has a c at the current position.
|
@@ -640,12 +669,13 @@ static cmark_syntax_extension *get_extension_for_special_char(cmark_parser *pars
|
|
640
669
|
return NULL;
|
641
670
|
}
|
642
671
|
|
643
|
-
static void process_emphasis(cmark_parser *parser, subject *subj,
|
644
|
-
delimiter *
|
672
|
+
static void process_emphasis(cmark_parser *parser, subject *subj, bufsize_t stack_bottom) {
|
673
|
+
delimiter *candidate;
|
674
|
+
delimiter *closer = NULL;
|
645
675
|
delimiter *opener;
|
646
676
|
delimiter *old_closer;
|
647
677
|
bool opener_found;
|
648
|
-
|
678
|
+
bufsize_t openers_bottom[3][128];
|
649
679
|
int i;
|
650
680
|
|
651
681
|
// initialize openers_bottom:
|
@@ -658,8 +688,10 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
658
688
|
}
|
659
689
|
|
660
690
|
// move back to first relevant delim.
|
661
|
-
|
662
|
-
|
691
|
+
candidate = subj->last_delim;
|
692
|
+
while (candidate != NULL && candidate->position >= stack_bottom) {
|
693
|
+
closer = candidate;
|
694
|
+
candidate = candidate->previous;
|
663
695
|
}
|
664
696
|
|
665
697
|
// now move forward, looking for closers, and handling each
|
@@ -669,8 +701,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
669
701
|
// Now look backwards for first matching opener:
|
670
702
|
opener = closer->previous;
|
671
703
|
opener_found = false;
|
672
|
-
while (opener != NULL && opener
|
673
|
-
opener
|
704
|
+
while (opener != NULL && opener->position >= stack_bottom &&
|
705
|
+
opener->position >= openers_bottom[closer->length % 3][closer->delim_char]) {
|
674
706
|
if (opener->can_open && opener->delim_char == closer->delim_char) {
|
675
707
|
// interior closer of size 2 can't match opener of size 1
|
676
708
|
// or of size 1 can't match 2
|
@@ -696,27 +728,29 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
696
728
|
} else {
|
697
729
|
closer = closer->next;
|
698
730
|
}
|
699
|
-
} else if (closer->delim_char == '\'') {
|
731
|
+
} else if (closer->delim_char == '\'' || closer->delim_char == '"') {
|
700
732
|
cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
|
701
|
-
closer->
|
702
|
-
|
703
|
-
|
704
|
-
|
733
|
+
if (closer->delim_char == '\'') {
|
734
|
+
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE);
|
735
|
+
} else {
|
736
|
+
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
|
705
737
|
}
|
706
738
|
closer = closer->next;
|
707
|
-
} else if (closer->delim_char == '"') {
|
708
|
-
cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
|
709
|
-
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
|
710
739
|
if (opener_found) {
|
711
740
|
cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
|
712
|
-
|
741
|
+
if (old_closer->delim_char == '\'') {
|
742
|
+
opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE);
|
743
|
+
} else {
|
744
|
+
opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE);
|
745
|
+
}
|
746
|
+
remove_delimiter(subj, opener);
|
747
|
+
remove_delimiter(subj, old_closer);
|
713
748
|
}
|
714
|
-
closer = closer->next;
|
715
749
|
}
|
716
750
|
if (!opener_found) {
|
717
751
|
// set lower bound for future searches for openers
|
718
752
|
openers_bottom[old_closer->length % 3][old_closer->delim_char] =
|
719
|
-
old_closer->
|
753
|
+
old_closer->position;
|
720
754
|
if (!old_closer->can_open) {
|
721
755
|
// we can remove a closer that can't be an
|
722
756
|
// opener, once we've seen there's no
|
@@ -729,7 +763,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
729
763
|
}
|
730
764
|
}
|
731
765
|
// free all delimiters in list until stack_bottom:
|
732
|
-
while (subj->last_delim != NULL &&
|
766
|
+
while (subj->last_delim != NULL &&
|
767
|
+
subj->last_delim->position >= stack_bottom) {
|
733
768
|
remove_delimiter(subj, subj->last_delim);
|
734
769
|
}
|
735
770
|
}
|
@@ -768,7 +803,8 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
|
|
768
803
|
tmp = opener_inl->next;
|
769
804
|
while (tmp && tmp != closer_inl) {
|
770
805
|
tmpnext = tmp->next;
|
771
|
-
|
806
|
+
cmark_node_unlink(tmp);
|
807
|
+
append_child(emph, tmp);
|
772
808
|
tmp = tmpnext;
|
773
809
|
}
|
774
810
|
cmark_node_insert_after(opener_inl, emph);
|
@@ -899,7 +935,63 @@ static cmark_node *handle_pointy_brace(subject *subj, int options) {
|
|
899
935
|
}
|
900
936
|
|
901
937
|
// finally, try to match an html tag
|
902
|
-
|
938
|
+
if (subj->pos + 2 <= subj->input.len) {
|
939
|
+
int c = subj->input.data[subj->pos];
|
940
|
+
if (c == '!' && (subj->flags & FLAG_SKIP_HTML_COMMENT) == 0) {
|
941
|
+
c = subj->input.data[subj->pos+1];
|
942
|
+
if (c == '-' && subj->input.data[subj->pos+2] == '-') {
|
943
|
+
if (subj->input.data[subj->pos+3] == '>') {
|
944
|
+
matchlen = 4;
|
945
|
+
} else if (subj->input.data[subj->pos+3] == '-' &&
|
946
|
+
subj->input.data[subj->pos+4] == '>') {
|
947
|
+
matchlen = 5;
|
948
|
+
} else {
|
949
|
+
matchlen = scan_html_comment(&subj->input, subj->pos + 1);
|
950
|
+
if (matchlen > 0) {
|
951
|
+
matchlen += 1; // prefix "<"
|
952
|
+
} else { // no match through end of input: set a flag so
|
953
|
+
// we don't reparse looking for -->:
|
954
|
+
subj->flags |= FLAG_SKIP_HTML_COMMENT;
|
955
|
+
}
|
956
|
+
}
|
957
|
+
} else if (c == '[') {
|
958
|
+
if ((subj->flags & FLAG_SKIP_HTML_CDATA) == 0) {
|
959
|
+
matchlen = scan_html_cdata(&subj->input, subj->pos + 2);
|
960
|
+
if (matchlen > 0) {
|
961
|
+
// The regex doesn't require the final "]]>". But if we're not at
|
962
|
+
// the end of input, it must come after the match. Otherwise,
|
963
|
+
// disable subsequent scans to avoid quadratic behavior.
|
964
|
+
matchlen += 5; // prefix "![", suffix "]]>"
|
965
|
+
if (subj->pos + matchlen > subj->input.len) {
|
966
|
+
subj->flags |= FLAG_SKIP_HTML_CDATA;
|
967
|
+
matchlen = 0;
|
968
|
+
}
|
969
|
+
}
|
970
|
+
}
|
971
|
+
} else if ((subj->flags & FLAG_SKIP_HTML_DECLARATION) == 0) {
|
972
|
+
matchlen = scan_html_declaration(&subj->input, subj->pos + 1);
|
973
|
+
if (matchlen > 0) {
|
974
|
+
matchlen += 2; // prefix "!", suffix ">"
|
975
|
+
if (subj->pos + matchlen > subj->input.len) {
|
976
|
+
subj->flags |= FLAG_SKIP_HTML_DECLARATION;
|
977
|
+
matchlen = 0;
|
978
|
+
}
|
979
|
+
}
|
980
|
+
}
|
981
|
+
} else if (c == '?') {
|
982
|
+
if ((subj->flags & FLAG_SKIP_HTML_PI) == 0) {
|
983
|
+
// Note that we allow an empty match.
|
984
|
+
matchlen = scan_html_pi(&subj->input, subj->pos + 1);
|
985
|
+
matchlen += 3; // prefix "?", suffix "?>"
|
986
|
+
if (subj->pos + matchlen > subj->input.len) {
|
987
|
+
subj->flags |= FLAG_SKIP_HTML_PI;
|
988
|
+
matchlen = 0;
|
989
|
+
}
|
990
|
+
}
|
991
|
+
} else {
|
992
|
+
matchlen = scan_html_tag(&subj->input, subj->pos);
|
993
|
+
}
|
994
|
+
}
|
903
995
|
if (matchlen > 0) {
|
904
996
|
contents = cmark_chunk_dup(&subj->input, subj->pos - 1, matchlen + 1);
|
905
997
|
subj->pos += matchlen;
|
@@ -1065,16 +1157,16 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
|
|
1065
1157
|
return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
|
1066
1158
|
}
|
1067
1159
|
|
1068
|
-
|
1160
|
+
// If we got here, we matched a potential link/image text.
|
1161
|
+
// Now we check to see if it's a link/image.
|
1162
|
+
is_image = opener->image;
|
1163
|
+
|
1164
|
+
if (!is_image && subj->no_link_openers) {
|
1069
1165
|
// take delimiter off stack
|
1070
1166
|
pop_bracket(subj);
|
1071
1167
|
return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
|
1072
1168
|
}
|
1073
1169
|
|
1074
|
-
// If we got here, we matched a potential link/image text.
|
1075
|
-
// Now we check to see if it's a link/image.
|
1076
|
-
is_image = opener->image;
|
1077
|
-
|
1078
1170
|
after_link_text_pos = subj->pos;
|
1079
1171
|
|
1080
1172
|
// First, look for an inline link.
|
@@ -1193,7 +1285,7 @@ noMatch:
|
|
1193
1285
|
// being replacing the opening '[' text node with a `^footnote-ref]` node.
|
1194
1286
|
cmark_node_insert_before(opener->inl_text, fnref);
|
1195
1287
|
|
1196
|
-
process_emphasis(parser, subj, opener->
|
1288
|
+
process_emphasis(parser, subj, opener->position);
|
1197
1289
|
// sometimes, the footnote reference text gets parsed into multiple nodes
|
1198
1290
|
// i.e. '[^example]' parsed into '[', '^exam', 'ple]'.
|
1199
1291
|
// this happens for ex with the autolink extension. when the autolinker
|
@@ -1238,42 +1330,22 @@ match:
|
|
1238
1330
|
tmp = opener->inl_text->next;
|
1239
1331
|
while (tmp) {
|
1240
1332
|
tmpnext = tmp->next;
|
1241
|
-
|
1333
|
+
cmark_node_unlink(tmp);
|
1334
|
+
append_child(inl, tmp);
|
1242
1335
|
tmp = tmpnext;
|
1243
1336
|
}
|
1244
1337
|
|
1245
1338
|
// Free the bracket [:
|
1246
1339
|
cmark_node_free(opener->inl_text);
|
1247
1340
|
|
1248
|
-
process_emphasis(parser, subj, opener->
|
1341
|
+
process_emphasis(parser, subj, opener->position);
|
1249
1342
|
pop_bracket(subj);
|
1250
1343
|
|
1251
|
-
// Now, if we have a link, we also want to deactivate
|
1252
|
-
//
|
1344
|
+
// Now, if we have a link, we also want to deactivate links until
|
1345
|
+
// we get a new opener. (This code can be removed if we decide to allow links
|
1253
1346
|
// inside links.)
|
1254
1347
|
if (!is_image) {
|
1255
|
-
|
1256
|
-
while (opener != NULL) {
|
1257
|
-
if (!opener->image) {
|
1258
|
-
if (!opener->active) {
|
1259
|
-
break;
|
1260
|
-
} else {
|
1261
|
-
opener->active = false;
|
1262
|
-
}
|
1263
|
-
}
|
1264
|
-
opener = opener->previous;
|
1265
|
-
}
|
1266
|
-
bool in_bracket_image1 = false;
|
1267
|
-
if (opener) {
|
1268
|
-
in_bracket_image1 = opener->in_bracket_image1;
|
1269
|
-
}
|
1270
|
-
bracket *opener2 = subj->last_bracket;
|
1271
|
-
while (opener2 != opener) {
|
1272
|
-
if (opener2->image) {
|
1273
|
-
opener2->in_bracket_image1 = in_bracket_image1;
|
1274
|
-
}
|
1275
|
-
opener2 = opener2->previous;
|
1276
|
-
}
|
1348
|
+
subj->no_link_openers = true;
|
1277
1349
|
}
|
1278
1350
|
|
1279
1351
|
return NULL;
|
@@ -1451,7 +1523,7 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
|
1451
1523
|
new_inl = make_str(subj, startpos, endpos - 1, contents);
|
1452
1524
|
}
|
1453
1525
|
if (new_inl != NULL) {
|
1454
|
-
|
1526
|
+
append_child(parent, new_inl);
|
1455
1527
|
}
|
1456
1528
|
|
1457
1529
|
return 1;
|
@@ -1470,7 +1542,7 @@ void cmark_parse_inlines(cmark_parser *parser,
|
|
1470
1542
|
while (!is_eof(&subj) && parse_inline(parser, &subj, parent, options))
|
1471
1543
|
;
|
1472
1544
|
|
1473
|
-
process_emphasis(parser, &subj,
|
1545
|
+
process_emphasis(parser, &subj, 0);
|
1474
1546
|
// free bracket and delim stack
|
1475
1547
|
while (subj.last_delim) {
|
1476
1548
|
remove_delimiter(&subj, subj.last_delim);
|
data/ext/commonmarker/map.c
CHANGED
@@ -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
|
-
|
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 (
|
95
|
-
|
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
|
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
|
}
|
data/ext/commonmarker/map.h
CHANGED
@@ -10,7 +10,8 @@ extern "C" {
|
|
10
10
|
struct cmark_map_entry {
|
11
11
|
struct cmark_map_entry *next;
|
12
12
|
unsigned char *label;
|
13
|
-
|
13
|
+
size_t age;
|
14
|
+
size_t size;
|
14
15
|
};
|
15
16
|
|
16
17
|
typedef struct cmark_map_entry cmark_map_entry;
|
@@ -23,7 +24,9 @@ struct cmark_map {
|
|
23
24
|
cmark_mem *mem;
|
24
25
|
cmark_map_entry *refs;
|
25
26
|
cmark_map_entry **sorted;
|
26
|
-
|
27
|
+
size_t size;
|
28
|
+
size_t ref_size;
|
29
|
+
size_t max_ref_size;
|
27
30
|
cmark_map_free_f free;
|
28
31
|
};
|
29
32
|
|
data/ext/commonmarker/node.c
CHANGED
@@ -9,6 +9,28 @@ static void S_node_unlink(cmark_node *node);
|
|
9
9
|
|
10
10
|
#define NODE_MEM(node) cmark_node_mem(node)
|
11
11
|
|
12
|
+
void cmark_register_node_flag(cmark_node_internal_flags *flags) {
|
13
|
+
static cmark_node_internal_flags nextflag = CMARK_NODE__REGISTER_FIRST;
|
14
|
+
|
15
|
+
// flags should be a pointer to a global variable and this function
|
16
|
+
// should only be called once to initialize its value.
|
17
|
+
if (*flags) {
|
18
|
+
fprintf(stderr, "flag initialization error in cmark_register_node_flag\n");
|
19
|
+
abort();
|
20
|
+
}
|
21
|
+
|
22
|
+
// Check that we haven't run out of bits.
|
23
|
+
if (nextflag == 0) {
|
24
|
+
fprintf(stderr, "too many flags in cmark_register_node_flag\n");
|
25
|
+
abort();
|
26
|
+
}
|
27
|
+
|
28
|
+
*flags = nextflag;
|
29
|
+
nextflag <<= 1;
|
30
|
+
}
|
31
|
+
|
32
|
+
void cmark_init_standard_node_flags() {}
|
33
|
+
|
12
34
|
bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
|
13
35
|
if (child_type == CMARK_NODE_DOCUMENT) {
|
14
36
|
return false;
|
@@ -301,6 +323,14 @@ cmark_node *cmark_node_last_child(cmark_node *node) {
|
|
301
323
|
}
|
302
324
|
}
|
303
325
|
|
326
|
+
cmark_node *cmark_node_parent_footnote_def(cmark_node *node) {
|
327
|
+
if (node == NULL) {
|
328
|
+
return NULL;
|
329
|
+
} else {
|
330
|
+
return node->parent_footnote_def;
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
304
334
|
void *cmark_node_get_user_data(cmark_node *node) {
|
305
335
|
if (node == NULL) {
|
306
336
|
return NULL;
|
data/ext/commonmarker/node.h
CHANGED
@@ -52,8 +52,14 @@ enum cmark_node__internal_flags {
|
|
52
52
|
CMARK_NODE__OPEN = (1 << 0),
|
53
53
|
CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
|
54
54
|
CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
|
55
|
+
|
56
|
+
// Extensions can register custom flags by calling `cmark_register_node_flag`.
|
57
|
+
// This is the starting value for the custom flags.
|
58
|
+
CMARK_NODE__REGISTER_FIRST = (1 << 3),
|
55
59
|
};
|
56
60
|
|
61
|
+
typedef uint16_t cmark_node_internal_flags;
|
62
|
+
|
57
63
|
struct cmark_node {
|
58
64
|
cmark_strbuf content;
|
59
65
|
|
@@ -72,7 +78,7 @@ struct cmark_node {
|
|
72
78
|
int end_column;
|
73
79
|
int internal_offset;
|
74
80
|
uint16_t type;
|
75
|
-
|
81
|
+
cmark_node_internal_flags flags;
|
76
82
|
|
77
83
|
cmark_syntax_extension *extension;
|
78
84
|
|
@@ -95,6 +101,26 @@ struct cmark_node {
|
|
95
101
|
} as;
|
96
102
|
};
|
97
103
|
|
104
|
+
/**
|
105
|
+
* Syntax extensions can use this function to register a custom node
|
106
|
+
* flag. The flags are stored in the `flags` field of the `cmark_node`
|
107
|
+
* struct. The `flags` parameter should be the address of a global variable
|
108
|
+
* which will store the flag value.
|
109
|
+
*/
|
110
|
+
CMARK_GFM_EXPORT
|
111
|
+
void cmark_register_node_flag(cmark_node_internal_flags *flags);
|
112
|
+
|
113
|
+
/**
|
114
|
+
* DEPRECATED.
|
115
|
+
*
|
116
|
+
* This function was added in cmark-gfm version 0.29.0.gfm.7, and was
|
117
|
+
* required to be called at program start time, which caused
|
118
|
+
* backwards-compatibility issues in applications that use cmark-gfm as a
|
119
|
+
* library. It is now a no-op.
|
120
|
+
*/
|
121
|
+
CMARK_GFM_EXPORT
|
122
|
+
void cmark_init_standard_node_flags();
|
123
|
+
|
98
124
|
static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
|
99
125
|
return node->content.mem;
|
100
126
|
}
|
data/ext/commonmarker/parser.h
CHANGED
@@ -46,6 +46,7 @@ struct cmark_parser {
|
|
46
46
|
/* Options set by the user, see the Options section in cmark.h */
|
47
47
|
int options;
|
48
48
|
bool last_buffer_ended_with_cr;
|
49
|
+
size_t total_size;
|
49
50
|
cmark_llist *syntax_extensions;
|
50
51
|
cmark_llist *inline_syntax_extensions;
|
51
52
|
cmark_ispunct_func backslash_ispunct;
|
@@ -32,6 +32,7 @@ void cmark_reference_create(cmark_map *map, cmark_chunk *label,
|
|
32
32
|
ref->title = cmark_clean_title(map->mem, title);
|
33
33
|
ref->entry.age = map->size;
|
34
34
|
ref->entry.next = map->refs;
|
35
|
+
ref->entry.size = ref->url.len + ref->title.len;
|
35
36
|
|
36
37
|
map->refs = (cmark_map_entry *)ref;
|
37
38
|
map->size++;
|