redcarpet 1.17.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/redcarpet/html.c CHANGED
@@ -23,87 +23,48 @@
23
23
  #include <stdio.h>
24
24
  #include <ctype.h>
25
25
 
26
- struct html_renderopt {
27
- struct {
28
- int header_count;
29
- int current_level;
30
- } toc_data;
31
-
32
- unsigned int flags;
33
- const char *close_tag;
34
- };
35
-
36
- static inline void
37
- put_scaped_char(struct buf *ob, char c)
38
- {
39
- switch (c) {
40
- case '<': BUFPUTSL(ob, "&lt;"); break;
41
- case '>': BUFPUTSL(ob, "&gt;"); break;
42
- case '&': BUFPUTSL(ob, "&amp;"); break;
43
- case '"': BUFPUTSL(ob, "&quot;"); break;
44
- default: bufputc(ob, c); break;
45
- }
46
- }
26
+ #include "houdini.h"
47
27
 
48
- /* upshtml_escape copy the buffer entity-escaping '<', '>', '&' and '"' */
49
- void
50
- upshtml_escape(struct buf *ob, const char *src, size_t size)
51
- {
52
- size_t i = 0, org;
53
- while (i < size) {
54
- /* copying directly unescaped characters */
55
- org = i;
56
- while (i < size && src[i] != '<' && src[i] != '>'
57
- && src[i] != '&' && src[i] != '"')
58
- i += 1;
59
- if (i > org) bufput(ob, src + org, i - org);
60
-
61
- /* escaping */
62
- if (i >= size) break;
63
-
64
- put_scaped_char(ob, src[i]);
65
- i++;
66
- }
67
- }
28
+ #define USE_XHTML(opt) (opt->flags & HTML_USE_XHTML)
68
29
 
69
- static int
70
- is_html_tag(struct buf *tag, const char *tagname)
30
+ int
31
+ sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname)
71
32
  {
72
- size_t i = 0;
73
-
74
- if (i < tag->size && tag->data[0] != '<')
75
- return 0;
33
+ size_t i;
34
+ int closed = 0;
76
35
 
77
- i++;
36
+ if (tag_size < 3 || tag_data[0] != '<')
37
+ return HTML_TAG_NONE;
78
38
 
79
- while (i < tag->size && isspace(tag->data[i]))
80
- i++;
81
-
82
- if (i < tag->size && tag->data[i] == '/')
83
- i++;
39
+ i = 1;
84
40
 
85
- while (i < tag->size && isspace(tag->data[i]))
41
+ if (tag_data[i] == '/') {
42
+ closed = 1;
86
43
  i++;
44
+ }
87
45
 
88
- for (; i < tag->size; ++i, ++tagname) {
46
+ for (; i < tag_size; ++i, ++tagname) {
89
47
  if (*tagname == 0)
90
48
  break;
91
49
 
92
- if (tag->data[i] != *tagname)
93
- return 0;
50
+ if (tag_data[i] != *tagname)
51
+ return HTML_TAG_NONE;
94
52
  }
95
53
 
96
- if (i == tag->size)
97
- return 0;
54
+ if (i == tag_size)
55
+ return HTML_TAG_NONE;
98
56
 
99
- return (isspace(tag->data[i]) || tag->data[i] == '>');
57
+ if (isspace(tag_data[i]) || tag_data[i] == '>')
58
+ return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN;
59
+
60
+ return HTML_TAG_NONE;
100
61
  }
101
62
 
102
63
  /********************
103
64
  * GENERIC RENDERER *
104
65
  ********************/
105
66
  static int
106
- rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *opaque)
67
+ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque)
107
68
  {
108
69
  struct html_renderopt *options = opaque;
109
70
 
@@ -111,15 +72,22 @@ rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *op
111
72
  return 0;
112
73
 
113
74
  if ((options->flags & HTML_SAFELINK) != 0 &&
114
- !is_safe_link(link->data, link->size) &&
75
+ !sd_autolink_issafe(link->data, link->size) &&
115
76
  type != MKDA_EMAIL)
116
77
  return 0;
117
78
 
118
79
  BUFPUTSL(ob, "<a href=\"");
119
80
  if (type == MKDA_EMAIL)
120
81
  BUFPUTSL(ob, "mailto:");
121
- bufput(ob, link->data, link->size);
122
- BUFPUTSL(ob, "\">");
82
+ houdini_escape_href(ob, link->data, link->size);
83
+
84
+ if (options->link_attributes) {
85
+ bufputc(ob, '\"');
86
+ options->link_attributes(ob, link, opaque);
87
+ bufputc(ob, '>');
88
+ } else {
89
+ BUFPUTSL(ob, "\">");
90
+ }
123
91
 
124
92
  /*
125
93
  * Pretty printing: if we get an email address as
@@ -127,9 +95,9 @@ rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *op
127
95
  * want to print the `mailto:` prefix
128
96
  */
129
97
  if (bufprefix(link, "mailto:") == 0) {
130
- upshtml_escape(ob, link->data + 7, link->size - 7);
98
+ houdini_escape_html(ob, link->data + 7, link->size - 7);
131
99
  } else {
132
- upshtml_escape(ob, link->data, link->size);
100
+ houdini_escape_html(ob, link->data, link->size);
133
101
  }
134
102
 
135
103
  BUFPUTSL(ob, "</a>");
@@ -138,7 +106,7 @@ rndr_autolink(struct buf *ob, struct buf *link, enum mkd_autolink type, void *op
138
106
  }
139
107
 
140
108
  static void
141
- rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
109
+ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque)
142
110
  {
143
111
  if (ob->size) bufputc(ob, '\n');
144
112
 
@@ -159,7 +127,7 @@ rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
159
127
  org++;
160
128
 
161
129
  if (cls) bufputc(ob, ' ');
162
- upshtml_escape(ob, lang->data + org, i - org);
130
+ houdini_escape_html(ob, lang->data + org, i - org);
163
131
  }
