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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +2 -2
  3. data/ext/mmd/aho-corasick.c +12 -8
  4. data/ext/mmd/beamer.c +29 -0
  5. data/ext/mmd/critic_markup.c +100 -4
  6. data/ext/mmd/critic_markup.h +7 -0
  7. data/ext/mmd/d_string.c +502 -119
  8. data/ext/mmd/epub.c +2 -4
  9. data/ext/mmd/file.c +436 -0
  10. data/ext/mmd/file.h +153 -0
  11. data/ext/mmd/html.c +130 -37
  12. data/ext/mmd/include/d_string.h +20 -19
  13. data/ext/mmd/include/libMultiMarkdown.h +42 -27
  14. data/ext/mmd/include/token.h +15 -15
  15. data/ext/mmd/latex.c +107 -30
  16. data/ext/mmd/lexer.c +19 -7
  17. data/ext/mmd/lexer.h +2 -2
  18. data/ext/mmd/memoir.c +29 -0
  19. data/ext/mmd/mmd.c +65 -39
  20. data/ext/mmd/object_pool.h +4 -4
  21. data/ext/mmd/opendocument-content.c +95 -13
  22. data/ext/mmd/opendocument.c +315 -313
  23. data/ext/mmd/opml-lexer.c +2183 -0
  24. data/ext/mmd/opml-lexer.h +157 -0
  25. data/ext/mmd/opml-parser.c +1193 -0
  26. data/ext/mmd/opml-parser.h +15 -0
  27. data/ext/mmd/opml-reader.c +435 -0
  28. data/ext/mmd/opml-reader.h +111 -0
  29. data/ext/mmd/opml.c +511 -0
  30. data/ext/mmd/opml.h +115 -0
  31. data/ext/mmd/parser.c +2 -0
  32. data/ext/mmd/rng.c +1 -1
  33. data/ext/mmd/scanners.c +51663 -24824
  34. data/ext/mmd/stack.c +4 -2
  35. data/ext/mmd/stack.h +8 -8
  36. data/ext/mmd/textbundle.c +2 -4
  37. data/ext/mmd/token.c +24 -12
  38. data/ext/mmd/token_pairs.c +2 -2
  39. data/ext/mmd/token_pairs.h +10 -10
  40. data/ext/mmd/transclude.c +1 -226
  41. data/ext/mmd/transclude.h +0 -8
  42. data/ext/mmd/uuid.c +3 -3
  43. data/ext/mmd/version.h +3 -3
  44. data/ext/mmd/writer.c +99 -30
  45. data/ext/mmd/writer.h +11 -0
  46. data/lib/multi_markdown.bundle +0 -0
  47. data/lib/multi_markdown/version.rb +1 -1
  48. metadata +13 -5
  49. data/ext/mmd/fodt.c +0 -2288
  50. data/ext/mmd/fodt.h +0 -81
@@ -1,4 +1,4 @@
1
- /* Generated by re2c 0.14.3 on Sun Jul 23 17:28:33 2017 */
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;
@@ -69,7 +69,7 @@ typedef struct Scanner Scanner;
69
69
 
70
70
  /// Scan for the next token
71
71
  int scan(
72
- Scanner * s, //!< Pointer to Scanner state structure
73
- const char * stop //!< Pointer to position in string at which to stop parsing
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
 
@@ -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");
@@ -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 = ENGLISH;
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
- (line->child->tail->prev->type <= HASH6)) {
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
- (line->child->tail->type <= HASH6)) {
522
- line->child->tail->type -= TEXT_EMPTY;
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
- (t->next->type == INDENT_TAB) ||
576
- (t->next->type == NON_INDENT_SPACE))) {
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
- (t->next->type == INDENT_TAB) ||
726
- (t->next->type == NON_INDENT_SPACE))) {
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
- !(e->extensions & EXT_COMPATIBILITY)) {
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
- !(e->extensions & EXT_NO_METADATA)) {
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
- (char_is_whitespace_or_line_ending_or_punctuation(str[offset - 1])) ||
1482
- (char_is_whitespace_or_line_ending_or_punctuation(str[offset + 1])))) {
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
- (char_is_alphanumeric(str[offset + 1]))) {
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
- (!char_is_digit(str[offset + 1]))) {
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
- // Look left -- no whitespace to left
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 (char_is_whitespace_or_line_ending_or_punctuation(str[offset])) {
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
- (t->next->mate == closer->prev) &&
1665
- (t->type == t->next->type) &&
1666
- (t->next->mate != t) &&
1667
- (t->start + t->len == t->next->start) &&
1668
- (closer->start == closer->prev->start + closer->prev->len)) {
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
- (block->child == NULL) ||
1792
- (block->child->type != LINE_PLAIN)) {
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
- (block->type == BLOCK_SETEXT_2)) {
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
- (block->type != BLOCK_CODE_FENCED)) {
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
- // Free existing parse tree
2279
- if (e->root) {
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
- d_string_append(temp, value);
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
- d_string_insert(e->dstr, start, value);
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