greenmat 3.2.2.4 → 3.5.1.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.
@@ -1,17 +1,23 @@
1
1
  /*
2
- * Copyright (c) 2011, Vicent Marti
2
+ * Copyright (c) 2015, Vicent Marti
3
3
  *
4
- * Permission to use, copy, modify, and distribute this software for any
5
- * purpose with or without fee is hereby granted, provided that the above
6
- * copyright notice and this permission notice appear in all copies.
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
7
10
  *
8
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
15
21
  */
16
22
 
17
23
  #include "greenmat.h"
@@ -34,10 +40,10 @@
34
40
  }
35
41
 
36
42
  extern VALUE rb_mGreenmat;
43
+ extern VALUE rb_cRenderHTML_TOC;
37
44
  VALUE rb_mRender;
38
45
  VALUE rb_cRenderBase;
39
46
  VALUE rb_cRenderHTML;
40
- VALUE rb_cRenderHTML_TOC;
41
47
  VALUE rb_mSmartyPants;
42
48
 
43
49
  #define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
@@ -369,16 +375,22 @@ static void rb_greenmat_rbase_mark(struct rb_greenmat_rndr *rndr)
369
375
  rb_gc_mark(rndr->options.link_attributes);
370
376
  }
371
377
 
378
+ static void rndr_deallocate(void *rndr)
379
+ {
380
+ xfree(rndr);
381
+ }
382
+
372
383
  static VALUE rb_greenmat_rbase_alloc(VALUE klass)
373
384
  {
374
385
  struct rb_greenmat_rndr *rndr = ALLOC(struct rb_greenmat_rndr);
375
386
  memset(rndr, 0x0, sizeof(struct rb_greenmat_rndr));
376
- return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark, NULL, rndr);
387
+ return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark, rndr_deallocate, rndr);
377
388
  }
378
389
 
379
390
  static void rb_greenmat__overload(VALUE self, VALUE base_class)
380
391
  {
381
392
  struct rb_greenmat_rndr *rndr;
393
+ VALUE options_ivar;
382
394
 
383
395
  Data_Get_Struct(self, struct rb_greenmat_rndr, rndr);
384
396
  rndr->options.self = self;
@@ -399,6 +411,10 @@ static void rb_greenmat__overload(VALUE self, VALUE base_class)
399
411
  dest[i] = source[i];
400
412
  }
401
413
  }
414
+
415
+ options_ivar = rb_attr_get(self, rb_intern("@options"));
416
+ if (options_ivar == Qundef || options_ivar == Qnil)
417
+ rb_iv_set(self, "@options", rb_hash_new());
402
418
  }
403
419
 
404
420
  static VALUE rb_greenmat_rbase_init(VALUE self)
@@ -418,6 +434,9 @@ static VALUE rb_greenmat_html_init(int argc, VALUE *argv, VALUE self)
418
434
  if (rb_scan_args(argc, argv, "01", &hash) == 1) {
419
435
  Check_Type(hash, T_HASH);
420
436
 
437
+ /* Give access to the passed options through `@options` */
438
+ rb_iv_set(self, "@options", hash);
439
+
421
440
  /* escape_html */
422
441
  if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
423
442
  render_flags |= HTML_ESCAPE;
@@ -472,25 +491,45 @@ static VALUE rb_greenmat_html_init(int argc, VALUE *argv, VALUE self)
472
491
  static VALUE rb_greenmat_htmltoc_init(int argc, VALUE *argv, VALUE self)
473
492
  {
474
493
  struct rb_greenmat_rndr *rndr;
475
- int nesting_level = 6;
476
- VALUE hash, key = Qnil;
494
+ unsigned int render_flags = HTML_TOC;
495
+ VALUE hash, nesting_level = Qnil;
477
496
 
478
497
  Data_Get_Struct(self, struct rb_greenmat_rndr, rndr);
479
498
 
480
499
  if (rb_scan_args(argc, argv, "01", &hash) == 1) {
481
500
  Check_Type(hash, T_HASH);
482
501
 
483
- key = CSTR2SYM("nesting_level");
502
+ /* Give access to the passed options through `@options` */
503
+ rb_iv_set(self, "@options", hash);
484
504
 
485
- if (RTEST(rb_hash_aref(hash, key))) {
486
- Check_Type(rb_hash_aref(hash, key), T_FIXNUM);
487
- nesting_level = NUM2INT(rb_hash_aref(hash, key));
488
- }
505
+ /* escape_html */
506
+ if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
507
+ render_flags |= HTML_ESCAPE;
508
+
509
+ /* Nesting level */
510
+ nesting_level = rb_hash_aref(hash, CSTR2SYM("nesting_level"));
489
511
  }
490
512
 
491
- sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, nesting_level);
513
+ sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
492
514
  rb_greenmat__overload(self, rb_cRenderHTML_TOC);
493
515
 
516
+ /* Check whether we are dealing with a Range object by
517
+ checking whether the object responds to min and max */
518
+ if (rb_respond_to(nesting_level, rb_intern("min")) &&
519
+ rb_respond_to(nesting_level, rb_intern("max"))) {
520
+ int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0));
521
+ int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0));
522
+
523
+ rndr->options.html.toc_data.nesting_bounds[0] = min;
524
+ rndr->options.html.toc_data.nesting_bounds[1] = max;
525
+ } else if (FIXNUM_P(nesting_level)) {
526
+ rndr->options.html.toc_data.nesting_bounds[0] = 1;
527
+ rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level);
528
+ } else {
529
+ rndr->options.html.toc_data.nesting_bounds[0] = 1;
530
+ rndr->options.html.toc_data.nesting_bounds[1] = 6;
531
+ }
532
+
494
533
  return Qnil;
