rmultimarkdown 4.7.1.1 → 6.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +2 -2
  3. data/README.md +7 -9
  4. data/Rakefile +33 -18
  5. data/ext/Makefile +261 -0
  6. data/ext/extconf.rb +23 -3
  7. data/ext/mmd/aho-corasick.c +596 -0
  8. data/ext/mmd/aho-corasick.h +120 -0
  9. data/ext/mmd/beamer.c +344 -0
  10. data/ext/mmd/beamer.h +72 -0
  11. data/ext/mmd/char.c +156 -0
  12. data/ext/mmd/char.h +111 -0
  13. data/ext/mmd/char_lookup.c +212 -0
  14. data/ext/mmd/critic_markup.c +330 -0
  15. data/ext/mmd/critic_markup.h +94 -0
  16. data/ext/mmd/d_string.c +402 -0
  17. data/ext/mmd/epub.c +563 -0
  18. data/ext/mmd/epub.h +69 -0
  19. data/ext/mmd/fodt.c +2288 -0
  20. data/ext/mmd/fodt.h +81 -0
  21. data/ext/mmd/html.c +2460 -0
  22. data/ext/mmd/html.h +81 -0
  23. data/ext/mmd/i18n.h +170 -0
  24. data/ext/mmd/include/d_string.h +182 -0
  25. data/ext/mmd/include/libMultiMarkdown.h +548 -0
  26. data/ext/mmd/include/token.h +233 -0
  27. data/ext/mmd/latex.c +2435 -0
  28. data/ext/mmd/latex.h +83 -0
  29. data/ext/mmd/lexer.c +3001 -0
  30. data/ext/mmd/lexer.h +75 -0
  31. data/ext/mmd/memoir.c +138 -0
  32. data/ext/mmd/memoir.h +67 -0
  33. data/ext/mmd/miniz.c +7557 -0
  34. data/ext/mmd/miniz.h +1328 -0
  35. data/ext/mmd/mmd.c +2798 -0
  36. data/ext/mmd/mmd.h +120 -0
  37. data/ext/mmd/object_pool.c +141 -0
  38. data/ext/mmd/object_pool.h +101 -0
  39. data/ext/mmd/opendocument-content.c +2071 -0
  40. data/ext/mmd/opendocument-content.h +135 -0
  41. data/ext/mmd/opendocument.c +981 -0
  42. data/ext/mmd/opendocument.h +118 -0
  43. data/ext/mmd/parser.c +1760 -0
  44. data/ext/mmd/parser.h +39 -0
  45. data/{MultiMarkdown-4 → ext/mmd}/rng.c +90 -49
  46. data/ext/mmd/scanners.c +77512 -0
  47. data/ext/mmd/scanners.h +101 -0
  48. data/ext/mmd/stack.c +142 -0
  49. data/ext/mmd/stack.h +113 -0
  50. data/ext/mmd/textbundle.c +455 -0
  51. data/ext/mmd/textbundle.h +115 -0
  52. data/ext/mmd/token.c +773 -0
  53. data/ext/mmd/token_pairs.c +263 -0
  54. data/ext/mmd/token_pairs.h +123 -0
  55. data/ext/mmd/transclude.c +549 -0
  56. data/ext/mmd/transclude.h +87 -0
  57. data/ext/mmd/uthash.h +1074 -0
  58. data/ext/mmd/uuid.c +154 -0
  59. data/ext/mmd/uuid.h +77 -0
  60. data/ext/mmd/version.h +111 -0
  61. data/ext/mmd/writer.c +2652 -0
  62. data/ext/mmd/writer.h +260 -0
  63. data/ext/mmd/zip.c +210 -0
  64. data/ext/mmd/zip.h +120 -0
  65. data/ext/{multi_markdown.c → ruby_multi_markdown.c} +87 -18
  66. data/lib/multi_markdown.bundle +0 -0
  67. data/lib/multi_markdown.rb +5 -8
  68. data/lib/multi_markdown/version.rb +1 -1
  69. data/rmultimarkdown.gemspec +2 -2
  70. data/test/{extensions_test.rb.rb → extensions_test.rb} +10 -54
  71. data/test/multi_markdown_test.rb +13 -0
  72. metadata +67 -47
  73. data/MultiMarkdown-4/GLibFacade.c +0 -310
  74. data/MultiMarkdown-4/GLibFacade.h +0 -100
  75. data/MultiMarkdown-4/beamer.c +0 -182
  76. data/MultiMarkdown-4/beamer.h +0 -11
  77. data/MultiMarkdown-4/critic.c +0 -111
  78. data/MultiMarkdown-4/critic.h +0 -15
  79. data/MultiMarkdown-4/glib.h +0 -11
  80. data/MultiMarkdown-4/html.c +0 -1117
  81. data/MultiMarkdown-4/html.h +0 -14
  82. data/MultiMarkdown-4/latex.c +0 -1217
  83. data/MultiMarkdown-4/latex.h +0 -16
  84. data/MultiMarkdown-4/libMultiMarkdown.h +0 -177
  85. data/MultiMarkdown-4/lyx.c +0 -2265
  86. data/MultiMarkdown-4/lyx.h +0 -37
  87. data/MultiMarkdown-4/lyxbeamer.c +0 -265
  88. data/MultiMarkdown-4/lyxbeamer.h +0 -11
  89. data/MultiMarkdown-4/memoir.c +0 -80
  90. data/MultiMarkdown-4/memoir.h +0 -10
  91. data/MultiMarkdown-4/multimarkdown.c +0 -518
  92. data/MultiMarkdown-4/odf.c +0 -1222
  93. data/MultiMarkdown-4/odf.h +0 -18
  94. data/MultiMarkdown-4/opml.c +0 -189
  95. data/MultiMarkdown-4/opml.h +0 -15
  96. data/MultiMarkdown-4/parse_utilities.c +0 -884
  97. data/MultiMarkdown-4/parser.c +0 -16656
  98. data/MultiMarkdown-4/parser.h +0 -188
  99. data/MultiMarkdown-4/rtf.c +0 -665
  100. data/MultiMarkdown-4/rtf.h +0 -17
  101. data/MultiMarkdown-4/strtok.c +0 -56
  102. data/MultiMarkdown-4/strtok.h +0 -9
  103. data/MultiMarkdown-4/text.c +0 -53
  104. data/MultiMarkdown-4/text.h +0 -11
  105. data/MultiMarkdown-4/toc.c +0 -142
  106. data/MultiMarkdown-4/toc.h +0 -15
  107. data/MultiMarkdown-4/transclude.c +0 -307
  108. data/MultiMarkdown-4/transclude.h +0 -28
  109. data/MultiMarkdown-4/writer.c +0 -731
  110. data/MultiMarkdown-4/writer.h +0 -38