164
132
  }
165
133
 
@@ -168,75 +136,31 @@ rndr_blockcode(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
168
136
  BUFPUTSL(ob, "<pre><code>");
169
137
 
170
138
  if (text)
171
- upshtml_escape(ob, text->data, text->size);
139
+ houdini_escape_html(ob, text->data, text->size);
172
140
 
173
141
  BUFPUTSL(ob, "</code></pre>\n");
174
142
  }
175
143
 
176
- /*
177
- * GitHub style code block:
178
- *
179
- * <pre lang="LANG"><code>
180
- * ...
181
- * </pre></code>
182
- *
183
- * Unlike other parsers, we store the language identifier in the <pre>,
184
- * and don't let the user generate custom classes.
185
- *
186
- * The language identifier in the <pre> block gets postprocessed and all
187
- * the code inside gets syntax highlighted with Pygments. This is much safer
188
- * than letting the user specify a CSS class for highlighting.
189
- *
190
- * Note that we only generate HTML for the first specifier.
191
- * E.g.
192
- * ~~~~ {.python .numbered} => <pre lang="python"><code>
193
- */
194
144
  static void
195
- rndr_blockcode_github(struct buf *ob, struct buf *text, struct buf *lang, void *opaque)
145
+ rndr_blockquote(struct buf *ob, const struct buf *text, void *opaque)
196
146
  {
197
147
  if (ob->size) bufputc(ob, '\n');
198
-
199
- if (lang && lang->size) {
200
- size_t i = 0;
201
- BUFPUTSL(ob, "<pre lang=\"");
202
-
203
- while (i < lang->size && !isspace(lang->data[i]))
204
- i++;
205
-
206
- if (lang->data[0] == '.')
207
- upshtml_escape(ob, lang->data + 1, i - 1);
208
- else
209
- upshtml_escape(ob, lang->data, i);
210
-
211
- BUFPUTSL(ob, "\"><code>");
212
- } else
213
- BUFPUTSL(ob, "<pre><code>");
214
-
215
- if (text)
216
- upshtml_escape(ob, text->data, text->size);
217
-
218
- BUFPUTSL(ob, "</code></pre>\n");
219
- }
220
-
221
- static void
222
- rndr_blockquote(struct buf *ob, struct buf *text, void *opaque)
223
- {
224
148
  BUFPUTSL(ob, "<blockquote>\n");
225
149
  if (text) bufput(ob, text->data, text->size);
226
- BUFPUTSL(ob, "</blockquote>");
150
+ BUFPUTSL(ob, "</blockquote>\n");
227
151
  }
