rdiscount 2.0.7.3 → 2.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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 )
|