qiita_marker 0.23.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +50 -0
  4. data/Rakefile +113 -0
  5. data/bin/qiita_marker +123 -0
  6. data/ext/qiita_marker/arena.c +103 -0
  7. data/ext/qiita_marker/autolink.c +425 -0
  8. data/ext/qiita_marker/autolink.h +8 -0
  9. data/ext/qiita_marker/blocks.c +1596 -0
  10. data/ext/qiita_marker/buffer.c +278 -0
  11. data/ext/qiita_marker/buffer.h +116 -0
  12. data/ext/qiita_marker/case_fold_switch.inc +4327 -0
  13. data/ext/qiita_marker/chunk.h +135 -0
  14. data/ext/qiita_marker/cmark-gfm-core-extensions.h +54 -0
  15. data/ext/qiita_marker/cmark-gfm-extension_api.h +736 -0
  16. data/ext/qiita_marker/cmark-gfm-extensions_export.h +42 -0
  17. data/ext/qiita_marker/cmark-gfm.h +817 -0
  18. data/ext/qiita_marker/cmark-gfm_export.h +42 -0
  19. data/ext/qiita_marker/cmark-gfm_version.h +7 -0
  20. data/ext/qiita_marker/cmark.c +55 -0
  21. data/ext/qiita_marker/cmark_ctype.c +44 -0
  22. data/ext/qiita_marker/cmark_ctype.h +33 -0
  23. data/ext/qiita_marker/commonmark.c +529 -0
  24. data/ext/qiita_marker/config.h +76 -0
  25. data/ext/qiita_marker/core-extensions.c +27 -0
  26. data/ext/qiita_marker/entities.inc +2138 -0
  27. data/ext/qiita_marker/ext_scanners.c +879 -0
  28. data/ext/qiita_marker/ext_scanners.h +24 -0
  29. data/ext/qiita_marker/extconf.rb +7 -0
  30. data/ext/qiita_marker/footnotes.c +63 -0
  31. data/ext/qiita_marker/footnotes.h +27 -0
  32. data/ext/qiita_marker/houdini.h +57 -0
  33. data/ext/qiita_marker/houdini_href_e.c +100 -0
  34. data/ext/qiita_marker/houdini_html_e.c +66 -0
  35. data/ext/qiita_marker/houdini_html_u.c +149 -0
  36. data/ext/qiita_marker/html.c +486 -0
  37. data/ext/qiita_marker/html.h +27 -0
  38. data/ext/qiita_marker/inlines.c +1691 -0
  39. data/ext/qiita_marker/inlines.h +29 -0
  40. data/ext/qiita_marker/iterator.c +159 -0
  41. data/ext/qiita_marker/iterator.h +26 -0
  42. data/ext/qiita_marker/latex.c +466 -0
  43. data/ext/qiita_marker/linked_list.c +37 -0
  44. data/ext/qiita_marker/man.c +278 -0
  45. data/ext/qiita_marker/map.c +122 -0
  46. data/ext/qiita_marker/map.h +41 -0
  47. data/ext/qiita_marker/node.c +979 -0
  48. data/ext/qiita_marker/node.h +125 -0
  49. data/ext/qiita_marker/parser.h +58 -0
  50. data/ext/qiita_marker/plaintext.c +235 -0
  51. data/ext/qiita_marker/plugin.c +36 -0
  52. data/ext/qiita_marker/plugin.h +34 -0
  53. data/ext/qiita_marker/qiita_marker.c +1321 -0
  54. data/ext/qiita_marker/qiita_marker.h +16 -0
  55. data/ext/qiita_marker/references.c +42 -0
  56. data/ext/qiita_marker/references.h +26 -0
  57. data/ext/qiita_marker/registry.c +63 -0
  58. data/ext/qiita_marker/registry.h +24 -0
  59. data/ext/qiita_marker/render.c +205 -0
  60. data/ext/qiita_marker/render.h +62 -0
  61. data/ext/qiita_marker/scanners.c +10520 -0
  62. data/ext/qiita_marker/scanners.h +62 -0
  63. data/ext/qiita_marker/scanners.re +341 -0
  64. data/ext/qiita_marker/strikethrough.c +167 -0
  65. data/ext/qiita_marker/strikethrough.h +9 -0
  66. data/ext/qiita_marker/syntax_extension.c +149 -0
  67. data/ext/qiita_marker/syntax_extension.h +34 -0
  68. data/ext/qiita_marker/table.c +822 -0
  69. data/ext/qiita_marker/table.h +12 -0
  70. data/ext/qiita_marker/tagfilter.c +60 -0
  71. data/ext/qiita_marker/tagfilter.h +8 -0
  72. data/ext/qiita_marker/tasklist.c +156 -0
  73. data/ext/qiita_marker/tasklist.h +8 -0
  74. data/ext/qiita_marker/utf8.c +317 -0
  75. data/ext/qiita_marker/utf8.h +35 -0
  76. data/ext/qiita_marker/xml.c +181 -0
  77. data/lib/qiita_marker/config.rb +52 -0
  78. data/lib/qiita_marker/node/inspect.rb +57 -0
  79. data/lib/qiita_marker/node.rb +83 -0
  80. data/lib/qiita_marker/renderer/html_renderer.rb +252 -0
  81. data/lib/qiita_marker/renderer.rb +135 -0
  82. data/lib/qiita_marker/version.rb +5 -0
  83. data/lib/qiita_marker.rb +45 -0
  84. data/qiita_marker.gemspec +40 -0
  85. data/test/benchmark.rb +32 -0
  86. data/test/fixtures/curly.md +1 -0
  87. data/test/fixtures/dingus.md +10 -0
  88. data/test/fixtures/strong.md +1 -0
  89. data/test/fixtures/table.md +10 -0
  90. data/test/test_attributes.rb +24 -0
  91. data/test/test_basics.rb +35 -0
  92. data/test/test_commands.rb +72 -0
  93. data/test/test_commonmark.rb +36 -0
  94. data/test/test_doc.rb +130 -0
  95. data/test/test_encoding.rb +23 -0
  96. data/test/test_extensions.rb +116 -0
  97. data/test/test_footnotes.rb +60 -0
  98. data/test/test_gc.rb +47 -0
  99. data/test/test_helper.rb +71 -0
  100. data/test/test_linebreaks.rb +15 -0
  101. data/test/test_maliciousness.rb +262 -0
  102. data/test/test_node.rb +89 -0
  103. data/test/test_options.rb +37 -0
  104. data/test/test_pathological_inputs.rb +94 -0
  105. data/test/test_plaintext.rb +46 -0
  106. data/test/test_renderer.rb +47 -0
  107. data/test/test_smartpunct.rb +27 -0
  108. data/test/test_spec.rb +30 -0
  109. data/test/test_tasklists.rb +43 -0
  110. data/test/test_xml.rb +107 -0
  111. metadata +313 -0
