rdiscount 1.6.8 → 2.0.7
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 +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
|
}
|