#!/bin/sh -e

PROG=$(basename $0)

usage ()
{
	cat << HELP
Usage: $PROG [options]

Test driver for 'pwebmac.tex' in combination with various TeX engines.
Produce TeX output in DVI, PDF or HINT format from a set of C/WEB programs
included in the 'TeX Live' source tree.

Options are (--long options only with Linux-getopt):
	-c, --changes		Apply change file to C/WEB source
	-f, --files STRING	Process only subset of C/WEB programs
	-h, --help		Print this help message and exit
	-n, --new		Use 'pwebmac' instead of 'webmac'
	-o, --outdir ARG	Create tarballs in path ARG
	-p, --pdftocfront	Place TOC page at the front (PDF only)
	-t, --tex ARG		Use TeX variant ARG=[(hi|pdf|xe)]tex
	-v, --validpdf		Use correct number of entries in NOS node

Public domain.  Originally written by Andreas Scherer, 2020.
HELP
}

LONGOPTS=changes,files:,help,new,outdir:,pdftocfront,tex:,validpdf
SHRTOPTS=cf:hno:pt:v

CHANGES= # apply changefile to C/WEB source
FILESELECT=false # user-defined '--files' selection
NEW=false # '\input pwebmac' instead of '\input webmac' for PDF et al.
OUTDIR=. # path where the resulting tarballs are placed
PDFTOCFRONT=false # push table-of-contents to front of PDF output
TEX=tex # or 'pdftex' or 'xetex' or 'hitex' or 'luatex'
VALID=false # give 'pdftex' a chance to produce valid output

# Extra material for editorial improvements
# published in https://ctan.org/pkg/pwebmac (editorsnote.tex etc.),
# https://github.com/ascherer/web (cosmetics for HiTeX and PDFTeX),
# and https://github.com/ascherer/mplibdir (cosmetics for MetaPost)
LOCALSTUFF=/opt/github/web

# Initial list of C/WEB sources to process, overridable with option '-f':
KNUTHWHERE=$(locate /bibtex.web)
if [ -z "$KNUTHWHERE" ]
then echo "$PROG: Can't locate the TeX Live source tree!" >&2; exit 1
fi
KNUTHWARE=$(dirname $KNUTHWHERE)

FILES="$KNUTHWARE/*.web pdftex.web xetex.web twill"
WEBINPUTS=$KNUTHWARE//:

FILES="$FILES common ctangle cweave ctwill refsort twinx ctie tie hitex \
	mp mpost mpmath mpmathbinary mpmathdecimal mpmathdouble mpstrings tfmin"
CWEBINPUTS=$KNUTHWARE//:

KNUTHWHERE=$(locate /glue.web)
if [ -n "$KNUTHWHERE" ]
then
	FILES="$FILES $KNUTHWHERE"
	WEBINPUTS=$(dirname $KNUTHWHERE):$KNUTHWARE//:
fi

export WEBINPUTS CWEBINPUTS

getopt -T >/dev/null && true # keep going

if [ $? -eq 4 ] # Check for Linux-getopt with extensions
then OPTS=$(getopt -n $PROG -o $SHRTOPTS -l $LONGOPTS -- "$@")
else OPTS=$(getopt $SHRTOPTS $*)
fi

if [ $? -eq 0 ] # Check return code from getopt
then eval set -- $OPTS
else echo 'Failed to parse options.' >&2; exit 1
fi

while true
do
	case "$1" in
		-c | --changes ) CHANGES='-changes'; shift ;;
		-f | --files ) FILES="$2"; FILESELECT=true; shift 2 ;;
		-h | --help ) usage; exit 0 ;;
		-n | --new ) NEW=true; shift ;;
		-o | --outdir ) OUTDIR="$2"; shift 2 ;;
		-p | --pdftocfront ) PDFTOCFRONT=true; shift ;;
		-t | --tex ) TEX=$2; shift 2 ;;
		-v | --validpdf ) VALID=true; shift ;;
		-- ) shift; break ;;
		* ) usage; exit 1 ;;
	esac
done

