redcarpet 1.3.3 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of redcarpet might be problematic. Click here for more details.
- data/ext/markdown.c +304 -32
- data/ext/markdown.h +35 -37
- data/ext/redcarpet.c +31 -18
- data/ext/xhtml.c +148 -75
- data/ext/xhtml.h +13 -13
- data/lib/redcarpet.rb +10 -1
- data/redcarpet.gemspec +2 -2
- data/test/redcarpet_test.rb +27 -0
- metadata +5 -5
data/ext/markdown.c
CHANGED
@@ -56,6 +56,8 @@ struct render {
|
|
56
56
|
struct array refs;
|
57
57
|
char_trigger active_char[256];
|
58
58
|
struct parray work;
|
59
|
+
unsigned int ext_flags;
|
60
|
+
size_t max_nesting;
|
59
61
|
};
|
60
62
|
|
61
63
|
/* html_tag • structure for quick HTML tag search (inspired from discount) */
|
@@ -238,7 +240,7 @@ parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
238
240
|
char_trigger action = 0;
|
239
241
|
struct buf work = { 0, 0, 0, 0, 0 };
|
240
242
|
|
241
|
-
if (rndr->work.size > rndr->
|
243
|
+
if (rndr->work.size > rndr->max_nesting)
|
242
244
|
return;
|
243
245
|
|
244
246
|
while (i < size) {
|
@@ -249,7 +251,7 @@ parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
249
251
|
if (rndr->make.normal_text) {
|
250
252
|
work.data = data + i;
|
251
253
|
work.size = end - i;
|
252
|
-
rndr->make.normal_text(ob, &work,
|
254
|
+
rndr->make.normal_text(ob, &work, rndr->make.opaque);
|
253
255
|
}
|
254
256
|
else
|
255
257
|
bufput(ob, data + i, end - i);
|
@@ -346,7 +348,7 @@ parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c
|
|
346
348
|
|
347
349
|
if (data[i] == c && !isspace(data[i - 1])) {
|
348
350
|
|
349
|
-
if ((rndr->
|
351
|
+
if ((rndr->ext_flags & MKDEXT_LAX_EMPHASIS) == 0) {
|
350
352
|
if (!(i + 1 == size || isspace(data[i + 1]) || ispunct(data[i + 1])))
|
351
353
|
continue;
|
352
354
|
}
|
@@ -360,7 +362,7 @@ parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c
|
|
360
362
|
}
|
361
363
|
|
362
364
|
parse_inline(work, rndr, data, i);
|
363
|
-
r = rndr->make.emphasis(ob, work, c,
|
365
|
+
r = rndr->make.emphasis(ob, work, c, rndr->make.opaque);
|
364
366
|
rndr->work.size -= 1;
|
365
367
|
return r ? i + 1 : 0;
|
366
368
|
}
|
@@ -395,7 +397,7 @@ parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c
|
|
395
397
|
}
|
396
398
|
|
397
399
|
parse_inline(work, rndr, data, i);
|
398
|
-
r = rndr->make.double_emphasis(ob, work, c,
|
400
|
+
r = rndr->make.double_emphasis(ob, work, c, rndr->make.opaque);
|
399
401
|
rndr->work.size -= 1;
|
400
402
|
return r ? i + 2 : 0;
|
401
403
|
}
|
@@ -433,7 +435,7 @@ parse_emph3(struct buf *ob, struct render *rndr, char *data, size_t size, char c
|
|
433
435
|
}
|
434
436
|
|
435
437
|
parse_inline(work, rndr, data, i);
|
436
|
-
r = rndr->make.triple_emphasis(ob, work, c,
|
438
|
+
r = rndr->make.triple_emphasis(ob, work, c, rndr->make.opaque);
|
437
439
|
rndr->work.size -= 1;
|
438
440
|
return r ? i + 3 : 0;
|
439
441
|
|
@@ -497,7 +499,7 @@ char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, s
|
|
497
499
|
while (ob->size && ob->data[ob->size - 1] == ' ')
|
498
500
|
ob->size--;
|
499
501
|
|
500
|
-
return rndr->make.linebreak(ob,
|
502
|
+
return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0;
|
501
503
|
}
|
502
504
|
|
503
505
|
|
@@ -533,10 +535,10 @@ char_codespan(struct buf *ob, struct render *rndr, char *data, size_t offset, si
|
|
533
535
|
/* real code span */
|
534
536
|
if (f_begin < f_end) {
|
535
537
|
struct buf work = { data + f_begin, f_end - f_begin, 0, 0, 0 };
|
536
|
-
if (!rndr->make.codespan(ob, &work,
|
538
|
+
if (!rndr->make.codespan(ob, &work, rndr->make.opaque))
|
537
539
|
end = 0;
|
538
540
|
} else {
|
539
|
-
if (!rndr->make.codespan(ob, 0,
|
541
|
+
if (!rndr->make.codespan(ob, 0, rndr->make.opaque))
|
540
542
|
end = 0;
|
541
543
|
}
|
542
544
|
|
@@ -554,7 +556,7 @@ char_escape(struct buf *ob, struct render *rndr, char *data, size_t offset, size
|
|
554
556
|
if (rndr->make.normal_text) {
|
555
557
|
work.data = data + 1;
|
556
558
|
work.size = 1;
|
557
|
-
rndr->make.normal_text(ob, &work,
|
559
|
+
rndr->make.normal_text(ob, &work, rndr->make.opaque);
|
558
560
|
}
|
559
561
|
else bufputc(ob, data[1]);
|
560
562
|
}
|
@@ -584,7 +586,7 @@ char_entity(struct buf *ob, struct render *rndr, char *data, size_t offset, size
|
|
584
586
|
if (rndr->make.entity) {
|
585
587
|
work.data = data;
|
586
588
|
work.size = end;
|
587
|
-
rndr->make.entity(ob, &work,
|
589
|
+
rndr->make.entity(ob, &work, rndr->make.opaque);
|
588
590
|
}
|
589
591
|
else bufput(ob, data, end);
|
590
592
|
|
@@ -604,10 +606,10 @@ char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset,
|
|
604
606
|
if (rndr->make.autolink && altype != MKDA_NOT_AUTOLINK) {
|
605
607
|
work.data = data + 1;
|
606
608
|
work.size = end - 2;
|
607
|
-
ret = rndr->make.autolink(ob, &work, altype,
|
609
|
+
ret = rndr->make.autolink(ob, &work, altype, rndr->make.opaque);
|
608
610
|
}
|
609
611
|
else if (rndr->make.raw_html_tag)
|
610
|
-
ret = rndr->make.raw_html_tag(ob, &work,
|
612
|
+
ret = rndr->make.raw_html_tag(ob, &work, rndr->make.opaque);
|
611
613
|
}
|
612
614
|
|
613
615
|
if (!ret) return 0;
|
@@ -847,9 +849,9 @@ char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t
|
|
847
849
|
if (ob->size && ob->data[ob->size - 1] == '!')
|
848
850
|
ob->size -= 1;
|
849
851
|
|
850
|
-
ret = rndr->make.image(ob, link, title, content,
|
852
|
+
ret = rndr->make.image(ob, link, title, content, rndr->make.opaque);
|
851
853
|
} else
|
852
|
-
ret = rndr->make.link(ob, link, title, content,
|
854
|
+
ret = rndr->make.link(ob, link, title, content, rndr->make.opaque);
|
853
855
|
|
854
856
|
/* cleanup */
|
855
857
|
cleanup:
|
@@ -902,6 +904,34 @@ is_hrule(char *data, size_t size)
|
|
902
904
|
return n >= 3;
|
903
905
|
}
|
904
906
|
|
907
|
+
/* check if a line is a code fence; return its size if it is */
|
908
|
+
static size_t
|
909
|
+
is_codefence(char *data, size_t size)
|
910
|
+
{
|
911
|
+
size_t i = 0, n = 0;
|
912
|
+
char c;
|
913
|
+
|
914
|
+
/* skipping initial spaces */
|
915
|
+
if (size < 3) return 0;
|
916
|
+
if (data[0] == ' ') { i += 1;
|
917
|
+
if (data[1] == ' ') { i += 1;
|
918
|
+
if (data[2] == ' ') { i += 1; } } }
|
919
|
+
|
920
|
+
/* looking at the hrule char */
|
921
|
+
if (i + 2 >= size || data[i] != '~')
|
922
|
+
return 0;
|
923
|
+
|
924
|
+
/* the whole line must be the char or whitespace */
|
925
|
+
while (i < size && data[i] != '\n') {
|
926
|
+
if (data[i] == '~') n++;
|
927
|
+
else if (data[i] != ' ' && data[i] != '\t')
|
928
|
+
return 0;
|
929
|
+
i++;
|
930
|
+
}
|
931
|
+
|
932
|
+
return n >= 3 ? i + 1 : 0;
|
933
|
+
}
|
934
|
+
|
905
935
|
/* is_headerline • returns whether the line is a setext-style hdr underline */
|
906
936
|
static int
|
907
937
|
is_headerline(char *data, size_t size)
|
@@ -1027,7 +1057,7 @@ parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1027
1057
|
|
1028
1058
|
parse_block(out, rndr, work_data, work_size);
|
1029
1059
|
if (rndr->make.blockquote)
|
1030
|
-
rndr->make.blockquote(ob, out,
|
1060
|
+
rndr->make.blockquote(ob, out, rndr->make.opaque);
|
1031
1061
|
rndr->work.size -= 1;
|
1032
1062
|
return end;
|
1033
1063
|
}
|
@@ -1084,7 +1114,7 @@ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1084
1114
|
|
1085
1115
|
parse_inline(tmp, rndr, work.data, work.size);
|
1086
1116
|
if (rndr->make.paragraph)
|
1087
|
-
rndr->make.paragraph(ob, tmp,
|
1117
|
+
rndr->make.paragraph(ob, tmp, rndr->make.opaque);
|
1088
1118
|
rndr->work.size--;
|
1089
1119
|
|
1090
1120
|
} else {
|
@@ -1114,7 +1144,7 @@ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1114
1144
|
parse_inline(tmp, rndr, work.data, work.size);
|
1115
1145
|
|
1116
1146
|
if (rndr->make.paragraph)
|
1117
|
-
rndr->make.paragraph(ob, tmp,
|
1147
|
+
rndr->make.paragraph(ob, tmp, rndr->make.opaque);
|
1118
1148
|
|
1119
1149
|
rndr->work.size -= 1;
|
1120
1150
|
work.data += beg;
|
@@ -1124,13 +1154,61 @@ parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1124
1154
|
}
|
1125
1155
|
|
1126
1156
|
if (rndr->make.header)
|
1127
|
-
rndr->make.header(ob, &work, level,
|
1157
|
+
rndr->make.header(ob, &work, level, rndr->make.opaque);
|
1128
1158
|
}
|
1129
1159
|
|
1130
1160
|
return end;
|
1131
1161
|
}
|
1132
1162
|
|
1133
1163
|
/* parse_blockquote • hanldes parsing of a block-level code fragment */
|
1164
|
+
static size_t
|
1165
|
+
parse_fencedcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1166
|
+
{
|
1167
|
+
size_t beg, end;
|
1168
|
+
struct buf *work = 0;
|
1169
|
+
|
1170
|
+
beg = is_codefence(data, size);
|
1171
|
+
if (beg == 0) return 0;
|
1172
|
+
|
1173
|
+
if (rndr->work.size < rndr->work.asize) {
|
1174
|
+
work = rndr->work.item[rndr->work.size ++];
|
1175
|
+
work->size = 0;
|
1176
|
+
} else {
|
1177
|
+
work = bufnew(WORK_UNIT);
|
1178
|
+
parr_push(&rndr->work, work);
|
1179
|
+
}
|
1180
|
+
|
1181
|
+
while (beg < size) {
|
1182
|
+
size_t fence_end;
|
1183
|
+
|
1184
|
+
fence_end = is_codefence(data + beg, size - beg);
|
1185
|
+
if (fence_end != 0) {
|
1186
|
+
beg += fence_end;
|
1187
|
+
break;
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
for (end = beg + 1; end < size && data[end - 1] != '\n'; end += 1);
|
1191
|
+
|
1192
|
+
if (beg < end) {
|
1193
|
+
/* verbatim copy to the working buffer,
|
1194
|
+
escaping entities */
|
1195
|
+
if (is_empty(data + beg, end - beg))
|
1196
|
+
bufputc(work, '\n');
|
1197
|
+
else bufput(work, data + beg, end - beg);
|
1198
|
+
}
|
1199
|
+
beg = end;
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
if (work->size && work->data[work->size - 1] != '\n')
|
1203
|
+
bufputc(work, '\n');
|
1204
|
+
|
1205
|
+
if (rndr->make.blockcode)
|
1206
|
+
rndr->make.blockcode(ob, work, rndr->make.opaque);
|
1207
|
+
|
1208
|
+
rndr->work.size -= 1;
|
1209
|
+
return beg;
|
1210
|
+
}
|
1211
|
+
|
1134
1212
|
static size_t
|
1135
1213
|
parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1136
1214
|
{
|
@@ -1165,7 +1243,7 @@ parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1165
1243
|
work->size -= 1;
|
1166
1244
|
bufputc(work, '\n');
|
1167
1245
|
if (rndr->make.blockcode)
|
1168
|
-
rndr->make.blockcode(ob, work,
|
1246
|
+
rndr->make.blockcode(ob, work, rndr->make.opaque);
|
1169
1247
|
rndr->work.size -= 1;
|
1170
1248
|
return beg;
|
1171
1249
|
}
|
@@ -1292,7 +1370,7 @@ parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int
|
|
1292
1370
|
|
1293
1371
|
/* render of li itself */
|
1294
1372
|
if (rndr->make.listitem)
|
1295
|
-
rndr->make.listitem(ob, inter, *flags,
|
1373
|
+
rndr->make.listitem(ob, inter, *flags, rndr->make.opaque);
|
1296
1374
|
|
1297
1375
|
rndr->work.size -= 2;
|
1298
1376
|
return beg;
|
@@ -1322,7 +1400,7 @@ parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int fla
|
|
1322
1400
|
}
|
1323
1401
|
|
1324
1402
|
if (rndr->make.list)
|
1325
|
-
rndr->make.list(ob, work, flags,
|
1403
|
+
rndr->make.list(ob, work, flags, rndr->make.opaque);
|
1326
1404
|
rndr->work.size -= 1;
|
1327
1405
|
return i;
|
1328
1406
|
}
|
@@ -1358,7 +1436,7 @@ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1358
1436
|
work.size = end - i;
|
1359
1437
|
|
1360
1438
|
if (rndr->make.header)
|
1361
|
-
rndr->make.header(ob, &work, (int)level,
|
1439
|
+
rndr->make.header(ob, &work, (int)level, rndr->make.opaque);
|
1362
1440
|
|
1363
1441
|
}
|
1364
1442
|
|
@@ -1433,7 +1511,7 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
|
|
1433
1511
|
if (j) {
|
1434
1512
|
work.size = i + j;
|
1435
1513
|
if (do_render && rndr->make.blockhtml)
|
1436
|
-
rndr->make.blockhtml(ob, &work,
|
1514
|
+
rndr->make.blockhtml(ob, &work, rndr->make.opaque);
|
1437
1515
|
return work.size;
|
1438
1516
|
}
|
1439
1517
|
}
|
@@ -1450,7 +1528,7 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
|
|
1450
1528
|
if (j) {
|
1451
1529
|
work.size = i + j;
|
1452
1530
|
if (do_render && rndr->make.blockhtml)
|
1453
|
-
rndr->make.blockhtml(ob, &work,
|
1531
|
+
rndr->make.blockhtml(ob, &work, rndr->make.opaque);
|
1454
1532
|
return work.size;
|
1455
1533
|
}
|
1456
1534
|
}
|
@@ -1505,11 +1583,192 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
|
|
1505
1583
|
/* the end of the block has been found */
|
1506
1584
|
work.size = i;
|
1507
1585
|
if (do_render && rndr->make.blockhtml)
|
1508
|
-
rndr->make.blockhtml(ob, &work,
|
1586
|
+
rndr->make.blockhtml(ob, &work, rndr->make.opaque);
|
1509
1587
|
|
1510
1588
|
return i;
|
1511
1589
|
}
|
1512
1590
|
|
1591
|
+
static void
|
1592
|
+
parse_table_row(struct buf *ob, struct render *rndr, char *data, size_t size, size_t columns, int *col_data)
|
1593
|
+
{
|
1594
|
+
size_t i = 0, col;
|
1595
|
+
struct buf *row_work = 0;
|
1596
|
+
|
1597
|
+
if (rndr->work.size < rndr->work.asize) {
|
1598
|
+
row_work = rndr->work.item[rndr->work.size ++];
|
1599
|
+
row_work->size = 0;
|
1600
|
+
} else {
|
1601
|
+
row_work = bufnew(WORK_UNIT);
|
1602
|
+
parr_push(&rndr->work, row_work);
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
if (i < size && data[i] == '|')
|
1606
|
+
i++;
|
1607
|
+
|
1608
|
+
for (col = 0; col < columns && i < size; ++col) {
|
1609
|
+
size_t cell_start, cell_end;
|
1610
|
+
struct buf *cell_work;
|
1611
|
+
|
1612
|
+
if (rndr->work.size < rndr->work.asize) {
|
1613
|
+
cell_work = rndr->work.item[rndr->work.size ++];
|
1614
|
+
cell_work->size = 0;
|
1615
|
+
} else {
|
1616
|
+
cell_work = bufnew(WORK_UNIT);
|
1617
|
+
parr_push(&rndr->work, cell_work);
|
1618
|
+
}
|
1619
|
+
|
1620
|
+
while (i < size && isspace(data[i]))
|
1621
|
+
i++;
|
1622
|
+
|
1623
|
+
cell_start = i;
|
1624
|
+
|
1625
|
+
while (i < size && data[i] != '|')
|
1626
|
+
i++;
|
1627
|
+
|
1628
|
+
cell_end = i - 1;
|
1629
|
+
|
1630
|
+
while (cell_end > cell_start && isspace(data[cell_end]))
|
1631
|
+
cell_end--;
|
1632
|
+
|
1633
|
+
parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start);
|
1634
|
+
if (rndr->make.table_cell)
|
1635
|
+
rndr->make.table_cell(row_work, cell_work, col_data ? col_data[col] : 0, rndr->make.opaque);
|
1636
|
+
|
1637
|
+
rndr->work.size -= 1;
|
1638
|
+
i++;
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
for (; col < columns; ++col) {
|
1642
|
+
struct buf empty_cell = {0, 0, 0, 0, 0};
|
1643
|
+
if (rndr->make.table_cell)
|
1644
|
+
rndr->make.table_cell(row_work, &empty_cell, col_data ? col_data[col] : 0, rndr->make.opaque);
|
1645
|
+
}
|
1646
|
+
|
1647
|
+
if (rndr->make.table_row)
|
1648
|
+
rndr->make.table_row(ob, row_work, rndr->make.opaque);
|
1649
|
+
|
1650
|
+
rndr->work.size -= 1;
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
static size_t
|
1654
|
+
parse_table_header(struct buf *ob, struct render *rndr, char *data, size_t size, size_t *columns, int **column_data)
|
1655
|
+
{
|
1656
|
+
int pipes;
|
1657
|
+
size_t i = 0, col, header_end, under_end;
|
1658
|
+
|
1659
|
+
pipes = 0;
|
1660
|
+
while (i < size && data[i] != '\n')
|
1661
|
+
if (data[i++] == '|')
|
1662
|
+
pipes++;
|
1663
|
+
|
1664
|
+
if (i == size || pipes == 0)
|
1665
|
+
return 0;
|
1666
|
+
|
1667
|
+
header_end = i;
|
1668
|
+
|
1669
|
+
if (data[0] == '|')
|
1670
|
+
pipes--;
|
1671
|
+
|
1672
|
+
if (i > 2 && data[i - 1] == '|')
|
1673
|
+
pipes--;
|
1674
|
+
|
1675
|
+
*columns = pipes + 1;
|
1676
|
+
*column_data = calloc(*columns, sizeof(int));
|
1677
|
+
|
1678
|
+
/* Parse the header underline */
|
1679
|
+
i++;
|
1680
|
+
if (i < size && data[i] == '|')
|
1681
|
+
i++;
|
1682
|
+
|
1683
|
+
under_end = i;
|
1684
|
+
while (under_end < size && data[under_end] != '\n')
|
1685
|
+
under_end++;
|
1686
|
+
|
1687
|
+
for (col = 0; col < *columns && i < under_end; ++col) {
|
1688
|
+
size_t cell_start, cell_end;
|
1689
|
+
|
1690
|
+
if (data[i] == ':') {
|
1691
|
+
i++; (*column_data)[col] |= MKD_TABLE_ALIGN_L;
|
1692
|
+
}
|
1693
|
+
|
1694
|
+
while (i < under_end && data[i] == '-')
|
1695
|
+
i++;
|
1696
|
+
|
1697
|
+
if (i < under_end && data[i] == ':') {
|
1698
|
+
i++; (*column_data)[col] |= MKD_TABLE_ALIGN_R;
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
if (i < under_end && data[i] != '|')
|
1702
|
+
break;
|
1703
|
+
|
1704
|
+
i++;
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
if (col < *columns)
|
1708
|
+
return 0;
|
1709
|
+
|
1710
|
+
parse_table_row(ob, rndr, data, header_end, *columns, *column_data);
|
1711
|
+
return under_end + 1;
|
1712
|
+
}
|
1713
|
+
|
1714
|
+
static size_t
|
1715
|
+
parse_table(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1716
|
+
{
|
1717
|
+
size_t i;
|
1718
|
+
|
1719
|
+
struct buf *header_work = 0;
|
1720
|
+
struct buf *body_work = 0;
|
1721
|
+
|
1722
|
+
size_t columns;
|
1723
|
+
int *col_data = NULL;
|
1724
|
+
|
1725
|
+
if (rndr->work.size < rndr->work.asize) {
|
1726
|
+
header_work = rndr->work.item[rndr->work.size ++];
|
1727
|
+
header_work->size = 0;
|
1728
|
+
} else {
|
1729
|
+
header_work = bufnew(WORK_UNIT);
|
1730
|
+
parr_push(&rndr->work, header_work);
|
1731
|
+
}
|
1732
|
+
|
1733
|
+
if (rndr->work.size < rndr->work.asize) {
|
1734
|
+
body_work = rndr->work.item[rndr->work.size ++];
|
1735
|
+
body_work->size = 0;
|
1736
|
+
} else {
|
1737
|
+
body_work = bufnew(WORK_UNIT);
|
1738
|
+
parr_push(&rndr->work, body_work);
|
1739
|
+
}
|
1740
|
+
|
1741
|
+
i = parse_table_header(header_work, rndr, data, size, &columns, &col_data);
|
1742
|
+
if (i > 0) {
|
1743
|
+
|
1744
|
+
while (i < size) {
|
1745
|
+
size_t row_len;
|
1746
|
+
size_t row_start;
|
1747
|
+
int pipes = 0;
|
1748
|
+
|
1749
|
+
row_start = i;
|
1750
|
+
|
1751
|
+
while (i < size && data[i] != '\n')
|
1752
|
+
if (data[i++] == '|')
|
1753
|
+
pipes++;
|
1754
|
+
|
1755
|
+
if (pipes == 0 || i == size) {
|
1756
|
+
i = row_start;
|
1757
|
+
break;
|
1758
|
+
}
|
1759
|
+
|
1760
|
+
parse_table_row(body_work, rndr, data + row_start, i - row_start, columns, col_data);
|
1761
|
+
i++;
|
1762
|
+
}
|
1763
|
+
|
1764
|
+
if (rndr->make.table)
|
1765
|
+
rndr->make.table(ob, header_work, body_work, rndr->make.opaque);
|
1766
|
+
}
|
1767
|
+
|
1768
|
+
free(col_data);
|
1769
|
+
rndr->work.size -= 2;
|
1770
|
+
return i;
|
1771
|
+
}
|
1513
1772
|
|
1514
1773
|
/* parse_block • parsing of one block, returning next char to parse */
|
1515
1774
|
static void
|
@@ -1519,7 +1778,7 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1519
1778
|
char *txt_data;
|
1520
1779
|
beg = 0;
|
1521
1780
|
|
1522
|
-
if (rndr->work.size > rndr->
|
1781
|
+
if (rndr->work.size > rndr->max_nesting)
|
1523
1782
|
return;
|
1524
1783
|
|
1525
1784
|
while (beg < size) {
|
@@ -1529,7 +1788,8 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1529
1788
|
if (data[beg] == '#')
|
1530
1789
|
beg += parse_atxheader(ob, rndr, txt_data, end);
|
1531
1790
|
|
1532
|
-
else if (data[beg] == '<' && rndr->make.blockhtml &&
|
1791
|
+
else if (data[beg] == '<' && rndr->make.blockhtml &&
|
1792
|
+
(i = parse_htmlblock(ob, rndr, txt_data, end, 1)) != 0)
|
1533
1793
|
beg += i;
|
1534
1794
|
|
1535
1795
|
else if ((i = is_empty(txt_data, end)) != 0)
|
@@ -1537,7 +1797,7 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1537
1797
|
|
1538
1798
|
else if (is_hrule(txt_data, end)) {
|
1539
1799
|
if (rndr->make.hrule)
|
1540
|
-
rndr->make.hrule(ob,
|
1800
|
+
rndr->make.hrule(ob, rndr->make.opaque);
|
1541
1801
|
|
1542
1802
|
while (beg < size && data[beg] != '\n')
|
1543
1803
|
beg++;
|
@@ -1545,6 +1805,14 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size)
|
|
1545
1805
|
beg++;
|
1546
1806
|
}
|
1547
1807
|
|
1808
|
+
else if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 &&
|
1809
|
+
(i = parse_fencedcode(ob, rndr, txt_data, end)) != 0)
|
1810
|
+
beg += i;
|
1811
|
+
|
1812
|
+
else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 &&
|
1813
|
+
(i = parse_table(ob, rndr, txt_data, end)) != 0)
|
1814
|
+
beg += i;
|
1815
|
+
|
1548
1816
|
else if (prefix_quote(txt_data, end))
|
1549
1817
|
beg += parse_blockquote(ob, rndr, txt_data, end);
|
1550
1818
|
|
@@ -1702,7 +1970,7 @@ static void expand_tabs(struct buf *ob, const char *line, size_t size)
|
|
1702
1970
|
|
1703
1971
|
/* markdown • parses the input buffer and renders it into the output buffer */
|
1704
1972
|
void
|
1705
|
-
markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
1973
|
+
markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer, unsigned int extensions) {
|
1706
1974
|
struct link_ref *lr;
|
1707
1975
|
struct buf *text = bufnew(TEXT_UNIT);
|
1708
1976
|
size_t i, beg, end;
|
@@ -1738,6 +2006,10 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1738
2006
|
rndr.active_char['\\'] = char_escape;
|
1739
2007
|
rndr.active_char['&'] = char_entity;
|
1740
2008
|
|
2009
|
+
/* Extension data */
|
2010
|
+
rndr.ext_flags = extensions;
|
2011
|
+
rndr.max_nesting = 16;
|
2012
|
+
|
1741
2013
|
/* first pass: looking for references, copying everything else */
|
1742
2014
|
beg = 0;
|
1743
2015
|
while (beg < ib->size) /* iterating over lines */
|
@@ -1775,12 +2047,12 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1775
2047
|
|
1776
2048
|
/* second pass: actual rendering */
|
1777
2049
|
if (rndr.make.doc_header)
|
1778
|
-
rndr.make.doc_header(ob,
|
2050
|
+
rndr.make.doc_header(ob, rndr.make.opaque);
|
1779
2051
|
|
1780
2052
|
parse_block(ob, &rndr, text->data, text->size);
|
1781
2053
|
|
1782
2054
|
if (rndr.make.doc_footer)
|
1783
|
-
rndr.make.doc_footer(ob,
|
2055
|
+
rndr.make.doc_footer(ob, rndr.make.opaque);
|
1784
2056
|
|
1785
2057
|
/* clean-up */
|
1786
2058
|
bufrelease(text);
|