#!/bin/bash
Version=1.05
Myname="${0##*/}"

:<<'DOC'
= text2pdf - convert text file(s) to pdf.

= Synopsis
text2pdf [options] [file ...]	

== Options
-h|--help	print short help and exit
-H|--Help	print full documentation via less and exit
-V|--version	print version and exit
-c|--cols=X	print X columns on the page, default: 1
-f|--font=X	set TTF/OTF font to X; default: Latin Modern Mono
-l|--lscape	print landscape; default: portrait
-m|--margin=X	set margins to X mm; default: 10
-n|--number	number the lines; default: no numbering
-o|--out=X	write PDF to X[.pdf]; default: write to standard output
-p|--page	start each file on a new page.
-s|--size=X	set fontsize to X points; default: 10
   --squeeze	squeeze multiple newlines in input to one
   --tabstop=X	have tabs X characters apart; default: 8
-t|--title	print counter + file name before the output of each file
-w|--white	set white between lines to X points; default: 2

= Description
text2pdf converts one or more text files to pdf. You can print the text in
up to 9 columns (default: 1), in any font size (default: 10). The font used
by default is Latin Modern Mono. You can start each file on a new page and
introduce each file with a numbered header containing its name; and you can
number the lines.

= Options
--help	
	prints short help information.
	
--Help	
	Prints full documentation /via/ less.
	
--title	
	the text of each file will be preceeded with a header line
	containing a counter followed by the file name.
	
--page	
	the text of each file will start on a new page.
	
--cols=X	
	the output will be printed in X columns, where n=1-9, default: 1.
	This is useful, for example, for printing a file listing.
	
--size=X	
	set the point size to X, default: 10.
	
--white=X	
	set white between lines to X, default: 2.
	
--font=X	
	changes the font to X, which must be the PostScript name of an
	available TTF or OTF font. The default (probably in your distro) is
	Latin Modern Mono. Be sure the choose a font that contains all
	characters occurring in your file. You probably also want the font
	to be monospaced.

--margin=X	
	set the margins to X mm; default: 10mm

--number	
	lines will be numbered.
	
--tabstop=X	
	tabs will be expanded to X spaces. The default is 8.
	
--squeeze	
	multiple empty lines will be squeezed to a single empty line.

= Author
[Wybo Dekker](wybodekker@me.com)

= Copyright
Released under the [GNU General Public License](www.gnu.org/copyleft/gpl.html)
DOC

REd='\e[38;5;9m' Mag='\e[38;5;5m' Nor='\e[0m'
    die() { local i; for i; do echo -e "$Myname: $REd$i$Nor"; done 1>&2; exit 1; }
   Warn() { local i; for i; do echo -e "$Myname: $Mag$i$Nor"; done 1>&2; }
helpsrt() { sed -n '/^= Synopsis/,/^= /p' "$0"|sed '1d;$d'; exit; }
helpall() { sed -n "/^:<<'DOC'$/,/^DOC/p" "$0"|sed '1d;$d'|
            less -P"$Myname-${Version/./·} (press h for help, q to quit)";exit; }

:<<'DOC' #---------------------------------------------------------------------
= inttest
synopsis:	 inttest opt int
description:	check if |int| is a positive integer and print it; if not, 
		give a fatal message.
DOC
#-------------------------------------------------------------------------------
inttest() {
   [[ $2 =~ ^[1-9][0-9]*$ ]] ||
      die "Argument for --$1 ($2) is not a positive integer"
}

:<<'DOC' #---------------------------------------------------------------------
= excheck
synopsis:	 excheck executable1 [executable2...]
description:	check if all needed execs are there and getopt is GNU
DOC
#-------------------------------------------------------------------------------
excheck() {
   local ok=true i
   ((BASH_VERSINFO>=4)) || die "Need bash version >= 4"
   for i; do 
      command -v "$i" > /dev/null && continue
      Warn "Missing executable: $i"
      ok=false
   done
   $ok || die
   getopt -T 
   [[ $? -ne 4 ]] && die "Your getopt is not GNU"
}

