greenmat 3.2.2.4 → 3.5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +19 -4
- data/CHANGELOG.md +4 -0
- data/COPYING +17 -11
- data/Gemfile +2 -2
- data/README.md +19 -13
- data/bin/greenmat +4 -40
- data/ext/greenmat/autolink.c +24 -12
- data/ext/greenmat/buffer.c +24 -17
- data/ext/greenmat/buffer.h +18 -13
- data/ext/greenmat/gm_markdown.c +35 -13
- data/ext/greenmat/gm_render.c +60 -21
- data/ext/greenmat/greenmat.h +22 -0
- data/ext/greenmat/houdini.h +22 -0
- data/ext/greenmat/houdini_href_e.c +27 -11
- data/ext/greenmat/houdini_html_e.c +22 -1
- data/ext/greenmat/html.c +127 -45
- data/ext/greenmat/html.h +19 -14
- data/ext/greenmat/html_blocks.h +68 -70
- data/ext/greenmat/html_smartypants.c +47 -20
- data/ext/greenmat/markdown.c +42 -30
- data/ext/greenmat/markdown.h +17 -15
- data/ext/greenmat/stack.c +22 -0
- data/ext/greenmat/stack.h +22 -0
- data/greenmat.gemspec +3 -3
- data/lib/greenmat.rb +1 -1
- data/lib/greenmat/cli.rb +86 -0
- data/lib/greenmat/compat.rb +0 -5
- data/lib/greenmat/render_strip.rb +13 -1
- data/lib/greenmat/version.rb +1 -1
- data/test/custom_render_test.rb +41 -2
- data/test/greenmat_bin_test.rb +80 -0
- data/test/greenmat_compat_test.rb +6 -6
- data/test/html5_test.rb +51 -38
- data/test/html_render_test.rb +161 -127
- data/test/html_toc_render_test.rb +74 -11
- data/test/markdown_test.rb +258 -182
- data/test/safe_render_test.rb +5 -6
- data/test/smarty_html_test.rb +19 -13
- data/test/smarty_pants_test.rb +10 -0
- data/test/stripdown_render_test.rb +38 -9
- data/test/test_helper.rb +30 -9
- metadata +15 -13
data/ext/greenmat/gm_render.c
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
3
|
*
|
4
|
-
* Permission
|
5
|
-
*
|
6
|
-
*
|
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
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
* OR
|
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,
|
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
|
476
|
-
VALUE hash,
|
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
|
-
|
502
|
+
/* Give access to the passed options through `@options` */
|
503
|
+
rb_iv_set(self, "@options", hash);
|
484
504
|
|
485
|
-
|
486
|
-
|
487
|
-
|
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,
|
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
|
|
data/ext/greenmat/greenmat.h
CHANGED
@@ -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
|
|
data/ext/greenmat/houdini.h
CHANGED
@@ -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
|
26
|
-
*
|
27
|
-
*
|
28
|
-
*
|
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,
|
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, "&");
|
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)
|
3
|
+
* Copyright (c) 2015, Vicent Marti
|
4
4
|
*
|
5
|
-
* Permission
|
6
|
-
*
|
7
|
-
*
|
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
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
* OR
|
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
|
-
|
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
|
-
|
280
|
+
static void
|
281
|
+
rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
269
282
|
{
|
270
|
-
|
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
|
-
|
275
|
-
|
276
|
-
|
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
|
-
|
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) &&
|
290
|
-
|
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,
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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, " <a href=\"#fnref%d\"
|
666
|
+
bufprintf(ob, " <a href=\"#fnref%d\">↩</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\"
|
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
|
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=\"
|
639
|
-
|
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
|
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 =
|
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.
|
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));
|