├── LICENSE ├── README.md └── src2pdf.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Andrew Pope 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # src2pdf :page_with_curl: 2 | 3 | Yet another source code to pdf script using LaTeX. 4 | 5 | ## Introduction 6 | ### Rationale 7 | 8 | Ever needed to hand in a hardcopy of the code you produced in a university assignment? Have you almost destroyed your keyboard trying to format a word document (or similar) containing this same source code? 9 | 10 | Well look no further, `src2pdf` is here to put your troubled mind at ease! Using LaTeX and Bash, present your development efforts in a neat and ordered format using one command! 11 | 12 | ### Example 13 | 14 | ![1](https://i.imgur.com/T4QiEX5m.png) ![2](https://i.imgur.com/YDpsWm9m.png) 15 | > _Show how fancy you are with a title page, table of contents, and syntax highlighting based on source language_ 16 | 17 | ### How is this script different? 18 | 19 | Honestly, this script is not that different to the others out there. However, this implementation does allow you to customise a **title**, **subtitle**, **author**, and source **language**. If this script gains popularity, I might put in _extra features_ such as _fancier_ title pages. 20 | 21 | ## Installation 22 | ### Required packages 23 | 24 | As this script extensively uses LaTeX, you will need to ensure that it is installed on your system. As an example for Ubuntu, you might install the packages... 25 | ```bash 26 | $ apt-get install texlive-latex-base texlive-latex-extra 27 | ``` 28 | More generally, this script will require the following packages to be installed: [pdflatex](http://linux.die.net/man/1/pdflatex), [color](http://www.ctan.org/tex-archive/macros/latex/contrib/xcolor/), [listings](https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings). 29 | 30 | ### Finding the script 31 | 32 | After installing the required packages, the script should work out-of-the-box after making it executable. Personally, I like to put the script somewhere where it can be easily found on `$PATH` (such as `/usr/local/bin`). 33 | 34 | ```bash 35 | $ chmod +x /usr/local/bin/src2pdf.sh 36 | ``` 37 | 38 | ## Operation 39 | 40 | Navigate to your project directory and run the following (assuming the script is on the `$PATH`): 41 | ``` 42 | arosspope@(project) $ src2pdf 43 | ``` 44 | You will then be prompted with a series of questions to generate and customise the pdf. Here is an example of the script running: 45 | 46 | 47 | ``` 48 | $ Title (blank to use prm_sim) : PRM Simulator 49 | $ Author (blank for nothing) : arosspope 50 | $ Subtitle (blank for nothing) : A Probabilistic RoadMap (PRM) simulator in ROS 51 | $ Language of files to parse (blank for 'C++') : 52 | $ Provide a space separated list of extensions to include (default is 'h cpp') : 53 | $ Re-order files to place header files in front of source files? (y/n) : y 54 | Re-ordering files. 55 | $ Review files found? (y/n) : n 56 | Creating tex file. 57 | Creating pdf. 58 | ... 59 | Renaming output files. 60 | Cleaning up. 61 | Done, output file is 'PRM Simulator.pdf' in this directory 62 | ``` 63 | Please note that _special characters_ `#%$_^&}{)(` within the title, subtitle and/or author positions **must be escaped**, or the script will fail to run. 64 | 65 | Currently, the supported languages are specified by the LaTeX [source code listings](http://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings) page. They include (but are not limited to) `C++`, `C`, `C#`, `Java`, `Matlab`, `Python`, `R`, `SQL` and `HTML`. 66 | 67 | ## Acknowledgements 68 | 69 | The bones of this script comes from the [tutorial](https://samhobbs.co.uk/2017/01/bash-script-generate-pdf-source-code-syntax-highlighting-using-latex) _'BASH Script to generate PDF of Source Code with Syntax Highlighting using LaTeX'_ by Sam Hobbs, 2017. 70 | -------------------------------------------------------------------------------- /src2pdf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | read -p "Title (blank to use ${PWD##*/}) : " answer 4 | 5 | if [[ $answer == "" ]]; then 6 | title=${PWD##*/} 7 | else 8 | title=$answer 9 | fi 10 | 11 | read -p "Author (blank for nothing) : " answer 12 | 13 | if [[ $answer == "" ]]; then 14 | author="" 15 | else 16 | author=$answer 17 | fi 18 | 19 | read -p "Subtitle (blank for nothing) : " answer 20 | 21 | if [[ $answer == "" ]]; then 22 | subtitle="" 23 | else 24 | subtitle=$answer 25 | fi 26 | 27 | # see http://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings, part `Supported languages` 28 | read -p "Language of files to parse (blank for 'C++') : " answer 29 | 30 | if [[ $answer == "" ]]; then 31 | lang="C++" 32 | else 33 | lang=$answer 34 | fi 35 | 36 | # if output files already exist, delete them 37 | if [ -f ./tmp.aux ] || [ -f ./tmp.log ] || [ -f ./tmp.out ] || [ -f ./tmp.pdf ] || [ -f ./tmp.toc ] ; then 38 | echo " Removing old output files." 39 | rm ./tmp.* 40 | fi 41 | 42 | tex_file=$(mktemp) ## Random temp file name 43 | 44 | if [ $? -ne 0 ]; then 45 | echo " ERROR: failed to create temporary file." 46 | exit 1; 47 | fi 48 | 49 | ## Begin Tex setup 50 | cat << EOF > $tex_file 51 | 52 | \documentclass[titlepage]{article} 53 | \usepackage[utf8]{inputenc} 54 | 55 | \usepackage{titling} 56 | \newcommand{\subtitle}[1]{% 57 | \posttitle{% 58 | \par\end{center} 59 | \begin{center}\large#1\end{center} 60 | \vskip0.5em}% 61 | } 62 | 63 | \author{$author} 64 | \title{$title} 65 | \subtitle{$subtitle} 66 | 67 | \usepackage{listings} 68 | \usepackage[usenames,dvipsnames]{color} %% Allow color names 69 | \lstdefinestyle{customasm}{ 70 | belowcaptionskip=1\baselineskip, 71 | xleftmargin=\parindent, 72 | language=$lang, 73 | breaklines=true, %% Wrap long lines 74 | basicstyle=\footnotesize\ttfamily, 75 | commentstyle=\itshape\color{Gray}, 76 | stringstyle=\color{Black}, 77 | keywordstyle=\bfseries\color{OliveGreen}, 78 | identifierstyle=\color{blue}, 79 | xleftmargin=-8em, 80 | } 81 | \usepackage[colorlinks=true,linkcolor=blue]{hyperref} 82 | \usepackage{fancyhdr} 83 | \pagestyle{fancy} 84 | \lhead{$title} 85 | \rhead{$author} 86 | \begin{document} 87 | 88 | \maketitle 89 | 90 | \pagenumbering{roman} 91 | \tableofcontents 92 | 93 | \newpage 94 | \setcounter{page}{1} 95 | \pagenumbering{arabic} 96 | 97 | EOF 98 | ## End Tex Setup 99 | 100 | # ask the user which file extensions to include 101 | 102 | read -p "Provide a space separated list of extensions to include (default is 'h cpp') : " answer 103 | 104 | if [[ $answer == "" ]]; then 105 | answer="h cpp" 106 | fi 107 | 108 | # replace spaces with double escaped pipe using substring replacement http://www.tldp.org/LDP/abs/html/parameter-substitution.html 109 | 110 | extensions="${answer// /\\|}" 111 | 112 | ############### 113 | 114 | # FINDING FILES TO INCLUDE 115 | # inline comments http://stackoverflow.com/questions/2524367/inline-comments-for-bash#2524617 116 | # not all of the conditions below are necessary now that the regex for c++ files has been added, but they don't harm 117 | 118 | filesarray=( 119 | $( 120 | find . `# find files in the current directory` \ 121 | -type f `# must be regular files` \ 122 | -regex ".*\.\($extensions\)" `# only files with the chosen extensions (.h, .cpp and .qml) by default` \ 123 | ! -regex ".*/\..*" `# exclude hidden directories - anything slash dot anything (Emacs regex on whole path https://www.emacswiki.org/emacs/RegularExpression)` \ 124 | ! -name ".*" `# not hidden files` \ 125 | ! -name "*~" `# don't include backup files` \ 126 | ! -name 'src2pdf' `# not this file if it's in the current directory` 127 | )) 128 | 129 | ############### 130 | 131 | # sort the array https://stackoverflow.com/questions/7442417/how-to-sort-an-array-in-bash#11789688 132 | # internal field separator $IFS https://bash.cyberciti.biz/guide/$IFS 133 | 134 | IFS=$'\n' filesarray=($(sort <<<"${filesarray[*]}")) 135 | unset IFS 136 | 137 | ############### 138 | 139 | ## TODO: This doesn't make much sense for other languages 140 | read -p "Re-order files to place header files in front of source files? (Y/n) : " answer 141 | 142 | if [[ ! $answer == "n" ]] && [[ ! $answer == "N" ]] ; then 143 | echo " Re-ordering files." 144 | 145 | # if this element is a .cpp file, check the next element to see if it is a matching .h file 146 | # if it is, swap the order of the two elements 147 | re="^(.*)\.c(pp)?$" 148 | 149 | # this element is ${filesarray[$i]}, next element is ${filesarray[$i+1]} 150 | for (( i=0; i<=$(( ${#filesarray[@]} -1 )); i++ )) 151 | do 152 | # if the element is a .cpp file, check the next element to see if it is a matching .h file 153 | if [[ ${filesarray[$i]} =~ $re ]]; then 154 | header=${BASH_REMATCH[1]} 155 | header+=".h" 156 | if [[ ${filesarray[$i+1]} == $header ]]; then 157 | # replace the next element in the array with the current element 158 | filesarray[$i+1]=${filesarray[$i]} 159 | # replace the current element in the array with $header 160 | filesarray[$i]=$header 161 | fi 162 | fi 163 | done 164 | fi 165 | 166 | ############### 167 | 168 | # Change ./foo/bar.src to foo/bar.src 169 | IFS=$'\n' filesarray=($(sed 's/^\..//' <<<"${filesarray[*]}")) 170 | unset IFS 171 | 172 | ############### 173 | 174 | read -p "Review files found? (y/N) : " answer 175 | 176 | if [[ $answer == "y" ]] || [[ $answer == "Y" ]] ; then 177 | 178 | echo " The following files will be included in the document." 179 | 180 | for i in "${filesarray[@]}" 181 | do 182 | echo $i 183 | done 184 | 185 | # allow the user to abort 186 | read -p "Proceed? (y/n) : " answer 187 | if [[ $answer == "n" ]] || [[ $answer == "N" ]] ; then 188 | exit 0 189 | fi 190 | 191 | fi 192 | 193 | ############### 194 | 195 | # create a .tex file with each section on its own page 196 | 197 | echo " Creating tex file." 198 | 199 | for i in "${filesarray[@]}" 200 | do 201 | name=$(echo $i | sed 's/\_/\\_/g') # Escape filename with underscores 202 | echo "\newpage" >> $tex_file # start each section on a new page 203 | echo "\section{$name}" >> $tex_file # create a section for each source file 204 | echo "\lstinputlisting[style=customasm]{$i}" >>$tex_file # place the contents of each file in a listing 205 | done 206 | 207 | echo "\end{document}" >> $tex_file 208 | 209 | ############### 210 | 211 | # run pdflatex twice to produce TOC 212 | echo " Creating pdf." 213 | echo 214 | 215 | pdflatex $tex_file -output-directory . && pdflatex $tex_file -output-directory . 216 | 217 | if [ $? -ne 0 ]; then 218 | echo " ERROR: pdflatex command failed, refer to tmp.log for more information." 219 | exit 1; 220 | fi 221 | 222 | ############### 223 | 224 | echo " Renaming output files." 225 | 226 | mv tmp.pdf "$title.pdf" 227 | 228 | echo " Cleaning up." 229 | 230 | rm ./tmp.* 231 | 232 | echo "Done, output file is '$title.pdf' in this directory" 233 | --------------------------------------------------------------------------------