rtomayko-rdiscount 1.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,52 @@
1
+ The core Discount C sources are
2
+ Copyright (C) 2007 David Loren Parsons.
3
+
4
+ The Discount Ruby extension sources are
5
+ Copyright (C) 2008 Ryan Tomayko.
6
+
7
+ All rights reserved.
8
+
9
+ Permission is hereby granted, free of charge, to any person
10
+ obtaining a copy of this software and associated documentation files
11
+ (the "Software"), to deal in the Software without restriction,
12
+ including without limitation the rights to use, copy, modify, merge,
13
+ publish, distribute, sublicence, and/or sell copies of the Software,
14
+ and to permit persons to whom the Software is furnished to do so,
15
+ subject to the following conditions:
16
+
17
+ 1. Redistributions of source code must retain the above copyright
18
+ notice, this list of conditions, and the following disclaimer.
19
+
20
+ 2. Redistributions in binary form must reproduce the above
21
+ copyright notice, this list of conditions and the following
22
+ disclaimer in the documentation and/or other materials provided
23
+ with the distribution, and in the same place and form as other
24
+ copyright, license and disclaimer information.
25
+
26
+ 3. The end-user documentation included with the redistribution, if
27
+ any, must include the following acknowledgment:
28
+
29
+ This product includes software developed by
30
+ David Loren Parsons <http://www.pell.portland.or.us/~orc>
31
+
32
+ in the same place and form as other third-party acknowledgments.
33
+ Alternately, this acknowledgment may appear in the software
34
+ itself, in the same form and location as other such third-party
35
+ acknowledgments.
36
+
37
+ 4. Except as contained in this notice, the name of David Loren
38
+ Parsons shall not be used in advertising or otherwise to promote
39
+ the sale, use or other dealings in this Software without prior
40
+ written authorization from David Loren Parsons.
41
+
42
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
43
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
44
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
45
+ IN NO EVENT SHALL DAVID LOREN PARSONS BE LIABLE FOR ANY DIRECT,
46
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
47
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52
+ OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.markdown ADDED
@@ -0,0 +1,58 @@
1
+ Discount Markdown Processor for Ruby
2
+ ====================================
3
+
4
+ Discount is an implementation of John Gruber's Markdown markup language in C. It
5
+ implements all of the language described in [the markdown syntax document][1] and
6
+ passes the [Markdown 1.0 test suite][2].
7
+
8
+ Discount was developed by [David Loren Parsons][3]. The Ruby extension was
9
+ developed by [Ryan Tomayko][4].
10
+
11
+ [1]: http://daringfireball.net/projects/markdown/syntax
12
+ [2]: http://daringfireball.net/projects/downloads/MarkdownTest_1.0.zip
13
+ [3]: http://www.pell.portland.or.us/~orc
14
+ [4]: http://tomayko.com/
15
+
16
+ Installation, Hacking
17
+ ---------------------
18
+
19
+ RDiscount Gem releases are published to RubyForge and can be installed as
20
+ follows:
21
+
22
+ $ [sudo] gem install rdiscount
23
+
24
+ The RDiscount sources are available via Git:
25
+
26
+ $ git clone git://github.com/rtomayko/rdiscount.git
27
+ $ cd rdiscount
28
+ $ rake --tasks
29
+
30
+ For more information, see [the project page](http://github.com/rtomayko/rdiscount).
31
+
32
+ Usage
33
+ -----
34
+
35
+ RDiscount implements the basic protocol popularized by RedCloth and adopted
36
+ by BlueCloth:
37
+
38
+ require 'rdiscount'
39
+ markdown = RDiscount.new("Hello World!")
40
+ puts markdown.to_html
41
+
42
+ Inject RDiscount into your BlueCloth-using code by replacing your bluecloth
43
+ require statements with the following:
44
+
45
+ begin
46
+ require 'rdiscount'
47
+ BlueCloth = RDiscount
48
+ rescue LoadError
49
+ require 'bluecloth'
50
+ end
51
+
52
+ COPYING
53
+ -------
54
+
55
+ Discount is free software; it is released under a BSD-style license
56
+ that allows you to do as you wish with it as long as you don't attempt
57
+ to claim it as your own work. RDiscount adopts Discount's license
58
+ verbatim. See the file COPYING for more information.
data/Rakefile ADDED
@@ -0,0 +1,198 @@
1
+ require 'rake/clean'
2
+
3
+ task :default => 'test:unit'
4
+
5
+ # PACKAGING =================================================================
6
+
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
15
+ end
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
66
+
67
+ # ==========================================================
68
+ # Ruby Extension
69
+ # ==========================================================
70
+
71
+ DLEXT = Config::CONFIG['DLEXT']
72
+
73
+ file 'ext/Makefile' => FileList['ext/{*.c,*.h,*.rb}'] do
74
+ chdir('ext') { ruby 'extconf.rb' }
75
+ end
76
+ CLEAN.include 'ext/Makefile', 'ext/mkmf.log'
77
+
78
+ file "ext/rdiscount.#{DLEXT}" => FileList['ext/Makefile', 'ext/*.{c,h,rb}'] do |f|
79
+ sh 'cd ext && make'
80
+ end
81
+ CLEAN.include 'ext/*.{o,bundle,so,dll}'
82
+
83
+ file "lib/rdiscount.#{DLEXT}" => "ext/rdiscount.#{DLEXT}" do |f|
84
+ cp f.prerequisites, "lib/", :preserve => true
85
+ end
86
+
87
+ desc 'Build the rdiscount extension'
88
+ task :build => "lib/rdiscount.#{DLEXT}"
89
+
90
+ # ==========================================================
91
+ # Testing
92
+ # ==========================================================
93
+
94
+ desc 'Run unit tests'
95
+ task 'test:unit' => [:build] do |t|
96
+ sh 'testrb test/markdown_test.rb test/rdiscount_test.rb'
97
+ end
98
+
99
+ desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0)'
100
+ task 'test:conformance' => [:build] do |t|
101
+ script = "#{pwd}/bin/rdiscount"
102
+ test_version = ENV['MARKDOWN_TEST_VER'] || '1.0'
103
+ chdir("test/MarkdownTest_#{test_version}") do
104
+ sh "./MarkdownTest.pl --script='#{script}' --tidy"
105
+ end
106
+ end
107
+
108
+ desc 'Run version 1.0 conformance suite'
109
+ task 'test:conformance:1.0' => 'test:conformance'
110
+
111
+ desc 'Run 1.0.3 conformance suite'
112
+ task 'test:conformance:1.0.3' => [:build] do |t|
113
+ ENV['MARKDOWN_TEST_VER'] = '1.0.3'
114
+ Rake::Task['test:conformance'].invoke
115
+ end
116
+
117
+ desc 'Run unit and conformance tests'
118
+ task :test => %w[test:unit test:conformance]
119
+
120
+ desc 'Run benchmarks'
121
+ task :benchmark => :build do |t|
122
+ $:.unshift 'lib'
123
+ load 'test/benchmark.rb'
124
+ end
125
+
126
+ # ==========================================================
127
+ # Documentation
128
+ # ==========================================================
129
+
130
+ desc 'Generate API documentation'
131
+ task :doc => 'doc/index.html'
132
+
133
+ file 'doc/index.html' => FileList['lib/*.rb'] do |f|
134
+ sh((<<-end).gsub(/\s+/, ' '))
135
+ hanna --charset utf8 \
136
+ --fmt html \
137
+ --inline-source \
138
+ --line-numbers \
139
+ --main RDiscount \
140
+ --op doc \
141
+ --title 'RDiscount API Documentation' \
142
+ #{f.prerequisites.join(' ')}
143
+ end
144
+ end
145
+
146
+ CLEAN.include 'doc'
147
+
148
+
149
+ # ==========================================================
150
+ # Rubyforge
151
+ # ==========================================================
152
+
153
+ desc 'Publish new release to rubyforge'
154
+ task :release => [package('.gem'), package('.tar.gz')] do |t|
155
+ sh <<-end
156
+ rubyforge add_release wink rdiscount #{$spec.version} #{package('.gem')} &&
157
+ rubyforge add_file wink rdiscount #{$spec.version} #{package('.tar.gz')}
158
+ end
159
+ end
160
+
161
+ desc 'Publish API docs to rubyforge'
162
+ task :publish => :doc do |t|
163
+ sh 'scp -rp doc/. rubyforge.org:/var/www/gforge-projects/wink/rdiscount'
164
+ end
165
+
166
+ # ==========================================================
167
+ # Update package's Discount sources
168
+ # ==========================================================
169
+
170
+ desc 'Gather required discount sources into extension directory'
171
+ task :gather => 'discount' do |t|
172
+ files =
173
+ FileList[
174
+ 'discount/{markdown,mkdio,amalloc,cstring}.h',
175
+ 'discount/{markdown,docheader,dumptree,generate,mkdio,resource}.c'
176
+ ]
177
+ cp files, 'ext/',
178
+ :preserve => true,
179
+ :verbose => true
180
+ end
181
+
182
+ # best. task. ever.
183
+ file 'discount' do |f|
184
+ STDERR.puts((<<-TEXT).gsub(/^ +/, ''))
185
+ Sorry, this operation requires a human. Tell your human to:
186
+
187
+ Grab a discount tarball from:
188
+ http://www.pell.portland.or.us/~orc/Code/discount/
189
+
190
+ Extract here with something like:
191
+ tar xvzf discount-1.2.9.tar.gz
192
+
193
+ Create a discount symlink pointing at the version directory:
194
+ ln -hsf discount-1.2.9 discount
195
+
196
+ TEXT
197
+ fail "discount sources required."
198
+ end
data/bin/rdiscount ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path(File.dirname(__FILE__) + "/../lib")
4
+ require 'rdiscount'
5
+ STDOUT.write(RDiscount.new(ARGF.read).to_html)
data/ext/amalloc.h ADDED
@@ -0,0 +1,29 @@
1
+ /*
2
+ * debugging malloc()/realloc()/calloc()/free() that attempts
3
+ * to keep track of just what's been allocated today.
4
+ */
5
+ #ifndef AMALLOC_D
6
+ #define AMALLOC_D
7
+
8
+ #include "config.h"
9
+
10
+ #ifdef USE_AMALLOC
11
+
12
+ extern void *amalloc(int);
13
+ extern void *acalloc(int,int);
14
+ extern void *arealloc(void*,int);
15
+ extern void afree(void*);
16
+ extern void adump();
17
+
18
+ #define malloc amalloc
19
+ #define calloc acalloc
20
+ #define realloc arealloc
21
+ #define free afree
22
+
23
+ #else
24
+
25
+ #define adump() (void)1
26
+
27
+ #endif
28
+
29
+ #endif/*AMALLOC_D*/
data/ext/config.h ADDED
@@ -0,0 +1,9 @@
1
+
2
+ /* rdiscount extension configuration */
3
+
4
+ #undef USE_AMALLOC
5
+
6
+ #define TABSTOP 4
7
+ #define COINTOSS() (random()&1)
8
+ #define INITRNG(x) srandom((unsigned int)x)
9
+ #define RELAXED_EMPHASIS 1
data/ext/cstring.h ADDED
@@ -0,0 +1,68 @@
1
+ /* two template types: STRING(t) which defines a pascal-style string
2
+ * of element (t) [STRING(char) is the closest to the pascal string],
3
+ * and ANCHOR(t) which defines a baseplate that a linked list can be
4
+ * built up from. [The linked list /must/ contain a ->next pointer
5
+ * for linking the list together with.]
6
+ */
7
+ #ifndef _CSTRING_D
8
+ #define _CSTRING_D
9
+
10
+ #include <string.h>
11
+ #include <stdlib.h>
12
+
13
+ #include "amalloc.h"
14
+
15
+ /* expandable Pascal-style string.
16
+ */
17
+ #define STRING(type) struct { type *text; int size, alloc; }
18
+
19
+ #define CREATE(x) T(x) = (void*)(S(x) = (x).alloc = 0)
20
+ #define EXPAND(x) (S(x)++)[(S(x) < (x).alloc) \
21
+ ? (T(x)) \
22
+ : (T(x) = T(x) ? realloc(T(x), sizeof T(x)[0] * ((x).alloc += 100)) \
23
+ : malloc(sizeof T(x)[0] * ((x).alloc += 100)) )]
24
+
25
+ #define DELETE(x) (x).alloc ? (free(T(x)), S(x) = (x).alloc = 0) \
26
+ : ( S(x) = 0 )
27
+ #define CLIP(t,i,sz) \
28
+ ( ((i) >= 0) && ((sz) > 0) && (((i)+(sz)) <= S(t)) ) ? \
29
+ (memmove(&T(t)[i], &T(t)[i+sz], (S(t)-(i+sz)+1)*sizeof(T(t)[0])), \
30
+ S(t) -= (sz)) : -1
31
+
32
+ #define RESERVE(x, sz) T(x) = ((x).alloc > S(x) + (sz) \
33
+ ? T(x) \
34
+ : T(x) \
35
+ ? realloc(T(x), sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))) \
36
+ : malloc(sizeof T(x)[0] * ((x).alloc = 100+(sz)+S(x))))
37
+ #define SUFFIX(t,p,sz) \
38
+ memcpy(((S(t) += (sz)) - (sz)) + \
39
+ (T(t) = T(t) ? realloc(T(t), sizeof T(t)[0] * ((t).alloc += sz)) \
40
+ : malloc(sizeof T(t)[0] * ((t).alloc += sz))), \
41
+ (p), sizeof(T(t)[0])*(sz))
42
+
43
+ #define PREFIX(t,p,sz) \
44
+ RESERVE( (t), (sz) ); \
45
+ if ( S(t) ) { memmove(T(t)+(sz), T(t), S(t)); } \
46
+ memcpy( T(t), (p), (sz) ); \
47
+ S(t) += (sz)
48
+
49
+ /* reference-style links (and images) are stored in an array
50
+ */
51
+ #define T(x) (x).text
52
+ #define S(x) (x).size
53
+
54
+ /* abstract anchor type that defines a list base
55
+ * with a function that attaches an element to
56
+ * the end of the list.
57
+ *
58
+ * the list base field is named .text so that the T()
59
+ * macro will work with it.
60
+ */
61
+ #define ANCHOR(t) struct { t *text, *end; }
62
+
63
+ #define ATTACH(t, p) ( (t).text ?( ((t).end->next = (p)), ((t).end = (p)) ) \
64
+ :( ((t).text = (t).end = (p)) ) )
65
+
66
+ typedef STRING(char) Cstring;
67
+
68
+ #endif/*_CSTRING_D*/
data/ext/docheader.c ADDED
@@ -0,0 +1,43 @@
1
+ /*
2
+ * docheader -- get values from the document header
3
+ *
4
+ * Copyright (C) 2007 David L Parsons.
5
+ * The redistribution terms are provided in the COPYRIGHT file that must
6
+ * be distributed with this source code.
7
+ */
8
+ #include "config.h"
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <ctype.h>
12
+
13
+ #include "cstring.h"
14
+ #include "markdown.h"
15
+ #include "amalloc.h"
16
+
17
+ #define afterdle(t) (T((t)->text) + (t)->dle)
18
+
19
+ char *
20
+ mkd_doc_title(Document *doc)
21
+ {
22
+ if ( doc && doc->headers )
23
+ return afterdle(doc->headers);
24
+ return 0;
25
+ }
26
+
27
+
28
+ char *
29
+ mkd_doc_author(Document *doc)
30
+ {
31
+ if ( doc && doc->headers && doc->headers->next )
32
+ return afterdle(doc->headers->next);
33
+ return 0;
34
+ }
35
+
36
+
37
+ char *
38
+ mkd_doc_date(Document *doc)
39
+ {
40
+ if ( doc && doc->headers && doc->headers->next && doc->headers->next->next )
41
+ return afterdle(doc->headers->next->next);
42
+ return 0;
43
+ }
data/ext/dumptree.c ADDED
@@ -0,0 +1,147 @@
1
+ /* markdown: a C implementation of John Gruber's Markdown markup language.
2
+ *
3
+ * Copyright (C) 2007 David L Parsons.
4
+ * The redistribution terms are provided in the COPYRIGHT file that must
5
+ * be distributed with this source code.
6
+ */
7
+ #include <stdio.h>
8
+ #include "markdown.h"
9
+ #include "cstring.h"
10
+ #include "amalloc.h"
11
+
12
+ struct frame {
13
+ int indent;
14
+ char c;
15
+ };
16
+
17
+ typedef STRING(struct frame) Stack;
18
+
19
+ static char *
20
+ Pptype(int typ)
21
+ {
22
+ switch (typ) {
23
+ case WHITESPACE: return "whitespace";
24
+ case CODE : return "code";
25
+ case QUOTE : return "quote";
26
+ case MARKUP : return "markup";
27
+ case HTML : return "html";
28
+ case DL : return "dl";
29
+ case UL : return "ul";
30
+ case OL : return "ol";
31
+ case LISTITEM : return "item";
32
+ case HDR : return "header";
33
+ case HR : return "HR";
34
+ default : return "mystery node!";
35
+ }
36
+ }
37
+
38
+ static void
39
+ pushpfx(int indent, char c, Stack *sp)
40
+ {
41
+ struct frame *q = &EXPAND(*sp);
42
+
43
+ q->indent = indent;
44
+ q->c = c;
45
+ }
46
+
47
+
48
+ static void
49
+ poppfx(Stack *sp)
50
+ {
51
+ S(*sp)--;
52
+ }
53
+
54
+
55
+ static void
56
+ changepfx(Stack *sp, char c)
57
+ {
58
+ char ch;
59
+
60
+ if ( !S(*sp) ) return;
61
+
62
+ ch = T(*sp)[S(*sp)-1].c;
63
+
64
+ if ( ch == '+' || ch == '|' )
65
+ T(*sp)[S(*sp)-1].c = c;
66
+ }
67
+
68
+
69
+ static void
70
+ printpfx(Stack *sp, FILE *f)
71
+ {
72
+ int i;
73
+ char c;
74
+
75
+ if ( !S(*sp) ) return;
76
+
77
+ c = T(*sp)[S(*sp)-1].c;
78
+
79
+ if ( c == '+' || c == '-' ) {
80
+ fprintf(f, "--%c", c);
81
+ T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|';
82
+ }
83
+ else
84
+ for ( i=0; i < S(*sp); i++ ) {
85
+ if ( i )
86
+ fprintf(f, " ");
87
+ fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c);
88
+ if ( T(*sp)[i].c == '`' )
89
+ T(*sp)[i].c = ' ';
90
+ }
91
+ fprintf(f, "--");
92
+ }
93
+
94
+
95
+ static void
96
+ dumptree(Paragraph *pp, Stack *sp, FILE *f)
97
+ {
98
+ int count;
99
+ Line *p;
100
+ int d;
101
+ static char *Begin[] = { 0, "P", "center" };
102
+
103
+ while ( pp ) {
104
+ if ( !pp->next )
105
+ changepfx(sp, '`');
106
+ printpfx(sp, f);
107
+
108
+ d = fprintf(f, "[%s", Pptype(pp->typ));
109
+ if ( pp->align )
110
+ d += fprintf(f, ", <%s>", Begin[pp->align]);
111
+
112
+ for (count=0, p=pp->text; p; ++count, (p = p->next) )
113
+ ;
114
+
115
+ if ( count )
116
+ d += fprintf(f, ", %d line%s", count, (count==1)?"":"s");
117
+
118
+ d += fprintf(f, "]");
119
+
120
+ if ( pp->down ) {
121
+ pushpfx(d, pp->down->next ? '+' : '-', sp);
122
+ dumptree(pp->down, sp, f);
123
+ poppfx(sp);
124
+ }
125
+ else fputc('\n', f);
126
+ pp = pp->next;
127
+ }
128
+ }
129
+
130
+
131
+ int
132
+ mkd_dump(Document *doc, FILE *out, int flags, char *title)
133
+ {
134
+ Stack stack;
135
+
136
+ if (mkd_compile(doc, flags) ) {
137
+
138
+ CREATE(stack);
139
+ pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack);
140
+ dumptree(doc->code, &stack, out);
141
+ DELETE(stack);
142
+
143
+ mkd_cleanup(doc);
144
+ return 0;
145
+ }
146
+ return -1;
147
+ }
data/ext/extconf.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ dir_config('rdiscount')
4
+
5
+ HAVE_RANDOM = have_func('random')
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
+
14
+ create_makefile('rdiscount')