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

doc=$(cat \
<<'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 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=X	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.

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

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

# --- colors, help from embedded doc, die and warn ---
[ -t 1 ] && { Red=$'\e[1;31m' Mag=$'\e[1;35m' Nor=$'\e[0m'; } || Red='' Mag='' Nor=''
nv="-$Myname-${Version/./\\.} (press h for help, q to quit)"
helpsrt() { sed -n '/^= Synopsis/,/^= Desc/{//d;p}' <<<"$doc"; exit; }
helpall() { less -P"$nv" <<<"$doc"; exit; }
    die() { printf "%s$Nor\n" "${@/#/$Myname: $Red}" >&2; exit 1; }
   Warn() { printf "%s$Nor\n" "${@/#/$Myname: $Mag}" >&2; }

:<<'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 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"