228
152
 
229
153
  static int
230
- rndr_codespan(struct buf *ob, struct buf *text, void *opaque)
154
+ rndr_codespan(struct buf *ob, const struct buf *text, void *opaque)
231
155
  {
232
156
  BUFPUTSL(ob, "<code>");
233
- if (text) upshtml_escape(ob, text->data, text->size);
157
+ if (text) houdini_escape_html(ob, text->data, text->size);
234
158
  BUFPUTSL(ob, "</code>");
235
159
  return 1;
236
160
  }
237
161
 
238
162
  static int
239
- rndr_strikethrough(struct buf *ob, struct buf *text, void *opaque)
163
+ rndr_strikethrough(struct buf *ob, const struct buf *text, void *opaque)
240
164
  {
241
165
  if (!text || !text->size)
242
166
  return 0;
@@ -248,7 +172,7 @@ rndr_strikethrough(struct buf *ob, struct buf *text, void *opaque)
248
172
  }
249
173
 
250
174
  static int
251
- rndr_double_emphasis(struct buf *ob, struct buf *text, void *opaque)
175
+ rndr_double_emphasis(struct buf *ob, const struct buf *text, void *opaque)
252
176
  {
253
177
  if (!text || !text->size)
254
178
  return 0;
@@ -261,7 +185,7 @@ rndr_double_emphasis(struct buf *ob, struct buf *text, void *opaque)
261
185
  }
262
186
 
263
187
  static int
264
- rndr_emphasis(struct buf *ob, struct buf *text, void *opaque)
188
+ rndr_emphasis(struct buf *ob, const struct buf *text, void *opaque)
265
189
  {
266
190
  if (!text || !text->size) return 0;
267
191
  BUFPUTSL(ob, "<em>");
@@ -270,11 +194,19 @@ rndr_emphasis(struct buf *ob, struct buf *text, void *opaque)
270
194
  return 1;
271
195
  }
272
196
 
197
+ static int
198
+ rndr_linebreak(struct buf *ob, void *opaque)
199
+ {
200
+ struct html_renderopt *options = opaque;
201
+ bufputs(ob, USE_XHTML(options) ? "<br/>\n" : "<br>\n");
202
+ return 1;
203
+ }
204
+
273
205
  static void
274
- rndr_header(struct buf *ob, struct buf *text, int level, void *opaque)
206
+ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
275
207
  {
276
208
  struct html_renderopt *options = opaque;
277
-
209
+
278
210
  if (ob->size)
279
211
  bufputc(ob, '\n');
280
212
 
@@ -288,26 +220,38 @@ rndr_header(struct buf *ob, struct buf *text, int level, void *opaque)
288
220
  }
289
221
 
290
222
  static int
291
- rndr_link(struct buf *ob, struct buf *link, struct buf *title, struct buf *content, void *opaque)
223
+ rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque)
292
224
  {
293
225
  struct html_renderopt *options = opaque;
294
-
295
- if ((options->flags & HTML_SAFELINK) != 0 && !is_safe_link(link->data, link->size))
226
+
227
+ if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size))
296
228
  return 0;
297
229
 
298
230
  BUFPUTSL(ob, "<a href=\"");
299
- if (link && link->size) bufput(ob, link->data, link->size);
231
+
232
+ if (link && link->size)
233
+ houdini_escape_href(ob, link->data, link->size);
234
+
300
235
  if (title && title->size) {
301
236
  BUFPUTSL(ob, "\" title=\"");
302
- upshtml_escape(ob, title->data, title->size); }
303
- BUFPUTSL(ob, "\">");
237
+ houdini_escape_html(ob, title->data, title->size);
238
+ }
239
+
240
+ if (options->link_attributes) {
241
+ bufputc(ob, '\"');
242
+ options->link_attributes(ob, link, opaque);
243
+ bufputc(ob, '>');
244
+ } else {
245
+ BUFPUTSL(ob, "\">");
246
+ }
247
+
304
248
  if (content && content->size) bufput(ob, content->data, content->size);
305
249
  BUFPUTSL(ob, "</a>");
306
250
  return 1;
