1 /**
2 
3 	MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
4 
5 	@file beamer.c
6 
7 	@brief
8 
9 
10 	@author	Fletcher T. Penney
11 	@bug
12 
13 **/
14 
15 /*
16 
17 	Copyright © 2016 - 2017 Fletcher T. Penney.
18 
19 
20 	The `MultiMarkdown 6` project is released under the MIT License..
21 
22 	GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
23 
24 		https://github.com/fletcher/MultiMarkdown-4/
25 
26 	MMD 4 is released under both the MIT License and GPL.
27 
28 
29 	CuTest is released under the zlib/libpng license. See CuTest.c for the text
30 	of the license.
31 
32 
33 	## The MIT License ##
34 
35 	Permission is hereby granted, free of charge, to any person obtaining a copy
36 	of this software and associated documentation files (the "Software"), to deal
37 	in the Software without restriction, including without limitation the rights
38 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
39 	copies of the Software, and to permit persons to whom the Software is
40 	furnished to do so, subject to the following conditions:
41 
42 	The above copyright notice and this permission notice shall be included in
43 	all copies or substantial portions of the Software.
44 
45 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
46 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
47 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
48 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
49 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
50 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
51 	THE SOFTWARE.
52 
53 */
54 
55 
56 #include "latex.h"
57 #include "beamer.h"
58 #include "parser.h"
59 #include "stack.h"
60 
61 #define print(x) d_string_append(out, x)
62 #define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
63 #define print_char(x) d_string_append_c(out, x)
64 #define printf(...) d_string_append_printf(out, __VA_ARGS__)
65 #define print_token(t) d_string_append_c_array(out, &(source[t->start]), t->len)
66 #define print_localized(x) mmd_print_localized_char_latex(out, x, scratch)
67 
68 
69 void mmd_outline_add_beamer(DString * out, token * current, scratch_pad * scratch) {
70 	token * t;
71 	short level;		// Header level we are adding
72 	short t_level;
73 	stack * s = scratch->outline_stack;
74 
75 	if (current) {
76 		switch (current->type) {
77 			case BLOCK_SETEXT_1:
78 				level = 1;
79 				break;
80 
81 			case BLOCK_SETEXT_2:
82 				level = 2;
83 				break;
84 
85 			default:
86 				level = 1 + current->type - BLOCK_H1;
87 		}
88 
89 		level += scratch->base_header_level - 1;
90 	} else {
91 		level = 0;
92 	}
93 
94 	if (s->size) {
95 		t = stack_peek(s);
96 
97 		while (t) {
98 			switch (t->type) {
99 				case BLOCK_SETEXT_1:
100 					t_level = 1;
101 					break;
102 
103 				case BLOCK_SETEXT_2:
104 					t_level = 2;
105 					break;
106 
107 				default:
108 					t_level = 1 + t->type - BLOCK_H1;
109 			}
110 
111 			t_level += scratch->base_header_level - 1;
112 
113 			if (t_level >= level) {
114 				// Close out level
115 				switch (t_level) {
116 					case 3:
117 						pad(out, 1, scratch);
118 						print_const("\\end{frame}\n\n");
119 						scratch->padded = 2;
120 						break;
121 
122 					case 4:
123 						pad(out, 1, scratch);
124 						print_const("}\n\n");
125 						scratch->padded = 2;
126 						break;
127 				}
128 
129 				stack_pop(s);
130 				t = stack_peek(s);
131 			} else {
132 				// Nothing to close
133 				t = NULL;
134 			}
135 		}
136 	}
137 
138 
139 	// Add current level to stack and open
140 	switch (level) {
141 		case 3:
142 			pad(out, 2, scratch);
143 			print_const("\\begin{frame}[fragile]\n");
144 			scratch->padded = 1;
145 			stack_push(s, current);
146 			break;
147 
148 		case 4:
149 			pad(out, 2, scratch);
150 			print_const("\\mode<article>{");
151 			scratch->padded = 0;
152 			stack_push(s, current);
153 			break;
154 	}
155 }
156 
157 
158 void mmd_export_token_beamer(DString * out, const char * source, token * t, scratch_pad * scratch) {
159 	if (t == NULL) {
160 		return;
161 	}
162 
163 	short	temp_short;
164 	char *	temp_char	= NULL;
165 	token *	temp_token	= NULL;
166 
167 	switch (t->type) {
168 		case DOC_START_TOKEN:
169 			mmd_export_token_tree_beamer(out, source, t->child, scratch);
170 			break;
171 
172 		case BLOCK_CODE_FENCED:
173 			pad(out, 2, scratch);
174 
175 			temp_char = get_fence_language_specifier(t->child->child, source);
176 
177 			if (temp_char) {
178 				if (strncmp("{=", temp_char, 2) == 0) {
179 					// Raw source
180 					if (raw_filter_text_matches(temp_char, FORMAT_BEAMER)) {
181 						switch (t->child->tail->type) {
182 							case LINE_FENCE_BACKTICK_3:
183 							case LINE_FENCE_BACKTICK_4:
184 							case LINE_FENCE_BACKTICK_5:
185 								temp_token = t->child->tail;
186 								break;
187 
188 							default:
189 								temp_token = NULL;
190 						}
191 
192 						if (temp_token) {
193 							d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
194 							scratch->padded = 1;
195 						} else {
196 							if (t->child->next) {
197 								d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
198 							}
199 
200 							scratch->padded = 0;
201 						}
202 					}
203 
204 					free(temp_char);
205 					break;
206 				}
207 
208 				printf("\\begin{lstlisting}[language=%s]\n", temp_char);
209 			} else {
210 				print_const("\\begin{verbatim}\n");
211 			}
212 
213 			mmd_export_token_tree_latex_raw(out, source, t->child->next, scratch);
214 
215 			if (temp_char) {
216 				print_const("\\end{lstlisting}");
217 				free(temp_char);
218 			} else {
219 				print_const("\\end{verbatim}");
220 			}
221 
222 			scratch->padded = 0;
223 			break;
224 
225 		case BLOCK_CODE_INDENTED:
226 			pad(out, 2, scratch);
227 			print_const("\\begin{verbatim}\n");
228 			mmd_export_token_tree_latex_raw(out, source, t->child, scratch);
229 			print_const("\\end{verbatim}");
230 			scratch->padded = 0;
231 			break;
232 
233 		case BLOCK_H1:
234 		case BLOCK_H2:
235 		case BLOCK_H3:
236 		case BLOCK_H4:
237 		case BLOCK_H5:
238 		case BLOCK_H6:
239 		case BLOCK_SETEXT_1:
240 		case BLOCK_SETEXT_2:
241 			pad(out, 2, scratch);
242 
243 			mmd_outline_add_beamer(out, t, scratch);
244 
245 			switch (t->type) {
246 				case BLOCK_SETEXT_1:
247 					temp_short = 1;
248 					break;
249 
250 				case BLOCK_SETEXT_2:
251 					temp_short = 2;
252 					break;
253 
254 				default:
255 					temp_short = t->type - BLOCK_H1 + 1;
256 			}
257 
258 			switch (temp_short + scratch->base_header_level - 1) {
259 				case 1:
260 					print_const("\\part{");
261 					break;
262 
263 				case 2:
264 					print_const("\\section{");
265 					break;
266 
267 				case 3:
268 					print_const("\\frametitle{");
269 					break;
270 
271 				default:
272 					print_const("\\emph{");
273 					break;
274 			}
275 
276 			mmd_export_token_tree_beamer(out, source, t->child, scratch);
277 			trim_trailing_whitespace_d_string(out);
278 
279 			if (scratch->extensions & EXT_NO_LABELS) {
280 				print_const("}");
281 			} else {
282 				temp_token = manual_label_from_header(t, source);
283 
284 				if (temp_token) {
285 					temp_char = label_from_token(source, temp_token);
286 				} else {
287 					temp_char = label_from_token(source, t);
288 				}
289 
290 				printf("}\n\\label{%s}", temp_char);
291 
292 				if (temp_char) {
293 					free(temp_char);
294 				}
295 			}
296 
297 			scratch->padded = 0;
298 			break;
299 
300 		default:
301 			// Default to LaTeX behavior
302 			mmd_export_token_latex(out, source, t, scratch);
303 	}
304 }
305 
306 
307 void mmd_export_token_tree_beamer(DString * out, const char * source, token * t, scratch_pad * scratch) {
308 
309 	// Prevent stack overflow with "dangerous" input causing extreme recursion
310 	if (scratch->recurse_depth == kMaxExportRecursiveDepth) {
311 		return;
312 	}
313 
314 	scratch->recurse_depth++;
315 
316 	while (t != NULL) {
317 		if (scratch->skip_token) {
318 			scratch->skip_token--;
319 		} else {
320 			mmd_export_token_beamer(out, source, t, scratch);
321 		}
322 
323 		t = t->next;
324 	}
325 
326 	scratch->recurse_depth--;
327 }
328 
329 
330 void mmd_export_citation_list_beamer(DString * out, const char * source, scratch_pad * scratch) {
331 	if (scratch->used_citations->size > 0) {
332 		footnote * note;
333 		token * content;
334 
335 		pad(out, 2, scratch);
336 		print_const("\\part{Bibliography}\n\\begin{frame}[allowframebreaks]\n\\frametitle{Bibliography}\n\\def\\newblock{}\n\\begin{thebibliography}{0}");
337 		scratch->padded = 0;
338 
339 		for (int i = 0; i < scratch->used_citations->size; ++i) {
340 			// Export footnote
341 			pad(out, 2, scratch);
342 
343 			note = stack_peek_index(scratch->used_citations, i);
344 
345 			printf("\\bibitem{%s}\n", note->label_text);
346 			scratch->padded = 6;
347 
348 			scratch->footnote_para_counter = 0;
349 
350 			content = note->content;
351 			scratch->citation_being_printed = i + 1;
352 
353 			mmd_export_token_tree_latex(out, source, content, scratch);
354 		}
355 
356 		pad(out, 1, scratch);
357 		print_const("\\end{thebibliography}\n\\end{frame}");
358 		scratch->padded = 0;
359 		scratch->citation_being_printed = 0;
360 	}
361 }
362 
363 
364 void mmd_end_complete_beamer(DString * out, const char * source, scratch_pad * scratch) {
365 	pad(out, 2, scratch);
366 
367 	print_const("\\mode<all>\n");
368 	meta * m = extract_meta_from_stack(scratch, "latexfooter");
369 
370 	if (m) {
371 		printf("\\input{%s}\n\n", m->value);
372 	} else {
373 		m = extract_meta_from_stack(scratch, "latexconfig");
374 
375 		if (m) {
376 			printf("\\input{mmd6-%s-footer}\n", m->value);
377 		}
378 	}
379 
380 	print_const("\\end{document}");
381 	print_const("\\mode*\n");
382 	scratch->padded = 0;
383 }
384