495
534
  }
496
535
 
@@ -1,3 +1,25 @@
1
+ /*
2
+ * Copyright (c) 2015, Vicent Marti
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
1
23
  #ifndef GREENMAT_H__
2
24
  #define GREENMAT_H__
3
25
 
@@ -1,3 +1,25 @@
1
+ /*
2
+ * Copyright (c) 2015, Vicent Marti
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
1
23
  #ifndef HOUDINI_H__
2
24
  #define HOUDINI_H__
3
25
 
@@ -1,3 +1,25 @@
1
+ /*
2
+ * Copyright (c) 2015, Vicent Marti
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
1
23
  #include <assert.h>
2
24
  #include <stdio.h>
3
25
  #include <string.h>
@@ -22,10 +44,10 @@
22
44
  * have its native function (i.e. as an URL
23
45
  * component/separator) and hence needs no escaping.
24
46
  *
25
- * There are two exceptions: the chacters & (amp)
26
- * and ' (single quote) do not appear in the table.
27
- * They are meant to appear in the URL as components,
28
- * yet they require special HTML-entity escaping
47
+ * There is one exception: the ' (single quote)
48
+ * character does not appear in the table.
49
+ * It is meant to appear in the URL as components,
50
+ * however it require special HTML-entity escaping
29
51
  * to generate valid HTML markup.
30
52
  *
31
53
  * All other characters will be escaped to %XX.
@@ -34,7 +56,7 @@
34
56
  static const char HREF_SAFE[] = {
35
57
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
36
58
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37
- 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
59
+ 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
38
60
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
39
61
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
40
62
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
@@ -73,12 +95,6 @@ houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size)
73
95
  break;
74
96
 
75
97
  switch (src[i]) {
76
- /* amp appears all the time in URLs, but needs
77
- * HTML-entity escaping to be inside an href */
78
- case '&':
79
- BUFPUTSL(ob, "&amp;");
80
- break;
81
-
82
98
  /* the single quote is a valid URL character
83
99
  * according to the standard; it needs HTML
84
100
  * entity escaping too */
@@ -1,3 +1,25 @@
1
+ /*
2
+ * Copyright (c) 2015, Vicent Marti
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
1
23
  #include <assert.h>
2
24
  #include <stdio.h>
3
25
  #include <string.h>
@@ -80,4 +102,3 @@ houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size)
80
102
  {
81
103
  houdini_escape_html0(ob, src, size, 1);
82
104
  }
83
-
data/ext/greenmat/html.c CHANGED
@@ -1,23 +1,28 @@
1
1
  /*
2
2
  * Copyright (c) 2009, Natacha Porté
3
- * Copyright (c) 2011, Vicent Marti
3
+ * Copyright (c) 2015, Vicent Marti
4
4
  *
5
- * Permission to use, copy, modify, and distribute this software for any
6
- * purpose with or without fee is hereby granted, provided that the above
7
- * copyright notice and this permission notice appear in all copies.
5
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ * of this software and associated documentation files (the "Software"), to deal
7
+ * in the Software without restriction, including without limitation the rights
8
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ * copies of the Software, and to permit persons to whom the Software is
10
+ * furnished to do so, subject to the following conditions:
8
11
  *
9
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
12
+ * The above copyright notice and this permission notice shall be included in
13
+ * all copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ * THE SOFTWARE.
16
22
  */
17
23
 
18
24
  #include "markdown.h"
19
25
  #include "html.h"
20
- #include "ruby.h"
21
26
  #include <string.h>
22
27
  #include <stdlib.h>
23
28
  #include <stdio.h>
@@ -250,8 +255,15 @@ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
250
255
  if (!text || !text->size)
251
256
  return 0;
252
257
 
258
+ struct html_renderopt *options = opaque;
259
+
253
260
  BUFPUTSL(ob, "<q>");