307
251
  }
308
252
 
309
253
  static void
310
- rndr_list(struct buf *ob, struct buf *text, int flags, void *opaque)
254
+ rndr_list(struct buf *ob, const struct buf *text, int flags, void *opaque)
311
255
  {
312
256
  if (ob->size) bufputc(ob, '\n');
313
257
  bufput(ob, flags & MKD_LIST_ORDERED ? "<ol>\n" : "<ul>\n", 5);
@@ -316,18 +260,21 @@ rndr_list(struct buf *ob, struct buf *text, int flags, void *opaque)
316
260
  }
317
261
 
318
262
  static void
319
- rndr_listitem(struct buf *ob, struct buf *text, int flags, void *opaque)
263
+ rndr_listitem(struct buf *ob, const struct buf *text, int flags, void *opaque)
320
264
  {
321
265
  BUFPUTSL(ob, "<li>");
322
266
  if (text) {
323
- while (text->size && text->data[text->size - 1] == '\n')
324
- text->size -= 1;
325
- bufput(ob, text->data, text->size); }
267
+ size_t size = text->size;
268
+ while (size && text->data[size - 1] == '\n')
269
+ size--;
270
+
271
+ bufput(ob, text->data, size);
272
+ }
326
273
  BUFPUTSL(ob, "</li>\n");
327
274
  }
328
275
 
329
276
  static void
330
- rndr_paragraph(struct buf *ob, struct buf *text, void *opaque)
277
+ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
331
278
  {
332
279
  struct html_renderopt *options = opaque;
333
280
  size_t i = 0;
@@ -353,11 +300,14 @@ rndr_paragraph(struct buf *ob, struct buf *text, void *opaque)
353
300
  if (i > org)
354
301
  bufput(ob, text->data + org, i - org);
355
302
 
356
- if (i >= text->size)
303
+ /*
304
+ * do not insert a line break if this newline
305
+ * is the last character on the paragraph
306
+ */
307
+ if (i >= text->size - 1)
357
308
  break;
358
309
 
359
- BUFPUTSL(ob, "<br");
360
- bufputs(ob, options->close_tag);
310
+ rndr_linebreak(ob, opaque);
361
311
  i++;
362
312
  }
363
313
  } else {
@@ -367,7 +317,7 @@ rndr_paragraph(struct buf *ob, struct buf *text, void *opaque)
367
317
  }
368
318
 
369
319
  static void
370
- rndr_raw_block(struct buf *ob, struct buf *text, void *opaque)
320
+ rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
371
321
  {
372
322
  size_t org, sz;
373
323
  if (!text) return;
@@ -382,7 +332,7 @@ rndr_raw_block(struct buf *ob, struct buf *text, void *opaque)
382
332
  }
383
333
 
384
334
  static int
385
- rndr_triple_emphasis(struct buf *ob, struct buf *text, void *opaque)
335
+ rndr_triple_emphasis(struct buf *ob, const struct buf *text, void *opaque)
386
336
  {
387
337
  if (!text || !text->size) return 0;
388
338
  BUFPUTSL(ob, "<strong><em>");
@@ -394,55 +344,50 @@ rndr_triple_emphasis(struct buf *ob, struct buf *text, void *opaque)
394
344
  static void
395
345
  rndr_hrule(struct buf *ob, void *opaque)
396
346
  {
397
- struct html_renderopt *options = opaque;
347
+ struct html_renderopt *options = opaque;
398
348
  if (ob->size) bufputc(ob, '\n');
399
- BUFPUTSL(ob, "<hr");
400
- bufputs(ob, options->close_tag);
349
+ bufputs(ob, USE_XHTML(options) ? "<hr/>\n" : "<hr>\n");
401
350
  }
402
351
 
403
352
  static int
404
- rndr_image(struct buf *ob, struct buf *link, struct buf *title, struct buf *alt, void *opaque)
353
+ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
405
354
  {
406
- struct html_renderopt *options = opaque;
355
+ struct html_renderopt *options = opaque;
407
356
  if (!link || !link->size) return 0;
357
+
408
358
  BUFPUTSL(ob, "<img src=\"");
409
- upshtml_escape(ob, link->data, link->size);
359
+ houdini_escape_href(ob, link->data, link->size);
410
360
  BUFPUTSL(ob, "\" alt=\"");
361
+
411
362
  if (alt && alt->size)
412
- upshtml_escape(ob, alt->data, alt->size);
363
+ houdini_escape_html(ob, alt->data, alt->size);
364
+
413
365
  if (title && title->size) {
414
366
  BUFPUTSL(ob, "\" title=\"");
415
- upshtml_escape(ob, title->data, title->size); }
416
-
417
- bufputc(ob, '"');
418
- bufputs(ob, options->close_tag);
419
- return 1;
420
- }
367
+ houdini_escape_html(ob, title->data, title->size); }
421
368
 
