pixeltrix-rdiscount 1.2.11 → 1.3.4
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/Rakefile +70 -38
- data/ext/Csio.c +49 -0
- data/ext/cstring.h +5 -0
- data/ext/extconf.rb +0 -6
- data/ext/generate.c +115 -59
- data/ext/markdown.c +127 -34
- data/ext/markdown.h +11 -2
- data/ext/mkdio.c +16 -0
- data/ext/mkdio.h +7 -0
- data/ext/rdiscount.c +62 -14
- data/ext/resource.c +2 -0
- data/ext/toc.c +86 -0
- data/lib/rdiscount.rb +4 -0
- data/rdiscount.gemspec +39 -35
- data/test/markdown_test.rb +20 -5
- data/test/rdiscount_test.rb +29 -1
- metadata +12 -14
- data/ext/rbstrio.c +0 -48
- data/ext/rbstrio.h +0 -4
data/Rakefile
CHANGED
|
@@ -1,43 +1,75 @@
|
|
|
1
1
|
require 'rake/clean'
|
|
2
|
-
require 'rake/packagetask'
|
|
3
|
-
require 'rake/gempackagetask'
|
|
4
2
|
|
|
5
|
-
task :default =>
|
|
3
|
+
task :default => :test
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
VERS = '1.2.11'
|
|
9
|
-
|
|
10
|
-
spec =
|
|
11
|
-
Gem::Specification.new do |s|
|
|
12
|
-
s.name = "rdiscount"
|
|
13
|
-
s.version = VERS
|
|
14
|
-
s.summary = "Fast Implementation of Gruber's Markdown in C"
|
|
15
|
-
s.files = FileList['README.markdown','COPYING','Rakefile','test/**','{lib,ext}/**.rb','ext/*.{c,h}']
|
|
16
|
-
s.bindir = 'bin'
|
|
17
|
-
s.require_path = 'lib'
|
|
18
|
-
s.has_rdoc = true
|
|
19
|
-
s.extra_rdoc_files = ['COPYING']
|
|
20
|
-
s.test_files = FileList['test/*_test.rb']
|
|
21
|
-
s.extensions = ['ext/extconf.rb']
|
|
22
|
-
|
|
23
|
-
s.author = 'Ryan Tomayko'
|
|
24
|
-
s.email = 'r@tomayko.com'
|
|
25
|
-
s.homepage = 'http://github.com/rtomayko/rdiscount'
|
|
26
|
-
s.rubyforge_project = 'wink'
|
|
27
|
-
end
|
|
5
|
+
# PACKAGING =================================================================
|
|
28
6
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
7
|
+
# Load the gemspec using the same limitations as github
|
|
8
|
+
$spec =
|
|
9
|
+
begin
|
|
10
|
+
require 'rubygems/specification'
|
|
11
|
+
data = File.read('rdiscount.gemspec')
|
|
12
|
+
spec = nil
|
|
13
|
+
Thread.new { spec = eval("$SAFE = 3\n#{data}") }.join
|
|
14
|
+
spec
|
|
34
15
|
end
|
|
35
16
|
|
|
17
|
+
def package(ext='')
|
|
18
|
+
"pkg/rdiscount-#{$spec.version}" + ext
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc 'Build packages'
|
|
22
|
+
task :package => %w[.gem .tar.gz].map {|e| package(e)}
|
|
23
|
+
|
|
24
|
+
desc 'Build and install as local gem'
|
|
25
|
+
task :install => package('.gem') do
|
|
26
|
+
sh "gem install #{package('.gem')}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
directory 'pkg/'
|
|
30
|
+
|
|
31
|
+
file package('.gem') => %w[pkg/ rdiscount.gemspec] + $spec.files do |f|
|
|
32
|
+
sh "gem build rdiscount.gemspec"
|
|
33
|
+
mv File.basename(f.name), f.name
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
file package('.tar.gz') => %w[pkg/] + $spec.files do |f|
|
|
37
|
+
sh "git archive --format=tar HEAD | gzip > #{f.name}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# GEMSPEC HELPERS ==========================================================
|
|
41
|
+
|
|
42
|
+
def source_version
|
|
43
|
+
line = File.read('lib/rdiscount.rb')[/^\s*VERSION = .*/]
|
|
44
|
+
line.match(/.*VERSION = '(.*)'/)[1]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
file 'rdiscount.gemspec' => FileList['Rakefile','lib/rdiscount.rb'] do |f|
|
|
48
|
+
# read spec file and split out manifest section
|
|
49
|
+
spec = File.read(f.name)
|
|
50
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
|
51
|
+
head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
|
|
52
|
+
head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
|
|
53
|
+
# determine file list from git ls-files
|
|
54
|
+
files = `git ls-files`.
|
|
55
|
+
split("\n").
|
|
56
|
+
sort.
|
|
57
|
+
reject{ |file| file =~ /^\./ || file =~ /^test\/MarkdownTest/ }.
|
|
58
|
+
map{ |file| " #{file}" }.
|
|
59
|
+
join("\n")
|
|
60
|
+
# piece file back together and write...
|
|
61
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
|
62
|
+
spec = [head,manifest,tail].join(" # = MANIFEST =\n")
|
|
63
|
+
File.open(f.name, 'w') { |io| io.write(spec) }
|
|
64
|
+
puts "updated #{f.name}"
|
|
65
|
+
end
|
|
36
66
|
|
|
37
67
|
# ==========================================================
|
|
38
68
|
# Ruby Extension
|
|
39
69
|
# ==========================================================
|
|
40
70
|
|
|
71
|
+
DLEXT = Config::CONFIG['DLEXT']
|
|
72
|
+
|
|
41
73
|
file 'ext/Makefile' => FileList['ext/{*.c,*.h,*.rb}'] do
|
|
42
74
|
chdir('ext') { ruby 'extconf.rb' }
|
|
43
75
|
end
|
|
@@ -55,7 +87,6 @@ end
|
|
|
55
87
|
desc 'Build the rdiscount extension'
|
|
56
88
|
task :build => "lib/rdiscount.#{DLEXT}"
|
|
57
89
|
|
|
58
|
-
|
|
59
90
|
# ==========================================================
|
|
60
91
|
# Testing
|
|
61
92
|
# ==========================================================
|
|
@@ -68,14 +99,17 @@ end
|
|
|
68
99
|
desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
|
|
69
100
|
task 'test:conformance' => [:build] do |t|
|
|
70
101
|
script = "#{pwd}/bin/rdiscount"
|
|
71
|
-
test_version = ENV['MARKDOWN_TEST_VER'] || '1.0'
|
|
102
|
+
test_version = ENV['MARKDOWN_TEST_VER'] || '1.0.3'
|
|
72
103
|
chdir("test/MarkdownTest_#{test_version}") do
|
|
73
104
|
sh "./MarkdownTest.pl --script='#{script}' --tidy"
|
|
74
105
|
end
|
|
75
106
|
end
|
|
76
107
|
|
|
77
108
|
desc 'Run version 1.0 conformance suite'
|
|
78
|
-
task 'test:conformance:1.0' =>
|
|
109
|
+
task 'test:conformance:1.0' => [:build] do |t|
|
|
110
|
+
ENV['MARKDOWN_TEST_VER'] = '1.0'
|
|
111
|
+
Rake::Task['test:conformance'].invoke
|
|
112
|
+
end
|
|
79
113
|
|
|
80
114
|
desc 'Run 1.0.3 conformance suite'
|
|
81
115
|
task 'test:conformance:1.0.3' => [:build] do |t|
|
|
@@ -119,13 +153,11 @@ CLEAN.include 'doc'
|
|
|
119
153
|
# Rubyforge
|
|
120
154
|
# ==========================================================
|
|
121
155
|
|
|
122
|
-
PKGNAME = "pkg/rdiscount-#{VERS}"
|
|
123
|
-
|
|
124
156
|
desc 'Publish new release to rubyforge'
|
|
125
|
-
task :release => [
|
|
157
|
+
task :release => [package('.gem'), package('.tar.gz')] do |t|
|
|
126
158
|
sh <<-end
|
|
127
|
-
rubyforge add_release wink rdiscount #{
|
|
128
|
-
rubyforge add_file wink rdiscount #{
|
|
159
|
+
rubyforge add_release wink rdiscount #{$spec.version} #{package('.gem')} &&
|
|
160
|
+
rubyforge add_file wink rdiscount #{$spec.version} #{package('.tar.gz')}
|
|
129
161
|
end
|
|
130
162
|
end
|
|
131
163
|
|
|
@@ -143,7 +175,7 @@ task :gather => 'discount' do |t|
|
|
|
143
175
|
files =
|
|
144
176
|
FileList[
|
|
145
177
|
'discount/{markdown,mkdio,amalloc,cstring}.h',
|
|
146
|
-
'discount/{markdown,docheader,dumptree,generate,mkdio,resource}.c'
|
|
178
|
+
'discount/{markdown,docheader,dumptree,generate,mkdio,resource,toc,Csio}.c'
|
|
147
179
|
]
|
|
148
180
|
cp files, 'ext/',
|
|
149
181
|
:preserve => true,
|
data/ext/Csio.c
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
#include <stdarg.h>
|
|
4
|
+
#include "cstring.h"
|
|
5
|
+
#include "markdown.h"
|
|
6
|
+
#include "amalloc.h"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/* putc() into a cstring
|
|
10
|
+
*/
|
|
11
|
+
void
|
|
12
|
+
Csputc(int c, Cstring *iot)
|
|
13
|
+
{
|
|
14
|
+
EXPAND(*iot) = c;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/* printf() into a cstring
|
|
19
|
+
*/
|
|
20
|
+
int
|
|
21
|
+
Csprintf(Cstring *iot, char *fmt, ...)
|
|
22
|
+
{
|
|
23
|
+
va_list ptr;
|
|
24
|
+
int siz=100;
|
|
25
|
+
|
|
26
|
+
do {
|
|
27
|
+
RESERVE(*iot, siz);
|
|
28
|
+
va_start(ptr, fmt);
|
|
29
|
+
siz = vsnprintf(T(*iot)+S(*iot), ALL(*iot)-S(*iot), fmt, ptr);
|
|
30
|
+
va_end(ptr);
|
|
31
|
+
} while ( siz > (ALL(*iot)-S(*iot)) );
|
|
32
|
+
|
|
33
|
+
S(*iot) += siz;
|
|
34
|
+
return siz;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
/* reparse() into a cstring
|
|
39
|
+
*/
|
|
40
|
+
void
|
|
41
|
+
Csreparse(Cstring *iot, char *buf, int size, int flags)
|
|
42
|
+
{
|
|
43
|
+
MMIOT f;
|
|
44
|
+
___mkd_initmmiot(&f, 0);
|
|
45
|
+
___mkd_reparse(buf, size, 0, &f);
|
|
46
|
+
___mkd_emblock(&f);
|
|
47
|
+
SUFFIX(*iot, T(f.out), S(f.out));
|
|
48
|
+
___mkd_freemmiot(&f, 0);
|
|
49
|
+
}
|
data/ext/cstring.h
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
*/
|
|
51
51
|
#define T(x) (x).text
|
|
52
52
|
#define S(x) (x).size
|
|
53
|
+
#define ALL(x) (x).alloc
|
|
53
54
|
|
|
54
55
|
/* abstract anchor type that defines a list base
|
|
55
56
|
* with a function that attaches an element to
|
|
@@ -65,4 +66,8 @@
|
|
|
65
66
|
|
|
66
67
|
typedef STRING(char) Cstring;
|
|
67
68
|
|
|
69
|
+
extern void Csputc(int, Cstring *);
|
|
70
|
+
extern int Csprintf(Cstring *, char *, ...);
|
|
71
|
+
extern void Csreparse(Cstring *, char *, int, int);
|
|
72
|
+
|
|
68
73
|
#endif/*_CSTRING_D*/
|
data/ext/extconf.rb
CHANGED
|
@@ -4,11 +4,5 @@ dir_config('rdiscount')
|
|
|
4
4
|
|
|
5
5
|
HAVE_RANDOM = have_func('random')
|
|
6
6
|
HAVE_SRANDOM = have_func('srandom')
|
|
7
|
-
HAVE_FUNOPEN = have_func('funopen')
|
|
8
|
-
HAVE_FOPENCOOKIE = have_func('fopencookie')
|
|
9
|
-
|
|
10
|
-
unless HAVE_FUNOPEN || HAVE_FOPENCOOKIE
|
|
11
|
-
fail "No funopen or fopencookie support available."
|
|
12
|
-
end
|
|
13
7
|
|
|
14
8
|
create_makefile('rdiscount')
|
data/ext/generate.c
CHANGED
|
@@ -26,6 +26,7 @@ typedef int (*stfu)(const void*,const void*);
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
/* forward declarations */
|
|
29
|
+
static int iscodeblock(MMIOT*);
|
|
29
30
|
static void code(int, MMIOT*);
|
|
30
31
|
static void text(MMIOT *f);
|
|
31
32
|
static Paragraph *display(Paragraph*, MMIOT*);
|
|
@@ -74,6 +75,31 @@ cursor(MMIOT *f)
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
|
|
78
|
+
static int
|
|
79
|
+
isthisspace(MMIOT *f, int i)
|
|
80
|
+
{
|
|
81
|
+
int c = peek(f, i);
|
|
82
|
+
|
|
83
|
+
return isspace(c) || (c == EOF);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
static int
|
|
88
|
+
isthisalnum(MMIOT *f, int i)
|
|
89
|
+
{
|
|
90
|
+
int c = peek(f, i);
|
|
91
|
+
|
|
92
|
+
return (c != EOF) && isalnum(c);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
static int
|
|
97
|
+
isthisnonword(MMIOT *f, int i)
|
|
98
|
+
{
|
|
99
|
+
return isthisspace(f, i) || ispunct(peek(f,i));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
77
103
|
/* return/set the current cursor position
|
|
78
104
|
*/
|
|
79
105
|
#define mmiotseek(f,x) (f->isp = x)
|
|
@@ -251,10 +277,10 @@ emmatch(MMIOT *f, int go)
|
|
|
251
277
|
}
|
|
252
278
|
|
|
253
279
|
|
|
254
|
-
/*
|
|
280
|
+
/* ___mkd_emblock()
|
|
255
281
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
282
|
+
void
|
|
283
|
+
___mkd_emblock(MMIOT *f)
|
|
258
284
|
{
|
|
259
285
|
int i;
|
|
260
286
|
block *p;
|
|
@@ -275,8 +301,8 @@ emblock(MMIOT *f)
|
|
|
275
301
|
|
|
276
302
|
/* generate html from a markup fragment
|
|
277
303
|
*/
|
|
278
|
-
|
|
279
|
-
|
|
304
|
+
void
|
|
305
|
+
___mkd_reparse(char *bfr, int size, int flags, MMIOT *f)
|
|
280
306
|
{
|
|
281
307
|
MMIOT sub;
|
|
282
308
|
|
|
@@ -290,7 +316,7 @@ reparse(char *bfr, int size, int flags, MMIOT *f)
|
|
|
290
316
|
S(sub.in)--;
|
|
291
317
|
|
|
292
318
|
text(&sub);
|
|
293
|
-
|
|
319
|
+
___mkd_emblock(&sub);
|
|
294
320
|
|
|
295
321
|
Qwrite(T(sub.out), S(sub.out), f);
|
|
296
322
|
|
|
@@ -313,6 +339,8 @@ puturl(char *s, int size, MMIOT *f)
|
|
|
313
339
|
Qstring("&", f);
|
|
314
340
|
else if ( c == '<' )
|
|
315
341
|
Qstring("<", f);
|
|
342
|
+
else if ( isalnum(c) || ispunct(c) )
|
|
343
|
+
Qchar(c, f);
|
|
316
344
|
else
|
|
317
345
|
Qchar(c, f);
|
|
318
346
|
}
|
|
@@ -469,12 +497,14 @@ linkykey(int image, Footnote *val, MMIOT *f)
|
|
|
469
497
|
{
|
|
470
498
|
Footnote *ret;
|
|
471
499
|
Cstring mylabel;
|
|
500
|
+
int here;
|
|
472
501
|
|
|
473
502
|
memset(val, 0, sizeof *val);
|
|
474
503
|
|
|
475
504
|
if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 )
|
|
476
505
|
return 0;
|
|
477
506
|
|
|
507
|
+
here = mmiottell(f);
|
|
478
508
|
eatspace(f);
|
|
479
509
|
switch ( pull(f) ) {
|
|
480
510
|
case '(':
|
|
@@ -489,14 +519,21 @@ linkykey(int image, Footnote *val, MMIOT *f)
|
|
|
489
519
|
|
|
490
520
|
return peek(f,0) == ')';
|
|
491
521
|
|
|
492
|
-
case '[':
|
|
522
|
+
case '[': /* footnote links /as defined in the standard/ */
|
|
523
|
+
default: /* footnote links -- undocumented extension */
|
|
493
524
|
/* footnote link */
|
|
494
525
|
mylabel = val->tag;
|
|
495
|
-
if ( (
|
|
496
|
-
|
|
526
|
+
if ( peek(f,0) == '[' ) {
|
|
527
|
+
if ( (T(val->tag) = linkylabel(f, &S(val->tag))) == 0 )
|
|
528
|
+
return 0;
|
|
497
529
|
|
|
498
|
-
|
|
499
|
-
|
|
530
|
+
if ( !S(val->tag) )
|
|
531
|
+
val->tag = mylabel;
|
|
532
|
+
}
|
|
533
|
+
else if ( f->flags & MKD_1_COMPAT )
|
|
534
|
+
break;
|
|
535
|
+
else
|
|
536
|
+
mmiotseek(f,here);
|
|
500
537
|
|
|
501
538
|
ret = bsearch(val, T(*f->footnotes), S(*f->footnotes),
|
|
502
539
|
sizeof *val, (stfu)__mkd_footsort);
|
|
@@ -576,7 +613,7 @@ linkylinky(int image, MMIOT *f)
|
|
|
576
613
|
Footnote link;
|
|
577
614
|
linkytype *tag;
|
|
578
615
|
|
|
579
|
-
if ( !
|
|
616
|
+
if ( !linkykey(image, &link, f) ) {
|
|
580
617
|
mmiotseek(f, start);
|
|
581
618
|
return 0;
|
|
582
619
|
}
|
|
@@ -605,12 +642,12 @@ linkylinky(int image, MMIOT *f)
|
|
|
605
642
|
|
|
606
643
|
if ( S(link.title) ) {
|
|
607
644
|
Qstring(" title=\"", f);
|
|
608
|
-
|
|
645
|
+
___mkd_reparse(T(link.title), S(link.title), INSIDE_TAG, f);
|
|
609
646
|
Qchar('"', f);
|
|
610
647
|
}
|
|
611
648
|
|
|
612
649
|
Qstring(tag->text_pfx, f);
|
|
613
|
-
|
|
650
|
+
___mkd_reparse(T(link.tag), S(link.tag), tag->flags, f);
|
|
614
651
|
Qstring(tag->text_sfx, f);
|
|
615
652
|
}
|
|
616
653
|
else
|
|
@@ -659,11 +696,11 @@ forbidden_tag(MMIOT *f)
|
|
|
659
696
|
if ( f->flags & DENY_HTML )
|
|
660
697
|
return 1;
|
|
661
698
|
|
|
662
|
-
if ( c == 'A' && (f->flags & DENY_A) && !
|
|
699
|
+
if ( c == 'A' && (f->flags & DENY_A) && !isthisalnum(f,2) )
|
|
663
700
|
return 1;
|
|
664
701
|
if ( c == 'I' && (f->flags & DENY_IMG)
|
|
665
702
|
&& strncasecmp(cursor(f)+1, "MG", 2) == 0
|
|
666
|
-
&& !
|
|
703
|
+
&& !isthisalnum(f,4) )
|
|
667
704
|
return 1;
|
|
668
705
|
return 0;
|
|
669
706
|
}
|
|
@@ -743,22 +780,6 @@ maybe_tag_or_link(MMIOT *f)
|
|
|
743
780
|
} /* maybe_tag_or_link */
|
|
744
781
|
|
|
745
782
|
|
|
746
|
-
static int
|
|
747
|
-
isthisspace(MMIOT *f, int i)
|
|
748
|
-
{
|
|
749
|
-
int c = peek(f, i);
|
|
750
|
-
|
|
751
|
-
return isspace(c) || (c == EOF);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
static int
|
|
756
|
-
isthisnonword(MMIOT *f, int i)
|
|
757
|
-
{
|
|
758
|
-
return isthisspace(f, i) || ispunct(peek(f,i));
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
|
|
762
783
|
/* smartyquote code that's common for single and double quotes
|
|
763
784
|
*/
|
|
764
785
|
static int
|
|
@@ -873,7 +894,7 @@ smartypants(int c, int *flags, MMIOT *f)
|
|
|
873
894
|
break;
|
|
874
895
|
else if ( c == '\'' && peek(f, j+1) == '\'' ) {
|
|
875
896
|
Qstring("“", f);
|
|
876
|
-
|
|
897
|
+
___mkd_reparse(cursor(f)+1, j-2, 0, f);
|
|
877
898
|
Qstring("”", f);
|
|
878
899
|
shift(f,j+1);
|
|
879
900
|
return 1;
|
|
@@ -928,7 +949,8 @@ text(MMIOT *f)
|
|
|
928
949
|
Qchar(c, f);
|
|
929
950
|
break;
|
|
930
951
|
#if SUPERSCRIPT
|
|
931
|
-
|
|
952
|
+
/* A^B -> A<sup>B</sup> */
|
|
953
|
+
case '^': if ( (f->flags & (STRICT|INSIDE_TAG)) || isthisspace(f,-1) || isthisspace(f,1) )
|
|
932
954
|
Qchar(c,f);
|
|
933
955
|
else {
|
|
934
956
|
char *sup = cursor(f);
|
|
@@ -938,18 +960,17 @@ text(MMIOT *f)
|
|
|
938
960
|
++len;
|
|
939
961
|
}
|
|
940
962
|
shift(f,len);
|
|
941
|
-
|
|
963
|
+
___mkd_reparse(sup, len, 0, f);
|
|
942
964
|
Qstring("</sup>", f);
|
|
943
965
|
}
|
|
944
966
|
break;
|
|
945
967
|
#endif
|
|
946
968
|
case '_':
|
|
947
969
|
#if RELAXED_EMPHASIS
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|| (isalnum(peek(f,-1)) && isalnum(peek(f,1))) ) {
|
|
970
|
+
/* Underscores don't count if they're in the middle of a word */
|
|
971
|
+
if ( (!(f->flags & STRICT))
|
|
972
|
+
&& ((isthisspace(f,-1) && isthisspace(f,1))
|
|
973
|
+
|| (isthisalnum(f,-1) && isthisalnum(f,1))) ){
|
|
953
974
|
Qchar(c, f);
|
|
954
975
|
break;
|
|
955
976
|
}
|
|
@@ -964,7 +985,7 @@ text(MMIOT *f)
|
|
|
964
985
|
}
|
|
965
986
|
break;
|
|
966
987
|
|
|
967
|
-
case '`': if ( tag_text(f) )
|
|
988
|
+
case '`': if ( tag_text(f) || !iscodeblock(f) )
|
|
968
989
|
Qchar(c, f);
|
|
969
990
|
else {
|
|
970
991
|
Qstring("<code>", f);
|
|
@@ -1003,7 +1024,7 @@ text(MMIOT *f)
|
|
|
1003
1024
|
break;
|
|
1004
1025
|
|
|
1005
1026
|
case '&': j = (peek(f,1) == '#' ) ? 2 : 1;
|
|
1006
|
-
while (
|
|
1027
|
+
while ( isthisalnum(f,j) )
|
|
1007
1028
|
++j;
|
|
1008
1029
|
|
|
1009
1030
|
if ( peek(f,j) != ';' )
|
|
@@ -1016,9 +1037,31 @@ text(MMIOT *f)
|
|
|
1016
1037
|
break;
|
|
1017
1038
|
}
|
|
1018
1039
|
}
|
|
1040
|
+
/* truncate the input string after we've finished processing it */
|
|
1041
|
+
S(f->in) = f->isp = 0;
|
|
1019
1042
|
} /* text */
|
|
1020
1043
|
|
|
1021
1044
|
|
|
1045
|
+
static int
|
|
1046
|
+
iscodeblock(MMIOT *f)
|
|
1047
|
+
{
|
|
1048
|
+
int i=1, single = 1, c;
|
|
1049
|
+
|
|
1050
|
+
if ( peek(f,i) == '`' ) {
|
|
1051
|
+
single=0;
|
|
1052
|
+
i++;
|
|
1053
|
+
}
|
|
1054
|
+
while ( (c=peek(f,i)) != EOF ) {
|
|
1055
|
+
if ( (c == '`') && (single || peek(f,i+1) == '`') )
|
|
1056
|
+
return 1;
|
|
1057
|
+
else if ( c == '\\' )
|
|
1058
|
+
i++;
|
|
1059
|
+
i++;
|
|
1060
|
+
}
|
|
1061
|
+
return 0;
|
|
1062
|
+
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1022
1065
|
static int
|
|
1023
1066
|
endofcode(int escape, int offset, MMIOT *f)
|
|
1024
1067
|
{
|
|
@@ -1072,7 +1115,13 @@ code(int escape, MMIOT *f)
|
|
|
1072
1115
|
static void
|
|
1073
1116
|
printheader(Paragraph *pp, MMIOT *f)
|
|
1074
1117
|
{
|
|
1075
|
-
Qprintf(f, "<h%d
|
|
1118
|
+
Qprintf(f, "<h%d", pp->hnumber);
|
|
1119
|
+
if ( f->flags & TOC ) {
|
|
1120
|
+
Qprintf(f, " id=\"", pp->hnumber);
|
|
1121
|
+
mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Qchar, f);
|
|
1122
|
+
Qchar('"', f);
|
|
1123
|
+
}
|
|
1124
|
+
Qchar('>', f);
|
|
1076
1125
|
push(T(pp->text->text), S(pp->text->text), f);
|
|
1077
1126
|
text(f);
|
|
1078
1127
|
Qprintf(f, "</h%d>", pp->hnumber);
|
|
@@ -1094,6 +1143,7 @@ printblock(Paragraph *pp, MMIOT *f)
|
|
|
1094
1143
|
push("<br/>\n", 6, f);
|
|
1095
1144
|
}
|
|
1096
1145
|
else {
|
|
1146
|
+
___mkd_tidy(t);
|
|
1097
1147
|
push(T(t->text), S(t->text), f);
|
|
1098
1148
|
if ( t->next )
|
|
1099
1149
|
push("\n", 1, f);
|
|
@@ -1149,19 +1199,21 @@ printhtml(Line *t, MMIOT *f)
|
|
|
1149
1199
|
|
|
1150
1200
|
|
|
1151
1201
|
static void
|
|
1152
|
-
htmlify(Paragraph *p, char *block, MMIOT *f)
|
|
1202
|
+
htmlify(Paragraph *p, char *block, char *arguments, MMIOT *f)
|
|
1153
1203
|
{
|
|
1154
|
-
|
|
1155
|
-
if ( block )
|
|
1156
|
-
|
|
1204
|
+
___mkd_emblock(f);
|
|
1205
|
+
if ( block )
|
|
1206
|
+
Qprintf(f, arguments ? "<%s %s>" : "<%s>", block, arguments);
|
|
1207
|
+
___mkd_emblock(f);
|
|
1157
1208
|
|
|
1158
1209
|
while (( p = display(p, f) )) {
|
|
1159
|
-
|
|
1210
|
+
___mkd_emblock(f);
|
|
1160
1211
|
Qstring("\n\n", f);
|
|
1161
1212
|
}
|
|
1162
1213
|
|
|
1163
|
-
if ( block )
|
|
1164
|
-
|
|
1214
|
+
if ( block )
|
|
1215
|
+
Qprintf(f, "</%s>", block);
|
|
1216
|
+
___mkd_emblock(f);
|
|
1165
1217
|
}
|
|
1166
1218
|
|
|
1167
1219
|
|
|
@@ -1177,11 +1229,11 @@ definitionlist(Paragraph *p, MMIOT *f)
|
|
|
1177
1229
|
for ( ; p ; p = p->next) {
|
|
1178
1230
|
for ( tag = p->text; tag; tag = tag->next ) {
|
|
1179
1231
|
Qstring("<dt>", f);
|
|
1180
|
-
|
|
1232
|
+
___mkd_reparse(T(tag->text), S(tag->text), 0, f);
|
|
1181
1233
|
Qstring("</dt>\n", f);
|
|
1182
1234
|
}
|
|
1183
1235
|
|
|
1184
|
-
htmlify(p->down, "dd", f);
|
|
1236
|
+
htmlify(p->down, "dd", p->ident, f);
|
|
1185
1237
|
}
|
|
1186
1238
|
|
|
1187
1239
|
Qstring("</dl>", f);
|
|
@@ -1194,10 +1246,13 @@ static void
|
|
|
1194
1246
|
listdisplay(int typ, Paragraph *p, MMIOT* f)
|
|
1195
1247
|
{
|
|
1196
1248
|
if ( p ) {
|
|
1197
|
-
Qprintf(f, "<%cl
|
|
1249
|
+
Qprintf(f, "<%cl", (typ==UL)?'u':'o');
|
|
1250
|
+
if ( typ == AL )
|
|
1251
|
+
Qprintf(f, " type=a");
|
|
1252
|
+
Qprintf(f, ">\n");
|
|
1198
1253
|
|
|
1199
1254
|
for ( ; p ; p = p->next ) {
|
|
1200
|
-
htmlify(p->down, "li", f);
|
|
1255
|
+
htmlify(p->down, "li", p->ident, f);
|
|
1201
1256
|
Qchar('\n', f);
|
|
1202
1257
|
}
|
|
1203
1258
|
|
|
@@ -1227,11 +1282,12 @@ display(Paragraph *p, MMIOT *f)
|
|
|
1227
1282
|
break;
|
|
1228
1283
|
|
|
1229
1284
|
case QUOTE:
|
|
1230
|
-
htmlify(p->down, "blockquote", f);
|
|
1285
|
+
htmlify(p->down, p->ident ? "div" : "blockquote", p->ident, f);
|
|
1231
1286
|
break;
|
|
1232
1287
|
|
|
1233
1288
|
case UL:
|
|
1234
1289
|
case OL:
|
|
1290
|
+
case AL:
|
|
1235
1291
|
listdisplay(p->typ, p->down, f);
|
|
1236
1292
|
break;
|
|
1237
1293
|
|
|
@@ -1288,7 +1344,7 @@ mkd_document(Document *p, char **res)
|
|
|
1288
1344
|
{
|
|
1289
1345
|
if ( p && p->compiled ) {
|
|
1290
1346
|
if ( ! p->html ) {
|
|
1291
|
-
htmlify(p->code, 0, p->ctx);
|
|
1347
|
+
htmlify(p->code, 0, 0, p->ctx);
|
|
1292
1348
|
p->html = 1;
|
|
1293
1349
|
}
|
|
1294
1350
|
|
|
@@ -1299,7 +1355,7 @@ mkd_document(Document *p, char **res)
|
|
|
1299
1355
|
}
|
|
1300
1356
|
|
|
1301
1357
|
|
|
1302
|
-
/* public interface for
|
|
1358
|
+
/* public interface for ___mkd_reparse()
|
|
1303
1359
|
*/
|
|
1304
1360
|
int
|
|
1305
1361
|
mkd_text(char *bfr, int size, FILE *output, int flags)
|
|
@@ -1309,8 +1365,8 @@ mkd_text(char *bfr, int size, FILE *output, int flags)
|
|
|
1309
1365
|
___mkd_initmmiot(&f, 0);
|
|
1310
1366
|
f.flags = flags & USER_FLAGS;
|
|
1311
1367
|
|
|
1312
|
-
|
|
1313
|
-
|
|
1368
|
+
___mkd_reparse(bfr, size, 0, &f);
|
|
1369
|
+
___mkd_emblock(&f);
|
|
1314
1370
|
if ( flags & CDATA_OUTPUT )
|
|
1315
1371
|
___mkd_xml(T(f.out), S(f.out), output);
|
|
1316
1372
|
else
|