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