422
- static int
423
- rndr_linebreak(struct buf *ob, void *opaque)
424
- {
425
- struct html_renderopt *options = opaque;
426
- BUFPUTSL(ob, "<br");
427
- bufputs(ob, options->close_tag);
369
+ bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">");
428
370
  return 1;
429
371
  }
430
372
 
431
373
  static int
432
- rndr_raw_html(struct buf *ob, struct buf *text, void *opaque)
374
+ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
433
375
  {
434
- struct html_renderopt *options = opaque;
376
+ struct html_renderopt *options = opaque;
435
377
 
436
378
  if ((options->flags & HTML_SKIP_HTML) != 0)
437
379
  return 1;
438
380
 
439
- if ((options->flags & HTML_SKIP_STYLE) != 0 && is_html_tag(text, "style"))
381
+ if ((options->flags & HTML_SKIP_STYLE) != 0 &&
382
+ sdhtml_is_tag(text->data, text->size, "style"))
440
383
  return 1;
441
384
 
442
- if ((options->flags & HTML_SKIP_LINKS) != 0 && is_html_tag(text, "a"))
385
+ if ((options->flags & HTML_SKIP_LINKS) != 0 &&
386
+ sdhtml_is_tag(text->data, text->size, "a"))
443
387
  return 1;
444
388
 
445
- if ((options->flags & HTML_SKIP_IMAGES) != 0 && is_html_tag(text, "img"))
389
+ if ((options->flags & HTML_SKIP_IMAGES) != 0 &&
390
+ sdhtml_is_tag(text->data, text->size, "img"))
446
391
  return 1;
447
392
 
448
393
  bufput(ob, text->data, text->size);
@@ -450,85 +395,105 @@ rndr_raw_html(struct buf *ob, struct buf *text, void *opaque)
450
395
  }
451
396
 
452
397
  static void
453
- rndr_table(struct buf *ob, struct buf *header, struct buf *body, void *opaque)
398
+ rndr_table(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque)
454
399
  {
455
400
  if (ob->size) bufputc(ob, '\n');
456
401
  BUFPUTSL(ob, "<table><thead>\n");
457
402
  if (header)
458
403
  bufput(ob, header->data, header->size);
459
- BUFPUTSL(ob, "\n</thead><tbody>\n");
404
+ BUFPUTSL(ob, "</thead><tbody>\n");
460
405
  if (body)
461
406
  bufput(ob, body->data, body->size);
462
- BUFPUTSL(ob, "\n</tbody></table>");
407
+ BUFPUTSL(ob, "</tbody></table>\n");
463
408
  }
464
409
 
465
410
  static void
466
- rndr_tablerow(struct buf *ob, struct buf *text, void *opaque)
411
+ rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque)
467
412
  {
468
- if (ob->size) bufputc(ob, '\n');
469
413
  BUFPUTSL(ob, "<tr>\n");
470
414
  if (text)
471
415
  bufput(ob, text->data, text->size);
472
- BUFPUTSL(ob, "\n</tr>");
416
+ BUFPUTSL(ob, "</tr>\n");
473
417
  }
474
418
 
475
419
  static void