CWEAVE='cweave -f +lX +bph'
CTWILL='ctwill -f +lpdf +bph'
HITEX='hitex --compress'
PAX='pax -wvzf'
EXT=pdf # default extension for 'knuth-pdf'
SED_I='sed -i' # non-GNU-sed requires an extra '' argument for '-i' option.
# Prevent '#1)' from showing up in the PDF bookmarks/outlines:
PURGE_OUTLINES='s/\\(\([0-9a-z]\)[0-9a-z]*)/\\9{\1}/g'
# Sorting order of new material from TEX.CH and ENCTEX2.CH
SORT_NOS='s/\(ump \)\(a couple\)/\1\\(a)\2/
s/\(ump \)\(constants\)/\1\\(c)\2/
s/\(ump \)\(enc\)/\1\\(e)\2/
s/\(ump \)\(ML\)/\1\\(m)\2/'
WEAVE=weave
XETEX=xetex

case "$TEX" in
	hitex ) # HINT format
		CTWILL="$CTWILL +P"
		TEX="$HITEX"
		EXT=hnt # default extension for 'knuth-hint'
		PDFTOCFRONT=false # use 'hintview -h' to start with TOC page
		VALID=false ;; # HiTeX has no command-line option '--shell-escape'

	pdftex | luatex ) # actually only necessary for 'pwebmac.tex'
		VALID=true ;;

	* ) # plain TeX and XeTeX use different approaches
		[ tex = "$TEX" ] && XETEX="$XETEX --no-pdf"
			# XeTeX's extended DVI format
		VALID=false ;;
esac

# Valid PDF output from 'pdftex' and 'luatex': In 'pwebmac.tex' set '\countNOS'
# to the actual number of @<named modules@>, not the number of all sections.
if $VALID
then
	NEW=true # PDF output requires 'pwebmac.tex'
	TEX="$TEX --shell-escape"
fi

# Use alternative TeX macros more suited for PDF output.
[ -n "$CHANGES" ] && NEW=true
$NEW && WEAVE="$WEAVE -p"

# Loop over WEB and CWEB programs we want to get formatted
for f in $FILES
do
	f=$(basename $f .web)

	# Prepare local C/WEB sources
	case $f in
		vftovp ) # FIX: Sorting order of named sections
			sed -e 's/\(Compute the \)\(|activity\)/\1\\9{a}\2/