@@ -0,0 +1,486 @@
1
+ #include <stdlib.h>
2
+ #include <stdio.h>
3
+ #include <string.h>
4
+ #include <assert.h>
5
+ #include "cmark_ctype.h"
6
+ #include "config.h"
7
+ #include "cmark-gfm.h"
8
+ #include "houdini.h"
9
+ #include "scanners.h"
10
+ #include "syntax_extension.h"
11
+ #include "html.h"
12
+ #include "render.h"
13
+
14
+ // Functions to convert cmark_nodes to HTML strings.
15
+
16
+ static void escape_html(cmark_strbuf *dest, const unsigned char *source,
17
+ bufsize_t length) {
18
+ houdini_escape_html0(dest, source, length, 0);
19
+ }
20
+
21
+ static void filter_html_block(cmark_html_renderer *renderer, uint8_t *data, size_t len) {
22
+ cmark_strbuf *html = renderer->html;
23
+ cmark_llist *it;
24
+ cmark_syntax_extension *ext;
25
+ bool filtered;
26
+ uint8_t *match;
27
+
28
+ while (len) {
29
+ match = (uint8_t *) memchr(data, '<', len);
30
+ if (!match)
31
+ break;
32
+
33
+ if (match != data) {
34
+ cmark_strbuf_put(html, data, (bufsize_t)(match - data));
35
+ len -= (match - data);
36
+ data = match;
37
+ }
38
+
39
+ filtered = false;
40
+ for (it = renderer->filter_extensions; it; it = it->next) {
41
+ ext = ((cmark_syntax_extension *) it->data);
42
+ if (!ext->html_filter_func(ext, data, len)) {
43
+ filtered = true;
44
+ break;
45
+ }
46
+ }
47
+
48
+ if (!filtered) {
49
+ cmark_strbuf_putc(html, '<');
50
+ } else {
51
+ cmark_strbuf_puts(html, "&lt;");
52
+ }
53
+
54
+ ++data;
55
+ --len;
56
+ }
57
+
58
+ if (len)
59
+ cmark_strbuf_put(html, data, (bufsize_t)len);
60
+ }
61
+
62
+ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *html, cmark_node *node) {
63
+ if (renderer->written_footnote_ix >= renderer->footnote_ix)
64
+ return false;
65
+ renderer->written_footnote_ix = renderer->footnote_ix;
66
+
67
+ cmark_strbuf_puts(html, "<a href=\"#fnref-");
68
+ houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
69
+ cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref aria-label=\"Back to content\">↩</a>");
70
+
71
+ if (node->footnote.def_count > 1)
72
+ {
73
+ for(int i = 2; i <= node->footnote.def_count; i++) {
74
+ char n[32];
75
+ snprintf(n, sizeof(n), "%d", i);
76
+
77
+ cmark_strbuf_puts(html, " <a href=\"#fnref-");
78
+ houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
79
+ cmark_strbuf_puts(html, "-");
80
+ cmark_strbuf_puts(html, n);
81
+ cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref aria-label=\"Back to content\">↩<sup class=\"footnote-ref\">");
82
+ cmark_strbuf_puts(html, n);
83
+ cmark_strbuf_puts(html, "</sup></a>");
84
+ }
85
+ }
86
+
87
+ return true;
88
+ }
89
+
90
+ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
91
+ cmark_event_type ev_type, int options) {
92
+ cmark_node *parent;
93
+ cmark_node *grandparent;
94
+ cmark_strbuf *html = renderer->html;
95
+ cmark_llist *it;
96
+ cmark_syntax_extension *ext;
97
+ char start_heading[] = "<h0";
98
+ char end_heading[] = "</h0";
99
+ bool tight;
100
+ bool filtered;
101
+ char buffer[BUFFER_SIZE];
102
+
103
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
104
+
105
+ if (renderer->plain == node) { // back at original node
106
+ renderer->plain = NULL;
107
+ }
108
+
109
+ if (renderer->plain != NULL) {
110
+ switch (node->type) {
111
+ case CMARK_NODE_TEXT:
112
+ case CMARK_NODE_CODE:
113
+ case CMARK_NODE_HTML_INLINE:
114
+ escape_html(html, node->as.literal.data, node->as.literal.len);
115
+ break;
116
+
117
+ case CMARK_NODE_LINEBREAK:
118
+ case CMARK_NODE_SOFTBREAK:
119
+ cmark_strbuf_putc(html, ' ');
120
+ break;
121
+
122
+ default:
123
+ break;
124
+ }
125
+ return 1;
126
+ }
127
+
128
+ if (node->extension && node->extension->html_render_func) {
129
+ node->extension->html_render_func(node->extension, renderer, node, ev_type, options);
130
+ return 1;
131
+ }
132
+
133
+ switch (node->type) {
134
+ case CMARK_NODE_DOCUMENT:
135
+ break;
136
+
137
+ case CMARK_NODE_BLOCK_QUOTE:
138
+ if (entering) {
139
+ cmark_html_render_cr(html);
140
+ cmark_strbuf_puts(html, "<blockquote");
141
+ cmark_html_render_sourcepos(node, html, options);
142
+ cmark_strbuf_puts(html, ">\n");
143
+ } else {
144
+ cmark_html_render_cr(html);
145
+ cmark_strbuf_puts(html, "</blockquote>\n");
146
+ }
147
+ break;
148
+
149
+ case CMARK_NODE_LIST: {
150
+ cmark_list_type list_type = node->as.list.list_type;
151
+ int start = node->as.list.start;
152
+
153
+ if (entering) {
154
+ cmark_html_render_cr(html);
155
+ if (list_type == CMARK_BULLET_LIST) {
156
+ cmark_strbuf_puts(html, "<ul");
157
+ cmark_html_render_sourcepos(node, html, options);
158
+ cmark_strbuf_puts(html, ">\n");
159
+ } else if (start == 1) {
160
+ cmark_strbuf_puts(html, "<ol");
161
+ cmark_html_render_sourcepos(node, html, options);
162
+ cmark_strbuf_puts(html, ">\n");
163
+ } else {
164
+ snprintf(buffer, BUFFER_SIZE, "<ol start=\"%d\"", start);
165
+ cmark_strbuf_puts(html, buffer);
166
+ cmark_html_render_sourcepos(node, html, options);
167
+ cmark_strbuf_puts(html, ">\n");
168
+ }
169
+ } else {
170
+ cmark_strbuf_puts(html,
171
+ list_type == CMARK_BULLET_LIST ? "</ul>\n" : "</ol>\n");
172
+ }
173
+ break;
174
+ }
175
+
176
+ case CMARK_NODE_ITEM:
177
+ if (entering) {
178
+ cmark_html_render_cr(html);
179
+ cmark_strbuf_puts(html, "<li");
180
+ cmark_html_render_sourcepos(node, html, options);
181
+ cmark_strbuf_putc(html, '>');
182
+ } else {
183
+ cmark_strbuf_puts(html, "</li>\n");
184
+ }
185
+ break;
186
+
187
+ case CMARK_NODE_HEADING:
188
+ if (entering) {
189
+ cmark_html_render_cr(html);
190
+ start_heading[2] = (char)('0' + node->as.heading.level);
191
+ cmark_strbuf_puts(html, start_heading);
192
+ cmark_html_render_sourcepos(node, html, options);
193
+ cmark_strbuf_putc(html, '>');
194
+ } else {
195
+ end_heading[3] = (char)('0' + node->as.heading.level);
196
+ cmark_strbuf_puts(html, end_heading);
197
+ cmark_strbuf_puts(html, ">\n");
198
+ }
199
+ break;
200
+
201
+ case CMARK_NODE_CODE_BLOCK:
202
+ cmark_html_render_cr(html);
203
+
204
+ if (node->as.code.info.len == 0) {
205
+ cmark_strbuf_puts(html, "<pre");
206
+ cmark_html_render_sourcepos(node, html, options);
207
+ cmark_strbuf_puts(html, "><code>");
208
+ } else {
209
+ bufsize_t first_tag = 0;
210
+ while (first_tag < node->as.code.info.len &&
211
+ !cmark_isspace(node->as.code.info.data[first_tag])) {
212
+ first_tag += 1;
213
+ }
214
+
215
+ if (options & CMARK_OPT_GITHUB_PRE_LANG) {
216
+ cmark_strbuf_puts(html, "<pre");
217
+ cmark_html_render_sourcepos(node, html, options);
218
+ cmark_strbuf_puts(html, " lang=\"");
219
+ escape_html(html, node->as.code.info.data, first_tag);
220
+ if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) {
221
+ cmark_strbuf_puts(html, "\" data-meta=\"");
222
+ escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1);
223
+ }
224
+ cmark_strbuf_puts(html, "\"><code>");
225
+ } else {
226
+ cmark_strbuf_puts(html, "<pre");
227
+ cmark_html_render_sourcepos(node, html, options);
228
+ cmark_strbuf_puts(html, "><code class=\"language-");
229
+ escape_html(html, node->as.code.info.data, first_tag);
230
+ if (first_tag < node->as.code.info.len && (options & CMARK_OPT_FULL_INFO_STRING)) {
231
+ cmark_strbuf_puts(html, "\" data-meta=\"");
232
+ escape_html(html, node->as.code.info.data + first_tag + 1, node->as.code.info.len - first_tag - 1);
233
+ }
234
+ cmark_strbuf_puts(html, "\">");
235
+ }
236
+ }
237
+
238
+ escape_html(html, node->as.code.literal.data, node->as.code.literal.len);
239
+ cmark_strbuf_puts(html, "</code></pre>\n");
240
+ break;
241
+
242
+ case CMARK_NODE_HTML_BLOCK:
243
+ cmark_html_render_cr(html);
244
+ if (!(options & CMARK_OPT_UNSAFE)) {
245
+ cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
246
+ } else if (renderer->filter_extensions) {
247
+ filter_html_block(renderer, node->as.literal.data, node->as.literal.len);
248
+ } else {
249
+ cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
250
+ }
251
+ cmark_html_render_cr(html);
252
+ break;
253
+
254
+ case CMARK_NODE_CUSTOM_BLOCK:
255
+ cmark_html_render_cr(html);
256
+ if (entering) {
257
+ cmark_strbuf_put(html, node->as.custom.on_enter.data,
258
+ node->as.custom.on_enter.len);
259
+ } else {
260
+ cmark_strbuf_put(html, node->as.custom.on_exit.data,
261
+ node->as.custom.on_exit.len);
262
+ }
263
+ cmark_html_render_cr(html);
264
+ break;
265
+
266
+ case CMARK_NODE_THEMATIC_BREAK:
267
+ cmark_html_render_cr(html);
268
+ cmark_strbuf_puts(html, "<hr");
269
+ cmark_html_render_sourcepos(node, html, options);
270
+ cmark_strbuf_puts(html, " />\n");
271
+ break;
272
+
273
+ case CMARK_NODE_PARAGRAPH:
274
+ parent = cmark_node_parent(node);
275
+ grandparent = cmark_node_parent(parent);
276
+ if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
277
+ tight = grandparent->as.list.tight;
278
+ } else {
279
+ tight = false;
280
+ }
281
+ if (!tight) {
282
+ if (entering) {
283
+ cmark_html_render_cr(html);
284
+ cmark_strbuf_puts(html, "<p");
285
+ cmark_html_render_sourcepos(node, html, options);
286
+ cmark_strbuf_putc(html, '>');
287
+ } else {
288
+ if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) {
289
+ cmark_strbuf_putc(html, ' ');
290
+ S_put_footnote_backref(renderer, html, parent);
291
+ }
292
+ cmark_strbuf_puts(html, "</p>\n");
293
+ }
294
+ }
295
+ break;
296
+
297
+ case CMARK_NODE_TEXT:
298
+ escape_html(html, node->as.literal.data, node->as.literal.len);
299
+ break;
300
+
301
+ case CMARK_NODE_LINEBREAK:
302
+ cmark_strbuf_puts(html, "<br />\n");
303
+ break;
304
+
305
+ case CMARK_NODE_SOFTBREAK:
306
+ if (options & CMARK_OPT_HARDBREAKS) {
307
+ cmark_strbuf_puts(html, "<br />\n");
308
+ } else if (options & CMARK_OPT_NOBREAKS) {
309
+ cmark_strbuf_putc(html, ' ');
310
+ } else {
311
+ cmark_strbuf_putc(html, '\n');
312
+ }
313
+ break;
314
+
315
+ case CMARK_NODE_CODE:
316
+ cmark_strbuf_puts(html, "<code>");
317
+ escape_html(html, node->as.literal.data, node->as.literal.len);
318
+ cmark_strbuf_puts(html, "</code>");
319
+ break;
320
+
321
+ case CMARK_NODE_HTML_INLINE:
322
+ if (!(options & CMARK_OPT_UNSAFE)) {
323
+ cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
324
+ } else {
325
+ filtered = false;
326
+ for (it = renderer->filter_extensions; it; it = it->next) {
327
+ ext = (cmark_syntax_extension *) it->data;
328
+ if (!ext->html_filter_func(ext, node->as.literal.data, node->as.literal.len)) {
329
+ filtered = true;
330
+ break;
331
+ }
332
+ }
333
+ if (!filtered) {
334
+ cmark_strbuf_put(html, node->as.literal.data, node->as.literal.len);
335
+ } else {
336
+ cmark_strbuf_puts(html, "&lt;");
337
+ cmark_strbuf_put(html, node->as.literal.data + 1, node->as.literal.len - 1);
338
+ }
339
+ }
340
+ break;
341
+
342
+ case CMARK_NODE_CUSTOM_INLINE:
343
+ if (entering) {
344
+ cmark_strbuf_put(html, node->as.custom.on_enter.data,
345
+ node->as.custom.on_enter.len);
346
+ } else {
347
+ cmark_strbuf_put(html, node->as.custom.on_exit.data,
348
+ node->as.custom.on_exit.len);
349
+ }
350
+ break;
351
+
352
+ case CMARK_NODE_STRONG:
353
+ if (entering) {
354
+ cmark_strbuf_puts(html, "<strong>");
355
+ } else {
356
+ cmark_strbuf_puts(html, "</strong>");
357
+ }
358
+ break;
359
+
360
+ case CMARK_NODE_EMPH:
361
+ if (entering) {
362
+ cmark_strbuf_puts(html, "<em>");
363
+ } else {
364
+ cmark_strbuf_puts(html, "</em>");
365
+ }
366
+ break;
367
+
368
+ case CMARK_NODE_LINK:
369
+ if (entering) {
370
+ cmark_strbuf_puts(html, "<a href=\"");
371
+ if ((options & CMARK_OPT_UNSAFE) ||
372
+ !(scan_dangerous_url(&node->as.link.url, 0))) {
373
+ houdini_escape_href(html, node->as.link.url.data,
374
+ node->as.link.url.len);
375
+ }
376
+ if (node->as.link.title.len) {
377
+ cmark_strbuf_puts(html, "\" title=\"");
378
+ escape_html(html, node->as.link.title.data, node->as.link.title.len);
379
+ }
380
+ cmark_strbuf_puts(html, "\">");
381
+ } else {
382
+ cmark_strbuf_puts(html, "</a>");
383
+ }
384
+ break;
385
+
386
+ case CMARK_NODE_IMAGE:
387
+ if (entering) {
388
+ cmark_strbuf_puts(html, "<img src=\"");
389
+ if ((options & CMARK_OPT_UNSAFE) ||
390
+ !(scan_dangerous_url(&node->as.link.url, 0))) {
391
+ houdini_escape_href(html, node->as.link.url.data,
392
+ node->as.link.url.len);
393
+ }
394
+ cmark_strbuf_puts(html, "\" alt=\"");
395
+ renderer->plain = node;
396
+ } else {
397
+ if (node->as.link.title.len) {
398
+ cmark_strbuf_puts(html, "\" title=\"");
399
+ escape_html(html, node->as.link.title.data, node->as.link.title.len);
400
+ }
401
+
402
+ cmark_strbuf_puts(html, "\" />");
403
+ }
404
+ break;
405
+
406
+ case CMARK_NODE_FOOTNOTE_DEFINITION:
407
+ if (entering) {
408
+ if (renderer->footnote_ix == 0) {
409
+ cmark_strbuf_puts(html, "<section class=\"footnotes\" data-footnotes>\n<ol>\n");
410
+ }
411
+ ++renderer->footnote_ix;
412
+
413
+ cmark_strbuf_puts(html, "<li id=\"fn-");
414
+ houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
415
+ cmark_strbuf_puts(html, "\">\n");
416
+ } else {
417
+ if (S_put_footnote_backref(renderer, html, node)) {
418
+ cmark_strbuf_putc(html, '\n');
419
+ }
420
+ cmark_strbuf_puts(html, "</li>\n");
421
+ }
422
+ break;
423
+
424
+ case CMARK_NODE_FOOTNOTE_REFERENCE:
425
+ if (entering) {
426
+ cmark_strbuf_puts(html, "<sup class=\"footnote-ref\"><a href=\"#fn-");
427
+ houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len);
428
+ cmark_strbuf_puts(html, "\" id=\"fnref-");
429
+ houdini_escape_href(html, node->parent_footnote_def->as.literal.data, node->parent_footnote_def->as.literal.len);
430
+
431
+ if (node->footnote.ref_ix > 1) {
432
+ char n[32];
433
+ snprintf(n, sizeof(n), "%d", node->footnote.ref_ix);
434
+ cmark_strbuf_puts(html, "-");
435
+ cmark_strbuf_puts(html, n);
436
+ }
437
+
438
+ cmark_strbuf_puts(html, "\" data-footnote-ref>");
439
+ houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
440
+ cmark_strbuf_puts(html, "</a></sup>");
441
+ }
442
+ break;
443
+
444
+ default:
445
+ assert(false);
446
+ break;
447
+ }
448
+
449
+ return 1;
450
+ }
451
+
452
+ char *cmark_render_html(cmark_node *root, int options, cmark_llist *extensions) {
453
+ return cmark_render_html_with_mem(root, options, extensions, cmark_node_mem(root));
454
+ }
455
+
456
+ char *cmark_render_html_with_mem(cmark_node *root, int options, cmark_llist *extensions, cmark_mem *mem) {
457
+ char *result;
458
+ cmark_strbuf html = CMARK_BUF_INIT(mem);
459
+ cmark_event_type ev_type;
460
+ cmark_node *cur;
461
+ cmark_html_renderer renderer = {&html, NULL, NULL, 0, 0, NULL};
462
+ cmark_iter *iter = cmark_iter_new(root);
463
+
464
+ for (; extensions; extensions = extensions->next)
465
+ if (((cmark_syntax_extension *) extensions->data)->html_filter_func)
466
+ renderer.filter_extensions = cmark_llist_append(
467
+ mem,
468
+ renderer.filter_extensions,
469
+ (cmark_syntax_extension *) extensions->data);
470
+
471
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
472
+ cur = cmark_iter_get_node(iter);
473
+ S_render_node(&renderer, cur, ev_type, options);
474
+ }
475
+
476
+ if (renderer.footnote_ix) {
477
+ cmark_strbuf_puts(&html, "</ol>\n</section>\n");
478
+ }
479
+
480
+ result = (char *)cmark_strbuf_detach(&html);
481
+
482
+ cmark_llist_free(mem, renderer.filter_extensions);
483
+
484
+ cmark_iter_free(iter);
485
+ return result;
486
+ }
@@ -0,0 +1,27 @@
1
+ #ifndef CMARK_HTML_H
2
+ #define CMARK_HTML_H
3
+
4
+ #include "buffer.h"
5
+ #include "node.h"
6
+
7
+ CMARK_INLINE
8
+ static void cmark_html_render_cr(cmark_strbuf *html) {
9
+ if (html->size && html->ptr[html->size - 1] != '\n')
10
+ cmark_strbuf_putc(html, '\n');
11
+ }
12
+
13
+ #define BUFFER_SIZE 100
14
+
15
+ CMARK_INLINE
16
+ static void cmark_html_render_sourcepos(cmark_node *node, cmark_strbuf *html, int options) {
17
+ char buffer[BUFFER_SIZE];
18
+ if (CMARK_OPT_SOURCEPOS & options) {
19
+ snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"",
20
+ cmark_node_get_start_line(node), cmark_node_get_start_column(node),
21
+ cmark_node_get_end_line(node), cmark_node_get_end_column(node));
22
+ cmark_strbuf_puts(html, buffer);
23
+ }
24
+ }
25
+
26
+
27
+ #endif