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/html.h
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
|
#ifndef HTML_H__
|
@@ -29,7 +35,7 @@ struct html_renderopt {
|
|
29
35
|
struct {
|
30
36
|
int current_level;
|
31
37
|
int level_offset;
|
32
|
-
int
|
38
|
+
int nesting_bounds[2];
|
33
39
|
} toc_data;
|
34
40
|
|
35
41
|
unsigned int flags;
|
@@ -65,7 +71,7 @@ extern void
|
|
65
71
|
sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
66
72
|
|
67
73
|
extern void
|
68
|
-
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, int
|
74
|
+
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
69
75
|
|
70
76
|
extern void
|
71
77
|
sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
@@ -75,4 +81,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
|
75
81
|
#endif
|
76
82
|
|
77
83
|
#endif
|
78
|
-
|
data/ext/greenmat/html_blocks.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
/* C code produced by gperf version 3.0.
|
1
|
+
/* C code produced by gperf version 3.0.3 */
|
2
2
|
/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
|
3
|
-
/* See
|
3
|
+
/* See https://git.io/vPLqa for the list of recognized elements */
|
4
4
|
/* Computed positions: -k'1-2' */
|
5
5
|
|
6
6
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
@@ -30,7 +30,7 @@
|
|
30
30
|
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
31
31
|
#endif
|
32
32
|
|
33
|
-
/* maximum key range =
|
33
|
+
/* maximum key range = 72, duplicates = 0 */
|
34
34
|
|
35
35
|
#ifndef GPERF_DOWNCASE
|
36
36
|
#define GPERF_DOWNCASE 1
|
@@ -94,34 +94,34 @@ hash_block_tag (str, len)
|
|
94
94
|
{
|
95
95
|
static const unsigned char asso_values[] =
|
96
96
|
{
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
0,
|
105
|
-
0,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
97
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
98
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
99
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
100
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
101
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
102
|
+
26, 60, 55, 45, 40, 35, 73, 73, 73, 73,
|
103
|
+
73, 73, 73, 73, 73, 20, 15, 15, 0, 35,
|
104
|
+
0, 25, 10, 10, 5, 73, 73, 0, 15, 15,
|
105
|
+
0, 73, 73, 15, 20, 10, 10, 73, 73, 73,
|
106
|
+
73, 73, 73, 73, 73, 73, 73, 20, 15, 15,
|
107
|
+
0, 35, 0, 25, 10, 10, 5, 73, 73, 0,
|
108
|
+
15, 15, 0, 73, 73, 15, 20, 10, 10, 73,
|
109
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
110
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
111
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
112
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
113
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
114
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
115
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
116
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
117
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
118
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
119
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
120
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
121
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
122
|
+
73, 73, 73, 73, 73, 73, 73
|
123
123
|
};
|
124
|
-
register int hval = len;
|
124
|
+
register unsigned int hval = len;
|
125
125
|
|
126
126
|
switch (hval)
|
127
127
|
{
|
@@ -135,12 +135,6 @@ hash_block_tag (str, len)
|
|
135
135
|
return hval;
|
136
136
|
}
|
137
137
|
|
138
|
-
#ifdef __GNUC__
|
139
|
-
__inline
|
140
|
-
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
141
|
-
__attribute__ ((__gnu_inline__))
|
142
|
-
#endif
|
143
|
-
#endif
|
144
138
|
const char *
|
145
139
|
find_block_tag (str, len)
|
146
140
|
register const char *str;
|
@@ -148,76 +142,80 @@ find_block_tag (str, len)
|
|
148
142
|
{
|
149
143
|
enum
|
150
144
|
{
|
151
|
-
TOTAL_KEYWORDS =
|
145
|
+
TOTAL_KEYWORDS = 43,
|
152
146
|
MIN_WORD_LENGTH = 1,
|
153
147
|
MAX_WORD_LENGTH = 10,
|
154
148
|
MIN_HASH_VALUE = 1,
|
155
|
-
MAX_HASH_VALUE =
|
149
|
+
MAX_HASH_VALUE = 72
|
156
150
|
};
|
157
151
|
|
158
152
|
static const char * const wordlist[] =
|
159
153
|
{
|
160
154
|
"",
|
161
155
|
"p",
|
162
|
-
"
|
163
|
-
"
|
156
|
+
"dl",
|
157
|
+
"del",
|
164
158
|
"form",
|
165
|
-
"
|
159
|
+
"",
|
166
160
|
"footer",
|
167
|
-
"
|
168
|
-
"",
|
161
|
+
"details",
|
162
|
+
"div",
|
163
|
+
"", "",
|
169
164
|
"figure",
|
170
|
-
"
|
165
|
+
"ul",
|
171
166
|
"fieldset",
|
172
|
-
"
|
167
|
+
"",
|
173
168
|
"figcaption",
|
174
169
|
"header",
|
175
|
-
"
|
176
|
-
"
|
177
|
-
"",
|
178
|
-
"
|
170
|
+
"ol",
|
171
|
+
"pre",
|
172
|
+
"math",
|
173
|
+
"video",
|
179
174
|
"script",
|
180
|
-
"
|
181
|
-
"
|
175
|
+
"section",
|
176
|
+
"noscript",
|
182
177
|
"",
|
183
|
-
"
|
178
|
+
"blockquote",
|
184
179
|
"hgroup",
|
185
|
-
"
|
186
|
-
"
|
187
|
-
"",
|
180
|
+
"hr",
|
181
|
+
"ins",
|
182
|
+
"",
|
183
|
+
"style",
|
184
|
+
"output",
|
185
|
+
"summary",
|
186
|
+
"nav",
|
187
|
+
"",
|
188
|
+
"audio",
|
188
189
|
"canvas",
|
189
190
|
"dd",
|
190
|
-
"
|
191
|
+
"h1",
|
191
192
|
"abbr",
|
192
|
-
"audio",
|
193
|
-
"iframe",
|
194
|
-
"address",
|
195
|
-
"ins",
|
196
|
-
"",
|
197
193
|
"table",
|
198
|
-
"",
|
199
|
-
"
|
194
|
+
"iframe",
|
195
|
+
"article",
|
200
196
|
"", "",
|
201
197
|
"aside",
|
202
|
-
"
|
203
|
-
"
|
198
|
+
"",
|
199
|
+
"h6",
|
204
200
|
"", "",
|
205
201
|
"tfoot",
|
206
202
|
"",
|
203
|
+
"h5",
|
204
|
+
"", "", "", "",
|
207
205
|
"h4",
|
208
206
|
"", "", "", "",
|
209
|
-
"
|
207
|
+
"address",
|
210
208
|
"", "", "", "",
|
211
|
-
"
|
209
|
+
"h3",
|
212
210
|
"", "", "", "",
|
213
|
-
"
|
211
|
+
"h2"
|
214
212
|
};
|
215
213
|
|
216
214
|
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
217
215
|
{
|
218
|
-
|
216
|
+
unsigned int key = hash_block_tag (str, len);
|
219
217
|
|
220
|
-
if (key <= MAX_HASH_VALUE
|
218
|
+
if (key <= MAX_HASH_VALUE)
|
221
219
|
{
|
222
220
|
register const char *s = wordlist[key];
|
223
221
|
|
@@ -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 "buffer.h"
|
@@ -83,6 +89,12 @@ word_boundary(uint8_t c)
|
|
83
89
|
return c == 0 || isspace(c) || ispunct(c);
|
84
90
|
}
|
85
91
|
|
92
|
+
static inline int
|
93
|
+
fraction_boundary(uint8_t c)
|
94
|
+
{
|
95
|
+
return c == 0 || isspace(c) || (c != '/' && ispunct(c));
|
96
|
+
}
|
97
|
+
|
86
98
|
// If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.),
|
87
99
|
// returns the length of the sequence of characters that makes up the single-
|
88
100
|
// quote. Otherwise, returns zero.
|
@@ -139,6 +151,9 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
139
151
|
return next_squote_len;
|
140
152
|
}
|
141
153
|
|
154
|
+
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
155
|
+
return 0;
|
156
|
+
|
142
157
|
// trailing single quotes: students', tryin'
|
143
158
|
if (word_boundary(t1)) {
|
144
159
|
BUFPUTSL(ob, "’");
|
@@ -166,9 +181,6 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
166
181
|
}
|
167
182
|
}
|
168
183
|
|
169
|
-
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
170
|
-
return 0;
|
171
|
-
|
172
184
|
bufput(ob, squote_text, squote_size);
|
173
185
|
return 0;
|
174
186
|
}
|
@@ -282,16 +294,16 @@ smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t
|
|
282
294
|
static size_t
|
283
295
|
smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
284
296
|
{
|
285
|
-
if (
|
297
|
+
if (fraction_boundary(previous_char) && size >= 3) {
|
286
298
|
if (text[0] == '1' && text[1] == '/' && text[2] == '2') {
|
287
|
-
if (size == 3 ||
|
299
|
+
if (size == 3 || fraction_boundary(text[3])) {
|
288
300
|
BUFPUTSL(ob, "½");
|
289
301
|
return 2;
|
290
302
|
}
|
291
303
|
}
|
292
304
|
|
293
305
|
if (text[0] == '1' && text[1] == '/' && text[2] == '4') {
|
294
|
-
if (size == 3 ||
|
306
|
+
if (size == 3 || fraction_boundary(text[3]) ||
|
295
307
|
(size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) {
|
296
308
|
BUFPUTSL(ob, "¼");
|
297
309
|
return 2;
|
@@ -299,7 +311,7 @@ smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
|
|
299
311
|
}
|
300
312
|
|
301
313
|
if (text[0] == '3' && text[1] == '/' && text[2] == '4') {
|
302
|
-
if (size == 3 ||
|
314
|
+
if (size == 3 || fraction_boundary(text[3]) ||
|
303
315
|
(size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) {
|
304
316
|
BUFPUTSL(ob, "¾");
|
305
317
|
return 2;
|
@@ -329,6 +341,7 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
329
341
|
};
|
330
342
|
static const size_t skip_tags_count = 8;
|
331
343
|
|
344
|
+
size_t next_to_closing_a = 0;
|
332
345
|
size_t tag, i = 0;
|
333
346
|
|
334
347
|
while (i < size && text[i] != '>')
|
@@ -357,7 +370,23 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
357
370
|
i++;
|
358
371
|
}
|
359
372
|
|
373
|
+
if (sdhtml_is_tag(text, size, "a") == HTML_TAG_CLOSE) {
|
374
|
+
while (i < size && text[i] != '>')
|
375
|
+
i++;
|
376
|
+
|
377
|
+
next_to_closing_a = 1;
|
378
|
+
}
|
379
|
+
|
360
380
|
bufput(ob, text, i + 1);
|
381
|
+
|
382
|
+
// Pretty tricky: since people may refer to something or someone
|
383
|
+
// with a link but use the possessive form right after it, we need
|
384
|
+
// to check whether a single quote is next to a closing "</a"> tag.
|
385
|
+
if (next_to_closing_a && strncmp("'", text+(i+1), 5) == 0) {
|
386
|
+
bufput(ob, "’", 7);
|
387
|
+
i += 5;
|
388
|
+
}
|
389
|
+
|
361
390
|
return i;
|
362
391
|
}
|
363
392
|
|
@@ -441,5 +470,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size)
|
|
441
470
|
}
|
442
471
|
}
|
443
472
|
}
|
444
|
-
|
445
|
-
|
data/ext/greenmat/markdown.c
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
-
/* markdown.c - generic markdown parser */
|
2
|
-
|
3
1
|
/*
|
4
2
|
* Copyright (c) 2009, Natacha Porté
|
5
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) 2015, Vicent Marti
|
4
|
+
*
|
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:
|
6
11
|
*
|
7
|
-
*
|
8
|
-
*
|
9
|
-
* copyright notice and this permission notice appear in all copies.
|
12
|
+
* The above copyright notice and this permission notice shall be included in
|
13
|
+
* all copies or substantial portions of the Software.
|
10
14
|
*
|
11
|
-
* THE SOFTWARE IS PROVIDED "AS IS"
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
17
|
-
*
|
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.
|
18
22
|
*/
|
19
23
|
|
20
24
|
#include "markdown.h"
|
@@ -88,7 +92,6 @@ typedef size_t
|
|
88
92
|
|
89
93
|
static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
90
94
|
static size_t char_underline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
91
|
-
static size_t char_highlight(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
92
95
|
static size_t char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
93
96
|
static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
94
97
|
static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
@@ -467,7 +470,7 @@ tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink)
|
|
467
470
|
static void
|
468
471
|
parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
469
472
|
{
|
470
|
-
size_t i = 0, end = 0;
|
473
|
+
size_t i = 0, end = 0, consumed = 0;
|
471
474
|
uint8_t action = 0;
|
472
475
|
struct buf work = { 0, 0, 0, 0 };
|
473
476
|
|
@@ -492,12 +495,13 @@ parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t siz
|
|
492
495
|
if (end >= size) break;
|
493
496
|
i = end;
|
494
497
|
|
495
|
-
end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i);
|
498
|
+
end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i - consumed, size - i);
|
496
499
|
if (!end) /* no action from the callback */
|
497
500
|
end = i + 1;
|
498
501
|
else {
|
499
502
|
i += end;
|
500
503
|
end = i;
|
504
|
+
consumed = i;
|
501
505
|
}
|
502
506
|
}
|
503
507
|
}
|
@@ -646,7 +650,7 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
646
650
|
if (data[i] == c && !_isspace(data[i - 1])) {
|
647
651
|
|
648
652
|
if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
|
649
|
-
if (i +
|
653
|
+
if (i + 1 < size && _isalnum(data[i + 1]))
|
650
654
|
continue;
|
651
655
|
}
|
652
656
|
|
@@ -898,7 +902,6 @@ char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offse
|
|
898
902
|
return end;
|
899
903
|
}
|
900
904
|
|
901
|
-
|
902
905
|
/* char_escape • '\\' backslash escape */
|
903
906
|
static size_t
|
904
907
|
char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
|
@@ -1176,7 +1179,7 @@ char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset
|
|
1176
1179
|
title_e--;
|
1177
1180
|
|
1178
1181
|
/* checking for closing quote presence */
|
1179
|
-
if (data[title_e] != '\'' &&
|
1182
|
+
if (data[title_e] != '\'' && data[title_e] != '"') {
|
1180
1183
|
title_b = title_e = 0;
|
1181
1184
|
link_e = i;
|
1182
1185
|
}
|
@@ -1605,7 +1608,7 @@ prefix_oli(uint8_t *data, size_t size)
|
|
1605
1608
|
return i + 2;
|
1606
1609
|
}
|
1607
1610
|
|
1608
|
-
/* prefix_uli • returns
|
1611
|
+
/* prefix_uli • returns unordered list item prefix */
|
1609
1612
|
static size_t
|
1610
1613
|
prefix_uli(uint8_t *data, size_t size)
|
1611
1614
|
{
|
@@ -1677,7 +1680,7 @@ parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1677
1680
|
static size_t
|
1678
1681
|
parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render);
|
1679
1682
|
|
1680
|
-
/*
|
1683
|
+
/* parse_paragraph • handles parsing of a regular paragraph */
|
1681
1684
|
static size_t
|
1682
1685
|
parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
1683
1686
|
{
|
@@ -2392,7 +2395,7 @@ parse_table_header(
|
|
2392
2395
|
if (i < under_end && data[i] != '|' && data[i] != '+')
|
2393
2396
|
break;
|
2394
2397
|
|
2395
|
-
if (dashes <
|
2398
|
+
if (dashes < 1)
|
2396
2399
|
break;
|
2397
2400
|
|
2398
2401
|
i++;
|
@@ -2810,10 +2813,13 @@ sd_markdown_new(
|
|
2810
2813
|
if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) {
|
2811
2814
|
md->active_char['*'] = MD_CHAR_EMPHASIS;
|
2812
2815
|
md->active_char['_'] = MD_CHAR_EMPHASIS;
|
2816
|
+
|
2813
2817
|
if (extensions & MKDEXT_STRIKETHROUGH)
|
2814
2818
|
md->active_char['~'] = MD_CHAR_EMPHASIS;
|
2815
2819
|
if (extensions & MKDEXT_HIGHLIGHT)
|
2816
2820
|
md->active_char['='] = MD_CHAR_EMPHASIS;
|
2821
|
+
if (extensions & MKDEXT_QUOTE)
|
2822
|
+
md->active_char['"'] = MD_CHAR_QUOTE;
|
2817
2823
|
}
|
2818
2824
|
|
2819
2825
|
if (md->cb.codespan)
|
@@ -2838,9 +2844,6 @@ sd_markdown_new(
|
|
2838
2844
|
if (extensions & MKDEXT_SUPERSCRIPT)
|
2839
2845
|
md->active_char['^'] = MD_CHAR_SUPERSCRIPT;
|
2840
2846
|
|
2841
|
-
if (extensions & MKDEXT_QUOTE)
|
2842
|
-
md->active_char['"'] = MD_CHAR_QUOTE;
|
2843
|
-
|
2844
2847
|
/* Extension data */
|
2845
2848
|
md->ext_flags = extensions;
|
2846
2849
|
md->opaque = opaque;
|
@@ -2858,6 +2861,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2858
2861
|
|
2859
2862
|
struct buf *text;
|
2860
2863
|
size_t beg, end;
|
2864
|
+
int in_fence = 0;
|
2861
2865
|
|
2862
2866
|
text = bufnew(64);
|
2863
2867
|
if (!text)
|
@@ -2869,7 +2873,8 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2869
2873
|
/* reset the references table */
|
2870
2874
|
memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
|
2871
2875
|
|
2872
|
-
int footnotes_enabled
|
2876
|
+
int footnotes_enabled = md->ext_flags & MKDEXT_FOOTNOTES;
|
2877
|
+
int codefences_enabled = md->ext_flags & MKDEXT_FENCED_CODE;
|
2873
2878
|
|
2874
2879
|
/* reset the footnotes lists */
|
2875
2880
|
if (footnotes_enabled) {
|
@@ -2885,10 +2890,13 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2885
2890
|
if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0)
|
2886
2891
|
beg += 3;
|
2887
2892
|
|
2888
|
-
while (beg < doc_size) /* iterating over lines */
|
2889
|
-
if (
|
2893
|
+
while (beg < doc_size) { /* iterating over lines */
|
2894
|
+
if (codefences_enabled && (is_codefence(document + beg, doc_size - beg, NULL) != 0))
|
2895
|
+
in_fence = !in_fence;
|
2896
|
+
|
2897
|
+
if (!in_fence && footnotes_enabled && is_footnote(document, beg, doc_size, &end, &md->footnotes_found))
|
2890
2898
|
beg = end;
|
2891
|
-
else if (is_ref(document, beg, doc_size, &end, md->refs))
|
2899
|
+
else if (!in_fence && is_ref(document, beg, doc_size, &end, md->refs))
|
2892
2900
|
beg = end;
|
2893
2901
|
else { /* skipping to the next line */
|
2894
2902
|
end = beg;
|
@@ -2908,6 +2916,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2908
2916
|
|
2909
2917
|
beg = end;
|
2910
2918
|
}
|
2919
|
+
}
|
2911
2920
|
|
2912
2921
|
/* pre-grow the output buffer to minimize allocations */
|
2913
2922
|
bufgrow(ob, MARKDOWN_GROW(text->size));
|
@@ -2918,7 +2927,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2918
2927
|
|
2919
2928
|
if (text->size) {
|
2920
2929
|
/* adding a final newline if not already present */
|
2921
|
-
if (text->data[text->size - 1] != '\n' &&
|
2930
|
+
if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r')
|
2922
2931
|
bufputc(text, '\n');
|
2923
2932
|
|
2924
2933
|
parse_block(ob, md, text->data, text->size);
|
@@ -2931,6 +2940,9 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2931
2940
|
if (md->cb.doc_footer)
|
2932
2941
|
md->cb.doc_footer(ob, md->opaque);
|
2933
2942
|
|
2943
|
+
/* Null-terminate the buffer */
|
2944
|
+
bufcstr(ob);
|
2945
|
+
|
2934
2946
|
/* clean-up */
|
2935
2947
|
bufrelease(text);
|
2936
2948
|
free_link_refs(md->refs);
|