rpeg-markdown 0.1.0
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/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
|
+
}
|