476
- rndr_tablecell(struct buf *ob, struct buf *text, int align, void *opaque)
420
+ rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque)
477
421
  {
478
- if (ob->size) bufputc(ob, '\n');
479
- switch (align) {
480
- case MKD_TABLE_ALIGN_L:
481
- BUFPUTSL(ob, "<td align=\"left\">");
422
+ if (flags & MKD_TABLE_HEADER) {
423
+ BUFPUTSL(ob, "<th");
424
+ } else {
425
+ BUFPUTSL(ob, "<td");
426
+ }
427
+
428
+ switch (flags & MKD_TABLE_ALIGNMASK) {
429
+ case MKD_TABLE_ALIGN_CENTER:
430
+ BUFPUTSL(ob, " align=\"center\">");
482
431
  break;
483
432
 
484
- case MKD_TABLE_ALIGN_R:
485
- BUFPUTSL(ob, "<td align=\"right\">");
433
+ case MKD_TABLE_ALIGN_L:
434
+ BUFPUTSL(ob, " align=\"left\">");
486
435
  break;
487
436
 
488
- case MKD_TABLE_ALIGN_CENTER:
489
- BUFPUTSL(ob, "<td align=\"center\">");
437
+ case MKD_TABLE_ALIGN_R:
438
+ BUFPUTSL(ob, " align=\"right\">");
490
439
  break;
491
440
 
492
441
  default:
493
- BUFPUTSL(ob, "<td>");
494
- break;
442
+ BUFPUTSL(ob, ">");
495
443
  }
496
444
 
497
445
  if (text)
498
446
  bufput(ob, text->data, text->size);
499
- BUFPUTSL(ob, "</td>");
447
+
448
+ if (flags & MKD_TABLE_HEADER) {
449
+ BUFPUTSL(ob, "</th>\n");
450
+ } else {
451
+ BUFPUTSL(ob, "</td>\n");
452
+ }
453
+ }
454
+
455
+ static int
456
+ rndr_superscript(struct buf *ob, const struct buf *text, void *opaque)
457
+ {
458
+ if (!text || !text->size) return 0;
459
+ BUFPUTSL(ob, "<sup>");
460
+ bufput(ob, text->data, text->size);
461
+ BUFPUTSL(ob, "</sup>");
462
+ return 1;
500
463
  }
501
464
 
502
465
  static void
503
- rndr_normal_text(struct buf *ob, struct buf *text, void *opaque)
466
+ rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque)
504
467
  {
505
468
  if (text)
506
- upshtml_escape(ob, text->data, text->size);
469
+ houdini_escape_html(ob, text->data, text->size);
507
470
  }
508
471
 
509
472
  static void