data/ext/mmd/fodt.h ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+
3
+ MultiMarkdown -- Lightweight markup processor to produce HTML, odf, and more.
4
+
5
+ @file fodt.h
6
+
7
+ @brief Convert token tree to Flat OpenDocument (ODF/FODT) output
8
+
9
+
10
+ @author Fletcher T. Penney
11
+ @bug
12
+
13
+ **/
14
+
15
+ /*
16
+
17
+ Copyright © 2016 - 2017 Fletcher T. Penney.
18
+
19
+
20
+ The `MultiMarkdown 6` project is released under the MIT License..
21
+
22
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
23
+
24
+ https://github.com/fletcher/MultiMarkdown-4/
25
+
26
+ MMD 4 is released under both the MIT License and GPL.
27
+
28
+
29
+ CuTest is released under the zlib/libpng license. See CuTest.c for the
30
+ text of the license.
31
+
32
+
33
+ ## The MIT License ##
34
+
35
+ Permission is hereby granted, free of charge, to any person obtaining
36
+ a copy of this software and associated documentation files (the
37
+ "Software"), to deal in the Software without restriction, including
38
+ without limitation the rights to use, copy, modify, merge, publish,
39
+ distribute, sublicense, and/or sell copies of the Software, and to
40
+ permit persons to whom the Software is furnished to do so, subject to
41
+ the following conditions:
42
+
43
+ The above copyright notice and this permission notice shall be
44
+ included in all copies or substantial portions of the Software.
45
+
46
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
49
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
50
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
51
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
52
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
53
+
54
+
55
+ */
56
+
57
+
58
+ #ifndef FODT_MULTIMARKDOWN_H
59
+ #define FODT_MULTIMARKDOWN_H
60
+
61
+
62
+ #include "d_string.h"
63
+ #include "token.h"
64
+ #include "writer.h"
65
+
66
+ void mmd_export_token_odf(DString * out, const char * source, token * t, scratch_pad * scratch);
67
+ void mmd_export_token_tree_odf(DString * out, const char * source, token * t, scratch_pad * scratch);
68
+
69
+ void mmd_export_token_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch);
70
+ void mmd_export_token_tree_odf_raw(DString * out, const char * source, token * t, scratch_pad * scratch);
71
+
72
+ void mmd_export_citation_list_odf(DString * out, const char * source, scratch_pad * scratch);
73
+ void mmd_export_footnote_list_odf(DString * out, const char * source, scratch_pad * scratch);
74
+
75
+ void mmd_start_complete_odf(DString * out, const char * source, scratch_pad * scratch);
76
+ void mmd_end_complete_odf(DString * out, const char * source, scratch_pad * scratch);
77
+
78
+ void mmd_export_citation_list_odf(DString * out, const char * source, scratch_pad * scratch);
79
+
80
+
81
+ #endif
data/ext/mmd/html.c ADDED
@@ -0,0 +1,2460 @@
1
+ /**
2
+
3
+ MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
4
+
5
+ @file html.c
6
+
7
+ @brief Convert token tree to HTML output.
8
+
9
+
10
+ @author Fletcher T. Penney
11
+ @bug
12
+
13
+ **/
14
+
15
+ /*
16
+
17
+ Copyright © 2016 - 2017 Fletcher T. Penney.
18
+
19
+
20
+ The `MultiMarkdown 6` project is released under the MIT License..
21
+
22
+ GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
23
+
24
+ https://github.com/fletcher/MultiMarkdown-4/
25
+
26
+ MMD 4 is released under both the MIT License and GPL.
27
+
28
+
29
+ CuTest is released under the zlib/libpng license. See CuTest.c for the text
30
+ of the license.
31
+
32
+
33
+ ## The MIT License ##
34
+
35
+ Permission is hereby granted, free of charge, to any person obtaining a copy
36
+ of this software and associated documentation files (the "Software"), to deal
37
+ in the Software without restriction, including without limitation the rights
38
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39
+ copies of the Software, and to permit persons to whom the Software is
40
+ furnished to do so, subject to the following conditions:
41
+
42
+ The above copyright notice and this permission notice shall be included in
43
+ all copies or substantial portions of the Software.
44
+
45
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51
+ THE SOFTWARE.
52
+
53
+ */
54
+
55
+ #include <ctype.h>
56
+ #include <stdio.h>
57
+ #include <stdlib.h>
58
+ #include <string.h>
59
+
60
+ #include "char.h"
61
+ #include "d_string.h"
62
+ #include "html.h"
63
+ #include "i18n.h"
64
+ #include "libMultiMarkdown.h"
65
+ #include "parser.h"
66
+ #include "token.h"
67
+ #include "scanners.h"
68
+ #include "writer.h"
69
+
70
+
71
+ #define print(x) d_string_append(out, x)
72
+ #define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
73
+ #define print_char(x) d_string_append_c(out, x)
74
+ #define printf(...) d_string_append_printf(out, __VA_ARGS__)
75
+ #define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len)
76
+ #define print_localized(x) mmd_print_localized_char_html(out, x, scratch)
77
+
78
+
79
+ /// strdup() not available on all platforms
80
+ static char * my_strdup(const char * source) {
81
+ if (source == NULL) {
82
+ return NULL;
83
+ }
84
+
85
+ char * result = malloc(strlen(source) + 1);
86
+
87
+ if (result) {
88
+ strcpy(result, source);
89
+ }
90
+
91
+ return result;
92
+ }
93
+
94
+
95
+ // Use Knuth's pseudo random generator to obfuscate email addresses predictably
96
+ long ran_num_next();
97
+
98
+ void mmd_print_char_html(DString * out, char c, bool obfuscate) {
99
+ switch (c) {
100
+ case '"':
101
+ print_const("&quot;");
102
+ break;
103
+
104
+ case '&':
105
+ print_const("&amp;");
106
+ break;
107
+
108
+ case '<':
109
+ print_const("&lt;");
110
+ break;
111
+
112
+ case '>':
113
+ print_const("&gt;");
114
+ break;
115
+
116
+ default:
117
+ if (obfuscate && ((int) c == (((int) c) & 127))) {
118
+ if (ran_num_next() % 2 == 0) {
119
+ printf("&#%d;", (int) c);
120
+ } else {
121
+ printf("&#x%x;", (unsigned int) c);
122
+ }
123
+ } else {
124
+ print_char(c);
125
+ }
126
+
127
+ break;
128
+ }
129
+ }
130
+
131
+
132
+ void mmd_print_string_html(DString * out, const char * str, bool obfuscate) {
133
+ if (str) {
134
+ while (*str != '\0') {
135
+ mmd_print_char_html(out, *str, obfuscate);
136
+ str++;
137
+ }
138
+ }
139
+ }
140
+
141
+
142
+ void mmd_print_localized_char_html(DString * out, unsigned short type, scratch_pad * scratch) {
143
+ switch (type) {
144
+ case DASH_N:
145
+ print_const("&#8211;");
146
+ break;
147
+
148
+ case DASH_M:
149
+ print_const("&#8212;");
150
+ break;
151
+
152
+ case ELLIPSIS:
153
+ print_const("&#8230;");
154
+ break;
155
+
156
+ case APOSTROPHE:
157
+ print_const("&#8217;");
158
+ break;
159
+
160
+ case QUOTE_LEFT_SINGLE:
161
+ switch (scratch->quotes_lang) {
162
+ case SWEDISH:
163
+ print( "&#8217;");
164
+ break;
165
+
166
+ case FRENCH:
167
+ print_const("&#39;");
168
+ break;
169
+
170
+ case GERMAN:
171
+ print_const("&#8218;");
172
+ break;
173
+
174
+ case GERMANGUILL:
175
+ print_const("&#8250;");
176
+ break;
177
+
178
+ default:
179
+ print_const("&#8216;");
180
+ }
181
+
182
+ break;
183
+
184
+ case QUOTE_RIGHT_SINGLE:
185
+ switch (scratch->quotes_lang) {
186
+ case GERMAN:
187
+ print_const("&#8216;");
188
+ break;
189
+
190
+ case GERMANGUILL:
191
+ print_const("&#8249;");
192
+ break;
193
+
194
+ default:
195
+ print_const("&#8217;");
196
+ }
197
+
198
+ break;
199
+
200
+ case QUOTE_LEFT_DOUBLE:
201
+ switch (scratch->quotes_lang) {
202
+ case DUTCH:
203
+ case GERMAN:
204
+ print_const("&#8222;");
205
+ break;
206
+
207
+ case GERMANGUILL:
208
+ print_const("&#187;");
209
+ break;
210
+
211
+ case FRENCH:
212
+ print_const("&#171;");
213
+ break;
214
+
215
+ case SWEDISH:
216
+ print( "&#8221;");
217
+ break;
218
+
219
+ default:
220
+ print_const("&#8220;");
221
+ }
222
+
223
+ break;
224
+
225
+ case QUOTE_RIGHT_DOUBLE:
226
+ switch (scratch->quotes_lang) {
227
+ case GERMAN:
228
+ print_const("&#8220;");
229
+ break;
230
+
231
+ case GERMANGUILL:
232
+ print_const("&#171;");
233
+ break;
234
+
235
+ case FRENCH:
236
+ print_const("&#187;");
237
+ break;
238
+
239
+ case SWEDISH:
240
+ case DUTCH:
241
+ default:
242
+ print_const("&#8221;");
243
+ }
244
+
245
+ break;
246
+ }
247
+ }
248
+
249
+
250
+ static char * strip_dimension_units(char *original) {
251
+ char *result;
252
+ int i;
253
+
254
+ result = my_strdup(original);
255
+
256
+ for (i = 0; result[i]; i++) {
257
+ result[i] = tolower(result[i]);
258
+ }
259
+
260
+ if (strstr(&result[strlen(result) - 2], "px")) {
261
+ // Leave 'px' alone
262
+ return result;
263
+ }
264
+
265
+ // Trim anything other than digits
266
+ for (i = 0; result[i]; i++) {
267
+ if (result[i] < '0' || result[i] > '9') {
268
+ result[i] = '\0';
269
+ return result;
270
+ }
271
+ }
272
+
273
+ return result;
274
+ }
275
+
276
+
277
+ void mmd_export_link_html(DString * out, const char * source, token * text, link * link, scratch_pad * scratch) {
278
+ attr * a = link->attributes;
279
+
280
+ if (link->url) {
281
+ print_const("<a href=\"");
282
+ mmd_print_string_html(out, link->url, false);
283
+ print_const("\"");
284
+ } else {
285
+ print_const("<a href=\"\"");
286
+ }
287
+
288
+ if (link->title && link->title[0] != '\0') {
289
+ print_const(" title=\"");
290
+ mmd_print_string_html(out, link->title, false);
291
+ print_const("\"");
292
+ }
293
+
294
+ while (a) {
295
+ print_const(" ");
296
+ print(a->key);
297
+ print_const("=\"");
298
+ print(a->value);
299
+ print_const("\"");
300
+ a = a->next;
301
+ }
302
+
303
+ print_const(">");
304
+
305
+ // If we're printing contents of bracket as text, then ensure we include it all
306
+ if (text && text->child && text->child->len > 1) {
307
+ text->child->next->start--;
308
+ text->child->next->len++;
309
+ }
310
+
311
+ if (text && text->child) {
312
+ mmd_export_token_tree_html(out, source, text->child, scratch);
313
+ }
314
+
315
+ print_const("</a>");
316
+ }
317
+
318
+
319
+ void mmd_export_image_html(DString * out, const char * source, token * text, link * link, scratch_pad * scratch, bool is_figure) {
320
+ attr * a = link->attributes;
321
+ char * width = NULL;
322
+ char * height = NULL;
323
+
324
+ // Compatibility mode doesn't allow figures
325
+ if (scratch->extensions & EXT_COMPATIBILITY) {
326
+ is_figure = false;
327
+ }
328
+
329
+ if (is_figure) {
330
+ // Remove wrapping <p> markers
331
+ d_string_erase(out, out->currentStringLength - 3, 3);
332
+ print_const("<figure>\n");
333
+ scratch->close_para = false;
334
+ }
335
+
336
+ if (link->url) {
337
+ if (scratch->store_assets) {
338
+ store_asset(scratch, link->url);
339
+ asset * a = extract_asset(scratch, link->url);
340
+
341
+ printf("<img src=\"assets/%s\"", a->asset_path);
342
+ } else {
343
+ if (scratch->remember_assets) {
344
+ store_asset(scratch, link->url);
345
+ }
346
+
347
+ printf("<img src=\"%s\"", link->url);
348
+ }
349
+ } else {
350
+ print_const("<img src=\"\"");
351
+ }
352
+
353
+ if (text) {
354
+ print_const(" alt=\"");
355
+ print_token_tree_raw(out, source, text->child);
356
+ print_const("\"");
357
+ }
358
+
359
+ if (link->label && !(scratch->extensions & EXT_COMPATIBILITY)) {
360
+ // \todo: Need to decide on approach to id's
361
+ char * label = label_from_token(source, link->label);
362
+ printf(" id=\"%s\"", label);
363
+ free(label);
364
+ }
365
+
366
+ if (link->title && link->title[0] != '\0') {
367
+ printf(" title=\"%s\"", link->title);
368
+ }
369
+
370
+ while (a) {
371
+ if (strcmp(a->key, "width") == 0) {
372
+ width = strip_dimension_units(a->value);
373
+
374
+ if (strcmp(a->value, width) == 0) {
375
+ print_const(" ");
376
+ print(a->key);
377
+ print_const("=\"");
378
+ print(a->value);
379
+ print_const("\"");
380
+ free(width);
381
+ width = NULL;
382
+ } else {
383
+ free(width);
384
+ width = a->value;
385
+ }
386
+ } else if (strcmp(a->key, "height") == 0) {
387
+ height = strip_dimension_units(a->value);
388
+
389
+ if (strcmp(a->value, height) == 0) {
390
+ print_const(" ");
391
+ print(a->key);
392
+ print_const("=\"");
393
+ print(a->value);
394
+ print_const("\"");
395
+ free(height);
396
+ height = NULL;
397
+ } else {
398
+ free(height);
399
+ height = a->value;
400
+ }
401
+ } else {
402
+ print_const(" ");
403
+ print(a->key);
404
+ print_const("=\"");
405
+ print(a->value);
406
+ print_const("\"");
407
+ }
408
+
409
+ a = a->next;
410
+ }
411
+
412
+ if (height || width) {
413
+ print_const(" style=\"");
414
+
415
+ if (height) {
416
+ printf("height:%s;", height);
417
+ }
418
+
419
+ if (width) {
420
+ printf("width:%s;", width);
421
+ }
422
+
423
+ print_const("\"");
424
+ }
425
+
426
+ print_const(" />");
427
+
428
+ if (is_figure) {
429
+ if (text) {
430
+ print_const("\n<figcaption>");
431
+ mmd_export_token_tree_html(out, source, text->child, scratch);
432
+ print_const("</figcaption>");
433
+ }
434
+
435
+ print_const("\n</figure>");
436
+ }
437
+ }
438
+
439
+
440
+ void mmd_export_toc_entry_html(DString * out, const char * source, scratch_pad * scratch, size_t * counter, short level) {
441
+ token * entry, * next;
442
+ short entry_level, next_level;
443
+ char * temp_char;
444
+
445
+ print_const("\n<ul>\n");
446
+
447
+ // Iterate over tokens
448
+ while (*counter < scratch->header_stack->size) {
449
+ // Get token for header
450
+ entry = stack_peek_index(scratch->header_stack, *counter);
451
+ entry_level = raw_level_for_header(entry);
452
+
453
+ if (entry_level >= level) {
454
+ // This entry is a direct descendant of the parent
455
+ temp_char = label_from_header(source, entry);
456
+ printf("<li><a href=\"#%s\">", temp_char);
457
+ mmd_export_token_tree_html(out, source, entry->child, scratch);
458
+ print_const("</a>");
459
+
460
+ if (*counter < scratch->header_stack->size - 1) {
461
+ next = stack_peek_index(scratch->header_stack, *counter + 1);
462
+ next_level = next->type - BLOCK_H1 + 1;
463
+
464
+ if (next_level > entry_level) {
465
+ // This entry has children
466
+ (*counter)++;
467
+ mmd_export_toc_entry_html(out, source, scratch, counter, entry_level + 1);
468
+ }
469
+ }
470
+
471
+ print_const("</li>\n");
472
+ free(temp_char);
473
+ } else if (entry_level < level ) {
474
+ // If entry < level, exit this level
475
+ // Decrement counter first, so that we can test it again later
476
+ (*counter)--;
477
+ break;
478
+ }
479
+
480
+ // Increment counter
481
+ (*counter)++;
482
+ }
483
+
484
+ print_const("</ul>\n");
485
+ }
486
+
487
+
488
+ void mmd_export_toc_html(DString * out, const char * source, scratch_pad * scratch) {
489
+ size_t counter = 0;
490
+
491
+ mmd_export_toc_entry_html(out, source, scratch, &counter, 0);
492
+ }
493
+
494
+
495
+ void mmd_export_token_html(DString * out, const char * source, token * t, scratch_pad * scratch) {
496
+ if (t == NULL) {
497
+ return;
498
+ }
499
+
500
+ short temp_short;
501
+ short temp_short2;
502
+ short temp_short3;
503
+ link * temp_link = NULL;
504
+ char * temp_char = NULL;
505
+ char * temp_char2 = NULL;
506
+ bool temp_bool = 0;
507
+ token * temp_token = NULL;
508
+ footnote * temp_note = NULL;
509
+
510
+ switch (t->type) {
511
+ case AMPERSAND:
512
+ case AMPERSAND_LONG:
513
+ print_const("&amp;");
514
+ break;
515
+
516
+ case ANGLE_LEFT:
517
+ print_const("&lt;");
518
+ break;
519
+
520
+ case ANGLE_RIGHT:
521
+ print_const("&gt;");
522
+ break;
523
+
524
+ case APOSTROPHE:
525
+ if (!(scratch->extensions & EXT_SMART)) {
526
+ print_token(t);
527
+ } else {
528
+ print_localized(APOSTROPHE);
529
+ }
530
+
531
+ break;
532
+
533
+ case BACKTICK:
534
+ if (t->mate == NULL) {
535
+ print_token(t);
536
+ } else if (t->mate->type == QUOTE_RIGHT_ALT)
537
+ if (!(scratch->extensions & EXT_SMART)) {
538
+ print_token(t);
539
+ } else {
540
+ print_localized(QUOTE_LEFT_DOUBLE);
541
+ } else if (t->start < t->mate->start) {
542
+ print_const("<code>");
543
+ } else {
544
+ print_const("</code>");
545
+ }
546
+
547
+ break;
548
+
549
+ case BLOCK_BLOCKQUOTE:
550
+ pad(out, 2, scratch);
551
+ print_const("<blockquote>\n");
552
+ scratch->padded = 2;
553
+ mmd_export_token_tree_html(out, source, t->child, scratch);
554
+ pad(out, 1, scratch);
555
+ print_const("</blockquote>");
556
+ scratch->padded = 0;
557
+ break;
558
+
559
+ case BLOCK_DEFINITION:
560
+ pad(out, 2, scratch);
561
+ print_const("<dd>");
562
+
563
+ temp_short = scratch->list_is_tight;
564
+
565
+ if (t->child) {
566
+ if (!(t->child->next && (t->child->next->type == BLOCK_EMPTY) && t->child->next->next)) {
567
+ scratch->list_is_tight = true;
568
+ }
569
+
570
+ mmd_export_token_tree_html(out, source, t->child, scratch);
571
+ }
572
+
573
+ print_const("</dd>");
574
+ scratch->padded = 0;
575
+
576
+ scratch->list_is_tight = temp_short;
577
+ break;
578
+
579
+ case BLOCK_DEFLIST:
580
+ pad(out, 2, scratch);
581
+
582
+ // Group consecutive definition lists into a single list.
583
+ // lemon's LALR(1) parser can't properly handle this (to my understanding).
584
+
585
+ if (!(t->prev && (t->prev->type == BLOCK_DEFLIST))) {
586
+ print_const("<dl>\n");
587
+ }
588
+
589
+ scratch->padded = 2;
590
+
591
+ mmd_export_token_tree_html(out, source, t->child, scratch);
592
+ pad(out, 1, scratch);
593
+
594
+ if (!(t->next && (t->next->type == BLOCK_DEFLIST))) {
595
+ print_const("</dl>\n");
596
+ }
597
+
598
+ scratch->padded = 1;
599
+ break;
600
+
601
+ case BLOCK_CODE_FENCED:
602
+ pad(out, 2, scratch);
603
+
604
+ temp_char = get_fence_language_specifier(t->child->child, source);
605
+
606
+ if (temp_char) {
607
+ if (strncmp("{=", temp_char, 2) == 0) {
608
+ // Raw source
609
+ if (raw_filter_text_matches(temp_char, FORMAT_HTML)) {
610
+ switch (t->child->tail->type) {
611
+ case LINE_FENCE_BACKTICK_3:
612
+ case LINE_FENCE_BACKTICK_4:
613
+ case LINE_FENCE_BACKTICK_5:
614
+ temp_token = t->child->tail;
615
+ break;
616
+
617
+ default:
618
+ temp_token = NULL;
619
+ }
620
+
621
+ if (temp_token) {
622
+ d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
623
+ scratch->padded = 1;
624
+ } else {
625
+ d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
626
+ scratch->padded = 0;
627
+ }
628
+ }
629
+
630
+ free(temp_char);
631
+ break;
632
+ }
633
+
634
+ print_const("<pre><code");
635
+ printf(" class=\"%s\"", temp_char);
636
+ free(temp_char);
637
+ } else {
638
+ print_const("<pre><code");
639
+ }
640
+
641
+ print_const(">");
642
+ mmd_export_token_tree_html_raw(out, source, t->child->next, scratch);
643
+ print_const("</code></pre>");
644
+ scratch->padded = 0;
645
+ break;
646
+
647
+ case BLOCK_CODE_INDENTED:
648
+ pad(out, 2, scratch);
649
+ print_const("<pre><code>");
650
+ mmd_export_token_tree_html_raw(out, source, t->child, scratch);
651
+ print_const("</code></pre>");
652
+ scratch->padded = 0;
653
+ break;
654
+
655
+ case BLOCK_EMPTY:
656
+ break;
657
+
658
+ case BLOCK_H1:
659
+ case BLOCK_H2:
660
+ case BLOCK_H3:
661
+ case BLOCK_H4:
662
+ case BLOCK_H5:
663
+ case BLOCK_H6:
664
+ pad(out, 2, scratch);
665
+ temp_short = t->type - BLOCK_H1 + 1;
666
+
667
+ if (scratch->extensions & EXT_NO_LABELS) {
668
+ printf("<h%1d>", temp_short + scratch->base_header_level - 1);
669
+ } else {
670
+ temp_char = label_from_header(source, t);
671
+ printf("<h%1d id=\"%s\">", temp_short + scratch->base_header_level - 1, temp_char);
672
+ free(temp_char);
673
+ }
674
+
675
+ mmd_export_token_tree_html(out, source, t->child, scratch);
676
+ printf("</h%1d>", temp_short + scratch->base_header_level - 1);
677
+ scratch->padded = 0;
678
+ break;
679
+
680
+ case BLOCK_HR:
681
+ pad(out, 2, scratch);
682
+ print_const("<hr />");
683
+ scratch->padded = 0;
684
+ break;
685
+
686
+ case BLOCK_HTML:
687
+ pad(out, 2, scratch);
688
+ print_token_raw(out, source, t);
689
+ scratch->padded = 1;
690
+ break;
691
+
692
+ case BLOCK_LIST_BULLETED_LOOSE:
693
+ case BLOCK_LIST_BULLETED:
694
+ temp_short = scratch->list_is_tight;
695
+
696
+ switch (t->type) {
697
+ case BLOCK_LIST_BULLETED_LOOSE:
698
+ scratch->list_is_tight = false;
699
+ break;
700
+
701
+ case BLOCK_LIST_BULLETED:
702
+ scratch->list_is_tight = true;
703
+ break;
704
+ }
705
+
706
+ pad(out, 2, scratch);
707
+ print_const("<ul>");
708
+ scratch->padded = 0;
709
+ mmd_export_token_tree_html(out, source, t->child, scratch);
710
+ pad(out, 1, scratch);
711
+ print_const("</ul>");
712
+ scratch->padded = 0;
713
+ scratch->list_is_tight = temp_short;
714
+ break;
715
+
716
+ case BLOCK_LIST_ENUMERATED_LOOSE:
717
+ case BLOCK_LIST_ENUMERATED:
718
+ temp_short = scratch->list_is_tight;
719
+
720
+ switch (t->type) {
721
+ case BLOCK_LIST_ENUMERATED_LOOSE:
722
+ scratch->list_is_tight = false;
723
+ break;
724
+
725
+ case BLOCK_LIST_ENUMERATED:
726
+ scratch->list_is_tight = true;
727
+ break;
728
+ }
729
+
730
+ pad(out, 2, scratch);
731
+ print_const("<ol>");
732
+ scratch->padded = 0;
733
+ mmd_export_token_tree_html(out, source, t->child, scratch);
734
+ pad(out, 1, scratch);
735
+ print_const("</ol>");
736
+ scratch->padded = 0;
737
+ scratch->list_is_tight = temp_short;
738
+ break;
739
+
740
+ case BLOCK_LIST_ITEM:
741
+ pad(out, 1, scratch);
742
+ print_const("<li>");
743
+ scratch->padded = 2;
744
+ mmd_export_token_tree_html(out, source, t->child, scratch);
745
+ print_const("</li>");
746
+ scratch->padded = 0;
747
+ break;
748
+
749
+ case BLOCK_LIST_ITEM_TIGHT:
750
+ pad(out, 1, scratch);
751
+ print_const("<li>");
752
+
753
+ if (!scratch->list_is_tight) {
754
+ print_const("<p>");
755
+ }
756
+
757
+ scratch->padded = 2;
758
+ mmd_export_token_tree_html(out, source, t->child, scratch);
759
+
760
+ if (scratch->close_para) {
761
+ if (!scratch->list_is_tight) {
762
+ print_const("</p>");
763
+ }
764
+ } else {
765
+ scratch->close_para = true;
766
+ }
767
+
768
+ print_const("</li>");
769
+ scratch->padded = 0;
770
+ break;
771
+
772
+ case BLOCK_META:
773
+ break;
774
+
775
+ case BLOCK_PARA:
776
+ case BLOCK_DEF_CITATION:
777
+ case BLOCK_DEF_FOOTNOTE:
778
+ case BLOCK_DEF_GLOSSARY:
779
+ pad(out, 2, scratch);
780
+
781
+ if (!scratch->list_is_tight) {
782
+ print_const("<p>");
783
+ }
784
+
785
+ mmd_export_token_tree_html(out, source, t->child, scratch);
786
+
787
+ if (scratch->citation_being_printed) {
788
+ scratch->footnote_para_counter--;
789
+
790
+ if (scratch->footnote_para_counter == 0) {
791
+ printf(" <a href=\"#cnref:%d\" title=\"%s\" class=\"reversecitation\">&#160;&#8617;</a>", scratch->citation_being_printed, LC("return to body"));
792
+ }
793
+ }
794
+
795
+ if (scratch->footnote_being_printed) {
796
+ scratch->footnote_para_counter--;
797
+
798
+ if (scratch->footnote_para_counter == 0) {
799
+ temp_short = scratch->footnote_being_printed;
800
+
801
+ if (scratch->extensions & EXT_RANDOM_FOOT) {
802
+ srand(scratch->random_seed_base + temp_short);
803
+ temp_short = rand() % 32000 + 1;
804
+ }
805
+
806
+ printf(" <a href=\"#fnref:%d\" title=\"%s\" class=\"reversefootnote\">&#160;&#8617;</a>", temp_short, LC("return to body"));
807
+ }
808
+ }
809
+
810
+ if (scratch->glossary_being_printed) {
811
+ scratch->footnote_para_counter--;
812
+
813
+ if (scratch->footnote_para_counter == 0) {
814
+ printf(" <a href=\"#gnref:%d\" title=\"%s\" class=\"reverseglossary\">&#160;&#8617;</a>", scratch->glossary_being_printed, LC("return to body"));
815
+ }
816
+ }
817
+
818
+ if (scratch->close_para) {
819
+ if (!scratch->list_is_tight) {
820
+ print_const("</p>");
821
+ }
822
+ } else {
823
+ scratch->close_para = true;
824
+ }
825
+
826
+ scratch->padded = 0;
827
+ break;
828
+
829
+ case BLOCK_SETEXT_1:
830
+ pad(out, 2, scratch);
831
+ temp_short = 1;
832
+
833
+ if (scratch->extensions & EXT_NO_LABELS) {
834
+ printf("<h%1d>", temp_short + scratch->base_header_level - 1);
835
+ } else {
836
+ temp_token = manual_label_from_header(t, source);
837
+
838
+ if (temp_token) {
839
+ temp_char = label_from_token(source, temp_token);
840
+ } else {
841
+ temp_char = label_from_token(source, t);
842
+ }
843
+
844
+ printf("<h%1d id=\"%s\">", temp_short + scratch->base_header_level - 1, temp_char);
845
+ free(temp_char);
846
+ }
847
+
848
+ mmd_export_token_tree_html(out, source, t->child, scratch);
849
+ printf("</h%1d>", temp_short + scratch->base_header_level - 1);
850
+ scratch->padded = 0;
851
+ break;
852
+
853
+ case BLOCK_SETEXT_2:
854
+ pad(out, 2, scratch);
855
+ temp_short = 2;
856
+
857
+ if (scratch->extensions & EXT_NO_LABELS) {
858
+ printf("<h%1d>", temp_short + scratch->base_header_level - 1);
859
+ } else {
860
+ temp_token = manual_label_from_header(t, source);
861
+
862
+ if (temp_token) {
863
+ temp_char = label_from_token(source, temp_token);
864
+ } else {
865
+ temp_char = label_from_token(source, t);
866
+ }
867
+
868
+ printf("<h%1d id=\"%s\">", temp_short + scratch->base_header_level - 1, temp_char);
869
+ free(temp_char);
870
+ }
871
+
872
+ mmd_export_token_tree_html(out, source, t->child, scratch);
873
+ printf("</h%1d>", temp_short + scratch->base_header_level - 1);
874
+ scratch->padded = 0;
875
+ break;
876
+
877
+ case BLOCK_TABLE:
878
+ pad(out, 2, scratch);
879
+ print_const("<table>\n");
880
+
881
+ // Are we followed by a caption?
882
+ if (table_has_caption(t)) {
883
+ temp_token = t->next->child;
884
+
885
+ if (temp_token->next &&
886
+ temp_token->next->type == PAIR_BRACKET) {
887
+ temp_token = temp_token->next;
888
+ }
889
+
890
+ temp_char = label_from_token(source, temp_token);
891
+ printf("<caption style=\"caption-side: bottom;\" id=\"%s\">", temp_char);
892
+ free(temp_char);
893
+
894
+ t->next->child->child->type = TEXT_EMPTY;
895
+ t->next->child->child->mate->type = TEXT_EMPTY;
896
+ mmd_export_token_tree_html(out, source, t->next->child->child, scratch);
897
+ print_const("</caption>\n");
898
+ temp_short = 1;
899
+ } else {
900
+ temp_short = 0;
901
+ }
902
+
903
+ scratch->padded = 2;
904
+ read_table_column_alignments(source, t, scratch);
905
+
906
+ print_const("<colgroup>\n");
907
+
908
+ for (int i = 0; i < scratch->table_column_count; ++i) {
909
+ switch (scratch->table_alignment[i]) {
910
+ case 'l':
911
+ print_const("<col style=\"text-align:left;\"/>\n");
912
+ break;
913
+
914
+ case 'N':
915
+ case 'L':
916
+ print_const("<col style=\"text-align:left;\" class=\"extended\"/>\n");
917
+ break;
918
+
919
+ case 'r':
920
+ print_const("<col style=\"text-align:right;\"/>\n");
921
+ break;
922
+
923
+ case 'R':
924
+ print_const("<col style=\"text-align:right;\" class=\"extended\"/>\n");
925
+ break;
926
+
927
+ case 'c':
928
+ print_const("<col style=\"text-align:center;\"/>\n");
929
+ break;
930
+
931
+ case 'C':
932
+ print_const("<col style=\"text-align:center;\" class=\"extended\"/>\n");
933
+ break;
934
+
935
+ default:
936
+ print_const("<col />\n");
937
+ break;
938
+ }
939
+ }
940
+
941
+ print_const("</colgroup>\n");
942
+ scratch->padded = 1;
943
+
944
+ mmd_export_token_tree_html(out, source, t->child, scratch);
945
+ pad(out, 1, scratch);
946
+ print_const("</table>");
947
+ scratch->padded = 0;
948
+
949
+ scratch->skip_token = temp_short;
950
+
951
+ break;
952
+
953
+ case BLOCK_TABLE_HEADER:
954
+ pad(out, 2, scratch);
955
+ print_const("<thead>\n");
956
+ scratch->in_table_header = 1;
957
+ mmd_export_token_tree_html(out, source, t->child, scratch);
958
+ scratch->in_table_header = 0;
959
+ print_const("</thead>\n");
960
+ scratch->padded = 1;
961
+ break;
962
+
963
+ case BLOCK_TABLE_SECTION:
964
+ pad(out, 2, scratch);
965
+ print_const("<tbody>\n");
966
+ scratch->padded = 2;
967
+ mmd_export_token_tree_html(out, source, t->child, scratch);
968
+ print_const("</tbody>");
969
+ scratch->padded = 0;
970
+ break;
971
+
972
+ case BLOCK_TERM:
973
+ pad(out, 2, scratch);
974
+ print_const("<dt>");
975
+ mmd_export_token_tree_html(out, source, t->child, scratch);
976
+ print_const("</dt>\n");
977
+ scratch->padded = 2;
978
+ break;
979
+
980
+ case BLOCK_TOC:
981
+
982
+ // EPUB uses a separate TOC
983
+ if (scratch->output_format == FORMAT_EPUB) {
984
+ break;
985
+ }
986
+
987
+ pad(out, 2, scratch);
988
+ print_const("<div class=\"TOC\">\n");
989
+
990
+ mmd_export_toc_html(out, source, scratch);
991
+ print_const("</div>");
992
+ scratch->padded = 0;
993
+ break;
994
+
995
+ case BRACE_DOUBLE_LEFT:
996
+ print_const("{{");
997
+ break;
998
+
999
+ case BRACE_DOUBLE_RIGHT:
1000
+ print_const("}}");
1001
+ break;
1002
+
1003
+ case BRACKET_LEFT:
1004
+ print_const("[");
1005
+ break;
1006
+
1007
+ case BRACKET_ABBREVIATION_LEFT:
1008
+ print_const("[>");
1009
+ break;
1010
+
1011
+ case BRACKET_CITATION_LEFT:
1012
+ print_const("[#");
1013
+ break;
1014
+
1015
+ case BRACKET_FOOTNOTE_LEFT:
1016
+ print_const("[^");
1017
+ break;
1018
+
1019
+ case BRACKET_GLOSSARY_LEFT:
1020
+ print_const("[?");
1021
+ break;
1022
+
1023
+ case BRACKET_IMAGE_LEFT:
1024
+ print_const("![");
1025
+ break;
1026
+
1027
+ case BRACKET_VARIABLE_LEFT:
1028
+ print_const("[\%");
1029
+ break;
1030
+
1031
+ case BRACKET_RIGHT:
1032
+ print_const("]");
1033
+ break;
1034
+
1035
+ case COLON:
1036
+ print_const(":");
1037
+ break;
1038
+
1039
+ case CRITIC_ADD_OPEN:
1040
+ print_const("{++");
1041
+ break;
1042
+
1043
+ case CRITIC_ADD_CLOSE:
1044
+ print_const("++}");
1045
+ break;
1046
+
1047
+ case CRITIC_COM_OPEN:
1048
+ print_const("{&gt;&gt;");
1049
+ break;
1050
+
1051
+ case CRITIC_COM_CLOSE:
1052
+ print_const("&lt;&lt;}");
1053
+ break;
1054
+
1055
+ case CRITIC_DEL_OPEN:
1056
+ print_const("{--");
1057
+ break;
1058
+
1059
+ case CRITIC_DEL_CLOSE:
1060
+ print_const("--}");
1061
+ break;
1062
+
1063
+ case CRITIC_HI_OPEN:
1064
+ print_const("{==");
1065
+ break;
1066
+
1067
+ case CRITIC_HI_CLOSE:
1068
+ print_const("==}");
1069
+ break;
1070
+
1071
+ case CRITIC_SUB_OPEN:
1072
+ print_const("{~~");
1073
+ break;
1074
+
1075
+ case CRITIC_SUB_DIV:
1076
+ print_const("~&gt;");
1077
+ break;
1078
+
1079
+ case CRITIC_SUB_CLOSE:
1080
+ print_const("~~}");
1081
+ break;
1082
+
1083
+ case DASH_M:
1084
+ if (!(scratch->extensions & EXT_SMART)) {
1085
+ print_token(t);
1086
+ } else {
1087
+ print_localized(DASH_M);
1088
+ }
1089
+
1090
+ break;
1091
+
1092
+ case DASH_N:
1093
+ if (!(scratch->extensions & EXT_SMART)) {
1094
+ print_token(t);
1095
+ } else {
1096
+ print_localized(DASH_N);
1097
+ }
1098
+
1099
+ break;
1100
+
1101
+ case DOC_START_TOKEN:
1102
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1103
+ break;
1104
+
1105
+ case ELLIPSIS:
1106
+ if (!(scratch->extensions & EXT_SMART)) {
1107
+ print_token(t);
1108
+ } else {
1109
+ print_localized(ELLIPSIS);
1110
+ }
1111
+
1112
+ break;
1113
+
1114
+ case EMPH_START:
1115
+ print_const("<em>");
1116
+ break;
1117
+
1118
+ case EMPH_STOP:
1119
+ print_const("</em>");
1120
+ break;
1121
+
1122
+ case EQUAL:
1123
+ print_const("=");
1124
+ break;
1125
+
1126
+ case ESCAPED_CHARACTER:
1127
+ if (!(scratch->extensions & EXT_COMPATIBILITY) &&
1128
+ (source[t->start + 1] == ' ')) {
1129
+ print_const("&nbsp;");
1130
+ } else {
1131
+ mmd_print_char_html(out, source[t->start + 1], false);
1132
+ }
1133
+
1134
+ break;
1135
+
1136
+ case HASH1:
1137
+ case HASH2:
1138
+ case HASH3:
1139
+ case HASH4:
1140
+ case HASH5:
1141
+ case HASH6:
1142
+ print_token(t);
1143
+ break;
1144
+
1145
+ case HTML_ENTITY:
1146
+ print_token(t);
1147
+ break;
1148
+
1149
+ case HTML_COMMENT_START:
1150
+ if (!(scratch->extensions & EXT_SMART)) {
1151
+ print_const("&lt;!--");
1152
+ } else {
1153
+ print_const("&lt;!");
1154
+ print_localized(DASH_N);
1155
+ }
1156
+
1157
+ break;
1158
+
1159
+ case HTML_COMMENT_STOP:
1160
+ if (!(scratch->extensions & EXT_SMART)) {
1161
+ print_const("--&gt;");
1162
+ } else {
1163
+ print_localized(DASH_N);
1164
+ print_const("&gt;");
1165
+ }
1166
+
1167
+ break;
1168
+
1169
+ case INDENT_SPACE:
1170
+ print_char(' ');
1171
+ break;
1172
+
1173
+ case INDENT_TAB:
1174
+ print_char('\t');
1175
+ break;
1176
+
1177
+ case LINE_LIST_BULLETED:
1178
+ case LINE_LIST_ENUMERATED:
1179
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1180
+ break;
1181
+
1182
+ case LINE_SETEXT_2:
1183
+ case MARKER_BLOCKQUOTE:
1184
+ case MARKER_H1:
1185
+ case MARKER_H2:
1186
+ case MARKER_H3:
1187
+ case MARKER_H4:
1188
+ case MARKER_H5:
1189
+ case MARKER_H6:
1190
+ break;
1191
+
1192
+ case MARKER_LIST_BULLET:
1193
+ case MARKER_LIST_ENUMERATOR:
1194
+ break;
1195
+
1196
+ case MATH_BRACKET_OPEN:
1197
+ if (t->mate) {
1198
+ print_const("<span class=\"math\">\\[");
1199
+ } else {
1200
+ print_const("\\[");
1201
+ }
1202
+
1203
+ break;
1204
+
1205
+ case MATH_BRACKET_CLOSE:
1206
+ if (t->mate) {
1207
+ print_const("\\]</span>");
1208
+ } else {
1209
+ print_const("\\]");
1210
+ }
1211
+
1212
+ break;
1213
+
1214
+ case MATH_DOLLAR_SINGLE:
1215
+ if (t->mate) {
1216
+ (t->start < t->mate->start) ? ( print_const("<span class=\"math\">\\(") ) : ( print_const("\\)</span>") );
1217
+ } else {
1218
+ print_const("$");
1219
+ }
1220
+
1221
+ break;
1222
+
1223
+ case MATH_DOLLAR_DOUBLE:
1224
+ if (t->mate) {
1225
+ (t->start < t->mate->start) ? ( print_const("<span class=\"math\">\\[") ) : ( print_const("\\]</span>") );
1226
+ } else {
1227
+ print_const("$$");
1228
+ }
1229
+
1230
+ break;
1231
+
1232
+ case MATH_PAREN_OPEN:
1233
+ if (t->mate) {
1234
+ print_const("<span class=\"math\">\\(");
1235
+ } else {
1236
+ print_const("\\(");
1237
+ }
1238
+
1239
+ break;
1240
+
1241
+ case MATH_PAREN_CLOSE:
1242
+ if (t->mate) {
1243
+ print_const("\\)</span>");
1244
+ } else {
1245
+ print_const("\\)");
1246
+ }
1247
+
1248
+ break;
1249
+
1250
+ case NON_INDENT_SPACE:
1251
+ print_char(' ');
1252
+ break;
1253
+
1254
+ case PAIR_BACKTICK:
1255
+
1256
+ // Strip leading whitespace
1257
+ switch (t->child->next->type) {
1258
+ case TEXT_NL:
1259
+ case INDENT_TAB:
1260
+ case INDENT_SPACE:
1261
+ case NON_INDENT_SPACE:
1262
+ t->child->next->type = TEXT_EMPTY;
1263
+ break;
1264
+
1265
+ case TEXT_PLAIN:
1266
+ while (t->child->next->len && char_is_whitespace(source[t->child->next->start])) {
1267
+ t->child->next->start++;
1268
+ t->child->next->len--;
1269
+ }
1270
+
1271
+ break;
1272
+ }
1273
+
1274
+ // Strip trailing whitespace
1275
+ switch (t->child->mate->prev->type) {
1276
+ case TEXT_NL:
1277
+ case INDENT_TAB:
1278
+ case INDENT_SPACE:
1279
+ case NON_INDENT_SPACE:
1280
+ t->child->mate->prev->type = TEXT_EMPTY;
1281
+ break;
1282
+
1283
+ case TEXT_PLAIN:
1284
+ while (t->child->mate->prev->len && char_is_whitespace(source[t->child->mate->prev->start + t->child->mate->prev->len - 1])) {
1285
+ t->child->mate->prev->len--;
1286
+ }
1287
+
1288
+ break;
1289
+ }
1290
+
1291
+ t->child->type = TEXT_EMPTY;
1292
+ t->child->mate->type = TEXT_EMPTY;
1293
+
1294
+ if (t->next && t->next->type == PAIR_RAW_FILTER) {
1295
+ // Raw text?
1296
+ if (raw_filter_matches(t->next, source, FORMAT_HTML)) {
1297
+ d_string_append_c_array(out, &(source[t->child->start + t->child->len]), t->child->mate->start - t->child->start - t->child->len);
1298
+ }
1299
+
1300
+ // Skip over PAIR_RAW_FILTER
1301
+ scratch->skip_token = 1;
1302
+ break;
1303
+ }
1304
+
1305
+ print_const("<code>");
1306
+ mmd_export_token_tree_html_raw(out, source, t->child, scratch);
1307
+ print_const("</code>");
1308
+ break;
1309
+
1310
+ case PAIR_ANGLE:
1311
+ temp_char = url_accept(source, t->start + 1, t->len - 2, NULL, true);
1312
+
1313
+ if (temp_char) {
1314
+ print_const("<a href=\"");
1315
+
1316
+ if (scan_email(temp_char)) {
1317
+ temp_bool = true;
1318
+
1319
+ if (strncmp("mailto:", temp_char, 7) != 0) {
1320
+ mmd_print_string_html(out, "mailto:", true);
1321
+ }
1322
+ } else {
1323
+ temp_bool = false;
1324
+ }
1325
+
1326
+ mmd_print_string_html(out, temp_char, temp_bool);
1327
+ print_const("\">");
1328
+ mmd_print_string_html(out, temp_char, temp_bool);
1329
+ print_const("</a>");
1330
+ } else if (scan_html(&source[t->start])) {
1331
+ print_token(t);
1332
+ } else {
1333
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1334
+ }
1335
+
1336
+ free(temp_char);
1337
+ break;
1338
+
1339
+ case PAIR_BRACE:
1340
+ case PAIR_BRACES:
1341
+ case PAIR_RAW_FILTER:
1342
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1343
+ break;
1344
+
1345
+ case PAIR_BRACKET:
1346
+ if ((scratch->extensions & EXT_NOTES) &&
1347
+ (t->next && t->next->type == PAIR_BRACKET_CITATION)) {
1348
+ goto parse_citation;
1349
+ }
1350
+
1351
+ case PAIR_BRACKET_IMAGE:
1352
+ parse_brackets(source, scratch, t, &temp_link, &temp_short, &temp_bool);
1353
+
1354
+ if (temp_link) {
1355
+ if (t->type == PAIR_BRACKET) {
1356
+ // Link
1357
+ mmd_export_link_html(out, source, t, temp_link, scratch);
1358
+ } else {
1359
+ // Image -- should it be a figure (e.g. image is only thing in paragraph)?
1360
+ temp_token = t->next;
1361
+
1362
+ if (temp_token &&
1363
+ ((temp_token->type == PAIR_BRACKET) ||
1364
+ (temp_token->type == PAIR_PAREN))) {
1365
+ temp_token = temp_token->next;
1366
+ }
1367
+
1368
+ if (temp_token && temp_token->type == TEXT_NL) {
1369
+ temp_token = temp_token->next;
1370
+ }
1371
+
1372
+ if (temp_token && temp_token->type == TEXT_LINEBREAK) {
1373
+ temp_token = temp_token->next;
1374
+ }
1375
+
1376
+ if (t->prev || temp_token) {
1377
+ mmd_export_image_html(out, source, t, temp_link, scratch, false);
1378
+ } else {
1379
+ mmd_export_image_html(out, source, t, temp_link, scratch, true);
1380
+ }
1381
+ }
1382
+
1383
+ if (temp_bool) {
1384
+ link_free(temp_link);
1385
+ }
1386
+
1387
+ scratch->skip_token = temp_short;
1388
+
1389
+ return;
1390
+ }
1391
+
1392
+ // No links exist, so treat as normal
1393
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1394
+ break;
1395
+
1396
+ case PAIR_BRACKET_ABBREVIATION:
1397
+
1398
+ // Which might also be an "auto-tagged" abbreviation
1399
+ if (scratch->extensions & EXT_NOTES) {
1400
+ // Note-based syntax enabled
1401
+
1402
+ // Classify this use
1403
+ temp_short2 = scratch->used_abbreviations->size;
1404
+ temp_short3 = scratch->inline_abbreviations_to_free->size;
1405
+ abbreviation_from_bracket(source, scratch, t, &temp_short);
1406
+
1407
+ if (temp_short == -1) {
1408
+ // This instance is not properly formed
1409
+ print_const("[>");
1410
+ mmd_export_token_tree_html(out, source, t->child->next, scratch);
1411
+ print_const("]");
1412
+ break;
1413
+ }
1414
+
1415
+ // Get instance of the note used
1416
+ temp_note = stack_peek_index(scratch->used_abbreviations, temp_short - 1);
1417
+
1418
+ if (t->child) {
1419
+ t->child->type = TEXT_EMPTY;
1420
+ t->child->mate->type = TEXT_EMPTY;
1421
+ }
1422
+
1423
+ if (temp_short3 == scratch->inline_abbreviations_to_free->size) {
1424
+ // This is a reference definition
1425
+
1426
+ if (temp_short2 == scratch->used_abbreviations->size) {
1427
+ // This is a re-use of a previously used note
1428
+ print_const("<abbr title=\"");
1429
+ mmd_print_string_html(out, temp_note->clean_text, false);
1430
+ print_const("\">");
1431
+
1432
+ if (t->child) {
1433
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1434
+ } else {
1435
+ print_token(t);
1436
+ }
1437
+
1438
+ print_const("</abbr>");
1439
+ } else {
1440
+ // This is the first time this note was used
1441
+ mmd_print_string_html(out, temp_note->clean_text, false);
1442
+ print_const(" (<abbr title=\"");
1443
+ mmd_print_string_html(out, temp_note->clean_text, false);
1444
+ print_const("\">");
1445
+
1446
+ if (t->child) {
1447
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1448
+ } else {
1449
+ print_token(t);
1450
+ }
1451
+
1452
+ print_const("</abbr>)");
1453
+ }
1454
+ } else {
1455
+ // This is an inline definition (and therefore the first use)
1456
+ mmd_print_string_html(out, temp_note->clean_text, false);
1457
+ print_const(" (<abbr title=\"");
1458
+ mmd_print_string_html(out, temp_note->clean_text, false);
1459
+ print_const("\">");
1460
+ mmd_print_string_html(out, temp_note->label_text, false);
1461
+ print_const("</abbr>)");
1462
+ }
1463
+ } else {
1464
+ // Note-based syntax disabled
1465
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1466
+ }
1467
+
1468
+ break;
1469
+
1470
+ case PAIR_BRACKET_CITATION:
1471
+ parse_citation:
1472
+ temp_bool = true; // Track whether this is regular vs 'not cited'
1473
+ temp_token = t; // Remember whether we need to skip ahead
1474
+
1475
+ if (scratch->extensions & EXT_NOTES) {
1476
+ // Note-based syntax enabled
1477
+
1478
+ if (t->type == PAIR_BRACKET) {
1479
+ // This is a locator for a subsequent citation (e.g. `[foo][#bar]`)
1480
+ temp_char = text_inside_pair(source, t);
1481
+ temp_char2 = label_from_string(temp_char);
1482
+
1483
+ if (strcmp(temp_char2, "notcited") == 0) {
1484
+ free(temp_char);
1485
+ temp_char = my_strdup("");
1486
+ temp_bool = false;
1487
+ }
1488
+
1489
+ free(temp_char2);
1490
+
1491
+ // Move ahead to actual citation
1492
+ t = t->next;
1493
+ } else {
1494
+ // This is the actual citation (e.g. `[#foo]`)
1495
+ // No locator
1496
+ temp_char = my_strdup("");
1497
+ }
1498
+
1499
+ // Classify this use
1500
+ temp_short2 = scratch->used_citations->size;
1501
+ citation_from_bracket(source, scratch, t, &temp_short);
1502
+
1503
+ if (temp_short == -1) {
1504
+ // This instance is not properly formed
1505
+ print_const("[#");
1506
+ mmd_export_token_tree_html(out, source, t->child->next, scratch);
1507
+ print_const("]");
1508
+
1509
+ free(temp_char);
1510
+ break;
1511
+ }
1512
+
1513
+ if (temp_bool) {
1514
+ // This is a regular citation
1515
+
1516
+ if (temp_char[0] == '\0') {
1517
+ // No locator
1518
+
1519
+ if (temp_short2 == scratch->used_citations->size) {
1520
+ // This is a re-use of a previously used note
1521
+ printf("<a href=\"#cn:%d\" title=\"%s\" class=\"citation\">(%d)</a>",
1522
+ temp_short, LC("see citation"), temp_short);
1523
+ } else {
1524
+ // This is the first time this note was used
1525
+ printf("<a href=\"#cn:%d\" id=\"cnref:%d\" title=\"%s\" class=\"citation\">(%d)</a>",
1526
+ temp_short, temp_short, LC("see citation"), temp_short);
1527
+ }
1528
+ } else {
1529
+ // Locator present
1530
+
1531
+ if (temp_short2 == scratch->used_citations->size) {
1532
+ // This is a re-use of a previously used note
1533
+ printf("<a href=\"#cn:%d\" title=\"%s\" class=\"citation\">(%s, %d)</a>",
1534
+ temp_short, LC("see citation"), temp_char, temp_short);
1535
+ } else {
1536
+ // This is the first time this note was used
1537
+ printf("<a href=\"#cn:%d\" id=\"cnref:%d\" title=\"%s\" class=\"citation\">(%s, %d)</a>",
1538
+ temp_short, temp_short, LC("see citation"), temp_char, temp_short);
1539
+ }
1540
+ }
1541
+ } else {
1542
+ // This is a "nocite"
1543
+ }
1544
+
1545
+ if (temp_token != t) {
1546
+ // Skip citation on next pass
1547
+ scratch->skip_token = 1;
1548
+ }
1549
+
1550
+ free(temp_char);
1551
+ } else {
1552
+ // Note-based syntax disabled
1553
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1554
+ }
1555
+
1556
+ break;
1557
+
1558
+ case PAIR_BRACKET_FOOTNOTE:
1559
+ if (scratch->extensions & EXT_NOTES) {
1560
+ // Note-based syntax enabled
1561
+
1562
+ // Classify this use
1563
+ temp_short2 = scratch->used_footnotes->size;
1564
+ footnote_from_bracket(source, scratch, t, &temp_short);
1565
+
1566
+ if (temp_short == -1) {
1567
+ // This instance is not properly formed
1568
+ print_const("[^");
1569
+ mmd_export_token_tree_html(out, source, t->child->next, scratch);
1570
+ print_const("]");
1571
+ break;
1572
+ }
1573
+
1574
+ if (temp_short2 == scratch->used_footnotes->size) {
1575
+ // This is a re-use of a previously used note
1576
+
1577
+ if (scratch->extensions & EXT_RANDOM_FOOT) {
1578
+ srand(scratch->random_seed_base + temp_short);
1579
+ temp_short3 = rand() % 32000 + 1;
1580
+ } else {
1581
+ temp_short3 = temp_short;
1582
+ }
1583
+
1584
+ printf("<a href=\"#fn:%d\" title=\"%s\" class=\"footnote\"><sup>%d</sup></a>",
1585
+ temp_short3, LC("see footnote"), temp_short);
1586
+ } else {
1587
+ // This is the first time this note was used
1588
+
1589
+ if (scratch->extensions & EXT_RANDOM_FOOT) {
1590
+ srand(scratch->random_seed_base + temp_short);
1591
+ temp_short3 = rand() % 32000 + 1;
1592
+ } else {
1593
+ temp_short3 = temp_short;
1594
+ }
1595
+
1596
+ printf("<a href=\"#fn:%d\" id=\"fnref:%d\" title=\"%s\" class=\"footnote\"><sup>%d</sup></a>",
1597
+ temp_short3, temp_short3, LC("see footnote"), temp_short);
1598
+ }
1599
+ } else {
1600
+ // Note-based syntax disabled
1601
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1602
+ }
1603
+
1604
+ break;
1605
+
1606
+ case PAIR_BRACKET_GLOSSARY:
1607
+
1608
+ // Which might also be an "auto-tagged" glossary
1609
+ if (scratch->extensions & EXT_NOTES) {
1610
+ // Note-based syntax enabled
1611
+
1612
+ // Classify this use
1613
+ temp_short2 = scratch->used_glossaries->size;
1614
+ glossary_from_bracket(source, scratch, t, &temp_short);
1615
+
1616
+ if (temp_short == -1) {
1617
+ // This instance is not properly formed
1618
+ print_const("[?");
1619
+
1620
+ if (t->child) {
1621
+ mmd_export_token_tree_html(out, source, t->child->next, scratch);
1622
+ } else {
1623
+ print_token(t);
1624
+ }
1625
+
1626
+ print_const("]");
1627
+ break;
1628
+ }
1629
+
1630
+ // Get instance of the note used
1631
+ temp_note = stack_peek_index(scratch->used_glossaries, temp_short - 1);
1632
+
1633
+ if (temp_short2 == scratch->used_glossaries->size) {
1634
+ // This is a re-use of a previously used note
1635
+
1636
+ printf("<a href=\"#gn:%d\" title=\"%s\" class=\"glossary\">",
1637
+ temp_short, LC("see glossary"));
1638
+ mmd_print_string_html(out, temp_note->clean_text, false);
1639
+ print_const("</a>");
1640
+ } else {
1641
+ // This is the first time this note was used
1642
+
1643
+
1644
+ printf("<a href=\"#gn:%d\" id=\"gnref:%d\" title=\"%s\" class=\"glossary\">",
1645
+ temp_short, temp_short, LC("see glossary"));
1646
+ mmd_print_string_html(out, temp_note->clean_text, false);
1647
+ print_const("</a>");
1648
+ }
1649
+ } else {
1650
+ // Note-based syntax disabled
1651
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1652
+ }
1653
+
1654
+ break;
1655
+
1656
+ case PAIR_BRACKET_VARIABLE:
1657
+ temp_char = text_inside_pair(source, t);
1658
+ temp_char2 = extract_metadata(scratch, temp_char);
1659
+
1660
+ if (temp_char2) {
1661
+ mmd_print_string_html(out, temp_char2, false);
1662
+ } else {
1663
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1664
+ }
1665
+
1666
+ // Don't free temp_char2 (it belongs to meta *)
1667
+ free(temp_char);
1668
+ break;
1669
+
1670
+ case PAIR_CRITIC_ADD:
1671
+
1672
+ // Ignore if we're rejecting
1673
+ if (scratch->extensions & EXT_CRITIC_REJECT) {
1674
+ break;
1675
+ }
1676
+
1677
+ if (scratch->extensions & EXT_CRITIC) {
1678
+ t->child->type = TEXT_EMPTY;
1679
+ t->child->mate->type = TEXT_EMPTY;
1680
+
1681
+ if (scratch->extensions & EXT_CRITIC_ACCEPT) {
1682
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1683
+ } else {
1684
+ print_const("<ins>");
1685
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1686
+ print_const("</ins>");
1687
+ }
1688
+ } else {
1689
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1690
+ }
1691
+
1692
+ break;
1693
+
1694
+ case PAIR_CRITIC_DEL:
1695
+
1696
+ // Ignore if we're accepting
1697
+ if (scratch->extensions & EXT_CRITIC_ACCEPT) {
1698
+ break;
1699
+ }
1700
+
1701
+ if (scratch->extensions & EXT_CRITIC) {
1702
+ t->child->type = TEXT_EMPTY;
1703
+ t->child->mate->type = TEXT_EMPTY;
1704
+
1705
+ if (scratch->extensions & EXT_CRITIC_REJECT) {
1706
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1707
+ } else {
1708
+ print_const("<del>");
1709
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1710
+ print_const("</del>");
1711
+ }
1712
+ } else {
1713
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1714
+ }
1715
+
1716
+ break;
1717
+
1718
+ case PAIR_CRITIC_COM:
1719
+
1720
+ // Ignore if we're rejecting or accepting
1721
+ if ((scratch->extensions & EXT_CRITIC_REJECT) ||
1722
+ (scratch->extensions & EXT_CRITIC_ACCEPT)) {
1723
+ break;
1724
+ }
1725
+
1726
+ if (scratch->extensions & EXT_CRITIC) {
1727
+ t->child->type = TEXT_EMPTY;
1728
+ t->child->mate->type = TEXT_EMPTY;
1729
+ print_const("<span class=\"critic comment\">");
1730
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1731
+ print_const("</span>");
1732
+ } else {
1733
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1734
+ }
1735
+
1736
+ break;
1737
+
1738
+ case PAIR_CRITIC_HI:
1739
+
1740
+ // Ignore if we're rejecting or accepting
1741
+ if ((scratch->extensions & EXT_CRITIC_REJECT) ||
1742
+ (scratch->extensions & EXT_CRITIC_ACCEPT)) {
1743
+ t->child->type = TEXT_EMPTY;
1744
+ t->child->mate->type = TEXT_EMPTY;
1745
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1746
+ break;
1747
+ }
1748
+
1749
+ if (scratch->extensions & EXT_CRITIC) {
1750
+ t->child->type = TEXT_EMPTY;
1751
+ t->child->mate->type = TEXT_EMPTY;
1752
+ print_const("<mark>");
1753
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1754
+ print_const("</mark>");
1755
+ } else {
1756
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1757
+ }
1758
+
1759
+ break;
1760
+
1761
+ case CRITIC_SUB_DIV_A:
1762
+ print_const("~");
1763
+ break;
1764
+
1765
+ case CRITIC_SUB_DIV_B:
1766
+ print_const("&gt;");
1767
+ break;
1768
+
1769
+ case PAIR_CRITIC_SUB_DEL:
1770
+ if ((scratch->extensions & EXT_CRITIC) &&
1771
+ (t->next) &&
1772
+ (t->next->type == PAIR_CRITIC_SUB_ADD)) {
1773
+ t->child->type = TEXT_EMPTY;
1774
+ t->child->mate->type = TEXT_EMPTY;
1775
+
1776
+ if (scratch->extensions & EXT_CRITIC_ACCEPT) {
1777
+
1778
+ } else if (scratch->extensions & EXT_CRITIC_REJECT) {
1779
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1780
+ } else {
1781
+ print_const("<del>");
1782
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1783
+ print_const("</del>");
1784
+ }
1785
+ } else {
1786
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1787
+ }
1788
+
1789
+ break;
1790
+
1791
+ case PAIR_CRITIC_SUB_ADD:
1792
+ if ((scratch->extensions & EXT_CRITIC) &&
1793
+ (t->prev) &&
1794
+ (t->prev->type == PAIR_CRITIC_SUB_DEL)) {
1795
+ t->child->type = TEXT_EMPTY;
1796
+ t->child->mate->type = TEXT_EMPTY;
1797
+
1798
+ if (scratch->extensions & EXT_CRITIC_REJECT) {
1799
+
1800
+ } else if (scratch->extensions & EXT_CRITIC_ACCEPT) {
1801
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1802
+ } else {
1803
+ print_const("<ins>");
1804
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1805
+ print_const("</ins>");
1806
+ }
1807
+ } else {
1808
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1809
+ }
1810
+
1811
+ break;
1812
+
1813
+ case PAIR_HTML_COMMENT:
1814
+ print_token(t);
1815
+ break;
1816
+
1817
+ case PAIR_MATH:
1818
+ print_const("<span class=\"math\">");
1819
+ mmd_export_token_tree_html_math(out, source, t->child, scratch);
1820
+ print_const("</span>");
1821
+ break;
1822
+
1823
+ case PAIR_EMPH:
1824
+ case PAIR_PAREN:
1825
+ case PAIR_QUOTE_DOUBLE:
1826
+ case PAIR_QUOTE_SINGLE:
1827
+ case PAIR_STAR:
1828
+ case PAIR_STRONG:
1829
+ case PAIR_SUBSCRIPT:
1830
+ case PAIR_SUPERSCRIPT:
1831
+ case PAIR_UL:
1832
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1833
+ break;
1834
+
1835
+ case PAREN_LEFT:
1836
+ print_char('(');
1837
+ break;
1838
+
1839
+ case PAREN_RIGHT:
1840
+ print_char(')');
1841
+ break;
1842
+
1843
+ case PIPE:
1844
+ print_token(t);
1845
+ break;
1846
+
1847
+ case PLUS:
1848
+ print_token(t);
1849
+ break;
1850
+
1851
+ case QUOTE_SINGLE:
1852
+ if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART))) {
1853
+ print_const("'");
1854
+ } else {
1855
+ (t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_SINGLE) ) : ( print_localized(QUOTE_RIGHT_SINGLE) );
1856
+ }
1857
+
1858
+ break;
1859
+
1860
+ case QUOTE_DOUBLE:
1861
+ if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART))) {
1862
+ print_const("&quot;");
1863
+ } else {
1864
+ (t->start < t->mate->start) ? ( print_localized(QUOTE_LEFT_DOUBLE) ) : ( print_localized(QUOTE_RIGHT_DOUBLE) );
1865
+ }
1866
+
1867
+ break;
1868
+
1869
+ case QUOTE_RIGHT_ALT:
1870
+ if ((t->mate == NULL) || (!(scratch->extensions & EXT_SMART))) {
1871
+ print_const("''");
1872
+ } else {
1873
+ print_localized(QUOTE_RIGHT_DOUBLE);
1874
+ }
1875
+
1876
+ break;
1877
+
1878
+ case SLASH:
1879
+ case STAR:
1880
+ print_token(t);
1881
+ break;
1882
+
1883
+ case STRONG_START:
1884
+ print_const("<strong>");
1885
+ break;
1886
+
1887
+ case STRONG_STOP:
1888
+ print_const("</strong>");
1889
+ break;
1890
+
1891
+ case SUBSCRIPT:
1892
+ if (t->mate) {
1893
+ (t->start < t->mate->start) ? (print_const("<sub>")) : (print_const("</sub>"));
1894
+ } else if (t->len != 1) {
1895
+ print_const("<sub>");
1896
+ mmd_export_token_html(out, source, t->child, scratch);
1897
+ print_const("</sub>");
1898
+ } else {
1899
+ print_const("~");
1900
+ }
1901
+
1902
+ break;
1903
+
1904
+ case SUPERSCRIPT:
1905
+ if (t->mate) {
1906
+ (t->start < t->mate->start) ? (print_const("<sup>")) : (print_const("</sup>"));
1907
+ } else if (t->len != 1) {
1908
+ print_const("<sup>");
1909
+ mmd_export_token_html(out, source, t->child, scratch);
1910
+ print_const("</sup>");
1911
+ } else {
1912
+ print_const("^");
1913
+ }
1914
+
1915
+ break;
1916
+
1917
+ case TABLE_CELL:
1918
+ if (scratch->in_table_header) {
1919
+ print_const("\t<th");
1920
+ } else {
1921
+ print_const("\t<td");
1922
+ }
1923
+
1924
+ switch (scratch->table_alignment[scratch->table_cell_count]) {
1925
+ case 'l':
1926
+ case 'L':
1927
+ print_const(" style=\"text-align:left;\"");
1928
+ break;
1929
+
1930
+ case 'r':
1931
+ case 'R':
1932
+ print_const(" style=\"text-align:right;\"");
1933
+ break;
1934
+
1935
+ case 'c':
1936
+ case 'C':
1937
+ print_const(" style=\"text-align:center;\"");
1938
+ break;
1939
+ }
1940
+
1941
+ if (t->next && t->next->type == TABLE_DIVIDER) {
1942
+ if (t->next->len > 1) {
1943
+ printf(" colspan=\"%d\"", t->next->len);
1944
+ }
1945
+ }
1946
+
1947
+ print_const(">");
1948
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1949
+
1950
+ if (scratch->in_table_header) {
1951
+ print_const("</th>\n");
1952
+ } else {
1953
+ print_const("</td>\n");
1954
+ }
1955
+
1956
+ if (t->next) {
1957
+ scratch->table_cell_count += t->next->len;
1958
+ } else {
1959
+ scratch->table_cell_count++;
1960
+ }
1961
+
1962
+ break;
1963
+
1964
+ case TABLE_DIVIDER:
1965
+ break;
1966
+
1967
+ case TABLE_ROW:
1968
+ print_const("<tr>\n");
1969
+ scratch->table_cell_count = 0;
1970
+ mmd_export_token_tree_html(out, source, t->child, scratch);
1971
+ print_const("</tr>\n");
1972
+ break;
1973
+
1974
+ case TEXT_LINEBREAK:
1975
+ if (t->next) {
1976
+ print_const("<br />\n");
1977
+ scratch->padded = 1;
1978
+ }
1979
+
1980
+ break;
1981
+
1982
+ case CODE_FENCE:
1983
+ case TEXT_EMPTY:
1984
+ case MANUAL_LABEL:
1985
+ break;
1986
+
1987
+ case TEXT_NL:
1988
+ if (t->next) {
1989
+ print_char('\n');
1990
+ }
1991
+
1992
+ break;
1993
+
1994
+ case RAW_FILTER_LEFT:
1995
+ case TEXT_BACKSLASH:
1996
+ case TEXT_BRACE_LEFT:
1997
+ case TEXT_BRACE_RIGHT:
1998
+ case TEXT_HASH:
1999
+ case TEXT_NUMBER_POSS_LIST:
2000
+ case TEXT_PERCENT:
2001
+ case TEXT_PERIOD:
2002
+ case TEXT_PLAIN:
2003
+ case TOC:
2004
+ print_token(t);
2005
+ break;
2006
+
2007
+ case UL:
2008
+ print_token(t);
2009
+ break;
2010
+
2011
+ default:
2012
+ fprintf(stderr, "Unknown token type: %d (%lu:%lu)\n", t->type, t->start, t->len);
2013
+ token_describe(t, source);
2014
+ break;
2015
+ }
2016
+ }
2017
+
2018
+
2019
+ void mmd_export_token_tree_html(DString * out, const char * source, token * t, scratch_pad * scratch) {
2020
+
2021
+ // Prevent stack overflow with "dangerous" input causing extreme recursion
2022
+ if (scratch->recurse_depth == kMaxExportRecursiveDepth) {
2023
+ return;
2024
+ }
2025
+
2026
+ scratch->recurse_depth++;
2027
+
2028
+ while (t != NULL) {
2029
+ if (scratch->skip_token) {
2030
+ scratch->skip_token--;
2031
+ } else {
2032
+ mmd_export_token_html(out, source, t, scratch);
2033
+ }
2034
+
2035
+ t = t->next;
2036
+ }
2037
+
2038
+ scratch->recurse_depth--;
2039
+ }
2040
+
2041
+
2042
+ void mmd_export_token_html_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
2043
+ if (t == NULL) {
2044
+ return;
2045
+ }
2046
+
2047
+ switch (t->type) {
2048
+ case BACKTICK:
2049
+ print_token(t);
2050
+ break;
2051
+
2052
+ case AMPERSAND:
2053
+ print_const("&amp;");
2054
+ break;
2055
+
2056
+ case AMPERSAND_LONG:
2057
+ print_const("&amp;amp;");
2058
+ break;
2059
+
2060
+ case ANGLE_RIGHT:
2061
+ print_const("&gt;");
2062
+ break;
2063
+
2064
+ case ANGLE_LEFT:
2065
+ print_const("&lt;");
2066
+ break;
2067
+
2068
+ case ESCAPED_CHARACTER:
2069
+ print_const("\\");
2070
+ mmd_print_char_html(out, source[t->start + 1], false);
2071
+ break;
2072
+
2073
+ case HTML_ENTITY:
2074
+ print_const("&amp;");
2075
+ d_string_append_c_array(out, &(source[t->start + 1]), t->len - 1);
2076
+ break;
2077
+
2078
+ case MATH_BRACKET_OPEN:
2079
+ print_const("\\\\[");
2080
+ break;
2081
+
2082
+ case MATH_BRACKET_CLOSE:
2083
+ print_const("\\\\]");
2084
+ break;
2085
+
2086
+ case MATH_DOLLAR_SINGLE:
2087
+ if (t->mate) {
2088
+ (t->start < t->mate->start) ? ( print_const("\\(") ) : ( print_const("\\)") );
2089
+ } else {
2090
+ print_const("$");
2091
+ }
2092
+
2093
+ break;
2094
+
2095
+ case MATH_DOLLAR_DOUBLE:
2096
+ if (t->mate) {
2097
+ (t->start < t->mate->start) ? ( print_const("\\[") ) : ( print_const("\\]") );
2098
+ } else {
2099
+ print_const("$$");
2100
+ }
2101
+
2102
+ break;
2103
+
2104
+ case MATH_PAREN_OPEN:
2105
+ print_const("\\\\(");
2106
+ break;
2107
+
2108
+ case MATH_PAREN_CLOSE:
2109
+ print_const("\\\\)");
2110
+ break;
2111
+
2112
+ case QUOTE_DOUBLE:
2113
+ print_const("&quot;");
2114
+ break;
2115
+
2116
+ case SUBSCRIPT:
2117
+ if (t->child) {
2118
+ print_const("~");
2119
+ mmd_export_token_tree_html_raw(out, source, t->child, scratch);
2120
+ } else {
2121
+ print_token(t);
2122
+ }
2123
+
2124
+ break;
2125
+
2126
+ case SUPERSCRIPT:
2127
+ if (t->child) {
2128
+ print_const("^");
2129
+ mmd_export_token_tree_html_raw(out, source, t->child, scratch);
2130
+ } else {
2131
+ print_token(t);
2132
+ }
2133
+
2134
+ break;
2135
+
2136
+ case CODE_FENCE:
2137
+ if (t->next) {
2138
+ t->next->type = TEXT_EMPTY;
2139
+ }
2140
+
2141
+ case TEXT_EMPTY:
2142
+ break;
2143
+
2144
+ default:
2145
+ if (t->child) {
2146
+ mmd_export_token_tree_html_raw(out, source, t->child, scratch);
2147
+ } else {
2148
+ print_token(t);
2149
+ }
2150
+
2151
+ break;
2152
+ }
2153
+ }
2154
+
2155
+
2156
+ void mmd_export_token_html_math(DString * out, const char * source, token * t, scratch_pad * scratch) {
2157
+ if (t == NULL) {
2158
+ return;
2159
+ }
2160
+
2161
+ switch (t->type) {
2162
+ case MATH_BRACKET_OPEN:
2163
+ print_const("\\[");
2164
+ break;
2165
+
2166
+ case MATH_BRACKET_CLOSE:
2167
+ print_const("\\]");
2168
+ break;
2169
+
2170
+ case MATH_PAREN_OPEN:
2171
+ print_const("\\(");
2172
+ break;
2173
+
2174
+ case MATH_PAREN_CLOSE:
2175
+ print_const("\\)");
2176
+ break;
2177
+
2178
+ default:
2179
+ mmd_export_token_html_raw(out, source, t, scratch);
2180
+ break;
2181
+ }
2182
+ }
2183
+
2184
+
2185
+ void mmd_start_complete_html(DString * out, const char * source, scratch_pad * scratch) {
2186
+ meta * m;
2187
+
2188
+ print_const("<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\"");
2189
+ HASH_FIND_STR(scratch->meta_hash, "language", m);
2190
+
2191
+ if (m) {
2192
+ printf(" lang=\"%s\"", m->value);
2193
+ } else {
2194
+ switch (scratch->language) {
2195
+ case LC_ES:
2196
+ print_const(" lang=\"es\"");
2197
+ break;
2198
+
2199
+ case LC_DE:
2200
+ print_const(" lang=\"de\"");
2201
+ break;
2202
+
2203
+ case LC_FR:
2204
+ print_const(" lang=\"fr\"");
2205
+ break;
2206
+
2207
+ case LC_NL:
2208
+ print_const(" lang=\"nl\"");
2209
+ break;
2210
+
2211
+ case LC_SV:
2212
+ print_const(" lang=\"sv\"");
2213
+ break;
2214
+
2215
+ default:
2216
+ print_const(" lang=\"en\"");
2217
+ }
2218
+ }
2219
+
2220
+ print_const(">\n<head>\n\t<meta charset=\"utf-8\"/>\n");
2221
+
2222
+ // Iterate over metadata keys
2223
+
2224
+ for (m = scratch->meta_hash; m != NULL; m = m->hh.next) {
2225
+ if (strcmp(m->key, "baseheaderlevel") == 0) {
2226
+ } else if (strcmp(m->key, "bibliostyle") == 0) {
2227
+ } else if (strcmp(m->key, "bibtex") == 0) {
2228
+ } else if (strcmp(m->key, "css") == 0) {
2229
+ print_const("\t<link type=\"text/css\" rel=\"stylesheet\" href=\"");
2230
+
2231
+ if (scratch->store_assets) {
2232
+ store_asset(scratch, m->value);
2233
+ asset * a = extract_asset(scratch, m->value);
2234
+
2235
+ mmd_print_string_html(out, "assets/", false);
2236
+ mmd_print_string_html(out, a->asset_path, false);
2237
+ } else {
2238
+ mmd_print_string_html(out, m->value, false);
2239
+ }
2240
+
2241
+ print_const("\"/>\n");
2242
+ } else if (strcmp(m->key, "htmlfooter") == 0) {
2243
+ } else if (strcmp(m->key, "htmlheader") == 0) {
2244
+ print(m->value);
2245
+ print_char('\n');
2246
+ } else if (strcmp(m->key, "htmlheaderlevel") == 0) {
2247
+ } else if (strcmp(m->key, "language") == 0) {
2248
+ } else if (strcmp(m->key, "latexbegin") == 0) {
2249
+ } else if (strcmp(m->key, "latexconfig") == 0) {
2250
+ } else if (strcmp(m->key, "latexfooter") == 0) {
2251
+ } else if (strcmp(m->key, "latexheaderlevel") == 0) {
2252
+ } else if (strcmp(m->key, "latexinput") == 0) {
2253
+ } else if (strcmp(m->key, "latexleader") == 0) {
2254
+ } else if (strcmp(m->key, "latexmode") == 0) {
2255
+ } else if (strcmp(m->key, "mmdfooter") == 0) {
2256
+ } else if (strcmp(m->key, "mmdheader") == 0) {
2257
+ } else if (strcmp(m->key, "quoteslanguage") == 0) {
2258
+ } else if (strcmp(m->key, "title") == 0) {
2259
+ print_const("\t<title>");
2260
+ mmd_print_string_html(out, m->value, false);
2261
+ print_const("</title>\n");
2262
+ } else if (strcmp(m->key, "transcludebase") == 0) {
2263
+ } else if (strcmp(m->key, "xhtmlheader") == 0) {
2264
+ print(m->value);
2265
+ print_char('\n');
2266
+ } else if (strcmp(m->key, "xhtmlheaderlevel") == 0) {
2267
+ } else {
2268
+ print_const("\t<meta name=\"");
2269
+ mmd_print_string_html(out, m->key, false);
2270
+ print_const("\" content=\"");
2271
+ mmd_print_string_html(out, m->value, false);
2272
+ print_const("\"/>\n");
2273
+ }
2274
+ }
2275
+
2276
+ print_const("</head>\n<body>\n\n");
2277
+ }
2278
+
2279
+
2280
+ void mmd_end_complete_html(DString * out, const char * source, scratch_pad * scratch) {
2281
+ print_const("\n\n</body>\n</html>\n");
2282
+ }
2283
+
2284
+
2285
+ void mmd_export_token_tree_html_raw(DString * out, const char * source, token * t, scratch_pad * scratch) {
2286
+ while (t != NULL) {
2287
+ if (scratch->skip_token) {
2288
+ scratch->skip_token--;
2289
+ } else {
2290
+ mmd_export_token_html_raw(out, source, t, scratch);
2291
+ }
2292
+
2293
+ t = t->next;
2294
+ }
2295
+ }
2296
+
2297
+
2298
+ void mmd_export_token_tree_html_math(DString * out, const char * source, token * t, scratch_pad * scratch) {
2299
+ while (t != NULL) {
2300
+ if (scratch->skip_token) {
2301
+ scratch->skip_token--;
2302
+ } else {
2303
+ mmd_export_token_html_math(out, source, t, scratch);
2304
+ }
2305
+
2306
+ t = t->next;
2307
+ }
2308
+ }
2309
+
2310
+
2311
+ void mmd_export_footnote_list_html(DString * out, const char * source, scratch_pad * scratch) {
2312
+ if (scratch->used_footnotes->size > 0) {
2313
+ footnote * note;
2314
+ token * content;
2315
+
2316
+ pad(out, 2, scratch);
2317
+ print_const("<div class=\"footnotes\">\n<hr />\n<ol>");
2318
+ scratch->padded = 0;
2319
+
2320
+ for (int i = 0; i < scratch->used_footnotes->size; ++i) {
2321
+ // Export footnote
2322
+ pad(out, 2, scratch);
2323
+
2324
+ printf("<li id=\"fn:%d\">\n", i + 1);
2325
+ scratch->padded = 6;
2326
+
2327
+ note = stack_peek_index(scratch->used_footnotes, i);
2328
+ content = note->content;
2329
+
2330
+ scratch->footnote_para_counter = 0;
2331
+
2332
+ // We need to know which block is the last one in the footnote
2333
+ while (content) {
2334
+ if (content->type == BLOCK_PARA) {
2335
+ scratch->footnote_para_counter++;
2336
+ }
2337
+
2338
+ content = content->next;
2339
+ }
2340
+
2341
+ content = note->content;
2342
+ scratch->footnote_being_printed = i + 1;
2343
+
2344
+ mmd_export_token_tree_html(out, source, content, scratch);
2345
+
2346
+ pad(out, 1, scratch);
2347
+ printf("</li>");
2348
+ scratch->padded = 0;
2349
+ }
2350
+
2351
+ pad(out, 2, scratch);
2352
+ print_const("</ol>\n</div>");
2353
+ scratch->padded = 0;
2354
+ scratch->footnote_being_printed = 0;
2355
+ }
2356
+ }
2357
+
2358
+
2359
+ void mmd_export_glossary_list_html(DString * out, const char * source, scratch_pad * scratch) {
2360
+ if (scratch->used_glossaries->size > 0) {
2361
+ footnote * note;
2362
+ token * content;
2363
+
2364
+ pad(out, 2, scratch);
2365
+ print_const("<div class=\"glossary\">\n<hr />\n<ol>");
2366
+ scratch->padded = 0;
2367
+
2368
+ for (int i = 0; i < scratch->used_glossaries->size; ++i) {
2369
+ // Export glossary
2370
+ pad(out, 2, scratch);
2371
+
2372
+ printf("<li id=\"gn:%d\">\n", i + 1);
2373
+ scratch->padded = 6;
2374
+
2375
+ note = stack_peek_index(scratch->used_glossaries, i);
2376
+ content = note->content;
2377
+
2378
+ // Print term
2379
+ mmd_print_string_html(out, note->clean_text, false);
2380
+ print_const(": ");
2381
+
2382
+ // Print contents
2383
+ scratch->footnote_para_counter = 0;
2384
+
2385
+ // We need to know which block is the last one in the footnote
2386
+ while (content) {
2387
+ if (content->type == BLOCK_PARA) {
2388
+ scratch->footnote_para_counter++;
2389
+ }
2390
+
2391
+ content = content->next;
2392
+ }
2393
+
2394
+ content = note->content;
2395
+ scratch->glossary_being_printed = i + 1;
2396
+
2397
+ mmd_export_token_tree_html(out, source, content, scratch);
2398
+
2399
+ pad(out, 1, scratch);
2400
+ printf("</li>");
2401
+ scratch->padded = 0;
2402
+ }
2403
+
2404
+ pad(out, 2, scratch);
2405
+ print_const("</ol>\n</div>");
2406
+ scratch->padded = 0;
2407
+ scratch->glossary_being_printed = 0;
2408
+ }
2409
+ }
2410
+
2411
+
2412
+ void mmd_export_citation_list_html(DString * out, const char * source, scratch_pad * scratch) {
2413
+ if (scratch->used_citations->size > 0) {
2414
+ footnote * note;
2415
+ token * content;
2416
+
2417
+ pad(out, 2, scratch);
2418
+ print_const("<div class=\"citations\">\n<hr />\n<ol>");
2419
+ scratch->padded = 0;
2420
+
2421
+ for (int i = 0; i < scratch->used_citations->size; ++i) {
2422
+ // Export footnote
2423
+ pad(out, 2, scratch);
2424
+
2425
+ printf("<li id=\"cn:%d\">\n", i + 1);
2426
+ scratch->padded = 6;
2427
+
2428
+ note = stack_peek_index(scratch->used_citations, i);
2429
+ content = note->content;
2430
+
2431
+ scratch->footnote_para_counter = 0;
2432
+
2433
+ // We need to know which block is the last one in the footnote
2434
+ while (content) {
2435
+ if (content->type == BLOCK_PARA) {
2436
+ scratch->footnote_para_counter++;
2437
+ }
2438
+
2439
+ content = content->next;
2440
+ }
2441
+
2442
+ content = note->content;
2443
+ scratch->citation_being_printed = i + 1;
2444
+
2445
+ mmd_export_token_tree_html(out, source, content, scratch);
2446
+
2447
+ pad(out, 1, scratch);
2448
+ printf("</li>");
2449
+ scratch->padded = 0;
2450
+ }
2451
+
2452
+ pad(out, 2, scratch);
2453
+ print_const("</ol>\n</div>");
2454
+ scratch->padded = 0;
2455
+ scratch->citation_being_printed = 0;
2456
+ }
2457
+ }
2458
+
2459
+
2460
+