/\\def\\(/d' -e $PURGE_OUTLINES $KNUTHWARE/$f.web > $f.web ;; # )

		pdftex ) # Fix several 'Overfull \hbox'es
			tie -m $f.web $f.web $LOCALSTUFF/$f.ch ;;

		hitex | mp | mpost | mpmath* | mpstrings | tfmin )
			# Beautifications for HiTeX and MetaPost
			tie -m $f.w $f.w $LOCALSTUFF/$f.ch
			$SED_I -e $PURGE_OUTLINES -e '/\\def\\(/d' $f.w ;; # )

		weave | twill ) # Fix non-constant factor
			if [ "$HITEX" = "$TEX" ] && [ ! -f weave.web ]
			then sed -e 's/\\the\\hsize/460pt/' \
				$KNUTHWARE/weave.web > weave.web
			fi ;;
	esac

	# Run C/WEAVE on the C/WEB sources w/o changes
	if [ -n "$CHANGES" ]
	then
		case $f in
			# These are changes in and of themselves
			ctwill | twill | glue | hitex | mp | mpost | \
				mpmath* | mpstrings | tfmin ) continue ;;

			# CWEB programs have individual changefiles
			common ) $CWEAVE $f comm-w2c ;;
			ctangle ) $CWEAVE $f ctang-w2c ;;
			cweave ) $CWEAVE $f cweav-w2c ;;
			refsort | twinx ) $CWEAVE $f $f ;;
			ctie ) $CWEAVE $f $f-k ;;
			tie ) $CWEAVE $f $f-w2c ;;

			# main WEB programs have complex change files
			mf | pdftex | xetex )
				WEBINPUTS=.:$KNUTHWARE/../../Work//:$WEBINPUTS: \
				$WEAVE $f $f-final ;;
			tex )
				sed -e "$SORT_NOS" $KNUTHWARE/$f.web > $f.web
				sed -e "$SORT_NOS" $KNUTHWARE/../../Work/texk/web2c/$f-final.ch > $f-final.ch
				WEBINPUTS=.:$WEBINPUTS $WEAVE $f $f-final ;;

			# FIX: Sorting order of new @<Define...@> sections
			vftovp ) WEBINPUTS=.:$WEBINPUTS $WEAVE $f $f
				$SED_I -e $PURGE_OUTLINES $f.tex ;;

			# all other WEB codes have singular changefiles
			* ) $WEAVE $f $f ;;
		esac

		# only document changed modules/sections
		$SED_I -e '/\\let\\maybe/s/\\iftrue/\\iffalse/' $f.tex
	else # -z $CHANGES
		case $f in
			ctwill ) # apply tons of editorial changes to 'ctwill.w'
				[ "$HITEX" = "$TEX" ] &&
					ctie -m $f.w cweave.w $f-w2c.ch $f-hint.ch ||
					ctie -m $f.w cweave.w $f-w2c.ch $f-mini.ch
				$CTWILL $f # prime the pump
				$CTWILL $f ;; # get decent answers

			c* | refsort | twinx | tie ) $CWEAVE $f ;;

			hitex | mp | mpost | mpmath* | mpstrings | tfmin )
				CWEBINPUTS=.: $CWEAVE $f ;;

			twill ) WEBINPUTS=.:$WEBINPUTS \
				tie -c $f.ch weave.web weave.ch weav-$f.ch &&
				$WEAVE weave $f $f ;;

			pdftex | weave | vftovp )
				WEBINPUTS=.:$WEBINPUTS $WEAVE $f ;;

			* ) $WEAVE $f ;;
		esac
	fi # $CHANGES

	case $f in
		# amend '\N' redefinition for PDF outlines in Metafont and TeX
		# (also pdfTeX and XeTeX); 'pwebmac' redefines the headers.
		mf | tex | pdftex | xetex ) $NEW && $SED_I -e \
's/\\outer\\def\\N.*{/&%/
/\\outer\\def\\N/a\
  \\ifpdf{\\makeoutlinetoks{[#2] #3}\\outlinedone}\\fi
s/\\def\\rhead/\\gtitle=/
/\\gtitle=/a\
  \\MN#1.\\vfill\\eject % begin starred section
s/{\\the\\pageno}/&{\\the\\toksE}/
/\\edef\\next/a\
  \\ifpdflua\\relax\\else\
  \\ifpdf\\special{pdf: outline 0 << /Title (\\the\\toksE) /Dest\
    [ @thispage /FitH @ypos ] >>}\\fi\\fi
/\\def\\(/d' -e $PURGE_OUTLINES $f.tex ;; # )}
	esac # mf | tex | pdftex | xetex

	# special treatment for individual C/WEB programs
	case $f in
		# replace former convention to indicate "not a title
		# page" to include page headers for table-of-contents;
		# purge conflict between bibtex.web and webmac.tex
		# 'E' no longer free to be active character
		# fix table-of-contents page for bibtex
		# FIX: don't wait for Oren Patashnik.
		bibtex ) $SED_I -e 's/\\def\\titlepage{F}/\\titletrue/' $f.tex
			[ -z "$CHANGES" ] && $SED_I -e '71,78d' $f.tex ;;

		# FIX: 'glue.web' obviously uses an old 'webmac.tex'.
		glue ) $SED_I -e 's/titlefalse/titletrue/
/\\def\\title{GLUE}/a\
\\pageno=\\contentspagenumber \\advance\\pageno by1\\relax' $f.tex ;;

		# FIX: GFtoDVI uses 'Metafont' in a module name;
		# this should appear correctly in the bookmarks, too.
		# FIX: Metafont uses '\over' in several module names;
		# this should appear correctly in the bookmarks, too.
		# FIX: typo in MF.WEB.
		gftodvi | mf ) $NEW && $SED_I -e '/\\def\\MF/a\
\\ifpdf\
\\sanitizecommand\\MF{Metafont}\
\\sanitizecommand\\over{\/}\
\\sanitizecommand\\langle{<}\
\\sanitizecommand\\rangle{>}\
\\fi' -e 's/a ano/ano/' $f.tex ;;

		# FIX: MFT uses '\pb' in several module names;
		# this should appear correctly in the bookmarks, too.
		mft ) $NEW && $SED_I -e '/\\def\\pb/a\
\\ifpdf\\sanitizecommand\\pb{\|...\|}\\fi' $f.tex ;;

		# FIX: pdfTeX uses '\pdfTeX' in section names; these should
		# appear correctly in the bookmarks, too.
		pdftex ) $NEW && $SED_I -e '/\\def\\pdfeTeX{pdf\\eTeX}/a\
\\ifpdf\
\\sanitizecommand\\pdfTeX{pdfTeX}\
\\sanitizecommand\\eTeX{e-TeX}\
\\sanitizecommand\\over{\/}\
\\fi' $f.tex ;;

		# FIX: weave uses '\max' in name of module 173; this should
		# appear correctly in the bookmarks, too.
		weave | twill ) $NEW && $SED_I -e '/\\def\\({}/a\
\\ifpdf\\sanitizecommand\\max{max}\\fi' $f.tex ;; # )

		# FIX: purge obsolete macros from XeTeX.
		# FIX: XeTeX uses '\pdfTeX' from section 114, which is not
		# changed and thus 'disappears'; repeat in preamble.
		# FIX: apply '\sanitizecommand' for bookmarks.
		xetex ) $SED_I -e '/\\input xewebmac/d