254
- bufput(ob, text->data, text->size);
261
+
262
+ if (options->flags & HTML_ESCAPE)
263
+ escape_html(ob, text->data, text->size);
264
+ else
265
+ bufput(ob, text->data, text->size);
266
+
255
267
  BUFPUTSL(ob, "</q>");
256
268
 
257
269
  return 1;
@@ -265,17 +277,52 @@ rndr_linebreak(struct buf *ob, void *opaque)
265
277
  return 1;
266
278
  }
267
279
 
268
- char *header_anchor(struct buf *text)
280
+ static void
281
+ rndr_header_anchor(struct buf *out, const struct buf *anchor)
269
282
  {
270
- VALUE str = rb_str_new2(bufcstr(text));
271
- VALUE space_regex = rb_reg_new(" +", 2 /* length */, 0);
272
- VALUE tags_regex = rb_reg_new("<\\/?[^>]*>", 10, 0);
283
+ static const char *STRIPPED = " -&+$,/:;=?@\"#{}|^~[]`\\*()%.!'";
273
284
 
274
- VALUE heading = rb_funcall(str, rb_intern("gsub"), 2, space_regex, rb_str_new2("-"));
275
- heading = rb_funcall(heading, rb_intern("gsub"), 2, tags_regex, rb_str_new2(""));
276
- heading = rb_funcall(heading, rb_intern("downcase"), 0);
285
+ const uint8_t *a = anchor->data;
286
+ const size_t size = anchor->size;
287
+ size_t i = 0;
288
+ int stripped = 0, inserted = 0;
277
289
 
278
- return StringValueCStr(heading);
290
+ for (; i < size; ++i) {
291
+ // skip html tags
292
+ if (a[i] == '<') {
293
+ while (i < size && a[i] != '>')
294
+ i++;
295
+ // skip html entities
296
+ } else if (a[i] == '&') {
297
+ while (i < size && a[i] != ';')
298
+ i++;
299
+ }
300
+ // replace non-ascii or invalid characters with dashes
301
+ else if (!isascii(a[i]) || strchr(STRIPPED, a[i])) {
302
+ if (inserted && !stripped)
303
+ bufputc(out, '-');
304
+ // and do it only once
305
+ stripped = 1;
306
+ }
307
+ else {
308
+ bufputc(out, tolower(a[i]));
309
+ stripped = 0;
310
+ inserted++;
311
+ }
312
+ }
313
+
314
+ // replace the last dash if there was anything added
315
+ if (stripped && inserted)
316
+ out->size--;
317
+
318
+ // if anchor found empty, use djb2 hash for it
319
+ if (!inserted && anchor->size) {
320
+ unsigned long hash = 5381;
321
+ for (i = 0; i < size; ++i) {
322
+ hash = ((hash << 5) + hash) + a[i]; /* h * 33 + c */
323
+ }
324
+ bufprintf(out, "part-%lx", hash);
325
+ }
279
326
  }
280
327
 
281
328
  static void
@@ -286,8 +333,12 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
286
333
  if (ob->size)
287
334
  bufputc(ob, '\n');
288
335
 
289
- if ((options->flags & HTML_TOC) && (level <= options->toc_data.nesting_level))
290
- bufprintf(ob, "<h%d id=\"%s\">", level, header_anchor(text));
336
+ if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] &&
337
+ level <= options->toc_data.nesting_bounds[1]) {
338
+ bufprintf(ob, "<h%d id=\"", level);
339
+ rndr_header_anchor(ob, text);
340
+ BUFPUTSL(ob, "\">");
341
+ }
291
342
  else
292
343
  bufprintf(ob, "<h%d>", level);
293
344
 
@@ -395,15 +446,30 @@ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
395
446
  static void
396
447
  rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
397
448
  {
398
- size_t org, sz;
399
- if (!text) return;
400
- sz = text->size;
401
- while (sz > 0 && text->data[sz - 1] == '\n') sz--;
402
- org = 0;
403
- while (org < sz && text->data[org] == '\n') org++;
404
- if (org >= sz) return;
405
- if (ob->size) bufputc(ob, '\n');
406
- bufput(ob, text->data + org, sz - org);
449
+ size_t org, size;
450
+ struct html_renderopt *options = opaque;
451
+
452
+ if (!text)
453
+ return;
454
+
455
+ size = text->size;
456
+ while (size > 0 && text->data[size - 1] == '\n')
457
+ size--;
458
+
459
+ for (org = 0; org < size && text->data[org] == '\n'; ++org)
460
+
461
+ if (org >= size)
462
+ return;
463
+
464
+ /* Remove style tags if the `:no_styles` option is enabled */
465
+ if ((options->flags & HTML_SKIP_STYLE) != 0 &&
466
+ sdhtml_is_tag(text->data, size, "style"))
467
+ return;
468
+
469
+ if (ob->size)
470
+ bufputc(ob, '\n');
471
+
472
+ bufput(ob, text->data + org, size - org);
407
473
  bufputc(ob, '\n');
408
474
  }
