parkdown-libertree 1.4.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +68 -0
  3. data/README.markdown +86 -0
  4. data/Rakefile +170 -0
  5. data/bin/parkdown +13 -0
  6. data/ext/extconf.h +3 -0
  7. data/ext/extconf.rb +15 -0
  8. data/ext/markdown.c +104 -0
  9. data/ext/markdown_lib.c +186 -0
  10. data/ext/markdown_lib.h +44 -0
  11. data/ext/markdown_output.c +1275 -0
  12. data/ext/markdown_parser.c +7275 -0
  13. data/ext/markdown_peg.h +90 -0
  14. data/ext/parsing_functions.c +128 -0
  15. data/ext/utility_functions.c +217 -0
  16. data/lib/markdown.rb +1 -0
  17. data/lib/peg_markdown.rb +104 -0
  18. data/test/MarkdownTest_1.0/MarkdownTest.pl +157 -0
  19. data/test/MarkdownTest_1.0/Tests/Amps and angle encoding.html +17 -0
  20. data/test/MarkdownTest_1.0/Tests/Amps and angle encoding.text +21 -0
  21. data/test/MarkdownTest_1.0/Tests/Auto links.html +18 -0
  22. data/test/MarkdownTest_1.0/Tests/Auto links.text +13 -0
  23. data/test/MarkdownTest_1.0/Tests/Backslash escapes.html +102 -0
  24. data/test/MarkdownTest_1.0/Tests/Backslash escapes.text +104 -0
  25. data/test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.html +15 -0
  26. data/test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.text +11 -0
  27. data/test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.html +8 -0
  28. data/test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.text +8 -0
  29. data/test/MarkdownTest_1.0/Tests/Horizontal rules.html +71 -0
  30. data/test/MarkdownTest_1.0/Tests/Horizontal rules.text +67 -0
  31. data/test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).html +14 -0
  32. data/test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).text +14 -0
  33. data/test/MarkdownTest_1.0/Tests/Inline HTML (Simple).html +72 -0
  34. data/test/MarkdownTest_1.0/Tests/Inline HTML (Simple).text +69 -0
  35. data/test/MarkdownTest_1.0/Tests/Inline HTML comments.html +13 -0
  36. data/test/MarkdownTest_1.0/Tests/Inline HTML comments.text +13 -0
  37. data/test/MarkdownTest_1.0/Tests/Links, inline style.html +9 -0
  38. data/test/MarkdownTest_1.0/Tests/Links, inline style.text +9 -0
  39. data/test/MarkdownTest_1.0/Tests/Links, reference style.html +18 -0
  40. data/test/MarkdownTest_1.0/Tests/Links, reference style.text +31 -0
  41. data/test/MarkdownTest_1.0/Tests/Literal quotes in titles.html +3 -0
  42. data/test/MarkdownTest_1.0/Tests/Literal quotes in titles.text +7 -0
  43. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Basics.html +314 -0
  44. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Basics.text +306 -0
  45. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Syntax.html +942 -0
  46. data/test/MarkdownTest_1.0/Tests/Markdown Documentation - Syntax.text +888 -0
  47. data/test/MarkdownTest_1.0/Tests/Nested blockquotes.html +9 -0
  48. data/test/MarkdownTest_1.0/Tests/Nested blockquotes.text +5 -0
  49. data/test/MarkdownTest_1.0/Tests/Ordered and unordered lists.html +137 -0
  50. data/test/MarkdownTest_1.0/Tests/Ordered and unordered lists.text +122 -0
  51. data/test/MarkdownTest_1.0/Tests/Strong and em together.html +7 -0
  52. data/test/MarkdownTest_1.0/Tests/Strong and em together.text +7 -0
  53. data/test/MarkdownTest_1.0/Tests/Tabs.html +25 -0
  54. data/test/MarkdownTest_1.0/Tests/Tabs.text +21 -0
  55. data/test/MarkdownTest_1.0/Tests/Tidyness.html +8 -0
  56. data/test/MarkdownTest_1.0/Tests/Tidyness.text +5 -0
  57. data/test/MarkdownTest_1.0.3/MarkdownTest.pl +176 -0
  58. data/test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.html +17 -0
  59. data/test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.text +21 -0
  60. data/test/MarkdownTest_1.0.3/Tests/Auto links.html +18 -0
  61. data/test/MarkdownTest_1.0.3/Tests/Auto links.text +13 -0
  62. data/test/MarkdownTest_1.0.3/Tests/Backslash escapes.html +118 -0
  63. data/test/MarkdownTest_1.0.3/Tests/Backslash escapes.text +120 -0
  64. data/test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html +15 -0
  65. data/test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text +11 -0
  66. data/test/MarkdownTest_1.0.3/Tests/Code Blocks.html +18 -0
  67. data/test/MarkdownTest_1.0.3/Tests/Code Blocks.text +14 -0
  68. data/test/MarkdownTest_1.0.3/Tests/Code Spans.html +6 -0
  69. data/test/MarkdownTest_1.0.3/Tests/Code Spans.text +6 -0
  70. data/test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html +8 -0
  71. data/test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text +8 -0
  72. data/test/MarkdownTest_1.0.3/Tests/Horizontal rules.html +71 -0
  73. data/test/MarkdownTest_1.0.3/Tests/Horizontal rules.text +67 -0
  74. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html +15 -0
  75. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text +15 -0
  76. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html +72 -0
  77. data/test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text +69 -0
  78. data/test/MarkdownTest_1.0.3/Tests/Inline HTML comments.html +13 -0
  79. data/test/MarkdownTest_1.0.3/Tests/Inline HTML comments.text +13 -0
  80. data/test/MarkdownTest_1.0.3/Tests/Links, inline style.html +11 -0
  81. data/test/MarkdownTest_1.0.3/Tests/Links, inline style.text +12 -0
  82. data/test/MarkdownTest_1.0.3/Tests/Links, reference style.html +52 -0
  83. data/test/MarkdownTest_1.0.3/Tests/Links, reference style.text +71 -0
  84. data/test/MarkdownTest_1.0.3/Tests/Links, shortcut references.html +9 -0
  85. data/test/MarkdownTest_1.0.3/Tests/Links, shortcut references.text +20 -0
  86. data/test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.html +3 -0
  87. data/test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.text +7 -0
  88. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.html +314 -0
  89. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Basics.text +306 -0
  90. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.html +942 -0
  91. data/test/MarkdownTest_1.0.3/Tests/Markdown Documentation - Syntax.text +888 -0
  92. data/test/MarkdownTest_1.0.3/Tests/Nested blockquotes.html +9 -0
  93. data/test/MarkdownTest_1.0.3/Tests/Nested blockquotes.text +5 -0
  94. data/test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html +148 -0
  95. data/test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text +131 -0
  96. data/test/MarkdownTest_1.0.3/Tests/Strong and em together.html +7 -0
  97. data/test/MarkdownTest_1.0.3/Tests/Strong and em together.text +7 -0
  98. data/test/MarkdownTest_1.0.3/Tests/Tabs.html +25 -0
  99. data/test/MarkdownTest_1.0.3/Tests/Tabs.text +21 -0
  100. data/test/MarkdownTest_1.0.3/Tests/Tidyness.html +8 -0
  101. data/test/MarkdownTest_1.0.3/Tests/Tidyness.text +5 -0
  102. data/test/benchmark.rb +49 -0
  103. data/test/markdown_test.rb +84 -0
  104. metadata +150 -0
