markly 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/conduct.md +133 -0
- data/ext/markly/arena.c +9 -8
- data/ext/markly/autolink.c +217 -134
- data/ext/markly/blocks.c +27 -2
- data/ext/markly/cmark-gfm-core-extensions.h +11 -11
- data/ext/markly/cmark-gfm-extension_api.h +1 -0
- data/ext/markly/cmark-gfm.h +18 -2
- data/ext/markly/cmark.c +3 -3
- data/ext/markly/commonmark.c +19 -34
- data/ext/markly/extconf.rb +8 -1
- data/ext/markly/html.c +22 -6
- data/ext/markly/inlines.c +148 -51
- data/ext/markly/latex.c +6 -4
- data/ext/markly/man.c +7 -11
- data/ext/markly/map.c +11 -4
- data/ext/markly/map.h +5 -2
- data/ext/markly/markly.c +582 -586
- data/ext/markly/markly.h +1 -1
- data/ext/markly/node.c +76 -10
- data/ext/markly/node.h +42 -1
- data/ext/markly/parser.h +1 -0
- data/ext/markly/plaintext.c +12 -29
- data/ext/markly/references.c +1 -0
- data/ext/markly/render.c +15 -7
- data/ext/markly/scanners.c +13916 -10380
- data/ext/markly/scanners.h +8 -0
- data/ext/markly/scanners.re +47 -8
- data/ext/markly/strikethrough.c +1 -1
- data/ext/markly/table.c +81 -31
- data/ext/markly/xml.c +2 -1
- data/lib/markly/flags.rb +16 -0
- data/lib/markly/node/inspect.rb +59 -53
- data/lib/markly/node.rb +125 -58
- data/lib/markly/renderer/generic.rb +129 -124
- data/lib/markly/renderer/html.rb +294 -275
- data/lib/markly/version.rb +7 -1
- data/lib/markly.rb +36 -30
- data/license.md +39 -0
- data/readme.md +36 -0
- data.tar.gz.sig +0 -0
- metadata +61 -29
- metadata.gz.sig +0 -0
- data/bin/markly +0 -94
- data/lib/markly/markly.bundle +0 -0
data/ext/markly/inlines.c
CHANGED
@@ -35,17 +35,24 @@ 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;
|
42
41
|
bool active;
|
43
42
|
bool bracket_after;
|
43
|
+
bool in_bracket_image0;
|
44
|
+
bool in_bracket_image1;
|
44
45
|
} bracket;
|
45
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
|
+
|
46
52
|
typedef struct subject{
|
47
53
|
cmark_mem *mem;
|
48
54
|
cmark_chunk input;
|
55
|
+
unsigned flags;
|
49
56
|
int line;
|
50
57
|
bufsize_t pos;
|
51
58
|
int block_offset;
|
@@ -55,6 +62,7 @@ typedef struct subject{
|
|
55
62
|
bracket *last_bracket;
|
56
63
|
bufsize_t backticks[MAXBACKTICKS + 1];
|
57
64
|
bool scanned_for_backticks;
|
65
|
+
bool no_link_openers;
|
58
66
|
} subject;
|
59
67
|
|
60
68
|
// Extensions may populate this.
|
@@ -109,6 +117,24 @@ static cmark_node *make_str_with_entities(subject *subj,
|
|
109
117
|
}
|
110
118
|
}
|
111
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
|
+
|
112
138
|
// Duplicate a chunk by creating a copy of the buffer not by reusing the
|
113
139
|
// buffer like cmark_chunk_dup does.
|
114
140
|
static cmark_chunk chunk_clone(cmark_mem *mem, cmark_chunk *src) {
|
@@ -152,7 +178,7 @@ static CMARK_INLINE cmark_node *make_autolink(subject *subj,
|
|
152
178
|
link->start_line = link->end_line = subj->line;
|
153
179
|
link->start_column = start_column + 1;
|
154
180
|
link->end_column = end_column + 1;
|
155
|
-
|
181
|
+
append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
|
156
182
|
return link;
|
157
183
|
}
|
158
184
|
|
@@ -161,6 +187,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
|
|
161
187
|
int i;
|
162
188
|
e->mem = mem;
|
163
189
|
e->input = *chunk;
|
190
|
+
e->flags = 0;
|
164
191
|
e->line = line_number;
|
165
192
|
e->pos = 0;
|
166
193
|
e->block_offset = block_offset;
|
@@ -172,6 +199,7 @@ static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset,
|
|
172
199
|
e->backticks[i] = 0;
|
173
200
|
}
|
174
201
|
e->scanned_for_backticks = false;
|
202
|
+
e->no_link_openers = true;
|
175
203
|
}
|
176
204
|
|
177
205
|
static CMARK_INLINE int isbacktick(int c) { return (c == '`'); }
|
@@ -503,6 +531,7 @@ static void push_delimiter(subject *subj, unsigned char c, bool can_open,
|
|
503
531
|
delim->can_open = can_open;
|
504
532
|
delim->can_close = can_close;
|
505
533
|
delim->inl_text = inl_text;
|
534
|
+
delim->position = subj->pos;
|
506
535
|
delim->length = inl_text->as.literal.len;
|
507
536
|
delim->previous = subj->last_delim;
|
508
537
|
delim->next = NULL;
|
@@ -516,15 +545,24 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
|
|
516
545
|
bracket *b = (bracket *)subj->mem->calloc(1, sizeof(bracket));
|
517
546
|
if (subj->last_bracket != NULL) {
|
518
547
|
subj->last_bracket->bracket_after = true;
|
548
|
+
b->in_bracket_image0 = subj->last_bracket->in_bracket_image0;
|
549
|
+
b->in_bracket_image1 = subj->last_bracket->in_bracket_image1;
|
519
550
|
}
|
520
551
|
b->image = image;
|
521
552
|
b->active = true;
|
522
553
|
b->inl_text = inl_text;
|
523
554
|
b->previous = subj->last_bracket;
|
524
|
-
b->previous_delimiter = subj->last_delim;
|
525
555
|
b->position = subj->pos;
|
526
556
|
b->bracket_after = false;
|
557
|
+
if (image) {
|
558
|
+
b->in_bracket_image1 = true;
|
559
|
+
} else {
|
560
|
+
b->in_bracket_image0 = true;
|
561
|
+
}
|
527
562
|
subj->last_bracket = b;
|
563
|
+
if (!image) {
|
564
|
+
subj->no_link_openers = false;
|
565
|
+
}
|
528
566
|
}
|
529
567
|
|
530
568
|
// Assumes the subject has a c at the current position.
|
@@ -631,12 +669,13 @@ static cmark_syntax_extension *get_extension_for_special_char(cmark_parser *pars
|
|
631
669
|
return NULL;
|
632
670
|
}
|
633
671
|
|
634
|
-
static void process_emphasis(cmark_parser *parser, subject *subj,
|
635
|
-
delimiter *
|
672
|
+
static void process_emphasis(cmark_parser *parser, subject *subj, bufsize_t stack_bottom) {
|
673
|
+
delimiter *candidate;
|
674
|
+
delimiter *closer = NULL;
|
636
675
|
delimiter *opener;
|
637
676
|
delimiter *old_closer;
|
638
677
|
bool opener_found;
|
639
|
-
|
678
|
+
bufsize_t openers_bottom[3][128];
|
640
679
|
int i;
|
641
680
|
|
642
681
|
// initialize openers_bottom:
|
@@ -649,8 +688,10 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
649
688
|
}
|
650
689
|
|
651
690
|
// move back to first relevant delim.
|
652
|
-
|
653
|
-
|
691
|
+
candidate = subj->last_delim;
|
692
|
+
while (candidate != NULL && candidate->position >= stack_bottom) {
|
693
|
+
closer = candidate;
|
694
|
+
candidate = candidate->previous;
|
654
695
|
}
|
655
696
|
|
656
697
|
// now move forward, looking for closers, and handling each
|
@@ -660,8 +701,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
660
701
|
// Now look backwards for first matching opener:
|
661
702
|
opener = closer->previous;
|
662
703
|
opener_found = false;
|
663
|
-
while (opener != NULL && opener
|
664
|
-
opener
|
704
|
+
while (opener != NULL && opener->position >= stack_bottom &&
|
705
|
+
opener->position >= openers_bottom[closer->length % 3][closer->delim_char]) {
|
665
706
|
if (opener->can_open && opener->delim_char == closer->delim_char) {
|
666
707
|
// interior closer of size 2 can't match opener of size 1
|
667
708
|
// or of size 1 can't match 2
|
@@ -687,27 +728,29 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
687
728
|
} else {
|
688
729
|
closer = closer->next;
|
689
730
|
}
|
690
|
-
} else if (closer->delim_char == '\'') {
|
731
|
+
} else if (closer->delim_char == '\'' || closer->delim_char == '"') {
|
691
732
|
cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
|
692
|
-
closer->
|
693
|
-
|
694
|
-
|
695
|
-
|
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);
|
696
737
|
}
|
697
738
|
closer = closer->next;
|
698
|
-
} else if (closer->delim_char == '"') {
|
699
|
-
cmark_chunk_free(subj->mem, &closer->inl_text->as.literal);
|
700
|
-
closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE);
|
701
739
|
if (opener_found) {
|
702
740
|
cmark_chunk_free(subj->mem, &opener->inl_text->as.literal);
|
703
|
-
|
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);
|
704
748
|
}
|
705
|
-
closer = closer->next;
|
706
749
|
}
|
707
750
|
if (!opener_found) {
|
708
751
|
// set lower bound for future searches for openers
|
709
752
|
openers_bottom[old_closer->length % 3][old_closer->delim_char] =
|
710
|
-
old_closer->
|
753
|
+
old_closer->position;
|
711
754
|
if (!old_closer->can_open) {
|
712
755
|
// we can remove a closer that can't be an
|
713
756
|
// opener, once we've seen there's no
|
@@ -720,7 +763,8 @@ static void process_emphasis(cmark_parser *parser, subject *subj, delimiter *sta
|
|
720
763
|
}
|
721
764
|
}
|
722
765
|
// free all delimiters in list until stack_bottom:
|
723
|
-
while (subj->last_delim != NULL &&
|
766
|
+
while (subj->last_delim != NULL &&
|
767
|
+
subj->last_delim->position >= stack_bottom) {
|
724
768
|
remove_delimiter(subj, subj->last_delim);
|
725
769
|
}
|
726
770
|
}
|
@@ -759,7 +803,8 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
|
|
759
803
|
tmp = opener_inl->next;
|
760
804
|
while (tmp && tmp != closer_inl) {
|
761
805
|
tmpnext = tmp->next;
|
762
|
-
|
806
|
+
cmark_node_unlink(tmp);
|
807
|
+
append_child(emph, tmp);
|
763
808
|
tmp = tmpnext;
|
764
809
|
}
|
765
810
|
cmark_node_insert_after(opener_inl, emph);
|
@@ -890,7 +935,63 @@ static cmark_node *handle_pointy_brace(subject *subj, int options) {
|
|
890
935
|
}
|
891
936
|
|
892
937
|
// finally, try to match an html tag
|
893
|
-
|
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
|
+
}
|
894
995
|
if (matchlen > 0) {
|
895
996
|
contents = cmark_chunk_dup(&subj->input, subj->pos - 1, matchlen + 1);
|
896
997
|
subj->pos += matchlen;
|
@@ -1056,16 +1157,16 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) {
|
|
1056
1157
|
return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
|
1057
1158
|
}
|
1058
1159
|
|
1059
|
-
|
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) {
|
1060
1165
|
// take delimiter off stack
|
1061
1166
|
pop_bracket(subj);
|
1062
1167
|
return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
|
1063
1168
|
}
|
1064
1169
|
|
1065
|
-
// If we got here, we matched a potential link/image text.
|
1066
|
-
// Now we check to see if it's a link/image.
|
1067
|
-
is_image = opener->image;
|
1068
|
-
|
1069
1170
|
after_link_text_pos = subj->pos;
|
1070
1171
|
|
1071
1172
|
// First, look for an inline link.
|
@@ -1184,7 +1285,7 @@ noMatch:
|
|
1184
1285
|
// being replacing the opening '[' text node with a `^footnote-ref]` node.
|
1185
1286
|
cmark_node_insert_before(opener->inl_text, fnref);
|
1186
1287
|
|
1187
|
-
process_emphasis(parser, subj, opener->
|
1288
|
+
process_emphasis(parser, subj, opener->position);
|
1188
1289
|
// sometimes, the footnote reference text gets parsed into multiple nodes
|
1189
1290
|
// i.e. '[^example]' parsed into '[', '^exam', 'ple]'.
|
1190
1291
|
// this happens for ex with the autolink extension. when the autolinker
|
@@ -1229,31 +1330,22 @@ match:
|
|
1229
1330
|
tmp = opener->inl_text->next;
|
1230
1331
|
while (tmp) {
|
1231
1332
|
tmpnext = tmp->next;
|
1232
|
-
|
1333
|
+
cmark_node_unlink(tmp);
|
1334
|
+
append_child(inl, tmp);
|
1233
1335
|
tmp = tmpnext;
|
1234
1336
|
}
|
1235
1337
|
|
1236
1338
|
// Free the bracket [:
|
1237
1339
|
cmark_node_free(opener->inl_text);
|
1238
1340
|
|
1239
|
-
process_emphasis(parser, subj, opener->
|
1341
|
+
process_emphasis(parser, subj, opener->position);
|
1240
1342
|
pop_bracket(subj);
|
1241
1343
|
|
1242
|
-
// Now, if we have a link, we also want to deactivate
|
1243
|
-
//
|
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
|
1244
1346
|
// inside links.)
|
1245
1347
|
if (!is_image) {
|
1246
|
-
|
1247
|
-
while (opener != NULL) {
|
1248
|
-
if (!opener->image) {
|
1249
|
-
if (!opener->active) {
|
1250
|
-
break;
|
1251
|
-
} else {
|
1252
|
-
opener->active = false;
|
1253
|
-
}
|
1254
|
-
}
|
1255
|
-
opener = opener->previous;
|
1256
|
-
}
|
1348
|
+
subj->no_link_openers = true;
|
1257
1349
|
}
|
1258
1350
|
|
1259
1351
|
return NULL;
|
@@ -1431,7 +1523,7 @@ static int parse_inline(cmark_parser *parser, subject *subj, cmark_node *parent,
|
|
1431
1523
|
new_inl = make_str(subj, startpos, endpos - 1, contents);
|
1432
1524
|
}
|
1433
1525
|
if (new_inl != NULL) {
|
1434
|
-
|
1526
|
+
append_child(parent, new_inl);
|
1435
1527
|
}
|
1436
1528
|
|
1437
1529
|
return 1;
|
@@ -1450,7 +1542,7 @@ void cmark_parse_inlines(cmark_parser *parser,
|
|
1450
1542
|
while (!is_eof(&subj) && parse_inline(parser, &subj, parent, options))
|
1451
1543
|
;
|
1452
1544
|
|
1453
|
-
process_emphasis(parser, &subj,
|
1545
|
+
process_emphasis(parser, &subj, 0);
|
1454
1546
|
// free bracket and delim stack
|
1455
1547
|
while (subj.last_delim) {
|
1456
1548
|
remove_delimiter(&subj, subj.last_delim);
|
@@ -1662,10 +1754,15 @@ cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) {
|
|
1662
1754
|
}
|
1663
1755
|
|
1664
1756
|
int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image) {
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1757
|
+
bracket *b = parser->last_bracket;
|
1758
|
+
if (!b) {
|
1759
|
+
return 0;
|
1760
|
+
}
|
1761
|
+
if (image != 0) {
|
1762
|
+
return b->in_bracket_image1;
|
1763
|
+
} else {
|
1764
|
+
return b->in_bracket_image0;
|
1765
|
+
}
|
1669
1766
|
}
|
1670
1767
|
|
1671
1768
|
void cmark_node_unput(cmark_node *node, int n) {
|
data/ext/markly/latex.c
CHANGED
@@ -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 (
|
389
|
-
|
390
|
-
|
391
|
-
|
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
|
|
data/ext/markly/man.c
CHANGED
@@ -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 =
|
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 (
|
229
|
-
|
230
|
-
|
231
|
-
|
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
|
|
data/ext/markly/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/markly/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
|
|