rdiscount 2.0.7.3 → 2.1.6
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/BUILDING +4 -3
- data/COPYING +25 -44
- data/Rakefile +4 -0
- data/ext/Csio.c +1 -1
- data/ext/VERSION +1 -1
- data/ext/blocktags +33 -0
- data/ext/config.h +6 -0
- data/ext/cstring.h +2 -2
- data/ext/flags.c +1 -0
- data/ext/generate.c +146 -64
- data/ext/github_flavoured.c +100 -0
- data/ext/html5.c +0 -2
- data/ext/markdown.c +229 -136
- data/ext/markdown.h +40 -3
- data/ext/mkdio.c +25 -28
- data/ext/mkdio.h +9 -2
- data/ext/mktags.c +89 -0
- data/ext/pgm_options.c +138 -0
- data/ext/pgm_options.h +9 -0
- data/ext/rdiscount.c +52 -52
- data/ext/setup.c +1 -9
- data/ext/tags.c +34 -66
- data/ext/toc.c +21 -10
- data/ext/version.c +9 -1
- data/lib/rdiscount.rb +7 -1
- data/rdiscount.gemspec +7 -2
- data/test/rdiscount_test.rb +86 -1
- metadata +7 -2
@@ -0,0 +1,100 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
* github_flavoured -- implement the obnoxious "returns are hard newlines"
|
4
|
+
* feature in github flavoured markdown.
|
5
|
+
*
|
6
|
+
* Copyright (C) 2012 David L Parsons.
|
7
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
8
|
+
* be distributed with this source code.
|
9
|
+
*/
|
10
|
+
#include "config.h"
|
11
|
+
#include <stdio.h>
|
12
|
+
#include <stdlib.h>
|
13
|
+
#include <ctype.h>
|
14
|
+
|
15
|
+
#include "cstring.h"
|
16
|
+
#include "markdown.h"
|
17
|
+
#include "amalloc.h"
|
18
|
+
|
19
|
+
/* build a Document from any old input.
|
20
|
+
*/
|
21
|
+
typedef int (*getc_func)(void*);
|
22
|
+
|
23
|
+
Document *
|
24
|
+
gfm_populate(getc_func getc, void* ctx, int flags)
|
25
|
+
{
|
26
|
+
Cstring line;
|
27
|
+
Document *a = __mkd_new_Document();
|
28
|
+
int c;
|
29
|
+
int pandoc = 0;
|
30
|
+
|
31
|
+
if ( !a ) return 0;
|
32
|
+
|
33
|
+
a->tabstop = (flags & MKD_TABSTOP) ? 4 : TABSTOP;
|
34
|
+
|
35
|
+
CREATE(line);
|
36
|
+
|
37
|
+
while ( (c = (*getc)(ctx)) != EOF ) {
|
38
|
+
if ( c == '\n' ) {
|
39
|
+
if ( pandoc != EOF && pandoc < 3 ) {
|
40
|
+
if ( S(line) && (T(line)[0] == '%') )
|
41
|
+
pandoc++;
|
42
|
+
else
|
43
|
+
pandoc = EOF;
|
44
|
+
}
|
45
|
+
|
46
|
+
if (pandoc == EOF) {
|
47
|
+
EXPAND(line) = ' ';
|
48
|
+
EXPAND(line) = ' ';
|
49
|
+
}
|
50
|
+
__mkd_enqueue(a, &line);
|
51
|
+
S(line) = 0;
|
52
|
+
}
|
53
|
+
else if ( isprint(c) || isspace(c) || (c & 0x80) )
|
54
|
+
EXPAND(line) = c;
|
55
|
+
}
|
56
|
+
|
57
|
+
if ( S(line) )
|
58
|
+
__mkd_enqueue(a, &line);
|
59
|
+
|
60
|
+
DELETE(line);
|
61
|
+
|
62
|
+
if ( (pandoc == 3) && !(flags & (MKD_NOHEADER|MKD_STRICT)) ) {
|
63
|
+
/* the first three lines started with %, so we have a header.
|
64
|
+
* clip the first three lines out of content and hang them
|
65
|
+
* off header.
|
66
|
+
*/
|
67
|
+
Line *headers = T(a->content);
|
68
|
+
|
69
|
+
a->title = headers; __mkd_header_dle(a->title);
|
70
|
+
a->author= headers->next; __mkd_header_dle(a->author);
|
71
|
+
a->date = headers->next->next; __mkd_header_dle(a->date);
|
72
|
+
|
73
|
+
T(a->content) = headers->next->next->next;
|
74
|
+
}
|
75
|
+
|
76
|
+
return a;
|
77
|
+
}
|
78
|
+
|
79
|
+
|
80
|
+
/* convert a block of text into a linked list
|
81
|
+
*/
|
82
|
+
Document *
|
83
|
+
gfm_string(const char *buf, int len, DWORD flags)
|
84
|
+
{
|
85
|
+
struct string_stream about;
|
86
|
+
|
87
|
+
about.data = buf;
|
88
|
+
about.size = len;
|
89
|
+
|
90
|
+
return gfm_populate((getc_func)__mkd_io_strget, &about, flags & INPUT_MASK);
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
/* convert a file into a linked list
|
95
|
+
*/
|
96
|
+
Document *
|
97
|
+
gfm_in(FILE *f, DWORD flags)
|
98
|
+
{
|
99
|
+
return gfm_populate((getc_func)fgetc, f, flags & INPUT_MASK);
|
100
|
+
}
|
data/ext/html5.c
CHANGED
data/ext/markdown.c
CHANGED
@@ -22,6 +22,9 @@ typedef int (*stfu)(const void*,const void*);
|
|
22
22
|
|
23
23
|
typedef ANCHOR(Paragraph) ParagraphRoot;
|
24
24
|
|
25
|
+
static Paragraph *Pp(ParagraphRoot *, Line *, int);
|
26
|
+
static Paragraph *compile(Line *, int, MMIOT *);
|
27
|
+
|
25
28
|
/* case insensitive string sort for Footnote tags.
|
26
29
|
*/
|
27
30
|
int
|
@@ -77,7 +80,7 @@ mkd_firstnonblank(Line *p)
|
|
77
80
|
}
|
78
81
|
|
79
82
|
|
80
|
-
static int
|
83
|
+
static inline int
|
81
84
|
blankline(Line *p)
|
82
85
|
{
|
83
86
|
return ! (p && (S(p->text) > p->dle) );
|
@@ -173,6 +176,68 @@ splitline(Line *t, int cutpoint)
|
|
173
176
|
}
|
174
177
|
}
|
175
178
|
|
179
|
+
#define UNCHECK(l) ((l)->flags &= ~CHECKED)
|
180
|
+
|
181
|
+
/*
|
182
|
+
* walk a line, seeing if it's any of half a dozen interesting regular
|
183
|
+
* types.
|
184
|
+
*/
|
185
|
+
static void
|
186
|
+
checkline(Line *l)
|
187
|
+
{
|
188
|
+
int eol, i;
|
189
|
+
int dashes = 0, spaces = 0,
|
190
|
+
equals = 0, underscores = 0,
|
191
|
+
stars = 0, tildes = 0,
|
192
|
+
backticks = 0;
|
193
|
+
|
194
|
+
l->flags |= CHECKED;
|
195
|
+
l->kind = chk_text;
|
196
|
+
l->count = 0;
|
197
|
+
|
198
|
+
if (l->dle >= 4) { l->kind=chk_code; return; }
|
199
|
+
|
200
|
+
for ( eol = S(l->text); eol > l->dle && isspace(T(l->text)[eol-1]); --eol )
|
201
|
+
;
|
202
|
+
|
203
|
+
for (i=l->dle; i<eol; i++) {
|
204
|
+
register int c = T(l->text)[i];
|
205
|
+
|
206
|
+
if ( c != ' ' ) l->count++;
|
207
|
+
|
208
|
+
switch (c) {
|
209
|
+
case '-': dashes = 1; break;
|
210
|
+
case ' ': spaces = 1; break;
|
211
|
+
case '=': equals = 1; break;
|
212
|
+
case '_': underscores = 1; break;
|
213
|
+
case '*': stars = 1; break;
|
214
|
+
#if WITH_FENCED_CODE
|
215
|
+
case '~': tildes = 1; break;
|
216
|
+
case '`': backticks = 1; break;
|
217
|
+
#endif
|
218
|
+
default: return;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
if ( dashes + equals + underscores + stars + tildes + backticks > 1 )
|
223
|
+
return;
|
224
|
+
|
225
|
+
if ( spaces ) {
|
226
|
+
if ( (underscores || stars || dashes) )
|
227
|
+
l->kind = chk_hr;
|
228
|
+
return;
|
229
|
+
}
|
230
|
+
|
231
|
+
if ( stars || underscores ) { l->kind = chk_hr; }
|
232
|
+
else if ( dashes ) { l->kind = chk_dash; }
|
233
|
+
else if ( equals ) { l->kind = chk_equal; }
|
234
|
+
#if WITH_FENCED_CODE
|
235
|
+
else if ( tildes ) { l->kind = chk_tilde; }
|
236
|
+
else if ( backticks ) { l->kind = chk_backtick; }
|
237
|
+
#endif
|
238
|
+
}
|
239
|
+
|
240
|
+
|
176
241
|
|
177
242
|
static Line *
|
178
243
|
commentblock(Paragraph *p, int *unclosed)
|
@@ -261,37 +326,6 @@ htmlblock(Paragraph *p, struct kw *tag, int *unclosed)
|
|
261
326
|
}
|
262
327
|
|
263
328
|
|
264
|
-
/* tables look like
|
265
|
-
* header|header{|header}
|
266
|
-
* ------|------{|......}
|
267
|
-
* {body lines}
|
268
|
-
*/
|
269
|
-
static int
|
270
|
-
istable(Line *t)
|
271
|
-
{
|
272
|
-
char *p;
|
273
|
-
Line *dashes = t->next;
|
274
|
-
int contains = 0; /* found character bits; 0x01 is |, 0x02 is - */
|
275
|
-
|
276
|
-
/* two lines, first must contain | */
|
277
|
-
if ( !(dashes && memchr(T(t->text), '|', S(t->text))) )
|
278
|
-
return 0;
|
279
|
-
|
280
|
-
/* second line must contain - or | and nothing
|
281
|
-
* else except for whitespace or :
|
282
|
-
*/
|
283
|
-
for ( p = T(dashes->text)+S(dashes->text)-1; p >= T(dashes->text); --p)
|
284
|
-
if ( *p == '|' )
|
285
|
-
contains |= 0x01;
|
286
|
-
else if ( *p == '-' )
|
287
|
-
contains |= 0x02;
|
288
|
-
else if ( ! ((*p == ':') || isspace(*p)) )
|
289
|
-
return 0;
|
290
|
-
|
291
|
-
return (contains & 0x03);
|
292
|
-
}
|
293
|
-
|
294
|
-
|
295
329
|
/* footnotes look like ^<whitespace>{0,3}[stuff]: <content>$
|
296
330
|
*/
|
297
331
|
static int
|
@@ -312,76 +346,46 @@ isfootnote(Line *t)
|
|
312
346
|
}
|
313
347
|
|
314
348
|
|
315
|
-
static int
|
349
|
+
static inline int
|
316
350
|
isquote(Line *t)
|
317
351
|
{
|
318
|
-
|
319
|
-
|
320
|
-
for ( j=0; j < 4; j++ )
|
321
|
-
if ( T(t->text)[j] == '>' )
|
322
|
-
return 1;
|
323
|
-
else if ( !isspace(T(t->text)[j]) )
|
324
|
-
return 0;
|
325
|
-
return 0;
|
352
|
+
return (t->dle < 4 && T(t->text)[t->dle] == '>');
|
326
353
|
}
|
327
354
|
|
328
355
|
|
329
|
-
static int
|
330
|
-
dashchar(char c)
|
331
|
-
{
|
332
|
-
return (c == '*') || (c == '-') || (c == '_');
|
333
|
-
}
|
334
|
-
|
335
|
-
|
336
|
-
static int
|
356
|
+
static inline int
|
337
357
|
iscode(Line *t)
|
338
358
|
{
|
339
359
|
return (t->dle >= 4);
|
340
360
|
}
|
341
361
|
|
342
362
|
|
343
|
-
static int
|
363
|
+
static inline int
|
344
364
|
ishr(Line *t)
|
345
365
|
{
|
346
|
-
|
347
|
-
|
348
|
-
char c;
|
349
|
-
|
350
|
-
if ( iscode(t) ) return 0;
|
351
|
-
|
352
|
-
for ( i = 0; i < S(t->text); i++) {
|
353
|
-
c = T(t->text)[i];
|
354
|
-
if ( (dash == 0) && dashchar(c) )
|
355
|
-
dash = c;
|
366
|
+
if ( ! (t->flags & CHECKED) )
|
367
|
+
checkline(t);
|
356
368
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
}
|
361
|
-
return (count >= 3);
|
369
|
+
if ( t->count > 2 )
|
370
|
+
return t->kind == chk_hr || t->kind == chk_dash || t->kind == chk_equal;
|
371
|
+
return 0;
|
362
372
|
}
|
363
373
|
|
364
374
|
|
365
375
|
static int
|
366
376
|
issetext(Line *t, int *htyp)
|
367
377
|
{
|
368
|
-
|
369
|
-
|
370
|
-
|
378
|
+
Line *n;
|
379
|
+
|
380
|
+
/* check for setext-style HEADER
|
381
|
+
* ======
|
371
382
|
*/
|
372
383
|
|
373
|
-
if ( t->next ) {
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
if ( (*q == '=') || (*q == '-') ) {
|
378
|
-
/* ignore trailing whitespace */
|
379
|
-
while ( (last > 1) && isspace(q[last-1]) )
|
380
|
-
--last;
|
384
|
+
if ( (n = t->next) ) {
|
385
|
+
if ( !(n->flags & CHECKED) )
|
386
|
+
checkline(n);
|
381
387
|
|
382
|
-
|
383
|
-
if ( q[0] != q[i] )
|
384
|
-
return 0;
|
388
|
+
if ( n->kind == chk_dash || n->kind == chk_equal ) {
|
385
389
|
*htyp = SETEXT;
|
386
390
|
return 1;
|
387
391
|
}
|
@@ -393,28 +397,31 @@ issetext(Line *t, int *htyp)
|
|
393
397
|
static int
|
394
398
|
ishdr(Line *t, int *htyp)
|
395
399
|
{
|
396
|
-
int i;
|
397
|
-
|
398
|
-
|
399
|
-
/* first check for etx-style ###HEADER###
|
400
|
-
*/
|
401
|
-
|
402
|
-
/* leading run of `#`'s ?
|
403
|
-
*/
|
404
|
-
for ( i=0; T(t->text)[i] == '#'; ++i)
|
405
|
-
;
|
406
|
-
|
407
400
|
/* ANY leading `#`'s make this into an ETX header
|
408
401
|
*/
|
409
|
-
if (
|
402
|
+
if ( (t->dle == 0) && (S(t->text) > 1) && (T(t->text)[0] == '#') ) {
|
410
403
|
*htyp = ETX;
|
411
404
|
return 1;
|
412
405
|
}
|
413
406
|
|
407
|
+
/* And if not, maybe it's a SETEXT header instead
|
408
|
+
*/
|
414
409
|
return issetext(t, htyp);
|
415
410
|
}
|
416
411
|
|
417
412
|
|
413
|
+
static inline int
|
414
|
+
end_of_block(Line *t)
|
415
|
+
{
|
416
|
+
int dummy;
|
417
|
+
|
418
|
+
if ( !t )
|
419
|
+
return 0;
|
420
|
+
|
421
|
+
return ( (S(t->text) <= t->dle) || ishr(t) || ishdr(t, &dummy) );
|
422
|
+
}
|
423
|
+
|
424
|
+
|
418
425
|
static Line*
|
419
426
|
is_discount_dt(Line *t, int *clip)
|
420
427
|
{
|
@@ -448,13 +455,12 @@ static Line*
|
|
448
455
|
is_extra_dt(Line *t, int *clip)
|
449
456
|
{
|
450
457
|
#if USE_EXTRA_DL
|
451
|
-
int i;
|
452
458
|
|
453
|
-
if ( t && t->next && T(t->text)[0] != '='
|
459
|
+
if ( t && t->next && S(t->text) && T(t->text)[0] != '='
|
454
460
|
&& T(t->text)[S(t->text)-1] != '=') {
|
455
461
|
Line *x;
|
456
462
|
|
457
|
-
if ( iscode(t) ||
|
463
|
+
if ( iscode(t) || end_of_block(t) )
|
458
464
|
return 0;
|
459
465
|
|
460
466
|
if ( (x = skipempty(t->next)) && is_extra_dd(x) ) {
|
@@ -490,7 +496,7 @@ islist(Line *t, int *clip, DWORD flags, int *list_type)
|
|
490
496
|
int i, j;
|
491
497
|
char *q;
|
492
498
|
|
493
|
-
if (
|
499
|
+
if ( end_of_block(t) )
|
494
500
|
return 0;
|
495
501
|
|
496
502
|
if ( !(flags & (MKD_NODLIST|MKD_STRICT)) && isdefinition(t,clip,list_type) )
|
@@ -518,6 +524,7 @@ islist(Line *t, int *clip, DWORD flags, int *list_type)
|
|
518
524
|
strtoul(T(t->text)+t->dle, &q, 10);
|
519
525
|
if ( (q > T(t->text)+t->dle) && (q == T(t->text) + (j-1)) ) {
|
520
526
|
j = nextnonblank(t,j);
|
527
|
+
/* *clip = j; */
|
521
528
|
*clip = (j > 4) ? 4 : j;
|
522
529
|
*list_type = OL;
|
523
530
|
return AL;
|
@@ -561,6 +568,7 @@ headerblock(Paragraph *pp, int htyp)
|
|
561
568
|
++i;
|
562
569
|
|
563
570
|
CLIP(p->text, 0, i);
|
571
|
+
UNCHECK(p);
|
564
572
|
|
565
573
|
for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j)
|
566
574
|
;
|
@@ -597,6 +605,49 @@ codeblock(Paragraph *p)
|
|
597
605
|
}
|
598
606
|
|
599
607
|
|
608
|
+
#ifdef WITH_FENCED_CODE
|
609
|
+
static int
|
610
|
+
iscodefence(Line *r, int size, line_type kind)
|
611
|
+
{
|
612
|
+
if ( !(r->flags & CHECKED) )
|
613
|
+
checkline(r);
|
614
|
+
|
615
|
+
if ( kind )
|
616
|
+
return (r->kind == kind) && (r->count >= size);
|
617
|
+
else
|
618
|
+
return (r->kind == chk_tilde || r->kind == chk_backtick) && (r->count >= size);
|
619
|
+
}
|
620
|
+
|
621
|
+
static Paragraph *
|
622
|
+
fencedcodeblock(ParagraphRoot *d, Line **ptr)
|
623
|
+
{
|
624
|
+
Line *first, *r;
|
625
|
+
Paragraph *ret;
|
626
|
+
|
627
|
+
first = (*ptr);
|
628
|
+
|
629
|
+
/* don't allow zero-length code fences
|
630
|
+
*/
|
631
|
+
if ( (first->next == 0) || iscodefence(first->next, first->count, 0) )
|
632
|
+
return 0;
|
633
|
+
|
634
|
+
/* find the closing fence, discard the fences,
|
635
|
+
* return a Paragraph with the contents
|
636
|
+
*/
|
637
|
+
for ( r = first; r && r->next; r = r->next )
|
638
|
+
if ( iscodefence(r->next, first->count, first->kind) ) {
|
639
|
+
(*ptr) = r->next->next;
|
640
|
+
ret = Pp(d, first->next, CODE);
|
641
|
+
___mkd_freeLine(first);
|
642
|
+
___mkd_freeLine(r->next);
|
643
|
+
r->next = 0;
|
644
|
+
return ret;
|
645
|
+
}
|
646
|
+
return 0;
|
647
|
+
}
|
648
|
+
#endif
|
649
|
+
|
650
|
+
|
600
651
|
static int
|
601
652
|
centered(Line *first, Line *last)
|
602
653
|
{
|
@@ -620,19 +671,18 @@ endoftextblock(Line *t, int toplevelblock, DWORD flags)
|
|
620
671
|
{
|
621
672
|
int z;
|
622
673
|
|
623
|
-
if (
|
674
|
+
if ( end_of_block(t) || isquote(t) )
|
624
675
|
return 1;
|
625
676
|
|
626
|
-
/* HORRIBLE STANDARDS
|
627
|
-
* code blocks
|
677
|
+
/* HORRIBLE STANDARDS KLUDGES:
|
678
|
+
* 1. non-toplevel paragraphs absorb adjacent code blocks
|
679
|
+
* 2. Toplevel paragraphs eat absorb adjacent list items,
|
680
|
+
* but sublevel blocks behave properly.
|
681
|
+
* (What this means is that we only need to check for code
|
682
|
+
* blocks at toplevel, and only check for list items at
|
683
|
+
* nested levels.)
|
628
684
|
*/
|
629
|
-
|
630
|
-
return 1;
|
631
|
-
|
632
|
-
/* HORRIBLE STANDARDS KLUDGE: Toplevel paragraphs eat absorb adjacent
|
633
|
-
* list items, but sublevel blocks behave properly.
|
634
|
-
*/
|
635
|
-
return toplevelblock ? 0 : islist(t,&z,flags, &z);
|
685
|
+
return toplevelblock ? 0 : islist(t,&z,flags,&z);
|
636
686
|
}
|
637
687
|
|
638
688
|
|
@@ -680,6 +730,7 @@ isdivmarker(Line *p, int start, DWORD flags)
|
|
680
730
|
if ( flags & (MKD_NODIVQUOTE|MKD_STRICT) )
|
681
731
|
return 0;
|
682
732
|
|
733
|
+
start = nextnonblank(p, start);
|
683
734
|
last= S(p->text) - (1 + start);
|
684
735
|
s = T(p->text) + start;
|
685
736
|
|
@@ -703,7 +754,7 @@ isdivmarker(Line *p, int start, DWORD flags)
|
|
703
754
|
*
|
704
755
|
* one sick horrible thing about blockquotes is that even though
|
705
756
|
* it just takes ^> to start a quote, following lines, if quoted,
|
706
|
-
* assume that the prefix is ``>''. This means that code needs
|
757
|
+
* assume that the prefix is ``> ''. This means that code needs
|
707
758
|
* to be indented *5* spaces from the leading '>', but *4* spaces
|
708
759
|
* from the start of the line. This does not appear to be
|
709
760
|
* documented in the reference implementation, but it's the
|
@@ -728,6 +779,7 @@ quoteblock(Paragraph *p, DWORD flags)
|
|
728
779
|
if ( T(t->text)[qp] == ' ' )
|
729
780
|
qp++;
|
730
781
|
CLIP(t->text, 0, qp);
|
782
|
+
UNCHECK(t);
|
731
783
|
t->dle = mkd_firstnonblank(t);
|
732
784
|
}
|
733
785
|
|
@@ -760,28 +812,6 @@ quoteblock(Paragraph *p, DWORD flags)
|
|
760
812
|
}
|
761
813
|
|
762
814
|
|
763
|
-
/*
|
764
|
-
* A table block starts with a table header (see istable()), and continues
|
765
|
-
* until EOF or a line that /doesn't/ contain a |.
|
766
|
-
*/
|
767
|
-
static Line *
|
768
|
-
tableblock(Paragraph *p)
|
769
|
-
{
|
770
|
-
Line *t, *q;
|
771
|
-
|
772
|
-
for ( t = p->text; t && (q = t->next); t = t->next ) {
|
773
|
-
if ( !memchr(T(q->text), '|', S(q->text)) ) {
|
774
|
-
t->next = 0;
|
775
|
-
return q;
|
776
|
-
}
|
777
|
-
}
|
778
|
-
return 0;
|
779
|
-
}
|
780
|
-
|
781
|
-
|
782
|
-
static Paragraph *Pp(ParagraphRoot *, Line *, int);
|
783
|
-
static Paragraph *compile(Line *, int, MMIOT *);
|
784
|
-
|
785
815
|
typedef int (*linefn)(Line *);
|
786
816
|
|
787
817
|
|
@@ -800,6 +830,7 @@ listitem(Paragraph *p, int indent, DWORD flags, linefn check)
|
|
800
830
|
|
801
831
|
for ( t = p->text; t ; t = q) {
|
802
832
|
CLIP(t->text, 0, clip);
|
833
|
+
UNCHECK(t);
|
803
834
|
t->dle = mkd_firstnonblank(t);
|
804
835
|
|
805
836
|
if ( (q = skipempty(t->next)) == 0 ) {
|
@@ -853,13 +884,14 @@ definition_block(Paragraph *top, int clip, MMIOT *f, int kind)
|
|
853
884
|
if ( (text = skipempty(q->next)) == 0 )
|
854
885
|
break;
|
855
886
|
|
856
|
-
if (
|
887
|
+
if ( para = (text != q->next) )
|
857
888
|
___mkd_freeLineRange(q, text);
|
858
889
|
|
859
890
|
q->next = 0;
|
860
891
|
if ( kind == 1 /* discount dl */ )
|
861
892
|
for ( q = labels; q; q = q->next ) {
|
862
893
|
CLIP(q->text, 0, 1);
|
894
|
+
UNCHECK(q);
|
863
895
|
S(q->text)--;
|
864
896
|
}
|
865
897
|
|
@@ -875,7 +907,7 @@ definition_block(Paragraph *top, int clip, MMIOT *f, int kind)
|
|
875
907
|
if ( (q = skipempty(text)) == 0 )
|
876
908
|
break;
|
877
909
|
|
878
|
-
if (
|
910
|
+
if ( para = (q != text) ) {
|
879
911
|
Line anchor;
|
880
912
|
|
881
913
|
anchor.next = text;
|
@@ -1065,6 +1097,7 @@ compile_document(Line *ptr, MMIOT *f)
|
|
1065
1097
|
|
1066
1098
|
while ( ptr ) {
|
1067
1099
|
if ( !(f->flags & MKD_NOHTML) && (tag = isopentag(ptr)) ) {
|
1100
|
+
int blocktype;
|
1068
1101
|
/* If we encounter a html/style block, compile and save all
|
1069
1102
|
* of the cached source BEFORE processing the html/style.
|
1070
1103
|
*/
|
@@ -1074,7 +1107,12 @@ compile_document(Line *ptr, MMIOT *f)
|
|
1074
1107
|
p->down = compile(T(source), 1, f);
|
1075
1108
|
T(source) = E(source) = 0;
|
1076
1109
|
}
|
1077
|
-
|
1110
|
+
|
1111
|
+
if ( f->flags & MKD_NOSTYLE )
|
1112
|
+
blocktype = HTML;
|
1113
|
+
else
|
1114
|
+
blocktype = strcmp(tag->id, "STYLE") == 0 ? STYLE : HTML;
|
1115
|
+
p = Pp(&d, ptr, blocktype);
|
1078
1116
|
ptr = htmlblock(p, tag, &unclosed);
|
1079
1117
|
if ( unclosed ) {
|
1080
1118
|
p->typ = SOURCE;
|
@@ -1109,6 +1147,58 @@ compile_document(Line *ptr, MMIOT *f)
|
|
1109
1147
|
}
|
1110
1148
|
|
1111
1149
|
|
1150
|
+
static int
|
1151
|
+
first_nonblank_before(Line *j, int dle)
|
1152
|
+
{
|
1153
|
+
return (j->dle < dle) ? j->dle : dle;
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
|
1157
|
+
static int
|
1158
|
+
actually_a_table(MMIOT *f, Line *pp)
|
1159
|
+
{
|
1160
|
+
Line *r;
|
1161
|
+
int j;
|
1162
|
+
int c;
|
1163
|
+
|
1164
|
+
/* tables need to be turned on */
|
1165
|
+
if ( f->flags & (MKD_STRICT|MKD_NOTABLES) )
|
1166
|
+
return 0;
|
1167
|
+
|
1168
|
+
/* tables need three lines */
|
1169
|
+
if ( !(pp && pp->next && pp->next->next) ) {
|
1170
|
+
return 0;
|
1171
|
+
}
|
1172
|
+
|
1173
|
+
/* all lines must contain |'s */
|
1174
|
+
for (r = pp; r; r = r->next )
|
1175
|
+
if ( !(r->flags & PIPECHAR) ) {
|
1176
|
+
return 0;
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
/* if the header has a leading |, all lines must have leading |'s */
|
1180
|
+
if ( T(pp->text)[pp->dle] == '|' ) {
|
1181
|
+
for ( r = pp; r; r = r->next )
|
1182
|
+
if ( T(r->text)[first_nonblank_before(r,pp->dle)] != '|' ) {
|
1183
|
+
return 0;
|
1184
|
+
}
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
/* second line must be only whitespace, -, |, or : */
|
1188
|
+
r = pp->next;
|
1189
|
+
|
1190
|
+
for ( j=r->dle; j < S(r->text); ++j ) {
|
1191
|
+
c = T(r->text)[j];
|
1192
|
+
|
1193
|
+
if ( !(isspace(c)||(c=='-')||(c==':')||(c=='|')) ) {
|
1194
|
+
return 0;
|
1195
|
+
}
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
return 1;
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
|
1112
1202
|
/*
|
1113
1203
|
* break a collection of markdown input into
|
1114
1204
|
* blocks of lists, code, html, and text to
|
@@ -1139,13 +1229,17 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
1139
1229
|
|
1140
1230
|
ptr = codeblock(p);
|
1141
1231
|
}
|
1232
|
+
#if WITH_FENCED_CODE
|
1233
|
+
else if ( iscodefence(ptr,3,0) && (p=fencedcodeblock(&d, &ptr)) )
|
1234
|
+
/* yay, it's already done */ ;
|
1235
|
+
#endif
|
1142
1236
|
else if ( ishr(ptr) ) {
|
1143
1237
|
p = Pp(&d, 0, HR);
|
1144
1238
|
r = ptr;
|
1145
1239
|
ptr = ptr->next;
|
1146
1240
|
___mkd_freeLine(r);
|
1147
1241
|
}
|
1148
|
-
else if (
|
1242
|
+
else if ( list_class = islist(ptr, &indent, f->flags, &list_type) ) {
|
1149
1243
|
if ( list_class == DL ) {
|
1150
1244
|
p = Pp(&d, ptr, DL);
|
1151
1245
|
ptr = definition_block(p, indent, f, list_type);
|
@@ -1165,13 +1259,12 @@ compile(Line *ptr, int toplevel, MMIOT *f)
|
|
1165
1259
|
p = Pp(&d, ptr, HDR);
|
1166
1260
|
ptr = headerblock(p, hdr_type);
|
1167
1261
|
}
|
1168
|
-
else if ( istable(ptr) && !(f->flags & (MKD_STRICT|MKD_NOTABLES)) ) {
|
1169
|
-
p = Pp(&d, ptr, TABLE);
|
1170
|
-
ptr = tableblock(p);
|
1171
|
-
}
|
1172
1262
|
else {
|
1173
1263
|
p = Pp(&d, ptr, MARKUP);
|
1174
1264
|
ptr = textblock(p, toplevel, f->flags);
|
1265
|
+
/* tables are a special kind of paragraph */
|
1266
|
+
if ( actually_a_table(f, p->text) )
|
1267
|
+
p->typ = TABLE;
|
1175
1268
|
}
|
1176
1269
|
|
1177
1270
|
if ( (para||toplevel) && !p->align )
|