:<<'DOC' #----------------------------------------------------------------------
= handle_options
synopsis:	 handle_options "$@"
description:	handle the options.
globals used:	 Myname Version
globals  set:	 args
DOC
#-------------------------------------------------------------------------------
handle_options() {
   local options
   options=$(getopt \
      -n "$Myname" \
      -o hHVIb:c:f:lm:no:pr:s:w:t \
      -l help,Help,version,batch:,cols:,font:,lscap,margin:,number,out:,page \
      -l size:,white:,squeeze,tabstop:,title,width: \
      -- "$@"
   ) || exit 1
   eval set -- "$options"
   cat='cat'
   colbeg=
   colend=
   font='Latin Modern Mono'
   lscape=
   number=false
   margin=10
   out=''
   page=false
   size=10
   white=2
   tabstop=8
   title=false
   while true; do
      case $1 in
      (-h|--help)      # print short help and exit
            	       helpsrt
		       ;;
      (-H|--Help)      # print full documentation via less and exit
            	       helpall
		       ;;
      (-V|--version)   # print version and exit
            	       echo $Version
		       exit
		       ;;
      (-c|--cols)      # print X columns on the page, default: 1
		       inttest cols "$2"
		       case $2 in
		       (1)      colbeg=
		                colend=
		                ;;
		       ([2-9])  colbeg="\\begin{multicols}{$2}"
		                colend="\\end{multicols}"
		                ;;
		       (*)	die "--cols option needs 1-digit argument"
		       esac
		       shift 2
		       ;;
      (-f|--font)    # set TTF/OTF font to X; default: Latin Modern Mono
		       font=$2
		       shift 2
		       ;;
      (-l|--lscape)    # print landscape; default: portrait
		       lscape=',landscape'
		       shift
		       ;;
      (-m|--margin)  # set margins to X mm; default: 10
		       margin=$2
		       shift 2
		       ;;
      (-n|--number)    # number the lines; default: no numbering
		       number=true
		       shift
		       ;;
      (-o|--out)     # write PDF to X[.pdf]; default: write to standard output
		       out=${2%.pdf}.pdf
		       shift 2
		       ;;
      (-p|--page)      # start each file on a new page.
		       page=true
		       shift
		       ;;
      (-s|--size)    # set fontsize to X points; default: 10
		       size=$2
		       shift 2
		       ;;
      (--squeeze)      # squeeze multiple newlines in input to one
		       cat='cat -s'
		       shift
		       ;;
      (--tabstop)    # have tabs X characters apart; default: 8
		       tabstop=$2
		       shift 2
		       ;;
      (-t|--title)     # print counter + file name before the output of each file
		       title=true
		       shift
		       ;;
      (-w|--white)     # set white between lines to X points; default: 2
		       white=$2
		       shift 2
		       ;;
      (-I)             instscript "$0" ||
		          die 'the -I option is for developers only'
		       exit
		       ;;
      (--)             shift
		       break
		       ;;
      (*)              break
		       ;;
      esac
   done
   args=("$@")
}

excheck getopt lualatex
handle_options "$@"
set -- "${args[@]}"

mess=()
for i; do
   if [[ ! -e $i ]]; then
      mess+=("File $i not found")
   else
      enc=$(file --mime-encoding -bL "$i")
      [[ $enc =~ us-ascii|utf-8 ]] ||
         mess+=("$i: encoding ($enc) is not us-ascii or utf-8; please convert")
   fi
done
(( ${#mess[@]} > 0 )) && die "${mess[@]}"

tmp=$(mktemp -d -t "$Myname.XXXXXXXXXX")

if (( $# == 0 )); then # read from stdin
   cat - > "$tmp/text"
   set -- "$tmp/text"
fi

cat <<-EOF > "$tmp/main.tex"
	%!lualatex
	\\documentclass{article}
	\\usepackage[a4paper,margin=${margin}mm,noheadfoot$lscape]{geometry}
	\\usepackage{fontspec,multicol}
	\\defaultfontfeatures{Ligatures=TeX}
	\\setmainfont{$font}\\setmonofont{$font}
	\\makeatletter %JCL
	\\def\\verbatimfile#1{\\begingroup
			    \\@verbatim \\frenchspacing \\@vobeyspaces
			    \\input#1 \\endgroup
	}
	\\newcounter{lineno}
	\\def\\verbatimlisting#1{\\setcounter{lineno}{0}%
	    \\begingroup \\@verbatim \\frenchspacing \\@vobeyspaces \\parindent=20pt
	    \\everypar{\\stepcounter{lineno}\\llap{{\\fontsize{7}{9}\\selectfont\\thelineno}\\ \\ }}\\input#1
	    \\endgroup
	}
	\\makeatother
	\\pagestyle{empty}
	\\begin{document}
	\\fontsize{$size}{$((size+white))pt}\\selectfont
	$colbeg
	EOF

n=0
for i; do
   eval "expand --tabs=$tabstop '$i' |$cat >>$tmp/text.$n"
   $page  && printf '\\newpage\n' 	   >> "$tmp/main.tex"
   $title && printf '\\section{%s}\n' "$i" >> "$tmp/main.tex"
   if $number; then
      echo "\\verbatimlisting{text.$n}" >> "$tmp/main.tex"
   else
      echo "\\verbatimfile{text.$n}" >> "$tmp/main.tex"
   fi
   ((n++))
done

cat <<-EOF >> "$tmp/main.tex"
	$colend
	\\end{document}
	EOF
cd "$tmp" || die "Could not cd to $tmp"
echo x |lualatex main.tex &>/dev/null ||
   die "Errors running lualatex; inspect $tmp"

if [[ -n $out ]]; then
   mv -f "$tmp/main.pdf" "$PWD/$out"
else
   cat "$tmp/main.pdf"
fi
rm -rf "$tmp"
