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 */
pad(GString * out,int num)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 */
list_contains_key(element * list,int key)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 */
print_html_string(GString * out,char * str,bool obfuscate)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, "&");
97 break;
98 case '<':
99 g_string_append_printf(out, "<");
100 break;
101 case '>':
102 g_string_append_printf(out, ">");
103 break;
104 case '"':
105 g_string_append_printf(out, """);
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 */
print_html_element_list(GString * out,element * list,bool obfuscate)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. */
add_endnote(element * elt)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 */
print_html_element(GString * out,element * elt,bool obfuscate)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, "…");
149 break;
150 case EMDASH:
151 g_string_append_printf(out, "—");
152 break;
153 case ENDASH:
154 g_string_append_printf(out, "–");
155 break;
156 case APOSTROPHE:
157 g_string_append_printf(out, "’");
158 break;
159 case SINGLEQUOTED:
160 g_string_append_printf(out, "‘");
161 print_html_element_list(out, elt->children, obfuscate);
162 g_string_append_printf(out, "’");
163 break;
164 case DOUBLEQUOTED:
165 g_string_append_printf(out, "“");
166 print_html_element_list(out, elt->children, obfuscate);
167 g_string_append_printf(out, "”");
168 break;
169 case CODE:
170 g_string_append_printf(out, "<code>");
171 print_html_string(out, elt->contents.str, obfuscate);
172 g_string_append_printf(out, "</code>");
173 break;
174 case HTML:
175 g_string_append_printf(out, "%s", elt->contents.str);
176 break;
177 case LINK:
178 if (strstr(elt->contents.link->url, "mailto:") == elt->contents.link->url)
179 obfuscate = true; /* obfuscate mailto: links */
180 g_string_append_printf(out, "<a href=\"");
181 print_html_string(out, elt->contents.link->url, obfuscate);
182 g_string_append_printf(out, "\"");
183 if (strlen(elt->contents.link->title) > 0) {
184 g_string_append_printf(out, " title=\"");
185 print_html_string(out, elt->contents.link->title, obfuscate);
186 g_string_append_printf(out, "\"");
187 }
188 g_string_append_printf(out, ">");
189 print_html_element_list(out, elt->contents.link->label, obfuscate);
190 g_string_append_printf(out, "</a>");
191 break;
192 case IMAGE:
193 g_string_append_printf(out, "<img src=\"");
194 print_html_string(out, elt->contents.link->url, obfuscate);
195 g_string_append_printf(out, "\" alt=\"");
196 print_html_element_list(out, elt->contents.link->label, obfuscate);
197 g_string_append_printf(out, "\"");
198 if (strlen(elt->contents.link->title) > 0) {
199 g_string_append_printf(out, " title=\"");
200 print_html_string(out, elt->contents.link->title, obfuscate);
201 g_string_append_printf(out, "\"");
202 }
203 g_string_append_printf(out, " />");
204 break;
205 case EMPH:
206 g_string_append_printf(out, "<em>");
207 print_html_element_list(out, elt->children, obfuscate);
208 g_string_append_printf(out, "</em>");
209 break;
210 case STRONG:
211 g_string_append_printf(out, "<strong>");
212 print_html_element_list(out, elt->children, obfuscate);
213 g_string_append_printf(out, "</strong>");
214 break;
215 case LIST:
216 print_html_element_list(out, elt->children, obfuscate);
217 break;
218 case RAW:
219 /* Shouldn't occur - these are handled by process_raw_blocks() */
220 assert(elt->key != RAW);
221 break;
222 case H1: case H2: case H3: case H4: case H5: case H6:
223 lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
224 pad(out, 2);
225 g_string_append_printf(out, "<h%1d>", lev);
226 print_html_element_list(out, elt->children, obfuscate);
227 g_string_append_printf(out, "</h%1d>", lev);
228 padded = 0;
229 break;
230 case PLAIN:
231 pad(out, 1);
232 print_html_element_list(out, elt->children, obfuscate);
233 padded = 0;
234 break;
235 case PARA:
236 pad(out, 2);
237 g_string_append_printf(out, "<p>");
238 print_html_element_list(out, elt->children, obfuscate);
239 g_string_append_printf(out, "</p>");
240 padded = 0;
241 break;
242 case HRULE:
243 pad(out, 2);
244 g_string_append_printf(out, "<hr />");
245 padded = 0;
246 break;
247 case HTMLBLOCK:
248 pad(out, 2);
249 g_string_append_printf(out, "%s", elt->contents.str);
250 padded = 0;
251 break;
252 case VERBATIM:
253 pad(out, 2);
254 g_string_append_printf(out, "%s", "<pre><code>");
255 print_html_string(out, elt->contents.str, obfuscate);
256 g_string_append_printf(out, "%s", "</code></pre>");
257 padded = 0;
258 break;
259 case BULLETLIST:
260 pad(out, 2);
261 g_string_append_printf(out, "%s", "<ul>");
262 padded = 0;
263 print_html_element_list(out, elt->children, obfuscate);
264 pad(out, 1);
265 g_string_append_printf(out, "%s", "</ul>");
266 padded = 0;
267 break;
268 case ORDEREDLIST:
269 pad(out, 2);
270 g_string_append_printf(out, "%s", "<ol>");
271 padded = 0;
272 print_html_element_list(out, elt->children, obfuscate);
273 pad(out, 1);
274 g_string_append_printf(out, "</ol>");
275 padded = 0;
276 break;
277 case LISTITEM:
278 pad(out, 1);
279 g_string_append_printf(out, "<li>");
280 padded = 2;
281 print_html_element_list(out, elt->children, obfuscate);
282 g_string_append_printf(out, "</li>");
283 padded = 0;
284 break;
285 case BLOCKQUOTE:
286 pad(out, 2);
287 g_string_append_printf(out, "<blockquote>\n");
288 padded = 2;
289 print_html_element_list(out, elt->children, obfuscate);
290 pad(out, 1);
291 g_string_append_printf(out, "</blockquote>");
292 padded = 0;
293 break;
294 case REFERENCE:
295 /* Nonprinting */
296 break;
297 case NOTE:
298 /* if contents.str == 0, then print note; else ignore, since this
299 * is a note block that has been incorporated into the notes list */
300 if (elt->contents.str == 0) {
301 add_endnote(elt);
302 ++notenumber;
303 g_string_append_printf(out, "<a class=\"noteref\" id=\"fnref%d\" href=\"#fn%d\" title=\"Jump to note %d\">[%d]</a>",
304 notenumber, notenumber, notenumber, notenumber);
305 }
306 break;
307 default:
308 fprintf(stderr, "print_html_element encountered unknown element key = %d\n", elt->key);
309 exit(EXIT_FAILURE);
310 }
311 }
312
print_html_endnotes(GString * out)313 static void print_html_endnotes(GString *out) {
314 int counter = 0;
315 GSList *note;
316 element *note_elt;
317 if (endnotes == NULL)
318 return;
319 note = g_slist_reverse(endnotes);
320 g_string_append_printf(out, "<hr/>\n<ol id=\"notes\">");
321 while (note != NULL) {
322 note_elt = note->data;
323 counter++;
324 pad(out, 1);
325 g_string_append_printf(out, "<li id=\"fn%d\">\n", counter);
326 padded = 2;
327 print_html_element_list(out, note_elt->children, false);
328 g_string_append_printf(out, " <a href=\"#fnref%d\" title=\"Jump back to reference\">[back]</a>", counter);
329 pad(out, 1);
330 g_string_append_printf(out, "</li>");
331 note = note->next;
332 }
333 pad(out, 1);
334 g_string_append_printf(out, "</ol>");
335 g_slist_free(endnotes);
336 }
337
338 /**********************************************************************
339
340 Functions for printing Elements as LaTeX
341
342 ***********************************************************************/
343
344 /* print_latex_string - print string, escaping for LaTeX */
print_latex_string(GString * out,char * str)345 static void print_latex_string(GString *out, char *str) {
346 while (*str != '\0') {
347 switch (*str) {
348 case '{': case '}': case '$': case '%':
349 case '&': case '_': case '#':
350 g_string_append_printf(out, "\\%c", *str);
351 break;
352 case '^':
353 g_string_append_printf(out, "\\^{}");
354 break;
355 case '\\':
356 g_string_append_printf(out, "\\textbackslash{}");
357 break;
358 case '~':
359 g_string_append_printf(out, "\\ensuremath{\\sim}");
360 break;
361 case '|':
362 g_string_append_printf(out, "\\textbar{}");
363 break;
364 case '<':
365 g_string_append_printf(out, "\\textless{}");
366 break;
367 case '>':
368 g_string_append_printf(out, "\\textgreater{}");
369 break;
370 default:
371 g_string_append_c(out, *str);
372 }
373 str++;
374 }
375 }
376
377 /* print_latex_element_list - print a list of elements as LaTeX */
print_latex_element_list(GString * out,element * list)378 static void print_latex_element_list(GString *out, element *list) {
379 while (list != NULL) {
380 print_latex_element(out, list);
381 list = list->next;
382 }
383 }
384
385 /* print_latex_element - print an element as LaTeX */
print_latex_element(GString * out,element * elt)386 static void print_latex_element(GString *out, element *elt) {
387 int lev;
388 int i;
389 switch (elt->key) {
390 case SPACE:
391 g_string_append_printf(out, "%s", elt->contents.str);
392 break;
393 case LINEBREAK:
394 g_string_append_printf(out, "\\\\\n");
395 break;
396 case STR:
397 print_latex_string(out, elt->contents.str);
398 break;
399 case ELLIPSIS:
400 g_string_append_printf(out, "\\ldots{}");
401 break;
402 case EMDASH:
403 g_string_append_printf(out, "---");
404 break;
405 case ENDASH:
406 g_string_append_printf(out, "--");
407 break;
408 case APOSTROPHE:
409 g_string_append_printf(out, "'");
410 break;
411 case SINGLEQUOTED:
412 g_string_append_printf(out, "`");
413 print_latex_element_list(out, elt->children);
414 g_string_append_printf(out, "'");
415 break;
416 case DOUBLEQUOTED:
417 g_string_append_printf(out, "``");
418 print_latex_element_list(out, elt->children);
419 g_string_append_printf(out, "''");
420 break;
421 case CODE:
422 g_string_append_printf(out, "\\texttt{");
423 print_latex_string(out, elt->contents.str);
424 g_string_append_printf(out, "}");
425 break;
426 case HTML:
427 /* don't print HTML */
428 break;
429 case LINK:
430 g_string_append_printf(out, "\\href{%s}{", elt->contents.link->url);
431 print_latex_element_list(out, elt->contents.link->label);
432 g_string_append_printf(out, "}");
433 break;
434 case IMAGE:
435 g_string_append_printf(out, "\\includegraphics{%s}", elt->contents.link->url);
436 break;
437 case EMPH:
438 g_string_append_printf(out, "\\emph{");
439 print_latex_element_list(out, elt->children);
440 g_string_append_printf(out, "}");
441 break;
442 case STRONG:
443 g_string_append_printf(out, "\\textbf{");
444 print_latex_element_list(out, elt->children);
445 g_string_append_printf(out, "}");
446 break;
447 case LIST:
448 print_latex_element_list(out, elt->children);
449 break;
450 case RAW:
451 /* Shouldn't occur - these are handled by process_raw_blocks() */
452 assert(elt->key != RAW);
453 break;
454 case H1: case H2: case H3:
455 pad(out, 2);
456 lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
457 g_string_append_printf(out, "\\");
458 for (i = elt->key; i > H1; i--)
459 g_string_append_printf(out, "sub");
460 g_string_append_printf(out, "section{");
461 print_latex_element_list(out, elt->children);
462 g_string_append_printf(out, "}");
463 padded = 0;
464 break;
465 case H4: case H5: case H6:
466 pad(out, 2);
467 g_string_append_printf(out, "\\noindent\\textbf{");
468 print_latex_element_list(out, elt->children);
469 g_string_append_printf(out, "}");
470 padded = 0;
471 break;
472 case PLAIN:
473 pad(out, 1);
474 print_latex_element_list(out, elt->children);
475 padded = 0;
476 break;
477 case PARA:
478 pad(out, 2);
479 print_latex_element_list(out, elt->children);
480 padded = 0;
481 break;
482 case HRULE:
483 pad(out, 2);
484 g_string_append_printf(out, "\\begin{center}\\rule{3in}{0.4pt}\\end{center}\n");
485 padded = 0;
486 break;
487 case HTMLBLOCK:
488 /* don't print HTML block */
489 break;
490 case VERBATIM:
491 pad(out, 1);
492 g_string_append_printf(out, "\\begin{verbatim}\n");
493 print_latex_string(out, elt->contents.str);
494 g_string_append_printf(out, "\n\\end{verbatim}");
495 padded = 0;
496 break;
497 case BULLETLIST:
498 pad(out, 1);
499 g_string_append_printf(out, "\\begin{itemize}");
500 padded = 0;
501 print_latex_element_list(out, elt->children);
502 pad(out, 1);
503 g_string_append_printf(out, "\\end{itemize}");
504 padded = 0;
505 break;
506 case ORDEREDLIST:
507 pad(out, 1);
508 g_string_append_printf(out, "\\begin{enumerate}");
509 padded = 0;
510 print_latex_element_list(out, elt->children);
511 pad(out, 1);
512 g_string_append_printf(out, "\\end{enumerate}");
513 padded = 0;
514 break;
515 case LISTITEM:
516 pad(out, 1);
517 g_string_append_printf(out, "\\item ");
518 padded = 2;
519 print_latex_element_list(out, elt->children);
520 g_string_append_printf(out, "\n");
521 break;
522 case BLOCKQUOTE:
523 pad(out, 1);
524 g_string_append_printf(out, "\\begin{quote}");
525 padded = 0;
526 print_latex_element_list(out, elt->children);
527 pad(out, 1);
528 g_string_append_printf(out, "\\end{quote}");
529 padded = 0;
530 break;
531 case NOTE:
532 /* if contents.str == 0, then print note; else ignore, since this
533 * is a note block that has been incorporated into the notes list */
534 if (elt->contents.str == 0) {
535 g_string_append_printf(out, "\\footnote{");
536 padded = 2;
537 print_latex_element_list(out, elt->children);
538 g_string_append_printf(out, "}");
539 padded = 0;
540 }
541 break;
542 case REFERENCE:
543 /* Nonprinting */
544 break;
545 default:
546 fprintf(stderr, "print_latex_element encountered unknown element key = %d\n", elt->key);
547 exit(EXIT_FAILURE);
548 }
549 }
550
551 /**********************************************************************
552
553 Functions for printing Elements as groff (mm macros)
554
555 ***********************************************************************/
556
557 static bool in_list_item = false; /* True if we're parsing contents of a list item. */
558
559 /* print_groff_string - print string, escaping for groff */
print_groff_string(GString * out,char * str)560 static void print_groff_string(GString *out, char *str) {
561 while (*str != '\0') {
562 switch (*str) {
563 case '\\':
564 g_string_append_printf(out, "\\e");
565 break;
566 default:
567 g_string_append_c(out, *str);
568 }
569 str++;
570 }
571 }
572
573 /* print_groff_mm_element_list - print a list of elements as groff ms */
print_groff_mm_element_list(GString * out,element * list)574 static void print_groff_mm_element_list(GString *out, element *list) {
575 int count = 1;
576 while (list != NULL) {
577 print_groff_mm_element(out, list, count);
578 list = list->next;
579 count++;
580 }
581 }
582
583 /* print_groff_mm_element - print an element as groff ms */
print_groff_mm_element(GString * out,element * elt,int count)584 static void print_groff_mm_element(GString *out, element *elt, int count) {
585 int lev;
586 switch (elt->key) {
587 case SPACE:
588 g_string_append_printf(out, "%s", elt->contents.str);
589 padded = 0;
590 break;
591 case LINEBREAK:
592 pad(out, 1);
593 g_string_append_printf(out, ".br\n");
594 padded = 0;
595 break;
596 case STR:
597 print_groff_string(out, elt->contents.str);
598 padded = 0;
599 break;
600 case ELLIPSIS:
601 g_string_append_printf(out, "...");
602 break;
603 case EMDASH:
604 g_string_append_printf(out, "\\[em]");
605 break;
606 case ENDASH:
607 g_string_append_printf(out, "\\[en]");
608 break;
609 case APOSTROPHE:
610 g_string_append_printf(out, "'");
611 break;
612 case SINGLEQUOTED:
613 g_string_append_printf(out, "`");
614 print_groff_mm_element_list(out, elt->children);
615 g_string_append_printf(out, "'");
616 break;
617 case DOUBLEQUOTED:
618 g_string_append_printf(out, "\\[lq]");
619 print_groff_mm_element_list(out, elt->children);
620 g_string_append_printf(out, "\\[rq]");
621 break;
622 case CODE:
623 g_string_append_printf(out, "\\fC");
624 print_groff_string(out, elt->contents.str);
625 g_string_append_printf(out, "\\fR");
626 padded = 0;
627 break;
628 case HTML:
629 /* don't print HTML */
630 break;
631 case LINK:
632 print_groff_mm_element_list(out, elt->contents.link->label);
633 g_string_append_printf(out, " (%s)", elt->contents.link->url);
634 padded = 0;
635 break;
636 case IMAGE:
637 g_string_append_printf(out, "[IMAGE: ");
638 print_groff_mm_element_list(out, elt->contents.link->label);
639 g_string_append_printf(out, "]");
640 padded = 0;
641 /* not supported */
642 break;
643 case EMPH:
644 g_string_append_printf(out, "\\fI");
645 print_groff_mm_element_list(out, elt->children);
646 g_string_append_printf(out, "\\fR");
647 padded = 0;
648 break;
649 case STRONG:
650 g_string_append_printf(out, "\\fB");
651 print_groff_mm_element_list(out, elt->children);
652 g_string_append_printf(out, "\\fR");
653 padded = 0;
654 break;
655 case LIST:
656 print_groff_mm_element_list(out, elt->children);
657 padded = 0;
658 break;
659 case RAW:
660 /* Shouldn't occur - these are handled by process_raw_blocks() */
661 assert(elt->key != RAW);
662 break;
663 case H1: case H2: case H3: case H4: case H5: case H6:
664 lev = elt->key - H1 + 1;
665 pad(out, 1);
666 g_string_append_printf(out, ".H %d \"", lev);
667 print_groff_mm_element_list(out, elt->children);
668 g_string_append_printf(out, "\"");
669 padded = 0;
670 break;
671 case PLAIN:
672 pad(out, 1);
673 print_groff_mm_element_list(out, elt->children);
674 padded = 0;
675 break;
676 case PARA:
677 pad(out, 1);
678 if (!in_list_item || count != 1)
679 g_string_append_printf(out, ".P\n");
680 print_groff_mm_element_list(out, elt->children);
681 padded = 0;
682 break;
683 case HRULE:
684 pad(out, 1);
685 g_string_append_printf(out, "\\l'\\n(.lu*8u/10u'");
686 padded = 0;
687 break;
688 case HTMLBLOCK:
689 /* don't print HTML block */
690 break;
691 case VERBATIM:
692 pad(out, 1);
693 g_string_append_printf(out, ".VERBON 2\n");
694 print_groff_string(out, elt->contents.str);
695 g_string_append_printf(out, ".VERBOFF");
696 padded = 0;
697 break;
698 case BULLETLIST:
699 pad(out, 1);
700 g_string_append_printf(out, ".BL");
701 padded = 0;
702 print_groff_mm_element_list(out, elt->children);
703 pad(out, 1);
704 g_string_append_printf(out, ".LE 1");
705 padded = 0;
706 break;
707 case ORDEREDLIST:
708 pad(out, 1);
709 g_string_append_printf(out, ".AL");
710 padded = 0;
711 print_groff_mm_element_list(out, elt->children);
712 pad(out, 1);
713 g_string_append_printf(out, ".LE 1");
714 padded = 0;
715 break;
716 case LISTITEM:
717 pad(out, 1);
718 g_string_append_printf(out, ".LI\n");
719 in_list_item = true;
720 padded = 2;
721 print_groff_mm_element_list(out, elt->children);
722 in_list_item = false;
723 break;
724 case BLOCKQUOTE:
725 pad(out, 1);
726 g_string_append_printf(out, ".DS I\n");
727 padded = 2;
728 print_groff_mm_element_list(out, elt->children);
729 pad(out, 1);
730 g_string_append_printf(out, ".DE");
731 padded = 0;
732 break;
733 case NOTE:
734 /* if contents.str == 0, then print note; else ignore, since this
735 * is a note block that has been incorporated into the notes list */
736 if (elt->contents.str == 0) {
737 g_string_append_printf(out, "\\*F\n");
738 g_string_append_printf(out, ".FS\n");
739 padded = 2;
740 print_groff_mm_element_list(out, elt->children);
741 pad(out, 1);
742 g_string_append_printf(out, ".FE\n");
743 padded = 1;
744 }
745 break;
746 case REFERENCE:
747 /* Nonprinting */
748 break;
749 default:
750 fprintf(stderr, "print_groff_mm_element encountered unknown element key = %d\n", elt->key);
751 exit(EXIT_FAILURE);
752 }
753 }
754
755 /**********************************************************************
756
757 Functions for printing Elements as ODF
758
759 ***********************************************************************/
760
761 /* print_odf_code_string - print string, escaping for HTML and saving newlines
762 */
print_odf_code_string(GString * out,char * str)763 static void print_odf_code_string(GString *out, char *str) {
764 char *tmp;
765 while (*str != '\0') {
766 switch (*str) {
767 case '&':
768 g_string_append_printf(out, "&");
769 break;
770 case '<':
771 g_string_append_printf(out, "<");
772 break;
773 case '>':
774 g_string_append_printf(out, ">");
775 break;
776 case '"':
777 g_string_append_printf(out, """);
778 break;
779 case '\n':
780 g_string_append_printf(out, "<text:line-break/>");
781 break;
782 case ' ':
783 tmp = str;
784 tmp++;
785 if (*tmp == ' ') {
786 tmp++;
787 if (*tmp == ' ') {
788 tmp++;
789 if (*tmp == ' ') {
790 g_string_append_printf(out, "<text:tab/>");
791 str = tmp;
792 } else {
793 g_string_append_printf(out, " ");
794 }
795 } else {
796 g_string_append_printf(out, " ");
797 }
798 } else {
799 g_string_append_printf(out, " ");
800 }
801 break;
802 default:
803 g_string_append_c(out, *str);
804 }
805 str++;
806 }
807 }
808
809 /* print_odf_string - print string, escaping for HTML and saving newlines */
print_odf_string(GString * out,char * str)810 static void print_odf_string(GString *out, char *str) {
811 char *tmp;
812 while (*str != '\0') {
813 switch (*str) {
814 case '&':
815 g_string_append_printf(out, "&");
816 break;
817 case '<':
818 g_string_append_printf(out, "<");
819 break;
820 case '>':
821 g_string_append_printf(out, ">");
822 break;
823 case '"':
824 g_string_append_printf(out, """);
825 break;
826 case '\n':
827 tmp = str;
828 tmp--;
829 if (*tmp == ' ') {
830 tmp--;
831 if (*tmp == ' ') {
832 g_string_append_printf(out, "<text:line-break/>");
833 } else {
834 g_string_append_printf(out, "\n");
835 }
836 } else {
837 g_string_append_printf(out, "\n");
838 }
839 break;
840 case ' ':
841 tmp = str;
842 tmp++;
843 if (*tmp == ' ') {
844 tmp++;
845 if (*tmp == ' ') {
846 tmp++;
847 if (*tmp == ' ') {
848 g_string_append_printf(out, "<text:tab/>");
849 str = tmp;
850 } else {
851 g_string_append_printf(out, " ");
852 }
853 } else {
854 g_string_append_printf(out, " ");
855 }
856 } else {
857 g_string_append_printf(out, " ");
858 }
859 break;
860 default:
861 g_string_append_c(out, *str);
862 }
863 str++;
864 }
865 }
866
867 /* print_odf_element_list - print an element list as ODF */
print_odf_element_list(GString * out,element * list)868 static void print_odf_element_list(GString *out, element *list) {
869 while (list != NULL) {
870 print_odf_element(out, list);
871 list = list->next;
872 }
873 }
874
875 /* print_odf_element - print an element as ODF */
print_odf_element(GString * out,element * elt)876 static void print_odf_element(GString *out, element *elt) {
877 int lev;
878 int old_type = 0;
879 switch (elt->key) {
880 case SPACE:
881 g_string_append_printf(out, "%s", elt->contents.str);
882 break;
883 case LINEBREAK:
884 g_string_append_printf(out, "<text:line-break/>");
885 break;
886 case STR:
887 print_html_string(out, elt->contents.str, 0);
888 break;
889 case ELLIPSIS:
890 g_string_append_printf(out, "…");
891 break;
892 case EMDASH:
893 g_string_append_printf(out, "—");
894 break;
895 case ENDASH:
896 g_string_append_printf(out, "–");
897 break;
898 case APOSTROPHE:
899 g_string_append_printf(out, "’");
900 break;
901 case SINGLEQUOTED:
902 g_string_append_printf(out, "‘");
903 print_odf_element_list(out, elt->children);
904 g_string_append_printf(out, "’");
905 break;
906 case DOUBLEQUOTED:
907 g_string_append_printf(out, "“");
908 print_odf_element_list(out, elt->children);
909 g_string_append_printf(out, "”");
910 break;
911 case CODE:
912 g_string_append_printf(out, "<text:span text:style-name=\"Source_20_Text\">");
913 print_html_string(out, elt->contents.str, 0);
914 g_string_append_printf(out, "</text:span>");
915 break;
916 case HTML:
917 break;
918 case LINK:
919 g_string_append_printf(out, "<text:a xlink:type=\"simple\" xlink:href=\"");
920 print_html_string(out, elt->contents.link->url, 0);
921 g_string_append_printf(out, "\"");
922 if (strlen(elt->contents.link->title) > 0) {
923 g_string_append_printf(out, " office:name=\"");
924 print_html_string(out, elt->contents.link->title, 0);
925 g_string_append_printf(out, "\"");
926 }
927 g_string_append_printf(out, ">");
928 print_odf_element_list(out, elt->contents.link->label);
929 g_string_append_printf(out, "</text:a>");
930 break;
931 case IMAGE:
932 g_string_append_printf(out, "<draw:frame text:anchor-type=\"as-char\"\ndraw:z-index=\"0\" draw:style-name=\"fr1\" svg:width=\"95%%\"");
933 g_string_append_printf(out, ">\n<draw:text-box><text:p><draw:frame text:anchor-type=\"as-char\" draw:z-index=\"1\" ");
934 g_string_append_printf(out, "><draw:image xlink:href=\"");
935 print_odf_string(out, elt->contents.link->url);
936 g_string_append_printf(out,"\" xlink:type=\"simple\" xlink:show=\"embed\" xlink:actuate=\"onLoad\" draw:filter-name=\"<All formats>\"/>\n</draw:frame></text:p>");
937 g_string_append_printf(out, "</draw:text-box></draw:frame>\n");
938 break;
939 case EMPH:
940 g_string_append_printf(out,
941 "<text:span text:style-name=\"MMD-Italic\">");
942 print_odf_element_list(out, elt->children);
943 g_string_append_printf(out, "</text:span>");
944 break;
945 case STRONG:
946 g_string_append_printf(out,
947 "<text:span text:style-name=\"MMD-Bold\">");
948 print_odf_element_list(out, elt->children);
949 g_string_append_printf(out, "</text:span>");
950 break;
951 case LIST:
952 print_odf_element_list(out, elt->children);
953 break;
954 case RAW:
955 /* Shouldn't occur - these are handled by process_raw_blocks() */
956 assert(elt->key != RAW);
957 break;
958 case H1: case H2: case H3: case H4: case H5: case H6:
959 lev = elt->key - H1 + 1; /* assumes H1 ... H6 are in order */
960 g_string_append_printf(out, "<text:h text:outline-level=\"%d\">", lev);
961 print_odf_element_list(out, elt->children);
962 g_string_append_printf(out, "</text:h>\n");
963 padded = 0;
964 break;
965 case PLAIN:
966 print_odf_element_list(out, elt->children);
967 padded = 0;
968 break;
969 case PARA:
970 g_string_append_printf(out, "<text:p");
971 switch (odf_type) {
972 case BLOCKQUOTE:
973 g_string_append_printf(out," text:style-name=\"Quotations\"");
974 break;
975 case CODE:
976 g_string_append_printf(out," text:style-name=\"Preformatted Text\"");
977 break;
978 case VERBATIM:
979 g_string_append_printf(out," text:style-name=\"Preformatted Text\"");
980 break;
981 case ORDEREDLIST:
982 case BULLETLIST:
983 g_string_append_printf(out," text:style-name=\"P2\"");
984 break;
985 case NOTE:
986 g_string_append_printf(out," text:style-name=\"Footnote\"");
987 break;
988 default:
989 g_string_append_printf(out," text:style-name=\"Standard\"");
990 break;
991 }
992 g_string_append_printf(out, ">");
993 print_odf_element_list(out, elt->children);
994 g_string_append_printf(out, "</text:p>\n");
995 break;
996 case HRULE:
997 g_string_append_printf(out,"<text:p text:style-name=\"Horizontal_20_Line\"/>\n");
998 break;
999 case HTMLBLOCK:
1000 /* don't print HTML block */
1001 /* but do print HTML comments for raw ODF */
1002 if (strncmp(elt->contents.str,"<!--",4) == 0) {
1003 /* trim "-->" from end */
1004 elt->contents.str[strlen(elt->contents.str)-3] = '\0';
1005 g_string_append_printf(out, "%s", &elt->contents.str[4]);
1006 }
1007 break;
1008 case VERBATIM:
1009 old_type = odf_type;
1010 odf_type = VERBATIM;
1011 g_string_append_printf(out, "<text:p text:style-name=\"Preformatted Text\">");
1012 print_odf_code_string(out, elt->contents.str);
1013 g_string_append_printf(out, "</text:p>\n");
1014 odf_type = old_type;
1015 break;
1016 case BULLETLIST:
1017 if ((odf_type == BULLETLIST) ||
1018 (odf_type == ORDEREDLIST)) {
1019 /* I think this was made unnecessary by another change.
1020 Same for ORDEREDLIST below */
1021 /* g_string_append_printf(out, "</text:p>"); */
1022 }
1023 old_type = odf_type;
1024 odf_type = BULLETLIST;
1025 g_string_append_printf(out, "%s", "<text:list>");
1026 print_odf_element_list(out, elt->children);
1027 g_string_append_printf(out, "%s", "</text:list>");
1028 odf_type = old_type;
1029 break;
1030 case ORDEREDLIST:
1031 if ((odf_type == BULLETLIST) ||
1032 (odf_type == ORDEREDLIST)) {
1033 /* g_string_append_printf(out, "</text:p>"); */
1034 }
1035 old_type = odf_type;
1036 odf_type = ORDEREDLIST;
1037 g_string_append_printf(out, "%s", "<text:list>\n");
1038 print_odf_element_list(out, elt->children);
1039 g_string_append_printf(out, "%s", "</text:list>\n");
1040 odf_type = old_type;
1041 break;
1042 case LISTITEM:
1043 g_string_append_printf(out, "<text:list-item>\n");
1044 if (elt->children->children->key != PARA) {
1045 g_string_append_printf(out, "<text:p text:style-name=\"P2\">");
1046 }
1047 print_odf_element_list(out, elt->children);
1048
1049 if ((list_contains_key(elt->children,BULLETLIST) ||
1050 (list_contains_key(elt->children,ORDEREDLIST)))) {
1051 } else {
1052 if (elt->children->children->key != PARA) {
1053 g_string_append_printf(out, "</text:p>");
1054 }
1055 }
1056 g_string_append_printf(out, "</text:list-item>\n");
1057 break;
1058 case BLOCKQUOTE:
1059 old_type = odf_type;
1060 odf_type = BLOCKQUOTE;
1061 print_odf_element_list(out, elt->children);
1062 odf_type = old_type;
1063 break;
1064 case REFERENCE:
1065 break;
1066 case NOTE:
1067 old_type = odf_type;
1068 odf_type = NOTE;
1069 /* if contents.str == 0 then print; else ignore - like above */
1070 if (elt->contents.str == 0) {
1071 g_string_append_printf(out, "<text:note text:id=\"\" text:note-class=\"footnote\"><text:note-body>\n");
1072 print_odf_element_list(out, elt->children);
1073 g_string_append_printf(out, "</text:note-body>\n</text:note>\n");
1074 }
1075 elt->children = NULL;
1076 odf_type = old_type;
1077 break;
1078 break; default:
1079 fprintf(stderr, "print_odf_element encountered unknown element key = %d\n", elt->key);
1080 exit(EXIT_FAILURE);
1081 }
1082 }
1083
1084 /**********************************************************************
1085
1086 Parameterized function for printing an Element.
1087
1088 ***********************************************************************/
1089
print_element_list(GString * out,element * elt,int format,int exts)1090 void print_element_list(GString *out, element *elt, int format, int exts) {
1091 /* Initialize globals */
1092 endnotes = NULL;
1093 notenumber = 0;
1094
1095 extensions = exts;
1096 padded = 2; /* set padding to 2, so no extra blank lines at beginning */
1097 switch (format) {
1098 case HTML_FORMAT:
1099 print_html_element_list(out, elt, false);
1100 if (endnotes != NULL) {
1101 pad(out, 2);
1102 print_html_endnotes(out);
1103 }
1104 break;
1105 case LATEX_FORMAT:
1106 print_latex_element_list(out, elt);
1107 break;
1108 case GROFF_MM_FORMAT:
1109 print_groff_mm_element_list(out, elt);
1110 break;
1111 case ODF_FORMAT:
1112 print_odf_header(out);
1113 g_string_append_printf(out, "<office:body>\n<office:text>\n");
1114 if (elt != NULL) print_odf_element_list(out,elt);
1115 print_odf_footer(out);
1116 break;
1117 default:
1118 fprintf(stderr, "print_element - unknown format = %d\n", format);
1119 exit(EXIT_FAILURE);
1120 }
1121 }
1122