#!/bin/ksh93

VERSION='$Id: mktexpk 34656 2014-07-18 23:38:50Z karl $'
typeset -r FPROG=${.sh.file}
typeset -r PROG=${FPROG##*/}
SDIR=${FPROG%/*}

# preferentially use subprograms from our own directory.
PATH="${SDIR}:${PATH}"
[[ ${ uname -s ; } == 'SunOS' ]] && GREP='/usr/xpg4/bin/grep' || GREP='grep'

function showUsage {
	[[ -z $1 ]] && X='--man' || X='-?'
	getopts -a ${PROG} "${ print ${USAGE} ; }" OPT $X
}

typeset -x MT_TEXMFMAIN KPSE_DOT		# cache its value globally
[[ -z ${KPSE_DOT} ]] && KPSE_DOT="${PWD}"
TDIR=

function cleanup {
	cd
	[[ -n ${TDIR} && -d ${TDIR} ]] && rm -rf ${TDIR}
}

function getTexMake {
	typeset -n VAR=$2
	[[ -n ${VAR} ]] && return 0

	[[ -z ${MT_TEXMFMAIN} ]] && \
		MT_TEXMFMAIN=${ kpsewhich --expand-path='$TEXMFMAIN' ; }
	typeset WHAT=
	case "$1" in
		name)	WHAT='mktexnam' ;;
		update)	WHAT='mktexupd' ;;
		dir)	WHAT='mktexdir' ;;
		*) return 1 
	esac

	VAR=${ kpsewhich --format='web2c files' ${WHAT} ; }
	[[ -z ${VAR} ]] && VAR="${MT_TEXMFMAIN}/web2c/${WHAT}"
	return 0
}

function doMain {
	[[ -z $1 ]] && showUsage 1 && return 1

	if [[ -n $2 ]]; then
		FD="${2#>\&}"
		(( FD > 1 )) && exec 1>&${FD} || \
			print -u2 "${PROG}: operand '$2' ignored - bad filenumber"
	fi
	# Where do potential driver files belong?
	[[ -z ${MT_MFDESTDIR} && \
		-n ${MT_FEATURES} && ${MT_FEATURES} == *nomfdrivers* ]] && \
		export MT_MFDESTDIR="${PWD}"

	typeset NAME="$1" MF= MODE= CMD X A

	if kpsewhich "${NAME}.mf" >/dev/null 2>&1 || \
		mktexmf "${NAME}" >/dev/null 2>&1
	then
		# determine the progname of metafont to use; prefer mf-nowin.
		MF=${ whence mf-nowin ; }
		[[ -z ${MF} ]] && MF='mf'

		# Check that $BDPI and $MODE are consistent; if not, ignore the mode and
		# hope we can correctly guess it from bdpi.  (People like to specify the
		# resolution on the command line, not the mode so much.)
		if [[ -n ${MODE} ]]; then
			X='\mode:='"${MODE}"';mode_setup;'
			X+='message"BDPI= "&decimal round pixels_per_inch;end.'
			${MF} $X </dev/null | while read KEY VAL ; do
				[[ ${KEY} == 'BDPI=' ]] && MF_BDPI=${VAL} && break
			done
			if (( MF_BDPI != BDPI )); then
				print -u2 "${PROG}: Mismatched mode ${MODE} and" \
					"resolution ${BDPI}; ignoring mode."
				MODE=
			fi
		fi

		# If an explicit mode is not supplied, try to guess. You can get a
		# list of extant modes from ftp://ftp.tug.org/tex/modes.mf.
		if [[ -z ${MODE} || ${MODE} == 'default' ]]; then
			case ${BDPI} in
				  85) MODE=sun;;
				 100) MODE=nextscrn;;
				 180) MODE=toshiba;;
				 300) MODE=cx;;
				 360) MODE=epstylus;;
				 400) MODE=nexthi;;
				 600) MODE=ljfour;;
				 720) MODE=epscszz;;
				1200) MODE=ultre;;
				1270) MODE=linoone;;
				8000) MODE=dpdfezzz;;
				   *) MODE= ;;
			esac
		fi
		if [[ -z ${MODE} ]]; then
			print -u2 "${PROG}: Can't guess mode for ${BDPI} dpi devices." \
				"\n${PROG}: Use a config file or option to specify the mode;" \
				"see:\n${PROG}:" \
			'http://tug.org/texinfohtml/kpathsea.html#Unable-to-generate-fonts'
			return 1
		fi

		# Run Metafont. Always use plain Metafont, since reading cmbase.mf
		# does not noticeably slow things down.
		CMD=("${MF}" "\mode:=${MODE}; mag:=${MAG}; nonstopmode; input ${NAME}")
	else
		MODE='modeless'
		# ps_to_pk is set in mktex.opt
		[[ -z ${PS_TO_PK} && -n ${ps_to_pk} ]] && PS_TO_PK="${ps_to_pk}"
		if [[ ${PS_TO_PK:-gsftopk} == 'gsftopk' ]]; then
			${PS_TO_PK} -t "${NAME}" && CMD=( "${PS_TO_PK}" "${NAME}" "${DPI}" )
		elif [[ ${PS_TO_PK} == 'ps2pk' ]]; then
			# grep for the font in $PSMAPFILE.  These are base font names, such
			# as rpplr (the original) or pplr0 (an interim step) or
			# pplr8r (current).
			[[ -z ${PSMAPFILE} ]] && \
				PSMAPFILE=${ kpsewhich --format=map psfonts.map ps2pk.map ; }
			[[ -z ${PSMAPFILE} ]] && X= || \
				X=${ ${GREP} -E "^${NAME}([[:space:]]|$)" ${PSMAPFILE} ; }
			if [[ -n $X ]]; then
				X="${X##*$'\n'}"	# keep the last line, only
				A=( ${X//+([<\[\"])} )
				X=${A[3]}
				typeset ENCODING= PSNAME= SLANT= EXTEND=
				for (( I=3; I < ${#A[@]}; I++ )); do
					X=${A[I]}
					case "$X" in
						*.enc)       ENCODING="-e $X" ;;
						*.pf[ab])    PSNAME="$X" ;;
						*SlantFont)  SLANT="-S ${A[I-1]}" ;;
						*ExtendFont) EXTEND="-E ${A[I-1]}" ;;
					esac
				done
				# Guessing the name of the type1 font file as fallback:
				A=( "${NAME}."{pfa,pfb} )
				[[ ${NAME: -2:2} == '8r' ]] && A+=( "${NAME%r}a."{pfa,pfb} )
				for X in "${A[@]}"; do
					kpsewhich "$X" >/dev/null 2>&1 && PSNAME="$X" && break
				done

				if [[ -n ${PSNAME} ]]; then
					CMD=( 'ps2pk' '-v' "-X${DPI}" "-R${BDPI}"
						${SLANT} ${EXTEND} ${ENCODING} "${PSNAME}"
						"${NAME}.${DPI}pk"
					)
				elif gsftopk -t "${NAME}" 1>&2 ; then
					print -u2 "${PROG}: cannot find '${NAME}.pfa' or" \
						"'${NAME}.pfb'. Trying gsftopk."
					CMD=( 'gsftopk' "${NAME}" ${DPI} )
				fi
			fi
		fi

		# unsupported by $ps_to_pk, try other conversions:
		if [[ -z ${CMD} ]]; then
			if ttf2pk -t -q "${NAME}" >/dev/null 2>&1 ; then
				CMD=( 'ttf2pk' '-q' "${NAME}" ${DPI} )
			elif hbf2gf -t -q "${NAME}" >/dev/null 2>&1 ; then
				CMD=( 'hbf2gf' '-q' '-p' "${NAME}" ${DPI} )
			else
				print -u2 "${PROG}: don't know how to create bitmap font for" \
					"${NAME}.\n${PROG}: perhaps ${NAME} is missing from the" \
					"map file."
				return 1
			fi
		fi
	fi

	typeset -x MT_MKTEXNAM MT_MKTEXUPD MT_MKTEXDIR
	getTexMake update MT_MKTEXUPD
	getTexMake name MT_MKTEXNAM
	X=${ "${MT_MKTEXNAM}" "${NAME}" ${DPI} "${MODE}" "${DEST}" ; }
	A=( ${X//:/ } )

	typeset PKDEST=${A[0]} PKDESTDIR=${PKDEST%/*} PKNAME=${.sh.match:1} \
		GFNAME="${NAME}.${DPI}gf"

	if [[ -r ${PKDESTDIR}/${PKNAME} ]]; then
		print -u2 "${PROG}: '${PKDESTDIR}/${PKNAME}' already exists."
		print ${PKDESTDIR}/${PKNAME}
		"${MT_MKTEXUPD}" ${PKDESTDIR} ${PKNAME} 1>&2
		return 0
	fi

	getTexMake dir MT_MKTEXDIR
	"${MT_MKTEXDIR}" ${PKDESTDIR} 1>&2
	if [[ ! -d ${PKDESTDIR} ]]; then
		print -u2 "${PROG}: '${MT_MKTEXDIR} ${PKDESTDIR}' failed."
		return 1
	fi

	print -u2 "${PROG}: Running  ${CMD[@]}"
	if ! "${CMD[@]}" 1>&2 </dev/null ; then
		# Don't abort if only "Strange path", "bad pos" or "angle(0,0)"
		# errors occurr.
		if [[ -s ${NAME}.log ]]; then
			[[ ${PWD} == "${KPSE_DOT}" ]] || \
				cp -f "${NAME}.log" "${KPSE_DOT}/" 2>/dev/null
			${GREP} '^!' ${NAME}.log | sort >${TDIR}errs 2>/dev/null
			${GREP} '^! Strange path' ${TDIR}errs >${TDIR}strange 2>/dev/null
			${GREP} '^! bad pos.' ${TDIR}errs >${TDIR}badpos 2>/dev/null
			${GREP} '^! angle(0,0) is taken as zero.' ${TDIR}errs \
				>${TDIR}angle 2>/dev/null
			cat ${TDIR}badpos ${TDIR}strange ${TDIR}angle | \
				sort > ${TDIR}errs_accept
			if cmp ${TDIR}errs ${TDIR}errs_accept >/dev/null 2>&1; then
				print -u2 "${PROG}: warning: '${CMD[@]}' caused:"
				[[ -s ${TDIR}strange  ]] && print -u2 "\t- strange path errors"
				[[ -s ${TDIR}badpos ]] && print -u2 "\t- bad pos errors."
				[[ -s ${TDIR}angle ]] && print -u2 "\t- angle(0,0) errors."
			else
				print -u2 "${PROG}: '${CMD[@]}' failed."
				return 1
			fi
		fi
	fi

	[[ -r ${GFNAME} ]] && { gftopk ./${GFNAME} ${PKNAME} || return 1; }
	[[ ! -f ${PKNAME} ]] && [[ -f ${NAME}.${DPI}pk ]] && \
		mv "${NAME}.${DPI}pk" ${PKNAME}
	if [[ ! -s ${PKNAME} ]]; then
		print -u2 "${PROG}: '${CMD[@]}' failed to make ${PKNAME}."
		return 1
	fi

	# Install the PK file carefully, since others may be working simultaneously.
	if [[ ! -f ${PKDESTDIR}/${PKNAME} ]]; then
		cp -f ${PKNAME} ${PKDESTDIR}/pk$$.tmp || return 1
		chmod 0644 pk$$.tmp
		mv ${PKDESTDIR}/pk$$.tmp ${PKDESTDIR}/${PKNAME}
	fi

	# Update ls-R if necessary.
	"${MT_MKTEXUPD}" ${PKDESTDIR} ${PKNAME} 1>&2

	# If this line (or an equivalent) is not present, dvipsk/xdvik/dviljk
	# will think mktexpk failed.  Any other output to stdout will also lose.
	print ${PKDESTDIR}/${PKNAME}
	print -u2 "${PROG}: '${PKDESTDIR}/${$PKNAME}' successfully generated."
}

USAGE='[-?'"${VERSION}"' ]
[-author?Thomas Esser, Karl Berry, and Olaf Weber]
[-author?Jens Elkner (2015 ksh93 port/cleanup)]
[-license?Public domain.]
[+NAME?'"${PROG}"' - create a PK font]
[+DESCRIPTION?'"${PROG}"' is used to generate a \bPK\b file from the Metafont source files or type1 sources for \afont\a, if possible.]
[+?If \aredirect\a is given, for historic reasons it must be string of the form ">&\an\a" where \an\a is the number of the file descriptor which is to receive, instead of standard output, the name of the  generated file. Note that you need to quote this operand, otherwise the running shell does the redirection according to its own rules.]
[+?'"${PROG}"' is typically called by other programs, rather than from the command line. Therefore it will only print the path of the created font file to stdout, everything else goes to stderr.]
[+?If you expected the font to be available as an outline, and thus this script does not work and should not have been called, most likely the font'"'"'s .tfm name is missing from the relevant map file (e.g., psfonts.map for dvips, pdftex.map for pdftex).  These map files are typically maintained using updmap; q.v.]
[+?For step-by-step instructions on making new fonts known to TeX, see
http://tug.org/fonts/fontinstall.html.]
[+BUGS?Report bugs to: tex-k@tug.org]
[+?TeX Live home page: \bhttp://tug.org/texlive/\b]
[h:help?Print this help and exit.]
[F:functions?Print a list of all functions available.]
[T:trace]:[fnList?A comma separated list of functions of this script to trace (convinience for troubleshooting).]
[+?]
[r:dpi]:[num?Use the resolution \anum\a for the font in dots per inch.]
[b:bdpi]:[num?Use base resolution \anum\a for the font in dots per inch.]
[z:mag]:[string?Use the magnificiation \astring\a. See \bmf\b(1) for details.]
[m:mfmode]:[mode?Use the given \amode\a as the \bMETAFONT\b mode.]
[d:destdir]:[directory?Write fonts to the given \adirectory\a.]
[V:version?Print version info for this script and exit.]
\n\n\afont\a [\aredirect\a]
'
X="${ print ${USAGE} ; }"
DEST= MODE= MAG= DPI= BDPI=
integer FD=0
while getopts "${X}" OPT ; do
	case ${OPT} in
		h) showUsage ; exit 0 ;;
		T)	if [[ ${OPTARG} == 'ALL' ]]; then
				typeset -ft ${ typeset +f ; }
			else
				typeset -ft ${OPTARG//,/ }
			fi
			;;
		F) typeset +f && exit 0 ;;
		r) DPI="${OPTARG}" ;;
		b) BDPI="${OPTARG}" ;;
		m) MODE="${OPTARG}" ;;
		z) MAG="${OPTARG}" ;;
		d) DEST="${OPTARG}" ;;
		V) print -u2 "${PROG}  ${VERSION}" ; exit 0 ;;
		*) showUsage 1 ; exit 1 ;
	esac
done
X=$((OPTIND-1))
shift $X && OPTIND=1
unset X

trap cleanup EXIT
doMain "$@"