/\\let\\maybe/i\
\\def\\pdfTeX{pdf\\TeX}' $f.tex
			$NEW && $SED_I -e '/\\def\\pdfTeX/a\
\\ifpdf\\sanitizecommand\\pdfTeX{pdfTeX}\\fi
/\\def\\eTeX/a\
\\ifpdf\
\\sanitizecommand\\eTeX{e-TeX}\
\\sanitizecommand\\over{\/}\
\\fi' $f.tex ;;
	esac

	# timestamp on table-of-contents page or the first page
	case $f in
		tex | pdftex | xetex | hitex | mf | mp )
			$NEW && $SED_I -e '/\\def\\title{/i\
\\datethis\
\\emergencystretch=.1\\hsize' $f.tex ;; # }

		common | ctangle | cweave | ctie | tie )
			$SED_I -e '/\\def\\botofcontents/i\
\\datethis' $f.tex ;;

		bibtex | patgen | tangle | weave | twill | \
		mpost | mpmath* | mpstrings | tfmin )
			$NEW && $SED_I -e '/\\def\\title{/i\
\\datecontentspage\
' $f.tex ;; # } { {{ {

		* ) $NEW && $SED_I -e '/\\def\\botofcontents/d
s/  \\centerline{\(\\hsize\)/\\def\\covernote{\1/
s/\(Publishing Company.}}\)}/\1\n\\datecontentspage/
s/\(Mathematical Society.}}\)}/\1\n\\datecontentspage/' $f.tex ;;
	esac

	# shift table-of-contents pages to the front in PDF
	if $PDFTOCFRONT && echo $f | grep -v -q -E 'ctwill|hitex'
	then $SED_I -e '0,/\\N[1{]/s/\\N[1{]/\\input pdfwebtocfront\n\n&/' $f.tex # }}
	fi

	if [ -n "$CHANGES" ] || [ twill = "$f" ]
	then
		# We add an Editor's Note and the list of changed
		# sections on the ToC page.
		[ -f editorsnote.tex ] || cp $LOCALSTUFF/editorsnote.tex .

		case $f in
			mf ) $SED_I -e '/\\datethis/i\
\\input editorsnote.tex\
\\def\\datethis{\\def\\startsection{\\leftline{\\sc\\today\\ at \\hours}\
  \\medskip\\editorsnote\\readchanges\\bigskip\
  \\let\\startsection=\\stsec\\stsec}}' $f.tex ;;

			# TeX and XeTeX grow significantly for TeX Live
			# so there's enough room on the last ToC page.
			pdftex | tex | xetex ) $SED_I -e '/\\datethis/d