409
475
 
@@ -429,10 +495,15 @@ static int
429
495
  rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
430
496
  {
431
497
  struct html_renderopt *options = opaque;
432
- if (!link || !link->size) return 0;
498
+
499
+ if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size))
500
+ return 0;
433
501
 
434
502
  BUFPUTSL(ob, "<img src=\"");
435
- escape_href(ob, link->data, link->size);
503
+
504
+ if (link && link->size)
505
+ escape_href(ob, link->data, link->size);
506
+
436
507
  BUFPUTSL(ob, "\" alt=\"");
437
508
 
438
509
  if (alt && alt->size)
@@ -440,7 +511,8 @@ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, cons
440
511
 
441
512
  if (title && title->size) {
442
513
  BUFPUTSL(ob, "\" title=\"");
443
- escape_html(ob, title->data, title->size); }
514
+ escape_html(ob, title->data, title->size);
515
+ }
444
516
 
445
517
  bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">");
446
518
  return 1;
@@ -452,7 +524,7 @@ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
452
524
  struct html_renderopt *options = opaque;
453
525
 
454
526
  /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES
455
- * It doens't see if there are any valid tags, just escape all of them. */
527
+ It doesn't see if there are any valid tags, just escape all of them. */
456
528
  if((options->flags & HTML_ESCAPE) != 0) {
457
529
  escape_html(ob, text->data, text->size);
458
530
  return 1;
@@ -591,7 +663,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
591
663
  bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
592
664
  if (pfound) {
593
665
  bufput(ob, text->data, i);
594
- bufprintf(ob, "&nbsp;<a href=\"#fnref%d\" rev=\"footnote\">&#8617;</a>", num);
666
+ bufprintf(ob, "&nbsp;<a href=\"#fnref%d\">&#8617;</a>", num);
595
667
  bufput(ob, text->data + i, text->size - i);
596
668
  } else if (text) {
597
669
  bufput(ob, text->data, text->size);
@@ -602,7 +674,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
602
674
  static int
603
675
  rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
604
676
  {
605
- bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num);
677
+ bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\">%d</a></sup>", num, num, num);
606
678
  return 1;
607
679
  }
608
680
 
@@ -611,7 +683,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
611
683
  {
612
684
  struct html_renderopt *options = opaque;
613
685
 
614
- if (level <= options->toc_data.nesting_level) {
686
+ if (level >= options->toc_data.nesting_bounds[0] &&
687
+ level <= options->toc_data.nesting_bounds[1]) {
615
688
  /* set the level offset if this is the first header
616
689
  * we're parsing for the document */
617
690
  if (options->toc_data.current_level == 0)
@@ -635,8 +708,17 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
635
708
  BUFPUTSL(ob,"</li>\n<li>\n");
636
709
  }
637
710
 
638
- bufprintf(ob, "<a href=\"#%s\">", header_anchor(text));
639
- if (text) escape_html(ob, text->data, text->size);
711
+ bufprintf(ob, "<a href=\"#");
712
+ rndr_header_anchor(ob, text);
713
+ BUFPUTSL(ob, "\">");
714
+
715
+ if (text) {
716
+ if (options->flags & HTML_ESCAPE)
717
+ escape_html(ob, text->data, text->size);
718
+ else
719
+ bufput(ob, text->data, text->size);
720
+ }
721
+
640
722
  BUFPUTSL(ob, "</a>\n");
641
723
  }
642
724
  }
@@ -661,7 +743,7 @@ toc_finalize(struct buf *ob, void *opaque)
661
743
  }
662
744
 
663
745
  void
664
- sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, int nesting_level)
746
+ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags)
665
747
  {
666
748
  static const struct sd_callbacks cb_default = {
667
749
  NULL,
@@ -702,8 +784,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
702
784
  };
703
785
 
704
786
  memset(options, 0x0, sizeof(struct html_renderopt));
705
- options->flags = HTML_TOC;
706
- options->toc_data.nesting_level = nesting_level;
787
+ options->flags = render_flags;
707
788
 
708
789
  memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
709
790
  }
@@ -752,7 +833,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
752
833
  /* Prepare the options pointer */
753
834
  memset(options, 0x0, sizeof(struct html_renderopt));
754
835
  options->flags = render_flags;
755
- options->toc_data.nesting_level = 99;
836
+ options->toc_data.nesting_bounds[0] = 1;
837
+ options->toc_data.nesting_bounds[1] = 6;
756
838
 
757
839
  /* Prepare the callbacks */
758
840
  memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));