rmultimarkdown 6.2.2.1 → 6.4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/Makefile +2 -2
- data/ext/mmd/aho-corasick.c +12 -8
- data/ext/mmd/beamer.c +29 -0
- data/ext/mmd/critic_markup.c +100 -4
- data/ext/mmd/critic_markup.h +7 -0
- data/ext/mmd/d_string.c +502 -119
- data/ext/mmd/epub.c +2 -4
- data/ext/mmd/file.c +436 -0
- data/ext/mmd/file.h +153 -0
- data/ext/mmd/html.c +130 -37
- data/ext/mmd/include/d_string.h +20 -19
- data/ext/mmd/include/libMultiMarkdown.h +42 -27
- data/ext/mmd/include/token.h +15 -15
- data/ext/mmd/latex.c +107 -30
- data/ext/mmd/lexer.c +19 -7
- data/ext/mmd/lexer.h +2 -2
- data/ext/mmd/memoir.c +29 -0
- data/ext/mmd/mmd.c +65 -39
- data/ext/mmd/object_pool.h +4 -4
- data/ext/mmd/opendocument-content.c +95 -13
- data/ext/mmd/opendocument.c +315 -313
- data/ext/mmd/opml-lexer.c +2183 -0
- data/ext/mmd/opml-lexer.h +157 -0
- data/ext/mmd/opml-parser.c +1193 -0
- data/ext/mmd/opml-parser.h +15 -0
- data/ext/mmd/opml-reader.c +435 -0
- data/ext/mmd/opml-reader.h +111 -0
- data/ext/mmd/opml.c +511 -0
- data/ext/mmd/opml.h +115 -0
- data/ext/mmd/parser.c +2 -0
- data/ext/mmd/rng.c +1 -1
- data/ext/mmd/scanners.c +51663 -24824
- data/ext/mmd/stack.c +4 -2
- data/ext/mmd/stack.h +8 -8
- data/ext/mmd/textbundle.c +2 -4
- data/ext/mmd/token.c +24 -12
- data/ext/mmd/token_pairs.c +2 -2
- data/ext/mmd/token_pairs.h +10 -10
- data/ext/mmd/transclude.c +1 -226
- data/ext/mmd/transclude.h +0 -8
- data/ext/mmd/uuid.c +3 -3
- data/ext/mmd/version.h +3 -3
- data/ext/mmd/writer.c +99 -30
- data/ext/mmd/writer.h +11 -0
- data/lib/multi_markdown.bundle +0 -0
- data/lib/multi_markdown/version.rb +1 -1
- metadata +13 -5
- data/ext/mmd/fodt.c +0 -2288
- data/ext/mmd/fodt.h +0 -81
data/ext/mmd/lexer.c
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
/* Generated by re2c 0.14.3 on
|
1
|
+
/* Generated by re2c 0.14.3 on Wed May 23 14:18:41 2018 */
|
2
2
|
/**
|
3
3
|
|
4
4
|
MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
|
@@ -643,6 +643,7 @@ yy53:
|
|
643
643
|
yyaccept = 8;
|
644
644
|
yych = *(YYMARKER = ++YYCURSOR);
|
645
645
|
switch (yych) {
|
646
|
+
case 0x00:
|
646
647
|
case '\t':
|
647
648
|
case '\n':
|
648
649
|
case '\r':
|
@@ -1088,6 +1089,7 @@ yy86:
|
|
1088
1089
|
YYCTXMARKER = YYCURSOR + 1;
|
1089
1090
|
yych = *++YYCURSOR;
|
1090
1091
|
switch (yych) {
|
1092
|
+
case 0x00:
|
1091
1093
|
case '\t':
|
1092
1094
|
case '\n':
|
1093
1095
|
case '\r':
|
@@ -1102,9 +1104,10 @@ yy87:
|
|
1102
1104
|
yych = *YYCURSOR;
|
1103
1105
|
yy88:
|
1104
1106
|
switch (yych) {
|
1107
|
+
case 0x00:
|
1108
|
+
case '\n': goto yy91;
|
1105
1109
|
case '\t':
|
1106
1110
|
case ' ': goto yy87;
|
1107
|
-
case '\n': goto yy91;
|
1108
1111
|
case '\r': goto yy93;
|
1109
1112
|
case 0xC2: goto yy90;
|
1110
1113
|
default: goto yy89;
|
@@ -1135,9 +1138,10 @@ yy94:
|
|
1135
1138
|
yych = *YYCURSOR;
|
1136
1139
|
yy95:
|
1137
1140
|
switch (yych) {
|
1141
|
+
case 0x00:
|
1142
|
+
case '\n': goto yy98;
|
1138
1143
|
case '\t':
|
1139
1144
|
case ' ': goto yy94;
|
1140
|
-
case '\n': goto yy98;
|
1141
1145
|
case '\r': goto yy100;
|
1142
1146
|
case 0xC2: goto yy97;
|
1143
1147
|
default: goto yy96;
|
@@ -1166,6 +1170,7 @@ yy101:
|
|
1166
1170
|
YYCTXMARKER = YYCURSOR + 1;
|
1167
1171
|
yych = *++YYCURSOR;
|
1168
1172
|
switch (yych) {
|
1173
|
+
case 0x00:
|
1169
1174
|
case '\t':
|
1170
1175
|
case '\n':
|
1171
1176
|
case '\r':
|
@@ -1178,6 +1183,7 @@ yy102:
|
|
1178
1183
|
YYCTXMARKER = YYCURSOR + 1;
|
1179
1184
|
yych = *++YYCURSOR;
|
1180
1185
|
switch (yych) {
|
1186
|
+
case 0x00:
|
1181
1187
|
case '\t':
|
1182
1188
|
case '\n':
|
1183
1189
|
case '\r':
|
@@ -1192,9 +1198,10 @@ yy103:
|
|
1192
1198
|
yych = *YYCURSOR;
|
1193
1199
|
yy104:
|
1194
1200
|
switch (yych) {
|
1201
|
+
case 0x00:
|
1202
|
+
case '\n': goto yy107;
|
1195
1203
|
case '\t':
|
1196
1204
|
case ' ': goto yy103;
|
1197
|
-
case '\n': goto yy107;
|
1198
1205
|
case '\r': goto yy109;
|
1199
1206
|
case 0xC2: goto yy106;
|
1200
1207
|
default: goto yy105;
|
@@ -1225,9 +1232,10 @@ yy110:
|
|
1225
1232
|
yych = *YYCURSOR;
|
1226
1233
|
yy111:
|
1227
1234
|
switch (yych) {
|
1235
|
+
case 0x00:
|
1236
|
+
case '\n': goto yy114;
|
1228
1237
|
case '\t':
|
1229
1238
|
case ' ': goto yy110;
|
1230
|
-
case '\n': goto yy114;
|
1231
1239
|
case '\r': goto yy116;
|
1232
1240
|
case 0xC2: goto yy113;
|
1233
1241
|
default: goto yy112;
|
@@ -1256,6 +1264,7 @@ yy117:
|
|
1256
1264
|
YYCTXMARKER = YYCURSOR + 1;
|
1257
1265
|
yych = *++YYCURSOR;
|
1258
1266
|
switch (yych) {
|
1267
|
+
case 0x00:
|
1259
1268
|
case '\t':
|
1260
1269
|
case '\n':
|
1261
1270
|
case '\r':
|
@@ -1268,6 +1277,7 @@ yy118:
|
|
1268
1277
|
YYCTXMARKER = YYCURSOR + 1;
|
1269
1278
|
yych = *++YYCURSOR;
|
1270
1279
|
switch (yych) {
|
1280
|
+
case 0x00:
|
1271
1281
|
case '\t':
|
1272
1282
|
case '\n':
|
1273
1283
|
case '\r':
|
@@ -1281,9 +1291,10 @@ yy119:
|
|
1281
1291
|
yych = *YYCURSOR;
|
1282
1292
|
yy120:
|
1283
1293
|
switch (yych) {
|
1294
|
+
case 0x00:
|
1295
|
+
case '\n': goto yy123;
|
1284
1296
|
case '\t':
|
1285
1297
|
case ' ': goto yy119;
|
1286
|
-
case '\n': goto yy123;
|
1287
1298
|
case '\r': goto yy125;
|
1288
1299
|
case 0xC2: goto yy122;
|
1289
1300
|
default: goto yy121;
|
@@ -1314,9 +1325,10 @@ yy126:
|
|
1314
1325
|
yych = *YYCURSOR;
|
1315
1326
|
yy127:
|
1316
1327
|
switch (yych) {
|
1328
|
+
case 0x00:
|
1329
|
+
case '\n': goto yy130;
|
1317
1330
|
case '\t':
|
1318
1331
|
case ' ': goto yy126;
|
1319
|
-
case '\n': goto yy130;
|
1320
1332
|
case '\r': goto yy132;
|
1321
1333
|
case 0xC2: goto yy129;
|
1322
1334
|
default: goto yy128;
|
data/ext/mmd/lexer.h
CHANGED
@@ -69,7 +69,7 @@ typedef struct Scanner Scanner;
|
|
69
69
|
|
70
70
|
/// Scan for the next token
|
71
71
|
int scan(
|
72
|
-
|
73
|
-
|
72
|
+
Scanner * s, //!< Pointer to Scanner state structure
|
73
|
+
const char * stop //!< Pointer to position in string at which to stop parsing
|
74
74
|
);
|
75
75
|
|
data/ext/mmd/memoir.c
CHANGED
@@ -55,6 +55,7 @@
|
|
55
55
|
|
56
56
|
#include "latex.h"
|
57
57
|
#include "memoir.h"
|
58
|
+
#include "parser.h"
|
58
59
|
|
59
60
|
#define print(x) d_string_append(out, x)
|
60
61
|
#define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
|
@@ -70,6 +71,7 @@ void mmd_export_token_memoir(DString * out, const char * source, token * t, scra
|
|
70
71
|
}
|
71
72
|
|
72
73
|
char * temp_char = NULL;
|
74
|
+
token * temp_token = NULL;
|
73
75
|
|
74
76
|
switch (t->type) {
|
75
77
|
case DOC_START_TOKEN:
|
@@ -82,6 +84,33 @@ void mmd_export_token_memoir(DString * out, const char * source, token * t, scra
|
|
82
84
|
temp_char = get_fence_language_specifier(t->child->child, source);
|
83
85
|
|
84
86
|
if (temp_char) {
|
87
|
+
if (strncmp("{=", temp_char, 2) == 0) {
|
88
|
+
// Raw source
|
89
|
+
if (raw_filter_text_matches(temp_char, FORMAT_MEMOIR)) {
|
90
|
+
switch (t->child->tail->type) {
|
91
|
+
case LINE_FENCE_BACKTICK_3:
|
92
|
+
case LINE_FENCE_BACKTICK_4:
|
93
|
+
case LINE_FENCE_BACKTICK_5:
|
94
|
+
temp_token = t->child->tail;
|
95
|
+
break;
|
96
|
+
|
97
|
+
default:
|
98
|
+
temp_token = NULL;
|
99
|
+
}
|
100
|
+
|
101
|
+
if (temp_token) {
|
102
|
+
d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
|
103
|
+
scratch->padded = 1;
|
104
|
+
} else {
|
105
|
+
d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
|
106
|
+
scratch->padded = 0;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
free(temp_char);
|
111
|
+
break;
|
112
|
+
}
|
113
|
+
|
85
114
|
printf("\\begin{adjustwidth}{2.5em}{2.5em}\n\\begin{lstlisting}[language=%s]\n", temp_char);
|
86
115
|
} else {
|
87
116
|
print_const("\\begin{adjustwidth}{2.5em}{2.5em}\n\\begin{verbatim}\n");
|
data/ext/mmd/mmd.c
CHANGED
@@ -65,6 +65,7 @@
|
|
65
65
|
#include "mmd.h"
|
66
66
|
#include "object_pool.h"
|
67
67
|
#include "opendocument.h"
|
68
|
+
#include "opml-reader.h"
|
68
69
|
#include "parser.h"
|
69
70
|
#include "scanners.h"
|
70
71
|
#include "stack.h"
|
@@ -115,6 +116,10 @@ mmd_engine * mmd_engine_create(DString * d, unsigned long extensions) {
|
|
115
116
|
|
116
117
|
e->allow_meta = (extensions & EXT_COMPATIBILITY) ? false : true;
|
117
118
|
|
119
|
+
if (e->allow_meta) {
|
120
|
+
e->allow_meta = (extensions & EXT_NO_METADATA) ? false : true;
|
121
|
+
}
|
122
|
+
|
118
123
|
e->language = LC_EN;
|
119
124
|
e->quotes_lang = ENGLISH;
|
120
125
|
|
@@ -237,7 +242,7 @@ void mmd_engine_set_language(mmd_engine * e, short language) {
|
|
237
242
|
break;
|
238
243
|
|
239
244
|
case LC_ES:
|
240
|
-
e->quotes_lang =
|
245
|
+
e->quotes_lang = SPANISH;
|
241
246
|
break;
|
242
247
|
|
243
248
|
case LC_FR:
|
@@ -506,20 +511,17 @@ void mmd_assign_line_type(mmd_engine * e, token * line) {
|
|
506
511
|
line->type = (first_child->type - HASH1) + LINE_ATX_1;
|
507
512
|
first_child->type = (line->type - LINE_ATX_1) + MARKER_H1;
|
508
513
|
|
509
|
-
// Strip trailing whitespace from '#' sequence
|
510
|
-
first_child->len = first_child->type - MARKER_H1 + 1;
|
511
|
-
|
512
514
|
// Strip trailing '#' sequence if present
|
513
515
|
if (line->child->tail->type == TEXT_NL) {
|
514
516
|
if ((line->child->tail->prev->type >= HASH1) &&
|
515
|
-
|
517
|
+
(line->child->tail->prev->type <= HASH6)) {
|
516
518
|
line->child->tail->prev->type -= HASH1;
|
517
519
|
line->child->tail->prev->type += MARKER_H1;
|
518
520
|
}
|
519
521
|
} else {
|
520
522
|
if ((line->child->tail->type >= HASH1) &&
|
521
|
-
|
522
|
-
line->child->tail->type -=
|
523
|
+
(line->child->tail->type <= HASH6)) {
|
524
|
+
line->child->tail->type -= HASH1;
|
523
525
|
line->child->tail->type += MARKER_H1;
|
524
526
|
}
|
525
527
|
}
|
@@ -572,8 +574,8 @@ void mmd_assign_line_type(mmd_engine * e, token * line) {
|
|
572
574
|
t = first_child;
|
573
575
|
|
574
576
|
while (t->next && ((t->next->type == INDENT_SPACE) ||
|
575
|
-
|
576
|
-
|
577
|
+
(t->next->type == INDENT_TAB) ||
|
578
|
+
(t->next->type == NON_INDENT_SPACE))) {
|
577
579
|
tokens_prune(t->next, t->next);
|
578
580
|
}
|
579
581
|
|
@@ -722,8 +724,8 @@ void mmd_assign_line_type(mmd_engine * e, token * line) {
|
|
722
724
|
t = first_child;
|
723
725
|
|
724
726
|
while (t->next && ((t->next->type == INDENT_SPACE) ||
|
725
|
-
|
726
|
-
|
727
|
+
(t->next->type == INDENT_TAB) ||
|
728
|
+
(t->next->type == NON_INDENT_SPACE))) {
|
727
729
|
tokens_prune(t->next, t->next);
|
728
730
|
}
|
729
731
|
|
@@ -832,7 +834,7 @@ void mmd_assign_line_type(mmd_engine * e, token * line) {
|
|
832
834
|
}
|
833
835
|
|
834
836
|
if ((line->type == LINE_PLAIN) &&
|
835
|
-
|
837
|
+
!(e->extensions & EXT_COMPATIBILITY)) {
|
836
838
|
// Check if this is a potential table line
|
837
839
|
token * walker = first_child;
|
838
840
|
|
@@ -966,6 +968,9 @@ token * mmd_tokenize_string(mmd_engine * e, size_t start, size_t len, bool stop_
|
|
966
968
|
// Reset metadata flag
|
967
969
|
e->allow_meta = (e->extensions & EXT_COMPATIBILITY) ? false : true;
|
968
970
|
|
971
|
+
if (e->allow_meta) {
|
972
|
+
e->allow_meta = (e->extensions & EXT_NO_METADATA) ? false : true;
|
973
|
+
}
|
969
974
|
|
970
975
|
// Create a scanner (for re2c)
|
971
976
|
Scanner s;
|
@@ -1253,7 +1258,7 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
|
|
1253
1258
|
|
1254
1259
|
// Do we treat this like metadata?
|
1255
1260
|
if (!(e->extensions & EXT_COMPATIBILITY) &&
|
1256
|
-
|
1261
|
+
!(e->extensions & EXT_NO_METADATA)) {
|
1257
1262
|
break;
|
1258
1263
|
}
|
1259
1264
|
|
@@ -1281,6 +1286,9 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
|
|
1281
1286
|
case BLOCK_SETEXT_1:
|
1282
1287
|
case BLOCK_SETEXT_2:
|
1283
1288
|
case BLOCK_TABLE:
|
1289
|
+
case BLOCK_TABLE_SECTION:
|
1290
|
+
case TABLE_ROW:
|
1291
|
+
case TABLE_CELL:
|
1284
1292
|
case BLOCK_TERM:
|
1285
1293
|
case LINE_LIST_BULLETED:
|
1286
1294
|
case LINE_LIST_ENUMERATED:
|
@@ -1478,14 +1486,14 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
|
|
1478
1486
|
offset = t->start;
|
1479
1487
|
|
1480
1488
|
if (!((offset == 0) ||
|
1481
|
-
|
1482
|
-
|
1489
|
+
(char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1])) ||
|
1490
|
+
(char_is_whitespace_or_line_ending_or_punctuation(str[offset + 1])))) {
|
1483
1491
|
t->type = APOSTROPHE;
|
1484
1492
|
break;
|
1485
1493
|
}
|
1486
1494
|
|
1487
1495
|
if (offset && (char_is_punctuation(str[offset - 1])) &&
|
1488
|
-
|
1496
|
+
(char_is_alphanumeric(str[offset + 1]))) {
|
1489
1497
|
// If possessive apostrophe, e.g. `x`'s
|
1490
1498
|
if (str[offset + 1] == 's' || str[offset + 1] == 'S') {
|
1491
1499
|
if (char_is_whitespace_or_line_ending_or_punctuation(str[offset + 2])) {
|
@@ -1520,7 +1528,7 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
|
|
1520
1528
|
if (t->len == 1) {
|
1521
1529
|
// Check whether we have '1-2'
|
1522
1530
|
if ((offset == 0) || (!char_is_digit(str[offset - 1])) ||
|
1523
|
-
|
1531
|
+
(!char_is_digit(str[offset + 1]))) {
|
1524
1532
|
t->type = TEXT_PLAIN;
|
1525
1533
|
}
|
1526
1534
|
}
|
@@ -1566,18 +1574,14 @@ void mmd_assign_ambidextrous_tokens_in_block(mmd_engine * e, token * block, size
|
|
1566
1574
|
|
1567
1575
|
offset = t->start;
|
1568
1576
|
|
1569
|
-
//
|
1570
|
-
if ((offset == 0) || (char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1]))) {
|
1571
|
-
t->can_open = 0;
|
1572
|
-
}
|
1573
|
-
|
1577
|
+
// Can't close if whitespace to left
|
1574
1578
|
if ((offset != 0) && (char_is_whitespace_or_line_ending(str[offset - 1]))) {
|
1575
1579
|
t->can_close = 0;
|
1576
1580
|
}
|
1577
1581
|
|
1578
1582
|
offset = t->start + t->len;
|
1579
1583
|
|
1580
|
-
if (
|
1584
|
+
if (char_is_whitespace_or_line_ending(str[offset])) {
|
1581
1585
|
t->can_open = 0;
|
1582
1586
|
}
|
1583
1587
|
|
@@ -1661,11 +1665,11 @@ void pair_emphasis_tokens(token * t) {
|
|
1661
1665
|
closer = t->mate;
|
1662
1666
|
|
1663
1667
|
if (t->next &&
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1668
|
+
(t->next->mate == closer->prev) &&
|
1669
|
+
(t->type == t->next->type) &&
|
1670
|
+
(t->next->mate != t) &&
|
1671
|
+
(t->start + t->len == t->next->start) &&
|
1672
|
+
(closer->start == closer->prev->start + closer->prev->len)) {
|
1669
1673
|
|
1670
1674
|
// We have a strong pair
|
1671
1675
|
t->type = STRONG_START;
|
@@ -1788,8 +1792,8 @@ void is_list_loose(token * list) {
|
|
1788
1792
|
/// Is this actually an HTML block?
|
1789
1793
|
void is_para_html(mmd_engine * e, token * block) {
|
1790
1794
|
if ((block == NULL) ||
|
1791
|
-
|
1792
|
-
|
1795
|
+
(block->child == NULL) ||
|
1796
|
+
(block->child->type != LINE_PLAIN)) {
|
1793
1797
|
return;
|
1794
1798
|
}
|
1795
1799
|
|
@@ -2043,7 +2047,7 @@ void strip_line_tokens_from_block(mmd_engine * e, token * block) {
|
|
2043
2047
|
case LINE_SETEXT_1:
|
2044
2048
|
case LINE_SETEXT_2:
|
2045
2049
|
if ((block->type == BLOCK_SETEXT_1) ||
|
2046
|
-
|
2050
|
+
(block->type == BLOCK_SETEXT_2)) {
|
2047
2051
|
temp = l->next;
|
2048
2052
|
tokens_prune(l, l);
|
2049
2053
|
l = temp;
|
@@ -2088,7 +2092,7 @@ handle_line:
|
|
2088
2092
|
|
2089
2093
|
// If we're not a code block, strip additional indents
|
2090
2094
|
if ((block->type != BLOCK_CODE_INDENTED) &&
|
2091
|
-
|
2095
|
+
(block->type != BLOCK_CODE_FENCED)) {
|
2092
2096
|
while (l->child && ((l->child->type == INDENT_SPACE) || (l->child->type == INDENT_TAB))) {
|
2093
2097
|
token_remove_first_child(l);
|
2094
2098
|
}
|
@@ -2123,7 +2127,7 @@ handle_line:
|
|
2123
2127
|
|
2124
2128
|
// Move children to parent
|
2125
2129
|
// Add ':' back
|
2126
|
-
if (e->dstr->str[l->child->start - 1] == ':') {
|
2130
|
+
if (l->child->start > 0 && e->dstr->str[l->child->start - 1] == ':') {
|
2127
2131
|
temp = token_new(COLON, l->child->start - 1, 1);
|
2128
2132
|
token_append_child(block, temp);
|
2129
2133
|
}
|
@@ -2184,6 +2188,10 @@ token * mmd_engine_parse_substring(mmd_engine * e, size_t byte_start, size_t byt
|
|
2184
2188
|
e->extensions |= EXT_NO_METADATA;
|
2185
2189
|
}
|
2186
2190
|
|
2191
|
+
if (e->extensions & EXT_PARSE_OPML) {
|
2192
|
+
// Convert from OPML first (if not done earlier)
|
2193
|
+
mmd_convert_opml_string(e, byte_start, byte_len);
|
2194
|
+
}
|
2187
2195
|
|
2188
2196
|
// Tokenize the string
|
2189
2197
|
token * doc = mmd_tokenize_string(e, byte_start, byte_len, false);
|
@@ -2259,6 +2267,7 @@ bool mmd_d_string_has_metadata(DString * source, size_t * end) {
|
|
2259
2267
|
/// Does the text have metadata?
|
2260
2268
|
bool mmd_engine_has_metadata(mmd_engine * e, size_t * end) {
|
2261
2269
|
bool result = false;
|
2270
|
+
token * old_root;
|
2262
2271
|
|
2263
2272
|
if (!e) {
|
2264
2273
|
return false;
|
@@ -2275,10 +2284,8 @@ bool mmd_engine_has_metadata(mmd_engine * e, size_t * end) {
|
|
2275
2284
|
return false;
|
2276
2285
|
}
|
2277
2286
|
|
2278
|
-
//
|
2279
|
-
|
2280
|
-
token_tree_free(e->root);
|
2281
|
-
}
|
2287
|
+
// Preserve existing parse tree (if any)
|
2288
|
+
old_root = e->root;
|
2282
2289
|
|
2283
2290
|
// Tokenize the string (up until first empty line)
|
2284
2291
|
token * doc = mmd_tokenize_string(e, 0, e->dstr->currentStringLength, true);
|
@@ -2298,6 +2305,9 @@ bool mmd_engine_has_metadata(mmd_engine * e, size_t * end) {
|
|
2298
2305
|
token_tree_free(doc);
|
2299
2306
|
}
|
2300
2307
|
|
2308
|
+
// Restore previous parse tree
|
2309
|
+
e->root = old_root;
|
2310
|
+
|
2301
2311
|
return result;
|
2302
2312
|
}
|
2303
2313
|
|
@@ -2399,6 +2409,10 @@ char * mmd_d_string_metavalue_for_key(DString * source, const char * key) {
|
|
2399
2409
|
/// Grab metadata without processing entire document
|
2400
2410
|
/// Returned char * does not need to be freed
|
2401
2411
|
char * mmd_engine_metavalue_for_key(mmd_engine * e, const char * key) {
|
2412
|
+
if (e == NULL || key == NULL) {
|
2413
|
+
return NULL;
|
2414
|
+
}
|
2415
|
+
|
2402
2416
|
if (e->metadata_stack->size == 0) {
|
2403
2417
|
// Ensure we have checked for metadata
|
2404
2418
|
if (!mmd_engine_has_metadata(e, NULL)) {
|
@@ -2538,7 +2552,11 @@ void mmd_engine_update_metavalue_for_key(mmd_engine * e, const char * key, const
|
|
2538
2552
|
|
2539
2553
|
DString * temp = d_string_new(key);
|
2540
2554
|
d_string_append(temp, ":\t");
|
2541
|
-
|
2555
|
+
|
2556
|
+
if (value) {
|
2557
|
+
d_string_append(temp, value);
|
2558
|
+
}
|
2559
|
+
|
2542
2560
|
d_string_append_c(temp, '\n');
|
2543
2561
|
|
2544
2562
|
if (start != -1) {
|
@@ -2568,7 +2586,10 @@ void mmd_engine_update_metavalue_for_key(mmd_engine * e, const char * key, const
|
|
2568
2586
|
|
2569
2587
|
d_string_erase(e->dstr, start, len);
|
2570
2588
|
d_string_insert(e->dstr, start, "\n");
|
2571
|
-
|
2589
|
+
|
2590
|
+
if (value) {
|
2591
|
+
d_string_insert(e->dstr, start, value);
|
2592
|
+
}
|
2572
2593
|
} else if (meta_end != 0) {
|
2573
2594
|
// We're appending metadata at the end
|
2574
2595
|
d_string_insert(e->dstr, meta_end, temp->str);
|
@@ -2743,6 +2764,11 @@ DString * mmd_engine_convert_to_data(mmd_engine * e, short format, const char *
|
|
2743
2764
|
DString * result = NULL;
|
2744
2765
|
|
2745
2766
|
if (format == FORMAT_MMD) {
|
2767
|
+
if (e->extensions & EXT_PARSE_OPML) {
|
2768
|
+
// Convert from OPML first (if not done earlier)
|
2769
|
+
mmd_convert_opml_string(e, 0, e->dstr->currentStringLength);
|
2770
|
+
}
|
2771
|
+
|
2746
2772
|
// Simply return text (transclusion is handled externally)
|
2747
2773
|
d_string_append_c_array(output, e->dstr->str, e->dstr->currentStringLength);
|
2748
2774
|
|