s/\(\\def\\botofcontents\).*/\1{\\hsize6.5in\\vskip 0pt plus 1filll/
/\\def\\botofcontents/i\
\\input editorsnote.tex
/\\def\\botofcontents/a\
  \\editorsnote\\readchanges\\medskip\\noindent\\sc\\today\\ at \\hours}
/\\input pdfwebtocfront/a\
\
\\def\\tocpages{2}' $f.tex ;;

			bibtex | patgen | tangle | weave | twill | \
				refsort | twinx )
				$SED_I -e 's/\\date.*/\\datecontentspage/
/\\datecontentspage/i\
\\input editorsnote\
\\def\\covernote{\\vbox{\\editorsnote\\readchanges\\par}}' $f.tex ;;

			common | ctangle | cweave | ctie | tie ) # {{
				$SED_I -e '/\\def\\covernote/i\
\\input editorsnote.tex
s/^}}/\\bigskip\\editorsnote\\readchanges\\par&/' $f.tex ;;

			* ) $SED_I -e '/\\def\\title{/i\
\\input editorsnote.tex
s/\\vbox{\\ninerm/&\\editorsnote\\readchanges\\medskip/' $f.tex ;; # }}
		esac
	fi # $CHANGES

	# Run TeX on the woven C/WEB programs
	case $f in
		ctwill ) # gives two different outcomes
			if [ "$HITEX" = "$TEX" ] # sort mini-indexes
			then # directly in the TeX file
				( ctwill-proofsort < $f.tex ) 1<> $f.tex
			else # in the TeX-created .ref file
				$TEX $f
				ctwill-refsort < $f.ref > $f.sref
			fi
			$TEX $f ;;

		* ) # run TeX twice
			if $PDFTOCFRONT || [ -n "$CHANGES" ]
			then [ xetex = $f ] && $XETEX $f || $TEX $f
			fi # only XeTeX can process XETEX.WEB
			[ xetex = $f ] && $XETEX $f || $TEX $f ;;
	esac
done

