thesiscomposer.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. <?php
  2. global $options;
  3. $options = [];
  4. global $preamble;
  5. global $sloppy_begin;
  6. global $sloppy_end;
  7. $sloppy_begin = "";
  8. $sloppy_end = "";
  9. $preamble = "";
  10. global $kpsefiles;
  11. $kpsefiles = [];
  12. global $ignore_packages;
  13. $ignore_packages = [];
  14. global $existing_mathops;
  15. $existing_mathops = [];
  16. global $tikzlibs;
  17. $tikzlibs = [];
  18. global $included_usepackages;
  19. $included_usepackages = [];
  20. global $additional_usepackages;
  21. $additional_usepackages = [];
  22. $steps = 10;
  23. function user_consent($msg,$defaultyes = null,$defaultno = null)
  24. {
  25. global $options;
  26. if ($defaultyes !== null && isset($options[$defaultyes]))
  27. return true;
  28. if ($defaultno !== null && isset($options[$defaultno]))
  29. return false;
  30. if (isset($options["-n"]))
  31. return false;
  32. $response = false;
  33. do
  34. {
  35. echo "$msg (y/n)\n";
  36. $response = rtrim(fgets(STDIN));
  37. if ($response === "n" || $response == "N")
  38. return false;
  39. } while ($response !== "y" && $response !== "Y" && $response !== "");
  40. return true;
  41. }
  42. function user_prompt($msg,$default)
  43. {
  44. global $options;
  45. if (!isset($options["-n"]))
  46. echo "$msg [Default: $default]\n";
  47. $response = "";
  48. if (!isset($options["-n"]))
  49. $response = rtrim(fgets(STDIN));
  50. if ($response == "")
  51. $response = $default;
  52. if (!isset($options["-n"]))
  53. echo "You entered: '$response'\n";
  54. return $response;
  55. }
  56. function print_help()
  57. {
  58. $name = basename(__FILE__);
  59. echo<<<END
  60. Usage: php thesiscomposer.php /path/folder1/main.tex /path/folder2/article.tex ... /path/folderN/paper.tex\n
  61. Generate a thesis template from the provided paper tex files and folders.
  62. You can also provide pdf files instead of tex files or a mix of both.
  63. The absolute minimum for a cumulative thesis is currently 3 papers first-authored and 6 in total.
  64. --force-overwrite overwrite files and folders
  65. --no-overwrite do not overwrite files and folders
  66. --no-compile-check do not perform a compile check
  67. --use-backups restore backups before making changes
  68. --no-cover do not generate book cover pdf files
  69. --use-subimport use \subimport for your papers / chapters
  70. --use-include use \include for your papers / chapters
  71. --compile run latexmk on the resulting main.tex of your generated thesis
  72. --not-sloppy disable use of sloppypar around places that struggle without
  73. (mainly the bibliographies)
  74. --cv add a CV
  75. (unusual for PhD theses, required for habilitation theses)
  76. --no-stat-declaration do not add the statutory declaration
  77. (required for PhD thesis, unusual for habilitation theses)
  78. -n skip all prompts (implies --no-overwrite)
  79. --help display this help and exit
  80. END;
  81. exit(0);
  82. }
  83. function error_exit($msg,$usage = false)
  84. {
  85. echo "ERROR: $msg\n";
  86. if ($usage)
  87. echo "Usage: php ".basename(__FILE__)." /path/folder1/main.tex /path/folder2/article.tex ... /path/folderN/paper.tex\n";
  88. exit(-1);
  89. }
  90. function check_software()
  91. {
  92. if (strpos(shell_exec("latexmk --version"),"Latexmk,") === false)
  93. error_exit("latexmk not installed");
  94. if (!str_starts_with(shell_exec("pdftotext --help 2>&1"),"pdftotext version"))
  95. error_exit("pdftotext not installed");
  96. }
  97. function rrmdir($dir) {
  98. if (is_dir($dir)) {
  99. $files = scandir($dir);
  100. foreach ($files as $file)
  101. if ($file != "." && $file != "..") rrmdir("$dir/$file");
  102. rmdir($dir);
  103. }
  104. else if (file_exists($dir)) unlink($dir);
  105. }
  106. function rcopy($src, $dst) {
  107. if (file_exists($dst)) rrmdir($dst);
  108. if (is_dir($src)) {
  109. mkdir($dst);
  110. $files = scandir($src);
  111. foreach ($files as $file)
  112. if ($file != "." && $file != "..") rcopy("$src/$file", "$dst/$file");
  113. }
  114. else if (file_exists($src)) copy($src, $dst);
  115. }
  116. function rscandir($dir,$extensions = []) {
  117. $result = [];
  118. if (!str_ends_with($dir,"/"))
  119. $dir .= "/";
  120. if (str_ends_with($dir,"latex.out/"))
  121. return $result;
  122. $array = scandir($dir);
  123. foreach ($array as $item) {
  124. if (!str_starts_with($item,"."))
  125. {
  126. if (!is_dir($dir.$item))
  127. {
  128. $extension_match = true;
  129. if ($extensions != [])
  130. {
  131. $extension_match = false;
  132. foreach ($extensions as $e)
  133. {
  134. if (str_ends_with($item,"$e"))
  135. {
  136. $extension_match = true;
  137. }
  138. }
  139. }
  140. if ($extension_match)
  141. $result[] = $dir.$item;
  142. }
  143. else
  144. $result = array_merge($result, rscandir($dir.$item,$extensions));
  145. }
  146. }
  147. return $result;
  148. }
  149. function unique_targets($targets)
  150. {
  151. $parts_required = 1;
  152. $unique_targets = [];
  153. while (count($unique_targets) != count($targets))
  154. {
  155. foreach ($targets as $t)
  156. {
  157. $tparts = explode("/",$t);
  158. $tpcount = count($tparts);
  159. $tparts = array_splice($tparts,$tpcount-$parts_required,$parts_required);
  160. $t = implode("_",$tparts);
  161. if (isset($unique_targets[$t]))
  162. {
  163. $parts_required++;
  164. $unique_targets = [];
  165. break;
  166. }
  167. $unique_targets[$t] = 1;
  168. }
  169. }
  170. return array_keys($unique_targets);
  171. }
  172. function check_folders($argv)
  173. {
  174. $sourcedirs = [];
  175. foreach ($argv as $a)
  176. {
  177. if (!str_starts_with($a,"-"))
  178. $sourcedirs[] = $a;
  179. }
  180. if (count($sourcedirs) < 1)
  181. {
  182. error_exit("Too few papers. Need at least one paper to run this.",true);
  183. }
  184. if (count($sourcedirs) < 3)
  185. {
  186. echo "Warning: Too few papers. The statutes require as an absolute minimum for a cumulative thesis at least 3 first-author papers and at least 6 in total.";
  187. }
  188. if (count($sourcedirs) < 5)
  189. {
  190. echo "Warning: Few papers. Check your institute guidelines to see how many papers are recommended. Also the statutes require as an absolute minimum for a cumulative thesis at least 6 papers in total.";
  191. }
  192. $texfiles = [];
  193. for ($i = 0; $i < count($sourcedirs); $i++)
  194. {
  195. $texfiles[$i] = basename($sourcedirs[$i]);
  196. $sourcedirs[$i] = dirname($sourcedirs[$i]);
  197. }
  198. $targets = unique_targets($sourcedirs);
  199. return [$targets,$texfiles,$sourcedirs];
  200. }
  201. function check_and_copy_folders($argv)
  202. {
  203. [$targets,$texfiles,$sourcedirs] = check_folders($argv);
  204. //echo "Source -> Target Directory Mapping:\n";
  205. $n = count($sourcedirs);
  206. //print_r($mapping);
  207. for ($i = 0; $i < $n; $i++)
  208. {
  209. $s = $sourcedirs[$i];
  210. $t = $targets[$i];
  211. $f = $texfiles[$i];
  212. if (str_ends_with($f,".pdf"))
  213. {
  214. if (!file_exists("$s/$f"))
  215. error_exit("$s/$f not found");
  216. if (file_exists("$t/$f.pdf") && !user_consent("$t/$f.pdf already exists... overwrite?","--force-overwrite","--no-overwrite"))
  217. {
  218. echo "Skipping $s/$f, $t/$f.pdf already exists...\n";
  219. }
  220. else
  221. {
  222. echo "Copying $s/$f to $t/$f...\n";
  223. if (!file_exists($t)) mkdir($t);
  224. rcopy("$s/$f","$t/$f");
  225. }
  226. }
  227. else
  228. {
  229. if (!file_exists($s))
  230. error_exit("$s not found");
  231. if (file_exists($t) && !user_consent("$t already exists... overwrite?","--force-overwrite","--no-overwrite"))
  232. {
  233. echo "Skipping ".$s.", ".$t." already exists...\n";
  234. }
  235. else
  236. {
  237. echo "Copying ".$s." to ".$t."...\n";
  238. rcopy($s,$t);
  239. }
  240. }
  241. }
  242. return array_combine($targets,$texfiles);
  243. }
  244. function file_get_and_backup($f,$bak = ".orig_bak")
  245. {
  246. global $options;
  247. if (isset($options["--use-backups"]))
  248. {
  249. if (file_exists("$f$bak"))
  250. copy("$f$bak", $f);
  251. }
  252. $content = file_get_contents("$f");
  253. if (!file_exists("$f$bak"))
  254. file_put_contents("$f$bak",$content);
  255. return $content;
  256. }
  257. function adjust_references($papers,$extensions = [])
  258. {
  259. $bibresources = [];
  260. foreach ($papers as $d => $f)
  261. {
  262. if (str_ends_with($f,".pdf"))
  263. continue;
  264. $files = rscandir($d,$extensions);
  265. foreach ($files as $file)
  266. {
  267. if (str_ends_with($file,".bib"))
  268. {
  269. $bib = file_get_and_backup($file);
  270. $bib = str_replace('\`','\\\'',$bib);
  271. $bib = preg_replace("/(^\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib);
  272. $bib = preg_replace("/(\n\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib);
  273. $bib = preg_replace("/([\{\"].*)[^\\\\]#(.*)/i",'${1}\#${2}',$bib);
  274. $bib = str_replace('\i}','i}',$bib);
  275. $bib = str_replace('$\textregistered$','\textregistered',$bib);
  276. $bib = str_replace('{$\textquoteright$}','\'',$bib);
  277. file_put_contents($file,$bib);
  278. $bibresources[$d][] = $file;
  279. }
  280. else
  281. {
  282. $tex = file_get_and_backup($file);
  283. // labels of lstlistings etc
  284. $lstlistings = [];
  285. preg_match_all("/(\\\\begin{lstlisting}.*?\\\\end{lstlisting}|\\\\lstset\s*(?<R>{((?:[^{}]+|(?&R))*)}))/sim",$tex,$lstlistings);
  286. if (count($lstlistings[0]) > 0)
  287. foreach ($lstlistings[0] as $l)
  288. {
  289. $l2 = preg_replace("/(label\s*=\s*\{?)(?!$d)/i",'${1}'.$d.':',$l);
  290. $tex = str_replace($l,$l2,$tex);
  291. }
  292. // normal labels
  293. $tex = preg_replace("/(\\\label\s*\{\s*)((?!$d)[^}]+\})/i",'${1}'.$d.':${2}',$tex);
  294. // cref ref autoref
  295. $refs = [];
  296. preg_match_all("/\\\(cref|ref|autoref)\s*\{\s*[^}]+\}/i",$tex,$refs);
  297. foreach ($refs[0] as $ref)
  298. {
  299. $oldref = $ref;
  300. $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref);
  301. $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref);
  302. $tex = str_replace($oldref,$ref,$tex);
  303. }
  304. // cite citeA citeauthor etc
  305. $cites = [];
  306. preg_match_all("/\\\([a-z]*cite[a-z]*)\s*\{\s*[^}]+\}/i",$tex,$cites);
  307. foreach ($cites[0] as $cite)
  308. {
  309. $oldcite = $cite;
  310. $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite);
  311. $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite);
  312. $tex = str_replace($oldcite,$cite,$tex);
  313. }
  314. file_put_contents($file,$tex);
  315. }
  316. }
  317. }
  318. return $bibresources;
  319. }
  320. function handle_appendix($tex)
  321. {
  322. $appendix = false;
  323. $lines = explode("\n",$tex);
  324. for ($i = 0; $i < count($lines); $i++)
  325. {
  326. if ($appendix)
  327. {
  328. $lines[$i] = str_replace(['\subsubsection','\subsection','\section'],['\paragraph','\subsubsection','\subsection'],$lines[$i]);
  329. }
  330. if (str_starts_with($lines[$i],'\appendices') || str_starts_with($lines[$i],'\appendix'))
  331. {
  332. $lines[$i] = '\section{Appendix}';
  333. $appendix = true;
  334. }
  335. }
  336. $tex = implode("\n",$lines);
  337. return $tex;
  338. }
  339. function stripformatting($tex)
  340. {
  341. return str_ireplace(['\Large ','\bf ','\rm ','\\\\'],[' ',' ',' ',' '],$tex);
  342. }
  343. function getusepackages($tex)
  344. {
  345. $packages = [];
  346. preg_match_all("/\n\s*(\\\\usepackage([^{}]*)(?<R>{((?:[^{}]+|(?&R))*)}))/i",$tex,$packages);
  347. if (isset($packages[1]))
  348. {
  349. return [$packages[1],$packages[4]];
  350. }
  351. return [[],[]];
  352. }
  353. function getmathops($tex)
  354. {
  355. $mathops = [];
  356. preg_match_all("/\n\s*(\\\\DeclareMath(Operator|Alphabet)\\*?((?<R>{((?:[^{}]+|(?&R))*)})([^{}]*)|\\\\[^\{]*)(?<P>{((?:[^{}]+|(?&P))*)})(?<Q>{((?:[^{}]+|(?&Q))*)})?(?<S>{((?:[^{}]+|(?&S))*)})?(?<T>{((?:[^{}]+|(?&T))*)})?)/i",$tex,$mathops);
  357. if (isset($mathops[4]))
  358. return [$mathops[1],$mathops[3]];
  359. return [[],[]];
  360. }
  361. function gettikzlibs($tex)
  362. {
  363. preg_match_all("/\\\\usetikzlibrary\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex,$matches);
  364. if (isset($matches[2]))
  365. return [$matches[0],$matches[2]];
  366. else
  367. return [[],[]];
  368. }
  369. function flatten($d,$f)
  370. {
  371. global $kpsefiles;
  372. $tex = file_get_and_backup("$d/$f",".interm_bak");
  373. preg_match_all("/\\n([^%]*?)(\\\\(input|include|usepackage)\s*\\\\*?\s*(?<R>{(?<RR>((?:[^{}]+|(?&R))*))}))/i",$tex,$inputs);
  374. $files = [];
  375. global $ignore_packages;
  376. if (count($inputs) > 0)
  377. {
  378. for ($i = 0; $i < count($inputs[0]); $i++)
  379. {
  380. $exts = ['.tex'];
  381. $f2 = $inputs['RR'][$i];
  382. if (strtolower($inputs[3][$i]) === 'usepackage')
  383. {
  384. if (strpos($f2,",") !== false || in_array($f2,$ignore_packages) || in_array("$f2.sty",$kpsefiles))
  385. continue;
  386. $f2 .= ".sty";
  387. }
  388. while (!file_exists("$d/$f2") && count($exts) > 0)
  389. $f2 = $inputs['RR'][$i].array_shift($exts);
  390. if (file_exists("$d/$f2"))
  391. $files[] = [$d,$f2,$inputs[2][$i]];
  392. }
  393. }
  394. preg_match_all("/\\n([^%]*?)(\\\\(import|subimport)\s*\\\\*?\s*(?<R>{(?<RR>((?:[^{}]+|(?&R))*))})\s*(?<Q>{(?<QQ>((?:[^{}]+|(?&Q))*))}))/i",$tex,$inputs);
  395. if (count($inputs) > 0)
  396. {
  397. for ($i = 0; $i < count($inputs[0]); $i++)
  398. {
  399. $exts = ['.tex'];
  400. $f2 = $inputs['QQ'][$i].'/'.$inputs['RR'][$i];
  401. while (!file_exists("$d/$f2") && count($exts) > 0)
  402. $f2 = $inputs['QQ'][$i].'/'.$inputs['RR'][$i].array_shift($exts);
  403. if (!file_exists("$d/$f2"))
  404. $files[] = [$d,$f2,$inputs[2][$i]];
  405. }
  406. }
  407. foreach ($files as $file)
  408. {
  409. $content = flatten($file[0],$file[1]);
  410. $tex = str_replace($file[2],$content,$tex);
  411. }
  412. file_put_contents("$d/$f",$tex);
  413. return $tex;
  414. }
  415. function adjust_papers($papers)
  416. {
  417. $tex = "";
  418. $paper_fulltitle = "";
  419. $authors = "";
  420. $institute = "";
  421. $header = "";
  422. foreach ($papers as $d => $f)
  423. {
  424. if (str_ends_with($f,".pdf"))
  425. {
  426. $paper_fulltitle = trim(user_prompt("Please enter the full title for the paper in folder '$d'","TODO"));
  427. $paper_shorttitle = trim(user_prompt("Please enter a short title for the paper in folder '$d'","TODO"));
  428. $authors = trim(user_prompt("Please enter the author list for paper '$d'","TODO"));
  429. $header=<<<END
  430. \chapter[$paper_shorttitle]{{$paper_fulltitle}}\label{chapter:$d}
  431. \section*{Publication Data}
  432. \\fullcite{TODO}
  433. \section*{Contributions}
  434. TODO
  435. \includepdf[pages=-]{{$d}/{$f}}
  436. END;
  437. file_put_contents("$d/main.tex",$header);
  438. continue;
  439. }
  440. $file = "$d/$f";
  441. $authors = "";
  442. $institute = "";
  443. $title = "";
  444. $paper_fulltitle = "";
  445. $paper_shorttitle = "";
  446. $tex = file_get_and_backup($file,".interm_bak");
  447. if ($authors == "" && preg_match("/\n\s*\\\\author\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex) == 1)
  448. {
  449. preg_match_all("/\n\s*\\\\author\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex,$authors);
  450. if (isset($authors[2]))
  451. $authors = trim(stripformatting(implode(" ",$authors[2])));
  452. }
  453. if ($institute == "" && preg_match("/\n\s*\\\\institute\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex) == 1)
  454. {
  455. preg_match_all("/\n\s*\\\\institute\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex,$institute);
  456. if (isset($institute[2]) && isset($institute[2][0]))
  457. $institute = trim(stripformatting($institute[2][0]));
  458. }
  459. if ($paper_shorttitle == "" && preg_match("/\n\s*\\\\title\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex) == 1)
  460. {
  461. preg_match_all("/\n\s*\\\\title\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex,$title);
  462. if (isset($title[2]) && isset($title[2][0]))
  463. $title = trim(stripformatting($title[2][0]));
  464. else
  465. $title = $d;
  466. $shorttitle = $title;
  467. if (strpos($title,":") !== false)
  468. $shorttitle = trim(explode(":",$title)[0]);
  469. $paper_fulltitle = trim(user_prompt("Please enter the full title for the paper in folder '$d'","$title"));
  470. $paper_shorttitle = trim(user_prompt("Please enter a short title for the paper in folder '$d'","$shorttitle"));
  471. }
  472. if ($paper_fulltitle != "" && $paper_shorttitle != "" && $authors != "")
  473. {
  474. $header=<<<END
  475. \chapter[$paper_shorttitle]{{$paper_fulltitle}}\label{chapter:$d}
  476. \section*{Publication Data}
  477. \\fullcite{TODO}
  478. \section*{Contributions}
  479. TODO
  480. \\newpage
  481. \begin{center}
  482. {\Large \bfseries
  483. $paper_fulltitle
  484. \\vspace{0.6cm}}
  485. {\large
  486. $authors
  487. } % TODO: check author list
  488. {\large
  489. $institute
  490. } % TODO: check institutes
  491. \\end{center}
  492. END;
  493. }
  494. [$mathopsfull,$mathops] = getmathops($tex);
  495. global $existing_mathops;
  496. global $preamble;
  497. $addmathops = array_diff($mathops,$existing_mathops);
  498. $existing_mathops = array_unique($existing_mathops);
  499. $addmathops = array_unique($addmathops);
  500. foreach ($addmathops as $k => $v)
  501. {
  502. $preamble .= $mathopsfull[$k] . "\n";
  503. $existing_mathops[] = $v;
  504. }
  505. global $tikzlibs;
  506. [$foundlibsfull,$foundlibs] = gettikzlibs($tex);
  507. $addlibs = array_diff($foundlibs,$tikzlibs);
  508. $tikzlibs = array_unique($tikzlibs);
  509. $addlibs = array_unique($addlibs);
  510. foreach ($addlibs as $k => $v)
  511. {
  512. $preamble .= $foundlibsfull[$k] . "\n";
  513. $tikzlibs[] = $v;
  514. }
  515. $tex = preg_replace("/\\\\documentclass{iacrtrans}/i","\declarecommand{\inst}[1]{\\textsuperscript{#1}}",$tex);
  516. $tex = preg_replace("/\\\\documentclass.*\\n/i","
  517. ",$tex);
  518. if (preg_match("/\\\\begin{abstract}/i",$tex) == 1)
  519. {
  520. $tex = preg_replace("/\\\\begin{abstract}/i",$header."\n\section*{Abstract}",$tex);
  521. $header = "";
  522. }
  523. if (preg_match("/\\\\maketitle/i",$tex) == 1)
  524. {
  525. $tex = preg_replace("/\\\\maketitle/i",$header,$tex);
  526. $header = "";
  527. }
  528. if (preg_match("/\\\\begin{document}/i",$tex) == 1)
  529. {
  530. $tex = preg_replace("/\\\\begin{document}/i",$header,$tex);
  531. $header = "";
  532. }
  533. $graphicspath = "";
  534. preg_match("/\\\\graphicspath\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$tex,$matches);
  535. if (count($matches) > 3)
  536. preg_match("/(?<R>{((?:[^{}]+|(?&R))*)})*/i",$matches[2],$matches);
  537. if (count($matches) > 3)
  538. $graphicspath = $matches[2];
  539. $tex = preg_replace("/\\\\includegraphics\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])(?<Q>{((?:[^{}]+|(?&Q))*)})/i",'\includegraphics${1}{'.$d."/".$graphicspath.'${4}}',$tex);
  540. $tex = str_replace("$graphicspath$graphicspath","$graphicspath",$tex);
  541. global $sloppy_begin;
  542. global $sloppy_end;
  543. $tex = preg_replace("/\s*\\\\bibliography\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","\n".$sloppy_begin.'
  544. \printbibliography[title={References}, heading=subbibliography]
  545. '.$sloppy_end,$tex);
  546. $tex = preg_replace("/\\\\begin{thebibliography}/i","\n".$sloppy_begin.'
  547. \printbibliography[title={References}, heading=subbibliography]
  548. '.$sloppy_end."\n$0",$tex);
  549. $tex = preg_replace("/(\\\\begin|end){(IEEEkeywords|CCSXML|thebibliography)}/i",'$1{comment}',$tex);
  550. $tex = preg_replace("/(\\\\csvautobooktabular\s*([^{}]*)\s*)(?<R>{((?:[^{}]+|(?&R))*)})/i","\\1{{$d}/\\4}",$tex);
  551. $tex = preg_replace("/\\\\(re)?newcommand/i",'\declarecommand',$tex);
  552. $tex = preg_replace("/\\\\(Re)?NewDocumentEnvironment/i",'\DeclareDocumentEnvironment',$tex);
  553. $tex = preg_replace("/\\\\(re)?newenvironment/i",'\declareenvironment',$tex);
  554. $tex = preg_replace("/\\\\acmBooktitle\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  555. $tex = preg_replace("/\\\\acmConference\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])?\s*(?<Q>{((?:[^{}]+|(?&Q))*)})\s*(?<X>{((?:[^{}]+|(?&X))*)})\s*(?<Y>{((?:[^{}]+|(?&Y))*)})/i","",$tex);
  556. $tex = preg_replace("/\\\\acmDOI\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  557. $tex = preg_replace("/\\\\acmISBN\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  558. $tex = preg_replace("/\\\\acmPrice\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  559. $tex = preg_replace("/\\\\acmYear\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  560. $tex = preg_replace("/\\\\affiliation\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  561. $tex = preg_replace("/\\\\AtBeginDocument\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",'',$tex);
  562. $tex = preg_replace("/\\\\begin{acks}/i","\section*{Acknowledgements}",$tex);
  563. $tex = preg_replace("/(\\\\bibitem\s*)(?<R>{((?:[^{}]+|(?&R))*)})/i",'$1{'.$d.':$3}',$tex);
  564. $tex = preg_replace("/\\\\bibliographystyle\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",'%$0',$tex);
  565. $tex = preg_replace("/\\\\captionsetup\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])?(?<Q>{((?:[^{}]+|(?&Q))*)})/i","",$tex);
  566. $tex = preg_replace("/\\\\ccsdesc\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])?(?<Q>{((?:[^{}]+|(?&Q))*)})/i","",$tex);
  567. $tex = preg_replace("/\\\\copyrightyear\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  568. $tex = preg_replace("/\\\\DeclareFloatFont\s*(?<R>{((?:[^{}]+|(?&R))*)})(?<Q>{((?:[^{}]+|(?&Q))*)})/i","",$tex);
  569. $tex = preg_replace("/\\\\DeclareMathAlphabet/i",'%$0',$tex);
  570. $tex = preg_replace("/\\\\DeclareMathOperator/i",'%$0',$tex);
  571. $tex = preg_replace("/\\\\DeclareRobustCommand\s*(?<R>{((?:[^{}]+|(?&R))*)})\s*(?<Q>{((?:[^{}]+|(?&Q))*)})/i",'',$tex);
  572. $tex = preg_replace("/\\\\email\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  573. $tex = preg_replace("/\\\\end{abstract}/i",'',$tex);
  574. $tex = preg_replace("/\\\\end{acks}/i","",$tex);
  575. $tex = preg_replace("/\\\\end{document}/i",'',$tex);
  576. $tex = preg_replace("/\\\\fancyhead\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  577. $tex = preg_replace("/\\\\floatsetup\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])(?<Q>{((?:[^{}]+|(?&Q))*)})/i","",$tex);
  578. $tex = preg_replace("/\\\\IEEEauthorblock[AN]/i","",$tex);
  579. $tex = preg_replace("/\\\\IEEEauthorrefmark/i","\\textsuperscript",$tex);
  580. $tex = preg_replace("/\\\\IEEEoverridecommandlockouts/i","",$tex);
  581. $tex = preg_replace("/\\\\newfloat\s*(?<R>{((?:[^{}]+|(?&R))*)})(?<Q>{((?:[^{}]+|(?&Q))*)})(?<P>{((?:[^{}]+|(?&P))*)})/i","",$tex);
  582. $tex = preg_replace("/\\\\onecolumn/i",'',$tex);
  583. $tex = preg_replace("/\\\\pagenumbering\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  584. $tex = preg_replace("/\\\\PassOptionsToPackage\s*(?<R>{((?:[^{}]+|(?&R))*)})(?<Q>{((?:[^{}]+|(?&Q))*)})/i",'',$tex);
  585. $tex = preg_replace("/\\\\ProvidesPackage\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  586. $tex = preg_replace("/\\\\RequirePackage\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])?(?<Q>{((?:[^{}]+|(?&Q))*)})/i","",$tex);
  587. $tex = preg_replace("/\\\\setcopyright\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  588. $tex = preg_replace("/\\\\settopmatter\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  589. $tex = preg_replace("/\\\\SetWatermarkLightness\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  590. $tex = preg_replace("/\\\\SetWatermarkScale\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  591. $tex = preg_replace("/\\\\SetWatermarkText\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  592. $tex = preg_replace("/\\\\special\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  593. $tex = preg_replace("/\\\\tag\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  594. $tex = preg_replace("/\\\\thispagestyle{empty}/i",'%$0',$tex);
  595. $tex = preg_replace("/\\\\tikzexternalize\s*(?<R>\[((?:[^\[\]]+|(?&R))*)\])/i","",$tex);
  596. $tex = preg_replace("/\\\\twocolumn/i","",$tex);
  597. $tex = preg_replace("/\\\\usepackage\s*(\[[^\[\]]*\])?\s*{minted}/i",'\usepackage{minted}',$tex);
  598. $tex = preg_replace("/\\\\usetikzlibrary\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",'%$0',$tex);
  599. $tex = preg_replace("/\n\s*\\\\author\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  600. $tex = preg_replace("/\n\s*\\\\authorrunning\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  601. $tex = preg_replace("/\n\s*\\\\date\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  602. $tex = preg_replace("/\n\s*\\\\institute\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  603. $tex = preg_replace("/\n\s*\\\\tikzexternalize/i","",$tex);
  604. $tex = preg_replace("/\n\s*\\\\title\s*(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  605. [$ups,$ps] = getusepackages($tex);
  606. global $ignore_packages;
  607. global $included_usepackages;
  608. global $additional_usepackages;
  609. foreach (array_diff($ps,$included_usepackages) as $k => $packagelist) {
  610. $packagelist = explode(",",$packagelist);
  611. foreach ($packagelist as $v)
  612. {
  613. // if (in_array($v,['minted']))
  614. // {
  615. // $additional_usepackages[] = "\usepackage{minted}";
  616. // $included_usepackages[] = $v;
  617. // }
  618. // else
  619. if (!in_array($v,$ignore_packages) && !($v == 'floatrow' && in_array('float',$included_usepackages)))
  620. {
  621. if (preg_match("/\\\\usepackage\s*(\[[^\[\]]*\])?\s*(?<R>{((?:[^{}]+|(?&R))*)})/i",$ups[$k]) > 0)
  622. $additional_usepackages[] = $ups[$k];
  623. $included_usepackages[] = $v;
  624. }
  625. }
  626. }
  627. array_unique($additional_usepackages);
  628. $tex = preg_replace("/\n\s*\\\\usepackage([^{}]*?)(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  629. $tex = preg_replace("/^\s*\\\\usepackage([^{}]*?)(?<R>{((?:[^{}]+|(?&R))*)})/i","",$tex);
  630. $tex = preg_replace("/\n\s*\\\\setlength{\s*\\\marginparwidth.*\n/i","\n",$tex);
  631. if (stripos($tex,"\appendices") !== false || stripos($tex,"\appendix") !== false)
  632. $tex = handle_appendix($tex);
  633. if (!str_starts_with($tex,"\\makeatletter\n\def\\relativepath{\\import@path}\n\\makeatother\n"))
  634. $tex = "\\makeatletter\n\def\\relativepath{\\import@path}\n\\makeatother\n" . $tex;
  635. $tex .= "\n\graphicspath{}";
  636. file_put_contents($file,$tex);
  637. }
  638. return;
  639. }
  640. function check_options($argv)
  641. {
  642. global $options;
  643. $rest = [];
  644. array_shift($argv);
  645. foreach ($argv as $a)
  646. {
  647. if (str_starts_with($a,"-"))
  648. $options[$a] = 1;
  649. else
  650. $rest[] = $a;
  651. }
  652. if (isset($options["-n"]) && !isset($options["--force-overwrite"]))
  653. $options["--no-overwrite"] = 1;
  654. return $rest;
  655. }
  656. function compile_check($papers,$precopy = false)
  657. {
  658. if ($precopy)
  659. $papers = array_combine($papers,$papers);
  660. foreach ($papers as $p => $f)
  661. {
  662. if (str_ends_with($f,".pdf"))
  663. {
  664. echo "======= Skipping PDF: $f =======\n";
  665. continue;
  666. }
  667. echo "======= Paper $p -> $f START =======\n";
  668. if ($precopy)
  669. {
  670. echo "$p\n";
  671. if (strpos($p,"/") === false || str_starts_with($p,".") || !is_dir(dirname($p)))
  672. continue;
  673. $f = basename($p);
  674. $p = dirname($p);
  675. }
  676. else
  677. {
  678. shell_exec("cd $p; latexmk -c 2>/dev/null; latexmk -C 2>/dev/null; rm -f *.bbl");
  679. }
  680. $str = shell_exec("cd $p; latexmk -latexoption=\"-file-line-error -shell-escape -interaction=nonstopmode\" -g -pdf $f 2>&1");
  681. $lines = explode("\n",$str);
  682. $skip = true;
  683. $failed = false;
  684. foreach($lines as $l)
  685. {
  686. if (str_starts_with($l,"Latexmk: ====List of undefined refs and citations:") || strpos($l,"LaTeX Error:") !== false)
  687. {
  688. $skip = false;
  689. $failed = true;
  690. }
  691. if ($skip)
  692. continue;
  693. if (stripos($l,"fail") !== false)
  694. $failed = true;
  695. echo "$l\n";
  696. }
  697. if ($failed || user_consent("Please check the PDF file. Are there any problems with invalid references to figures, tables or with the bibliography?","","-n"))
  698. error_exit("The paper did not compile properly, please fix the errors next before continuing.");
  699. echo "======= Paper $p -> $f END =======\n";
  700. }
  701. }
  702. function init_kpse()
  703. {
  704. global $kpsefiles;
  705. $kpsepath = shell_exec("kpsepath tex");
  706. $kpsepath = explode(":",$kpsepath);
  707. foreach ($kpsepath as $k)
  708. {
  709. $k = str_replace(["!!","\n","///","//"],["","","/","/"],$k);
  710. if (str_starts_with($k,"."))
  711. continue;
  712. $found = null;
  713. if (is_dir($k))
  714. $found = rscandir($k,[".sty"]);
  715. if ($found != null)
  716. {
  717. for ($i = 0; $i < count($found); $i++)
  718. $found[$i] = basename($found[$i]);
  719. $kpsefiles = array_unique(array_merge($kpsefiles,$found));
  720. }
  721. }
  722. sort($kpsefiles);
  723. }
  724. echo "\n=== Step 1/$steps: Check Software and Command Line Options ===\n\n";
  725. check_software();
  726. $argv = check_options($argv);
  727. if (isset($options["--help"]))
  728. print_help();
  729. if (!isset($options["--no-sloppy"]))
  730. {
  731. $sloppy_begin = '\begin{sloppypar}';
  732. $sloppy_end = '\end{sloppypar}';
  733. }
  734. echo "\n=== Step 2/$steps: Check Folders ===\n\n";
  735. [$targets,$texfiles,$sourcedirs] = check_folders($argv);
  736. echo "\n=== Step 3/$steps: Pre-Copy Compile Check ===\n\n";
  737. $targets_exist = true;
  738. foreach ($targets as $t)
  739. if (!is_dir($t))
  740. $targets_exist = false;
  741. if (isset($options["--no-compile-check"]) || $targets_exist)
  742. echo "Skipping...\n";
  743. else
  744. compile_check($argv,true);
  745. echo "\n=== Step 4/$steps: Copying Files ===\n\n";
  746. $papers = check_and_copy_folders($argv);
  747. echo "\n=== Step 5/$steps: Adjusting References (in *.bib *.tex *.tikz) ===\n\n";
  748. $bibresources = adjust_references($papers,[".bib",".tex",".tikz"]);
  749. echo "\n=== Step 6/$steps: Post-Copy Compile Check ===\n\n";
  750. if (isset($options["--no-compile-check"]))
  751. echo "Skipping...\n";
  752. else
  753. compile_check($papers);
  754. echo "\n=== Step 7/$steps: Initialize KPSE Database ===\n\n";
  755. init_kpse();
  756. global $ignore_packages;
  757. $ignore_packages = explode(",",user_prompt("Enter a comma-separated list of packages that should be considered ignored (e.g. publisher or conference styles, as well as packages that modify font or page formats)","a4paper,cite,csvenhanced,draftwatermark,endnotes,epsfig,etex,fdsymbol,filecontents,flushend,fontenc,mathptmx,microtype,pslatex,subfig,usenix,usenixbadges,xwatermark"));
  758. echo "\n=== Step 8/$steps: Flattening Papers ===\n\n";
  759. foreach ($papers as $d => $f)
  760. flatten($d,$f);
  761. echo "\n=== Step 9/$steps: Post-Flattening Compile Check ===\n\n";
  762. if (isset($options["--no-compile-check"]))
  763. echo "Skipping...\n";
  764. else
  765. compile_check($papers);
  766. echo "\n=== Step 10/$steps: Preparing Extraction of Used Packages, Tikz Libs, Math Ops etc. ===\n\n";
  767. [$_t,$usepackages1] = getusepackages(file_get_contents("main.tex.php"));
  768. [$_t,$usepackages2] = getusepackages(file_get_contents("tugraz_defaults.sty"));
  769. global $included_usepackages;
  770. $included_usepackages = array_unique(array_merge($usepackages1, $usepackages2));
  771. sort($included_usepackages);
  772. echo "\n=== Step 12/$steps: Adjusting Papers ===\n\n";
  773. adjust_papers($papers);
  774. foreach ($papers as $k => $v)
  775. {
  776. if (str_ends_with($papers[$k],".pdf"))
  777. $papers[$k] = 'main.tex';
  778. }
  779. echo "\n=== Step 12/$steps: Generate main.tex ===\n\n";
  780. $thesis_type = user_prompt("Enter Thesis Type ","PhD Thesis");
  781. $thesis_title = user_prompt("Enter Thesis Title ","Security of TODO");
  782. $thesis_part1_title = user_prompt("Enter Introductory Part Title ","Introduction to the Security of TODO");
  783. $thesis_author = user_prompt("Enter Your Name ","Harry Potter");
  784. $thesis_date = user_prompt("Enter Prospective Defense Month", "July 1998");
  785. $thesis_institute = user_prompt("Enter Your Institute","Institute for Applied Information Processing and Communications");
  786. $thesis_assessors = user_prompt("Enter Names of your Assessors (comma-separated)","Severus Snape, Minerva McGonagall");
  787. $num_publications_in_thesis = count($papers);
  788. $num_publications = user_prompt("How many publications did you co-author during your PhD? (6 is the absolute minimum for a cumulative thesis)","6");
  789. ob_start();
  790. require "main.tex.php";
  791. $maintex_content = ob_get_contents();
  792. ob_end_clean();
  793. if (!file_exists("main.tex") || user_consent("main.tex already exists. overwrite?","--force-overwrite","--no-overwrite"))
  794. file_put_contents("main.tex",$maintex_content);
  795. if (!file_exists("mypreamble.sty") || user_consent("mypreamble.sty already exists... overwrite?","--force-overwrite","--no-overwrite"))
  796. file_put_contents("mypreamble.sty","\ProvidesPackage{mypreamble}\n\n".implode("\n",array_unique($additional_usepackages))."\n\n".$preamble);
  797. @mkdir("tikz");
  798. if (!file_exists("abstract.tex"))
  799. file_put_contents("abstract.tex","");
  800. if (!file_exists("intro.tex"))
  801. file_put_contents("intro.tex","");
  802. if (!file_exists("main.bib"))
  803. file_put_contents("main.bib",'@inproceedings{Kocher2019,
  804. author = {Paul Kocher and Jann Horn and Anders Fogh and Daniel Genkin and Daniel Gruss and Werner Haas and Mike Hamburg and Moritz Lipp and Stefan Mangard and Thomas Prescher and Michael Schwarz and Yuval Yarom},
  805. booktitle = {S\&P},
  806. title = {{Spectre Attacks: Exploiting Speculative Execution}},
  807. year = {2019}
  808. }');
  809. if (isset($options["--cv"]))
  810. {
  811. if (!file_exists("cv.bib"))
  812. file_put_contents("cv.bib","");
  813. if (!file_exists("cv.tex"))
  814. file_put_contents("cv.tex","This is my CV! Thanks for checking it out!");
  815. }
  816. if (!isset($options["--no-cover"]))
  817. {
  818. ob_start();
  819. require "cover1.tex.php";
  820. $covertex_content = ob_get_contents();
  821. ob_end_clean();
  822. if (!file_exists("cover1.tex") || user_consent("cover1.tex already exists. overwrite?","--force-overwrite","--no-overwrite"))
  823. file_put_contents("cover1.tex",$covertex_content);
  824. shell_exec('latexmk -latexoption="-file-line-error -shell-escape -interaction=nonstopmode" -g -pdf cover1.tex 1>/dev/null 2>/dev/null');
  825. ob_start();
  826. require "cover2.tex.php";
  827. $covertex_content = ob_get_contents();
  828. ob_end_clean();
  829. if (!file_exists("cover2.tex") || user_consent("cover2.tex already exists. overwrite?","--force-overwrite","--no-overwrite"))
  830. file_put_contents("cover2.tex",$covertex_content);
  831. shell_exec('latexmk -latexoption="-file-line-error -shell-escape -interaction=nonstopmode" -g -pdf cover2.tex 1>/dev/null 2>/dev/null');
  832. }
  833. if (isset($options["--compile"]))
  834. {
  835. passthru('latexmk -latexoption="-file-line-error -shell-escape" -g -pdf main.tex');
  836. }
  837. else
  838. {
  839. echo "=== done ===\nNext step, run this command:\nlatexmk -latexoption=\"-file-line-error -shell-escape -interaction=errorstopmode -halt-on-error\" -g -pdf main.tex\n";
  840. }
  841. ?>