latex.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. #include <string.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include <stdbool.h>
  6. #include <regex.h>
  7. #include <hoedown/escape.h>
  8. #include <hoedown/document.h>
  9. #include "main.h"
  10. #include "latex.h"
  11. #include "str_split.h"
  12. #include "postproc.h"
  13. static int rndr_autolink(
  14. hoedown_buffer *ob,
  15. const hoedown_buffer *link,
  16. hoedown_autolink_type type,
  17. const hoedown_renderer_data *data) {
  18. hoedown_latex_renderer_state *state = data->opaque;
  19. if (!link || !link->size) {
  20. return 0;
  21. }
  22. HOEDOWN_BUFPUTSL(ob, "\\href{");
  23. if (type == HOEDOWN_AUTOLINK_EMAIL) {
  24. HOEDOWN_BUFPUTSL(ob, "mailto:");
  25. }
  26. hoedown_buffer_put(ob, link->data, link->size);
  27. HOEDOWN_BUFPUTSL(ob, "}{");
  28. if (hoedown_buffer_prefix(link, "mailto:") == 0) {
  29. hoedown_buffer_put(ob, link->data + 7, link->size - 7);
  30. } else {
  31. hoedown_buffer_put(ob, link->data, link->size);
  32. }
  33. HOEDOWN_BUFPUTSL(ob, "}");
  34. return 1;
  35. }
  36. static void rndr_blockcode(
  37. hoedown_buffer *ob,
  38. const hoedown_buffer *text,
  39. const hoedown_buffer *lang,
  40. const hoedown_renderer_data *data) {
  41. hoedown_latex_renderer_state *state = data->opaque;
  42. if (ob->size) {
  43. hoedown_buffer_putc(ob, '\n');
  44. }
  45. bool lang_detected = false;
  46. bool lang_supported = false;
  47. char* language_brackets = (char*)malloc(1);
  48. language_brackets = '\0';
  49. char* language = (char*)malloc(1);
  50. language[0] = '\0';
  51. if(state->use_minted && lang && lang->size > strlen("{.}")) {
  52. // The "lang" structure encodes for a brace-delimited
  53. // markdown string, eg "{.c}".
  54. // We first extract that substring from lang->data,
  55. // then we remove the brackets and fullstop as an extra
  56. // step to get the final language string.
  57. lang_detected = true;
  58. language_brackets = (char*)malloc(lang->size+1);
  59. if(!language_brackets) {
  60. fprintf(stderr, "Could not allocate memory.\n");
  61. exit(1);
  62. }
  63. substring(language_brackets, lang->data, 0, lang->size);
  64. int nremove = sizeof("{.}") - 1;
  65. language = (char*)malloc(sizeof(language_brackets)-nremove);
  66. if(!language) {
  67. fprintf(stderr, "Could not allocate memory.\n");
  68. exit(1);
  69. }
  70. substring(language, language_brackets, sizeof("{.")-1, lang->size - sizeof("}"));
  71. /* Check whether language is supported by minted. */
  72. int L;
  73. for(L = 0; *(pygment_langs + L); ++L) {
  74. if(strcasecmp(*(pygment_langs + L), language) == 0) {
  75. lang_supported = true;
  76. }
  77. }
  78. }
  79. // write text to file.
  80. bool really_using_minted = state->use_minted && lang_detected && lang_supported;
  81. if(really_using_minted) {
  82. HOEDOWN_BUFPUTSL(ob, "\\begin{minted}{");
  83. hoedown_buffer_printf(ob, "%s", language);
  84. HOEDOWN_BUFPUTSL(ob, "}\n");
  85. } else {
  86. HOEDOWN_BUFPUTSL(ob, "\\begin{verbatim}\n");
  87. }
  88. if(text) {
  89. hoedown_buffer_put(ob, text->data, text->size);
  90. }
  91. if(really_using_minted) {
  92. HOEDOWN_BUFPUTSL(ob, "\\end{minted}\n");
  93. } else {
  94. HOEDOWN_BUFPUTSL(ob, "\\end{verbatim}\n");
  95. }
  96. // Tidy up
  97. if(language_brackets) {
  98. free(language_brackets);
  99. }
  100. language_brackets = NULL;
  101. if(language) {
  102. free(language);
  103. }
  104. language = NULL;
  105. }
  106. static void rndr_blockquote(
  107. hoedown_buffer *ob,
  108. const hoedown_buffer *content,
  109. const hoedown_renderer_data *data) {
  110. if(ob->size) {
  111. hoedown_buffer_putc(ob, '\n');
  112. }
  113. if(!content || content->size < 1) {
  114. return;
  115. }
  116. HOEDOWN_BUFPUTSL(ob, "\\begin{minipage}{0.9\\textwidth}\n");
  117. hoedown_buffer_put(ob, content->data, content->size);
  118. HOEDOWN_BUFPUTSL(ob, "\\end{minipage}\n\\vspace{\\baselineskip}\n\n");
  119. }
  120. static int rndr_codespan(
  121. hoedown_buffer *ob,
  122. const hoedown_buffer *text,
  123. const hoedown_renderer_data *data) {
  124. if(text) {
  125. HOEDOWN_BUFPUTSL(ob, "\\texttt{");
  126. char* line = (char*)malloc(text->size);
  127. substring(line, text->data, 0, text->size - 1);
  128. char* replacement = escape_latex_specials(line);
  129. hoedown_buffer_put(ob, replacement, strlen(replacement));
  130. HOEDOWN_BUFPUTSL(ob, "}");
  131. if(line) {
  132. free(line);
  133. }
  134. line = NULL;
  135. if(replacement) {
  136. free(replacement);
  137. }
  138. replacement = NULL;
  139. }
  140. return 1;
  141. }
  142. static int rndr_strikethrough(
  143. hoedown_buffer *ob,
  144. const hoedown_buffer *content,
  145. const hoedown_renderer_data *data) {
  146. if(content) {
  147. HOEDOWN_BUFPUTSL(ob, "\\sout{");
  148. hoedown_buffer_put(ob, content->data, content->size);
  149. HOEDOWN_BUFPUTSL(ob, "}");
  150. }
  151. return 1;
  152. }
  153. static int rndr_double_emphasis(
  154. hoedown_buffer *ob,
  155. const hoedown_buffer *content,
  156. const hoedown_renderer_data *data) {
  157. if(content) {
  158. HOEDOWN_BUFPUTSL(ob, "\\textsc{");
  159. hoedown_buffer_put(ob, content->data, content->size);
  160. HOEDOWN_BUFPUTSL(ob, "}");
  161. }
  162. return 1;
  163. }
  164. static int rndr_emphasis(
  165. hoedown_buffer *ob,
  166. const hoedown_buffer *content,
  167. const hoedown_renderer_data *data) {
  168. if(content) {
  169. HOEDOWN_BUFPUTSL(ob, "\\emph{");
  170. hoedown_buffer_put(ob, content->data, content->size);
  171. HOEDOWN_BUFPUTSL(ob, "}");
  172. }
  173. return 1;
  174. }
  175. static int rndr_underline(
  176. hoedown_buffer *ob,
  177. const hoedown_buffer *content,
  178. const hoedown_renderer_data *data) {
  179. if(content) {
  180. HOEDOWN_BUFPUTSL(ob, "\\underline{");
  181. hoedown_buffer_put(ob, content->data, content->size);
  182. HOEDOWN_BUFPUTSL(ob, "}");
  183. }
  184. return 1;
  185. }
  186. static int rndr_highlight(
  187. hoedown_buffer *ob,
  188. const hoedown_buffer *content,
  189. const hoedown_renderer_data *data) {
  190. return 1;
  191. }
  192. static int rndr_quote(
  193. hoedown_buffer *ob,
  194. const hoedown_buffer *content,
  195. const hoedown_renderer_data *data) {
  196. if (!content || !content->size) {
  197. return 0;
  198. }
  199. HOEDOWN_BUFPUTSL(ob, "``");
  200. hoedown_buffer_put(ob, content->data, content->size);
  201. HOEDOWN_BUFPUTSL(ob, "''");
  202. return 1;
  203. }
  204. static int rndr_linebreak(
  205. hoedown_buffer *ob,
  206. const hoedown_renderer_data *data) {
  207. return 1;
  208. }
  209. static void rndr_header(
  210. hoedown_buffer *ob,
  211. const hoedown_buffer *content,
  212. int level,
  213. const hoedown_renderer_data *data) {
  214. hoedown_latex_renderer_state *state = data->opaque;
  215. if (ob->size) {
  216. hoedown_buffer_putc(ob, '\n');
  217. }
  218. if(level < 5) { // Ignore higher section levels.
  219. hoedown_buffer_printf(ob, "\\");
  220. if(level == 1) {
  221. hoedown_buffer_printf(ob, "part");
  222. } else if(level <= 4) {
  223. int sub;
  224. for(sub = 3; sub <= level && sub <= 4; ++sub) {
  225. hoedown_buffer_printf(ob, "sub");
  226. }
  227. hoedown_buffer_printf(ob, "section");
  228. }
  229. }
  230. hoedown_buffer_printf(ob, "{");
  231. if (content) {
  232. hoedown_buffer_put(ob, content->data, content->size);
  233. }
  234. hoedown_buffer_printf(ob, "}\n");
  235. }
  236. static int rndr_link(
  237. hoedown_buffer *ob,
  238. const hoedown_buffer *content,
  239. const hoedown_buffer *link,
  240. const hoedown_buffer *title,
  241. const hoedown_renderer_data *data) {
  242. hoedown_latex_renderer_state *state = data->opaque;
  243. if (!link || !link->size) {
  244. return 0;
  245. }
  246. HOEDOWN_BUFPUTSL(ob, "\\href{");
  247. hoedown_buffer_put(ob, link->data, link->size);
  248. HOEDOWN_BUFPUTSL(ob, "}{");
  249. hoedown_buffer_put(ob, content->data, content->size);
  250. HOEDOWN_BUFPUTSL(ob, "}");
  251. return 1;
  252. }
  253. static void rndr_list(
  254. hoedown_buffer *ob,
  255. const hoedown_buffer *content,
  256. hoedown_list_flags flags,
  257. const hoedown_renderer_data *data) {
  258. if(ob->size) {
  259. hoedown_buffer_putc(ob, '\n');
  260. }
  261. if(flags & HOEDOWN_LIST_ORDERED) {
  262. HOEDOWN_BUFPUTSL(ob, "\\begin{enumerate}\n");
  263. } else {
  264. HOEDOWN_BUFPUTSL(ob, "\\begin{itemize}\n");
  265. }
  266. if(content) {
  267. hoedown_buffer_put(ob, content->data, content->size);
  268. }
  269. if(flags & HOEDOWN_LIST_ORDERED) {
  270. HOEDOWN_BUFPUTSL(ob, "\\end{enumerate}\n");
  271. } else {
  272. HOEDOWN_BUFPUTSL(ob, "\\end{itemize}\n");
  273. }
  274. }
  275. static void rndr_listitem(
  276. hoedown_buffer *ob,
  277. const hoedown_buffer *content,
  278. hoedown_list_flags flags,
  279. const hoedown_renderer_data *data) {
  280. HOEDOWN_BUFPUTSL(ob, " \\item ");
  281. if (content) {
  282. size_t size = content->size;
  283. while (size && content->data[size - 1] == '\n') {
  284. size--;
  285. }
  286. hoedown_buffer_put(ob, content->data, size);
  287. }
  288. HOEDOWN_BUFPUTSL(ob, "\n");
  289. }
  290. static void rndr_paragraph(
  291. hoedown_buffer *ob,
  292. const hoedown_buffer *content,
  293. const hoedown_renderer_data *data) {
  294. hoedown_latex_renderer_state *state = data->opaque;
  295. if (ob->size) {
  296. hoedown_buffer_putc(ob, '\n');
  297. }
  298. if (!content || !content->size) {
  299. return;
  300. }
  301. hoedown_buffer_put(ob, content->data, content->size);
  302. HOEDOWN_BUFPUTSL(ob, "\n");
  303. }
  304. static int rndr_triple_emphasis(
  305. hoedown_buffer *ob,
  306. const hoedown_buffer *content,
  307. const hoedown_renderer_data *data) {
  308. return 1;
  309. }
  310. static void rndr_hrule(
  311. hoedown_buffer *ob,
  312. const hoedown_renderer_data *data) {
  313. HOEDOWN_BUFPUTSL(ob, "\n\\begin{center}\n");
  314. HOEDOWN_BUFPUTSL(ob, "\\rule{0.95\\textwidth}{0.4pt}\n");
  315. HOEDOWN_BUFPUTSL(ob, "\\end{center}\n");
  316. }
  317. static int rndr_image(
  318. hoedown_buffer *ob,
  319. const hoedown_buffer *link,
  320. const hoedown_buffer *title,
  321. const hoedown_buffer *alt,
  322. const hoedown_renderer_data *data) {
  323. hoedown_latex_renderer_state *state = data->opaque;
  324. if(!link || !link->size) {
  325. return 0;
  326. }
  327. HOEDOWN_BUFPUTSL(ob, "\n\\begin{figure}[p]\n");
  328. HOEDOWN_BUFPUTSL(ob, "\\centering");
  329. HOEDOWN_BUFPUTSL(ob, "\\includegraphics[width=0.8\\textwidth]{");
  330. hoedown_buffer_put(ob, link->data, link->size);
  331. HOEDOWN_BUFPUTSL(ob, "}\n");
  332. if(alt && alt->size) {
  333. HOEDOWN_BUFPUTSL(ob, "\\caption{");
  334. hoedown_buffer_put(ob, alt->data, alt->size);
  335. HOEDOWN_BUFPUTSL(ob, "}\n");
  336. }
  337. if (title && title->size) {
  338. HOEDOWN_BUFPUTSL(ob, "\\label{");
  339. hoedown_buffer_put(ob, title->data, title->size);
  340. HOEDOWN_BUFPUTSL(ob, "}\n");
  341. }
  342. HOEDOWN_BUFPUTSL(ob, "\\end{figure}\n");
  343. return 1;
  344. }
  345. static int rndr_raw_html(
  346. hoedown_buffer *ob,
  347. const hoedown_buffer *text,
  348. const hoedown_renderer_data *data) {
  349. return 1;
  350. }
  351. static void rndr_table(
  352. hoedown_buffer *ob,
  353. const hoedown_buffer *content,
  354. const hoedown_renderer_data *data) {
  355. if(!content || content->size < 1) {
  356. return;
  357. }
  358. /* Form substring up to first newline ("\\") in content. */
  359. const char* newline_re = "\\\\";
  360. regex_t* newline = (regex_t*)malloc(sizeof(regex_t));
  361. if(!newline) {
  362. fprintf(stderr, "Failed to allocate memory to newline regex.\n");
  363. return;
  364. }
  365. if(regcomp(newline, newline_re, REG_EXTENDED) != 0) {
  366. fprintf(stderr, "Failed to compile regex '%s' for LaTeX newlines.\n", newline_re);
  367. return;
  368. }
  369. regmatch_t* group = (regmatch_t*)malloc(sizeof(regmatch_t));
  370. if(!group) {
  371. fprintf(stderr, "Failed to allocate memory for regex match group.\n");
  372. return;
  373. }
  374. size_t newline_pos;
  375. if(regexec(newline, content->data, 1, group, 0) == 0) {
  376. newline_pos = group->rm_so;
  377. } else {
  378. newline_pos = content->size;
  379. }
  380. char* row = (char*)malloc(newline_pos+1);
  381. if(!row) {
  382. fprintf(stderr, "Failed to allocate memory for row when rendering table.\n");
  383. return;
  384. }
  385. substring(row, content->data, 0, newline_pos);
  386. /* Count number of ampersands up to first newline. */
  387. const char* amp_re = "&";
  388. regex_t* amp = (regex_t*)malloc(sizeof(regex_t));
  389. if(!amp) {
  390. fprintf(stderr, "Failed to allocate memory to ampersand regex.\n");
  391. return;
  392. }
  393. if(regcomp(amp, amp_re, REG_EXTENDED) != 0) {
  394. fprintf(stderr, "Failed to compile regex '%s' for LaTeX column dividers.\n", newline_re);
  395. return;
  396. }
  397. char* cursor = row;
  398. int ncols = 1;
  399. while(regexec(amp, cursor, 1, group, 0) == 0) {
  400. cursor += group->rm_eo;
  401. ++ncols;
  402. }
  403. /* Tidy up */
  404. if(row) {
  405. free(row);
  406. }
  407. row = NULL;
  408. if(group) {
  409. free(group);
  410. }
  411. group = NULL;
  412. regfree(amp);
  413. regfree(newline);
  414. /* Render the table */
  415. HOEDOWN_BUFPUTSL(ob, "\\begin{table}[h]\n");
  416. HOEDOWN_BUFPUTSL(ob, "\\centering\n");
  417. HOEDOWN_BUFPUTSL(ob, "\\begin{tabular}{l");
  418. int col;
  419. for(col = 1; col < ncols; ++col) {
  420. HOEDOWN_BUFPUTSL(ob, " l");
  421. }
  422. HOEDOWN_BUFPUTSL(ob, "}\n");
  423. hoedown_buffer_put(ob, content->data, content->size);
  424. HOEDOWN_BUFPUTSL(ob, "\\end{tabular}\n");
  425. HOEDOWN_BUFPUTSL(ob, "\\end{table}\n");
  426. }
  427. static void rndr_table_header(
  428. hoedown_buffer *ob,
  429. const hoedown_buffer *content,
  430. const hoedown_renderer_data *data) {
  431. if(!content || content->size < 0) {
  432. return;
  433. }
  434. hoedown_buffer_put(ob, content->data, content->size);
  435. HOEDOWN_BUFPUTSL(ob, "\\hline\n");
  436. }
  437. static void rndr_table_body(
  438. hoedown_buffer *ob,
  439. const hoedown_buffer *content,
  440. const hoedown_renderer_data *data) {
  441. if(!content || content->size < 0) {
  442. return;
  443. }
  444. hoedown_buffer_put(ob, content->data, content->size);
  445. HOEDOWN_BUFPUTSL(ob, "\\hline\n");
  446. }
  447. static void rndr_table_row(
  448. hoedown_buffer *ob,
  449. const hoedown_buffer *content,
  450. const hoedown_renderer_data *data) {
  451. if(!content || content->size < 0) {
  452. return;
  453. }
  454. hoedown_latex_renderer_state* state = data->opaque;
  455. state->column_number = 0;
  456. hoedown_buffer_put(ob, content->data, content->size);
  457. HOEDOWN_BUFPUTSL(ob, " \\\\\n");
  458. }
  459. static void rndr_table_cell(
  460. hoedown_buffer *ob,
  461. const hoedown_buffer *content,
  462. hoedown_table_flags flags,
  463. const hoedown_renderer_data *data) {
  464. if(!content || content->size < 0) {
  465. return;
  466. }
  467. hoedown_latex_renderer_state* state = data->opaque;
  468. state->column_number++;
  469. if(state->column_number > 1) {
  470. HOEDOWN_BUFPUTSL(ob, " & ");
  471. }
  472. hoedown_buffer_put(ob, content->data, content->size);
  473. }
  474. static int rndr_superscript(
  475. hoedown_buffer *ob,
  476. const hoedown_buffer *content,
  477. const hoedown_renderer_data *data) {
  478. return 1;
  479. }
  480. static void rndr_entity(
  481. hoedown_buffer *ob,
  482. const hoedown_buffer *text,
  483. const hoedown_renderer_data *data) {
  484. }
  485. static void rndr_normal_text(
  486. hoedown_buffer *ob,
  487. const hoedown_buffer *content,
  488. const hoedown_renderer_data *data) {
  489. if(!content || content->size < 1) {
  490. return;
  491. }
  492. char* line = (char*)malloc(content->size+1);
  493. if(!line) {
  494. fprintf(stderr, "Failed to allocate memory for line of normal text.\n");
  495. return;
  496. }
  497. substring(line, content->data, 0, content->size-1);
  498. postprocess_line(ob, line, content->size);
  499. if(line) {
  500. free(line);
  501. }
  502. line = NULL;
  503. }
  504. static void rndr_footnotes(
  505. hoedown_buffer *ob,
  506. const hoedown_buffer *content,
  507. const hoedown_renderer_data *data) {
  508. if(!content || content->size < 0) {
  509. return;
  510. }
  511. hoedown_buffer_put(ob, content->data, content->size);
  512. }
  513. static void rndr_footnote_def(
  514. hoedown_buffer *ob,
  515. const hoedown_buffer *content,
  516. unsigned int num,
  517. const hoedown_renderer_data *data) {
  518. if(!content || content->size < 0) {
  519. return;
  520. }
  521. hoedown_buffer_printf(ob, "\\footnotetext[%d]{", num);
  522. hoedown_buffer_put(ob, content->data, content->size);
  523. HOEDOWN_BUFPUTSL(ob, "}\n");
  524. }
  525. static int rndr_footnote_ref(
  526. hoedown_buffer *ob,
  527. unsigned int num,
  528. const hoedown_renderer_data *data) {
  529. hoedown_buffer_printf(ob, "\\footnotemark[%d]", num);
  530. return 1;
  531. }
  532. static void rndr_blockhtml(
  533. hoedown_buffer *ob,
  534. const hoedown_buffer *text,
  535. const hoedown_renderer_data *data) {
  536. if (ob->size) hoedown_buffer_putc(ob, '\n');
  537. HOEDOWN_BUFPUTSL(ob, "\\begin{verbatim}\n");
  538. if (text) {
  539. hoedown_buffer_put(ob, text->data, text->size);
  540. }
  541. HOEDOWN_BUFPUTSL(ob, "\\end{verbatim}\n");
  542. }
  543. static int rndr_math(
  544. hoedown_buffer *ob,
  545. const hoedown_buffer *text,
  546. int displaymode,
  547. const hoedown_renderer_data *data) {
  548. hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\[" : "$"), 2);
  549. hoedown_buffer_put(ob, text->data, text->size);
  550. hoedown_buffer_put(ob, (const uint8_t *)(displaymode ? "\\]" : "$"), 2);
  551. return 1;
  552. }
  553. static void rndr_preamble(
  554. hoedown_buffer *ob,
  555. int inline_render,
  556. const hoedown_renderer_data *data) {
  557. hoedown_latex_renderer_state *state = data->opaque;
  558. HOEDOWN_BUFPUTSL(ob, "\\documentclass[12pt,a4paper]{article}\n");
  559. HOEDOWN_BUFPUTSL(ob, "\\usepackage[bookmarks=false, pdfstartview=FitH]{hyperref}\n");
  560. HOEDOWN_BUFPUTSL(ob, "\\hypersetup{\n");
  561. HOEDOWN_BUFPUTSL(ob, " colorlinks=true,\n");
  562. HOEDOWN_BUFPUTSL(ob, " urlcolor=blue,\n");
  563. HOEDOWN_BUFPUTSL(ob, " linkcolor=black,\n");
  564. HOEDOWN_BUFPUTSL(ob, " citecolor=black\n");
  565. HOEDOWN_BUFPUTSL(ob, "}\n");
  566. HOEDOWN_BUFPUTSL(ob, "\\usepackage{enumitem}\n");
  567. HOEDOWN_BUFPUTSL(ob, "\\usepackage{placeins}\n");
  568. HOEDOWN_BUFPUTSL(ob, "\\usepackage{graphicx}\n");
  569. HOEDOWN_BUFPUTSL(ob, "\\usepackage[autostyle]{csquotes}\n");
  570. HOEDOWN_BUFPUTSL(ob, "\\usepackage[normalem]{ulem}\n");
  571. if(state->use_minted) {
  572. HOEDOWN_BUFPUTSL(ob, "\\usepackage{minted}\n");
  573. }
  574. if(state->titledata.title != NULL && strlen(state->titledata.title) > 0) {
  575. HOEDOWN_BUFPUTSL(ob, "\\title{");
  576. hoedown_buffer_printf(ob, "%s", state->titledata.title);
  577. HOEDOWN_BUFPUTSL(ob, "}\n");
  578. if(state->titledata.author != NULL && strlen(state->titledata.author) > 0) {
  579. HOEDOWN_BUFPUTSL(ob, "\\author{");
  580. char** authors = str_split(state->titledata.author, '\n');
  581. hoedown_buffer_printf(ob, "%s\n", authors[0]);
  582. int a;
  583. for(a = 1; *(authors + a); ++a) {
  584. HOEDOWN_BUFPUTSL(ob, " \\and ");
  585. hoedown_buffer_printf(ob, "%s\n", authors[a]);
  586. free(authors[a]);
  587. authors[a] = NULL;
  588. }
  589. free(authors);
  590. authors = NULL;
  591. HOEDOWN_BUFPUTSL(ob, "}\n");
  592. }
  593. if(state->titledata.date_given) {
  594. HOEDOWN_BUFPUTSL(ob, "\\date{");
  595. if(state->titledata.date != NULL && strlen(state->titledata.date) > 0) {
  596. hoedown_buffer_printf(ob, "%s", state->titledata.date);
  597. }
  598. HOEDOWN_BUFPUTSL(ob, "}\n");
  599. }
  600. }
  601. HOEDOWN_BUFPUTSL(ob, "\\begin{document}\n");
  602. if(state->titledata.title != NULL && strlen(state->titledata.title) > 0) {
  603. HOEDOWN_BUFPUTSL(ob, "\\maketitle\n");
  604. }
  605. HOEDOWN_BUFPUTSL(ob, "\\tableofcontents\n");
  606. }
  607. static void rndr_end_document(
  608. hoedown_buffer *ob,
  609. int inline_render,
  610. const hoedown_renderer_data *data) {
  611. HOEDOWN_BUFPUTSL(ob, "\\end{document}\n");
  612. }
  613. hoedown_renderer *hoedown_latex_renderer_new(hoedown_latex_title_data* td, bool mint) {
  614. static const hoedown_renderer cb_default = {
  615. //opaque
  616. NULL,
  617. //blockcode
  618. rndr_blockcode,
  619. //blockquote
  620. rndr_blockquote,
  621. //header
  622. rndr_header,
  623. //hrule
  624. rndr_hrule,
  625. //list
  626. rndr_list,
  627. //listitem
  628. rndr_listitem,
  629. //paragraph
  630. rndr_paragraph,
  631. //table
  632. rndr_table,
  633. //table_header
  634. rndr_table_header,
  635. //table_body
  636. rndr_table_body,
  637. //table_row
  638. rndr_table_row,
  639. //table_cell
  640. rndr_table_cell,
  641. //footnotes
  642. rndr_footnotes,
  643. //footnote_def
  644. rndr_footnote_def,
  645. //blockhtml
  646. rndr_blockhtml,
  647. //autolink
  648. rndr_autolink,
  649. //codespan
  650. rndr_codespan,
  651. //double_emphasis
  652. rndr_double_emphasis,
  653. //emphasis
  654. rndr_emphasis,
  655. //underline
  656. rndr_underline,
  657. //highlight
  658. NULL,
  659. //quote
  660. rndr_quote,
  661. //image
  662. rndr_image,
  663. //linebreak
  664. rndr_linebreak,
  665. //link
  666. rndr_link,
  667. //triple_emphasis
  668. NULL,
  669. //strikethrough
  670. rndr_strikethrough,
  671. //superscript
  672. rndr_superscript,
  673. //footnote_ref
  674. rndr_footnote_ref,
  675. //math
  676. rndr_math,
  677. //raw_html
  678. rndr_codespan,
  679. //entity
  680. rndr_entity,
  681. //normal_text
  682. rndr_normal_text,
  683. //doc_header
  684. rndr_preamble,
  685. //doc_footer
  686. rndr_end_document
  687. };
  688. /* Prepare the state pointer */
  689. hoedown_latex_renderer_state *state;
  690. state = hoedown_malloc(sizeof(hoedown_latex_renderer_state));
  691. memset(state, 0x0, sizeof(hoedown_latex_renderer_state));
  692. state->titledata = *td;
  693. state->use_minted = mint;
  694. /* Prepare the renderer */
  695. hoedown_renderer *renderer;
  696. renderer = hoedown_malloc(sizeof(hoedown_renderer));
  697. memcpy(renderer, &cb_default, sizeof(hoedown_renderer));
  698. renderer->opaque = state;
  699. return renderer;
  700. }
  701. void hoedown_latex_renderer_free(hoedown_renderer * renderer) {
  702. free(renderer->opaque);
  703. free(renderer);
  704. }
  705. void hoedown_render(FILE* fp, hoedown_latex_title_data* td, bool mint) {
  706. hoedown_buffer *ib;
  707. ib = hoedown_buffer_new(IUNIT);
  708. bool proc_input_success = (hoedown_buffer_putf(ib, fp) == 0);
  709. if(fp != NULL) {
  710. fclose(fp);
  711. }
  712. fp = NULL;
  713. if(!proc_input_success) {
  714. fprintf(stderr, "Error reading input.\n");
  715. if(ib) {
  716. hoedown_buffer_free(ib);
  717. }
  718. exit(IO_ERROR);
  719. }
  720. /* Print in defined output format to destination. */
  721. unsigned int extensions = HOEDOWN_EXT_FENCED_CODE
  722. | HOEDOWN_EXT_AUTOLINK
  723. | HOEDOWN_EXT_MATH
  724. | HOEDOWN_EXT_MATH_EXPLICIT
  725. | HOEDOWN_EXT_STRIKETHROUGH
  726. | HOEDOWN_EXT_UNDERLINE
  727. | HOEDOWN_EXT_TABLES
  728. | HOEDOWN_EXT_FOOTNOTES
  729. | HOEDOWN_EXT_QUOTE;
  730. hoedown_renderer* renderer = hoedown_latex_renderer_new(td, mint);
  731. hoedown_document* document = hoedown_document_new(renderer, extensions, 16);
  732. hoedown_buffer* ob = hoedown_buffer_new(16);
  733. hoedown_document_render(document, ob, ib->data, ib->size);
  734. (void)fwrite(ob->data, ob->size, 1, stdout);
  735. /* Tidy up */
  736. hoedown_buffer_free(ob);
  737. hoedown_buffer_free(ib);
  738. hoedown_document_free(document);
  739. hoedown_latex_renderer_free(renderer);
  740. }
  741. void free_title_data(hoedown_latex_title_data* td) {
  742. if(td->title && strlen(td->title) > 0) {
  743. free(td->title);
  744. }
  745. td->title = NULL;
  746. if(td->author && strlen(td->author) > 0) {
  747. free(td->author);
  748. }
  749. td->author = NULL;
  750. if(td->date && strlen(td->date) > 0) {
  751. free(td->date);
  752. }
  753. td->date = NULL;
  754. if(td) {
  755. free(td);
  756. }
  757. }