# create tarballs w/o changes for publication
if ( $PDFTOCFRONT || [ "$HITEX" = "$TEX" ] ) && ! $FILESELECT
then
	export TEXINPUTS=.:$(kpsewhich --var-value=TEXMFDIST)//:$KNUTHWARE//

	# Prepare 'webman' with section links and bookmarks.
	rm -f webman.tex
	f=$(kpsewhich -engine tex webman)
	[ -z "$CHANGES" ] &&
		tie -m webman.tex $f $LOCALSTUFF/webman-outlines.ch ||
		tie -m webman.tex $f $LOCALSTUFF/webman-outlines.ch \
			$LOCALSTUFF/webman-changes.ch
	$TEX webman

	if [ -z "$CHANGES" ]
	then
		touch pages.tex # let 'manmac' produce output at all

		$TEX -jobname=errorlog $LOCALSTUFF/Xerrorlog.tex
		for f in one two three four five six seven eight nine ten \
			eleven twelve
		do $TEX -jobname errata.$f errata.$f
		done
		$TEX errata
		$PAX "$OUTDIR/errata.tar.gz" -s ,^,errata/, err*.$EXT && true

		$PAX "$OUTDIR/hitex.tar.gz" -s ,^,hitex/, hitex.$EXT && true
		$PAX "$OUTDIR/mp.tar.gz" -s ,^,mp/, mp.$EXT mpost.$EXT && true

		# Finally, build the remaining documents
		# * TeX and Metafont test routines
		# * WEB and CWEB manuals
		rm -f trapman.tex cwebman.tex

		# FIX: Prepare 'trapman' for automatic processing; several
		# input files are renamed in TeX Live (in fact, there are
		# additional files for MetaPost).
		f=$(kpsewhich -engine tex trapman)
		tie -m trapman.tex $f $LOCALSTUFF/trapman.ch

		# Prepare 'cwebman' with footnotes describing the extended CWEB.
		f=$(kpsewhich -engine tex cwebman)
		tie -m cwebman.tex $f cwebman-w2c.ch

		for f in tripman trapman cwebman
		do $TEX $f
		done

		$PAX "$OUTDIR/mf.tar.gz" -s ,^,mf/, mf.$EXT trapman.$EXT && true
		$PAX "$OUTDIR/tex.tar.gz" -s ,^,tex/, \
			glue.$EXT tex.$EXT tripman.$EXT && true
		$PAX "$OUTDIR/web.tar.gz" -s ,^,web/, \
			webman.$EXT tangle.$EXT weave.$EXT twill.$EXT && true
		$PAX "$OUTDIR/cweb.tar.gz" -s ,^,cweb/, \
			cwebman.$EXT common.$EXT ctangle.$EXT cweave.$EXT \
			ctwill.$EXT refsort.$EXT twinx.$EXT && true
	else # -n $CHANGES
		for f in *.$EXT
		do
			case $f in *$CHANGES.$EXT ) rm -f $f; continue ;; esac
			mv $f $(basename $f .$EXT)$CHANGES.$EXT && true
		done
		[ "$HITEX" = "$TEX" ] && mv -f xetex.pdf xetex$CHANGES.pdf
		$PAX "$OUTDIR/mf$CHANGES.tar.gz" -s ,^,mf/, mf$CHANGES.$EXT && true
		$PAX "$OUTDIR/tex$CHANGES.tar.gz" -s ,^,tex/, tex$CHANGES.$EXT && true
		$PAX "$OUTDIR/web$CHANGES.tar.gz" -s ,^,web/, \
			webman$CHANGES.$EXT \
			tangle$CHANGES.$EXT weave$CHANGES.$EXT && true
		$PAX "$OUTDIR/cweb$CHANGES.tar.gz" -s ,^,cweb/, \
			common$CHANGES.$EXT ctangle$CHANGES.$EXT \
			cweave$CHANGES.$EXT refsort$CHANGES.$EXT \
			twinx$CHANGES.$EXT && true
	fi # $CHANGES

	$PAX "$OUTDIR/etc$CHANGES.tar.gz" -s ,^,etc/, \
		vftovp$CHANGES.$EXT vptovf$CHANGES.$EXT && true
	$PAX "$OUTDIR/mfware$CHANGES.tar.gz" -s ,^,mfware/, \
		gftodvi$CHANGES.$EXT gftopk$CHANGES.$EXT \
		gftype$CHANGES.$EXT mft$CHANGES.$EXT && true
	$PAX "$OUTDIR/texware$CHANGES.tar.gz" -s ,^,texware/, \
		dvitype$CHANGES.$EXT pltotf$CHANGES.$EXT \
		pooltype$CHANGES.$EXT tftopl$CHANGES.$EXT && true
	$PAX "$OUTDIR/other$CHANGES.tar.gz" -s ,^,other/, \
		dvicopy$CHANGES.$EXT patgen$CHANGES.$EXT \
		pktogf$CHANGES.$EXT pktype$CHANGES.$EXT && true
	[ "$HITEX" = "$TEX" ] || {
		$PAX "$OUTDIR/xetex$CHANGES.tar.gz" -s ,^,xetex/, \
		xetex$CHANGES.pdf && true ; }
	for f in bibtex pdftex ctie tie
	do $PAX "$OUTDIR/$f$CHANGES.tar.gz" -s ,^,$f/, $f$CHANGES.$EXT && true
	done

	# Notes to self:
	# (1) Create a user-friendly central entrypoint with
	#     (a) pandoc index.md -o index.pdf
	#     (b) pandoc index.md -s -o index.tex
	#         pandoc index.tex -s -o index.html
	#         rm index.tex
	# (2) Prepare a super-tarball from all the contents of these
	#     individual tarballs (42/53 and 34/54) with either of
	#     (a) pax -wzf knuth-pdf.tar.gz knuth-pdf
	#     (a') pax -wzf knuth-hint.tar.gz knuth-hint
	#     (b) zip -r knuth-pdf.zip knuth-pdf
	#     (b') zip -r knuth-hint.zip knuth-hint
fi

exit 0
