rpeg-markdown 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +85 -0
- data/README +14 -0
- data/Rakefile +96 -0
- data/bin/rpeg-markdown +13 -0
- data/ext/extconf.rb +6 -0
- data/ext/markdown.c +90 -0
- data/ext/markdown_buffer.c +46 -0
- data/ext/markdown_buffer.h +6 -0
- data/ext/markdown_output.c +769 -0
- data/ext/markdown_parser.c +5608 -0
- data/ext/markdown_peg.h +84 -0
- data/lib/markdown.rb +21 -0
- data/test.rb +25 -0
- metadata +66 -0
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
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,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("&");;;
|
77
|
+
break;
|
78
|
+
case '<':
|
79
|
+
printf("<");;;
|
80
|
+
break;
|
81
|
+
case '>':
|
82
|
+
printf(">");;;
|
83
|
+
break;
|
84
|
+
case '"':
|
85
|
+
printf(""");;;
|
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("…");;;
|
125
|
+
break;
|
126
|
+
case EMDASH:
|
127
|
+
printf("—");;;
|
128
|
+
break;
|
129
|
+
case ENDASH:
|
130
|
+
printf("–");;;
|
131
|
+
break;
|
132
|
+
case APOSTROPHE:
|
133
|
+
printf("’");;;
|
134
|
+
break;
|
135
|
+
case SINGLEQUOTED:
|
136
|
+
printf("‘");;;
|
137
|
+
print_html_element_list(elt.children, obfuscate);
|
138
|
+
printf("’");;;
|
139
|
+
break;
|
140
|
+
case DOUBLEQUOTED:
|
141
|
+
printf("“");;;
|
142
|
+
print_html_element_list(elt.children, obfuscate);
|
143
|
+
printf("”");;;
|
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
|
+
}
|