rmultimarkdown 4.7.1.1 → 6.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
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
+