@@ -0,0 +1,186 @@
1
+ /**********************************************************************
2
+
3
+ markdown_lib.c - markdown in C using a PEG grammar.
4
+ (c) 2008 John MacFarlane (jgm at berkeley dot edu).
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 or the MIT
8
+ license. See LICENSE for details.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ ***********************************************************************/
16
+
17
+ #include <stdio.h>
18
+ #include <stdlib.h>
19
+ #include <string.h>
20
+ #include "markdown_peg.h"
21
+
22
+ #define TABSTOP 4
23
+
24
+ /* preformat_text - allocate and copy text buffer while
25
+ * performing tab expansion. */
26
+ static GString *preformat_text(char *text) {
27
+ GString *buf;
28
+ char next_char;
29
+ int charstotab;
30
+
31
+ int len = 0;
32
+
33
+ buf = g_string_new("");
34
+
35
+ charstotab = TABSTOP;
36
+ while ((next_char = *text++) != '\0') {
37
+ switch (next_char) {
38
+ case '\t':
39
+ while (charstotab > 0)
40
+ g_string_append_c(buf, ' '), len++, charstotab--;
41
+ break;
42
+ case '\n':
43
+ g_string_append_c(buf, '\n'), len++, charstotab = TABSTOP;
44
+ break;
45
+ default:
46
+ g_string_append_c(buf, next_char), len++, charstotab--;
47
+ }
48
+ if (charstotab == 0)
49
+ charstotab = TABSTOP;
50
+ }
51
+ g_string_append(buf, "\n\n");
52
+ return(buf);
53
+ }
54
+
55
+ /* print_tree - print tree of elements, for debugging only. */
56
+ static void print_tree(element * elt, int indent) {
57
+ int i;
58
+ char * key;
59
+ while (elt != NULL) {
60
+ for (i = 0; i < indent; i++)
61
+ fputc(' ', stderr);
62
+ switch (elt->key) {
63
+ case LIST: key = "LIST"; break;
64
+ case RAW: key = "RAW"; break;
65
+ case SPACE: key = "SPACE"; break;
66
+ case LINEBREAK: key = "LINEBREAK"; break;
67
+ case ELLIPSIS: key = "ELLIPSIS"; break;
68
+ case EMDASH: key = "EMDASH"; break;
69
+ case ENDASH: key = "ENDASH"; break;
70
+ case APOSTROPHE: key = "APOSTROPHE"; break;
71
+ case SINGLEQUOTED: key = "SINGLEQUOTED"; break;
72
+ case DOUBLEQUOTED: key = "DOUBLEQUOTED"; break;
73
+ case STR: key = "STR"; break;
74
+ case LINK: key = "LINK"; break;
75
+ case IMAGE: key = "IMAGE"; break;
76
+ case AUDIO: key = "AUDIO"; break;
77
+ case VIDEO: key = "VIDEO"; break;
78
+ case CODE: key = "CODE"; break;
79
+ case HTML: key = "HTML"; break;
80
+ case EMPH: key = "EMPH"; break;
81
+ case STRONG: key = "STRONG"; break;
82
+ case PLAIN: key = "PLAIN"; break;
83
+ case PARA: key = "PARA"; break;
84
+ case LISTITEM: key = "LISTITEM"; break;
85
+ case BULLETLIST: key = "BULLETLIST"; break;
86
+ case ORDEREDLIST: key = "ORDEREDLIST"; break;
87
+ case H1: key = "H1"; break;
88
+ case H2: key = "H2"; break;
89
+ case H3: key = "H3"; break;
90
+ case H4: key = "H4"; break;
91
+ case H5: key = "H5"; break;
92
+ case H6: key = "H6"; break;
93
+ case BLOCKQUOTE: key = "BLOCKQUOTE"; break;
94
+ case SPOILERBLOCK: key = "SPOILERBLOCK"; break;
95
+ case VERBATIM: key = "VERBATIM"; break;
96
+ case HTMLBLOCK: key = "HTMLBLOCK"; break;
97
+ case HRULE: key = "HRULE"; break;
98
+ case REFERENCE: key = "REFERENCE"; break;
99
+ case NOTE: key = "NOTE"; break;
100
+ case HASHTAG: key = "HASHTAG"; break;
101
+ case USERNAME: key = "USERNAME"; break;
102
+ default: key = "?";
103
+ }
104
+ if ( elt->key == STR ) {
105
+ fprintf(stderr, "0x%p: %s '%s'\n", (void *)elt, key, elt->contents.str);
106
+ } else {
107
+ fprintf(stderr, "0x%p: %s\n", (void *)elt, key);
108
+ }
109
+ if (elt->children)
110
+ print_tree(elt->children, indent + 4);
111
+ elt = elt->next;
112
+ }
113
+ }
114
+
115
+ /* process_raw_blocks - traverses an element list, replacing any RAW elements with
116
+ * the result of parsing them as markdown text, and recursing into the children
117
+ * of parent elements. The result should be a tree of elements without any RAWs. */
118
+ static element * process_raw_blocks(element *input, int extensions, element *references, element *notes) {
119
+ element *current = NULL;
120
+ element *last_child = NULL;
121
+ char *contents;
122
+ current = input;
123
+
124
+ while (current != NULL) {
125
+ if (current->key == RAW) {
126
+ /* \001 is used to indicate boundaries between nested lists when there
127
+ * is no blank line. We split the string by \001 and parse
128
+ * each chunk separately. */
129
+ contents = strtok(current->contents.str, "\001");
130
+ current->key = LIST;
131
+ current->children = parse_markdown(contents, extensions, references, notes);
132
+ last_child = current->children;
133
+ while ((contents = strtok(NULL, "\001"))) {
134
+ while (last_child->next != NULL)
135
+ last_child = last_child->next;
136
+ last_child->next = parse_markdown(contents, extensions, references, notes);
137
+ }
138
+ free(current->contents.str);
139
+ current->contents.str = NULL;
140
+ }
141
+ if (current->children != NULL)
142
+ current->children = process_raw_blocks(current->children, extensions, references, notes);
143
+ current = current->next;
144
+ }
145
+ return input;
146
+ }
147
+
148
+ /* markdown_to_gstring - convert markdown text to the output format specified.
149
+ * Returns a GString, which must be freed after use using g_string_free(). */
150
+ GString * markdown_to_g_string(char *text, int extensions, int output_format) {
151
+ element *result;
152
+ element *references;
153
+ element *notes;
154
+ GString *formatted_text;
155
+ GString *out;
156
+ out = g_string_new("");
157
+
158
+ formatted_text = preformat_text(text);
159
+
160
+ references = parse_references(formatted_text->str, extensions);
161
+ notes = parse_notes(formatted_text->str, extensions, references);
162
+ result = parse_markdown(formatted_text->str, extensions, references, notes);
163
+
164
+ result = process_raw_blocks(result, extensions, references, notes);
165
+
166
+ g_string_free(formatted_text, TRUE);
167
+
168
+ print_element_list(out, result, output_format, extensions);
169
+
170
+ free_element_list(result);
171
+ free_element_list(references);
172
+ return out;
173
+ }
174
+
175
+ /* markdown_to_string - convert markdown text to the output format specified.
176
+ * Returns a null-terminated string, which must be freed after use. */
177
+ char * markdown_to_string(char *text, int extensions, int output_format) {
178
+ GString *out;
179
+ char *char_out;
180
+ out = markdown_to_g_string(text, extensions, output_format);
181
+ char_out = out->str;
182
+ g_string_free(out, FALSE);
183
+ return char_out;
184
+ }
185
+
186
+ /* vim:set ts=4 sw=4: */
@@ -0,0 +1,44 @@
1
+ #ifndef MARKDOWN_LIB_H
2
+ #define MARKDOWN_LIB_H
3
+
4
+ #include <stdlib.h>
5
+ #include <stdio.h>
6
+ #include <glib.h>
7
+
8
+ #ifdef __cplusplus
9
+ extern "C" {
10
+ #endif
11
+
12
+ enum markdown_extensions {
13
+ EXT_SMART = 0x0001,
14
+ EXT_NOTES = 0x0002,
15
+ EXT_FILTER_HTML = 0x0004,
16
+ EXT_FILTER_STYLES = 0x0008,
17
+ EXT_STRIKE = 0x0010,
18
+ EXT_AUTOLINK = 0x0020,
19
+ EXT_HARD_WRAP = 0x0040,
20
+ EXT_NO_IMAGES = 0x0080,
21
+ EXT_MEDIA = 0x0100,
22
+ EXT_CODEBLOCK = 0x0200,
23
+ EXT_HASHTAGS = 0x0400,
24
+ EXT_USERNAMES = 0x0800,
25
+ EXT_SPOILERBLOCK = 0x1000,
26
+ };
27
+
28
+ enum markdown_formats {
29
+ HTML_FORMAT,
30
+ LATEX_FORMAT,
31
+ GROFF_MM_FORMAT,
32
+ ODF_FORMAT
33
+ };
34
+
35
+ GString * markdown_to_g_string(char *text, int extensions, int output_format);
36
+ char * markdown_to_string(char *text, int extensions, int output_format);
37
+
38
+ #ifdef __cplusplus
39
+ }
40
+ #endif
41
+
42
+ /* vim: set ts=4 sw=4 : */
43
+ #endif
44
+
@@ -0,0 +1,1275 @@
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 or the MIT
9
+ license. See LICENSE for details.
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 <glib.h>
24
+ #include "markdown_peg.h"
25
+ #include "odf.h"
26
+
27
+ static int extensions;
28
+ static int odf_type = 0;
29
+
30
+ static void print_html_string(GString *out, char *str, bool obfuscate);
31
+ static void print_html_element_list(GString *out, element *list, bool obfuscate);
32
+ static void print_html_element(GString *out, element *elt, bool obfuscate);
33
+ static void print_latex_string(GString *out, char *str);
34
+ static void print_latex_element_list(GString *out, element *list);
35
+ static void print_latex_element(GString *out, element *elt);
36
+ static void print_groff_string(GString *out, char *str);
37
+ static void print_groff_mm_element_list(GString *out, element *list);
38
+ static void print_groff_mm_element(GString *out, element *elt, int count);
39
+ static void print_odf_code_string(GString *out, char *str);
40
+ static void print_odf_string(GString *out, char *str);
41
+ static void print_odf_element_list(GString *out, element *list);
42
+ static void print_odf_element(GString *out, element *elt);
43
+ static bool list_contains_key(element *list, int key);
44
+
45
+ /**********************************************************************
46
+
47
+ Utility functions for printing
48
+
49
+ ***********************************************************************/
50
+
51
+ static int padded = 2; /* Number of newlines after last output.
52
+ Starts at 2 so no newlines are needed at start.
53
+ */
54
+
55
+ static GSList *endnotes = NULL; /* List of endnotes to print after main content. */
56
+ static int notenumber = 0; /* Number of footnote. */
57
+
58
+ /* pad - add newlines if needed */
59
+ static void pad(GString *out, int num) {
60
+ while (num-- > padded)
61
+ g_string_append_printf(out, "\n");;
62
+ padded = num;
63
+ }
64
+
65
+ /* determine whether a certain element is contained within a given list */
66
+ static bool list_contains_key(element *list, int key) {
67
+ element *step = NULL;
68
+
69
+ step = list;
70
+ while ( step != NULL ) {
71
+ if (step->key == key) {
72
+ return TRUE;
73
+ }
74
+ if (step->children != NULL) {
75
+ if (list_contains_key(step->children, key)) {
76
+ return TRUE;
77
+ }
78
+ }
79
+ step = step->next;
80
+ }
81
+ return FALSE;
82
+ }
83
+
84
+ /**********************************************************************
85
+
86
+ Functions for printing Elements as HTML
87
+
88
+ ***********************************************************************/
89
+
90
+ /* print_html_string - print string, escaping for HTML
91
+ * If obfuscate selected, convert characters to hex or decimal entities at random */
92
+ static void print_html_string(GString *out, char *str, bool obfuscate) {
93
+ while (*str != '\0') {
94
+ switch (*str) {
95
+ case '&':
96
+ g_string_append_printf(out, "&amp;");
97
+ break;
98
+ case '<':
99
+ g_string_append_printf(out, "&lt;");
100
+ break;
101
+ case '>':
102
+ g_string_append_printf(out, "&gt;");
103
+ break;
104
+ case '"':
105
+ g_string_append_printf(out, "&quot;");
106
+ break;
107
+ default:
108
+ if (obfuscate && ((int) *str < 128) && ((int) *str >= 0)){
109
+ if (rand() % 2 == 0)
110
+ g_string_append_printf(out, "&#%d;", (int) *str);
111
+ else
112
+ g_string_append_printf(out, "&#x%x;", (unsigned int) *str);
113
+ }
114
+ else
115
+ g_string_append_c(out, *str);
116
+ }
117
+ str++;
118
+ }
119
+ }
120
+
121
+ /* print_html_element_list - print a list of elements as HTML */
122
+ static void print_html_element_list(GString *out, element *list, bool obfuscate) {
123
+ while (list != NULL) {
124
+ print_html_element(out, list, obfuscate);
125
+ list = list->next;
126
+ }
127
+ }
128
+
129
+ /* add_endnote - add an endnote to global endnotes list. */
130
+ static void add_endnote(element *elt) {
131
+ endnotes = g_slist_prepend(endnotes, elt);
132
+ }
133
+
134
+ /* print_html_element - print an element as HTML */
135
+ static void print_html_element(GString *out, element *elt, bool obfuscate) {
136
+ int lev;
137
+ switch (elt->key) {
138
+ case SPACE:
139
+ g_string_append_printf(out, "%s", elt->contents.str);
140
+ break;
141
+ case LINEBREAK:
142
+ g_string_append_printf(out, "<br/>\n");
143
+ break;
144
+ case STR:
145
+ print_html_string(out, elt->contents.str, obfuscate);
146
+ break;
147
+ case ELLIPSIS:
148
+ g_string_append_printf(out, "&hellip;");
149
+ break;
150
+ case EMDASH:
151
+ g_string_append_printf(out, "&mdash;");
152
+ break;
153
+ case ENDASH:
154
+ g_string_append_printf(out, "&ndash;");
155
+ break;
156
+ case ENSPACE:
157
+ g_string_append_printf(out, "&ensp;");
158
+ break;
159
+ case APOSTROPHE:
160
+ g_string_append_printf(out, "&rsquo;");
161
+ break;
162
+ case SINGLEQUOTED:
163
+ g_string_append_printf(out, "&lsquo;");
164
+ print_html_element_list(out, elt->children, obfuscate);
165
+ g_string_append_printf(out, "&rsquo;");
166
+ break;
167
+ case DOUBLEQUOTED:
168
+ g_string_append_printf(out, "&ldquo;");
169
+ print_html_element_list(out, elt->children, obfuscate);
170
+ g_string_append_printf(out, "&rdquo;");
171
+ break;
172
+ case CODE:
173
+ g_string_append_printf(out, "<code>");
174
+ print_html_string(out, elt->contents.str, obfuscate);
175
+ g_string_append_printf(out, "</code>");
176
+ break;
177
+ case HTML:
178
+ g_string_append_printf(out, "%s", elt->contents.str);
179
+ break;
180
+ case HASHTAG:
181
+ g_string_append_printf(out, "<span rel='hashtag'>%s</span>", elt->contents.str);
182
+ break;
183
+ case USERNAME:
184
+ g_string_append_printf(out, "<span rel='username'>%s</span>", elt->contents.str);
185
+ break;
186
+ case LINK:
187
+ if (strstr(elt->contents.link->url, "mailto:") == elt->contents.link->url)
188
+ obfuscate = true; /* obfuscate mailto: links */
189
+ g_string_append_printf(out, "<a href=\"");
190
+ print_html_string(out, elt->contents.link->url, obfuscate);
191
+ g_string_append_printf(out, "\"");
192
+ if (strlen(elt->contents.link->title) > 0) {
193
+ g_string_append_printf(out, " title=\"");
194
+ print_html_string(out, elt->contents.link->title, obfuscate);
195
+ g_string_append_printf(out, "\"");
196
+ }
197
+ g_string_append_printf(out, ">");
198
+ print_html_element_list(out, elt->contents.link->label, obfuscate);
199
+ g_string_append_printf(out, "</a>");
200
+ break;
201
+ case IMAGE:
202
+ g_string_append_printf(out, "<img src=\"");
203
+ print_html_string(out, elt->contents.link->url, obfuscate);
204
+ g_string_append_printf(out, "\" alt=\"");
205
+ print_html_element_list(out, elt->contents.link->label, obfuscate);
206
+ g_string_append_printf(out, "\"");
207
+ if (strlen(elt->contents.link->title) > 0) {
208
+ g_string_append_printf(out, " title=\"");
209
+ print_html_string(out, elt->contents.link->title, obfuscate);
210
+ g_string_append_printf(out, "\"");
211
+ }
212
+ g_string_append_printf(out, " />");
213
+ break;
214
+ case AUDIO:
215
+ pad(out, 2);
216
+ g_string_append_printf(out, "<audio controls=\"true\">\n");
217
+ g_string_append_printf(out, " <source src=\"");
218
+ print_html_string(out, elt->contents.media->source1, obfuscate);
219
+ g_string_append_printf(out, "\" />\n");
220
+ if (strcmp(elt->contents.media->source2, "")) {
221
+ g_string_append_printf(out, " <source src=\"");
222
+ print_html_string(out, elt->contents.media->source2, obfuscate);
223
+ g_string_append_printf(out, "\" />\n");
224
+ }
225
+ g_string_append_printf(out, "</audio>\n");
226
+ g_string_append_printf(out, "<div class=\"audio-file-title\">");
227
+ print_html_element_list(out, elt->contents.link->label, obfuscate);
228
+ g_string_append_printf(out, "</div>");
229
+ padded = 0;
230
+ break;
231
+ case VIDEO:
232
+ pad(out, 2);
233
+ g_string_append_printf(out, "<video controls=\"true\">\n");
234
+ g_string_append_printf(out, " <source src=\"");
235
+ print_html_string(out, elt->contents.media->source1, obfuscate);
236
+ g_string_append_printf(out, "\" />\n");
237
+ if (strcmp(elt->contents.media->source2, "")) {
238
+ g_string_append_printf(out, " <source src=\"");
239
+ print_html_string(out, elt->contents.media->source2, obfuscate);
240
+ g_string_append_printf(out, "\" />\n");
241
+ }
242
+ g_string_append_printf(out, "</video>\n");
243
+ g_string_append_printf(out, "<div class=\"video-file-title\">");
244
+ print_html_element_list(out, elt->contents.link->label, obfuscate);
245
+ g_string_append_printf(out, "</div>");
246
+ padded = 0;
247
+ break;
248
+ case EMPH:
249
+ g_string_append_printf(out, "<em>");
250
+ print_html_element_list(out, elt->children, obfuscate);
251
+ g_string_append_printf(out, "</em>");
252
+ break;
253
+ case STRONG:
254
+ g_string_append_printf(out, "<strong>");
255
+ print_html_element_list(out, elt->children, obfuscate);
256
+ g_string_append_printf(out, "</strong>");
257
+ break;
258
+ case STRIKE:
259
+ g_string_append_printf(out, "<del>");
260
+ print_html_element_list(out, elt->children, obfuscate);
261
+ g_string_append_printf(out, "</del>");
262
+ break;
263
+ case LIST:
264
+ print_html_element_list(out, elt->children, obfuscate);
265
+ break;
266
+ case RAW:
267
+ /* Shouldn't occur - these are handled by process_raw_blocks() */
268
+ assert(elt->key != RAW);
269
+ break;
270
+ case H1: case H2: case H3: case H4: case H5: case H6:
271
+ lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
272
+ pad(out, 2);
273
+ g_string_append_printf(out, "<h%1d>", lev);
274
+ print_html_element_list(out, elt->children, obfuscate);
275
+ g_string_append_printf(out, "</h%1d>", lev);
276
+ padded = 0;
277
+ break;
278
+ case PLAIN:
279
+ pad(out, 1);
280
+ print_html_element_list(out, elt->children, obfuscate);
281
+ padded = 0;
282
+ break;
283
+ case PARA:
284
+ pad(out, 2);
285
+ g_string_append_printf(out, "<p>");
286
+ print_html_element_list(out, elt->children, obfuscate);
287
+ g_string_append_printf(out, "</p>");
288
+ padded = 0;
289
+ break;
290
+ case HRULE:
291
+ pad(out, 2);
292
+ g_string_append_printf(out, "<hr />");
293
+ padded = 0;
294
+ break;
295
+ case HTMLBLOCK:
296
+ pad(out, 2);
297
+ g_string_append_printf(out, "%s", elt->contents.str);
298
+ padded = 0;
299
+ break;
300
+ case VERBATIM:
301
+ pad(out, 2);
302
+ g_string_append_printf(out, "%s", "<pre><code>");
303
+ print_html_string(out, elt->contents.str, obfuscate);
304
+ g_string_append_printf(out, "%s", "</code></pre>");
305
+ padded = 0;
306
+ break;
307
+ case BULLETLIST:
308
+ pad(out, 2);
309
+ g_string_append_printf(out, "%s", "<ul>");
310
+ padded = 0;
311
+ print_html_element_list(out, elt->children, obfuscate);
312
+ pad(out, 1);
313
+ g_string_append_printf(out, "%s", "</ul>");
314
+ padded = 0;
315
+ break;
316
+ case ORDEREDLIST:
317
+ pad(out, 2);
318
+ g_string_append_printf(out, "%s", "<ol>");
319
+ padded = 0;
320
+ print_html_element_list(out, elt->children, obfuscate);
321
+ pad(out, 1);
322
+ g_string_append_printf(out, "</ol>");
323
+ padded = 0;
324
+ break;
325
+ case LISTITEM:
326
+ pad(out, 1);
327
+ g_string_append_printf(out, "<li>");
328
+ padded = 2;
329
+ print_html_element_list(out, elt->children, obfuscate);
330
+ g_string_append_printf(out, "</li>");
331
+ padded = 0;
332
+ break;
333
+ case BLOCKQUOTE:
334
+ pad(out, 2);
335
+ g_string_append_printf(out, "<blockquote>\n");
336
+ padded = 2;
337
+ print_html_element_list(out, elt->children, obfuscate);
338
+ pad(out, 1);
339
+ g_string_append_printf(out, "</blockquote>");
340
+ padded = 0;
341
+ break;
342
+ case SPOILERBLOCK:
343
+ pad(out, 2);
344
+ g_string_append_printf(out, "<div class='spoilers'>\n");
345
+ padded = 2;
346
+ print_html_element_list(out, elt->children, obfuscate);
347
+ pad(out, 1);
348
+ g_string_append_printf(out, "</div>");
349
+ padded = 0;
350
+ break;
351
+ case REFERENCE:
352
+ /* Nonprinting */
353
+ break;
354
+ case NOTE:
355
+ /* if contents.str == 0, then print note; else ignore, since this
356
+ * is a note block that has been incorporated into the notes list */
357
+ if (elt->contents.str == 0) {
358
+ add_endnote(elt);
359
+ ++notenumber;
360
+ g_string_append_printf(out, "<a class=\"noteref\" id=\"fnref%d\" href=\"#fn%d\" title=\"Jump to note %d\">[%d]</a>",
361
+ notenumber, notenumber, notenumber, notenumber);
362
+ }
363
+ break;
364
+ default:
365
+ fprintf(stderr, "print_html_element encountered unknown element key = %d\n", elt->key);
366
+ exit(EXIT_FAILURE);
367
+ }
368
+ }
369
+
370
+ static void print_html_endnotes(GString *out) {
371
+ int counter = 0;
372
+ GSList *note;
373
+ element *note_elt;
374
+ if (endnotes == NULL)
375
+ return;
376
+ note = g_slist_reverse(endnotes);
377
+ g_string_append_printf(out, "<hr/>\n<ol id=\"notes\">");
378
+ while (note != NULL) {
379
+ note_elt = note->data;
380
+ counter++;
381
+ pad(out, 1);
382
+ g_string_append_printf(out, "<li id=\"fn%d\">\n", counter);
383
+ padded = 2;
384
+ print_html_element_list(out, note_elt->children, false);
385
+ g_string_append_printf(out, " <a href=\"#fnref%d\" title=\"Jump back to reference\">[⤴]</a>", counter);
386
+ pad(out, 1);
387
+ g_string_append_printf(out, "</li>");
388
+ note = note->next;
389
+ }
390
+ pad(out, 1);
391
+ g_string_append_printf(out, "</ol>");
392
+ g_slist_free(endnotes);
393
+ }
394
+
395
+ /**********************************************************************
396
+
397
+ Functions for printing Elements as LaTeX
398
+
399
+ ***********************************************************************/
400
+
401
+ /* print_latex_string - print string, escaping for LaTeX */
402
+ static void print_latex_string(GString *out, char *str) {
403
+ while (*str != '\0') {
404
+ switch (*str) {
405
+ case '{': case '}': case '$': case '%':
406
+ case '&': case '_': case '#':
407
+ g_string_append_printf(out, "\\%c", *str);
408
+ break;
409
+ case '^':
410
+ g_string_append_printf(out, "\\^{}");
411
+ break;
412
+ case '\\':
413
+ g_string_append_printf(out, "\\textbackslash{}");
414
+ break;
415
+ case '~':
416
+ g_string_append_printf(out, "\\ensuremath{\\sim}");
417
+ break;
418
+ case '|':
419
+ g_string_append_printf(out, "\\textbar{}");
420
+ break;
421
+ case '<':
422
+ g_string_append_printf(out, "\\textless{}");
423
+ break;
424
+ case '>':
425
+ g_string_append_printf(out, "\\textgreater{}");
426
+ break;
427
+ default:
428
+ g_string_append_c(out, *str);
429
+ }
430
+ str++;
431
+ }
432
+ }
433
+
434
+ /* print_latex_element_list - print a list of elements as LaTeX */
435
+ static void print_latex_element_list(GString *out, element *list) {
436
+ while (list != NULL) {
437
+ print_latex_element(out, list);
438
+ list = list->next;
439
+ }
440
+ }
441
+
442
+ /* print_latex_element - print an element as LaTeX */
443
+ static void print_latex_element(GString *out, element *elt) {
444
+ int lev;
445
+ int i;
446
+ switch (elt->key) {
447
+ case SPACE:
448
+ g_string_append_printf(out, "%s", elt->contents.str);
449
+ break;
450
+ case LINEBREAK:
451
+ g_string_append_printf(out, "\\\\\n");
452
+ break;
453
+ case STR:
454
+ print_latex_string(out, elt->contents.str);
455
+ break;
456
+ case ELLIPSIS:
457
+ g_string_append_printf(out, "\\ldots{}");
458
+ break;
459
+ case EMDASH:
460
+ g_string_append_printf(out, "---");
461
+ break;
462
+ case ENDASH:
463
+ g_string_append_printf(out, "--");
464
+ break;
465
+ case ENSPACE:
466
+ g_string_append_printf(out, " ");
467
+ break;
468
+ case APOSTROPHE:
469
+ g_string_append_printf(out, "'");
470
+ break;
471
+ case SINGLEQUOTED:
472
+ g_string_append_printf(out, "`");
473
+ print_latex_element_list(out, elt->children);
474
+ g_string_append_printf(out, "'");
475
+ break;
476
+ case DOUBLEQUOTED:
477
+ g_string_append_printf(out, "``");
478
+ print_latex_element_list(out, elt->children);
479
+ g_string_append_printf(out, "''");
480
+ break;
481
+ case CODE:
482
+ g_string_append_printf(out, "\\texttt{");
483
+ print_latex_string(out, elt->contents.str);
484
+ g_string_append_printf(out, "}");
485
+ break;
486
+ case HTML:
487
+ /* don't print HTML */
488
+ break;
489
+ case LINK:
490
+ g_string_append_printf(out, "\\href{%s}{", elt->contents.link->url);
491
+ print_latex_element_list(out, elt->contents.link->label);
492
+ g_string_append_printf(out, "}");
493
+ break;
494
+ case IMAGE:
495
+ g_string_append_printf(out, "\\includegraphics{%s}", elt->contents.link->url);
496
+ break;
497
+ case AUDIO:
498
+ g_string_append_printf(out, "\n\n[AUDIO: {%s}]", elt->contents.media->source1);
499
+ padded = 0;
500
+ /* not supported */
501
+ break;
502
+ case VIDEO:
503
+ pad(out, 2);
504
+ g_string_append_printf(out, "\n\n[VIDEO: {%s}]", elt->contents.media->source1);
505
+ padded = 0;
506
+ /* not supported */
507
+ break;
508
+ case EMPH:
509
+ g_string_append_printf(out, "\\emph{");
510
+ print_latex_element_list(out, elt->children);
511
+ g_string_append_printf(out, "}");
512
+ break;
513
+ case STRONG:
514
+ g_string_append_printf(out, "\\textbf{");
515
+ print_latex_element_list(out, elt->children);
516
+ g_string_append_printf(out, "}");
517
+ break;
518
+ case STRIKE:
519
+ g_string_append_printf(out, "\\sout{");
520
+ print_latex_element_list(out, elt->children);
521
+ g_string_append_printf(out, "}");
522
+ break;
523
+ case LIST:
524
+ print_latex_element_list(out, elt->children);
525
+ break;
526
+ case RAW:
527
+ /* Shouldn't occur - these are handled by process_raw_blocks() */
528
+ assert(elt->key != RAW);
529
+ break;
530
+ case H1: case H2: case H3:
531
+ pad(out, 2);
532
+ lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
533
+ g_string_append_printf(out, "\\");
534
+ for (i = elt->key; i > H1; i--)
535
+ g_string_append_printf(out, "sub");
536
+ g_string_append_printf(out, "section{");
537
+ print_latex_element_list(out, elt->children);
538
+ g_string_append_printf(out, "}");
539
+ padded = 0;
540
+ break;
541
+ case H4: case H5: case H6:
542
+ pad(out, 2);
543
+ g_string_append_printf(out, "\\noindent\\textbf{");
544
+ print_latex_element_list(out, elt->children);
545
+ g_string_append_printf(out, "}");
546
+ padded = 0;
547
+ break;
548
+ case PLAIN:
549
+ pad(out, 1);
550
+ print_latex_element_list(out, elt->children);
551
+ padded = 0;
552
+ break;
553
+ case PARA:
554
+ pad(out, 2);
555
+ print_latex_element_list(out, elt->children);
556
+ padded = 0;
557
+ break;
558
+ case HRULE:
559
+ pad(out, 2);
560
+ g_string_append_printf(out, "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n");
561
+ padded = 0;
562
+ break;
563
+ case HTMLBLOCK:
564
+ /* don't print HTML block */
565
+ break;
566
+ case HASHTAG:
567
+ print_latex_string(out, elt->contents.str);
568
+ break;
569
+ case USERNAME:
570
+ print_latex_string(out, elt->contents.str);
571
+ break;
572
+ case VERBATIM:
573
+ pad(out, 1);
574
+ g_string_append_printf(out, "\\begin{verbatim}\n");
575
+ print_latex_string(out, elt->contents.str);
576
+ g_string_append_printf(out, "\n\\end{verbatim}");
577
+ padded = 0;
578
+ break;
579
+ case BULLETLIST:
580
+ pad(out, 1);
581
+ g_string_append_printf(out, "\\begin{itemize}");
582
+ padded = 0;
583
+ print_latex_element_list(out, elt->children);
584
+ pad(out, 1);
585
+ g_string_append_printf(out, "\\end{itemize}");
586
+ padded = 0;
587
+ break;
588
+ case ORDEREDLIST:
589
+ pad(out, 1);
590
+ g_string_append_printf(out, "\\begin{enumerate}");
591
+ padded = 0;
592
+ print_latex_element_list(out, elt->children);
593
+ pad(out, 1);
594
+ g_string_append_printf(out, "\\end{enumerate}");
595
+ padded = 0;
596
+ break;
597
+ case LISTITEM:
598
+ pad(out, 1);
599
+ g_string_append_printf(out, "\\item ");
600
+ padded = 2;
601
+ print_latex_element_list(out, elt->children);
602
+ g_string_append_printf(out, "\n");
603
+ break;
604
+ case BLOCKQUOTE:
605
+ pad(out, 1);
606
+ g_string_append_printf(out, "\\begin{quote}");
607
+ padded = 0;
608
+ print_latex_element_list(out, elt->children);
609
+ pad(out, 1);
610
+ g_string_append_printf(out, "\\end{quote}");
611
+ padded = 0;
612
+ break;
613
+ case SPOILERBLOCK:
614
+ pad(out, 1);
615
+ print_latex_element_list(out, elt->children);
616
+ padded = 0;
617
+ break;
618
+ case NOTE:
619
+ /* if contents.str == 0, then print note; else ignore, since this
620
+ * is a note block that has been incorporated into the notes list */
621
+ if (elt->contents.str == 0) {
622
+ g_string_append_printf(out, "\\footnote{");
623
+ padded = 2;
624
+ print_latex_element_list(out, elt->children);
625
+ g_string_append_printf(out, "}");
626
+ padded = 0;
627
+ }
628
+ break;
629
+ case REFERENCE:
630
+ /* Nonprinting */
631
+ break;
632
+ default:
633
+ fprintf(stderr, "print_latex_element encountered unknown element key = %d\n", elt->key);
634
+ exit(EXIT_FAILURE);
635
+ }
636
+ }
637
+
638
+ /**********************************************************************
639
+
640
+ Functions for printing Elements as groff (mm macros)
641
+
642
+ ***********************************************************************/
643
+
644
+ static bool in_list_item = false; /* True if we're parsing contents of a list item. */
645
+
646
+ /* print_groff_string - print string, escaping for groff */
647
+ static void print_groff_string(GString *out, char *str) {
648
+ /* escape dots if it is the first character */
649
+ if (*str == '.') {
650
+ g_string_append_printf(out, "\\[char46]");
651
+ str++;
652
+ }
653
+
654
+ while (*str != '\0') {
655
+ switch (*str) {
656
+ case '\\':
657
+ g_string_append_printf(out, "\\e");
658
+ break;
659
+ default:
660
+ g_string_append_c(out, *str);
661
+ }
662
+ str++;
663
+ }
664
+ }
665
+
666
+ /* print_groff_mm_element_list - print a list of elements as groff ms */
667
+ static void print_groff_mm_element_list(GString *out, element *list) {
668
+ int count = 1;
669
+ while (list != NULL) {
670
+ print_groff_mm_element(out, list, count);
671
+ list = list->next;
672
+ count++;
673
+ }
674
+ }
675
+
676
+ /* print_groff_mm_element - print an element as groff ms */
677
+ static void print_groff_mm_element(GString *out, element *elt, int count) {
678
+ int lev;
679
+ switch (elt->key) {
680
+ case SPACE:
681
+ g_string_append_printf(out, "%s", elt->contents.str);
682
+ padded = 0;
683
+ break;
684
+ case LINEBREAK:
685
+ pad(out, 1);
686
+ g_string_append_printf(out, ".br\n");
687
+ padded = 0;
688
+ break;
689
+ case STR:
690
+ print_groff_string(out, elt->contents.str);
691
+ padded = 0;
692
+ break;
693
+ case ELLIPSIS:
694
+ g_string_append_printf(out, "...");
695
+ break;
696
+ case EMDASH:
697
+ g_string_append_printf(out, "\\[em]");
698
+ break;
699
+ case ENDASH:
700
+ g_string_append_printf(out, "\\[en]");
701
+ break;
702
+ case ENSPACE:
703
+ g_string_append_printf(out, " ");
704
+ break;
705
+ case APOSTROPHE:
706
+ g_string_append_printf(out, "'");
707
+ break;
708
+ case SINGLEQUOTED:
709
+ g_string_append_printf(out, "`");
710
+ print_groff_mm_element_list(out, elt->children);
711
+ g_string_append_printf(out, "'");
712
+ break;
713
+ case DOUBLEQUOTED:
714
+ g_string_append_printf(out, "\\[lq]");
715
+ print_groff_mm_element_list(out, elt->children);
716
+ g_string_append_printf(out, "\\[rq]");
717
+ break;
718
+ case CODE:
719
+ g_string_append_printf(out, "\\fC");
720
+ print_groff_string(out, elt->contents.str);
721
+ g_string_append_printf(out, "\\fR");
722
+ padded = 0;
723
+ break;
724
+ case HTML:
725
+ /* don't print HTML */
726
+ break;
727
+ case HASHTAG:
728
+ print_groff_string(out, elt->contents.str);
729
+ break;
730
+ case USERNAME:
731
+ print_groff_string(out, elt->contents.str);
732
+ break;
733
+ case LINK:
734
+ print_groff_mm_element_list(out, elt->contents.link->label);
735
+ g_string_append_printf(out, " (%s)", elt->contents.link->url);
736
+ padded = 0;
737
+ break;
738
+ case IMAGE:
739
+ g_string_append_printf(out, "[IMAGE: ");
740
+ print_groff_mm_element_list(out, elt->contents.link->label);
741
+ g_string_append_printf(out, "]");
742
+ padded = 0;
743
+ /* not supported */
744
+ break;
745
+ case AUDIO:
746
+ pad(out, 2);
747
+ g_string_append_printf(out, "[AUDIO: ");
748
+ print_groff_string(out, elt->contents.media->source1);
749
+ g_string_append_printf(out, "]");
750
+ padded = 0;
751
+ /* not supported */
752
+ break;
753
+ case VIDEO:
754
+ pad(out, 2);
755
+ g_string_append_printf(out, "[VIDEO: ");
756
+ print_groff_string(out, elt->contents.media->source1);
757
+ g_string_append_printf(out, "]");
758
+ padded = 0;
759
+ /* not supported */
760
+ break;
761
+ case EMPH:
762
+ g_string_append_printf(out, "\\fI");
763
+ print_groff_mm_element_list(out, elt->children);
764
+ g_string_append_printf(out, "\\fR");
765
+ padded = 0;
766
+ break;
767
+ case STRONG:
768
+ g_string_append_printf(out, "\\fB");
769
+ print_groff_mm_element_list(out, elt->children);
770
+ g_string_append_printf(out, "\\fR");
771
+ padded = 0;
772
+ break;
773
+ case STRIKE:
774
+ g_string_append_printf(out, "\\c\n.ST \"");
775
+ print_groff_mm_element_list(out, elt->children);
776
+ g_string_append_printf(out, "\"");
777
+ pad(out, 1);
778
+ break;
779
+ case LIST:
780
+ print_groff_mm_element_list(out, elt->children);
781
+ padded = 0;
782
+ break;
783
+ case RAW:
784
+ /* Shouldn't occur - these are handled by process_raw_blocks() */
785
+ assert(elt->key != RAW);
786
+ break;
787
+ case H1: case H2: case H3: case H4: case H5: case H6:
788
+ lev = elt->key - H1 + 1;
789
+ pad(out, 1);
790
+ g_string_append_printf(out, ".H %d \"", lev);
791
+ print_groff_mm_element_list(out, elt->children);
792
+ g_string_append_printf(out, "\"");
793
+ padded = 0;
794
+ break;
795
+ case PLAIN:
796
+ pad(out, 1);
797
+ print_groff_mm_element_list(out, elt->children);
798
+ padded = 0;
799
+ break;
800
+ case PARA:
801
+ pad(out, 1);
802
+ if (!in_list_item || count != 1)
803
+ g_string_append_printf(out, ".P\n");
804
+ print_groff_mm_element_list(out, elt->children);
805
+ padded = 0;
806
+ break;
807
+ case HRULE:
808
+ pad(out, 1);
809
+ g_string_append_printf(out, "\\l'\\n(.lu*8u/10u'");
810
+ padded = 0;
811
+ break;
812
+ case HTMLBLOCK:
813
+ /* don't print HTML block */
814
+ break;
815
+ case VERBATIM:
816
+ pad(out, 1);
817
+ g_string_append_printf(out, ".VERBON 2\n");
818
+ print_groff_string(out, elt->contents.str);
819
+ g_string_append_printf(out, ".VERBOFF");
820
+ padded = 0;
821
+ break;
822
+ case BULLETLIST:
823
+ pad(out, 1);
824
+ g_string_append_printf(out, ".BL");
825
+ padded = 0;
826
+ print_groff_mm_element_list(out, elt->children);
827
+ pad(out, 1);
828
+ g_string_append_printf(out, ".LE 1");
829
+ padded = 0;
830
+ break;
831
+ case ORDEREDLIST:
832
+ pad(out, 1);
833
+ g_string_append_printf(out, ".AL");
834
+ padded = 0;
835
+ print_groff_mm_element_list(out, elt->children);
836
+ pad(out, 1);
837
+ g_string_append_printf(out, ".LE 1");
838
+ padded = 0;
839
+ break;
840
+ case LISTITEM:
841
+ pad(out, 1);
842
+ g_string_append_printf(out, ".LI\n");
843
+ in_list_item = true;
844
+ padded = 2;
845
+ print_groff_mm_element_list(out, elt->children);
846
+ in_list_item = false;
847
+ break;
848
+ case BLOCKQUOTE:
849
+ pad(out, 1);
850
+ g_string_append_printf(out, ".DS I\n");
851
+ padded = 2;
852
+ print_groff_mm_element_list(out, elt->children);
853
+ pad(out, 1);
854
+ g_string_append_printf(out, ".DE");
855
+ padded = 0;
856
+ break;
857
+ case SPOILERBLOCK:
858
+ pad(out, 1);
859
+ print_groff_mm_element_list(out, elt->children);
860
+ padded = 0;
861
+ break;
862
+ case NOTE:
863
+ /* if contents.str == 0, then print note; else ignore, since this
864
+ * is a note block that has been incorporated into the notes list */
865
+ if (elt->contents.str == 0) {
866
+ g_string_append_printf(out, "\\*F\n");
867
+ g_string_append_printf(out, ".FS\n");
868
+ padded = 2;
869
+ print_groff_mm_element_list(out, elt->children);
870
+ pad(out, 1);
871
+ g_string_append_printf(out, ".FE\n");
872
+ padded = 1;
873
+ }
874
+ break;
875
+ case REFERENCE:
876
+ /* Nonprinting */
877
+ break;
878
+ default:
879
+ fprintf(stderr, "print_groff_mm_element encountered unknown element key = %d\n", elt->key);
880
+ exit(EXIT_FAILURE);
881
+ }
882
+ }
883
+
884
+ /**********************************************************************
885
+
886
+ Functions for printing Elements as ODF
887
+
888
+ ***********************************************************************/
889
+
890
+ /* print_odf_code_string - print string, escaping for HTML and saving newlines
891
+ */
892
+ static void print_odf_code_string(GString *out, char *str) {
893
+ char *tmp;
894
+ while (*str != '\0') {
895
+ switch (*str) {
896
+ case '&':
897
+ g_string_append_printf(out, "&amp;");
898
+ break;
899
+ case '<':
900
+ g_string_append_printf(out, "&lt;");
901
+ break;
902
+ case '>':
903
+ g_string_append_printf(out, "&gt;");
904
+ break;
905
+ case '"':
906
+ g_string_append_printf(out, "&quot;");
907
+ break;
908
+ case '\n':
909
+ g_string_append_printf(out, "<text:line-break/>");
910
+ break;
911
+ case ' ':
912
+ tmp = str;
913
+ tmp++;
914
+ if (*tmp == ' ') {
915
+ tmp++;
916
+ if (*tmp == ' ') {
917
+ tmp++;
918
+ if (*tmp == ' ') {
919
+ g_string_append_printf(out, "<text:tab/>");
920
+ str = tmp;
921
+ } else {
922
+ g_string_append_printf(out, " ");
923
+ }
924
+ } else {
925
+ g_string_append_printf(out, " ");
926
+ }
927
+ } else {
928
+ g_string_append_printf(out, " ");
929
+ }
930
+ break;
931
+ default:
932
+ g_string_append_c(out, *str);
933
+ }
934
+ str++;
935
+ }
936
+ }
937
+
938
+ /* print_odf_string - print string, escaping for HTML and saving newlines */
939
+ static void print_odf_string(GString *out, char *str) {
940
+ char *tmp;
941
+ while (*str != '\0') {
942
+ switch (*str) {
943
+ case '&':
944
+ g_string_append_printf(out, "&amp;");
945
+ break;
946
+ case '<':
947
+ g_string_append_printf(out, "&lt;");
948
+ break;
949
+ case '>':
950
+ g_string_append_printf(out, "&gt;");
951
+ break;
952
+ case '"':
953
+ g_string_append_printf(out, "&quot;");
954
+ break;
955
+ case '\n':
956
+ tmp = str;
957
+ tmp--;
958
+ if (*tmp == ' ') {
959
+ tmp--;
960
+ if (*tmp == ' ') {
961
+ g_string_append_printf(out, "<text:line-break/>");
962
+ } else {
963
+ g_string_append_printf(out, "\n");
964
+ }
965
+ } else {
966
+ g_string_append_printf(out, "\n");
967
+ }
968
+ break;
969
+ case ' ':
970
+ tmp = str;
971
+ tmp++;
972
+ if (*tmp == ' ') {
973
+ tmp++;
974
+ if (*tmp == ' ') {
975
+ tmp++;
976
+ if (*tmp == ' ') {
977
+ g_string_append_printf(out, "<text:tab/>");
978
+ str = tmp;
979
+ } else {
980
+ g_string_append_printf(out, " ");
981
+ }
982
+ } else {
983
+ g_string_append_printf(out, " ");
984
+ }
985
+ } else {
986
+ g_string_append_printf(out, " ");
987
+ }
988
+ break;
989
+ default:
990
+ g_string_append_c(out, *str);
991
+ }
992
+ str++;
993
+ }
994
+ }
995
+
996
+ /* print_odf_element_list - print an element list as ODF */
997
+ static void print_odf_element_list(GString *out, element *list) {
998
+ while (list != NULL) {
999
+ print_odf_element(out, list);
1000
+ list = list->next;
1001
+ }
1002
+ }
1003
+
1004
+ /* print_odf_element - print an element as ODF */
1005
+ static void print_odf_element(GString *out, element *elt) {
1006
+ int lev;
1007
+ int old_type = 0;
1008
+ switch (elt->key) {
1009
+ case SPACE:
1010
+ g_string_append_printf(out, "%s", elt->contents.str);
1011
+ break;
1012
+ case LINEBREAK:
1013
+ g_string_append_printf(out, "<text:line-break/>");
1014
+ break;
1015
+ case STR:
1016
+ print_html_string(out, elt->contents.str, 0);
1017
+ break;
1018
+ case ELLIPSIS:
1019
+ g_string_append_printf(out, "&hellip;");
1020
+ break;
1021
+ case EMDASH:
1022
+ g_string_append_printf(out, "&mdash;");
1023
+ break;
1024
+ case ENDASH:
1025
+ g_string_append_printf(out, "&ndash;");
1026
+ break;
1027
+ case ENSPACE:
1028
+ g_string_append_printf(out, "&ensp;");
1029
+ break;
1030
+ case APOSTROPHE:
1031
+ g_string_append_printf(out, "&rsquo;");
1032
+ break;
1033
+ case SINGLEQUOTED:
1034
+ g_string_append_printf(out, "&lsquo;");
1035
+ print_odf_element_list(out, elt->children);
1036
+ g_string_append_printf(out, "&rsquo;");
1037
+ break;
1038
+ case DOUBLEQUOTED:
1039
+ g_string_append_printf(out, "&ldquo;");
1040
+ print_odf_element_list(out, elt->children);
1041
+ g_string_append_printf(out, "&rdquo;");
1042
+ break;
1043
+ case CODE:
1044
+ g_string_append_printf(out, "<text:span text:style-name=\"Source_20_Text\">");
1045
+ print_html_string(out, elt->contents.str, 0);
1046
+ g_string_append_printf(out, "</text:span>");
1047
+ break;
1048
+ case HTML:
1049
+ break;
1050
+ case HASHTAG:
1051
+ print_html_string(out, elt->contents.str, 0);
1052
+ break;
1053
+ case USERNAME:
1054
+ print_html_string(out, elt->contents.str, 0);
1055
+ break;
1056
+ case LINK:
1057
+ g_string_append_printf(out, "<text:a xlink:type=\"simple\" xlink:href=\"");
1058
+ print_html_string(out, elt->contents.link->url, 0);
1059
+ g_string_append_printf(out, "\"");
1060
+ if (strlen(elt->contents.link->title) > 0) {
1061
+ g_string_append_printf(out, " office:name=\"");
1062
+ print_html_string(out, elt->contents.link->title, 0);
1063
+ g_string_append_printf(out, "\"");
1064
+ }
1065
+ g_string_append_printf(out, ">");
1066
+ print_odf_element_list(out, elt->contents.link->label);
1067
+ g_string_append_printf(out, "</text:a>");
1068
+ break;
1069
+ case IMAGE:
1070
+ g_string_append_printf(out, "<draw:frame text:anchor-type=\"as-char\"\ndraw:z-index=\"0\" draw:style-name=\"fr1\" svg:width=\"95%%\"");
1071
+ g_string_append_printf(out, ">\n<draw:text-box><text:p><draw:frame text:anchor-type=\"as-char\" draw:z-index=\"1\" ");
1072
+ g_string_append_printf(out, "><draw:image xlink:href=\"");
1073
+ print_odf_string(out, elt->contents.link->url);
1074
+ g_string_append_printf(out,"\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" draw:filter-name=\"&lt;All formats&gt;\"/>\n</draw:frame></text:p>");
1075
+ g_string_append_printf(out, "</draw:text-box></draw:frame>\n");
1076
+ break;
1077
+ case EMPH:
1078
+ g_string_append_printf(out,
1079
+ "<text:span text:style-name=\"MMD-Italic\">");
1080
+ print_odf_element_list(out, elt->children);
1081
+ g_string_append_printf(out, "</text:span>");
1082
+ break;
1083
+ case STRONG:
1084
+ g_string_append_printf(out,
1085
+ "<text:span text:style-name=\"MMD-Bold\">");
1086
+ print_odf_element_list(out, elt->children);
1087
+ g_string_append_printf(out, "</text:span>");
1088
+ break;
1089
+ case STRIKE:
1090
+ g_string_append_printf(out,
1091
+ "<text:span text:style-name=\"StrikeThrough\">");
1092
+ print_odf_element_list(out, elt->children);
1093
+ g_string_append_printf(out, "</text:span>");
1094
+ break;
1095
+ case LIST:
1096
+ print_odf_element_list(out, elt->children);
1097
+ break;
1098
+ case RAW:
1099
+ /* Shouldn't occur - these are handled by process_raw_blocks() */
1100
+ assert(elt->key != RAW);
1101
+ break;
1102
+ case H1: case H2: case H3: case H4: case H5: case H6:
1103
+ lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
1104
+ g_string_append_printf(out, "<text:h text:outline-level=\"%d\">", lev);
1105
+ print_odf_element_list(out, elt->children);
1106
+ g_string_append_printf(out, "</text:h>\n");
1107
+ padded = 0;
1108
+ break;
1109
+ case PLAIN:
1110
+ print_odf_element_list(out, elt->children);
1111
+ padded = 0;
1112
+ break;
1113
+ case PARA:
1114
+ g_string_append_printf(out, "<text:p");
1115
+ switch (odf_type) {
1116
+ case BLOCKQUOTE:
1117
+ g_string_append_printf(out," text:style-name=\"Quotations\"");
1118
+ break;
1119
+ case CODE:
1120
+ g_string_append_printf(out," text:style-name=\"Preformatted Text\"");
1121
+ break;
1122
+ case VERBATIM:
1123
+ g_string_append_printf(out," text:style-name=\"Preformatted Text\"");
1124
+ break;
1125
+ case ORDEREDLIST:
1126
+ case BULLETLIST:
1127
+ g_string_append_printf(out," text:style-name=\"P2\"");
1128
+ break;
1129
+ case NOTE:
1130
+ g_string_append_printf(out," text:style-name=\"Footnote\"");
1131
+ break;
1132
+ default:
1133
+ g_string_append_printf(out," text:style-name=\"Standard\"");
1134
+ break;
1135
+ }
1136
+ g_string_append_printf(out, ">");
1137
+ print_odf_element_list(out, elt->children);
1138
+ g_string_append_printf(out, "</text:p>\n");
1139
+ break;
1140
+ case HRULE:
1141
+ g_string_append_printf(out,"<text:p text:style-name=\"Horizontal_20_Line\"/>\n");
1142
+ break;
1143
+ case HTMLBLOCK:
1144
+ /* don't print HTML block */
1145
+ /* but do print HTML comments for raw ODF */
1146
+ if (strncmp(elt->contents.str,"<!--",4) == 0) {
1147
+ /* trim "-->" from end */
1148
+ elt->contents.str[strlen(elt->contents.str)-3] = '\0';
1149
+ g_string_append_printf(out, "%s", &elt->contents.str[4]);
1150
+ }
1151
+ break;
1152
+ case VERBATIM:
1153
+ old_type = odf_type;
1154
+ odf_type = VERBATIM;
1155
+ g_string_append_printf(out, "<text:p text:style-name=\"Preformatted Text\">");
1156
+ print_odf_code_string(out, elt->contents.str);
1157
+ g_string_append_printf(out, "</text:p>\n");
1158
+ odf_type = old_type;
1159
+ break;
1160
+ case BULLETLIST:
1161
+ if ((odf_type == BULLETLIST) ||
1162
+ (odf_type == ORDEREDLIST)) {
1163
+ /* I think this was made unnecessary by another change.
1164
+ Same for ORDEREDLIST below */
1165
+ /* g_string_append_printf(out, "</text:p>"); */
1166
+ }
1167
+ old_type = odf_type;
1168
+ odf_type = BULLETLIST;
1169
+ g_string_append_printf(out, "%s", "<text:list>");
1170
+ print_odf_element_list(out, elt->children);
1171
+ g_string_append_printf(out, "%s", "</text:list>");
1172
+ odf_type = old_type;
1173
+ break;
1174
+ case ORDEREDLIST:
1175
+ if ((odf_type == BULLETLIST) ||
1176
+ (odf_type == ORDEREDLIST)) {
1177
+ /* g_string_append_printf(out, "</text:p>"); */
1178
+ }
1179
+ old_type = odf_type;
1180
+ odf_type = ORDEREDLIST;
1181
+ g_string_append_printf(out, "%s", "<text:list>\n");
1182
+ print_odf_element_list(out, elt->children);
1183
+ g_string_append_printf(out, "%s", "</text:list>\n");
1184
+ odf_type = old_type;
1185
+ break;
1186
+ case LISTITEM:
1187
+ g_string_append_printf(out, "<text:list-item>\n");
1188
+ if (elt->children->children->key != PARA) {
1189
+ g_string_append_printf(out, "<text:p text:style-name=\"P2\">");
1190
+ }
1191
+ print_odf_element_list(out, elt->children);
1192
+
1193
+ if ((list_contains_key(elt->children,BULLETLIST) ||
1194
+ (list_contains_key(elt->children,ORDEREDLIST)))) {
1195
+ } else {
1196
+ if (elt->children->children->key != PARA) {
1197
+ g_string_append_printf(out, "</text:p>");
1198
+ }
1199
+ }
1200
+ g_string_append_printf(out, "</text:list-item>\n");
1201
+ break;
1202
+ case BLOCKQUOTE:
1203
+ old_type = odf_type;
1204
+ odf_type = BLOCKQUOTE;
1205
+ print_odf_element_list(out, elt->children);
1206
+ odf_type = old_type;
1207
+ break;
1208
+ case SPOILERBLOCK:
1209
+ old_type = odf_type;
1210
+ odf_type = SPOILERBLOCK;
1211
+ print_odf_element_list(out, elt->children);
1212
+ odf_type = old_type;
1213
+ break;
1214
+ case REFERENCE:
1215
+ break;
1216
+ case NOTE:
1217
+ old_type = odf_type;
1218
+ odf_type = NOTE;
1219
+ /* if contents.str == 0 then print; else ignore - like above */
1220
+ if (elt->contents.str == 0) {
1221
+ g_string_append_printf(out, "<text:note text:id=\"\" text:note-class=\"footnote\"><text:note-body>\n");
1222
+ print_odf_element_list(out, elt->children);
1223
+ g_string_append_printf(out, "</text:note-body>\n</text:note>\n");
1224
+ }
1225
+ elt->children = NULL;
1226
+ odf_type = old_type;
1227
+ break;
1228
+ break; default:
1229
+ fprintf(stderr, "print_odf_element encountered unknown element key = %d\n", elt->key);
1230
+ exit(EXIT_FAILURE);
1231
+ }
1232
+ }
1233
+
1234
+ /**********************************************************************
1235
+
1236
+ Parameterized function for printing an Element.
1237
+
1238
+ ***********************************************************************/
1239
+
1240
+ void print_element_list(GString *out, element *elt, int format, int exts) {
1241
+ /* Initialize globals */
1242
+ endnotes = NULL;
1243
+ notenumber = 0;
1244
+
1245
+ extensions = exts;
1246
+ padded = 2; /* set padding to 2, so no extra blank lines at beginning */
1247
+ switch (format) {
1248
+ case HTML_FORMAT:
1249
+ print_html_element_list(out, elt, false);
1250
+ if (endnotes != NULL) {
1251
+ pad(out, 2);
1252
+ print_html_endnotes(out);
1253
+ }
1254
+ break;
1255
+ case LATEX_FORMAT:
1256
+ print_latex_element_list(out, elt);
1257
+ break;
1258
+ case GROFF_MM_FORMAT:
1259
+ if (extensions & EXT_STRIKE) {
1260
+ g_string_append_printf(out,
1261
+ ".de ST\n.nr width \\w'\\\\$1'\n\\Z@\\v'-.25m'\\l'\\\\n[width]u'@\\\\$1\\c\n..\n.\n");
1262
+ }
1263
+ print_groff_mm_element_list(out, elt);
1264
+ break;
1265
+ case ODF_FORMAT:
1266
+ print_odf_header(out);
1267
+ g_string_append_printf(out, "<office:body>\n<office:text>\n");
1268
+ if (elt != NULL) print_odf_element_list(out,elt);
1269
+ print_odf_footer(out);
1270
+ break;
1271
+ default:
1272
+ fprintf(stderr, "print_element - unknown format = %d\n", format);
1273
+ exit(EXIT_FAILURE);
1274
+ }
1275
+ }