&1"),"pdftotext version")) error_exit("pdftotext not installed"); } function rrmdir($dir) { if (is_dir($dir)) { $files = scandir($dir); foreach ($files as $file) if ($file != "." && $file != "..") rrmdir("$dir/$file"); rmdir($dir); } else if (file_exists($dir)) unlink($dir); } function rcopy($src, $dst) { if (file_exists($dst)) rrmdir($dst); if (is_dir($src)) { mkdir($dst); $files = scandir($src); foreach ($files as $file) if ($file != "." && $file != "..") rcopy("$src/$file", "$dst/$file"); } else if (file_exists($src)) copy($src, $dst); } function rscandir($dir,$extensions = []) { $result = []; if (!str_ends_with($dir,"/")) $dir .= "/"; if (str_ends_with($dir,"latex.out/")) return $result; $array = scandir($dir); foreach ($array as $item) { if (!str_starts_with($item,".")) { if (!is_dir($dir.$item)) { $extension_match = true; if ($extensions != []) { $extension_match = false; foreach ($extensions as $e) { if (str_ends_with($item,"$e")) { $extension_match = true; } } } if ($extension_match) $result[] = $dir.$item; } else $result = array_merge($result, rscandir($dir.$item,$extensions)); } } return $result; } function unique_targets($targets) { $parts_required = 1; $unique_targets = []; while (count($unique_targets) != count($targets)) { foreach ($targets as $t) { $tparts = explode("/",$t); $tpcount = count($tparts); $tparts = array_splice($tparts,$tpcount-$parts_required,$parts_required); $t = implode("_",$tparts); if (isset($unique_targets[$t])) { $parts_required++; $unique_targets = []; break; } $unique_targets[$t] = 1; } } return array_keys($unique_targets); } function check_folders($argv) { $args = array_slice($argv,1); $sourcedirs = []; foreach ($args as $a) { if (!str_starts_with($a,"-")) $sourcedirs[] = $a; } if (count($sourcedirs) < 1) { error_exit("Too few papers. Need at least one paper to run this.",true); } if (count($sourcedirs) < 3) { 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."; } if (count($sourcedirs) < 5) { 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."; } $texfiles = []; for ($i = 0; $i < count($sourcedirs); $i++) { $texfiles[$i] = basename($sourcedirs[$i]); $sourcedirs[$i] = dirname($sourcedirs[$i]); } $targets = unique_targets($sourcedirs); return [$targets,$texfiles,$sourcedirs]; } function check_and_copy_folders($argv) { [$targets,$texfiles,$sourcedirs] = check_folders($argv); //echo "Source -> Target Directory Mapping:\n"; $n = count($sourcedirs); //print_r($mapping); for ($i = 0; $i < $n; $i++) { $s = $sourcedirs[$i]; $t = $targets[$i]; $f = $texfiles[$i]; if (str_ends_with($f,".pdf")) { if (!file_exists("$s/$f")) error_exit("$s/$f not found"); if (file_exists("$t/$f.pdf") && !user_consent("$t/$f.pdf already exists... overwrite?","--force-overwrite","--no-overwrite")) { echo "Skipping $s/$f, $t/$f.pdf already exists...\n"; } else { echo "Copying $s/$f to $t/$f...\n"; if (!file_exists($t)) mkdir($t); rcopy("$s/$f","$t/$f"); } } else { if (!file_exists($s)) error_exit("$s not found"); if (file_exists($t) && !user_consent("$t already exists... overwrite?","--force-overwrite","--no-overwrite")) { echo "Skipping ".$s.", ".$t." already exists...\n"; } else { echo "Copying ".$s." to ".$t."...\n"; rcopy($s,$t); } } } return array_combine($targets,$texfiles); } function file_get_and_backup($f,$bak = ".orig_bak") { global $options; if (isset($options["--use-backups"])) { if (file_exists("$f$bak")) copy("$f$bak", $f); } $content = file_get_contents("$f"); if (!file_exists("$f$bak")) file_put_contents("$f$bak",$content); return $content; } function adjust_references($papers,$extensions = []) { $bibresources = []; foreach ($papers as $d => $f) { if (str_ends_with($f,".pdf")) continue; $files = rscandir($d,$extensions); foreach ($files as $file) { if (str_ends_with($file,".bib")) { $bib = file_get_and_backup($file); $bib = preg_replace("/(^\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib); $bib = preg_replace("/(\n\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib); $bib = preg_replace("/([\{\"].*)[^\\\\]#(.*)/i",'${1}\#${2}',$bib); $bib = preg_replace("/{\\\\i}/","{i}",$bib); file_put_contents($file,$bib); $bibresources[$d] = $file; } else { $tex = file_get_and_backup($file); // labels of lstlistings etc $tex = preg_replace("/([\[,]\s*label\s*=\s*)((?!$d)[^\[,]+[\[,])/i",'${1}'.$d.':${2}',$tex); // normal labels $tex = preg_replace("/(\\\label\s*\{\s*)((?!$d)[^}]+\})/i",'${1}'.$d.':${2}',$tex); // cref ref autoref $refs = []; preg_match_all("/\\\(cref|ref|autoref)\s*\{\s*[^}]+\}/i",$tex,$refs); foreach ($refs[0] as $ref) { $oldref = $ref; $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref); $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref); $tex = str_replace($oldref,$ref,$tex); } // cite citeA citeauthor etc $cites = []; preg_match_all("/\\\([a-z]*cite[a-z]*)\s*\{\s*[^}]+\}/i",$tex,$cites); foreach ($cites[0] as $cite) { $oldcite = $cite; $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite); $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite); $tex = str_replace($oldcite,$cite,$tex); } file_put_contents($file,$tex); } } } return $bibresources; } function handle_appendix($tex) { $appendix = false; $lines = explode("\n",$tex); for ($i = 0; $i < count($lines); $i++) { if ($appendix) { $lines[$i] = str_replace(['\subsubsection','\subsection','\section'],['\paragraph','\subsubsection','\subsection'],$lines[$i]); } if (str_starts_with($lines[$i],'\appendices') || str_starts_with($lines[$i],'\appendix')) { $lines[$i] = '\section*{Appendix}'; $appendix = true; } } $tex = implode("\n",$lines); return $tex; } function stripformatting($tex) { return str_ireplace(['\Large ','\bf ','\rm ','\\\\'],[' ',' ',' ',' '],$tex); } function getusepackages($tex) { $packages = []; preg_match_all("/\n\s*(\\\\usepackage([^{}]*)(?{((?:[^{}]+|(?&R))*)}))/i",$tex,$packages); if (isset($packages[1])) { return [$packages[1],$packages[4]]; } return [[],[]]; } function getmathops($tex) { $mathops = []; preg_match_all("/\n\s*(\\\\DeclareMath(Operator|Alphabet)\\*?((?{((?:[^{}]+|(?&R))*)})([^{}]*)|\\\\[^\{]*)(?

{((?:[^{}]+|(?&P))*)})(?{((?:[^{}]+|(?&Q))*)})?(?{((?:[^{}]+|(?&S))*)})?(?{((?:[^{}]+|(?&T))*)})?)/i",$tex,$mathops); if (isset($mathops[4])) return [$mathops[1],$mathops[3]]; return []; } function getnewcommands($tex) { $newcommands = []; preg_match_all("/\n\s*(\\\\newcommand([^{}]*)(?{((?:[^{}]+|(?&R))*)})([^{}]*)(?

{((?:[^{}]+|(?&P))*)}))/i",$tex,$newcommands); if (isset($newcommands[4])) return $newcommands[4]; return []; } function adjust_papers($papers,$extensions = []) { $tex = ""; $paper_fulltitle = ""; $authors = ""; $institute = ""; foreach ($papers as $d => $f) { if (str_ends_with($f,".pdf")) { $paper_fulltitle = trim(user_prompt("Please enter the full title for the paper in folder '$d'","TODO")); $paper_shorttitle = trim(user_prompt("Please enter a short title for the paper in folder '$d'","TODO")); $authors = trim(user_prompt("Please enter the author list for paper '$d'","TODO")); $header=<<{((?:[^{}]+|(?&R))*)})/i",$tex) == 1) { preg_match_all("/\n\s*\\\\author\s*(?{((?:[^{}]+|(?&R))*)})/i",$tex,$authors); if (isset($authors[2]) && isset($authors[2][0])) $authors = trim(stripformatting($authors[2][0])); } if ($institute == "" && preg_match("/\n\s*\\\\institute\s*(?{((?:[^{}]+|(?&R))*)})/i",$tex) == 1) { preg_match_all("/\n\s*\\\\institute\s*(?{((?:[^{}]+|(?&R))*)})/i",$tex,$institute); if (isset($institute[2]) && isset($institute[2][0])) $institute = trim(stripformatting($institute[2][0])); } if ($paper_shorttitle == "" && preg_match("/\n\s*\\\\title\s*(?{((?:[^{}]+|(?&R))*)})/i",$tex) == 1) { preg_match_all("/\n\s*\\\\title\s*(?{((?:[^{}]+|(?&R))*)})/i",$tex,$title); if (isset($title[2]) && isset($title[2][0])) $title = trim(stripformatting($title[2][0])); else $title = $d; $shorttitle = $title; if (strpos($title,":") !== false) $shorttitle = trim(explode(":",$title)[0]); $paper_fulltitle = trim(user_prompt("Please enter the full title for the paper in folder '$d'","$title")); $paper_shorttitle = trim(user_prompt("Please enter a short title for the paper in folder '$d'","$shorttitle")); } $header = ""; if ($paper_fulltitle != "" && $paper_shorttitle != "" && $authors != "") { $header=<< $v) { $preamble .= $mathopsfull[$k] . "\n"; $existing_mathops[] = $v; } $tex = preg_replace("/\\\documentclass.*\\n/i"," ",$tex); $tex = preg_replace("/\\\begin{document}/i",$header,$tex); $tex = preg_replace("/\\\begin{abstract}/i",'\section*{Abstract}',$tex); $tex = preg_replace("/\\\\newcommand/i",'\declarecommand',$tex); $tex = preg_replace("/\\\\renewcommand/i",'\declarecommand',$tex); $tex = preg_replace("/\\\\end{abstract}/i",'',$tex); $tex = preg_replace("/\\\\DeclareMathOperator/i",'%$0',$tex); $tex = preg_replace("/\\\\DeclareMathAlphabet/i",'%$0',$tex); $tex = preg_replace("/\\\\usepackage[cache=false]{minted}/i",'\usepackage{minted}',$tex); $tex = preg_replace("/\\\\thispagestyle{empty}/i",'',$tex); $tex = preg_replace("/\\\\PassOptionsToPackage\s*(?{((?:[^{}]+|(?&R))*)})(?{((?:[^{}]+|(?&Q))*)})/i",'',$tex); $tex = preg_replace("/(\\\\csvautobooktabular\s*([^{}]*)\s*)(?{((?:[^{}]+|(?&R))*)})/i","\\1{{$d}/\\4}",$tex); $tex = preg_replace("/\\\\bibliographystyle\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\\\\usetikzlibrary\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\\\\DeclareFloatFont\s*(?{((?:[^{}]+|(?&R))*)})(?{((?:[^{}]+|(?&Q))*)})/i","",$tex); $tex = preg_replace("/\\\\captionsetup\s*(?\[((?:[^\[\]]+|(?&R))*)\])?(?{((?:[^{}]+|(?&Q))*)})/i","",$tex); $tex = preg_replace("/\\\\tikzexternalize\s*(?\[((?:[^\[\]]+|(?&R))*)\])/i","",$tex); $tex = preg_replace("/\\\\floatsetup\s*(?\[((?:[^\[\]]+|(?&R))*)\])(?{((?:[^{}]+|(?&Q))*)})/i","",$tex); $tex = preg_replace("/\s*\\\\bibliography\s*(?{((?:[^{}]+|(?&R))*)})/i","\n".'\begin{sloppypar} \printbibliography[title={References}, heading=subbibliography] \end{sloppypar}',$tex); $tex = preg_replace("/\\\\end{document}/i",'',$tex); $tex = preg_replace("/\n\s*\\\\author\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\n\s*\\\\authorrunning\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\n\s*\\\\institute\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\n\s*\\\\title\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\n\s*\\\\date\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\\\\includegraphics\s*(?\[((?:[^\[\]]+|(?&R))*)\])(?{((?:[^{}]+|(?&Q))*)})/i",'\includegraphics${1}{'.$d.'/${4}}',$tex); $tex = preg_replace("/\n\s*\\\\maketitle/i","",$tex); $tex = preg_replace("/\\\\IEEEoverridecommandlockouts/i","",$tex); $tex = preg_replace("/\\\\twocolumn/i","",$tex); $tex = preg_replace("/\n\s*\\\\tikzexternalize/i","",$tex); [$ups,$ps] = getusepackages($tex); global $included_usepackages; global $additional_usepackages; foreach (array_diff($ps,$included_usepackages) as $k => $v) { if (in_array($v,['minted'])) { $additional_usepackages[] = "\usepackage{minted}"; $included_usepackages[] = $v; } else if (!in_array($v,['usenix','usenix,epsfig,endnotes','flushend','mathptmx','usenixbadges','cite','csvenhanced']) && !($v == 'floatrow' && in_array('float',$included_usepackages))) { $additional_usepackages[] = $ups[$k]; $included_usepackages[] = $v; } } array_unique($additional_usepackages); $tex = preg_replace("/\n\s*\\\\usepackage([^{}]*)(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/^\s*\\\\usepackage([^{}]*)(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $newcommands = getnewcommands($tex); global $existing_commands; $rmcommands = array_intersect($newcommands,$existing_commands); foreach ($rmcommands as $rmc) { //$tex = preg_replace("/\n\s*\\\\newcommand([^{}]*)({\s*\\".$rmc."\s*}.*\n)/i","\n",$tex); } $matches = []; $tex = preg_replace("/\n\s*\\\\pgfplotsset\s*(?{((?:[^{}]+|(?&R))*)})/i","",$tex); $tex = preg_replace("/\n\s*\\\\setlength{\s*\\\marginparwidth.*\n/i","\n",$tex); if (stripos($tex,"\appendices") !== false || stripos($tex,"\appendix") !== false) $tex = handle_appendix($tex); if (!str_starts_with($tex,"\\makeatletter\n\def\\relativepath{\\import@path}\n\\makeatother\n")) $tex = "\\makeatletter\n\def\\relativepath{\\import@path}\n\\makeatother\n" . $tex; file_put_contents($file,$tex); } } return; } function check_options($argv) { $options = []; foreach ($argv as $a) { if (str_starts_with($a,"-")) $options[$a] = 1; if ($a == "-n") $options["--no-overwrite"] = 1; } return $options; } function compile_check($papers,$precopy = false) { //array_shift($papers); weird... if ($precopy) $papers = array_combine($papers,$papers); foreach ($papers as $p => $f) { if (str_ends_with($f,".pdf")) { echo "======= Skipping PDF: $f =======\n"; continue; } echo "======= Paper $p -> $f START =======\n"; if ($precopy) { echo "$p\n"; if (strpos($p,"/") === false || str_starts_with($p,".") || !is_dir(dirname($p))) continue; $f = basename($p); $p = dirname($p); } else { shell_exec("cd $p; latexmk -c 2>/dev/null; latexmk -C 2>/dev/null; rm -f *.bbl"); } $str = shell_exec("cd $p; latexmk -latexoption=\"-shell-escape\" -g -pdf $f 2>&1"); $lines = explode("\n",$str); $skip = true; $failed = false; foreach($lines as $l) { if (str_starts_with($l,"Latexmk: ====List of undefined refs and citations:")) $skip = false; if ($skip) continue; if (stripos($l,"fail") !== false) $failed = true; echo "$l\n"; } if ($failed || user_consent("Please check the PDF file. Are there any problems with invalid references to figures, tables or with the bibliography?","--","--no-overwrite")) error_exit("The paper did not compile properly, please fix the errors next before continuing."); echo "======= Paper $p -> $f END =======\n"; } } function init_kpse() { global $kpsefiles; $kpsepath = shell_exec("kpsepath tex"); $kpsepath = explode(":",$kpsepath); foreach ($kpsepath as $k) { $k = str_replace(["!!","\n","///","//"],["","","/","/"],$k); if (str_starts_with($k,".")) continue; $found = null; if (is_dir($k)) $found = rscandir($k,[".sty"]); if ($found != null) { for ($i = 0; $i < count($found); $i++) $found[$i] = basename($found[$i]); $kpsefiles = array_unique(array_merge($kpsefiles,$found)); } } sort($kpsefiles); } check_software(); $options = check_options($argv); if (isset($options["--help"])) print_help(); echo "\n=== Step 1/$steps: Check Folders ===\n\n"; [$targets,$texfiles,$sourcedirs] = check_folders($argv); echo "\n=== Step 2/$steps: Pre-Copy Compile Check ===\n\n"; $targets_exist = true; foreach ($targets as $t) if (!is_dir($t)) $targets_exist = false; if (isset($options["--no-compile-check"]) || $targets_exist) echo "Skipping...\n"; else compile_check($argv,true); echo "\n=== Step 3/$steps: Copying Files ===\n\n"; $papers = check_and_copy_folders($argv); echo "\n=== Step 4/$steps: Adjusting References (in *.bib *.tex *.tikz) ===\n\n"; $bibresources = adjust_references($papers,[".bib",".tex",".tikz"]); echo "\n=== Step 5/$steps: Compile Check ===\n\n"; if (isset($options["--no-compile-check"])) echo "Skipping...\n"; else compile_check($papers); [$_t,$usepackages1] = getusepackages(file_get_contents("main.tex.php")); [$_t,$usepackages2] = getusepackages(file_get_contents("tugraz_defaults.sty")); global $included_usepackages; $included_usepackages = array_unique(array_merge($usepackages1, $usepackages2)); sort($included_usepackages); $cmds1 = getnewcommands(file_get_contents("main.tex.php")); $cmds2 = getnewcommands(file_get_contents("tugraz_defaults.sty")); global $existing_commands; $existing_commands = array_unique(array_merge($cmds1, $cmds2)); [$del,$mathops1] = getmathops(file_get_contents("main.tex.php")); [$del,$mathops2] = getmathops(file_get_contents("tugraz_defaults.sty")); global $existing_mathops; $existing_mathops = array_unique(array_merge($mathops1, $mathops2)); echo "\n=== Step 5/$steps: Adjusting Papers (checking *.tex and *.tikz files) ===\n\n"; adjust_papers($papers,[".tex",".tikz",".sty"]); init_kpse(); foreach ($papers as $k => $v) { if (str_ends_with($papers[$k],".pdf")) $papers[$k] = 'main.tex'; else { $stys = rscandir($k,[".sty"]); foreach ($stys as $styf) { $styfb = basename($styf); if (in_array($styfb,$kpsefiles) === false && !file_exists("./$styfb")) { echo "Copying $styf to ./$styfb...\n"; copy($styf,"./$styfb"); } } } } echo "\n=== Step 6/$steps: Generate main.tex ===\n\n"; $thesis_type = user_prompt("Enter Thesis Type ","PhD Thesis"); $thesis_title = user_prompt("Enter Thesis Title ","Security of TODO"); $thesis_part1_title = user_prompt("Enter Introductory Part Title ","Introduction to the Security of TODO"); $thesis_author = user_prompt("Enter Your Name ","Harry Potter"); $thesis_date = user_prompt("Enter Prospective Defense Month", "July 1998"); $thesis_institute = user_prompt("Enter Your Institute","Institute for Applied Information Processing and Communications"); $thesis_assessors = user_prompt("Enter Names of your Assessors (comma-separated)","Severus Snape, Minerva McGonagall"); $num_publications_in_thesis = count($papers); $num_publications = user_prompt("How many publications did you co-author during your PhD? (6 is the absolute minimum for a cumulative thesis)","6"); $sloppy_begin = ""; $sloppy_end = ""; if (!isset($options["--no-sloppy"])) { $sloppy_begin = '\begin{sloppypar}'; $sloppy_end = '\end{sloppypar}'; } ob_start(); require "main.tex.php"; $maintex_content = ob_get_contents(); ob_end_clean(); if (!file_exists("main.tex") || user_consent("main.tex already exists. overwrite?")) file_put_contents("main.tex",$maintex_content); if (!file_exists("mypreamble.sty") || user_consent("mypreamble.sty already exists... overwrite?","--force-overwrite","--no-overwrite")) file_put_contents("mypreamble.sty","\ProvidesPackage{mypreamble}\n\n".implode("\n",$additional_usepackages)."\n\n".$preamble); @mkdir("tikz"); if (!file_exists("abstract.tex")) file_put_contents("abstract.tex",""); if (!file_exists("intro.tex")) file_put_contents("intro.tex",""); if (!file_exists("main.bib")) file_put_contents("main.bib",'@inproceedings{Kocher2019, 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}, booktitle = {S\&P}, title = {{Spectre Attacks: Exploiting Speculative Execution}}, year = {2019} }'); if (isset($options["--cv"])) { if (!file_exists("cv.bib")) file_put_contents("cv.bib",""); if (!file_exists("cv.tex")) file_put_contents("cv.tex","This is my CV! Thanks for checking it out!"); } ob_start(); require "cover1.tex.php"; $covertex_content = ob_get_contents(); ob_end_clean(); if (!file_exists("cover1.tex") || user_consent("cover1.tex already exists. overwrite?")) file_put_contents("cover1.tex",$covertex_content); shell_exec('latexmk -latexoption="-shell-escape" -g -pdf cover1.tex 1>/dev/null 2>/dev/null'); ob_start(); require "cover2.tex.php"; $covertex_content = ob_get_contents(); ob_end_clean(); if (!file_exists("cover2.tex") || user_consent("cover2.tex already exists. overwrite?")) file_put_contents("cover2.tex",$covertex_content); shell_exec('latexmk -latexoption="-shell-escape" -g -pdf cover2.tex 1>/dev/null 2>/dev/null'); echo "=== done ===\nNext step, run this command:\nlatexmk -latexoption=\"-shell-escape\" -g -pdf main.tex\n"; ?>