510
- toc_header(struct buf *ob, struct buf *text, int level, void *opaque)
473
+ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
511
474
  {
512
475
  struct html_renderopt *options = opaque;
513
476
 
514
- while (level > options->toc_data.current_level) {
515
- if (options->toc_data.current_level > 0)
516
- BUFPUTSL(ob, "<li>");
517
- BUFPUTSL(ob, "<ul>\n");
518
- options->toc_data.current_level++;
519
- }
520
-
521
- while (level < options->toc_data.current_level) {
522
- BUFPUTSL(ob, "</ul>");
523
- if (options->toc_data.current_level > 1)
524
- BUFPUTSL(ob, "</li>\n");
525
- options->toc_data.current_level--;
477
+ if (level > options->toc_data.current_level) {
478
+ while (level > options->toc_data.current_level) {
479
+ BUFPUTSL(ob, "<ul>\n<li>\n");
480
+ options->toc_data.current_level++;
481
+ }
482
+ } else if (level < options->toc_data.current_level) {
483
+ BUFPUTSL(ob, "</li>\n");
484
+ while (level < options->toc_data.current_level) {
485
+ BUFPUTSL(ob, "</ul>\n</li>\n");
486
+ options->toc_data.current_level--;
487
+ }
488
+ BUFPUTSL(ob,"<li>\n");
489
+ } else {
490
+ BUFPUTSL(ob,"</li>\n<li>\n");
526
491
  }
527
492
 
528
- bufprintf(ob, "<li><a href=\"#toc_%d\">", options->toc_data.header_count++);
493
+ bufprintf(ob, "<a href=\"#toc_%d\">", options->toc_data.header_count++);
529
494
  if (text)
530
495
  bufput(ob, text->data, text->size);
531
- BUFPUTSL(ob, "</a></li>\n");
496
+ BUFPUTSL(ob, "</a>\n");
532
497
  }
533
498
 
534
499
  static void
@@ -536,19 +501,16 @@ toc_finalize(struct buf *ob, void *opaque)
536
501
  {
537
502
  struct html_renderopt *options = opaque;
538
503
 
539
- while (options->toc_data.current_level > 1) {
540
- BUFPUTSL(ob, "</ul></li>\n");
504
+ while (options->toc_data.current_level > 0) {
505
+ BUFPUTSL(ob, "</li>\n</ul>\n");
541
506
  options->toc_data.current_level--;
542
507
  }
543
-
544
- if (options->toc_data.current_level)
545
- BUFPUTSL(ob, "</ul>\n");
546
508
  }
547
509
 
548
510
  void
549
- upshtml_toc_renderer(struct mkd_renderer *renderer)
511
+ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options)
550
512
  {
551
- static const struct mkd_renderer toc_render = {
513
+ static const struct sd_callbacks cb_default = {
552
514
  NULL,
553
515
  NULL,
554
516
  NULL,
@@ -571,31 +533,25 @@ upshtml_toc_renderer(struct mkd_renderer *renderer)
571
533
  NULL,
572
534
  rndr_triple_emphasis,
573
535
  rndr_strikethrough,
536
+ rndr_superscript,
574
537
 
575
538
  NULL,
576
539
  NULL,
577
540
 
578
541
  NULL,
579
542
  toc_finalize,
580
-
581
- NULL
582
543
  };
583
544
 
584
- struct html_renderopt *options;
585
- options = calloc(1, sizeof(struct html_renderopt));
545
+ memset(options, 0x0, sizeof(struct html_renderopt));
586
546
  options->flags = HTML_TOC;
587
547
 
588
- memcpy(renderer, &toc_render, sizeof(struct mkd_renderer));
589
- renderer->opaque = options;
548
+ memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
590
549
  }
591
550
 
592
551
  void
593
- upshtml_renderer(struct mkd_renderer *renderer, unsigned int render_flags)
552
+ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags)
594
553
  {
595
- static const char *xhtml_close = "/>\n";
596
- static const char *html_close = ">\n";
597
-
598
- static const struct mkd_renderer renderer_default = {
554
+ static const struct sd_callbacks cb_default = {
599
555
  rndr_blockcode,
600
556
  rndr_blockquote,
601
557
  rndr_raw_block,
@@ -618,42 +574,30 @@ upshtml_renderer(struct mkd_renderer *renderer, unsigned int render_flags)
618
574
  rndr_raw_html,
619
575
  rndr_triple_emphasis,
620
576
  rndr_strikethrough,
577
+ rndr_superscript,
621
578
 
622
579
  NULL,
623
580
  rndr_normal_text,
624
581
 
625
582
  NULL,
626
583
  NULL,
627
-
628
- NULL
629
584
  };
630
585
 
631
- struct html_renderopt *options;
632
- options = calloc(1, sizeof(struct html_renderopt));
586
+ /* Prepare the options pointer */
587
+ memset(options, 0x0, sizeof(struct html_renderopt));
633
588
  options->flags = render_flags;
634
- options->close_tag = (render_flags & HTML_USE_XHTML) ? xhtml_close : html_close;
635
589
 
636
- memcpy(renderer, &renderer_default, sizeof(struct mkd_renderer));
637
- renderer->opaque = options;
590
+ /* Prepare the callbacks */
591
+ memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
638
592
 
639
593
  if (render_flags & HTML_SKIP_IMAGES)
640
- renderer->image = NULL;
594
+ callbacks->image = NULL;
641
595
 
642
596
  if (render_flags & HTML_SKIP_LINKS) {
643
- renderer->link = NULL;
644
- renderer->autolink = NULL;
597
+ callbacks->link = NULL;
598
+ callbacks->autolink = NULL;
645
599
  }
646
600
 
647
601
  if (render_flags & HTML_SKIP_HTML)
648
- renderer->blockhtml = NULL;
649
-
650
- if (render_flags & HTML_GITHUB_BLOCKCODE)
651
- renderer->blockcode = rndr_blockcode_github;
602
+ callbacks->blockhtml = NULL;
652
603
  }
653
-
654
- void
655
- upshtml_free_renderer(struct mkd_renderer *renderer)
656
- {
657
- free(renderer->opaque);
658
- }
659
-