rdiscount 1.6.8 → 2.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/BUILDING +5 -1
- data/README.markdown +7 -7
- data/Rakefile +3 -2
- data/ext/config.h +8 -6
- data/ext/css.c +14 -5
- data/ext/cstring.h +1 -1
- data/ext/docheader.c +13 -7
- data/ext/dumptree.c +1 -1
- data/ext/emmatch.c +1 -1
- data/ext/extconf.rb +13 -0
- data/ext/generate.c +215 -55
- data/ext/markdown.c +225 -100
- data/ext/markdown.h +48 -27
- data/ext/mkdio.c +49 -32
- data/ext/mkdio.h +42 -24
- data/ext/rdiscount.c +4 -0
- data/ext/resource.c +3 -1
- data/ext/setup.c +47 -0
- data/ext/tags.c +15 -2
- data/ext/tags.h +1 -0
- data/ext/toc.c +35 -22
- data/lib/rdiscount.rb +5 -1
- data/rdiscount.gemspec +4 -4
- data/test/rdiscount_test.rb +12 -2
- metadata +25 -41
data/BUILDING
CHANGED
@@ -16,8 +16,12 @@ Gathering changes from an upstream Orc/discount.git clone requires first
|
|
16
16
|
grabbing the discount submodule into the root of the project and then running
|
17
17
|
the rake gather task to copy discount source files into the ext/ directory:
|
18
18
|
|
19
|
-
$ git submodule init
|
19
|
+
$ git submodule update --init
|
20
20
|
Submodule 'discount' (git://github.com/rtomayko/discount.git) registered for path 'discount'
|
21
|
+
Cloning into discount...
|
22
|
+
$ cd discount
|
23
|
+
$ ./configure.sh # to generate mkdio.h from mkdio.h.in
|
24
|
+
$ cd ..
|
21
25
|
$ rake gather
|
22
26
|
$ rake build
|
23
27
|
|
data/README.markdown
CHANGED
@@ -8,22 +8,22 @@ passes the [Markdown 1.0 test suite][2].
|
|
8
8
|
CODE: `git clone git://github.com/rtomayko/rdiscount.git`
|
9
9
|
HOME: <http://github.com/rtomayko/rdiscount>
|
10
10
|
DOCS: <http://rdoc.info/projects/rtomayko/rdiscount>
|
11
|
-
BUGS: <http://github.com/rtomayko/rdiscount/issues>
|
11
|
+
BUGS: <http://github.com/rtomayko/rdiscount/issues>
|
12
12
|
|
13
13
|
Discount was developed by [David Loren Parsons][3]. The Ruby extension
|
14
|
-
is maintained by [
|
14
|
+
is maintained by [David Foster][4].
|
15
15
|
|
16
16
|
[1]: http://daringfireball.net/projects/markdown/syntax
|
17
17
|
[2]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
|
18
18
|
[3]: http://www.pell.portland.or.us/~orc
|
19
|
-
[4]:
|
19
|
+
[4]: https://github.com/davidfstr
|
20
20
|
|
21
21
|
INSTALL, HACKING
|
22
22
|
----------------
|
23
23
|
|
24
|
-
New releases of RDiscount are published to [
|
24
|
+
New releases of RDiscount are published to [RubyGems][]:
|
25
25
|
|
26
|
-
$ [sudo] gem install rdiscount
|
26
|
+
$ [sudo] gem install rdiscount
|
27
27
|
|
28
28
|
The RDiscount sources are available via Git:
|
29
29
|
|
@@ -33,8 +33,8 @@ The RDiscount sources are available via Git:
|
|
33
33
|
|
34
34
|
See the file [BUILDING][] for hacking instructions.
|
35
35
|
|
36
|
-
[
|
37
|
-
[BUILDING]: BUILDING
|
36
|
+
[RubyGems]: https://rubygems.org/gems/rdiscount
|
37
|
+
[BUILDING]: https://github.com/rtomayko/rdiscount/blob/master/BUILDING
|
38
38
|
|
39
39
|
USAGE
|
40
40
|
-----
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ task :default => :test
|
|
9
9
|
# ==========================================================
|
10
10
|
|
11
11
|
DLEXT = Config::MAKEFILE_CONFIG['DLEXT']
|
12
|
-
RUBYDIGEST = Digest::MD5.hexdigest(
|
12
|
+
RUBYDIGEST = Digest::MD5.hexdigest(`ruby --version`)
|
13
13
|
|
14
14
|
file "ext/ruby-#{RUBYDIGEST}" do |f|
|
15
15
|
rm_f FileList["ext/ruby-*"]
|
@@ -61,8 +61,9 @@ desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
|
|
61
61
|
task 'test:conformance' => [:build] do |t|
|
62
62
|
script = "#{pwd}/bin/rdiscount"
|
63
63
|
test_version = ENV['MARKDOWN_TEST_VER'] || '1.0.3'
|
64
|
+
lib_dir = "#{pwd}/lib"
|
64
65
|
chdir("test/MarkdownTest_#{test_version}") do
|
65
|
-
sh "./MarkdownTest.pl --script='#{script}' --tidy"
|
66
|
+
sh "RUBYLIB=#{lib_dir} ./MarkdownTest.pl --script='#{script}' --tidy"
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
data/ext/config.h
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* rdiscount extension discount configuration
|
3
|
+
*/
|
4
|
+
#ifndef __MARKDOWN_D
|
5
|
+
#define __MARKDOWN_D 1
|
1
6
|
|
2
|
-
/*
|
3
|
-
|
4
|
-
#undef USE_AMALLOC
|
5
|
-
|
7
|
+
/* tabs are four spaces */
|
6
8
|
#define TABSTOP 4
|
7
9
|
|
10
|
+
/* these are setup by extconf.rb */
|
8
11
|
#if HAVE_RANDOM
|
9
12
|
#define COINTOSS() (random()&1)
|
10
13
|
#elif HAVE_RAND
|
@@ -17,5 +20,4 @@
|
|
17
20
|
#define INITRNG(x) srand((unsigned int)x)
|
18
21
|
#endif
|
19
22
|
|
20
|
-
#
|
21
|
-
#define SUPERSCRIPT 1
|
23
|
+
#endif/* __MARKDOWN_D */
|
data/ext/css.c
CHANGED
@@ -28,9 +28,10 @@ stylesheets(Paragraph *p, Cstring *f)
|
|
28
28
|
|
29
29
|
for ( ; p ; p = p->next ) {
|
30
30
|
if ( p->typ == STYLE ) {
|
31
|
-
for ( q = p->text; q ; q = q->next )
|
31
|
+
for ( q = p->text; q ; q = q->next ) {
|
32
32
|
Cswrite(f, T(q->text), S(q->text));
|
33
33
|
Csputc('\n', f);
|
34
|
+
}
|
34
35
|
}
|
35
36
|
if ( p->down )
|
36
37
|
stylesheets(p->down, f);
|
@@ -44,17 +45,25 @@ int
|
|
44
45
|
mkd_css(Document *d, char **res)
|
45
46
|
{
|
46
47
|
Cstring f;
|
48
|
+
int size;
|
47
49
|
|
48
|
-
if ( res &&
|
50
|
+
if ( res && d && d->compiled ) {
|
51
|
+
*res = 0;
|
49
52
|
CREATE(f);
|
50
53
|
RESERVE(f, 100);
|
51
54
|
stylesheets(d->code, &f);
|
52
55
|
|
56
|
+
if ( (size = S(f)) > 0 ) {
|
57
|
+
EXPAND(f) = 0;
|
53
58
|
/* HACK ALERT! HACK ALERT! HACK ALERT! */
|
54
|
-
|
59
|
+
*res = T(f);/* we know that a T(Cstring) is a character pointer */
|
55
60
|
/* so we can simply pick it up and carry it away, */
|
56
|
-
|
61
|
+
/* leaving the husk of the Ctring on the stack */
|
57
62
|
/* END HACK ALERT */
|
63
|
+
}
|
64
|
+
else
|
65
|
+
DELETE(f);
|
66
|
+
return size;
|
58
67
|
}
|
59
68
|
return EOF;
|
60
69
|
}
|
@@ -69,7 +78,7 @@ mkd_generatecss(Document *d, FILE *f)
|
|
69
78
|
int written = EOF, size = mkd_css(d, &res);
|
70
79
|
|
71
80
|
if ( size > 0 )
|
72
|
-
written = fwrite(res,
|
81
|
+
written = fwrite(res, 1, size, f);
|
73
82
|
if ( res )
|
74
83
|
free(res);
|
75
84
|
return (written == size) ? size : EOF;
|
data/ext/cstring.h
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
*/
|
19
19
|
#define STRING(type) struct { type *text; int size, alloc; }
|
20
20
|
|
21
|
-
#define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0)
|
21
|
+
#define CREATE(x) ( (T(x) = (void*)0), (S(x) = (x).alloc = 0) )
|
22
22
|
#define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \
|
23
23
|
? (T(x)) \
|
24
24
|
: (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \
|
data/ext/docheader.c
CHANGED
@@ -14,13 +14,19 @@
|
|
14
14
|
#include "markdown.h"
|
15
15
|
#include "amalloc.h"
|
16
16
|
|
17
|
-
|
17
|
+
static char *
|
18
|
+
onlyifset(Line *l)
|
19
|
+
{
|
20
|
+
char *ret = T(l->text) + l->dle;
|
21
|
+
|
22
|
+
return ret[0] ? ret : 0;
|
23
|
+
}
|
18
24
|
|
19
25
|
char *
|
20
26
|
mkd_doc_title(Document *doc)
|
21
27
|
{
|
22
|
-
if ( doc && doc->
|
23
|
-
return
|
28
|
+
if ( doc && doc->title )
|
29
|
+
return onlyifset(doc->title);
|
24
30
|
return 0;
|
25
31
|
}
|
26
32
|
|
@@ -28,8 +34,8 @@ mkd_doc_title(Document *doc)
|
|
28
34
|
char *
|
29
35
|
mkd_doc_author(Document *doc)
|
30
36
|
{
|
31
|
-
if ( doc && doc->
|
32
|
-
return
|
37
|
+
if ( doc && doc->author )
|
38
|
+
return onlyifset(doc->author);
|
33
39
|
return 0;
|
34
40
|
}
|
35
41
|
|
@@ -37,7 +43,7 @@ mkd_doc_author(Document *doc)
|
|
37
43
|
char *
|
38
44
|
mkd_doc_date(Document *doc)
|
39
45
|
{
|
40
|
-
if ( doc && doc->
|
41
|
-
return
|
46
|
+
if ( doc && doc->date )
|
47
|
+
return onlyifset(doc->date);
|
42
48
|
return 0;
|
43
49
|
}
|
data/ext/dumptree.c
CHANGED
@@ -111,7 +111,7 @@ dumptree(Paragraph *pp, Stack *sp, FILE *f)
|
|
111
111
|
d = fprintf(f, "[%s", Pptype(pp->typ));
|
112
112
|
if ( pp->ident )
|
113
113
|
d += fprintf(f, " %s", pp->ident);
|
114
|
-
if ( pp->align )
|
114
|
+
if ( pp->align > 1 )
|
115
115
|
d += fprintf(f, ", <%s>", Begin[pp->align]);
|
116
116
|
|
117
117
|
for (count=0, p=pp->text; p; ++count, (p = p->next) )
|
data/ext/emmatch.c
CHANGED
@@ -163,7 +163,7 @@ emblock(MMIOT *f, int first, int last)
|
|
163
163
|
} /* emblock */
|
164
164
|
|
165
165
|
|
166
|
-
/* ___mkd_emblock() -- emblock a string of blocks, then
|
166
|
+
/* ___mkd_emblock() -- emblock a string of blocks, then concatenate the
|
167
167
|
* resulting text onto f->out.
|
168
168
|
*/
|
169
169
|
void
|
data/ext/extconf.rb
CHANGED
@@ -7,4 +7,17 @@ HAVE_SRANDOM = have_func('srandom')
|
|
7
7
|
HAVE_RAND = have_func('rand')
|
8
8
|
HAVE_SRAND = have_func('srand')
|
9
9
|
|
10
|
+
def sized_int(size, types)
|
11
|
+
types.find { |type| check_sizeof(type) == 4 } ||
|
12
|
+
abort("no int with size #{size}")
|
13
|
+
end
|
14
|
+
|
15
|
+
DWORD = sized_int(4, ["unsigned long", "unsigned int"])
|
16
|
+
WORD = sized_int(2, ["unsigned int", "unsigned short"])
|
17
|
+
BYTE = "unsigned char"
|
18
|
+
|
19
|
+
$defs.push("-DDWORD='#{DWORD}'")
|
20
|
+
$defs.push("-DWORD='#{WORD}'")
|
21
|
+
$defs.push("-DBYTE='#{BYTE}'")
|
22
|
+
|
10
23
|
create_makefile('rdiscount')
|
data/ext/generate.c
CHANGED
@@ -191,6 +191,7 @@ ___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
|
|
191
191
|
|
192
192
|
sub.flags = f->flags | flags;
|
193
193
|
sub.cb = f->cb;
|
194
|
+
sub.ref_prefix = f->ref_prefix;
|
194
195
|
|
195
196
|
push(bfr, size, &sub);
|
196
197
|
EXPAND(sub.in) = 0;
|
@@ -351,6 +352,53 @@ linkysize(MMIOT *f, Footnote *ref)
|
|
351
352
|
}
|
352
353
|
|
353
354
|
|
355
|
+
/* extract a <...>-encased url from the input stream.
|
356
|
+
* (markdown 1.0.2b8 compatibility; older versions
|
357
|
+
* of markdown treated the < and > as syntactic
|
358
|
+
* sugar that didn't have to be there. 1.0.2b8
|
359
|
+
* requires a closing >, and then falls into the
|
360
|
+
* title or closing )
|
361
|
+
*/
|
362
|
+
static int
|
363
|
+
linkybroket(MMIOT *f, int image, Footnote *p)
|
364
|
+
{
|
365
|
+
int c;
|
366
|
+
int good = 0;
|
367
|
+
|
368
|
+
T(p->link) = cursor(f);
|
369
|
+
for ( S(p->link)=0; (c = pull(f)) != '>'; ++S(p->link) ) {
|
370
|
+
/* pull in all input until a '>' is found, or die trying.
|
371
|
+
*/
|
372
|
+
if ( c == EOF )
|
373
|
+
return 0;
|
374
|
+
else if ( (c == '\\') && ispunct(peek(f,2)) ) {
|
375
|
+
++S(p->link);
|
376
|
+
pull(f);
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
c = eatspace(f);
|
381
|
+
|
382
|
+
/* next nonspace needs to be a title, a size, or )
|
383
|
+
*/
|
384
|
+
if ( ( c == '\'' || c == '"' ) && linkytitle(f,c,p) )
|
385
|
+
good=1;
|
386
|
+
else if ( image && (c == '=') && linkysize(f,p) )
|
387
|
+
good=1;
|
388
|
+
else
|
389
|
+
good=( c == ')' );
|
390
|
+
|
391
|
+
if ( good ) {
|
392
|
+
if ( peek(f, 1) == ')' )
|
393
|
+
pull(f);
|
394
|
+
|
395
|
+
___mkd_tidy(&p->link);
|
396
|
+
}
|
397
|
+
|
398
|
+
return good;
|
399
|
+
} /* linkybroket */
|
400
|
+
|
401
|
+
|
354
402
|
/* extract a (-prefixed url from the input stream.
|
355
403
|
* the label is either of the format `<link>`, where I
|
356
404
|
* extract until I find a >, or it is of the format
|
@@ -368,6 +416,8 @@ linkyurl(MMIOT *f, int image, Footnote *p)
|
|
368
416
|
|
369
417
|
if ( c == '<' ) {
|
370
418
|
pull(f);
|
419
|
+
if ( !(f->flags & MKD_1_COMPAT) )
|
420
|
+
return linkybroket(f,image,p);
|
371
421
|
mayneedtotrim=1;
|
372
422
|
}
|
373
423
|
|
@@ -405,10 +455,10 @@ static struct _protocol {
|
|
405
455
|
int nlen;
|
406
456
|
} protocol[] = {
|
407
457
|
#define _aprotocol(x) { x, (sizeof x)-1 }
|
408
|
-
_aprotocol( "https
|
409
|
-
_aprotocol( "http
|
410
|
-
_aprotocol( "news
|
411
|
-
_aprotocol( "ftp
|
458
|
+
_aprotocol( "https:" ),
|
459
|
+
_aprotocol( "http:" ),
|
460
|
+
_aprotocol( "news:" ),
|
461
|
+
_aprotocol( "ftp:" ),
|
412
462
|
#undef _aprotocol
|
413
463
|
};
|
414
464
|
#define NRPROTOCOLS (sizeof protocol / sizeof protocol[0])
|
@@ -445,9 +495,9 @@ typedef struct linkytype {
|
|
445
495
|
} linkytype;
|
446
496
|
|
447
497
|
static linkytype imaget = { 0, 0, "<img src=\"", "\"",
|
448
|
-
1, " alt=\"", "\" />",
|
498
|
+
1, " alt=\"", "\" />", MKD_NOIMAGE|MKD_TAGTEXT, IS_URL };
|
449
499
|
static linkytype linkt = { 0, 0, "<a href=\"", "\"",
|
450
|
-
0, ">", "</a>",
|
500
|
+
0, ">", "</a>", MKD_NOLINKS, IS_URL };
|
451
501
|
|
452
502
|
/*
|
453
503
|
* pseudo-protocols for [][];
|
@@ -457,8 +507,8 @@ static linkytype linkt = { 0, 0, "<a href=\"", "\"",
|
|
457
507
|
* raw: just dump the link without any processing
|
458
508
|
*/
|
459
509
|
static linkytype specials[] = {
|
460
|
-
{ "id:", 3, "<
|
461
|
-
{ "raw:", 4, 0, 0, 0, 0, 0,
|
510
|
+
{ "id:", 3, "<span id=\"", "\"", 0, ">", "</span>", 0, 0 },
|
511
|
+
{ "raw:", 4, 0, 0, 0, 0, 0, MKD_NOHTML, 0 },
|
462
512
|
{ "lang:", 5, "<span lang=\"", "\"", 0, ">", "</span>", 0, 0 },
|
463
513
|
{ "abbr:", 5, "<abbr title=\"", "\"", 0, ">", "</abbr>", 0, 0 },
|
464
514
|
{ "class:", 6, "<span class=\"", "\"", 0, ">", "</span>", 0, 0 },
|
@@ -489,10 +539,13 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
|
|
489
539
|
{
|
490
540
|
char *edit;
|
491
541
|
|
542
|
+
if ( f->flags & IS_LABEL )
|
543
|
+
return;
|
544
|
+
|
492
545
|
Qstring(tag->link_pfx, f);
|
493
546
|
|
494
547
|
if ( tag->kind & IS_URL ) {
|
495
|
-
if ( f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
|
548
|
+
if ( f->cb && f->cb->e_url && (edit = (*f->cb->e_url)(link, size, f->cb->e_data)) ) {
|
496
549
|
puturl(edit, strlen(edit), f, 0);
|
497
550
|
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
498
551
|
}
|
@@ -500,11 +553,11 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
|
|
500
553
|
puturl(link + tag->szpat, size - tag->szpat, f, 0);
|
501
554
|
}
|
502
555
|
else
|
503
|
-
___mkd_reparse(link + tag->szpat, size - tag->szpat,
|
556
|
+
___mkd_reparse(link + tag->szpat, size - tag->szpat, MKD_TAGTEXT, f);
|
504
557
|
|
505
558
|
Qstring(tag->link_sfx, f);
|
506
559
|
|
507
|
-
if ( f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
|
560
|
+
if ( f->cb && f->cb->e_flags && (edit = (*f->cb->e_flags)(link, size, f->cb->e_data)) ) {
|
508
561
|
Qchar(' ', f);
|
509
562
|
Qstring(edit, f);
|
510
563
|
if ( f->cb->e_free ) (*f->cb->e_free)(edit, f->cb->e_data);
|
@@ -512,6 +565,38 @@ printlinkyref(MMIOT *f, linkytype *tag, char *link, int size)
|
|
512
565
|
} /* printlinkyref */
|
513
566
|
|
514
567
|
|
568
|
+
/* helper function for php markdown extra footnotes; allow the user to
|
569
|
+
* define a prefix tag instead of just `fn`
|
570
|
+
*/
|
571
|
+
static char *
|
572
|
+
p_or_nothing(p)
|
573
|
+
MMIOT *p;
|
574
|
+
{
|
575
|
+
return p->ref_prefix ? p->ref_prefix : "fn";
|
576
|
+
}
|
577
|
+
|
578
|
+
|
579
|
+
/* php markdown extra/daring fireball style print footnotes
|
580
|
+
*/
|
581
|
+
static int
|
582
|
+
extra_linky(MMIOT *f, Cstring text, Footnote *ref)
|
583
|
+
{
|
584
|
+
if ( ref->flags & REFERENCED )
|
585
|
+
return 0;
|
586
|
+
|
587
|
+
if ( f->flags & IS_LABEL )
|
588
|
+
___mkd_reparse(T(text), S(text), linkt.flags, f);
|
589
|
+
else {
|
590
|
+
ref->flags |= REFERENCED;
|
591
|
+
ref->refnumber = ++ f->reference;
|
592
|
+
Qprintf(f, "<sup id=\"%sref:%d\"><a href=\"#%s:%d\" rel=\"footnote\">%d</a></sup>",
|
593
|
+
p_or_nothing(f), ref->refnumber,
|
594
|
+
p_or_nothing(f), ref->refnumber, ref->refnumber);
|
595
|
+
}
|
596
|
+
return 1;
|
597
|
+
} /* extra_linky */
|
598
|
+
|
599
|
+
|
515
600
|
/* print out a linky (or fail if it's Not Allowed)
|
516
601
|
*/
|
517
602
|
static int
|
@@ -519,16 +604,16 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
519
604
|
{
|
520
605
|
linkytype *tag;
|
521
606
|
|
522
|
-
if ( image )
|
607
|
+
if ( image || (ref == 0) )
|
523
608
|
tag = &imaget;
|
524
609
|
else if ( tag = pseudo(ref->link) ) {
|
525
|
-
if ( f->flags & (
|
610
|
+
if ( f->flags & (MKD_NO_EXT|MKD_SAFELINK) )
|
526
611
|
return 0;
|
527
612
|
}
|
528
|
-
else if ( (f->flags &
|
529
|
-
|
530
|
-
|
531
|
-
/* if
|
613
|
+
else if ( (f->flags & MKD_SAFELINK) && T(ref->link)
|
614
|
+
&& (T(ref->link)[0] != '/')
|
615
|
+
&& !isautoprefix(T(ref->link), S(ref->link)) )
|
616
|
+
/* if MKD_SAFELINK, only accept links that are local or
|
532
617
|
* a well-known protocol
|
533
618
|
*/
|
534
619
|
return 0;
|
@@ -538,7 +623,9 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
538
623
|
if ( f->flags & tag->flags )
|
539
624
|
return 0;
|
540
625
|
|
541
|
-
if (
|
626
|
+
if ( f->flags & IS_LABEL )
|
627
|
+
___mkd_reparse(T(text), S(text), tag->flags, f);
|
628
|
+
else if ( tag->link_pfx ) {
|
542
629
|
printlinkyref(f, tag, T(ref->link), S(ref->link));
|
543
630
|
|
544
631
|
if ( tag->WxH ) {
|
@@ -548,7 +635,7 @@ linkyformat(MMIOT *f, Cstring text, int image, Footnote *ref)
|
|
548
635
|
|
549
636
|
if ( S(ref->title) ) {
|
550
637
|
Qstring(" title=\"", f);
|
551
|
-
___mkd_reparse(T(ref->title), S(ref->title),
|
638
|
+
___mkd_reparse(T(ref->title), S(ref->title), MKD_TAGTEXT, f);
|
552
639
|
Qchar('"', f);
|
553
640
|
}
|
554
641
|
|
@@ -574,6 +661,7 @@ linkylinky(int image, MMIOT *f)
|
|
574
661
|
Footnote key, *ref;
|
575
662
|
|
576
663
|
int status = 0;
|
664
|
+
int extra_footnote = 0;
|
577
665
|
|
578
666
|
CREATE(name);
|
579
667
|
memset(&key, 0, sizeof key);
|
@@ -587,7 +675,10 @@ linkylinky(int image, MMIOT *f)
|
|
587
675
|
else {
|
588
676
|
int goodlink, implicit_mark = mmiottell(f);
|
589
677
|
|
590
|
-
if (
|
678
|
+
if ( isspace(peek(f,1)) )
|
679
|
+
pull(f);
|
680
|
+
|
681
|
+
if ( peek(f,1) == '[' ) {
|
591
682
|
pull(f); /* consume leading '[' */
|
592
683
|
goodlink = linkylabel(f, &key.tag);
|
593
684
|
}
|
@@ -597,6 +688,9 @@ linkylinky(int image, MMIOT *f)
|
|
597
688
|
*/
|
598
689
|
mmiotseek(f, implicit_mark);
|
599
690
|
goodlink = !(f->flags & MKD_1_COMPAT);
|
691
|
+
|
692
|
+
if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (!image) && S(name) && T(name)[0] == '^' )
|
693
|
+
extra_footnote = 1;
|
600
694
|
}
|
601
695
|
|
602
696
|
if ( goodlink ) {
|
@@ -607,8 +701,14 @@ linkylinky(int image, MMIOT *f)
|
|
607
701
|
}
|
608
702
|
|
609
703
|
if ( ref = bsearch(&key, T(*f->footnotes), S(*f->footnotes),
|
610
|
-
sizeof key, (stfu)__mkd_footsort) )
|
611
|
-
|
704
|
+
sizeof key, (stfu)__mkd_footsort) ) {
|
705
|
+
if ( extra_footnote )
|
706
|
+
status = extra_linky(f,name,ref);
|
707
|
+
else
|
708
|
+
status = linkyformat(f, name, image, ref);
|
709
|
+
}
|
710
|
+
else if ( f->flags & IS_LABEL )
|
711
|
+
status = linkyformat(f, name, image, 0);
|
612
712
|
}
|
613
713
|
}
|
614
714
|
}
|
@@ -744,19 +844,19 @@ codespan(MMIOT *f, int size)
|
|
744
844
|
|
745
845
|
|
746
846
|
/* before letting a tag through, validate against
|
747
|
-
*
|
847
|
+
* MKD_NOLINKS and MKD_NOIMAGE
|
748
848
|
*/
|
749
849
|
static int
|
750
850
|
forbidden_tag(MMIOT *f)
|
751
851
|
{
|
752
852
|
int c = toupper(peek(f, 1));
|
753
853
|
|
754
|
-
if ( f->flags &
|
854
|
+
if ( f->flags & MKD_NOHTML )
|
755
855
|
return 1;
|
756
856
|
|
757
|
-
if ( c == 'A' && (f->flags &
|
857
|
+
if ( c == 'A' && (f->flags & MKD_NOLINKS) && !isthisalnum(f,2) )
|
758
858
|
return 1;
|
759
|
-
if ( c == 'I' && (f->flags &
|
859
|
+
if ( c == 'I' && (f->flags & MKD_NOIMAGE)
|
760
860
|
&& strncasecmp(cursor(f)+1, "MG", 2) == 0
|
761
861
|
&& !isthisalnum(f,4) )
|
762
862
|
return 1;
|
@@ -803,7 +903,7 @@ process_possible_link(MMIOT *f, int size)
|
|
803
903
|
int mailto = 0;
|
804
904
|
char *text = cursor(f);
|
805
905
|
|
806
|
-
if ( f->flags &
|
906
|
+
if ( f->flags & MKD_NOLINKS ) return 0;
|
807
907
|
|
808
908
|
if ( (size > 7) && strncasecmp(text, "mailto:", 7) == 0 ) {
|
809
909
|
/* if it says it's a mailto, it's a mailto -- who am
|
@@ -850,7 +950,7 @@ maybe_tag_or_link(MMIOT *f)
|
|
850
950
|
int c, size;
|
851
951
|
int maybetag = 1;
|
852
952
|
|
853
|
-
if ( f->flags &
|
953
|
+
if ( f->flags & MKD_TAGTEXT )
|
854
954
|
return 0;
|
855
955
|
|
856
956
|
for ( size=0; (c = peek(f, size+1)) != '>'; size++) {
|
@@ -1013,7 +1113,7 @@ smartypants(int c, int *flags, MMIOT *f)
|
|
1013
1113
|
{
|
1014
1114
|
int i;
|
1015
1115
|
|
1016
|
-
if ( f->flags & (
|
1116
|
+
if ( f->flags & (MKD_NOPANTS|MKD_TAGTEXT|IS_LABEL) )
|
1017
1117
|
return 0;
|
1018
1118
|
|
1019
1119
|
for ( i=0; i < NRSMART; i++)
|
@@ -1081,7 +1181,7 @@ tickhandler(MMIOT *f, int tickchar, int minticks, spanhandler spanner)
|
|
1081
1181
|
return 0;
|
1082
1182
|
}
|
1083
1183
|
|
1084
|
-
#define tag_text(f) (f->flags &
|
1184
|
+
#define tag_text(f) (f->flags & MKD_TAGTEXT)
|
1085
1185
|
|
1086
1186
|
|
1087
1187
|
static void
|
@@ -1092,7 +1192,7 @@ text(MMIOT *f)
|
|
1092
1192
|
int smartyflags = 0;
|
1093
1193
|
|
1094
1194
|
while (1) {
|
1095
|
-
if ( (f->flags &
|
1195
|
+
if ( (f->flags & MKD_AUTOLINK) && isalpha(peek(f,1)) && !tag_text(f) )
|
1096
1196
|
maybe_autolink(f);
|
1097
1197
|
|
1098
1198
|
c = pull(f);
|
@@ -1131,32 +1231,48 @@ text(MMIOT *f)
|
|
1131
1231
|
case '[': if ( tag_text(f) || !linkylinky(0, f) )
|
1132
1232
|
Qchar(c, f);
|
1133
1233
|
break;
|
1134
|
-
#if SUPERSCRIPT
|
1135
1234
|
/* A^B -> A<sup>B</sup> */
|
1136
|
-
case '^': if ( (f->flags & (
|
1235
|
+
case '^': if ( (f->flags & (MKD_NOSUPERSCRIPT|MKD_STRICT|MKD_TAGTEXT))
|
1236
|
+
|| (isthisnonword(f,-1) && peek(f,-1) != ')')
|
1237
|
+
|| isthisspace(f,1) )
|
1137
1238
|
Qchar(c,f);
|
1138
1239
|
else {
|
1139
1240
|
char *sup = cursor(f);
|
1140
1241
|
int len = 0;
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1242
|
+
|
1243
|
+
if ( peek(f,1) == '(' ) {
|
1244
|
+
int here = mmiottell(f);
|
1245
|
+
pull(f);
|
1246
|
+
|
1247
|
+
if ( (len = parenthetical('(',')',f)) <= 0 ) {
|
1248
|
+
mmiotseek(f,here);
|
1249
|
+
Qchar(c, f);
|
1250
|
+
break;
|
1251
|
+
}
|
1252
|
+
sup++;
|
1144
1253
|
}
|
1145
|
-
|
1254
|
+
else {
|
1255
|
+
while ( isthisalnum(f,1+len) )
|
1256
|
+
++len;
|
1257
|
+
if ( !len ) {
|
1258
|
+
Qchar(c,f);
|
1259
|
+
break;
|
1260
|
+
}
|
1261
|
+
shift(f,len);
|
1262
|
+
}
|
1263
|
+
Qstring("<sup>",f);
|
1146
1264
|
___mkd_reparse(sup, len, 0, f);
|
1147
1265
|
Qstring("</sup>", f);
|
1148
1266
|
}
|
1149
1267
|
break;
|
1150
|
-
#endif
|
1151
1268
|
case '_':
|
1152
|
-
#if RELAXED_EMPHASIS
|
1153
1269
|
/* Underscores don't count if they're in the middle of a word */
|
1154
|
-
if ( !(f->flags &
|
1155
|
-
|
1270
|
+
if ( !(f->flags & (MKD_NORELAXED|MKD_STRICT))
|
1271
|
+
&& isthisalnum(f,-1)
|
1272
|
+
&& isthisalnum(f,1) ) {
|
1156
1273
|
Qchar(c, f);
|
1157
1274
|
break;
|
1158
1275
|
}
|
1159
|
-
#endif
|
1160
1276
|
case '*':
|
1161
1277
|
/* Underscores & stars don't count if they're out in the middle
|
1162
1278
|
* of whitespace */
|
@@ -1174,7 +1290,7 @@ text(MMIOT *f)
|
|
1174
1290
|
}
|
1175
1291
|
break;
|
1176
1292
|
|
1177
|
-
case '~': if ( (f->flags & (
|
1293
|
+
case '~': if ( (f->flags & (MKD_NOSTRIKETHROUGH|MKD_TAGTEXT|MKD_STRICT)) || !tickhandler(f,c,2,delspan) )
|
1178
1294
|
Qchar(c, f);
|
1179
1295
|
break;
|
1180
1296
|
|
@@ -1187,6 +1303,14 @@ text(MMIOT *f)
|
|
1187
1303
|
break;
|
1188
1304
|
case '<': Qstring("<", f);
|
1189
1305
|
break;
|
1306
|
+
case '^': if ( f->flags & (MKD_STRICT|MKD_NOSUPERSCRIPT) ) {
|
1307
|
+
Qchar('\\', f);
|
1308
|
+
shift(f,-1);
|
1309
|
+
break;
|
1310
|
+
}
|
1311
|
+
Qchar(c, f);
|
1312
|
+
break;
|
1313
|
+
|
1190
1314
|
case '>': case '#': case '.': case '-':
|
1191
1315
|
case '+': case '{': case '}': case ']':
|
1192
1316
|
case '!': case '[': case '*': case '_':
|
@@ -1229,13 +1353,14 @@ text(MMIOT *f)
|
|
1229
1353
|
static void
|
1230
1354
|
printheader(Paragraph *pp, MMIOT *f)
|
1231
1355
|
{
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1356
|
+
if ( f->flags & MKD_TOC ) {
|
1357
|
+
Qstring("<a name=\"", f);
|
1358
|
+
mkd_string_to_anchor(T(pp->text->text),
|
1359
|
+
S(pp->text->text),
|
1360
|
+
(mkd_sta_function_t)Qchar, f, 1);
|
1361
|
+
Qstring("\"></a>\n", f);
|
1237
1362
|
}
|
1238
|
-
|
1363
|
+
Qprintf(f, "<h%d>", pp->hnumber);
|
1239
1364
|
push(T(pp->text->text), S(pp->text->text), f);
|
1240
1365
|
text(f);
|
1241
1366
|
Qprintf(f, "</h%d>", pp->hnumber);
|
@@ -1432,7 +1557,6 @@ htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
|
|
1432
1557
|
}
|
1433
1558
|
|
1434
1559
|
|
1435
|
-
#if DL_TAG_EXTENSION
|
1436
1560
|
static void
|
1437
1561
|
definitionlist(Paragraph *p, MMIOT *f)
|
1438
1562
|
{
|
@@ -1455,7 +1579,6 @@ definitionlist(Paragraph *p, MMIOT *f)
|
|
1455
1579
|
Qstring("</dl>", f);
|
1456
1580
|
}
|
1457
1581
|
}
|
1458
|
-
#endif
|
1459
1582
|
|
1460
1583
|
|
1461
1584
|
static void
|
@@ -1464,7 +1587,7 @@ listdisplay(int typ, Paragraph *p, MMIOT* f)
|
|
1464
1587
|
if ( p ) {
|
1465
1588
|
Qprintf(f, "<%cl", (typ==UL)?'u':'o');
|
1466
1589
|
if ( typ == AL )
|
1467
|
-
Qprintf(f, " type
|
1590
|
+
Qprintf(f, " type=\"a\"");
|
1468
1591
|
Qprintf(f, ">\n");
|
1469
1592
|
|
1470
1593
|
for ( ; p ; p = p->next ) {
|
@@ -1507,11 +1630,9 @@ display(Paragraph *p, MMIOT *f)
|
|
1507
1630
|
listdisplay(p->typ, p->down, f);
|
1508
1631
|
break;
|
1509
1632
|
|
1510
|
-
#if DL_TAG_EXTENSION
|
1511
1633
|
case DL:
|
1512
1634
|
definitionlist(p->down, f);
|
1513
1635
|
break;
|
1514
|
-
#endif
|
1515
1636
|
|
1516
1637
|
case HR:
|
1517
1638
|
Qstring("<hr />", f);
|
@@ -1537,20 +1658,59 @@ display(Paragraph *p, MMIOT *f)
|
|
1537
1658
|
}
|
1538
1659
|
|
1539
1660
|
|
1661
|
+
/* dump out a list of footnotes
|
1662
|
+
*/
|
1663
|
+
static void
|
1664
|
+
mkd_extra_footnotes(MMIOT *m)
|
1665
|
+
{
|
1666
|
+
int j, i;
|
1667
|
+
Footnote *t;
|
1668
|
+
|
1669
|
+
if ( m->reference == 0 )
|
1670
|
+
return;
|
1671
|
+
|
1672
|
+
Csprintf(&m->out, "\n<div class=\"footnotes\">\n<hr/>\n<ol>\n");
|
1673
|
+
|
1674
|
+
for ( i=1; i <= m->reference; i++ ) {
|
1675
|
+
for ( j=0; j < S(*m->footnotes); j++ ) {
|
1676
|
+
t = &T(*m->footnotes)[j];
|
1677
|
+
if ( (t->refnumber == i) && (t->flags & REFERENCED) ) {
|
1678
|
+
Csprintf(&m->out, "<li id=\"%s:%d\">\n<p>",
|
1679
|
+
p_or_nothing(m), t->refnumber);
|
1680
|
+
Csreparse(&m->out, T(t->title), S(t->title), 0);
|
1681
|
+
Csprintf(&m->out, "<a href=\"#%sref:%d\" rev=\"footnote\">↩</a>",
|
1682
|
+
p_or_nothing(m), t->refnumber);
|
1683
|
+
Csprintf(&m->out, "</p></li>\n");
|
1684
|
+
}
|
1685
|
+
}
|
1686
|
+
}
|
1687
|
+
Csprintf(&m->out, "</ol>\n</div>\n");
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
|
1540
1691
|
/* return a pointer to the compiled markdown
|
1541
1692
|
* document.
|
1542
1693
|
*/
|
1543
1694
|
int
|
1544
1695
|
mkd_document(Document *p, char **res)
|
1545
1696
|
{
|
1697
|
+
int size;
|
1698
|
+
|
1546
1699
|
if ( p && p->compiled ) {
|
1547
1700
|
if ( ! p->html ) {
|
1548
1701
|
htmlify(p->code, 0, 0, p->ctx);
|
1702
|
+
if ( p->ctx->flags & MKD_EXTRA_FOOTNOTE )
|
1703
|
+
mkd_extra_footnotes(p->ctx);
|
1549
1704
|
p->html = 1;
|
1550
1705
|
}
|
1551
1706
|
|
1707
|
+
size = S(p->ctx->out);
|
1708
|
+
|
1709
|
+
if ( (size == 0) || T(p->ctx->out)[size-1] )
|
1710
|
+
EXPAND(p->ctx->out) = 0;
|
1711
|
+
|
1552
1712
|
*res = T(p->ctx->out);
|
1553
|
-
return
|
1713
|
+
return size;
|
1554
1714
|
}
|
1555
1715
|
return EOF;
|
1556
1716
|
}
|