rpeg-markdown 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,85 @@
1
+ Ruby Markdown Extension, implemented using peg-markdown
2
+ Copyright (c) 2008 Ryan Tomayko
3
+
4
+ Released under GPL:
5
+
6
+ This program is free software; you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation; either version 2 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program; if not, write to the Free Software
18
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
+
20
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21
+
22
+ markdown in c, implemented using PEG grammar
23
+ Copyright (c) 2008 John MacFarlane
24
+
25
+ Released under GPL:
26
+
27
+ This program is free software; you can redistribute it and/or modify
28
+ it under the terms of the GNU General Public License as published by
29
+ the Free Software Foundation; either version 2 of the License, or
30
+ (at your option) any later version.
31
+
32
+ This program is distributed in the hope that it will be useful,
33
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+ GNU General Public License for more details.
36
+
37
+ You should have received a copy of the GNU General Public License
38
+ along with this program; if not, write to the Free Software
39
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40
+
41
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
42
+
43
+ peg-0.1.4 (included for convenience - http://piumarta.com/software/peg/)
44
+
45
+ Copyright (c) 2007 by Ian Piumarta
46
+ All rights reserved.
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining a
49
+ copy of this software and associated documentation files (the 'Software'),
50
+ to deal in the Software without restriction, including without limitation
51
+ the rights to use, copy, modify, merge, publish, distribute, and/or sell
52
+ copies of the Software, and to permit persons to whom the Software is
53
+ furnished to do so, provided that the above copyright notice(s) and this
54
+ permission notice appear in all copies of the Software. Acknowledgement
55
+ of the use of this Software in supporting documentation would be
56
+ appreciated but is not required.
57
+
58
+ THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
59
+
60
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
61
+
62
+ my_getopt (included for convenience - http://www.geocities.com/bsittler/)
63
+
64
+ Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler
65
+
66
+ Permission is hereby granted, free of charge, to any person
67
+ obtaining a copy of this software and associated documentation
68
+ files (the "Software"), to deal in the Software without
69
+ restriction, including without limitation the rights to use, copy,
70
+ modify, merge, publish, distribute, sublicense, and/or sell copies
71
+ of the Software, and to permit persons to whom the Software is
72
+ furnished to do so, subject to the following conditions:
73
+
74
+ The above copyright notice and this permission notice shall be
75
+ included in all copies or substantial portions of the Software.
76
+
77
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
78
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
79
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
80
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
81
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
82
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
83
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
84
+ DEALINGS IN THE SOFTWARE.
85
+
data/README ADDED
@@ -0,0 +1,14 @@
1
+ Ruby peg-markdown Extension
2
+ ===========================
3
+
4
+ The peg-markdown extension wraps John MacFarlane's C implementation of
5
+ Markdown (see [peg-markdown][1]) in a Ruby extension.
6
+
7
+ [1]: http://github.com/jgm/peg-markdown/
8
+ "Jon MacFarleane's peg-markdown project"
9
+
10
+ ### COPYING
11
+
12
+ The peg-markdown sources are licensed under the GPL and the Ruby extension
13
+ sources adopts this license. See the file LICENSE included with this
14
+ distribution for more information.
data/Rakefile ADDED
@@ -0,0 +1,96 @@
1
+ require 'rake/clean'
2
+ require 'rake/packagetask'
3
+ require 'rake/gempackagetask'
4
+
5
+ DLEXT = Config::CONFIG['DLEXT']
6
+ VERS = '0.1.0'
7
+
8
+ spec =
9
+ Gem::Specification.new do |s|
10
+ s.name = "rpeg-markdown"
11
+ s.version = VERS
12
+ s.summary = "Ruby extension library for peg-markdown"
13
+ s.files = FileList['README','LICENSE','Rakefile','test.rb','{lib,ext}/**.rb','ext/*.{c,h}','bin/rpeg-markdown']
14
+ s.bindir = 'bin'
15
+ s.executables << 'rpeg-markdown'
16
+ s.require_path = 'lib'
17
+ s.has_rdoc = true
18
+ s.extra_rdoc_files = ['README', 'LICENSE']
19
+ s.test_files = Dir['test.rb']
20
+ s.extensions = ['ext/extconf.rb']
21
+
22
+ s.author = 'Ryan Tomayko'
23
+ s.email = 'r@tomayko.com'
24
+ s.homepage = 'http://github.com/rtomayko/rpeg-markdown'
25
+ s.rubyforge_project = 'wink'
26
+ end
27
+
28
+ Rake::GemPackageTask.new(spec) do |p|
29
+ p.gem_spec = spec
30
+ p.need_tar_gz = true
31
+ p.need_tar = false
32
+ p.need_zip = false
33
+ end
34
+
35
+ namespace :submodule do
36
+ desc 'Init the peg-markdown submodule'
37
+ task :init do |t|
38
+ unless File.exist? 'peg-markdown/markdown.c'
39
+ rm_rf 'peg-markdown'
40
+ sh 'git submodule init peg-markdown'
41
+ sh 'git submodule update peg-markdown'
42
+ end
43
+ end
44
+
45
+ task :update => :init do
46
+ sh 'git submodule update peg-markdown'
47
+ end
48
+ end
49
+
50
+ desc 'Gather required peg-markdown sources into extension directory'
51
+ task :gather => 'submodule:update' do |t|
52
+ sh 'cd peg-markdown && make markdown_parser.c'
53
+ cp FileList['peg-markdown/markdown_{peg.h,parser.c,output.c}'], 'ext/',
54
+ :preserve => true,
55
+ :verbose => true
56
+ end
57
+ CLOBBER.include 'ext/markdown_{peg.h,parser.c,output.c}'
58
+
59
+ file 'ext/Makefile' => FileList['ext/{extconf.rb,*.c,*.h,*.rb}'] do
60
+ chdir('ext') { ruby 'extconf.rb' }
61
+ end
62
+ CLEAN.include 'ext/Makefile'
63
+
64
+ file "ext/markdown.#{DLEXT}" => FileList['ext/Makefile', 'ext/*.{c,h,rb}'] do |f|
65
+ sh 'cd ext && make'
66
+ end
67
+ CLEAN.include 'ext/*.{o,bundle,so}'
68
+
69
+ file "lib/markdown.#{DLEXT}" => "ext/markdown.#{DLEXT}" do |f|
70
+ cp f.prerequisites, "lib/", :preserve => true
71
+ end
72
+
73
+ desc 'Build the peg-markdown extension'
74
+ task :build => "lib/markdown.#{DLEXT}"
75
+
76
+ task 'test:unit' => [ :build ] do |t|
77
+ ruby 'test.rb'
78
+ end
79
+
80
+ task 'test:conformance' => [ 'submodule:update', :build ] do |t|
81
+ chdir('peg-markdown/MarkdownTest_1.0.3') do
82
+ sh "./MarkdownTest.pl --script=../../bin/rpeg-markdown --tidy"
83
+ end
84
+ end
85
+
86
+
87
+
88
+ # ==========================================================
89
+ # Rubyforge
90
+ # ==========================================================
91
+
92
+ task 'release' => [ "pkg/rpeg-markdown-#{VERS}.gem", "pkg/rpeg-markdown-#{VERS}.tar.gz" ] do |t|
93
+ # "pkg/rpeg-markdown-#{VERS}.gem",
94
+ # "pkg/rpeg-markdown-#{VERS}.tar.gz"
95
+ sh "rubyforge add_release wink rpeg-markdown #{VERS} pkg/rpeg-markdown-#{VERS}.gem"
96
+ end
data/bin/rpeg-markdown ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'markdown'
5
+ rescue LoadError => boom
6
+ local_path = File.expand_path(File.dirname(__FILE__))
7
+ $: << "#{local_path}/../lib"
8
+ require 'markdown'
9
+ end
10
+
11
+ STDIN.reopen(ARGV[0], 'rb') if ARGV.any?
12
+ markdown = Markdown.new(STDIN.read)
13
+ STDOUT.write(markdown.to_html)
data/ext/extconf.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS = "-Wall"
4
+
5
+ dir_config('markdown')
6
+ create_makefile('markdown')
data/ext/markdown.c ADDED
@@ -0,0 +1,90 @@
1
+ #include "ruby.h"
2
+ #include "markdown_peg.h"
3
+ #include "markdown_buffer.h"
4
+
5
+ static VALUE rb_cMarkdown;
6
+
7
+ static ID id_text;
8
+ static ID id_smart;
9
+ static ID id_notes;
10
+
11
+ #define TABSTOP 4
12
+ #define INCREMENT 4096 /* size of chunks in which to allocate memory */
13
+
14
+ static VALUE
15
+ markdown_to_html(VALUE self)
16
+ {
17
+ element parsed_input;
18
+ VALUE output_buffer;
19
+
20
+ char *inputbuf, *curchar;
21
+ int charstotab, buflength, maxlength;
22
+
23
+ /* grab char pointer to markdown input text */
24
+ VALUE text = rb_funcall(self, id_text, 0);
25
+ Check_Type(text, T_STRING);
26
+ char * ptext = StringValuePtr(text);
27
+
28
+ buflength = 0;
29
+ maxlength = RSTRING(text)->len >= INCREMENT ?
30
+ RSTRING(text)->len :
31
+ INCREMENT;
32
+ inputbuf = malloc(maxlength);
33
+ curchar = inputbuf;
34
+
35
+ charstotab = TABSTOP;
36
+ while ((*curchar = *ptext++) != '\0') {
37
+ switch (*curchar) {
38
+ case '\t':
39
+ while (charstotab > 0)
40
+ *curchar = ' ', curchar++, buflength++, charstotab--;
41
+ break;
42
+ case '\n':
43
+ curchar++, buflength++, charstotab = TABSTOP;
44
+ break;
45
+ default:
46
+ curchar++, buflength++, charstotab--;
47
+ }
48
+ if (charstotab == 0)
49
+ charstotab = TABSTOP;
50
+ if (buflength > maxlength - TABSTOP - 3) {
51
+ maxlength += INCREMENT;
52
+ inputbuf = realloc(inputbuf, maxlength);
53
+ curchar = inputbuf + buflength;
54
+ if (inputbuf == NULL) {
55
+ /* TODO: no memory */
56
+ }
57
+ }
58
+ }
59
+ *curchar++ = '\n';
60
+ *curchar++ = '\n';
61
+ *curchar = '\0';
62
+ buflength+= 2;
63
+
64
+ /* flip extension bits */
65
+ int extensions = 0;
66
+ if ( rb_funcall(self, id_smart, 0) == Qtrue )
67
+ extensions = extensions | EXT_SMART ;
68
+ if ( rb_funcall(self, id_notes, 0) == Qtrue )
69
+ extensions = extensions | EXT_NOTES ;
70
+
71
+ /* parse markdown input into sematic element tree */
72
+ parsed_input = markdown(inputbuf, extensions);
73
+
74
+ /* allocate output buffer and generate output */
75
+ output_buffer = rb_markdown_buffer_init(buflength * 2);
76
+ print_element(parsed_input, HTML_FORMAT);
77
+ rb_markdown_buffer_free();
78
+ return output_buffer;
79
+ }
80
+
81
+ void Init_markdown()
82
+ {
83
+ /* Initialize frequently used Symbols */
84
+ id_text = rb_intern("text");
85
+ id_smart = rb_intern("smart");
86
+ id_notes = rb_intern("notes");
87
+
88
+ rb_cMarkdown = rb_define_class("Markdown", rb_cObject);
89
+ rb_define_method(rb_cMarkdown, "to_html", markdown_to_html, 0);
90
+ }
@@ -0,0 +1,46 @@
1
+ #include <stdio.h>
2
+ #include <stdarg.h>
3
+ #include "ruby.h"
4
+ #include "markdown_buffer.h"
5
+
6
+ static VALUE markdown_buffer;
7
+ static int registered = 0;
8
+
9
+ VALUE rb_markdown_buffer_init(long size) {
10
+ if ( registered != 1 ) {
11
+ rb_gc_register_address(&markdown_buffer);
12
+ registered = 1;
13
+ }
14
+ markdown_buffer = rb_str_buf_new(size);
15
+ return markdown_buffer;
16
+ }
17
+
18
+ void rb_markdown_buffer_free(void) {
19
+ markdown_buffer = Qnil;
20
+ }
21
+
22
+ int rb_markdown_buffer_printf(const char * format, ...)
23
+ {
24
+ va_list args;
25
+ int length;
26
+ char * buf = NULL;
27
+
28
+ va_start(args, format);
29
+ length = vasprintf(&buf, format, args);
30
+ va_end(args);
31
+
32
+ if ( buf != NULL ) {
33
+ rb_str_buf_cat(markdown_buffer, buf, length);
34
+ free(buf);
35
+ } else {
36
+ /* TODO: handle out of memory condition */
37
+ }
38
+
39
+ return length;
40
+ }
41
+
42
+ char rb_markdown_buffer_putchar(char c)
43
+ {
44
+ rb_str_buf_cat(markdown_buffer, &c, 1);
45
+ return c;
46
+ }
@@ -0,0 +1,6 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE rb_markdown_buffer_init(long size);
4
+ void rb_markdown_buffer_free(void);
5
+ int rb_markdown_buffer_printf(const char * format, ...);
6
+ char rb_markdown_buffer_putchar(char c);
@@ -0,0 +1,769 @@
1
+ /**********************************************************************
2
+
3
+ markdown_output.c - functions for printing Elements parsed by
4
+ markdown_peg.
5
+ (c) 2008 John MacFarlane (jgm at berkeley dot edu).
6
+
7
+ This program is free software; you can redistribute it and/or modify
8
+ it under the terms of the GNU General Public License as published by
9
+ the Free Software Foundation; version 2 of the License.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ ***********************************************************************/
17
+
18
+ #include <stdbool.h>
19
+ #include <stdio.h>
20
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <assert.h>
23
+ #include "markdown_peg.h"
24
+
25
+ /***********************************************************************/
26
+ #include "markdown_buffer.h"
27
+ #define printf rb_markdown_buffer_printf
28
+ #define putchar rb_markdown_buffer_putchar
29
+ /***********************************************************************/
30
+
31
+ /* TODO remove */
32
+ static extensions = 0;
33
+
34
+ static void print_html_string(char *str, bool obfuscate);
35
+ static void print_html_element_list(element *list, bool obfuscate);
36
+ static void print_html_element(element elt, bool obfuscate);
37
+ static void print_latex_string(char *str);
38
+ static void print_latex_element_list(element *list);
39
+ static void print_latex_element(element elt);
40
+ static void print_groff_string(char *str);
41
+ static void print_groff_mm_element_list(element *list);
42
+ static void print_groff_mm_element(element elt, int count);
43
+
44
+ /**********************************************************************
45
+
46
+ Utility functions for printing
47
+
48
+ ***********************************************************************/
49
+
50
+ static int padded = 2; /* Number of newlines after last output.
51
+ Starts at 2 so no newlines are needed at start.
52
+ */
53
+
54
+ static element *endnotes; /* List of endnotes to print after main content. */
55
+ static int notenumber = 0; /* Number of footnote. */
56
+
57
+ /* pad - add newlines if needed */
58
+ static void pad(int num) {
59
+ while (num-- > padded)
60
+ printf("\n");;
61
+ padded = num;
62
+ }
63
+
64
+ /**********************************************************************
65
+
66
+ Functions for printing Elements as HTML
67
+
68
+ ***********************************************************************/
69
+
70
+ /* print_html_string - print string, escaping for HTML
71
+ * If obfuscate selected, convert characters to hex or decimal entities at random */
72
+ static void print_html_string(char *str, bool obfuscate) {
73
+ while (*str != '\0') {
74
+ switch (*str) {
75
+ case '&':
76
+ printf("&amp;");;;
77
+ break;
78
+ case '<':
79
+ printf("&lt;");;;
80
+ break;
81
+ case '>':
82
+ printf("&gt;");;;
83
+ break;
84
+ case '"':
85
+ printf("&quot;");;;
86
+ break;
87
+ default:
88
+ if (obfuscate) {
89
+ if (rand() % 2 == 0)
90
+ printf("&#%d;", (int) *str);
91
+ else
92
+ printf("&#x%x;", (unsigned int) *str);
93
+ }
94
+ else
95
+ putchar(*str);
96
+ }
97
+ str++;
98
+ }
99
+ }
100
+
101
+ /* print_html_element_list - print a list of elements as HTML */
102
+ static void print_html_element_list(element *list, bool obfuscate) {
103
+ while (list != NULL) {
104
+ print_html_element(*list, obfuscate);
105
+ list = list->next;
106
+ }
107
+ }
108
+
109
+ /* print_html_element - print an element as HTML */
110
+ static void print_html_element(element elt, bool obfuscate) {
111
+ int lev;
112
+ char *contents;
113
+ switch (elt.key) {
114
+ case SPACE:
115
+ printf("%s", elt.contents.str);
116
+ break;
117
+ case LINEBREAK:
118
+ printf("<br/>");;;
119
+ break;
120
+ case STR:
121
+ print_html_string(elt.contents.str, obfuscate);
122
+ break;
123
+ case ELLIPSIS:
124
+ printf("&hellip;");;;
125
+ break;
126
+ case EMDASH:
127
+ printf("&mdash;");;;
128
+ break;
129
+ case ENDASH:
130
+ printf("&ndash;");;;
131
+ break;
132
+ case APOSTROPHE:
133
+ printf("&rsquo;");;;
134
+ break;
135
+ case SINGLEQUOTED:
136
+ printf("&lsquo;");;;
137
+ print_html_element_list(elt.children, obfuscate);
138
+ printf("&rsquo;");;;
139
+ break;
140
+ case DOUBLEQUOTED:
141
+ printf("&ldquo;");;;
142
+ print_html_element_list(elt.children, obfuscate);
143
+ printf("&rdquo;");;;
144
+ break;
145
+ case CODE:
146
+ printf("<code>");;;
147
+ print_html_string(elt.contents.str, obfuscate);
148
+ printf("</code>");;;
149
+ break;
150
+ case HTML:
151
+ printf("%s", elt.contents.str);
152
+ break;
153
+ case LINK:
154
+ if (strstr(elt.contents.link.url, "mailto:") == elt.contents.link.url)
155
+ obfuscate = true; /* obfuscate mailto: links */
156
+ printf("<a href=\"");
157
+ print_html_string(elt.contents.link.url, obfuscate);
158
+ printf("\"");
159
+ if (strlen(elt.contents.link.title) > 0) {
160
+ printf(" title=\"");
161
+ print_html_string(elt.contents.link.title, obfuscate);
162
+ printf("\"");
163
+ }
164
+ printf(">");;;
165
+ print_html_element_list(elt.contents.link.label, obfuscate);
166
+ printf("</a>");;;
167
+ break;
168
+ case IMAGE:
169
+ printf("<img src=\"");
170
+ print_html_string(elt.contents.link.url, obfuscate);
171
+ printf("\" alt=\"");
172
+ print_html_element_list(elt.contents.link.label, obfuscate);
173
+ printf("\"");
174
+ if (strlen(elt.contents.link.title) > 0) {
175
+ printf(" title=\"");
176
+ print_html_string(elt.contents.link.title, obfuscate);
177
+ printf("\"");
178
+ }
179
+ printf(" />");;;
180
+ break;
181
+ case EMPH:
182
+ printf("<em>");;;
183
+ print_html_element_list(elt.children, obfuscate);
184
+ printf("</em>");;;
185
+ break;
186
+ case STRONG:
187
+ printf("<strong>");;;
188
+ print_html_element_list(elt.children, obfuscate);
189
+ printf("</strong>");;;
190
+ break;
191
+ case LIST:
192
+ print_html_element_list(elt.children, obfuscate);
193
+ break;
194
+ case RAW:
195
+ /* \001 is used to indicate boundaries between nested lists when there
196
+ * is no blank line. We split the string by \001 and parse
197
+ * each chunk separately. */
198
+ contents = strtok(elt.contents.str, "\001");
199
+ print_html_element(markdown(contents, extensions), obfuscate);
200
+ while ((contents = strtok(NULL, "\001")))
201
+ print_html_element(markdown(contents, extensions), obfuscate);
202
+ break;
203
+ case H1: case H2: case H3: case H4: case H5: case H6:
204
+ lev = elt.key - H1 + 1; /* assumes H1 ... H6 are in order */
205
+ pad(2);
206
+ printf("<h%1d>", lev);
207
+ print_html_element_list(elt.children, obfuscate);
208
+ printf("</h%1d>", lev);
209
+ padded = 0;
210
+ break;
211
+ case PLAIN:
212
+ pad(1);
213
+ print_html_element_list(elt.children, obfuscate);
214
+ padded = 0;
215
+ break;
216
+ case PARA:
217
+ pad(2);
218
+ printf("<p>");;;
219
+ print_html_element_list(elt.children, obfuscate);
220
+ printf("</p>");;;
221
+ padded = 0;
222
+ break;
223
+ case HRULE:
224
+ pad(2);
225
+ printf("<hr />");;;
226
+ padded = 0;
227
+ break;
228
+ case HTMLBLOCK:
229
+ pad(2);
230
+ printf("%s", elt.contents.str);
231
+ padded = 0;
232
+ break;
233
+ case VERBATIM:
234
+ pad(2);
235
+ printf("%s", "<pre><code>");
236
+ print_html_string(elt.contents.str, obfuscate);
237
+ printf("%s", "</code></pre>");
238
+ padded = 0;
239
+ break;
240
+ case BULLETLIST:
241
+ pad(2);
242
+ printf("%s", "<ul>");
243
+ padded = 0;
244
+ print_html_element_list(elt.children, obfuscate);
245
+ pad(1);
246
+ printf("%s", "</ul>");
247
+ padded = 0;
248
+ break;
249
+ case ORDEREDLIST:
250
+ pad(2);
251
+ printf("%s", "<ol>");
252
+ padded = 0;
253
+ print_html_element_list(elt.children, obfuscate);
254
+ pad(1);
255
+ printf("</ol>");;;
256
+ padded = 0;
257
+ break;
258
+ case LISTITEM:
259
+ pad(1);
260
+ printf("<li>");;;
261
+ padded = 2;
262
+ print_html_element_list(elt.children, obfuscate);
263
+ printf("</li>");;;
264
+ padded = 0;
265
+ break;
266
+ case BLOCKQUOTE:
267
+ pad(2);
268
+ printf("<blockquote>\n");;;
269
+ padded = 2;
270
+ print_html_element_list(elt.children, obfuscate);
271
+ pad(1);
272
+ printf("</blockquote>");;;
273
+ padded = 0;
274
+ break;
275
+ case REFERENCE:
276
+ /* Nonprinting */
277
+ break;
278
+ case NOTE:
279
+ /* if contents.str == 0, then print note; else ignore, since this
280
+ * is a note block that has been incorporated into the notes list */
281
+ if (elt.contents.str == 0) {
282
+ endnotes = cons(elt, endnotes);
283
+ ++notenumber;
284
+ printf("<a class=\"noteref\" id=\"fnref%d\" href=\"#fn%d\" title=\"Jump to note %d\">[%d]</a>",
285
+ notenumber, notenumber, notenumber, notenumber);
286
+ }
287
+ break;
288
+ default:
289
+ fprintf(stderr, "print_html_element encountered unknown element key = %d\n", elt.key);
290
+ exit(EXIT_FAILURE);
291
+ }
292
+ }
293
+
294
+ static void print_html_endnotes(void) {
295
+ int counter = 0;
296
+ if (endnotes == NULL) {
297
+ return;
298
+ }
299
+ printf("<hr/>\n<ol id=\"notes\">");
300
+ endnotes = reverse(endnotes);
301
+ while (endnotes != NULL) {
302
+ counter++;
303
+ pad(1);
304
+ printf("<li id=\"fn%d\">\n", counter);
305
+ padded = 2;
306
+ print_html_element_list(endnotes->children, false);
307
+ printf(" <a href=\"#fnref%d\" title=\"Jump back to reference\">[back]</a>", counter);
308
+ pad(1);
309
+ printf("</li>");;
310
+ endnotes = endnotes->next;
311
+ }
312
+ pad(1);
313
+ printf("</ol>");;;
314
+ }
315
+
316
+ /**********************************************************************
317
+
318
+ Functions for printing Elements as LaTeX
319
+
320
+ ***********************************************************************/
321
+
322
+ /* print_latex_string - print string, escaping for LaTeX */
323
+ static void print_latex_string(char *str) {
324
+ while (*str != '\0') {
325
+ switch (*str) {
326
+ case '{': case '}': case '$': case '%':
327
+ case '&': case '_': case '#':
328
+ printf("\\%c", *str);
329
+ break;
330
+ case '^':
331
+ printf("\\^{}");;;
332
+ break;
333
+ case '\\':
334
+ printf("\\textbackslash{}");;;
335
+ break;
336
+ case '~':
337
+ printf("\\ensuremath{\\sim}");;;
338
+ break;
339
+ case '|':
340
+ printf("\\textbar{}");;;
341
+ break;
342
+ case '<':
343
+ printf("\\textless{}");;;
344
+ break;
345
+ case '>':
346
+ printf("\\textgreater{}");;;
347
+ break;
348
+ default:
349
+ putchar(*str);
350
+ }
351
+ str++;
352
+ }
353
+ }
354
+
355
+ /* print_latex_element_list - print a list of elements as LaTeX */
356
+ static void print_latex_element_list(element *list) {
357
+ while (list != NULL) {
358
+ print_latex_element(*list);
359
+ list = list->next;
360
+ }
361
+ }
362
+
363
+ /* print_latex_element - print an element as LaTeX */
364
+ static void print_latex_element(element elt) {
365
+ int lev;
366
+ int i;
367
+ char *contents;
368
+ switch (elt.key) {
369
+ case SPACE:
370
+ printf("%s", elt.contents.str);
371
+ break;
372
+ case LINEBREAK:
373
+ printf("\\\\\n");;;
374
+ break;
375
+ case STR:
376
+ print_latex_string(elt.contents.str);
377
+ break;
378
+ case ELLIPSIS:
379
+ printf("\\ldots{}");;;
380
+ break;
381
+ case EMDASH:
382
+ printf("---");;;
383
+ break;
384
+ case ENDASH:
385
+ printf("--");;;
386
+ break;
387
+ case APOSTROPHE:
388
+ printf("'");;;
389
+ break;
390
+ case SINGLEQUOTED:
391
+ printf("`");;;
392
+ print_latex_element_list(elt.children);
393
+ printf("'");;;
394
+ break;
395
+ case DOUBLEQUOTED:
396
+ printf("``");;;
397
+ print_latex_element_list(elt.children);
398
+ printf("''");;;
399
+ break;
400
+ case CODE:
401
+ printf("\\texttt{");;;
402
+ print_latex_string(elt.contents.str);
403
+ printf("}");;;
404
+ break;
405
+ case HTML:
406
+ /* don't print HTML */
407
+ break;
408
+ case LINK:
409
+ printf("\\href{%s}{", elt.contents.link.url);
410
+ print_latex_element_list(elt.contents.link.label);
411
+ printf("}");;;
412
+ break;
413
+ case IMAGE:
414
+ printf("\\includegraphics{%s}", elt.contents.link.url);
415
+ break;
416
+ case EMPH:
417
+ printf("\\emph{");;;
418
+ print_latex_element_list(elt.children);
419
+ printf("}");;;
420
+ break;
421
+ case STRONG:
422
+ printf("\\textbf{");;;
423
+ print_latex_element_list(elt.children);
424
+ printf("}");;;
425
+ break;
426
+ case LIST:
427
+ print_latex_element_list(elt.children);
428
+ break;
429
+ case RAW:
430
+ /* \001 is used to indicate boundaries between nested lists when there
431
+ * is no blank line. We split the string by \001 and parse
432
+ * each chunk separately. */
433
+ contents = strtok(elt.contents.str, "\001");
434
+ print_latex_element(markdown(contents, extensions));
435
+ while ((contents = strtok(NULL, "\001")))
436
+ print_latex_element(markdown(contents, extensions));
437
+ break;
438
+ case H1: case H2: case H3:
439
+ pad(2);
440
+ lev = elt.key - H1 + 1; /* assumes H1 ... H6 are in order */
441
+ printf("\\");;;
442
+ for (i = elt.key; i > H1; i--)
443
+ printf("sub");;;
444
+ printf("section{");;;
445
+ print_latex_element_list(elt.children);
446
+ printf("}");;;
447
+ padded = 0;
448
+ break;
449
+ case H4: case H5: case H6:
450
+ pad(2);
451
+ printf("\\noindent\\textbf{");;;
452
+ print_latex_element_list(elt.children);
453
+ printf("}");;;
454
+ padded = 0;
455
+ break;
456
+ case PLAIN:
457
+ pad(1);
458
+ print_latex_element_list(elt.children);
459
+ padded = 0;
460
+ break;
461
+ case PARA:
462
+ pad(2);
463
+ print_latex_element_list(elt.children);
464
+ padded = 0;
465
+ break;
466
+ case HRULE:
467
+ pad(2);
468
+ printf("\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n");;;
469
+ padded = 0;
470
+ break;
471
+ case HTMLBLOCK:
472
+ /* don't print HTML block */
473
+ break;
474
+ case VERBATIM:
475
+ pad(1);
476
+ printf("\\begin{verbatim}\n");;;
477
+ print_latex_string(elt.contents.str);
478
+ printf("\n\\end{verbatim}");;;
479
+ padded = 0;
480
+ break;
481
+ case BULLETLIST:
482
+ pad(1);
483
+ printf("\\begin{itemize}");;;
484
+ padded = 0;
485
+ print_latex_element_list(elt.children);
486
+ pad(1);
487
+ printf("\\end{itemize}");;;
488
+ padded = 0;
489
+ break;
490
+ case ORDEREDLIST:
491
+ pad(1);
492
+ printf("\\begin{enumerate}");;;
493
+ padded = 0;
494
+ print_latex_element_list(elt.children);
495
+ pad(1);
496
+ printf("\\end{enumerate}");;;
497
+ padded = 0;
498
+ break;
499
+ case LISTITEM:
500
+ pad(1);
501
+ printf("\\item ");;;
502
+ padded = 2;
503
+ print_latex_element_list(elt.children);
504
+ printf("\n");;;
505
+ break;
506
+ case BLOCKQUOTE:
507
+ pad(1);
508
+ printf("\\begin{quote}");;;
509
+ padded = 0;
510
+ print_latex_element(markdown(elt.contents.str, extensions));
511
+ printf("\\end{quote}");;;
512
+ padded = 0;
513
+ break;
514
+ case NOTE:
515
+ /* if contents.str == 0, then print note; else ignore, since this
516
+ * is a note block that has been incorporated into the notes list */
517
+ if (elt.contents.str == 0) {
518
+ printf("\\footnote{");;;
519
+ padded = 2;
520
+ print_latex_element_list(elt.children);
521
+ printf("}");;;
522
+ padded = 0;
523
+ }
524
+ break;
525
+ case REFERENCE:
526
+ /* Nonprinting */
527
+ break;
528
+ default:
529
+ fprintf(stderr, "print_latex_element encountered unknown element key = %d\n", elt.key);
530
+ exit(EXIT_FAILURE);
531
+ }
532
+ }
533
+
534
+ /**********************************************************************
535
+
536
+ Functions for printing Elements as groff (mm macros)
537
+
538
+ ***********************************************************************/
539
+
540
+ static bool in_list_item = false; /* True if we're parsing contents of a list item. */
541
+
542
+ /* print_groff_string - print string, escaping for groff */
543
+ static void print_groff_string(char *str) {
544
+ while (*str != '\0') {
545
+ switch (*str) {
546
+ case '\\':
547
+ printf("\\e");;;
548
+ break;
549
+ default:
550
+ putchar(*str);
551
+ }
552
+ str++;
553
+ }
554
+ }
555
+
556
+ /* print_groff_mm_element_list - print a list of elements as groff ms */
557
+ static void print_groff_mm_element_list(element *list) {
558
+ int count = 1;
559
+ while (list != NULL) {
560
+ print_groff_mm_element(*list, count);
561
+ list = list->next;
562
+ count++;
563
+ }
564
+ }
565
+
566
+ /* print_groff_mm_element - print an element as groff ms */
567
+ static void print_groff_mm_element(element elt, int count) {
568
+ int lev;
569
+ char *contents;
570
+ switch (elt.key) {
571
+ case SPACE:
572
+ printf("%s", elt.contents.str);
573
+ padded = 0;
574
+ break;
575
+ case LINEBREAK:
576
+ pad(1);
577
+ printf(".br");;;
578
+ padded = 0;
579
+ break;
580
+ case STR:
581
+ print_groff_string(elt.contents.str);
582
+ padded = 0;
583
+ break;
584
+ case ELLIPSIS:
585
+ printf("...");;;
586
+ break;
587
+ case EMDASH:
588
+ printf("\\[em]");;;
589
+ break;
590
+ case ENDASH:
591
+ printf("\\[en]");;;
592
+ break;
593
+ case APOSTROPHE:
594
+ printf("'");;;
595
+ break;
596
+ case SINGLEQUOTED:
597
+ printf("`");;;
598
+ print_groff_mm_element_list(elt.children);
599
+ printf("'");;;
600
+ break;
601
+ case DOUBLEQUOTED:
602
+ printf("\\[lq]");;;
603
+ print_groff_mm_element_list(elt.children);
604
+ printf("\\[rq]");;;
605
+ break;
606
+ case CODE:
607
+ printf("\\fC");;;
608
+ print_groff_string(elt.contents.str);
609
+ printf("\\fR");;;
610
+ padded = 0;
611
+ break;
612
+ case HTML:
613
+ /* don't print HTML */
614
+ break;
615
+ case LINK:
616
+ print_groff_mm_element_list(elt.contents.link.label);
617
+ printf(" (%s)", elt.contents.link.url);
618
+ padded = 0;
619
+ break;
620
+ case IMAGE:
621
+ printf("[IMAGE: ");;;
622
+ print_groff_mm_element_list(elt.contents.link.label);
623
+ printf("]");;;
624
+ padded = 0;
625
+ /* not supported */
626
+ break;
627
+ case EMPH:
628
+ printf("\\fI");;;
629
+ print_groff_mm_element_list(elt.children);
630
+ printf("\\fR");;;
631
+ padded = 0;
632
+ break;
633
+ case STRONG:
634
+ printf("\\fB");;;
635
+ print_groff_mm_element_list(elt.children);
636
+ printf("\\fR");;;
637
+ padded = 0;
638
+ break;
639
+ case LIST:
640
+ print_groff_mm_element_list(elt.children);
641
+ padded = 0;
642
+ break;
643
+ case RAW:
644
+ /* \001 is used to indicate boundaries between nested lists when there
645
+ * is no blank line. We split the string by \001 and parse
646
+ * each chunk separately. */
647
+ contents = strtok(elt.contents.str, "\001");
648
+ print_groff_mm_element(markdown(contents, extensions), count);
649
+ while ((contents = strtok(NULL, "\001")))
650
+ print_groff_mm_element(markdown(contents, extensions), count);
651
+ break;
652
+ case H1: case H2: case H3: case H4: case H5: case H6:
653
+ lev = elt.key - H1 + 1;
654
+ pad(1);
655
+ printf(".H %d \"", lev);
656
+ print_groff_mm_element_list(elt.children);
657
+ printf("\"");
658
+ padded = 0;
659
+ break;
660
+ case PLAIN:
661
+ pad(1);
662
+ print_groff_mm_element_list(elt.children);
663
+ padded = 0;
664
+ break;
665
+ case PARA:
666
+ pad(1);
667
+ if (!in_list_item || count != 1)
668
+ printf(".P\n");;;
669
+ print_groff_mm_element_list(elt.children);
670
+ padded = 0;
671
+ break;
672
+ case HRULE:
673
+ pad(1);
674
+ printf("\\l'\\n(.lu*8u/10u'");;;
675
+ padded = 0;
676
+ break;
677
+ case HTMLBLOCK:
678
+ /* don't print HTML block */
679
+ break;
680
+ case VERBATIM:
681
+ pad(1);
682
+ printf(".VERBON 2\n");;;
683
+ print_groff_string(elt.contents.str);
684
+ printf(".VERBOFF");;;
685
+ padded = 0;
686
+ break;
687
+ case BULLETLIST:
688
+ pad(1);
689
+ printf(".BL");;;
690
+ padded = 0;
691
+ print_groff_mm_element_list(elt.children);
692
+ pad(1);
693
+ printf(".LE 1");;;
694
+ padded = 0;
695
+ break;
696
+ case ORDEREDLIST:
697
+ pad(1);
698
+ printf(".AL");;;
699
+ padded = 0;
700
+ print_groff_mm_element_list(elt.children);
701
+ pad(1);
702
+ printf(".LE 1");;;
703
+ padded = 0;
704
+ break;
705
+ case LISTITEM:
706
+ pad(1);
707
+ printf(".LI\n");;;
708
+ in_list_item = true;
709
+ padded = 2;
710
+ print_groff_mm_element_list(elt.children);
711
+ in_list_item = false;
712
+ break;
713
+ case BLOCKQUOTE:
714
+ pad(1);
715
+ printf(".DS I\n");;;
716
+ padded = 2;
717
+ print_groff_mm_element(markdown(elt.contents.str, extensions), 1);
718
+ pad(1);
719
+ printf(".DE");;;
720
+ padded = 0;
721
+ break;
722
+ case NOTE:
723
+ /* if contents.str == 0, then print note; else ignore, since this
724
+ * is a note block that has been incorporated into the notes list */
725
+ if (elt.contents.str == 0) {
726
+ printf("\\*F\n");;;
727
+ printf(".FS\n");;;
728
+ padded = 2;
729
+ print_groff_mm_element_list(elt.children);
730
+ pad(1);
731
+ printf(".FE\n");;;
732
+ padded = 1;
733
+ }
734
+ break;
735
+ case REFERENCE:
736
+ /* Nonprinting */
737
+ break;
738
+ default:
739
+ fprintf(stderr, "print_groff_mm_element encountered unknown element key = %d\n", elt.key);
740
+ exit(EXIT_FAILURE);
741
+ }
742
+ }
743
+
744
+ /**********************************************************************
745
+
746
+ Parameterized function for printing an Element.
747
+
748
+ ***********************************************************************/
749
+
750
+ void print_element(element elt, int format) {
751
+ switch (format) {
752
+ case HTML_FORMAT:
753
+ print_html_element(elt, false);
754
+ if (endnotes != NULL) {
755
+ pad(2);
756
+ print_html_endnotes();
757
+ }
758
+ break;
759
+ case LATEX_FORMAT:
760
+ print_latex_element(elt);
761
+ break;
762
+ case GROFF_MM_FORMAT:
763
+ print_groff_mm_element(elt, 1);
764
+ break;
765
+ default:
766
+ fprintf(stderr, "print_element - unknown format = %d\n", format);
767
+ exit(EXIT_FAILURE);
768
+ }
769
+ }