texlive[48594] Build/source/texk/web2c/luatexdir: luatex: correct

commits+lscarso at tug.org commits+lscarso at tug.org
Wed Sep 5 23:57:30 CEST 2018


Revision: 48594
          http://tug.org/svn/texlive?view=revision&revision=48594
Author:   lscarso
Date:     2018-09-05 23:57:30 +0200 (Wed, 05 Sep 2018)
Log Message:
-----------
luatex: correct  automake file for pplib; replaced cweb files with c files.

Added Paths:
-----------
    trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am
    trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
    trunk/Build/source/texk/web2c/luatexdir/font/dofont.c
    trunk/Build/source/texk/web2c/luatexdir/font/luafont.c
    trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c
    trunk/Build/source/texk/web2c/luatexdir/font/pkin.c
    trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c
    trunk/Build/source/texk/web2c/luatexdir/font/subfont.c
    trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
    trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c
    trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c
    trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
    trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c
    trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c
    trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c
    trunk/Build/source/texk/web2c/luatexdir/font/writecff.c
    trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c
    trunk/Build/source/texk/web2c/luatexdir/font/writefont.c
    trunk/Build/source/texk/web2c/luatexdir/font/writet1.c
    trunk/Build/source/texk/web2c/luatexdir/font/writet3.c
    trunk/Build/source/texk/web2c/luatexdir/font/writettf.c
    trunk/Build/source/texk/web2c/luatexdir/font/writetype0.c
    trunk/Build/source/texk/web2c/luatexdir/font/writetype2.c
    trunk/Build/source/texk/web2c/luatexdir/image/pdftoepdf.c
    trunk/Build/source/texk/web2c/luatexdir/image/writeimg.c
    trunk/Build/source/texk/web2c/luatexdir/image/writejbig2.c
    trunk/Build/source/texk/web2c/luatexdir/image/writejp2.c
    trunk/Build/source/texk/web2c/luatexdir/image/writejpg.c
    trunk/Build/source/texk/web2c/luatexdir/image/writepng.c
    trunk/Build/source/texk/web2c/luatexdir/lang/hnjalloc.c
    trunk/Build/source/texk/web2c/luatexdir/lang/hyphen.c
    trunk/Build/source/texk/web2c/luatexdir/lang/texlang.c
    trunk/Build/source/texk/web2c/luatexdir/lua/helpers.c
    trunk/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
    trunk/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luainit.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luanode.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.c
    trunk/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
    trunk/Build/source/texk/web2c/luatexdir/lua/texluac.c
    trunk/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdffont.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfimage.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfobj.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfrule.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfxform.c
    trunk/Build/source/texk/web2c/luatexdir/tex/align.c
    trunk/Build/source/texk/web2c/luatexdir/tex/arithmetic.c
    trunk/Build/source/texk/web2c/luatexdir/tex/backend.c
    trunk/Build/source/texk/web2c/luatexdir/tex/backend.h
    trunk/Build/source/texk/web2c/luatexdir/tex/buildpage.c
    trunk/Build/source/texk/web2c/luatexdir/tex/commands.c
    trunk/Build/source/texk/web2c/luatexdir/tex/conditional.c
    trunk/Build/source/texk/web2c/luatexdir/tex/directions.c
    trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
    trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.c
    trunk/Build/source/texk/web2c/luatexdir/tex/errors.c
    trunk/Build/source/texk/web2c/luatexdir/tex/expand.c
    trunk/Build/source/texk/web2c/luatexdir/tex/extensions.c
    trunk/Build/source/texk/web2c/luatexdir/tex/filename.c
    trunk/Build/source/texk/web2c/luatexdir/tex/inputstack.c
    trunk/Build/source/texk/web2c/luatexdir/tex/linebreak.c
    trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.c
    trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
    trunk/Build/source/texk/web2c/luatexdir/tex/mathcodes.c
    trunk/Build/source/texk/web2c/luatexdir/tex/memoryword.c
    trunk/Build/source/texk/web2c/luatexdir/tex/mlist.c
    trunk/Build/source/texk/web2c/luatexdir/tex/nesting.c
    trunk/Build/source/texk/web2c/luatexdir/tex/packaging.c
    trunk/Build/source/texk/web2c/luatexdir/tex/postlinebreak.c
    trunk/Build/source/texk/web2c/luatexdir/tex/primitive.c
    trunk/Build/source/texk/web2c/luatexdir/tex/printing.c
    trunk/Build/source/texk/web2c/luatexdir/tex/scanning.c
    trunk/Build/source/texk/web2c/luatexdir/tex/stringpool.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texdeffont.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texmath.c
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.c
    trunk/Build/source/texk/web2c/luatexdir/tex/textcodes.c
    trunk/Build/source/texk/web2c/luatexdir/tex/textoken.c
    trunk/Build/source/texk/web2c/luatexdir/utils/avlstuff.c
    trunk/Build/source/texk/web2c/luatexdir/utils/managed-sa.c
    trunk/Build/source/texk/web2c/luatexdir/utils/unistring.c
    trunk/Build/source/texk/web2c/luatexdir/utils/utils.c

Removed Paths:
-------------
    trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
    trunk/Build/source/texk/web2c/luatexdir/font/dofont.w
    trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
    trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w
    trunk/Build/source/texk/web2c/luatexdir/font/pkin.w
    trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w
    trunk/Build/source/texk/web2c/luatexdir/font/subfont.w
    trunk/Build/source/texk/web2c/luatexdir/font/texfont.w
    trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w
    trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w
    trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
    trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w
    trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w
    trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w
    trunk/Build/source/texk/web2c/luatexdir/font/writecff.w
    trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w
    trunk/Build/source/texk/web2c/luatexdir/font/writefont.w
    trunk/Build/source/texk/web2c/luatexdir/font/writet1.w
    trunk/Build/source/texk/web2c/luatexdir/font/writet3.w
    trunk/Build/source/texk/web2c/luatexdir/font/writettf.w
    trunk/Build/source/texk/web2c/luatexdir/font/writetype0.w
    trunk/Build/source/texk/web2c/luatexdir/font/writetype2.w
    trunk/Build/source/texk/web2c/luatexdir/image/pdftoepdf.w
    trunk/Build/source/texk/web2c/luatexdir/image/writeimg.w
    trunk/Build/source/texk/web2c/luatexdir/image/writejbig2.w
    trunk/Build/source/texk/web2c/luatexdir/image/writejp2.w
    trunk/Build/source/texk/web2c/luatexdir/image/writejpg.w
    trunk/Build/source/texk/web2c/luatexdir/image/writepng.w
    trunk/Build/source/texk/web2c/luatexdir/lang/hnjalloc.w
    trunk/Build/source/texk/web2c/luatexdir/lang/hyphen.w
    trunk/Build/source/texk/web2c/luatexdir/lang/texlang.w
    trunk/Build/source/texk/web2c/luatexdir/lua/helpers.w
    trunk/Build/source/texk/web2c/luatexdir/lua/llfslibext.c
    trunk/Build/source/texk/web2c/luatexdir/lua/luainit.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luanode.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luastuff.w
    trunk/Build/source/texk/web2c/luatexdir/lua/luatoken.w
    trunk/Build/source/texk/web2c/luatexdir/lua/mplibstuff.w
    trunk/Build/source/texk/web2c/luatexdir/lua/texluac.w
    trunk/Build/source/texk/web2c/luatexdir/lua/texluajitc.w
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua
    trunk/Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdffont.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflink.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdftables.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w
    trunk/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w
    trunk/Build/source/texk/web2c/luatexdir/tex/align.w
    trunk/Build/source/texk/web2c/luatexdir/tex/arithmetic.w
    trunk/Build/source/texk/web2c/luatexdir/tex/buildpage.w
    trunk/Build/source/texk/web2c/luatexdir/tex/commands.w
    trunk/Build/source/texk/web2c/luatexdir/tex/conditional.w
    trunk/Build/source/texk/web2c/luatexdir/tex/directions.w
    trunk/Build/source/texk/web2c/luatexdir/tex/dumpdata.w
    trunk/Build/source/texk/web2c/luatexdir/tex/equivalents.w
    trunk/Build/source/texk/web2c/luatexdir/tex/errors.w
    trunk/Build/source/texk/web2c/luatexdir/tex/expand.w
    trunk/Build/source/texk/web2c/luatexdir/tex/extensions.w
    trunk/Build/source/texk/web2c/luatexdir/tex/filename.w
    trunk/Build/source/texk/web2c/luatexdir/tex/inputstack.w
    trunk/Build/source/texk/web2c/luatexdir/tex/linebreak.w
    trunk/Build/source/texk/web2c/luatexdir/tex/mainbody.w
    trunk/Build/source/texk/web2c/luatexdir/tex/maincontrol.w
    trunk/Build/source/texk/web2c/luatexdir/tex/mathcodes.w
    trunk/Build/source/texk/web2c/luatexdir/tex/memoryword.w
    trunk/Build/source/texk/web2c/luatexdir/tex/mlist.w
    trunk/Build/source/texk/web2c/luatexdir/tex/nesting.w
    trunk/Build/source/texk/web2c/luatexdir/tex/packaging.w
    trunk/Build/source/texk/web2c/luatexdir/tex/postlinebreak.w
    trunk/Build/source/texk/web2c/luatexdir/tex/primitive.w
    trunk/Build/source/texk/web2c/luatexdir/tex/printing.w
    trunk/Build/source/texk/web2c/luatexdir/tex/scanning.w
    trunk/Build/source/texk/web2c/luatexdir/tex/stringpool.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texdeffont.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texfileio.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texmath.w
    trunk/Build/source/texk/web2c/luatexdir/tex/texnodes.w
    trunk/Build/source/texk/web2c/luatexdir/tex/textcodes.w
    trunk/Build/source/texk/web2c/luatexdir/tex/textoken.w
    trunk/Build/source/texk/web2c/luatexdir/utils/avlstuff.w
    trunk/Build/source/texk/web2c/luatexdir/utils/managed-sa.w
    trunk/Build/source/texk/web2c/luatexdir/utils/unistring.w
    trunk/Build/source/texk/web2c/luatexdir/utils/utils.w

Added: trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/am/luapplib.am	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,86 @@
+## texk/web2c/luatexdir/am/luapplib.am: Makefile fragment for libluapplib.
+##
+## Copyright (C) 2018 Luigi Scarso <tex-live at tug.org>
+## You may freely use, modify and/or distribute this file.
+
+## luapplib
+##
+EXTRA_LIBRARIES += libluapplib.a liblua53pplib.a libluajitpplib.a
+
+libluapplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+liblua53pplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+libluajitpplib_a_DEPENDENCIES = $(ZLIB_DEPEND)
+
+$(libluapplib_a_OBJECTS): $(LUA_DEPEND)
+$(liblua53pplib_a_OBJECTS): $(LUA_DEPEND)
+$(libluajitpplib_a_OBJECTS): $(LUAJIT_DEPEND)
+
+## replace -I../../libs/zlib/include $(ZLIB_INCLUDES)
+
+libluapplib_a_CPPFLAGS = \
+	-I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUA_INCLUDES)
+
+liblua53pplib_a_CPPFLAGS = \
+	-I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUA_LUA53_INCLUDES)
+
+libluajitpplib_a_CPPFLAGS = \
+	-I$(top_srcdir)/luatexdir/luapplib -I$(top_srcdir)/luatexdir/luapplib/util $(ZLIB_INCLUDES) $(LUAJIT_INCLUDES)
+
+libluapplib_a_CFLAGS = # $(WARNING_CFLAGS)
+libluajitpplib_a_CFLAGS = # $(WARNING_CFLAGS)
+
+nodist_libluapplib_a_SOURCES = $(libluapplib_sources)
+nodist_liblua53pplib_a_SOURCES = $(libluapplib_sources)
+nodist_libluajitpplib_a_SOURCES = $(libluapplib_sources)
+
+libluapplib_sources = \
+	luatexdir/luapplib/ppapi.h \
+	luatexdir/luapplib/pparray.c \
+	luatexdir/luapplib/pparray.h \
+	luatexdir/luapplib/ppconf.h \
+	luatexdir/luapplib/ppcrypt.c \
+	luatexdir/luapplib/ppcrypt.h \
+	luatexdir/luapplib/ppdict.c \
+	luatexdir/luapplib/ppdict.h \
+	luatexdir/luapplib/ppfilter.h \
+	luatexdir/luapplib/ppheap.c \
+	luatexdir/luapplib/ppheap.h \
+	luatexdir/luapplib/pplib.h \
+	luatexdir/luapplib/ppload.c \
+	luatexdir/luapplib/ppload.h \
+	luatexdir/luapplib/ppstream.c \
+	luatexdir/luapplib/ppstream.h \
+	luatexdir/luapplib/ppxref.c \
+	luatexdir/luapplib/ppxref.h \
+	luatexdir/luapplib/util/utilbasexx.c \
+	luatexdir/luapplib/util/utilbasexx.h \
+	luatexdir/luapplib/util/utilcrypt.c \
+	luatexdir/luapplib/util/utilcrypt.h \
+	luatexdir/luapplib/util/utilcryptdef.h \
+	luatexdir/luapplib/util/utildecl.h \
+	luatexdir/luapplib/util/utilflate.c \
+	luatexdir/luapplib/util/utilflate.h \
+	luatexdir/luapplib/util/utilfpred.c \
+	luatexdir/luapplib/util/utilfpred.h \
+	luatexdir/luapplib/util/utiliof.c \
+	luatexdir/luapplib/util/utiliof.h \
+	luatexdir/luapplib/util/utillog.c \
+	luatexdir/luapplib/util/utillog.h \
+	luatexdir/luapplib/util/utillzw.c \
+	luatexdir/luapplib/util/utillzw.h \
+	luatexdir/luapplib/util/utilmd5.c \
+	luatexdir/luapplib/util/utilmd5.h \
+	luatexdir/luapplib/util/utilmem.c \
+	luatexdir/luapplib/util/utilmem.h \
+	luatexdir/luapplib/util/utilnumber.c \
+	luatexdir/luapplib/util/utilnumber.h \
+	luatexdir/luapplib/util/utilplat.h \
+	luatexdir/luapplib/util/utilsha.c \
+	luatexdir/luapplib/util/utilsha.h \
+	luatexdir/luapplib/zlib/zconf.h \
+	luatexdir/luapplib/zlib/zlib.h 
+
+
+
+liblua53pplib_sources = $(libluapplib_sources)
+libluajitpplib_sources = $(libluapplib_sources)

Added: trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1558 @@
+/*
+
+dvigen.w
+
+Copyright 2009-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#undef write_dvi
+
+/*tex This is the current mode: */
+
+#define mode cur_list.mode_field
+
+/*tex
+
+The most important output produced by a run of \TeX\ is the ``device
+independent'' (\.{DVI}) file that specifies where characters and rules are to
+appear on printed pages. The form of these files was designed by David R. Fuchs
+in 1979. Almost any reasonable typesetting device can be driven by a program that
+takes \.{DVI} files as input, and dozens of such \.{DVI}-to-whatever programs
+have been written. Thus, it is possible to print the output of \TeX\ on many
+different kinds of equipment, using \TeX\ as a device-independent ``front end.''
+
+A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a series of
+commands in a machine-like language. The first byte of each command is the
+operation code, and this code is followed by zero or more bytes that provide
+parameters to the command. The parameters themselves may consist of several
+consecutive bytes; for example, the `|set_rule|' command has two parameters, each
+of which is four bytes long. Parameters are usually regarded as nonnegative
+integers; but four-byte-long parameters, and shorter parameters that denote
+distances, can be either positive or negative. Such parameters are given in two's
+complement notation. For example, a two-byte-long distance parameter has a value
+between $-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy more
+than one byte position appear in BigEndian order.
+
+A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one or more
+``pages,'' followed by a ``postamble.'' The preamble is simply a |pre| command,
+with its parameters that define the dimensions used in the file; this must come
+first. Each ``page'' consists of a |bop| command, followed by any number of other
+commands that tell where characters are to be placed on a physical page, followed
+by an |eop| command. The pages appear in the order that \TeX\ generated them. If
+we ignore |nop| commands and \\{fnt\_def} commands (which are allowed between any
+two commands in the file), each |eop| command is immediately followed by a |bop|
+command, or by a |post| command; in the latter case, there are no more pages in
+the file, and the remaining bytes form the postamble. Further details about the
+postamble will be explained later.
+
+Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
+quantities that give the location number of some other byte in the file; the
+first byte is number~0, then comes number~1, and so on. For example, one of the
+parameters of a |bop| command points to the previous |bop|; this makes it
+feasible to read the pages in backwards order, in case the results are being
+directed to a device that stacks its output face up. Suppose the preamble of a
+\.{DVI} file occupies bytes 0 to 99. Now if the first page occupies bytes 100 to
+999, say, and if the second page occupies bytes 1000 to 1999, then the |bop| that
+starts in byte 1000 points to 100 and the |bop| that starts in byte 2000 points
+to 1000. (The very first |bop|, i.e., the one starting in byte 100, has a pointer
+of~$-1$.)
+
+The \.{DVI} format is intended to be both compact and easily interpreted by a
+machine. Compactness is achieved by making most of the information implicit
+instead of explicit. When a \.{DVI}-reading program reads the commands for a
+page, it keeps track of several quantities: (a)~The current font |f| is an
+integer; this value is changed only by \\{fnt} and \\{fnt\_num} commands. (b)~The
+current position on the page is given by two numbers called the horizontal and
+vertical coordinates, |h| and |v|. Both coordinates are zero at the upper left
+corner of the page; moving to the right corresponds to increasing the horizontal
+coordinate, and moving down corresponds to increasing the vertical coordinate.
+Thus, the coordinates are essentially Cartesian, except that vertical directions
+are flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The current
+spacing amounts are given by four numbers |w|, |x|, |y|, and |z|, where |w|
+and~|x| are used for horizontal spacing and where |y| and~|z| are used for
+vertical spacing. (d)~There is a stack containing |(h,v,w,x,y,z)| values; the
+\.{DVI} commands |push| and |pop| are used to change the current level of
+operation. Note that the current font~|f| is not pushed and popped; the stack
+contains only information about positioning.
+
+The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up to
+32 bits, including the sign. Since they represent physical distances, there is a
+small unit of measurement such that increasing |h| by~1 means moving a certain
+tiny distance to the right. The actual unit of measurement is variable, as
+explained below; \TeX\ sets things up so that its \.{DVI} output is in sp units,
+i.e., scaled points, in agreement with all the |scaled| dimensions in \TeX's data
+structures.
+
+Here is a list of all the commands that may appear in a \.{DVI} file. Each
+command is specified by its symbolic name (e.g., |bop|), its opcode byte (e.g.,
+139), and its parameters (if any). The parameters are followed by a bracketed
+number telling how many bytes they occupy; for example, `|p[4]|' means that
+parameter |p| is four bytes long.
+
+\startitemize
+
+\startitem
+    |set_char_0| 0. Typeset character number~0 from font~|f| such that the
+    reference point of the character is at |(h,v)|. Then increase |h| by the
+    width of that character. Note that a character may have zero or negative
+    width, so one cannot be sure that |h| will advance after this command; but
+    |h| usually does increase.
+\stopitem
+
+\startitem
+    \\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
+    Do the operations of |set_char_0|; but use the character whose number
+    matches the opcode, instead of character~0.
+\stopitem
+
+\startitem
+    |set1| 128 |c[1]|. Same as |set_char_0|, except that character number~|c| is
+    typeset. \TeX82 uses this command for characters in the range |128<=c<256|.
+\stopitem
+
+\startitem
+    |set2| 129 |c[2]|. Same as |set1|, except that |c|~is two bytes long, so it
+    is in the range |0<=c<65536|. \TeX82 never uses this command, but it should
+    come in handy for extensions of \TeX\ that deal with oriental languages.
+\stopitem
+
+\startitem
+    |set3| 130 |c[3]|. Same as |set1|, except that |c|~is three bytes long, so it
+    can be as large as $2^{24}-1$. Not even the Chinese language has this many
+    characters, but this command might prove useful in some yet unforeseen
+    extension.
+\stopitem
+
+\startitem
+    |set4| 131 |c[4]|. Same as |set1|, except that |c|~is four bytes long.
+    Imagine that.
+\stopitem
+
+\startitem
+    |set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle of height~|a|
+    and width~|b|, with its bottom left corner at |(h,v)|. Then set |h:=h+b|. If
+    either |a<=0| or |b<=0|, nothing should be typeset. Note that if |b<0|, the
+    value of |h| will decrease even though nothing else happens. See below for
+    details about how to typeset rules so that consistency with \MF\ is
+    guaranteed.
+\stopitem
+
+\startitem
+    |put1| 133 |c[1]|. Typeset character number~|c| from font~|f| such that the
+    reference point of the character is at |(h,v)|. (The `put' commands are
+    exactly like the `set' commands, except that they simply put out a character
+    or a rule without moving the reference point afterwards.)
+\stopitem
+
+\startitem
+    |put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
+\stopitem
+
+\startitem
+    |put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
+\stopitem
+
+\startitem
+    |put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
+\stopitem
+
+\startitem
+    |put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that |h| is not
+    changed.
+\stopitem
+
+\startitem
+    |nop| 138. No operation, do nothing. Any number of |nop|'s may occur between
+    \.{DVI} commands, but a |nop| cannot be inserted between a command and its
+    parameters or between two parameters.
+\stopitem
+
+\startitem
+    |bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning of a page:
+    Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set the current
+    font |f| to an undefined value. The ten $c_i$ parameters hold the values of
+    \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time \.{\\shipout} was
+    invoked for this page; they can be used to identify pages, if a user wants to
+    print only part of a \.{DVI} file. The parameter |p| points to the previous
+    |bop| in the file; the first |bop| has $p=-1$.
+\stopitem
+
+\startitem
+    |eop| 140. End of page: Print what you have read since the previous |bop|. At
+    this point the stack should be empty. (The \.{DVI}-reading programs that
+    drive most output devices will have kept a buffer of the material that
+    appears on the page that has just ended. This material is largely, but not
+    entirely, in order by |v| coordinate and (for fixed |v|) by |h|~coordinate;
+    so it usually needs to be sorted into some order that is appropriate for the
+    device in question.)
+\stopitem
+
+\startitem
+    |push| 141. Push the current values of |(h,v,w,x,y,z)| onto the top of the
+    stack; do not change any of these values. Note that |f| is not pushed.
+\stopitem
+
+\startitem
+    |pop| 142. Pop the top six values off of the stack and assign them
+    respectively to |(h,v,w,x,y,z)|. The number of pops should never exceed the
+    number of pushes, since it would be highly embarrassing if the stack were
+    empty at the time of a |pop| command.
+
+\startitem
+    |right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units. The parameter
+    is a signed number in two's complement notation, |-128<=b<128|; if |b<0|, the
+    reference point moves left.
+\stopitem
+
+\startitem
+    |right2| 144 |b[2]|. Same as |right1|, except that |b| is a two-byte quantity
+    in the range |-32768<=b<32768|.
+\stopitem
+
+\startitem
+    |right3| 145 |b[3]|. Same as |right1|, except that |b| is a three-byte
+    quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |right4| 146 |b[4]|. Same as |right1|, except that |b| is a four-byte
+    quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck, this
+    parameterless command will usually suffice, because the same kind of motion
+    will occur several times in succession; the following commands explain how
+    |w| gets particular values.
+\stopitem
+
+\startitem
+    |w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a signed
+    quantity in two's complement notation, |-128<=b<128|. This command changes
+    the current |w|~spacing and moves right by |b|.
+\stopitem
+
+\startitem
+    |w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long, |-32768<=b<32768|.
+\stopitem
+
+\startitem
+    |w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
+    |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
+    |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|' commands are
+    like the `|w|' commands except that they involve |x| instead of |w|.
+\stopitem
+
+\startitem
+    |x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a signed
+    quantity in two's complement notation, |-128<=b<128|. This command changes
+    the current |x|~spacing and moves right by |b|.
+\stopitem
+
+\startitem
+    |x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long, |-32768<=b<32768|.
+\stopitem
+
+\startitem
+    |x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
+    |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
+    |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units. The parameter is
+    a signed number in two's complement notation, |-128<=a<128|; if |a<0|, the
+    reference point moves up.
+\stopitem
+
+\startitem
+    |down2| 158 |a[2]|. Same as |down1|, except that |a| is a two-byte quantity
+    in the range |-32768<=a<32768|.
+\stopitem
+
+\startitem
+    |down3| 159 |a[3]|. Same as |down1|, except that |a| is a three-byte quantity
+    in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |down4| 160 |a[4]|. Same as |down1|, except that |a| is a four-byte quantity
+    in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck, this
+    parameterless command will usually suffice, because the same kind of motion
+    will occur several times in succession; the following commands explain how
+    |y| gets particular values.
+\stopitem
+
+\startitem
+    |y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a signed
+    quantity in two's complement notation, |-128<=a<128|. This command changes
+    the current |y|~spacing and moves down by |a|.
+\stopitem
+
+\startitem
+    |y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long, |-32768<=a<32768|.
+\stopitem
+
+\startitem
+    |y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
+    |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
+    |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands are
+    like the `|y|' commands except that they involve |z| instead of |y|.
+\stopitem
+
+\startitem
+    |z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a signed
+    quantity in two's complement notation, |-128<=a<128|. This command changes
+    the current |z|~spacing and moves down by |a|.
+\stopitem
+
+\startitem
+    |z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long, |-32768<=a<32768|.
+\stopitem
+
+\startitem
+    |z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
+    |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
+\stopitem
+
+\startitem
+    |z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
+    |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been defined by a
+    \\{fnt\_def} instruction, as explained below.
+\stopitem
+
+\startitem
+    \\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set |f:=1|,
+    \dots, \hbox{|f:=63|}, respectively.
+\stopitem
+
+\startitem
+    |fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font numbers in
+    the range |64<=k<256|.
+\stopitem
+
+\startitem
+    |fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two bytes long, so it
+    is in the range |0<=k<65536|. \TeX82 never generates this command, but large
+    font numbers may prove useful for specifications of color or texture, or they
+    may be used for special fonts that have fixed numbers in some external coding
+    scheme.
+\stopitem
+
+\startitem
+    |fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three bytes long, so it
+    can be as large as $2^{24}-1$.
+\stopitem
+
+\startitem
+    |fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four bytes long; this
+    is for the really big font numbers (and for the negative ones).
+\stopitem
+
+\startitem
+    |xxx1| 239 |k[1]| |x[k]|. This command is undefined in general; it functions
+    as a $(k+2)$-byte |nop| unless special \.{DVI}-reading programs are being
+    used. \TeX82 generates |xxx1| when a short enough \.{\\special} appears,
+    setting |k| to the number of bytes being sent. It is recommended that |x| be
+    a string having the form of a keyword followed by possible parameters
+    relevant to that keyword.
+\stopitem
+
+\startitem
+    |xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
+\stopitem
+
+\startitem
+    |xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
+\stopitem
+
+\startitem
+    |xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously large.
+    \TeX82 uses |xxx4| when sending a string of length 256 or more.
+\stopitem
+
+\startitem
+    |fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+    font |k|, where |0<=k<256|; font definitions will be explained shortly.
+\stopitem
+
+\startitem
+    |fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+    font |k|, where |0<=k<65536|.
+\stopitem
+
+\startitem
+    |fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+    font |k|, where |0<=k<@t$2^{24}$@>|.
+\stopitem
+
+\startitem
+    |fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. Define
+    font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
+\stopitem
+
+\startitem
+    |pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|. Beginning of the
+    preamble; this must come at the very beginning of the file. Parameters |i|,
+    |num|, |den|, |mag|, |k|, and |x| are explained below.
+\stopitem
+
+\startitem
+    |post| 248. Beginning of the postamble, see below.
+\stopitem
+
+\startitem
+    |post_post| 249. Ending of the postamble, see below.
+\stopitem
+
+\startitem
+    Commands 250--255 are undefined at the present time.
+\stopitem
+
+*/
+
+#define set_char_0  0           /* typeset character 0 and move right */
+#define set1  128               /* typeset a character and move right */
+#define set_rule  132           /* typeset a rule and move right */
+#define put1    133             /* typeset a character without moving */
+#define put_rule  137           /* typeset a rule */
+#define nop  138                /* no operation */
+#define bop  139                /* beginning of page */
+#define eop  140                /* ending of page */
+#define push  141               /* save the current positions */
+#define pop  142                /* restore previous positions */
+#define right1    143           /* move right */
+#define right4    146           /* move right, 4 bytes */
+#define w0  147                 /* move right by |w| */
+#define w1  148                 /* move right and set |w| */
+#define x0  152                 /* move right by |x| */
+#define x1  153                 /* move right and set |x| */
+#define down1  157              /* move down */
+#define down4  160              /* move down, 4 bytes */
+#define y0  161                 /* move down by |y| */
+#define y1  162                 /* move down and set |y| */
+#define z0  166                 /* move down by |z| */
+#define z1  167                 /* move down and set |z| */
+#define fnt_num_0  171          /* set current font to 0 */
+#define fnt1  235               /* set current font */
+#define xxx1  239               /* extension to \.{DVI} primitives */
+#define xxx4  242               /* potentially long extension to \.{DVI} primitives */
+#define fnt_def1  243           /* define the meaning of a font number */
+#define pre  247                /* preamble */
+#define post  248               /* postamble beginning */
+#define post_post  249          /* postamble ending */
+
+/*tex
+
+The preamble contains basic information about the file as a whole. As stated
+above, there are six parameters: $$\hbox{|i[1]| |num[4]| |den[4]|
+|mag[4]| |k[1]| |x[k]|.}$$ The |i| byte identifies \.{DVI} format;
+currently this byte is always set to~2. (The value |i=3| is currently used for an
+extended format that allows a mixture of right-to-left and left-to-right
+typesetting. Some day we will set |i=4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The next two parameters, |num| and |den|, are positive integers that define the
+units of measurement; they are the numerator and denominator of a fraction by
+which all dimensions in the \.{DVI} file could be multiplied in order to get
+lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} = 254{cm}$, and since
+\TeX\ works with scaled points where there are $2^{16}$ sp in a point, \TeX\ sets
+$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
+
+The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the desired
+magnification. The actual fraction by which dimensions are multiplied is
+therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\ source document does
+not call for any `\.{true}' dimensions, and if you change it only by specifying a
+different \.{\\mag} setting, the \.{DVI} file that \TeX\ creates will be
+completely unchanged except for the value of |mag| in the preamble and postamble.
+(Fancy \.{DVI}-reading programs allow users to override the |mag|~setting when a
+\.{DVI} file is being printed.)
+
+Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
+interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
+
+The next macro identifies the kind of \.{DVI} files described here.
+
+*/
+
+#define id_byte 2
+
+/*tex
+
+Font definitions for a given font number |k| contain further parameters
+$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$ The four-byte value |c|
+is the check sum that \TeX\ found in the \.{TFM} file for this font; |c| should
+match the check sum of the font found by programs that read this \.{DVI} file.
+
+Parameter |s| contains a fixed-point scale factor that is applied to the
+character widths in font |k|; font dimensions in \.{TFM} files and other font
+files are relative to this quantity, which is called the ``at size'' elsewhere in
+this documentation. The value of |s| is always positive and less than $2^{27}$.
+It is given in the same units as the other \.{DVI} dimensions, i.e., in sp when
+\TeX82 has made the file. Parameter |d| is similar to |s|; it is the ``design
+size,'' and (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
+at $|mag|\cdot s/1000d$ times its normal size.
+
+The remaining part of a font definition gives the external name of the font,
+which is an ASCII string of length |a+l|. The number |a| is the length of the
+``area'' or directory, and |l| is the length of the font name itself; the
+standard local system font area is supposed to be used when |a=0|. The |n| field
+contains the area in its first |a| bytes.
+
+Font definitions must appear before the first use of a particular font number.
+Once font |k| is defined, it must not be defined again; however, we
+shall see below that font definitions appear in the postamble as well as
+in the pages, so in this sense each font number is defined exactly twice,
+if at all. Like |nop| commands, font definitions can
+appear before the first |bop|, or between an |eop| and a |bop|.
+
+Sometimes it is desirable to make horizontal or vertical rules line up precisely
+with certain features in characters of a font. It is possible to guarantee the
+correct matching between \.{DVI} output and the characters generated by \MF\ by
+adhering to the following principles: (1)~The \MF\ characters should be
+positioned so that a bottom edge or left edge that is supposed to line up with
+the bottom or left edge of a rule appears at the reference point, i.e., in row~0
+and column~0 of the \MF\ raster. This ensures that the position of the rule will
+not be rounded differently when the pixel size is not a perfect multiple of the
+units of measurement in the \.{DVI} file. (2)~A typeset rule of height $a>0$ and
+width $b>0$ should be equivalent to a \MF-generated character having black pixels
+in precisely those raster positions whose \MF\ coordinates satisfy
+|0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number of
+pixels per \.{DVI} unit.
+
+The last page in a \.{DVI} file is followed by `|post|'; this command introduces
+the postamble, which summarizes important facts that \TeX\ has accumulated about
+the file, making it possible to print subsets of the data with reasonable
+efficiency. The postamble has the form
+
+$$\vbox{\halign{\hbox{#\hfil}\cr
+  |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
+  $\langle\,$font definitions$\,\rangle$\cr
+  |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
+
+Here |p| is a pointer to the final |bop| in the file. The next three parameters,
+|num|, |den|, and |mag|, are duplicates of the quantities that appeared in the
+preamble.
+
+Parameters |l| and |u| give respectively the height-plus-depth of the tallest
+page and the width of the widest page, in the same units as other dimensions of
+the file. These numbers might be used by a \.{DVI}-reading program to position
+individual ``pages'' on large sheets of film or paper; however, the standard
+convention for output on normal size paper is to position each page so that the
+upper left-hand corner is exactly one inch from the left and the top. Experience
+has shown that it is unwise to design \.{DVI}-to-printer software that attempts
+cleverly to center the output; a fixed position of the upper left corner is
+easiest for users to understand and to work with. Therefore |l| and~|u| are often
+ignored. Parameter |s| is the maximum stack depth (i.e., the largest excess of
+
+|push| commands over |pop| commands) needed to process this file. Then comes |t|,
+the total number of pages (|bop| commands) present.
+
+The postamble continues with font definitions, which are any number of
+\\{fnt\_def} commands as described above, possibly interspersed with |nop|
+commands. Each font number that is used in the \.{DVI} file must be defined
+exactly twice: Once before it is first selected by a \\{fnt} command, and once in
+the postamble.
+
+The last part of the postamble, following the |post_post| byte that signifies the
+end of the font definitions, contains |q|, a pointer to the |post| command that
+started the postamble. An identification byte, |i|, comes next; this currently
+equals~2, as in the preamble.
+
+The |i| byte is followed by four or more bytes that are all equal to the decimal
+number 223 (i.e., '337 in octal). \TeX\ puts out four to seven of these trailing
+bytes, until the total length of the file is a multiple of four bytes, since this
+works out best on machines that pack four bytes per word; but any number of 223's
+is allowed, as long as there are at least four of them. In effect, 223 is a sort
+of signature that is added at the very end.
+
+This curious way to finish off a \.{DVI} file makes it feasible for
+\.{DVI}-reading programs to find the postamble first, on most computers, even
+though \TeX\ wants to write the postamble last. Most operating systems permit
+random access to individual words or bytes of a file, so the \.{DVI} reader can
+start at the end and skip backwards over the 223's until finding the
+identification byte. Then it can back up four bytes, read |q|, and move to byte
+|q| of the file. This byte should, of course, contain the value 248 (|post|); now
+the postamble can be read, so the \.{DVI} reader can discover all the information
+needed for typesetting the pages. Note that it is also possible to skip through
+the \.{DVI} file at reasonably high speed to locate a particular page, if that
+proves desirable. This saves a lot of time, since \.{DVI} files used in
+production jobs tend to be large.
+
+Unfortunately, however, standard \PASCAL\ does not include the ability to access
+a random position in a file, or even to determine the length of a file. Almost
+all systems nowadays provide the necessary capabilities, so \.{DVI} format has
+been designed to work most efficiently with modern operating systems. But if
+\.{DVI} files have to be processed under the restrictions of standard \PASCAL,
+one can simply read them from front to back, since the necessary header
+information is present in the preamble and in the font definitions. (The |l| and
+|u| and |s| and |t| parameters, which appear only in the postamble, are
+``frills'' that are handy but not absolutely necessary.)
+
+After considering \TeX's eyes and stomach, we come now to the bowels.
+
+The |ship_out| procedure is given a pointer to a box; its mission is to describe
+that box in \.{DVI} form, outputting a ``page'' to |dvi_file|. The \.{DVI}
+coordinates $(h,v)=(0,0)$ should correspond to the upper left corner of the box
+being shipped.
+
+Since boxes can be inside of boxes inside of boxes, the main work of |ship_out|
+is done by two mutually recursive routines, |hlist_out| and |vlist_out|, which
+traverse the hlists and vlists inside of horizontal and vertical boxes.
+
+As individual pages are being processed, we need to accumulate information about
+the entire set of pages, since such statistics must be reported in the postamble.
+The global variables |total_pages|, |max_v|, |max_h|, |max_push|, and |last_bop|
+are used to record this information.
+
+The variable |doing_leaders| is |true| while leaders are being output. The
+variable |dead_cycles| contains the number of times an output routine has been
+initiated since the last |ship_out|.
+
+A few additional global variables are also defined here for use in |vlist_out|
+and |hlist_out|. They could have been local variables, but that would waste stack
+space when boxes are deeply nested, since the values of these variables are not
+needed during recursive calls.
+
+*/
+
+/* Some global variables are defined in |backend| module. */
+
+static int max_push = 0;  /* deepest nesting of |push| commands encountered so far */
+static int last_bop = -1; /* location of previous |bop| in the \.{DVI} output */
+static int oval, ocmd;    /* used by |out_cmd| for generating |set|, |fnt| and |fnt_def| commands */
+pointer g;                /* current glue specification */
+
+/*tex
+
+The \.{DVI} bytes are output to a buffer instead of being written directly to the
+output file. This makes it possible to reduce the overhead of subroutine calls,
+thereby measurably speeding up the computation, since output of \.{DVI} bytes is
+part of \TeX's inner loop. And it has another advantage as well, since we can
+change instructions in the buffer in order to make the output more compact. For
+example, a `|down2|' command can be changed to a `|y2|', thereby making a
+subsequent `|y0|' command possible, saving two bytes.
+
+The output buffer is divided into two parts of equal size; the bytes found in
+|dvi_buf[0..half_buf-1]| constitute the first half, and those in
+|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global variable
+|dvi_ptr| points to the position that will receive the next output byte. When
+|dvi_ptr| reaches |dvi_limit|, which is always equal to one of the two values
+|half_buf| or |dvi_buf_size|, the half buffer that is about to be invaded next is
+sent to the output and |dvi_limit| is changed to its other value. Thus, there is
+always at least a half buffer's worth of information present, except at the very
+beginning of the job.
+
+Bytes of the \.{DVI} file are numbered sequentially starting with 0; the next
+byte to be generated will be number |dvi_offset+dvi_ptr|. A byte is present in
+the buffer only if its number is |>=dvi_gone|.
+
+Some systems may find it more efficient to make |dvi_buf| a |packed| array, since
+output of four bytes at once may be facilitated.
+
+Initially the buffer is all in one piece; we will output half of it only after it
+first fills up.
+
+*/
+
+int dvi_buf_size = 800;     /* size of the output buffer; must be a multiple of 8 */
+eight_bits *dvi_buf;        /* buffer for \.{DVI} output */
+static int half_buf = 0;    /* half of |dvi_buf_size| */
+static int dvi_limit = 0;   /* end of the current half buffer */
+static int dvi_ptr = 0;     /* the next available buffer address */
+static int dvi_offset = 0;  /* |dvi_buf_size| times the number of times the output buffer has been fully emptied */
+static int dvi_gone = 0;    /* the number of bytes already output to |dvi_file| */
+
+/*
+To put a byte in the buffer without paying the cost of invoking a procedure
+each time, we use the macro |dvi_out|.
+*/
+
+#define dvi_out(A) do {                 \
+	dvi_buf[dvi_ptr++]=(eight_bits)(A);	\
+    if (dvi_ptr==dvi_limit) dvi_swap(); \
+} while (0)
+
+#define dvi_set(A,B) do {                       \
+    oval=A; ocmd=set1; out_cmd(); dvi.h += (B); \
+} while (0)
+
+#define dvi_put(A)  do {          \
+    oval=A; ocmd=put1; out_cmd(); \
+} while (0)
+
+/*
+The |vinfo| fields in the entries of the down stack or the right stack
+have six possible settings: |y_here| or |z_here| mean that the \.{DVI}
+command refers to |y| or |z|, respectively (or to |w| or |x|, in the
+case of horizontal motion); |yz_OK| means that the \.{DVI} command is
+\\{down} (or \\{right}) but can be changed to either |y| or |z| (or
+to either |w| or |x|); |y_OK| means that it is \\{down} and can be changed
+to |y| but not |z|; |z_OK| is similar; and |d_fixed| means it must stay
+\\{down}.
+
+The four settings |yz_OK|, |y_OK|, |z_OK|, |d_fixed| would not need to
+be distinguished from each other if we were simply solving the
+digit-subscripting problem mentioned above. But in \TeX's case there is
+a complication because of the nested structure of |push| and |pop|
+commands. Suppose we add parentheses to the digit-subscripting problem,
+redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between
+the $\delta$'s are enclosed in properly nested parentheses, and if the
+parenthesis level of the right-hand $\delta_y$ is deeper than or equal to
+that of the left-hand one. Thus, `(' and `)' correspond to `|push|'
+and `|pop|'. Now if we want to assign a subscript to the final 1 in the
+sequence
+$$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$
+we cannot change the previous $1_d$ to $1_y$, since that would invalidate
+the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit
+since the intervening $8_z$'s are enclosed in parentheses.
+*/
+
+typedef enum {
+    y_here = 1,                 /* |vinfo| when the movement entry points to a |y| command */
+    z_here = 2,                 /* |vinfo| when the movement entry points to a |z| command */
+    yz_OK = 3,                  /* |vinfo| corresponding to an unconstrained \\{down} command */
+    y_OK = 4,                   /* |vinfo| corresponding to a \\{down} that can't become a |z| */
+    z_OK = 5,                   /* |vinfo| corresponding to a \\{down} that can't become a |y| */
+    d_fixed = 6,                /* |vinfo| corresponding to a \\{down} that can't change */
+} movement_codes;
+
+/* As we search through the stack, we are in one of three states,
+   |y_seen|, |z_seen|, or |none_seen|, depending on whether we have
+   encountered |y_here| or |z_here| nodes. These states are encoded as
+   multiples of 6, so that they can be added to the |info| fields for quick
+   decision-making. */
+
+#  define none_seen 0           /* no |y_here| or |z_here| nodes have been encountered yet */
+#  define y_seen 6              /* we have seen |y_here| but not |z_here| */
+#  define z_seen 12             /* we have seen |z_here| but not |y_here| */
+
+void movement(scaled w, eight_bits o);
+
+/*
+extern void prune_movements(int l);
+*/
+
+/*
+The actual distances by which we want to move might be computed as the
+sum of several separate movements. For example, there might be several
+glue nodes in succession, or we might want to move right by the width of
+some box plus some amount of glue. More importantly, the baselineskip
+distances are computed in terms of glue together with the depth and
+height of adjacent boxes, and we want the \.{DVI} file to lump these
+three quantities together into a single motion.
+
+Therefore, \TeX\ maintains two pairs of global variables: |dvi.h| and |dvi.v|
+are the |h| and |v| coordinates corresponding to the commands actually
+output to the \.{DVI} file, while |cur.h| and |cur.v| are the coordinates
+corresponding to the current state of the output routines. Coordinate
+changes will accumulate in |cur.h| and |cur.v| without being reflected
+in the output, until such a change becomes necessary or desirable; we
+can call the |movement| procedure whenever we want to make |dvi.h=pos.h|
+or |dvi.v=pos.v|.
+
+The current font reflected in the \.{DVI} output is called |dvi_f|;
+there is no need for a `\\{cur\_f}' variable.
+
+The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|;
+this is essentially the depth of |push| commands in the \.{DVI} output.
+*/
+
+/*tex A \.{DVI} position in page coordinates, in sync with DVI file: */
+
+static scaledpos dvi;
+
+#  define synch_h(p) do {            \
+    if (p.h != dvi.h) {              \
+      movement(p.h - dvi.h, right1); \
+      dvi.h = p.h;                   \
+    }                                \
+  } while (0)
+
+#  define synch_v(p) do {            \
+    if (p.v != dvi.v) {              \
+      movement(dvi.v - p.v, down1);  \
+      dvi.v = p.v;                   \
+    }                                \
+  } while (0)
+
+#  define synch_dvi_with_pos(p) do {synch_h(p); synch_v(p); } while (0)
+
+/*tex
+
+The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
+|write_dvi(a,b)|. For best results, this procedure should be optimized to run as
+fast as possible on each particular system, since it is part of \TeX's inner
+loop. It is safe to assume that |a| and |b+1| will both be multiples of 4 when
+|write_dvi(a,b)| is called; therefore it is possible on many machines to use
+efficient methods to pack four bytes per word and to output an array of words
+with one system call.
+
+*/
+
+static void write_dvi(int a, int b)
+{
+    int k;
+    for (k = a; k <= b; k++)
+        fputc(dvi_buf[k], static_pdf->file);
+}
+
+/*tex This outputs half of the buffer: */
+
+static void dvi_swap(void)
+{
+    if (dvi_limit == dvi_buf_size) {
+        write_dvi(0, half_buf - 1);
+        dvi_limit = half_buf;
+        dvi_offset = dvi_offset + dvi_buf_size;
+        dvi_ptr = 0;
+    } else {
+        write_dvi(half_buf, dvi_buf_size - 1);
+        dvi_limit = dvi_buf_size;
+    }
+    dvi_gone = dvi_gone + half_buf;
+}
+
+/*tex
+
+The |dvi_four| procedure outputs four bytes in two's complement notation, without
+risking arithmetic overflow.
+
+*/
+
+static void dvi_four(int x)
+{
+    if (x >= 0) {
+        dvi_out(x / 0100000000);
+    } else {
+        x = x + 010000000000;
+        x = x + 010000000000;
+        dvi_out((x / 0100000000) + 128);
+    }
+    x = x % 0100000000;
+    dvi_out(x / 0200000);
+    x = x % 0200000;
+    dvi_out(x / 0400);
+    dvi_out(x % 0400);
+}
+
+/*tex
+
+A mild optimization of the output is performed by the |dvi_pop| routine, which
+issues a |pop| unless it is possible to cancel a `|push| |pop|' pair. The
+parameter to |dvi_pop| is the byte address following the old |push| that matches
+the new |pop|.
+
+*/
+
+static void dvi_push(void)
+{
+    dvi_out(push);
+}
+
+static void dvi_pop(int l)
+{
+    if ((l == dvi_offset + dvi_ptr) && (dvi_ptr > 0))
+        decr(dvi_ptr);
+    else
+        dvi_out(pop);
+}
+
+/*tex
+
+Here's a procedure that outputs a font definition. $\Omega$ allows more than 256
+different fonts per job, so the right font definition command must be selected.
+
+*/
+
+static void out_cmd(void)
+{
+    if ((oval < 0x100) && (oval >= 0)) {
+        if ((ocmd != set1) || (oval > 127)) {
+            if ((ocmd == fnt1) && (oval < 64))
+                oval += fnt_num_0;
+            else
+                dvi_out(ocmd);
+        }
+    } else {
+        if ((oval < 0x10000) && (oval >= 0)) {
+            dvi_out(ocmd + 1);
+        } else {
+            if ((oval < 0x1000000) && (oval >= 0)) {
+                dvi_out(ocmd + 2);
+            } else {
+                dvi_out(ocmd + 3);
+                if (oval >= 0) {
+                    dvi_out(oval / 0x1000000);
+                } else {
+                    oval += 0x40000000;
+                    oval += 0x40000000;
+                    dvi_out((oval / 0x1000000) + 128);
+                    oval = oval % 0x1000000;
+                }
+                dvi_out(oval / 0x10000);
+                oval = oval % 0x10000;
+            }
+            dvi_out(oval / 0x10000);
+            oval = oval % 0x10000;
+        }
+        dvi_out(oval / 0x100);
+        oval = oval % 0x100;
+    }
+    dvi_out(oval);
+}
+
+static void dvi_font_def(internal_font_number f)
+{
+    char *fa;
+    oval = f - 1;
+    ocmd = fnt_def1;
+    out_cmd();
+    dvi_out(font_check_0(f));
+    dvi_out(font_check_1(f));
+    dvi_out(font_check_2(f));
+    dvi_out(font_check_3(f));
+    dvi_four(font_size(f));
+    dvi_four(font_dsize(f));
+    dvi_out(0);                 /* |font_area(f)| is unused */
+    dvi_out(strlen(font_name(f)));
+    /* Output the font name whose internal number is |f| */
+    fa = font_name(f);
+    while (*fa != '\0') {
+        dvi_out(*fa++);
+    }
+}
+
+/*tex
+
+Versions of \TeX\ intended for small computers might well choose to omit the
+ideas in the next few parts of this program, since it is not really necessary to
+optimize the \.{DVI} code by making use of the |w0|, |x0|, |y0|, and |z0|
+commands. Furthermore, the algorithm that we are about to describe does not
+pretend to give an optimum reduction in the length of the \.{DVI} code; after
+all, speed is more important than compactness. But the method is surprisingly
+effective, and it takes comparatively little time.
+
+We can best understand the basic idea by first considering a simpler problem that
+has the same essential characteristics. Given a sequence of digits, say
+$3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts $d$, $y$,
+or $z$ to each digit so as to maximize the number of ``$y$-hits'' and
+``$z$-hits''; a $y$-hit is an instance of two appearances of the same digit with
+the subscript $y$, where no $y$'s intervene between the two appearances, and a
+$z$-hit is defined similarly. For example, the sequence above could be decorated
+with subscripts as follows:
+$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$ There are
+three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and one $z$-hit
+($3_z\ldots3_z$); there are no $d$-hits, since the two appearances of $9_d$ have
+$d$'s between them, but we don't count $d$-hits so it doesn't matter how many
+there are. These subscripts are analogous to the \.{DVI} commands called
+\\{down}, $y$, and $z$, and the digits are analogous to different amounts of
+vertical motion; a $y$-hit or $z$-hit corresponds to the opportunity to use the
+one-byte commands |y0| or |z0| in a \.{DVI} file.
+
+\TeX's method of assigning subscripts works like this: Append a new digit, say
+$\delta$, to the right of the sequence. Now look back through the sequence until
+one of the following things happens: (a)~You see $\delta_y$ or $\delta_z$, and
+this was the first time you encountered a $y$ or $z$ subscript, respectively.
+Then assign $y$ or $z$ to the new $\delta$; you have scored a hit. (b)~You see
+$\delta_d$, and no $y$ subscripts have been encountered so far during this
+search. Then change the previous $\delta_d$ to $\delta_y$ (this corresponds to
+changing a command in the output buffer), and assign $y$ to the new $\delta$;
+it's another hit. (c)~You see $\delta_d$, and a $y$ subscript has been seen but
+not a $z$. Change the previous $\delta_d$ to $\delta_z$ and assign $z$ to the new
+$\delta$. (d)~You encounter both $y$ and $z$ subscripts before encountering a
+suitable $\delta$, or you scan all the way to the front of the sequence. Assign
+$d$ to the new $\delta$; this assignment may be changed later.
+
+The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
+produced by this procedure, as the reader can verify. (Go ahead and try it.)
+
+In order to implement such an idea, \TeX\ maintains a stack of pointers to the
+\\{down}, $y$, and $z$ commands that have been generated for the current page.
+And there is a similar stack for \\{right}, |w|, and |x| commands. These stacks
+are called the down stack and right stack, and their top elements are maintained
+in the variables |down_ptr| and |right_ptr|.
+
+Each entry in these stacks contains four fields: The |width| field is the amount
+of motion down or to the right; the |location| field is the byte number of the
+\.{DVI} command in question (including the appropriate |dvi_offset|); the |vlink|
+field points to the next item below this one on the stack; and the |vinfo| field
+encodes the options for possible change in the \.{DVI} command.
+
+*/
+
+/*tex The \.{DVI} byte number for a movement command: */
+
+#define location(A) varmem[(A)+1].cint
+
+/*tex The heads of the down and right stacks: */
+
+static halfword down_ptr = null;
+static halfword right_ptr = null;
+
+/*tex
+
+Here is a subroutine that produces a \.{DVI} command for some specified downward
+or rightward motion. It has two parameters: |w| is the amount of motion, and |o|
+is either |down1| or |right1|. We use the fact that the command codes have
+convenient arithmetic properties: |y1-down1=w1-right1| and |z1-down1=x1-right1|.
+
+*/
+
+void movement(scaled w, eight_bits o)
+{
+    small_number mstate;        /* have we seen a |y| or |z|? */
+    halfword p, q;              /* current and top nodes on the stack */
+    int k;                      /* index into |dvi_buf|, modulo |dvi_buf_size| */
+    /*tex something todo? */
+    if (false) {
+        /*tex new node for the top of the stack */
+        q = new_node(movement_node, 0);
+        width(q) = w;
+        location(q) = dvi_offset + dvi_ptr;
+        if (o == down1) {
+            vlink(q) = down_ptr;
+            down_ptr = q;
+        } else {
+            vlink(q) = right_ptr;
+            right_ptr = q;
+        }
+        /*tex
+
+            Look at the other stack entries until deciding what sort of \.{DVI}
+            command to generate; |goto found| if node |p| is a ``hit''.
+        */
+        p = vlink(q);
+        mstate = none_seen;
+        while (p != null) {
+            if (width(p) == w) {
+                /*
+                    Consider a node with matching width;|goto found| if it's a
+                    hit. We might find a valid hit in a |y| or |z| byte that is
+                    already gone from the buffer. But we can't change bytes that
+                    are gone forever; ``the moving finger writes, $\ldots\,\,$.''
+                */
+                switch (mstate + vinfo(p)) {
+                    case none_seen + yz_OK:
+                    case none_seen + y_OK:
+                    case z_seen + yz_OK:
+                    case z_seen + y_OK:
+                        if (location(p) < dvi_gone) {
+                            goto NOT_FOUND;
+                        } else {
+                            /* Change buffered instruction to |y| or |w| and |goto found| */
+                            k = location(p) - dvi_offset;
+                            if (k < 0)
+                                k = k + dvi_buf_size;
+                            dvi_buf[k] = (eight_bits) (dvi_buf[k] + y1 - down1);
+                            vinfo(p) = y_here;
+                            goto FOUND;
+                        }
+                        break;
+                    case none_seen + z_OK:
+                    case y_seen + yz_OK:
+                    case y_seen + z_OK:
+                        if (location(p) < dvi_gone) {
+                            goto NOT_FOUND;
+                        } else {
+                            /* Change buffered instruction to |z| or |x| and |goto found| */
+                            k = location(p) - dvi_offset;
+                            if (k < 0)
+                                k = k + dvi_buf_size;
+                            dvi_buf[k] = (eight_bits) (dvi_buf[k] + z1 - down1);
+                            vinfo(p) = z_here;
+                            goto FOUND;
+                        }
+                        break;
+                    case none_seen + y_here:
+                    case none_seen + z_here:
+                    case y_seen + z_here:
+                    case z_seen + y_here:
+                        goto FOUND;
+                        break;
+                    default:
+                        break;
+                }
+            } else {
+                switch (mstate + vinfo(p)) {
+                    case none_seen + y_here:
+                        mstate = y_seen;
+                        break;
+                    case none_seen + z_here:
+                        mstate = z_seen;
+                        break;
+                    case y_seen + z_here:
+                    case z_seen + y_here:
+                        goto NOT_FOUND;
+                        break;
+                    default:
+                        break;
+                }
+            }
+            p = vlink(p);
+        }
+    }
+  NOT_FOUND:
+    /*tex
+        Generate a |down| or |right| command for |w| and |return|:
+    */
+    if (abs(w) >= 040000000) {
+        /*tex |down4| or |right4| */
+        dvi_out(o + 3);
+        dvi_four(w);
+        return;
+    }
+    if (abs(w) >= 0100000) {
+        /*tex |down3| or |right3| */
+        dvi_out(o + 2);
+        if (w < 0)
+            w = w + 0100000000;
+        dvi_out(w / 0200000);
+        w = w % 0200000;
+        goto TWO;
+    }
+    if (abs(w) >= 0200) {
+        /*tex |down2| or |right2| */
+        dvi_out(o + 1);
+        if (w < 0)
+            w = w + 0200000;
+        goto TWO;
+    }
+    /*tex |down1| or |right1| */
+    dvi_out(o);
+    if (w < 0)
+        w = w + 0400;
+    goto ONE;
+  TWO:
+    dvi_out(w / 0400);
+  ONE:
+    dvi_out(w % 0400);
+    return;
+  FOUND:
+    /*tex
+
+        Generate a |y0| or |z0| command in order to reuse a previous appearance
+        of~|w|.
+
+        The program below removes movement nodes that are introduced after a
+        |push|, before it outputs the corresponding |pop|.
+
+        When the |movement| procedure gets to the label |found|, the value of
+        |vinfo(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
+        the procedure generates a |y0| command (or a |w0| command), and marks all
+        |vinfo| fields between |q| and |p| so that |y| is not OK in that range.
+
+     */
+    vinfo(q) = vinfo(p);
+    if (vinfo(q) == y_here) {
+        /*tex |y0| or |w0| */
+        dvi_out(o + y0 - down1);
+        while (vlink(q) != p) {
+            q = vlink(q);
+            switch (vinfo(q)) {
+            case yz_OK:
+                vinfo(q) = z_OK;
+                break;
+            case y_OK:
+                vinfo(q) = d_fixed;
+                break;
+            default:
+                break;
+            }
+        }
+    } else {
+        /*tex |z0| or |x0| */
+        dvi_out(o + z0 - down1);
+        while (vlink(q) != p) {
+            q = vlink(q);
+            switch (vinfo(q)) {
+            case yz_OK:
+                vinfo(q) = y_OK;
+                break;
+            case z_OK:
+                vinfo(q) = d_fixed;
+                break;
+            default:
+                break;
+            }
+        }
+    }
+}
+
+/*tex
+
+In case you are wondering when all the movement nodes are removed from \TeX's
+memory, the answer is that they are recycled just before |hlist_out| and
+|vlist_out| finish outputting a box. This restores the down and right stacks to
+the state they were in before the box was output, except that some |vinfo|'s may
+have become more restrictive.
+
+Here we delete movement nodes with |location>=l|:
+
+*/
+
+static void prune_movements(int l)
+{
+    pointer p;
+    while (down_ptr != null) {
+        if (location(down_ptr) < l)
+            break;
+        p = down_ptr;
+        down_ptr = vlink(p);
+        flush_node(p);
+    }
+    while (right_ptr != null) {
+        if (location(right_ptr) < l)
+            return;
+        p = right_ptr;
+        right_ptr = vlink(p);
+        flush_node(p);
+    }
+}
+
+/*tex
+
+When |hlist_out| is called, its duty is to output the box represented by the
+|hlist_node| pointed to by |temp_ptr|. The reference point of that box has
+coordinates |(cur.h,cur.v)|.
+
+Similarly, when |vlist_out| is called, its duty is to output the box represented
+by the |vlist_node| pointed to by |temp_ptr|. The reference point of that box has
+coordinates |(cur.h,cur.v)|.
+
+The recursive procedures |hlist_out| and |vlist_out| each have a local variable
+|save_dvi| to hold the value of |dvi| just before entering a new level of
+recursion. In effect, the value of |save_dvi| on \TeX's run-time stack
+corresponds to the values of |h| and |v| that a \.{DVI}-reading program will push
+onto its coordinate stack.
+
+*/
+
+void dvi_place_rule(PDF pdf, halfword q, scaledpos size)
+{
+    synch_dvi_with_pos(pdf->posstruct->pos);
+    if ((subtype(q) >= box_rule) && (subtype(q) <= user_rule)) {
+        /*tex place nothing, only take space */
+        if (textdir_is_L(pdf->posstruct->dir))
+            dvi.h += size.h;
+    } else {
+        /*tex normal_rule or >= 100 being a leader rule */
+        if (textdir_is_L(pdf->posstruct->dir)) {
+            /*tex movement optimization for |dir_*L*| */
+            dvi_out(set_rule);
+            dvi.h += size.h;
+        } else
+            dvi_out(put_rule);
+    }
+    dvi_four(size.v);
+    dvi_four(size.h);
+}
+
+void dvi_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
+{
+    scaled_whd ci;
+    synch_dvi_with_pos(pdf->posstruct->pos);
+    if (f != pdf->f_cur) {
+        /*tex Change font |f_cur| to |f| */
+        if (!font_used(f)) {
+            dvi_font_def(f);
+            set_font_used(f, true);
+        }
+        oval = f - 1;
+        ocmd = fnt1;
+        out_cmd();
+        pdf->f_cur = f;
+    }
+    if (textdir_is_L(pdf->posstruct->dir)) {
+        ci = get_charinfo_whd(f, c);
+        /*tex movement optimization for |dir_*L*| */
+        dvi_set(c, ci.wd);
+    } else {
+        dvi_put(c);
+    }
+}
+
+void dvi_special(PDF pdf, halfword p)
+{
+    /*tex holds print |selector| */
+    int old_setting;
+    /*tex index into |cur_string| */
+    unsigned k;
+    synch_dvi_with_pos(pdf->posstruct->pos);
+    old_setting = selector;
+    selector = new_string;
+    show_token_list(token_link(write_tokens(p)), null, -1);
+    selector = old_setting;
+    if (cur_length < 256) {
+        dvi_out(xxx1);
+        dvi_out(cur_length);
+    } else {
+        dvi_out(xxx4);
+        dvi_four((int) cur_length);
+    }
+    for (k = 0; k < cur_length; k++) {
+        dvi_out(cur_string[k]);
+    }
+    /*tex erase the string */
+    cur_length = 0;
+}
+
+/*tex
+
+Here's an example of how these conventions are used. Whenever it is time to ship
+out a box of stuff, we shall use the macro |ensure_dvi_open|.
+
+*/
+
+void dvi_write_header(PDF pdf)
+{
+    unsigned l;
+    /*tex index into |str_pool| */
+    unsigned s;
+    /*tex saved |selector| setting */
+    int old_setting;
+    if (half_buf == 0) {
+        half_buf = dvi_buf_size / 2;
+        dvi_limit = dvi_buf_size;
+    }
+    dvi_out(pre);
+    /*tex output the preamble */
+    dvi_out(id_byte);
+    dvi_four(25400000);
+    /*tex conversion ratio for sp */
+    dvi_four(473628672);
+    prepare_mag();
+    /*tex magnification factor is frozen */
+    dvi_four(mag_par);
+    if (output_comment) {
+        l = (unsigned) strlen(output_comment);
+        dvi_out(l);
+        for (s = 0; s < l; s++) {
+            dvi_out(output_comment[s]);
+        }
+    } else {
+        /*tex the default code is unchanged */
+        old_setting = selector;
+        selector = new_string;
+        tprint(" LuaTeX output ");
+        print_int(year_par);
+        print_char('.');
+        print_two(month_par);
+        print_char('.');
+        print_two(day_par);
+        print_char(':');
+        print_two(time_par / 60);
+        print_two(time_par % 60);
+        selector = old_setting;
+        dvi_out(cur_length);
+        for (s = 0; s < cur_length; s++)
+            dvi_out(cur_string[s]);
+        cur_length = 0;
+    }
+}
+
+void dvi_begin_page(PDF pdf)
+{
+    int k;
+    /*tex location of the current |bop| */
+    int page_loc;
+    ensure_output_state(pdf, ST_HEADER_WRITTEN);
+    /*tex Initialize variables as |ship_out| begins */
+    page_loc = dvi_offset + dvi_ptr;
+    dvi_out(bop);
+    for (k = 0; k <= 9; k++)
+        dvi_four(count(k));
+    dvi_four(last_bop);
+    last_bop = page_loc;
+}
+
+void dvi_end_page(PDF pdf)
+{
+    (void) pdf;
+    dvi_out(eop);
+}
+
+/*tex
+
+At the end of the program, we must finish things off by writing the post\-amble.
+If |total_pages=0|, the \.{DVI} file was never opened. If |total_pages>=65536|,
+the \.{DVI} file will lie. And if |max_push>=65536|, the user deserves whatever
+chaos might ensue.
+
+*/
+
+void dvi_open_file(PDF pdf) {
+    ensure_output_file_open(pdf, ".dvi");
+}
+
+void dvi_finish_file(PDF pdf, int fatal_error)
+{
+    int k;
+    int callback_id = callback_defined(stop_run_callback);
+    if (fatal_error) {
+        print_err(" ==> Fatal error occurred, bad output DVI file produced!");
+    }
+    while (cur_s > -1) {
+        if (cur_s > 0) {
+            dvi_out(pop);
+        } else {
+            dvi_out(eop);
+            incr(total_pages);
+        }
+        decr(cur_s);
+    }
+    if (total_pages == 0) {
+        if (callback_id == 0) {
+            tprint_nl("No pages of output.");
+            print_ln();
+        } else if (callback_id > 0) {
+            run_callback(callback_id, "->");
+        }
+    } else {
+        /*tex beginning of the postamble */
+        dvi_out(post);
+        dvi_four(last_bop);
+        last_bop = dvi_offset + dvi_ptr - 5;
+        /*tex |post| location */
+        dvi_four(25400000);
+        /*tex conversion ratio for sp */
+        dvi_four(473628672);
+        prepare_mag();
+        /*tex magnification factor */
+        dvi_four(mag_par);
+        dvi_four(max_v);
+        dvi_four(max_h);
+        dvi_out(max_push / 256);
+        dvi_out(max_push % 256);
+        dvi_out((total_pages / 256) % 256);
+        dvi_out(total_pages % 256);
+        /*tex Output the font definitions for all fonts that were used */
+        k = max_font_id();
+        while (k > 0) {
+            if (font_used(k)) {
+                dvi_font_def(k);
+            }
+            decr(k);
+        }
+        dvi_out(post_post);
+        dvi_four(last_bop);
+        dvi_out(id_byte);
+        /*tex the number of 223's */
+#ifndef IPC
+        k = 4 + ((dvi_buf_size - dvi_ptr) % 4);
+#else
+        k = 7 - ((3 + dvi_offset + dvi_ptr) % 4);
+#endif
+        while (k > 0) {
+            dvi_out(223);
+            decr(k);
+        }
+        /*tex
+            Here is how we clean out the buffer when \TeX\ is all through;
+            |dvi_ptr| will be a multiple of~4.
+        */
+        if (dvi_limit == half_buf)
+            write_dvi(half_buf, dvi_buf_size - 1);
+        if (dvi_ptr > 0)
+            write_dvi(0, dvi_ptr - 1);
+        if (callback_id == 0) {
+            tprint_nl("Output written on ");
+            tprint(pdf->file_name);
+            tprint(" (");
+            print_int(total_pages);
+            tprint(" page");
+            if (total_pages != 1)
+                print_char('s');
+            tprint(", ");
+            print_int(dvi_offset + dvi_ptr);
+            tprint(" bytes).");
+        } else if (callback_id > 0) {
+            run_callback(callback_id, "->");
+        }
+        close_file(pdf->file);
+    }
+}
+
+void dvi_push_list(PDF pdf, scaledpos *saved_pos, int *saved_loc)
+{
+    if (cur_s > max_push) {
+        max_push = cur_s;
+    }
+    if (cur_s > 0) {
+        dvi_push();
+        *saved_pos = dvi;
+    }
+    *saved_loc = dvi_offset + dvi_ptr;
+}
+
+void dvi_pop_list(PDF pdf, scaledpos *saved_pos, int *saved_loc)
+{
+    prune_movements(*saved_loc);
+    if (cur_s > 0) {
+        dvi_pop(*saved_loc);
+        dvi = *saved_pos;
+    }
+}
+
+void dvi_set_reference_point(PDF pdf, posstructure *refpoint)
+{
+    refpoint->pos.h = one_true_inch;
+    refpoint->pos.v = pdf->page_size.v - one_true_inch;
+    dvi = refpoint->pos;
+}
+
+int dvi_get_status_ptr(PDF pdf)
+{
+    return dvi_ptr;
+}
+
+int dvi_get_status_gone(PDF pdf)
+{
+    return dvi_gone;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/dvi/dvigen.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1258 +0,0 @@
-% dvigen.w
-%
-% Copyright 2009-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-\def\MF{MetaFont}
-\def\MP{MetaPost}
-\def\PASCAL{Pascal}
-\def\[#1]{#1}
-\pdfoutput=1
-\pdfmapline{cmtex10 < cmtex10.pfb}
-\pdfmapfile{pdftex.map}
-
-\title{: generation of DVI output}
-
-@ Initial identification of this file, and the needed headers.
- at c
-#include "ptexlib.h"
-
-@ Here is the start of the actual C file.
- at c
-#undef write_dvi
-
-/* todo: move macros to api */
-
-#define mode cur_list.mode_field        /* current mode */
-
-@ The most important output produced by a run of \TeX\ is the ``device
-independent'' (\.{DVI}) file that specifies where characters and rules
-are to appear on printed pages. The form of these files was designed by
-David R. Fuchs in 1979. Almost any reasonable typesetting device can be
-@^Fuchs, David Raymond@>
-@:DVI_files}{\.{DVI} files@>
-driven by a program that takes \.{DVI} files as input, and dozens of such
-\.{DVI}-to-whatever programs have been written. Thus, it is possible to
-print the output of \TeX\ on many different kinds of equipment, using \TeX\
-as a device-independent ``front end.''
-
-A \.{DVI} file is a stream of 8-bit bytes, which may be regarded as a
-series of commands in a machine-like language. The first byte of each command
-is the operation code, and this code is followed by zero or more bytes
-that provide parameters to the command. The parameters themselves may consist
-of several consecutive bytes; for example, the `|set_rule|' command has two
-parameters, each of which is four bytes long. Parameters are usually
-regarded as nonnegative integers; but four-byte-long parameters,
-and shorter parameters that denote distances, can be
-either positive or negative. Such parameters are given in two's complement
-notation. For example, a two-byte-long distance parameter has a value between
-$-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy
-more than one byte position appear in BigEndian order.
-
-A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one
-or more ``pages,'' followed by a ``postamble.'' The preamble is simply a
-|pre| command, with its parameters that define the dimensions used in the
-file; this must come first.  Each ``page'' consists of a |bop| command,
-followed by any number of other commands that tell where characters are to
-be placed on a physical page, followed by an |eop| command. The pages
-appear in the order that \TeX\ generated them. If we ignore |nop| commands
-and \\{fnt\_def} commands (which are allowed between any two commands in
-the file), each |eop| command is immediately followed by a |bop| command,
-or by a |post| command; in the latter case, there are no more pages in the
-file, and the remaining bytes form the postamble.  Further details about
-the postamble will be explained later.
-
-Some parameters in \.{DVI} commands are ``pointers.'' These are four-byte
-quantities that give the location number of some other byte in the file;
-the first byte is number~0, then comes number~1, and so on. For example,
-one of the parameters of a |bop| command points to the previous |bop|;
-this makes it feasible to read the pages in backwards order, in case the
-results are being directed to a device that stacks its output face up.
-Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the
-first page occupies bytes 100 to 999, say, and if the second
-page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000
-points to 100 and the |bop| that starts in byte 2000 points to 1000. (The
-very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.)
-
-@ The \.{DVI} format is intended to be both compact and easily interpreted
-by a machine. Compactness is achieved by making most of the information
-implicit instead of explicit. When a \.{DVI}-reading program reads the
-commands for a page, it keeps track of several quantities: (a)~The current
-font |f| is an integer; this value is changed only
-by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page
-is given by two numbers called the horizontal and vertical coordinates,
-|h| and |v|. Both coordinates are zero at the upper left corner of the page;
-moving to the right corresponds to increasing the horizontal coordinate, and
-moving down corresponds to increasing the vertical coordinate. Thus, the
-coordinates are essentially Cartesian, except that vertical directions are
-flipped; the Cartesian version of |(h,v)| would be |(h,-v)|.  (c)~The
-current spacing amounts are given by four numbers |w|, |x|, |y|, and |z|,
-where |w| and~|x| are used for horizontal spacing and where |y| and~|z|
-are used for vertical spacing. (d)~There is a stack containing
-|(h,v,w,x,y,z)| values; the \.{DVI} commands |push| and |pop| are used to
-change the current level of operation. Note that the current font~|f| is
-not pushed and popped; the stack contains only information about
-positioning.
-
-The values of |h|, |v|, |w|, |x|, |y|, and |z| are signed integers having up
-to 32 bits, including the sign. Since they represent physical distances,
-there is a small unit of measurement such that increasing |h| by~1 means
-moving a certain tiny distance to the right. The actual unit of
-measurement is variable, as explained below; \TeX\ sets things up so that
-its \.{DVI} output is in sp units, i.e., scaled points, in agreement with
-all the |scaled| dimensions in \TeX's data structures.
-
-@ Here is a list of all the commands that may appear in a \.{DVI} file. Each
-command is specified by its symbolic name (e.g., |bop|), its opcode byte
-(e.g., 139), and its parameters (if any). The parameters are followed
-by a bracketed number telling how many bytes they occupy; for example,
-`|p[4]|' means that parameter |p| is four bytes long.
-
-\yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f|
-such that the reference point of the character is at |(h,v)|. Then
-increase |h| by the width of that character. Note that a character may
-have zero or negative width, so one cannot be sure that |h| will advance
-after this command; but |h| usually does increase.
-
-\yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127).
-Do the operations of |set_char_0|; but use the character whose number
-matches the opcode, instead of character~0.
-
-\yskip\hang|set1| 128 |c[1]|. Same as |set_char_0|, except that character
-number~|c| is typeset. \TeX82 uses this command for characters in the
-range |128<=c<256|.
-
-\yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two
-bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
-command, but it should come in handy for extensions of \TeX\ that deal
-with oriental languages.
-@^oriental characters@>@^Chinese characters@>@^Japanese characters@>
-
-\yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three
-bytes long, so it can be as large as $2^{24}-1$. Not even the Chinese
-language has this many characters, but this command might prove useful
-in some yet unforeseen extension.
-
-\yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four
-bytes long. Imagine that.
-
-\yskip\hang|set_rule| 132 |a[4]| |b[4]|. Typeset a solid black rectangle
-of height~|a| and width~|b|, with its bottom left corner at |(h,v)|. Then
-set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note
-that if |b<0|, the value of |h| will decrease even though nothing else happens.
-See below for details about how to typeset rules so that consistency with
-\MF\ is guaranteed.
-
-\yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f|
-such that the reference point of the character is at |(h,v)|. (The `put'
-commands are exactly like the `set' commands, except that they simply put out a
-character or a rule without moving the reference point afterwards.)
-
-\yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed.
-
-\yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed.
-
-\yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed.
-
-\yskip\hang|put_rule| 137 |a[4]| |b[4]|. Same as |set_rule|, except that
-|h| is not changed.
-
-\yskip\hang|nop| 138. No operation, do nothing. Any number of |nop|'s
-may occur between \.{DVI} commands, but a |nop| cannot be inserted between
-a command and its parameters or between two parameters.
-
-\yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning
-of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set
-the current font |f| to an undefined value.  The ten $c_i$ parameters hold
-the values of \.{\\count0} $\ldots$ \.{\\count9} in \TeX\ at the time
-\.{\\shipout} was invoked for this page; they can be used to identify
-pages, if a user wants to print only part of a \.{DVI} file. The parameter
-|p| points to the previous |bop| in the file; the first
-|bop| has $p=-1$.
-
-\yskip\hang|eop| 140.  End of page: Print what you have read since the
-previous |bop|. At this point the stack should be empty. (The \.{DVI}-reading
-programs that drive most output devices will have kept a buffer of the
-material that appears on the page that has just ended. This material is
-largely, but not entirely, in order by |v| coordinate and (for fixed |v|) by
-|h|~coordinate; so it usually needs to be sorted into some order that is
-appropriate for the device in question.)
-
-\yskip\hang|push| 141. Push the current values of |(h,v,w,x,y,z)| onto the
-top of the stack; do not change any of these values. Note that |f| is
-not pushed.
-
-\yskip\hang|pop| 142. Pop the top six values off of the stack and assign
-them respectively to |(h,v,w,x,y,z)|. The number of pops should never
-exceed the number of pushes, since it would be highly embarrassing if the
-stack were empty at the time of a |pop| command.
-
-\yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units.
-The parameter is a signed number in two's complement notation, |-128<=b<128|;
-if |b<0|, the reference point moves left.
-
-\yskip\hang|right2| 144 |b[2]|. Same as |right1|, except that |b| is a
-two-byte quantity in the range |-32768<=b<32768|.
-
-\yskip\hang|right3| 145 |b[3]|. Same as |right1|, except that |b| is a
-three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|right4| 146 |b[4]|. Same as |right1|, except that |b| is a
-four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck,
-this parameterless command will usually suffice, because the same kind of motion
-will occur several times in succession; the following commands explain how
-|w| gets particular values.
-
-\yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a
-signed quantity in two's complement notation, |-128<=b<128|. This command
-changes the current |w|~spacing and moves right by |b|.
-
-\yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long,
-|-32768<=b<32768|.
-
-\yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long,
-|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long,
-|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|'
-commands are like the `|w|' commands except that they involve |x| instead
-of |w|.
-
-\yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a
-signed quantity in two's complement notation, |-128<=b<128|. This command
-changes the current |x|~spacing and moves right by |b|.
-
-\yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long,
-|-32768<=b<32768|.
-
-\yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long,
-|@t$-2^{23}$@><=b<@t$2^{23}$@>|.
-
-\yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long,
-|@t$-2^{31}$@><=b<@t$2^{31}$@>|.
-
-\yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units.
-The parameter is a signed number in two's complement notation, |-128<=a<128|;
-if |a<0|, the reference point moves up.
-
-\yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a
-two-byte quantity in the range |-32768<=a<32768|.
-
-\yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a
-three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a
-four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck,
-this parameterless command will usually suffice, because the same kind of motion
-will occur several times in succession; the following commands explain how
-|y| gets particular values.
-
-\yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a
-signed quantity in two's complement notation, |-128<=a<128|. This command
-changes the current |y|~spacing and moves down by |a|.
-
-\yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long,
-|-32768<=a<32768|.
-
-\yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long,
-|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long,
-|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands
-are like the `|y|' commands except that they involve |z| instead of |y|.
-
-\yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a
-signed quantity in two's complement notation, |-128<=a<128|. This command
-changes the current |z|~spacing and moves down by |a|.
-
-\yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long,
-|-32768<=a<32768|.
-
-\yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long,
-|@t$-2^{23}$@><=a<@t$2^{23}$@>|.
-
-\yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long,
-|@t$-2^{31}$@><=a<@t$2^{31}$@>|.
-
-\yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been
-defined by a \\{fnt\_def} instruction, as explained below.
-
-\yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set
-|f:=1|, \dots, \hbox{|f:=63|}, respectively.
-
-\yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font
-numbers in the range |64<=k<256|.
-
-\yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two
-bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this
-command, but large font numbers may prove useful for specifications of
-color or texture, or they may be used for special fonts that have fixed
-numbers in some external coding scheme.
-
-\yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three
-bytes long, so it can be as large as $2^{24}-1$.
-
-\yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four
-bytes long; this is for the really big font numbers (and for the negative ones).
-
-\yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in
-general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading
-programs are being used. \TeX82 generates |xxx1| when a short enough
-\.{\\special} appears, setting |k| to the number of bytes being sent. It
-is recommended that |x| be a string having the form of a keyword followed
-by possible parameters relevant to that keyword.
-
-\yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|.
-
-\yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|.
-
-\yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously
-large. \TeX82 uses |xxx4| when sending a string of length 256 or more.
-
-\yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<256|; font definitions will be explained shortly.
-
-\yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<65536|.
-
-\yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |0<=k<@t$2^{24}$@>|.
-
-\yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.
-Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|.
-
-\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
-Beginning of the preamble; this must come at the very beginning of the
-file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
-
-\yskip\hang|post| 248. Beginning of the postamble, see below.
-
-\yskip\hang|post_post| 249. Ending of the postamble, see below.
-
-\yskip\noindent Commands 250--255 are undefined at the present time.
-
- at c
-#define set_char_0  0           /* typeset character 0 and move right */
-#define set1  128               /* typeset a character and move right */
-#define set_rule  132           /* typeset a rule and move right */
-#define put1    133             /* typeset a character without moving */
-#define put_rule  137           /* typeset a rule */
-#define nop  138                /* no operation */
-#define bop  139                /* beginning of page */
-#define eop  140                /* ending of page */
-#define push  141               /* save the current positions */
-#define pop  142                /* restore previous positions */
-#define right1    143           /* move right */
-#define right4    146           /* move right, 4 bytes */
-#define w0  147                 /* move right by |w| */
-#define w1  148                 /* move right and set |w| */
-#define x0  152                 /* move right by |x| */
-#define x1  153                 /* move right and set |x| */
-#define down1  157              /* move down */
-#define down4  160              /* move down, 4 bytes */
-#define y0  161                 /* move down by |y| */
-#define y1  162                 /* move down and set |y| */
-#define z0  166                 /* move down by |z| */
-#define z1  167                 /* move down and set |z| */
-#define fnt_num_0  171          /* set current font to 0 */
-#define fnt1  235               /* set current font */
-#define xxx1  239               /* extension to \.{DVI} primitives */
-#define xxx4  242               /* potentially long extension to \.{DVI} primitives */
-#define fnt_def1  243           /* define the meaning of a font number */
-#define pre  247                /* preamble */
-#define post  248               /* postamble beginning */
-#define post_post  249          /* postamble ending */
-
-@ The preamble contains basic information about the file as a whole. As
-stated above, there are six parameters:
-$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
-The |i| byte identifies \.{DVI} format; currently this byte is always set
-to~2. (The value |i=3| is currently used for an extended format that
-allows a mixture of right-to-left and left-to-right typesetting.
-Some day we will set |i=4|, when \.{DVI} format makes another
-incompatible change---perhaps in the year 2048.)
-
-The next two parameters, |num| and |den|, are positive integers that define
-the units of measurement; they are the numerator and denominator of a
-fraction by which all dimensions in the \.{DVI} file could be multiplied
-in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} =
-254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$
-sp in a point, \TeX\ sets
-$|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$.
-@^sp@>
-
-The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the
-desired magnification. The actual fraction by which dimensions are
-multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\
-source document does not call for any `\.{true}' dimensions, and if you
-change it only by specifying a different \.{\\mag} setting, the \.{DVI}
-file that \TeX\ creates will be completely unchanged except for the value
-of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow
-users to override the |mag|~setting when a \.{DVI} file is being printed.)
-
-Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not
-interpreted further. The length of comment |x| is |k|, where |0<=k<256|.
-
-
- at c
-#define id_byte 2               /* identifies the kind of \.{DVI} files described here */
-
-@ Font definitions for a given font number |k| contain further parameters
-$$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$
-The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM}
-file for this font; |c| should match the check sum of the font found by
-programs that read this \.{DVI} file.
-@^check sum@>
-
-Parameter |s| contains a fixed-point scale factor that is applied to
-the character widths in font |k|; font dimensions in \.{TFM} files and
-other font files are relative to this quantity, which is called the
-``at size'' elsewhere in this documentation. The value of |s| is
-always positive and less than $2^{27}$. It is given in the same units
-as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the
-file.  Parameter |d| is similar to |s|; it is the ``design size,'' and
-(like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used
-at $|mag|\cdot s/1000d$ times its normal size.
-
-The remaining part of a font definition gives the external name of the font,
-which is an ASCII string of length |a+l|. The number |a| is the length
-of the ``area'' or directory, and |l| is the length of the font name itself;
-the standard local system font area is supposed to be used when |a=0|.
-The |n| field contains the area in its first |a| bytes.
-
-Font definitions must appear before the first use of a particular font number.
-Once font |k| is defined, it must not be defined again; however, we
-shall see below that font definitions appear in the postamble as well as
-in the pages, so in this sense each font number is defined exactly twice,
-if at all. Like |nop| commands, font definitions can
-appear before the first |bop|, or between an |eop| and a |bop|.
-
-@ Sometimes it is desirable to make horizontal or vertical rules line up
-precisely with certain features in characters of a font. It is possible to
-guarantee the correct matching between \.{DVI} output and the characters
-generated by \MF\ by adhering to the following principles: (1)~The \MF\
-characters should be positioned so that a bottom edge or left edge that is
-supposed to line up with the bottom or left edge of a rule appears at the
-reference point, i.e., in row~0 and column~0 of the \MF\ raster. This
-ensures that the position of the rule will not be rounded differently when
-the pixel size is not a perfect multiple of the units of measurement in
-the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$
-should be equivalent to a \MF-generated character having black pixels in
-precisely those raster positions whose \MF\ coordinates satisfy
-|0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number
-of pixels per \.{DVI} unit.
-@:METAFONT}{\MF@>
-@^alignment of rules with characters@>
-@^rules aligning with characters@>
-
-@ The last page in a \.{DVI} file is followed by `|post|'; this command
-introduces the postamble, which summarizes important facts that \TeX\ has
-accumulated about the file, making it possible to print subsets of the data
-with reasonable efficiency. The postamble has the form
-$$\vbox{\halign{\hbox{#\hfil}\cr
-  |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr
-  $\langle\,$font definitions$\,\rangle$\cr
-  |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$
-Here |p| is a pointer to the final |bop| in the file. The next three
-parameters, |num|, |den|, and |mag|, are duplicates of the quantities that
-appeared in the preamble.
-
-Parameters |l| and |u| give respectively the height-plus-depth of the tallest
-page and the width of the widest page, in the same units as other dimensions
-of the file. These numbers might be used by a \.{DVI}-reading program to
-position individual ``pages'' on large sheets of film or paper; however,
-the standard convention for output on normal size paper is to position each
-page so that the upper left-hand corner is exactly one inch from the left
-and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer
-software that attempts cleverly to center the output; a fixed position of
-the upper left corner is easiest for users to understand and to work with.
-Therefore |l| and~|u| are often ignored.
-
-Parameter |s| is the maximum stack depth (i.e., the largest excess of
-|push| commands over |pop| commands) needed to process this file. Then
-comes |t|, the total number of pages (|bop| commands) present.
-
-The postamble continues with font definitions, which are any number of
-\\{fnt\_def} commands as described above, possibly interspersed with |nop|
-commands. Each font number that is used in the \.{DVI} file must be defined
-exactly twice: Once before it is first selected by a \\{fnt} command, and once
-in the postamble.
-
-@ The last part of the postamble, following the |post_post| byte that
-signifies the end of the font definitions, contains |q|, a pointer to the
-|post| command that started the postamble.  An identification byte, |i|,
-comes next; this currently equals~2, as in the preamble.
-
-The |i| byte is followed by four or more bytes that are all equal to
-the decimal number 223 (i.e., '337 in octal). \TeX\ puts out four to seven of
-these trailing bytes, until the total length of the file is a multiple of
-four bytes, since this works out best on machines that pack four bytes per
-word; but any number of 223's is allowed, as long as there are at least four
-of them. In effect, 223 is a sort of signature that is added at the very end.
-@^Fuchs, David Raymond@>
-
-This curious way to finish off a \.{DVI} file makes it feasible for
-\.{DVI}-reading programs to find the postamble first, on most computers,
-even though \TeX\ wants to write the postamble last. Most operating
-systems permit random access to individual words or bytes of a file, so
-the \.{DVI} reader can start at the end and skip backwards over the 223's
-until finding the identification byte. Then it can back up four bytes, read
-|q|, and move to byte |q| of the file. This byte should, of course,
-contain the value 248 (|post|); now the postamble can be read, so the
-\.{DVI} reader can discover all the information needed for typesetting the
-pages. Note that it is also possible to skip through the \.{DVI} file at
-reasonably high speed to locate a particular page, if that proves
-desirable. This saves a lot of time, since \.{DVI} files used in production
-jobs tend to be large.
-
-Unfortunately, however, standard \PASCAL\ does not include the ability to
-@^system dependencies@>
-access a random position in a file, or even to determine the length of a file.
-Almost all systems nowadays provide the necessary capabilities, so \.{DVI}
-format has been designed to work most efficiently with modern operating systems.
-But if \.{DVI} files have to be processed under the restrictions of standard
-\PASCAL, one can simply read them from front to back, since the necessary
-header information is present in the preamble and in the font definitions.
-(The |l| and |u| and |s| and |t| parameters, which appear only in the
-postamble, are ``frills'' that are handy but not absolutely necessary.)
-
-
-@* \[32] Shipping pages out.
-After considering \TeX's eyes and stomach, we come now to the bowels.
-@^bowels@>
-
-The |ship_out| procedure is given a pointer to a box; its mission is
-to describe that box in \.{DVI} form, outputting a ``page'' to |dvi_file|.
-The \.{DVI} coordinates $(h,v)=(0,0)$ should correspond to the upper left
-corner of the box being shipped.
-
-Since boxes can be inside of boxes inside of boxes, the main work of
-|ship_out| is done by two mutually recursive routines, |hlist_out|
-and |vlist_out|, which traverse the hlists and vlists inside of horizontal
-and vertical boxes.
-
-As individual pages are being processed, we need to accumulate
-information about the entire set of pages, since such statistics must be
-reported in the postamble. The global variables |total_pages|, |max_v|,
-|max_h|, |max_push|, and |last_bop| are used to record this information.
-
-The variable |doing_leaders| is |true| while leaders are being output.
-The variable |dead_cycles| contains the number of times an output routine
-has been initiated since the last |ship_out|.
-
-A few additional global variables are also defined here for use in
-|vlist_out| and |hlist_out|. They could have been local variables, but
-that would waste stack space when boxes are deeply nested, since the
-values of these variables are not needed during recursive calls.
-@^recursion@>
-
- at c
-int total_pages = 0;            /* the number of pages that have been shipped out */
-scaled max_v = 0;               /* maximum height-plus-depth of pages shipped so far */
-scaled max_h = 0;               /* maximum width of pages shipped so far */
-int max_push = 0;               /* deepest nesting of |push| commands encountered so far */
-int last_bop = -1;              /* location of previous |bop| in the \.{DVI} output */
-int dead_cycles = 0;            /* recent outputs that didn't ship anything out */
-boolean doing_leaders = false;  /* are we inside a leader box? */
-int oval, ocmd;                 /* used by |out_cmd| for generating |set|, |fnt| and |fnt_def| commands */
-pointer g;                      /* current glue specification */
-int lq, lr;                     /* quantities used in calculations for leaders */
-int cur_s = -1;                 /* current depth of output box nesting, initially $-1$ */
-
-@ The \.{DVI} bytes are output to a buffer instead of being written directly
-to the output file. This makes it possible to reduce the overhead of
-subroutine calls, thereby measurably speeding up the computation, since
-output of \.{DVI} bytes is part of \TeX's inner loop. And it has another
-advantage as well, since we can change instructions in the buffer in order to
-make the output more compact. For example, a `|down2|' command can be
-changed to a `|y2|', thereby making a subsequent `|y0|' command possible,
-saving two bytes.
-
-The output buffer is divided into two parts of equal size; the bytes found
-in |dvi_buf[0..half_buf-1]| constitute the first half, and those in
-|dvi_buf[half_buf..dvi_buf_size-1]| constitute the second. The global
-variable |dvi_ptr| points to the position that will receive the next
-output byte. When |dvi_ptr| reaches |dvi_limit|, which is always equal
-to one of the two values |half_buf| or |dvi_buf_size|, the half buffer that
-is about to be invaded next is sent to the output and |dvi_limit| is
-changed to its other value. Thus, there is always at least a half buffer's
-worth of information present, except at the very beginning of the job.
-
-Bytes of the \.{DVI} file are numbered sequentially starting with 0;
-the next byte to be generated will be number |dvi_offset+dvi_ptr|.
-A byte is present in the buffer only if its number is |>=dvi_gone|.
-
-Some systems may find it more efficient to make |dvi_buf| a |packed|
-array, since output of four bytes at once may be facilitated.
-@^system dependencies@>
-
-
-@ Initially the buffer is all in one piece; we will output half of it only
-after it first fills up.
-
- at c
-int dvi_buf_size = 800;         /* size of the output buffer; must be a multiple of 8 */
-eight_bits *dvi_buf;            /* buffer for \.{DVI} output */
-dvi_index half_buf = 0;         /* half of |dvi_buf_size| */
-dvi_index dvi_limit = 0;        /* end of the current half buffer */
-dvi_index dvi_ptr = 0;          /* the next available buffer address */
-int dvi_offset = 0;             /* |dvi_buf_size| times the number of times the output buffer has been fully emptied */
-int dvi_gone = 0;               /* the number of bytes already output to |dvi_file| */
-
-@ The actual output of |dvi_buf[a..b]| to |dvi_file| is performed by calling
-|write_dvi(a,b)|. For best results, this procedure should be optimized to
-run as fast as possible on each particular system, since it is part of
-\TeX's inner loop. It is safe to assume that |a| and |b+1| will both be
-multiples of 4 when |write_dvi(a,b)| is called; therefore it is possible on
-many machines to use efficient methods to pack four bytes per word and to
-output an array of words with one system call.
-@^system dependencies@>
-@^inner loop@>
-@^defecation@>
-
- at c
-static void write_dvi(dvi_index a, dvi_index b)
-{
-    dvi_index k;
-    for (k = a; k <= b; k++)
-        fputc(dvi_buf[k], static_pdf->file);
-}
-
-/* outputs half of the buffer */
-void dvi_swap(void)
-{
-    if (dvi_limit == dvi_buf_size) {
-        write_dvi(0, half_buf - 1);
-        dvi_limit = half_buf;
-        dvi_offset = dvi_offset + dvi_buf_size;
-        dvi_ptr = 0;
-    } else {
-        write_dvi(half_buf, dvi_buf_size - 1);
-        dvi_limit = dvi_buf_size;
-    }
-    dvi_gone = dvi_gone + half_buf;
-}
-
-@ The |dvi_four| procedure outputs four bytes in two's complement notation,
-without risking arithmetic overflow.
-
- at c
-void dvi_four(int x)
-{
-    if (x >= 0) {
-        dvi_out(x / 0100000000);
-    } else {
-        x = x + 010000000000;
-        x = x + 010000000000;
-        dvi_out((x / 0100000000) + 128);
-    }
-    x = x % 0100000000;
-    dvi_out(x / 0200000);
-    x = x % 0200000;
-    dvi_out(x / 0400);
-    dvi_out(x % 0400);
-}
-
-@
-A mild optimization of the output is performed by the |dvi_pop|
-routine, which issues a |pop| unless it is possible to cancel a
-`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address
-following the old |push| that matches the new |pop|.
-
-
- at c
-void dvi_push(void)
-{
-    dvi_out(push);
-}
-
-void dvi_pop(int l)
-{
-    if ((l == dvi_offset + dvi_ptr) && (dvi_ptr > 0))
-        decr(dvi_ptr);
-    else
-        dvi_out(pop);
-}
-
-@ Here's a procedure that outputs a font definition. $\Omega$ allows
-more than 256 different fonts per job, so the right font definition
-command must be selected.
-
- at c
-void out_cmd(void)
-{
-    if ((oval < 0x100) && (oval >= 0)) {
-        if ((ocmd != set1) || (oval > 127)) {
-            if ((ocmd == fnt1) && (oval < 64))
-                oval += fnt_num_0;
-            else
-                dvi_out(ocmd);
-        }
-    } else {
-        if ((oval < 0x10000) && (oval >= 0)) {
-            dvi_out(ocmd + 1);
-        } else {
-            if ((oval < 0x1000000) && (oval >= 0)) {
-                dvi_out(ocmd + 2);
-            } else {
-                dvi_out(ocmd + 3);
-                if (oval >= 0) {
-                    dvi_out(oval / 0x1000000);
-                } else {
-                    oval += 0x40000000;
-                    oval += 0x40000000;
-                    dvi_out((oval / 0x1000000) + 128);
-                    oval = oval % 0x1000000;
-                }
-                dvi_out(oval / 0x10000);
-                oval = oval % 0x10000;
-            }
-            dvi_out(oval / 0x10000);
-            oval = oval % 0x10000;
-        }
-        dvi_out(oval / 0x100);
-        oval = oval % 0x100;
-    }
-    dvi_out(oval);
-}
-
-void dvi_font_def(internal_font_number f)
-{
-    char *fa;
-    oval = f - 1;
-    ocmd = fnt_def1;
-    out_cmd();
-    dvi_out(font_check_0(f));
-    dvi_out(font_check_1(f));
-    dvi_out(font_check_2(f));
-    dvi_out(font_check_3(f));
-    dvi_four(font_size(f));
-    dvi_four(font_dsize(f));
-    dvi_out(0);                 /* |font_area(f)| is unused */
-    dvi_out(strlen(font_name(f)));
-    /* Output the font name whose internal number is |f| */
-    fa = font_name(f);
-    while (*fa != '\0') {
-        dvi_out(*fa++);
-    }
-}
-
-@ Versions of \TeX\ intended for small computers might well choose to omit
-the ideas in the next few parts of this program, since it is not really
-necessary to optimize the \.{DVI} code by making use of the |w0|, |x0|,
-|y0|, and |z0| commands. Furthermore, the algorithm that we are about to
-describe does not pretend to give an optimum reduction in the length
-of the \.{DVI} code; after all, speed is more important than compactness.
-But the method is surprisingly effective, and it takes comparatively little
-time.
-
-We can best understand the basic idea by first considering a simpler problem
-that has the same essential characteristics. Given a sequence of digits,
-say $3\,1\,4\,1\,5\,9\,2\,6\,5\,3\,5\,8\,9$, we want to assign subscripts
-$d$, $y$, or $z$ to each digit so as to maximize the number of ``$y$-hits''
-and ``$z$-hits''; a $y$-hit is an instance of two appearances of the same
-digit with the subscript $y$, where no $y$'s intervene between the two
-appearances, and a $z$-hit is defined similarly. For example, the sequence
-above could be decorated with subscripts as follows:
-$$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$
-There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and
-one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances
-of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't
-matter how many there are. These subscripts are analogous to the \.{DVI}
-commands called \\{down}, $y$, and $z$, and the digits are analogous to
-different amounts of vertical motion; a $y$-hit or $z$-hit corresponds to
-the opportunity to use the one-byte commands |y0| or |z0| in a \.{DVI} file.
-
-\TeX's method of assigning subscripts works like this: Append a new digit,
-say $\delta$, to the right of the sequence. Now look back through the
-sequence until one of the following things happens: (a)~You see
-$\delta_y$ or $\delta_z$, and this was the first time you encountered a
-$y$ or $z$ subscript, respectively.  Then assign $y$ or $z$ to the new
-$\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$
-subscripts have been encountered so far during this search.  Then change
-the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a
-command in the output buffer), and assign $y$ to the new $\delta$; it's
-another hit.  (c)~You see $\delta_d$, and a $y$ subscript has been seen
-but not a $z$.  Change the previous $\delta_d$ to $\delta_z$ and assign
-$z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts
-before encountering a suitable $\delta$, or you scan all the way to the
-front of the sequence. Assign $d$ to the new $\delta$; this assignment may
-be changed later.
-
-The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact,
-produced by this procedure, as the reader can verify. (Go ahead and try it.)
-
-@ In order to implement such an idea, \TeX\ maintains a stack of pointers
-to the \\{down}, $y$, and $z$ commands that have been generated for the
-current page. And there is a similar stack for \\{right}, |w|, and |x|
-commands. These stacks are called the down stack and right stack, and their
-top elements are maintained in the variables |down_ptr| and |right_ptr|.
-
-Each entry in these stacks contains four fields: The |width| field is
-the amount of motion down or to the right; the |location| field is the
-byte number of the \.{DVI} command in question (including the appropriate
-|dvi_offset|); the |vlink| field points to the next item below this one
-on the stack; and the |vinfo| field encodes the options for possible change
-in the \.{DVI} command.
-
- at c
-#define location(A) varmem[(A)+1].cint  /* \.{DVI} byte number for a movement command */
-
-halfword down_ptr = null, right_ptr = null;     /* heads of the down and right stacks */
-
-@ Here is a subroutine that produces a \.{DVI} command for some specified
-downward or rightward motion. It has two parameters: |w| is the amount
-of motion, and |o| is either |down1| or |right1|. We use the fact that
-the command codes have convenient arithmetic properties: |y1-down1=w1-right1|
-and |z1-down1=x1-right1|.
-
- at c
-void movement(scaled w, eight_bits o)
-{
-    small_number mstate;        /* have we seen a |y| or |z|? */
-    halfword p, q;              /* current and top nodes on the stack */
-    int k;                      /* index into |dvi_buf|, modulo |dvi_buf_size| */
-    if (false) {                /* TODO: HUH? */
-        q = new_node(movement_node, 0); /* new node for the top of the stack */
-        width(q) = w;
-        location(q) = dvi_offset + dvi_ptr;
-        if (o == down1) {
-            vlink(q) = down_ptr;
-            down_ptr = q;
-        } else {
-            vlink(q) = right_ptr;
-            right_ptr = q;
-        }
-        /* Look at the other stack entries until deciding what sort of \.{DVI} command
-           to generate; |goto found| if node |p| is a ``hit'' */
-        p = vlink(q);
-        mstate = none_seen;
-        while (p != null) {
-            if (width(p) == w) {
-                /* Consider a node with matching width;|goto found| if it's a hit */
-                /* We might find a valid hit in a |y| or |z| byte that is already gone
-                   from the buffer. But we can't change bytes that are gone forever; ``the
-                   moving finger writes, $\ldots\,\,$.'' */
-
-                switch (mstate + vinfo(p)) {
-                case none_seen + yz_OK:
-                case none_seen + y_OK:
-                case z_seen + yz_OK:
-                case z_seen + y_OK:
-                    if (location(p) < dvi_gone) {
-                        goto NOT_FOUND;
-                    } else {
-                        /* Change buffered instruction to |y| or |w| and |goto found| */
-                        k = location(p) - dvi_offset;
-                        if (k < 0)
-                            k = k + dvi_buf_size;
-                        dvi_buf[k] = (eight_bits) (dvi_buf[k] + y1 - down1);
-                        vinfo(p) = y_here;
-                        goto FOUND;
-                    }
-                    break;
-                case none_seen + z_OK:
-                case y_seen + yz_OK:
-                case y_seen + z_OK:
-                    if (location(p) < dvi_gone) {
-                        goto NOT_FOUND;
-                    } else {
-                        /* Change buffered instruction to |z| or |x| and |goto found| */
-                        k = location(p) - dvi_offset;
-                        if (k < 0)
-                            k = k + dvi_buf_size;
-                        dvi_buf[k] = (eight_bits) (dvi_buf[k] + z1 - down1);
-                        vinfo(p) = z_here;
-                        goto FOUND;
-                    }
-                    break;
-                case none_seen + y_here:
-                case none_seen + z_here:
-                case y_seen + z_here:
-                case z_seen + y_here:
-                    goto FOUND;
-                    break;
-                default:
-                    break;
-                }
-            } else {
-                switch (mstate + vinfo(p)) {
-                case none_seen + y_here:
-                    mstate = y_seen;
-                    break;
-                case none_seen + z_here:
-                    mstate = z_seen;
-                    break;
-                case y_seen + z_here:
-                case z_seen + y_here:
-                    goto NOT_FOUND;
-                    break;
-                default:
-                    break;
-                }
-            }
-            p = vlink(p);
-        }
-    }
-  NOT_FOUND:
-    /* Generate a |down| or |right| command for |w| and |return| */
-    if (abs(w) >= 040000000) {
-        dvi_out(o + 3);         /* |down4| or |right4| */
-        dvi_four(w);
-        return;
-    }
-    if (abs(w) >= 0100000) {
-        dvi_out(o + 2);         /* |down3| or |right3| */
-        if (w < 0)
-            w = w + 0100000000;
-        dvi_out(w / 0200000);
-        w = w % 0200000;
-        goto TWO;
-    }
-    if (abs(w) >= 0200) {
-        dvi_out(o + 1);         /* |down2| or |right2| */
-        if (w < 0)
-            w = w + 0200000;
-        goto TWO;
-    }
-    dvi_out(o);                 /* |down1| or |right1| */
-    if (w < 0)
-        w = w + 0400;
-    goto ONE;
-  TWO:
-    dvi_out(w / 0400);
-  ONE:
-    dvi_out(w % 0400);
-    return;
-  FOUND:
-    /* Generate a |y0| or |z0| command in order to reuse a previous appearance of~|w| */
-    /* The program below removes movement nodes that are introduced after a |push|,
-       before it outputs the corresponding |pop|. */
-    /*
-       When the |movement| procedure gets to the label |found|, the value of
-       |vinfo(p)| will be either |y_here| or |z_here|. If it is, say, |y_here|,
-       the procedure generates a |y0| command (or a |w0| command), and marks
-       all |vinfo| fields between |q| and |p| so that |y| is not OK in that range.
-     */
-    vinfo(q) = vinfo(p);
-    if (vinfo(q) == y_here) {
-        dvi_out(o + y0 - down1);        /* |y0| or |w0| */
-        while (vlink(q) != p) {
-            q = vlink(q);
-            switch (vinfo(q)) {
-            case yz_OK:
-                vinfo(q) = z_OK;
-                break;
-            case y_OK:
-                vinfo(q) = d_fixed;
-                break;
-            default:
-                break;
-            }
-        }
-    } else {
-        dvi_out(o + z0 - down1);        /* |z0| or |x0| */
-        while (vlink(q) != p) {
-            q = vlink(q);
-            switch (vinfo(q)) {
-            case yz_OK:
-                vinfo(q) = y_OK;
-                break;
-            case z_OK:
-                vinfo(q) = d_fixed;
-                break;
-            default:
-                break;
-            }
-        }
-    }
-}
-
-@ In case you are wondering when all the movement nodes are removed from
-\TeX's memory, the answer is that they are recycled just before
-|hlist_out| and |vlist_out| finish outputting a box. This restores the
-down and right stacks to the state they were in before the box was output,
-except that some |vinfo|'s may have become more restrictive.
-
-
- at c
-/* delete movement nodes with |location>=l| */
-void prune_movements(int l)
-{
-    pointer p;                  /* node being deleted */
-    while (down_ptr != null) {
-        if (location(down_ptr) < l)
-            break;
-        p = down_ptr;
-        down_ptr = vlink(p);
-        flush_node(p);
-    }
-    while (right_ptr != null) {
-        if (location(right_ptr) < l)
-            return;
-        p = right_ptr;
-        right_ptr = vlink(p);
-        flush_node(p);
-    }
-}
-
-scaledpos dvi;                  /* a \.{DVI} position in page coordinates, in sync with DVI file */
-
-@ When |hlist_out| is called, its duty is to output the box represented
-by the |hlist_node| pointed to by |temp_ptr|. The reference point of that
-box has coordinates |(cur.h,cur.v)|.
-
-Similarly, when |vlist_out| is called, its duty is to output the box represented
-by the |vlist_node| pointed to by |temp_ptr|. The reference point of that
-box has coordinates |(cur.h,cur.v)|.
-@^recursion@>
-
-@ The recursive procedures |hlist_out| and |vlist_out| each have a local variable
-|save_dvi| to hold the value of |dvi| just before
-entering a new level of recursion.  In effect, the value of |save_dvi|
-on \TeX's run-time stack corresponds to the values of |h| and |v|
-that a \.{DVI}-reading program will push onto its coordinate stack.
-
- at c
-void dvi_place_rule(PDF pdf, halfword q, scaledpos size)
-{
-    synch_dvi_with_pos(pdf->posstruct->pos);
-    if ((subtype(q) >= box_rule) && (subtype(q) <= user_rule)) {
-        /* place nothing, only take space */
-        if (textdir_is_L(pdf->posstruct->dir))
-            dvi.h += size.h;
-    } else {
-        /* normal_rule or >= 100 being a leader rule */
-        if (textdir_is_L(pdf->posstruct->dir)) {
-            dvi_out(set_rule);      /* movement optimization for |dir_*L*| */
-            dvi.h += size.h;
-        } else
-            dvi_out(put_rule);
-    }
-    dvi_four(size.v);
-    dvi_four(size.h);
-}
-
-void dvi_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
-{
-    /* TODO: do something on ex, select font (if possible) */
-    scaled_whd ci;
-    synch_dvi_with_pos(pdf->posstruct->pos);
-    if (f != pdf->f_cur) {
-        /* Change font |f_cur| to |f| */
-        if (!font_used(f)) {
-            dvi_font_def(f);
-            set_font_used(f, true);
-        }
-        oval = f - 1;
-        ocmd = fnt1;
-        out_cmd();
-        pdf->f_cur = f;
-    }
-    if (textdir_is_L(pdf->posstruct->dir)) {
-        ci = get_charinfo_whd(f, c);
-        dvi_set(c, ci.wd);      /* movement optimization for |dir_*L*| */
-    } else
-        dvi_put(c);
-}
-
-void dvi_special(PDF pdf, halfword p)
-{
-    int old_setting;            /* holds print |selector| */
-    unsigned k;                 /* index into |cur_string| */
-    synch_dvi_with_pos(pdf->posstruct->pos);
-    old_setting = selector;
-    selector = new_string;
-    show_token_list(token_link(write_tokens(p)), null, -1);
-    selector = old_setting;
-    if (cur_length < 256) {
-        dvi_out(xxx1);
-        dvi_out(cur_length);
-    } else {
-        dvi_out(xxx4);
-        dvi_four((int) cur_length);
-    }
-    for (k = 0; k < cur_length; k++)
-        dvi_out(cur_string[k]);
-    cur_length = 0;             /* erase the string */
-}
-
-@ Here's an example of how these conventions are used. Whenever it is time to
-ship out a box of stuff, we shall use the macro |ensure_dvi_open|.
-
- at c
-void ensure_dvi_header_written(PDF pdf)
-{
-    unsigned l;
-    unsigned s;                 /* index into |str_pool| */
-    int old_setting;            /* saved |selector| setting */
-    assert(output_mode_used == OMODE_DVI);
-    assert(pdf->o_state == ST_FILE_OPEN);
-
-    if (half_buf == 0) {
-        half_buf = dvi_buf_size / 2;
-        dvi_limit = dvi_buf_size;
-    }
-
-    dvi_out(pre);
-    dvi_out(id_byte);           /* output the preamble */
-    dvi_four(25400000);
-    dvi_four(473628672);        /* conversion ratio for sp */
-    prepare_mag();
-    dvi_four(mag_par);          /* magnification factor is frozen */
-    if (output_comment) {
-        l = (unsigned) strlen(output_comment);
-        dvi_out(l);
-        for (s = 0; s < l; s++)
-            dvi_out(output_comment[s]);
-    } else {                    /* the default code is unchanged */
-        old_setting = selector;
-        selector = new_string;
-        tprint(" LuaTeX output ");
-        print_int(year_par);
-        print_char('.');
-        print_two(month_par);
-        print_char('.');
-        print_two(day_par);
-        print_char(':');
-        print_two(time_par / 60);
-        print_two(time_par % 60);
-        selector = old_setting;
-        dvi_out(cur_length);
-        for (s = 0; s < cur_length; s++)
-            dvi_out(cur_string[s]);
-        cur_length = 0;
-    }
-}
-
-void dvi_begin_page(PDF pdf)
-{
-    int k;
-    int page_loc;               /* location of the current |bop| */
-    ensure_output_state(pdf, ST_HEADER_WRITTEN);
-    /* Initialize variables as |ship_out| begins */
-    page_loc = dvi_offset + dvi_ptr;
-    dvi_out(bop);
-    for (k = 0; k <= 9; k++)
-        dvi_four(count(k));
-    dvi_four(last_bop);
-    last_bop = page_loc;
-}
-
-void dvi_end_page(PDF pdf)
-{
-    (void) pdf;
-    dvi_out(eop);
-}
-
-@ At the end of the program, we must finish things off by writing the
-post\-amble. If |total_pages=0|, the \.{DVI} file was never opened.
-If |total_pages>=65536|, the \.{DVI} file will lie. And if
-|max_push>=65536|, the user deserves whatever chaos might ensue.
-
- at c
-void finish_dvi_file(PDF pdf, int version, int revision)
-{
-    int k;
-    int callback_id = callback_defined(stop_run_callback);
-    (void) version;
-    (void) revision;
-    while (cur_s > -1) {
-        if (cur_s > 0) {
-            dvi_out(pop);
-        } else {
-            dvi_out(eop);
-            incr(total_pages);
-        }
-        decr(cur_s);
-    }
-    if (total_pages == 0) {
-        if (callback_id == 0) {
-            tprint_nl("No pages of output.");
-            print_ln();
-        } else if (callback_id > 0) {
-            run_callback(callback_id, "->");
-        }
-    } else {
-        dvi_out(post);          /* beginning of the postamble */
-        dvi_four(last_bop);
-        last_bop = dvi_offset + dvi_ptr - 5;    /* |post| location */
-        dvi_four(25400000);
-        dvi_four(473628672);    /* conversion ratio for sp */
-        prepare_mag();
-        dvi_four(mag_par);      /* magnification factor */
-        dvi_four(max_v);
-        dvi_four(max_h);
-        dvi_out(max_push / 256);
-        dvi_out(max_push % 256);
-        dvi_out((total_pages / 256) % 256);
-        dvi_out(total_pages % 256);
-        /* Output the font definitions for all fonts that were used */
-        k = max_font_id();
-        while (k > 0) {
-            if (font_used(k)) {
-                dvi_font_def(k);
-            }
-            decr(k);
-        }
-
-        dvi_out(post_post);
-        dvi_four(last_bop);
-        dvi_out(id_byte);
-#ifndef IPC
-        k = 4 + ((dvi_buf_size - dvi_ptr) % 4); /* the number of 223's */
-#else
-        k = 7 - ((3 + dvi_offset + dvi_ptr) % 4);       /* the number of 223's */
-#endif
-
-        while (k > 0) {
-            dvi_out(223);
-            decr(k);
-        }
-        /* Empty the last bytes out of |dvi_buf| */
-        /* Here is how we clean out the buffer when \TeX\ is all through; |dvi_ptr|
-           will be a multiple of~4. */
-        if (dvi_limit == half_buf)
-            write_dvi(half_buf, dvi_buf_size - 1);
-        if (dvi_ptr > 0)
-            write_dvi(0, dvi_ptr - 1);
-
-        if (callback_id == 0) {
-            tprint_nl("Output written on ");
-            tprint(pdf->file_name);
-            tprint(" (");
-            print_int(total_pages);
-            tprint(" page");
-            if (total_pages != 1)
-                print_char('s');
-            tprint(", ");
-            print_int(dvi_offset + dvi_ptr);
-            tprint(" bytes).");
-        } else if (callback_id > 0) {
-            run_callback(callback_id, "->");
-        }
-        close_file(pdf->file);
-    }
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/dofont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/dofont.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/dofont.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,141 @@
+/*
+
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/*tex
+
+    A bit more interfacing is needed for proper error reporting.
+
+*/
+
+static char *font_error_message(pointer u, char *nom, scaled s)
+{
+    char *str = xmalloc(256);
+    char *c = makecstring(cs_text(u));
+    const char *extra = "metric data not found or bad";
+    if (s >= 0) {
+        snprintf(str, 255, "Font \\%s=%s at %gpt not loadable: %s", c, nom, (double) s / 65536, extra);
+    } else if (s != -1000) {
+        snprintf(str, 255, "Font \\%s=%s scaled %d not loadable: %s", c, nom, (int) (-s), extra);
+    } else {
+        snprintf(str, 255, "Font \\%s=%s not loadable: %s", c, nom, extra);
+    }
+    free(c);
+    return str;
+}
+
+static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
+{
+    boolean res = 0;
+    char *cnam;
+    int r, t;
+    int callback_id = callback_defined(define_font_callback);
+    if (callback_id > 0) {
+        cnam = xstrdup(cnom);
+        callback_id = run_and_save_callback(callback_id, "Sdd->", cnam, s, f);
+        free(cnam);
+        if (callback_id > 0) {
+            /*tex Success. */
+            luaL_checkstack(Luas, 1, "out of stack space");
+            lua_rawgeti(Luas, LUA_REGISTRYINDEX, callback_id);
+            t = lua_type(Luas, -1);
+            if (t == LUA_TTABLE) {
+                res = font_from_lua(Luas, f);
+                destroy_saved_callback(callback_id);
+            } else if (t == LUA_TNUMBER) {
+                r = (int) lua_tointeger(Luas, -1);
+                destroy_saved_callback(callback_id);
+                delete_font(f);
+                lua_pop(Luas, 1);
+                return r;
+            } else {
+                lua_pop(Luas, 1);
+                delete_font(f);
+                return 0;
+            }
+        }
+    } else if (callback_id == 0) {
+        res = read_tfm_info(f, cnom, s);
+        if (res) {
+            set_hyphen_char(f, default_hyphen_char_par);
+            set_skew_char(f, default_skew_char_par);
+        }
+    }
+    if (font_name(f) && strlen(font_name(f)) > 255) {
+        /*tex
+
+            The font name has to fit in the dvi file's single byte storage. There
+            is no need to test area, as we are never using it.
+        */
+        res = 0;
+    }
+    if (res) {
+        if (font_type(f) != virtual_font_type) {
+            /*tex This implies \LUA. */
+            do_vf(f);
+            set_font_natural_dir(f, natural_dir);
+        }
+        return f;
+    } else {
+        delete_font(f);
+        return 0;
+    }
+
+}
+
+int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
+{
+    int f;
+    char *msg;
+
+    f = new_font();
+    if ((f = do_define_font(f, cnom, s, natural_dir))) {
+        return f;
+    } else {
+        const char *help[] = {
+            "I wasn't able to read the size data for this font,",
+            "so I will ignore the font specification.",
+            "[Wizards can fix TFM files using TFtoPL/PLtoTF.]",
+            "You might try inserting a different font spec;",
+            "e.g., type `I\\font<same font id>=<substitute font name>'.",
+            NULL
+        };
+        if (suppress_fontnotfound_error_par == 0) {
+            msg = font_error_message(u, cnom, s);
+            tex_error(msg, help);
+            free(msg);
+        }
+        return 0;
+    }
+}
+
+int find_font_id(const char *nom, scaled s)
+{
+    int f;
+    f = new_font();
+    if ((f = do_define_font(f, nom, s, -1))) {
+        return f;
+    } else {
+        return 0;
+    }
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/dofont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/dofont.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/dofont.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,145 +0,0 @@
-% dofont.w
-%
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-@ a bit more interfacing is needed for proper error reporting
-
- at c
-static char *font_error_message(pointer u, char *nom, scaled s)
-{
-    char *str = xmalloc(256);
-    char *c = makecstring(cs_text(u));
-    const char *extra = "metric data not found or bad";
-    if (s >= 0) {
-        snprintf(str, 255, "Font \\%s=%s at %gpt not loadable: %s", c, nom,
-                 (double) s / 65536, extra);
-    } else if (s != -1000) {
-        snprintf(str, 255, "Font \\%s=%s scaled %d not loadable: %s", c, nom,
-                 (int) (-s), extra);
-    } else {
-        snprintf(str, 255, "Font \\%s=%s not loadable: %s", c, nom, extra);
-    }
-    free(c);
-    return str;
-}
-
-static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
-{
-
-    boolean res;                /* was the callback successful? */
-    int callback_id;
-    char *cnam;
-    int r, t;
-    res = 0;
-
-    callback_id = callback_defined(define_font_callback);
-    if (callback_id > 0) {
-        cnam = xstrdup(cnom);
-        callback_id = run_and_save_callback(callback_id, "Sdd->", cnam, s, f);
-        free(cnam);
-        if (callback_id > 0) {  /* success */
-            luaL_checkstack(Luas, 1, "out of stack space");
-            lua_rawgeti(Luas, LUA_REGISTRYINDEX, callback_id);
-            t = lua_type(Luas, -1);
-            if (t == LUA_TTABLE) {
-                res = font_from_lua(Luas, f);
-                destroy_saved_callback(callback_id);
-                /* |lua_pop(Luas, 1);| *//* done by |font_from_lua| */
-            } else if (t == LUA_TNUMBER) {
-                r = (int) lua_tointeger(Luas, -1);
-                destroy_saved_callback(callback_id);
-                delete_font(f);
-                lua_pop(Luas, 1);
-                return r;
-            } else {
-                lua_pop(Luas, 1);
-                delete_font(f);
-                return 0;
-            }
-        }
-    } else if (callback_id == 0) {
-        res = read_tfm_info(f, cnom, s);
-        if (res) {
-            set_hyphen_char(f, default_hyphen_char_par);
-            set_skew_char(f, default_skew_char_par);
-        }
-    }
-    if (font_name(f) && strlen(font_name(f)) > 255) {
-        /* the font name has to fit in the dvi file's single byte storage */
-        /* no need to test area, as we are never using it */
-        res = 0;
-    }
-    if (res) {
-        if (font_type(f) != virtual_font_type) {        /* implies lua */
-            do_vf(f);
-            set_font_natural_dir(f, natural_dir);
-        }
-        return f;
-    } else {
-        delete_font(f);
-        return 0;
-    }
-
-}
-
-int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
-{
-    int f;
-    char *msg;
-
-    f = new_font();
-    if ((f = do_define_font(f, cnom, s, natural_dir))) {
-        return f;
-    } else {
-        const char *help[] =
-            { "I wasn't able to read the size data for this font,",
-            "so I will ignore the font specification.",
-            "[Wizards can fix TFM files using TFtoPL/PLtoTF.]",
-            "You might try inserting a different font spec;",
-            "e.g., type `I\\font<same font id>=<substitute font name>'.",
-            NULL
-        };
-        if (suppress_fontnotfound_error_par == 0) {
-            msg = font_error_message(u, cnom, s);
-            tex_error(msg, help);
-            free(msg);
-        }
-        return 0;
-    }
-}
-
-@ TODO This function is a placeholder. There can easily appears holes in
-   the |font_tables| array, and we could attempt to reuse those
-
- at c
-int find_font_id(const char *nom, scaled s)
-{
-    int f;
-    f = new_font();
-    if ((f = do_define_font(f, nom, s, -1))) {
-        return f;
-    } else {
-        return 0;
-    }
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/luafont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/luafont.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/luafont.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,2420 @@
+/*
+
+Copyright 2006-2011 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define noVERBOSE
+
+/*tex
+
+    Todo: make these keys.
+
+*/
+
+const char *font_type_strings[] = {
+    "unknown", "virtual", "real", NULL
+};
+
+const char *font_writingmode_strings[] = {
+    "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_identity_strings[] = {
+    "unknown", "horizontal", "vertical", NULL
+};
+
+const char *font_format_strings[] = {
+    "unknown", "type1", "type3", "truetype", "opentype", NULL
+};
+
+const char *font_embedding_strings[] = {
+    "unknown", "no", "subset", "full", NULL
+};
+
+const char *ligature_type_strings[] = {
+    "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
+};
+
+const char *MATH_param_names[] = {
+    "nil",
+    "ScriptPercentScaleDown",
+    "ScriptScriptPercentScaleDown",
+    "DelimitedSubFormulaMinHeight",
+    "DisplayOperatorMinHeight",
+    "MathLeading",
+    "AxisHeight",
+    "AccentBaseHeight",
+    "FlattenedAccentBaseHeight",
+    "SubscriptShiftDown",
+    "SubscriptTopMax",
+    "SubscriptBaselineDropMin",
+    "SuperscriptShiftUp",
+    "SuperscriptShiftUpCramped",
+    "SuperscriptBottomMin",
+    "SuperscriptBaselineDropMax",
+    "SubSuperscriptGapMin",
+    "SuperscriptBottomMaxWithSubscript",
+    "SpaceAfterScript",
+    "UpperLimitGapMin",
+    "UpperLimitBaselineRiseMin",
+    "LowerLimitGapMin",
+    "LowerLimitBaselineDropMin",
+    "StackTopShiftUp",
+    "StackTopDisplayStyleShiftUp",
+    "StackBottomShiftDown",
+    "StackBottomDisplayStyleShiftDown",
+    "StackGapMin",
+    "StackDisplayStyleGapMin",
+    "StretchStackTopShiftUp",
+    "StretchStackBottomShiftDown",
+    "StretchStackGapAboveMin",
+    "StretchStackGapBelowMin",
+    "FractionNumeratorShiftUp",
+    "FractionNumeratorDisplayStyleShiftUp",
+    "FractionDenominatorShiftDown",
+    "FractionDenominatorDisplayStyleShiftDown",
+    "FractionNumeratorGapMin",
+    "FractionNumeratorDisplayStyleGapMin",
+    "FractionRuleThickness",
+    "FractionDenominatorGapMin",
+    "FractionDenominatorDisplayStyleGapMin",
+    "SkewedFractionHorizontalGap",
+    "SkewedFractionVerticalGap",
+    "OverbarVerticalGap",
+    "OverbarRuleThickness",
+    "OverbarExtraAscender",
+    "UnderbarVerticalGap",
+    "UnderbarRuleThickness",
+    "UnderbarExtraDescender",
+    "RadicalVerticalGap",
+    "RadicalDisplayStyleVerticalGap",
+    "RadicalRuleThickness",
+    "RadicalExtraAscender",
+    "RadicalKernBeforeDegree",
+    "RadicalKernAfterDegree",
+    "RadicalDegreeBottomRaisePercent",
+    "MinConnectorOverlap",
+    "SubscriptShiftDownWithSuperscript",
+    "FractionDelimiterSize",
+    "FractionDelimiterDisplayStyleSize",
+    "NoLimitSubFactor",
+    "NoLimitSupFactor",
+    NULL,
+};
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
+
+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
+    const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
+    int i;
+    for (i=0; lst[i]; i++)
+    if (strcmp(lst[i], name) == 0)
+        return i;
+    return -1;
+}
+
+#define dump_intfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushinteger(L, c); \
+    lua_rawset(L, -3); \
+
+#define dump_stringfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushstring(L, c); \
+    lua_rawset(L, -3);
+
+#define dump_booleanfield(L,n,c) \
+    lua_push_string_by_name(L,n); \
+    lua_pushboolean(L, c); \
+    lua_rawset(L, -3);
+
+static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
+{
+    int i;
+    for (i = 0; i < l; i++) {
+        lua_newtable(L);
+        if (id==top_left_kern) {
+            dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->top_left_math_kern_array[(2*i)+1]);
+        } else if (id==top_right_kern) {
+            dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->top_right_math_kern_array[(2*i)+1]);
+        } else if (id==bottom_right_kern) {
+            dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->bottom_right_math_kern_array[(2*i)+1]);
+        } else if (id==bottom_left_kern) {
+            dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
+            dump_intfield(L, kern,   co->bottom_left_math_kern_array[(2*i)+1]);
+        }
+        lua_rawseti(L, -2, (i + 1));
+    }
+}
+
+static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
+{
+    liginfo *l;
+    kerninfo *ki;
+    lua_createtable(L, 0, 10);
+    dump_intfield(L,width,get_charinfo_width(co));
+    dump_intfield(L,height,get_charinfo_height(co));
+    dump_intfield(L,depth,get_charinfo_depth(co));
+    if (get_charinfo_italic(co) != 0) {
+       dump_intfield(L,italic,get_charinfo_italic(co));
+    }
+    if (get_charinfo_vert_italic(co) != 0) {
+       dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
+    }
+    if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
+       dump_intfield(L,top_accent,get_charinfo_top_accent(co));
+    }
+    if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
+       dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
+    }
+    if (get_charinfo_ef(co) != 1000) {
+        dump_intfield(L,expansion_factor,get_charinfo_ef(co));
+    }
+    if (get_charinfo_lp(co) != 0) {
+        dump_intfield(L,left_protruding,get_charinfo_lp(co));
+    }
+    if (get_charinfo_rp(co) != 0) {
+        dump_intfield(L,right_protruding,get_charinfo_rp(co));
+    }
+    if (font_encodingbytes(f) == 2) {
+        dump_intfield(L,index,get_charinfo_index(co));
+    }
+    if (get_charinfo_name(co) != NULL) {
+        dump_stringfield(L,name,get_charinfo_name(co));
+    }
+    if (get_charinfo_tounicode(co) != NULL) {
+        dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
+    }
+    if (get_charinfo_tag(co) == list_tag) {
+        dump_intfield(L,next,get_charinfo_remainder(co));
+    }
+    if (get_charinfo_used(co)) {
+        dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
+    }
+    if (get_charinfo_tag(co) == ext_tag) {
+        extinfo *h;
+        h = get_charinfo_hor_variants(co);
+        if (h != NULL) {
+            int i = 1;
+            lua_push_string_by_name(L,horiz_variants);
+            lua_newtable(L);
+            while (h != NULL) {
+                lua_createtable(L, 0, 5);
+                dump_intfield(L, glyph, h->glyph);
+                dump_intfield(L, extender, h->extender);
+                dump_intfield(L, start, h->start_overlap);
+                dump_intfield(L, end, h->end_overlap);
+                dump_intfield(L, advance, h->advance);
+                lua_rawseti(L, -2, i);
+                i++;
+                h = h->next;
+            }
+            lua_rawset(L, -3);
+        }
+        h = get_charinfo_vert_variants(co);
+        if (h != NULL) {
+            int i = 1;
+            lua_push_string_by_name(L,vert_variants);
+            lua_newtable(L);
+            while (h != NULL) {
+                lua_createtable(L, 0, 5);
+                dump_intfield(L, glyph, h->glyph);
+                dump_intfield(L, extender, h->extender);
+                dump_intfield(L, start, h->start_overlap);
+                dump_intfield(L, end, h->end_overlap);
+                dump_intfield(L, advance, h->advance);
+                lua_rawseti(L, -2, i);
+                i++;
+                h = h->next;
+            }
+            lua_rawset(L, -3);
+        }
+    }
+    ki = get_charinfo_kerns(co);
+    if (ki != NULL) {
+        int i;
+        lua_push_string_by_name(L,kerns);
+        lua_createtable(L, 10, 1);
+        for (i = 0; !kern_end(ki[i]); i++) {
+            if (kern_disabled(ki[i])) {
+                /*tex Skip like in lookup. */
+            } else {
+                lua_rawgeti(L, -1, kern_char(ki[i]));
+                if (lua_type(L,-1) == LUA_TNIL) {
+                    lua_pop(L,1);
+                    if (kern_char(ki[i]) == right_boundarychar) {
+                        lua_push_string_by_name(L,right_boundary);
+                    } else {
+                        lua_pushinteger(L, kern_char(ki[i]));
+                    }
+                    lua_pushinteger(L, kern_kern(ki[i]));
+                    lua_rawset(L, -3);
+                } else {
+                    /*tex The first one wins. */
+                    lua_pop(L,1);
+                }
+            }
+        }
+        lua_rawset(L, -3);
+    }
+    l = get_charinfo_ligatures(co);
+    if (l != NULL) {
+        int i;
+        lua_push_string_by_name(L,ligatures);
+        lua_createtable(L, 10, 1);
+        for (i = 0; !lig_end(l[i]); i++) {
+            if (lig_char(l[i]) == right_boundarychar) {
+                lua_push_string_by_name(L,right_boundary);
+            } else {
+                lua_pushinteger(L, lig_char(l[i]));
+            }
+            lua_createtable(L, 0, 2);
+            lua_push_string_by_name(L,type);
+            lua_pushinteger(L, lig_type(l[i]));
+            lua_rawset(L, -3);
+            lua_push_string_by_name(L,char);
+            lua_pushinteger(L, lig_replacement(l[i]));
+            lua_rawset(L, -3);
+            lua_rawset(L, -3);
+        }
+        lua_rawset(L, -3);
+    }
+    lua_push_string_by_name(L,mathkern);
+    lua_newtable(L);
+    {
+        int i, j;
+        i = get_charinfo_math_kerns(co, top_right_kern);
+        j = 0;
+        if (i > 0) {
+            j++;
+            lua_push_string_by_name(L,top_right);
+            lua_newtable(L);
+            dump_math_kerns(L, co, i, top_right_kern);
+            lua_rawset(L, -3);
+        }
+        i = get_charinfo_math_kerns(co, top_left_kern);
+        if (i > 0) {
+            j++;
+            lua_push_string_by_name(L,top_left);
+            lua_newtable(L);
+            dump_math_kerns(L, co, i, top_left_kern);
+            lua_rawset(L, -3);
+        }
+        i = get_charinfo_math_kerns(co, bottom_right_kern);
+        if (i > 0) {
+            j++;
+            lua_push_string_by_name(L,bottom_right);
+            lua_newtable(L);
+            dump_math_kerns(L, co, i, bottom_right_kern);
+            lua_rawset(L, -3);
+        }
+        i = get_charinfo_math_kerns(co, bottom_left_kern);
+        if (i > 0) {
+            j++;
+            lua_push_string_by_name(L,bottom_left);
+            lua_newtable(L);
+            dump_math_kerns(L, co, i, bottom_left_kern);
+            lua_rawset(L, -3);
+        }
+        if (j > 0)
+            lua_rawset(L, -3);
+        else
+            lua_pop(L, 2);
+    }
+}
+
+static void write_lua_parameters(lua_State * L, int f)
+{
+    int k;
+    lua_push_string_by_name(L,parameters);
+    lua_newtable(L);
+    for (k = 1; k <= font_params(f); k++) {
+        switch (k) {
+            case slant_code:
+                dump_intfield(L,slant,font_param(f, k));
+                break;
+            case space_code:
+                dump_intfield(L,space,font_param(f, k));
+                break;
+            case space_stretch_code:
+                dump_intfield(L,space_stretch,font_param(f, k));
+                break;
+            case space_shrink_code:
+                dump_intfield(L,space_shrink,font_param(f, k));
+                break;
+            case x_height_code:
+                dump_intfield(L,x_height,font_param(f, k));
+                break;
+            case quad_code:
+                dump_intfield(L,quad,font_param(f, k));
+                break;
+            case extra_space_code:
+                dump_intfield(L,extra_space,font_param(f, k));
+                break;
+            default:
+                lua_pushinteger(L, font_param(f, k));
+                lua_rawseti(L, -2, k);
+        }
+    }
+    lua_rawset(L, -3);
+}
+
+static void write_lua_math_parameters(lua_State * L, int f)
+{
+    int k;
+    lua_push_string_by_name(L,MathConstants);
+    lua_newtable(L);
+    for (k = 1; k <= font_math_params(f); k++) {
+        lua_pushinteger(L, font_math_param(f, k));
+        if (k <= MATH_param_max) {
+            lua_setfield(L, -2, MATH_param_names[k]);
+        } else {
+            lua_rawseti(L, -2, k);
+        }
+    }
+    lua_rawset(L, -3);
+}
+
+int font_to_lua(lua_State * L, int f)
+{
+    int k;
+    charinfo *co;
+    if (font_cache_id(f) > 0) {
+        /*tex Fetch the table from the registry if it was saved there by |font_from_lua|. */
+        lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
+        /*tex Font dimenensions can be changed from \TEX\ code. */
+        write_lua_parameters(L, f);
+        return 1;
+    }
+    lua_newtable(L);
+    lua_push_string_by_name(L,name);
+    lua_pushstring(L, font_name(f));
+    lua_rawset(L, -3);
+    if (font_area(f) != NULL) {
+        dump_stringfield(L,area,font_area(f));
+    }
+    if (font_filename(f) != NULL) {
+        dump_stringfield(L,filename,font_filename(f));
+    }
+    if (font_fullname(f) != NULL) {
+        dump_stringfield(L,fullname,font_fullname(f));
+    }
+    if (font_psname(f) != NULL) {
+        dump_stringfield(L,psname,font_psname(f));
+    }
+    if (font_encodingname(f) != NULL) {
+        dump_stringfield(L,encodingname,font_encodingname(f));
+    }
+    dump_booleanfield(L,used,(font_used(f) ? true : false));
+    dump_stringfield(L,type,font_type_strings[font_type(f)]);
+    dump_stringfield(L,format,font_format_strings[font_format(f)]);
+    dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
+    dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
+    dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
+    dump_intfield(L,streamprovider,font_streamprovider(f));
+    dump_intfield(L,units_per_em,font_units_per_em(f));
+    dump_intfield(L,size,font_size(f));
+    dump_intfield(L,designsize,font_dsize(f));
+    dump_intfield(L,checksum,font_checksum(f));
+    dump_intfield(L,slant,font_slant(f));
+    dump_intfield(L,extend,font_extend(f));
+    dump_intfield(L,squeeze,font_squeeze(f));
+    dump_intfield(L,mode,font_mode(f));
+    dump_intfield(L,width,font_width(f));
+    dump_intfield(L,direction,font_natural_dir(f));
+    dump_intfield(L,encodingbytes,font_encodingbytes(f));
+    dump_booleanfield(L,oldmath,font_oldmath(f));
+    dump_intfield(L,tounicode,font_tounicode(f));
+    /*tex The next one is read only: */
+    if (font_max_shrink(f) != 0) {
+        dump_intfield(L,shrink,font_max_shrink(f));
+    }
+    if (font_max_stretch(f) != 0) {
+        dump_intfield(L,stretch,font_max_stretch(f));
+    }
+    if (font_step(f) != 0) {
+        dump_intfield(L,step,font_step(f));
+    }
+    if (pdf_font_attr(f) != 0) {
+        char *s = makecstring(pdf_font_attr(f));
+        dump_stringfield(L,attributes,s);
+        free(s);
+    }
+    /*tex Parameters: */
+    write_lua_parameters(L, f);
+    write_lua_math_parameters(L, f);
+    /*tex Characters: */
+    lua_push_string_by_name(L,characters);
+    lua_createtable(L, font_tables[f]->charinfo_size, 0);
+    if (has_left_boundary(f)) {
+        co = get_charinfo(f, left_boundarychar);
+        lua_push_string_by_name(L,left_boundary);
+        font_char_to_lua(L, f, co);
+        lua_rawset(L, -3);
+    }
+    if (has_right_boundary(f)) {
+        co = get_charinfo(f, right_boundarychar);
+        lua_push_string_by_name(L,right_boundary);
+        font_char_to_lua(L, f, co);
+        lua_rawset(L, -3);
+    }
+    for (k = font_bc(f); k <= font_ec(f); k++) {
+        if (quick_char_exists(f, k)) {
+            lua_pushinteger(L, k);
+            co = get_charinfo(f, k);
+            font_char_to_lua(L, f, co);
+            lua_rawset(L, -3);
+        }
+    }
+    lua_rawset(L, -3);
+    if (font_cache_id(f) == 0) {
+        /*tex Renew the cache. */
+        int r;
+        lua_pushvalue(L, -1);
+        r = luaL_ref(L, LUA_REGISTRYINDEX);
+        set_font_cache_id(f, r);
+    }
+    return 1;
+}
+
+#define count_hash_items(L,name,n) \
+    n = 0; \
+    lua_key_rawgeti(name); \
+    if (lua_type(L, -1) == LUA_TTABLE) { \
+        lua_pushnil(L); \
+        while (lua_next(L, -2) != 0) { \
+            n++; \
+            lua_pop(L, 1); \
+        } \
+    } \
+    if (n) { \
+        /*tex Keep the table on stack. */ \
+    } else{ \
+        lua_pop(L, 1); \
+    }
+
+#define streq(a,b) (strcmp(a,b)==0)
+
+#define append_packet(k) { *(cp++) = (eight_bits) (k); }
+
+#define do_store_four(l) {                 \
+    append_packet((l & 0xFF000000) >> 24); \
+    append_packet((l & 0x00FF0000) >> 16); \
+    append_packet((l & 0x0000FF00) >> 8);  \
+    append_packet((l & 0x000000FF));       \
+}
+
+static void append_float(eight_bits ** cpp, float a)
+{
+    unsigned int i;
+    eight_bits *cp = *cpp;
+    union U {
+        float a;
+        eight_bits b[sizeof(float)];
+    } u;
+    u.a = a;
+    for (i = 0; i < sizeof(float); i++)
+        append_packet(u.b[i]);
+    *cpp = cp;
+}
+
+static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
+{
+    int k, t;
+    const char *s;
+    int i = dflt;
+    /*tex Fetch the string pointer: */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+    lua_rawget(L, -2);
+    t = lua_type(L,-1);
+    if (t == LUA_TNUMBER) {
+        i = (int) lua_tointeger(L, -1);
+    } else if (t == LUA_TSTRING) {
+        s = lua_tostring(L, -1);
+        k = 0;
+        while (values[k] != NULL) {
+            if (strcmp(values[k], s) == 0) {
+                i = k;
+                break;
+            }
+            k++;
+        }
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static int n_boolean_field(lua_State * L, int name_index, int dflt)
+{
+    int i = dflt;
+    /*tex Fetch the string pointer: */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+    lua_rawget(L, -2);
+    if (lua_isboolean(L, -1)) {
+        i = lua_toboolean(L, -1);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
+{
+    char *i;
+    /*tex Fetch the string pointer: */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+    lua_rawget(L, -2);
+    if (lua_type(L,-1) == LUA_TSTRING) {
+        i = xstrdup(lua_tostring(L, -1));
+    } else if (dflt == NULL) {
+        i = NULL;
+    } else {
+        i = xstrdup(dflt);
+    }
+    lua_pop(L, 1);
+    return i;
+}
+
+static const char *n_string_field(lua_State * L, int name_index)
+{
+    /*tex Fetch the string pointer: */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+    lua_rawget(L, -2);
+    return lua_tostring(L,-1);
+}
+
+static int n_some_field(lua_State * L, int name_index)
+{
+    /*tex Fetch the string pointer: */
+    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
+    lua_rawget(L, -2);
+    return lua_type(L,-1);
+}
+
+static int count_char_packet_bytes(lua_State * L)
+{
+    register int i;
+    register int ts;
+    register int l = 0;
+    int ff = 0;
+    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+        lua_rawgeti(L, -1, i);
+        if (lua_istable(L, -1)) {
+            lua_rawgeti(L, -1, 1);
+            if (lua_type(L,-1) == LUA_TSTRING) {
+                const char *s = lua_tostring(L, -1);
+                if (lua_key_eq(s, font)) {
+                    l += 5;
+                    ff = 1;
+                } else if (lua_key_eq(s, char)) {
+                    if (ff == 0) {
+                        l += 5;
+                    }
+                    l += 5;
+                    ff = 1;
+                } else if (lua_key_eq(s, slot)) {
+                    l += 10;
+                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+                    ;
+                } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
+                    l++;
+                } else if (lua_key_eq(s, rule)) {
+                    l += 9;
+                } else if (lua_key_eq(s, right) || lua_key_eq(s, node) || lua_key_eq(s, down) || lua_key_eq(s, image) || lua_key_eq(s, lua)) {
+                    l += 5;
+                } else if (lua_key_eq(s, scale)) {
+                    l += sizeof(float) + 1;
+                } else if (lua_key_eq(s, pdf)) {
+                    size_t len;
+                    l += 5;
+                    ts = lua_rawlen(L, -2);
+                    lua_rawgeti(L, -2, 2);
+                    if (ts == 3) {
+                        if (lua_type(L,-1) == LUA_TSTRING) {
+                            /*tex There is no need to do something. */
+                        } else if (lua_type(L,-1) == LUA_TNUMBER) {
+                            /*tex There is no need to do something. */
+                        } else {
+                            normal_error("vf command","invalid packet pdf literal category");
+                        }
+                        lua_rawgeti(L, -3, 3);
+                    }
+                    if (lua_type(L,-1) == LUA_TSTRING) {
+                        (void) lua_tolstring(L, -1, &len);
+                        if (len > 0) {
+                            l = (int) (l + 5 + (int) len);
+                        }
+                    } else {
+                        normal_error("vf command","invalid packet pdf literal");
+                    }
+                    lua_pop(L, ts == 3 ? 2 : 1);
+                } else if (lua_key_eq(s, special)) {
+                    size_t len;
+                    lua_rawgeti(L, -2, 2);
+                    if (lua_type(L,-1) == LUA_TSTRING) {
+                        (void) lua_tolstring(L, -1, &len);
+                        if (len > 0) {
+                            l = (int) (l + 5 + (int) len);
+                        }
+                    } else {
+                        normal_error("vf command","invalid packet special");
+                    }
+                    lua_pop(L, 1);
+                } else {
+                    normal_error("vf command","unknown packet command");
+                }
+            } else {
+                normal_error("vf command","no packet command");
+            }
+            /*tex Pop the command name: */
+            lua_pop(L, 1);
+        }
+        /*tex Pop this item: */
+        lua_pop(L, 1);
+    }
+    return l;
+}
+
+static scaled sp_to_dvi(halfword sp, halfword atsize)
+{
+    double result, mult;
+    mult = (double) (atsize / 65536.0);
+    result = (double) (sp * 16.0);
+    return floor(result / mult);
+}
+
+static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
+{
+    int i, n, m;
+    size_t l;
+    int cmd;
+    const char *s;
+    eight_bits *cpackets, *cp;
+    int ff = 0;
+    int sf = 0;
+    int ts = 0;
+    int max_f = 0;
+    int pc = count_char_packet_bytes(L);
+    if (pc <= 0)
+        return;
+    while (l_fonts[(max_f + 1)] != 0)
+        max_f++;
+    cp = cpackets = xmalloc((unsigned) (pc + 1));
+    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
+        lua_rawgeti(L, -1, i);
+        if (lua_istable(L, -1)) {
+            /*tex fetch the command code */
+            lua_rawgeti(L, -1, 1);
+            if (lua_type(L,-1) == LUA_TSTRING) {
+                s = lua_tostring(L, -1);
+                cmd = 0;
+                if (lua_key_eq(s, font)) {
+                    cmd = packet_font_code;
+                } else if (lua_key_eq(s, char)) {
+                    cmd = packet_char_code;
+                    if (ff == 0) {
+                        append_packet(packet_font_code);
+                        ff = l_fonts[1];
+                        do_store_four(ff);
+                    }
+                } else if (lua_key_eq(s, slot)) {
+                    /*tex we could be sparse but no real reason */
+                    cmd = packet_nop_code;
+                    lua_rawgeti(L, -2, 2);
+                    n = (int) lua_roundnumber(L, -1);
+                    if (n == 0) {
+                        sf = f;
+                    } else {
+                        sf = (n > max_f ? l_fonts[1] : l_fonts[n]);
+                    }
+                    lua_rawgeti(L, -3, 3);
+                    n = (int) lua_roundnumber(L, -1);
+                    lua_pop(L, 2);
+                    append_packet(packet_font_code);
+                    do_store_four(sf);
+                    append_packet(packet_char_code);
+                    do_store_four(n);
+                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
+                    cmd = packet_nop_code;
+                } else if (lua_key_eq(s, node)) {
+                    cmd = packet_node_code;
+                } else if (lua_key_eq(s, push)) {
+                    cmd = packet_push_code;
+                } else if (lua_key_eq(s, pop)) {
+                    cmd = packet_pop_code;
+                } else if (lua_key_eq(s, rule)) {
+                    cmd = packet_rule_code;
+                } else if (lua_key_eq(s, right)) {
+                    cmd = packet_right_code;
+                } else if (lua_key_eq(s, down)) {
+                    cmd = packet_down_code;
+                } else if (lua_key_eq(s, pdf)) {
+                    cmd = packet_pdf_code;
+                } else if (lua_key_eq(s, special)) {
+                    cmd = packet_special_code;
+                } else if (lua_key_eq(s, image)) {
+                    cmd = packet_image_code;
+                } else if (lua_key_eq(s, scale)) {
+                    cmd = packet_scale_code;
+                } else if (lua_key_eq(s, lua)) {
+                    cmd = packet_lua_code;
+                }
+                switch (cmd) {
+                    case packet_push_code:
+                    case packet_pop_code:
+                        append_packet(cmd);
+                        break;
+                    case packet_font_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) lua_roundnumber(L, -1);
+                        if (n == 0) {
+                            ff = n;
+                        } else {
+                            ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
+                        }
+                        do_store_four(ff);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_node_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = copy_node_list(nodelist_from_lua(L,-1));
+                        do_store_four(n);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_char_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) lua_roundnumber(L, -1);
+                        do_store_four(n);
+                        lua_pop(L, 1);
+                        break;
+                    case packet_right_code:
+                    case packet_down_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) lua_roundnumber(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_pop(L, 1);
+                        break;
+                    case packet_rule_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = (int) lua_roundnumber(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_rawgeti(L, -3, 3);
+                        n = (int) lua_roundnumber(L, -1);
+                        do_store_four(sp_to_dvi(n, atsize));
+                        lua_pop(L, 2);
+                        break;
+                    case packet_pdf_code:
+                        ts = (int) lua_rawlen(L, -2);
+                        lua_rawgeti(L, -2, 2);
+                        if (ts == 3) {
+                            /*tex mode on stack */
+                            s = lua_tostring(L, -1);
+                            if (lua_type(L, -1) == LUA_TSTRING) {
+                                /*tex |<pdf> <mode> <direct|page|text|raw|origin>| */
+                                if (lua_key_eq(s, mode)) {
+                                    cmd = packet_pdf_mode;
+                                    lua_rawgeti(L, -3, 3);
+                                    /*tex mode on stack */
+                                    s = lua_tostring(L, -1);
+                                }
+                            } else {
+                                /*tex |<pdf> <direct|page|text|raw|origin> <string>| */
+                            }
+                            if (lua_type(L, -1) == LUA_TSTRING) {
+                                if (lua_key_eq(s, direct)) {
+                                    n = direct_always;
+                                } else if (lua_key_eq(s, page)) {
+                                    n = direct_page;
+                                } else if (lua_key_eq(s, text)) {
+                                    n = direct_text;
+                                } else if (lua_key_eq(s, font)) {
+                                    n = direct_font;
+                                } else if (lua_key_eq(s, raw)) {
+                                    n = direct_raw;
+                                } else if (lua_key_eq(s, origin)) {
+                                    n = set_origin;
+                                } else {
+                                    n = set_origin ;
+                                }
+                            } else {
+                                n = (int) lua_roundnumber(L, -1);
+                                if (n < set_origin || n >= scan_special) {
+                                    n = set_origin ;
+                                }
+                            }
+                            if (cmd == packet_pdf_code) {
+                                /*tex string on stack */
+                                lua_rawgeti(L, -3, 3);
+                            }
+                        } else {
+                            n = set_origin;
+                        }
+                        append_packet(cmd);
+                        do_store_four(n);
+                        if (cmd == packet_pdf_code) {
+                            s = luaL_checklstring(L, -1, &l);
+                            do_store_four(l);
+                            if (l > 0) {
+                                m = (int) l;
+                                while (m > 0) {
+                                    n = *s++;
+                                    m--;
+                                    append_packet(n);
+                                }
+                            }
+                        }
+                        lua_pop(L,ts == 3 ? 2 : 1);
+                        break;
+                    case packet_special_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        s = luaL_checklstring(L, -1, &l);
+                        if (l > 0) {
+                            do_store_four(l);
+                            m = (int) l;
+                            while (m > 0) {
+                                n = *s++;
+                                m--;
+                                append_packet(n);
+                            }
+                        }
+                        lua_pop(L, 1);
+                        break;
+                    case packet_lua_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        n = luaL_ref(L, LUA_REGISTRYINDEX);
+                        do_store_four(n);
+                        break;
+                    case packet_image_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        if (lua_istable(L, -1)) {
+                            lua_getglobal(L, "img");
+                            lua_pushstring(L, "new");
+                            lua_gettable(L, -2);
+                            lua_insert(L, -3);
+                            lua_pop(L, 1);
+                            lua_call(L, 1, 1);
+                        }
+                        luaL_checkudata(L, -1, TYPE_IMG);
+                        n = luaL_ref(L, LUA_REGISTRYINDEX);
+                        do_store_four(n);
+                        break;
+                    case packet_nop_code:
+                        break;
+                    case packet_scale_code:
+                        append_packet(cmd);
+                        lua_rawgeti(L, -2, 2);
+                        append_float(&cp, (float) luaL_checknumber(L, -1));
+                        lua_pop(L, 1);
+                        break;
+                    default:
+                        normal_error("vf command","invalid packet code");
+                }
+            }
+            /*tex Command code: */
+            lua_pop(L, 1);
+        } else {
+            normal_error("vf command","commands has to be a table");
+        }
+        /*tex Command table: */
+        lua_pop(L, 1);
+    }
+    append_packet(packet_end_code);
+    set_charinfo_packets(co, cpackets);
+    return;
+}
+
+static void read_lua_cidinfo(lua_State * L, int f)
+{
+    int i;
+    char *s;
+    lua_key_rawgeti(cidinfo);
+    if (lua_istable(L, -1)) {
+        i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
+        set_font_cidversion(f, i);
+        i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
+        set_font_cidsupplement(f, i);
+        s = n_string_field_copy(L, lua_key_index(registry), "Adobe");
+        set_font_cidregistry(f, s);
+        s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
+        set_font_cidordering(f, s);
+    }
+    lua_pop(L, 1);
+}
+
+static void read_lua_parameters(lua_State * L, int f)
+{
+    int i, n, t;
+    const char *s;
+    lua_key_rawgeti(parameters);
+    if (lua_istable(L, -1)) {
+        /*tex The number of parameters is the |max(IntegerKeys(L)),7)| */
+        n = 7;
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            if (lua_type(L, -2) == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+                if (i > n)
+                    n = i;
+            }
+            lua_pop(L, 1);
+        }
+        if (n > 7)
+            set_font_params(f, n);
+        /*tex Sometimes it is handy to have all integer keys: */
+        for (i = 1; i <= 7; i++) {
+            lua_rawgeti(L, -1, i);
+            if (lua_type(L, -1) == LUA_TNUMBER) {
+                n = lua_roundnumber(L, -1);
+                set_font_param(f, i, n);
+            }
+            lua_pop(L, 1);
+        }
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            t = lua_type(L,-2);
+            if (t == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+                if (i >= 8) {
+                    if (lua_type(L,-1) == LUA_TNUMBER) {
+                        n = lua_roundnumber(L, -1);
+                    } else {
+                        n = 0;
+                    }
+                    set_font_param(f, i, n);
+                }
+            } else if (t == LUA_TSTRING) {
+                s = lua_tostring(L, -2);
+                if (lua_type(L,-1) == LUA_TNUMBER) {
+                    n = lua_roundnumber(L, -1);
+                } else {
+                    n = 0;
+                }
+                if (lua_key_eq(s, slant)) {
+                    set_font_param(f, slant_code, n);
+                } else if (lua_key_eq(s, space)) {
+                    set_font_param(f, space_code, n);
+                } else if (lua_key_eq(s, space_stretch)) {
+                    set_font_param(f, space_stretch_code, n);
+                } else if (lua_key_eq(s, space_shrink)) {
+                    set_font_param(f, space_shrink_code, n);
+                } else if (lua_key_eq(s, x_height)) {
+                    set_font_param(f, x_height_code, n);
+                } else if (lua_key_eq(s, quad)) {
+                    set_font_param(f, quad_code, n);
+                } else if (lua_key_eq(s, extra_space)) {
+                    set_font_param(f, extra_space_code, n);
+                }
+            }
+            lua_pop(L, 1);
+        }
+    }
+    lua_pop(L, 1);
+
+}
+
+static void read_lua_math_parameters(lua_State * L, int f)
+{
+    int i = 0, n = 0, t;
+    lua_key_rawgeti(MathConstants);
+    if (lua_istable(L, -1)) {
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            t = lua_type(L,-2);
+            if (t == LUA_TNUMBER) {
+                i = (int) lua_tointeger(L, -2);
+            } else if (t == LUA_TSTRING) {
+                i = ff_checkoption(L, -2, NULL, MATH_param_names);
+            }
+            n = (int) lua_roundnumber(L, -1);
+            if (i > 0) {
+                set_font_math_param(f, i, n);
+            }
+            lua_pop(L, 1);
+        }
+        set_font_oldmath(f,false);
+    } else {
+        set_font_oldmath(f,true);
+    }
+    lua_pop(L, 1);
+}
+
+#define MIN_INF -0x7FFFFFFF
+
+static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
+{
+    int l, k;
+    scaled ht, krn;
+    lua_key_direct_rawgeti(index);
+    if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
+        for (l = 0; l < k; l++) {
+            lua_rawgeti(L, -1, (l + 1));
+            if (lua_istable(L, -1)) {
+                ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
+                krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
+                if (krn > MIN_INF && ht > MIN_INF)
+                    add_charinfo_math_kern(co, id, ht, krn);
+            }
+            lua_pop(L, 1);
+        }
+    }
+    lua_pop(L, 1);
+}
+
+static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
+{
+    int k, r, t, lt, u, n;
+    charinfo *co;
+    kerninfo *ckerns;
+    liginfo *cligs;
+    scaled j;
+    const char *s;
+    /*tex The number of ligature table items: */
+    int nl = 0;
+    /*tex The number of kern table items: */
+    int nk = 0;
+    int ctr = 0;
+    int atsize = font_size(f);
+    if (lua_istable(L, -1)) {
+        co = get_charinfo(f, i);
+        set_charinfo_tag(co, 0);
+        j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
+        set_charinfo_width(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
+        set_charinfo_height(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
+        set_charinfo_depth(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
+        set_charinfo_italic(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
+        set_charinfo_vert_italic(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
+        set_charinfo_index(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
+        set_charinfo_ef(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
+        set_charinfo_lp(co, j);
+        j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
+        set_charinfo_rp(co, j);
+        k = n_boolean_field(L, lua_key_index(used), 0);
+        set_charinfo_used(co, k);
+        s = n_string_field(L, lua_key_index(name));
+        if (s != NULL)
+            set_charinfo_name(co, xstrdup(s));
+        else
+            set_charinfo_name(co, NULL);
+        /*tex |n_string_field| leaves a value on stack*/
+        lua_pop(L,1);
+        u = n_some_field(L,lua_key_index(tounicode));
+        if (u == LUA_TNUMBER) {
+            u = lua_tointeger(L,-1);
+            if (u < 0) {
+                set_charinfo_tounicode(co, NULL);
+            } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                char *s = malloc(5);
+                sprintf(s,"%04X",(unsigned int) u);
+                set_charinfo_tounicode(co,s);
+            } else {
+                char *s = malloc(11);
+                u = u - 0x10000;
+                sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+                set_charinfo_tounicode(co,s);
+            }
+        } else if (u == LUA_TTABLE) {
+            n = lua_rawlen(L,-1);
+            u = 0;
+            for (k = 1; k <= n; k++) {
+                lua_rawgeti(L, -1, k);
+                if (lua_type(L,-1) == LUA_TNUMBER) {
+                    u = lua_tointeger(L,-1);
+                } else {
+                    lua_pop(L, 1);
+                    break;
+                }
+                if (u < 0) {
+                    u = -1;
+                    lua_pop(L, 1);
+                    break;
+                } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                    u = u + 4;
+                } else {
+                    u = u + 8;
+                }
+                lua_pop(L, 1);
+            }
+            if (u>0) {
+                char *s = malloc(u+1);
+                char *t = s ;
+                for (k = 1; k <= n; k++) {
+                    lua_rawgeti(L, -1, k);
+                    u = lua_tointeger(L,-1);
+                    if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
+                        sprintf(t,"%04X",(unsigned int) u);
+                        t += 4;
+                    } else {
+                        u = u - 0x10000;
+                        sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
+                        t += 8;
+                    }
+                    lua_pop(L, 1);
+                }
+                set_charinfo_tounicode(co,s);
+            } else {
+                set_charinfo_tounicode(co, NULL);
+            }
+        } else if (u == LUA_TSTRING) {
+            s = lua_tostring(L,-1);
+            set_charinfo_tounicode(co, xstrdup(s));
+        } else {
+            set_charinfo_tounicode(co, NULL);
+        }
+        lua_pop(L,1);
+        if (has_math) {
+            j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
+            set_charinfo_top_accent(co, j);
+            j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
+            set_charinfo_bot_accent(co, j);
+            k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
+            if (k >= 0) {
+                set_charinfo_tag(co, list_tag);
+                set_charinfo_remainder(co, k);
+            }
+            lua_key_rawgeti(extensible);
+            if (lua_istable(L, -1)) {
+                int top, bot, mid, rep;
+                top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
+                bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
+                mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
+                rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
+                if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
+                    set_charinfo_tag(co, ext_tag);
+                    set_charinfo_extensible(co, top, bot, mid, rep);
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", font_name(f), (int) i);
+                }
+            }
+            lua_pop(L, 1);
+            lua_key_rawgeti(horiz_variants);
+            if (lua_istable(L, -1)) {
+                int glyph, startconnect, endconnect, advance, extender;
+                extinfo *h;
+                set_charinfo_tag(co, ext_tag);
+                set_charinfo_hor_variants(co, NULL);
+                for (k = 1;; k++) {
+                    lua_rawgeti(L, -1, k);
+                    if (lua_istable(L, -1)) {
+                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
+                        add_charinfo_hor_variant(co, h);
+                        lua_pop(L, 1);
+                    } else {
+                        lua_pop(L, 1);
+                        break;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+            lua_key_rawgeti(vert_variants);
+            if (lua_istable(L, -1)) {
+                int glyph, startconnect, endconnect, advance, extender;
+                extinfo *h;
+                set_charinfo_tag(co, ext_tag);
+                set_charinfo_vert_variants(co, NULL);
+                for (k = 1;; k++) {
+                    lua_rawgeti(L, -1, k);
+                    if (lua_istable(L, -1)) {
+                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
+                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
+                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
+                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
+                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
+                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
+                        add_charinfo_vert_variant(co, h);
+                        lua_pop(L, 1);
+                    } else {
+                        lua_pop(L, 1);
+                        break;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+            /*tex
+                Here is a complete example:
+
+                \starttyping
+                mathkern = {
+                     bottom_left  = { { height = 420, kern = 80  }, { height = 520, kern = 4   } },
+                     bottom_right = { { height = 0,   kern = 48  } },
+                     top_left     = { { height = 620, kern = 0   }, { height = 720, kern = -80 } },
+                     top_right    = { { height = 676, kern = 115 }, { height = 776, kern = 45  } },
+                }
+                \stoptyping
+
+            */
+            lua_key_rawgeti(mathkern);
+            if (lua_istable(L, -1)) {
+                store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
+                store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
+                store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
+                store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
+            }
+            lua_pop(L, 1);
+        }
+        /*tex end of |has_math| */
+        count_hash_items(L, kerns, nk);
+        if (nk > 0) {
+            /*tex The kerns table is still on stack. */
+            ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
+            ctr = 0;
+            /*tex Traverse the hash. */
+            lua_pushnil(L);
+            while (lua_next(L, -2) != 0) {
+                k = non_boundarychar;
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    /*tex Adjacent char: */
+                    k = (int) lua_tointeger(L, -2);
+                    if (k < 0)
+                        k = non_boundarychar;
+                } else if (lt == LUA_TSTRING) {
+                    s = lua_tostring(L, -2);
+                    if (lua_key_eq(s, right_boundary)) {
+                        k = right_boundarychar;
+                        if (!has_right_boundary(f))
+                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
+                    }
+                }
+                j = lua_roundnumber(L, -1);
+                if (k != non_boundarychar) {
+                    set_kern_item(ckerns[ctr], k, j);
+                    ctr++;
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field", font_name(f), (int) i);
+                }
+                lua_pop(L, 1);
+            }
+            /*tex A guard against empty tables. */
+            if (ctr > 0) {
+                set_kern_item(ckerns[ctr], end_kern, 0);
+                set_charinfo_kerns(co, ckerns);
+            } else {
+                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", font_name(f), (int) i);
+            }
+            lua_pop(L, 1);
+        }
+        /*tex Packet commands. */
+        lua_key_rawgeti(commands);
+        if (lua_istable(L, -1)) {
+            lua_pushnil(L);
+            if (lua_next(L, -2) != 0) {
+                lua_pop(L, 2);
+                read_char_packets(L, (int *) l_fonts, co, f, atsize);
+            }
+        }
+        lua_pop(L, 1);
+        /*tex The ligatures. */
+        count_hash_items(L, ligatures, nl);
+        if (nl > 0) {
+            /*tex The ligatures table still on stack. */
+            cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
+            ctr = 0;
+            /*tex Traverse the hash. */
+            lua_pushnil(L);
+            while (lua_next(L, -2) != 0) {
+                k = non_boundarychar;
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    /*tex Adjacent char: */
+                    k = (int) lua_tointeger(L, -2);
+                    if (k < 0) {
+                        k = non_boundarychar;
+                    }
+                } else if (lt == LUA_TSTRING) {
+                    s = lua_tostring(L, -2);
+                    if (lua_key_eq(s, right_boundary)) {
+                        k = right_boundarychar;
+                        if (!has_right_boundary(f))
+                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
+                    }
+                }
+                r = -1;
+                if (lua_istable(L, -1)) {
+                    /*tex Ligature: */
+                    r = lua_numeric_field_by_index(L, lua_key_index(char), -1);
+                }
+                if (r != -1 && k != non_boundarychar) {
+                    t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
+                    set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
+                    ctr++;
+                } else {
+                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field", font_name(f), (int) i);
+                }
+                /*tex The iterator value: */
+                lua_pop(L, 1);
+            }
+            /*tex A guard against empty tables. */
+            if (ctr > 0) {
+                set_ligature_item(cligs[ctr], 0, end_ligature, 0);
+                set_charinfo_ligatures(co, cligs);
+            } else {
+                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field", font_name(f), (int) i);
+            }
+            /*tex The ligatures table. */
+            lua_pop(L, 1);
+        }
+    }
+}
+
+/*tex
+
+    The caller has to fix the state of the lua stack when there is an error!
+
+*/
+
+int font_from_lua(lua_State * L, int f)
+{
+    int i, n, r, t, lt;
+    int s_top;
+    int bc;
+    int ec;
+    char *s;
+    const char *ss;
+    int *l_fonts = NULL;
+    int save_ref ;
+    boolean no_math = false;
+    /*tex Will we save a cache of the \LUA\ table? */
+    save_ref = 1;
+    ss = NULL;
+    ss = n_string_field(L, lua_key_index(cache));
+    if (lua_key_eq(ss, no))
+        save_ref = -1;
+    else if (lua_key_eq(ss, renew))
+        save_ref = 0;
+    /*tex |n_string_field| leaves a value on stack. */
+    lua_pop(L,1);
+    /*tex The table is at stack |index -1| */
+    s = n_string_field_copy(L,lua_key_index(area), "");
+    set_font_area(f, s);
+    s = n_string_field_copy(L, lua_key_index(filename), NULL);
+    set_font_filename(f, s);
+    s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
+    set_font_encodingname(f, s);
+    s = n_string_field_copy(L, lua_key_index(name), NULL);
+    set_font_name(f, s);
+    s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
+    set_font_fullname(f, s);
+    if (s == NULL) {
+        formatted_error("font","lua-loaded font '%d' has no name!", f);
+        return false;
+    }
+    s = n_string_field_copy(L, lua_key_index(psname), NULL);
+    set_font_psname(f, s);
+    i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
+    set_font_units_per_em(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
+    set_font_dsize(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
+    set_font_size(f, i);
+    set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
+    i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
+    set_font_natural_dir(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
+    set_font_encodingbytes(f, (char) i);
+    i = lua_numeric_field_by_index(L,lua_key_index(streamprovider), 0);
+    set_font_streamprovider(f, (char) i);
+    i = n_boolean_field(L,lua_key_index(oldmath), 0);
+    set_font_oldmath(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
+    set_font_tounicode(f, (char) i);
+    i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
+    if (i < FONT_SLANT_MIN)
+        i = FONT_SLANT_MIN;
+    if (i > FONT_SLANT_MAX)
+        i = FONT_SLANT_MAX;
+    set_font_slant(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
+    if (i < FONT_EXTEND_MIN)
+        i = FONT_EXTEND_MIN;
+    if (i > FONT_EXTEND_MAX)
+        i = FONT_EXTEND_MAX;
+    set_font_extend(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(squeeze), 1000);
+    if (i < FONT_SQUEEZE_MIN)
+        i = FONT_SQUEEZE_MIN;
+    if (i > FONT_SQUEEZE_MAX)
+        i = FONT_SQUEEZE_MAX;
+    set_font_squeeze(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(width), 0);
+    if (i < FONT_WIDTH_MIN)
+        i = FONT_WIDTH_MIN;
+    if (i > FONT_WIDTH_MAX)
+        i = FONT_WIDTH_MAX;
+    set_font_width(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(mode), 0);
+    if (i < FONT_MODE_MIN)
+        i = FONT_MODE_MIN;
+    if (i > FONT_MODE_MAX)
+        i = FONT_MODE_MAX;
+    set_font_mode(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
+    set_hyphen_char(f, i);
+    i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
+    set_skew_char(f, i);
+    i = n_boolean_field(L, lua_key_index(used), 0);
+    set_font_used(f, (char) i);
+    s = n_string_field_copy(L, lua_key_index(attributes), NULL);
+    if (s != NULL && strlen(s) > 0) {
+        i = maketexstring(s);
+        set_pdf_font_attr(f, i);
+    }
+    free(s);
+    i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
+    set_font_type(f, i);
+    i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
+    set_font_format(f, i);
+    i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
+    set_font_writingmode(f, i);
+    i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
+    set_font_identity(f, i);
+    i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
+    set_font_embedding(f, i);
+    if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
+        set_font_encodingbytes(f, 2);
+    }
+    /*tex Now fetch the base fonts, if needed. */
+    count_hash_items(L, fonts, n);
+    if (n > 0) {
+        /*tex The font table still on stack. */
+        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
+        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
+        for (i = 1; i <= n; i++) {
+            lua_rawgeti(L, -1, i);
+            if (lua_istable(L, -1)) {
+                lua_key_rawgeti(id);
+                if (lua_isnumber(L, -1)) {
+                    l_fonts[i] = (int) lua_tointeger(L, -1);
+                    if (l_fonts[i] == 0) {
+                        l_fonts[i] = (int) f;
+                    }
+                    /*tex Pop id and entry. */
+                    lua_pop(L, 2);
+                    continue;
+                }
+                /*tex Pop id. */
+                lua_pop(L, 1);
+            };
+            ss = NULL;
+            if (lua_istable(L, -1)) {
+                ss = n_string_field(L, lua_key_index(name));
+                /*tex The string is anchored. */
+                lua_pop(L,1);
+            }
+            if (ss != NULL) {
+                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
+                /*tex The stack is messed up, otherwise this explicit resizing would not be needed! */
+                s_top = lua_gettop(L);
+                if (strcmp(font_name(f), ss) == 0)
+                    l_fonts[i] = f;
+                else
+                    l_fonts[i] = find_font_id(ss, t);
+                lua_settop(L, s_top);
+            } else {
+                formatted_error("font","invalid local font at index %i in lua-loaded font '%s' (1)",i,font_name(f));
+            }
+            /*tex Pop the list entry. */
+            lua_pop(L, 1);
+        }
+        /*tex Pop the font table. */
+        lua_pop(L, 1);
+    } else if (font_type(f) == virtual_font_type) {
+        /*tex
+            We no longer do this check but instead create an entry. This permits
+            (valid) tricks.
+        */
+        /*
+        formatted_error("font","invalid local fonts in lua-loaded font '%s' (2)", font_name(f));
+        */
+    } else {
+        l_fonts = xmalloc(3 * sizeof(int));
+        l_fonts[0] = 0;
+        l_fonts[1] = f;
+        l_fonts[2] = 0;
+    }
+    /*tex The parameters. */
+    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
+    read_lua_parameters(L, f);
+    if (!no_math) {
+        read_lua_math_parameters(L, f);
+        if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
+            set_font_oldmath(f,true);
+        }
+
+    } else {
+        set_font_oldmath(f,true);
+    }
+    read_lua_cidinfo(L, f);
+    /*tex The characters. */
+    lua_key_rawgeti(characters);
+    if (lua_istable(L, -1)) {
+        /*tex Find the array size values; |num| holds the number of characters to add. */
+        int num = 0;
+        ec = 0;
+        bc = -1;
+        /*tex The first key: */
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            if (lua_isnumber(L, -2)) {
+                i = (int) lua_tointeger(L, -2);
+                if (i >= 0) {
+                    if (lua_istable(L, -1)) {
+                        num++;
+                        if (i > ec)
+                            ec = i;
+                        if (bc < 0)
+                            bc = i;
+                        if (bc >= 0 && i < bc)
+                            bc = i;
+                    }
+                }
+            }
+            lua_pop(L, 1);
+        }
+        if (bc != -1) {
+            int fstep;
+            font_malloc_charinfo(f, num);
+            set_font_bc(f, bc);
+            set_font_ec(f, ec);
+            /*tex The first key: */
+            lua_pushnil(L);
+            while (lua_next(L, -2) != 0) {
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    i = (int) lua_tointeger(L, -2);
+                    if (i >= 0) {
+                        font_char_from_lua(L, f, i, l_fonts, !no_math);
+                    }
+                } else if (lt == LUA_TSTRING) {
+                    const char *ss1 = lua_tostring(L, -2);
+                    if (lua_key_eq(ss1, left_boundary)) {
+                        font_char_from_lua(L, f, left_boundarychar, l_fonts, !no_math);
+                    } else if (lua_key_eq(ss1, right_boundary)) {
+                        font_char_from_lua(L, f, right_boundarychar, l_fonts, !no_math);
+                    }
+                }
+                lua_pop(L, 1);
+            }
+            lua_pop(L, 1);
+            /*tex
+
+                Handle font expansion last: the |copy_font| routine is called eventually,
+                and that needs to know |bc| and |ec|. We permits virtual fonts to use
+                expansion as one can always turn it off.
+
+            */
+            fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
+            if (fstep < 0)
+                fstep = 0;
+            if (fstep > 100)
+                fstep = 100;
+            if (fstep != 0) {
+                int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
+                int fstretch= lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
+                if (fshrink < 0)
+                    fshrink = 0;
+                if (fshrink > 500)
+                    fshrink = 500;
+                fshrink -= (fshrink % fstep);
+                if (fshrink < 0)
+                    fshrink = 0;
+                if (fstretch < 0)
+                    fstretch = 0;
+                if (fstretch > 1000)
+                    fstretch = 1000;
+                fstretch -= (fstretch % fstep);
+                if (fstretch < 0)
+                    fstretch = 0;
+                set_expand_params(f, fstretch, fshrink, fstep);
+            }
+
+        } else {
+            formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
+        }
+        if (save_ref > 0) {
+            /*tex This pops the table. */
+            r = luaL_ref(L, LUA_REGISTRYINDEX);
+            set_font_cache_id(f, r);
+        } else {
+            lua_pop(L, 1);
+            set_font_cache_id(f, save_ref);
+        }
+    } else {
+        formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
+    }
+    if (l_fonts != NULL)
+        free(l_fonts);
+    return true;
+}
+
+int characters_from_lua(lua_State * L, int f)
+{
+    int i, n, t, lt;
+    int *l_fonts = NULL;
+    int s_top;
+    const char *ss;
+    boolean no_math = false;
+    /*tex Speedup: */
+    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
+    /*tex Type: */
+    i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings);
+    set_font_type(f, i);
+    /*tex Fonts: */
+    count_hash_items(L, fonts, n);
+    if (n > 0) {
+        /*tex The font table still on stack. */
+        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
+        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
+        for (i = 1; i <= n; i++) {
+            lua_rawgeti(L, -1, i);
+            if (lua_istable(L, -1)) {
+                lua_key_rawgeti(id);
+                if (lua_isnumber(L, -1)) {
+                    l_fonts[i] = (int) lua_tointeger(L, -1);
+                    if (l_fonts[i] == 0) {
+                        l_fonts[i] = (int) f;
+                    }
+                    /*tex Pop id and entry. */
+                    lua_pop(L, 2);
+                    continue;
+                }
+                /*tex Pop id. */
+                lua_pop(L, 1);
+            };
+            ss = NULL;
+            if (lua_istable(L, -1)) {
+                ss = n_string_field(L, lua_key_index(name));
+                /* string is anchored */
+                lua_pop(L,1);
+            }
+            if (ss != NULL) {
+                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
+                /*tex the stack is messed up, otherwise this explicit resizing would not be needed! */
+                s_top = lua_gettop(L);
+                if (strcmp(font_name(f), ss) == 0)
+                    l_fonts[i] = f;
+                else
+                    l_fonts[i] = find_font_id(ss, t);
+                lua_settop(L, s_top);
+            } else {
+                formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f));
+            }
+            /*tex Pop list entry. */
+            lua_pop(L, 1);
+        }
+        /*tex Pop font table. */
+        lua_pop(L, 1);
+    } else if (font_type(f) == virtual_font_type) {
+        formatted_error("font","invalid local fonts in lua-loaded font '%s' (4)", font_name(f));
+    } else {
+        l_fonts = xmalloc(3 * sizeof(int));
+        l_fonts[0] = 0;
+        l_fonts[1] = f;
+        l_fonts[2] = 0;
+    }
+    /*tex The characters. */
+    lua_key_rawgeti(characters);
+    if (lua_istable(L, -1)) {
+        /*tex Find the array size values; |num| has the amount. */
+        int num = 0;
+        int todo = 0;
+        int bc = font_bc(f);
+        int ec = font_ec(f);
+        /*tex First key: */
+        lua_pushnil(L);
+        while (lua_next(L, -2) != 0) {
+            if (lua_isnumber(L, -2)) {
+                i = (int) lua_tointeger(L, -2);
+                if (i >= 0) {
+                    if (lua_istable(L, -1)) {
+                        todo++;
+                        if (! quick_char_exists(f,i)) {
+                            num++;
+                            if (i > ec)
+                                ec = i;
+                            if (bc < 0)
+                                bc = i;
+                            if (bc >= 0 && i < bc)
+                                bc = i;
+                        }
+                    }
+                }
+            }
+            lua_pop(L, 1);
+        }
+        if (todo > 0) {
+            font_malloc_charinfo(f, num);
+            set_font_bc(f, bc);
+            set_font_ec(f, ec);
+            /*tex First key: */
+            lua_pushnil(L);
+            while (lua_next(L, -2) != 0) {
+                lt = lua_type(L,-2);
+                if (lt == LUA_TNUMBER) {
+                    i = (int) lua_tointeger(L, -2);
+                    if (i >= 0) {
+                        if (quick_char_exists(f,i)) {
+                            charinfo *co = char_info(f, i);
+                            set_charinfo_name(co, NULL);
+                            set_charinfo_tounicode(co, NULL);
+                            set_charinfo_packets(co, NULL);
+                            set_charinfo_ligatures(co, NULL);
+                            set_charinfo_kerns(co, NULL);
+                            set_charinfo_vert_variants(co, NULL);
+                            set_charinfo_hor_variants(co, NULL);
+                        }
+                        font_char_from_lua(L, f, i, l_fonts, !no_math);
+                    }
+                }
+                lua_pop(L, 1);
+            }
+            lua_pop(L, 1);
+        }
+    }
+    if (l_fonts != NULL)
+        free(l_fonts);
+    return true;
+}
+
+/*tex Ligaturing starts here */
+
+static void nesting_append(halfword nest1, halfword newn)
+{
+    halfword tail = tlink(nest1);
+    if (tail == null) {
+        couple_nodes(nest1, newn);
+    } else {
+        couple_nodes(tail, newn);
+    }
+    tlink(nest1) = newn;
+}
+
+static void nesting_prepend(halfword nest1, halfword newn)
+{
+    halfword head = vlink(nest1);
+    couple_nodes(nest1, newn);
+    if (head == null) {
+        tlink(nest1) = newn;
+    } else {
+        couple_nodes(newn, head);
+    }
+}
+
+static void nesting_prepend_list(halfword nest1, halfword newn)
+{
+    halfword head = vlink(nest1);
+    couple_nodes(nest1, newn);
+    if (head == null) {
+        tlink(nest1) = tail_of_list(newn);
+    } else {
+        halfword tail = tail_of_list(newn);
+        couple_nodes(tail, head);
+    }
+}
+
+static int test_ligature(liginfo * lig, halfword left, halfword right)
+{
+    if (type(left) != glyph_node)
+        return 0;
+    if (font(left) != font(right))
+        return 0;
+    if (is_ghost(left) || is_ghost(right))
+        return 0;
+    *lig = get_ligature(font(left), character(left), character(right));
+    if (is_valid_ligature(*lig)) {
+        return 1;
+    }
+    return 0;
+}
+
+static int try_ligature(halfword * frst, halfword fwd)
+{
+    halfword cur = *frst;
+    liginfo lig;
+    if (test_ligature(&lig, cur, fwd)) {
+        int move_after = (lig_type(lig) & 0x0C) >> 2;
+        int keep_right = ((lig_type(lig) & 0x01) != 0);
+        int keep_left = ((lig_type(lig) & 0x02) != 0);
+        halfword newgl = raw_glyph_node();
+        font(newgl) = font(cur);
+        character(newgl) = lig_replacement(lig);
+        set_is_ligature(newgl);
+        /*tex
+            Below might not be correct in contrived border case. but we use it
+            only for debugging.
+        */
+        if (character(cur) < 0) {
+            set_is_leftboundary(newgl);
+        }
+        if (character(fwd) < 0) {
+            set_is_rightboundary(newgl);
+        }
+        if (character(cur) < 0) {
+            if (character(fwd) < 0) {
+                build_attribute_list(newgl);
+            } else {
+                add_node_attr_ref(node_attr(fwd));
+                node_attr(newgl) = node_attr(fwd);
+            }
+        } else {
+            add_node_attr_ref(node_attr(cur));
+            node_attr(newgl) = node_attr(cur);
+        }
+        /*tex
+            Maybe if this ligature is consists of another ligature we should add
+            it's |lig_ptr| to the new glyphs |lig_ptr| (and cleanup the no longer
+            needed node). This has a very low priority, so low that it might
+            never happen.
+        */
+        /*tex Left side: */
+        if (keep_left) {
+            halfword new_first = copy_node(cur);
+            lig_ptr(newgl) = new_first;
+            couple_nodes(cur, newgl);
+            if (move_after) {
+                move_after--;
+                cur = newgl;
+            }
+        } else {
+            halfword prev = alink(cur);
+            uncouple_node(cur);
+            lig_ptr(newgl) = cur;
+            couple_nodes(prev, newgl);
+            cur = newgl;        /* as cur has disappeared */
+        }
+        /*tex Right side: */
+        if (keep_right) {
+            halfword new_second = copy_node(fwd);
+            /*tex This is correct, because we {\em know} |lig_ptr| points to {\em one} node. */
+            couple_nodes(lig_ptr(newgl), new_second);
+            couple_nodes(newgl, fwd);
+            if (move_after) {
+                move_after--;
+                cur = fwd;
+            }
+        } else {
+            halfword next = vlink(fwd);
+            uncouple_node(fwd);
+            /*tex This works because we {\em know} |lig_ptr| points to {\em one} node. */
+            couple_nodes(lig_ptr(newgl), fwd);
+            if (next != null) {
+                couple_nodes(newgl, next);
+            }
+        }
+        /*tex Check and return. */
+        *frst = cur;
+        return 1;
+    }
+    return 0;
+}
+
+/*tex
+
+    There shouldn't be any ligatures here - we only add them at the end of
+    |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing
+    \.{DISC-1} (we continue with \.{DISC-1}'s |post_| and |no_break|.
+
+*/
+
+static halfword handle_lig_nest(halfword root, halfword cur)
+{
+    if (cur == null)
+        return root;
+    while (vlink(cur) != null) {
+        halfword fwd = vlink(cur);
+        if (type(cur) == glyph_node && type(fwd) == glyph_node &&
+                font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
+            continue;
+        }
+        cur = vlink(cur);
+    }
+    tlink(root) = cur;
+    return root;
+}
+
+static halfword handle_lig_word(halfword cur)
+{
+    halfword right = null;
+    if (type(cur) == boundary_node) {
+        halfword prev = alink(cur);
+        halfword fwd = vlink(cur);
+        /*tex There is no need to uncouple |cur|, it is freed. */
+        flush_node(cur);
+        if (fwd == null) {
+            vlink(prev) = fwd;
+            return prev;
+        }
+        couple_nodes(prev, fwd);
+        if (type(fwd) != glyph_node)
+            return prev;
+        cur = fwd;
+    } else if (has_left_boundary(font(cur))) {
+        halfword prev = alink(cur);
+        halfword p = new_glyph(font(cur), left_boundarychar);
+        couple_nodes(prev, p);
+        couple_nodes(p, cur);
+        cur = p;
+    }
+    if (has_right_boundary(font(cur))) {
+        right = new_glyph(font(cur), right_boundarychar);
+    }
+    while (1) {
+        /*tex A glyph followed by \unknown */
+        if (type(cur) == glyph_node) {
+            halfword fwd = vlink(cur);
+            if (fwd == null) {
+                /*tex The last character of a paragraph. */
+                if (right == null)
+                    break;
+                /*tex |par| prohibits the use of |couple_nodes| here. */
+                try_couple_nodes(cur, right);
+                right = null;
+                continue;
+            }
+            if (type(fwd) == glyph_node) {
+                /*tex a glyph followed by a glyph */
+                if (font(cur) != font(fwd))
+                    break;
+                if (try_ligature(&cur, fwd))
+                    continue;
+            } else if (type(fwd) == disc_node) {
+                /*tex a glyph followed by a disc */
+                halfword pre = vlink_pre_break(fwd);
+                halfword nob = vlink_no_break(fwd);
+                halfword next, tail;
+                liginfo lig;
+                /*tex Check on: |a{b?}{?}{?}| and |a+b=>B| : |{B?}{?}{a?}| */
+                /*tex Check on: |a{?}{?}{b?}| and |a+b=>B| : |{a?}{?}{B?}| */
+                if ((pre != null && type(pre) == glyph_node && test_ligature(&lig, cur, pre))
+                       || (nob != null && type(nob) == glyph_node && test_ligature(&lig, cur, nob))) {
+                    /*tex Move |cur| from before disc to skipped part */
+                    halfword prev = alink(cur);
+                    uncouple_node(cur);
+                    couple_nodes(prev, fwd);
+                    nesting_prepend(no_break(fwd), cur);
+                    /*tex Now ligature the |pre_break|. */
+                    nesting_prepend(pre_break(fwd), copy_node(cur));
+                    /*tex As we have removed cur, we need to start again. */
+                    cur = prev;
+                }
+                /*tex Check on: |a{?}{?}{}b| and |a+b=>B| : |{a?}{?b}{B}|. */
+                next = vlink(fwd);
+                if (nob == null && next != null && type(next) == glyph_node && test_ligature(&lig, cur, next)) {
+                    /*tex Move |cur| from before |disc| to |no_break| part. */
+                    halfword prev = alink(cur);
+                    uncouple_node(cur);
+                    couple_nodes(prev, fwd);
+                    /*tex We {\em know} it's empty. */
+                    couple_nodes(no_break(fwd), cur);
+                    /*tex Now copy |cur| the |pre_break|. */
+                    nesting_prepend(pre_break(fwd), copy_node(cur));
+                    /*tex Move next from after disc to |no_break| part. */
+                    tail = vlink(next);
+                    uncouple_node(next);
+                    try_couple_nodes(fwd, tail);
+                    /*tex We {\em know} this works. */
+                    couple_nodes(cur, next);
+                    /*tex Make sure the list is correct. */
+                    tlink(no_break(fwd)) = next;
+                    /*tex Now copy next to the |post_break|. */
+                    nesting_append(post_break(fwd), copy_node(next));
+                    /*tex As we have removed cur, we need to start again. */
+                    cur = prev;
+                }
+                /*tex We are finished with the |pre_break|. */
+                handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
+            } else if (type(fwd) == boundary_node) {
+                halfword next = vlink(fwd);
+                try_couple_nodes(cur, next);
+                flush_node(fwd);
+                if (right != null) {
+                    /*tex Shame, didn't need it. */
+                    flush_node(right);
+                    /*tex No need to reset |right|, we're going to leave the loop anyway. */
+                }
+                break;
+            } else {
+                /*tex Is something unknown. */
+                if (right == null)
+                    break;
+                couple_nodes(cur, right);
+                couple_nodes(right, fwd);
+                right = null;
+                continue;
+            }
+            /*tex A discretionary followed by \unknown */
+        } else if (type(cur) == disc_node) {
+            /*tex If |{?}{x}{?}| or |{?}{?}{y}| then: */
+            if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
+                halfword prev = 0;
+                halfword fwd;
+                liginfo lig;
+                if (subtype(cur) == select_disc) {
+                    prev = alink(cur);
+                    if (vlink_post_break(cur) != null)
+                        handle_lig_nest(post_break(prev), vlink_post_break(prev));
+                    if (vlink_no_break(cur) != null)
+                        handle_lig_nest(no_break(prev), vlink_no_break(prev));
+                }
+                if (vlink_post_break(cur) != null)
+                    handle_lig_nest(post_break(cur), vlink_post_break(cur));
+                if (vlink_no_break(cur) != null)
+                    handle_lig_nest(no_break(cur), vlink_no_break(cur));
+                while ((fwd = vlink(cur)) != null) {
+                    halfword nob, pst, next;
+                    if (type(fwd) != glyph_node)
+                        break;
+                    if (subtype(cur) != select_disc) {
+                        nob = tlink_no_break(cur);
+                        pst = tlink_post_break(cur);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            break;
+                        nesting_append(no_break(cur), copy_node(fwd));
+                        handle_lig_nest(no_break(cur), nob);
+                    } else {
+                        int dobreak = 0;
+                        nob = tlink_no_break(prev);
+                        pst = tlink_post_break(prev);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            dobreak = 1;
+                        if (!dobreak) {
+                            nesting_append(no_break(prev), copy_node(fwd));
+                            handle_lig_nest(no_break(prev), nob);
+                            nesting_append(post_break(prev), copy_node(fwd));
+                            handle_lig_nest(post_break(prev), pst);
+                        }
+                        dobreak = 0;
+                        nob = tlink_no_break(cur);
+                        pst = tlink_post_break(cur);
+                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
+                            (pst == null || !test_ligature(&lig, pst, fwd)))
+                            dobreak = 1;
+                        if (!dobreak) {
+                            nesting_append(no_break(cur), copy_node(fwd));
+                            handle_lig_nest(no_break(cur), nob);
+                        }
+                        if (dobreak)
+                            break;
+                    }
+                    next = vlink(fwd);
+                    uncouple_node(fwd);
+                    try_couple_nodes(cur, next);
+                    nesting_append(post_break(cur), fwd);
+                    handle_lig_nest(post_break(cur), pst);
+                }
+                if (fwd != null && type(fwd) == disc_node) {
+                        halfword next = vlink(fwd);
+                        if (vlink_no_break(fwd) == null
+                        && vlink_post_break(fwd) == null
+                        && next != null
+                        && type(next) == glyph_node
+                        && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
+                            (tlink_no_break  (cur) != null && test_ligature(&lig, tlink_no_break  (cur), next)))) {
+                        /*tex Building an |init_disc| followed by a |select_disc|: |{a-}{b}{AB} {-}{}{} c| */
+  		        halfword last1 = vlink(next), tail;
+                        uncouple_node(next);
+                        try_couple_nodes(fwd, last1);
+                        /*tex |{a-}{b}{AB} {-}{c}{}| */
+                        nesting_append(post_break(fwd), copy_node(next));
+                        /*tex |{a-}{b}{AB} {-}{c}{-}| */
+                        if (vlink_no_break(cur) != null) {
+                            nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
+                        }
+                        /*tex |{a-}{b}{AB} {b-}{c}{-}| */
+                        if (vlink_post_break(cur) != null)
+                            nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
+                        /*tex |{a-}{b}{AB} {b-}{c}{AB-}| */
+                        if (vlink_no_break(cur) != null) {
+                            nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
+                        }
+                        /*tex |{a-}{b}{ABC} {b-}{c}{AB-}| */
+                        tail = tlink_no_break(cur);
+                        nesting_append(no_break(cur), copy_node(next));
+                        handle_lig_nest(no_break(cur), tail);
+                        /*tex |{a-}{BC}{ABC} {b-}{c}{AB-}| */
+                        tail = tlink_post_break(cur);
+                        nesting_append(post_break(cur), next);
+                        handle_lig_nest(post_break(cur), tail);
+                        /*tex Set the subtypes: */
+                        subtype(cur) = init_disc;
+                        subtype(fwd) = select_disc;
+                    }
+                }
+            }
+
+        } else {
+            /*tex We have glyph nor disc. */
+            return cur;
+        }
+        /*tex Goto the next node, where |\par| allows |vlink(cur)| to be NULL. */
+        cur = vlink(cur);
+    }
+    return cur;
+}
+
+/*tex The return value is the new tail, head should be a dummy: */
+
+halfword handle_ligaturing(halfword head, halfword tail)
+{
+    /*tex A trick to allow explicit |node==null| tests. */
+    halfword save_tail1 = null;
+    halfword cur, prev;
+    if (vlink(head) == null)
+        return tail;
+    if (tail != null) {
+        save_tail1 = vlink(tail);
+        vlink(tail) = null;
+    }
+    if (fix_node_lists) {
+        fix_node_list(head);
+    }
+    prev = head;
+    cur = vlink(prev);
+    while (cur != null) {
+        if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
+            cur = handle_lig_word(cur);
+        }
+        prev = cur;
+        cur = vlink(cur);
+    }
+    if (prev == null) {
+        prev = tail;
+    }
+    if (tail != null) {
+        try_couple_nodes(prev, save_tail1);
+    }
+    return prev;
+}
+
+
+/*tex Kerning starts here: */
+
+static void add_kern_before(halfword left, halfword right)
+{
+    if ((!is_rightghost(right)) &&
+        font(left) == font(right) && has_kern(font(left), character(left))) {
+        int k = raw_get_kern(font(left), character(left), character(right));
+        if (k != 0) {
+            halfword kern = new_kern(k);
+            halfword prev = alink(right);
+            couple_nodes(prev, kern);
+            couple_nodes(kern, right);
+            /*tex Update the attribute list (inherit from left): */
+            delete_attribute_ref(node_attr(kern));
+            add_node_attr_ref(node_attr(left));
+            node_attr(kern) = node_attr(left);
+        }
+    }
+}
+
+static void add_kern_after(halfword left, halfword right, halfword aft)
+{
+    if ((!is_rightghost(right)) &&
+        font(left) == font(right) && has_kern(font(left), character(left))) {
+        int k = raw_get_kern(font(left), character(left), character(right));
+        if (k != 0) {
+            halfword kern = new_kern(k);
+            halfword next = vlink(aft);
+            couple_nodes(aft, kern);
+            try_couple_nodes(kern, next);
+            /*tex Update the attribute list (inherit from left == aft): */
+            delete_attribute_ref(node_attr(kern));
+            add_node_attr_ref(node_attr(aft));
+            node_attr(kern) = node_attr(aft);
+        }
+    }
+}
+
+static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
+{
+    halfword cur = vlink(root);
+    halfword left = null;
+    if (cur == null) {
+        if (init_left != null && init_right != null) {
+            add_kern_after(init_left, init_right, root);
+            tlink(root) = vlink(root);
+        }
+        return;
+    }
+    if (type(cur) == glyph_node) {
+        set_is_glyph(cur);
+        if (init_left != null)
+            add_kern_before(init_left, cur);
+        left = cur;
+    }
+    while ((cur = vlink(cur)) != null) {
+        if (type(cur) == glyph_node) {
+            set_is_glyph(cur);
+            if (left != null) {
+                add_kern_before(left, cur);
+                if (character(left) < 0 || is_ghost(left)) {
+                    halfword prev = alink(left);
+                    couple_nodes(prev, cur);
+                    flush_node(left);
+                }
+            }
+            left = cur;
+        } else {
+            if (type(cur) == disc_node) {
+                halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
+                do_handle_kerning(pre_break(cur), left, null);
+                if (vlink_pre_break(cur) != null)
+                    tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
+                do_handle_kerning(post_break(cur), null, right);
+                if (vlink_post_break(cur) != null)
+                    tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
+                do_handle_kerning(no_break(cur), left, right);
+                if (vlink_no_break(cur) != null)
+                    tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));
+            }
+            if (left != null) {
+                if (character(left) < 0 || is_ghost(left)) {
+                    halfword prev = alink(left);
+                    couple_nodes(prev, cur);
+                    flush_node(left);
+                }
+                left = null;
+            }
+        }
+    }
+    if (left != null) {
+        if (init_right != null)
+            add_kern_after(left, init_right, left);
+        if (character(left) < 0 || is_ghost(left)) {
+            halfword prev = alink(left);
+            halfword next = vlink(left);
+            if (next != null) {
+                couple_nodes(prev, next);
+                tlink(root) = next;
+            } else if (prev != root) {
+                vlink(prev) = null;
+                tlink(root) = prev;
+            } else {
+                vlink(root) = null;
+                tlink(root) = null;
+            }
+            flush_node(left);
+        }
+    }
+}
+
+halfword handle_kerning(halfword head, halfword tail)
+{
+    halfword save_link = null;
+    if (tail == null) {
+        tlink(head) = null;
+        do_handle_kerning(head, null, null);
+    } else {
+        save_link = vlink(tail);
+        vlink(tail) = null;
+        tlink(head) = tail;
+        do_handle_kerning(head, null, null);
+        tail = tlink(head);
+        if (valid_node(save_link)) {
+            try_couple_nodes(tail, save_link);
+        }
+    }
+    return tail;
+}
+
+/*tex The ligaturing and kerning \LUA\ interface: */
+
+static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
+{
+    int i;
+    int top = lua_gettop(Luas);
+    if (!get_callback(Luas, callback_id)) {
+        lua_settop(Luas, top);
+        return tail;
+    }
+    nodelist_to_lua(Luas, head);
+    nodelist_to_lua(Luas, tail);
+    if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
+        formatted_warning("ligkern","error: %s",lua_tostring(Luas, -1));
+        lua_settop(Luas, top);
+        luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+        return tail;
+    }
+    if (fix_node_lists) {
+        fix_node_list(head);
+    }
+    lua_settop(Luas, top);
+    return tail;
+}
+
+halfword new_ligkern(halfword head, halfword tail)
+{
+    int callback_id = 0;
+    if (vlink(head) == null)
+        return tail;
+    callback_id = callback_defined(ligaturing_callback);
+    if (callback_id > 0) {
+        tail = run_lua_ligkern_callback(head, tail, callback_id);
+        if (tail == null)
+            tail = tail_of_list(head);
+    } else if (callback_id == 0) {
+        tail = handle_ligaturing(head, tail);
+    }
+    callback_id = callback_defined(kerning_callback);
+    if (callback_id > 0) {
+        tail = run_lua_ligkern_callback(head, tail, callback_id);
+        if (tail == null) {
+            tail = tail_of_list(head);
+        }
+    } else if (callback_id == 0) {
+        halfword nest1 = new_node(nesting_node, 1);
+        halfword cur = vlink(head);
+        halfword aft = vlink(tail);
+        couple_nodes(nest1, cur);
+        tlink(nest1) = tail;
+        vlink(tail) = null;
+        do_handle_kerning(nest1, null, null);
+        couple_nodes(head, vlink(nest1));
+        tail = tlink(nest1);
+        try_couple_nodes(tail, aft);
+        flush_node(nest1);
+    }
+    return tail;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/luafont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/luafont.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/luafont.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,2426 +0,0 @@
-% luafont.w
-%
-% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-#define noVERBOSE
-
-/* todo: also keys */
-
-const char *font_type_strings[] = {
-    "unknown", "virtual", "real", NULL
-};
-
-const char *font_writingmode_strings[] = {
-    "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_identity_strings[] = {
-    "unknown", "horizontal", "vertical", NULL
-};
-
-const char *font_format_strings[] = {
-    "unknown", "type1", "type3", "truetype", "opentype", NULL
-};
-
-const char *font_embedding_strings[] = {
-    "unknown", "no", "subset", "full", NULL
-};
-
-const char *ligature_type_strings[] = {
-    "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL
-};
-
-const char *MATH_param_names[] = {
-    "nil",
-    "ScriptPercentScaleDown",
-    "ScriptScriptPercentScaleDown",
-    "DelimitedSubFormulaMinHeight",
-    "DisplayOperatorMinHeight",
-    "MathLeading",
-    "AxisHeight",
-    "AccentBaseHeight",
-    "FlattenedAccentBaseHeight",
-    "SubscriptShiftDown",
-    "SubscriptTopMax",
-    "SubscriptBaselineDropMin",
-    "SuperscriptShiftUp",
-    "SuperscriptShiftUpCramped",
-    "SuperscriptBottomMin",
-    "SuperscriptBaselineDropMax",
-    "SubSuperscriptGapMin",
-    "SuperscriptBottomMaxWithSubscript",
-    "SpaceAfterScript",
-    "UpperLimitGapMin",
-    "UpperLimitBaselineRiseMin",
-    "LowerLimitGapMin",
-    "LowerLimitBaselineDropMin",
-    "StackTopShiftUp",
-    "StackTopDisplayStyleShiftUp",
-    "StackBottomShiftDown",
-    "StackBottomDisplayStyleShiftDown",
-    "StackGapMin",
-    "StackDisplayStyleGapMin",
-    "StretchStackTopShiftUp",
-    "StretchStackBottomShiftDown",
-    "StretchStackGapAboveMin",
-    "StretchStackGapBelowMin",
-    "FractionNumeratorShiftUp",
-    "FractionNumeratorDisplayStyleShiftUp",
-    "FractionDenominatorShiftDown",
-    "FractionDenominatorDisplayStyleShiftDown",
-    "FractionNumeratorGapMin",
-    "FractionNumeratorDisplayStyleGapMin",
-    "FractionRuleThickness",
-    "FractionDenominatorGapMin",
-    "FractionDenominatorDisplayStyleGapMin",
-    "SkewedFractionHorizontalGap",
-    "SkewedFractionVerticalGap",
-    "OverbarVerticalGap",
-    "OverbarRuleThickness",
-    "OverbarExtraAscender",
-    "UnderbarVerticalGap",
-    "UnderbarRuleThickness",
-    "UnderbarExtraDescender",
-    "RadicalVerticalGap",
-    "RadicalDisplayStyleVerticalGap",
-    "RadicalRuleThickness",
-    "RadicalExtraAscender",
-    "RadicalKernBeforeDegree",
-    "RadicalKernAfterDegree",
-    "RadicalDegreeBottomRaisePercent",
-    "MinConnectorOverlap",
-    "SubscriptShiftDownWithSuperscript",
-    "FractionDelimiterSize",
-    "FractionDelimiterDisplayStyleSize",
-    "NoLimitSubFactor",
-    "NoLimitSupFactor",
-    NULL,
-};
-
-/* here for now, may be useful elsewhere */
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]);
-
-int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) {
-    const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
-    int i;
-    for (i=0; lst[i]; i++)
-    if (strcmp(lst[i], name) == 0)
-        return i;
-    return -1;
-}
-
-#define dump_intfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushinteger(L, c); \
-    lua_rawset(L, -3); \
-
-#define dump_stringfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushstring(L, c); \
-    lua_rawset(L, -3);
-
-#define dump_booleanfield(L,n,c) \
-    lua_push_string_by_name(L,n); \
-    lua_pushboolean(L, c); \
-    lua_rawset(L, -3);
-
-static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id)
-{
-    int i;
-    for (i = 0; i < l; i++) {
-        lua_newtable(L);
-        if (id==top_left_kern) {
-            dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->top_left_math_kern_array[(2*i)+1]);
-        } else if (id==top_right_kern) {
-            dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->top_right_math_kern_array[(2*i)+1]);
-        } else if (id==bottom_right_kern) {
-            dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->bottom_right_math_kern_array[(2*i)+1]);
-        } else if (id==bottom_left_kern) {
-            dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]);
-            dump_intfield(L, kern,   co->bottom_left_math_kern_array[(2*i)+1]);
-        }
-        lua_rawseti(L, -2, (i + 1));
-    }
-}
-
-static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co)
-{
-    liginfo *l;
-    kerninfo *ki;
-
-    lua_createtable(L, 0, 10);
-
-    dump_intfield(L,width,get_charinfo_width(co));
-    dump_intfield(L,height,get_charinfo_height(co));
-    dump_intfield(L,depth,get_charinfo_depth(co));
-
-    if (get_charinfo_italic(co) != 0) {
-       dump_intfield(L,italic,get_charinfo_italic(co));
-    }
-    if (get_charinfo_vert_italic(co) != 0) {
-       dump_intfield(L,vert_italic,get_charinfo_vert_italic(co));
-    }
-    if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) {
-       dump_intfield(L,top_accent,get_charinfo_top_accent(co));
-    }
-    if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) {
-       dump_intfield(L,bot_accent,get_charinfo_bot_accent(co));
-    }
-    if (get_charinfo_ef(co) != 1000) {
-        dump_intfield(L,expansion_factor,get_charinfo_ef(co));
-    }
-    if (get_charinfo_lp(co) != 0) {
-        dump_intfield(L,left_protruding,get_charinfo_lp(co));
-    }
-    if (get_charinfo_rp(co) != 0) {
-        dump_intfield(L,right_protruding,get_charinfo_rp(co));
-    }
-    if (font_encodingbytes(f) == 2) {
-        dump_intfield(L,index,get_charinfo_index(co));
-    }
-    if (get_charinfo_name(co) != NULL) {
-        dump_stringfield(L,name,get_charinfo_name(co));
-    }
-    if (get_charinfo_tounicode(co) != NULL) {
-        dump_stringfield(L,tounicode,get_charinfo_tounicode(co));
-    }
-    if (get_charinfo_tag(co) == list_tag) {
-        dump_intfield(L,next,get_charinfo_remainder(co));
-    }
-    if (get_charinfo_used(co)) {
-        dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false));
-    }
-    if (get_charinfo_tag(co) == ext_tag) {
-        extinfo *h;
-        h = get_charinfo_hor_variants(co);
-        if (h != NULL) {
-            int i = 1;
-            lua_push_string_by_name(L,horiz_variants);
-            lua_newtable(L);
-            while (h != NULL) {
-                lua_createtable(L, 0, 5);
-                dump_intfield(L, glyph, h->glyph);
-                dump_intfield(L, extender, h->extender);
-                dump_intfield(L, start, h->start_overlap);
-                dump_intfield(L, end, h->end_overlap);
-                dump_intfield(L, advance, h->advance);
-                lua_rawseti(L, -2, i);
-                i++;
-                h = h->next;
-            }
-            lua_rawset(L, -3);
-        }
-        h = get_charinfo_vert_variants(co);
-        if (h != NULL) {
-            int i = 1;
-            lua_push_string_by_name(L,vert_variants);
-            lua_newtable(L);
-            while (h != NULL) {
-                lua_createtable(L, 0, 5);
-                dump_intfield(L, glyph, h->glyph);
-                dump_intfield(L, extender, h->extender);
-                dump_intfield(L, start, h->start_overlap);
-                dump_intfield(L, end, h->end_overlap);
-                dump_intfield(L, advance, h->advance);
-                lua_rawseti(L, -2, i);
-                i++;
-                h = h->next;
-            }
-            lua_rawset(L, -3);
-        }
-    }
-    ki = get_charinfo_kerns(co);
-    if (ki != NULL) {
-        int i;
-        lua_push_string_by_name(L,kerns);
-        lua_createtable(L, 10, 1);
-        for (i = 0; !kern_end(ki[i]); i++) {
-            if (kern_disabled(ki[i])) {
-                /* skip like in lookup */
-            } else {
-                lua_rawgeti(L, -1, kern_char(ki[i]));
-                if (lua_type(L,-1) == LUA_TNIL) {
-                    lua_pop(L,1);
-                    if (kern_char(ki[i]) == right_boundarychar) {
-                        lua_push_string_by_name(L,right_boundary);
-                    } else {
-                        lua_pushinteger(L, kern_char(ki[i]));
-                    }
-                    lua_pushinteger(L, kern_kern(ki[i]));
-                    lua_rawset(L, -3);
-                } else {
-                    /* first one wins */
-                    lua_pop(L,1);
-                }
-            }
-        }
-        lua_rawset(L, -3);
-    }
-    l = get_charinfo_ligatures(co);
-    if (l != NULL) {
-        int i;
-        lua_push_string_by_name(L,ligatures);
-        lua_createtable(L, 10, 1);
-        for (i = 0; !lig_end(l[i]); i++) {
-            if (lig_char(l[i]) == right_boundarychar) {
-                lua_push_string_by_name(L,right_boundary);
-            } else {
-                lua_pushinteger(L, lig_char(l[i]));
-            }
-            lua_createtable(L, 0, 2);
-            lua_push_string_by_name(L,type);
-            lua_pushinteger(L, lig_type(l[i]));
-            lua_rawset(L, -3);
-            lua_push_string_by_name(L,char);
-            lua_pushinteger(L, lig_replacement(l[i]));
-            lua_rawset(L, -3);
-            lua_rawset(L, -3);
-        }
-        lua_rawset(L, -3);
-    }
-
-    lua_push_string_by_name(L,mathkern);
-    lua_newtable(L);
-    {
-    int i, j;
-    i = get_charinfo_math_kerns(co, top_right_kern);
-    j = 0;
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,top_right);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, top_right_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, top_left_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,top_left);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, top_left_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, bottom_right_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,bottom_right);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, bottom_right_kern);
-        lua_rawset(L, -3);
-    }
-    i = get_charinfo_math_kerns(co, bottom_left_kern);
-    if (i > 0) {
-        j++;
-        lua_push_string_by_name(L,bottom_left);
-        lua_newtable(L);
-        dump_math_kerns(L, co, i, bottom_left_kern);
-        lua_rawset(L, -3);
-    }
-    if (j > 0)
-        lua_rawset(L, -3);
-    else
-        lua_pop(L, 2);
-    }
-}
-
-static void write_lua_parameters(lua_State * L, int f)
-{
-    int k;
-    lua_push_string_by_name(L,parameters);
-    lua_newtable(L);
-    for (k = 1; k <= font_params(f); k++) {
-        switch (k) {
-            case slant_code:
-                dump_intfield(L,slant,font_param(f, k));
-                break;
-            case space_code:
-                dump_intfield(L,space,font_param(f, k));
-                break;
-            case space_stretch_code:
-                dump_intfield(L,space_stretch,font_param(f, k));
-                break;
-            case space_shrink_code:
-                dump_intfield(L,space_shrink,font_param(f, k));
-                break;
-            case x_height_code:
-                dump_intfield(L,x_height,font_param(f, k));
-                break;
-            case quad_code:
-                dump_intfield(L,quad,font_param(f, k));
-                break;
-            case extra_space_code:
-                dump_intfield(L,extra_space,font_param(f, k));
-                break;
-            default:
-                lua_pushinteger(L, font_param(f, k));
-                lua_rawseti(L, -2, k);
-        }
-    }
-    lua_rawset(L, -3);
-}
-
-@ @c
-static void write_lua_math_parameters(lua_State * L, int f)
-{
-    int k;
-    lua_push_string_by_name(L,MathConstants);
-    lua_newtable(L);
-    for (k = 1; k <= font_math_params(f); k++) {
-        lua_pushinteger(L, font_math_param(f, k));
-        if (k <= MATH_param_max) {
-            lua_setfield(L, -2, MATH_param_names[k]);
-        } else {
-            lua_rawseti(L, -2, k);
-        }
-    }
-    lua_rawset(L, -3);
-}
-
-int font_to_lua(lua_State * L, int f)
-{
-    int k;
-    charinfo *co;
-    if (font_cache_id(f) > 0) {
-        /* fetch the table from the registry if it was
-           saved there by |font_from_lua()| */
-        lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f));
-        /* fontdimens can be changed from tex code */
-        write_lua_parameters(L, f);
-        return 1;
-    }
-
-    lua_newtable(L);
-    lua_push_string_by_name(L,name);
-    lua_pushstring(L, font_name(f));
-    lua_rawset(L, -3);
-    if (font_area(f) != NULL) {
-        dump_stringfield(L,area,font_area(f));
-    }
-    if (font_filename(f) != NULL) {
-        dump_stringfield(L,filename,font_filename(f));
-    }
-    if (font_fullname(f) != NULL) {
-        dump_stringfield(L,fullname,font_fullname(f));
-    }
-    if (font_psname(f) != NULL) {
-        dump_stringfield(L,psname,font_psname(f));
-    }
-    if (font_encodingname(f) != NULL) {
-        dump_stringfield(L,encodingname,font_encodingname(f));
-    }
-
-    dump_booleanfield(L,used,(font_used(f) ? true : false));
-    dump_stringfield(L,type,font_type_strings[font_type(f)]);
-    dump_stringfield(L,format,font_format_strings[font_format(f)]);
-    dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]);
-    dump_stringfield(L,identity,font_identity_strings[font_identity(f)]);
-    dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]);
-    dump_intfield(L,streamprovider,font_streamprovider(f));
-
-    dump_intfield(L,units_per_em,font_units_per_em(f));
-    dump_intfield(L,size,font_size(f));
-    dump_intfield(L,designsize,font_dsize(f));
-    dump_intfield(L,checksum,font_checksum(f));
-    dump_intfield(L,slant,font_slant(f));
-    dump_intfield(L,extend,font_extend(f));
-    dump_intfield(L,direction,font_natural_dir(f));
-    dump_intfield(L,encodingbytes,font_encodingbytes(f));
-    dump_booleanfield(L,oldmath,font_oldmath(f));
-    dump_intfield(L,tounicode,font_tounicode(f));
-
-    /* the next one is read only */
-    if (font_max_shrink(f) != 0) {
-        dump_intfield(L,shrink,font_max_shrink(f));
-    }
-    if (font_max_stretch(f) != 0) {
-        dump_intfield(L,stretch,font_max_stretch(f));
-    }
-    if (font_step(f) != 0) {
-        dump_intfield(L,step,font_step(f));
-    }
-    if (pdf_font_attr(f) != 0) {
-        char *s = makecstring(pdf_font_attr(f));
-        dump_stringfield(L,attributes,s);
-        free(s);
-    }
-
-    /* params */
-    write_lua_parameters(L, f);
-    write_lua_math_parameters(L, f);
-
-    /* chars */
-    lua_push_string_by_name(L,characters);
-    lua_createtable(L, font_tables[f]->charinfo_size, 0);       /* all characters */
-    if (has_left_boundary(f)) {
-        co = get_charinfo(f, left_boundarychar);
-        lua_push_string_by_name(L,left_boundary);
-        font_char_to_lua(L, f, co);
-        lua_rawset(L, -3);
-    }
-    if (has_right_boundary(f)) {
-        co = get_charinfo(f, right_boundarychar);
-        lua_push_string_by_name(L,right_boundary);
-        font_char_to_lua(L, f, co);
-        lua_rawset(L, -3);
-    }
-    for (k = font_bc(f); k <= font_ec(f); k++) {
-        if (quick_char_exists(f, k)) {
-            lua_pushinteger(L, k);
-            co = get_charinfo(f, k);
-            font_char_to_lua(L, f, co);
-            lua_rawset(L, -3);
-        }
-    }
-    lua_rawset(L, -3);
-
-    if (font_cache_id(f) == 0) {        /* renew */
-        int r;
-        lua_pushvalue(L, -1);
-        r = luaL_ref(L, LUA_REGISTRYINDEX);     /* pops the table */
-        set_font_cache_id(f, r);
-    }
-    return 1;
-}
-
-#define count_hash_items(L,name,n) \
-    n = 0; \
-    lua_key_rawgeti(name); \
-    if (lua_type(L, -1) == LUA_TTABLE) { \
-        lua_pushnil(L); \
-        while (lua_next(L, -2) != 0) { \
-            n++; \
-            lua_pop(L, 1); \
-        } \
-    } \
-    if (n) { \
-        /* keep table on stack */ \
-    } else{ \
-        lua_pop(L, 1); \
-    }
-
-@ @c
-#define streq(a,b) (strcmp(a,b)==0)
-
-#define append_packet(k) { *(cp++) = (eight_bits) (k); }
-
-#define do_store_four(l) {                 \
-    append_packet((l & 0xFF000000) >> 24); \
-    append_packet((l & 0x00FF0000) >> 16); \
-    append_packet((l & 0x0000FF00) >> 8);  \
-    append_packet((l & 0x000000FF));       \
-}
-
-@ @c
-static void append_float(eight_bits ** cpp, float a)
-{
-    unsigned int i;
-    eight_bits *cp = *cpp;
-    union U {
-        float a;
-        eight_bits b[sizeof(float)];
-    } u;
-    u.a = a;
-    for (i = 0; i < sizeof(float); i++)
-        append_packet(u.b[i]);
-    *cpp = cp;
-}
-
-static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values)
-{
-    int k, t;
-    const char *s;
-    int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    t = lua_type(L,-1);
-    if (t == LUA_TNUMBER) {
-        i = (int) lua_tointeger(L, -1);
-    } else if (t == LUA_TSTRING) {
-        s = lua_tostring(L, -1);
-        k = 0;
-        while (values[k] != NULL) {
-            if (strcmp(values[k], s) == 0) {
-                i = k;
-                break;
-            }
-            k++;
-        }
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static int n_boolean_field(lua_State * L, int name_index, int dflt)
-{
-    int i = dflt;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_isboolean(L, -1)) {
-        i = lua_toboolean(L, -1);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt)
-{
-    char *i;
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    if (lua_type(L,-1) == LUA_TSTRING) {
-        i = xstrdup(lua_tostring(L, -1));
-    } else if (dflt == NULL) {
-        i = NULL;
-    } else {
-        i = xstrdup(dflt);
-    }
-    lua_pop(L, 1);
-    return i;
-}
-
-static const char *n_string_field(lua_State * L, int name_index)
-{
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    return lua_tostring(L,-1);
-}
-
-static int n_some_field(lua_State * L, int name_index)
-{
-    lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);      /* fetch the stringptr */
-    lua_rawget(L, -2);
-    return lua_type(L,-1);
-}
-
-/*static void init_font_string_pointers(lua_State * L){}*/
-
-static int count_char_packet_bytes(lua_State * L)
-{
-    register int i;
-    register int ts;
-    register int l = 0;
-    int ff = 0;
-    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
-        lua_rawgeti(L, -1, i);
-        if (lua_istable(L, -1)) {
-            lua_rawgeti(L, -1, 1);
-            if (lua_type(L,-1) == LUA_TSTRING) {
-                const char *s = lua_tostring(L, -1);
-                if (lua_key_eq(s, font)) {
-                    l += 5;
-                    ff = 1;
-                } else if (lua_key_eq(s, char)) {
-                    if (ff == 0) {
-                        l += 5;
-                    }
-                    l += 5;
-                    ff = 1;
-                } else if (lua_key_eq(s, slot)) {
-                    l += 10;
-                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
-                    ;
-                } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) {
-                    l++;
-                } else if (lua_key_eq(s, rule)) {
-                    l += 9;
-                } else if (lua_key_eq(s, right) || lua_key_eq(s, node) || lua_key_eq(s, down) || lua_key_eq(s, image)) {
-                    l += 5;
-                } else if (lua_key_eq(s, scale)) {
-                    l += sizeof(float) + 1;
-                } else if (lua_key_eq(s, pdf)) {
-                    size_t len;
-                    l += 5;
-                    ts = lua_rawlen(L, -2);
-                    lua_rawgeti(L, -2, 2);
-                    if (ts == 3) {
-                        if (lua_type(L,-1) == LUA_TSTRING) {
-                            /* no need to do something */
-                        } else if (lua_type(L,-1) == LUA_TNUMBER) {
-                            /* no need to do something */
-                        } else {
-                            normal_error("vf command","invalid packet pdf literal category");
-                        }
-                        lua_rawgeti(L, -3, 3);
-                    }
-                    if (lua_type(L,-1) == LUA_TSTRING) {
-                        (void) lua_tolstring(L, -1, &len);
-                        if (len > 0) {
-                            l = (int) (l + 5 + (int) len);
-                        }
-                    } else {
-                        normal_error("vf command","invalid packet pdf literal");
-                    }
-                    lua_pop(L, ts == 3 ? 2 : 1);
-                } else if (lua_key_eq(s, special) || lua_key_eq(s, lua)) {
-                    size_t len;
-                    lua_rawgeti(L, -2, 2);
-                    if (lua_type(L,-1) == LUA_TSTRING) {
-                        (void) lua_tolstring(L, -1, &len);
-                        if (len > 0) {
-                            l = (int) (l + 5 + (int) len);
-                        }
-                    } else {
-                        normal_error("vf command","invalid packet special");
-                    }
-                    lua_pop(L, 1);
-                } else {
-                    normal_error("vf command","unknown packet command");
-                }
-            } else {
-                normal_error("vf command","no packet command");
-            }
-            lua_pop(L, 1);      /* command name */
-        }
-        lua_pop(L, 1);          /* item */
-    }
-    return l;
-}
-
-static scaled sp_to_dvi(halfword sp, halfword atsize)
-{
-    double result, mult;
-    mult = (double) (atsize / 65536.0);
-    result = (double) (sp * 16.0);
-    return floor(result / mult);
-}
-
-@ @c
-static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize)
-{
-    int i, n, m;
-    size_t l;
-    int cmd;
-    const char *s;
-    eight_bits *cpackets, *cp;
-    int ff = 0;
-    int sf = 0;
-    int ts = 0;
-    int max_f = 0;
-    int pc = count_char_packet_bytes(L);
-    if (pc <= 0)
-        return;
-    while (l_fonts[(max_f + 1)] != 0)
-        max_f++;
-    cp = cpackets = xmalloc((unsigned) (pc + 1));
-    for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
-        lua_rawgeti(L, -1, i);
-        if (lua_istable(L, -1)) {
-            /* fetch the command code */
-            lua_rawgeti(L, -1, 1);
-            if (lua_type(L,-1) == LUA_TSTRING) {
-                s = lua_tostring(L, -1);
-                cmd = 0;
-                if (lua_key_eq(s, font)) {
-                    cmd = packet_font_code;
-                } else if (lua_key_eq(s, char)) {
-                    cmd = packet_char_code;
-                    if (ff == 0) {
-                        append_packet(packet_font_code);
-                        ff = l_fonts[1];
-                        do_store_four(ff);
-                    }
-                } else if (lua_key_eq(s, slot)) {
-                    /* we could be sparse but no real reason */
-                    cmd = packet_nop_code;
-                    lua_rawgeti(L, -2, 2);
-                    n = (int) lua_roundnumber(L, -1);
-                    if (n == 0) {
-                        sf = f;
-                    } else {
-                        sf = (n > max_f ? l_fonts[1] : l_fonts[n]);
-                    }
-                    lua_rawgeti(L, -3, 3);
-                    n = (int) lua_roundnumber(L, -1);
-                    lua_pop(L, 2);
-                    append_packet(packet_font_code);
-                    do_store_four(sf);
-                    append_packet(packet_char_code);
-                    do_store_four(n);
-                } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) {
-                    cmd = packet_nop_code;
-                } else if (lua_key_eq(s, node)) {
-                    cmd = packet_node_code;
-                } else if (lua_key_eq(s, push)) {
-                    cmd = packet_push_code;
-                } else if (lua_key_eq(s, pop)) {
-                    cmd = packet_pop_code;
-                } else if (lua_key_eq(s, rule)) {
-                    cmd = packet_rule_code;
-                } else if (lua_key_eq(s, right)) {
-                    cmd = packet_right_code;
-                } else if (lua_key_eq(s, down)) {
-                    cmd = packet_down_code;
-                } else if (lua_key_eq(s, pdf)) {
-                    cmd = packet_pdf_code;
-                } else if (lua_key_eq(s, special)) {
-                    cmd = packet_special_code;
-                } else if (lua_key_eq(s, image)) {
-                    cmd = packet_image_code;
-                } else if (lua_key_eq(s, scale)) {
-                    cmd = packet_scale_code;
-                } else if (lua_key_eq(s, lua)) {
-                    cmd = packet_lua_code;
-                }
-                switch (cmd) {
-                    case packet_push_code:
-                    case packet_pop_code:
-                        append_packet(cmd);
-                        break;
-                    case packet_font_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) lua_roundnumber(L, -1);
-                        if (n == 0) {
-                            ff = n;
-                        } else {
-                            ff = (n > max_f ? l_fonts[1] : l_fonts[n]);
-                        }
-                        do_store_four(ff);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_node_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = copy_node_list(nodelist_from_lua(L));
-                        do_store_four(n);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_char_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) lua_roundnumber(L, -1);
-                        do_store_four(n);
-                        lua_pop(L, 1);
-                        break;
-                    case packet_right_code:
-                    case packet_down_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) lua_roundnumber(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_pop(L, 1);
-                        break;
-                    case packet_rule_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        n = (int) lua_roundnumber(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_rawgeti(L, -3, 3);
-                        n = (int) lua_roundnumber(L, -1);
-                        do_store_four(sp_to_dvi(n, atsize));
-                        lua_pop(L, 2);
-                        break;
-                    case packet_pdf_code:
-                        ts = (int) lua_rawlen(L, -2);
-                        lua_rawgeti(L, -2, 2);
-                        if (ts == 3) {
-                            /* mode on stack */
-                            s = lua_tostring(L, -1);
-                            if (lua_type(L, -1) == LUA_TSTRING) {
-                                /* <pdf> <mode> <direct|page|text|raw|origin> */
-                                if (lua_key_eq(s, mode)) {
-                                    cmd = packet_pdf_mode;
-                                    lua_rawgeti(L, -3, 3);
-                                    /* mode on stack */
-                                    s = lua_tostring(L, -1);
-                                }
-                            } else {
-                                /* <pdf> <direct|page|text|raw|origin> <string> */
-                            }
-                            if (lua_type(L, -1) == LUA_TSTRING) {
-                                if (lua_key_eq(s, direct)) {
-                                    n = direct_always;
-                                } else if (lua_key_eq(s, page)) {
-                                    n = direct_page;
-                                } else if (lua_key_eq(s, text)) {
-                                    n = direct_text;
-                                } else if (lua_key_eq(s, font)) {
-                                    n = direct_font;
-                                } else if (lua_key_eq(s, raw)) {
-                                    n = direct_raw;
-                                } else if (lua_key_eq(s, origin)) {
-                                    n = set_origin;
-                                } else {
-                                 /* normal_warning("vf command","invalid pdf literal type"); */
-                                    n = set_origin ;
-                                }
-                            } else {
-                                n = (int) lua_roundnumber(L, -1);
-                                if (n < set_origin || n >= scan_special) {
-                                    n = set_origin ;
-                                }
-                            }
-                            if (cmd == packet_pdf_code) {
-                                lua_rawgeti(L, -3, 3);
-                                /* string on stack */
-                            }
-                        } else {
-                            n = set_origin;
-                        }
-                        append_packet(cmd);
-                        do_store_four(n);
-                        if (cmd == packet_pdf_code) {
-                            s = luaL_checklstring(L, -1, &l);
-                            do_store_four(l);
-                            if (l > 0) {
-                                m = (int) l;
-                                while (m > 0) {
-                                    n = *s++;
-                                    m--;
-                                    append_packet(n);
-                                }
-                            }
-                        }
-                        lua_pop(L,ts == 3 ? 2 : 1);
-                        break;
-                    case packet_special_code:
-                    case packet_lua_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        s = luaL_checklstring(L, -1, &l);
-                        if (l > 0) {
-                            do_store_four(l);
-                            m = (int) l;
-                            while (m > 0) {
-                                n = *s++;
-                                m--;
-                                append_packet(n);
-                            }
-                        }
-                        lua_pop(L, 1);
-                        break;
-                    case packet_image_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);      /* img/imgtable? ... */
-                        if (lua_istable(L, -1)) {   /* imgtable ... */
-                            lua_getglobal(L, "img");        /* imglib imgtable ... */
-                            lua_pushstring(L, "new");       /* `new' imglib imgtable ... */
-                            lua_gettable(L, -2);    /* f imglib imgtable ... */
-                            lua_insert(L, -3);      /* imglib imgtable f ... */
-                            lua_pop(L, 1);  /* imgtable f ... */
-                            lua_call(L, 1, 1);
-                        }           /* img ... */
-                        luaL_checkudata(L, -1, TYPE_IMG);   /* img ... --- just typecheck */
-                        n = luaL_ref(L, LUA_REGISTRYINDEX);  /* ... */
-                        do_store_four(n);
-                        break;
-                    case packet_nop_code:
-                        break;
-                    case packet_scale_code:
-                        append_packet(cmd);
-                        lua_rawgeti(L, -2, 2);
-                        append_float(&cp, (float) luaL_checknumber(L, -1));
-                        lua_pop(L, 1);
-                        break;
-                    default:
-                        normal_error("vf command","invalid packet code");
-                        /* fprintf(stdout, "Unknown char packet code %s\n", s); */
-                }
-            }
-            lua_pop(L, 1);      /* command code */
-        } else {
-            normal_error("vf command","commands has to be a table");
-            /* fprintf(stdout, "Found a `commands' item that is not a table\n"); */
-        }
-        lua_pop(L, 1);          /* command table */
-    }
-    append_packet(packet_end_code);
-    set_charinfo_packets(co, cpackets);
-    return;
-}
-
-@ @c
-static void read_lua_cidinfo(lua_State * L, int f)
-{
-    int i;
-    char *s;
-    /*lua_getfield(L, -1, "cidinfo");*/
-    lua_key_rawgeti(cidinfo);
-    if (lua_istable(L, -1)) {
-        i = lua_numeric_field_by_index(L,lua_key_index(version), 0);
-        set_font_cidversion(f, i);
-        i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0);
-        set_font_cidsupplement(f, i);
-        s = n_string_field_copy(L, lua_key_index(registry), "Adobe");       /* Adobe-Identity-0 */
-        set_font_cidregistry(f, s);
-        s = n_string_field_copy(L, lua_key_index(ordering), "Identity");
-        set_font_cidordering(f, s);
-    }
-    lua_pop(L, 1);
-}
-
-
-@ @c
-static void read_lua_parameters(lua_State * L, int f)
-{
-    int i, n, t;
-    const char *s;
-    /*lua_getfield(L, -1, "parameters");*/
-    lua_key_rawgeti(parameters);
-    if (lua_istable(L, -1)) {
-        /* the number of parameters is the max(IntegerKeys(L)),7) */
-        n = 7;
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            if (lua_type(L, -2) == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-                if (i > n)
-                    n = i;
-            }
-            lua_pop(L, 1);      /* pop value */
-        }
-        if (n > 7)
-            set_font_params(f, n);
-        /* sometimes it is handy to have all integer keys */
-        for (i = 1; i <= 7; i++) {
-            lua_rawgeti(L, -1, i);
-            if (lua_type(L, -1) == LUA_TNUMBER) {
-                n = lua_roundnumber(L, -1); /* round ? */
-                set_font_param(f, i, n);
-            }
-            lua_pop(L, 1);
-        }
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            t = lua_type(L,-2);
-            if (t == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-                if (i >= 8) {
-                    if (lua_type(L,-1) == LUA_TNUMBER) {
-                        n = lua_roundnumber(L, -1);
-                    } else {
-                        n = 0;
-                    }
-                    set_font_param(f, i, n);
-                }
-            } else if (t == LUA_TSTRING) {
-                s = lua_tostring(L, -2);
-                if (lua_type(L,-1) == LUA_TNUMBER) {
-                    n = lua_roundnumber(L, -1);
-                } else {
-                    n = 0;
-                }
-                if (lua_key_eq(s, slant)) {
-                    set_font_param(f, slant_code, n);
-                } else if (lua_key_eq(s, space)) {
-                    set_font_param(f, space_code, n);
-                } else if (lua_key_eq(s, space_stretch)) {
-                    set_font_param(f, space_stretch_code, n);
-                } else if (lua_key_eq(s, space_shrink)) {
-                    set_font_param(f, space_shrink_code, n);
-                } else if (lua_key_eq(s, x_height)) {
-                    set_font_param(f, x_height_code, n);
-                } else if (lua_key_eq(s, quad)) {
-                    set_font_param(f, quad_code, n);
-                } else if (lua_key_eq(s, extra_space)) {
-                    set_font_param(f, extra_space_code, n);
-                }
-            }
-            lua_pop(L, 1);
-        }
-    }
-    lua_pop(L, 1);
-
-}
-
-@ @c
-static void read_lua_math_parameters(lua_State * L, int f)
-{
-    int i = 0, n = 0, t;
-    /*lua_getfield(L, -1, "MathConstants");*/
-    lua_key_rawgeti(MathConstants);
-    if (lua_istable(L, -1)) {
-        lua_pushnil(L);
-        while (lua_next(L, -2) != 0) {
-            t = lua_type(L,-2);
-            if (t == LUA_TNUMBER) {
-                i = (int) lua_tointeger(L, -2);
-            } else if (t == LUA_TSTRING) {
-                i = ff_checkoption(L, -2, NULL, MATH_param_names);
-            }
-            n = (int) lua_roundnumber(L, -1);
-            if (i > 0) {
-                set_font_math_param(f, i, n);
-            }
-            lua_pop(L, 1);      /* pop value */
-        }
-        set_font_oldmath(f,false);
-    } else {
-        set_font_oldmath(f,true);
-    }
-    lua_pop(L, 1);
-}
-
-@ @c
-#define MIN_INF -0x7FFFFFFF
-
-static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
-{
-    int l, k;
-    scaled ht, krn;
-    lua_key_direct_rawgeti(index);
-    if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) {
-        for (l = 0; l < k; l++) {
-            lua_rawgeti(L, -1, (l + 1));
-            if (lua_istable(L, -1)) {
-                ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF);
-                krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF);
-                if (krn > MIN_INF && ht > MIN_INF)
-                    add_charinfo_math_kern(co, id, ht, krn);
-            }
-            lua_pop(L, 1);
-        }
-    }
-    lua_pop(L, 1);
-}
-
-@ @c
-static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math)
-{
-    int k, r, t, lt, u, n;
-    charinfo *co;
-    kerninfo *ckerns;
-    liginfo *cligs;
-    scaled j;
-    const char *s;
-    int nl = 0;                 /* number of ligature table items */
-    int nk = 0;                 /* number of kern table items */
-    int ctr = 0;
-    int atsize = font_size(f);
-    if (lua_istable(L, -1)) {
-        co = get_charinfo(f, i);
-        set_charinfo_tag(co, 0);
-        j = lua_numeric_field_by_index(L, lua_key_index(width), 0);
-        set_charinfo_width(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(height), 0);
-        set_charinfo_height(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(depth), 0);
-        set_charinfo_depth(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(italic), 0);
-        set_charinfo_italic(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0);
-        set_charinfo_vert_italic(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(index), 0);
-        set_charinfo_index(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000);
-        set_charinfo_ef(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0);
-        set_charinfo_lp(co, j);
-        j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0);
-        set_charinfo_rp(co, j);
-        k = n_boolean_field(L, lua_key_index(used), 0);
-        set_charinfo_used(co, k);
-        s = n_string_field(L, lua_key_index(name));
-        if (s != NULL)
-            set_charinfo_name(co, xstrdup(s));
-        else
-            set_charinfo_name(co, NULL);
-        /* n_string_field leaves a value on stack*/
-        lua_pop(L,1);
-        u = n_some_field(L,lua_key_index(tounicode));
-        if (u == LUA_TNUMBER) {
-            u = lua_tointeger(L,-1);
-            if (u < 0) {
-                set_charinfo_tounicode(co, NULL);
-            } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                char *s = malloc(5);
-                sprintf(s,"%04X",(unsigned int) u);
-                set_charinfo_tounicode(co,s);
-            } else {
-                char *s = malloc(9);
-                u = u - 0x10000;
-                sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
-                set_charinfo_tounicode(co,s);
-            }
-        } else if (u == LUA_TTABLE) {
-            n = lua_rawlen(L,-1);
-            u = 0;
-            for (k = 1; k <= n; k++) {
-                lua_rawgeti(L, -1, k);
-                if (lua_type(L,-1) == LUA_TNUMBER) {
-                    u = lua_tointeger(L,-1);
-                } else {
-                    lua_pop(L, 1);
-                    break;
-                }
-                if (u < 0) {
-                    u = -1;
-                    lua_pop(L, 1);
-                    break;
-                } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                    u = u + 4;
-                } else {
-                    u = u + 8;
-                }
-                lua_pop(L, 1);
-            }
-            if (u>0) {
-                char *s = malloc(u+1);
-                char *t = s ;
-                for (k = 1; k <= n; k++) {
-                    lua_rawgeti(L, -1, k);
-                    u = lua_tointeger(L,-1);
-                    if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) {
-                        sprintf(t,"%04X",(unsigned int) u);
-                        t += 4;
-                    } else {
-                        u = u - 0x10000;
-                        sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00));
-                        t += 8;
-                    }
-                    lua_pop(L, 1);
-                }
-                set_charinfo_tounicode(co,s);
-            } else {
-                set_charinfo_tounicode(co, NULL);
-            }
-        } else if (u == LUA_TSTRING) {
-            s = lua_tostring(L,-1);
-            set_charinfo_tounicode(co, xstrdup(s));
-        } else {
-            set_charinfo_tounicode(co, NULL);
-        }
-        /* ... leaves a value on stack*/
-        lua_pop(L,1);
-
-        if (has_math) {
-            j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN);
-            set_charinfo_top_accent(co, j);
-            j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN);
-            set_charinfo_bot_accent(co, j);
-            k = lua_numeric_field_by_index(L, lua_key_index(next), -1);
-            if (k >= 0) {
-                set_charinfo_tag(co, list_tag);
-                set_charinfo_remainder(co, k);
-            }
-
-            lua_key_rawgeti(extensible);
-            if (lua_istable(L, -1)) {
-                int top, bot, mid, rep;
-                top = lua_numeric_field_by_index(L, lua_key_index(top), 0);
-                bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0);
-                mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0);
-                rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0);
-                if (top != 0 || bot != 0 || mid != 0 || rep != 0) {
-                    set_charinfo_tag(co, ext_tag);
-                    set_charinfo_extensible(co, top, bot, mid, rep);
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", font_name(f), (int) i);
-                }
-            }
-            lua_pop(L, 1);
-
-            lua_key_rawgeti(horiz_variants);
-            if (lua_istable(L, -1)) {
-                int glyph, startconnect, endconnect, advance, extender;
-                extinfo *h;
-                set_charinfo_tag(co, ext_tag);
-                set_charinfo_hor_variants(co, NULL);
-                for (k = 1;; k++) {
-                    lua_rawgeti(L, -1, k);
-                    if (lua_istable(L, -1)) {
-                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
-                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
-                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
-                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
-                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
-                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
-                        add_charinfo_hor_variant(co, h);
-                        lua_pop(L, 1);
-                    } else {
-                        lua_pop(L, 1);
-                        break;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-
-            lua_key_rawgeti(vert_variants);
-            if (lua_istable(L, -1)) {
-                int glyph, startconnect, endconnect, advance, extender;
-                extinfo *h;
-                set_charinfo_tag(co, ext_tag);
-                set_charinfo_vert_variants(co, NULL);
-                for (k = 1;; k++) {
-                    lua_rawgeti(L, -1, k);
-                    if (lua_istable(L, -1)) {
-                        glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0);
-                        extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0);
-                        startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0);
-                        endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0);
-                        advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0);
-                        h = new_variant(glyph, startconnect, endconnect, advance, extender);
-                        add_charinfo_vert_variant(co, h);
-                        lua_pop(L, 1);
-                    } else {
-                        lua_pop(L, 1);
-                        break;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-
-            /*
-                Here is a complete example:
-
-                |mathkern = {|
-                    | bottom_left  = { { height = 420, kern = 80  }, { height = 520, kern = 4   } },|
-                    | bottom_right = { { height = 0,   kern = 48  } },|
-                    | top_left     = { { height = 620, kern = 0   }, { height = 720, kern = -80 } },|
-                    | top_right    = { { height = 676, kern = 115 }, { height = 776, kern = 45  } },|
-                |}|
-
-            */
-
-            lua_key_rawgeti(mathkern);
-            if (lua_istable(L, -1)) {
-                store_math_kerns(L,lua_key_index(top_left), co, top_left_kern);
-                store_math_kerns(L,lua_key_index(top_right), co, top_right_kern);
-                store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern);
-                store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern);
-            }
-            lua_pop(L, 1);
-        }
-        /* end of |has_math| */
-        count_hash_items(L, kerns, nk);
-        if (nk > 0) {
-            /* kerns table still on stack */
-            ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
-            ctr = 0;
-            lua_pushnil(L); /* traverse hash */
-            while (lua_next(L, -2) != 0) {
-                k = non_boundarychar;
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    k = (int) lua_tointeger(L, -2); /* adjacent char */
-                    if (k < 0)
-                        k = non_boundarychar;
-                } else if (lt == LUA_TSTRING) {
-                    s = lua_tostring(L, -2);
-                    if (lua_key_eq(s, right_boundary)) {
-                        k = right_boundarychar;
-                        if (!has_right_boundary(f))
-                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
-                    }
-                }
-                j = lua_roundnumber(L, -1); /* movement */
-                if (k != non_boundarychar) {
-                    set_kern_item(ckerns[ctr], k, j);
-                    ctr++;
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field", font_name(f), (int) i);
-                }
-                lua_pop(L, 1);
-            }
-            /* guard against empty tables */
-            if (ctr > 0) {
-                set_kern_item(ckerns[ctr], end_kern, 0);
-                set_charinfo_kerns(co, ckerns);
-            } else {
-                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", font_name(f), (int) i);
-            }
-            lua_pop(L, 1);
-        }
-
-        /* packet commands */
-
-        lua_key_rawgeti(commands);
-        if (lua_istable(L, -1)) {
-            lua_pushnil(L);     /* first key */
-            if (lua_next(L, -2) != 0) {
-                lua_pop(L, 2);
-                read_char_packets(L, (int *) l_fonts, co, f, atsize);
-            }
-        }
-        lua_pop(L, 1);
-
-        /* ligatures */
-        count_hash_items(L, ligatures, nl);
-        if (nl > 0) {
-            /* ligatures table still on stack */
-            cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
-            ctr = 0;
-            lua_pushnil(L); /* traverse hash */
-            while (lua_next(L, -2) != 0) {
-                k = non_boundarychar;
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    k = (int) lua_tointeger(L, -2); /* adjacent char */
-                    if (k < 0) {
-                        k = non_boundarychar;
-                    }
-                } else if (lt == LUA_TSTRING) {
-                    s = lua_tostring(L, -2);
-                    if (lua_key_eq(s, right_boundary)) {
-                        k = right_boundarychar;
-                        if (!has_right_boundary(f))
-                            set_right_boundary(f, get_charinfo(f, right_boundarychar));
-                    }
-                }
-                r = -1;
-                if (lua_istable(L, -1)) {
-                    r = lua_numeric_field_by_index(L, lua_key_index(char), -1);    /* ligature */
-                }
-                if (r != -1 && k != non_boundarychar) {
-                    t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings);
-                    set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r);
-                    ctr++;
-                } else {
-                    formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field", font_name(f), (int) i);
-                }
-                lua_pop(L, 1);      /* iterator value */
-            }
-            /* guard against empty tables */
-            if (ctr > 0) {
-                set_ligature_item(cligs[ctr], 0, end_ligature, 0);
-                set_charinfo_ligatures(co, cligs);
-            } else {
-                formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field", font_name(f), (int) i);
-            }
-            lua_pop(L, 1);      /* ligatures table */
-        }
-    }
-}
-
-@ The caller has to fix the state of the lua stack when there is an error!
-
- at c
-int font_from_lua(lua_State * L, int f)
-{
-    int i, n, r, t, lt;
-    int s_top;                  /* lua stack top */
-    int bc;                     /* first char index */
-    int ec;                     /* last char index */
-    char *s;
-    const char *ss;
-    int *l_fonts = NULL;
-    int save_ref ;
-    boolean no_math = false;
-
-    /* will we save a cache of the luat table? */
-
-    save_ref = 1; /* we start with  ss = "yes" */
-    ss = NULL;
-    ss = n_string_field(L, lua_key_index(cache));
-    if (lua_key_eq(ss, no))
-        save_ref = -1;
-    else if (lua_key_eq(ss, renew))
-        save_ref = 0;
-    /* n_string_field leaves a value on stack*/
-    lua_pop(L,1);
-
-    /* the table is at stack index -1 */
-    s = n_string_field_copy(L,lua_key_index(area), "");
-    set_font_area(f, s);
-    s = n_string_field_copy(L, lua_key_index(filename), NULL);
-    set_font_filename(f, s);
-    s = n_string_field_copy(L, lua_key_index(encodingname), NULL);
-    set_font_encodingname(f, s);
-
-    s = n_string_field_copy(L, lua_key_index(name), NULL);
-    set_font_name(f, s);
-    s = n_string_field_copy(L, lua_key_index(fullname), font_name(f));
-    set_font_fullname(f, s);
-
-    if (s == NULL) {
-        formatted_error("font","lua-loaded font '%d' has no name!", f);
-        return false;
-    }
-    s = n_string_field_copy(L, lua_key_index(psname), NULL);
-    set_font_psname(f, s);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0);
-    set_font_units_per_em(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360);
-    set_font_dsize(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f));
-    set_font_size(f, i);
-    set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ;
-    i = lua_numeric_field_by_index(L,lua_key_index(direction), 0);
-    set_font_natural_dir(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0);
-    set_font_encodingbytes(f, (char) i);
-    i = lua_numeric_field_by_index(L,lua_key_index(streamprovider), 0);
-    set_font_streamprovider(f, (char) i);
-    i = n_boolean_field(L,lua_key_index(oldmath), 0);
-    set_font_oldmath(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0);
-    set_font_tounicode(f, (char) i);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000);
-    if (i < FONT_EXTEND_MIN)
-        i = FONT_EXTEND_MIN;
-    if (i > FONT_EXTEND_MAX)
-        i = FONT_EXTEND_MAX;
-    set_font_extend(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(slant), 0);
-    if (i < FONT_SLANT_MIN)
-        i = FONT_SLANT_MIN;
-    if (i > FONT_SLANT_MAX)
-        i = FONT_SLANT_MAX;
-    set_font_slant(f, i);
-
-    i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par);
-    set_hyphen_char(f, i);
-    i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par);
-    set_skew_char(f, i);
-    i = n_boolean_field(L, lua_key_index(used), 0);
-    set_font_used(f, (char) i);
-
-    s = n_string_field_copy(L, lua_key_index(attributes), NULL);
-    if (s != NULL && strlen(s) > 0) {
-        i = maketexstring(s);
-        set_pdf_font_attr(f, i);
-    }
-    free(s);
-
-    i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings);
-    set_font_type(f, i);
-    i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings);
-    set_font_format(f, i);
-    i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings);
-    set_font_writingmode(f, i);
-    i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings);
-    set_font_identity(f, i);
-    i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings);
-    set_font_embedding(f, i);
-    if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) {
-        set_font_encodingbytes(f, 2);
-    }
-
-    /* now fetch the base fonts, if needed */
-    count_hash_items(L, fonts, n);
-    if (n > 0) {
-        /* font table still on stack */
-        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
-        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
-        for (i = 1; i <= n; i++) {
-            lua_rawgeti(L, -1, i);
-            if (lua_istable(L, -1)) {
-                lua_key_rawgeti(id);
-                if (lua_isnumber(L, -1)) {
-                    l_fonts[i] = (int) lua_tointeger(L, -1);
-                    if (l_fonts[i] == 0) {
-                        l_fonts[i] = (int) f;
-                    }
-                    lua_pop(L, 2); /* pop id and entry */
-                    continue;
-                }
-                lua_pop(L, 1); /* pop id */
-            };
-            ss = NULL;
-            if (lua_istable(L, -1)) {
-                ss = n_string_field(L, lua_key_index(name));
-                /* string is anchored */
-                lua_pop(L,1);
-            }
-            if (ss != NULL) {
-                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
-                /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
-                s_top = lua_gettop(L);
-                if (strcmp(font_name(f), ss) == 0)
-                    l_fonts[i] = f;
-                else
-                    l_fonts[i] = find_font_id(ss, t);
-                lua_settop(L, s_top);
-            } else {
-                formatted_error("font","invalid local font at index %i in lua-loaded font '%s' (1)",i,font_name(f));
-            }
-            lua_pop(L, 1); /* pop list entry */
-        }
-        lua_pop(L, 1); /* pop font table */
-    } else if (font_type(f) == virtual_font_type) {
-        formatted_error("font","invalid local fonts in lua-loaded font '%s' (2)", font_name(f));
-    } else {
-        l_fonts = xmalloc(3 * sizeof(int));
-        l_fonts[0] = 0;
-        l_fonts[1] = f;
-        l_fonts[2] = 0;
-    }
-    /* parameters */
-    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
-    read_lua_parameters(L, f);
-    if (!no_math) {
-        read_lua_math_parameters(L, f);
-        if (n_boolean_field(L, lua_key_index(oldmath), 0)) {
-            set_font_oldmath(f,true);
-        }
-
-    } else {
-        set_font_oldmath(f,true);
-    }
-    read_lua_cidinfo(L, f);
-
-    /* characters */
-    lua_key_rawgeti(characters);
-    if (lua_istable(L, -1)) {
-        /* find the array size values */
-        int num = 0;            /* number of charinfo's to add */
-        ec = 0;
-        bc = -1;
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            if (lua_isnumber(L, -2)) {
-                i = (int) lua_tointeger(L, -2);
-                if (i >= 0) {
-                    if (lua_istable(L, -1)) {
-                        num++;
-                        if (i > ec)
-                            ec = i;
-                        if (bc < 0)
-                            bc = i;
-                        if (bc >= 0 && i < bc)
-                            bc = i;
-                    }
-                }
-            }
-            lua_pop(L, 1);
-        }
-        if (bc != -1) {
-            font_malloc_charinfo(f, num);
-            set_font_bc(f, bc);
-            set_font_ec(f, ec);
-            lua_pushnil(L);     /* first key */
-            while (lua_next(L, -2) != 0) {
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    i = (int) lua_tointeger(L, -2);
-                    if (i >= 0) {
-                        font_char_from_lua(L, f, i, l_fonts, !no_math);
-                    }
-                } else if (lt == LUA_TSTRING) {
-                    const char *ss1 = lua_tostring(L, -2);
-                    if (lua_key_eq(ss1, left_boundary)) {
-                        font_char_from_lua(L, f, left_boundarychar, l_fonts, !no_math);
-                    } else if (lua_key_eq(ss1, right_boundary)) {
-                        font_char_from_lua(L, f, right_boundarychar, l_fonts, !no_math);
-                    }
-                }
-                lua_pop(L, 1);
-            }
-            lua_pop(L, 1);
-
-            /*
-                Handle font expansion last: the |copy_font| routine is called eventually,
-                and that needs to know |bc| and |ec|.
-            */
-
-            if (font_type(f) != virtual_font_type) {
-                int fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0);
-                if (fstep < 0)
-                    fstep = 0;
-                if (fstep > 100)
-                    fstep = 100;
-                if (fstep != 0) {
-                    int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0);
-                    int fstretch =lua_numeric_field_by_index(L, lua_key_index(stretch), 0);
-                    if (fshrink < 0)
-                        fshrink = 0;
-                    if (fshrink > 500)
-                        fshrink = 500;
-                    fshrink -= (fshrink % fstep);
-                    if (fshrink < 0)
-                        fshrink = 0;
-                    if (fstretch < 0)
-                        fstretch = 0;
-                    if (fstretch > 1000)
-                        fstretch = 1000;
-                    fstretch -= (fstretch % fstep);
-                    if (fstretch < 0)
-                        fstretch = 0;
-                    set_expand_params(f, fstretch, fshrink, fstep);
-                }
-            }
-
-        } else {
-            /* jikes, no characters */
-            formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f));
-        }
-
-        if (save_ref > 0) {
-            r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
-            set_font_cache_id(f, r);
-        } else {
-            lua_pop(L, 1);
-            set_font_cache_id(f, save_ref);
-        }
-    } else {
-        /* jikes, no characters */
-        formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f));
-    }
-    if (l_fonts != NULL)
-        free(l_fonts);
-    return true;
-}
-
-int characters_from_lua(lua_State * L, int f)
-{
-    int i, n, t, lt;
-    int *l_fonts = NULL;
-    int s_top;
-    const char *ss;
-    boolean no_math = false;
-    /* speedup */
-    no_math = n_boolean_field(L, lua_key_index(nomath), 0);
-    /* type */
-    i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings);
-    set_font_type(f, i);
-    /* fonts */
-    count_hash_items(L, fonts, n);
-    if (n > 0) {
-        /* font table still on stack */
-        l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int)));
-        memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int)));
-        for (i = 1; i <= n; i++) {
-            lua_rawgeti(L, -1, i);
-            if (lua_istable(L, -1)) {
-                lua_key_rawgeti(id);
-                if (lua_isnumber(L, -1)) {
-                    l_fonts[i] = (int) lua_tointeger(L, -1);
-                    if (l_fonts[i] == 0) {
-                        l_fonts[i] = (int) f;
-                    }
-                    lua_pop(L, 2); /* pop id and entry */
-                    continue;
-                }
-                lua_pop(L, 1); /* pop id */
-            };
-            ss = NULL;
-            if (lua_istable(L, -1)) {
-                ss = n_string_field(L, lua_key_index(name));
-                /* string is anchored */
-                lua_pop(L,1);
-            }
-            if (ss != NULL) {
-                t = lua_numeric_field_by_index(L, lua_key_index(size), -1000);
-                /* TODO: the stack is messed up, otherwise this explicit resizing would not be needed */
-                s_top = lua_gettop(L);
-                if (strcmp(font_name(f), ss) == 0)
-                    l_fonts[i] = f;
-                else
-                    l_fonts[i] = find_font_id(ss, t);
-                lua_settop(L, s_top);
-            } else {
-                formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f));
-            }
-            lua_pop(L, 1); /* pop list entry */
-        }
-        lua_pop(L, 1); /* pop font table */
-    } else if (font_type(f) == virtual_font_type) {
-        formatted_error("font","invalid local fonts in lua-loaded font '%s' (4)", font_name(f));
-    } else {
-        l_fonts = xmalloc(3 * sizeof(int));
-        l_fonts[0] = 0;
-        l_fonts[1] = f;
-        l_fonts[2] = 0;
-    }
-    /* characters */
-    lua_key_rawgeti(characters);
-    if (lua_istable(L, -1)) {
-        /* find the array size values */
-        int num = 0;            /* number of charinfo's to add */
-        int todo = 0;
-        int bc = font_bc(f);
-        int ec = font_ec(f);
-        lua_pushnil(L);         /* first key */
-        while (lua_next(L, -2) != 0) {
-            if (lua_isnumber(L, -2)) {
-                i = (int) lua_tointeger(L, -2);
-                if (i >= 0) {
-                    if (lua_istable(L, -1)) {
-                        todo++;
-                        if (! quick_char_exists(f,i)) {
-                            num++;
-                            if (i > ec)
-                                ec = i;
-                            if (bc < 0)
-                                bc = i;
-                            if (bc >= 0 && i < bc)
-                                bc = i;
-                        }
-                    }
-                }
-            }
-            lua_pop(L, 1);
-        }
-        if (todo > 0) {
-            font_malloc_charinfo(f, num);
-            set_font_bc(f, bc);
-            set_font_ec(f, ec);
-            lua_pushnil(L);     /* first key */
-            while (lua_next(L, -2) != 0) {
-                lt = lua_type(L,-2);
-                if (lt == LUA_TNUMBER) {
-                    i = (int) lua_tointeger(L, -2);
-                    if (i >= 0) {
-                        if (quick_char_exists(f,i)) {
-                            charinfo *co = char_info(f, i);
-                            set_charinfo_name(co, NULL);
-                            set_charinfo_tounicode(co, NULL);
-                            set_charinfo_packets(co, NULL);
-                            set_charinfo_ligatures(co, NULL);
-                            set_charinfo_kerns(co, NULL);
-                            set_charinfo_vert_variants(co, NULL);
-                            set_charinfo_hor_variants(co, NULL);
-                        }
-                        font_char_from_lua(L, f, i, l_fonts, !no_math);
-                    }
-                }
-                lua_pop(L, 1);
-            }
-            lua_pop(L, 1);
-        }
-    }
-    if (l_fonts != NULL)
-        free(l_fonts);
-    return true;
-}
-
-@* Ligaturing.
-
- at c
-static void nesting_append(halfword nest1, halfword newn)
-{
-    halfword tail = tlink(nest1);
-    if (tail == null) {
-        couple_nodes(nest1, newn);
-    } else {
-        couple_nodes(tail, newn);
-    }
-    tlink(nest1) = newn;
-}
-
-static void nesting_prepend(halfword nest1, halfword newn)
-{
-    halfword head = vlink(nest1);
-    couple_nodes(nest1, newn);
-    if (head == null) {
-        tlink(nest1) = newn;
-    } else {
-        couple_nodes(newn, head);
-    }
-}
-
-static void nesting_prepend_list(halfword nest1, halfword newn)
-{
-    halfword head = vlink(nest1);
-    couple_nodes(nest1, newn);
-    if (head == null) {
-        tlink(nest1) = tail_of_list(newn);
-    } else {
-        halfword tail = tail_of_list(newn);
-        couple_nodes(tail, head);
-    }
-}
-
-static int test_ligature(liginfo * lig, halfword left, halfword right)
-{
-    if (type(left) != glyph_node)
-        return 0;
-    if (font(left) != font(right))
-        return 0;
-    if (is_ghost(left) || is_ghost(right))
-        return 0;
-    *lig = get_ligature(font(left), character(left), character(right));
-    if (is_valid_ligature(*lig)) {
-        return 1;
-    }
-    return 0;
-}
-
-static int try_ligature(halfword * frst, halfword fwd)
-{
-    halfword cur = *frst;
-    liginfo lig;
-    if (test_ligature(&lig, cur, fwd)) {
-        int move_after = (lig_type(lig) & 0x0C) >> 2;
-        int keep_right = ((lig_type(lig) & 0x01) != 0);
-        int keep_left = ((lig_type(lig) & 0x02) != 0);
-        halfword newgl = raw_glyph_node();
-        font(newgl) = font(cur);
-        character(newgl) = lig_replacement(lig);
-        set_is_ligature(newgl);
-        /*
-            below might not be correct in contrived border case.
-            but we use it only for debugging, so ...
-        */
-        if (character(cur) < 0) {
-            set_is_leftboundary(newgl);
-        }
-        if (character(fwd) < 0) {
-            set_is_rightboundary(newgl);
-        }
-        if (character(cur) < 0) {
-            if (character(fwd) < 0) {
-                build_attribute_list(newgl);
-            } else {
-                add_node_attr_ref(node_attr(fwd));
-                node_attr(newgl) = node_attr(fwd);
-            }
-        } else {
-            add_node_attr_ref(node_attr(cur));
-            node_attr(newgl) = node_attr(cur);
-        }
-
-        /*
-            TODO/FIXME if this ligature is consists of another ligature
-            we should add it's |lig_ptr| to the new glyphs |lig_ptr| (and
-            cleanup the no longer needed node) LOW PRIORITY
-        */
-        /* left side */
-        if (keep_left) {
-            halfword new_first = copy_node(cur);
-            lig_ptr(newgl) = new_first;
-            couple_nodes(cur, newgl);
-            if (move_after) {
-                move_after--;
-                cur = newgl;
-            }
-        } else {
-            halfword prev = alink(cur);
-            uncouple_node(cur);
-            lig_ptr(newgl) = cur;
-            couple_nodes(prev, newgl);
-            cur = newgl;        /* as cur has disappeared */
-        }
-        /* right side */
-        if (keep_right) {
-            halfword new_second = copy_node(fwd);
-            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
-            couple_nodes(lig_ptr(newgl), new_second);
-            couple_nodes(newgl, fwd);
-            if (move_after) {
-                move_after--;
-                cur = fwd;
-            }
-        } else {
-            halfword next = vlink(fwd);
-            uncouple_node(fwd);
-            /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
-            couple_nodes(lig_ptr(newgl), fwd);
-            if (next != null) {
-                couple_nodes(newgl, next);
-            }
-        }
-        /* check and return */
-        *frst = cur;
-        return 1;
-    }
-    return 0;
-}
-
-@ there shouldn't be any ligatures here - we only add them at the end of
- |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing \.{DISC-1}
- (we continue with \.{DISC-1}'s |post_| and |no_break|.
-
- at c
-static halfword handle_lig_nest(halfword root, halfword cur)
-{
-    if (cur == null)
-        return root;
-    while (vlink(cur) != null) {
-        halfword fwd = vlink(cur);
-        if (type(cur) == glyph_node && type(fwd) == glyph_node &&
-                font(cur) == font(fwd) && try_ligature(&cur, fwd)) {
-            continue;
-        }
-        cur = vlink(cur);
-    }
-    tlink(root) = cur;
-    return root;
-}
-
-static halfword handle_lig_word(halfword cur)
-{
-    halfword right = null;
-    if (type(cur) == boundary_node) {
-        halfword prev = alink(cur);
-        halfword fwd = vlink(cur);
-        /* no need to uncouple |cur|, it is freed */
-        flush_node(cur);
-        if (fwd == null) {
-            vlink(prev) = fwd;
-            return prev;
-        }
-        couple_nodes(prev, fwd);
-        if (type(fwd) != glyph_node)
-            return prev;
-        cur = fwd;
-    } else if (has_left_boundary(font(cur))) {
-        halfword prev = alink(cur);
-        halfword p = new_glyph(font(cur), left_boundarychar);
-        couple_nodes(prev, p);
-        couple_nodes(p, cur);
-        cur = p;
-    }
-    if (has_right_boundary(font(cur))) {
-        right = new_glyph(font(cur), right_boundarychar);
-    }
-    while (1) {
-        /* A glyph followed by ... */
-        if (type(cur) == glyph_node) {
-            halfword fwd = vlink(cur);
-            if (fwd == null) {  /* last character of paragraph */
-                if (right == null)
-                    break;
-                /* \.{--\\par} prohibits use of |couple_nodes| here */
-                try_couple_nodes(cur, right);
-                right = null;
-                continue;
-            }
-            if (type(fwd) == glyph_node) {      /* |GLYPH - GLYPH| */
-                if (font(cur) != font(fwd))
-                    break;
-                if (try_ligature(&cur, fwd))
-                    continue;
-            } else if (type(fwd) == disc_node) {        /* |GLYPH - DISC| */
-
-                /* if  \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
-                halfword pre = vlink_pre_break(fwd);
-                halfword nob = vlink_no_break(fwd);
-                halfword next, tail;
-                liginfo lig;
-                /* Check on: a{b?}{?}{?} and a+b=>B : {B?}{?}{a?} */
-                /* Check on: a{?}{?}{b?} and a+b=>B : {a?}{?}{B?} */
-                if ((pre != null && type(pre) == glyph_node
-                     && test_ligature(&lig, cur, pre))
-                    || (nob != null && type(nob) == glyph_node
-                        && test_ligature(&lig, cur, nob))) {
-                    /* move cur from before disc, to skipped part */
-                    halfword prev = alink(cur);
-                    uncouple_node(cur);
-                    couple_nodes(prev, fwd);
-                    nesting_prepend(no_break(fwd), cur);
-                    /* now ligature the |pre_break| */
-                    nesting_prepend(pre_break(fwd), copy_node(cur));
-                    /* As we have removed cur, we need to start again ... */
-                    cur = prev;
-                }
-                /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
-                next = vlink(fwd);
-                if (nob == null && next != null && type(next) == glyph_node
-                    && test_ligature(&lig, cur, next)) {
-                    /* move |cur| from before |disc| to |no_break| part */
-                    halfword prev = alink(cur);
-                    uncouple_node(cur);
-                    couple_nodes(prev, fwd);
-                    couple_nodes(no_break(fwd), cur);   /* we {\it know\/} it's empty */
-                    /* now copy cur the |pre_break| */
-                    nesting_prepend(pre_break(fwd), copy_node(cur));
-                    /* move next from after disc to |no_break| part */
-                    tail = vlink(next);
-                    uncouple_node(next);
-                    try_couple_nodes(fwd, tail);
-                    couple_nodes(cur, next);    /* we {\it know\/} this works */
-                    tlink(no_break(fwd)) = next;        /* and make sure the list is correct */
-                    /* now copy next to the |post_break| */
-                    nesting_append(post_break(fwd), copy_node(next));
-                    /* As we have removed cur, we need to start again ... */
-                    cur = prev;
-                }
-                /* we are finished with the |pre_break| */
-                handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd));
-            } else if (type(fwd) == boundary_node) {
-                halfword next = vlink(fwd);
-                try_couple_nodes(cur, next);
-                flush_node(fwd);
-                if (right != null) {
-                    flush_node(right);  /* Shame, didn't need it */
-                    /* no need to reset |right|, we're going to leave the loop anyway */
-                }
-                break;
-            } else {
-                /* fwd is something unknown */
-                if (right == null)
-                    break;
-                couple_nodes(cur, right);
-                couple_nodes(right, fwd);
-                right = null;
-                continue;
-            }
-            /* A discretionary followed by ... */
-        } else if (type(cur) == disc_node) {
-            /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
-            if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
-                halfword prev = 0;
-                halfword fwd;
-                liginfo lig;
-                if (subtype(cur) == select_disc) {
-                    prev = alink(cur);
-                    if (vlink_post_break(cur) != null)
-                        handle_lig_nest(post_break(prev), vlink_post_break(prev));
-                    if (vlink_no_break(cur) != null)
-                        handle_lig_nest(no_break(prev), vlink_no_break(prev));
-                }
-                if (vlink_post_break(cur) != null)
-                    handle_lig_nest(post_break(cur), vlink_post_break(cur));
-                if (vlink_no_break(cur) != null)
-                    handle_lig_nest(no_break(cur), vlink_no_break(cur));
-                while ((fwd = vlink(cur)) != null) {
-                    halfword nob, pst, next;
-                    if (type(fwd) != glyph_node)
-                        break;
-                    if (subtype(cur) != select_disc) {
-                        nob = tlink_no_break(cur);
-                        pst = tlink_post_break(cur);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            break;
-                        nesting_append(no_break(cur), copy_node(fwd));
-                        handle_lig_nest(no_break(cur), nob);
-                    } else {
-                        int dobreak = 0;
-                        nob = tlink_no_break(prev);
-                        pst = tlink_post_break(prev);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            dobreak = 1;
-                        if (!dobreak) {
-                            nesting_append(no_break(prev), copy_node(fwd));
-                            handle_lig_nest(no_break(prev), nob);
-                            nesting_append(post_break(prev), copy_node(fwd));
-                            handle_lig_nest(post_break(prev), pst);
-                        }
-                        dobreak = 0;
-                        nob = tlink_no_break(cur);
-                        pst = tlink_post_break(cur);
-                        if ((nob == null || !test_ligature(&lig, nob, fwd)) &&
-                            (pst == null || !test_ligature(&lig, pst, fwd)))
-                            dobreak = 1;
-                        if (!dobreak) {
-                            nesting_append(no_break(cur), copy_node(fwd));
-                            handle_lig_nest(no_break(cur), nob);
-                        }
-                        if (dobreak)
-                            break;
-                    }
-                    next = vlink(fwd);
-                    uncouple_node(fwd);
-                    try_couple_nodes(cur, next);
-                    nesting_append(post_break(cur), fwd);
-                    handle_lig_nest(post_break(cur), pst);
-                }
-                if (fwd != null && type(fwd) == disc_node) {
-                        halfword next = vlink(fwd);
-                        if (vlink_no_break(fwd) == null
-                        && vlink_post_break(fwd) == null
-                        && next != null
-                        && type(next) == glyph_node
-                        && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) ||
-                            (tlink_no_break  (cur) != null && test_ligature(&lig, tlink_no_break  (cur), next)))) {
-                        /* Building an |init_disc| followed by a |select_disc|
-                          \.{{a-}{b}{AB} {-}{}{}} 'c'
-                         */
-                        /* is it tail necessary ? */
-                        halfword last1 = vlink(next), tail ;
-                        uncouple_node(next);
-                        try_couple_nodes(fwd, last1);
-                        /* \.{{a-}{b}{AB} {-}{c}{}} */
-                        nesting_append(post_break(fwd), copy_node(next));
-                        /* \.{{a-}{b}{AB} {-}{c}{-}} */
-                        if (vlink_no_break(cur) != null) {
-                            nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd)));
-                        }
-                        /* \.{{a-}{b}{AB} {b-}{c}{-}} */
-                        if (vlink_post_break(cur) != null)
-                            nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur)));
-                        /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
-                        if (vlink_no_break(cur) != null) {
-                            nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur)));
-                        }
-                        /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
-                        tail = tlink_no_break(cur);
-                        nesting_append(no_break(cur), copy_node(next));
-                        handle_lig_nest(no_break(cur), tail);
-                        /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
-                        tail = tlink_post_break(cur);
-                        nesting_append(post_break(cur), next);
-                        handle_lig_nest(post_break(cur), tail);
-                        /* and set the subtypes */
-                        subtype(cur) = init_disc;
-                        subtype(fwd) = select_disc;
-                    }
-                }
-            }
-
-        } else {
-            /* NO GLYPH NOR DISC */
-            return cur;
-        }
-        /* step-to-next-node */
-        /* \.{--\\par} allows |vlink(cur)| to be null */
-        cur = vlink(cur);
-    }
-
-    return cur;
-}
-
-@ Return value is the new tail, head should be a dummy
-
- at c
-halfword handle_ligaturing(halfword head, halfword tail)
-{
-    halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */
-    halfword cur, prev;
-
-    if (vlink(head) == null)
-        return tail;
-    if (tail != null) {
-        save_tail1 = vlink(tail);
-        vlink(tail) = null;
-    }
-
-    if (fix_node_lists) {
-        fix_node_list(head);
-    }
-
-    prev = head;
-    cur = vlink(prev);
-
-    while (cur != null) {
-        if (type(cur) == glyph_node || (type(cur) == boundary_node)) {
-            cur = handle_lig_word(cur);
-        }
-        prev = cur;
-        cur = vlink(cur);
-    }
-    if (prev == null) {
-        /* hh: looks bad to me */
-        prev = tail;
-    }
-
-    if (tail != null) {
-        try_couple_nodes(prev, save_tail1);
-    }
-    return prev;
-}
-
-
-@* Kerning.
-
- at c
-static void add_kern_before(halfword left, halfword right)
-{
-    if ((!is_rightghost(right)) &&
-        font(left) == font(right) && has_kern(font(left), character(left))) {
-        int k = raw_get_kern(font(left), character(left), character(right));
-        if (k != 0) {
-            halfword kern = new_kern(k);
-            halfword prev = alink(right);
-            couple_nodes(prev, kern);
-            couple_nodes(kern, right);
-            /* update the attribute list (inherit from left) */
-            delete_attribute_ref(node_attr(kern));
-            add_node_attr_ref(node_attr(left));
-            node_attr(kern) = node_attr(left);
-        }
-    }
-}
-
-static void add_kern_after(halfword left, halfword right, halfword aft)
-{
-    if ((!is_rightghost(right)) &&
-        font(left) == font(right) && has_kern(font(left), character(left))) {
-        int k = raw_get_kern(font(left), character(left), character(right));
-        if (k != 0) {
-            halfword kern = new_kern(k);
-            halfword next = vlink(aft);
-            couple_nodes(aft, kern);
-            try_couple_nodes(kern, next);
-            /* update the attribute list (inherit from left == aft) */
-            delete_attribute_ref(node_attr(kern));
-            add_node_attr_ref(node_attr(aft));
-            node_attr(kern) = node_attr(aft);
-        }
-    }
-}
-
-static void do_handle_kerning(halfword root, halfword init_left, halfword init_right)
-{
-    halfword cur = vlink(root);
-    halfword left = null;
-    if (cur == null) {
-        if (init_left != null && init_right != null) {
-            add_kern_after(init_left, init_right, root);
-            tlink(root) = vlink(root);
-        }
-        return;
-    }
-    if (type(cur) == glyph_node) {
-        set_is_glyph(cur);
-        if (init_left != null)
-            add_kern_before(init_left, cur);
-        left = cur;
-    }
-    while ((cur = vlink(cur)) != null) {
-        if (type(cur) == glyph_node) {
-            set_is_glyph(cur);
-            if (left != null) {
-                add_kern_before(left, cur);
-                if (character(left) < 0 || is_ghost(left)) {
-                    halfword prev = alink(left);
-                    couple_nodes(prev, cur);
-                    flush_node(left);
-                }
-            }
-            left = cur;
-        } else {
-            if (type(cur) == disc_node) {
-                halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null;
-                do_handle_kerning(pre_break(cur), left, null);
-                if (vlink_pre_break(cur) != null)
-                    tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur));
-                do_handle_kerning(post_break(cur), null, right);
-                if (vlink_post_break(cur) != null)
-                    tlink_post_break(cur) = tail_of_list(vlink_post_break(cur));
-                do_handle_kerning(no_break(cur), left, right);
-                if (vlink_no_break(cur) != null)
-                    tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));    /* needed? */
-            }
-            if (left != null) {
-                if (character(left) < 0 || is_ghost(left)) {
-                    halfword prev = alink(left);
-                    couple_nodes(prev, cur);
-                    flush_node(left);
-                }
-                left = null;
-            }
-        }
-    }
-    if (left != null) {
-        if (init_right != null)
-            add_kern_after(left, init_right, left);
-        if (character(left) < 0 || is_ghost(left)) {
-            halfword prev = alink(left);
-            halfword next = vlink(left);
-            if (next != null) {
-                couple_nodes(prev, next);
-                tlink(root) = next;
-            } else if (prev != root) {
-                vlink(prev) = null;
-                tlink(root) = prev;
-            } else {
-                vlink(root) = null;
-                tlink(root) = null;
-            }
-            flush_node(left);
-        }
-    }
-}
-
-/*
-halfword handle_kerning(halfword head, halfword tail)
-{
-    halfword save_link;
-    save_link = vlink(tail);
-    vlink(tail) = null;
-    tlink(head) = tail;
-    do_handle_kerning(head, null, null);
-    tail = tlink(head);
-    if (valid_node(save_link)) {
-        try_couple_nodes(tail, save_link);
-    }
-    return tail;
-}
-*/
-
-halfword handle_kerning(halfword head, halfword tail)
-{
-    halfword save_link = null;
-    if (tail == null) {
-        tlink(head) = null;
-        do_handle_kerning(head, null, null);
-    } else {
-        save_link = vlink(tail);
-        vlink(tail) = null;
-        tlink(head) = tail;
-        do_handle_kerning(head, null, null);
-        tail = tlink(head);
-        if (valid_node(save_link)) {
-            try_couple_nodes(tail, save_link);
-        }
-    }
-    return tail;
-}
-
-@* ligaturing and kerning : lua-interface.
-
- at c
-static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id)
-{
-    int i;
-    int top = lua_gettop(Luas);
-    if (!get_callback(Luas, callback_id)) {
-        lua_pop(Luas, 2);
-        return tail;
-    }
-    nodelist_to_lua(Luas, head);
-    nodelist_to_lua(Luas, tail);
-    if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
-        luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
-        return tail;
-    }
-    if (fix_node_lists) {
-        fix_node_list(head);
-    }
-    lua_settop(Luas, top);
-    return tail;
-}
-
-halfword new_ligkern(halfword head, halfword tail)
-{
-    int callback_id = 0;
-    if (vlink(head) == null)
-        return tail;
-    callback_id = callback_defined(ligaturing_callback);
-    if (callback_id > 0) {
-        tail = run_lua_ligkern_callback(head, tail, callback_id);
-        if (tail == null)
-            tail = tail_of_list(head);
-    } else if (callback_id == 0) {
-        tail = handle_ligaturing(head, tail);
-    }
-    callback_id = callback_defined(kerning_callback);
-    if (callback_id > 0) {
-        tail = run_lua_ligkern_callback(head, tail, callback_id);
-        if (tail == null) {
-            tail = tail_of_list(head);
-        }
-    } else if (callback_id == 0) {
-        halfword nest1 = new_node(nesting_node, 1);
-        halfword cur = vlink(head);
-        halfword aft = vlink(tail);
-        couple_nodes(nest1, cur);
-        tlink(nest1) = tail;
-        vlink(tail) = null;
-        do_handle_kerning(nest1, null, null);
-        couple_nodes(head, vlink(nest1));
-        tail = tlink(nest1);
-        try_couple_nodes(tail, aft);
-        flush_node(nest1);
-    }
-    return tail;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/mapfile.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,770 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <math.h>
+#include <kpathsea/c-auto.h>
+#include <kpathsea/c-memstr.h>
+#include <string.h>
+
+#define FM_BUF_SIZE 1024
+
+static FILE *fm_file;
+
+static unsigned char *fm_buffer = NULL;
+static int fm_size = 0;
+static int fm_curbyte = 0;
+
+#define fm_open(a)        (fm_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+#define fm_read_file()    readbinfile(fm_file,&fm_buffer,&fm_size)
+#define fm_close()        xfclose(fm_file, cur_file_name)
+#define fm_getchar()      fm_buffer[fm_curbyte++]
+#define fm_eof()          (fm_curbyte>fm_size)
+#define is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
+
+typedef enum { FM_DUPIGNORE, FM_REPLACE, FM_DELETE } updatemode;
+
+typedef struct mitem {
+    /*tex |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
+    updatemode mode;
+    /*tex map file or map line */
+    maptype type;
+    /*tex pointer to map file name or map line */
+    char *line;
+    /*tex line number in map file */
+    int lineno;
+} mapitem;
+
+mapitem *mitem = NULL;
+
+#define read_field(r, q, buf) do { \
+    q = buf;                       \
+    while (*r != ' ' && *r != '<' && *r != '"' && *r != '\0') \
+        *q++ = *r++;               \
+    *q = '\0';                     \
+    skip_char(r, ' ');             \
+} while (0)
+
+#define set_field(F) do {     \
+    if (q > buf)              \
+        fm->F = xstrdup(buf); \
+    if (*r == '\0')           \
+        goto done;            \
+} while (0)
+
+fm_entry *new_fm_entry(void)
+{
+    fm_entry *fm;
+    fm = xtalloc(1, fm_entry);
+    fm->tfm_name = NULL;
+    fm->ps_name = NULL;
+    fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
+    fm->ff_name = NULL;
+    fm->encname = NULL;
+    fm->type = 0;
+    fm->slant = 0;
+    fm->extend = 1000;
+    unset_slantset(fm);
+    unset_extendset(fm);
+    unset_inuse(fm);
+    return fm;
+}
+
+void delete_fm_entry(fm_entry * fm)
+{
+    xfree(fm->tfm_name);
+    xfree(fm->ps_name);
+    xfree(fm->ff_name);
+    xfree(fm);
+}
+
+static ff_entry *new_ff_entry(void)
+{
+    ff_entry *ff;
+    ff = xtalloc(1, ff_entry);
+    ff->ff_name = NULL;
+    ff->ff_path = NULL;
+    return ff;
+}
+
+static void delete_ff_entry(ff_entry * ff)
+{
+    xfree(ff->ff_name);
+    xfree(ff->ff_path);
+    xfree(ff);
+}
+
+static struct avl_table *tfm_tree = NULL;
+static struct avl_table *ff_tree = NULL;
+static struct avl_table *encname_tree = NULL;
+
+/*tex
+
+    We sort |fm_entry| into |tfm_tree| by |tfm_name|:
+
+*/
+
+static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const fm_entry *) pa)->tfm_name, ((const fm_entry *) pb)->tfm_name);
+}
+
+/* We sort |ff_entry| into |ff_tree| by |ff_name|: */
+
+static int comp_ff_entry(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const ff_entry *) pa)->ff_name, ((const ff_entry *) pb)->ff_name);
+}
+
+static void create_avl_trees(void)
+{
+    tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator);
+    ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator);
+    encname_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+}
+
+int avl_do_entry(fm_entry * fm, int mode)
+{
+    fm_entry *p;
+    void *a;
+    void **aa;
+    int delete_new = 0;
+    if (tfm_tree == NULL)
+        create_avl_trees();
+    p = (fm_entry *) avl_find(tfm_tree, fm);
+    if (p != NULL) {
+        switch (mode) {
+            case FM_DUPIGNORE:
+                formatted_warning("map file", "entry for '%s' already exists, duplicates ignored", fm->tfm_name);
+                delete_new = 1;
+                break;
+            case FM_REPLACE:
+            case FM_DELETE:
+                if (is_inuse(p)) {
+                    formatted_warning("map file", "entry for '%s' has been used, replace/delete not allowed", fm->tfm_name);
+                    delete_new = 1;
+                } else {
+                    a = avl_delete(tfm_tree, p);
+                    assert(a != NULL);
+                    delete_fm_entry(p);
+                }
+                break;
+            default:
+                formatted_error("map file", "something bad happened",0);
+        }
+    }
+    if ((mode == FM_DUPIGNORE || mode == FM_REPLACE) && delete_new == 0) {
+        aa = avl_probe(tfm_tree, fm);
+        if (aa == NULL) {
+            /*tex Is this a problem? */
+        }
+    } else
+        delete_new = 1;
+    return delete_new;
+}
+
+/*tex
+
+    Add the encoding name to an AVL tree. This has nothing to do with |writeenc.c|.
+
+*/
+
+static char *add_encname(char *s)
+{
+    char *p;
+    void **aa;
+    if ((p = (char *) avl_find(encname_tree, s)) == NULL) {
+        /*tex The encoding name has not yet been registered. */
+        p = xstrdup(s);
+        aa = avl_probe(encname_tree, p);
+        if (aa == NULL) {
+            /*tex Is this a problem? */
+        }
+    }
+    return p;
+}
+
+/*tex
+
+    A consistency check for map entry, with warn flag.
+
+*/
+
+static int check_fm_entry(fm_entry * fm, boolean warn)
+{
+    int a = 0;
+    if (is_fontfile(fm) && !is_included(fm)) {
+        if (warn)
+            formatted_warning("map file",
+                "ambiguous entry for '%s': font file present but not included, "
+                "will be treated as font file not present", fm->tfm_name);
+        xfree(fm->ff_name);
+        /*tex Do not set variable |a| as this entry will be still accepted. */
+    }
+    /*tex If both ps_name and font file are missing, drop this entry. */
+    if (fm->ps_name == NULL && !is_fontfile(fm)) {
+        if (warn)
+            formatted_warning("map file", "invalid entry for '%s': both ps_name and font file missing", fm->tfm_name);
+        a += 1;
+    }
+    /*tex \TRUETYPE\ fonts cannot be reencoded without subsetting. */
+    if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) {
+        if (warn)
+            formatted_warning("map file", "invalid entry for '%s': only subsetted TrueType font can be reencoded", fm->tfm_name);
+        a += 2;
+    }
+    /*tex The value of |SlantFont| and |ExtendFont| must be reasonable. */
+    if (fm->slant < FONT_SLANT_MIN || fm->slant > FONT_SLANT_MAX) {
+        if (warn)
+            formatted_warning("map file", "invalid entry for '%s': value '%g' is to large for SlantFont",
+                 fm->tfm_name, fm->slant / 1000.0);
+        a += 8;
+    }
+    if (fm->extend < FONT_EXTEND_MIN || fm->extend > FONT_EXTEND_MAX) {
+        if (warn)
+            formatted_warning("map file", "invalid entry for '%s': value '%g' is too large for ExtendFont",
+                 fm->tfm_name, fm->extend / 1000.0);
+        a += 16;
+    }
+    return a;
+}
+
+/*tex
+
+    Returns the font number if s is one of the 14 std. font names, -1 otherwise.
+    A bit speed trimmed. Using these base fonts is oldfashioned and doesn't
+    happen in a decent \LUATEX\ produced file.
+
+*/
+
+int check_std_t1font(char *s)
+{
+    static const char *std_t1font_names[] = {
+        "Courier",               /* 0:7 */
+        "Courier-Bold",          /* 1:12 */
+        "Courier-Oblique",       /* 2:15 */
+        "Courier-BoldOblique",   /* 3:19 */
+        "Helvetica",             /* 4:9 */
+        "Helvetica-Bold",        /* 5:14 */
+        "Helvetica-Oblique",     /* 6:17 */
+        "Helvetica-BoldOblique", /* 7:21 */
+        "Symbol",                /* 8:6 */
+        "Times-Roman",           /* 9:11 */
+        "Times-Bold",            /* 10:10 */
+        "Times-Italic",          /* 11:12 */
+        "Times-BoldItalic",      /* 12:16 */
+        "ZapfDingbats"           /* 13:12 */
+    };
+    static const int index[] = {
+        -1, -1, -1, -1, -1, -1, 8,  0, -1,  4, 10,
+         9, -1, -1,  5,  2, 12, 6, -1,  3, -1,  7
+    };
+    size_t n;
+    int k = -1;
+    n = strlen(s);
+    if (n > 21)
+        return -1;
+    if (n == 12) {
+        /*tex three names have length 12 */
+        switch (*s) {
+            case 'C':
+                /*tex Courier-Bold */
+                k = 1;
+                break;
+            case 'T':
+                /*tex Times-Italic */
+                k = 11;
+                break;
+            case 'Z':
+                /*tex ZapfDingbats */
+                k = 13;
+                break;
+            default:
+                return -1;
+        }
+    } else
+        k = index[n];
+    if (k > -1 && !strcmp(std_t1font_names[k], s))
+        return k;
+    return -1;
+}
+
+static void fm_scan_line(void)
+{
+    int a, b, c, j, u = 0, v = 0;
+    char cc;
+    float d;
+    fm_entry *fm;
+    char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
+    char *p, *q, *s;
+    char *r = NULL;
+    switch (mitem->type) {
+        case MAPFILE:
+            p = fm_line;
+            while (!fm_eof()) {
+                if (fm_curbyte == fm_size) {
+                    fm_curbyte++;
+                    cc = 10;
+                } else {
+                    cc = (char) fm_getchar();
+                }
+                append_char_to_buf(cc, p, fm_line, FM_BUF_SIZE);
+                if (cc == 10)
+                    break;
+            }
+            *(--p) = '\0';
+            r = fm_line;
+            break;
+        case MAPLINE:
+            /*tex Work on a string from |makecstring|. */
+            r = mitem->line;
+            break;
+        default:
+            assert(0);
+    }
+    if (*r == '\0' || is_cfg_comment(*r))
+        return;
+    fm = new_fm_entry();
+    read_field(r, q, buf);
+    set_field(tfm_name);
+    if (!isdigit((unsigned char)*r)) {
+        /*tex The 2nd field |ps_name| may not start with a digit. */
+        read_field(r, q, buf);
+        set_field(ps_name);
+    }
+    if (isdigit((unsigned char)*r)) {
+        /*tex Is the font descriptor |/Flags| given? */
+        for (s = r; isdigit((unsigned char)*s); s++);
+        if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') {
+            /*tex not e.g.\ |8r.enc| */
+            fm->fd_flags = atoi(r);
+            while (isdigit((unsigned char)*r))
+                r++;
+        }
+    }
+    /*tex Loop through specials, encoding, font file:*/
+    while (1) {
+        skip_char(r, ' ');
+        switch (*r) {
+            case '\0':
+                goto done;
+            case '"':
+                /*tex The pening quote. */
+                r++;
+                u = v = 0;
+                do {
+                    skip_char(r, ' ');
+                    if (sscanf(r, "%f %n", &d, &j) > 0) {
+                        /*tex Jump behind number, eat also blanks, if any. */
+                        s = r + j;
+                        if (*(s - 1) == 'E' || *(s - 1) == 'e') {
+                            /*tex  e.g.\ |0.5ExtendFont|: |%f = 0.5E| */
+                            s--;
+                        }
+                        if (str_prefix(s, "SlantFont")) {
+                            /*tex Correct rounding also for negative numbers. */
+                            d *= (float) 1000.0;
+                            fm->slant = (int) (d > 0 ? d + 0.5 : d - 0.5);
+                            set_slantset(fm);
+                            r = s + strlen("SlantFont");
+                        } else if (str_prefix(s, "ExtendFont")) {
+                            d *= (float) 1000.0;
+                            fm->extend = (int) (d > 0 ? d + 0.5 : d - 0.5);
+                            set_extendset(fm);
+                            r = s + strlen("ExtendFont");
+                        } else {
+                            /*tex unknown name, jump over it */
+                            for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++);
+                            c = *r;
+                            *r = '\0';
+                            formatted_warning("map file", "invalid entry for '%s': unknown name '%s' ignored", fm->tfm_name, s);
+                            *r = (char) c;
+                        }
+                    } else
+                        for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
+                }
+                while (*r == ' ');
+                if (*r == '"') {
+                    /*tex The closing quote. */
+                    r++;
+                } else {
+                    formatted_warning("map file", "invalid entry for '%s': closing quote missing", fm->tfm_name);
+                    goto bad_line;
+                }
+                break;
+            case 'P':
+                /*tex Handle cases for sub fonts like |PidEid=3,1| */
+                formatted_warning("map file", "invalid entry for '%s': subfonts are not supported", fm->tfm_name);
+                goto bad_line;
+                break;
+            default:
+                /*tex Encoding or font file specification. */
+                a = b = 0;
+                if (*r == '<') {
+                    a = *r++;
+                    if (*r == '<' || *r == '[')
+                        b = *r++;
+                }
+                read_field(r, q, buf);
+                /*tex Encoding, Formats: |8r.enc| or |<8r.enc| or |<[8r.enc| */
+                if (strlen(buf) > 4 && strcasecmp(strend(buf) - 4, ".enc") == 0) {
+                    /*tex |u|, |v| used if intervening blank: |<< foo| */
+                    fm->encname = add_encname(buf);
+                    u = v = 0;
+                } else if (strlen(buf) > 0) {
+                    /*tex
+
+                        We get the file name given where possible formats are:
+
+                        \starttabulate[|||]
+                        \NC subsetting    \NC \tpe {<cmr10.pfa}  \NC \NR
+                        \NC no subsetting \NC \tpe {<<cmr10.pfa} \NC \NR
+                        \NC no embedding  \NC \tpe {cmr10.pfa}   \NC \NR
+                        \stoptabulate
+
+                    */
+                    if (a == '<' || u == '<') {
+                        set_included(fm);
+                        if ((a == '<' && b == 0) || (a == 0 && v == 0)) {
+                            set_subsetted(fm);
+                        } else {
+                            /*tex
+
+                                Otherwise |b| equals |<| or |[| which means that we have no subsetting.
+                            */
+                        }
+                    }
+                    set_field(ff_name);
+                    u = v = 0;
+                } else {
+                    u = a;
+                    v = b;
+                }
+        }
+    }
+  done:
+    if (fm->ps_name != NULL && (check_std_t1font(fm->ps_name) >= 0))
+        set_std_t1font(fm);
+    if (is_fontfile(fm) && strlen(fm_fontfile(fm)) > 3) {
+        if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 0)
+            set_truetype(fm);
+        else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttc") == 0)
+            set_truetype(fm);
+        else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".otf") == 0)
+            set_opentype(fm);
+        else
+            set_type1(fm);
+    } else {
+        /*tex Assume a builtin font is \TYPEONE\: */
+        set_type1(fm);
+    }
+    if (check_fm_entry(fm, true) != 0)
+        goto bad_line;
+    /*tex
+
+       Until here the map line has been completely scanned without errors; |fm|
+       points to a valid, freshly filled-out |fm_entry| structure. Now follows
+       the actual work of registering or deleting.
+
+    */
+    if (avl_do_entry(fm, mitem->mode) == 0)
+        return;
+  bad_line:
+    delete_fm_entry(fm);
+}
+
+static void fm_read_info(void)
+{
+    int callback_id;
+    int file_opened = 0;
+
+    if (tfm_tree == NULL)
+        create_avl_trees();
+    if (mitem->line == NULL) {
+        /*tex There is nothing to do. */
+        return;
+    }
+    mitem->lineno = 1;
+    switch (mitem->type) {
+    case MAPFILE:
+        xfree(fm_buffer);
+        fm_curbyte = 0;
+        fm_size = 0;
+        cur_file_name = luatex_find_file(mitem->line, find_map_file_callback);
+        if (cur_file_name) {
+            callback_id = callback_defined(read_map_file_callback);
+            if (callback_id > 0) {
+                if (run_callback(callback_id, "S->bSd", cur_file_name,
+                                 &file_opened, &fm_buffer, &fm_size)) {
+                    if (file_opened) {
+                        if (fm_size > 0) {
+                            report_start_file(filetype_map,cur_file_name);
+                            while (!fm_eof()) {
+                                fm_scan_line();
+                                mitem->lineno++;
+                            }
+                            report_stop_file(filetype_map);
+                            fm_file = NULL;
+                        }
+                    } else {
+                        formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+                    }
+                } else {
+                    formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+                }
+            } else {
+                if (!fm_open(cur_file_name)) {
+                    formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
+                } else {
+                    fm_read_file();
+                    report_start_file(filetype_map,cur_file_name);
+                    while (!fm_eof()) {
+                        fm_scan_line();
+                        mitem->lineno++;
+                    }
+                    fm_close();
+                    report_stop_file(filetype_map);
+                    fm_file = NULL;
+                }
+            }
+            cur_file_name = NULL;
+        }
+        break;
+    case MAPLINE:
+        cur_file_name = NULL;
+        fm_scan_line();
+        break;
+    default:
+        assert(0);
+    }
+    /*tex Done with this line: */
+    mitem->line = NULL;
+    cur_file_name = NULL;
+    return;
+}
+
+fm_entry *getfontmap(char *tfm_name)
+{
+    fm_entry *fm;
+    fm_entry tmp;
+    if (tfm_name == NULL) {
+        /*tex Wide \LUA\ loaded fonts may not have a name. */
+        return NULL;
+    }
+    if (tfm_tree == NULL) {
+        /*tex Only read the default map file. */
+        fm_read_info();
+    }
+    /*tex Look up the name. */
+    tmp.tfm_name = tfm_name;
+    fm = (fm_entry *) avl_find(tfm_tree, &tmp);
+    if (fm == NULL)
+        return NULL;
+    set_inuse(fm);
+    return fm;
+}
+
+/*tex
+
+    Process map file given by its name or map line contents. Items not beginning
+    with [+-=] flush default map file, if it has not yet been read. Leading
+    blanks and blanks immediately following [+-=] are ignored.
+
+*/
+
+void process_map_item(char *s, int type)
+{
+    char *p;
+    int mode;
+    if (*s == ' ') {
+        /*tex Ignore leading blanks: */
+        s++;
+    }
+    switch (*s) {
+        case '+':
+            /* +mapfile.map, +mapline: insert an entry, if it is not duplicate */
+            mode = FM_DUPIGNORE;
+            s++;
+            break;
+        case '=':
+            /* =mapfile.map, =mapline: try to replace an existing entry */
+            mode = FM_REPLACE;
+            s++;
+            break;
+        case '-':
+            /* -mapfile.map, -mapline: try to delete an entry */
+            mode = FM_DELETE;
+            s++;
+            break;
+        default:
+            /* like +, but also: flush the default map file name */
+            mode = FM_DUPIGNORE;
+            mitem->line = NULL;
+    }
+    if (*s == ' ') {
+        /*tex Ignore a blank after |[+-=]| */
+        s++;
+    }
+    /*tex The map item starts here. */
+    p = s;
+    switch (type) {
+        case MAPFILE:
+            /*tex Remove blank at the end. */
+            while (*p != '\0' && *p != ' ')
+                p++;
+            *p = '\0';
+            break;
+        case MAPLINE:
+            /*tex A blank at end is allowed. */
+            break;
+        default:
+            assert(0);
+    }
+    if (mitem->line != NULL) {
+        /*tex Read default map file first */
+        fm_read_info();
+    }
+    if (*s != '\0') {
+        /*tex Only if real item to process. */
+        mitem->mode = mode;
+        mitem->type = type;
+        mitem->line = s;
+        fm_read_info();
+    }
+}
+
+void pdfmapfile(int t)
+{
+    char *s = tokenlist_to_cstring(t, true, NULL);
+    process_map_item(s, MAPFILE);
+    free(s);
+}
+
+void pdfmapline(int t)
+{
+    char *s = tokenlist_to_cstring(t, true, NULL);
+    process_map_item(s, MAPLINE);
+    free(s);
+}
+
+void pdf_init_map_file(const char *map_name)
+{
+    assert(mitem == NULL);
+    mitem = xtalloc(1, mapitem);
+    mitem->mode = FM_DUPIGNORE;
+    mitem->type = MAPFILE;
+    mitem->line = xstrdup(map_name);
+}
+
+/*tex
+
+    An early check whether a font file exists. Search tree |ff_tree| is used in
+    1st instance, as it may be faster than the |kpse_find_file|, and
+    |kpse_find_file| is called only once per font file name plus expansion
+    parameter. This might help keeping speed, if many \PDF\ pages with same fonts
+    are to be embedded (not that we deal with that fragile approach any longer in
+    \LUATEX).
+
+    The |ff_tree| contains only font files, which are actually needed, so this tree
+    typically is much smaller than the tfm_tree.
+
+*/
+
+ff_entry *check_ff_exist(char *ff_name, boolean is_tt)
+{
+    ff_entry *ff;
+    ff_entry tmp;
+    void **aa;
+    int callback_id;
+    char *filepath = NULL;
+    tmp.ff_name = ff_name;
+    ff = (ff_entry *) avl_find(ff_tree, &tmp);
+    if (ff == NULL) {
+        /*tex The name is not yet in the database. */
+        ff = new_ff_entry();
+        ff->ff_name = xstrdup(ff_name);
+        if (is_tt) {
+            callback_id = callback_defined(find_truetype_file_callback);
+            if (callback_id > 0) {
+                run_callback(callback_id, "S->S", ff_name, &filepath);
+                if (filepath && strlen(filepath) == 0)
+                    filepath = NULL;
+                ff->ff_path = filepath;
+            } else {
+                ff->ff_path = kpse_find_file(ff_name, kpse_truetype_format, 0);
+            }
+        } else {
+            callback_id = callback_defined(find_type1_file_callback);
+            if (callback_id > 0) {
+                run_callback(callback_id, "S->S", ff_name, &filepath);
+                if (filepath && strlen(filepath) == 0)
+                    filepath = NULL;
+                ff->ff_path = filepath;
+            } else {
+                ff->ff_path = kpse_find_file(ff_name, kpse_type1_format, 0);
+            }
+        }
+        aa = avl_probe(ff_tree, ff);
+        if (aa == NULL) {
+            /*tex Is this a problem? */
+        }
+    }
+    return ff;
+}
+
+int is_subsetable(fm_entry * fm)
+{
+    assert(is_included(fm));
+    return is_subsetted(fm);
+}
+
+/*tex Cleaning up: */
+
+static void destroy_fm_entry_tfm(void *pa, void *pb)
+{
+    fm_entry *fm;
+    (void) pb;
+    fm = (fm_entry *) pa;
+    delete_fm_entry(fm);
+}
+
+static void destroy_ff_entry(void *pa, void *pb)
+{
+    ff_entry *ff;
+    (void) pb;
+    ff = (ff_entry *) pa;
+    delete_ff_entry(ff);
+}
+
+void fm_free(void)
+{
+    if (tfm_tree != NULL) {
+        avl_destroy(tfm_tree, destroy_fm_entry_tfm);
+        tfm_tree = NULL;
+    }
+    if (ff_tree != NULL) {
+        avl_destroy(ff_tree, destroy_ff_entry);
+        ff_tree = NULL;
+    }
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/mapfile.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,715 +0,0 @@
-% mapfile.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <math.h>
-#include <kpathsea/c-auto.h>
-#include <kpathsea/c-memstr.h>
-#include <string.h>
-
-#define FM_BUF_SIZE     1024
-
-static FILE *fm_file;
-
-static unsigned char *fm_buffer = NULL;
-static int fm_size = 0;
-static int fm_curbyte = 0;
-
-#define fm_open(a)      (fm_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-#define fm_read_file()  readbinfile(fm_file,&fm_buffer,&fm_size)
-#define fm_close()      xfclose(fm_file, cur_file_name)
-#define fm_getchar()    fm_buffer[fm_curbyte++]
-#define fm_eof()        (fm_curbyte>fm_size)
-#define is_cfg_comment(c) \
-    (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
-
-typedef enum { FM_DUPIGNORE, FM_REPLACE, FM_DELETE } updatemode;
-
-typedef struct mitem {
-    updatemode mode;            /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE */
-    maptype type;               /* map file or map line */
-    char *line;                 /* pointer to map file name or map line */
-    int lineno;                 /* line number in map file */
-} mapitem;
-mapitem *mitem = NULL;
-
-#define read_field(r, q, buf) do {  \
-    q = buf;                        \
-    while (*r != ' ' && *r != '<' && *r != '"' && *r != '\0') \
-        *q++ = *r++;                \
-    *q = '\0';                      \
-    skip_char(r, ' ');                  \
-} while (0)
-
-#define set_field(F) do {           \
-    if (q > buf)                    \
-        fm->F = xstrdup(buf);       \
-    if (*r == '\0')                 \
-        goto done;                  \
-} while (0)
-
-fm_entry *new_fm_entry(void)
-{
-    fm_entry *fm;
-    fm = xtalloc(1, fm_entry);
-    fm->tfm_name = NULL;
-    fm->ps_name = NULL;
-    fm->fd_flags = FD_FLAGS_NOT_SET_IN_MAPLINE;
-    fm->ff_name = NULL;
-    fm->encname = NULL;
-    fm->type = 0;
-    fm->slant = 0;
-    fm->extend = 1000;
-    unset_slantset(fm);
-    unset_extendset(fm);
-    unset_inuse(fm);
-    return fm;
-}
-
-void delete_fm_entry(fm_entry * fm)
-{
-    xfree(fm->tfm_name);
-    xfree(fm->ps_name);
-    xfree(fm->ff_name);
-    xfree(fm);
-}
-
-static ff_entry *new_ff_entry(void)
-{
-    ff_entry *ff;
-    ff = xtalloc(1, ff_entry);
-    ff->ff_name = NULL;
-    ff->ff_path = NULL;
-    return ff;
-}
-
-static void delete_ff_entry(ff_entry * ff)
-{
-    xfree(ff->ff_name);
-    xfree(ff->ff_path);
-    xfree(ff);
-}
-
-/**********************************************************************/
-
-static struct avl_table *tfm_tree = NULL;
-static struct avl_table *ff_tree = NULL;
-static struct avl_table *encname_tree = NULL;
-
-/* AVL sort fm_entry into tfm_tree by tfm_name */
-
-static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const fm_entry *) pa)->tfm_name,
-                  ((const fm_entry *) pb)->tfm_name);
-}
-
-/* AVL sort ff_entry into ff_tree by ff_name */
-
-static int comp_ff_entry(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const ff_entry *) pa)->ff_name,
-                  ((const ff_entry *) pb)->ff_name);
-}
-
-static void create_avl_trees(void)
-{
-    assert(tfm_tree == NULL);
-    tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator);
-    assert(tfm_tree != NULL);
-    assert(ff_tree == NULL);
-    ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator);
-    assert(ff_tree != NULL);
-    assert(encname_tree == NULL);
-    encname_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
-    assert(encname_tree != NULL);
-}
-
-int avl_do_entry(fm_entry * fm, int mode)
-{
-    fm_entry *p;
-    void *a;
-    void **aa;
-    int delete_new = 0;
-    if (tfm_tree == NULL)
-        create_avl_trees();
-    p = (fm_entry *) avl_find(tfm_tree, fm);
-    if (p != NULL) {
-        switch (mode) {
-        case FM_DUPIGNORE:
-            formatted_warning("map file", "entry for '%s' already exists, duplicates ignored", fm->tfm_name);
-            delete_new = 1;
-            break;
-        case FM_REPLACE:
-        case FM_DELETE:
-            if (is_inuse(p)) {
-                formatted_warning("map file", "entry for '%s' has been used, replace/delete not allowed", fm->tfm_name);
-                delete_new = 1;
-            } else {
-                a = avl_delete(tfm_tree, p);
-                assert(a != NULL);
-                delete_fm_entry(p);
-            }
-            break;
-        default:
-            assert(0);
-        }
-    }
-    if ((mode == FM_DUPIGNORE || mode == FM_REPLACE) && delete_new == 0) {
-        aa = avl_probe(tfm_tree, fm);
-        assert(aa != NULL);
-    } else
-        delete_new = 1;
-    return delete_new;
-}
-
-/* add the encoding name to an AVL tree. this has nothing to do with writeenc.c */
-
-static char *add_encname(char *s)
-{
-    char *p;
-    void **aa;
-    assert(s != NULL);
-    assert(encname_tree != NULL);
-    if ((p = (char *) avl_find(encname_tree, s)) == NULL) {     /* encoding name not yet registered */
-        p = xstrdup(s);
-        aa = avl_probe(encname_tree, p);
-        assert(aa != NULL);
-    }
-    return p;
-}
-
-/**********************************************************************/
-/* consistency check for map entry, with warn flag */
-
-static int check_fm_entry(fm_entry * fm, boolean warn)
-{
-    int a = 0;
-    assert(fm != NULL);
-
-    if (is_fontfile(fm) && !is_included(fm)) {
-        if (warn)
-            formatted_warning("map file",
-                 "ambiguous entry for '%s': font file present but not included, "
-                 "will be treated as font file not present", fm->tfm_name);
-        xfree(fm->ff_name);
-        /* do not set variable |a| as this entry will be still accepted */
-    }
-
-    /* if both ps_name and font file are missing, drop this entry */
-    if (fm->ps_name == NULL && !is_fontfile(fm)) {
-        if (warn)
-            formatted_warning("map file", "invalid entry for '%s': both ps_name and font file missing", fm->tfm_name);
-        a += 1;
-    }
-
-    /* TrueType fonts cannot be reencoded without subsetting */
-    if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) {
-        if (warn)
-            formatted_warning("map file", "invalid entry for '%s': only subsetted TrueType font can be reencoded", fm->tfm_name);
-        a += 2;
-    }
-
-    /* the value of SlantFont and ExtendFont must be reasonable */
-    if (fm->slant < FONT_SLANT_MIN || fm->slant > FONT_SLANT_MAX) {
-        if (warn)
-            formatted_warning("map file", "invalid entry for '%s': value '%g' is to large for SlantFont",
-                 fm->tfm_name, fm->slant / 1000.0);
-        a += 8;
-    }
-    if (fm->extend < FONT_EXTEND_MIN || fm->extend > FONT_EXTEND_MAX) {
-        if (warn)
-            formatted_warning("map file", "invalid entry for '%s': value '%g' is too large for ExtendFont",
-                 fm->tfm_name, fm->extend / 1000.0);
-        a += 16;
-    }
-
-    return a;
-}
-
-/**********************************************************************/
-/* returns the font number if s is one of the 14 std. font names, -1 otherwise; speed-trimmed. */
-
-int check_std_t1font(char *s)
-{
-    static const char *std_t1font_names[] = {
-        "Courier",              /* 0:7 */
-        "Courier-Bold",         /* 1:12 */
-        "Courier-Oblique",      /* 2:15 */
-        "Courier-BoldOblique",  /* 3:19 */
-        "Helvetica",            /* 4:9 */
-        "Helvetica-Bold",       /* 5:14 */
-        "Helvetica-Oblique",    /* 6:17 */
-        "Helvetica-BoldOblique",        /* 7:21 */
-        "Symbol",               /* 8:6 */
-        "Times-Roman",          /* 9:11 */
-        "Times-Bold",           /* 10:10 */
-        "Times-Italic",         /* 11:12 */
-        "Times-BoldItalic",     /* 12:16 */
-        "ZapfDingbats"          /* 13:12 */
-    };
-    static const int index[] =
-        { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, -1,
-        3, -1, 7
-    };
-    size_t n;
-    int k = -1;
-    assert(s != NULL);
-    n = strlen(s);
-    if (n > 21)
-        return -1;
-    if (n == 12) {              /* three names have length 12 */
-        switch (*s) {
-        case 'C':
-            k = 1;              /* Courier-Bold */
-            break;
-        case 'T':
-            k = 11;             /* Times-Italic */
-            break;
-        case 'Z':
-            k = 13;             /* ZapfDingbats */
-            break;
-        default:
-            return -1;
-        }
-    } else
-        k = index[n];
-    if (k > -1 && !strcmp(std_t1font_names[k], s))
-        return k;
-    return -1;
-}
-
-/**********************************************************************/
-
-static void fm_scan_line(void)
-{
-    int a, b, c, j, u = 0, v = 0;
-    char cc;
-    float d;
-    fm_entry *fm;
-    char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
-    char *p, *q, *s;
-    char *r = NULL;
-    switch (mitem->type) {
-    case MAPFILE:
-        p = fm_line;
-        while (!fm_eof()) {
-            if (fm_curbyte == fm_size) {
-                fm_curbyte++;
-                cc = 10;
-            } else {
-                cc = (char) fm_getchar();
-            }
-            append_char_to_buf(cc, p, fm_line, FM_BUF_SIZE);
-            if (cc == 10)
-                break;
-        }
-        *(--p) = '\0';
-        r = fm_line;
-        break;
-    case MAPLINE:
-        r = mitem->line;        /* work on string from makecstring() */
-        break;
-    default:
-        assert(0);
-    }
-    if (*r == '\0' || is_cfg_comment(*r))
-        return;
-    fm = new_fm_entry();
-    read_field(r, q, buf);
-    set_field(tfm_name);
-    if (!isdigit((unsigned char)*r)) {         /* 2nd field ps_name may not start with a digit */
-        read_field(r, q, buf);
-        set_field(ps_name);
-    }
-    if (isdigit((unsigned char)*r)) {          /* font descriptor /Flags given? */
-        for (s = r; isdigit((unsigned char)*s); s++);
-        if (*s == ' ' || *s == '"' || *s == '<' || *s == '\0') {        /* not e. g. 8r.enc */
-            fm->fd_flags = atoi(r);
-            while (isdigit((unsigned char)*r))
-                r++;
-        }
-    }
-    while (1) {                 /* loop through "specials", encoding, font file */
-        skip_char(r, ' ');
-        switch (*r) {
-        case '\0':
-            goto done;
-        case '"':              /* opening quote */
-            r++;
-            u = v = 0;
-            do {
-                skip_char(r, ' ');
-                if (sscanf(r, "%f %n", &d, &j) > 0) {
-                    s = r + j;  /* jump behind number, eat also blanks, if any */
-                    if (*(s - 1) == 'E' || *(s - 1) == 'e')
-                        s--;    /* e. g. 0.5ExtendFont: %f = 0.5E */
-                    if (str_prefix(s, "SlantFont")) {
-                        d *= (float) 1000.0;    /* correct rounding also for neg. numbers */
-                        fm->slant = (int) (d > 0 ? d + 0.5 : d - 0.5);
-                        set_slantset(fm);
-                        r = s + strlen("SlantFont");
-                    } else if (str_prefix(s, "ExtendFont")) {
-                        d *= (float) 1000.0;
-                        fm->extend = (int) (d > 0 ? d + 0.5 : d - 0.5);
-                        set_extendset(fm);
-                        r = s + strlen("ExtendFont");
-                    } else {    /* unknown name */
-                        for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++); /* jump over name */
-                        c = *r; /* remember char for temporary end of string */
-                        *r = '\0';
-                        formatted_warning("map file", "invalid entry for '%s': unknown name '%s' ignored", fm->tfm_name, s);
-                        *r = (char) c;
-                    }
-                } else
-                    for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
-            }
-            while (*r == ' ');
-            if (*r == '"')      /* closing quote */
-                r++;
-            else {
-                formatted_warning("map file", "invalid entry for '%s': closing quote missing", fm->tfm_name);
-                goto bad_line;
-            }
-            break;
-        case 'P':              /* handle cases for sub fonts like 'PidEid=3,1' */
-            formatted_warning("map file", "invalid entry for '%s': subfonts are not supported", fm->tfm_name);
-            goto bad_line;
-            break;
-        default:               /* encoding or font file specification */
-            a = b = 0;
-            if (*r == '<') {
-                a = *r++;
-                if (*r == '<' || *r == '[')
-                    b = *r++;
-            }
-            read_field(r, q, buf);
-            /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
-            if (strlen(buf) > 4 && strcasecmp(strend(buf) - 4, ".enc") == 0) {
-                fm->encname = add_encname(buf);
-                u = v = 0;      /* u, v used if intervening blank: "<< foo" */
-            } else if (strlen(buf) > 0) {       /* file name given */
-                /* font file, formats:
-                 * subsetting:    '<cmr10.pfa'
-                 * no subsetting: '<<cmr10.pfa'
-                 * no embedding:  'cmr10.pfa'
-                 */
-                if (a == '<' || u == '<') {
-                    set_included(fm);
-                    if ((a == '<' && b == 0) || (a == 0 && v == 0))
-                        set_subsetted(fm);
-                    /* otherwise b == '<' (or '[') => no subsetting */
-                }
-                set_field(ff_name);
-                u = v = 0;
-            } else {
-                u = a;
-                v = b;
-            }
-        }
-    }
-  done:
-    if (fm->ps_name != NULL && (check_std_t1font(fm->ps_name) >= 0))
-        set_std_t1font(fm);
-    if (is_fontfile(fm) && strlen(fm_fontfile(fm)) > 3) {
-        if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 0)
-            set_truetype(fm);
-        else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttc") == 0)
-            set_truetype(fm);
-        else if (strcasecmp(strend(fm_fontfile(fm)) - 4, ".otf") == 0)
-            set_opentype(fm);
-        else
-            set_type1(fm);
-    } else
-        set_type1(fm);          /* assume a builtin font is Type1 */
-    if (check_fm_entry(fm, true) != 0)
-        goto bad_line;
-    /*
-       Until here the map line has been completely scanned without errors;
-       fm points to a valid, freshly filled-out fm_entry structure.
-       Now follows the actual work of registering/deleting.
-     */
-    if (avl_do_entry(fm, mitem->mode) == 0)
-        return;
-  bad_line:
-    delete_fm_entry(fm);
-}
-
-/**********************************************************************/
-
-static void fm_read_info(void)
-{
-    int callback_id;
-    int file_opened = 0;
-
-    if (tfm_tree == NULL)
-        create_avl_trees();
-    if (mitem->line == NULL)    /* nothing to do */
-        return;
-    mitem->lineno = 1;
-    switch (mitem->type) {
-    case MAPFILE:
-        xfree(fm_buffer);
-        fm_curbyte = 0;
-        fm_size = 0;
-        cur_file_name = luatex_find_file(mitem->line, find_map_file_callback);
-        if (cur_file_name) {
-            callback_id = callback_defined(read_map_file_callback);
-            if (callback_id > 0) {
-                if (run_callback(callback_id, "S->bSd", cur_file_name,
-                                 &file_opened, &fm_buffer, &fm_size)) {
-                    if (file_opened) {
-                        if (fm_size > 0) {
-                            report_start_file(filetype_map,cur_file_name);
-                            while (!fm_eof()) {
-                                fm_scan_line();
-                                mitem->lineno++;
-                            }
-                            report_stop_file(filetype_map);
-                            fm_file = NULL;
-                        }
-                    } else {
-                        formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
-                    }
-                } else {
-                    formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
-                }
-            } else {
-                if (!fm_open(cur_file_name)) {
-                    formatted_warning("map file", "cannot open font map file '%s'", cur_file_name);
-                } else {
-                    fm_read_file();
-                    report_start_file(filetype_map,cur_file_name);
-                    while (!fm_eof()) {
-                        fm_scan_line();
-                        mitem->lineno++;
-                    }
-                    fm_close();
-                    report_stop_file(filetype_map);
-                    fm_file = NULL;
-                }
-            }
-            cur_file_name = NULL;
-        }
-        break;
-    case MAPLINE:
-        cur_file_name = NULL;
-        fm_scan_line();
-        break;
-    default:
-        assert(0);
-    }
-    mitem->line = NULL;         /* done with this line */
-    cur_file_name = NULL;
-    return;
-}
-
-/**********************************************************************/
-
-fm_entry *getfontmap(char *tfm_name)
-{
-    fm_entry *fm;
-    fm_entry tmp;
-    if (tfm_name == NULL)       /* wide, lua loaded fonts may not have a name */
-        return NULL;
-    if (tfm_tree == NULL)
-        fm_read_info();         /* only to read default map file */
-    tmp.tfm_name = tfm_name;    /* Look up for tfmname */
-    fm = (fm_entry *) avl_find(tfm_tree, &tmp);
-    if (fm == NULL)
-        return NULL;
-    set_inuse(fm);
-    return fm;
-}
-
-/**********************************************************************/
-/*
- * Process map file given by its name or map line contents. Items not
- * beginning with [+-=] flush default map file, if it has not yet been
- * read. Leading blanks and blanks immediately following [+-=] are
- * ignored.
- */
-
-void process_map_item(char *s, int type)
-{
-    char *p;
-    int mode;
-    if (*s == ' ')
-        s++;                    /* ignore leading blank */
-    switch (*s) {
-    case '+':                  /* +mapfile.map, +mapline */
-        mode = FM_DUPIGNORE;    /* insert entry, if it is not duplicate */
-        s++;
-        break;
-    case '=':                  /* =mapfile.map, =mapline */
-        mode = FM_REPLACE;      /* try to replace earlier entry */
-        s++;
-        break;
-    case '-':                  /* -mapfile.map, -mapline */
-        mode = FM_DELETE;       /* try to delete entry */
-        s++;
-        break;
-    default:
-        mode = FM_DUPIGNORE;    /* like +, but also: */
-        mitem->line = NULL;     /* flush default map file name */
-    }
-    if (*s == ' ')
-        s++;                    /* ignore blank after [+-=] */
-    p = s;                      /* map item starts here */
-    switch (type) {
-    case MAPFILE:              /* remove blank at end */
-        while (*p != '\0' && *p != ' ')
-            p++;
-        *p = '\0';
-        break;
-    case MAPLINE:              /* blank at end allowed */
-        break;
-    default:
-        assert(0);
-    }
-    if (mitem->line != NULL)    /* read default map file first */
-        fm_read_info();
-    if (*s != '\0') {           /* only if real item to process */
-        mitem->mode = mode;
-        mitem->type = type;
-        mitem->line = s;
-        fm_read_info();
-    }
-}
-
-void pdfmapfile(int t)
-{
-    char *s = tokenlist_to_cstring(t, true, NULL);
-    process_map_item(s, MAPFILE);
-    free(s);
-}
-
-void pdfmapline(int t)
-{
-    char *s = tokenlist_to_cstring(t, true, NULL);
-    process_map_item(s, MAPLINE);
-    free(s);
-}
-
-void pdf_init_map_file(const char *map_name)
-{
-    assert(mitem == NULL);
-    mitem = xtalloc(1, mapitem);
-    mitem->mode = FM_DUPIGNORE;
-    mitem->type = MAPFILE;
-    mitem->line = xstrdup(map_name);
-}
-
-/**********************************************************************/
-/*
- * Early check whether a font file exists. Search tree ff_tree is used
- * in 1st instance, as it may be faster than the kpse_find_file(), and
- * kpse_find_file() is called only once per font file name + expansion
- * parameter. This might help keeping speed, if many PDF pages with
- * same fonts are to be embedded.
- *
- * The ff_tree contains only font files, which are actually needed,
- * so this tree typically is much smaller than the tfm_tree.
- */
-
-ff_entry *check_ff_exist(char *ff_name, boolean is_tt)
-{
-    ff_entry *ff;
-    ff_entry tmp;
-    void **aa;
-    int callback_id;
-    char *filepath = NULL;
-
-    assert(ff_name != NULL);
-    tmp.ff_name = ff_name;
-    ff = (ff_entry *) avl_find(ff_tree, &tmp);
-    if (ff == NULL) {           /* not yet in database */
-        ff = new_ff_entry();
-        ff->ff_name = xstrdup(ff_name);
-        if (is_tt) {
-            callback_id = callback_defined(find_truetype_file_callback);
-            if (callback_id > 0) {
-                run_callback(callback_id, "S->S", ff_name, &filepath);
-                if (filepath && strlen(filepath) == 0)
-                    filepath = NULL;
-                ff->ff_path = filepath;
-            } else {
-                ff->ff_path = kpse_find_file(ff_name, kpse_truetype_format, 0);
-            }
-        } else {
-            callback_id = callback_defined(find_type1_file_callback);
-            if (callback_id > 0) {
-                run_callback(callback_id, "S->S", ff_name, &filepath);
-                if (filepath && strlen(filepath) == 0)
-                    filepath = NULL;
-                ff->ff_path = filepath;
-            } else {
-                ff->ff_path = kpse_find_file(ff_name, kpse_type1_format, 0);
-            }
-        }
-        aa = avl_probe(ff_tree, ff);
-        assert(aa != NULL);
-    }
-    return ff;
-}
-
-/**********************************************************************/
-
-int is_subsetable(fm_entry * fm)
-{
-    assert(is_included(fm));
-    return is_subsetted(fm);
-}
-
-/**********************************************************************/
-/* cleaning up... */
-
-static void destroy_fm_entry_tfm(void *pa, void *pb)
-{
-    fm_entry *fm;
-    (void) pb;
-    fm = (fm_entry *) pa;
-    delete_fm_entry(fm);
-}
-
-static void destroy_ff_entry(void *pa, void *pb)
-{
-    ff_entry *ff;
-    (void) pb;
-    ff = (ff_entry *) pa;
-    delete_ff_entry(ff);
-}
-
-void fm_free(void)
-{
-    if (tfm_tree != NULL) {
-        avl_destroy(tfm_tree, destroy_fm_entry_tfm);
-        tfm_tree = NULL;
-    }
-    if (ff_tree != NULL) {
-        avl_destroy(ff_tree, destroy_ff_entry);
-        ff_tree = NULL;
-    }
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/pkin.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/pkin.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/pkin.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,424 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2008 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+This implementation of readchar() uses parts of the program dvips written by
+Tomas Rokicki--the inventor of the pkformat--(loadfont.c, download.c and
+unpack.c). Dvips in turn is derived from pktype. Pktype(TeX) is described in debt
+in ``The PKtype processor'', which is available as pktype.weave as part of the
+METAFONTware. What was needed to implement readchar() is rearranged in pkfile.c
+to get more modularity in the style of MODULA2.
+
+May 1997: Eric Delaunay <delaunay at lix.polytechnique.fr> reports a problem with
+huge fonts (greater than 1008 DPI). The code for handling PK characters in
+`extended format' was wrongly derived from dvips. Made some minor improvements
+regarding error handling.
+
+At some point Piet Tutelaers <rcpt at urc.tue.nl> redesigned the code and later Han
+The Thanh <thanh at fi.muni.cz> again modified the code to suite \PDFTEX. Of course
+in \LUATEX\ again we adapted the code.
+
+*/
+
+#include "ptexlib.h"
+
+typedef short shalfword;
+
+/*tex
+
+Now we have some routines to get stuff from the \PK\ file. |pkbyte| returns the
+next byte from the \PK\ file.
+
+*/
+
+static shalfword pkbyte(void)
+{
+    register shalfword i;
+    i = t3_getchar();
+    if (t3_eof())
+        normal_error("type 3","unexpected EOF in pk file");
+    return (i);
+}
+
+static int pkduo(void)
+{
+    register int i;
+    i = pkbyte();
+    if (i > 127)
+        i -= 256;
+    i = i * 256 + pkbyte();
+    return (i);
+}
+
+static int pktrio(void)
+{
+    register int i;
+    i = pkbyte();
+    if (i > 127)
+        i -= 256;
+    i = i * 256 + pkbyte();
+    i = i * 256 + pkbyte();
+    return (i);
+}
+
+static int pkquad(void)
+{
+    register int i;
+    i = pkbyte();
+    if (i > 127)
+        i -= 256;
+    i = i * 256 + pkbyte();
+    i = i * 256 + pkbyte();
+    i = i * 256 + pkbyte();
+    return (i);
+}
+
+/*tex
+
+    The next part is devoted to unpacking the character data. We need procedures
+    to get a nybble, bit, and packed word from the packed data structure.
+
+*/
+
+static halfword inputbyte, flagbyte;
+static halfword bitweight;
+static halfword dynf;
+static halfword repeatcount;
+
+static shalfword getnyb(void)
+{
+    halfword temp;
+    if (bitweight == 0) {
+        bitweight = 16;
+        inputbyte = pkbyte();
+        temp = inputbyte >> 4;
+    } else {
+        bitweight = 0;
+        temp = inputbyte & 15;
+    }
+    return (shalfword) (temp);
+}
+
+static boolean getbit(void)
+{
+    bitweight >>= 1;
+    if (bitweight == 0) {
+        inputbyte = pkbyte();
+        bitweight = 128;
+    }
+    return (inputbyte & bitweight);
+}
+
+static halfword(*realfunc) (void);
+long pk_remainder;
+static halfword handlehuge(halfword i, halfword k);
+
+static halfword pkpackednum(void)
+{
+    register halfword i, j;
+    i = getnyb();
+    if (i == 0) {
+        do {
+            j = getnyb();
+            i++;
+        } while (!(j != 0));
+        if (i > 3) {
+            /*tex
+                Hm, we got a huge count! We {\em fake} it by giving an
+                artificially large repeat count.
+            */
+            return (handlehuge(i, j));
+        } else {
+            while (i > 0) {
+                j = j * 16 + getnyb();
+                i--;
+            }
+            return (j - 15 + (13 - dynf) * 16 + dynf);
+        }
+    } else if (i <= dynf)
+        return (i);
+    else if (i < 14)
+        return ((i - dynf - 1) * 16 + getnyb() + dynf + 1);
+    else {
+        if (i == 14)
+            repeatcount = pkpackednum();
+        else
+            repeatcount = 1;
+        return ((*realfunc) ());
+    }
+}
+
+static halfword rest(void)
+{
+    halfword i;
+    if (pk_remainder < 0) {
+        pk_remainder = -pk_remainder;
+        return (0);
+    } else if (pk_remainder > 0) {
+        if (pk_remainder > 4000) {
+            pk_remainder = 4000 - pk_remainder;
+            return (4000);
+        } else {
+            i = (halfword) pk_remainder;
+            pk_remainder = 0;
+            realfunc = pkpackednum;
+            return (i);
+        }
+    } else {
+        normal_error("type 3","pk issue that shouldn't happen");
+        return 0;
+    }
+}
+
+static halfword handlehuge(halfword i, halfword k)
+{
+    register long j = k;
+    while (i) {
+        j = (j << 4L) + getnyb();
+        i--;
+    }
+    pk_remainder = j - 15 + (13 - dynf) * 16 + dynf;
+    realfunc = rest;
+    return (rest());
+}
+
+
+/*tex
+
+    And now we have our unpacking routine.
+
+*/
+
+static halfword gpower[17] = {
+        0,   1,    3,    7,   15,   31,    63,   127,
+      255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
+    65535
+};
+
+static void unpack(chardesc * cd)
+{
+    register int i, j;
+    register halfword word, wordweight;
+    halfword *raster;
+    shalfword rowsleft;
+    boolean turnon;
+    shalfword hbit;
+    halfword count;
+    shalfword wordwidth;
+    wordwidth = (shalfword) ((cd->cwidth + 15) / 16);
+    i = (int) (2 * cd->cheight * (long) wordwidth);
+    if (i <= 0)
+        i = 2;
+    if (i > cd->rastersize) {
+        xfree(cd->raster);
+        cd->rastersize = i;
+        cd->raster = xtalloc((unsigned) cd->rastersize, halfword);
+    }
+    raster = cd->raster;
+    realfunc = pkpackednum;
+    dynf = flagbyte / 16;
+    turnon = flagbyte & 8;
+    if (dynf == 14) {
+        bitweight = 0;
+        for (i = 1; i <= cd->cheight; i++) {
+            word = 0;
+            wordweight = 32768;
+            for (j = 1; j <= cd->cwidth; j++) {
+                if (getbit())
+                    word += wordweight;
+                wordweight >>= 1;
+                if (wordweight == 0) {
+                    *raster++ = word;
+                    word = 0;
+                    wordweight = 32768;
+                }
+            }
+            if (wordweight != 32768)
+                *raster++ = word;
+        }
+    } else {
+        rowsleft = (shalfword) cd->cheight;
+        hbit = (shalfword) cd->cwidth;
+        repeatcount = 0;
+        wordweight = 16;
+        word = 0;
+        bitweight = 0;
+        while (rowsleft > 0) {
+            count = (*realfunc) ();
+            while (count != 0) {
+                if ((count < wordweight) && (count < hbit)) {
+                    if (turnon)
+                        word += gpower[wordweight] - gpower[wordweight - count];
+                    hbit = (shalfword) (hbit - count);
+                    wordweight -= count;
+                    count = 0;
+                } else if ((count >= hbit) && (hbit <= wordweight)) {
+                    if (turnon)
+                        word += gpower[wordweight] - gpower[wordweight - hbit];
+                    *raster++ = word;
+                    for (i = 1; i <= repeatcount; i++) {
+                        for (j = 1; j <= wordwidth; j++) {
+                            *raster = *(raster - wordwidth);
+                            raster++;
+                        }
+                    }
+                    rowsleft = (shalfword) (rowsleft - repeatcount - 1);
+                    repeatcount = 0;
+                    word = 0;
+                    wordweight = 16;
+                    count -= hbit;
+                    hbit = (shalfword) cd->cwidth;
+                } else {
+                    if (turnon)
+                        word += gpower[wordweight];
+                    *raster++ = word;
+                    word = 0;
+                    count -= wordweight;
+                    hbit = (shalfword) (hbit - wordweight);
+                    wordweight = 16;
+                }
+            }
+            turnon = !turnon;
+        }
+        if ((rowsleft != 0) || ((int) hbit != cd->cwidth))
+            normal_error("type 3","error while unpacking, more bits than required");
+    }
+}
+
+/*tex
+
+    The main routine check pk preamble if necessary. It reads the character
+    definition of character |c| into |cd| if available or return |FALSE|
+    otherwise.
+
+*/
+
+int readchar(boolean check_preamble, chardesc * cd)
+{
+    register shalfword i;
+    register int k;
+    register int length = 0;
+    /*tex Check the preamble of the \PK\ file. */
+    if (check_preamble) {
+        if (pkbyte() != 247)
+            normal_error("type 3","bad pk file, expected pre");
+        if (pkbyte() != 89)
+            normal_error("type 3","bad version of pk file");
+        /*tex The creator of the file: */
+        for (i = pkbyte(); i > 0; i--)
+            (void) pkbyte();
+        /*tex The design size: */
+        (void) pkquad();
+        /*tex The checksum: */
+        k = pkquad();
+        /*tex The hppp: */
+        k = pkquad();
+        /*tex The vppp: */
+        k = pkquad();
+    }
+    /*tex
+        We also skip to the desired character definition.
+    */
+    while ((flagbyte = pkbyte()) != 245) {
+        if (flagbyte < 240) {
+            switch (flagbyte & 7) {
+                case 0:
+                case 1:
+                case 2:
+                case 3:
+                    length = (flagbyte & 7) * 256 + pkbyte() - 3;
+                    cd->charcode = pkbyte();
+                    /*tex The \TFM\ width: */
+                    (void) pktrio();
+                    /*tex the pixel width: */
+                    cd->xescape = pkbyte();
+                    cd->cwidth = pkbyte();
+                    cd->cheight = pkbyte();
+                    cd->xoff = pkbyte();
+                    cd->yoff = pkbyte();
+                    if (cd->xoff > 127)
+                        cd->xoff -= 256;
+                    if (cd->yoff > 127)
+                        cd->yoff -= 256;
+                    break;
+                case 4:
+                case 5:
+                case 6:
+                    length = (int) ((flagbyte & 3) * 65536L + pkbyte() * 256L);
+                    length = (int) (length + pkbyte() - 4L);
+                    cd->charcode = pkbyte();
+                    /*tex The \TFM\ width: */
+                    (void) pktrio();
+                    /*tex the pixel width: */
+                    cd->xescape = pkduo();
+                    cd->cwidth = pkduo();
+                    cd->cheight = pkduo();
+                    cd->xoff = pkduo();
+                    cd->yoff = pkduo();
+                    break;
+                case 7:
+                    length = (int) (pkquad() - 9L);
+                    cd->charcode = pkquad();
+                    /*tex The \TFM\ width: */
+                    (void) pkquad();
+                    /*tex the pixel width: */
+                    cd->xescape = pkquad();
+                    k = pkquad();
+                    cd->cwidth = pkquad();
+                    cd->cheight = pkquad();
+                    cd->xoff = pkquad();
+                    cd->yoff = pkquad();
+            }
+            if (length <= 0)
+                formatted_error("type 3","pk packet length '%i' too small", (int) length);
+            unpack(cd);
+            return 1;
+        } else {
+            k = 0;
+            switch (flagbyte) {
+                case 243:
+                    k = pkbyte();
+                    if (k > 127)
+                        k -= 256;
+                case 242:
+                    k = k * 256 + pkbyte();
+                case 241:
+                    k = k * 256 + pkbyte();
+                case 240:
+                    k = k * 256 + pkbyte();
+                    while (k-- > 0)
+                        i = pkbyte();
+                    break;
+                case 244:
+                    k = pkquad();
+                    break;
+                case 246:
+                    break;
+                default:
+                    formatted_error("type 3","unexpected pk command '%i'", (int) flagbyte);
+            }
+        }
+    }
+    /*tex Character not found: */
+    return 0;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/pkin.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/pkin.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/pkin.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,426 +0,0 @@
-% pkin.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@
-NAME
-
-pkin.c - implementation of readchar()
-
-DESCRIPTION
-
-This implementation of readchar() uses parts of the program dvips
-written by Tomas Rokicki--the inventor of the pkformat--(loadfont.c,
-download.c and unpack.c). Dvips in turn is derived from pktype.
-Pktype(TeX) is described in debt in ``The PKtype processor'',
-which is available as pktype.weave as part of the METAFONTware.
-What was needed to implement readchar() is rearranged in pkfile.c to
-get more modularity in the style of MODULA2.
-
-BUGFIXES
-
-May 1997: Eric Delaunay <delaunay@@lix.polytechnique.fr> reports a
-problem with huge fonts (greater than 1008 DPI). The code for
-handling PK characters in `extended format' was wrongly derived
-from dvips. Made some minor improvements regarding error handling.
-
-REDESIGN
-
-Piet Tutelaers <rcpt@@urc.tue.nl>
-
-Modified for use with pdftex by Han The Thanh <thanh@@fi.muni.cz>.
-
- at c
-
-
-#include "ptexlib.h"
-
-typedef short shalfword;
-
-@
-Now we have some routines to get stuff from the pk file.  pkbyte returns
-the next byte from the pk file.
-
- at c
-static shalfword pkbyte(void)
-{
-    register shalfword i;
-    i = t3_getchar();
-    if (t3_eof())
-        normal_error("type 3","unexpected EOF in pk file");
-    return (i);
-}
-
-static int pkduo(void)
-{
-    register int i;
-
-    i = pkbyte();
-    if (i > 127)
-        i -= 256;
-    i = i * 256 + pkbyte();
-    return (i);
-}
-
-static int pktrio(void)
-{
-    register int i;
-
-    i = pkbyte();
-    if (i > 127)
-        i -= 256;
-    i = i * 256 + pkbyte();
-    i = i * 256 + pkbyte();
-    return (i);
-}
-
-static int pkquad(void)
-{
-    register int i;
-
-    i = pkbyte();
-    if (i > 127)
-        i -= 256;
-    i = i * 256 + pkbyte();
-    i = i * 256 + pkbyte();
-    i = i * 256 + pkbyte();
-    return (i);
-}
-
-
-
-@  The next part is devoted to unpacking the character data.
-
-@  We need procedures to get a nybble, bit, and packed word from the
-packed data structure.
-
- at c
-static halfword inputbyte, flagbyte;
-static halfword bitweight;
-static halfword dynf;
-static halfword repeatcount;
-
-static shalfword getnyb(void)
-{
-    halfword temp;
-    if (bitweight == 0) {
-        bitweight = 16;
-        inputbyte = pkbyte();
-        temp = inputbyte >> 4;
-    } else {
-        bitweight = 0;
-        temp = inputbyte & 15;
-    }
-    return (shalfword) (temp);
-}
-
-static boolean getbit(void)
-{
-    bitweight >>= 1;
-    if (bitweight == 0) {
-        inputbyte = pkbyte();
-        bitweight = 128;
-    }
-    return (inputbyte & bitweight);
-}
-
-static halfword(*realfunc) (void);
-long pk_remainder;
-static halfword handlehuge(halfword i, halfword k);
-
-static halfword pkpackednum(void)
-{
-    register halfword i, j;
-    i = getnyb();
-    if (i == 0) {
-        do {
-            j = getnyb();
-            i++;
-        } while (!(j != 0));
-        if (i > 3) {
-/*
-    Damn, we got a huge count!  We {\it fake} it by giving an artificially
-    large repeat count.
- */
-            return (handlehuge(i, j));
-        } else {
-            while (i > 0) {
-                j = j * 16 + getnyb();
-                i--;
-            }
-            return (j - 15 + (13 - dynf) * 16 + dynf);
-        }
-    } else if (i <= dynf)
-        return (i);
-    else if (i < 14)
-        return ((i - dynf - 1) * 16 + getnyb() + dynf + 1);
-    else {
-        if (i == 14)
-            repeatcount = pkpackednum();
-        else
-            repeatcount = 1;
-#ifdef DEBUG
-        printf("[%d]", (int) repeatcount);
-#endif
-        return ((*realfunc) ());
-    }
-}
-
-static halfword rest(void)
-{
-    halfword i;
-
-    if (pk_remainder < 0) {
-        pk_remainder = -pk_remainder;
-        return (0);
-    } else if (pk_remainder > 0) {
-        if (pk_remainder > 4000) {
-            pk_remainder = 4000 - pk_remainder;
-            return (4000);
-        } else {
-            i = (halfword) pk_remainder;
-            pk_remainder = 0;
-            realfunc = pkpackednum;
-            return (i);
-        }
-    } else {
-        normal_error("type 3","pk issue that shouldn't happen");
-        return 0;
-     /*NOTREACHED*/}
-}
-
-static halfword handlehuge(halfword i, halfword k)
-{
-    register long j = k;
-
-    while (i) {
-        j = (j << 4L) + getnyb();
-        i--;
-    }
-    pk_remainder = j - 15 + (13 - dynf) * 16 + dynf;
-    realfunc = rest;
-    return (rest());
-}
-
-
-@  And now we have our unpacking routine.
-
- at c
-static halfword gpower[17] = { 0, 1, 3, 7, 15, 31, 63, 127,
-    255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535
-};
-
-static void unpack(chardesc * cd)
-{
-    register int i, j;
-    register halfword word, wordweight;
-    halfword *raster;
-    shalfword rowsleft;
-    boolean turnon;
-    shalfword hbit;
-    halfword count;
-    shalfword wordwidth;
-
-    wordwidth = (shalfword) ((cd->cwidth + 15) / 16);
-    i = (int) (2 * cd->cheight * (long) wordwidth);
-    if (i <= 0)
-        i = 2;
-    if (i > cd->rastersize) {
-        xfree(cd->raster);
-        cd->rastersize = i;
-        cd->raster = xtalloc((unsigned) cd->rastersize, halfword);
-    }
-    raster = cd->raster;
-    realfunc = pkpackednum;
-    dynf = flagbyte / 16;
-    turnon = flagbyte & 8;
-    if (dynf == 14) {
-        bitweight = 0;
-        for (i = 1; i <= cd->cheight; i++) {
-            word = 0;
-            wordweight = 32768;
-            for (j = 1; j <= cd->cwidth; j++) {
-                if (getbit())
-                    word += wordweight;
-                wordweight >>= 1;
-                if (wordweight == 0) {
-                    *raster++ = word;
-                    word = 0;
-                    wordweight = 32768;
-                }
-            }
-            if (wordweight != 32768)
-                *raster++ = word;
-        }
-    } else {
-        rowsleft = (shalfword) cd->cheight;
-        hbit = (shalfword) cd->cwidth;
-        repeatcount = 0;
-        wordweight = 16;
-        word = 0;
-        bitweight = 0;
-        while (rowsleft > 0) {
-            count = (*realfunc) ();
-            while (count != 0) {
-                if ((count < wordweight) && (count < hbit)) {
-                    if (turnon)
-                        word += gpower[wordweight] - gpower[wordweight - count];
-                    hbit = (shalfword) (hbit - count);
-                    wordweight -= count;
-                    count = 0;
-                } else if ((count >= hbit) && (hbit <= wordweight)) {
-                    if (turnon)
-                        word += gpower[wordweight] - gpower[wordweight - hbit];
-                    *raster++ = word;
-                    for (i = 1; i <= repeatcount; i++) {
-                        for (j = 1; j <= wordwidth; j++) {
-                            *raster = *(raster - wordwidth);
-                            raster++;
-                        }
-                    }
-                    rowsleft = (shalfword) (rowsleft - repeatcount - 1);
-                    repeatcount = 0;
-                    word = 0;
-                    wordweight = 16;
-                    count -= hbit;
-                    hbit = (shalfword) cd->cwidth;
-                } else {
-                    if (turnon)
-                        word += gpower[wordweight];
-                    *raster++ = word;
-                    word = 0;
-                    count -= wordweight;
-                    hbit = (shalfword) (hbit - wordweight);
-                    wordweight = 16;
-                }
-            }
-            turnon = !turnon;
-        }
-        if ((rowsleft != 0) || ((int) hbit != cd->cwidth))
-            normal_error("type 3","error while unpacking, more bits than required");
-    }
-}
-
-@
-|readchar()|: the main routine
-check pk preamble if necessary,
-Reads the character definition of character `c' into `cd' if available,
-return FALSE (0) otherwise.
-
- at c
-int readchar(boolean check_preamble, chardesc * cd)
-{
-    register shalfword i;
-    register int k;
-    register int length = 0;
-
-/*
-    Check the preamble of the pkfile
- */
-    if (check_preamble) {
-        if (pkbyte() != 247)
-            normal_error("type 3","bad pk file, expected pre");
-        if (pkbyte() != 89)
-            normal_error("type 3","bad version of pk file");
-        for (i = pkbyte(); i > 0; i--)  /* creator of pkfile */
-            (void) pkbyte();
-        (void) pkquad();        /* design size */
-        k = pkquad();           /* checksum    */
-        k = pkquad();           /* hppp        */
-        k = pkquad();           /* vppp   */
-    }
-/*
-    Now we skip to the desired character definition
- */
-    while ((flagbyte = pkbyte()) != 245) {
-        if (flagbyte < 240) {
-            switch (flagbyte & 7) {
-            case 0:
-            case 1:
-            case 2:
-            case 3:
-                length = (flagbyte & 7) * 256 + pkbyte() - 3;
-                cd->charcode = pkbyte();
-                (void) pktrio();        /* TFMwidth */
-                cd->xescape = pkbyte(); /* pixel width */
-                cd->cwidth = pkbyte();
-                cd->cheight = pkbyte();
-                cd->xoff = pkbyte();
-                cd->yoff = pkbyte();
-                if (cd->xoff > 127)
-                    cd->xoff -= 256;
-                if (cd->yoff > 127)
-                    cd->yoff -= 256;
-                break;
-            case 4:
-            case 5:
-            case 6:
-                length = (int) ((flagbyte & 3) * 65536L + pkbyte() * 256L);
-                length = (int) (length + pkbyte() - 4L);
-                cd->charcode = pkbyte();
-                (void) pktrio();        /* TFMwidth */
-                cd->xescape = pkduo();  /* pixelwidth */
-                cd->cwidth = pkduo();
-                cd->cheight = pkduo();
-                cd->xoff = pkduo();
-                cd->yoff = pkduo();
-                break;
-            case 7:
-                length = (int) (pkquad() - 9L);
-                cd->charcode = pkquad();
-                (void) pkquad();        /* TFMwidth */
-                cd->xescape = pkquad(); /* pixelwidth */
-                k = pkquad();
-                cd->cwidth = pkquad();
-                cd->cheight = pkquad();
-                cd->xoff = pkquad();
-                cd->yoff = pkquad();
-            }
-            if (length <= 0)
-                formatted_error("type 3","pk packet length '%i' too small", (int) length);
-            unpack(cd);
-            return 1;
-        } else {
-            k = 0;
-            switch (flagbyte) {
-            case 243:
-                k = pkbyte();
-                if (k > 127)
-                    k -= 256;
-            case 242:
-                k = k * 256 + pkbyte();
-            case 241:
-                k = k * 256 + pkbyte();
-            case 240:
-                k = k * 256 + pkbyte();
-                while (k-- > 0)
-                    i = pkbyte();
-                break;
-            case 244:
-                k = pkquad();
-                break;
-            case 246:
-                break;
-            default:
-                formatted_error("type 3","unexpected pk command '%i'", (int) flagbyte);
-            }
-        }
-    }
-    return 0;                   /* character not found */
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/sfnt.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,392 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
+Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+    The code below is originally based on |dvipdfmx-0.13.2c|:
+
+*/
+
+#include "ptexlib.h"
+
+#if HAVE_CONFIG_H
+#  include <w2c/config.h>
+#endif
+
+#include <string.h>
+
+#include "font/sfnt.h"
+
+/*tex
+
+    Types:
+
+    \starttabulate[||||]
+    \NC \type {true} \NC 0x74727565 \NC (Mac) TrueType  \NC \NR
+    \NC \type {typ1| \NC 0x74797031 \NC (Mac) PostScript font housed in a sfnt wrapper \NC \NR
+    \NC              \NC 0x00010000 \NC TrueType (Win)/OpenType \NC \NR
+    \NC \type {OTTO} \NC            \NC PostScript CFF font with OpenType wrapper \NC \NR
+    \NC \type {ttcf} \NC            \NC TrueType Collection \NC \NR
+    \stoptabulate
+
+*/
+
+#define SFNT_TRUETYPE   0x00010000UL
+#define SFNT_MAC_TRUE   0x74727565UL
+#define SFNT_OPENTYPE   0x00010000UL
+#define SFNT_POSTSCRIPT 0x4f54544fUL
+#define SFNT_TTC        0x74746366UL
+
+sfnt *sfnt_open(unsigned char *buff, int buflen)
+{
+    sfnt *sfont;
+    ULONG type;
+    sfont = xmalloc(sizeof(sfnt));
+    sfont->loc = 0;
+    sfont->buffer = buff;
+    sfont->buflen = buflen;
+    type = sfnt_get_ulong(sfont);
+    if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) {
+        sfont->type = SFNT_TYPE_TRUETYPE;
+    } else if (type == SFNT_OPENTYPE) {
+        sfont->type = SFNT_TYPE_OPENTYPE;
+    } else if (type == SFNT_POSTSCRIPT) {
+        sfont->type = SFNT_TYPE_POSTSCRIPT;
+    } else if (type == SFNT_TTC) {
+        sfont->type = SFNT_TYPE_TTC;
+    }
+    sfont->loc = 0;
+    sfont->directory = NULL;
+    return sfont;
+}
+
+static void release_directory(struct sfnt_table_directory *td)
+{
+    long i;
+    if (td) {
+        if (td->tables) {
+            for (i = 0; i < td->num_tables; i++) {
+                if (td->tables[i].data)
+                    RELEASE(td->tables[i].data);
+            }
+            RELEASE(td->tables);
+        }
+        if (td->flags)
+            RELEASE(td->flags);
+        RELEASE(td);
+    }
+    return;
+}
+
+void sfnt_close(sfnt * sfont)
+{
+    if (sfont) {
+        if (sfont->directory)
+            release_directory(sfont->directory);
+        RELEASE(sfont);
+    }
+    return;
+}
+
+int put_big_endian(void *s, LONG q, int n)
+{
+    int i;
+    char *p;
+    p = (char *) s;
+    for (i = n - 1; i >= 0; i--) {
+        p[i] = (char) (q & 0xff);
+        q >>= 8;
+    }
+    return n;
+}
+
+/*tex
+
+    Convert four-byte number to big endianess in a machine independent way.
+
+*/
+
+static void convert_tag(char *tag, unsigned long u_tag)
+{
+    int i;
+    for (i = 3; i >= 0; i--) {
+        tag[i] = (char) (u_tag % 256);
+        u_tag /= 256;
+    }
+    return;
+}
+
+/*tex
+
+    Computes the max power of $|2 <= n$:
+
+*/
+
+static unsigned max2floor(unsigned n)
+{
+    int val = 1;
+    while (n > 1) {
+        n /= 2;
+        val *= 2;
+    }
+    return (unsigned) val;
+}
+
+/*tex
+
+    Computes the log2 of the max power of $2 <= n$
+
+*/
+
+static unsigned log2floor(unsigned n)
+{
+    unsigned val = 0;
+    while (n > 1) {
+        n /= 2;
+        val++;
+    }
+    return val;
+}
+
+static ULONG sfnt_calc_checksum(void *data, ULONG length)
+{
+    ULONG chksum = 0;
+    BYTE *p, *endptr;
+    ULONG count = 0;
+    p = (BYTE *) data;
+    endptr = p + length;
+    while (p < endptr) {
+        chksum = chksum + (ULONG) (p[0] << (8 * (3 - count)));
+        count = ((count + 1) & 3);
+        p++;
+    }
+    return chksum;
+}
+
+static int find_table_index(struct sfnt_table_directory *td, const char *tag)
+{
+    int idx;
+    if (!td)
+        return -1;
+    for (idx = 0; idx < td->num_tables; idx++) {
+        if (!memcmp(td->tables[idx].tag, tag, 4))
+            return idx;
+    }
+    return -1;
+}
+
+void sfnt_set_table(sfnt * sfont, const char *tag, void *data, ULONG length)
+{
+    struct sfnt_table_directory *td;
+    int idx;
+    td = sfont->directory;
+    idx = find_table_index(td, tag);
+    if (idx < 0) {
+        idx = td->num_tables;
+        td->num_tables++;
+        td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table);
+        memcpy(td->tables[idx].tag, tag, 4);
+    }
+    td->tables[idx].check_sum = sfnt_calc_checksum(data, length);
+    td->tables[idx].offset = 0L;
+    td->tables[idx].length = length;
+    td->tables[idx].data = data;
+    return;
+}
+
+ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
+{
+    ULONG length;
+    struct sfnt_table_directory *td;
+    int idx;
+    td = sfont->directory;
+    idx = find_table_index(td, tag);
+    if (idx < 0)
+        length = 0;
+    else {
+        length = td->tables[idx].length;
+    }
+    return length;
+}
+
+ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
+{
+    ULONG offset;
+    struct sfnt_table_directory *td;
+    int idx;
+    td = sfont->directory;
+    idx = find_table_index(td, tag);
+    if (idx < 0)
+        offset = 0;
+    else {
+        offset = td->tables[idx].offset;
+    }
+    return offset;
+}
+
+ULONG sfnt_locate_table(sfnt * sfont, const char *tag)
+{
+    ULONG offset;
+    offset = sfnt_find_table_pos(sfont, tag);
+    if (offset == 0)
+        normal_error("ttf","sfnt table not found");
+    sfnt_seek_set(sfont, (long) offset);
+    return offset;
+}
+
+int sfnt_read_table_directory(sfnt * sfont, ULONG offset)
+{
+    struct sfnt_table_directory *td;
+    unsigned long i, u_tag;
+    if (sfont->directory)
+        release_directory(sfont->directory);
+    sfont->directory = td = NEW(1, struct sfnt_table_directory);
+    sfnt_seek_set(sfont, (long) offset);
+    td->version = sfnt_get_ulong(sfont);
+    td->num_tables = sfnt_get_ushort(sfont);
+    td->search_range = sfnt_get_ushort(sfont);
+    td->entry_selector = sfnt_get_ushort(sfont);
+    td->range_shift = sfnt_get_ushort(sfont);
+    td->flags = NEW(td->num_tables, char);
+    td->tables = NEW(td->num_tables, struct sfnt_table);
+    for (i = 0; i < td->num_tables; i++) {
+        u_tag = sfnt_get_ulong(sfont);
+        convert_tag(td->tables[i].tag, u_tag);
+        td->tables[i].check_sum = sfnt_get_ulong(sfont);
+        td->tables[i].offset = sfnt_get_ulong(sfont);
+        td->tables[i].length = sfnt_get_ulong(sfont);
+        td->tables[i].data = NULL;
+        td->flags[i] = 0;
+    }
+    td->num_kept_tables = 0;
+    return 0;
+}
+
+int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
+{
+    struct sfnt_table_directory *td;
+    int idx;
+    td = sfont->directory;
+    idx = find_table_index(td, tag);
+    if (idx < 0) {
+        if (must_exist)
+            return -1;
+    } else {
+        td->flags[idx] |= SFNT_TABLE_REQUIRED;
+        td->num_kept_tables++;
+    }
+    return 0;
+}
+
+/*tex
+
+    All tables begin on four byte boundries, and pad any remaining space between
+    tables with zeros. Entries in the Table Directory must be sorted in ascending
+    order by tag The head table contains checksum of the whole font file. To
+    compute: first set it to 0, sum the entire font as ULONG, then store
+    0xB1B0AFBA - sum.
+
+*/
+
+#  include "font/luatexfont.h"
+#  undef MIN
+#  define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#  define STREAM_COMPRESS
+
+static unsigned char wbuf[1024], padbytes[4] = { 0, 0, 0, 0 };
+
+pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
+{
+    pdf_obj *stream;
+    struct sfnt_table_directory *td;
+    long offset, nb_read, length;
+    int i, sr;
+    char *p;
+    stream = pdf_new_stream(STREAM_COMPRESS);
+    td = sfont->directory;
+    p = (char *) wbuf;
+    p += sfnt_put_ulong(p, (LONG) td->version);
+    p += sfnt_put_ushort(p, td->num_kept_tables);
+    sr = (int) (max2floor(td->num_kept_tables) * 16);
+    p += sfnt_put_ushort(p, sr);
+    p += sfnt_put_ushort(p, log2floor(td->num_kept_tables));
+    p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr);
+    pdf_add_stream(stream, wbuf, 12);
+    /*tex Compute start of actual tables (after headers). */
+    offset = 12 + 16 * td->num_kept_tables;
+    for (i = 0; i < td->num_tables; i++) {
+        /*tex This table must exist in |FontFile|: */
+        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
+            if ((offset % 4) != 0) {
+                offset += 4 - (offset % 4);
+            }
+            p = (char *) wbuf;
+            memcpy(p, td->tables[i].tag, 4);
+            p += 4;
+            p += sfnt_put_ulong(p, (LONG) td->tables[i].check_sum);
+            p += sfnt_put_ulong(p, offset);
+            p += sfnt_put_ulong(p, (LONG) td->tables[i].length);
+            pdf_add_stream(stream, wbuf, 16);
+            offset = (long) (offset + (long) td->tables[i].length);
+        }
+    }
+    offset = 12 + 16 * td->num_kept_tables;
+    for (i = 0; i < td->num_tables; i++) {
+        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
+            if ((offset % 4) != 0) {
+                length = 4 - (offset % 4);
+                pdf_add_stream(stream, padbytes, length);
+                offset += length;
+            }
+            if (!td->tables[i].data) {
+                if (!sfont->buffer) {
+                    pdf_release_obj(stream);
+                    normal_error("ttf","file not opened or already closed");
+                    return NULL;
+                }
+                length = (long) td->tables[i].length;
+                sfnt_seek_set(sfont, (long) td->tables[i].offset);
+                while (length > 0) {
+                    nb_read = sfnt_read(wbuf, (int) MIN(length, 1024), sfont);
+                    if (nb_read < 0) {
+                        pdf_release_obj(stream);
+                        normal_error("ttf","reading file failed");
+                        return NULL;
+                    } else if (nb_read > 0) {
+                        pdf_add_stream(stream, wbuf, nb_read);
+                    }
+                    length -= nb_read;
+                }
+            } else {
+                pdf_add_stream(stream,
+                               (unsigned char *) td->tables[i].data,
+                               (long) td->tables[i].length);
+                RELEASE(td->tables[i].data);
+                td->tables[i].data = NULL;
+            }
+            /*tex Set offset for next table. */
+            offset = (long) (offset + (long) td->tables[i].length);
+        }
+    }
+    return stream;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/sfnt.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,462 +0,0 @@
-% sfnt.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ Based on dvipdfmx-0.13.2c
- at c
-
-
-#include "ptexlib.h"
-
-#if  HAVE_CONFIG_H
-#  include <w2c/config.h>
-#endif                          /* |HAVE_CONFIG_H_| */
-
-#include <string.h>
-
-#include "font/sfnt.h"
-
-@ type:
-
- `true' (0x74727565): TrueType (Mac)
-
- `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper
-
- 0x00010000: TrueType (Win)/OpenType
-
- `OTTO': PostScript CFF font with OpenType wrapper
-
- `ttcf': TrueType Collection
-
- at c
-#define SFNT_TRUETYPE   0x00010000UL
-#define SFNT_MAC_TRUE 0x74727565UL
-#define SFNT_OPENTYPE   0x00010000UL
-#define SFNT_POSTSCRIPT 0x4f54544fUL
-#define SFNT_TTC        0x74746366UL
-
-sfnt *sfnt_open(unsigned char *buff, int buflen)
-{
-    sfnt *sfont;
-    ULONG type;
-
-    sfont = xmalloc(sizeof(sfnt));
-    sfont->loc = 0;
-    sfont->buffer = buff;
-    sfont->buflen = buflen;
-
-    type = sfnt_get_ulong(sfont);
-
-    if (type == SFNT_TRUETYPE || type == SFNT_MAC_TRUE) {
-        sfont->type = SFNT_TYPE_TRUETYPE;
-    } else if (type == SFNT_OPENTYPE) {
-        sfont->type = SFNT_TYPE_OPENTYPE;
-    } else if (type == SFNT_POSTSCRIPT) {
-        sfont->type = SFNT_TYPE_POSTSCRIPT;
-    } else if (type == SFNT_TTC) {
-        sfont->type = SFNT_TYPE_TTC;
-    }
-
-    sfont->loc = 0;
-    sfont->directory = NULL;
-    return sfont;
-}
-
-static void release_directory(struct sfnt_table_directory *td)
-{
-    long i;
-
-    if (td) {
-        if (td->tables) {
-            for (i = 0; i < td->num_tables; i++) {
-                if (td->tables[i].data)
-                    RELEASE(td->tables[i].data);
-            }
-            RELEASE(td->tables);
-        }
-        if (td->flags)
-            RELEASE(td->flags);
-        RELEASE(td);
-    }
-
-    return;
-}
-
-void sfnt_close(sfnt * sfont)
-{
-
-    if (sfont) {
-        if (sfont->directory)
-            release_directory(sfont->directory);
-        RELEASE(sfont);
-    }
-
-    return;
-}
-
-int put_big_endian(void *s, LONG q, int n)
-{
-    int i;
-    char *p;
-
-    p = (char *) s;
-    for (i = n - 1; i >= 0; i--) {
-        p[i] = (char) (q & 0xff);
-        q >>= 8;
-    }
-
-    return n;
-}
-
-@ Convert four-byte number to big endianess in a machine independent way.
-
- at c
-static void convert_tag(char *tag, unsigned long u_tag)
-{
-    int i;
-
-    for (i = 3; i >= 0; i--) {
-        tag[i] = (char) (u_tag % 256);
-        u_tag /= 256;
-    }
-
-    return;
-}
-
-
-@ Computes the max power of 2 <= n
-
- at c
-static unsigned max2floor(unsigned n)
-{
-    int val = 1;
-
-    while (n > 1) {
-        n /= 2;
-        val *= 2;
-    }
-
-    return (unsigned) val;
-}
-
-
-@ Computes the log2 of the max power of 2 <= n
-
- at c
-static unsigned log2floor(unsigned n)
-{
-    unsigned val = 0;
-
-    while (n > 1) {
-        n /= 2;
-        val++;
-    }
-
-    return val;
-}
-
-@ @c
-static ULONG sfnt_calc_checksum(void *data, ULONG length)
-{
-    ULONG chksum = 0;
-    BYTE *p, *endptr;
-    ULONG count = 0;
-
-    p = (BYTE *) data;
-    endptr = p + length;
-    while (p < endptr) {
-        chksum = chksum + (ULONG) (p[0] << (8 * (3 - count)));
-        count = ((count + 1) & 3);
-        p++;
-    }
-
-    return chksum;
-}
-
-@ @c
-static int find_table_index(struct sfnt_table_directory *td, const char *tag)
-{
-    int idx;
-
-    if (!td)
-        return -1;
-
-    for (idx = 0; idx < td->num_tables; idx++) {
-        if (!memcmp(td->tables[idx].tag, tag, 4))
-            return idx;
-    }
-
-    return -1;
-}
-
-@ @c
-void sfnt_set_table(sfnt * sfont, const char *tag, void *data, ULONG length)
-{
-    struct sfnt_table_directory *td;
-    int idx;
-
-    ASSERT(sfont);
-
-    td = sfont->directory;
-    idx = find_table_index(td, tag);
-
-    if (idx < 0) {
-        idx = td->num_tables;
-        td->num_tables++;
-        td->tables = RENEW(td->tables, td->num_tables, struct sfnt_table);
-        memcpy(td->tables[idx].tag, tag, 4);
-    }
-
-    td->tables[idx].check_sum = sfnt_calc_checksum(data, length);
-    td->tables[idx].offset = 0L;
-    td->tables[idx].length = length;
-    td->tables[idx].data = data;
-
-    return;
-}
-
-@ @c
-ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
-{
-    ULONG length;
-    struct sfnt_table_directory *td;
-    int idx;
-
-    ASSERT(sfont && tag);
-
-    td = sfont->directory;
-    idx = find_table_index(td, tag);
-    if (idx < 0)
-        length = 0;
-    else {
-        length = td->tables[idx].length;
-    }
-
-    return length;
-}
-
-@ @c
-ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
-{
-    ULONG offset;
-    struct sfnt_table_directory *td;
-    int idx;
-
-    ASSERT(sfont && tag);
-
-    td = sfont->directory;
-    idx = find_table_index(td, tag);
-    if (idx < 0)
-        offset = 0;
-    else {
-        offset = td->tables[idx].offset;
-    }
-
-    return offset;
-}
-
-@ @c
-ULONG sfnt_locate_table(sfnt * sfont, const char *tag)
-{
-    ULONG offset;
-
-    ASSERT(sfont && tag);
-
-    offset = sfnt_find_table_pos(sfont, tag);
-    if (offset == 0)
-        normal_error("ttf","sfnt table not found");
-
-    sfnt_seek_set(sfont, (long) offset);
-
-    return offset;
-}
-
-@ @c
-int sfnt_read_table_directory(sfnt * sfont, ULONG offset)
-{
-    struct sfnt_table_directory *td;
-    unsigned long i, u_tag;
-
-    ASSERT(sfont);
-
-    if (sfont->directory)
-        release_directory(sfont->directory);
-    sfont->directory = td = NEW(1, struct sfnt_table_directory);
-
-    ASSERT(sfont->buffer);
-    sfnt_seek_set(sfont, (long) offset);
-
-    td->version = sfnt_get_ulong(sfont);
-    td->num_tables = sfnt_get_ushort(sfont);
-    td->search_range = sfnt_get_ushort(sfont);
-    td->entry_selector = sfnt_get_ushort(sfont);
-    td->range_shift = sfnt_get_ushort(sfont);
-
-    td->flags = NEW(td->num_tables, char);
-    td->tables = NEW(td->num_tables, struct sfnt_table);
-
-    for (i = 0; i < td->num_tables; i++) {
-        u_tag = sfnt_get_ulong(sfont);
-
-        convert_tag(td->tables[i].tag, u_tag);
-        td->tables[i].check_sum = sfnt_get_ulong(sfont);
-        td->tables[i].offset = sfnt_get_ulong(sfont);
-        td->tables[i].length = sfnt_get_ulong(sfont);
-        td->tables[i].data = NULL;
-
-        td->flags[i] = 0;
-    }
-
-    td->num_kept_tables = 0;
-
-    return 0;
-}
-
-@ @c
-int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
-{
-    struct sfnt_table_directory *td;
-    int idx;
-
-    ASSERT(sfont && sfont->directory);
-
-    td = sfont->directory;
-    idx = find_table_index(td, tag);
-    if (idx < 0) {
-        if (must_exist)
-            return -1;
-    } else {
-        td->flags[idx] |= SFNT_TABLE_REQUIRED;
-        td->num_kept_tables++;
-    }
-
-    return 0;
-}
-
-
-
-@ All tables begin on four byte boundries, and pad any remaining space
-  between tables with zeros
-
-  Entries in the Table Directory must be sorted in ascending order by tag
-
-  The head table contains checksum of the whole font file.
-  To compute:  first set it to 0, sum the entire font as ULONG,
-  then store 0xB1B0AFBA - sum.
-
- at c
-#  include "font/luatexfont.h"
-#  undef MIN
-#  define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#  define STREAM_COMPRESS
-
-static unsigned char wbuf[1024], padbytes[4] = { 0, 0, 0, 0 };
-
-pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
-{
-    pdf_obj *stream;
-    struct sfnt_table_directory *td;
-    long offset, nb_read, length;
-    int i, sr;
-    char *p;
-
-    ASSERT(sfont && sfont->directory);
-
-    stream = pdf_new_stream(STREAM_COMPRESS);
-
-    td = sfont->directory;
-
-    /* Header */
-    p = (char *) wbuf;
-    p += sfnt_put_ulong(p, (LONG) td->version);
-    p += sfnt_put_ushort(p, td->num_kept_tables);
-    sr = (int) (max2floor(td->num_kept_tables) * 16);
-    p += sfnt_put_ushort(p, sr);
-    p += sfnt_put_ushort(p, log2floor(td->num_kept_tables));
-    p += sfnt_put_ushort(p, td->num_kept_tables * 16 - sr);
-
-    pdf_add_stream(stream, wbuf, 12);
-
-    /*
-     Compute start of actual tables (after headers).
-     */
-    offset = 12 + 16 * td->num_kept_tables;
-    for (i = 0; i < td->num_tables; i++) {
-        /* This table must exist in FontFile */
-        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
-            if ((offset % 4) != 0) {
-                offset += 4 - (offset % 4);
-            }
-
-            p = (char *) wbuf;
-            memcpy(p, td->tables[i].tag, 4);
-            p += 4;
-            p += sfnt_put_ulong(p, (LONG) td->tables[i].check_sum);
-            p += sfnt_put_ulong(p, offset);
-            p += sfnt_put_ulong(p, (LONG) td->tables[i].length);
-            pdf_add_stream(stream, wbuf, 16);
-
-            offset = (long) (offset + (long) td->tables[i].length);
-        }
-    }
-
-    offset = 12 + 16 * td->num_kept_tables;
-    for (i = 0; i < td->num_tables; i++) {
-        if (td->flags[i] & SFNT_TABLE_REQUIRED) {
-            if ((offset % 4) != 0) {
-                length = 4 - (offset % 4);
-                pdf_add_stream(stream, padbytes, length);
-                offset += length;
-            }
-            if (!td->tables[i].data) {
-                if (!sfont->buffer)
-                {
-                    pdf_release_obj(stream);
-                    normal_error("ttf","file not opened or already closed");
-                    return NULL;
-                }
-
-                length = (long) td->tables[i].length;
-                sfnt_seek_set(sfont, (long) td->tables[i].offset);
-                while (length > 0) {
-                    nb_read = sfnt_read(wbuf, (int) MIN(length, 1024), sfont);
-                    if (nb_read < 0) {
-                        pdf_release_obj(stream);
-                        normal_error("ttf","reading file failed");
-                        return NULL;
-                    } else if (nb_read > 0) {
-                        pdf_add_stream(stream, wbuf, nb_read);
-                    }
-                    length -= nb_read;
-                }
-            } else {
-                pdf_add_stream(stream,
-                               (unsigned char *) td->tables[i].data,
-                               (long) td->tables[i].length);
-                RELEASE(td->tables[i].data);
-                td->tables[i].data = NULL;
-            }
-            /* Set offset for next table */
-            offset = (long) (offset + (long) td->tables[i].length);
-        }
-    }
-
-    return stream;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/subfont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/subfont.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/subfont.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,277 @@
+/*
+
+Copyright 2005-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2008 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <string.h>
+
+static struct avl_table *sfd_tree = NULL;
+
+static unsigned char *sfd_buffer = NULL;
+static int sfd_size = 0;
+static int sfd_curbyte = 0;
+
+#define SFD_BUF_SIZE    SMALL_BUF_SIZE
+
+#define sfd_close()     xfclose(sfd_file, cur_file_name)
+#define sfd_open(a)     (sfd_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+
+#define sfd_read_file() readbinfile(sfd_file,&sfd_buffer,&sfd_size)
+#define sfd_getchar()   sfd_buffer[sfd_curbyte++]
+#define sfd_eof()       (sfd_curbyte>=sfd_size)
+
+static FILE *sfd_file;
+static char sfd_line[SFD_BUF_SIZE];
+
+static subfont_entry *new_subfont_entry(void)
+{
+    int i;
+    subfont_entry *subfont;
+    subfont = xtalloc(1, subfont_entry);
+    subfont->infix = NULL;
+    for (i = 0; i < 256; ++i) {
+        /*tex Unassigned: */
+        subfont->charcodes[i] = -1;
+    }
+    subfont->next = NULL;
+    return subfont;
+}
+
+static sfd_entry *new_sfd_entry(void)
+{
+    sfd_entry *sfd;
+    sfd = xtalloc(1, sfd_entry);
+    sfd->name = NULL;
+    sfd->subfont = NULL;
+    return sfd;
+}
+
+static void destroy_sfd_entry(void *pa, void *pb)
+{
+    subfont_entry *p, *q;
+    sfd_entry *sfd;
+    sfd = (sfd_entry *) pa;
+    (void) pb;
+    p = sfd->subfont;
+    while (p != NULL) {
+        q = p->next;
+        xfree(p->infix);
+        xfree(p);
+        p = q;
+    }
+    xfree(sfd->name);
+}
+
+static int comp_sfd_entry(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const sfd_entry *) pa)->name, ((const sfd_entry *) pb)->name);
+}
+
+void sfd_free(void)
+{
+    if (sfd_tree != NULL)
+        avl_destroy(sfd_tree, destroy_sfd_entry);
+}
+
+static void sfd_getline(boolean expect_eof)
+{
+    char *p;
+    char c;
+  restart:
+    if (sfd_eof()) {
+        if (expect_eof) {
+            if (*sfd_line == '#')
+                *sfd_line = 10;
+            return;
+        } else
+            normal_error("sub font","unexpected end of file");
+    }
+    p = sfd_line;
+    do {
+        c = (char) sfd_getchar();
+        append_char_to_buf(c, p, sfd_line, SFD_BUF_SIZE);
+    } while (c != 10 && !sfd_eof());
+    append_eol(p, sfd_line, SFD_BUF_SIZE);
+    if (p - sfd_line < 2 || *sfd_line == '#')
+        goto restart;
+}
+
+static sfd_entry *read_sfd(char *sfd_name)
+{
+    void **aa;
+    sfd_entry *sfd, tmp_sfd;
+    subfont_entry *sf;
+    char buf[SMALL_BUF_SIZE], *p;
+    long int i, j, k;
+    int n;
+    int callback_id = 0;
+    int file_opened = 0;
+    /*tex Check whether this |sfd| has been read: */
+    tmp_sfd.name = sfd_name;
+    if (sfd_tree == NULL) {
+        sfd_tree = avl_create(comp_sfd_entry, NULL, &avl_xallocator);
+        assert(sfd_tree != NULL);
+    }
+    sfd = (sfd_entry *) avl_find(sfd_tree, &tmp_sfd);
+    if (sfd != NULL)
+        return sfd;
+    xfree(sfd_buffer);
+    sfd_curbyte = 0;
+    sfd_size = 0;
+    cur_file_name = luatex_find_file(sfd_name, find_sfd_file_callback);
+    if (cur_file_name) {
+        callback_id = callback_defined(read_sfd_file_callback);
+        if (callback_id > 0) {
+            if (!(run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &sfd_buffer, &sfd_size) &&
+                  file_opened && sfd_size > 0)) {
+                formatted_warning("ttf font","cannot open SFD file for reading '%s'", cur_file_name);
+                cur_file_name = NULL;
+                return NULL;
+            }
+        } else {
+            if (!sfd_open(cur_file_name)) {
+                formatted_warning("ttf font", "cannot open SFD file for reading '%s'", cur_file_name);
+                cur_file_name = NULL;
+                return NULL;
+            }
+            sfd_read_file();
+            sfd_close();
+        }
+    }
+    tex_printf("{");
+    tex_printf("%s", cur_file_name);
+    sfd = new_sfd_entry();
+    sfd->name = xstrdup(sfd_name);
+    while (!sfd_eof()) {
+        sfd_getline(true);
+        if (*sfd_line == 10) {
+            /*tex An empty line indicates |EOF|. */
+            break;
+        }
+        sf = new_subfont_entry();
+        sf->next = sfd->subfont;
+        sfd->subfont = sf;
+        sscanf(sfd_line, "%s %n", buf, &n);
+        sf->infix = xstrdup(buf);
+        /*tex Skip to the next word: */
+        p = sfd_line + n;
+        k = 0;
+      read_ranges:
+        for (;;) {
+            if (*p == '\\') {
+                /*tex Continue on the next line: */
+                sfd_getline(false);
+                p = sfd_line;
+                goto read_ranges;
+            } else if (*p == 0) {
+                /*tex End of subfont. */
+                break;
+            }
+            if (sscanf(p, " %li %n", &i, &n) == 0)
+                formatted_error("sub font","invalid token: %s", p);
+            p += n;
+            if (*p == ':') {
+                /*tex Variant: offset */
+                k = i;
+                p++;
+            } else if (*p == '_') {
+                /*tex Variant: range */
+                if (sscanf(p + 1, " %li %n", &j, &n) == 0)
+                    formatted_error("sub font","invalid token: %s", p);
+                if (i > j || k + (j - i) > 255)
+                    formatted_error("sub font","invalid range: %s", p);
+                while (i <= j)
+                    sf->charcodes[k++] = i++;
+                p += n + 1;
+            } else {
+                /*tex Variant: codepoint */
+                sf->charcodes[k++] = i;
+            }
+        }
+    }
+    tex_printf("}");
+    aa = avl_probe(sfd_tree, sfd);
+    assert(aa != NULL);
+    return sfd;
+}
+
+boolean handle_subfont_fm(fm_entry * fm, int mode)
+{
+    size_t l;
+    char *p, *q, *r;
+    sfd_entry *sfd;
+    subfont_entry *sf;
+    fm_entry *fm2;
+    char buf[SMALL_BUF_SIZE];
+    assert(fm->tfm_name != NULL);
+    p = fm->tfm_name;
+    /*tex Search for the first |@|. */
+    q = strchr(p, '@');
+    if (q == NULL)
+        return false;
+    /*tex Search for the second |@|: */
+    r = strchr(q + 1, '@');
+    if (r == NULL)
+        return false;
+    /*tex Check if prefix or sfd name is empty or the second |@| is not the last char yet. */
+    if (q <= p || r <= q + 1 || r - p != (int) strlen(p) - 1) {
+        return false;
+    }
+    /*tex The length of sfd name: */
+    l = (size_t) (r - (q + 1));
+    strncpy(buf, q + 1, l);
+    buf[l] = 0;
+    check_buf(strlen(buf) + 4, SMALL_BUF_SIZE);
+    strcat(buf, ".sfd");
+    sfd = read_sfd(buf);
+    if (sfd == NULL)
+        return false;
+    /*tex At this point we know fm is a subfont. */
+    set_subfont(fm);
+    xfree(fm->ps_name);
+    /*tex Set default values for |Pid| and |Eid|: */
+    if (fm->pid == -1) {
+        fm->pid = 3;
+        fm->eid = 1;
+    }
+    /*tex Calculate the length of base tfm name (prefix). */
+    l = (size_t) (q - p);
+    for (sf = sfd->subfont; sf != NULL; sf = sf->next) {
+        strncpy(buf, p, l);
+        buf[l] = 0;
+        strcat(buf, sf->infix);
+        fm2 = new_fm_entry();
+        fm2->tfm_name = xstrdup(buf);
+        fm2->ff_name = xstrdup(fm->ff_name);
+        fm2->type = fm->type;
+        fm2->pid = fm->pid;
+        fm2->eid = fm->eid;
+        fm2->subfont = sf;
+        /*tex Try to insert the entry. */
+        if (avl_do_entry(fm2, mode) != 0) {
+            /*tex And delete it if we failed. */
+            delete_fm_entry(fm2);
+        }
+    }
+    delete_fm_entry(fm);
+    return true;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/subfont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/subfont.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/subfont.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,265 +0,0 @@
-% subfont.w
-%
-% Copyright 2005-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <string.h>
-
-@ @c
-static struct avl_table *sfd_tree = NULL;
-
-static unsigned char *sfd_buffer = NULL;
-static int sfd_size = 0;
-static int sfd_curbyte = 0;
-
-#define SFD_BUF_SIZE    SMALL_BUF_SIZE
-
-#define sfd_close()     xfclose(sfd_file, cur_file_name)
-#define sfd_open(a)      (sfd_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-
-#define sfd_read_file() readbinfile(sfd_file,&sfd_buffer,&sfd_size)
-#define sfd_getchar()   sfd_buffer[sfd_curbyte++]
-#define sfd_eof()      (sfd_curbyte>=sfd_size)
-
-
-static FILE *sfd_file;
-static char sfd_line[SFD_BUF_SIZE];
-
-static subfont_entry *new_subfont_entry(void)
-{
-    int i;
-    subfont_entry *subfont;
-    subfont = xtalloc(1, subfont_entry);
-    subfont->infix = NULL;
-    for (i = 0; i < 256; ++i)
-        subfont->charcodes[i] = -1;     /* unassigned */
-    subfont->next = NULL;
-    return subfont;
-}
-
-static sfd_entry *new_sfd_entry(void)
-{
-    sfd_entry *sfd;
-    sfd = xtalloc(1, sfd_entry);
-    sfd->name = NULL;
-    sfd->subfont = NULL;
-    return sfd;
-}
-
-static void destroy_sfd_entry(void *pa, void *pb)
-{
-    subfont_entry *p, *q;
-    sfd_entry *sfd;
-    sfd = (sfd_entry *) pa;
-    (void) pb;
-    p = sfd->subfont;
-    while (p != NULL) {
-        q = p->next;
-        xfree(p->infix);
-        xfree(p);
-        p = q;
-    }
-    xfree(sfd->name);
-}
-
-static int comp_sfd_entry(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const sfd_entry *) pa)->name,
-                  ((const sfd_entry *) pb)->name);
-}
-
-void sfd_free(void)
-{
-    if (sfd_tree != NULL)
-        avl_destroy(sfd_tree, destroy_sfd_entry);
-}
-
-static void sfd_getline(boolean expect_eof)
-{
-    char *p;
-    char c;
-  restart:
-    if (sfd_eof()) {
-        if (expect_eof) {
-            if (*sfd_line == '#')
-                *sfd_line = 10;
-            return;
-        } else
-            normal_error("sub font","unexpected end of file");
-    }
-    p = sfd_line;
-    do {
-        c = (char) sfd_getchar();
-        append_char_to_buf(c, p, sfd_line, SFD_BUF_SIZE);
-    } while (c != 10 && !sfd_eof());
-    append_eol(p, sfd_line, SFD_BUF_SIZE);
-    if (p - sfd_line < 2 || *sfd_line == '#')
-        goto restart;
-}
-
-@ @c
-static sfd_entry *read_sfd(char *sfd_name)
-{
-    void **aa;
-    sfd_entry *sfd, tmp_sfd;
-    subfont_entry *sf;
-
-    char buf[SMALL_BUF_SIZE], *p;
-    long int i, j, k;
-    int n;
-    int callback_id = 0;
-    int file_opened = 0;
-    /* check whether this sfd has been read */
-    tmp_sfd.name = sfd_name;
-    if (sfd_tree == NULL) {
-        sfd_tree = avl_create(comp_sfd_entry, NULL, &avl_xallocator);
-        assert(sfd_tree != NULL);
-    }
-    sfd = (sfd_entry *) avl_find(sfd_tree, &tmp_sfd);
-    if (sfd != NULL)
-        return sfd;
-    xfree(sfd_buffer);
-    sfd_curbyte = 0;
-    sfd_size = 0;
-
-    cur_file_name = luatex_find_file(sfd_name, find_sfd_file_callback);
-    if (cur_file_name) {
-        callback_id = callback_defined(read_sfd_file_callback);
-        if (callback_id > 0) {
-            if (!(run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &sfd_buffer, &sfd_size) &&
-                  file_opened && sfd_size > 0)) {
-                formatted_warning("ttf font","cannot open SFD file for reading '%s'", cur_file_name);
-                cur_file_name = NULL;
-                return NULL;
-            }
-        } else {
-            if (!sfd_open(cur_file_name)) {
-                formatted_warning("ttf font", "cannot open SFD file for reading '%s'", cur_file_name);
-                cur_file_name = NULL;
-                return NULL;
-            }
-            sfd_read_file();
-            sfd_close();
-        }
-    }
-    tex_printf("{");
-    tex_printf("%s", cur_file_name);
-    sfd = new_sfd_entry();
-    sfd->name = xstrdup(sfd_name);
-    while (!sfd_eof()) {
-        sfd_getline(true);
-        if (*sfd_line == 10)    /* empty line indicating eof */
-            break;
-        sf = new_subfont_entry();
-        sf->next = sfd->subfont;
-        sfd->subfont = sf;
-        sscanf(sfd_line, "%s %n", buf, &n);
-        sf->infix = xstrdup(buf);
-        p = sfd_line + n;       /* skip to the next word */
-        k = 0;
-      read_ranges:
-        for (;;) {
-            if (*p == '\\') {   /* continue on next line */
-                sfd_getline(false);
-                p = sfd_line;
-                goto read_ranges;
-            } else if (*p == 0) /* end of subfont */
-                break;
-            if (sscanf(p, " %li %n", &i, &n) == 0)
-                formatted_error("sub font","invalid token: %s", p);
-            p += n;
-            if (*p == ':') {    /* offset */
-                k = i;
-                p++;
-            } else if (*p == '_') {     /* range */
-                if (sscanf(p + 1, " %li %n", &j, &n) == 0)
-                    formatted_error("sub font","invalid token: %s", p);
-                if (i > j || k + (j - i) > 255)
-                    formatted_error("sub font","invalid range: %s", p);
-                while (i <= j)
-                    sf->charcodes[k++] = i++;
-                p += n + 1;
-            } else              /* codepoint */
-                sf->charcodes[k++] = i;
-        }
-    }
-    tex_printf("}");
-    aa = avl_probe(sfd_tree, sfd);
-    assert(aa != NULL);
-    return sfd;
-}
-
-@ @c
-boolean handle_subfont_fm(fm_entry * fm, int mode)
-{
-    size_t l;
-    char *p, *q, *r;
-    sfd_entry *sfd;
-    subfont_entry *sf;
-    fm_entry *fm2;
-    char buf[SMALL_BUF_SIZE];
-    assert(fm->tfm_name != NULL);
-    p = fm->tfm_name;
-    q = strchr(p, '@@');         /* search for the first '@@' */
-    if (q == NULL)
-        return false;
-    r = strchr(q + 1, '@@');     /* search for the second '@@' */
-    if (r == NULL)
-        return false;
-    if (q <= p || r <= q + 1    /* prefix or sfd name is empty */
-        || r - p != (int) strlen(p) - 1)        /* or the second '@@' is not the last char yet */
-        return false;
-    l = (size_t) (r - (q + 1)); /* length of sfd name */
-    strncpy(buf, q + 1, l);
-    buf[l] = 0;
-    check_buf(strlen(buf) + 4, SMALL_BUF_SIZE);
-    strcat(buf, ".sfd");
-    sfd = read_sfd(buf);
-    if (sfd == NULL)
-        return false;
-    /* at this point we know fm is a subfont */
-    set_subfont(fm);
-    xfree(fm->ps_name);
-    /* set default values for PidEid */
-    if (fm->pid == -1) {
-        fm->pid = 3;
-        fm->eid = 1;
-    }
-    l = (size_t) (q - p);       /* length of base tfm name (prefix) */
-    for (sf = sfd->subfont; sf != NULL; sf = sf->next) {
-        strncpy(buf, p, l);
-        buf[l] = 0;
-        strcat(buf, sf->infix);
-        fm2 = new_fm_entry();
-        fm2->tfm_name = xstrdup(buf);
-        fm2->ff_name = xstrdup(fm->ff_name);
-        fm2->type = fm->type;
-        fm2->pid = fm->pid;
-        fm2->eid = fm->eid;
-        fm2->subfont = sf;
-        if (avl_do_entry(fm2, mode) != 0)       /* try to insert the entry */
-            delete_fm_entry(fm2);       /* delete it if failed */
-    }
-    delete_fm_entry(fm);
-    return true;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/texfont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/texfont.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/texfont.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1950 @@
+/*
+
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+    Here is the main font API implementation for the original pascal parts. Stuff
+    to watch out for:
+
+    \startitemize
+
+        \startitem
+            Knuth had a |'null_character'| that was used when a character could
+            not be found by the |fetch()| routine, to signal an error. This has
+            been deleted, but it may mean that the output of luatex is
+            incompatible with TeX after |fetch()| has detected an error
+            condition.
+        \stopitem
+
+        \startitem
+            Knuth also had a |font_glue()| optimization. I've removed that
+            because it was a bit of dirty programming and it also was problematic
+            |if 0 != null|.
+        \stopitem
+
+    \stopitemize
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define noDEBUG
+
+#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f))
+#define do_realloc(a,b,d)    a = xrealloc(a,(unsigned)((unsigned)(b)*sizeof(d)))
+
+texfont **font_tables = NULL;
+
+static int font_arr_max = 0;
+static int font_id_maxval = 0;
+
+static void grow_font_table(int id)
+{
+    int j;
+    if (id >= font_arr_max) {
+        font_bytes +=
+            (int) (((id + 8 - font_arr_max) * (int) sizeof(texfont *)));
+        font_tables =
+            xrealloc(font_tables,
+                     (unsigned) (((unsigned) id + 8) * sizeof(texfont *)));
+        j = 8;
+        while (j--) {
+            font_tables[id + j] = NULL;
+        }
+        font_arr_max = id + 8;
+    }
+}
+
+int new_font_id(void)
+{
+    int i;
+    for (i = 0; i < font_arr_max; i++) {
+        if (font_tables[i] == NULL) {
+            break;
+        }
+    }
+    if (i >= font_arr_max)
+        grow_font_table(i);
+    if (i > font_id_maxval)
+        font_id_maxval = i;
+    return i;
+}
+
+int max_font_id(void)
+{
+    return font_id_maxval;
+}
+
+void set_max_font_id(int i)
+{
+    font_id_maxval = i;
+}
+
+int new_font(void)
+{
+    int k;
+    int id;
+    charinfo *ci;
+    sa_tree_item sa_value = { 0 };
+    id = new_font_id();
+    font_bytes += (int) sizeof(texfont);
+    /*tex Most stuff is zero */
+    font_tables[id] = xcalloc(1, sizeof(texfont));
+    font_tables[id]->_font_name = NULL;
+    font_tables[id]->_font_area = NULL;
+    font_tables[id]->_font_filename = NULL;
+    font_tables[id]->_font_fullname = NULL;
+    font_tables[id]->_font_psname = NULL;
+    font_tables[id]->_font_encodingname = NULL;
+    font_tables[id]->_font_cidregistry = NULL;
+    font_tables[id]->_font_cidordering = NULL;
+    font_tables[id]->_left_boundary = NULL;
+    font_tables[id]->_right_boundary = NULL;
+    font_tables[id]->_param_base = NULL;
+    font_tables[id]->_math_param_base = NULL;
+    /*tex |ec = 0| */
+    set_font_bc(id, 1);
+    set_font_writingmode(id, 0);
+    set_font_identity(id, 0);
+    set_hyphen_char(id, '-');
+    set_skew_char(id, -1);
+    /*tex vertical */
+    font_slant(id) = 0;
+    /*tex normal width */
+    font_extend(id) = 1000;
+    /*tex normal height */
+    font_squeeze(id) = 1000;
+    font_width(id) = 0;
+    font_mode(id) = 0;
+    /*tex allocate eight values including 0 */
+    set_font_params(id, 7);
+    for (k = 0; k <= 7; k++) {
+        set_font_param(id, k, 0);
+    }
+    /*tex character info zero is reserved for |notdef|. The stack size 1, default item value 0. */
+    font_tables[id]->characters = new_sa_tree(1, 1, sa_value);
+    ci = xcalloc(1, sizeof(charinfo));
+    set_charinfo_name(ci, xstrdup(".notdef"));
+    font_tables[id]->charinfo = ci;
+    font_tables[id]->charinfo_size = 1;
+    font_tables[id]->charinfo_cache = NULL;
+    return id;
+}
+
+void font_malloc_charinfo(internal_font_number f, int num)
+{
+    int glyph = font_tables[f]->charinfo_size;
+    font_bytes += (int) (num * (int) sizeof(charinfo));
+    do_realloc(font_tables[f]->charinfo, (unsigned) (glyph + num), charinfo);
+    memset(&(font_tables[f]->charinfo[glyph]), 0, (size_t) (num * (int) sizeof(charinfo)));
+    font_tables[f]->charinfo_size += num;
+}
+
+#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
+
+charinfo *get_charinfo(internal_font_number f, int c)
+{
+    int glyph;
+    charinfo *ci;
+    if (proper_char_index(c)) {
+        glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+        if (!glyph) {
+            sa_tree_item sa_value = { 0 };
+            int tglyph = ++font_tables[f]->charinfo_count;
+            if (tglyph >= font_tables[f]->charinfo_size) {
+                font_malloc_charinfo(f, 256);
+            }
+            font_tables[f]->charinfo[tglyph].ef = 1000;
+            sa_value.int_value = tglyph;
+            /*tex 1 means global */
+            set_sa_item(font_tables[f]->characters, c, sa_value, 1);
+            glyph = tglyph;
+        }
+        return &(font_tables[f]->charinfo[glyph]);
+    } else if (c == left_boundarychar) {
+        if (left_boundary(f) == NULL) {
+            ci = xcalloc(1, sizeof(charinfo));
+            font_bytes += (int) sizeof(charinfo);
+            set_left_boundary(f, ci);
+        }
+        return left_boundary(f);
+    } else if (c == right_boundarychar) {
+        if (right_boundary(f) == NULL) {
+            ci = xcalloc(1, sizeof(charinfo));
+            font_bytes += (int) sizeof(charinfo);
+            set_right_boundary(f, ci);
+        }
+        return right_boundary(f);
+    }
+    return &(font_tables[f]->charinfo[0]);
+}
+
+static void set_charinfo(internal_font_number f, int c, charinfo * ci)
+{
+    int glyph;
+    if (proper_char_index(c)) {
+        glyph = get_sa_item(font_tables[f]->characters, c).int_value;
+        if (glyph) {
+            font_tables[f]->charinfo[glyph] = *ci;
+        } else {
+            normal_error("font","character insertion failed");
+        }
+    } else if (c == left_boundarychar) {
+        set_left_boundary(f, ci);
+    } else if (c == right_boundarychar) {
+        set_right_boundary(f, ci);
+    }
+}
+
+charinfo *copy_charinfo(charinfo * ci)
+{
+    int x, k;
+    kerninfo *kern;
+    liginfo *lig;
+    eight_bits *packet;
+    charinfo *co = NULL;
+    if (ci == NULL)
+        return NULL;
+    co = xmalloc(sizeof(charinfo));
+    memcpy(co, ci, sizeof(charinfo));
+    set_charinfo_used(co, false);
+    co->name = NULL;
+    co->tounicode = NULL;
+    co->packets = NULL;
+    co->ligatures = NULL;
+    co->kerns = NULL;
+    co->vert_variants = NULL;
+    co->hor_variants = NULL;
+    if (ci->name != NULL) {
+        co->name = xstrdup(ci->name);
+    }
+    if (ci->tounicode != NULL) {
+        co->tounicode = xstrdup(ci->tounicode);
+    }
+    /*tex Kerns */
+    if ((kern = get_charinfo_kerns(ci)) != NULL) {
+        x = 0;
+        while (!kern_end(kern[x])) {
+            x++;
+        }
+        x++;
+        co->kerns = xmalloc((unsigned) (x * (int) sizeof(kerninfo)));
+        memcpy(co->kerns, ci->kerns, (size_t) (x * (int) sizeof(kerninfo)));
+    }
+    /*tex Ligatures */
+    if ((lig = get_charinfo_ligatures(ci)) != NULL) {
+        x = 0;
+        while (!lig_end(lig[x])) {
+            x++;
+        }
+        x++;
+        co->ligatures = xmalloc((unsigned) (x * (int) sizeof(liginfo)));
+        memcpy(co->ligatures, ci->ligatures,
+               (size_t) (x * (int) sizeof(liginfo)));
+    }
+    /*tex Packets */
+    if ((packet = get_charinfo_packets(ci)) != NULL) {
+        x = vf_packet_bytes(ci);
+        co->packets = xmalloc((unsigned) x);
+        memcpy(co->packets, ci->packets, (size_t) x);
+    }
+    /*tex Horizontal and vertical extenders */
+    if (get_charinfo_vert_variants(ci) != NULL) {
+        set_charinfo_vert_variants(co, copy_variants(get_charinfo_vert_variants(ci)));
+    }
+    if (get_charinfo_hor_variants(ci) != NULL) {
+        set_charinfo_hor_variants(co, copy_variants(get_charinfo_hor_variants(ci)));
+    }
+    x = ci->top_left_math_kerns;
+    co->top_left_math_kerns = x;
+    if (x > 0) {
+        co->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        for (k = 0; k < co->top_left_math_kerns; k++) {
+            co->top_left_math_kern_array[(2 * k)] = ci->top_left_math_kern_array[(2 * k)];
+            co->top_left_math_kern_array[(2 * k) + 1] = ci->top_left_math_kern_array[(2 * k) + 1];
+        }
+    }
+    x = ci->bottom_left_math_kerns;
+    co->bottom_left_math_kerns = x;
+    if (x > 0) {
+        co->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        for (k = 0; k < co->bottom_left_math_kerns; k++) {
+            co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
+            co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
+        }
+    }
+    x = ci->top_right_math_kerns;
+    co->top_right_math_kerns = x;
+    if (x > 0) {
+        co->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        for (k = 0; k < co->top_right_math_kerns; k++) {
+            co->top_right_math_kern_array[(2 * k)] = ci->top_right_math_kern_array[(2 * k)];
+            co->top_right_math_kern_array[(2 * k) + 1] = ci->top_right_math_kern_array[(2 * k) + 1];
+        }
+    }
+    x = ci->bottom_right_math_kerns;
+    co->bottom_right_math_kerns = x;
+    if (x > 0) {
+        co->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+        for (k = 0; k < co->bottom_right_math_kerns; k++) {
+            co->bottom_right_math_kern_array[(2 * k)] = ci->bottom_right_math_kern_array[(2 * k)];
+            co->bottom_right_math_kern_array[(2 * k) + 1] = ci->bottom_right_math_kern_array[(2 * k) + 1];
+        }
+    }
+    return co;
+}
+
+charinfo *char_info(internal_font_number f, int c)
+{
+    if (f > font_id_maxval)
+        return 0;
+    if (proper_char_index(c)) {
+        register int glyph = (int) find_charinfo_id(f, c);
+        return &(font_tables[f]->charinfo[glyph]);
+    } else if (c == left_boundarychar && left_boundary(f) != NULL) {
+        return left_boundary(f);
+    } else if (c == right_boundarychar && right_boundary(f) != NULL) {
+        return right_boundary(f);
+    }
+    return &(font_tables[f]->charinfo[0]);
+}
+
+scaled_whd get_charinfo_whd(internal_font_number f, int c)
+{
+    scaled_whd s;
+    charinfo *i;
+    i = char_info(f, c);
+    s.wd = i->width;
+    s.dp = i->depth;
+    s.ht = i->height;
+    return s;
+}
+
+int char_exists(internal_font_number f, int c)
+{
+    if (f > font_id_maxval)
+        return 0;
+    if (proper_char_index(c)) {
+        return (int) find_charinfo_id(f, c);
+    } else if ((c == left_boundarychar) && has_left_boundary(f)) {
+        return 1;
+    } else if ((c == right_boundarychar) && has_right_boundary(f)) {
+        return 1;
+    }
+    return 0;
+}
+
+int lua_glyph_not_found_callback(internal_font_number f, int c)
+{
+    int callback_id;
+    int ret = 0;
+    int top, i;
+    callback_id = callback_defined(glyph_not_found_callback);
+    if (callback_id != 0) {
+        top = lua_gettop(Luas);
+        if (!get_callback(Luas, callback_id)) {
+            lua_settop(Luas, top);
+            return 0;
+        }
+        lua_pushinteger(Luas, f);
+        lua_pushinteger(Luas, c);
+        if ((i=lua_pcall(Luas, 2, 1, 0)) != 0) {
+            formatted_warning   ("glyph not found", "error: %s", lua_tostring(Luas, -1));
+            lua_settop(Luas, top);
+            luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+        } else {
+            ret = lua_toboolean(Luas, -1);
+        }
+        lua_settop(Luas, top);
+    } else {
+        char_warning(f,c);
+    }
+    return ret;
+}
+
+extinfo *new_variant(int glyph, int startconnect, int endconnect, int advance, int repeater)
+{
+    extinfo *ext;
+    ext = xmalloc(sizeof(extinfo));
+    ext->next = NULL;
+    ext->glyph = glyph;
+    ext->start_overlap = startconnect;
+    ext->end_overlap = endconnect;
+    ext->advance = advance;
+    ext->extender = repeater;
+    return ext;
+}
+
+static extinfo *copy_variant(extinfo * old)
+{
+    extinfo *ext;
+    ext = xmalloc(sizeof(extinfo));
+    ext->next = NULL;
+    ext->glyph = old->glyph;
+    ext->start_overlap = old->start_overlap;
+    ext->end_overlap = old->end_overlap;
+    ext->advance = old->advance;
+    ext->extender = old->extender;
+    return ext;
+}
+
+static void dump_variant(extinfo * ext)
+{
+    dump_int(ext->glyph);
+    dump_int(ext->start_overlap);
+    dump_int(ext->end_overlap);
+    dump_int(ext->advance);
+    dump_int(ext->extender);
+    return;
+}
+
+static extinfo *undump_variant(void)
+{
+    int x;
+    extinfo *ext;
+    undump_int(x);
+    if (x == 0)
+        return NULL;
+    ext = xmalloc(sizeof(extinfo));
+    ext->next = NULL;
+    ext->glyph = x;
+    undump_int(x);
+    ext->start_overlap = x;
+    undump_int(x);
+    ext->end_overlap = x;
+    undump_int(x);
+    ext->advance = x;
+    undump_int(x);
+    ext->extender = x;
+    return ext;
+}
+
+void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
+{
+    if (ci->vert_variants == NULL) {
+        ci->vert_variants = ext;
+    } else {
+        extinfo *lst = ci->vert_variants;
+        while (lst->next != NULL)
+            lst = lst->next;
+        lst->next = ext;
+    }
+
+}
+
+void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
+{
+    if (ci->hor_variants == NULL) {
+        ci->hor_variants = ext;
+    } else {
+        extinfo *lst = ci->hor_variants;
+        while (lst->next != NULL)
+            lst = lst->next;
+        lst->next = ext;
+    }
+
+}
+
+extinfo *copy_variants(extinfo * o)
+{
+    extinfo *c, *t = NULL, *h = NULL;
+    while (o != NULL) {
+        c = copy_variant(o);
+        if (h == null)
+            h = c;
+        else
+            t->next = c;
+        t = c;
+        o = o->next;
+    }
+
+    return h;
+}
+
+static void dump_charinfo_variants(extinfo * o)
+{
+    while (o != NULL) {
+        dump_variant(o);
+        o = o->next;
+    }
+    dump_int(0);
+    return;
+}
+
+static extinfo *undump_charinfo_variants(void)
+{
+    extinfo *c, *t = NULL, *h = NULL;
+    c = undump_variant();
+    while (c != NULL) {
+        if (h == null)
+            h = c;
+        else
+            t->next = c;
+        t = c;
+        c = undump_variant();
+    }
+    return h;
+}
+
+
+/*tex
+
+    Note that many more small things like this are implemented as macros in the
+    header file.
+*/
+
+void set_charinfo_width(charinfo * ci, scaled val)
+{
+    ci->width = val;
+}
+
+void set_charinfo_height(charinfo * ci, scaled val)
+{
+    ci->height = val;
+}
+
+void set_charinfo_depth(charinfo * ci, scaled val)
+{
+    ci->depth = val;
+}
+
+void set_charinfo_italic(charinfo * ci, scaled val)
+{
+    ci->italic = val;
+}
+
+void set_charinfo_vert_italic(charinfo * ci, scaled val)
+{
+    ci->vert_italic = val;
+}
+
+void set_charinfo_top_accent(charinfo * ci, scaled val)
+{
+    ci->top_accent = val;
+}
+
+void set_charinfo_bot_accent(charinfo * ci, scaled val)
+{
+    ci->bot_accent = val;
+}
+
+void set_charinfo_tag(charinfo * ci, scaled val)
+{
+    ci->tag = (char) val;
+}
+
+void set_charinfo_remainder(charinfo * ci, scaled val)
+{
+    ci->remainder = val;
+}
+
+void set_charinfo_used(charinfo * ci, scaled val)
+{
+    ci->used = (char) val;
+}
+
+void set_charinfo_index(charinfo * ci, scaled val)
+{
+    ci->index = (unsigned short) val;
+}
+
+void set_charinfo_name(charinfo * ci, char *val)
+{
+    xfree(ci->name);
+    ci->name = val;
+}
+
+void set_charinfo_tounicode(charinfo * ci, char *val)
+{
+    xfree(ci->tounicode);
+    ci->tounicode = val;
+}
+
+void set_charinfo_ligatures(charinfo * ci, liginfo * val)
+{
+    dxfree(ci->ligatures, val);
+}
+
+void set_charinfo_kerns(charinfo * ci, kerninfo * val)
+{
+    dxfree(ci->kerns, val);
+}
+
+void set_charinfo_packets(charinfo * ci, eight_bits * val)
+{
+    dxfree(ci->packets, val);
+}
+
+void set_charinfo_ef(charinfo * ci, scaled val)
+{
+    ci->ef = val;
+}
+
+void set_charinfo_lp(charinfo * ci, scaled val)
+{
+    ci->lp = val;
+}
+
+void set_charinfo_rp(charinfo * ci, scaled val)
+{
+    ci->rp = val;
+}
+
+void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
+{
+    extinfo *c, *lst;
+    if (ci->vert_variants != NULL) {
+        lst = ci->vert_variants;
+        while (lst != NULL) {
+            c = lst->next;
+            free(lst);
+            lst = c;
+        }
+    }
+    ci->vert_variants = ext;
+}
+
+void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
+{
+    extinfo *c, *lst;
+    if (ci->hor_variants != NULL) {
+        lst = ci->hor_variants;
+        while (lst != NULL) {
+            c = lst->next;
+            free(lst);
+            lst = c;
+        }
+    }
+    ci->hor_variants = ext;
+
+}
+
+int get_charinfo_math_kerns(charinfo * ci, int id)
+{
+    /*tex All callers check for |result>0|. */
+    int k = 0;
+    if (id == top_left_kern) {
+        k = ci->top_left_math_kerns;
+    } else if (id == bottom_left_kern) {
+        k = ci->bottom_left_math_kerns;
+    } else if (id == top_right_kern) {
+        k = ci->top_right_math_kerns;
+    } else if (id == bottom_right_kern) {
+        k = ci->bottom_right_math_kerns;
+    } else {
+        confusion("get_charinfo_math_kerns");
+    }
+    return k;
+}
+
+void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
+{
+    int k;
+    if (id == top_left_kern) {
+        k = ci->top_left_math_kerns;
+        do_realloc(ci->top_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+        ci->top_left_math_kern_array[(2 * (k))] = ht;
+        ci->top_left_math_kern_array[((2 * (k)) + 1)] = krn;
+        ci->top_left_math_kerns++;
+    } else if (id == bottom_left_kern) {
+        k = ci->bottom_left_math_kerns;
+        do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+        ci->bottom_left_math_kern_array[(2 * (k))] = ht;
+        ci->bottom_left_math_kern_array[(2 * (k)) + 1] = krn;
+        ci->bottom_left_math_kerns++;
+    } else if (id == top_right_kern) {
+        k = ci->top_right_math_kerns;
+        do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+        ci->top_right_math_kern_array[(2 * (k))] = ht;
+        ci->top_right_math_kern_array[(2 * (k)) + 1] = krn;
+        ci->top_right_math_kerns++;
+    } else if (id == bottom_right_kern) {
+        k = ci->bottom_right_math_kerns;
+        do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
+        ci->bottom_right_math_kern_array[(2 * (k))] = ht;
+        ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
+        ci->bottom_right_math_kerns++;
+    } else {
+        confusion("add_charinfo_math_kern");
+    }
+}
+
+static void dump_math_kerns(charinfo * ci)
+{
+    int k, l;
+    l = ci->top_left_math_kerns;
+    dump_int(l);
+    for (k = 0; k < l; k++) {
+        dump_int(ci->top_left_math_kern_array[(2 * k)]);
+        dump_int(ci->top_left_math_kern_array[(2 * k) + 1]);
+    }
+    l = ci->bottom_left_math_kerns;
+    dump_int(l);
+    for (k = 0; k < l; k++) {
+        dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
+        dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
+    }
+    l = ci->top_right_math_kerns;
+    dump_int(l);
+    for (k = 0; k < l; k++) {
+        dump_int(ci->top_right_math_kern_array[(2 * k)]);
+        dump_int(ci->top_right_math_kern_array[(2 * k) + 1]);
+    }
+    l = ci->bottom_right_math_kerns;
+    dump_int(l);
+    for (k = 0; k < l; k++) {
+        dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
+        dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
+    }
+}
+
+static void undump_math_kerns(charinfo * ci)
+{
+    int k, x;
+    undump_int(x);
+    ci->top_left_math_kerns = x;
+    if (x > 0)
+        ci->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->top_left_math_kerns; k++) {
+        undump_int(x);
+        ci->top_left_math_kern_array[(2 * k)] = (scaled) x;
+        undump_int(x);
+        ci->top_left_math_kern_array[(2 * k) + 1] = (scaled) x;
+    }
+    undump_int(x);
+    ci->bottom_left_math_kerns = x;
+    if (x > 0)
+        ci->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->bottom_left_math_kerns; k++) {
+        undump_int(x);
+        ci->bottom_left_math_kern_array[(2 * k)] = (scaled) x;
+        undump_int(x);
+        ci->bottom_left_math_kern_array[(2 * k) + 1] = (scaled) x;
+    }
+    undump_int(x);
+    ci->top_right_math_kerns = x;
+    if (x > 0)
+        ci->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->top_right_math_kerns; k++) {
+        undump_int(x);
+        ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
+        undump_int(x);
+        ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+    }
+    undump_int(x);
+    ci->bottom_right_math_kerns = x;
+    if (x > 0)
+        ci->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
+    for (k = 0; k < ci->bottom_right_math_kerns; k++) {
+        undump_int(x);
+        ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
+        undump_int(x);
+        ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
+    }
+}
+
+/*tex
+
+    In TeX, extensibles were fairly simple things. This function squeezes a TFM
+    extensible into the vertical extender structures. |advance==0| is a special
+    case for TFM fonts, because finding the proper advance width during tfm
+    reading can be tricky.
+
+    A small complication arises if |rep| is the only non-zero: it needs to be
+    doubled as a non-repeatable to avoid mayhem.
+
+*/
+
+void set_charinfo_extensible(charinfo * ci, int top, int bot, int mid, int rep)
+{
+    extinfo *ext;
+    /*tex Clear old data: */
+    set_charinfo_vert_variants(ci, NULL);
+    if (bot == 0 && top == 0 && mid == 0 && rep != 0) {
+        ext = new_variant(rep, 0, 0, 0, EXT_NORMAL);
+        add_charinfo_vert_variant(ci, ext);
+        ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+        add_charinfo_vert_variant(ci, ext);
+        return;
+    }
+    if (bot != 0) {
+        ext = new_variant(bot, 0, 0, 0, EXT_NORMAL);
+        add_charinfo_vert_variant(ci, ext);
+    }
+    if (rep != 0) {
+        ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+        add_charinfo_vert_variant(ci, ext);
+    }
+    if (mid != 0) {
+        ext = new_variant(mid, 0, 0, 0, EXT_NORMAL);
+        add_charinfo_vert_variant(ci, ext);
+        if (rep != 0) {
+            ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
+            add_charinfo_vert_variant(ci, ext);
+        }
+    }
+    if (top != 0) {
+        ext = new_variant(top, 0, 0, 0, EXT_NORMAL);
+        add_charinfo_vert_variant(ci, ext);
+    }
+}
+
+/*tex
+
+    Note that many more simple things like this are implemented as macros in the
+    header file.
+
+*/
+
+scaled get_charinfo_width(charinfo * ci)
+{
+    return ci->width;
+}
+
+scaled get_charinfo_height(charinfo * ci)
+{
+    return ci->height;
+}
+
+scaled get_charinfo_depth(charinfo * ci)
+{
+    return ci->depth;
+}
+
+scaled get_charinfo_italic(charinfo * ci)
+{
+    return ci->italic;
+}
+
+scaled get_charinfo_vert_italic(charinfo * ci)
+{
+    return ci->vert_italic;
+}
+
+scaled get_charinfo_top_accent(charinfo * ci)
+{
+    return ci->top_accent;
+}
+
+scaled get_charinfo_bot_accent(charinfo * ci)
+{
+    return ci->bot_accent;
+}
+
+char get_charinfo_tag(charinfo * ci)
+{
+    return ci->tag;
+}
+
+int get_charinfo_remainder(charinfo * ci)
+{
+    return ci->remainder;
+}
+
+char get_charinfo_used(charinfo * ci)
+{
+    return ci->used;
+}
+
+int get_charinfo_index(charinfo * ci)
+{
+    return ci->index;
+}
+
+char *get_charinfo_name(charinfo * ci)
+{
+    return ci->name;
+}
+
+char *get_charinfo_tounicode(charinfo * ci)
+{
+    return ci->tounicode;
+}
+
+liginfo *get_charinfo_ligatures(charinfo * ci)
+{
+    return ci->ligatures;
+}
+
+kerninfo *get_charinfo_kerns(charinfo * ci)
+{
+    return ci->kerns;
+}
+
+eight_bits *get_charinfo_packets(charinfo * ci)
+{
+    return ci->packets;
+}
+
+int get_charinfo_ef(charinfo * ci)
+{
+    return ci->ef;
+}
+
+int get_charinfo_rp(charinfo * ci)
+{
+    return ci->rp;
+}
+
+int get_charinfo_lp(charinfo * ci)
+{
+    return ci->lp;
+}
+
+extinfo *get_charinfo_vert_variants(charinfo * ci)
+{
+    extinfo *w = NULL;
+    if (ci->vert_variants != NULL)
+        w = ci->vert_variants;
+    return w;
+}
+
+extinfo *get_charinfo_hor_variants(charinfo * ci)
+{
+    extinfo *w = NULL;
+    if (ci->hor_variants != NULL)
+        w = ci->hor_variants;
+    return w;
+}
+
+
+scaled char_width(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    scaled w = get_charinfo_width(ci);
+    return w;
+}
+
+scaled calc_char_width(internal_font_number f, int c, int ex)
+{
+    charinfo *ci = char_info(f, c);
+    scaled w = get_charinfo_width(ci);
+    if (ex != 0)
+        w = round_xn_over_d(w, 1000 + ex, 1000);
+    return w;
+}
+
+scaled char_depth(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    scaled d = get_charinfo_depth(ci);
+    return d;
+}
+
+scaled char_height(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    scaled h = get_charinfo_height(ci);
+    return h;
+}
+
+scaled char_italic(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    scaled i = get_charinfo_italic(ci);
+    return i;
+}
+
+scaled char_vert_italic(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    scaled i = get_charinfo_vert_italic(ci);
+    return i;
+}
+
+scaled char_top_accent(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_top_accent(ci);
+}
+
+scaled char_bot_accent(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_bot_accent(ci);
+}
+
+int char_remainder(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_remainder(ci);
+}
+
+char char_tag(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_tag(ci);
+}
+
+char char_used(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_used(ci);
+}
+
+char *char_name(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_name(ci);
+}
+
+int char_index(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_index(ci);
+}
+
+liginfo *char_ligatures(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_ligatures(ci);
+}
+
+kerninfo *char_kerns(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_kerns(ci);
+}
+
+eight_bits *char_packets(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_packets(ci);
+}
+
+void set_font_params(internal_font_number f, int b)
+{
+    int i;
+    i = font_params(f);
+    if (i != b) {
+        font_bytes +=
+            (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
+        do_realloc(param_base(f), (b + 2), int);
+        font_params(f) = b;
+        if (b > i) {
+            while (i < b) {
+                i++;
+                set_font_param(f, i, 0);
+            }
+        }
+    }
+}
+
+void set_font_math_params(internal_font_number f, int b)
+{
+    int i;
+    i = font_math_params(f);
+    if (i != b) {
+        font_bytes +=
+            ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
+        do_realloc(math_param_base(f), (b + 2), int);
+        font_math_params(f) = b;
+        if (b > i) {
+            while (i < b) {
+                i++;
+                set_font_math_param(f, i, undefined_math_parameter);
+            }
+        }
+    }
+}
+
+int copy_font(int f)
+{
+    int i, ci_cnt, ci_size;
+    charinfo *ci;
+    int k = new_font();
+    {
+        ci = font_tables[k]->charinfo;
+        ci_cnt = font_tables[k]->charinfo_count;
+        ci_size = font_tables[k]->charinfo_size;
+        memcpy(font_tables[k], font_tables[f], sizeof(texfont));
+        font_tables[k]->charinfo = ci;
+        font_tables[k]->charinfo_count = ci_cnt;
+        font_tables[k]->charinfo_size = ci_size;
+    }
+    font_malloc_charinfo(k, font_tables[f]->charinfo_count);
+    set_font_cache_id(k, 0);
+    set_font_used(k, 0);
+    set_font_touched(k, 0);
+    font_tables[k]->_font_name = NULL;
+    font_tables[k]->_font_filename = NULL;
+    font_tables[k]->_font_fullname = NULL;
+    font_tables[k]->_font_psname = NULL;
+    font_tables[k]->_font_encodingname = NULL;
+    font_tables[k]->_font_area = NULL;
+    font_tables[k]->_font_cidregistry = NULL;
+    font_tables[k]->_font_cidordering = NULL;
+    font_tables[k]->_left_boundary = NULL;
+    font_tables[k]->_right_boundary = NULL;
+    set_font_name(k, xstrdup(font_name(f)));
+    if (font_filename(f) != NULL)
+        set_font_filename(k, xstrdup(font_filename(f)));
+    if (font_fullname(f) != NULL)
+        set_font_fullname(k, xstrdup(font_fullname(f)));
+    if (font_psname(f) != NULL)
+        set_font_psname(k, xstrdup(font_psname(f)));
+    if (font_encodingname(f) != NULL)
+        set_font_encodingname(k, xstrdup(font_encodingname(f)));
+    if (font_area(f) != NULL)
+        set_font_area(k, xstrdup(font_area(f)));
+    if (font_cidregistry(f) != NULL)
+        set_font_cidregistry(k, xstrdup(font_cidregistry(f)));
+    if (font_cidordering(f) != NULL)
+        set_font_cidordering(k, xstrdup(font_cidordering(f)));
+    i = (int) (sizeof(*param_base(f)) * (unsigned) (font_params(f)+1));
+    font_bytes += i;
+    param_base(k) = xmalloc((unsigned) (i+1));
+    memcpy(param_base(k), param_base(f), (size_t) (i));
+    if (font_math_params(f) > 0) {
+        i = (int) (sizeof(*math_param_base(f)) *
+                   (unsigned) font_math_params(f));
+        font_bytes += i;
+        math_param_base(k) = xmalloc((unsigned) i);
+        memcpy(math_param_base(k), math_param_base(f), (size_t) i);
+    }
+    for (i = 0; i <= font_tables[f]->charinfo_count; i++) {
+        ci = copy_charinfo(&font_tables[f]->charinfo[i]);
+        font_tables[k]->charinfo[i] = *ci;
+    }
+    if (left_boundary(f) != NULL) {
+        ci = copy_charinfo(left_boundary(f));
+        set_charinfo(k, left_boundarychar, ci);
+    }
+    if (right_boundary(f) != NULL) {
+        ci = copy_charinfo(right_boundary(f));
+        set_charinfo(k, right_boundarychar, ci);
+    }
+    /*tex Not updated yet: */
+    font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
+    return k;
+}
+
+void delete_font(int f)
+{
+    int i;
+    charinfo *co;
+    assert(f > 0);
+    if (font_tables[f] != NULL) {
+        set_font_name(f, NULL);
+        set_font_filename(f, NULL);
+        set_font_fullname(f, NULL);
+        set_font_psname(f, NULL);
+        set_font_encodingname(f, NULL);
+        set_font_area(f, NULL);
+        set_font_cidregistry(f, NULL);
+        set_font_cidordering(f, NULL);
+        set_left_boundary(f, NULL);
+        set_right_boundary(f, NULL);
+        for (i = font_bc(f); i <= font_ec(f); i++) {
+            if (quick_char_exists(f, i)) {
+                co = char_info(f, i);
+                set_charinfo_name(co, NULL);
+                set_charinfo_tounicode(co, NULL);
+                set_charinfo_packets(co, NULL);
+                set_charinfo_ligatures(co, NULL);
+                set_charinfo_kerns(co, NULL);
+                set_charinfo_vert_variants(co, NULL);
+                set_charinfo_hor_variants(co, NULL);
+            }
+        }
+        /*tex free |notdef| */
+        set_charinfo_name(font_tables[f]->charinfo + 0, NULL);
+        free(font_tables[f]->charinfo);
+        destroy_sa_tree(font_tables[f]->characters);
+        free(param_base(f));
+        if (math_param_base(f) != NULL)
+            free(math_param_base(f));
+        free(font_tables[f]);
+        font_tables[f] = NULL;
+        if (font_id_maxval == f) {
+            font_id_maxval--;
+        }
+    }
+}
+
+void create_null_font(void)
+{
+    int i = new_font();
+    assert(i == 0);
+    set_font_name(i, xstrdup("nullfont"));
+    set_font_area(i, xstrdup(""));
+    set_font_touched(i, 1);
+}
+
+boolean is_valid_font(int id)
+{
+    int ret = 0;
+    if (id >= 0 && id <= font_id_maxval && font_tables[id] != NULL)
+        ret = 1;
+    return ret;
+}
+
+boolean cmp_font_area(int id, str_number t)
+{
+    char *tt = NULL;
+    char *tid = font_area(id);
+    if (t == 0) {
+        if (tid == NULL || strlen(tid) == 0)
+            return 1;
+        else
+            return 0;
+    }
+    tt = makecstring(t);
+    if ((tt == NULL || strlen(tt) == 0) && (tid == NULL || strlen(tid) == 0))
+        return 1;
+    if (tt == NULL || strcmp(tid, tt) != 0)
+        return 0;
+    free(tt);
+    return 1;
+}
+
+/*tex
+
+    Here come some subroutines to deal with expanded fonts for HZ-algorithm.
+    returning 1 means that they are identical.
+
+*/
+
+static boolean cmp_font_name(int id, char *tt)
+{
+    char *tid;
+    if (!is_valid_font(id))
+        return 0;
+    tid = font_name(id);
+    if (tt == NULL && tid == NULL)
+        return 1;
+    if (tt == NULL || tid == NULL || strcmp(tid, tt) != 0)
+        return 0;
+    return 1;
+}
+
+int test_no_ligatures(internal_font_number f)
+{
+    int c;
+    for (c = font_bc(f); c <= font_ec(f); c++) {
+        if (has_lig(f, c))
+            return 0;
+    }
+    return 1;
+}
+
+int get_tag_code(internal_font_number f, int c)
+{
+    small_number i;
+    if (char_exists(f, c)) {
+        i = char_tag(f, c);
+        if (i == lig_tag)
+            return 1;
+        else if (i == list_tag)
+            return 2;
+        else if (i == ext_tag)
+            return 4;
+        else
+            return 0;
+    }
+    return -1;
+}
+
+int get_lp_code(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_lp(ci);
+}
+
+int get_rp_code(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_rp(ci);
+}
+
+int get_ef_code(internal_font_number f, int c)
+{
+    charinfo *ci = char_info(f, c);
+    return get_charinfo_ef(ci);
+}
+
+void set_tag_code(internal_font_number f, int c, int i)
+{
+    int fixedi;
+    charinfo *co;
+    if (char_exists(f, c)) {
+        fixedi = -(i < -7 ? -7 : (i > 0 ? 0 : i));
+        co = char_info(f, c);
+        if (fixedi >= 4) {
+            if (char_tag(f, c) == ext_tag)
+                set_charinfo_tag(co, (char_tag(f, c) - ext_tag));
+            fixedi = fixedi - 4;
+        }
+        if (fixedi >= 2) {
+            if (char_tag(f, c) == list_tag)
+                set_charinfo_tag(co, (char_tag(f, c) - list_tag));
+            fixedi = fixedi - 2;
+        };
+        if (fixedi >= 1) {
+            if (has_lig(f, c))
+                set_charinfo_ligatures(co, NULL);
+            if (has_kern(f, c))
+                set_charinfo_kerns(co, NULL);
+        }
+    }
+}
+
+void set_lp_code(internal_font_number f, int c, int i)
+{
+    charinfo *co;
+    if (char_exists(f, c)) {
+        co = char_info(f, c);
+        set_charinfo_lp(co, i);
+    }
+}
+
+void set_rp_code(internal_font_number f, int c, int i)
+{
+    charinfo *co;
+    if (char_exists(f, c)) {
+        co = char_info(f, c);
+        set_charinfo_rp(co, i);
+    }
+}
+
+void set_ef_code(internal_font_number f, int c, int i)
+{
+    charinfo *co;
+    if (char_exists(f, c)) {
+        co = char_info(f, c);
+        set_charinfo_ef(co, i);
+    }
+}
+
+void set_no_ligatures(internal_font_number f)
+{
+    int c;
+    charinfo *co;
+    if (font_tables[f]->ligatures_disabled)
+        return;
+    co = char_info(f, left_boundarychar);
+    set_charinfo_ligatures(co, NULL);
+    co = char_info(f, right_boundarychar);
+    set_charinfo_ligatures(co, NULL);
+    for (c = 0; c < font_tables[f]->charinfo_count; c++) {
+        co = font_tables[f]->charinfo + c;
+        set_charinfo_ligatures(co, NULL);
+    }
+    font_tables[f]->ligatures_disabled = 1;
+}
+
+liginfo get_ligature(internal_font_number f, int lc, int rc)
+{
+    int k = 0;
+    liginfo t, u;
+    charinfo *co;
+    t.lig = 0;
+    t.type = 0;
+    t.adj = 0;
+    if (lc == non_boundarychar || rc == non_boundarychar || (!has_lig(f, lc)))
+        return t;
+    co = char_info(f, lc);
+    while (1) {
+        u = charinfo_ligature(co, k);
+        if (lig_end(u))
+            break;
+        if (lig_char(u) == rc) {
+            if (lig_disabled(u)) {
+                return t;
+            } else {
+                return u;
+            }
+        }
+        k++;
+    }
+    return t;
+}
+
+scaled raw_get_kern(internal_font_number f, int lc, int rc)
+{
+    int k = 0;
+    kerninfo u;
+    charinfo *co;
+    if (lc == non_boundarychar || rc == non_boundarychar)
+        return 0;
+    co = char_info(f, lc);
+    while (1) {
+        u = charinfo_kern(co, k);
+        if (kern_end(u))
+            break;
+        if (kern_char(u) == rc) {
+            if (kern_disabled(u))
+                return 0;
+            else
+                return kern_kern(u);
+        }
+        k++;
+    }
+    return 0;
+}
+
+scaled get_kern(internal_font_number f, int lc, int rc)
+{
+    if (lc == non_boundarychar || rc == non_boundarychar || (!has_kern(f, lc)))
+        return 0;
+    return raw_get_kern(f, lc, rc);
+}
+
+
+/*tex Dumping and undumping fonts. */
+
+#define dump_string(a)                    \
+    if (a!=NULL) {                        \
+        x = (int)(strlen(a)+1);           \
+        dump_int(x);  dump_things(*a, x); \
+    } else {                              \
+        x = 0; dump_int(x);               \
+    }
+
+static void dump_charinfo(int f, int c)
+{
+    charinfo *co;
+    int x;
+    liginfo *lig;
+    kerninfo *kern;
+    dump_int(c);
+    co = char_info(f, c);
+    set_charinfo_used(co, 0);
+    dump_int(get_charinfo_width(co));
+    dump_int(get_charinfo_height(co));
+    dump_int(get_charinfo_depth(co));
+    dump_int(get_charinfo_italic(co));
+    dump_int(get_charinfo_vert_italic(co));
+    dump_int(get_charinfo_top_accent(co));
+    dump_int(get_charinfo_bot_accent(co));
+    dump_int(get_charinfo_tag(co));
+    dump_int(get_charinfo_ef(co));
+    dump_int(get_charinfo_rp(co));
+    dump_int(get_charinfo_lp(co));
+    dump_int(get_charinfo_remainder(co));
+    dump_int(get_charinfo_used(co));
+    dump_int(get_charinfo_index(co));
+    dump_string(get_charinfo_name(co));
+    dump_string(get_charinfo_tounicode(co));
+    /*tex Ligatures */
+    x = 0;
+    if ((lig = get_charinfo_ligatures(co)) != NULL) {
+        while (!lig_end(lig[x])) {
+            x++;
+        }
+        x++;
+        dump_int(x);
+        dump_things(*lig, x);
+    } else {
+        dump_int(x);
+    }
+    /*tex Kerns */
+    x = 0;
+    if ((kern = get_charinfo_kerns(co)) != NULL) {
+        while (!kern_end(kern[x])) {
+            x++;
+        }
+        x++;
+        dump_int(x);
+        dump_things(*kern, x);
+    } else {
+        dump_int(x);
+    }
+    /*tex Packets */
+    x = vf_packet_bytes(co);
+    dump_int(x);
+    if (x > 0) {
+        dump_things(*get_charinfo_packets(co), x);
+    }
+    if (get_charinfo_tag(co) == ext_tag) {
+        dump_charinfo_variants(get_charinfo_vert_variants(co));
+        dump_charinfo_variants(get_charinfo_hor_variants(co));
+    }
+    dump_math_kerns(co);
+}
+
+static void dump_font_entry(texfont * f)
+{
+    int x;
+    dump_int(f->_font_size);
+    dump_int(f->_font_dsize);
+    dump_int(f->_font_cidversion);
+    dump_int(f->_font_cidsupplement);
+    dump_int(f->_font_ec);
+    x = (int) f->_font_checksum;
+    dump_int(x);
+    dump_int(f->_font_used);
+    dump_int(f->_font_touched);
+    dump_int(f->_font_cache_id);
+    dump_int(f->_font_encodingbytes);
+    dump_int(f->_font_oldmath);
+    dump_int(f->_font_slant);
+    dump_int(f->_font_extend);
+    dump_int(f->_font_squeeze);
+    dump_int(f->_font_mode);
+    dump_int(f->_font_width);
+    dump_int(f->font_max_shrink);
+    dump_int(f->font_max_stretch);
+    dump_int(f->_font_step);
+    dump_int(f->_font_tounicode);
+    dump_int(f->_font_type);
+    dump_int(f->_font_format);
+    dump_int(f->_font_writingmode);
+    dump_int(f->_font_identity);
+    dump_int(f->_font_embedding);
+    dump_int(f->_font_streamprovider);
+    dump_int(f->_font_bc);
+    dump_int(f->_hyphen_char);
+    dump_int(f->_skew_char);
+    dump_int(f->_font_natural_dir);
+    dump_int(f->_font_params);
+    dump_int(f->_font_math_params);
+    dump_int(f->ligatures_disabled);
+    dump_int(f->_pdf_font_num);
+    dump_int(f->_pdf_font_attr);
+}
+
+void dump_font(int f)
+{
+    int i, x;
+    set_font_used(f, 0);
+    font_tables[f]->charinfo_cache = NULL;
+    dump_font_entry(font_tables[f]);
+    dump_string(font_name(f));
+    dump_string(font_area(f));
+    dump_string(font_filename(f));
+    dump_string(font_fullname(f));
+    dump_string(font_psname(f));
+    dump_string(font_encodingname(f));
+    dump_string(font_cidregistry(f));
+    dump_string(font_cidordering(f));
+    dump_things(*param_base(f), (font_params(f) + 1));
+    if (font_math_params(f) > 0) {
+        dump_things(*math_param_base(f), (font_math_params(f) + 1 ));
+    }
+    if (has_left_boundary(f)) {
+        dump_int(1);
+        dump_charinfo(f, left_boundarychar);
+    } else {
+        dump_int(0);
+    }
+    if (has_right_boundary(f)) {
+        dump_int(1);
+        dump_charinfo(f, right_boundarychar);
+    } else {
+        dump_int(0);
+    }
+    for (i = font_bc(f); i <= font_ec(f); i++) {
+        if (quick_char_exists(f, i)) {
+            dump_charinfo(f, i);
+        }
+    }
+}
+
+static int undump_charinfo(int f)
+{
+    charinfo *co;
+    int x, i;
+    char *s = NULL;
+    liginfo *lig = NULL;
+    kerninfo *kern = NULL;
+    eight_bits *packet = NULL;
+    undump_int(i);
+    co = get_charinfo(f, i);
+    undump_int(x);
+    set_charinfo_width(co, x);
+    undump_int(x);
+    set_charinfo_height(co, x);
+    undump_int(x);
+    set_charinfo_depth(co, x);
+    undump_int(x);
+    set_charinfo_italic(co, x);
+    undump_int(x);
+    set_charinfo_vert_italic(co, x);
+    undump_int(x);
+    set_charinfo_top_accent(co, x);
+    undump_int(x);
+    set_charinfo_bot_accent(co, x);
+    undump_int(x);
+    set_charinfo_tag(co, x);
+    undump_int(x);
+    set_charinfo_ef(co, x);
+    undump_int(x);
+    set_charinfo_rp(co, x);
+    undump_int(x);
+    set_charinfo_lp(co, x);
+    undump_int(x);
+    set_charinfo_remainder(co, x);
+    undump_int(x);
+    set_charinfo_used(co, x);
+    undump_int(x);
+    set_charinfo_index(co, x);
+    /*tex Name */
+    undump_int(x);
+    if (x > 0) {
+        font_bytes += x;
+        s = xmalloc((unsigned) x);
+        undump_things(*s, x);
+    }
+    set_charinfo_name(co, s);
+    /*tex Tounicode */
+    undump_int(x);
+    if (x > 0) {
+        font_bytes += x;
+        s = xmalloc((unsigned) x);
+        undump_things(*s, x);
+    }
+    set_charinfo_tounicode(co, s);
+    /*tex Ligatures */
+    undump_int(x);
+    if (x > 0) {
+        font_bytes += (int) ((unsigned) x * sizeof(liginfo));
+        lig = xmalloc((unsigned) ((unsigned) x * sizeof(liginfo)));
+        undump_things(*lig, x);
+    }
+    set_charinfo_ligatures(co, lig);
+    /*tex Kerns */
+    undump_int(x);
+    if (x > 0) {
+        font_bytes += (int) ((unsigned) x * sizeof(kerninfo));
+        kern = xmalloc((unsigned) ((unsigned) x * sizeof(kerninfo)));
+        undump_things(*kern, x);
+    }
+    set_charinfo_kerns(co, kern);
+
+    /*tex Packets */
+    undump_int(x);
+    if (x > 0) {
+        font_bytes += x;
+        packet = xmalloc((unsigned) x);
+        undump_things(*packet, x);
+    }
+    set_charinfo_packets(co, packet);
+    if (get_charinfo_tag(co) == ext_tag) {
+        set_charinfo_vert_variants(co, undump_charinfo_variants());
+        set_charinfo_hor_variants(co, undump_charinfo_variants());
+    }
+    undump_math_kerns(co);
+    return i;
+}
+
+#define undump_font_string(a)     \
+    undump_int (x);               \
+    if (x>0) {                    \
+        font_bytes += x;          \
+        s = xmalloc((unsigned)x); \
+        undump_things(*s,x);      \
+        a(f,s);                   \
+    }
+
+static void undump_font_entry(texfont * f)
+{
+    int x = 0;
+    undump_int(x); f->_font_size = x;
+    undump_int(x); f->_font_dsize = x;
+    undump_int(x); f->_font_cidversion = x;
+    undump_int(x); f->_font_cidsupplement = x;
+    undump_int(x); f->_font_ec = x;
+    undump_int(x); f->_font_checksum = (unsigned)x;
+    undump_int(x); f->_font_used = (char)x;
+    undump_int(x); f->_font_touched = (char)x;
+    undump_int(x); f->_font_cache_id = x;
+    undump_int(x); f->_font_encodingbytes = (char)x;
+    undump_int(x); f->_font_oldmath = x;
+    undump_int(x); f->_font_slant = x;
+    undump_int(x); f->_font_extend = x;
+    undump_int(x); f->_font_squeeze = x;
+    undump_int(x); f->_font_mode = x;
+    undump_int(x); f->_font_width = x;
+    undump_int(x); f->font_max_shrink = x;
+    undump_int(x); f->font_max_stretch = x;
+    undump_int(x); f->_font_step = x;
+    undump_int(x); f->_font_tounicode = (char)x;
+    undump_int(x); f->_font_type = x;
+    undump_int(x); f->_font_format = x;
+    undump_int(x); f->_font_writingmode = x;
+    undump_int(x); f->_font_identity = x;
+    undump_int(x); f->_font_embedding = x;
+    undump_int(x); f->_font_streamprovider = x;
+    undump_int(x); f->_font_bc = x;
+    undump_int(x); f->_hyphen_char = x;
+    undump_int(x); f->_skew_char = x;
+    undump_int(x); f->_font_natural_dir = x;
+    undump_int(x); f->_font_params = x;
+    undump_int(x); f->_font_math_params = x;
+    undump_int(x); f->ligatures_disabled = x;
+    undump_int(x); f->_pdf_font_num = x;
+    undump_int(x); f->_pdf_font_attr = x;
+}
+
+void undump_font(int f)
+{
+    int x, i;
+    texfont *tt;
+    charinfo *ci;
+    char *s;
+    sa_tree_item sa_value = { 0 };
+    grow_font_table(f);
+    tt = xmalloc(sizeof(texfont));
+    memset(tt, 0, sizeof(texfont));
+    font_bytes += (int) sizeof(texfont);
+    undump_font_entry(tt);
+    font_tables[f] = tt;
+    undump_font_string(set_font_name);
+    undump_font_string(set_font_area);
+    undump_font_string(set_font_filename);
+    undump_font_string(set_font_fullname);
+    undump_font_string(set_font_psname);
+    undump_font_string(set_font_encodingname);
+    undump_font_string(set_font_cidregistry);
+    undump_font_string(set_font_cidordering);
+    i = (int) (sizeof(*param_base(f)) * ((unsigned) font_params(f) + 1));
+    font_bytes += i;
+    param_base(f) = xmalloc((unsigned) i);
+    undump_things(*param_base(f), (font_params(f) + 1));
+    if (font_math_params(f) > 0) {
+        i = (int) (sizeof(*math_param_base(f)) *
+                   ((unsigned) font_math_params(f) + 1));
+        font_bytes += i;
+        math_param_base(f) = xmalloc((unsigned) i);
+        undump_things(*math_param_base(f), (font_math_params(f) + 1));
+    }
+    /*tex stack size 1, default item value 0 */
+    font_tables[f]->characters = new_sa_tree(1, 1, sa_value);
+    ci = xcalloc(1, sizeof(charinfo));
+    set_charinfo_name(ci, xstrdup(".notdef"));
+    font_tables[f]->charinfo = ci;
+    undump_int(x);
+    if (x) {
+        /*tex left boundary */
+        i = undump_charinfo(f);
+    }
+    undump_int(x);
+    if (x) {
+        /*tex right boundary */
+        i = undump_charinfo(f);
+    }
+    i = font_bc(f);
+    while (i < font_ec(f)) {
+        i = undump_charinfo(f);
+    }
+}
+
+/* The \PK\ pixel density value from |texmf.cnf| */
+
+int pk_dpi;
+
+/*tex
+
+    This one looks up the font for a \TFM\ with name |s| loaded at |fs| size and
+    if found then flushes |s|.
+
+*/
+
+internal_font_number tfm_lookup(char *s, scaled fs)
+{
+    internal_font_number k;
+    if (fs != 0) {
+        for (k = 1; k <= max_font_id(); k++) {
+            if (cmp_font_name(k, s) && font_size(k) == fs) {
+                return k;
+            }
+        }
+    } else {
+        for (k = 1; k <= max_font_id(); k++) {
+            if (cmp_font_name(k, s)) {
+                return k;
+            }
+        }
+    }
+    return null_font;
+}
+
+/*tex
+
+    This returns the multiple of |font_step(f)| that is nearest to |e|.
+
+*/
+
+int fix_expand_value(internal_font_number f, int e)
+{
+    int step;
+    int max_expand;
+    boolean neg;
+    if (e == 0)
+        return 0;
+    if (e < 0) {
+        e = -e;
+        neg = true;
+        max_expand = font_max_shrink(f);
+    } else {
+        neg = false;
+        max_expand = font_max_stretch(f);
+    }
+    if (e > max_expand) {
+        e = max_expand;
+    } else {
+        step = font_step(f);
+        if (e % step > 0)
+            e = step * round_xn_over_d(e, 1, step);
+    }
+    if (neg)
+        e = -e;
+    return e;
+}
+
+void set_expand_params(internal_font_number f, int stretch_limit, int shrink_limit, int font_step)
+{
+    set_font_step(f, font_step);
+    set_font_max_shrink(f, shrink_limit);
+    set_font_max_stretch(f, stretch_limit);
+}
+
+/*tex
+
+    This reads font expansion spec and load expanded font.
+
+*/
+
+void read_expand_font(void)
+{
+    int shrink_limit, stretch_limit, font_step;
+    internal_font_number f;
+    scan_font_ident();
+    f = cur_val;
+    if (f == null_font)
+        normal_error("font expansion", "invalid font identifier");
+    scan_optional_equals();
+    scan_int();
+    stretch_limit = fix_int(cur_val, 0, 1000);
+    scan_int();
+    shrink_limit = fix_int(cur_val, 0, 500);
+    scan_int();
+    font_step = fix_int(cur_val, 0, 100);
+    if (font_step == 0)
+        normal_error("font expansion", "invalid step");
+    stretch_limit = stretch_limit - stretch_limit % font_step;
+    if (stretch_limit < 0)
+        stretch_limit = 0;
+    shrink_limit = shrink_limit - shrink_limit % font_step;
+    if (shrink_limit < 0)
+        shrink_limit = 0;
+    if ((stretch_limit == 0) && (shrink_limit == 0))
+        normal_error("font expansion", "invalid limit(s)");
+    if (scan_keyword("autoexpand")) {
+        normal_warning("font expansion", "autoexpand not supported");
+        /*tex scan an optional space */
+        get_x_token();
+        if (cur_cmd != spacer_cmd)
+            back_input();
+    }
+    if (font_step(f) != 0) {
+        /*tex This font has been expanded, ensure the expansion parameters are identical. */
+        if (font_step(f) != font_step)
+            normal_error("font expansion","font has been expanded with different expansion step");
+        if (((font_max_stretch(f) == 0) && (stretch_limit != 0)) ||
+            ((font_max_stretch(f) > 0) && (font_max_stretch(f) != stretch_limit)))
+            normal_error("font expansion","font has been expanded with different stretch limit");
+
+        if (((font_max_shrink(f) == 0) && (shrink_limit != 0)) ||
+            ((font_max_shrink(f) > 0) && (font_max_shrink(f) != shrink_limit)))
+            normal_error("font expansion","font has been expanded with different shrink limit");
+    } else {
+        if (font_used(f))
+            normal_warning("font expansion", "font should be expanded before its first use");
+        set_expand_params(f, stretch_limit, shrink_limit, font_step);
+    }
+}
+
+/*tex
+
+    Here's an old (sort of obsolete) letterspace-a-font helper. It does so by by
+    creating a virtual font.
+
+*/
+
+void new_letterspaced_font(small_number a)
+{
+    pointer u;
+    str_number t;
+    internal_font_number f, k;
+    boolean nolig = false;
+    get_r_token();
+    u = cur_cs;
+    if (u >= hash_base)
+        t = cs_text(u);
+    else
+        t = maketexstring("FONT");
+    define(u, set_font_cmd, null_font);
+    scan_optional_equals();
+    scan_font_ident();
+    k = cur_val;
+    scan_int();
+    if (scan_keyword("nolig"))
+       nolig=true;
+    f = letter_space_font(k, fix_int(cur_val, -1000, 1000), nolig);
+    equiv(u) = f;
+    eqtb[font_id_base + f] = eqtb[u];
+    font_id_text(f) = t;
+}
+
+/*tex
+
+    This makes a font copy for further use with font expansion. Again a
+    traditional font related helper.
+
+*/
+
+void make_font_copy(small_number a)
+{
+    pointer u;
+    str_number t;
+    internal_font_number f, k;
+    get_r_token();
+    u = cur_cs;
+    if (u >= hash_base)
+        t = cs_text(u);
+    else
+        t = maketexstring("FONT");
+    define(u, set_font_cmd, null_font);
+    scan_optional_equals();
+    scan_font_ident();
+    k = cur_val;
+    f = copy_font_info(k);
+    equiv(u) = f;
+    eqtb[font_id_base + f] = eqtb[u];
+    font_id_text(f) = t;
+}
+
+void glyph_to_unicode(void)
+{
+    str_number s1, s2;
+    scan_toks(false, true);
+    s1 = tokens_to_string(def_ref);
+    delete_token_ref(def_ref);
+    scan_toks(false, true);
+    s2 = tokens_to_string(def_ref);
+    delete_token_ref(def_ref);
+    def_tounicode(s1, s2);
+    flush_str(s2);
+    flush_str(s1);
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/texfont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/texfont.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/texfont.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1972 +0,0 @@
-% texfont.w
-%
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@* Main font API implementation for the original pascal parts.
-
-Stuff to watch out for:
-
-\item{} Knuth had a |'null_character'| that was used when a character could
-not be found by the |fetch()| routine, to signal an error. This has
-been deleted, but it may mean that the output of luatex is
-incompatible with TeX after |fetch()| has detected an error condition.
-
-\item{} Knuth also had a |font_glue()| optimization. I've removed that
-because it was a bit of dirty programming and it also was
-problematic |if 0 != null|.
-
- at c
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-@ @c
-#define noDEBUG
-
-#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f))
-#define do_realloc(a,b,d)    a = xrealloc(a,(unsigned)((unsigned)(b)*sizeof(d)))
-
-texfont **font_tables = NULL;
-
-static int font_arr_max = 0;
-static int font_id_maxval = 0;
-
-@ @c
-static void grow_font_table(int id)
-{
-    int j;
-    if (id >= font_arr_max) {
-        font_bytes +=
-            (int) (((id + 8 - font_arr_max) * (int) sizeof(texfont *)));
-        font_tables =
-            xrealloc(font_tables,
-                     (unsigned) (((unsigned) id + 8) * sizeof(texfont *)));
-        j = 8;
-        while (j--) {
-            font_tables[id + j] = NULL;
-        }
-        font_arr_max = id + 8;
-    }
-}
-
-int new_font_id(void)
-{
-    int i;
-    for (i = 0; i < font_arr_max; i++) {
-        if (font_tables[i] == NULL) {
-            break;
-        }
-    }
-    if (i >= font_arr_max)
-        grow_font_table(i);
-    if (i > font_id_maxval)
-        font_id_maxval = i;
-    return i;
-}
-
-int max_font_id(void)
-{
-    return font_id_maxval;
-}
-
-void set_max_font_id(int i)
-{
-    font_id_maxval = i;
-}
-
-@ @c
-int new_font(void)
-{
-    int k;
-    int id;
-    charinfo *ci;
-    sa_tree_item sa_value = { 0 };
-    id = new_font_id();
-    font_bytes += (int) sizeof(texfont);
-    /* most stuff is zero */
-    font_tables[id] = xcalloc(1, sizeof(texfont));
-    font_tables[id]->_font_name = NULL;
-    font_tables[id]->_font_area = NULL;
-    font_tables[id]->_font_filename = NULL;
-    font_tables[id]->_font_fullname = NULL;
-    font_tables[id]->_font_psname = NULL;
-    font_tables[id]->_font_encodingname = NULL;
-    font_tables[id]->_font_cidregistry = NULL;
-    font_tables[id]->_font_cidordering = NULL;
-    font_tables[id]->_left_boundary = NULL;
-    font_tables[id]->_right_boundary = NULL;
-    font_tables[id]->_param_base = NULL;
-    font_tables[id]->_math_param_base = NULL;
-
-    set_font_bc(id, 1);          /* ec = 0 */
-    set_font_writingmode(id, 0);
-    set_font_identity(id, 0);
-    set_hyphen_char(id, '-');
-    set_skew_char(id, -1);
-    font_slant(id) = 0;          /* vertical */
-    font_extend(id) = 1000;      /* normal width */
-
-    /* allocate eight values including 0 */
-    set_font_params(id, 7);
-    for (k = 0; k <= 7; k++) {
-        set_font_param(id, k, 0);
-    }
-    /* character info zero is reserved for notdef */
-    font_tables[id]->characters = new_sa_tree(1, 1, sa_value);    /* stack size 1, default item value 0 */
-    ci = xcalloc(1, sizeof(charinfo));
-    set_charinfo_name(ci, xstrdup(".notdef"));
-    font_tables[id]->charinfo = ci;
-    font_tables[id]->charinfo_size = 1;
-    font_tables[id]->charinfo_cache = NULL;
-
-    return id;
-}
-
-@ @c
-void font_malloc_charinfo(internal_font_number f, int num)
-{
-    int glyph = font_tables[f]->charinfo_size;
-    font_bytes += (int) (num * (int) sizeof(charinfo));
-    do_realloc(font_tables[f]->charinfo, (unsigned) (glyph + num), charinfo);
-    memset(&(font_tables[f]->charinfo[glyph]), 0,
-           (size_t) (num * (int) sizeof(charinfo)));
-    font_tables[f]->charinfo_size += num;
-}
-
-@ @c
-#define find_charinfo_id(f,c) (get_sa_item(font_tables[f]->characters,c).int_value)
-
-charinfo *get_charinfo(internal_font_number f, int c)
-{
-    int glyph;
-    charinfo *ci;
-    if (proper_char_index(c)) {
-        glyph = get_sa_item(font_tables[f]->characters, c).int_value;
-        if (!glyph) {
-            sa_tree_item sa_value = { 0 };
-            int tglyph = ++font_tables[f]->charinfo_count;
-            if (tglyph >= font_tables[f]->charinfo_size) {
-                font_malloc_charinfo(f, 256);
-            }
-            font_tables[f]->charinfo[tglyph].ef = 1000; /* init */
-            sa_value.int_value = tglyph;
-            set_sa_item(font_tables[f]->characters, c, sa_value, 1); /* 1 = global */
-            glyph = tglyph;
-        }
-        return &(font_tables[f]->charinfo[glyph]);
-    } else if (c == left_boundarychar) {
-        if (left_boundary(f) == NULL) {
-            ci = xcalloc(1, sizeof(charinfo));
-            font_bytes += (int) sizeof(charinfo);
-            set_left_boundary(f, ci);
-        }
-        return left_boundary(f);
-    } else if (c == right_boundarychar) {
-        if (right_boundary(f) == NULL) {
-            ci = xcalloc(1, sizeof(charinfo));
-            font_bytes += (int) sizeof(charinfo);
-            set_right_boundary(f, ci);
-        }
-        return right_boundary(f);
-    }
-    return &(font_tables[f]->charinfo[0]);
-}
-
-@ @c
-static void set_charinfo(internal_font_number f, int c, charinfo * ci)
-{
-    int glyph;
-    if (proper_char_index(c)) {
-        glyph = get_sa_item(font_tables[f]->characters, c).int_value;
-        if (glyph) {
-            font_tables[f]->charinfo[glyph] = *ci;
-        } else {
-            normal_error("font","character insertion failed");
-        }
-    } else if (c == left_boundarychar) {
-        set_left_boundary(f, ci);
-    } else if (c == right_boundarychar) {
-        set_right_boundary(f, ci);
-    }
-}
-
-@ @c
-charinfo *copy_charinfo(charinfo * ci)
-{
-    int x, k;
-    kerninfo *kern;
-    liginfo *lig;
-    eight_bits *packet;
-    charinfo *co = NULL;
-    if (ci == NULL)
-        return NULL;
-    co = xmalloc(sizeof(charinfo));
-    memcpy(co, ci, sizeof(charinfo));
-    set_charinfo_used(co, false);
-    co->name = NULL;
-    co->tounicode = NULL;
-    co->packets = NULL;
-    co->ligatures = NULL;
-    co->kerns = NULL;
-    co->vert_variants = NULL;
-    co->hor_variants = NULL;
-    if (ci->name != NULL) {
-        co->name = xstrdup(ci->name);
-    }
-    if (ci->tounicode != NULL) {
-        co->tounicode = xstrdup(ci->tounicode);
-    }
-    /* kerns */
-    if ((kern = get_charinfo_kerns(ci)) != NULL) {
-        x = 0;
-        while (!kern_end(kern[x])) {
-            x++;
-        }
-        x++;
-        co->kerns = xmalloc((unsigned) (x * (int) sizeof(kerninfo)));
-        memcpy(co->kerns, ci->kerns, (size_t) (x * (int) sizeof(kerninfo)));
-    }
-    /* ligs */
-    if ((lig = get_charinfo_ligatures(ci)) != NULL) {
-        x = 0;
-        while (!lig_end(lig[x])) {
-            x++;
-        }
-        x++;
-        co->ligatures = xmalloc((unsigned) (x * (int) sizeof(liginfo)));
-        memcpy(co->ligatures, ci->ligatures,
-               (size_t) (x * (int) sizeof(liginfo)));
-    }
-    /* packets */
-    if ((packet = get_charinfo_packets(ci)) != NULL) {
-        x = vf_packet_bytes(ci);
-        co->packets = xmalloc((unsigned) x);
-        memcpy(co->packets, ci->packets, (size_t) x);
-    }
-
-    /* horizontal and vertical extenders */
-    if (get_charinfo_vert_variants(ci) != NULL) {
-        set_charinfo_vert_variants(co, copy_variants(get_charinfo_vert_variants(ci)));
-    }
-    if (get_charinfo_hor_variants(ci) != NULL) {
-        set_charinfo_hor_variants(co, copy_variants(get_charinfo_hor_variants(ci)));
-    }
-    x = ci->top_left_math_kerns;
-    co->top_left_math_kerns = x;
-    if (x > 0) {
-        co->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-        for (k = 0; k < co->top_left_math_kerns; k++) {
-            co->top_left_math_kern_array[(2 * k)] = ci->top_left_math_kern_array[(2 * k)];
-            co->top_left_math_kern_array[(2 * k) + 1] = ci->top_left_math_kern_array[(2 * k) + 1];
-        }
-    }
-    x = ci->bottom_left_math_kerns;
-    co->bottom_left_math_kerns = x;
-    if (x > 0) {
-        co->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-        for (k = 0; k < co->bottom_left_math_kerns; k++) {
-            co->bottom_left_math_kern_array[(2 * k)] = ci->bottom_left_math_kern_array[(2 * k)];
-            co->bottom_left_math_kern_array[(2 * k) + 1] = ci->bottom_left_math_kern_array[(2 * k) + 1];
-        }
-    }
-    x = ci->top_right_math_kerns;
-    co->top_right_math_kerns = x;
-    if (x > 0) {
-        co->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-        for (k = 0; k < co->top_right_math_kerns; k++) {
-            co->top_right_math_kern_array[(2 * k)] = ci->top_right_math_kern_array[(2 * k)];
-            co->top_right_math_kern_array[(2 * k) + 1] = ci->top_right_math_kern_array[(2 * k) + 1];
-        }
-    }
-    x = ci->bottom_right_math_kerns;
-    co->bottom_right_math_kerns = x;
-    if (x > 0) {
-        co->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-        for (k = 0; k < co->bottom_right_math_kerns; k++) {
-            co->bottom_right_math_kern_array[(2 * k)] = ci->bottom_right_math_kern_array[(2 * k)];
-            co->bottom_right_math_kern_array[(2 * k) + 1] = ci->bottom_right_math_kern_array[(2 * k) + 1];
-        }
-    }
-    return co;
-}
-
-charinfo *char_info(internal_font_number f, int c)
-{
-    if (f > font_id_maxval)
-        return 0;
-    if (proper_char_index(c)) {
-        register int glyph = (int) find_charinfo_id(f, c);
-        return &(font_tables[f]->charinfo[glyph]);
-    } else if (c == left_boundarychar && left_boundary(f) != NULL) {
-        return left_boundary(f);
-    } else if (c == right_boundarychar && right_boundary(f) != NULL) {
-        return right_boundary(f);
-    }
-    return &(font_tables[f]->charinfo[0]);
-}
-
-@ @c
-scaled_whd get_charinfo_whd(internal_font_number f, int c)
-{
-    scaled_whd s;
-    charinfo *i;
-    i = char_info(f, c);
-    s.wd = i->width;
-    s.dp = i->depth;
-    s.ht = i->height;
-    return s;
-}
-
-@ @c
-int char_exists(internal_font_number f, int c)
-{
-    if (f > font_id_maxval)
-        return 0;
-    if (proper_char_index(c)) {
-        return (int) find_charinfo_id(f, c);
-    } else if ((c == left_boundarychar) && has_left_boundary(f)) {
-        return 1;
-    } else if ((c == right_boundarychar) && has_right_boundary(f)) {
-        return 1;
-    }
-    return 0;
-}
-
-@ @c
-int lua_glyph_not_found_callback(internal_font_number f, int c)
-{
-    int callback_id;
-    int ret = 0;
-    callback_id = callback_defined(glyph_not_found_callback);
-    if (callback_id != 0) {
-        if (!get_callback(Luas, callback_id)) {
-            lua_pop(Luas, 2);
-            return 0;
-        }
-        lua_pushinteger(Luas, f);
-        lua_pushinteger(Luas, c);
-        if (lua_pcall(Luas, 2, 1, 0) != 0) {       /* two args, 1 result */
-            fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
-            lua_pop(Luas, 2);
-            error();
-        } else {
-            ret = lua_toboolean(Luas, -1);
-        }
-    } else {
-        char_warning(f,c);
-    }
-    return ret;
-}
-
-@ @c
-extinfo *new_variant(int glyph, int startconnect, int endconnect,
-                     int advance, int repeater)
-{
-    extinfo *ext;
-    ext = xmalloc(sizeof(extinfo));
-    ext->next = NULL;
-    ext->glyph = glyph;
-    ext->start_overlap = startconnect;
-    ext->end_overlap = endconnect;
-    ext->advance = advance;
-    ext->extender = repeater;
-    return ext;
-}
-
-
-@ @c
-static extinfo *copy_variant(extinfo * old)
-{
-    extinfo *ext;
-    ext = xmalloc(sizeof(extinfo));
-    ext->next = NULL;
-    ext->glyph = old->glyph;
-    ext->start_overlap = old->start_overlap;
-    ext->end_overlap = old->end_overlap;
-    ext->advance = old->advance;
-    ext->extender = old->extender;
-    return ext;
-}
-
-@ @c
-static void dump_variant(extinfo * ext)
-{
-    dump_int(ext->glyph);
-    dump_int(ext->start_overlap);
-    dump_int(ext->end_overlap);
-    dump_int(ext->advance);
-    dump_int(ext->extender);
-    return;
-}
-
-
-@ @c
-static extinfo *undump_variant(void)
-{
-    int x;
-    extinfo *ext;
-    undump_int(x);
-    if (x == 0)
-        return NULL;
-    ext = xmalloc(sizeof(extinfo));
-    ext->next = NULL;
-    ext->glyph = x;
-    undump_int(x);
-    ext->start_overlap = x;
-    undump_int(x);
-    ext->end_overlap = x;
-    undump_int(x);
-    ext->advance = x;
-    undump_int(x);
-    ext->extender = x;
-    return ext;
-}
-
-@ @c
-void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
-{
-    if (ci->vert_variants == NULL) {
-        ci->vert_variants = ext;
-    } else {
-        extinfo *lst = ci->vert_variants;
-        while (lst->next != NULL)
-            lst = lst->next;
-        lst->next = ext;
-    }
-
-}
-
-@ @c
-void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
-{
-    if (ci->hor_variants == NULL) {
-        ci->hor_variants = ext;
-    } else {
-        extinfo *lst = ci->hor_variants;
-        while (lst->next != NULL)
-            lst = lst->next;
-        lst->next = ext;
-    }
-
-}
-
-@ @c
-extinfo *copy_variants(extinfo * o)
-{
-    extinfo *c, *t = NULL, *h = NULL;
-    while (o != NULL) {
-        c = copy_variant(o);
-        if (h == null)
-            h = c;
-        else
-            t->next = c;
-        t = c;
-        o = o->next;
-    }
-
-    return h;
-}
-
-@ @c
-static void dump_charinfo_variants(extinfo * o)
-{
-    while (o != NULL) {
-        dump_variant(o);
-        o = o->next;
-    }
-    dump_int(0);
-    return;
-}
-
-@ @c
-static extinfo *undump_charinfo_variants(void)
-{
-    extinfo *c, *t = NULL, *h = NULL;
-    c = undump_variant();
-    while (c != NULL) {
-        if (h == null)
-            h = c;
-        else
-            t->next = c;
-        t = c;
-        c = undump_variant();
-    }
-    return h;
-}
-
-
-@ Note that mant more small things like this are implemented
-as macros in the header file.
- at c
-void set_charinfo_width(charinfo * ci, scaled val)
-{
-    ci->width = val;
-}
-
-void set_charinfo_height(charinfo * ci, scaled val)
-{
-    ci->height = val;
-}
-
-void set_charinfo_depth(charinfo * ci, scaled val)
-{
-    ci->depth = val;
-}
-
-void set_charinfo_italic(charinfo * ci, scaled val)
-{
-    ci->italic = val;
-}
-
-void set_charinfo_vert_italic(charinfo * ci, scaled val)
-{
-    ci->vert_italic = val;
-}
-
-void set_charinfo_top_accent(charinfo * ci, scaled val)
-{
-    ci->top_accent = val;
-}
-
-void set_charinfo_bot_accent(charinfo * ci, scaled val)
-{
-    ci->bot_accent = val;
-}
-
-void set_charinfo_tag(charinfo * ci, scaled val)
-{
-    ci->tag = (char) val;
-}
-
-void set_charinfo_remainder(charinfo * ci, scaled val)
-{
-    ci->remainder = val;
-}
-
-void set_charinfo_used(charinfo * ci, scaled val)
-{
-    ci->used = (char) val;
-}
-
-void set_charinfo_index(charinfo * ci, scaled val)
-{
-    ci->index = (unsigned short) val;
-}
-
-void set_charinfo_name(charinfo * ci, char *val)
-{
-    xfree(ci->name);
-    ci->name = val;
-}
-
-void set_charinfo_tounicode(charinfo * ci, char *val)
-{
-    xfree(ci->tounicode);
-    ci->tounicode = val;
-}
-
-void set_charinfo_ligatures(charinfo * ci, liginfo * val)
-{
-    dxfree(ci->ligatures, val);
-}
-
-void set_charinfo_kerns(charinfo * ci, kerninfo * val)
-{
-    dxfree(ci->kerns, val);
-}
-
-void set_charinfo_packets(charinfo * ci, eight_bits * val)
-{
-    dxfree(ci->packets, val);
-}
-
-void set_charinfo_ef(charinfo * ci, scaled val)
-{
-    ci->ef = val;
-}
-
-void set_charinfo_lp(charinfo * ci, scaled val)
-{
-    ci->lp = val;
-}
-
-void set_charinfo_rp(charinfo * ci, scaled val)
-{
-    ci->rp = val;
-}
-
-@ @c
-void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
-{
-    extinfo *c, *lst;
-    if (ci->vert_variants != NULL) {
-        lst = ci->vert_variants;
-        while (lst != NULL) {
-            c = lst->next;
-            free(lst);
-            lst = c;
-        }
-    }
-    ci->vert_variants = ext;
-}
-
-@ @c
-void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
-{
-    extinfo *c, *lst;
-    if (ci->hor_variants != NULL) {
-        lst = ci->hor_variants;
-        while (lst != NULL) {
-            c = lst->next;
-            free(lst);
-            lst = c;
-        }
-    }
-    ci->hor_variants = ext;
-
-}
-
-@ @c
-int get_charinfo_math_kerns(charinfo * ci, int id)
-{
-
-    int k = 0;                  /* all callers check for |result>0| */
-    if (id == top_left_kern) {
-        k = ci->top_left_math_kerns;
-    } else if (id == bottom_left_kern) {
-        k = ci->bottom_left_math_kerns;
-    } else if (id == top_right_kern) {
-        k = ci->top_right_math_kerns;
-    } else if (id == bottom_right_kern) {
-        k = ci->bottom_right_math_kerns;
-    } else {
-        confusion("get_charinfo_math_kerns");
-    }
-    return k;
-}
-
-@ @c
-void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
-{
-    int k;
-    if (id == top_left_kern) {
-        k = ci->top_left_math_kerns;
-        do_realloc(ci->top_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
-        ci->top_left_math_kern_array[(2 * (k))] = ht;
-        ci->top_left_math_kern_array[((2 * (k)) + 1)] = krn;
-        ci->top_left_math_kerns++;
-    } else if (id == bottom_left_kern) {
-        k = ci->bottom_left_math_kerns;
-        do_realloc(ci->bottom_left_math_kern_array, ((k + 1) * 2), sizeof(scaled));
-        ci->bottom_left_math_kern_array[(2 * (k))] = ht;
-        ci->bottom_left_math_kern_array[(2 * (k)) + 1] = krn;
-        ci->bottom_left_math_kerns++;
-    } else if (id == top_right_kern) {
-        k = ci->top_right_math_kerns;
-        do_realloc(ci->top_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
-        ci->top_right_math_kern_array[(2 * (k))] = ht;
-        ci->top_right_math_kern_array[(2 * (k)) + 1] = krn;
-        ci->top_right_math_kerns++;
-    } else if (id == bottom_right_kern) {
-        k = ci->bottom_right_math_kerns;
-        do_realloc(ci->bottom_right_math_kern_array, ((k + 1) * 2), sizeof(scaled));
-        ci->bottom_right_math_kern_array[(2 * (k))] = ht;
-        ci->bottom_right_math_kern_array[(2 * (k)) + 1] = krn;
-        ci->bottom_right_math_kerns++;
-    } else {
-        confusion("add_charinfo_math_kern");
-    }
-}
-
-
-@ @c
-static void dump_math_kerns(charinfo * ci)
-{
-    int k, l;
-    l = ci->top_left_math_kerns;
-    dump_int(l);
-    for (k = 0; k < l; k++) {
-        dump_int(ci->top_left_math_kern_array[(2 * k)]);
-        dump_int(ci->top_left_math_kern_array[(2 * k) + 1]);
-    }
-    l = ci->bottom_left_math_kerns;
-    dump_int(l);
-    for (k = 0; k < l; k++) {
-        dump_int(ci->bottom_left_math_kern_array[(2 * k)]);
-        dump_int(ci->bottom_left_math_kern_array[(2 * k) + 1]);
-    }
-    l = ci->top_right_math_kerns;
-    dump_int(l);
-    for (k = 0; k < l; k++) {
-        dump_int(ci->top_right_math_kern_array[(2 * k)]);
-        dump_int(ci->top_right_math_kern_array[(2 * k) + 1]);
-    }
-    l = ci->bottom_right_math_kerns;
-    dump_int(l);
-    for (k = 0; k < l; k++) {
-        dump_int(ci->bottom_right_math_kern_array[(2 * k)]);
-        dump_int(ci->bottom_right_math_kern_array[(2 * k) + 1]);
-    }
-}
-
-@ @c
-static void undump_math_kerns(charinfo * ci)
-{
-    int k;
-    int x;
-    undump_int(x);
-    ci->top_left_math_kerns = x;
-    if (x > 0)
-        ci->top_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->top_left_math_kerns; k++) {
-        undump_int(x);
-        ci->top_left_math_kern_array[(2 * k)] = (scaled) x;
-        undump_int(x);
-        ci->top_left_math_kern_array[(2 * k) + 1] = (scaled) x;
-    }
-    undump_int(x);
-    ci->bottom_left_math_kerns = x;
-    if (x > 0)
-        ci->bottom_left_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->bottom_left_math_kerns; k++) {
-        undump_int(x);
-        ci->bottom_left_math_kern_array[(2 * k)] = (scaled) x;
-        undump_int(x);
-        ci->bottom_left_math_kern_array[(2 * k) + 1] = (scaled) x;
-    }
-    undump_int(x);
-    ci->top_right_math_kerns = x;
-    if (x > 0)
-        ci->top_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->top_right_math_kerns; k++) {
-        undump_int(x);
-        ci->top_right_math_kern_array[(2 * k)] = (scaled) x;
-        undump_int(x);
-        ci->top_right_math_kern_array[(2 * k) + 1] = (scaled) x;
-    }
-    undump_int(x);
-    ci->bottom_right_math_kerns = x;
-    if (x > 0)
-        ci->bottom_right_math_kern_array = xmalloc((unsigned) (2 * (int) sizeof(scaled) * x));
-    for (k = 0; k < ci->bottom_right_math_kerns; k++) {
-        undump_int(x);
-        ci->bottom_right_math_kern_array[(2 * k)] = (scaled) x;
-        undump_int(x);
-        ci->bottom_right_math_kern_array[(2 * k) + 1] = (scaled) x;
-    }
-}
-
-
-@ In TeX, extensibles were fairly simple things.
-   This function squeezes a TFM extensible into the vertical extender structures.
-   |advance==0| is a special case for TFM fonts, because finding the proper
-   advance width during tfm reading can be tricky
-
-
-  a small complication arises if |rep| is the only non-zero: it needs to be
-  doubled as a non-repeatable to avoid mayhem */
-
- at c
-void set_charinfo_extensible(charinfo * ci, int top, int bot, int mid, int rep)
-{
-    extinfo *ext;
-    set_charinfo_vert_variants(ci, NULL);       /* clear old */
-    if (bot == 0 && top == 0 && mid == 0 && rep != 0) {
-        ext = new_variant(rep, 0, 0, 0, EXT_NORMAL);
-        add_charinfo_vert_variant(ci, ext);
-        ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
-        add_charinfo_vert_variant(ci, ext);
-        return;
-    }
-    if (bot != 0) {
-        ext = new_variant(bot, 0, 0, 0, EXT_NORMAL);
-        add_charinfo_vert_variant(ci, ext);
-    }
-    if (rep != 0) {
-        ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
-        add_charinfo_vert_variant(ci, ext);
-    }
-    if (mid != 0) {
-        ext = new_variant(mid, 0, 0, 0, EXT_NORMAL);
-        add_charinfo_vert_variant(ci, ext);
-        if (rep != 0) {
-            ext = new_variant(rep, 0, 0, 0, EXT_REPEAT);
-            add_charinfo_vert_variant(ci, ext);
-        }
-    }
-    if (top != 0) {
-        ext = new_variant(top, 0, 0, 0, EXT_NORMAL);
-        add_charinfo_vert_variant(ci, ext);
-    }
-}
-
-@ Note that many more simple things like this are implemented as macros
-in the header file.
-
- at c
-scaled get_charinfo_width(charinfo * ci)
-{
-    return ci->width;
-}
-
-scaled get_charinfo_height(charinfo * ci)
-{
-    return ci->height;
-}
-
-scaled get_charinfo_depth(charinfo * ci)
-{
-    return ci->depth;
-}
-
-scaled get_charinfo_italic(charinfo * ci)
-{
-    return ci->italic;
-}
-
-scaled get_charinfo_vert_italic(charinfo * ci)
-{
-    return ci->vert_italic;
-}
-
-scaled get_charinfo_top_accent(charinfo * ci)
-{
-    return ci->top_accent;
-}
-
-scaled get_charinfo_bot_accent(charinfo * ci)
-{
-    return ci->bot_accent;
-}
-
-char get_charinfo_tag(charinfo * ci)
-{
-    return ci->tag;
-}
-
-int get_charinfo_remainder(charinfo * ci)
-{
-    return ci->remainder;
-}
-
-char get_charinfo_used(charinfo * ci)
-{
-    return ci->used;
-}
-
-int get_charinfo_index(charinfo * ci)
-{
-    return ci->index;
-}
-
-char *get_charinfo_name(charinfo * ci)
-{
-    return ci->name;
-}
-
-char *get_charinfo_tounicode(charinfo * ci)
-{
-    return ci->tounicode;
-}
-
-liginfo *get_charinfo_ligatures(charinfo * ci)
-{
-    return ci->ligatures;
-}
-
-kerninfo *get_charinfo_kerns(charinfo * ci)
-{
-    return ci->kerns;
-}
-
-eight_bits *get_charinfo_packets(charinfo * ci)
-{
-    return ci->packets;
-}
-
-int get_charinfo_ef(charinfo * ci)
-{
-    return ci->ef;
-}
-
-int get_charinfo_rp(charinfo * ci)
-{
-    return ci->rp;
-}
-
-int get_charinfo_lp(charinfo * ci)
-{
-    return ci->lp;
-}
-
-extinfo *get_charinfo_vert_variants(charinfo * ci)
-{
-    extinfo *w = NULL;
-    if (ci->vert_variants != NULL)
-        w = ci->vert_variants;
-    return w;
-}
-
-extinfo *get_charinfo_hor_variants(charinfo * ci)
-{
-    extinfo *w = NULL;
-    if (ci->hor_variants != NULL)
-        w = ci->hor_variants;
-    return w;
-}
-
-
-scaled char_width(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    scaled w = get_charinfo_width(ci);
-    return w;
-}
-
-scaled calc_char_width(internal_font_number f, int c, int ex)
-{
-    charinfo *ci = char_info(f, c);
-    scaled w = get_charinfo_width(ci);
-    if (ex != 0)
-        w = round_xn_over_d(w, 1000 + ex, 1000);
-    return w;
-}
-
-scaled char_depth(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    scaled d = get_charinfo_depth(ci);
-    return d;
-}
-
-scaled char_height(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    scaled h = get_charinfo_height(ci);
-    return h;
-}
-
-scaled char_italic(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    scaled i = get_charinfo_italic(ci);
-    return i;
-}
-
-scaled char_vert_italic(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    scaled i = get_charinfo_vert_italic(ci);
-    return i;
-}
-
-scaled char_top_accent(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_top_accent(ci);
-}
-
-scaled char_bot_accent(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_bot_accent(ci);
-}
-
-
-int char_remainder(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_remainder(ci);
-}
-
-char char_tag(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_tag(ci);
-}
-
-char char_used(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_used(ci);
-}
-
-char *char_name(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_name(ci);
-}
-
-int char_index(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_index(ci);
-}
-
-liginfo *char_ligatures(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_ligatures(ci);
-}
-
-kerninfo *char_kerns(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_kerns(ci);
-}
-
-eight_bits *char_packets(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_packets(ci);
-}
-
-@ @c
-void set_font_params(internal_font_number f, int b)
-{
-    int i;
-    i = font_params(f);
-    if (i != b) {
-        font_bytes +=
-            (int) ((b - (int) font_params(f) + 1) * (int) sizeof(scaled));
-        do_realloc(param_base(f), (b + 2), int);
-        font_params(f) = b;
-        if (b > i) {
-            while (i < b) {
-                i++;
-                set_font_param(f, i, 0);
-            }
-        }
-    }
-}
-
-@ @c
-void set_font_math_params(internal_font_number f, int b)
-{
-    int i;
-    i = font_math_params(f);
-    if (i != b) {
-        font_bytes +=
-            ((b - (int) font_math_params(f) + 1) * (int) sizeof(scaled));
-        do_realloc(math_param_base(f), (b + 2), int);
-        font_math_params(f) = b;
-        if (b > i) {
-            while (i < b) {
-                i++;
-                set_font_math_param(f, i, undefined_math_parameter);
-            }
-        }
-    }
-}
-
-@ @c
-int copy_font(int f)
-{
-    int i, ci_cnt, ci_size;
-    charinfo *ci;
-    int k = new_font();
-
-    {
-        ci = font_tables[k]->charinfo;
-        ci_cnt = font_tables[k]->charinfo_count;
-        ci_size = font_tables[k]->charinfo_size;
-        memcpy(font_tables[k], font_tables[f], sizeof(texfont));
-        font_tables[k]->charinfo = ci;
-        font_tables[k]->charinfo_count = ci_cnt;
-        font_tables[k]->charinfo_size = ci_size;
-    }
-
-    font_malloc_charinfo(k, font_tables[f]->charinfo_count);
-    set_font_cache_id(k, 0);
-    set_font_used(k, 0);
-    set_font_touched(k, 0);
-
-    font_tables[k]->_font_name = NULL;
-    font_tables[k]->_font_filename = NULL;
-    font_tables[k]->_font_fullname = NULL;
-    font_tables[k]->_font_psname = NULL;
-    font_tables[k]->_font_encodingname = NULL;
-    font_tables[k]->_font_area = NULL;
-    font_tables[k]->_font_cidregistry = NULL;
-    font_tables[k]->_font_cidordering = NULL;
-    font_tables[k]->_left_boundary = NULL;
-    font_tables[k]->_right_boundary = NULL;
-
-    set_font_name(k, xstrdup(font_name(f)));
-    if (font_filename(f) != NULL)
-        set_font_filename(k, xstrdup(font_filename(f)));
-    if (font_fullname(f) != NULL)
-        set_font_fullname(k, xstrdup(font_fullname(f)));
-    if (font_psname(f) != NULL)
-        set_font_psname(k, xstrdup(font_psname(f)));
-    if (font_encodingname(f) != NULL)
-        set_font_encodingname(k, xstrdup(font_encodingname(f)));
-    if (font_area(f) != NULL)
-        set_font_area(k, xstrdup(font_area(f)));
-    if (font_cidregistry(f) != NULL)
-        set_font_cidregistry(k, xstrdup(font_cidregistry(f)));
-    if (font_cidordering(f) != NULL)
-        set_font_cidordering(k, xstrdup(font_cidordering(f)));
-
-    i = (int) (sizeof(*param_base(f)) * (unsigned) (font_params(f)+1));
-    font_bytes += i;
-    param_base(k) = xmalloc((unsigned) (i+1));
-    memcpy(param_base(k), param_base(f), (size_t) (i));
-
-    if (font_math_params(f) > 0) {
-        i = (int) (sizeof(*math_param_base(f)) *
-                   (unsigned) font_math_params(f));
-        font_bytes += i;
-        math_param_base(k) = xmalloc((unsigned) i);
-        memcpy(math_param_base(k), math_param_base(f), (size_t) i);
-    }
-
-    for (i = 0; i <= font_tables[f]->charinfo_count; i++) {
-        ci = copy_charinfo(&font_tables[f]->charinfo[i]);
-        font_tables[k]->charinfo[i] = *ci;
-    }
-
-    if (left_boundary(f) != NULL) {
-        ci = copy_charinfo(left_boundary(f));
-        set_charinfo(k, left_boundarychar, ci);
-    }
-
-    if (right_boundary(f) != NULL) {
-        ci = copy_charinfo(right_boundary(f));
-        set_charinfo(k, right_boundarychar, ci);
-    }
-    /* not updated yet: */
-    font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
-    return k;
-}
-
-@ @c
-void delete_font(int f)
-{
-    int i;
-    charinfo *co;
-    assert(f > 0);
-    if (font_tables[f] != NULL) {
-        set_font_name(f, NULL);
-        set_font_filename(f, NULL);
-        set_font_fullname(f, NULL);
-        set_font_psname(f, NULL);
-        set_font_encodingname(f, NULL);
-        set_font_area(f, NULL);
-        set_font_cidregistry(f, NULL);
-        set_font_cidordering(f, NULL);
-        set_left_boundary(f, NULL);
-        set_right_boundary(f, NULL);
-
-        for (i = font_bc(f); i <= font_ec(f); i++) {
-            if (quick_char_exists(f, i)) {
-                co = char_info(f, i);
-                set_charinfo_name(co, NULL);
-                set_charinfo_tounicode(co, NULL);
-                set_charinfo_packets(co, NULL);
-                set_charinfo_ligatures(co, NULL);
-                set_charinfo_kerns(co, NULL);
-                set_charinfo_vert_variants(co, NULL);
-                set_charinfo_hor_variants(co, NULL);
-            }
-        }
-        /* free .notdef */
-        set_charinfo_name(font_tables[f]->charinfo + 0, NULL);
-        free(font_tables[f]->charinfo);
-        destroy_sa_tree(font_tables[f]->characters);
-
-        free(param_base(f));
-        if (math_param_base(f) != NULL)
-            free(math_param_base(f));
-        free(font_tables[f]);
-        font_tables[f] = NULL;
-
-        if (font_id_maxval == f) {
-            font_id_maxval--;
-        }
-    }
-}
-
-@ @c
-void create_null_font(void)
-{
-    int i = new_font();
-    assert(i == 0);
-    set_font_name(i, xstrdup("nullfont"));
-    set_font_area(i, xstrdup(""));
-    set_font_touched(i, 1);
-}
-
-@ @c
-boolean is_valid_font(int id)
-{
-    int ret = 0;
-    if (id >= 0 && id <= font_id_maxval && font_tables[id] != NULL)
-        ret = 1;
-    return ret;
-}
-
-@ @c
-boolean cmp_font_area(int id, str_number t)
-{
-    char *tt = NULL;
-    char *tid = font_area(id);
-    if (t == 0) {
-        if (tid == NULL || strlen(tid) == 0)
-            return 1;
-        else
-            return 0;
-    }
-    tt = makecstring(t);
-    if ((tt == NULL || strlen(tt) == 0) && (tid == NULL || strlen(tid) == 0))
-        return 1;
-    if (tt == NULL || strcmp(tid, tt) != 0)
-        return 0;
-    free(tt);
-    return 1;
-}
-
-@ Here come some subroutines to deal with expanded fonts for HZ-algorithm.
-return 1 == identical
- at c
-static boolean cmp_font_name(int id, char *tt)
-{
-    char *tid;
-    if (!is_valid_font(id))
-        return 0;
-    tid = font_name(id);
-    if (tt == NULL && tid == NULL)
-        return 1;
-    if (tt == NULL || tid == NULL || strcmp(tid, tt) != 0)
-        return 0;
-    return 1;
-}
-
-@ @c
-int test_no_ligatures(internal_font_number f)
-{
-    int c;
-    for (c = font_bc(f); c <= font_ec(f); c++) {
-        if (has_lig(f, c))      /* |char_exists(f,c)| */
-            return 0;
-    }
-    return 1;
-}
-
-@ @c
-int get_tag_code(internal_font_number f, int c)
-{
-    small_number i;
-    if (char_exists(f, c)) {
-        i = char_tag(f, c);
-        if (i == lig_tag)
-            return 1;
-        else if (i == list_tag)
-            return 2;
-        else if (i == ext_tag)
-            return 4;
-        else
-            return 0;
-    }
-    return -1;
-}
-
-@ @c
-int get_lp_code(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_lp(ci);
-}
-
-int get_rp_code(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_rp(ci);
-}
-
-int get_ef_code(internal_font_number f, int c)
-{
-    charinfo *ci = char_info(f, c);
-    return get_charinfo_ef(ci);
-}
-
-@ @c
-void set_tag_code(internal_font_number f, int c, int i)
-{
-    int fixedi;
-    charinfo *co;
-    if (char_exists(f, c)) {
-        /* |abs(fix_int(i-7,0))| */
-        fixedi = -(i < -7 ? -7 : (i > 0 ? 0 : i));
-        co = char_info(f, c);
-        if (fixedi >= 4) {
-            if (char_tag(f, c) == ext_tag)
-                set_charinfo_tag(co, (char_tag(f, c) - ext_tag));
-            fixedi = fixedi - 4;
-        }
-        if (fixedi >= 2) {
-            if (char_tag(f, c) == list_tag)
-                set_charinfo_tag(co, (char_tag(f, c) - list_tag));
-            fixedi = fixedi - 2;
-        };
-        if (fixedi >= 1) {
-            if (has_lig(f, c))
-                set_charinfo_ligatures(co, NULL);
-            if (has_kern(f, c))
-                set_charinfo_kerns(co, NULL);
-        }
-    }
-}
-
-@ @c
-void set_lp_code(internal_font_number f, int c, int i)
-{
-    charinfo *co;
-    if (char_exists(f, c)) {
-        co = char_info(f, c);
-        set_charinfo_lp(co, i);
-    }
-}
-
-void set_rp_code(internal_font_number f, int c, int i)
-{
-    charinfo *co;
-    if (char_exists(f, c)) {
-        co = char_info(f, c);
-        set_charinfo_rp(co, i);
-    }
-}
-
-void set_ef_code(internal_font_number f, int c, int i)
-{
-    charinfo *co;
-    if (char_exists(f, c)) {
-        co = char_info(f, c);
-        set_charinfo_ef(co, i);
-    }
-}
-
-@ @c
-void set_no_ligatures(internal_font_number f)
-{
-    int c;
-    charinfo *co;
-    if (font_tables[f]->ligatures_disabled)
-        return;
-    co = char_info(f, left_boundarychar);
-    set_charinfo_ligatures(co, NULL);
-    co = char_info(f, right_boundarychar);      /* this is weird */
-    set_charinfo_ligatures(co, NULL);
-    for (c = 0; c < font_tables[f]->charinfo_count; c++) {
-        co = font_tables[f]->charinfo + c;
-        set_charinfo_ligatures(co, NULL);
-    }
-    font_tables[f]->ligatures_disabled = 1;
-}
-
-@ @c
-liginfo get_ligature(internal_font_number f, int lc, int rc)
-{
-    int k = 0;
-    liginfo t, u;
-    charinfo *co;
-    t.lig = 0;
-    t.type = 0;
-    t.adj = 0;
-    if (lc == non_boundarychar || rc == non_boundarychar || (!has_lig(f, lc)))
-        return t;
-    co = char_info(f, lc);
-    while (1) {
-        u = charinfo_ligature(co, k);
-        if (lig_end(u))
-            break;
-        if (lig_char(u) == rc) {
-            if (lig_disabled(u)) {
-                return t;
-            } else {
-                return u;
-            }
-        }
-        k++;
-    }
-    return t;
-}
-
-@ @c
-scaled raw_get_kern(internal_font_number f, int lc, int rc)
-{
-    int k = 0;
-    kerninfo u;
-    charinfo *co;
-    if (lc == non_boundarychar || rc == non_boundarychar)
-        return 0;
-    co = char_info(f, lc);
-    while (1) {
-        u = charinfo_kern(co, k);
-        if (kern_end(u))
-            break;
-        if (kern_char(u) == rc) {
-            if (kern_disabled(u))
-                return 0;
-            else
-                return kern_kern(u);
-        }
-        k++;
-    }
-    return 0;
-}
-
-@ @c
-scaled get_kern(internal_font_number f, int lc, int rc)
-{
-    if (lc == non_boundarychar || rc == non_boundarychar || (!has_kern(f, lc)))
-        return 0;
-    return raw_get_kern(f, lc, rc);
-}
-
-
-@ dumping and undumping fonts
-
- at c
-#define dump_string(a)			\
-    if (a!=NULL) {			\
-      x = (int)(strlen(a)+1);		\
-      dump_int(x);  dump_things(*a, x);	\
-    } else {				\
-	x = 0; dump_int(x);		\
-    }
-
-static void dump_charinfo(int f, int c)
-{
-    charinfo *co;
-    int x;
-    liginfo *lig;
-    kerninfo *kern;
-    dump_int(c);
-    co = char_info(f, c);
-    set_charinfo_used(co, 0);
-    dump_int(get_charinfo_width(co));
-    dump_int(get_charinfo_height(co));
-    dump_int(get_charinfo_depth(co));
-    dump_int(get_charinfo_italic(co));
-    dump_int(get_charinfo_vert_italic(co));
-    dump_int(get_charinfo_top_accent(co));
-    dump_int(get_charinfo_bot_accent(co));
-    dump_int(get_charinfo_tag(co));
-    dump_int(get_charinfo_ef(co));
-    dump_int(get_charinfo_rp(co));
-    dump_int(get_charinfo_lp(co));
-    dump_int(get_charinfo_remainder(co));
-    dump_int(get_charinfo_used(co));
-    dump_int(get_charinfo_index(co));
-    dump_string(get_charinfo_name(co));
-    dump_string(get_charinfo_tounicode(co));
-
-    /* ligatures */
-    x = 0;
-    if ((lig = get_charinfo_ligatures(co)) != NULL) {
-        while (!lig_end(lig[x])) {
-            x++;
-        }
-        x++;
-        dump_int(x);
-        dump_things(*lig, x);
-    } else {
-        dump_int(x);
-    }
-    /* kerns */
-    x = 0;
-    if ((kern = get_charinfo_kerns(co)) != NULL) {
-        while (!kern_end(kern[x])) {
-            x++;
-        }
-        x++;
-        dump_int(x);
-        dump_things(*kern, x);
-    } else {
-        dump_int(x);
-    }
-    /* packets */
-    x = vf_packet_bytes(co);
-    dump_int(x);
-    if (x > 0) {
-        dump_things(*get_charinfo_packets(co), x);
-    }
-
-    if (get_charinfo_tag(co) == ext_tag) {
-        dump_charinfo_variants(get_charinfo_vert_variants(co));
-        dump_charinfo_variants(get_charinfo_hor_variants(co));
-    }
-    dump_math_kerns(co);
-}
-
-static void dump_font_entry(texfont * f)
-{
-    int x;
-    dump_int(f->_font_size);
-    dump_int(f->_font_dsize);
-    dump_int(f->_font_cidversion);
-    dump_int(f->_font_cidsupplement);
-    dump_int(f->_font_ec);
-    x = (int) f->_font_checksum;
-    dump_int(x);
-    dump_int(f->_font_used);
-    dump_int(f->_font_touched);
-    dump_int(f->_font_cache_id);
-    dump_int(f->_font_encodingbytes);
-    dump_int(f->_font_oldmath);
-    dump_int(f->_font_slant);
-    dump_int(f->_font_extend);
-    dump_int(f->font_max_shrink);
-    dump_int(f->font_max_stretch);
-    dump_int(f->_font_step);
-    dump_int(f->_font_tounicode);
-    dump_int(f->_font_type);
-    dump_int(f->_font_format);
-    dump_int(f->_font_writingmode);
-    dump_int(f->_font_identity);
-    dump_int(f->_font_embedding);
-    dump_int(f->_font_streamprovider);
-    dump_int(f->_font_bc);
-    dump_int(f->_hyphen_char);
-    dump_int(f->_skew_char);
-    dump_int(f->_font_natural_dir);
-    dump_int(f->_font_params);
-    dump_int(f->_font_math_params);
-    dump_int(f->ligatures_disabled);
-    dump_int(f->_pdf_font_num);
-    dump_int(f->_pdf_font_attr);
-}
-
-void dump_font(int f)
-{
-    int i, x;
-
-    set_font_used(f, 0);
-    font_tables[f]->charinfo_cache = NULL;
-    dump_font_entry(font_tables[f]);
-    dump_string(font_name(f));
-    dump_string(font_area(f));
-    dump_string(font_filename(f));
-    dump_string(font_fullname(f));
-    dump_string(font_psname(f));
-    dump_string(font_encodingname(f));
-    dump_string(font_cidregistry(f));
-    dump_string(font_cidordering(f));
-
-    dump_things(*param_base(f), (font_params(f) + 1));
-
-    if (font_math_params(f) > 0) {
-        dump_things(*math_param_base(f), (font_math_params(f) + 1 ));
-    }
-    if (has_left_boundary(f)) {
-        dump_int(1);
-        dump_charinfo(f, left_boundarychar);
-    } else {
-        dump_int(0);
-    }
-    if (has_right_boundary(f)) {
-        dump_int(1);
-        dump_charinfo(f, right_boundarychar);
-    } else {
-        dump_int(0);
-    }
-
-    for (i = font_bc(f); i <= font_ec(f); i++) {
-        if (quick_char_exists(f, i)) {
-            dump_charinfo(f, i);
-        }
-    }
-}
-
-@ @c
-static int undump_charinfo(int f)
-{
-    charinfo *co;
-    int x, i;
-    char *s = NULL;
-    liginfo *lig = NULL;
-    kerninfo *kern = NULL;
-    eight_bits *packet = NULL;
-
-    undump_int(i);
-    co = get_charinfo(f, i);
-    undump_int(x);
-    set_charinfo_width(co, x);
-    undump_int(x);
-    set_charinfo_height(co, x);
-    undump_int(x);
-    set_charinfo_depth(co, x);
-    undump_int(x);
-    set_charinfo_italic(co, x);
-    undump_int(x);
-    set_charinfo_vert_italic(co, x);
-    undump_int(x);
-    set_charinfo_top_accent(co, x);
-    undump_int(x);
-    set_charinfo_bot_accent(co, x);
-    undump_int(x);
-    set_charinfo_tag(co, x);
-    undump_int(x);
-    set_charinfo_ef(co, x);
-    undump_int(x);
-    set_charinfo_rp(co, x);
-    undump_int(x);
-    set_charinfo_lp(co, x);
-    undump_int(x);
-    set_charinfo_remainder(co, x);
-    undump_int(x);
-    set_charinfo_used(co, x);
-    undump_int(x);
-    set_charinfo_index(co, x);
-
-    /* name */
-    undump_int(x);
-    if (x > 0) {
-        font_bytes += x;
-        s = xmalloc((unsigned) x);
-        undump_things(*s, x);
-    }
-    set_charinfo_name(co, s);
-    /* tounicode */
-    undump_int(x);
-    if (x > 0) {
-        font_bytes += x;
-        s = xmalloc((unsigned) x);
-        undump_things(*s, x);
-    }
-    set_charinfo_tounicode(co, s);
-    /* ligatures */
-    undump_int(x);
-    if (x > 0) {
-        font_bytes += (int) ((unsigned) x * sizeof(liginfo));
-        lig = xmalloc((unsigned) ((unsigned) x * sizeof(liginfo)));
-        undump_things(*lig, x);
-    }
-    set_charinfo_ligatures(co, lig);
-    /* kerns */
-    undump_int(x);
-    if (x > 0) {
-        font_bytes += (int) ((unsigned) x * sizeof(kerninfo));
-        kern = xmalloc((unsigned) ((unsigned) x * sizeof(kerninfo)));
-        undump_things(*kern, x);
-    }
-    set_charinfo_kerns(co, kern);
-
-    /* packets */
-    undump_int(x);
-    if (x > 0) {
-        font_bytes += x;
-        packet = xmalloc((unsigned) x);
-        undump_things(*packet, x);
-    }
-    set_charinfo_packets(co, packet);
-
-    if (get_charinfo_tag(co) == ext_tag) {
-        set_charinfo_vert_variants(co, undump_charinfo_variants());
-        set_charinfo_hor_variants(co, undump_charinfo_variants());
-    }
-    undump_math_kerns(co);
-    return i;
-}
-
-#define undump_font_string(a) \
-    undump_int (x); \
-    if (x>0) { \
-        font_bytes += x; \
-        s = xmalloc((unsigned)x); \
-        undump_things(*s,x); \
-        a(f,s); \
-    }
-
-static void undump_font_entry(texfont * f)
-{
-    int x = 0;
-    /* *INDENT-OFF* */
-    undump_int(x); f->_font_size = x;
-    undump_int(x); f->_font_dsize = x;
-    undump_int(x); f->_font_cidversion = x;
-    undump_int(x); f->_font_cidsupplement = x;
-    undump_int(x); f->_font_ec = x;
-    undump_int(x); f->_font_checksum = (unsigned)x;
-    undump_int(x); f->_font_used = (char)x;
-    undump_int(x); f->_font_touched = (char)x;
-    undump_int(x); f->_font_cache_id = x;
-    undump_int(x); f->_font_encodingbytes = (char)x;
-    undump_int(x); f->_font_oldmath = x;
-    undump_int(x); f->_font_slant = x;
-    undump_int(x); f->_font_extend = x;
-    undump_int(x); f->font_max_shrink = x;
-    undump_int(x); f->font_max_stretch = x;
-    undump_int(x); f->_font_step = x;
-    undump_int(x); f->_font_tounicode = (char)x;
-    undump_int(x); f->_font_type = x;
-    undump_int(x); f->_font_format = x;
-    undump_int(x); f->_font_writingmode = x;
-    undump_int(x); f->_font_identity = x;
-    undump_int(x); f->_font_embedding = x;
-    undump_int(x); f->_font_streamprovider = x;
-    undump_int(x); f->_font_bc = x;
-    undump_int(x); f->_hyphen_char = x;
-    undump_int(x); f->_skew_char = x;
-    undump_int(x); f->_font_natural_dir = x;
-    undump_int(x); f->_font_params = x;
-    undump_int(x); f->_font_math_params = x;
-    undump_int(x); f->ligatures_disabled = x;
-    undump_int(x); f->_pdf_font_num = x;
-    undump_int(x); f->_pdf_font_attr = x;
-    /* *INDENT-ON* */
-}
-
-void undump_font(int f)
-{
-    int x, i;
-    texfont *tt;
-    charinfo *ci;
-    char *s;
-    sa_tree_item sa_value = { 0 };
-    grow_font_table(f);
-    tt = xmalloc(sizeof(texfont));
-    memset(tt, 0, sizeof(texfont));
-    font_bytes += (int) sizeof(texfont);
-    undump_font_entry(tt);
-    font_tables[f] = tt;
-
-    undump_font_string(set_font_name);
-    undump_font_string(set_font_area);
-    undump_font_string(set_font_filename);
-    undump_font_string(set_font_fullname);
-    undump_font_string(set_font_psname);
-    undump_font_string(set_font_encodingname);
-    undump_font_string(set_font_cidregistry);
-    undump_font_string(set_font_cidordering);
-
-    i = (int) (sizeof(*param_base(f)) * ((unsigned) font_params(f) + 1));
-    font_bytes += i;
-    param_base(f) = xmalloc((unsigned) i);
-    undump_things(*param_base(f), (font_params(f) + 1));
-
-    if (font_math_params(f) > 0) {
-        i = (int) (sizeof(*math_param_base(f)) *
-                   ((unsigned) font_math_params(f) + 1));
-        font_bytes += i;
-        math_param_base(f) = xmalloc((unsigned) i);
-        undump_things(*math_param_base(f), (font_math_params(f) + 1));
-    }
-
-    /* stack size 1, default item value 0 */
-    font_tables[f]->characters = new_sa_tree(1, 1, sa_value);
-    ci = xcalloc(1, sizeof(charinfo));
-    set_charinfo_name(ci, xstrdup(".notdef"));
-    font_tables[f]->charinfo = ci;
-    undump_int(x);
-    if (x) {
-        i = undump_charinfo(f); /* left boundary */
-    }
-    undump_int(x);
-    if (x) {
-        i = undump_charinfo(f); /* right boundary */
-    }
-
-    i = font_bc(f);
-    while (i < font_ec(f)) {
-        i = undump_charinfo(f);
-    }
-}
-
-/* moved from pdffont.w */
-
-@ @c
-int pk_dpi; /* PK pixel density value from \.{texmf.cnf} */
-
-@ @c
-internal_font_number tfm_lookup(char *s, scaled fs)
-{   /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
-    internal_font_number k;
-    if (fs != 0) {
-        for (k = 1; k <= max_font_id(); k++) {
-            if (cmp_font_name(k, s) && font_size(k) == fs) {
-                return k;
-            }
-        }
-    } else {
-        for (k = 1; k <= max_font_id(); k++) {
-            if (cmp_font_name(k, s)) {
-                return k;
-            }
-        }
-    }
-    return null_font;
-}
-
-@ @c
-int fix_expand_value(internal_font_number f, int e)
-{                               /* return the multiple of |font_step(f)| that is nearest to |e| */
-    int step;
-    int max_expand;
-    boolean neg;
-    if (e == 0)
-        return 0;
-    if (e < 0) {
-        e = -e;
-        neg = true;
-        max_expand = font_max_shrink(f);
-    } else {
-        neg = false;
-        max_expand = font_max_stretch(f);
-    }
-    if (e > max_expand) {
-        e = max_expand;
-    } else {
-        step = font_step(f);
-        if (e % step > 0)
-            e = step * round_xn_over_d(e, 1, step);
-    }
-    if (neg)
-        e = -e;
-    return e;
-}
-
-@ @c
-void set_expand_params(internal_font_number f, int stretch_limit, int shrink_limit, int font_step)
-{
-    set_font_step(f, font_step);
-    set_font_max_shrink(f, shrink_limit);
-    set_font_max_stretch(f, stretch_limit);
-}
-
-@ @c
-void read_expand_font(void)
-{                               /* read font expansion spec and load expanded font */
-    int shrink_limit, stretch_limit, font_step;
-    internal_font_number f;
-    /* read font expansion parameters */
-    scan_font_ident();
-    f = cur_val;
-    if (f == null_font)
-        normal_error("font expansion", "invalid font identifier");
-    /*if (pdf_font_blink(f) != null_font)*/
-    /*    normal_error("font expansion",*/
-    /*              "\\fontexpand cannot be used this way (the base font has been expanded)");*/
-    scan_optional_equals();
-    scan_int();
-    stretch_limit = fix_int(cur_val, 0, 1000);
-    scan_int();
-    shrink_limit = fix_int(cur_val, 0, 500);
-    scan_int();
-    font_step = fix_int(cur_val, 0, 100);
-    if (font_step == 0)
-        normal_error("font expansion", "invalid step");
-    stretch_limit = stretch_limit - stretch_limit % font_step;
-    if (stretch_limit < 0)
-        stretch_limit = 0;
-    shrink_limit = shrink_limit - shrink_limit % font_step;
-    if (shrink_limit < 0)
-        shrink_limit = 0;
-    if ((stretch_limit == 0) && (shrink_limit == 0))
-        normal_error("font expansion", "invalid limit(s)");
-    if (scan_keyword("autoexpand")) {
-        normal_warning("font expansion", "autoexpand not supported");
-        /* Scan an optional space */
-        get_x_token();
-        if (cur_cmd != spacer_cmd)
-            back_input();
-    }
-    if (font_step(f) != 0) {
-        /* this font has been expanded, ensure the expansion parameters are identical */
-        if (font_step(f) != font_step)
-            normal_error("font expansion","font has been expanded with different expansion step");
-
-        if (((font_max_stretch(f) == 0) && (stretch_limit != 0)) ||
-            ((font_max_stretch(f) > 0)
-             && (font_max_stretch(f) != stretch_limit)))
-            normal_error("font expansion","font has been expanded with different stretch limit");
-
-        if (((font_max_shrink(f) == 0) && (shrink_limit != 0)) ||
-            ((font_max_shrink(f) > 0)
-             && (font_max_shrink(f) != shrink_limit)))
-            normal_error("font expansion","font has been expanded with different shrink limit");
-    } else {
-        if (font_used(f))
-            normal_warning("font expansion", "font should be expanded before its first use");
-        set_expand_params(f, stretch_limit, shrink_limit, font_step);
-    }
-}
-
-@ @c
-void new_letterspaced_font(small_number a)
-{                               /* letter-space a font by creating a virtual font */
-    pointer u;                  /* user's font identifier */
-    str_number t;               /* name for the frozen font identifier */
-    internal_font_number f, k;
-    boolean nolig = false;
-    get_r_token();
-    u = cur_cs;
-    if (u >= hash_base)
-        t = cs_text(u);
-    else
-        t = maketexstring("FONT");
-    define(u, set_font_cmd, null_font);
-    scan_optional_equals();
-    scan_font_ident();
-    k = cur_val;
-    scan_int();
-    if (scan_keyword("nolig"))
-       nolig=true;
-    f = letter_space_font(k, fix_int(cur_val, -1000, 1000), nolig);
-    equiv(u) = f;
-    eqtb[font_id_base + f] = eqtb[u];
-    font_id_text(f) = t;
-}
-
-@ @c
-void make_font_copy(small_number a)
-{                               /* make a font copy for further use with font expansion */
-    pointer u;                  /* user's font identifier */
-    str_number t;               /* name for the frozen font identifier */
-    internal_font_number f, k;
-    get_r_token();
-    u = cur_cs;
-    if (u >= hash_base)
-        t = cs_text(u);
-    else
-        t = maketexstring("FONT");
-    define(u, set_font_cmd, null_font);
-    scan_optional_equals();
-    scan_font_ident();
-    k = cur_val;
-    f = copy_font_info(k);
-    equiv(u) = f;
-    eqtb[font_id_base + f] = eqtb[u];
-    font_id_text(f) = t;
-}
-
-@ @c
-void glyph_to_unicode(void)
-{
-    str_number s1, s2;
-    scan_toks(false, true);
-    s1 = tokens_to_string(def_ref);
-    delete_token_ref(def_ref);
-    scan_toks(false, true);
-    s2 = tokens_to_string(def_ref);
-    delete_token_ref(def_ref);
-    def_tounicode(s1, s2);
-    flush_str(s2);
-    flush_str(s1);
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1186 @@
+/*
+
+Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex Here are some macros that help process ligatures and kerns */
+
+#define lig_kern_start(f,c)   char_remainder(f,c)
+
+/*tex A value indicating |STOP| in a lig/kern program: */
+
+#define stop_flag 128
+
+/*tex The op code for a kern step: */
+
+#define kern_flag 128
+
+#define skip_byte(z)        lig_kerns[z].b0
+#define next_char(z)        lig_kerns[z].b1
+#define op_byte(z)          lig_kerns[z].b2
+#define rem_byte(z)         lig_kerns[z].b3
+#define lig_kern_restart(c) (256*op_byte(c)+rem_byte(c))
+
+
+/*tex
+
+    The information in a \TFM\file appears in a sequence of 8-bit bytes. Since
+    the number of bytes is always a multiple of 4, we could also regard the file
+    as a sequence of 32-bit words, but \TeX\ uses the byte interpretation. The
+    format of \TFM\files was designed by Lyle Ramshaw in 1980. The intent is
+    to convey a lot of different kinds of information in a compact but useful
+    form.
+
+    $\Omega$ is capable of reading not only \TFM\files, but also \.{OFM}
+    files, which can describe fonts with up to 65536 characters and with huge
+    lig/kern tables. These fonts will often be virtual fonts built up from real
+    fonts with 256 characters, but $\Omega$ is not aware of this.
+
+    The documentation below describes \TFM\files, with slight additions to
+    show where \.{OFM} files differ.
+
+    The first 24 bytes (6 words) of a \TFM\file contain twelve 16-bit integers
+    that give the lengths of the various subsequent portions of the file. These
+    twelve integers are, in order:
+
+    \starttabulate
+        \NC \type {lf| \NC length of the entire file, in words \NC \NR
+        \NC \type {lh| \NC length of the header data, in words \NC \NR
+        \NC \type {bc| \NC smallest character code in the font \NC \NR
+        \NC \type {ec| \NC largest character code in the font \NC \NR
+        \NC \type {nw| \NC number of words in the width table \NC \NR
+        \NC \type {nh| \NC number of words in the height table \NC \NR
+        \NC \type {nd| \NC number of words in the depth table \NC \NR
+        \NC \type {ni| \NC number of words in the italic correction table \NC \NR
+        \NC \type {nl| \NC number of words in the lig/kern table \NC \NR
+        \NC \type {nk| \NC number of words in the kern table \NC \NR
+        \NC \type {ne| \NC number of words in the extensible character table \NC \NR
+        \NC \type {np| \NC number of font parameter words \NC \NR
+    \stoptabulate
+
+    They are all nonnegative and less than $2^{15}$. We must have
+    |bc-1<=ec<=255|, and $|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|$. Note that
+    a \TFM\font may contain as many as 256 characters (if |bc=0| and
+    |ec=255|), and as few as 0 characters (if |bc=ec+1|).
+
+    Incidentally, when two or more 8-bit bytes are combined to form an integer of
+    16 or more bits, the most significant bytes appear first in the file. This is
+    called BigEndian order.
+
+    The first 52 bytes (13 words) of an \.{OFM} file contains thirteen 32-bit
+    integers that give the lengths of the various subsequent portions of the
+    file. The first word is 0 (future versions of \.{OFM} files could have
+    different values; what is important is that the first two bytes be 0 to
+    differentiate \TFM\and \.{OFM} files). The next twelve integers are as
+    above, all nonegative and less than~$2^{31}$. We must have |bc-1<=ec<=65535|,
+    and $$\hbox{|lf=13+lh+2*(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$ Note that an
+    \.{OFM} font may contain as many as 65536 characters (if |bc=0| and
+    |ec=65535|), and as few as 0 characters (if |bc=ec+1|).
+
+    The rest of the \TFM\file may be regarded as a sequence of ten data arrays
+    having the informal specification
+
+    \starttabulate
+    \NC \type {header}     \NC \type {[0..lh-1]} \NC \type {stuff} \NC \NR
+    \NC \type {char\_info} \NC \type {[bc..ec]}  \NC \type {char_info_word} \NC \NR
+    \NC \type {width}      \NC \type {[0..nw-1]} \NC \type {fix_word} \NC \NR
+    \NC \type {height}     \NC \type {[0..nh-1]} \NC \type {fix_word} \NC \NR
+    \NC \type {depth}      \NC \type {[0..nd-1]} \NC \type {fix_word} \NC \NR
+    \NC \type {italic}     \NC \type {[0..ni-1]} \NC \type {fix_word} \NC \NR
+    \NC \type {lig\_kern}  \NC \type {[0..nl-1]} \NC \type {lig_kern_command} \NC \NR
+    \NC \type {kern}       \NC \type {[0..nk-1]} \NC \type {fix_word} \NC \NR
+    \NC \type {exten}      \NC \type {[0..ne-1]} \NC \type {extensible_recipe} \NC \NR
+    \NC \type {param}      \NC \type {[1..np]}   \NC \type {fix_word} \NC \NR
+    \stoptabulate
+
+    The most important data type used here is a |@!fix_word|, which is a 32-bit
+    representation of a binary fraction. A |fix_word| is a signed quantity, with
+    the two's complement of the entire word used to represent negation. Of the 32
+    bits in a |fix_word|, exactly 12 are to the left of the binary point; thus,
+    the largest |fix_word| value is $2048-2^{-20}$, and the smallest is $-2048$.
+    We will see below, however, that all but two of the |fix_word| values must
+    lie between $-16$ and $+16$.
+
+    The first data array is a block of header information, which contains general
+    facts about the font. The header must contain at least two words, |header[0]|
+    and |header[1]|, whose meaning is explained below. Additional header
+    information of use to other software routines might also be included, but
+    \TeX82 does not need to know about such details. For example, 16 more words
+    of header information are in use at the Xerox Palo Alto Research Center; the
+    first ten specify the character coding scheme used (e.g., `\.{XEROX text}' or
+    `\.{TeX math symbols}'), the next five give the font identifier (e.g.,
+    `\.{HELVETICA}' or `\.{CMSY}'), and the last gives the ``face byte.'' The
+    program that converts \.{DVI} files to Xerox printing format gets this
+    information by looking at the \TFM\file, which it needs to read anyway
+    because of other information that is not explicitly repeated in
+    \.{DVI}~format.
+
+    \startitemize
+
+        \startitem
+            |header[0]| is a 32-bit check sum that \TeX\ will copy into the
+            \.{DVI} output file. Later on when the \.{DVI} file is printed,
+            possibly on another computer, the actual font that gets used is
+            supposed to have a check sum that agrees with the one in the \TFM\
+            file used by \TeX. In this way, users will be warned about potential
+            incompatibilities. (However, if the check sum is zero in either the
+            font file or the \TFM\file, no check is made.) The actual relation
+            between this check sum and the rest of the \TFM\file is not
+            important; the check sum is simply an identification number with the
+            property that incompatible fonts almost always have distinct check
+            sums.
+        \stopitem
+
+        \startitem
+            |header[1]| is a |fix_word| containing the design size of the font,
+            in units of \TeX\ points. This number must be at least 1.0; it is
+            fairly arbitrary, but usually the design size is 10.0 for a ``10
+            point'' font, i.e., a font that was designed to look best at a
+            10-point size, whatever that really means. When a \TeX\ user asks for
+            a font `\.{at} $\delta$ \.{pt}', the effect is to override the design
+            size and replace it by $\delta$, and to multiply the $x$ and~$y$
+            coordinates of the points in the font image by a factor of $\delta$
+            divided by the design size. {\sl All other dimensions in the\/
+            \TFM\file are |fix_word|\kern-1pt\ numbers in design-size units},
+            with the exception of |param[1]| (which denotes the slant ratio).
+            Thus, for example, the value of |param[6]|, which defines the \.{em}
+            unit, is often the |fix_word| value $2^{20}=1.0$, since many fonts
+            have a design size equal to one em. The other dimensions must be less
+            than 16 design-size units in absolute value; thus, |header[1]| and
+            |param[1]| are the only |fix_word| entries in the whole \TFM\file
+            whose first byte might be something besides 0 or 255.
+        \stopitem
+
+    \stopitemize
+
+    Next comes the |char_info| array, which contains one |@!char_info_word| per
+    character. Each word in this part of a \TFM\file contains six fields
+    packed into four bytes as follows.
+
+    \startitemize
+        \startitem
+            first byte: |width_index| (8 bits)
+        \stopitem
+        \startitem
+            second byte: |height_index| (4 bits) times 16, plus |depth_index|
+            (4~bits)
+        \stopitem
+        \startitem
+            third byte: |italic_index| (6 bits) times 4, plus |tag| (2~bits)
+        \stopitem
+        \startitem
+            fourth byte: |remainder| (8 bits)
+        \stopitem
+    \stopitemize
+
+    The actual width of a character is \\{width}|[width_index]|, in design-size
+    units; this is a device for compressing information, since many characters
+    have the same width. Since it is quite common for many characters to have the
+    same height, depth, or italic correction, the \TFM\format imposes a limit
+    of 16 different heights, 16 different depths, and 64 different italic
+    corrections.
+
+    For \.{OFM} files, two words (eight bytes) are used. The arrangement is as
+    follows.
+
+    \startitemize
+        \startitem
+            first and second bytes: |width_index| (16 bits)
+        \stopitem
+            \startitem third byte: |height_index| (8 bits)
+        \stopitem
+        \startitem
+            fourth byte: |depth_index| (8~bits)
+        \stopitem
+        \startitem
+            fifth and sixth bytes: |italic_index| (14 bits) times 4, plus |tag|
+            (2~bits)
+        \startitem
+            seventh and eighth bytes: |remainder| (16 bits)
+        \stopitem
+    \stopitemize
+
+    Therefore the \.{OFM} format imposes a limit of 256 different heights, 256
+    different depths, and 16384 different italic corrections.
+
+    The italic correction of a character has two different uses. (a)~In ordinary
+    text, the italic correction is added to the width only if the \TeX\ user
+    specifies `\.{\\/}' after the character. (b)~In math formulas, the italic
+    correction is always added to the width, except with respect to the
+    positioning of subscripts.
+
+    Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
+    \\{italic}[0]=0$ should always hold, so that an index of zero implies a value
+    of zero. The |width_index| should never be zero unless the character does not
+    exist in the font, since a character is valid if and only if it lies between
+    |bc| and |ec| and has a nonzero |width_index|.
+
+    \TeX\ checks the information of a \TFM\file for validity as the file is
+    being read in, so that no further checks will be needed when typesetting is
+    going on. The somewhat tedious subroutine that does this is called
+    |read_font_info|. It has four parameters: the user font identifier~|u|, the
+    file name and area strings |nom| and |aire|, and the ``at'' size~|s|. If
+    |s|~is negative, it's the negative of a scale factor to be applied to the
+    design size; |s=-1000| is the normal case. Otherwise |s| will be substituted
+    for the design size; in this case, |s| must be positive and less than
+    $2048\rm\,pt$ (i.e., it must be less than $2^{27}$ when considered as an
+    integer).
+
+    The subroutine opens and closes a global file variable called |tfm_file|. It
+    returns the value of the internal font number that was just loaded. If an
+    error is detected, an error message is issued and no font information is
+    stored; |null_font| is returned in this case.
+
+    The |tag| field in a |char_info_word| has four values that explain how to
+    interpret the |remainder| field.
+
+    \startitemize
+        \startitem
+            |tag=0| (|no_tag|) means that |remainder| is unused.
+        \stopitem
+        \startitem
+            |tag=1| (|lig_tag|) means that this character has a ligature/kerning
+            program starting at position |remainder| in the |lig_kern| array
+        \stopitem
+        \startitem
+            |tag=2| (|list_tag|) means that this character is part of a chain of
+            characters of ascending sizes, and not the largest in the chain. The
+            |remainder| field gives the character code of the next larger
+            character
+        \stopitem
+        \startitem
+            |tag=3| (|ext_tag|) means that this character code represents an
+            extensible character, i.e., a character that is built up of smaller
+            pieces so that it can be made arbitrarily large. The pieces are
+            specified in |exten[remainder]|
+        \stopitem
+    \stopitemize
+
+    Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
+    unless they are used in special circumstances in math formulas. For example,
+    the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left} operation
+    looks for both |list_tag| and |ext_tag|.
+
+    The |lig_kern| array contains instructions in a simple programming language
+    that explains what to do for special letter pairs. Each word in this array,
+    in a \TFM\file, is a |@!lig_kern_command| of four bytes.
+
+    \startitemize
+        \startitem
+            first byte: |skip_byte|, indicates that this is the final program
+            step if the byte is 128 or more, otherwise the next step is obtained
+            by skipping this number of intervening steps
+        \stopitem
+        \startitem
+            second byte: |next_char|, if |next_char| follows the current
+            character, then perform the operation and stop, otherwise
+            continue
+        \stopitem
+        \startitem
+            third byte: |op_byte|, indicates a ligature step if less than~128, a
+            kern step otherwise
+        \stopitem
+        \startitem
+            fourth byte: |remainder|
+        \stopitem
+    \stopitemize
+
+    In an \.{OFM} file, eight bytes are used, two bytes for each field.
+
+    In a kern step, an additional space equal to |kern[256 * (op_byte-128) +
+    remainder]| is inserted between the current character and |next_char|. This
+    amount is often negative, so that the characters are brought closer together
+    by kerning; but it might be positive.
+
+    There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$
+    where $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
+    |remainder| is inserted between the current character and |next_char|; then
+    the current character is deleted if $b=0$, and |next_char| is deleted if
+    $c=0$; then we pass over $a$~characters to reach the next current character
+    (which may have a ligature/kerning program of its own).
+
+    If the very first instruction of the |lig_kern| array has |skip_byte=255|,
+    the |next_char| byte is the so-called right boundary character of this font;
+    the value of |next_char| need not lie between |bc| and~|ec|. If the very last
+    instruction of the |lig_kern| array has |skip_byte=255|, there is a special
+    ligature/kerning program for a left boundary character, beginning at location
+    |256*op_byte+remainder|. The interpretation is that \TeX\ puts implicit
+    boundary characters before and after each consecutive string of characters
+    from the same font. These implicit characters do not appear in the output,
+    but they can affect ligatures and kerning.
+
+    If the very first instruction of a character's |lig_kern| program has
+    |skip_byte>128|, the program actually begins in location
+    |256*op_byte+remainder|. This feature allows access to large |lig_kern|
+    arrays, because the first instruction must otherwise appear in a location
+    |<=255| in a \TFM\file, |<=65535| in an \.{OFM} file.
+
+    Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy the
+    condition $$\hbox{|256*op_byte+remainder<nl|.}$$ If such an instruction is
+    encountered during normal program execution, it denotes an unconditional
+    halt; no ligature or kerning command is performed.
+
+    Extensible characters are specified by an |@!extensible_recipe|, which
+    consists of four bytes in a \TFM\file, called |@!top|, |@!mid|, |@!bot|,
+    and |@!rep| (in this order). In an \.{OFM} file, each field takes two bytes,
+    for eight in total. These bytes are the character codes of individual pieces
+    used to build up a large symbol. If |top|, |mid|, or |bot| are zero, they are
+    not present in the built-up result. For example, an extensible vertical line
+    is like an extensible bracket, except that the top and bottom pieces are
+    missing.
+
+    Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box if
+    the piece isn't present. Then the extensible characters have the form
+    $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent; in the
+    latter case we can have $TR^kB$ for both even and odd values of~|k|. The
+    width of the extensible character is the width of $R$; and the
+    height-plus-depth is the sum of the individual height-plus-depths of the
+    components used, since the pieces are butted together in a vertical list.
+
+    The final portion of a \TFM\file is the |param| array, which is another
+    sequence of |fix_word| values.
+
+    \startitemize
+
+    \startitem
+        |param[1]=slant| is the amount of italic slant, which is used to help
+        position accents. For example, |slant=.25| means that when you go up one
+        unit, you also go .25 units to the right. The |slant| is a pure number;
+        it's the only |fix_word| other than the design size itself that is not
+        scaled by the design size.
+    \stopitem
+
+    \startitem
+        |param[2]=space| is the normal spacing between words in text. Note that
+        character |" "| in the font need not have anything to do with blank
+        spaces.
+    \stopitem
+
+    \startitem
+        |param[3]=space_stretch| is the amount of glue stretching between words.
+    \stopitem
+
+    \startitem
+        |param[4]=space_shrink| is the amount of glue shrinking between words.
+    \stopitem
+
+    \startitem
+        |param[5]=x_height| is the size of one ex in the font; it is also the
+        height of letters for which accents don't have to be raised or lowered.
+    \stopitem
+
+    \startitem
+        |param[6]=quad| is the size of one em in the font.
+    \stopitem
+
+    \startitem
+        |param[7]=extra_space| is the amount added to |param[2]| at the ends of
+        sentences.
+    \stopitem
+
+
+    If fewer than seven parameters are present, \TeX\ sets the missing parameters
+    to zero. Fonts used for math symbols are required to have additional
+    parameter information, which is explained later.
+
+
+    There are programs called \.{TFtoPL} and \.{PLtoTF} that convert between the
+    \TFM\format and a symbolic property-list format that can be easily edited.
+    These programs contain extensive diagnostic information, so \TeX\ does not
+    have to bother giving precise details about why it rejects a particular
+    \TFM\file.
+
+*/
+
+#define tfm_abort {                    \
+    font_tables[f]->_font_name = NULL; \
+    font_tables[f]->_font_area = NULL; \
+    xfree(tfm_buffer); xfree(kerns);   \
+    xfree(widths);                     \
+    xfree(heights);                    \
+    xfree(depths);                     \
+    xfree(italics);                    \
+    xfree(extens);                     \
+    xfree(lig_kerns);                  \
+    xfree(xligs);                      \
+    xfree(xkerns);                     \
+    return 0;                          \
+}
+
+#define tfm_success {  \
+    xfree(tfm_buffer); \
+    xfree(kerns);      \
+    xfree(widths);     \
+    xfree(heights);    \
+    xfree(depths);     \
+    xfree(italics);    \
+    xfree(extens);     \
+    xfree(lig_kerns);  \
+    xfree(xligs);      \
+    xfree(xkerns);     \
+    return 1;          \
+}
+
+static int open_tfm_file(const char *nom, unsigned char **tfm_buf, int *tfm_siz)
+{
+    /*tex Was the callback successful? */
+    boolean res;
+    /*tex Was |tfm_file| successfully opened? */
+    boolean opened;
+    int callback_id;
+    FILE *tfm_file;
+    char *fname = luatex_find_file(nom, find_font_file_callback);
+    if (!fname)
+        return -1;
+    callback_id = callback_defined(read_font_file_callback);
+    if (callback_id > 0) {
+        res = run_callback(callback_id, "S->bSd", fname, &opened, tfm_buf, tfm_siz);
+        if (res && opened && (*tfm_siz > 0)) {
+            return 1;
+        }
+        if (!opened)
+            return -1;
+    } else {
+        if (luatex_open_input(&(tfm_file), fname, kpse_ofm_format, FOPEN_RBIN_MODE, true)) {
+            res = read_tfm_file(tfm_file, tfm_buf, tfm_siz);
+            close_file(tfm_file);
+            if (res) {
+                return 1;
+            }
+        } else {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*tex
+
+  Note: A malformed \TFM\file might be shorter than it claims to be; thus
+  |eof(tfm_file)| might be true when |read_font_info| refers to |tfm_file^| or
+  when it says |get(tfm_file)|. If such circumstances cause system error
+  messages, you will have to defeat them somehow, for example by defining |fget|
+  to be `\ignorespaces|begin get(tfm_file);| |if eof(tfm_file) then abort;
+  end|'.
+
+*/
+
+#define fget  tfm_byte++
+#define fbyte tfm_buffer[tfm_byte]
+
+#define read_sixteen(a) {           \
+    a=tfm_buffer[tfm_byte++];       \
+    if (a>127) { tfm_abort; }       \
+    a=(a*256)+tfm_buffer[tfm_byte]; \
+}
+
+#define read_sixteen_unsigned(a) {  \
+    a=tfm_buffer[tfm_byte++];       \
+    a=(a*256)+tfm_buffer[tfm_byte]; \
+}
+
+#define read_thirtytwo(a) {           \
+    a=tfm_buffer[++tfm_byte];         \
+    if (a>127) { tfm_abort; }         \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+}
+
+#define store_four_bytes(z) {         \
+    a=tfm_buffer[++tfm_byte];         \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+    a=(a*256)+tfm_buffer[++tfm_byte]; \
+    z = a;                            \
+}
+
+#define store_char_info(z) {            \
+    if (font_level!=-1) {               \
+        fget; read_sixteen_unsigned(a); \
+        ci._width_index=a;              \
+        fget; read_sixteen_unsigned(b); \
+        ci._height_index=b>>8;          \
+        ci._depth_index=b%256;          \
+        fget; read_sixteen_unsigned(c); \
+        ci._italic_index=c>>8;          \
+        ci._tag=(unsigned char)(c%4);   \
+        fget; read_sixteen_unsigned(d); \
+        ci._remainder=d;                \
+    } else {                            \
+          a=tfm_buffer[++tfm_byte];     \
+          ci._width_index=a;            \
+          b=tfm_buffer[++tfm_byte];     \
+          ci._height_index=b>>4;        \
+          ci._depth_index=b%16;         \
+          c=tfm_buffer[++tfm_byte];     \
+          ci._italic_index=c>>2;        \
+          ci._tag=(unsigned char)(c%4); \
+          d=tfm_buffer[++tfm_byte];     \
+          ci._remainder=d;              \
+    }                                   \
+}
+
+#define read_four_quarters(q) {                              \
+    if (font_level!=-1) {                                    \
+        fget; read_sixteen_unsigned(a); q.b0=(quarterword)a; \
+        fget; read_sixteen_unsigned(b); q.b1=(quarterword)b; \
+        fget; read_sixteen_unsigned(c); q.b2=(quarterword)c; \
+        fget; read_sixteen_unsigned(d); q.b3=(quarterword)d; \
+    } else {                                                 \
+          a=tfm_buffer[++tfm_byte]; q.b0=(quarterword)a;     \
+          b=tfm_buffer[++tfm_byte]; q.b1=(quarterword)b;     \
+          c=tfm_buffer[++tfm_byte]; q.b2=(quarterword)c;     \
+          d=tfm_buffer[++tfm_byte]; q.b3=(quarterword)d;     \
+    }                                                        \
+}
+
+#define check_byte_range(z) { if ((z<bc)||(z>ec)) tfm_abort ; }
+
+/*
+
+    A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
+    the number $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
+    b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
+    -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$ (No other
+    choices of |a| are allowed, since the magnitude of a number in design-size
+    units must be less than 16.) We want to multiply this quantity by the
+    integer~|z|, which is known to be less than $2^{27}$. If $|z|<2^{23}$, the
+    individual multiplications $b\cdot z$, $c\cdot z$, $d\cdot z$ cannot
+    overflow; otherwise we will divide |z| by 2, 4, 8, or 16, to obtain a
+    multiplier less than $2^{23}$, and we can compensate for this later. If |z|
+    has thereby been replaced by $|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we
+    shall compute $$\lfloor (b + c \cdot2^{-8} + d \cdot2^{-16}) \, z^\prime /
+    \beta \rfloor$$ if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$
+    if $a=255$. This calculation must be done exactly, in order to guarantee
+    portability of \TeX\ between computers.
+
+*/
+
+#define store_scaled(zz) {                       \
+    fget;                                        \
+    a = fbyte;                                   \
+    fget;                                        \
+    b = fbyte;                                   \
+    fget;                                        \
+    c = fbyte;                                   \
+    fget;                                        \
+    d = fbyte;                                   \
+    sw = (((((d*z)>>8)+(c*z))>>8)+(b*z)) / beta; \
+    if (a == 0) {                                \
+        zz = sw;                                 \
+    } else if (a == 255) {                       \
+        zz = sw-alpha;                           \
+    } else {                                     \
+        tfm_abort;                               \
+    }                                            \
+}
+
+scaled store_scaled_f(scaled sq, scaled z_in)
+{
+    eight_bits a, b, c, d;
+    scaled sw;
+    /*tex Here beta: runs from 1 upto 16 */
+    static int alpha, beta;
+    static scaled z, z_prev = 0;
+    /*tex Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
+    if (z_in != z_prev || z_prev == 0) {
+        z = z_prev = z_in;
+        alpha = 16;
+        while (z >= 0x800000) {
+            z /= 2;
+            alpha += alpha;
+        }
+        beta = 256 / alpha;
+        alpha *= z;
+    };
+    if (sq >= 0) {
+        d = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        c = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        b = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        a = (eight_bits) (sq % 256);
+    } else {
+        sq = (sq + 1073741824) + 1073741824;
+        d = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        c = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        b = (eight_bits) (sq % 256);
+        sq = sq / 256;
+        a = (eight_bits) ((sq + 128) % 256);
+    }
+    if (beta==0)
+        normal_error("vf", "vf scaling");
+    sw = (((((d * z) >> 8) + (c * z)) >> 8) + (b * z)) / beta;
+    if (a == 0)
+        return sw;
+    else if (a == 255)
+        return (sw - alpha);
+    else
+        normal_error("vf", "vf scaling");
+    return sw;
+}
+
+#define check_existence(z) { \
+    check_byte_range(z);     \
+    if (!char_exists(f,z)) { \
+        tfm_abort;           \
+    }                        \
+}
+
+typedef struct tfmcharacterinfo {
+    int _kern_index;
+    int _lig_index;
+    int _width_index;
+    int _height_index;
+    int _depth_index;
+    int _italic_index;
+    int _remainder;
+    unsigned char _tag;
+} tfmcharacterinfo;
+
+int read_tfm_info(internal_font_number f, const char *cnom, scaled s)
+{
+    /*tex index into |font_info| */
+    int k;
+    /*tex sizes of subfiles */
+    halfword lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, slh;
+    scaled *widths, *heights, *depths, *italics, *kerns;
+    halfword font_dir;
+    /*tex byte variables */
+    int a, b, c=0, d=0;
+    /*tex counter */
+    int i;
+    int font_level, header_length;
+    int ncw, nlw, neew;
+    tfmcharacterinfo ci;
+    charinfo *co;
+    four_quarters qw;
+    four_quarters *lig_kerns, *extens;
+    /*tex accumulators */
+    scaled sw;
+    /*tex left boundary start location, or infinity */
+    int bch_label;
+    /*tex 0..too_big_char; right boundary character, or |too_big_char| */
+    int bchar;
+    int first_two;
+    /*tex the design size or the ``at'' size */
+    scaled z;
+    int alpha;
+    /*tex 1..16 */
+    char beta;
+    /*tex aux. for ligkern processing */
+    int *xligs, *xkerns;
+    liginfo *cligs;
+    kerninfo *ckerns;
+    int fligs, fkerns;
+    char *tmpnam;
+    /*tex index into |tfm_buffer| */
+    int tfm_byte = 0;
+    /*tex saved index into |tfm_buffer| */
+    int saved_tfm_byte = 0;
+    /*tex byte buffer for tfm files */
+    unsigned char *tfm_buffer = NULL;
+    /*tex total size of the tfm file */
+    int tfm_size = 0;
+    int tmp;
+    widths = NULL;
+    heights = NULL;
+    depths = NULL;
+    italics = NULL;
+    kerns = NULL;
+    lig_kerns = NULL;
+    extens = NULL;
+    xkerns = NULL;
+    ckerns = NULL;
+    xligs = NULL;
+    cligs = NULL;
+    font_dir = 0;
+    memset(&ci, 0, sizeof(tfmcharacterinfo));
+    if (open_tfm_file(cnom, &tfm_buffer, &tfm_size) != 1)
+        tfm_abort;
+    /*tex When |cnom| is an absolute filename |xbasename| fixes that. */
+    tmpnam = strdup(xbasename(cnom));
+    if (strcmp(tmpnam + strlen(tmpnam) - 4, ".tfm") == 0 || strcmp(tmpnam + strlen(tmpnam) - 4, ".ofm") == 0) {
+        *(tmpnam + strlen(tmpnam) - 4) = 0;
+    }
+    set_font_name(f, tmpnam);
+    set_font_area(f, NULL);
+    /*tex Read the \TFM\ size fields. */
+    ncw = 0;
+    read_sixteen(first_two);
+    if (first_two != 0) {
+        font_level = -1;
+        lf = first_two;
+        fget;
+        read_sixteen(lh);
+        fget;
+        read_sixteen(bc);
+        fget;
+        read_sixteen(ec);
+        if ((bc > ec + 1) || (ec > 255))
+            tfm_abort;
+        if (bc > 255) {
+            /*tex |bc=256| and |ec=255| */
+            bc = 1;
+            ec = 0;
+        };
+        fget;
+        read_sixteen(nw);
+        fget;
+        read_sixteen(nh);
+        fget;
+        read_sixteen(nd);
+        fget;
+        read_sixteen(ni);
+        fget;
+        read_sixteen(nl);
+        fget;
+        read_sixteen(nk);
+        fget;
+        read_sixteen(ne);
+        fget;
+        read_sixteen(np);
+        header_length = 6;
+        ncw = (ec - bc + 1);
+        nlw = nl;
+        neew = ne;
+    } else {
+        fget;
+        read_sixteen(font_level);
+        if (font_level != 0)
+            tfm_abort;
+        read_thirtytwo(lf);
+        read_thirtytwo(lh);
+        read_thirtytwo(bc);
+        read_thirtytwo(ec);
+        if ((bc > ec + 1) || (ec > 65535))
+            tfm_abort;
+        if (bc > 65535) {
+            /*tex |bc=65536| and |ec=65535| */
+            bc = 1;
+            ec = 0;
+        };
+        read_thirtytwo(nw);
+        read_thirtytwo(nh);
+        read_thirtytwo(nd);
+        read_thirtytwo(ni);
+        read_thirtytwo(nl);
+        read_thirtytwo(nk);
+        read_thirtytwo(ne);
+        read_thirtytwo(np);
+        /*tex Some junk: */
+        read_thirtytwo(font_dir);
+        nlw = 2 * nl;
+        neew = 2 * ne;
+        header_length = 14;
+        ncw = 2 * (ec - bc + 1);
+    };
+    if (lf !=
+        (header_length + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np))
+        tfm_abort;
+    if ((nw == 0) || (nh == 0) || (nd == 0) || (ni == 0))
+        tfm_abort;
+    /*tex
+        We check to see that the \TFM\ file doesn't end prematurely; but no
+        error message is given for files having more than |lf| words.
+     */
+    if (lf * 4 > tfm_size)
+        tfm_abort;
+    /*tex Use size fields to allocate font information. */
+    set_font_natural_dir(f, font_dir);
+    set_font_bc(f, bc);
+    set_font_ec(f, ec);
+    /*tex Read the arrays first. */
+    widths = xmalloc((unsigned) ((unsigned) nw * sizeof(scaled)));
+    heights = xmalloc((unsigned) ((unsigned) nh * sizeof(scaled)));
+    depths = xmalloc((unsigned) ((unsigned) nd * sizeof(scaled)));
+    italics = xmalloc((unsigned) ((unsigned) ni * sizeof(scaled)));
+    extens = xmalloc((unsigned) ((unsigned) ne * sizeof(four_quarters)));
+    lig_kerns = xmalloc((unsigned) ((unsigned) nl * sizeof(four_quarters)));
+    kerns = xmalloc((unsigned) ((unsigned) nk * sizeof(scaled)));
+    /*
+        Read the \TFM\ header. Only the first two words of the header are needed
+        by \TeX82.
+    */
+    slh = lh;
+    if (lh < 2)
+        tfm_abort;
+    store_four_bytes(tmp);
+    font_checksum(f) = (unsigned) tmp;
+    fget;
+    /*tex This rejects a negative design size. */
+    read_sixteen(z);
+    fget;
+    z = z * 256 + fbyte;
+    fget;
+    z = (z * 16) + (fbyte >> 4);
+    if (z < unity)
+        tfm_abort;
+    while (lh > 2) {
+        fget;
+        fget;
+        fget;
+        fget;
+        /*tex Ignore the rest of the header. */
+        lh--;
+    };
+    /*tex Read the arrays before the character info. */
+    set_font_dsize(f, z);
+    if (s != -1000) {
+        z = (s >= 0 ? s : xn_over_d(z, -s, 1000));
+    }
+    set_font_size(f, z);
+    if (np > 7) {
+        set_font_params(f, np);
+    }
+    saved_tfm_byte = tfm_byte;
+    tfm_byte = (header_length + slh + ncw) * 4 - 1;
+    /*tex Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
+    alpha = 16;
+    while (z >= 040000000) {
+        z = z >> 1;
+        alpha = alpha + alpha;
+    };
+    beta = (char) (256 / alpha);
+    /*tex |beta| cannot be zero. */
+    if (beta==0)
+       normal_error("vf", "vf reading");
+    alpha = alpha * z;
+    /*tex Read box dimensions. */
+    for (k = 0; k < nw; k++) {
+        store_scaled(sw);
+        widths[k] = sw;
+    }
+    /*tex |width[0]| must be zero */
+    if (widths[0] != 0)
+        tfm_abort;
+    for (k = 0; k < nh; k++) {
+        store_scaled(sw);
+        heights[k] = sw;
+    }
+    /*tex |height[0]| must be zero */
+    if (heights[0] != 0)
+        tfm_abort;
+    for (k = 0; k < nd; k++) {
+        store_scaled(sw);
+        depths[k] = sw;
+    }
+    /*tex |depth[0]| must be zero */
+    if (depths[0] != 0)
+        tfm_abort;
+    for (k = 0; k < ni; k++) {
+        store_scaled(sw);
+        italics[k] = sw;
+    }
+    /*tex |italic[0]| must be zero */
+    if (italics[0] != 0)
+        tfm_abort;
+    /*tex Read ligature and kern programs */
+    bch_label = nl;
+    bchar = 65536;
+    if (nl > 0) {
+        for (k = 0; k < nl; k++) {
+            read_four_quarters(qw);
+            lig_kerns[k] = qw;
+            if (a > 128) {
+                if (256 * c + d >= nl)
+                    tfm_abort;
+                if (a == 255 && k == 0)
+                    bchar = b;
+            } else {
+                if (c < 128) {
+                    /*tex Do nothing. */
+                } else if (256 * (c - 128) + d >= nk) {
+                    /*tex Check kern. */
+                    tfm_abort;
+                }
+                if ((a < 128) && (k - 0 + a + 1 >= nl))
+                    tfm_abort;
+            };
+        };
+        if (a == 255)
+            bch_label = 256 * c + d;
+    };
+    /*tex The actual kerns */
+    for (k = 0; k < nk; k++) {
+        store_scaled(sw);
+        kerns[k] = sw;
+    }
+    /*tex Read extensible character recipes */
+    for (k = 0; k < ne; k++) {
+        read_four_quarters(qw);
+        extens[k] = qw;
+    }
+    /*tex Read font parameters. */
+    if (np > 7) {
+        set_font_params(f, np);
+    }
+    for (k = 1; k <= np; k++) {
+        if (k == 1) {
+            /*tex The |slant| parameter is a pure number. */
+            fget;
+            sw = fbyte;
+            if (sw > 127)
+                sw = sw - 256;
+            fget;
+            sw = sw * 256 + fbyte;
+            fget;
+            sw = sw * 256 + fbyte;
+            fget;
+            sw = (sw * 16) + (fbyte >> 4);
+            set_font_param(f, k, sw);
+        } else {
+            store_scaled(font_param(f, k));
+        }
+    }
+    tfm_byte = saved_tfm_byte;
+    /*tex Fix up the left boundary character. */
+    fligs = 0;
+    fkerns = 0;
+    if (bch_label != nl) {
+        k = bch_label;
+        while (1) {
+            if (skip_byte(k) <= stop_flag) {
+                if (op_byte(k) >= kern_flag) {
+                    fkerns++;
+                } else {
+                    fligs++;
+                }
+            }
+            if (skip_byte(k) == 0) {
+                k++;
+            } else {
+                if (skip_byte(k) >= stop_flag)
+                    break;
+                k += skip_byte(k) + 1;
+            }
+        }
+    }
+    if (fkerns > 0 || fligs > 0) {
+        if (fligs > 0)
+            cligs = xcalloc((unsigned) (fligs + 1), sizeof(liginfo));
+        if (fkerns > 0)
+            ckerns = xcalloc((unsigned) (fkerns + 1), sizeof(kerninfo));
+        fligs = 0;
+        fkerns = 0;
+        k = bch_label;
+        while (1) {
+            if (skip_byte(k) <= stop_flag) {
+                if (op_byte(k) >= kern_flag) {
+                    set_kern_item(ckerns[fkerns], next_char(k), kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+                    fkerns++;
+                } else {
+                    set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), next_char(k), rem_byte(k));
+                    fligs++;
+                }
+            }
+            if (skip_byte(k) == 0) {
+                k++;
+            } else {
+                if (skip_byte(k) >= stop_flag)
+                    break;
+                k += skip_byte(k) + 1;
+            }
+        }
+        if (fkerns > 0 || fligs > 0) {
+            co = get_charinfo(f, left_boundarychar);
+            if (fkerns > 0) {
+                set_kern_item(ckerns[fkerns], end_kern, 0);
+                fkerns++;
+                set_charinfo_kerns(co, ckerns);
+            }
+            if (fligs > 0) {
+                set_ligature_item(cligs[fligs], 0, end_ligature, 0);
+                fligs++;
+                set_charinfo_ligatures(co, cligs);
+            }
+            set_charinfo_remainder(co, 0);
+        }
+    }
+    /*tex Read character data. */
+    for (k = bc; k <= ec; k++) {
+        store_char_info(k);
+        if (ci._width_index == 0)
+            continue;
+        if (ci._width_index >= nw || ci._height_index >= nh ||
+            ci._depth_index >= nd || ci._italic_index >= ni)
+            tfm_abort;
+        d = ci._remainder;
+        switch (ci._tag) {
+        case lig_tag:
+            if (d >= nl)
+                tfm_abort;
+            break;
+        case ext_tag:
+            if (d >= ne)
+                tfm_abort;
+            break;
+        case list_tag:
+            /*tex
+
+                We want to make sure that there is no cycle of characters linked
+                together by |list_tag| entries, since such a cycle would get
+                \TEX\ into an endless loop. If such a cycle exists, the routine
+                here detects it when processing the largest character code in the
+                cycle.
+
+             */
+            check_byte_range(d);
+            while (d < k) {
+                /* |current_character == k| */
+                if (char_tag(f, d) != list_tag) {
+                    /*tex Not a cycle. */
+                    goto NOT_FOUND;
+                }
+                /*tex Goto the next character on the list. */
+                d = char_remainder(f, d);
+            };
+            if (d == k) {
+                /*tex Yes, there's a cycle! */
+                tfm_abort;
+            }
+          NOT_FOUND:
+            break;
+        }
+        /*tex Put it in the actual font. */
+        co = get_charinfo(f, k);
+        set_charinfo_index(co, k);
+        set_charinfo_tag(co, ci._tag);
+        if (ci._tag == ext_tag) {
+            /*tex top, bot, mid, rep */
+            set_charinfo_extensible(co,
+                extens[ci._remainder].b0,
+                extens[ci._remainder].b2,
+                extens[ci._remainder].b1,
+                extens[ci._remainder].b3);
+            set_charinfo_remainder(co, 0);
+        } else {
+            set_charinfo_remainder(co, ci._remainder);
+        }
+        set_charinfo_width(co, widths[ci._width_index]);
+        set_charinfo_height(co, heights[ci._height_index]);
+        set_charinfo_depth(co, depths[ci._depth_index]);
+        set_charinfo_italic(co, italics[ci._italic_index]);
+    };
+    /*tex We now know the number of ligatures and kerns. */
+    xligs = xcalloc((unsigned) (ec + 1), sizeof(int));
+    xkerns = xcalloc((unsigned) (ec + 1), sizeof(int));
+    for (i = bc; i <= ec; i++) {
+        if (char_tag(f, i) == lig_tag) {
+            k = lig_kern_start(f, i);
+            if (skip_byte(k) > stop_flag)
+                k = lig_kern_restart(k);
+            /*tex Now k is the start index. */
+            while (1) {
+                if (skip_byte(k) <= stop_flag) {
+                    if (op_byte(k) >= kern_flag) {
+                        xkerns[i]++;
+                        if (next_char(k) == bchar)
+                            xkerns[i]++;
+                    } else {
+                        xligs[i]++;
+                        if (next_char(k) == bchar)
+                            xligs[i]++;
+                    }
+                }
+                if (skip_byte(k) == 0) {
+                    k++;
+                } else {
+                    if (skip_byte(k) >= stop_flag)
+                        break;
+                    k += skip_byte(k) + 1;
+                }
+            }
+        }
+    }
+    cligs = NULL;
+    ckerns = NULL;
+    for (i = bc; i <= ec; i++) {
+        fligs = 0;
+        fkerns = 0;
+        if (char_tag(f, i) == lig_tag) {
+            k = lig_kern_start(f, i);
+            if (skip_byte(k) > stop_flag)
+                k = lig_kern_restart(k);
+            /*tex Now k is the start index. */
+            if (xligs[i] > 0)
+                cligs = xcalloc((unsigned) (xligs[i] + 1), sizeof(liginfo));
+            if (xkerns[i] > 0)
+                ckerns = xcalloc((unsigned) (xkerns[i] + 1), sizeof(kerninfo));
+            while (1) {
+                if (skip_byte(k) <= stop_flag) {
+                    if (op_byte(k) >= kern_flag) {
+                        if (next_char(k) == bchar) {
+                            set_kern_item(ckerns[fkerns], right_boundarychar, kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+                            fkerns++;
+                        }
+                        set_kern_item(ckerns[fkerns], next_char(k), kerns[256 * (op_byte(k) - 128) + rem_byte(k)]);
+                        fkerns++;
+                    } else {    /* lig */
+                        if (next_char(k) == bchar) {
+                            set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), right_boundarychar, rem_byte(k));
+                            fligs++;
+                        }
+                        set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1), next_char(k), rem_byte(k));
+                        fligs++;
+                    }
+                }
+                if (skip_byte(k) == 0) {
+                    k++;
+                } else {
+                    if (skip_byte(k) >= stop_flag)
+                        break;
+                    k += skip_byte(k) + 1;
+                }
+            }
+            if (fkerns > 0 || fligs > 0) {
+                co = get_charinfo(f, i);
+                if (fkerns > 0) {
+                    set_kern_item(ckerns[fkerns], end_kern, 0);
+                    fkerns++;
+                    set_charinfo_kerns(co, ckerns);
+                }
+                if (fligs > 0) {
+                    set_ligature_item(cligs[fligs], 0, end_ligature, 0);
+                    fligs++;
+                    set_charinfo_ligatures(co, cligs);
+                }
+                set_charinfo_remainder(co, 0);
+            }
+        }
+    }
+    /*tex
+
+        Now it's time to wrap it up, we have checked all the necessary things
+        about the \TFM\file, and all we need to do is put the finishing
+        touches on the data for the new font.
+
+    */
+    if (bchar != 65536) {
+        co = copy_charinfo(char_info(f, bchar));
+        set_right_boundary(f, co);
+    }
+    tfm_success;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tfmofm.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1119 +0,0 @@
-% tfmofm.w
-%
-% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ Here are some macros that help process ligatures and kerns
- at c
-#define lig_kern_start(f,c)   char_remainder(f,c)
-#define stop_flag 128           /* value indicating `\.{STOP}' in a lig/kern program */
-#define kern_flag 128           /* op code for a kern step */
-
-#define skip_byte(z)         lig_kerns[z].b0
-#define next_char(z)         lig_kerns[z].b1
-#define op_byte(z)           lig_kerns[z].b2
-#define rem_byte(z)          lig_kerns[z].b3
-#define lig_kern_restart(c)  (256*op_byte(c)+rem_byte(c))
-
-
-@
-The information in a \.{TFM} file appears in a sequence of 8-bit bytes.
-Since the number of bytes is always a multiple of 4, we could
-also regard the file as a sequence of 32-bit words, but \TeX\ uses the
-byte interpretation. The format of \.{TFM} files was designed by
-Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds
-@^Ramshaw, Lyle Harold@>
-of information in a compact but useful form.
-
-$\Omega$ is capable of reading not only \.{TFM} files, but also
-\.{OFM} files, which can describe fonts with up to 65536 characters
-and with huge lig/kern tables.  These fonts will often be virtual
-fonts built up from real fonts with 256 characters, but $\Omega$
-is not aware of this.
-
-The documentation below describes \.{TFM} files, with slight additions
-to show where \.{OFM} files differ.
-
-@
-The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit
-integers that give the lengths of the various subsequent portions
-of the file. These twelve integers are, in order:
-$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr
-|lf|&length of the entire file, in words;\cr
-|lh|&length of the header data, in words;\cr
-|bc|&smallest character code in the font;\cr
-|ec|&largest character code in the font;\cr
-|nw|&number of words in the width table;\cr
-|nh|&number of words in the height table;\cr
-|nd|&number of words in the depth table;\cr
-|ni|&number of words in the italic correction table;\cr
-|nl|&number of words in the lig/kern table;\cr
-|nk|&number of words in the kern table;\cr
-|ne|&number of words in the extensible character table;\cr
-|np|&number of font parameter words.\cr}}$$
-They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|,
-and
-$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
-Note that a \.{TFM} font may contain as many as 256 characters
-(if |bc=0| and |ec=255|), and as few as 0 characters (if |bc=ec+1|).
-
-Incidentally, when two or more 8-bit bytes are combined to form an integer of
-16 or more bits, the most significant bytes appear first in the file.
-This is called BigEndian order.
-@!@^BigEndian order@>
-
-The first 52 bytes (13 words) of an \.{OFM} file contains thirteen
-32-bit integers that give the lengths of the various subsequent
-portions of the file.  The first word is 0 (future versions of
-\.{OFM} files could have different values;  what is important is that
-the first two bytes be 0 to differentiate \.{TFM} and \.{OFM} files).
-The next twelve integers are as above, all nonegative and less
-than~$2^{31}$.  We must have |bc-1<=ec<=65535|, and
-$$\hbox{|lf=13+lh+2*(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$
-Note that an \.{OFM} font may contain as many as 65536 characters
-(if |bc=0| and |ec=65535|), and as few as 0 characters (if |bc=ec+1|).
-
-The rest of the \.{TFM} file may be regarded as a sequence of ten data
-arrays having the informal specification
-$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2}
-\def\doarr\PB#1{\arr#1}
-\vbox{\halign{\hfil\\{#}&$\,:\,$\doarr#\hfil\cr
-header&|[0..lh-1]stuff|\cr
-char\_info&|[bc..ec]char_info_word|\cr
-width&|[0..nw-1]fix_word|\cr
-height&|[0..nh-1]fix_word|\cr
-depth&|[0..nd-1]fix_word|\cr
-italic&|[0..ni-1]fix_word|\cr
-lig\_kern&|[0..nl-1]lig_kern_command|\cr
-kern&|[0..nk-1]fix_word|\cr
-exten&|[0..ne-1]extensible_recipe|\cr
-param&\omit |[1..np]fix_word|\cr}}$$
-The most important data type used here is a |@!fix_word|, which is
-a 32-bit representation of a binary fraction. A |fix_word| is a signed
-quantity, with the two's complement of the entire word used to represent
-negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the
-binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and
-the smallest is $-2048$. We will see below, however, that all but two of
-the |fix_word| values must lie between $-16$ and $+16$.
-
-The first data array is a block of header information, which contains
-general facts about the font. The header must contain at least two words,
-|header[0]| and |header[1]|, whose meaning is explained below.
-Additional header information of use to other software routines might
-also be included, but \TeX82 does not need to know about such details.
-For example, 16 more words of header information are in use at the Xerox
-Palo Alto Research Center; the first ten specify the character coding
-scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five
-give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the
-last gives the ``face byte.'' The program that converts \.{DVI} files
-to Xerox printing format gets this information by looking at the \.{TFM}
-file, which it needs to read anyway because of other information that
-is not explicitly repeated in \.{DVI}~format.
-
-\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into
-the \.{DVI} output file. Later on when the \.{DVI} file is printed,
-possibly on another computer, the actual font that gets used is supposed
-to have a check sum that agrees with the one in the \.{TFM} file used by
-\TeX. In this way, users will be warned about potential incompatibilities.
-(However, if the check sum is zero in either the font file or the \.{TFM}
-file, no check is made.)  The actual relation between this check sum and
-the rest of the \.{TFM} file is not important; the check sum is simply an
-identification number with the property that incompatible fonts almost
-always have distinct check sums.
-@^check sum@>
-
-\yskip\hang|header[1]| is a |fix_word| containing the design size of
-the font, in units of \TeX\ points. This number must be at least 1.0; it is
-fairly arbitrary, but usually the design size is 10.0 for a ``10 point''
-font, i.e., a font that was designed to look best at a 10-point size,
-whatever that really means. When a \TeX\ user asks for a font
-`\.{at} $\delta$ \.{pt}', the effect is to override the design size
-and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates
-of the points in the font image by a factor of $\delta$ divided by the
-design size.  {\sl All other dimensions in the\/ \.{TFM} file are
-|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of
-|param[1]| (which denotes the slant ratio). Thus, for example, the value
-of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value
-$2^{20}=1.0$, since many fonts have a design size equal to one em.
-The other dimensions must be less than 16 design-size units in absolute
-value; thus, |header[1]| and |param[1]| are the only |fix_word|
-entries in the whole \.{TFM} file whose first byte might be something
-besides 0 or 255.
-
-Next comes the |char_info| array, which contains one |@!char_info_word|
-per character. Each word in this part of a \.{TFM} file contains six fields
-packed into four bytes as follows.
-
-\yskip\hang first byte: |@!width_index| (8 bits)\par
-\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index|
-  (4~bits)\par
-\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag|
-  (2~bits)\par
-\hang fourth byte: |@!remainder| (8 bits)\par
-\yskip\noindent
-The actual width of a character is \\{width}|[width_index]|, in design-size
-units; this is a device for compressing information, since many characters
-have the same width. Since it is quite common for many characters
-to have the same height, depth, or italic correction, the \.{TFM} format
-imposes a limit of 16 different heights, 16 different depths, and
-64 different italic corrections.
-
-For \.{OFM} files, two words (eight bytes) are used.
-The arrangement is as follows.
-
-\yskip\hang first and second bytes: |@!width_index| (16 bits)\par
-\hang third byte: |@!height_index| (8 bits)\par
-\hang fourth byte: |@!depth_index| (8~bits)\par
-\hang fifth and sixth bytes:
-|@!italic_index| (14 bits) times 4, plus |@!tag| (2~bits)\par
-\hang seventh and eighth bytes: |@!remainder| (16 bits)\par
-\yskip\noindent
-Therefore the \.{OFM} format imposes a limit of 256 different heights,
-256 different depths, and 16384 different italic corrections.
-
-@!@^italic correction@>
-The italic correction of a character has two different uses.
-(a)~In ordinary text, the italic correction is added to the width only if
-the \TeX\ user specifies `\.{\\/}' after the character.
-(b)~In math formulas, the italic correction is always added to the width,
-except with respect to the positioning of subscripts.
-
-Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]=
-\\{italic}[0]=0$ should always hold, so that an index of zero implies a
-value of zero.  The |width_index| should never be zero unless the
-character does not exist in the font, since a character is valid if and
-only if it lies between |bc| and |ec| and has a nonzero |width_index|.
-
-
-@ \TeX\ checks the information of a \.{TFM} file for validity as the
-file is being read in, so that no further checks will be needed when
-typesetting is going on. The somewhat tedious subroutine that does this
-is called |read_font_info|. It has four parameters: the user font
-identifier~|u|, the file name and area strings |nom| and |aire|, and the
-``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor
-to be applied to the design size; |s=-1000| is the normal case.
-Otherwise |s| will be substituted for the design size; in this
-case, |s| must be positive and less than $2048\rm\,pt$
-(i.e., it must be less than $2^{27}$ when considered as an integer).
-
-The subroutine opens and closes a global file variable called |tfm_file|.
-It returns the value of the internal font number that was just loaded.
-If an error is detected, an error message is issued and no font
-information is stored; |null_font| is returned in this case.
-
-@
-The |tag| field in a |char_info_word| has four values that explain how to
-interpret the |remainder| field.
-
-\yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par
-\hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning
-program starting at position |remainder| in the |lig_kern| array.\par
-\hang|tag=2| (|list_tag|) means that this character is part of a chain of
-characters of ascending sizes, and not the largest in the chain.  The
-|remainder| field gives the character code of the next larger character.\par
-\hang|tag=3| (|ext_tag|) means that this character code represents an
-extensible character, i.e., a character that is built up of smaller pieces
-so that it can be made arbitrarily large. The pieces are specified in
-|@!exten[remainder]|.\par
-\yskip\noindent
-Characters with |tag=2| and |tag=3| are treated as characters with |tag=0|
-unless they are used in special circumstances in math formulas. For example,
-the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left}
-operation looks for both |list_tag| and |ext_tag|.
-
-
-@ The |lig_kern| array contains instructions in a simple programming language
-that explains what to do for special letter pairs. Each word in this array,
-in a \.{TFM} file, is a |@!lig_kern_command| of four bytes.
-
-\yskip\hang first byte: |skip_byte|, indicates that this is the final program
-  step if the byte is 128 or more, otherwise the next step is obtained by
-  skipping this number of intervening steps.\par
-\hang second byte: |next_char|, ``if |next_char| follows the current character,
-  then perform the operation and stop, otherwise continue.''\par
-\hang third byte: |op_byte|, indicates a ligature step if less than~128,
-  a kern step otherwise.\par
-\hang fourth byte: |remainder|.\par
-\yskip\noindent
-In an \.{OFM} file, eight bytes are used, two bytes for each field.
-
-In a kern step, an
-additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted
-between the current character and |next_char|. This amount is
-often negative, so that the characters are brought closer together
-by kerning; but it might be positive.
-
-There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where
-$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is
-|remainder| is inserted between the current character and |next_char|;
-then the current character is deleted if $b=0$, and |next_char| is
-deleted if $c=0$; then we pass over $a$~characters to reach the next
-current character (which may have a ligature/kerning program of its own).
-
-If the very first instruction of the |lig_kern| array has |skip_byte=255|,
-the |next_char| byte is the so-called right boundary character of this font;
-the value of |next_char| need not lie between |bc| and~|ec|.
-If the very last instruction of the |lig_kern| array has |skip_byte=255|,
-there is a special ligature/kerning program for a left boundary character,
-beginning at location |256*op_byte+remainder|.
-The interpretation is that \TeX\ puts implicit boundary characters
-before and after each consecutive string of characters from the same font.
-These implicit characters do not appear in the output, but they can affect
-ligatures and kerning.
-
-If the very first instruction of a character's |lig_kern| program has
-|skip_byte>128|, the program actually begins in location
-|256*op_byte+remainder|. This feature allows access to large |lig_kern|
-arrays, because the first instruction must otherwise
-appear in a location |<=255| in a \.{TFM} file, |<=65535| in an \.{OFM} file.
-
-Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy
-the condition
-$$\hbox{|256*op_byte+remainder<nl|.}$$
-If such an instruction is encountered during
-normal program execution, it denotes an unconditional halt; no ligature
-or kerning command is performed.
-
-
-@ Extensible characters are specified by an |@!extensible_recipe|, which
-consists of four bytes in a \.{TFM} file,
-called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this order).
-In an \.{OFM} file, each field takes two bytes, for eight in total.
-These bytes are the character codes of individual pieces used to
-build up a large symbol.  If |top|, |mid|, or |bot| are zero, they are not
-present in the built-up result. For example, an extensible vertical line is
-like an extensible bracket, except that the top and bottom pieces are missing.
-
-Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box
-if the piece isn't present. Then the extensible characters have the form
-$TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent;
-in the latter case we can have $TR^kB$ for both even and odd values of~|k|.
-The width of the extensible character is the width of $R$; and the
-height-plus-depth is the sum of the individual height-plus-depths of the
-components used, since the pieces are butted together in a vertical list.
-
-
-@
-The final portion of a \.{TFM} file is the |param| array, which is another
-sequence of |fix_word| values.
-
-\yskip\hang|param[1]=slant| is the amount of italic slant, which is used
-to help position accents. For example, |slant=.25| means that when you go
-up one unit, you also go .25 units to the right. The |slant| is a pure
-number; it's the only |fix_word| other than the design size itself that is
-not scaled by the design size.
-
-\hang|param[2]=space| is the normal spacing between words in text.
-Note that character |" "| in the font need not have anything to do with
-blank spaces.
-
-\hang|param[3]=space_stretch| is the amount of glue stretching between words.
-
-\hang|param[4]=space_shrink| is the amount of glue shrinking between words.
-
-\hang|param[5]=x_height| is the size of one ex in the font; it is also
-the height of letters for which accents don't have to be raised or lowered.
-
-\hang|param[6]=quad| is the size of one em in the font.
-
-\hang|param[7]=extra_space| is the amount added to |param[2]| at the
-ends of sentences.
-
-\yskip\noindent
-If fewer than seven parameters are present, \TeX\ sets the missing parameters
-to zero. Fonts used for math symbols are required to have
-additional parameter information, which is explained later.
-
-
-@
- There are programs called \.{TFtoPL} and \.{PLtoTF} that convert
- between the \.{TFM} format and a symbolic property-list format
- that can be easily edited. These programs contain extensive
- diagnostic information, so \TeX\ does not have to bother giving
- precise details about why it rejects a particular \.{TFM} file.
-
- at c
-#define tfm_abort { font_tables[f]->_font_name = NULL;      \
-                    font_tables[f]->_font_area = NULL;      \
-                    xfree(tfm_buffer); xfree(kerns);      \
-        xfree(widths);  xfree(heights);  xfree(depths);     \
-        xfree(italics);  xfree(extens);  xfree(lig_kerns);  \
-        xfree(xligs);  xfree(xkerns);           \
-      return 0; }
-
-#define tfm_success { xfree(tfm_buffer); xfree(kerns);       \
-                xfree(widths);  xfree(heights);  xfree(depths);    \
-          xfree(italics);  xfree(extens);  xfree(lig_kerns); \
-          xfree(xligs);  xfree(xkerns); return 1; }
-
-@ @c
-static int open_tfm_file(const char *nom, unsigned char **tfm_buf, int *tfm_siz)
-{
-    boolean res;                /* was the callback successful? */
-    boolean opened;             /* was |tfm_file| successfully opened? */
-    int callback_id;
-    FILE *tfm_file;
-    char *fname = luatex_find_file(nom, find_font_file_callback);
-    if (!fname)
-        return -1;
-    callback_id = callback_defined(read_font_file_callback);
-    if (callback_id > 0) {
-        res =
-            run_callback(callback_id, "S->bSd", fname, &opened, tfm_buf,
-                         tfm_siz);
-        if (res && opened && (*tfm_siz > 0)) {
-            return 1;
-        }
-        if (!opened)
-            return -1;
-    } else {
-        if (luatex_open_input
-            (&(tfm_file), fname, kpse_ofm_format, FOPEN_RBIN_MODE, true)) {
-            res = read_tfm_file(tfm_file, tfm_buf, tfm_siz);
-            close_file(tfm_file);
-            if (res) {
-                return 1;
-            }
-        } else {
-            return -1;
-        }
-    }
-    return 0;
-}
-
-
-@
-  Note: A malformed \.{TFM} file might be shorter than it claims to be;
-  thus |eof(tfm_file)| might be true when |read_font_info| refers to
-  |tfm_file^| or when it says |get(tfm_file)|. If such circumstances
-  cause system error messages, you will have to defeat them somehow,
-  for example by defining |fget| to be `\ignorespaces|begin get(tfm_file);|
-  |if eof(tfm_file) then abort; end|\unskip'.
-  @^system dependencies@>
- at c
-
-#define fget  tfm_byte++
-#define fbyte tfm_buffer[tfm_byte]
-
-#define read_sixteen(a)                                                 \
-  { a=tfm_buffer[tfm_byte++];                                           \
-    if (a>127) { tfm_abort; }                                               \
-    a=(a*256)+tfm_buffer[tfm_byte]; }
-
-#define read_sixteen_unsigned(a)                                        \
-  { a=tfm_buffer[tfm_byte++];                                           \
-    a=(a*256)+tfm_buffer[tfm_byte]; }
-
-#define read_thirtytwo(a)                                               \
-  { a=tfm_buffer[++tfm_byte];                                           \
-    if (a>127) { tfm_abort; }                                               \
-    a=(a*256)+tfm_buffer[++tfm_byte];                                   \
-    a=(a*256)+tfm_buffer[++tfm_byte];                                   \
-    a=(a*256)+tfm_buffer[++tfm_byte]; }
-
-#define store_four_bytes(z)                                             \
-  { a=tfm_buffer[++tfm_byte];           \
-    a=(a*256)+tfm_buffer[++tfm_byte];         \
-    a=(a*256)+tfm_buffer[++tfm_byte];         \
-    a=(a*256)+tfm_buffer[++tfm_byte];         \
-    z = a; }
-
-#define store_char_info(z)                                              \
-  { if (font_level!=-1) {                                               \
-      fget; read_sixteen_unsigned(a);         \
-      ci._width_index=a;            \
-      fget; read_sixteen_unsigned(b);         \
-      ci._height_index=b>>8;            \
-      ci._depth_index=b%256;            \
-      fget; read_sixteen_unsigned(c);         \
-      ci._italic_index=c>>8;            \
-      ci._tag=(unsigned char)(c%4);	      \
-      fget; read_sixteen_unsigned(d);         \
-      ci._remainder=d;              \
-    } else {                                                            \
-      a=tfm_buffer[++tfm_byte];           \
-      ci._width_index=a;            \
-      b=tfm_buffer[++tfm_byte];           \
-      ci._height_index=b>>4;            \
-      ci._depth_index=b%16;           \
-      c=tfm_buffer[++tfm_byte];           \
-      ci._italic_index=c>>2;            \
-      ci._tag=(unsigned char)(c%4);	  \
-      d=tfm_buffer[++tfm_byte];           \
-      ci._remainder=d;              \
-    } }
-
-#define read_four_quarters(q)           \
-  { if (font_level!=-1) {                                        \
-      fget; read_sixteen_unsigned(a); q.b0=(quarterword)a;	 \
-      fget; read_sixteen_unsigned(b); q.b1=(quarterword)b;       \
-      fget; read_sixteen_unsigned(c); q.b2=(quarterword)c;       \
-      fget; read_sixteen_unsigned(d); q.b3=(quarterword)d;       \
-      } else {							 \
-      a=tfm_buffer[++tfm_byte]; q.b0=(quarterword)a;         \
-      b=tfm_buffer[++tfm_byte]; q.b1=(quarterword)b;         \
-      c=tfm_buffer[++tfm_byte]; q.b2=(quarterword)c;         \
-      d=tfm_buffer[++tfm_byte]; q.b3=(quarterword)d;	     \
-    } }
-
-#define check_byte_range(z)  { if ((z<bc)||(z>ec)) tfm_abort ; }
-
-
-@ A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents
-   the number
-   $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
-   b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
-   -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
-   (No other choices of |a| are allowed, since the magnitude of a number in
-   design-size units must be less than 16.)  We want to multiply this
-   quantity by the integer~|z|, which is known to be less than $2^{27}$.
-   If $|z|<2^{23}$, the individual multiplications $b\cdot z$,
-   $c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2,
-   4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can
-   compensate for this later. If |z| has thereby been replaced by
-   $|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute
-   $$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$
-   if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$.
-   This calculation must be done exactly, in order to guarantee portability
-   of \TeX\ between computers.
-
- at c
-#define store_scaled(zz)                                                   \
-  { fget; a=fbyte; fget; b=fbyte;                                          \
-    fget; c=fbyte; fget; d=fbyte;                                          \
-    sw=(((((d*z)>>8)+(c*z))>>8)+(b*z)) / beta;                             \
-    if (a==0) { zz=sw; } else if (a==255) { zz=sw-alpha; } else tfm_abort; \
-  }
-
-scaled store_scaled_f(scaled sq, scaled z_in)
-{
-    eight_bits a, b, c, d;
-    scaled sw;
-    static int alpha, beta;     /* beta:1..16 */
-    static scaled z, z_prev = 0;
-    /* Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
-    if (z_in != z_prev || z_prev == 0) {
-        z = z_prev = z_in;
-        alpha = 16;
-        while (z >= 0x800000) {
-            z /= 2;
-            alpha += alpha;
-        }
-        beta = 256 / alpha;
-        alpha *= z;
-    };
-    if (sq >= 0) {
-        d = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        c = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        b = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        a = (eight_bits) (sq % 256);
-    } else {
-        sq = (sq + 1073741824) + 1073741824;    /* braces for optimizing compiler */
-        d = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        c = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        b = (eight_bits) (sq % 256);
-        sq = sq / 256;
-        a = (eight_bits) ((sq + 128) % 256);
-    }
-    if (beta==0)
-        normal_error("vf", "vf scaling");
-    sw = (((((d * z) >> 8) + (c * z)) >> 8) + (b * z)) / beta;
-    if (a == 0)
-        return sw;
-    else if (a == 255)
-        return (sw - alpha);
-    else
-        normal_error("vf", "vf scaling");
-    return sw;                  /* not reached, just to make the compiler happy */
-}
-
-@ @c
-#define  check_existence(z)                                             \
-  { check_byte_range(z);                                                \
-    if (!char_exists(f,z)) tfm_abort;         \
-  }
-
-typedef struct tfmcharacterinfo {
-    int _kern_index;
-    int _lig_index;
-    int _width_index;
-    int _height_index;
-    int _depth_index;
-    int _italic_index;
-    int _remainder;
-    unsigned char _tag;
-} tfmcharacterinfo;
-
-@ @c
-int read_tfm_info(internal_font_number f, const char *cnom, scaled s)
-{
-    int k;                      /* index into |font_info| */
-    halfword lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, slh;       /* sizes of subfiles */
-    scaled *widths, *heights, *depths, *italics, *kerns;
-    halfword font_dir;
-    int a, b, c=0, d=0;             /* byte variables */
-    int i;                      /* counter */
-    int font_level, header_length;
-    int ncw, nlw, neew;
-    tfmcharacterinfo ci;
-    charinfo *co;
-    four_quarters qw;
-    four_quarters *lig_kerns, *extens;
-    scaled sw;                  /* accumulators */
-    int bch_label;              /* left boundary start location, or infinity */
-    int bchar;                  /* |:0..too_big_char;| *//* right boundary character, or |too_big_char| */
-    int first_two;
-    scaled z;                   /* the design size or the ``at'' size */
-    int alpha;
-    char beta;                  /* :1..16 */
-    int *xligs, *xkerns;        /* aux. for ligkern processing */
-    liginfo *cligs;
-    kerninfo *ckerns;
-    int fligs, fkerns;
-    char *tmpnam;
-    int tfm_byte = 0;           /* index into |tfm_buffer| */
-    int saved_tfm_byte = 0;     /* saved index into |tfm_buffer| */
-    unsigned char *tfm_buffer = NULL;   /* byte buffer for tfm files */
-    int tfm_size = 0;           /* total size of the tfm file */
-    int tmp;
-
-    widths = NULL;
-    heights = NULL;
-    depths = NULL;
-    italics = NULL;
-    kerns = NULL;
-    lig_kerns = NULL;
-    extens = NULL;
-    xkerns = NULL;
-    ckerns = NULL;
-    xligs = NULL;
-    cligs = NULL;
-
-    font_dir = 0;
-
-    memset(&ci, 0, sizeof(tfmcharacterinfo));
-
-    if (open_tfm_file(cnom, &tfm_buffer, &tfm_size) != 1)
-        tfm_abort;
-
-    /* cnom can be an absolute filename, xbasename() fixes that. */
-
-    tmpnam = strdup(xbasename(cnom));
-    if (strcmp(tmpnam + strlen(tmpnam) - 4, ".tfm") == 0 || strcmp(tmpnam + strlen(tmpnam) - 4, ".ofm") == 0) {
-        *(tmpnam + strlen(tmpnam) - 4) = 0;
-    }
-    set_font_name(f, tmpnam);
-    set_font_area(f, NULL);
-
-    /* Read the {\.{TFM}} size fields */
-    ncw = 0;
-    read_sixteen(first_two);
-    if (first_two != 0) {
-        font_level = -1;
-        lf = first_two;
-        fget;
-        read_sixteen(lh);
-        fget;
-        read_sixteen(bc);
-        fget;
-        read_sixteen(ec);
-        if ((bc > ec + 1) || (ec > 255))
-            tfm_abort;
-        if (bc > 255) {         /* |bc=256| and |ec=255| */
-            bc = 1;
-            ec = 0;
-        };
-        fget;
-        read_sixteen(nw);
-        fget;
-        read_sixteen(nh);
-        fget;
-        read_sixteen(nd);
-        fget;
-        read_sixteen(ni);
-        fget;
-        read_sixteen(nl);
-        fget;
-        read_sixteen(nk);
-        fget;
-        read_sixteen(ne);
-        fget;
-        read_sixteen(np);
-        header_length = 6;
-        ncw = (ec - bc + 1);
-        nlw = nl;
-        neew = ne;
-    } else {
-        fget;
-        read_sixteen(font_level);
-        if (font_level != 0)
-            tfm_abort;
-        read_thirtytwo(lf);
-        read_thirtytwo(lh);
-        read_thirtytwo(bc);
-        read_thirtytwo(ec);
-        if ((bc > ec + 1) || (ec > 65535))
-            tfm_abort;
-        if (bc > 65535) {       /* |bc=65536| and |ec=65535| */
-            bc = 1;
-            ec = 0;
-        };
-        read_thirtytwo(nw);
-        read_thirtytwo(nh);
-        read_thirtytwo(nd);
-        read_thirtytwo(ni);
-        read_thirtytwo(nl);
-        read_thirtytwo(nk);
-        read_thirtytwo(ne);
-        read_thirtytwo(np);
-        read_thirtytwo(font_dir);       /* junk */
-        nlw = 2 * nl;
-        neew = 2 * ne;
-        header_length = 14;
-        ncw = 2 * (ec - bc + 1);
-    };
-    if (lf !=
-        (header_length + lh + ncw + nw + nh + nd + ni + nlw + nk + neew + np))
-        tfm_abort;
-    if ((nw == 0) || (nh == 0) || (nd == 0) || (ni == 0))
-        tfm_abort;
-
-    /*
-       We check to see that the \.{TFM} file doesn't end prematurely; but
-       no error message is given for files having more than |lf| words.
-     */
-    if (lf * 4 > tfm_size)
-        tfm_abort;
-
-    /* Use size fields to allocate font information */
-
-    set_font_natural_dir(f, font_dir);
-    set_font_bc(f, bc);
-    set_font_ec(f, ec);
-
-    /* read the arrays first */
-    widths = xmalloc((unsigned) ((unsigned) nw * sizeof(scaled)));
-    heights = xmalloc((unsigned) ((unsigned) nh * sizeof(scaled)));
-    depths = xmalloc((unsigned) ((unsigned) nd * sizeof(scaled)));
-    italics = xmalloc((unsigned) ((unsigned) ni * sizeof(scaled)));
-    extens = xmalloc((unsigned) ((unsigned) ne * sizeof(four_quarters)));
-    lig_kerns = xmalloc((unsigned) ((unsigned) nl * sizeof(four_quarters)));
-    kerns = xmalloc((unsigned) ((unsigned) nk * sizeof(scaled)));
-
-    /* Read the {\.{TFM}} header */
-
-    /* Only the first two words of the header are needed by \TeX82. */
-    slh = lh;
-    if (lh < 2)
-        tfm_abort;
-    store_four_bytes(tmp);
-    font_checksum(f) = (unsigned) tmp;
-    fget;
-    read_sixteen(z);            /* this rejects a negative design size */
-    fget;
-    z = z * 256 + fbyte;
-    fget;
-    z = (z * 16) + (fbyte >> 4);
-    if (z < unity)
-        tfm_abort;
-    while (lh > 2) {
-        fget;
-        fget;
-        fget;
-        fget;
-        lh--;                   /* ignore the rest of the header */
-    };
-
-    /* read the arrays before the character info */
-
-    set_font_dsize(f, z);
-    if (s != -1000) {
-        z = (s >= 0 ? s : xn_over_d(z, -s, 1000));
-    }
-    set_font_size(f, z);
-
-    if (np > 7)
-        set_font_params(f, np);
-
-    saved_tfm_byte = tfm_byte;
-    tfm_byte = (header_length + slh + ncw) * 4 - 1;
-
-    /* Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$ */
-
-    alpha = 16;
-    while (z >= 040000000) {
-        z = z >> 1;
-        alpha = alpha + alpha;
-    };
-    beta = (char) (256 / alpha);
-
-    /* beta cannot be zero */
-    if (beta==0)
-       normal_error("vf", "vf reading");
-    alpha = alpha * z;
-
-    /* Read box dimensions */
-
-    for (k = 0; k < nw; k++) {
-        store_scaled(sw);
-        widths[k] = sw;
-    }
-    if (widths[0] != 0)         /* \\{width}[0] must be zero */
-        tfm_abort;
-    for (k = 0; k < nh; k++) {
-        store_scaled(sw);
-        heights[k] = sw;
-    }
-    if (heights[0] != 0)
-        tfm_abort;              /* \\{height}[0] must be zero */
-    for (k = 0; k < nd; k++) {
-        store_scaled(sw);
-        depths[k] = sw;
-    }
-    if (depths[0] != 0)
-        tfm_abort;              /* \\{depth}[0] must be zero */
-    for (k = 0; k < ni; k++) {
-        store_scaled(sw);
-        italics[k] = sw;
-    }
-    if (italics[0] != 0)
-        tfm_abort;              /* \\{italic}[0] must be zero */
-
-
-    /* Read ligature/kern program */
-
-    bch_label = nl;             /* infinity */
-    bchar = 65536;
-    if (nl > 0) {
-        for (k = 0; k < nl; k++) {
-            read_four_quarters(qw);
-            lig_kerns[k] = qw;
-            if (a > 128) {
-                if (256 * c + d >= nl)
-                    tfm_abort;
-                if (a == 255 && k == 0)
-                    bchar = b;
-            } else {
-#if 0
-                if (b!=bchar) check_existence(b);
-#endif
-                if (c < 128) {
-#if 0
-                    check_existence(d); /* check ligature */
-#endif
-                } else if (256 * (c - 128) + d >= nk) {
-                    tfm_abort;  /* check kern */
-                }
-                if ((a < 128) && (k - 0 + a + 1 >= nl))
-                    tfm_abort;
-            };
-        };
-        if (a == 255)
-            bch_label = 256 * c + d;
-    };
-
-    /* the actual kerns */
-    for (k = 0; k < nk; k++) {
-        store_scaled(sw);
-        kerns[k] = sw;
-    }
-
-    /* Read extensible character recipes */
-    for (k = 0; k < ne; k++) {
-        read_four_quarters(qw);
-        extens[k] = qw;
-    }
-
-    /* Read font parameters */
-
-    if (np > 7) {
-        set_font_params(f, np);
-    }
-    for (k = 1; k <= np; k++) {
-        if (k == 1) {           /* the |slant| parameter is a pure number */
-            fget;
-            sw = fbyte;
-            if (sw > 127)
-                sw = sw - 256;
-            fget;
-            sw = sw * 256 + fbyte;
-            fget;
-            sw = sw * 256 + fbyte;
-            fget;
-            sw = (sw * 16) + (fbyte >> 4);
-            set_font_param(f, k, sw);
-        } else {
-            store_scaled(font_param(f, k));
-        }
-    }
-
-    tfm_byte = saved_tfm_byte;
-
-    /* fix up the left boundary character */
-    fligs = 0;
-    fkerns = 0;
-    if (bch_label != nl) {
-        k = bch_label;
-#if 0
-           if (skip_byte(k) > stop_flag)
-           k = lig_kern_restart(k);
-#endif
-        while (1) {
-            if (skip_byte(k) <= stop_flag) {
-                if (op_byte(k) >= kern_flag) {  /* kern */
-                    fkerns++;
-                } else {        /* lig */
-                    fligs++;
-                }
-            }
-            if (skip_byte(k) == 0) {
-                k++;
-            } else {
-                if (skip_byte(k) >= stop_flag)
-                    break;
-                k += skip_byte(k) + 1;
-            }
-        }
-    }
-    if (fkerns > 0 || fligs > 0) {
-        if (fligs > 0)
-            cligs = xcalloc((unsigned) (fligs + 1), sizeof(liginfo));
-        if (fkerns > 0)
-            ckerns = xcalloc((unsigned) (fkerns + 1), sizeof(kerninfo));
-        fligs = 0;
-        fkerns = 0;
-        k = bch_label;
-#if 0
-        if (skip_byte(k) > stop_flag)
-           k = lig_kern_restart(k);
-#endif
-        while (1) {
-            if (skip_byte(k) <= stop_flag) {
-                if (op_byte(k) >= kern_flag) {  /* kern */
-                    set_kern_item(ckerns[fkerns], next_char(k),
-                                  kerns[256 * (op_byte(k) - 128) +
-                                        rem_byte(k)]);
-                    fkerns++;
-                } else {        /* lig */
-                    set_ligature_item(cligs[fligs], (char) (op_byte(k) * 2 + 1),
-                                      next_char(k), rem_byte(k));
-                    fligs++;
-                }
-            }
-            if (skip_byte(k) == 0) {
-                k++;
-            } else {
-                if (skip_byte(k) >= stop_flag)
-                    break;
-                k += skip_byte(k) + 1;
-            }
-        }
-        if (fkerns > 0 || fligs > 0) {
-            co = get_charinfo(f, left_boundarychar);
-            if (fkerns > 0) {
-                set_kern_item(ckerns[fkerns], end_kern, 0);
-                fkerns++;
-                set_charinfo_kerns(co, ckerns);
-            }
-            if (fligs > 0) {
-                set_ligature_item(cligs[fligs], 0, end_ligature, 0);
-                fligs++;
-                set_charinfo_ligatures(co, cligs);
-            }
-            set_charinfo_remainder(co, 0);
-        }
-    }
-
-    /* Read character data */
-    for (k = bc; k <= ec; k++) {
-        store_char_info(k);
-        if (ci._width_index == 0)
-            continue;
-        if (ci._width_index >= nw || ci._height_index >= nh ||
-            ci._depth_index >= nd || ci._italic_index >= ni)
-            tfm_abort;
-        d = ci._remainder;
-        switch (ci._tag) {
-        case lig_tag:
-            if (d >= nl)
-                tfm_abort;
-            break;
-        case ext_tag:
-            if (d >= ne)
-                tfm_abort;
-            break;
-        case list_tag:
-            /* We want to make sure that there is no cycle of characters linked together
-               by |list_tag| entries, since such a cycle would get \TeX\ into an endless
-               loop. If such a cycle exists, the routine here detects it when processing
-               the largest character code in the cycle.
-             */
-            check_byte_range(d);
-            while (d < k) {     /* |current_character == k| */
-                if (char_tag(f, d) != list_tag)
-                    goto NOT_FOUND;     /* not a cycle */
-                d = char_remainder(f, d);       /* next character on the list */
-            };
-            if (d == k)
-                tfm_abort;      /* yes, there's a cycle */
-          NOT_FOUND:
-            break;
-        }
-        /* put it in the actual font */
-        co = get_charinfo(f, k);
-        set_charinfo_index(co, k);
-        set_charinfo_tag(co, ci._tag);
-        if (ci._tag == ext_tag) {
-            set_charinfo_extensible(co, extens[ci._remainder].b0,       /* top */
-                                    extens[ci._remainder].b2,   /* bot */
-                                    extens[ci._remainder].b1,   /* mid */
-                                    extens[ci._remainder].b3);  /* rep */
-            set_charinfo_remainder(co, 0);
-        } else {
-            set_charinfo_remainder(co, ci._remainder);
-        }
-        set_charinfo_width(co, widths[ci._width_index]);
-        set_charinfo_height(co, heights[ci._height_index]);
-        set_charinfo_depth(co, depths[ci._depth_index]);
-        set_charinfo_italic(co, italics[ci._italic_index]);
-    };
-
-    /* first pass: count ligs and kerns */
-
-    xligs = xcalloc((unsigned) (ec + 1), sizeof(int));
-    xkerns = xcalloc((unsigned) (ec + 1), sizeof(int));
-
-    for (i = bc; i <= ec; i++) {
-        if (char_tag(f, i) == lig_tag) {
-            k = lig_kern_start(f, i);
-            if (skip_byte(k) > stop_flag)
-                k = lig_kern_restart(k);
-            /* now k is the start index */
-            while (1) {
-                if (skip_byte(k) <= stop_flag) {
-                    if (op_byte(k) >= kern_flag) {      /* kern */
-                        xkerns[i]++;
-                        if (next_char(k) == bchar)
-                            xkerns[i]++;
-                    } else {    /* lig */
-                        xligs[i]++;
-                        if (next_char(k) == bchar)
-                            xligs[i]++;
-                    }
-                }
-                if (skip_byte(k) == 0) {
-                    k++;
-                } else {
-                    if (skip_byte(k) >= stop_flag)
-                        break;
-                    k += skip_byte(k) + 1;
-                }
-            }
-        }
-    }
-
-    cligs = NULL;
-    ckerns = NULL;
-
-    for (i = bc; i <= ec; i++) {
-        fligs = 0;
-        fkerns = 0;
-        if (char_tag(f, i) == lig_tag) {
-            k = lig_kern_start(f, i);
-            if (skip_byte(k) > stop_flag)
-                k = lig_kern_restart(k);
-            /* now k is the start index */
-            if (xligs[i] > 0)
-                cligs = xcalloc((unsigned) (xligs[i] + 1), sizeof(liginfo));
-            if (xkerns[i] > 0)
-                ckerns = xcalloc((unsigned) (xkerns[i] + 1), sizeof(kerninfo));
-            while (1) {
-                if (skip_byte(k) <= stop_flag) {
-                    if (op_byte(k) >= kern_flag) {      /* kern */
-                        if (next_char(k) == bchar) {
-                            set_kern_item(ckerns[fkerns], right_boundarychar,
-                                          kerns[256 * (op_byte(k) - 128) +
-                                                rem_byte(k)]);
-                            fkerns++;
-                        }
-                        set_kern_item(ckerns[fkerns], next_char(k),
-                                      kerns[256 * (op_byte(k) - 128) +
-                                            rem_byte(k)]);
-                        fkerns++;
-                    } else {    /* lig */
-                        if (next_char(k) == bchar) {
-                            set_ligature_item(cligs[fligs],
-                                              (char) (op_byte(k) * 2 + 1),
-                                              right_boundarychar, rem_byte(k));
-                            fligs++;
-                        }
-                        set_ligature_item(cligs[fligs],
-                                          (char) (op_byte(k) * 2 + 1),
-                                          next_char(k), rem_byte(k));
-                        fligs++;
-                    }
-                }
-                if (skip_byte(k) == 0) {
-                    k++;
-                } else {
-                    if (skip_byte(k) >= stop_flag)
-                        break;
-                    k += skip_byte(k) + 1;
-                }
-            }
-            if (fkerns > 0 || fligs > 0) {
-                co = get_charinfo(f, i);
-                if (fkerns > 0) {
-                    set_kern_item(ckerns[fkerns], end_kern, 0);
-                    fkerns++;
-                    set_charinfo_kerns(co, ckerns);
-                }
-                if (fligs > 0) {
-                    set_ligature_item(cligs[fligs], 0, end_ligature, 0);
-                    fligs++;
-                    set_charinfo_ligatures(co, cligs);
-                }
-                set_charinfo_remainder(co, 0);
-            }
-        }
-    }
-
-
-    /* Make final adjustments and |goto done| */
-
-    /* Now to wrap it up, we have checked all the necessary things about the \.{TFM}
-       file, and all we need to do is put the finishing touches on the data for
-       the new font.
-     */
-
-    if (bchar != 65536) {
-        co = copy_charinfo(char_info(f, bchar));
-        set_right_boundary(f, co);
-    }
-
-    tfm_success;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tounicode.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,624 @@
+/*
+
+Copyright 2006 Han The Thanh, <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#define isXdigit(c) (isdigit(c) || ('A' <= (c) && (c) <= 'F'))
+
+/*tex
+
+    |UNIC_STRING| is a string allocated by |def_tounicode| while
+    |UNI_EXTRA_STRING| is one allocated by |set_glyph_unicode|.
+
+*/
+
+#define UNI_UNDEF        -1
+#define UNI_STRING       -2
+#define UNI_EXTRA_STRING -3
+
+static struct avl_table *glyph_unicode_tree = NULL;
+
+static int comp_glyph_unicode_entry(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const glyph_unicode_entry *) pa)->name, ((const glyph_unicode_entry *) pb)->name);
+}
+
+static glyph_unicode_entry *new_glyph_unicode_entry(void)
+{
+    glyph_unicode_entry *e;
+    e = xtalloc(1, glyph_unicode_entry);
+    e->name = NULL;
+    e->code = UNI_UNDEF;
+    e->unicode_seq = NULL;
+    return e;
+}
+
+static void destroy_glyph_unicode_entry(void *pa, void *pb)
+{
+    glyph_unicode_entry *e = (glyph_unicode_entry *) pa;
+    (void) pb;
+    xfree(e->name);
+    if (e->code == UNI_STRING) {
+        xfree(e->unicode_seq);
+    }
+}
+
+void glyph_unicode_free(void)
+{
+    if (glyph_unicode_tree != NULL)
+        avl_destroy(glyph_unicode_tree, destroy_glyph_unicode_entry);
+}
+
+void def_tounicode(str_number glyph, str_number unistr)
+{
+    char buf[SMALL_BUF_SIZE], *p, *ph;
+    char buf2[SMALL_BUF_SIZE], *q;
+    /*tex |0| is invalid, |1| an \UNICODE\ value and |2| a string */
+    int valid_unistr;
+    int i, l;
+    glyph_unicode_entry *gu, t;
+    void **aa;
+    p = makecstring(glyph);
+    assert(strlen(p) < SMALL_BUF_SIZE);
+    strcpy(buf, p);
+    free(p);
+    p = makecstring(unistr);
+    ph = p;
+    /*tex Ignore leading spaces. */
+    while (*p == ' ')
+        p++;
+    l = (int) strlen(p);
+    /*tex Ignore traling spaces. */
+    while (l > 0 && p[l - 1] == ' ')
+        l--;
+    /*tex A \UNICODE\ value is the most common case. */
+    valid_unistr = 1;
+    for (i = 0; i < l; i++) {
+        /*tex If a space occurs we treat this entry as a string. */
+        if (p[i] == ' ')
+            valid_unistr = 2;
+        else if (!isXdigit((unsigned char)p[i])) {
+            valid_unistr = 0;
+            break;
+        }
+    }
+    if (l == 0 || valid_unistr == 0 || strlen(buf) == 0 || strcmp(buf, notdef) == 0) {
+        formatted_warning("tounicode", "invalid parameter(s): %s -> %s", buf, p);
+        return;
+    }
+    if (glyph_unicode_tree == NULL) {
+        glyph_unicode_tree = avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
+    }
+    t.name = buf;
+    /*tex Allow overriding existing entries. */
+    if ((gu = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &t)) != NULL) {
+        if (gu->code == UNI_STRING) {
+            xfree(gu->unicode_seq);
+        }
+    } else {
+        /*tex Make a new entry. */
+        gu = new_glyph_unicode_entry();
+        gu->name = xstrdup(buf);
+    }
+    if (valid_unistr == 2) {
+        /*tex A string can have space(s) that we ignore by copying |p| to |buf2|. */
+        for (q = buf2; *p != 0; p++)
+            if (*p != ' ')
+                *q++ = *p;
+        *q = 0;
+        gu->code = UNI_STRING;
+        gu->unicode_seq = xstrdup(buf2);
+    } else {
+        i = sscanf(p, "%lX", &(gu->code));
+    }
+    aa = avl_probe(glyph_unicode_tree, gu);
+    assert(aa != NULL);
+    free(ph);
+}
+
+static long check_unicode_value(char *s, boolean multiple_value)
+{
+    int l = (int) strlen(s);
+    int i;
+    /*tex Anything that is not |UNI_UNDEF| will do: */
+    long code = 0;
+    if (l == 0)
+        return UNI_UNDEF;
+    if (multiple_value && l % 4 != 0)
+        return UNI_UNDEF;
+    if (!multiple_value && !(4 <= l && l <= 6))
+        return UNI_UNDEF;
+    for (i = 0; i < l; i++) {
+        if (!isXdigit((unsigned char)s[i]))
+            return UNI_UNDEF;
+        if (multiple_value) {
+            if (i % 4 == 3) {
+                if (sscanf(s + i - 3, "%4lX", &code) != 1)
+                    return UNI_UNDEF;
+                if (!((0x0000 <= code && code <= 0xD7FF) ||
+                      (0xE000 <= code && code <= 0xFFFF)))
+                    return UNI_UNDEF;
+            }
+        } else {                /* single value */
+            if (i == l - 1) {
+                if (sscanf(s, "%lX", &code) != 1)
+                    return UNI_UNDEF;
+                if (!((0x0000 <= code && code <= 0xD7FF) ||
+                      (0xE000 <= code && code <= 0x10FFFF)))
+                    return UNI_UNDEF;
+            }
+        }
+    }
+    return code;
+}
+
+/*
+
+    This function set proper values to |*gp| based on |s|; in case it returns
+    |gp->code == UNI_EXTRA_STRING| then the caller is responsible for freeing
+    |gp->unicode_seq| too.
+
+*/
+
+static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
+{
+    char buf[SMALL_BUF_SIZE], buf2[SMALL_BUF_SIZE], *p;
+    long code;
+    boolean last_component;
+    glyph_unicode_entry tmp, *ptmp;
+    /*tex Skip dummy entries. */
+    if (s == NULL || s == notdef)
+        return;
+    /*tex Strip everything after the first dot. */
+    p = strchr(s, '.');
+    if (p != NULL) {
+        *buf = 0;
+        strncat(buf, s, (size_t) (p - s));
+        s = buf;
+    }
+    if (strlen(s) == 0)
+        return;
+    /*tex Check for case of multiple components separated by |_|. */
+    p = strchr(s, '_');
+    if (p != NULL) {
+        assert(strlen(s) < sizeof(buf));
+        if (s != buf) {
+            strcpy(buf, s);
+            p = strchr(buf, '_');
+            s = buf;
+        }
+        *buf2 = 0;
+        last_component = false;
+        for (;;) {
+            *p = 0;
+            tmp.code = UNI_UNDEF;
+            set_glyph_unicode(s, &tmp);
+            switch (tmp.code) {
+            case UNI_UNDEF:
+                /*tex Not found, do nothing. */
+                break;
+            case UNI_STRING:
+                /*tex |s| matched an entry with string value in the database. */
+                assert(tmp.unicode_seq != NULL);
+                assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
+                strcat(buf2, tmp.unicode_seq);
+                break;
+            case UNI_EXTRA_STRING:
+                /*tex |s| is a multiple value of form "uniXXXX" */
+                assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
+                strcat(buf2, tmp.unicode_seq);
+                xfree(tmp.unicode_seq);
+                break;
+            default:
+                /*tex
+                    |s| matched an entry with numeric value in the database, or a
+                    value derived from |uXXXX|.
+                */
+                assert(tmp.code >= 0);
+                strcat(buf2, utf16be_str(tmp.code));
+            }
+            if (last_component)
+                break;
+            s = p + 1;
+            p = strchr(s, '_');
+            if (p == NULL) {
+                p = strend(s);
+                last_component = true;
+            }
+        }
+        gp->code = UNI_EXTRA_STRING;
+        gp->unicode_seq = xstrdup(buf2);
+        return;
+    }
+    /*tex Lookup glyph name in the database. */
+    tmp.name = s;
+    tmp.code = UNI_UNDEF;
+    ptmp = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &tmp);
+    if (ptmp != NULL) {
+        gp->code = ptmp->code;
+        gp->unicode_seq = ptmp->unicode_seq;
+        return;
+    }
+    /*tex Check for case of |uniXXXX|, multiple 4-hex-digit values allowed. */
+    if (str_prefix(s, "uni")) {
+        p = s + strlen("uni");
+        code = check_unicode_value(p, true);
+        if (code != UNI_UNDEF) {
+            if (strlen(p) == 4) {
+                /*tex Single value: */
+                gp->code = code;
+            } else {
+                /*tex Multiple value: */
+                gp->code = UNI_EXTRA_STRING;
+                gp->unicode_seq = xstrdup(p);
+            }
+        }
+        /*tex Since the last case cannot happen: */
+        return;
+    }
+    /*tex Check for case of |uXXXX|, a single value up to 6 hex digits. */
+    if (str_prefix(s, "u")) {
+        p = s + strlen("u");
+        code = check_unicode_value(p, false);
+        if (code != UNI_UNDEF) {
+            assert(code >= 0);
+            gp->code = code;
+        }
+    }
+}
+
+static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp, internal_font_number f)
+{
+    char *s;
+    if (font_tounicode(f)) {
+        if ((s = get_charinfo_tounicode(char_info(f, (int) index))) != NULL) {
+            gp->code = UNI_EXTRA_STRING;
+            gp->unicode_seq = xstrdup(s);
+        } else {
+            /*tex No fall back as we're providing them ourselves. */
+        }
+    } else {
+        /*tex Fall back. */
+        gp->code = index;
+    }
+}
+
+int write_tounicode(PDF pdf, char **glyph_names, char *name)
+{
+    char buf[SMALL_BUF_SIZE], *p;
+    static char builtin_suffix[] = "-builtin";
+    short range_size[257];
+    glyph_unicode_entry gtab[257];
+    int objnum;
+    int i, j;
+    int bfchar_count, bfrange_count, subrange_count;
+    assert(strlen(name) + strlen(builtin_suffix) < SMALL_BUF_SIZE);
+    if (glyph_unicode_tree == NULL) {
+        pdf->gen_tounicode = 0;
+        return 0;
+    }
+    strcpy(buf, name);
+    if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".enc") == 0) {
+        /*tex
+            Strip |.enc| from encoding name.
+        */
+        *p = 0;
+    } else {
+        /*
+            The suffix |.enc| is not present so this is a builtin encoding so the
+            name becomes e.g. |cmr10-builtin|.
+        */
+        strcat(buf, builtin_suffix);
+    }
+    objnum = pdf_create_obj(pdf, obj_type_others, 0);
+    pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_streaminfo(pdf);
+    pdf_end_dict(pdf);
+    pdf_begin_stream(pdf);
+    pdf_printf(pdf,
+        "%%!PS-Adobe-3.0 Resource-CMap\n"
+        "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"
+        "%%%%IncludeResource: ProcSet (CIDInit)\n"
+        "%%%%BeginResource: CMap (TeX-%s-0)\n"
+        "%%%%Title: (TeX-%s-0 TeX %s 0)\n"
+        "%%%%Version: 1.000\n"
+        "%%%%EndComments\n"
+        "/CIDInit /ProcSet findresource begin\n"
+        "12 dict begin\n"
+        "begincmap\n"
+        "/CIDSystemInfo\n"
+        "<< /Registry (TeX)\n"
+        "/Ordering (%s)\n"
+        "/Supplement 0\n"
+        ">> def\n"
+        "/CMapName /TeX-%s-0 def\n"
+        "/CMapType 2 def\n"
+        "1 begincodespacerange\n"
+        "<00> <FF>\n" "endcodespacerange\n",
+        buf, buf, buf, buf, buf);
+    /*tex Set gtab: */
+    for (i = 0; i < 256; ++i) {
+        gtab[i].code = UNI_UNDEF;
+        set_glyph_unicode(glyph_names[i], &gtab[i]);
+    }
+    gtab[256].code = UNI_UNDEF;
+    /*tex Set |range_size|: */
+    for (i = 0; i < 256;) {
+        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+            /*tex Single entry: */
+            range_size[i] = 1;
+            i++;
+        } else if (gtab[i].code == UNI_UNDEF) {
+            /*tex No entry: */
+            range_size[i] = 0;
+            i++;
+        } else {
+            /*tex |gtab[i].code >= 0| */
+            j = i;
+            while (i < 256 && gtab[i + 1].code >= 0 && gtab[i].code + 1 == gtab[i + 1].code)
+                i++;
+            /*tex
+                At this point |i| is the last entry of the subrange so we move |i| to
+                the next entry.
+            */
+            i++;
+            range_size[j] = (short) (i - j);
+        }
+    }
+    /*tex Calculate |bfrange_count| and |bfchar_count|. */
+    bfrange_count = 0;
+    bfchar_count = 0;
+    for (i = 0; i < 256;) {
+        if (range_size[i] == 1) {
+            bfchar_count++;
+            i++;
+        } else if (range_size[i] > 1) {
+            bfrange_count++;
+            i += range_size[i];
+        } else
+            i++;
+    }
+    /*tex Write out |bfrange|. */
+    i = 0;
+  write_bfrange:
+    if (bfrange_count > 100)
+        subrange_count = 100;
+    else
+        subrange_count = bfrange_count;
+    bfrange_count -= subrange_count;
+    pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
+    for (j = 0; j < subrange_count; j++) {
+        while (range_size[i] <= 1 && i < 256)
+            i++;
+        assert(i < 256);
+        pdf_printf(pdf, "<%02X> <%02X> <%s>\n", i, i + range_size[i] - 1,
+                   utf16be_str(gtab[i].code));
+        i += range_size[i];
+    }
+    pdf_printf(pdf, "endbfrange\n");
+    if (bfrange_count > 0)
+        goto write_bfrange;
+    /*tex Write out |bfchar|. */
+    i = 0;
+  write_bfchar:
+    if (bfchar_count > 100)
+        subrange_count = 100;
+    else
+        subrange_count = bfchar_count;
+    bfchar_count -= subrange_count;
+    pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
+    for (j = 0; j < subrange_count; j++) {
+        while (i < 256) {
+            if (range_size[i] > 1)
+                i += range_size[i];
+            else if (range_size[i] == 0)
+                i++;
+            else
+                break;
+        }
+        assert(i < 256 && gtab[i].code != UNI_UNDEF);
+        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+            assert(gtab[i].unicode_seq != NULL);
+            pdf_printf(pdf, "<%02X> <%s>\n", i, gtab[i].unicode_seq);
+        } else
+            pdf_printf(pdf, "<%02X> <%s>\n", i, utf16be_str(gtab[i].code));
+        i++;
+    }
+    pdf_printf(pdf, "endbfchar\n");
+    if (bfchar_count > 0)
+        goto write_bfchar;
+    /*tex Free strings allocated by |set_glyph_unicode|. */
+    for (i = 0; i < 256; ++i) {
+        if (gtab[i].code == UNI_EXTRA_STRING)
+            xfree(gtab[i].unicode_seq);
+    }
+    pdf_printf(pdf,
+        "endcmap\n"
+        "CMapName currentdict /CMap defineresource pop\n"
+        "end\n"
+        "end\n"
+        "%%%%EndResource\n"
+        "%%%%EOF\n");
+    pdf_end_stream(pdf);
+    pdf_end_obj(pdf);
+    return objnum;
+}
+
+int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+    static int range_size[65537];
+    static glyph_unicode_entry gtab[65537];
+    int objnum;
+    int i, j, k;
+    int bfchar_count, bfrange_count, subrange_count;
+    char *buf;
+    buf = xmalloc((unsigned) (strlen(fo->fd->fontname) + 8));
+    sprintf(buf, "%s-%s", (fo->fd->subset_tag != NULL ? fo->fd->subset_tag : "UCS"), fo->fd->fontname);
+    objnum = pdf_create_obj(pdf, obj_type_others, 0);
+    pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_streaminfo(pdf);
+    pdf_end_dict(pdf);
+    pdf_begin_stream(pdf);
+    pdf_printf(pdf,
+        "%%!PS-Adobe-3.0 Resource-CMap\n"
+        "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"
+        "%%%%IncludeResource: ProcSet (CIDInit)\n"
+        "%%%%BeginResource: CMap (TeX-%s-0)\n"
+        "%%%%Title: (TeX-%s-0 TeX %s 0)\n"
+        "%%%%Version: 1.000\n"
+        "%%%%EndComments\n"
+        "/CIDInit /ProcSet findresource begin\n"
+        "12 dict begin\n"
+        "begincmap\n"
+        "/CIDSystemInfo\n"
+        "<< /Registry (TeX)\n"
+        "/Ordering (%s)\n"
+        "/Supplement 0\n"
+        ">> def\n"
+        "/CMapName /TeX-Identity-%s def\n"
+        "/CMapType 2 def\n"
+        "1 begincodespacerange\n"
+        "<0000> <FFFF>\n"
+        "endcodespacerange\n",
+        buf, buf, buf, buf, buf);
+    xfree(buf);
+    /*tex Set up |gtab|: */
+    for (i = 0; i < 65537; ++i) {
+        gtab[i].code = UNI_UNDEF;
+    }
+    for (k = 1; k <= max_font_id(); k++) {
+        if (k == f || -f == pdf_font_num(k)) {
+            for (i = font_bc(k); i <= font_ec(k); i++) {
+                if (quick_char_exists(k, i) && char_used(k, i)) {
+                    j = char_index(k, i);
+                    if (gtab[j].code == UNI_UNDEF) {
+                        set_cid_glyph_unicode(i, &gtab[j], f);
+                    }
+                }
+            }
+        }
+    }
+    /*tex Set |range_size|: */
+    for (i = 0; i < 65536;) {
+        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+            /*tex Single entry. */
+            range_size[i] = 1;
+            i++;
+        } else if (gtab[i].code == UNI_UNDEF) {
+            /*tex No entry. */
+            range_size[i] = 0;
+            i++;
+        } else {
+            /*tex |gtab[i].code >= 0| */
+            j = i;
+            k = i % 256;
+            while (i < 65536 && k<255 && gtab[i + 1].code >= 0 &&
+                   gtab[i].code + 1 == gtab[i + 1].code) {
+                i++; k++;
+            }
+            /* tex
+                At this point |i| is the last entry of the subrange so we move
+                |i| to the next entry
+            */
+            i++;
+            range_size[j] = i - j;
+        }
+    }
+    /*tex Calculate |bfrange_count| and |bfchar_count|. */
+    bfrange_count = 0;
+    bfchar_count = 0;
+    for (i = 0; i < 65536;) {
+        if (range_size[i] == 1) {
+            bfchar_count++;
+            i++;
+        } else if (range_size[i] > 1) {
+            bfrange_count++;
+            i += range_size[i];
+        } else
+            i++;
+    }
+    /*tex Write out |bfrange|. */
+    i = 0;
+  write_bfrange:
+    if (bfrange_count > 100)
+        subrange_count = 100;
+    else
+        subrange_count = bfrange_count;
+    bfrange_count -= subrange_count;
+    pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
+    for (j = 0; j < subrange_count; j++) {
+        while (range_size[i] <= 1 && i < 65536)
+            i++;
+        pdf_printf(pdf, "<%04X> <%04X> <%s>\n", i, i + range_size[i] - 1, utf16be_str(gtab[i].code));
+        i += range_size[i];
+    }
+    pdf_printf(pdf, "endbfrange\n");
+    if (bfrange_count > 0)
+        goto write_bfrange;
+    /*tex Write out |bfchar| */
+    i = 0;
+  write_bfchar:
+    if (bfchar_count > 100)
+        subrange_count = 100;
+    else
+        subrange_count = bfchar_count;
+    bfchar_count -= subrange_count;
+    pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
+    for (j = 0; j < subrange_count; j++) {
+        while (i < 65536) {
+            if (range_size[i] > 1)
+                i += range_size[i];
+            else if (range_size[i] == 0)
+                i++;
+            else
+                /* |range_size[i] == 1| */
+                break;
+        }
+        assert(i < 65536 && gtab[i].code != UNI_UNDEF);
+        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
+            pdf_printf(pdf, "<%04X> <%s>\n", i, gtab[i].unicode_seq);
+        } else
+            pdf_printf(pdf, "<%04X> <%s>\n", i, utf16be_str(gtab[i].code));
+        i++;
+    }
+    pdf_printf(pdf, "endbfchar\n");
+    if (bfchar_count > 0)
+        goto write_bfchar;
+    /*tex Free strings allocated by |set_glyph_unicode|: */
+    for (i = 0; i < 65536; ++i) {
+        if (gtab[i].code == UNI_EXTRA_STRING)
+            xfree(gtab[i].unicode_seq);
+    }
+    pdf_printf(pdf,
+        "endcmap\n"
+        "CMapName currentdict /CMap defineresource pop\n"
+        "end\n"
+        "end\n"
+        "%%%%EndResource\n"
+        "%%%%EOF\n");
+    pdf_end_stream(pdf);
+    pdf_end_obj(pdf);
+    return objnum;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tounicode.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,612 +0,0 @@
-% tounicode.w
-%
-% Copyright 2006 Han The Thanh, <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ @c
-#define isXdigit(c) (isdigit(c) || ('A' <= (c) && (c) <= 'F'))
-#define UNI_UNDEF          -1
-#define UNI_STRING         -2   /* string allocated by |def_tounicode()| */
-#define UNI_EXTRA_STRING   -3   /* string allocated by |set_glyph_unicode()| */
-
-static struct avl_table *glyph_unicode_tree = NULL;
-
-static int comp_glyph_unicode_entry(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const glyph_unicode_entry *) pa)->name,
-                  ((const glyph_unicode_entry *) pb)->name);
-}
-
-static glyph_unicode_entry *new_glyph_unicode_entry(void)
-{
-    glyph_unicode_entry *e;
-    e = xtalloc(1, glyph_unicode_entry);
-    e->name = NULL;
-    e->code = UNI_UNDEF;
-    e->unicode_seq = NULL;
-    return e;
-}
-
-static void destroy_glyph_unicode_entry(void *pa, void *pb)
-{
-    glyph_unicode_entry *e = (glyph_unicode_entry *) pa;
-    (void) pb;
-    xfree(e->name);
-    if (e->code == UNI_STRING) {
-        assert(e->unicode_seq != NULL);
-        xfree(e->unicode_seq);
-    }
-}
-
-void glyph_unicode_free(void)
-{
-    if (glyph_unicode_tree != NULL)
-        avl_destroy(glyph_unicode_tree, destroy_glyph_unicode_entry);
-}
-
-@ @c
-void def_tounicode(str_number glyph, str_number unistr)
-{
-    char buf[SMALL_BUF_SIZE], *p, *ph;
-    char buf2[SMALL_BUF_SIZE], *q;
-    int valid_unistr;           /* 0: invalid; 1: unicode value; 2: string */
-    int i, l;
-    glyph_unicode_entry *gu, t;
-    void **aa;
-
-    p = makecstring(glyph);
-    assert(strlen(p) < SMALL_BUF_SIZE);
-    strcpy(buf, p);
-    free(p);
-    p = makecstring(unistr);
-    ph = p;
-    while (*p == ' ')
-        p++;                    /* ignore leading spaces */
-    l = (int) strlen(p);
-    while (l > 0 && p[l - 1] == ' ')
-        l--;                    /* ignore traling spaces */
-    valid_unistr = 1;           /* a unicode value is the most common case */
-    for (i = 0; i < l; i++) {
-        if (p[i] == ' ')
-            valid_unistr = 2;   /* if a space occurs we treat this entry as a string */
-        else if (!isXdigit((unsigned char)p[i])) {
-            valid_unistr = 0;
-            break;
-        }
-    }
-    if (l == 0 || valid_unistr == 0 || strlen(buf) == 0 || strcmp(buf, notdef) == 0) {
-        formatted_warning("tounicode", "invalid parameter(s): %s -> %s", buf, p);
-        return;
-    }
-    if (glyph_unicode_tree == NULL) {
-        glyph_unicode_tree =
-            avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
-        assert(glyph_unicode_tree != NULL);
-    }
-    t.name = buf;
-    /* allow overriding existing entries */
-    if ((gu = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &t)) != NULL) {
-        if (gu->code == UNI_STRING) {
-            assert(gu->unicode_seq != NULL);
-            xfree(gu->unicode_seq);
-        }
-    } else {                    /* make new entry */
-        gu = new_glyph_unicode_entry();
-        gu->name = xstrdup(buf);
-    }
-    if (valid_unistr == 2) {    /* a string with space(s) */
-        /* copy p to buf2, ignoring spaces */
-        for (q = buf2; *p != 0; p++)
-            if (*p != ' ')
-                *q++ = *p;
-        *q = 0;
-        gu->code = UNI_STRING;
-        gu->unicode_seq = xstrdup(buf2);
-    } else {
-        i = sscanf(p, "%lX", &(gu->code));
-        assert(i == 1);
-    }
-    aa = avl_probe(glyph_unicode_tree, gu);
-    assert(aa != NULL);
-    free(ph);
-}
-
-
-@ @c
-static long check_unicode_value(char *s, boolean multiple_value)
-{
-    int l = (int) strlen(s);
-    int i;
-    long code = 0; /* anything that is not |UNI_UNDEF| will do */
-
-    if (l == 0)
-        return UNI_UNDEF;
-    if (multiple_value && l % 4 != 0)
-        return UNI_UNDEF;
-    if (!multiple_value && !(4 <= l && l <= 6))
-        return UNI_UNDEF;
-
-    for (i = 0; i < l; i++) {
-        if (!isXdigit((unsigned char)s[i]))
-            return UNI_UNDEF;
-        if (multiple_value) {
-            if (i % 4 == 3) {
-                if (sscanf(s + i - 3, "%4lX", &code) != 1)
-                    return UNI_UNDEF;
-                if (!((0x0000 <= code && code <= 0xD7FF) ||
-                      (0xE000 <= code && code <= 0xFFFF)))
-                    return UNI_UNDEF;
-            }
-        } else {                /* single value */
-            if (i == l - 1) {
-                if (sscanf(s, "%lX", &code) != 1)
-                    return UNI_UNDEF;
-                if (!((0x0000 <= code && code <= 0xD7FF) ||
-                      (0xE000 <= code && code <= 0x10FFFF)))
-                    return UNI_UNDEF;
-            }
-        }
-    }
-    return code;
-}
-
-@ This function set proper values to |*gp| based on |s|; in case it returns
- |gp->code == UNI_EXTRA_STRING| then the caller is responsible for freeing
- |gp->unicode_seq| too.
- at c
-static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
-{
-    char buf[SMALL_BUF_SIZE], buf2[SMALL_BUF_SIZE], *p;
-    long code;
-    boolean last_component;
-    glyph_unicode_entry tmp, *ptmp;
-
-    /* skip dummy entries */
-    if (s == NULL || s == notdef)
-        return;
-
-    /* strip everything after the first dot */
-    p = strchr(s, '.');
-    if (p != NULL) {
-        *buf = 0;
-        strncat(buf, s, (size_t) (p - s));
-        s = buf;
-    }
-
-    if (strlen(s) == 0)
-        return;
-
-    /* check for case of multiple components separated by |'_'| */
-    p = strchr(s, '_');
-    if (p != NULL) {
-        assert(strlen(s) < sizeof(buf));
-        if (s != buf) {
-            strcpy(buf, s);
-            p = strchr(buf, '_');
-            s = buf;
-        }
-        *buf2 = 0;
-        last_component = false;
-        for (;;) {
-            *p = 0;
-            tmp.code = UNI_UNDEF;
-            set_glyph_unicode(s, &tmp);
-            switch (tmp.code) {
-            case UNI_UNDEF:    /* not found, do nothing */
-                break;
-            case UNI_STRING:   /* s matched an entry with string value in the database */
-                assert(tmp.unicode_seq != NULL);
-                assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
-                strcat(buf2, tmp.unicode_seq);
-                break;
-            case UNI_EXTRA_STRING:     /* s is a multiple value of form "uniXXXX" */
-                assert(strlen(buf2) + strlen(tmp.unicode_seq) < sizeof(buf2));
-                strcat(buf2, tmp.unicode_seq);
-                xfree(tmp.unicode_seq);
-                break;
-            default:           /* s matched an entry with numeric value in the
-                                   database, or a value derived from "uXXXX" */
-                assert(tmp.code >= 0);
-                strcat(buf2, utf16be_str(tmp.code));
-            }
-            if (last_component)
-                break;
-            s = p + 1;
-            p = strchr(s, '_');
-            if (p == NULL) {
-                p = strend(s);
-                last_component = true;
-            }
-        }
-        gp->code = UNI_EXTRA_STRING;
-        gp->unicode_seq = xstrdup(buf2);
-        return;
-    }
-
-    /* lookup for glyph name in the database */
-    tmp.name = s;
-    tmp.code = UNI_UNDEF;
-    ptmp = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &tmp);
-    if (ptmp != NULL) {
-        gp->code = ptmp->code;
-        gp->unicode_seq = ptmp->unicode_seq;
-        return;
-    }
-
-    /* check for case of "uniXXXX" (multiple 4-hex-digit values allowed) */
-    if (str_prefix(s, "uni")) {
-        p = s + strlen("uni");
-        code = check_unicode_value(p, true);
-        if (code != UNI_UNDEF) {
-            if (strlen(p) == 4) /* single value */
-                gp->code = code;
-            else {              /* multiple value */
-                gp->code = UNI_EXTRA_STRING;
-                gp->unicode_seq = xstrdup(p);
-            }
-        }
-        return;                 /* since the last case cannot happen */
-    }
-
-    /* check for case of "uXXXX" (single value up to 6 hex digits) */
-    if (str_prefix(s, "u")) {
-        p = s + strlen("u");
-        code = check_unicode_value(p, false);
-        if (code != UNI_UNDEF) {
-            assert(code >= 0);
-            gp->code = code;
-        }
-    }
-}
-
-@ @c
-static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp,
-                                  internal_font_number f)
-{
-    char *s;
-    if (font_tounicode(f)) {
-        if ((s = get_charinfo_tounicode(char_info(f, (int) index))) != NULL) {
-            gp->code = UNI_EXTRA_STRING;
-            gp->unicode_seq = xstrdup(s);
-        } else {
-            /* no fallback as we're providing them ourselves */
-        }
-    } else {
-        /* fallback */
-        gp->code = index;
-    }
-}
-
-@ @c
-int write_tounicode(PDF pdf, char **glyph_names, char *name)
-{
-    char buf[SMALL_BUF_SIZE], *p;
-    static char builtin_suffix[] = "-builtin";
-    short range_size[257];
-    glyph_unicode_entry gtab[257];
-    int objnum;
-    int i, j;
-    int bfchar_count, bfrange_count, subrange_count;
-    assert(strlen(name) + strlen(builtin_suffix) < SMALL_BUF_SIZE);
-    if (glyph_unicode_tree == NULL) {
-        pdf->gen_tounicode = 0;
-        return 0;
-    }
-    strcpy(buf, name);
-    if ((p = strrchr(buf, '.')) != NULL && strcmp(p, ".enc") == 0)
-        *p = 0;                 /* strip ".enc" from encoding name */
-    else
-        strcat(buf, builtin_suffix);    /* ".enc" not present, this is a builtin
-                                           encoding so the name is eg "cmr10-builtin" */
-    objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_streaminfo(pdf);
-    pdf_end_dict(pdf);
-    pdf_begin_stream(pdf);
-    pdf_printf(pdf, "%%!PS-Adobe-3.0 Resource-CMap\n"@/
-               "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"@/
-               "%%%%IncludeResource: ProcSet (CIDInit)\n"@/
-               "%%%%BeginResource: CMap (TeX-%s-0)\n"@/
-               "%%%%Title: (TeX-%s-0 TeX %s 0)\n"@/
-               "%%%%Version: 1.000\n"@/
-               "%%%%EndComments\n"@/
-               "/CIDInit /ProcSet findresource begin\n"@/
-               "12 dict begin\n"@/
-               "begincmap\n"@/
-               "/CIDSystemInfo\n"@/
-               "<< /Registry (TeX)\n"@/
-               "/Ordering (%s)\n"@/
-               "/Supplement 0\n"@/
-               ">> def\n"@/
-               "/CMapName /TeX-%s-0 def\n"@/
-               "/CMapType 2 def\n"@/
-               "1 begincodespacerange\n"@/
-               "<00> <FF>\n" "endcodespacerange\n", buf, buf, buf, buf, buf);
-
-    /* set gtab */
-    for (i = 0; i < 256; ++i) {
-        gtab[i].code = UNI_UNDEF;
-        set_glyph_unicode(glyph_names[i], &gtab[i]);
-    }
-    gtab[256].code = UNI_UNDEF;
-
-    /* set |range_size| */
-    for (i = 0; i < 256;) {
-        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
-            range_size[i] = 1;  /* single entry */
-            i++;
-        } else if (gtab[i].code == UNI_UNDEF) {
-            range_size[i] = 0;  /* no entry */
-            i++;
-        } else {                /* gtab[i].code >= 0 */
-            j = i;
-            while (i < 256 && gtab[i + 1].code >= 0 &&
-                   gtab[i].code + 1 == gtab[i + 1].code)
-                i++;
-            /* at this point i is the last entry of the subrange */
-            i++;                /* move i to the next entry */
-            range_size[j] = (short) (i - j);
-        }
-    }
-
-    /* calculate |bfrange_count| and |bfchar_count| */
-    bfrange_count = 0;
-    bfchar_count = 0;
-    for (i = 0; i < 256;) {
-        if (range_size[i] == 1) {
-            bfchar_count++;
-            i++;
-        } else if (range_size[i] > 1) {
-            bfrange_count++;
-            i += range_size[i];
-        } else
-            i++;
-    }
-
-    /* write out bfrange */
-    i = 0;
-  write_bfrange:
-    if (bfrange_count > 100)
-        subrange_count = 100;
-    else
-        subrange_count = bfrange_count;
-    bfrange_count -= subrange_count;
-    pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
-    for (j = 0; j < subrange_count; j++) {
-        while (range_size[i] <= 1 && i < 256)
-            i++;
-        assert(i < 256);
-        pdf_printf(pdf, "<%02X> <%02X> <%s>\n", i, i + range_size[i] - 1,
-                   utf16be_str(gtab[i].code));
-        i += range_size[i];
-    }
-    pdf_printf(pdf, "endbfrange\n");
-    if (bfrange_count > 0)
-        goto write_bfrange;
-
-    /* write out bfchar */
-    i = 0;
-  write_bfchar:
-    if (bfchar_count > 100)
-        subrange_count = 100;
-    else
-        subrange_count = bfchar_count;
-    bfchar_count -= subrange_count;
-    pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
-    for (j = 0; j < subrange_count; j++) {
-        while (i < 256) {
-            if (range_size[i] > 1)
-                i += range_size[i];
-            else if (range_size[i] == 0)
-                i++;
-            else                /* |range_size[i] == 1| */
-                break;
-        }
-        assert(i < 256 && gtab[i].code != UNI_UNDEF);
-        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
-            assert(gtab[i].unicode_seq != NULL);
-            pdf_printf(pdf, "<%02X> <%s>\n", i, gtab[i].unicode_seq);
-        } else
-            pdf_printf(pdf, "<%02X> <%s>\n", i, utf16be_str(gtab[i].code));
-        i++;
-    }
-    pdf_printf(pdf, "endbfchar\n");
-    if (bfchar_count > 0)
-        goto write_bfchar;
-
-    /* free strings allocated by |set_glyph_unicode()| */
-    for (i = 0; i < 256; ++i) {
-        if (gtab[i].code == UNI_EXTRA_STRING)
-            xfree(gtab[i].unicode_seq);
-    }
-
-    pdf_printf(pdf, "endcmap\n"
-               "CMapName currentdict /CMap defineresource pop\n"
-               "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n");
-    pdf_end_stream(pdf);
-    pdf_end_obj(pdf);
-    return objnum;
-}
-
-@ @c
-int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
-{
-
-    static int range_size[65537];
-    static glyph_unicode_entry gtab[65537];
-    int objnum;
-    int i, j, k;
-    int bfchar_count, bfrange_count, subrange_count;
-    char *buf;
-
-    assert(fo->fd->fontname);
-    buf = xmalloc((unsigned) (strlen(fo->fd->fontname) + 8));
-    sprintf(buf, "%s-%s",
-            (fo->fd->subset_tag != NULL ? fo->fd->subset_tag : "UCS"),
-            fo->fd->fontname);
-
-    objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, objnum, OBJSTM_NEVER);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_streaminfo(pdf);
-    pdf_end_dict(pdf);
-    pdf_begin_stream(pdf);
-    pdf_printf(pdf, "%%!PS-Adobe-3.0 Resource-CMap\n"@/
-               "%%%%DocumentNeededResources: ProcSet (CIDInit)\n"@/
-               "%%%%IncludeResource: ProcSet (CIDInit)\n"@/
-               "%%%%BeginResource: CMap (TeX-%s-0)\n"@/
-               "%%%%Title: (TeX-%s-0 TeX %s 0)\n"@/
-               "%%%%Version: 1.000\n"@/
-               "%%%%EndComments\n"@/
-               "/CIDInit /ProcSet findresource begin\n"@/
-               "12 dict begin\n"@/
-               "begincmap\n"@/
-               "/CIDSystemInfo\n"@/
-               "<< /Registry (TeX)\n"@/
-               "/Ordering (%s)\n"@/
-               "/Supplement 0\n"@/
-               ">> def\n"@/
-               "/CMapName /TeX-Identity-%s def\n"@/
-               "/CMapType 2 def\n"@/
-               "1 begincodespacerange\n"@/
-               "<0000> <FFFF>\n"@/
-               "endcodespacerange\n", buf, buf, buf, buf, buf);
-    xfree(buf);
-    /* set up gtab */
-    for (i = 0; i < 65537; ++i) {
-        gtab[i].code = UNI_UNDEF;
-    }
-    for (k = 1; k <= max_font_id(); k++) {
-        if (k == f || -f == pdf_font_num(k)) {
-            for (i = font_bc(k); i <= font_ec(k); i++) {
-                if (quick_char_exists(k, i) && char_used(k, i)) {
-                    j = char_index(k, i);
-                    if (gtab[j].code == UNI_UNDEF) {
-                        set_cid_glyph_unicode(i, &gtab[j], f);
-                    }
-                }
-            }
-        }
-    }
-
-    /* set |range_size| */
-    for (i = 0; i < 65536;) {
-        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
-            range_size[i] = 1;  /* single entry */
-            i++;
-        } else if (gtab[i].code == UNI_UNDEF) {
-            range_size[i] = 0;  /* no entry */
-            i++;
-        } else {                /* |gtab[i].code >= 0| */
-            j = i;
-            k = i % 256;
-            while (i < 65536 && k<255 && gtab[i + 1].code >= 0 &&
-                   gtab[i].code + 1 == gtab[i + 1].code) {
-                i++; k++;
-            }
-            /* at this point i is the last entry of the subrange */
-            i++;                /* move i to the next entry */
-            range_size[j] = i - j;
-        }
-    }
-
-    /* calculate |bfrange_count| and |bfchar_count| */
-    bfrange_count = 0;
-    bfchar_count = 0;
-    for (i = 0; i < 65536;) {
-        if (range_size[i] == 1) {
-            bfchar_count++;
-            i++;
-        } else if (range_size[i] > 1) {
-            bfrange_count++;
-            i += range_size[i];
-        } else
-            i++;
-    }
-
-    /* write out bfrange */
-    i = 0;
-  write_bfrange:
-    if (bfrange_count > 100)
-        subrange_count = 100;
-    else
-        subrange_count = bfrange_count;
-    bfrange_count -= subrange_count;
-    pdf_printf(pdf, "%i beginbfrange\n", subrange_count);
-    for (j = 0; j < subrange_count; j++) {
-        while (range_size[i] <= 1 && i < 65536)
-            i++;
-        assert(i < 65536);
-        pdf_printf(pdf, "<%04X> <%04X> <%s>\n", i, i + range_size[i] - 1,
-                   utf16be_str(gtab[i].code));
-        i += range_size[i];
-    }
-    pdf_printf(pdf, "endbfrange\n");
-    if (bfrange_count > 0)
-        goto write_bfrange;
-
-    /* write out bfchar */
-    i = 0;
-  write_bfchar:
-    if (bfchar_count > 100)
-        subrange_count = 100;
-    else
-        subrange_count = bfchar_count;
-    bfchar_count -= subrange_count;
-    pdf_printf(pdf, "%i beginbfchar\n", subrange_count);
-    for (j = 0; j < subrange_count; j++) {
-        while (i < 65536) {
-            if (range_size[i] > 1)
-                i += range_size[i];
-            else if (range_size[i] == 0)
-                i++;
-            else                /* |range_size[i] == 1| */
-                break;
-        }
-        assert(i < 65536 && gtab[i].code != UNI_UNDEF);
-        if (gtab[i].code == UNI_STRING || gtab[i].code == UNI_EXTRA_STRING) {
-            assert(gtab[i].unicode_seq != NULL);
-            pdf_printf(pdf, "<%04X> <%s>\n", i, gtab[i].unicode_seq);
-        } else
-            pdf_printf(pdf, "<%04X> <%s>\n", i, utf16be_str(gtab[i].code));
-        i++;
-    }
-    pdf_printf(pdf, "endbfchar\n");
-    if (bfchar_count > 0)
-        goto write_bfchar;
-
-    /* free strings allocated by |set_glyph_unicode()| */
-    for (i = 0; i < 65536; ++i) {
-        if (gtab[i].code == UNI_EXTRA_STRING)
-            xfree(gtab[i].unicode_seq);
-    }
-
-    pdf_printf(pdf, "endcmap\n"
-               "CMapName currentdict /CMap defineresource pop\n"
-               "end\n" "end\n" "%%%%EndResource\n" "%%%%EOF\n");
-    pdf_end_stream(pdf);
-    pdf_end_obj(pdf);
-    return objnum;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,569 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+the dvipdfmx project team <dvipdfmx at project.ktug.or.kr>
+Copyright 2006-2012 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#include "font/sfnt.h"
+#include "font/tt_table.h"
+#include "font/tt_glyf.h"
+#include "font/writettf.h"
+
+#define NUM_GLYPH_LIMIT        65534
+#define TABLE_DATA_ALLOC_SIZE  40960
+#define GLYPH_ARRAY_ALLOC_SIZE 256
+
+static USHORT find_empty_slot(struct tt_glyphs *g)
+{
+    USHORT gid;
+    for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
+        if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
+            break;
+    }
+    if (gid == NUM_GLYPH_LIMIT)
+        normal_error("ttf","no empty glyph slot available.");
+    return gid;
+}
+
+USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
+{
+    USHORT idx, new_gid = 0;
+    for (idx = 0; idx < g->num_glyphs; idx++) {
+        if (gid == g->gd[idx].ogid) {
+            new_gid = g->gd[idx].gid;
+            break;
+        }
+    }
+    return new_gid;
+}
+
+USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
+{
+    USHORT idx;
+    for (idx = 0; idx < g->num_glyphs; idx++) {
+        if (gid == g->gd[idx].gid)
+            break;
+    }
+    if (idx == g->num_glyphs)
+        idx = 0;
+    return idx;
+}
+
+USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
+{
+    if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
+        formatted_warning("ttf","slot %u already used", new_gid);
+    } else {
+        if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
+            normal_error("ttf","too many glyphs");
+
+        if (g->num_glyphs >= g->max_glyphs) {
+            g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
+            g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
+        }
+        g->gd[g->num_glyphs].gid = new_gid;
+        g->gd[g->num_glyphs].ogid = gid;
+        g->gd[g->num_glyphs].length = 0;
+        g->gd[g->num_glyphs].data = NULL;
+        g->used_slot[new_gid / 8] = (unsigned char) (g->used_slot[new_gid / 8] | (1 << (7 - (new_gid % 8))));
+        g->num_glyphs++;
+    }
+    if (new_gid > g->last_gid) {
+        g->last_gid = new_gid;
+    }
+    return new_gid;
+}
+
+/*tex Initialization */
+
+struct tt_glyphs *tt_build_init(void)
+{
+    struct tt_glyphs *g;
+    g = NEW(1, struct tt_glyphs);
+    g->num_glyphs = 0;
+    g->max_glyphs = 0;
+    g->last_gid = 0;
+    g->emsize = 1;
+    g->default_advh = 0;
+    g->default_tsb = 0;
+    g->gd = NULL;
+    g->used_slot = NEW(8192, unsigned char);
+    memset(g->used_slot, 0, 8192);
+    tt_add_glyph(g, 0, 0);
+    return g;
+}
+
+void tt_build_finish(struct tt_glyphs *g)
+{
+    if (g) {
+        if (g->gd) {
+            USHORT idx;
+            for (idx = 0; idx < g->num_glyphs; idx++) {
+                if (g->gd[idx].data)
+                    RELEASE(g->gd[idx].data);
+            }
+            RELEASE(g->gd);
+        }
+        if (g->used_slot)
+            RELEASE(g->used_slot);
+        RELEASE(g);
+    }
+}
+
+static int glyf_cmp(const void *v1, const void *v2)
+{
+    int cmp = 0;
+    const struct tt_glyph_desc *sv1, *sv2;
+    sv1 = (const struct tt_glyph_desc *) v1;
+    sv2 = (const struct tt_glyph_desc *) v2;
+    if (sv1->gid == sv2->gid)
+        cmp = 0;
+    else if (sv1->gid < sv2->gid)
+        cmp = -1;
+    else
+        cmp = 1;
+    return cmp;
+}
+
+int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
+{
+    char *hmtx_table_data = NULL, *loca_table_data = NULL;
+    char *glyf_table_data = NULL;
+    ULONG hmtx_table_size, loca_table_size, glyf_table_size, glyf_table_used;
+    /*tex Some information available from other \TRUETYPE\ table. */
+    struct tt_head_table *head = NULL;
+    struct tt_hhea_table *hhea = NULL;
+    struct tt_maxp_table *maxp = NULL;
+    struct tt_longMetrics *hmtx, *vmtx = NULL;
+    struct tt_os2__table *os2;
+    /*tex Something temporary: */
+    ULONG *location, offset;
+    long i;
+    /*tex Estimate the most frequently appeared width. */
+    USHORT *w_stat;
+    int tex_font = fd->tex_font;
+    int streamprovider = 0;
+    int callback_id = 0 ;
+    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
+        streamprovider = font_streamprovider(tex_font);
+        callback_id = callback_defined(glyph_stream_provider_callback);
+    }
+    if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+        normal_error("ttf","invalid font type");
+    if (g->num_glyphs > NUM_GLYPH_LIMIT)
+        normal_error("ttf","too many glyphs");
+    head = tt_read_head_table(sfont);
+    hhea = tt_read_hhea_table(sfont);
+    maxp = tt_read_maxp_table(sfont);
+    if (hhea->metricDataFormat != 0)
+        normal_error("ttf","unknown metricDataFormat");
+    g->emsize = head->unitsPerEm;
+    sfnt_locate_table(sfont, "hmtx");
+    hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+    os2 = tt_read_os2__table(sfont);
+    if (os2) {
+        g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+        g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+        /*tex |dvipdfmx| does this elsewhere! */
+        fd_cur->font_dim[STEMV_CODE].val =
+            (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
+    }
+    if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+        struct tt_vhea_table *vhea;
+        vhea = tt_read_vhea_table(sfont);
+        sfnt_locate_table(sfont, "vmtx");
+        vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics);
+        RELEASE(vhea);
+    } else {
+        vmtx = NULL;
+    }
+    sfnt_locate_table(sfont, "loca");
+    location = NEW(maxp->numGlyphs + 1, ULONG);
+    if (head->indexToLocFormat == 0) {
+        for (i = 0; i <= maxp->numGlyphs; i++)
+            location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+    } else if (head->indexToLocFormat == 1) {
+        for (i = 0; i <= maxp->numGlyphs; i++)
+            location[i] = sfnt_get_ulong(sfont);
+    } else {
+        normal_error("ttf","unknown IndexToLocFormat");
+    }
+    w_stat = NEW(g->emsize + 2, USHORT);
+    memset(w_stat, 0, (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
+    offset = sfnt_locate_table(sfont, "glyf");
+    /*tex
+
+        The |num_glyphs| may grow when composite glyph is found. A component of
+        glyph refered by a composite glyph is appended to |used_glyphs| if it is
+        not already registered in |used_glyphs|. Glyph programs of composite
+        glyphs are modified so that it correctly refer to new gid of their
+        components.
+    */
+    for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
+        USHORT gid;
+        ULONG loc, len;
+        BYTE *p, *endptr;
+        SHORT number_of_contours;
+        if (i >= g->num_glyphs)
+            break;
+        gid = g->gd[i].ogid;
+        if (gid >= maxp->numGlyphs)
+            formatted_error("ttf","invalid glyph index (gid %u)", gid);
+        loc = location[gid];
+        len = location[gid + 1] - loc;
+        g->gd[i].advw = hmtx[gid].advance;
+        g->gd[i].lsb = hmtx[gid].sideBearing;
+        if (vmtx) {
+            g->gd[i].advh = vmtx[gid].advance;
+            g->gd[i].tsb = vmtx[gid].sideBearing;
+        } else {
+            g->gd[i].advh = g->default_advh;
+            g->gd[i].tsb = g->default_tsb;
+        }
+        g->gd[i].length = len;
+        g->gd[i].data = NULL;
+        if (g->gd[i].advw <= g->emsize) {
+            w_stat[g->gd[i].advw]++;
+        } else {
+            /*tex It's larger than em. */
+            w_stat[g->emsize + 1]++;
+        }
+
+        if (len == 0) {
+            /*tex Does not contain any data. */
+            continue;
+        } else if (len < 10) {
+            formatted_error("ttf","invalid glyph data (gid %u)", gid);
+        }
+        /*tex There is no real need for this. */
+        g->gd[i].data = p = NEW(len, BYTE);
+        endptr = p + len;
+        sfnt_seek_set(sfont, (long) (offset + loc));
+        number_of_contours = sfnt_get_short(sfont);
+        p += sfnt_put_short(p, number_of_contours);
+        /* BoundingBox: FWord x 4 */
+        g->gd[i].llx = sfnt_get_short(sfont);
+        g->gd[i].lly = sfnt_get_short(sfont);
+        g->gd[i].urx = sfnt_get_short(sfont);
+        g->gd[i].ury = sfnt_get_short(sfont);
+        if (!vmtx) {
+            /*tex A fix: |vertOriginY == sTypeAscender| */
+            g->gd[i].tsb = (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+        }
+        p += sfnt_put_short(p, g->gd[i].llx);
+        p += sfnt_put_short(p, g->gd[i].lly);
+        p += sfnt_put_short(p, g->gd[i].urx);
+        p += sfnt_put_short(p, g->gd[i].ury);
+        /*tex Read evrything else. */
+        sfnt_read(p, (int) len - 10, sfont);
+        /*tex Fix GIDs of composite glyphs. */
+        if (number_of_contours < 0) {
+            USHORT flags, cgid, new_gid;
+            do {
+                if (p >= endptr)
+                    formatted_error("ttf","invalid glyph data (gid %u): %u bytes", gid, (unsigned int) len);
+                flags = (USHORT) (((*p) << 8) | *(p + 1));
+                p += 2;
+                cgid = (USHORT) (((*p) << 8) | *(p + 1));
+                if (cgid >= maxp->numGlyphs) {
+                    formatted_error("ttf","invalid gid (%u > %u) in composite glyph %u", cgid, maxp->numGlyphs, gid);
+                }
+                new_gid = tt_find_glyph(g, cgid);
+                if (new_gid == 0) {
+                    new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
+                }
+                p += sfnt_put_ushort(p, new_gid);
+                /*tex Just skip remaining part. */
+                p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
+                if (flags & WE_HAVE_A_SCALE) {
+                    /*tex |F2Dot14| */
+                    p += 2;
+                } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
+                    /*tex two times |F2Dot14| */
+                    p += 4;
+                } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+                    /*tex four times |F2Dot14| */
+                    p += 8;
+                }
+            } while (flags & MORE_COMPONENTS);
+            /*tex
+
+                TrueType instructions comes here. The call pattern is:
+
+                \starttyping
+                |length_of_instruction| (|ushort|)
+                instruction (|byte * length_of_instruction|)
+                \stoptyping
+
+             */
+        }
+    }
+    RELEASE(location);
+    RELEASE(hmtx);
+    if (vmtx) {
+        RELEASE(vmtx);
+    }
+    {
+        int max_count = -1;
+        g->dw = g->gd[0].advw;
+        for (i = 0; i < g->emsize + 1; i++) {
+            if (w_stat[i] > max_count) {
+                max_count = w_stat[i];
+                g->dw = (USHORT) i;
+            }
+        }
+    }
+    RELEASE(w_stat);
+    qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
+    {
+        USHORT prev, last_advw;
+        char *p, *q;
+        int padlen, num_hm_known;
+        glyf_table_size = 0UL;
+        num_hm_known = 0;
+        last_advw = g->gd[g->num_glyphs - 1].advw;
+        for (i = g->num_glyphs - 1; i >= 0; i--) {
+            padlen =
+                (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+            glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
+            if (!num_hm_known && last_advw != g->gd[i].advw) {
+                hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
+                num_hm_known = 1;
+            }
+        }
+        /*tex All advance widths are the same. */
+        if (!num_hm_known) {
+            hhea->numberOfHMetrics = 1;
+        }
+        hmtx_table_size = (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
+        /*tex
+
+            Choosing short format does not always give good result when
+            compressed. Sometimes increases size.
+
+        */
+        if (glyf_table_size < 0x20000UL) {
+            head->indexToLocFormat = 0;
+            loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
+        } else {
+            head->indexToLocFormat = 1;
+            loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
+        }
+        hmtx_table_data = p = NEW(hmtx_table_size, char);
+        loca_table_data = q = NEW(loca_table_size, char);
+        glyf_table_data = NEW(glyf_table_size, char);
+        glyf_table_used = 0;
+        offset = 0UL;
+        prev = 0;
+        for (i = 0; i < g->num_glyphs; i++) {
+            long gap, j;
+            gap = (long) g->gd[i].gid - prev - 1;
+            for (j = 1; j <= gap; j++) {
+                if (prev + j == hhea->numberOfHMetrics - 1) {
+                    p += sfnt_put_ushort(p, last_advw);
+                } else if (prev + j < hhea->numberOfHMetrics) {
+                    p += sfnt_put_ushort(p, 0);
+                }
+                p += sfnt_put_short(p, 0);
+                if (head->indexToLocFormat == 0) {
+                    q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+                } else {
+                    q += sfnt_put_ulong(q, (LONG) offset);
+                }
+            }
+            if (g->gd[i].gid < hhea->numberOfHMetrics) {
+                p += sfnt_put_ushort(p, g->gd[i].advw);
+            }
+            p += sfnt_put_short(p, g->gd[i].lsb);
+            if (head->indexToLocFormat == 0) {
+                q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+            } else {
+                q += sfnt_put_ulong(q, (LONG) offset);
+            }
+            if (callback_id > 0) {
+                lstring * result;
+                long size = 0;
+                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result);
+                padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
+                size = (size_t) result->l + (ULONG) padlen;
+                if (glyf_table_used + size >= glyf_table_size) {
+                    glyf_table_size = glyf_table_size + 20 * size; /* just a guess */
+                    glyf_table_data = xrealloc(glyf_table_data, (unsigned)((unsigned)glyf_table_size*sizeof(char)));
+                }
+                glyf_table_used += size;
+                memset(glyf_table_data + offset, 0, (size_t) size);
+                memcpy(glyf_table_data + offset, (const char *) result->s, (size_t) result->l);
+                offset += size;
+                xfree(result);
+            } else {
+                padlen = (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
+                memset(glyf_table_data + offset, 0, (size_t) (g->gd[i].length + (ULONG) padlen));
+                memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
+                offset += (g->gd[i].length + (ULONG) padlen);
+            }
+            prev = g->gd[i].gid;
+            RELEASE(g->gd[i].data);
+            /*tex We free data here since it consume much memory. */
+            g->gd[i].length = 0;
+            g->gd[i].data = NULL;
+        }
+        if (head->indexToLocFormat == 0) {
+            q += sfnt_put_ushort(q, (USHORT) (offset / 2));
+        } else {
+            q += sfnt_put_ulong(q, (LONG) offset);
+        }
+        sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
+        sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
+        if (callback_id > 0) {
+            glyf_table_size = glyf_table_used;
+        }
+        sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
+    }
+    head->checkSumAdjustment = 0;
+    maxp->numGlyphs = (USHORT) (g->last_gid + 1);
+    sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
+    sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
+    sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
+    RELEASE(maxp);
+    RELEASE(hhea);
+    RELEASE(head);
+    if (os2) {
+        RELEASE(os2);
+    }
+    return 0;
+}
+
+int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
+{
+    struct tt_head_table *head = NULL;
+    struct tt_hhea_table *hhea = NULL;
+    struct tt_maxp_table *maxp = NULL;
+    struct tt_longMetrics *hmtx, *vmtx = NULL;
+    struct tt_os2__table *os2;
+    ULONG *location, offset;
+    long i;
+    USHORT *w_stat;
+    if (sfont == NULL || sfont->buffer == NULL)
+        normal_error("ttf","file not opened");
+    if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
+        normal_error("ttf","invalid font type");
+    head = tt_read_head_table(sfont);
+    hhea = tt_read_hhea_table(sfont);
+    maxp = tt_read_maxp_table(sfont);
+    if (hhea->metricDataFormat != 0)
+        normal_error("ttf","unknown metricDataFormat");
+    g->emsize = head->unitsPerEm;
+    sfnt_locate_table(sfont, "hmtx");
+    hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
+    os2 = tt_read_os2__table(sfont);
+    g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
+    g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
+    if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
+        struct tt_vhea_table *vhea;
+        vhea = tt_read_vhea_table(sfont);
+        sfnt_locate_table(sfont, "vmtx");
+        vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics);
+        RELEASE(vhea);
+    } else {
+        vmtx = NULL;
+    }
+    sfnt_locate_table(sfont, "loca");
+    location = NEW(maxp->numGlyphs + 1, ULONG);
+    if (head->indexToLocFormat == 0) {
+        for (i = 0; i <= maxp->numGlyphs; i++)
+            location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
+    } else if (head->indexToLocFormat == 1) {
+        for (i = 0; i <= maxp->numGlyphs; i++)
+            location[i] = sfnt_get_ulong(sfont);
+    } else {
+        normal_error("ttf","inknown IndexToLocFormat");
+    }
+    w_stat = NEW(g->emsize + 2, USHORT);
+    memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
+    /*tex Read glyf table. */
+    offset = sfnt_locate_table(sfont, "glyf");
+    for (i = 0; i < g->num_glyphs; i++) {
+        USHORT gid;
+        ULONG loc, len;
+        gid = g->gd[i].ogid;
+        if (gid >= maxp->numGlyphs)
+            formatted_error("ttf","invalid glyph index (gid %u)", gid);
+        loc = location[gid];
+        len = location[gid + 1] - loc;
+        g->gd[i].advw = hmtx[gid].advance;
+        g->gd[i].lsb = hmtx[gid].sideBearing;
+        if (vmtx) {
+            g->gd[i].advh = vmtx[gid].advance;
+            g->gd[i].tsb = vmtx[gid].sideBearing;
+        } else {
+            g->gd[i].advh = g->default_advh;
+            g->gd[i].tsb = g->default_tsb;
+        }
+        g->gd[i].length = len;
+        g->gd[i].data = NULL;
+        if (g->gd[i].advw <= g->emsize) {
+            w_stat[g->gd[i].advw]++;
+        } else {
+            /*tex It's larger than em: */
+            w_stat[g->emsize + 1]++;
+        }
+        if (len == 0) {
+            /*tex No data. */
+            continue;
+        } else if (len < 10) {
+            formatted_error("ttf","invalid glyph data (gid %u)", gid);
+        }
+        sfnt_seek_set(sfont, (long) (offset + loc));
+        /*tex Skip the number of contours */
+        (void)sfnt_get_short(sfont);
+        /*tex Fetch the BoundingBox. */
+        g->gd[i].llx = sfnt_get_short(sfont);
+        g->gd[i].lly = sfnt_get_short(sfont);
+        g->gd[i].urx = sfnt_get_short(sfont);
+        g->gd[i].ury = sfnt_get_short(sfont);
+        if (!vmtx) {
+            /*tex We fix |vertOriginY == sTypeAscender|. */
+            g->gd[i].tsb = (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
+        }
+    }
+    RELEASE(location);
+    RELEASE(hmtx);
+    RELEASE(maxp);
+    RELEASE(hhea);
+    RELEASE(head);
+    RELEASE(os2);
+    if (vmtx) {
+        RELEASE(vmtx);
+    }
+    {
+        int max_count = -1;
+        g->dw = g->gd[0].advw;
+        for (i = 0; i < g->emsize + 1; i++) {
+            if (w_stat[i] > max_count) {
+                max_count = w_stat[i];
+                g->dw = (USHORT) i;
+            }
+        }
+    }
+    RELEASE(w_stat);
+    return 0;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_glyf.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,695 +0,0 @@
-% tt_glyf.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@* Subsetting glyf, updating loca, hmtx, etc.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-#include "font/sfnt.h"
-#include "font/tt_table.h"
-#include "font/tt_glyf.h"
-#include "font/writettf.h"
-
-@ @c
-#define NUM_GLYPH_LIMIT        65534
-#define TABLE_DATA_ALLOC_SIZE  40960
-#define GLYPH_ARRAY_ALLOC_SIZE 256
-
-static USHORT find_empty_slot(struct tt_glyphs *g)
-{
-    USHORT gid;
-
-    ASSERT(g);
-
-    for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
-        if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
-            break;
-    }
-    if (gid == NUM_GLYPH_LIMIT)
-        normal_error("ttf","no empty glyph slot available.");
-
-    return gid;
-}
-
-USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
-{
-    USHORT idx, new_gid = 0;
-
-    ASSERT(g);
-
-    for (idx = 0; idx < g->num_glyphs; idx++) {
-        if (gid == g->gd[idx].ogid) {
-            new_gid = g->gd[idx].gid;
-            break;
-        }
-    }
-
-    return new_gid;
-}
-
-USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
-{
-    USHORT idx;
-
-    ASSERT(g);
-
-    for (idx = 0; idx < g->num_glyphs; idx++) {
-        if (gid == g->gd[idx].gid)
-            break;
-    }
-    if (idx == g->num_glyphs)
-        idx = 0;
-
-    return idx;
-}
-
-USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
-{
-    ASSERT(g);
-
-    if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
-        formatted_warning("ttf","slot %u already used", new_gid);
-    } else {
-        if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
-            normal_error("ttf","too many glyphs");
-
-        if (g->num_glyphs >= g->max_glyphs) {
-            g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
-            g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
-        }
-        g->gd[g->num_glyphs].gid = new_gid;
-        g->gd[g->num_glyphs].ogid = gid;
-        g->gd[g->num_glyphs].length = 0;
-        g->gd[g->num_glyphs].data = NULL;
-        g->used_slot[new_gid / 8] =
-            (unsigned char) (g->used_slot[new_gid /
-                                          8] | (1 << (7 - (new_gid % 8))));
-        g->num_glyphs++;
-    }
-
-    if (new_gid > g->last_gid) {
-        g->last_gid = new_gid;
-    }
-
-    return new_gid;
-}
-
-
-@ Initialization
- at c
-struct tt_glyphs *tt_build_init(void)
-{
-    struct tt_glyphs *g;
-
-    g = NEW(1, struct tt_glyphs);
-
-    g->num_glyphs = 0;
-    g->max_glyphs = 0;
-    g->last_gid = 0;
-    g->emsize = 1;
-    g->default_advh = 0;
-    g->default_tsb = 0;
-    g->gd = NULL;
-    g->used_slot = NEW(8192, unsigned char);
-    memset(g->used_slot, 0, 8192);
-    tt_add_glyph(g, 0, 0);
-
-    return g;
-}
-
-void tt_build_finish(struct tt_glyphs *g)
-{
-    if (g) {
-        if (g->gd) {
-            USHORT idx;
-            for (idx = 0; idx < g->num_glyphs; idx++) {
-                if (g->gd[idx].data)
-                    RELEASE(g->gd[idx].data);
-            }
-            RELEASE(g->gd);
-        }
-        if (g->used_slot)
-            RELEASE(g->used_slot);
-        RELEASE(g);
-    }
-}
-
-static int glyf_cmp(const void *v1, const void *v2)
-{
-    int cmp = 0;
-    const struct tt_glyph_desc *sv1, *sv2;
-
-    sv1 = (const struct tt_glyph_desc *) v1;
-    sv2 = (const struct tt_glyph_desc *) v2;
-
-    if (sv1->gid == sv2->gid)
-        cmp = 0;
-    else if (sv1->gid < sv2->gid)
-        cmp = -1;
-    else
-        cmp = 1;
-
-    return cmp;
-}
-
-@ @c
-int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
-{
-    char *hmtx_table_data = NULL, *loca_table_data = NULL;
-    char *glyf_table_data = NULL;
-    ULONG hmtx_table_size, loca_table_size, glyf_table_size, glyf_table_used;
-    /* some information available from other TrueType table */
-    struct tt_head_table *head = NULL;
-    struct tt_hhea_table *hhea = NULL;
-    struct tt_maxp_table *maxp = NULL;
-    struct tt_longMetrics *hmtx, *vmtx = NULL;
-    struct tt_os2__table *os2;
-    /* temp */
-    ULONG *location, offset;
-    long i;
-    USHORT *w_stat;             /* Estimate most frequently appeared width */
-
-    int tex_font = fd->tex_font;
-    int streamprovider = 0;
-    int callback_id = 0 ;
-    if ((tex_font > 0) && (font_streamprovider(tex_font) == 2)) {
-        streamprovider = font_streamprovider(tex_font);
-        callback_id = callback_defined(glyph_stream_provider_callback);
-    }
-
-    ASSERT(g);
-
-    if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
-        normal_error("ttf","invalid font type");
-
-    if (g->num_glyphs > NUM_GLYPH_LIMIT)
-        normal_error("ttf","too many glyphs");
-
-    /*
-     Read head, hhea, maxp, loca:
-
-     unitsPerEm       --> head
-
-     numHMetrics      --> hhea
-
-     indexToLocFormat --> head
-
-     numGlyphs        --> maxp
-     */
-    head = tt_read_head_table(sfont);
-    hhea = tt_read_hhea_table(sfont);
-    maxp = tt_read_maxp_table(sfont);
-
-    if (hhea->metricDataFormat != 0)
-        normal_error("ttf","unknown metricDataFormat");
-
-    g->emsize = head->unitsPerEm;
-
-    sfnt_locate_table(sfont, "hmtx");
-    hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
-
-    os2 = tt_read_os2__table(sfont);
-    if (os2) {
-        g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
-        g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
-
-        /* dvipdfmx does this elsewhere! */
-        fd_cur->font_dim[STEMV_CODE].val =
-            (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
-    }
-
-    if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
-        struct tt_vhea_table *vhea;
-        vhea = tt_read_vhea_table(sfont);
-        sfnt_locate_table(sfont, "vmtx");
-        vmtx =
-            tt_read_longMetrics(sfont, maxp->numGlyphs,
-                                vhea->numOfLongVerMetrics);
-        RELEASE(vhea);
-    } else {
-        vmtx = NULL;
-    }
-
-    sfnt_locate_table(sfont, "loca");
-    location = NEW(maxp->numGlyphs + 1, ULONG);
-    if (head->indexToLocFormat == 0) {
-        for (i = 0; i <= maxp->numGlyphs; i++)
-            location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
-    } else if (head->indexToLocFormat == 1) {
-        for (i = 0; i <= maxp->numGlyphs; i++)
-            location[i] = sfnt_get_ulong(sfont);
-    } else {
-        normal_error("ttf","unknown IndexToLocFormat");
-    }
-
-    w_stat = NEW(g->emsize + 2, USHORT);
-    memset(w_stat, 0,
-           (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
-    /*
-     * Read glyf table.
-     */
-    offset = sfnt_locate_table(sfont, "glyf");
-    /*
-     The |num_glyphs| may grow when composite glyph is found.
-     A component of glyph refered by a composite glyph is appended
-     to |used_glyphs| if it is not already registered in |used_glyphs|.
-     Glyph programs of composite glyphs are modified so that it
-     correctly refer to new gid of their components.
-     */
-    for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
-        USHORT gid;             /* old gid */
-        ULONG loc, len;
-        BYTE *p, *endptr;
-        SHORT number_of_contours;
-
-        if (i >= g->num_glyphs) /* finished */
-            break;
-
-        gid = g->gd[i].ogid;
-        if (gid >= maxp->numGlyphs)
-            formatted_error("ttf","invalid glyph index (gid %u)", gid);
-
-        loc = location[gid];
-        len = location[gid + 1] - loc;
-        g->gd[i].advw = hmtx[gid].advance;
-        g->gd[i].lsb = hmtx[gid].sideBearing;
-        if (vmtx) {
-            g->gd[i].advh = vmtx[gid].advance;
-            g->gd[i].tsb = vmtx[gid].sideBearing;
-        } else {
-            g->gd[i].advh = g->default_advh;
-            g->gd[i].tsb = g->default_tsb;
-        }
-        g->gd[i].length = len;
-        g->gd[i].data = NULL;
-        if (g->gd[i].advw <= g->emsize) {
-            w_stat[g->gd[i].advw]++;
-        } else {
-            w_stat[g->emsize + 1]++;    /* larger than em */
-        }
-
-        if (len == 0) {         /* Does not contains any data. */
-            continue;
-        } else if (len < 10) {
-            formatted_error("ttf","invalid glyph data (gid %u)", gid);
-        }
-
-/* todo: no need for this */
-        g->gd[i].data = p = NEW(len, BYTE);
-        endptr = p + len;
-
-        sfnt_seek_set(sfont, (long) (offset + loc));
-        number_of_contours = sfnt_get_short(sfont);
-        p += sfnt_put_short(p, number_of_contours);
-
-        /* BoundingBox: FWord x 4 */
-        g->gd[i].llx = sfnt_get_short(sfont);
-        g->gd[i].lly = sfnt_get_short(sfont);
-        g->gd[i].urx = sfnt_get_short(sfont);
-        g->gd[i].ury = sfnt_get_short(sfont);
-        /* |_FIXME_| */
-#if  1
-        if (!vmtx)              /* |vertOriginY == sTypeAscender| */
-            g->gd[i].tsb =
-                (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
-        p += sfnt_put_short(p, g->gd[i].llx);
-        p += sfnt_put_short(p, g->gd[i].lly);
-        p += sfnt_put_short(p, g->gd[i].urx);
-        p += sfnt_put_short(p, g->gd[i].ury);
-
-        /* Read evrything else. */
-        sfnt_read(p, (int) len - 10, sfont);
-        /*
-         Fix GIDs of composite glyphs.
-         */
-        if (number_of_contours < 0) {
-            USHORT flags, cgid, new_gid;        /* flag, gid of a component */
-            do {
-                if (p >= endptr)
-                    formatted_error("ttf","invalid glyph data (gid %u): %u bytes", gid, (unsigned int) len);
-                /*
-                 * Flags and gid of component glyph are both USHORT.
-                 */
-                flags = (USHORT) (((*p) << 8) | *(p + 1));
-                p += 2;
-                cgid = (USHORT) (((*p) << 8) | *(p + 1));
-                if (cgid >= maxp->numGlyphs) {
-                    formatted_error("ttf","invalid gid (%u > %u) in composite glyph %u", cgid, maxp->numGlyphs, gid);
-                }
-                new_gid = tt_find_glyph(g, cgid);
-                if (new_gid == 0) {
-                    new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
-                }
-                p += sfnt_put_ushort(p, new_gid);
-                /*
-                 * Just skip remaining part.
-                 */
-                p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
-                if (flags & WE_HAVE_A_SCALE)    /* F2Dot14 */
-                    p += 2;
-                else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)      /* F2Dot14 x 2 */
-                    p += 4;
-                else if (flags & WE_HAVE_A_TWO_BY_TWO)  /* F2Dot14 x 4 */
-                    p += 8;
-            } while (flags & MORE_COMPONENTS);
-            /*
-             TrueType instructions comes here:
-
-             |length_of_instruction| (|ushort|)
-
-             instruction (|byte * length_of_instruction|)
-             */
-        }
-    }
-    RELEASE(location);
-    RELEASE(hmtx);
-    if (vmtx)
-        RELEASE(vmtx);
-
-    {
-        int max_count = -1;
-
-        g->dw = g->gd[0].advw;
-        for (i = 0; i < g->emsize + 1; i++) {
-            if (w_stat[i] > max_count) {
-                max_count = w_stat[i];
-                g->dw = (USHORT) i;
-            }
-        }
-    }
-    RELEASE(w_stat);
-
-    qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
-    {
-        USHORT prev, last_advw;
-        char *p, *q;
-        int padlen, num_hm_known;
-
-        glyf_table_size = 0UL;
-        num_hm_known = 0;
-        last_advw = g->gd[g->num_glyphs - 1].advw;
-        for (i = g->num_glyphs - 1; i >= 0; i--) {
-            padlen =
-                (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
-            glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
-            if (!num_hm_known && last_advw != g->gd[i].advw) {
-                hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
-                num_hm_known = 1;
-            }
-        }
-        /* All advance widths are same. */
-        if (!num_hm_known) {
-            hhea->numberOfHMetrics = 1;
-        }
-        hmtx_table_size =
-            (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
-
-        /*
-         Choosing short format does not always give good result
-         when compressed. Sometimes increases size.
-         */
-        if (glyf_table_size < 0x20000UL) {
-            head->indexToLocFormat = 0;
-            loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
-        } else {
-            head->indexToLocFormat = 1;
-            loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
-        }
-
-        hmtx_table_data = p = NEW(hmtx_table_size, char);
-        loca_table_data = q = NEW(loca_table_size, char);
-        glyf_table_data = NEW(glyf_table_size, char);
-        glyf_table_used = 0;
-
-        offset = 0UL;
-        prev = 0;
-        for (i = 0; i < g->num_glyphs; i++) {
-            long gap, j;
-            gap = (long) g->gd[i].gid - prev - 1;
-            for (j = 1; j <= gap; j++) {
-                if (prev + j == hhea->numberOfHMetrics - 1) {
-                    p += sfnt_put_ushort(p, last_advw);
-                } else if (prev + j < hhea->numberOfHMetrics) {
-                    p += sfnt_put_ushort(p, 0);
-                }
-                p += sfnt_put_short(p, 0);
-                if (head->indexToLocFormat == 0) {
-                    q += sfnt_put_ushort(q, (USHORT) (offset / 2));
-                } else {
-                    q += sfnt_put_ulong(q, (LONG) offset);
-                }
-            }
-            if (g->gd[i].gid < hhea->numberOfHMetrics) {
-                p += sfnt_put_ushort(p, g->gd[i].advw);
-            }
-            p += sfnt_put_short(p, g->gd[i].lsb);
-            if (head->indexToLocFormat == 0) {
-                q += sfnt_put_ushort(q, (USHORT) (offset / 2));
-            } else {
-                q += sfnt_put_ulong(q, (LONG) offset);
-            }
-
-            if (callback_id > 0) {
-
-                lstring * result;
-                long size = 0;
-                run_callback(callback_id, "ddd->L", tex_font, g->gd[i].gid, streamprovider, &result); /* this call can be sped up */
-                padlen = (int) ((result->l % 4) ? (4 - (result->l % 4)) : 0);
-                size = (size_t) result->l + (ULONG) padlen;
-                if (glyf_table_used + size >= glyf_table_size) {
-                    glyf_table_size = glyf_table_size + 20 * size; /* just a guess */
-                    glyf_table_data = xrealloc(glyf_table_data, (unsigned)((unsigned)glyf_table_size*sizeof(char)));
-                }
-                glyf_table_used += size;
-                memset(glyf_table_data + offset, 0, (size_t) size);
-                memcpy(glyf_table_data + offset, (const char *) result->s, (size_t) result->l);
-                offset += size;
-                xfree(result);
-
-            } else {
-
-                padlen = (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
-                memset(glyf_table_data + offset, 0, (size_t) (g->gd[i].length + (ULONG) padlen));
-                memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
-                offset += (g->gd[i].length + (ULONG) padlen);
-
-            }
-            prev = g->gd[i].gid;
-            RELEASE(g->gd[i].data);
-            /* free data here since it consume much memory */
-            g->gd[i].length = 0;
-            g->gd[i].data = NULL;
-        }
-        if (head->indexToLocFormat == 0) {
-            q += sfnt_put_ushort(q, (USHORT) (offset / 2));
-        } else {
-            q += sfnt_put_ulong(q, (LONG) offset);
-        }
-
-        sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
-        sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
-        if (callback_id > 0) {
-            glyf_table_size = glyf_table_used;
-        }
-        sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
-    }
-
-    head->checkSumAdjustment = 0;
-    maxp->numGlyphs = (USHORT) (g->last_gid + 1);
-
-    /* TODO */
-    sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
-    sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
-    sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
-    RELEASE(maxp);
-    RELEASE(hhea);
-    RELEASE(head);
-    if (os2)
-        RELEASE(os2);
-
-    return 0;
-}
-
-int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
-{
-    struct tt_head_table *head = NULL;
-    struct tt_hhea_table *hhea = NULL;
-    struct tt_maxp_table *maxp = NULL;
-    struct tt_longMetrics *hmtx, *vmtx = NULL;
-    struct tt_os2__table *os2;
-    /* temp */
-    ULONG *location, offset;
-    long i;
-    USHORT *w_stat;
-
-    ASSERT(g);
-
-    if (sfont == NULL ||
-#ifdef XETEX
-        sfont->ft_face == NULL
-#elif defined(pdfTeX)
-        sfont->buffer == NULL
-#else
-        sfont->stream == NULL
-#endif
-        )
-        normal_error("ttf","file not opened");
-
-    if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
-        normal_error("ttf","invalid font type");
-
-    /*
-     Read head, hhea, maxp, loca:
-
-     unitsPerEm       --> head
-
-     numHMetrics      --> hhea
-
-     indexToLocFormat --> head
-
-     numGlyphs        --> maxp
-     */
-    head = tt_read_head_table(sfont);
-    hhea = tt_read_hhea_table(sfont);
-    maxp = tt_read_maxp_table(sfont);
-
-    if (hhea->metricDataFormat != 0)
-        normal_error("ttf","unknown metricDataFormat");
-
-    g->emsize = head->unitsPerEm;
-
-    sfnt_locate_table(sfont, "hmtx");
-    hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
-
-    os2 = tt_read_os2__table(sfont);
-    g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
-    g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
-
-    if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
-        struct tt_vhea_table *vhea;
-        vhea = tt_read_vhea_table(sfont);
-        sfnt_locate_table(sfont, "vmtx");
-        vmtx =
-            tt_read_longMetrics(sfont, maxp->numGlyphs,
-                                vhea->numOfLongVerMetrics);
-        RELEASE(vhea);
-    } else {
-        vmtx = NULL;
-    }
-
-    sfnt_locate_table(sfont, "loca");
-    location = NEW(maxp->numGlyphs + 1, ULONG);
-    if (head->indexToLocFormat == 0) {
-        for (i = 0; i <= maxp->numGlyphs; i++)
-            location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
-    } else if (head->indexToLocFormat == 1) {
-        for (i = 0; i <= maxp->numGlyphs; i++)
-            location[i] = sfnt_get_ulong(sfont);
-    } else {
-        normal_error("ttf","inknown IndexToLocFormat");
-    }
-
-    w_stat = NEW(g->emsize + 2, USHORT);
-    memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
-    /*
-     Read glyf table.
-     */
-    offset = sfnt_locate_table(sfont, "glyf");
-    for (i = 0; i < g->num_glyphs; i++) {
-        USHORT gid;             /* old gid */
-        ULONG loc, len;
-        /*SHORT number_of_contours;*/
-
-        gid = g->gd[i].ogid;
-        if (gid >= maxp->numGlyphs)
-            formatted_error("ttf","invalid glyph index (gid %u)", gid);
-
-        loc = location[gid];
-        len = location[gid + 1] - loc;
-        g->gd[i].advw = hmtx[gid].advance;
-        g->gd[i].lsb = hmtx[gid].sideBearing;
-        if (vmtx) {
-            g->gd[i].advh = vmtx[gid].advance;
-            g->gd[i].tsb = vmtx[gid].sideBearing;
-        } else {
-            g->gd[i].advh = g->default_advh;
-            g->gd[i].tsb = g->default_tsb;
-        }
-        g->gd[i].length = len;
-        g->gd[i].data = NULL;
-
-        if (g->gd[i].advw <= g->emsize) {
-            w_stat[g->gd[i].advw]++;
-        } else {
-            w_stat[g->emsize + 1]++;    /* larger than em */
-        }
-
-        if (len == 0) {         /* Does not contains any data. */
-            continue;
-        } else if (len < 10) {
-            formatted_error("ttf","invalid glyph data (gid %u)", gid);
-        }
-
-        sfnt_seek_set(sfont, (long) (offset + loc));
-        /*number_of_contours = */(void)sfnt_get_short(sfont);
-
-        /* BoundingBox: FWord x 4 */
-        g->gd[i].llx = sfnt_get_short(sfont);
-        g->gd[i].lly = sfnt_get_short(sfont);
-        g->gd[i].urx = sfnt_get_short(sfont);
-        g->gd[i].ury = sfnt_get_short(sfont);
-        /* |_FIXME_| */
-#if  1
-        if (!vmtx)              /* |vertOriginY == sTypeAscender| */
-            g->gd[i].tsb =
-                (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
-    }
-    RELEASE(location);
-    RELEASE(hmtx);
-    RELEASE(maxp);
-    RELEASE(hhea);
-    RELEASE(head);
-    RELEASE(os2);
-
-    if (vmtx)
-        RELEASE(vmtx);
-
-    {
-        int max_count = -1;
-
-        g->dw = g->gd[0].advw;
-        for (i = 0; i < g->emsize + 1; i++) {
-            if (w_stat[i] > max_count) {
-                max_count = w_stat[i];
-                g->dw = (USHORT) i;
-            }
-        }
-    }
-    RELEASE(w_stat);
-
-
-    return 0;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_table.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,404 @@
+/*
+
+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project
+    team <dvipdfmx at project.ktug.or.kr>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <stdio.h>
+#include "font/sfnt.h"
+#include "font/tt_table.h"
+
+/*tex
+
+    Tables contain information referred by other tables.
+
+*/
+
+char *tt_pack_head_table(struct tt_head_table *table)
+{
+    int i;
+    char *p, *data;
+    if (table == NULL)
+        normal_error("ttf","passed NULL pointer");
+    p = data = NEW(TT_HEAD_TABLE_SIZE, char);
+    p += sfnt_put_ulong(p, (LONG) table->version);
+    p += sfnt_put_ulong(p, (LONG) table->fontRevision);
+    p += sfnt_put_ulong(p, (LONG) table->checkSumAdjustment);
+    p += sfnt_put_ulong(p, (LONG) table->magicNumber);
+    p += sfnt_put_ushort(p, table->flags);
+    p += sfnt_put_ushort(p, table->unitsPerEm);
+    for (i = 0; i < 8; i++) {
+        *(p++) = (char) (table->created)[i];
+    }
+    for (i = 0; i < 8; i++) {
+        *(p++) = (char) (table->modified)[i];
+    }
+    p += sfnt_put_short(p, table->xMin);
+    p += sfnt_put_short(p, table->yMin);
+    p += sfnt_put_short(p, table->xMax);
+    p += sfnt_put_short(p, table->yMax);
+    p += sfnt_put_ushort(p, table->macStyle);
+    p += sfnt_put_ushort(p, table->lowestRecPPEM);
+    p += sfnt_put_short(p, table->fontDirectionHint);
+    p += sfnt_put_short(p, table->indexToLocFormat);
+    p += sfnt_put_short(p, table->glyphDataFormat);
+    return data;
+}
+
+struct tt_head_table *tt_read_head_table(sfnt * sfont)
+{
+    int i;
+    struct tt_head_table *table = NULL;
+    table = NEW(1, struct tt_head_table);
+    sfnt_locate_table(sfont, "head");
+    table->version = sfnt_get_ulong(sfont);
+    table->fontRevision = sfnt_get_ulong(sfont);
+    table->checkSumAdjustment = sfnt_get_ulong(sfont);
+    table->magicNumber = sfnt_get_ulong(sfont);
+    table->flags = sfnt_get_ushort(sfont);
+    table->unitsPerEm = sfnt_get_ushort(sfont);
+    for (i = 0; i < 8; i++) {
+        (table->created)[i] = sfnt_get_byte(sfont);
+    }
+    for (i = 0; i < 8; i++) {
+        (table->modified)[i] = sfnt_get_byte(sfont);
+    }
+    table->xMin = sfnt_get_short(sfont);
+    table->yMin = sfnt_get_short(sfont);
+    table->xMax = sfnt_get_short(sfont);
+    table->yMax = sfnt_get_short(sfont);
+    table->macStyle = (USHORT) sfnt_get_short(sfont);
+    table->lowestRecPPEM = (USHORT) sfnt_get_short(sfont);
+    table->fontDirectionHint = sfnt_get_short(sfont);
+    table->indexToLocFormat = sfnt_get_short(sfont);
+    table->glyphDataFormat = sfnt_get_short(sfont);
+    return table;
+}
+
+char *tt_pack_maxp_table(struct tt_maxp_table *table)
+{
+    char *p, *data;
+    p = data = NEW(TT_MAXP_TABLE_SIZE, char);
+    p += sfnt_put_ulong(p, (LONG) table->version);
+    p += sfnt_put_ushort(p, table->numGlyphs);
+    p += sfnt_put_ushort(p, table->maxPoints);
+    p += sfnt_put_ushort(p, table->maxContours);
+    p += sfnt_put_ushort(p, table->maxComponentPoints);
+    p += sfnt_put_ushort(p, table->maxComponentContours);
+    p += sfnt_put_ushort(p, table->maxZones);
+    p += sfnt_put_ushort(p, table->maxTwilightPoints);
+    p += sfnt_put_ushort(p, table->maxStorage);
+    p += sfnt_put_ushort(p, table->maxFunctionDefs);
+    p += sfnt_put_ushort(p, table->maxInstructionDefs);
+    p += sfnt_put_ushort(p, table->maxStackElements);
+    p += sfnt_put_ushort(p, table->maxSizeOfInstructions);
+    p += sfnt_put_ushort(p, table->maxComponentElements);
+    p += sfnt_put_ushort(p, table->maxComponentDepth);
+    return data;
+}
+
+struct tt_maxp_table *tt_read_maxp_table(sfnt * sfont)
+{
+    struct tt_maxp_table *table = NULL;
+    table = NEW(1, struct tt_maxp_table);
+    sfnt_locate_table(sfont, "maxp");
+    table->version = sfnt_get_ulong(sfont);
+    table->numGlyphs = sfnt_get_ushort(sfont);
+    table->maxPoints = sfnt_get_ushort(sfont);
+    table->maxContours = sfnt_get_ushort(sfont);
+    table->maxComponentPoints = sfnt_get_ushort(sfont);
+    table->maxComponentContours = sfnt_get_ushort(sfont);
+    table->maxZones = sfnt_get_ushort(sfont);
+    table->maxTwilightPoints = sfnt_get_ushort(sfont);
+    table->maxStorage = sfnt_get_ushort(sfont);
+    table->maxFunctionDefs = sfnt_get_ushort(sfont);
+    table->maxInstructionDefs = sfnt_get_ushort(sfont);
+    table->maxStackElements = sfnt_get_ushort(sfont);
+    table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
+    table->maxComponentElements = sfnt_get_ushort(sfont);
+    table->maxComponentDepth = sfnt_get_ushort(sfont);
+    return table;
+}
+
+char *tt_pack_hhea_table(struct tt_hhea_table *table)
+{
+    int i;
+    char *p, *data;
+    p = data = NEW(TT_HHEA_TABLE_SIZE, char);
+    p += sfnt_put_ulong(p, (LONG) table->version);
+    p += sfnt_put_short(p, table->Ascender);
+    p += sfnt_put_short(p, table->Descender);
+    p += sfnt_put_short(p, table->LineGap);
+    p += sfnt_put_ushort(p, table->advanceWidthMax);
+    p += sfnt_put_short(p, table->minLeftSideBearing);
+    p += sfnt_put_short(p, table->minRightSideBearing);
+    p += sfnt_put_short(p, table->xMaxExtent);
+    p += sfnt_put_short(p, table->caretSlopeRise);
+    p += sfnt_put_short(p, table->caretSlopeRun);
+    for (i = 0; i < 5; i++) {
+        p += sfnt_put_short(p, table->reserved[i]);
+    }
+    p += sfnt_put_short(p, table->metricDataFormat);
+    p += sfnt_put_ushort(p, table->numberOfHMetrics);
+    return data;
+}
+
+struct tt_hhea_table *tt_read_hhea_table(sfnt * sfont)
+{
+    int i;
+    struct tt_hhea_table *table = NULL;
+    table = NEW(1, struct tt_hhea_table);
+    sfnt_locate_table(sfont, "hhea");
+    table->version = sfnt_get_ulong(sfont);
+    table->Ascender = sfnt_get_short(sfont);
+    table->Descender = sfnt_get_short(sfont);
+    table->LineGap = sfnt_get_short(sfont);
+    table->advanceWidthMax = sfnt_get_ushort(sfont);
+    table->minLeftSideBearing = sfnt_get_short(sfont);
+    table->minRightSideBearing = sfnt_get_short(sfont);
+    table->xMaxExtent = sfnt_get_short(sfont);
+    table->caretSlopeRise = sfnt_get_short(sfont);
+    table->caretSlopeRun = sfnt_get_short(sfont);
+    for (i = 0; i < 5; i++) {
+        table->reserved[i] = sfnt_get_short(sfont);
+    }
+    table->metricDataFormat = sfnt_get_short(sfont);
+    if (table->metricDataFormat != 0)
+        normal_error("ttf","unknown metricDaraFormat");
+    table->numberOfHMetrics = sfnt_get_ushort(sfont);
+    return table;
+}
+
+char *tt_pack_vhea_table(struct tt_vhea_table *table)
+{
+    int i;
+    char *p, *data;
+    p = data = NEW(TT_VHEA_TABLE_SIZE, char);
+    p += sfnt_put_ulong(p, (LONG) table->version);
+    p += sfnt_put_short(p, table->vertTypoAscender);
+    p += sfnt_put_short(p, table->vertTypoDescender);
+    p += sfnt_put_short(p, table->vertTypoLineGap);
+    p += sfnt_put_short(p, table->advanceHeightMax);
+    p += sfnt_put_short(p, table->minTopSideBearing);
+    p += sfnt_put_short(p, table->minBottomSideBearing);
+    p += sfnt_put_short(p, table->yMaxExtent);
+    p += sfnt_put_short(p, table->caretSlopeRise);
+    p += sfnt_put_short(p, table->caretSlopeRun);
+    p += sfnt_put_short(p, table->caretOffset);
+    for (i = 0; i < 5; i++) {
+        p += sfnt_put_short(p, table->reserved[i]);
+    }
+    p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
+    return data;
+}
+
+struct tt_vhea_table *tt_read_vhea_table(sfnt * sfont)
+{
+    int i;
+    struct tt_vhea_table *table = NULL;
+    table = NEW(1, struct tt_vhea_table);
+    sfnt_locate_table(sfont, "vhea");
+    table->version = sfnt_get_ulong(sfont);
+    table->vertTypoAscender = sfnt_get_short(sfont);
+    table->vertTypoDescender = sfnt_get_short(sfont);
+    table->vertTypoLineGap = sfnt_get_short(sfont);
+    table->advanceHeightMax = sfnt_get_short(sfont);
+    table->minTopSideBearing = sfnt_get_short(sfont);
+    table->minBottomSideBearing = sfnt_get_short(sfont);
+    table->yMaxExtent = sfnt_get_short(sfont);
+    table->caretSlopeRise = sfnt_get_short(sfont);
+    table->caretSlopeRun = sfnt_get_short(sfont);
+    table->caretOffset = sfnt_get_short(sfont);
+    for (i = 0; i < 5; i++) {
+        (table->reserved)[i] = sfnt_get_short(sfont);
+    }
+    table->numOfLongVerMetrics = sfnt_get_ushort(sfont);
+    return table;
+}
+
+struct tt_VORG_table *tt_read_VORG_table(sfnt * sfont)
+{
+    struct tt_VORG_table *vorg;
+    ULONG offset;
+    USHORT i;
+    offset = sfnt_find_table_pos(sfont, "VORG");
+    if (offset > 0) {
+        vorg = NEW(1, struct tt_VORG_table);
+        sfnt_locate_table(sfont, "VORG");
+        if (sfnt_get_ushort(sfont) != 1 || sfnt_get_ushort(sfont) != 0)
+            normal_error("ttf","unsupported VORG version");
+        vorg->defaultVertOriginY = sfnt_get_short(sfont);
+        vorg->numVertOriginYMetrics = sfnt_get_ushort(sfont);
+        vorg->vertOriginYMetrics = NEW(vorg->numVertOriginYMetrics, struct tt_vertOriginYMetrics);
+        /*tex
+            The |vertOriginYMetrics| array must be sorted in increasing |glyphIndex| order.
+        */
+        for (i = 0; i < vorg->numVertOriginYMetrics; i++) {
+            vorg->vertOriginYMetrics[i].glyphIndex = sfnt_get_ushort(sfont);
+            vorg->vertOriginYMetrics[i].vertOriginY = sfnt_get_short(sfont);
+        }
+    } else {
+        vorg = NULL;
+    }
+    return vorg;
+}
+
+/*tex
+
+    Reading and writing |hmtx| and |vmtx| depends on other tables, like |maxp|,
+    |hhea| and |vhea|.
+
+*/
+
+struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs, USHORT numLongMetrics)
+{
+    struct tt_longMetrics *m;
+    USHORT gid, last_adv = 0;
+    m = NEW(numGlyphs, struct tt_longMetrics);
+    for (gid = 0; gid < numGlyphs; gid++) {
+        if (gid < numLongMetrics)
+            last_adv = sfnt_get_ushort(sfont);
+        m[gid].sideBearing = sfnt_get_short(sfont);
+        m[gid].advance = last_adv;
+    }
+    return m;
+}
+
+/*tex
+
+    The |OS/2| table may not exist.
+
+*/
+
+struct tt_os2__table *tt_read_os2__table(sfnt * sfont)
+{
+    struct tt_os2__table *table = NULL;
+    int i;
+    if (sfnt_find_table_pos(sfont, "OS/2") == 0)
+        return NULL;
+    sfnt_locate_table(sfont, "OS/2");
+    table = NEW(1, struct tt_os2__table);
+    table->version = sfnt_get_ushort(sfont);
+    table->xAvgCharWidth = sfnt_get_short(sfont);
+    table->usWeightClass = sfnt_get_ushort(sfont);
+    table->usWidthClass = sfnt_get_ushort(sfont);
+    table->fsType = sfnt_get_short(sfont);
+    table->ySubscriptXSize = sfnt_get_short(sfont);
+    table->ySubscriptYSize = sfnt_get_short(sfont);
+    table->ySubscriptXOffset = sfnt_get_short(sfont);
+    table->ySubscriptYOffset = sfnt_get_short(sfont);
+    table->ySuperscriptXSize = sfnt_get_short(sfont);
+    table->ySuperscriptYSize = sfnt_get_short(sfont);
+    table->ySuperscriptXOffset = sfnt_get_short(sfont);
+    table->ySuperscriptYOffset = sfnt_get_short(sfont);
+    table->yStrikeoutSize = sfnt_get_short(sfont);
+    table->yStrikeoutPosition = sfnt_get_short(sfont);
+    table->sFamilyClass = sfnt_get_short(sfont);
+    for (i = 0; i < 10; i++) {
+        table->panose[i] = sfnt_get_byte(sfont);
+    }
+    table->ulUnicodeRange1 = sfnt_get_ulong(sfont);
+    table->ulUnicodeRange2 = sfnt_get_ulong(sfont);
+    table->ulUnicodeRange3 = sfnt_get_ulong(sfont);
+    table->ulUnicodeRange4 = sfnt_get_ulong(sfont);
+    for (i = 0; i < 4; i++) {
+        table->achVendID[i] = sfnt_get_char(sfont);
+    }
+    table->fsSelection = sfnt_get_ushort(sfont);
+    table->usFirstCharIndex = sfnt_get_ushort(sfont);
+    table->usLastCharIndex = sfnt_get_ushort(sfont);
+    table->sTypoAscender = sfnt_get_short(sfont);
+    table->sTypoDescender = sfnt_get_short(sfont);
+    table->sTypoLineGap = sfnt_get_short(sfont);
+    table->usWinAscent = sfnt_get_ushort(sfont);
+    table->usWinDescent = sfnt_get_ushort(sfont);
+    table->ulCodePageRange1 = sfnt_get_ulong(sfont);
+    table->ulCodePageRange2 = sfnt_get_ulong(sfont);
+    if (table->version == 0x0002) {
+        table->sxHeight = sfnt_get_short(sfont);
+        table->sCapHeight = sfnt_get_short(sfont);
+        table->usDefaultChar = sfnt_get_ushort(sfont);
+        table->usBreakChar = sfnt_get_ushort(sfont);
+        table->usMaxContext = sfnt_get_ushort(sfont);
+    }
+    return table;
+}
+
+USHORT tt_get_name(sfnt * sfont, char *dest, USHORT destlen,
+            USHORT plat_id, USHORT enco_id, USHORT lang_id, USHORT name_id)
+{
+    USHORT length = 0;
+    USHORT num_names, string_offset;
+    ULONG name_offset;
+    int i;
+    name_offset = sfnt_locate_table(sfont, "name");
+    if (sfnt_get_ushort(sfont))
+        normal_error("ttf","expecting zero");
+    num_names = sfnt_get_ushort(sfont);
+    string_offset = sfnt_get_ushort(sfont);
+    for (i = 0; i < num_names; i++) {
+        USHORT p_id, e_id, n_id, l_id;
+        USHORT offset;
+        p_id = sfnt_get_ushort(sfont);
+        e_id = sfnt_get_ushort(sfont);
+        l_id = sfnt_get_ushort(sfont);
+        n_id = sfnt_get_ushort(sfont);
+        length = sfnt_get_ushort(sfont);
+        offset = sfnt_get_ushort(sfont);
+        /*tex The language |ID| value |0xffffu| stands for ``accept any language ID''. */
+        if ((p_id == plat_id) && (e_id == enco_id) &&
+            (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) {
+            if (length > destlen - 1) {
+                normal_warning("ttf","truncating a very long name");
+                length = (USHORT) (destlen - 1);
+            }
+            sfnt_seek_set(sfont, (long) (name_offset + string_offset + offset));
+            sfnt_read((unsigned char *) dest, length, sfont);
+            dest[length] = '\0';
+            break;
+        }
+    }
+    if (i == num_names) {
+        length = 0;
+    }
+    return length;
+}
+
+USHORT tt_get_ps_fontname(sfnt * sfont, char *dest, USHORT destlen)
+{
+    USHORT namelen = 0;
+    /*tex First try Mac-Roman PS name and then Win-Unicode PS name. */
+    if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 6)) != 0 ||
+        (namelen = tt_get_name(sfont, dest, destlen, 3, 1, 0x409u, 6)) != 0 ||
+        (namelen = tt_get_name(sfont, dest, destlen, 3, 5, 0x412u, 6)) != 0)
+        return namelen;
+    normal_warning("ttf","no valid PostScript name available");
+    /*tex
+        This is a workaround for some bad TTfonts: the language ID value |0xffffu|
+        indicates ``accept any language ID''.
+    */
+    if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0xffffu, 6)) == 0) {
+        /*tex
+            Finally we're falling back to Mac Roman name field. Some bad Japanese TTfonts
+            using SJIS encoded string in the Mac Roman name field.
+        */
+        namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 1);
+    }
+    return namelen;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/tt_table.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,460 +0,0 @@
-% tt_table.w
-%
-% Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
-% the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-#include <stdio.h>
-#include "font/sfnt.h"
-#include "font/tt_table.h"
-
-@ tables contains information refered by other tables
-
-  |maxp->numGlyphs, etc --> loca, etc|
-
-  |hhea->numberOfHMetrics --> hmtx|
-
-  |head->indexToLocFormat --> loca|
-
-  |head->glyphDataFormat --> glyf|
-
- at c
-char *tt_pack_head_table(struct tt_head_table *table)
-{
-    int i;
-    char *p, *data;
-
-    if (table == NULL)
-        normal_error("ttf","passed NULL pointer");
-
-    p = data = NEW(TT_HEAD_TABLE_SIZE, char);
-    p += sfnt_put_ulong(p, (LONG) table->version);
-    p += sfnt_put_ulong(p, (LONG) table->fontRevision);
-    p += sfnt_put_ulong(p, (LONG) table->checkSumAdjustment);
-    p += sfnt_put_ulong(p, (LONG) table->magicNumber);
-    p += sfnt_put_ushort(p, table->flags);
-    p += sfnt_put_ushort(p, table->unitsPerEm);
-    for (i = 0; i < 8; i++) {
-        *(p++) = (char) (table->created)[i];
-    }
-    for (i = 0; i < 8; i++) {
-        *(p++) = (char) (table->modified)[i];
-    }
-    p += sfnt_put_short(p, table->xMin);
-    p += sfnt_put_short(p, table->yMin);
-    p += sfnt_put_short(p, table->xMax);
-    p += sfnt_put_short(p, table->yMax);
-    p += sfnt_put_ushort(p, table->macStyle);
-    p += sfnt_put_ushort(p, table->lowestRecPPEM);
-    p += sfnt_put_short(p, table->fontDirectionHint);
-    p += sfnt_put_short(p, table->indexToLocFormat);
-    p += sfnt_put_short(p, table->glyphDataFormat);
-
-    return data;
-}
-
-struct tt_head_table *tt_read_head_table(sfnt * sfont)
-{
-    int i;
-    struct tt_head_table *table = NULL;
-
-    table = NEW(1, struct tt_head_table);
-
-    sfnt_locate_table(sfont, "head");
-
-    table->version = sfnt_get_ulong(sfont);
-    table->fontRevision = sfnt_get_ulong(sfont);
-    table->checkSumAdjustment = sfnt_get_ulong(sfont);
-    table->magicNumber = sfnt_get_ulong(sfont);
-    table->flags = sfnt_get_ushort(sfont);
-    table->unitsPerEm = sfnt_get_ushort(sfont);
-    for (i = 0; i < 8; i++) {
-        (table->created)[i] = sfnt_get_byte(sfont);
-    }
-    for (i = 0; i < 8; i++) {
-        (table->modified)[i] = sfnt_get_byte(sfont);
-    }
-    table->xMin = sfnt_get_short(sfont);
-    table->yMin = sfnt_get_short(sfont);
-    table->xMax = sfnt_get_short(sfont);
-    table->yMax = sfnt_get_short(sfont);
-    table->macStyle = (USHORT) sfnt_get_short(sfont);
-    table->lowestRecPPEM = (USHORT) sfnt_get_short(sfont);
-    table->fontDirectionHint = sfnt_get_short(sfont);
-    table->indexToLocFormat = sfnt_get_short(sfont);
-    table->glyphDataFormat = sfnt_get_short(sfont);
-
-    return table;
-}
-
-char *tt_pack_maxp_table(struct tt_maxp_table *table)
-{
-    char *p, *data;
-
-    p = data = NEW(TT_MAXP_TABLE_SIZE, char);
-    p += sfnt_put_ulong(p, (LONG) table->version);
-    p += sfnt_put_ushort(p, table->numGlyphs);
-    p += sfnt_put_ushort(p, table->maxPoints);
-    p += sfnt_put_ushort(p, table->maxContours);
-    p += sfnt_put_ushort(p, table->maxComponentPoints);
-    p += sfnt_put_ushort(p, table->maxComponentContours);
-    p += sfnt_put_ushort(p, table->maxZones);
-    p += sfnt_put_ushort(p, table->maxTwilightPoints);
-    p += sfnt_put_ushort(p, table->maxStorage);
-    p += sfnt_put_ushort(p, table->maxFunctionDefs);
-    p += sfnt_put_ushort(p, table->maxInstructionDefs);
-    p += sfnt_put_ushort(p, table->maxStackElements);
-    p += sfnt_put_ushort(p, table->maxSizeOfInstructions);
-    p += sfnt_put_ushort(p, table->maxComponentElements);
-    p += sfnt_put_ushort(p, table->maxComponentDepth);
-
-    return data;
-}
-
-struct tt_maxp_table *tt_read_maxp_table(sfnt * sfont)
-{
-    struct tt_maxp_table *table = NULL;
-
-    table = NEW(1, struct tt_maxp_table);
-
-    sfnt_locate_table(sfont, "maxp");
-    table->version = sfnt_get_ulong(sfont);
-    table->numGlyphs = sfnt_get_ushort(sfont);
-    table->maxPoints = sfnt_get_ushort(sfont);
-    table->maxContours = sfnt_get_ushort(sfont);
-    table->maxComponentPoints = sfnt_get_ushort(sfont);
-    table->maxComponentContours = sfnt_get_ushort(sfont);
-    table->maxZones = sfnt_get_ushort(sfont);
-    table->maxTwilightPoints = sfnt_get_ushort(sfont);
-    table->maxStorage = sfnt_get_ushort(sfont);
-    table->maxFunctionDefs = sfnt_get_ushort(sfont);
-    table->maxInstructionDefs = sfnt_get_ushort(sfont);
-    table->maxStackElements = sfnt_get_ushort(sfont);
-    table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
-    table->maxComponentElements = sfnt_get_ushort(sfont);
-    table->maxComponentDepth = sfnt_get_ushort(sfont);
-
-    return table;
-}
-
-char *tt_pack_hhea_table(struct tt_hhea_table *table)
-{
-    int i;
-    char *p, *data;
-
-    p = data = NEW(TT_HHEA_TABLE_SIZE, char);
-    p += sfnt_put_ulong(p, (LONG) table->version);
-    p += sfnt_put_short(p, table->Ascender);
-    p += sfnt_put_short(p, table->Descender);
-    p += sfnt_put_short(p, table->LineGap);
-    p += sfnt_put_ushort(p, table->advanceWidthMax);
-    p += sfnt_put_short(p, table->minLeftSideBearing);
-    p += sfnt_put_short(p, table->minRightSideBearing);
-    p += sfnt_put_short(p, table->xMaxExtent);
-    p += sfnt_put_short(p, table->caretSlopeRise);
-    p += sfnt_put_short(p, table->caretSlopeRun);
-    for (i = 0; i < 5; i++) {
-        p += sfnt_put_short(p, table->reserved[i]);
-    }
-    p += sfnt_put_short(p, table->metricDataFormat);
-    p += sfnt_put_ushort(p, table->numberOfHMetrics);
-
-    return data;
-}
-
-struct tt_hhea_table *tt_read_hhea_table(sfnt * sfont)
-{
-    int i;
-    struct tt_hhea_table *table = NULL;
-
-    table = NEW(1, struct tt_hhea_table);
-
-    sfnt_locate_table(sfont, "hhea");
-    table->version = sfnt_get_ulong(sfont);
-    table->Ascender = sfnt_get_short(sfont);
-    table->Descender = sfnt_get_short(sfont);
-    table->LineGap = sfnt_get_short(sfont);
-    table->advanceWidthMax = sfnt_get_ushort(sfont);
-    table->minLeftSideBearing = sfnt_get_short(sfont);
-    table->minRightSideBearing = sfnt_get_short(sfont);
-    table->xMaxExtent = sfnt_get_short(sfont);
-    table->caretSlopeRise = sfnt_get_short(sfont);
-    table->caretSlopeRun = sfnt_get_short(sfont);
-    for (i = 0; i < 5; i++) {
-        table->reserved[i] = sfnt_get_short(sfont);
-    }
-    table->metricDataFormat = sfnt_get_short(sfont);
-    if (table->metricDataFormat != 0)
-        normal_error("ttf","unknown metricDaraFormat");
-    table->numberOfHMetrics = sfnt_get_ushort(sfont);
-
-    return table;
-}
-
-@ vhea
- at c
-char *tt_pack_vhea_table(struct tt_vhea_table *table)
-{
-    int i;
-    char *p, *data;
-
-    p = data = NEW(TT_VHEA_TABLE_SIZE, char);
-    p += sfnt_put_ulong(p, (LONG) table->version);
-    p += sfnt_put_short(p, table->vertTypoAscender);
-    p += sfnt_put_short(p, table->vertTypoDescender);
-    p += sfnt_put_short(p, table->vertTypoLineGap);
-    p += sfnt_put_short(p, table->advanceHeightMax);    /* ushort ? */
-    p += sfnt_put_short(p, table->minTopSideBearing);
-    p += sfnt_put_short(p, table->minBottomSideBearing);
-    p += sfnt_put_short(p, table->yMaxExtent);
-    p += sfnt_put_short(p, table->caretSlopeRise);
-    p += sfnt_put_short(p, table->caretSlopeRun);
-    p += sfnt_put_short(p, table->caretOffset);
-    for (i = 0; i < 5; i++) {
-        p += sfnt_put_short(p, table->reserved[i]);
-    }
-    p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
-
-    return data;
-}
-
-struct tt_vhea_table *tt_read_vhea_table(sfnt * sfont)
-{
-    int i;
-    struct tt_vhea_table *table = NULL;
-
-    table = NEW(1, struct tt_vhea_table);
-
-    sfnt_locate_table(sfont, "vhea");
-    table->version = sfnt_get_ulong(sfont);
-    table->vertTypoAscender = sfnt_get_short(sfont);
-    table->vertTypoDescender = sfnt_get_short(sfont);
-    table->vertTypoLineGap = sfnt_get_short(sfont);
-    table->advanceHeightMax = sfnt_get_short(sfont);    /* ushort ? */
-    table->minTopSideBearing = sfnt_get_short(sfont);
-    table->minBottomSideBearing = sfnt_get_short(sfont);
-    table->yMaxExtent = sfnt_get_short(sfont);
-    table->caretSlopeRise = sfnt_get_short(sfont);
-    table->caretSlopeRun = sfnt_get_short(sfont);
-    table->caretOffset = sfnt_get_short(sfont);
-    for (i = 0; i < 5; i++) {
-        (table->reserved)[i] = sfnt_get_short(sfont);
-    }
-    table->numOfLongVerMetrics = sfnt_get_ushort(sfont);
-
-    return table;
-}
-
-
-struct tt_VORG_table *tt_read_VORG_table(sfnt * sfont)
-{
-    struct tt_VORG_table *vorg;
-    ULONG offset;
-    USHORT i;
-
-    offset = sfnt_find_table_pos(sfont, "VORG");
-
-    if (offset > 0) {
-        vorg = NEW(1, struct tt_VORG_table);
-
-        sfnt_locate_table(sfont, "VORG");
-        if (sfnt_get_ushort(sfont) != 1 || sfnt_get_ushort(sfont) != 0)
-            normal_error("ttf","unsupported VORG version");
-
-        vorg->defaultVertOriginY = sfnt_get_short(sfont);
-        vorg->numVertOriginYMetrics = sfnt_get_ushort(sfont);
-        vorg->vertOriginYMetrics = NEW(vorg->numVertOriginYMetrics,
-                                       struct tt_vertOriginYMetrics);
-        /*
-         * The vertOriginYMetrics array must be sorted in increasing
-         * glyphIndex order.
-         */
-        for (i = 0; i < vorg->numVertOriginYMetrics; i++) {
-            vorg->vertOriginYMetrics[i].glyphIndex = sfnt_get_ushort(sfont);
-            vorg->vertOriginYMetrics[i].vertOriginY = sfnt_get_short(sfont);
-        }
-    } else {
-        vorg = NULL;
-    }
-
-    return vorg;
-}
-
-
-@ hmtx and vmtx
-
-Reading/writing hmtx and vmtx depend on other tables, maxp and hhea/vhea.
-
- at c
-struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs,
-                                           USHORT numLongMetrics)
-{
-    struct tt_longMetrics *m;
-    USHORT gid, last_adv = 0;
-
-    m = NEW(numGlyphs, struct tt_longMetrics);
-    for (gid = 0; gid < numGlyphs; gid++) {
-        if (gid < numLongMetrics)
-            last_adv = sfnt_get_ushort(sfont);
-        m[gid].sideBearing = sfnt_get_short(sfont);
-        m[gid].advance = last_adv;
-    }
-
-    return m;
-}
-
-@ OS/2 table
-
-this table may not exist
- at c
-struct tt_os2__table *tt_read_os2__table(sfnt * sfont)
-{
-    struct tt_os2__table *table = NULL;
-    int i;
-
-    if (sfnt_find_table_pos(sfont, "OS/2") == 0)
-        return NULL;
-
-    sfnt_locate_table(sfont, "OS/2");
-
-    table = NEW(1, struct tt_os2__table);
-
-    table->version = sfnt_get_ushort(sfont);
-    table->xAvgCharWidth = sfnt_get_short(sfont);
-    table->usWeightClass = sfnt_get_ushort(sfont);
-    table->usWidthClass = sfnt_get_ushort(sfont);
-    table->fsType = sfnt_get_short(sfont);
-    table->ySubscriptXSize = sfnt_get_short(sfont);
-    table->ySubscriptYSize = sfnt_get_short(sfont);
-    table->ySubscriptXOffset = sfnt_get_short(sfont);
-    table->ySubscriptYOffset = sfnt_get_short(sfont);
-    table->ySuperscriptXSize = sfnt_get_short(sfont);
-    table->ySuperscriptYSize = sfnt_get_short(sfont);
-    table->ySuperscriptXOffset = sfnt_get_short(sfont);
-    table->ySuperscriptYOffset = sfnt_get_short(sfont);
-    table->yStrikeoutSize = sfnt_get_short(sfont);
-    table->yStrikeoutPosition = sfnt_get_short(sfont);
-    table->sFamilyClass = sfnt_get_short(sfont);
-    for (i = 0; i < 10; i++) {
-        table->panose[i] = sfnt_get_byte(sfont);
-    }
-    table->ulUnicodeRange1 = sfnt_get_ulong(sfont);
-    table->ulUnicodeRange2 = sfnt_get_ulong(sfont);
-    table->ulUnicodeRange3 = sfnt_get_ulong(sfont);
-    table->ulUnicodeRange4 = sfnt_get_ulong(sfont);
-    for (i = 0; i < 4; i++) {
-        table->achVendID[i] = sfnt_get_char(sfont);
-    }
-    table->fsSelection = sfnt_get_ushort(sfont);
-    table->usFirstCharIndex = sfnt_get_ushort(sfont);
-    table->usLastCharIndex = sfnt_get_ushort(sfont);
-    table->sTypoAscender = sfnt_get_short(sfont);
-    table->sTypoDescender = sfnt_get_short(sfont);
-    table->sTypoLineGap = sfnt_get_short(sfont);
-    table->usWinAscent = sfnt_get_ushort(sfont);
-    table->usWinDescent = sfnt_get_ushort(sfont);
-    table->ulCodePageRange1 = sfnt_get_ulong(sfont);
-    table->ulCodePageRange2 = sfnt_get_ulong(sfont);
-    if (table->version == 0x0002) {
-        table->sxHeight = sfnt_get_short(sfont);
-        table->sCapHeight = sfnt_get_short(sfont);
-        table->usDefaultChar = sfnt_get_ushort(sfont);
-        table->usBreakChar = sfnt_get_ushort(sfont);
-        table->usMaxContext = sfnt_get_ushort(sfont);
-    }
-
-    return table;
-}
-
-USHORT
-tt_get_name(sfnt * sfont, char *dest, USHORT destlen,
-            USHORT plat_id, USHORT enco_id, USHORT lang_id, USHORT name_id)
-{
-    USHORT length = 0;
-    USHORT num_names, string_offset;
-    ULONG name_offset;
-    int i;
-
-    name_offset = sfnt_locate_table(sfont, "name");
-
-    if (sfnt_get_ushort(sfont))
-        normal_error("ttf","expecting zero");
-
-    num_names = sfnt_get_ushort(sfont);
-    string_offset = sfnt_get_ushort(sfont);
-    for (i = 0; i < num_names; i++) {
-        USHORT p_id, e_id, n_id, l_id;
-        USHORT offset;
-
-        p_id = sfnt_get_ushort(sfont);
-        e_id = sfnt_get_ushort(sfont);
-        l_id = sfnt_get_ushort(sfont);
-        n_id = sfnt_get_ushort(sfont);
-        length = sfnt_get_ushort(sfont);
-        offset = sfnt_get_ushort(sfont);
-        /* language ID value 0xffffu for `accept any language ID' */
-        if ((p_id == plat_id) && (e_id == enco_id) &&
-            (lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) {
-            if (length > destlen - 1) {
-                normal_warning("ttf","truncating a very long name");
-                length = (USHORT) (destlen - 1);
-            }
-            sfnt_seek_set(sfont, (long) (name_offset + string_offset + offset));
-            sfnt_read((unsigned char *) dest, length, sfont);
-            dest[length] = '\0';
-            break;
-        }
-    }
-    if (i == num_names) {
-        length = 0;
-    }
-
-    return length;
-}
-
-USHORT tt_get_ps_fontname(sfnt * sfont, char *dest, USHORT destlen)
-{
-    USHORT namelen = 0;
-
-    /* First try Mac-Roman PS name and then Win-Unicode PS name */
-    if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 6)) != 0 ||
-        (namelen = tt_get_name(sfont, dest, destlen, 3, 1, 0x409u, 6)) != 0 ||
-        (namelen = tt_get_name(sfont, dest, destlen, 3, 5, 0x412u, 6)) != 0)
-        return namelen;
-
-    normal_warning("ttf","no valid PostScript name available");
-    /*
-       Wrokaround for some bad TTfonts:
-       Language ID value 0xffffu for `accept any language ID'
-     */
-    if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0xffffu, 6)) == 0) {
-        /*
-           Finally falling back to Mac Roman name field.
-           Warning: Some bad Japanese TTfonts using SJIS encoded string in the
-           Mac Roman name field.
-         */
-        namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 1);
-    }
-
-    return namelen;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfovf.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1444 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under the terms
+of the GNU General Public License as published by the Free Software Foundation;
+either version 2 of the License, or (at your option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#define font_max 5000
+
+/* The instruction set: */
+
+#define set_char_0 0   /* typeset character 0 and move right */
+#define set1 128       /* typeset a character and move right */
+#define set2 129       /* typeset a character and move right */
+#define set3 130       /* typeset a character and move right */
+#define set4 131       /* typeset a character and move right */
+#define set_rule 132   /* typeset a rule and move right */
+#define put1  133      /* typeset a character without moving */
+#define put2  134      /* typeset a character without moving */
+#define put3  135      /* typeset a character without moving */
+#define put4  136      /* typeset a character without moving */
+#define put_rule 137   /* typeset a rule */
+#define nop 138        /* no operation */
+#define bop 139        /* beginning of page */
+#define eop 140        /* ending of page */
+#define push 141       /* save the current positions */
+#define pop 142        /* restore previous positions */
+#define right1  143    /* move right */
+#define right2  144    /* move right */
+#define right3  145    /* move right */
+#define right4  146    /* move right, 4 bytes */
+#define w0 147         /* move right by |w| */
+#define w1 148         /* move right and set |w| */
+#define w2 149         /* move right and set |w| */
+#define w3 150         /* move right and set |w| */
+#define w4 151         /* move right and set |w| */
+#define x0 152         /* move right by |x| */
+#define x1 153         /* move right and set |x| */
+#define x2 154         /* move right and set |x| */
+#define x3 155         /* move right and set |x| */
+#define x4 156         /* move right and set |x| */
+#define down1 157      /* move down */
+#define down2 158      /* move down */
+#define down3 159      /* move down */
+#define down4 160      /* move down, 4 bytes */
+#define y0 161         /* move down by |y| */
+#define y1 162         /* move down and set |y| */
+#define y2 163         /* move down and set |y| */
+#define y3 164         /* move down and set |y| */
+#define y4 165         /* move down and set |y| */
+#define z0 166         /* move down by |z| */
+#define z1 167         /* move down and set |z| */
+#define z2 168         /* move down and set |z| */
+#define z3 169         /* move down and set |z| */
+#define z4 170         /* move down and set |z| */
+#define fnt_num_0 171  /* set current font to 0 */
+#define fnt1 235       /* set current font */
+#define fnt2 236       /* set current font */
+#define fnt3 237       /* set current font */
+#define fnt4 238       /* set current font */
+#define xxx1 239       /* extension to DVI  primitives */
+#define xxx2 240       /* extension to DVI  primitives */
+#define xxx3 241       /* extension to DVI  primitives */
+#define xxx4 242       /* potentially long extension to DVI primitives */
+#define fnt_def1 243   /* define the meaning of a font number */
+#define pre 247        /* preamble */
+#define post 248       /* postamble beginning */
+#define post_post 249  /* postamble ending */
+#define yyy1 250       /* PDF literal text */
+#define yyy2 251       /* PDF literal text */
+#define yyy3 252       /* PDF literal text */
+#define yyy4 253       /* PDF literal text */
+
+#define null_font 0
+
+#define long_char 242  /* |VF| command for general character packet */
+
+#define vf_id 202      /* identifies \VF\ files */
+
+/*tex
+
+    Quit |VF| processing with an error message.
+
+*/
+
+#define bad_vf(a) { \
+    xfree(vf_buffer); \
+    print_nlp(); \
+    formatted_warning("virtual font","file '%s', %s, font will be ignored",font_name(f),a); \
+    print_ln(); \
+    return; \
+}
+
+#define lua_bad_vf(a) { \
+    xfree(vf_buffer); \
+    lua_settop(L,s_top); \
+    lua_pushnil(L); \
+    lua_pushstring(L,a); \
+    return 2; \
+}
+
+#define tmp_b0  tmp_w.qqqq.b0
+#define tmp_b1  tmp_w.qqqq.b1
+#define tmp_b2  tmp_w.qqqq.b2
+#define tmp_b3  tmp_w.qqqq.b3
+#define tmp_int tmp_w.cint
+
+/*tex \DVI\ files shouldn't |push| beyond this depth: */
+
+#define vf_stack_size 100
+
+/*tex An index into the stack: */
+
+typedef unsigned char vf_stack_index;
+
+typedef struct vf_stack_record {
+    scaled stack_w, stack_x, stack_y, stack_z;
+} vf_stack_record;
+
+/*tex Get a byte from the \VF\ file: */
+
+#define vf_byte(a)                                     \
+{                                                      \
+  eight_bits vf_tmp_b;                                 \
+    if (vf_cur >= vf_size) {                           \
+        normal_error("virtual font","unexpected eof"); \
+    }                                                  \
+    vf_tmp_b = vf_buffer[vf_cur++];                    \
+    a = vf_tmp_b;                                      \
+}
+
+#define vf_replace_z()                          \
+{                                               \
+    vf_alpha = 16;                              \
+    while (vf_z >= 040000000) {                 \
+        vf_z = vf_z / 2;                        \
+        vf_alpha += vf_alpha;                   \
+    }                                           \
+    /*tex |vf_beta = (char)(256 / vf_alpha)| */ \
+    vf_alpha = (vf_alpha * vf_z);               \
+}
+
+/*tex
+
+    Read |k| bytes as an integer from \VF\ file. Beware: the |vf_read| macro
+    differs from |vf_read| in |vftovp.web| for 1 upto 3 byte words.
+
+*/
+
+#define vf_read(k, l)                        \
+{                                            \
+    int itmp = 0, dtmp = (int)(k), jtmp = 0; \
+    while (dtmp > 0) {                       \
+        vf_byte(jtmp);                       \
+        if ((dtmp == (int) k) && jtmp > 127) \
+            jtmp = jtmp - 256;               \
+        itmp = itmp * 256 + jtmp;            \
+        decr(dtmp);                          \
+    }                                        \
+    l = itmp;                                \
+}
+
+#define vf_read_u(k, l)              \
+{                                    \
+    int dtmp = (int)(k);             \
+    unsigned int itmp = 0, jtmp = 0; \
+    while (dtmp-- > 0) {             \
+        vf_byte(jtmp);               \
+        itmp = itmp * 256 + jtmp;    \
+    }                                \
+    l = itmp;                        \
+}
+
+void pdf_check_vf(internal_font_number f)
+{
+    if (font_type(f) == virtual_font_type)
+        normal_error("font", "command cannot be used with virtual font");
+}
+
+static void vf_local_font_warning(internal_font_number f, internal_font_number k, const char *s, int a, int b)
+{
+    print_nlp();
+    tprint(s);
+    tprint(" in local font ");
+    tprint(font_name(k));
+    tprint(" (");
+    print_int(b);
+    tprint(" != ");
+    print_int(a);
+    tprint(") in virtual font ");
+    tprint(font_name(f));
+    tprint(".vf ignored.");
+}
+
+/*tex Process a local font in the \VF\ file. */
+
+int level = 0;
+
+static internal_font_number vf_def_font(internal_font_number f, unsigned char *vf_buffer, int *vf_cr)
+{
+    internal_font_number k;
+    str_number s;
+    char *st;
+    scaled ds, fs;
+    four_quarters cs;
+    /*tex The accumulator: */
+    memory_word tmp_w;
+    int junk;
+    unsigned int checksum;
+    cs.b0 = vf_buffer[(*vf_cr)];
+    cs.b1 = vf_buffer[(*vf_cr) + 1];
+    cs.b2 = vf_buffer[(*vf_cr) + 2];
+    cs.b3 = vf_buffer[(*vf_cr) + 3];
+    (*vf_cr) += 4;
+    checksum = (unsigned) (cs.b0 * 256 * 256 * 256 + cs.b1 * 256 * 256 + cs.b2 * 256 + cs.b3);
+    k = vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    if (k > 127)
+        k -= 256;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    fs = store_scaled_f(k, font_size(f));
+    k = vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    if (k > 127)
+        k -= 256;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    k = k * 256 + vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    ds = k / 16;
+    tmp_b0 = vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    tmp_b1 = vf_buffer[(*vf_cr)];
+    (*vf_cr)++;
+    while (tmp_b0 > 0) {
+        /*tex Skip the font path. */
+        tmp_b0--;
+        (*vf_cr)++;
+    }
+    str_room((unsigned) tmp_b1);
+    while (tmp_b1 > 0) {
+        tmp_b1--;
+        junk = vf_buffer[(*vf_cr)];
+        (*vf_cr)++;
+        append_char(junk);
+    }
+    if (level > 5) {
+        normal_warning("vf","quitting at recurse depth > 5");
+        k = f ;
+    } else if ((level > 1) && (fs > 65536*1024)) {
+        normal_warning("vf","quitting when recursing at size > 65536*1024");
+        k = f ;
+    } else {
+        level += 1 ;
+        s = make_string();
+        st = makecstring(s);
+        k = tfm_lookup(st, fs);
+        if (k == null_font)
+            k = read_font_info(null_cs, st, fs, -1);
+        free(st);
+        level -= 1 ;
+        if (k != null_font) {
+            if (checksum != 0 && font_checksum(k) != 0
+                && checksum != font_checksum(k))
+                vf_local_font_warning(f, k, "checksum mismatch", (int) checksum, (int) font_checksum(k));
+            if (ds != font_dsize(k))
+                vf_local_font_warning(f, k, "design size mismatch", ds, font_dsize(k));
+        }
+    }
+    return k;
+}
+
+static int open_vf_file(const char *fn, unsigned char **vbuffer, int *vsize)
+{
+    /*tex Was the callback successful? */
+    boolean res;
+    int callback_id;
+    /*tex Was |vf_file| successfully read? */
+    boolean file_read = false;
+    FILE *vf_file;
+    const char *fname = luatex_find_file(fn, find_vf_file_callback);
+    if (fname == NULL || strlen(fname) == 0) {
+       return 0;
+    }
+
+    callback_id = callback_defined(read_vf_file_callback);
+    if (callback_id > 0) {
+        res = run_callback(callback_id, "S->bSd", fname,
+                           &file_read, vbuffer, vsize);
+        if (res && file_read && (*vsize > 0)) {
+            return 1;
+        }
+        if (!file_read)
+            return 0;
+    } else {
+        if (luatex_open_input
+            (&(vf_file), fname, kpse_ovf_format, FOPEN_RBIN_MODE, false)
+            || luatex_open_input(&(vf_file), fname, kpse_vf_format, FOPEN_RBIN_MODE, false)) {
+                res = read_vf_file(vf_file, vbuffer, vsize);
+                close_file(vf_file);
+                if (res) {
+                    return 1;
+            }
+        } else {
+            return 0;
+        }
+    }
+    return 0;
+}
+
+/*tex
+
+    The |do_vf| procedure attempts to read the \VF\ file for a font, and sets
+    |font_type()| to |real_font_type| if the \VF\ file could not be found or
+    loaded, otherwise sets |font_type()| to |virtual_font_type|. At this time,
+    |tmp_f| is the internal font number of the current \TFM\ font. To process
+    font definitions in virtual font we call |vf_def_font|.
+
+*/
+
+#define append_packet(k) vpackets[vf_np++] = (eight_bits)(k)
+
+/*tex
+
+    Life is easier if all internal font commands are |fnt4| and all character
+    commands are |set4| or |put4|.
+
+*/
+
+#define append_fnt_set(k)            \
+{                                    \
+    assert(k > 0);                   \
+    append_packet(packet_font_code); \
+    append_four(k);                  \
+}
+
+#define append_four(k)                     \
+{                                          \
+    append_packet((k & 0xFF000000) >> 24); \
+    append_packet((k & 0x00FF0000) >> 16); \
+    append_packet((k & 0x0000FF00) >> 8);  \
+    append_packet((k & 0x000000FF));       \
+}
+
+/*tex Some of these things happen twice, adding a define is simplest. */
+
+#define test_checksum()  { vf_byte(tmp_b0); vf_byte(tmp_b1); \
+    vf_byte(tmp_b2); vf_byte(tmp_b3); \
+    if (((tmp_b0 != 0) || (tmp_b1 != 0) || (tmp_b2 != 0) || (tmp_b3 != 0)) && \
+  ((font_check_0(f) != 0) || (font_check_1(f) != 0) || \
+   (font_check_2(f) != 0) || (font_check_3(f) != 0)) && \
+  ((tmp_b0 != font_check_0(f)) || (tmp_b1 != font_check_1(f)) ||  \
+   (tmp_b2 != font_check_2(f)) || (tmp_b3 != font_check_3(f)))) { \
+      print_nlp(); \
+      tprint("checksum mismatch in font "); \
+      tprint(font_name(f)); \
+      tprint(".vf ignored "); } }
+
+#define test_dsize()                             \
+{                                                \
+    int read_tmp;                                \
+    vf_read(4, read_tmp);                        \
+    if ((read_tmp / 16) != font_dsize(f)) {      \
+        print_nlp();                             \
+        tprint("design size mismatch in font "); \
+        tprint(font_name(f));                    \
+        tprint(".vf ignored");                   \
+    }                                            \
+}
+
+static int count_packet_bytes(eight_bits * vf_buf, int cur_bute, int count)
+{
+    unsigned k = 0;
+    int ff = 0;
+    int acc = 0;
+    unsigned int cmd = 0;
+    unsigned int d = 0;
+    while (k < (unsigned) count) {
+        cmd = vf_buf[cur_bute + (int) k];
+        k++;
+        if (cmd < set1) {
+            if (ff == 0) {
+                ff = 1;
+                acc += 5;
+            }
+            acc += 5;
+        } else if ((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) {
+            ff = 1;
+            acc += 5;
+        } else {
+            switch (cmd) {
+                case fnt1:
+                    acc += 5;
+                    k += 1;
+                    ff = 1;
+                    break;
+                case fnt2:
+                    acc += 5;
+                    k += 2;
+                    ff = 1;
+                    break;
+                case fnt3:
+                    acc += 5;
+                    k += 3;
+                    ff = 1;
+                    break;
+                case fnt4:
+                    acc += 5;
+                    k += 4;
+                    ff = 1;
+                    break;
+                case set_rule:
+                    acc += 9;
+                    k += 8;
+                    break;
+                case put_rule:
+                    acc += 11;
+                    k += 8;
+                    break;
+                case set1:
+                    acc += 5;
+                    k += 1;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case set2:
+                    acc += 5;
+                    k += 2;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case set3:
+                    acc += 5;
+                    k += 3;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case set4:
+                    acc += 5;
+                    k += 4;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case put1:
+                    acc += 7;
+                    k += 1;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case put2:
+                    acc += 7;
+                    k += 2;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case put3:
+                    acc += 7;
+                    k += 3;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case put4:
+                    acc += 7;
+                    k += 4;
+                    if (ff == 0) {
+                        ff = 1;
+                        acc += 5;
+                    }
+                    break;
+                case right1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case right2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case right3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case right4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case w1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case w2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case w3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case w4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case x1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case x2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case x3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case x4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case down1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case down2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case down3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case down4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case y1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case y2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case y3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case y4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case z1:
+                    acc += 5;
+                    k += 1;
+                    break;
+                case z2:
+                    acc += 5;
+                    k += 2;
+                    break;
+                case z3:
+                    acc += 5;
+                    k += 3;
+                    break;
+                case z4:
+                    acc += 5;
+                    k += 4;
+                    break;
+                case xxx1:
+                    d = vf_buf[cur_bute + (int) k];
+                    k++;
+                    k += d;
+                    acc += 5 + (int) d;
+                    break;
+                case xxx2:
+                    d = vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    k += d;
+                    acc += 5 + (int) d;
+                    break;
+                case xxx3:
+                    d = vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    k += d;
+                    acc += 5 + (int) d;
+                    break;
+                case xxx4:
+                    d = vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    d = d * 256 + vf_buf[cur_bute + (int) k];
+                    k++;
+                    k += d;
+                    acc += 5 + (int) d;
+                    break;
+                case w0:
+                    acc += 5;
+                    break;
+                case x0:
+                    acc += 5;
+                    break;
+                case y0:
+                    acc += 5;
+                    break;
+                case z0:
+                    acc += 5;
+                    break;
+                case nop:
+                    break;
+                case push:
+                    acc += 1;
+                    break;
+                case pop:
+                    acc += 1;
+                    break;
+            }
+        }
+    }
+    return (acc + 1);
+}
+
+void do_vf(internal_font_number f)
+{
+    int k, i;
+    unsigned cmd, n;
+    scaled x, y, w, z, h, v;
+    int cc, cmd_length;
+    unsigned packet_length;
+    charinfo *co;
+    scaled tfm_width;
+    int save_cur_byte;
+    vf_stack_index stack_level;
+    /*tex multiplier */
+    int vf_z;
+    /*tex correction for negative values */
+    int vf_alpha;
+    int vf_np;
+    eight_bits *vpackets;
+    /*tex accumulator */
+    memory_word tmp_w;
+    vf_stack_record vf_stack[256];
+    int junk;
+    unsigned utmp;
+    unsigned char *vf_buffer;
+    int vf_size;
+    int vf_cur;
+    /*tex external font ids */
+    unsigned *vf_local_fnts = NULL;
+    /*tex internal font ids */
+    unsigned *vf_real_fnts = NULL;
+    /*tex local font counter */
+    unsigned vf_nf = 0;
+    if (font_type(f) != unknown_font_type)
+        return;
+    set_font_type(f, real_font_type);
+    stack_level = 0;
+    /*tex Open |vf_file|, return if not found */
+    vf_cur = 0;
+    vf_buffer = NULL;
+    vf_size = 0;
+    if (!open_vf_file(font_name(f), &vf_buffer, &vf_size))
+        return;
+    /*tex Process the preamble */
+    set_font_type(f, virtual_font_type);
+    vf_byte(k);
+    if (k != pre)
+        bad_vf("PRE command expected");
+    vf_byte(k);
+    if (k != vf_id)
+        bad_vf("wrong id byte");
+    vf_byte(cmd_length);
+    for (k = 1; k <= cmd_length; k++)
+        vf_byte(junk);
+    test_checksum();
+    test_dsize();
+    vf_z = font_size(f);
+    vf_replace_z();
+    /*tex Process the font definitions; scan forward to find the number of internal fonts. */
+    vf_nf = 0;
+    save_cur_byte = vf_cur;
+    vf_byte(cmd);
+    while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
+        vf_read_u((cmd - fnt_def1 + 1), utmp);
+        vf_read(4, junk);
+        vf_read(4, junk);
+        vf_read(4, junk);
+        vf_byte(k);
+        vf_byte(junk);
+        k += junk;
+        while (k-- > 0) {
+            vf_byte(junk);
+        }
+        incr(vf_nf);
+        vf_byte(cmd);
+    }
+    vf_cur = save_cur_byte;
+    vf_byte(cmd);
+    /*tex Do a |malloc| and fill the local font arrays. */
+    if (vf_nf > 0) {
+        unsigned ii = (unsigned) ((unsigned) vf_nf * sizeof(int));
+        vf_local_fnts = xmalloc(ii);
+        memset(vf_local_fnts, 0, ii);
+        vf_real_fnts = xmalloc(ii);
+        memset(vf_real_fnts, 0, ii);
+        vf_nf = 0;
+        while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
+            vf_read_u((cmd - fnt_def1 + 1), vf_local_fnts[vf_nf]);
+            vf_real_fnts[vf_nf] = (unsigned) vf_def_font(f, vf_buffer, &vf_cur);
+            incr(vf_nf);
+            vf_byte(cmd);
+        }
+    }
+    while (cmd <= long_char) {
+        /*tex Build a character packet. */
+        vf_np = 0;
+        if (cmd == long_char) {
+            vf_read_u(4, packet_length);
+            vf_read_u(4, utmp);
+            cc = (int) utmp;
+            if (!char_exists(f, cc)) {
+                bad_vf("invalid character code");
+            }
+            vf_read(4, k);
+            tfm_width = store_scaled_f(k, font_size(f));
+        } else {
+            packet_length = cmd;
+            vf_byte(cc);
+            if (!char_exists(f, cc)) {
+                bad_vf("invalid character code");
+            }
+            vf_read_u(3, utmp);
+            /*tex cf. |vftovp.web|, line 1028 */
+            k = (int) utmp;
+            tfm_width = store_scaled_f(k, font_size(f));
+        }
+        if (tfm_width != char_width(f, cc)) {
+            if (tfm_width != char_width(f, cc)) {
+                print_nlp();
+                tprint("character width mismatch in font ");
+                tprint(font_name(f));
+                tprint(".vf ignored");
+            }
+        }
+        k = count_packet_bytes(vf_buffer, vf_cur, (int) packet_length);
+        /*tex We need one extra extra for |packet_end|. */
+        vpackets = xmalloc((unsigned) (k + 1));
+        co = get_charinfo(f, cc);
+        k = 0;
+        w = 0;
+        x = 0;
+        y = 0;
+        z = 0;
+        while (packet_length > 0) {
+            vf_byte(cmd);
+            decr(packet_length);
+            if (cmd < set1) {
+                if (k == 0) {
+                    k = (int) vf_real_fnts[0];
+                    append_fnt_set(k);
+                }
+                append_packet(packet_char_code);
+                append_four(cmd);
+                cmd_length = 0;
+                cmd = nop;
+            } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
+                       ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
+                if (cmd >= fnt1) {
+                    vf_read_u((cmd - fnt1 + 1), utmp);
+                    k = (int) utmp;
+                    packet_length -= (cmd - fnt1 + 1);
+                } else {
+                    k = (int) cmd - fnt_num_0;
+                }
+                /*tex Change from local to external font id. */
+                n = 0;
+                while ((n < vf_nf) && (vf_local_fnts[n] != (unsigned) k))
+                    n++;
+                if (n == vf_nf)
+                    bad_vf("undefined local font");
+                k = (int) vf_real_fnts[n];
+                append_fnt_set(k);
+                cmd_length = 0;
+                cmd = nop;
+            } else {
+                switch (cmd) {
+                    case set_rule:
+                        vf_read(4, h);
+                        vf_read(4, v);
+                        append_packet(packet_rule_code);
+                        append_four(h);
+                        append_four(v);
+                        packet_length -= 8;
+                        break;
+                    case put_rule:
+                        vf_read(4, h);
+                        vf_read(4, v);
+                        append_packet(packet_push_code);
+                        append_packet(packet_rule_code);
+                        append_four(h);
+                        append_four(v);
+                        append_packet(packet_pop_code);
+                        packet_length -= 8;
+                        break;
+                    case set1:
+                    case set2:
+                    case set3:
+                    case set4:
+                        if (k == 0) {
+                            k = (int) vf_real_fnts[0];
+                            append_fnt_set(k);
+                        }
+                        vf_read_u((cmd - set1 + 1), utmp);
+                        i = (int) utmp;
+                        append_packet(packet_char_code);
+                        append_four(i);
+                        packet_length -= (cmd - set1 + 1);
+                        break;
+                    case put1:
+                    case put2:
+                    case put3:
+                    case put4:
+                        if (k == 0) {
+                            k = (int) vf_real_fnts[0];
+                            append_fnt_set(k);
+                        }
+                        vf_read_u((cmd - put1 + 1), utmp);
+                        i = (int) utmp;
+                        append_packet(packet_push_code);
+                        append_packet(packet_char_code);
+                        append_four(i);
+                        append_packet(packet_pop_code);
+                        packet_length -= (cmd - put1 + 1);
+                        break;
+                    case right1:
+                    case right2:
+                    case right3:
+                    case right4:
+                        vf_read((cmd - right1 + 1), i);
+                        append_packet(packet_right_code);
+                        append_four(i);
+                        packet_length -= (cmd - right1 + 1);
+                        break;
+                    case w1:
+                    case w2:
+                    case w3:
+                    case w4:
+                        vf_read((cmd - w1 + 1), w);
+                        append_packet(packet_right_code);
+                        append_four(w);
+                        packet_length -= (cmd - w1 + 1);
+                        break;
+                    case x1:
+                    case x2:
+                    case x3:
+                    case x4:
+                        vf_read((cmd - x1 + 1), x);
+                        append_packet(packet_right_code);
+                        append_four(x);
+                        packet_length -= (cmd - x1 + 1);
+                        break;
+                    case down1:
+                    case down2:
+                    case down3:
+                    case down4:
+                        vf_read((cmd - down1 + 1), i);
+                        append_packet(packet_down_code);
+                        append_four(i);
+                        packet_length -= (cmd - down1 + 1);
+                        break;
+                    case y1:
+                    case y2:
+                    case y3:
+                    case y4:
+                        vf_read((cmd - y1 + 1), y);
+                        append_packet(packet_down_code);
+                        append_four(y);
+                        packet_length -= (cmd - y1 + 1);
+                        break;
+                    case z1:
+                    case z2:
+                    case z3:
+                    case z4:
+                        vf_read((cmd - z1 + 1), z);
+                        append_packet(packet_down_code);
+                        append_four(z);
+                        packet_length -= (cmd - z1 + 1);
+                        break;
+                    case xxx1:
+                    case xxx2:
+                    case xxx3:
+                    case xxx4:
+                        vf_read_u((cmd - xxx1 + 1), utmp);
+                        cmd_length = (int) utmp;
+                        packet_length -= (cmd - xxx1 + 1);
+                        if (cmd_length <= 0)
+                            bad_vf("special of negative length");
+                        packet_length -= (unsigned) cmd_length;
+                        append_packet(packet_special_code);
+                        append_four(cmd_length);
+                        while (cmd_length > 0) {
+                            cmd_length--;
+                            vf_byte(i);
+                            append_packet(i);
+                        }
+                        break;
+                    case w0:
+                        append_packet(packet_right_code);
+                        append_four(w);
+                        break;
+                    case x0:
+                        append_packet(packet_right_code);
+                        append_four(x);
+                        break;
+                    case y0:
+                        append_packet(packet_down_code);
+                        append_four(y);
+                        break;
+                    case z0:
+                        append_packet(packet_down_code);
+                        append_four(z);
+                        break;
+                    case nop:
+                        break;
+                    case push:
+                        if (stack_level == vf_stack_size) {
+                            overflow("virtual font stack size", vf_stack_size);
+                        } else {
+                            vf_stack[stack_level].stack_w = w;
+                            vf_stack[stack_level].stack_x = x;
+                            vf_stack[stack_level].stack_y = y;
+                            vf_stack[stack_level].stack_z = z;
+                            incr(stack_level);
+                            append_packet(packet_push_code);
+                        }
+                        break;
+                    case pop:
+                        if (stack_level == 0) {
+                            bad_vf("more POPs than PUSHs in character");
+                        } else {
+                            decr(stack_level);
+                            w = vf_stack[stack_level].stack_w;
+                            x = vf_stack[stack_level].stack_x;
+                            y = vf_stack[stack_level].stack_y;
+                            z = vf_stack[stack_level].stack_z;
+                            append_packet(packet_pop_code);
+                        }
+                        break;
+                    default:
+                        bad_vf("improver DVI command");
+                }
+            }
+        }
+        /*tex Signal end of packet. */
+        append_packet(packet_end_code);
+        if (stack_level != 0)
+            bad_vf("more PUSHs than POPs in character packet");
+        if (packet_length != 0)
+            bad_vf("invalid packet length or DVI command in packet");
+        /*tex Store the packet being built. */
+        set_charinfo_packets(co, vpackets);
+        vf_byte(cmd);
+    }
+    if (cmd != post)
+        bad_vf("POST command expected");
+
+    xfree(vf_buffer);
+}
+
+#define make_command0(N,K) { \
+    lua_newtable(L);         \
+    lua_pushstring(L, N);    \
+    lua_rawseti(L,-2, 1);    \
+    lua_rawseti(L,-2, K);    \
+    K++; }
+
+#define make_command1(N,V,K) { \
+    lua_newtable(L);           \
+    lua_pushstring(L, N);      \
+    lua_rawseti(L,-2, 1);      \
+    lua_pushinteger(L, V);     \
+    lua_rawseti(L,-2, 2);      \
+    lua_rawseti(L,-2, K);      \
+    K++; }
+
+#define make_command2(N,V,W,K) { \
+    lua_newtable(L);             \
+    lua_pushstring(L, N);        \
+    lua_rawseti(L,-2, 1);        \
+    lua_pushinteger(L, V);       \
+    lua_rawseti(L,-2, 2);        \
+    lua_pushinteger(L, W);       \
+    lua_rawseti(L,-2, 3);        \
+    lua_rawseti(L,-2, K);        \
+    K++; }
+
+#define make_commands(N,S,V,K) { \
+    lua_newtable(L);             \
+    lua_pushstring(L, N);        \
+    lua_rawseti(L,-2, 1);        \
+    lua_pushlstring(L, S, V);    \
+    lua_rawseti(L,-2, 2);        \
+    lua_rawseti(L,-2, K);        \
+    K++; }
+
+int make_vf_table(lua_State * L, const char *cnom, scaled atsize)
+{
+    int cmd, k, i;
+    int cc;
+    unsigned cmd_length, packet_length;
+    scaled tfm_width;
+    vf_stack_index stack_level;
+    /*tex multiplier */
+    int vf_z;
+    /*tex correction for negative values */
+    int vf_alpha;
+    eight_bits *s;
+    scaled h, v;
+    scaled w, x, y, z;
+    /*tex \LUA\ stack */
+    int s_top;
+    /*tex local font counter */
+    int vf_nf;
+    scaled ds, fs;
+    four_quarters cs;
+    /*tex accumulator */
+    memory_word tmp_w;
+    vf_stack_record vf_stack[256];
+    unsigned char *vf_buffer;
+    int vf_size;
+    int vf_cur;
+    unsigned utmp;
+    stack_level = 0;
+    /*tex Open |vf_file|, return if not found. */
+    vf_cur = 0;
+    vf_buffer = NULL;
+    vf_size = 0;
+    if (!open_vf_file(cnom, &vf_buffer, &vf_size)) {
+        lua_pushnil(L);
+        return 1;
+    }
+    /*tex Start by creating a table. */
+    s_top = lua_gettop(L);
+    lua_newtable(L);
+    /*tex Process the preamble. */
+    vf_byte(k);
+    if (k != pre)
+        lua_bad_vf("PRE command expected");
+    vf_byte(k);
+    if (k != vf_id)
+        lua_bad_vf("wrong id byte");
+    vf_byte(cmd_length);
+    s = xmalloc(cmd_length);
+    for (k = 1; k <= (int) cmd_length; k++)
+        vf_byte(s[(k - 1)]);
+    lua_pushlstring(L, (char *) s, (size_t) cmd_length);
+    free(s);
+    lua_setfield(L, -2, "header");
+    vf_byte(cs.b0);
+    vf_byte(cs.b1);
+    vf_byte(cs.b2);
+    vf_byte(cs.b3);
+    lua_pushinteger(L,  (lua_Number) ((cs.b0 << 24) + (cs.b1 << 16) + (cs.b2 << 8) + cs.b3));
+    lua_setfield(L, -2, "checksum");
+    vf_read(4, k);
+    ds = k / 16;
+    lua_pushinteger(L, ds);
+    lua_setfield(L, -2, "designsize");
+    lua_pushstring(L, cnom);
+    lua_setfield(L, -2, "name");
+    lua_pushinteger(L, atsize);
+    lua_setfield(L, -2, "size");
+    vf_z = atsize;
+    vf_replace_z();
+    /*tex Process the font definitions. */
+    vf_byte(cmd);
+    lua_newtable(L);
+    i = 1;
+    while ((cmd >= fnt_def1) && (cmd <= fnt_def1 + 3)) {
+        lua_newtable(L);
+        vf_read_u((cmd - fnt_def1 + 1), utmp);
+        vf_nf = (int) utmp;
+        vf_nf++;
+        /*tex Add a checksum. */
+        vf_byte(cs.b0);
+        vf_byte(cs.b1);
+        vf_byte(cs.b2);
+        vf_byte(cs.b3);
+        vf_read(4, k);
+        fs = store_scaled_f(k, atsize);
+        lua_pushstring(L, "size");
+        lua_pushinteger(L, fs);
+        lua_rawset(L, -3);
+        vf_read(4, k);
+        /*tex |dsize| is not used */
+        ds = k / 16;
+        vf_byte(tmp_b0);
+        vf_byte(tmp_b1);
+        /*tex Skip the font path. */
+        while (tmp_b0 > 0) {
+            tmp_b0--;
+            vf_byte(k);
+        }
+        s = xmalloc((unsigned) (tmp_b1 + 1));
+        k = 0;
+        while (tmp_b1-- > 0)
+            vf_byte(s[k++]);
+        s[k] = 0;
+        lua_pushstring(L, "name");
+        lua_pushstring(L, xstrdup((char *) s));
+        free(s);
+        lua_rawset(L, -3);
+        lua_rawseti(L, -2, vf_nf);
+        i++;
+        vf_byte(cmd);
+    }
+    if (i > 1) {
+        lua_setfield(L, -2, "fonts");
+    } else {
+        lua_pop(L, 1);
+    }
+    /*tex The table; with characters comes next. */
+    lua_newtable(L);
+    while (cmd <= long_char) {
+        /*tex Build a character packet. */
+        if (cmd == long_char) {
+            vf_read_u(4, packet_length);
+            vf_read_u(4, utmp);
+            cc = (int) utmp;
+            vf_read(4, tfm_width);
+        } else {
+            packet_length = (unsigned) cmd;
+            vf_byte(cc);
+            vf_read_u(3, utmp);
+            tfm_width = (int) utmp;
+        }
+        /*tex For this character entry. */
+        lua_newtable(L);
+        lua_pushinteger(L, tfm_width);
+        lua_setfield(L, -2, "width");
+        /*tex for |commands|: */
+        lua_newtable(L);
+        k = 1;
+        vf_nf = 0;
+        w = 0;
+        x = 0;
+        y = 0;
+        z = 0;
+        while (packet_length > 0) {
+            vf_byte(cmd);
+            decr(packet_length);
+            if ((cmd >= set_char_0) && (cmd < set1)) {
+                if (vf_nf == 0) {
+                    vf_nf = 1;
+                    make_command1("font", vf_nf, k);
+                }
+                make_command1("char", cmd, k);
+            } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) || ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
+                if (cmd >= fnt1) {
+                    vf_read_u((cmd - fnt1 + 1), utmp);
+                    vf_nf = (int) utmp;
+                    vf_nf++;
+                    packet_length -= (unsigned) (cmd - fnt1 + 1);
+                } else {
+                    vf_nf = cmd - fnt_num_0 + 1;
+                }
+                make_command1("font", vf_nf, k);
+            } else {
+                switch (cmd) {
+                    case set_rule:
+                        vf_read(4, h);
+                        vf_read(4, v);
+                        make_command2("rule", store_scaled_f(h, atsize),
+                                      store_scaled_f(v, atsize), k);
+                        packet_length -= 8;
+                        break;
+                    case put_rule:
+                        vf_read(4, h);
+                        vf_read(4, v);
+                        make_command0("push", k);
+                        make_command2("rule", store_scaled_f(h, atsize),
+                                      store_scaled_f(v, atsize), k);
+                        make_command0("pop", k);
+                        packet_length -= 8;
+                        break;
+                    case set1:
+                    case set2:
+                    case set3:
+                    case set4:
+                        if (vf_nf == 0) {
+                            vf_nf = 1;
+                            make_command1("font", vf_nf, k);
+                        }
+                        vf_read_u((cmd - set1 + 1), utmp);
+                        i = (int) utmp;
+                        make_command1("char", i, k);
+                        packet_length -= (unsigned) (cmd - set1 + 1);
+                        break;
+                    case put1:
+                    case put2:
+                    case put3:
+                    case put4:
+                        if (vf_nf == 0) {
+                            vf_nf = 1;
+                            make_command1("font", vf_nf, k);
+                        }
+                        vf_read_u((cmd - put1 + 1), utmp);
+                        i = (int) utmp;
+                        make_command0("push", k);
+                        make_command1("char", i, k);
+                        make_command0("pop", k);
+                        packet_length -= (unsigned) (cmd - put1 + 1);
+                        break;
+                    case right1:
+                    case right2:
+                    case right3:
+                    case right4:
+                        vf_read((cmd - right1 + 1), i);
+                        make_command1("right", store_scaled_f(i, atsize), k);
+                        packet_length -= (unsigned) (cmd - right1 + 1);
+                        break;
+                    case w1:
+                    case w2:
+                    case w3:
+                    case w4:
+                        vf_read((cmd - w1 + 1), w);
+                        make_command1("right", store_scaled_f(w, atsize), k);
+                        packet_length -= (unsigned) (cmd - w1 + 1);
+                        break;
+                    case x1:
+                    case x2:
+                    case x3:
+                    case x4:
+                        vf_read((cmd - x1 + 1), x);
+                        make_command1("right", store_scaled_f(x, atsize), k);
+                        packet_length -= (unsigned) (cmd - x1 + 1);
+                        break;
+                    case down1:
+                    case down2:
+                    case down3:
+                    case down4:
+                        vf_read((cmd - down1 + 1), i);
+                        make_command1("down", store_scaled_f(i, atsize), k);
+                        packet_length -= (unsigned) (cmd - down1 + 1);
+                        break;
+                    case y1:
+                    case y2:
+                    case y3:
+                    case y4:
+                        vf_read((cmd - y1 + 1), y);
+                        make_command1("down", store_scaled_f(y, atsize), k);
+                        packet_length -= (unsigned) (cmd - y1 + 1);
+                        break;
+                    case z1:
+                    case z2:
+                    case z3:
+                    case z4:
+                        vf_read((cmd - z1 + 1), z);
+                        make_command1("down", store_scaled_f(z, atsize), k);
+                        packet_length -= (unsigned) (cmd - z1 + 1);
+                        break;
+                    case xxx1:
+                    case xxx2:
+                    case xxx3:
+                    case xxx4:
+                        vf_read_u((cmd - xxx1 + 1), cmd_length);
+                        packet_length -= (unsigned) (cmd - xxx1 + 1);
+                        if (cmd_length <= 0)
+                            lua_bad_vf("special of negative length");
+                        packet_length -= cmd_length;
+                        s = xmalloc((cmd_length + 1));
+                        i = 0;
+                        while (cmd_length > 0) {
+                            cmd_length--;
+                            vf_byte(s[i]);
+                            i++;
+                        }
+                        s[i] = 0;
+                        make_commands("special", xstrdup((char *) s), (size_t) i, k);
+                        free(s);
+                        break;
+                    case w0:
+                        make_command1("right", store_scaled_f(w, atsize), k);
+                        break;
+                    case x0:
+                        make_command1("right", store_scaled_f(x, atsize), k);
+                        break;
+                    case y0:
+                        make_command1("down", store_scaled_f(y, atsize), k);
+                        break;
+                    case z0:
+                        make_command1("down", store_scaled_f(z, atsize), k);
+                        break;
+                    case nop:
+                        break;
+                    case push:
+                        if (stack_level == vf_stack_size) {
+                            overflow("virtual font stack size", vf_stack_size);
+                        } else {
+                            vf_stack[stack_level].stack_w = w;
+                            vf_stack[stack_level].stack_x = x;
+                            vf_stack[stack_level].stack_y = y;
+                            vf_stack[stack_level].stack_z = z;
+                            incr(stack_level);
+                            make_command0("push", k);
+                        }
+                        break;
+                    case pop:
+                        if (stack_level == 0) {
+                            lua_bad_vf("more POPs than PUSHs in character");
+                        } else {
+                            decr(stack_level);
+                            w = vf_stack[stack_level].stack_w;
+                            x = vf_stack[stack_level].stack_x;
+                            y = vf_stack[stack_level].stack_y;
+                            z = vf_stack[stack_level].stack_z;
+                            make_command0("pop", k);
+                        }
+                        break;
+                    default:
+                        lua_bad_vf("improver DVI command");
+                }
+            }
+        }
+        /*tex Signal end of packet. */
+        lua_setfield(L, -2, "commands");
+        if (stack_level != 0)
+            lua_bad_vf("more PUSHs than POPs in character packet");
+        if (packet_length != 0)
+            lua_bad_vf("invalid packet length or DVI command in packet");
+        lua_rawseti(L, -2, cc);
+        vf_byte(cmd);
+    }
+    lua_setfield(L, -2, "characters");
+    if (cmd != post)
+        lua_bad_vf("POST command expected");
+    xfree(vf_buffer);
+    return 1;
+}
+
+internal_font_number letter_space_font(internal_font_number f, int e, boolean nolig)
+{
+    internal_font_number k;
+    scaled w;
+    int c;
+    charinfo *co;
+    char *new_font_name;
+    /*tex Read a new font and expand the character widths. */
+    k = copy_font(f);
+    if (nolig) {
+        /*tex Disable ligatures for letter-spaced fonts. */
+        set_no_ligatures(k);
+    }
+    /*tex append e.g. |+100ls| to font name; |abs(e) <= 1000|. */
+    new_font_name = xmalloc((unsigned) (strlen(font_name(k)) + 8));
+    if (e > 0) {
+        sprintf(new_font_name, "%s+%ils", font_name(k), (int) e);
+    } else {
+        /*tex Minus from |%i|: */
+        sprintf(new_font_name, "%s%ils", font_name(k), (int) e);
+    }
+    set_font_name(k, new_font_name);
+    /* Create the corresponding virtual font. */
+    set_font_type(k, virtual_font_type);
+    for (c=font_bc(k);c<=font_ec(k);c++) {
+       if (quick_char_exists(k, c)) {
+           int half_w;
+           int vf_np = 0;
+           eight_bits *vpackets = xmalloc((unsigned) (10+10+1));
+           if (e<0) {
+             half_w = -round_xn_over_d(quad(k), -e, 2000);
+           } else {
+             half_w  = round_xn_over_d(quad(k), e, 2000);
+           }
+           co = get_charinfo(k, c);
+           w = char_width(k, c)+2*half_w;
+           set_charinfo_width(co, w);
+           append_packet(packet_right_code);
+           append_four(half_w);
+           append_fnt_set(f);
+           append_packet(packet_char_code);
+           append_four(c);
+           append_packet(packet_right_code);
+           append_four(half_w);
+           append_packet(packet_end_code);
+           set_charinfo_packets(co, vpackets);
+       }
+    }
+    /*tex Now patch the quad size. Ok, not in order to remain compatible with \PDFTEX: */
+#if 0
+    if (e<0) {
+       set_font_param(k, quad_code, -round_xn_over_d(quad(k), 1000-e, 1000));
+    } else {
+       set_font_param(k, quad_code, round_xn_over_d(quad(k), 1000+e, 1000));
+    }
+#endif
+    return k;
+}
+
+internal_font_number copy_font_info(internal_font_number f)
+{
+    return copy_font(f);
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfovf.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1480 +0,0 @@
-% vfovf.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ @c
-/* this is a hack! */
-#define font_max 5000
-
-#define set_char_0 0            /* typeset character 0 and move right */
-#define set1 128                /* typeset a character and move right */
-#define set2 129                /* typeset a character and move right */
-#define set3 130                /* typeset a character and move right */
-#define set4 131                /* typeset a character and move right */
-#define set_rule 132            /* typeset a rule and move right */
-#define put1  133               /* typeset a character without moving */
-#define put2  134               /* typeset a character without moving */
-#define put3  135               /* typeset a character without moving */
-#define put4  136               /* typeset a character without moving */
-#define put_rule 137            /* typeset a rule */
-#define nop 138                 /* no operation */
-#define bop 139                 /* beginning of page */
-#define eop 140                 /* ending of page */
-#define push 141                /* save the current positions */
-#define pop 142                 /* restore previous positions */
-#define right1  143             /* move right */
-#define right2  144             /* move right */
-#define right3  145             /* move right */
-#define right4  146             /* move right, 4 bytes */
-#define w0 147                  /* move right by |w| */
-#define w1 148                  /* move right and set |w| */
-#define w2 149                  /* move right and set |w| */
-#define w3 150                  /* move right and set |w| */
-#define w4 151                  /* move right and set |w| */
-#define x0 152                  /* move right by |x| */
-#define x1 153                  /* move right and set |x| */
-#define x2 154                  /* move right and set |x| */
-#define x3 155                  /* move right and set |x| */
-#define x4 156                  /* move right and set |x| */
-#define down1 157               /* move down */
-#define down2 158               /* move down */
-#define down3 159               /* move down */
-#define down4 160               /* move down, 4 bytes */
-#define y0 161                  /* move down by |y| */
-#define y1 162                  /* move down and set |y| */
-#define y2 163                  /* move down and set |y| */
-#define y3 164                  /* move down and set |y| */
-#define y4 165                  /* move down and set |y| */
-#define z0 166                  /* move down by |z| */
-#define z1 167                  /* move down and set |z| */
-#define z2 168                  /* move down and set |z| */
-#define z3 169                  /* move down and set |z| */
-#define z4 170                  /* move down and set |z| */
-#define fnt_num_0 171           /* set current font to 0 */
-#define fnt1 235                /* set current font */
-#define fnt2 236                /* set current font */
-#define fnt3 237                /* set current font */
-#define fnt4 238                /* set current font */
-#define xxx1 239                /* extension to DVI  primitives */
-#define xxx2 240                /* extension to DVI  primitives */
-#define xxx3 241                /* extension to DVI  primitives */
-#define xxx4 242                /* potentially long extension to DVI primitives */
-#define fnt_def1 243            /* define the meaning of a font number */
-#define pre 247                 /* preamble */
-#define post 248                /* postamble beginning */
-#define post_post 249           /* postamble ending */
-#define yyy1 250                /* PDF literal text */
-#define yyy2 251                /* PDF literal text */
-#define yyy3 252                /* PDF literal text */
-#define yyy4 253                /* PDF literal text */
-
-#define null_font 0
-
-#define long_char 242           /* \.{VF} command for general character packet */
-#define vf_id 202               /* identifies \.{VF} files */
-
-@ go out \.{VF} processing with an error message
- at c
-#define bad_vf(a) { \
-    xfree(vf_buffer); \
-    print_nlp(); \
-    formatted_warning("virtual font","file '%s', %s, font will be ignored",font_name(f),a); \
-    print_ln(); \
-    return; \
-}
-
-#define lua_bad_vf(a) { \
-    xfree(vf_buffer); \
-    lua_settop(L,s_top); \
-    lua_pushnil(L); \
-    lua_pushstring(L,a); \
-    return 2; \
-}
-
-#define tmp_b0  tmp_w.qqqq.b0
-#define tmp_b1  tmp_w.qqqq.b1
-#define tmp_b2  tmp_w.qqqq.b2
-#define tmp_b3  tmp_w.qqqq.b3
-#define tmp_int tmp_w.cint
-
-#define vf_stack_size 100       /* \.{DVI} files shouldn't |push| beyond this depth */
-
-@ @c
-typedef unsigned char vf_stack_index;   /* an index into the stack */
-
-typedef struct vf_stack_record {
-    scaled stack_w, stack_x, stack_y, stack_z;
-} vf_stack_record;
-
-@ get a byte from\.{VF} file
- at c
-#define vf_byte(a)                                     \
-{                                                      \
-  eight_bits vf_tmp_b;				                   \
-    if (vf_cur >= vf_size) {                           \
-        normal_error("virtual font","unexpected eof"); \
-    }                                                  \
-    vf_tmp_b = vf_buffer[vf_cur++];                    \
-    a = vf_tmp_b;                                      \
-}
-
-@ @c
-#define vf_replace_z()                           \
-{                                                \
-    vf_alpha = 16;                               \
-    while (vf_z >= 040000000) {                  \
-        vf_z = vf_z / 2;                         \
-        vf_alpha += vf_alpha;                    \
-    }                                            \
-    /*vf_beta = (char)(256 / vf_alpha);*/	 \
-    vf_alpha = (vf_alpha * vf_z);		 \
-}
-
-
-@ read |k| bytes as an integer from \.{VF} file
-beware: the |vf_read()| macro differs from |vf_read()| in vftovp.web for 1...3 byte words.
- at c
-#define vf_read(k, l)                            \
-{                                                \
-    int itmp = 0, dtmp = (int)(k), jtmp = 0;	 \
-    while (dtmp > 0) {                           \
-        vf_byte(jtmp);                           \
-        if ((dtmp == (int) k) && jtmp > 127)     \
-            jtmp = jtmp - 256;                   \
-        itmp = itmp * 256 + jtmp;                \
-        decr(dtmp);                              \
-    }                                            \
-    l = itmp;                                    \
-}
-
-#define vf_read_u(k, l)                          \
-{                                                \
-    int dtmp = (int)(k);			 \
-    unsigned int itmp = 0, jtmp = 0;		 \
-    while (dtmp-- > 0) {                         \
-        vf_byte(jtmp);                           \
-        itmp = itmp * 256 + jtmp;                \
-    }                                            \
-    l = itmp;                                    \
-}
-
-@ @c
-void pdf_check_vf(internal_font_number f)
-{
-    if (font_type(f) == virtual_font_type)
-        normal_error("font", "command cannot be used with virtual font");
-}
-
-static void
-vf_local_font_warning(internal_font_number f, internal_font_number k, const char *s, int a, int b)
-{
-    print_nlp();
-    tprint(s);
-    tprint(" in local font ");
-    tprint(font_name(k));
-    tprint(" (");
-    print_int(b);
-    tprint(" != ");
-    print_int(a);
-    tprint(") in virtual font ");
-    tprint(font_name(f));
-    tprint(".vf ignored.");
-}
-
-
-@ process a local font in \.{VF} file
- at c
-int level = 0;
-
-static internal_font_number
-vf_def_font(internal_font_number f, unsigned char *vf_buffer, int *vf_cr)
-{
-    internal_font_number k;
-    str_number s;
-    char *st;
-    scaled ds, fs;
-    four_quarters cs;
-    memory_word tmp_w;          /* accumulator */
-    int junk;
-    unsigned int checksum;
-    cs.b0 = vf_buffer[(*vf_cr)];
-    cs.b1 = vf_buffer[(*vf_cr) + 1];
-    cs.b2 = vf_buffer[(*vf_cr) + 2];
-    cs.b3 = vf_buffer[(*vf_cr) + 3];
-    (*vf_cr) += 4;
-    checksum = (unsigned)
-        (cs.b0 * 256 * 256 * 256 + cs.b1 * 256 * 256 + cs.b2 * 256 + cs.b3);
-    k = vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    if (k > 127)
-        k -= 256;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-
-    fs = store_scaled_f(k, font_size(f));
-
-    k = vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    if (k > 127)
-        k -= 256;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    k = k * 256 + vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-
-    ds = k / 16;
-
-
-    tmp_b0 = vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    tmp_b1 = vf_buffer[(*vf_cr)];
-    (*vf_cr)++;
-    while (tmp_b0 > 0) {
-        tmp_b0--;
-        (*vf_cr)++;             /* skip the font path */
-    }
-    str_room((unsigned) tmp_b1);
-    while (tmp_b1 > 0) {
-        tmp_b1--;
-        junk = vf_buffer[(*vf_cr)];
-        (*vf_cr)++;
-        append_char(junk);
-    }
-    if (level > 5) {
-        normal_warning("vf","quitting at recurse depth > 5");
-        k = f ;
-    } else if ((level > 1) && (fs > 65536*1024)) {
-        normal_warning("vf","quitting when recursing at size > 65536*1024");
-        k = f ;
-    } else {
-        level += 1 ;
-        s = make_string();
-        st = makecstring(s);
-        k = tfm_lookup(st, fs);
-        if (k == null_font)
-            k = read_font_info(null_cs, st, fs, -1);
-        free(st);
-        level -= 1 ;
-        if (k != null_font) {
-            if (checksum != 0 && font_checksum(k) != 0
-                && checksum != font_checksum(k))
-                vf_local_font_warning(f, k, "checksum mismatch", (int) checksum, (int) font_checksum(k));
-            if (ds != font_dsize(k))
-                vf_local_font_warning(f, k, "design size mismatch", ds, font_dsize(k));
-        }
-    }
-    return k;
-}
-
-@ @c
-static int open_vf_file(const char *fn, unsigned char **vbuffer, int *vsize)
-{
-    boolean res;                /* was the callback successful? */
-    int callback_id;
-    boolean file_read = false;  /* was |vf_file| successfully read? */
-    FILE *vf_file;
-    const char *fname = luatex_find_file(fn, find_vf_file_callback);
-    if (fname == NULL || strlen(fname) == 0) {
-       /* fname = fn; */
-       return 0;
-    }
-
-    callback_id = callback_defined(read_vf_file_callback);
-    if (callback_id > 0) {
-        res = run_callback(callback_id, "S->bSd", fname,
-                           &file_read, vbuffer, vsize);
-        if (res && file_read && (*vsize > 0)) {
-            return 1;
-        }
-        if (!file_read)
-            return 0;           /* -1 */
-    } else {
-        if (luatex_open_input
-            (&(vf_file), fname, kpse_ovf_format, FOPEN_RBIN_MODE, false)
-            || luatex_open_input(&(vf_file), fname, kpse_vf_format,
-                                 FOPEN_RBIN_MODE, false)) {
-            res = read_vf_file(vf_file, vbuffer, vsize);
-            close_file(vf_file);
-            if (res) {
-                return 1;
-            }
-        } else {
-            return 0;           /* -1 */
-        }
-    }
-    return 0;
-}
-
-
-
-@ The |do_vf| procedure attempts to read the \.{VF} file for a font, and sets
-  |font_type()| to |real_font_type| if the \.{VF} file could not be found
-  or loaded, otherwise sets |font_type()| to |virtual_font_type|.  At this
-  time, |tmp_f| is the internal font number of the current \.{TFM} font.  To
-  process font definitions in virtual font we call |vf_def_font|.
-
- at c
-#define append_packet(k) vpackets[vf_np++] = (eight_bits)(k)
-
-@ life is easier if all internal font commands are fnt4 and
-   all character commands are set4 or put4
-
- at c
-#define append_fnt_set(k)            \
-{                                    \
-    assert(k > 0);                   \
-    append_packet(packet_font_code); \
-    append_four(k);                  \
-}
-
-#define append_four(k)                     \
-{                                          \
-    append_packet((k & 0xFF000000) >> 24); \
-    append_packet((k & 0x00FF0000) >> 16); \
-    append_packet((k & 0x0000FF00) >> 8);  \
-    append_packet((k & 0x000000FF));       \
-}
-
-@ some of these things happen twice, adding a define is simplest
-
- at c
-#define test_checksum()  { vf_byte(tmp_b0); vf_byte(tmp_b1);    \
-    vf_byte(tmp_b2); vf_byte(tmp_b3);         \
-    if (((tmp_b0 != 0) || (tmp_b1 != 0) || (tmp_b2 != 0) || (tmp_b3 != 0)) && \
-  ((font_check_0(f) != 0) || (font_check_1(f) != 0) ||    \
-   (font_check_2(f) != 0) || (font_check_3(f) != 0)) &&   \
-  ((tmp_b0 != font_check_0(f)) || (tmp_b1 != font_check_1(f)) ||  \
-   (tmp_b2 != font_check_2(f)) || (tmp_b3 != font_check_3(f)))) { \
-      print_nlp();              \
-      tprint("checksum mismatch in font ");     \
-      tprint(font_name(f));         \
-      tprint(".vf ignored "); } }
-
-#define test_dsize()                                   \
-{                                                      \
-    int read_tmp;                                      \
-    vf_read(4, read_tmp);                              \
-    if ((read_tmp / 16) != font_dsize(f)) {            \
-        print_nlp();                                   \
-        tprint("design size mismatch in font ");       \
-        tprint(font_name(f));			       \
-        tprint(".vf ignored");			       \
-    }                                                  \
-}
-
-@ @c
-static int count_packet_bytes(eight_bits * vf_buf, int cur_bute, int count)
-{
-    unsigned k = 0;
-    int ff = 0;
-    int acc = 0;
-    unsigned int cmd = 0;
-    unsigned int d = 0;
-    while (k < (unsigned) count) {
-        cmd = vf_buf[cur_bute + (int) k];
-        k++;
-        if (cmd < set1) {
-            if (ff == 0) {
-                ff = 1;
-                acc += 5;
-            }
-            acc += 5;
-        } else if ((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) {
-            ff = 1;
-            acc += 5;
-        } else {
-            switch (cmd) {
-            case fnt1:
-                acc += 5;
-                k += 1;
-                ff = 1;
-                break;
-            case fnt2:
-                acc += 5;
-                k += 2;
-                ff = 1;
-                break;
-            case fnt3:
-                acc += 5;
-                k += 3;
-                ff = 1;
-                break;
-            case fnt4:
-                acc += 5;
-                k += 4;
-                ff = 1;
-                break;
-            case set_rule:
-                acc += 9;
-                k += 8;
-                break;
-            case put_rule:
-                acc += 11;
-                k += 8;
-                break;
-            case set1:
-                acc += 5;
-                k += 1;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case set2:
-                acc += 5;
-                k += 2;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case set3:
-                acc += 5;
-                k += 3;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case set4:
-                acc += 5;
-                k += 4;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case put1:
-                acc += 7;
-                k += 1;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case put2:
-                acc += 7;
-                k += 2;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case put3:
-                acc += 7;
-                k += 3;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case put4:
-                acc += 7;
-                k += 4;
-                if (ff == 0) {
-                    ff = 1;
-                    acc += 5;
-                }
-                break;
-            case right1:
-                acc += 5;
-                k += 1;
-                break;
-            case right2:
-                acc += 5;
-                k += 2;
-                break;
-            case right3:
-                acc += 5;
-                k += 3;
-                break;
-            case right4:
-                acc += 5;
-                k += 4;
-                break;
-            case w1:
-                acc += 5;
-                k += 1;
-                break;
-            case w2:
-                acc += 5;
-                k += 2;
-                break;
-            case w3:
-                acc += 5;
-                k += 3;
-                break;
-            case w4:
-                acc += 5;
-                k += 4;
-                break;
-            case x1:
-                acc += 5;
-                k += 1;
-                break;
-            case x2:
-                acc += 5;
-                k += 2;
-                break;
-            case x3:
-                acc += 5;
-                k += 3;
-                break;
-            case x4:
-                acc += 5;
-                k += 4;
-                break;
-            case down1:
-                acc += 5;
-                k += 1;
-                break;
-            case down2:
-                acc += 5;
-                k += 2;
-                break;
-            case down3:
-                acc += 5;
-                k += 3;
-                break;
-            case down4:
-                acc += 5;
-                k += 4;
-                break;
-            case y1:
-                acc += 5;
-                k += 1;
-                break;
-            case y2:
-                acc += 5;
-                k += 2;
-                break;
-            case y3:
-                acc += 5;
-                k += 3;
-                break;
-            case y4:
-                acc += 5;
-                k += 4;
-                break;
-            case z1:
-                acc += 5;
-                k += 1;
-                break;
-            case z2:
-                acc += 5;
-                k += 2;
-                break;
-            case z3:
-                acc += 5;
-                k += 3;
-                break;
-            case z4:
-                acc += 5;
-                k += 4;
-                break;
-            case xxx1:
-                d = vf_buf[cur_bute + (int) k];
-                k++;
-                k += d;
-                acc += 5 + (int) d;
-                break;
-            case xxx2:
-                d = vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                k += d;
-                acc += 5 + (int) d;
-                break;
-            case xxx3:
-                d = vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                k += d;
-                acc += 5 + (int) d;
-                break;
-            case xxx4:
-                d = vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                d = d * 256 + vf_buf[cur_bute + (int) k];
-                k++;
-                k += d;
-                acc += 5 + (int) d;
-                break;
-            case w0:
-                acc += 5;
-                break;
-            case x0:
-                acc += 5;
-                break;
-            case y0:
-                acc += 5;
-                break;
-            case z0:
-                acc += 5;
-                break;
-            case nop:
-                break;
-            case push:
-                acc += 1;
-                break;
-            case pop:
-                acc += 1;
-                break;
-            }
-        }
-    }
-    return (acc + 1);
-}
-
-@ @c
-void do_vf(internal_font_number f)
-{
-    int k, i;
-    unsigned cmd, n;
-    scaled x, y, w, z, h, v;
-    int cc, cmd_length;
-    unsigned packet_length;
-    charinfo *co;
-    scaled tfm_width;
-    int save_cur_byte;
-    vf_stack_index stack_level;
-    int vf_z;                   /* multiplier */
-    int vf_alpha;               /* correction for negative values */
-    /*char vf_beta;*/               /* divisor */
-    int vf_np;
-    eight_bits *vpackets;
-    memory_word tmp_w;          /* accumulator */
-    vf_stack_record vf_stack[256];
-    int junk;
-    unsigned utmp;
-    unsigned char *vf_buffer;
-    int vf_size;
-    int vf_cur;
-    unsigned *vf_local_fnts = NULL;     /* external font ids */
-    unsigned *vf_real_fnts = NULL;      /* internal font ids */
-    unsigned vf_nf = 0;         /* local font counter */
-
-    if (font_type(f) != unknown_font_type)
-        return;
-    set_font_type(f, real_font_type);
-    stack_level = 0;
-    /* Open |vf_file|, return if not found */
-    vf_cur = 0;
-    vf_buffer = NULL;
-    vf_size = 0;
-    if (!open_vf_file(font_name(f), &vf_buffer, &vf_size))
-        return;
-    /* Process the preamble */
-    set_font_type(f, virtual_font_type);
-    vf_byte(k);
-    if (k != pre)
-        bad_vf("PRE command expected");
-    vf_byte(k);
-    if (k != vf_id)
-        bad_vf("wrong id byte");
-    vf_byte(cmd_length);
-    for (k = 1; k <= cmd_length; k++)
-        vf_byte(junk);
-    test_checksum();
-    test_dsize();
-    vf_z = font_size(f);
-    vf_replace_z();
-    /* Process the font definitions */
-    /* scan forward to find the number of internal fonts */
-    vf_nf = 0;
-    save_cur_byte = vf_cur;
-    vf_byte(cmd);
-    while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
-        vf_read_u((cmd - fnt_def1 + 1), utmp);
-        vf_read(4, junk);
-        vf_read(4, junk);
-        vf_read(4, junk);
-        vf_byte(k);
-        vf_byte(junk);
-        k += junk;
-        while (k-- > 0) {
-            vf_byte(junk);
-        }
-        incr(vf_nf);
-        vf_byte(cmd);
-    }
-    vf_cur = save_cur_byte;
-    vf_byte(cmd);
-    /* malloc and fill the local font arrays */
-    if (vf_nf > 0) {
-        unsigned ii = (unsigned) ((unsigned) vf_nf * sizeof(int));
-        vf_local_fnts = xmalloc(ii);
-        memset(vf_local_fnts, 0, ii);
-        vf_real_fnts = xmalloc(ii);
-        memset(vf_real_fnts, 0, ii);
-        vf_nf = 0;
-        while ((cmd >= fnt_def1) && (cmd <= (fnt_def1 + 3))) {
-            vf_read_u((cmd - fnt_def1 + 1), vf_local_fnts[vf_nf]);
-            vf_real_fnts[vf_nf] = (unsigned) vf_def_font(f, vf_buffer, &vf_cur);
-            incr(vf_nf);
-            vf_byte(cmd);
-        }
-    }
-
-
-    while (cmd <= long_char) {
-        /* Build a character packet */
-        vf_np = 0;
-        if (cmd == long_char) {
-            vf_read_u(4, packet_length);
-            vf_read_u(4, utmp);
-            cc = (int) utmp;
-            if (!char_exists(f, cc)) {
-                bad_vf("invalid character code");
-            }
-            vf_read(4, k);
-            tfm_width = store_scaled_f(k, font_size(f));
-        } else {
-            packet_length = cmd;
-            vf_byte(cc);
-            if (!char_exists(f, cc)) {
-                bad_vf("invalid character code");
-            }
-            vf_read_u(3, utmp);
-            k = (int) utmp;     /* cf. vftovp.web, line 1028 */
-            tfm_width = store_scaled_f(k, font_size(f));
-        }
-
-
-        if (tfm_width != char_width(f, cc)) {
-            if (tfm_width != char_width(f, cc)) {
-                print_nlp();
-                tprint("character width mismatch in font ");
-                tprint(font_name(f));
-                tprint(".vf ignored");
-            }
-        }
-        k = count_packet_bytes(vf_buffer, vf_cur, (int) packet_length);
-        vpackets = xmalloc((unsigned) (k + 1)); /* need one extra extra for |packet_end| */
-        co = get_charinfo(f, cc);
-        k = 0;
-        w = 0;
-        x = 0;
-        y = 0;
-        z = 0;
-        while (packet_length > 0) {
-            vf_byte(cmd);
-            decr(packet_length);
-
-            if (cmd < set1) {
-                if (k == 0) {
-                    k = (int) vf_real_fnts[0];
-                    append_fnt_set(k);
-                }
-                append_packet(packet_char_code);
-                append_four(cmd);
-                cmd_length = 0;
-                cmd = nop;
-
-            } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
-                       ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
-                if (cmd >= fnt1) {
-                    vf_read_u((cmd - fnt1 + 1), utmp);
-                    k = (int) utmp;
-                    packet_length -= (cmd - fnt1 + 1);
-                } else {
-                    k = (int) cmd - fnt_num_0;
-                }
-
-                /*  change from local to external font id */
-                n = 0;
-                while ((n < vf_nf) && (vf_local_fnts[n] != (unsigned) k))
-                    n++;
-                if (n == vf_nf)
-                    bad_vf("undefined local font");
-
-                k = (int) vf_real_fnts[n];
-                append_fnt_set(k);
-                cmd_length = 0;
-                cmd = nop;
-            } else {
-                switch (cmd) {
-                case set_rule:
-                    vf_read(4, h);
-                    vf_read(4, v);
-                    append_packet(packet_rule_code);
-                    append_four(h);
-                    append_four(v);
-                    packet_length -= 8;
-                    break;
-                case put_rule:
-                    vf_read(4, h);
-                    vf_read(4, v);
-                    append_packet(packet_push_code);
-                    append_packet(packet_rule_code);
-                    append_four(h);
-                    append_four(v);
-                    append_packet(packet_pop_code);
-                    packet_length -= 8;
-                    break;
-                case set1:
-                case set2:
-                case set3:
-                case set4:
-                    if (k == 0) {
-                        k = (int) vf_real_fnts[0];
-                        append_fnt_set(k);
-                    }
-                    vf_read_u((cmd - set1 + 1), utmp);
-                    i = (int) utmp;
-                    append_packet(packet_char_code);
-                    append_four(i);
-                    packet_length -= (cmd - set1 + 1);
-                    break;
-                case put1:
-                case put2:
-                case put3:
-                case put4:
-                    if (k == 0) {
-                        k = (int) vf_real_fnts[0];
-                        append_fnt_set(k);
-                    }
-                    vf_read_u((cmd - put1 + 1), utmp);
-                    i = (int) utmp;
-                    append_packet(packet_push_code);
-                    append_packet(packet_char_code);
-                    append_four(i);
-                    append_packet(packet_pop_code);
-                    packet_length -= (cmd - put1 + 1);
-                    break;
-                case right1:
-                case right2:
-                case right3:
-                case right4:
-                    vf_read((cmd - right1 + 1), i);
-                    append_packet(packet_right_code);
-                    append_four(i);
-                    packet_length -= (cmd - right1 + 1);
-                    break;
-                case w1:
-                case w2:
-                case w3:
-                case w4:
-                    vf_read((cmd - w1 + 1), w);
-                    append_packet(packet_right_code);
-                    append_four(w);
-                    packet_length -= (cmd - w1 + 1);
-                    break;
-                case x1:
-                case x2:
-                case x3:
-                case x4:
-                    vf_read((cmd - x1 + 1), x);
-                    append_packet(packet_right_code);
-                    append_four(x);
-                    packet_length -= (cmd - x1 + 1);
-                    break;
-                case down1:
-                case down2:
-                case down3:
-                case down4:
-                    vf_read((cmd - down1 + 1), i);
-                    append_packet(packet_down_code);
-                    append_four(i);
-                    packet_length -= (cmd - down1 + 1);
-                    break;
-                case y1:
-                case y2:
-                case y3:
-                case y4:
-                    vf_read((cmd - y1 + 1), y);
-                    append_packet(packet_down_code);
-                    append_four(y);
-                    packet_length -= (cmd - y1 + 1);
-                    break;
-                case z1:
-                case z2:
-                case z3:
-                case z4:
-                    vf_read((cmd - z1 + 1), z);
-                    append_packet(packet_down_code);
-                    append_four(z);
-                    packet_length -= (cmd - z1 + 1);
-                    break;
-                case xxx1:
-                case xxx2:
-                case xxx3:
-                case xxx4:
-                    vf_read_u((cmd - xxx1 + 1), utmp);
-                    cmd_length = (int) utmp;
-                    packet_length -= (cmd - xxx1 + 1);
-                    if (cmd_length <= 0)
-                        bad_vf("special of negative length");
-                    packet_length -= (unsigned) cmd_length;
-
-                    append_packet(packet_special_code);
-                    append_four(cmd_length);
-                    while (cmd_length > 0) {
-                        cmd_length--;
-                        vf_byte(i);
-                        append_packet(i);
-                    }
-                    break;
-                case w0:
-                    append_packet(packet_right_code);
-                    append_four(w);
-                    break;
-                case x0:
-                    append_packet(packet_right_code);
-                    append_four(x);
-                    break;
-                case y0:
-                    append_packet(packet_down_code);
-                    append_four(y);
-                    break;
-                case z0:
-                    append_packet(packet_down_code);
-                    append_four(z);
-                    break;
-                case nop:
-                    break;
-                case push:
-                    if (stack_level == vf_stack_size) {
-                        overflow("virtual font stack size", vf_stack_size);
-                    } else {
-                        vf_stack[stack_level].stack_w = w;
-                        vf_stack[stack_level].stack_x = x;
-                        vf_stack[stack_level].stack_y = y;
-                        vf_stack[stack_level].stack_z = z;
-                        incr(stack_level);
-                        append_packet(packet_push_code);
-                    }
-                    break;
-                case pop:
-                    if (stack_level == 0) {
-                        bad_vf("more POPs than PUSHs in character");
-                    } else {
-                        decr(stack_level);
-                        w = vf_stack[stack_level].stack_w;
-                        x = vf_stack[stack_level].stack_x;
-                        y = vf_stack[stack_level].stack_y;
-                        z = vf_stack[stack_level].stack_z;
-                        append_packet(packet_pop_code);
-                    }
-                    break;
-                default:
-                    bad_vf("improver DVI command");
-                }
-            }
-        }
-        /* signal end of packet */
-        append_packet(packet_end_code);
-
-        if (stack_level != 0)
-            bad_vf("more PUSHs than POPs in character packet");
-        if (packet_length != 0)
-            bad_vf("invalid packet length or DVI command in packet");
-        /* \.{Store the packet being built} */
-        set_charinfo_packets(co, vpackets);
-        vf_byte(cmd);
-    }
-    if (cmd != post)
-        bad_vf("POST command expected");
-
-    xfree(vf_buffer);
-}
-
-@ @c
-#define make_command0(N,K) { \
-    lua_newtable(L);         \
-    lua_pushstring(L, N);    \
-    lua_rawseti(L,-2, 1);    \
-    lua_rawseti(L,-2, K);    \
-    K++; }
-
-#define make_command1(N,V,K) { \
-    lua_newtable(L);           \
-    lua_pushstring(L, N);      \
-    lua_rawseti(L,-2, 1);      \
-    lua_pushinteger(L, V);     \
-    lua_rawseti(L,-2, 2);      \
-    lua_rawseti(L,-2, K);      \
-    K++; }
-
-#define make_command2(N,V,W,K) { \
-    lua_newtable(L);             \
-    lua_pushstring(L, N);        \
-    lua_rawseti(L,-2, 1);        \
-    lua_pushinteger(L, V);       \
-    lua_rawseti(L,-2, 2);        \
-    lua_pushinteger(L, W);       \
-    lua_rawseti(L,-2, 3);        \
-    lua_rawseti(L,-2, K);        \
-    K++; }
-
-#define make_commands(N,S,V,K) {    \
-    lua_newtable(L);        \
-    lua_pushstring(L, N);     \
-    lua_rawseti(L,-2, 1);     \
-    lua_pushlstring(L, S, V);     \
-    lua_rawseti(L,-2, 2);     \
-    lua_rawseti(L,-2, K);     \
-    K++; }
-
-
-int make_vf_table(lua_State * L, const char *cnom, scaled atsize)
-{
-    int cmd, k, i;
-    int cc;
-    unsigned cmd_length, packet_length;
-    scaled tfm_width;
-    vf_stack_index stack_level;
-    int vf_z;                   /* multiplier */
-    int vf_alpha;               /* correction for negative values */
-    /*char vf_beta;*/               /* divisor */
-    eight_bits *s;
-    scaled h, v;
-    scaled w, x, y, z;
-    int s_top;                  /* lua stack */
-    int vf_nf;                  /* local font counter */
-    scaled ds, fs;
-    four_quarters cs;
-    memory_word tmp_w;          /* accumulator */
-    vf_stack_record vf_stack[256];
-    unsigned char *vf_buffer;
-    int vf_size;
-    int vf_cur;
-    unsigned utmp;
-
-
-    stack_level = 0;
-    /* Open |vf_file|, return if not found */
-    vf_cur = 0;
-    vf_buffer = NULL;
-    vf_size = 0;
-    if (!open_vf_file(cnom, &vf_buffer, &vf_size)) {
-        lua_pushnil(L);
-        return 1;
-    }
-
-    /* start by creating a table */
-    s_top = lua_gettop(L);
-    lua_newtable(L);
-
-    /* Process the preamble */
-    vf_byte(k);
-    if (k != pre)
-        lua_bad_vf("PRE command expected");
-    vf_byte(k);
-    if (k != vf_id)
-        lua_bad_vf("wrong id byte");
-    vf_byte(cmd_length);
-
-    s = xmalloc(cmd_length);
-    for (k = 1; k <= (int) cmd_length; k++)
-        vf_byte(s[(k - 1)]);
-
-    lua_pushlstring(L, (char *) s, (size_t) cmd_length);
-    free(s);
-    lua_setfield(L, -2, "header");
-
-    vf_byte(cs.b0);
-    vf_byte(cs.b1);
-    vf_byte(cs.b2);
-    vf_byte(cs.b3);
-    lua_pushinteger(L,  (lua_Number) ((cs.b0 << 24) + (cs.b1 << 16) + (cs.b2 << 8) + cs.b3));
-    lua_setfield(L, -2, "checksum");
-
-    vf_read(4, k);
-    ds = k / 16;
-    lua_pushinteger(L, ds);
-    lua_setfield(L, -2, "designsize");
-
-
-    lua_pushstring(L, cnom);
-    lua_setfield(L, -2, "name");
-
-    lua_pushinteger(L, atsize);
-    lua_setfield(L, -2, "size");
-
-    vf_z = atsize;
-    vf_replace_z();
-    /* Process the font definitions */
-    vf_byte(cmd);
-    lua_newtable(L);
-
-    i = 1;
-    while ((cmd >= fnt_def1) && (cmd <= fnt_def1 + 3)) {
-
-        lua_newtable(L);
-        vf_read_u((cmd - fnt_def1 + 1), utmp);
-        vf_nf = (int) utmp;
-        vf_nf++;
-        /* checksum */
-        vf_byte(cs.b0);
-        vf_byte(cs.b1);
-        vf_byte(cs.b2);
-        vf_byte(cs.b3);
-
-        vf_read(4, k);
-        fs = store_scaled_f(k, atsize);
-        lua_pushstring(L, "size");
-        lua_pushinteger(L, fs);
-        lua_rawset(L, -3);
-
-        vf_read(4, k);
-        ds = k / 16;            /* dsize, not used */
-
-        vf_byte(tmp_b0);
-        vf_byte(tmp_b1);
-        while (tmp_b0 > 0) {
-            tmp_b0--;
-            vf_byte(k);
-        }                       /* skip the font path */
-
-        s = xmalloc((unsigned) (tmp_b1 + 1));
-        k = 0;
-        while (tmp_b1-- > 0)
-            vf_byte(s[k++]);
-        s[k] = 0;
-        lua_pushstring(L, "name");
-        lua_pushstring(L, xstrdup((char *) s));
-        free(s);
-        lua_rawset(L, -3);
-
-        lua_rawseti(L, -2, vf_nf);
-        i++;
-        vf_byte(cmd);
-    }
-
-    if (i > 1) {
-        lua_setfield(L, -2, "fonts");
-    } else {
-        lua_pop(L, 1);
-    }
-
-    lua_newtable(L);            /* 'characters' */
-    while (cmd <= long_char) {
-        /* Build a character packet */
-        if (cmd == long_char) {
-            vf_read_u(4, packet_length);
-            vf_read_u(4, utmp);
-            cc = (int) utmp;
-            vf_read(4, tfm_width);
-        } else {
-            packet_length = (unsigned) cmd;
-            vf_byte(cc);
-            vf_read_u(3, utmp);
-            tfm_width = (int) utmp;
-        }
-        lua_newtable(L);        /* for this character */
-        lua_pushinteger(L, tfm_width);
-        lua_setfield(L, -2, "width");
-        lua_newtable(L);        /* for 'commands' */
-        k = 1;
-        vf_nf = 0;
-        w = 0;
-        x = 0;
-        y = 0;
-        z = 0;
-        while (packet_length > 0) {
-            vf_byte(cmd);
-            decr(packet_length);
-            if ((cmd >= set_char_0) && (cmd < set1)) {
-                if (vf_nf == 0) {
-                    vf_nf = 1;
-                    make_command1("font", vf_nf, k);
-                }
-                make_command1("char", cmd, k);
-            } else if (((fnt_num_0 <= cmd) && (cmd <= fnt_num_0 + 63)) ||
-                       ((fnt1 <= cmd) && (cmd <= fnt1 + 3))) {
-                if (cmd >= fnt1) {
-                    vf_read_u((cmd - fnt1 + 1), utmp);
-                    vf_nf = (int) utmp;
-                    vf_nf++;
-                    packet_length -= (unsigned) (cmd - fnt1 + 1);
-                } else {
-                    vf_nf = cmd - fnt_num_0 + 1;
-                }
-                make_command1("font", vf_nf, k);
-            } else {
-                switch (cmd) {
-                case set_rule:
-                    vf_read(4, h);
-                    vf_read(4, v);
-                    make_command2("rule", store_scaled_f(h, atsize),
-                                  store_scaled_f(v, atsize), k);
-                    packet_length -= 8;
-                    break;
-                case put_rule:
-                    vf_read(4, h);
-                    vf_read(4, v);
-                    make_command0("push", k);
-                    make_command2("rule", store_scaled_f(h, atsize),
-                                  store_scaled_f(v, atsize), k);
-                    make_command0("pop", k);
-                    packet_length -= 8;
-                    break;
-                case set1:
-                case set2:
-                case set3:
-                case set4:
-                    if (vf_nf == 0) {
-                        vf_nf = 1;
-                        make_command1("font", vf_nf, k);
-                    }
-                    vf_read_u((cmd - set1 + 1), utmp);
-                    i = (int) utmp;
-                    make_command1("char", i, k);
-                    packet_length -= (unsigned) (cmd - set1 + 1);
-                    break;
-                case put1:
-                case put2:
-                case put3:
-                case put4:
-                    if (vf_nf == 0) {
-                        vf_nf = 1;
-                        make_command1("font", vf_nf, k);
-                    }
-                    vf_read_u((cmd - put1 + 1), utmp);
-                    i = (int) utmp;
-                    make_command0("push", k);
-                    make_command1("char", i, k);
-                    make_command0("pop", k);
-                    packet_length -= (unsigned) (cmd - put1 + 1);
-                    break;
-                case right1:
-                case right2:
-                case right3:
-                case right4:
-                    vf_read((cmd - right1 + 1), i);
-                    make_command1("right", store_scaled_f(i, atsize), k);
-                    packet_length -= (unsigned) (cmd - right1 + 1);
-                    break;
-                case w1:
-                case w2:
-                case w3:
-                case w4:
-                    vf_read((cmd - w1 + 1), w);
-                    make_command1("right", store_scaled_f(w, atsize), k);
-                    packet_length -= (unsigned) (cmd - w1 + 1);
-                    break;
-                case x1:
-                case x2:
-                case x3:
-                case x4:
-                    vf_read((cmd - x1 + 1), x);
-                    make_command1("right", store_scaled_f(x, atsize), k);
-                    packet_length -= (unsigned) (cmd - x1 + 1);
-                    break;
-                case down1:
-                case down2:
-                case down3:
-                case down4:
-                    vf_read((cmd - down1 + 1), i);
-                    make_command1("down", store_scaled_f(i, atsize), k);
-                    packet_length -= (unsigned) (cmd - down1 + 1);
-                    break;
-                case y1:
-                case y2:
-                case y3:
-                case y4:
-                    vf_read((cmd - y1 + 1), y);
-                    make_command1("down", store_scaled_f(y, atsize), k);
-                    packet_length -= (unsigned) (cmd - y1 + 1);
-                    break;
-                case z1:
-                case z2:
-                case z3:
-                case z4:
-                    vf_read((cmd - z1 + 1), z);
-                    make_command1("down", store_scaled_f(z, atsize), k);
-                    packet_length -= (unsigned) (cmd - z1 + 1);
-                    break;
-                case xxx1:
-                case xxx2:
-                case xxx3:
-                case xxx4:
-                    vf_read_u((cmd - xxx1 + 1), cmd_length);
-                    packet_length -= (unsigned) (cmd - xxx1 + 1);
-                    if (cmd_length <= 0)
-                        lua_bad_vf("special of negative length");
-                    packet_length -= cmd_length;
-
-                    s = xmalloc((cmd_length + 1));
-                    i = 0;
-                    while (cmd_length > 0) {
-                        cmd_length--;
-                        vf_byte(s[i]);
-                        i++;
-                    }
-                    s[i] = 0;
-                    make_commands("special", xstrdup((char *) s), (size_t) i,
-                                  k);
-                    free(s);
-                    break;
-                case w0:
-                    make_command1("right", store_scaled_f(w, atsize), k);
-                    break;
-                case x0:
-                    make_command1("right", store_scaled_f(x, atsize), k);
-                    break;
-                case y0:
-                    make_command1("down", store_scaled_f(y, atsize), k);
-                    break;
-                case z0:
-                    make_command1("down", store_scaled_f(z, atsize), k);
-                    break;
-                case nop:
-                    break;
-                case push:
-                    if (stack_level == vf_stack_size) {
-                        overflow("virtual font stack size", vf_stack_size);
-                    } else {
-                        vf_stack[stack_level].stack_w = w;
-                        vf_stack[stack_level].stack_x = x;
-                        vf_stack[stack_level].stack_y = y;
-                        vf_stack[stack_level].stack_z = z;
-                        incr(stack_level);
-                        make_command0("push", k);
-                    }
-                    break;
-                case pop:
-                    if (stack_level == 0) {
-                        lua_bad_vf("more POPs than PUSHs in character");
-                    } else {
-                        decr(stack_level);
-                        w = vf_stack[stack_level].stack_w;
-                        x = vf_stack[stack_level].stack_x;
-                        y = vf_stack[stack_level].stack_y;
-                        z = vf_stack[stack_level].stack_z;
-                        make_command0("pop", k);
-                    }
-                    break;
-                default:
-                    lua_bad_vf("improver DVI command");
-                }
-            }
-        }
-        /* signal end of packet */
-        lua_setfield(L, -2, "commands");
-
-        if (stack_level != 0)
-            lua_bad_vf("more PUSHs than POPs in character packet");
-        if (packet_length != 0)
-            lua_bad_vf("invalid packet length or DVI command in packet");
-
-        lua_rawseti(L, -2, cc);
-
-        vf_byte(cmd);
-    }
-    lua_setfield(L, -2, "characters");
-
-    if (cmd != post)
-        lua_bad_vf("POST command expected");
-    xfree(vf_buffer);
-    return 1;
-}
-
-@ @c
-internal_font_number
-letter_space_font(internal_font_number f, int e, boolean nolig)
-{
-    internal_font_number k;
-    scaled w;
-    int c;
-    charinfo *co;
-    char *new_font_name;
-
-    /* read a new font and expand the character widths */
-    k = copy_font(f);
-
-    if (nolig)
-      set_no_ligatures(k);        /* disable ligatures for letter-spaced fonts */
-
-    /* append eg '+100ls' to font name */
-    new_font_name = xmalloc((unsigned) (strlen(font_name(k)) + 8));     /* |abs(e) <= 1000| */
-    if (e > 0) {
-        sprintf(new_font_name, "%s+%ils", font_name(k), (int) e);
-    } else {
-        /* minus from \%i */
-        sprintf(new_font_name, "%s%ils", font_name(k), (int) e);
-    }
-    set_font_name(k, new_font_name);
-
-    /* create the corresponding virtual font */
-    set_font_type(k, virtual_font_type);
-
-    for (c=font_bc(k);c<=font_ec(k);c++) {
-       if (quick_char_exists(k, c)) {
-           int half_w;
-           int vf_np = 0;
-           eight_bits *vpackets = xmalloc((unsigned) (10+10+1));
-           if (e<0) {
-             half_w = -round_xn_over_d(quad(k), -e, 2000);
-           } else {
-             half_w  = round_xn_over_d(quad(k), e, 2000);
-           }
-           co = get_charinfo(k, c);
-           w = char_width(k, c)+2*half_w;
-           set_charinfo_width(co, w);
-
-           append_packet(packet_right_code);
-           append_four(half_w);
-           append_fnt_set(f);
-           append_packet(packet_char_code);
-           append_four(c);
-           append_packet(packet_right_code);
-           append_four(half_w);
-           append_packet(packet_end_code);
-
-           set_charinfo_packets(co, vpackets);
-       }
-    }
-    /* now patch the quad size */
-    /* Patch 20100922:  do not do this, to remain compatible with pdftex */
-#if 0
-    if (e<0) {
-       set_font_param(k, quad_code, -round_xn_over_d(quad(k), 1000-e, 1000));
-    } else {
-       set_font_param(k, quad_code, round_xn_over_d(quad(k), 1000+e, 1000));
-    }
-#endif
-    return k;
-}
-
-@ @c
-internal_font_number copy_font_info(internal_font_number f)
-{
-    return copy_font(f);
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,445 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2013 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/*tex
+
+    Some macros for processing character packets.
+
+*/
+
+#define packet_number(fw) {    \
+    fw = *(vfp++);             \
+    fw = fw * 256 + *(vfp++);  \
+    fw = fw * 256 + *(vfp++);  \
+    fw = fw * 256 + *(vfp++);  \
+}
+
+#define packet_scaled(a, fs) {  \
+    int fw;                     \
+    fw = *(vfp++);              \
+    if (fw > 127)               \
+        fw = fw - 256;          \
+    fw = fw * 256 + *(vfp++);   \
+    fw = fw * 256 + *(vfp++);   \
+    fw = fw * 256 + *(vfp++);   \
+    a = store_scaled_f(fw, fs); \
+}
+
+vf_struct *new_vfstruct(void)
+{
+    vf_struct *vp = (vf_struct *) xmalloc(sizeof(vf_struct));
+    vp->packet_stack_level = vp->packet_stack_minlevel = 0;
+    vp->packet_stack = (packet_stack_record *) xmalloc(packet_stack_size * sizeof(packet_stack_record));
+    vp->lf = 0;
+    vp->fs_f = 0;
+    vp->packet_cur_s = 0;
+    vp->refpos = NULL;
+    vp->vflua = false;
+    return vp;
+}
+
+/*tex
+
+     Count the number of bytes in a command packet.
+*/
+
+int vf_packet_bytes(charinfo * co)
+{
+    eight_bits *vf_packets, *vfp;
+    unsigned k;
+    int cmd;
+    vfp = vf_packets = get_charinfo_packets(co);
+    if (vf_packets == NULL) {
+        return 0;
+    }
+    while ((cmd = *(vfp++)) != packet_end_code) {
+        switch (cmd) {
+        case packet_nop_code:
+        case packet_pop_code:
+        case packet_push_code:
+            break;
+        case packet_char_code:
+        case packet_down_code:
+        case packet_font_code:
+        case packet_image_code:
+        case packet_node_code:
+        case packet_right_code:
+            vfp += 4;
+            break;
+        case packet_rule_code:
+            vfp += 8;
+            break;
+        case packet_pdf_mode:
+            vfp += 4;
+            break;
+        case packet_pdf_code:
+            vfp += 4;
+            /*tex Plus a string so we fall through: */
+        case packet_special_code:
+            /*tex |+4| */
+            packet_number(k);
+            vfp += (int) k;
+            break;
+        default:
+            normal_error("vf", "invalid DVI command (1)");
+        }
+    };
+    return (vfp - vf_packets);
+}
+
+/*tex
+
+    Typeset the \.{DVI} commands in the character packet for character |c| in
+    current font |f|.
+*/
+
+const char *packet_command_names[] = {
+    /*tex |slot| maps to |char| and |font| */
+    "char",
+    "font",
+    "pop",
+    "push",
+    "special",
+    "image",
+    "right",
+    "down",
+    "rule",
+    "node",
+    "nop",
+    "end",
+    /*tex the next one is not (yet) supported */
+    "scale",
+    "lua",
+    "pdf",
+    NULL
+};
+
+static float packet_float(eight_bits ** vfpp)
+{
+    unsigned int i;
+    union U {
+        float a;
+        eight_bits b[sizeof(float)];
+    } u;
+    eight_bits *vfp = *vfpp;
+    for (i = 0; i < sizeof(float); i++)
+        u.b[i] = *(vfp++);
+    *vfpp = vfp;
+    return u.a;
+}
+
+/*tex
+
+    The |do_vf_packet| procedure is called in order to interpret the character
+    packet for a virtual character. Such a packet may contain the instruction to
+    typeset a character from the same or an other virtual font; in such cases
+    |do_vf_packet| calls itself recursively. The recursion level, i.e., the
+    number of times this has happened, is kept in the global variable
+    |packet_cur_s| and should not exceed |packet_max_recursion|.
+*/
+
+void do_vf_packet(PDF pdf, internal_font_number vf_f, int c, int ex_glyph)
+{
+    eight_bits *vfp;
+    posstructure *save_posstruct, localpos;
+    vf_struct *save_vfstruct, localvfstruct, *vp;
+    int cmd, w, mode;
+    unsigned k;
+    scaledpos size;
+    scaled i;
+    str_number s;
+    float f;
+    packet_stack_record *mat_p;
+    vfp = get_charinfo_packets(get_charinfo(vf_f, c));
+    save_posstruct = pdf->posstruct;
+    /*tex use local structure for recursion */
+    pdf->posstruct = &localpos;
+    localpos.pos = save_posstruct->pos;
+    /*tex invariably for vf */
+    localpos.dir = dir_TLT;
+    save_vfstruct = pdf->vfstruct;
+    vp = pdf->vfstruct = &localvfstruct;
+    localvfstruct = *save_vfstruct;
+    vp->packet_stack_minlevel = ++(vp->packet_stack_level);
+    vp->lf = 0;
+    vp->fs_f = font_size(vf_f);
+    vp->ex_glyph = ex_glyph;
+    vp->packet_cur_s++;
+    if (vp->packet_cur_s == packet_max_recursion)
+        overflow("max level recursion of virtual fonts", packet_max_recursion);
+    vp->refpos = save_posstruct;
+    vp->vflua = false;
+    mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+    mat_p->c0 = 1.0;
+    mat_p->c1 = 0.0;
+    mat_p->c2 = 0.0;
+    mat_p->c3 = 1.0;
+    mat_p->pos.h = 0;
+    mat_p->pos.v = 0;
+    while ((cmd = *(vfp++)) != packet_end_code) {
+        switch (cmd) {
+            case packet_font_code:
+                packet_number(vp->lf);
+                break;
+            case packet_push_code:
+                vp->packet_stack_level++;
+                if (vp->packet_stack_level == packet_stack_size)
+                    normal_error("vf", "packet_stack_level overflow");
+                vp->packet_stack[vp->packet_stack_level] = *mat_p;
+                mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+                break;
+            case packet_pop_code:
+                if (vp->packet_stack_level == vp->packet_stack_minlevel)
+                    normal_error("vf", "packet_stack_level underflow");
+                vp->packet_stack_level--;
+                mat_p = &(vp->packet_stack[vp->packet_stack_level]);
+                break;
+            case packet_char_code:
+                packet_number(k);
+                /*tex We also check if |c == k| and |font(c) == font(k)| */
+                if (!char_exists(vp->lf, (int) k)) {
+                    char_warning(vp->lf, (int) k);
+                } else if (! ((c == k && vp->lf == vf_f)) && (has_packet(vp->lf, (int) k))) {
+                    do_vf_packet(pdf, vp->lf, (int) k, ex_glyph);
+                } else {
+                    backend_out[glyph_node] (pdf, vp->lf, (int) k, ex_glyph);
+                }
+                w = char_width(vp->lf, (int) k);
+                if (ex_glyph != 0 && w != 0)
+                    w = round_xn_over_d(w, 1000 + ex_glyph, 1000);
+                mat_p->pos.h += w;
+                break;
+            case packet_rule_code:
+                packet_scaled(size.v, vp->fs_f);
+                packet_scaled(size.h, vp->fs_f);
+                if (ex_glyph != 0 && size.h > 0)
+                    size.h = round_xn_over_d(size.h, 1000 + ex_glyph, 1000);
+                if (size.h > 0 && size.v > 0)
+                    backend_out[rule_node](pdf, 0, size);
+                mat_p->pos.h += size.h;
+                break;
+            case packet_right_code:
+                packet_scaled(i, vp->fs_f);
+                if (ex_glyph != 0 && i != 0)
+                    i = round_xn_over_d(i, 1000 + ex_glyph, 1000);
+                mat_p->pos.h += i;
+                break;
+            case packet_down_code:
+                packet_scaled(i, vp->fs_f);
+                mat_p->pos.v += i;
+                break;
+            case packet_pdf_code:
+                packet_number(mode);
+                packet_number(k);
+                str_room(k);
+                while (k > 0) {
+                    k--;
+                    append_char(*(vfp++));
+                }
+                s = make_string();
+                pdf_literal(pdf, s, mode, false);
+                flush_str(s);
+                break;
+            case packet_pdf_mode:
+                packet_number(mode);
+                pdf_literal_set_mode(pdf, mode);
+                break;
+            case packet_special_code:
+                packet_number(k);
+                str_room(k);
+                while (k > 0) {
+                    k--;
+                    append_char(*(vfp++));
+                }
+                s = make_string();
+                pdf_literal(pdf, s, scan_special, false);
+                flush_str(s);
+                break;
+            case packet_lua_code:
+                packet_number(k);
+                vp->vflua = true;
+                luacall_vf(k, vf_f, c);
+                /*tex
+
+                    We don't release as we (can ) flush multiple times, so no:
+
+                    \starttyping
+                    luaL_unref(Luas, LUA_REGISTRYINDEX, k);
+                    \stoptyping
+
+                    here!
+
+                */
+                vp->vflua = false;
+                break;
+            case packet_image_code:
+                packet_number(k);
+                vf_out_image(pdf, k);
+                break;
+            case packet_node_code:
+                packet_number(k);
+                hlist_out(pdf, (halfword) k, 0);
+                break;
+            case packet_nop_code:
+                break;
+            case packet_scale_code:
+                /*tex This is not yet supported in the backend. */
+                f = packet_float(&vfp);
+                mat_p->c0 = mat_p->c0 * f;
+                mat_p->c3 = mat_p->c3 * f;
+                /* pdf->pstruct->scale = f; */
+                pdf->pstruct->need_tm = true;
+                pdf->pstruct->need_tf = true;
+                break;
+            default:
+                normal_error("vf", "invalid DVI command (2)");
+        }
+        /*tex The trivial case, always |TLT|. */
+        synch_pos_with_cur(&localpos, save_posstruct, mat_p->pos);
+    }
+    pdf->posstruct = save_posstruct;
+    pdf->vfstruct = save_vfstruct;
+}
+
+int *packet_local_fonts(internal_font_number f, int *num)
+{
+    int c, cmd, lf, k, l, i;
+    int localfonts[256] = { 0 };
+    int *lfs;
+    charinfo *co;
+    eight_bits *vf_packets, *vfp;
+    k = 0;
+    for (c = font_bc(f); c <= font_ec(f); c++) {
+        if (quick_char_exists(f, c)) {
+            co = get_charinfo(f, c);
+            vfp = vf_packets = get_charinfo_packets(co);
+            if (vf_packets == NULL)
+                continue;
+            while ((cmd = *(vfp++)) != packet_end_code) {
+                switch (cmd) {
+                    case packet_font_code:
+                        packet_number(lf);
+                        for (l = 0; l < k; l++) {
+                            if (localfonts[l] == lf) {
+                                break;
+                            }
+                        }
+                        if (l == k) {
+                            localfonts[k++] = lf;
+                        }
+                        break;
+                    case packet_nop_code:
+                    case packet_pop_code:
+                    case packet_push_code:
+                        break;
+                    case packet_char_code:
+                    case packet_down_code:
+                    case packet_image_code:
+                    case packet_node_code:
+                    case packet_right_code:
+                        vfp += 4;
+                        break;
+                    case packet_rule_code:
+                        vfp += 8;
+                        break;
+                    case packet_special_code:
+                        packet_number(i);
+                        vfp += i;
+                        break;
+                    default:
+                        normal_error("vf", "invalid DVI command (3)");
+                }
+            }
+        }
+    }
+    *num = k;
+    if (k > 0) {
+        lfs = xmalloc((unsigned) ((unsigned) k * sizeof(int)));
+        memcpy(lfs, localfonts, (size_t) ((unsigned) k * sizeof(int)));
+        return lfs;
+    }
+    return NULL;
+}
+
+void replace_packet_fonts(internal_font_number f, int *old_fontid, int *new_fontid, int count)
+{
+    int c, cmd, lf, k, l;
+    charinfo *co;
+    eight_bits *vf_packets, *vfp;
+    for (c = font_bc(f); c <= font_ec(f); c++) {
+        if (quick_char_exists(f, c)) {
+            co = get_charinfo(f, c);
+            vfp = vf_packets = get_charinfo_packets(co);
+            if (vf_packets == NULL)
+                continue;
+            while ((cmd = *(vfp++)) != packet_end_code) {
+                switch (cmd) {
+                    case packet_font_code:
+                        packet_number(lf);
+                        for (l = 0; l < count; l++) {
+                            if (old_fontid[l] == lf) {
+                                break;
+                            }
+                        }
+                        if (l < count) {
+                            k = new_fontid[l];
+                            *(vfp - 4) = (eight_bits)
+                                ((k & 0xFF000000) >> 24);
+                            *(vfp - 3) = (eight_bits)
+                                ((k & 0x00FF0000) >> 16);
+                            *(vfp - 2) = (eight_bits)
+                                ((k & 0x0000FF00) >> 8);
+                            *(vfp - 1) = (eight_bits) (k & 0x000000FF);
+                        }
+                        break;
+                    case packet_nop_code:
+                    case packet_pop_code:
+                    case packet_push_code:
+                        break;
+                    case packet_char_code:
+                    case packet_down_code:
+                    case packet_image_code:
+                    case packet_node_code:
+                    case packet_right_code:
+                    case packet_rule_code:
+                        vfp += 8;
+                        break;
+                    case packet_pdf_mode:
+                        vfp += 4;
+                        break;
+                    case packet_pdf_code:
+                        vfp += 4;
+                        /*tex Plus a string so we fall through. */
+                    case packet_special_code:
+                        packet_number(k);
+                        vfp += k;
+                        break;
+                    default:
+                        normal_error("vf", "invalid DVI command (4)");
+                }
+            }
+        }
+    }
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/vfpacket.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,424 +0,0 @@
-% vfpacket.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ Some macros for processing character packets.
- at c
-#define packet_number(fw) {    \
-    fw = *(vfp++);             \
-    fw = fw * 256 + *(vfp++);  \
-    fw = fw * 256 + *(vfp++);  \
-    fw = fw * 256 + *(vfp++);  \
-}
-
-#define packet_scaled(a, fs) {  \
-    int fw;                     \
-    fw = *(vfp++);              \
-    if (fw > 127)               \
-        fw = fw - 256;          \
-    fw = fw * 256 + *(vfp++);   \
-    fw = fw * 256 + *(vfp++);   \
-    fw = fw * 256 + *(vfp++);   \
-    a = store_scaled_f(fw, fs); \
-}
-
-@ @c
-vf_struct *new_vfstruct(void)
-{
-    vf_struct *vp = (vf_struct *) xmalloc(sizeof(vf_struct));
-    vp->packet_stack_level = vp->packet_stack_minlevel = 0;
-    vp->packet_stack =
-        (packet_stack_record *) xmalloc(packet_stack_size *
-                                        sizeof(packet_stack_record));
-    vp->lf = 0;
-    vp->fs_f = 0;
-    vp->packet_cur_s = 0;
-    vp->refpos = NULL;
-    vp->vflua = false;
-    return vp;
-}
-
-@ Count the number of bytes in a command packet.
- at c
-int vf_packet_bytes(charinfo * co)
-{
-    eight_bits *vf_packets, *vfp;
-    unsigned k;
-    int cmd;
-
-    vfp = vf_packets = get_charinfo_packets(co);
-    if (vf_packets == NULL) {
-        return 0;
-    }
-    while ((cmd = *(vfp++)) != packet_end_code) {
-        switch (cmd) {
-        case packet_nop_code:
-        case packet_pop_code:
-        case packet_push_code:
-            break;
-        case packet_char_code:
-        case packet_down_code:
-        case packet_font_code:
-        case packet_image_code:
-        case packet_node_code:
-        case packet_right_code:
-        case packet_rule_code:
-            vfp += 8;
-            break;
-        case packet_pdf_mode:
-            vfp += 4;
-            break;
-        case packet_pdf_code:
-            vfp += 4;
-            /* plus a string so we fall through */
-        case packet_special_code:
-            packet_number(k);   /* +4 */
-            vfp += (int) k;
-            break;
-        default:
-            normal_error("vf", "invalid DVI command (1)");
-        }
-    };
-    return (vfp - vf_packets);
-}
-
-@ Typeset the \.{DVI} commands in the character packet
-  for character |c| in current font |f|.
- at c
-const char *packet_command_names[] = {
-    "char", "font", "pop", "push", "special", "image",
-    "right", "down", "rule", "node", "nop", "end", "scale", "lua", "pdf", NULL
-};
-
-@ @c
-static float packet_float(eight_bits ** vfpp)
-{
-    unsigned int i;
-    union U {
-        float a;
-        eight_bits b[sizeof(float)];
-    } u;
-    eight_bits *vfp = *vfpp;
-    for (i = 0; i < sizeof(float); i++)
-        u.b[i] = *(vfp++);
-    *vfpp = vfp;
-    return u.a;
-}
-
-@ The |do_vf_packet| procedure is called in order to interpret the
-  character packet for a virtual character. Such a packet may contain
-  the instruction to typeset a character from the same or an other
-  virtual font; in such cases |do_vf_packet| calls itself
-  recursively. The recursion level, i.e., the number of times this has
-  happened, is kept in the global variable |packet_cur_s| and should
-  not exceed |packet_max_recursion|.
- at c
-void do_vf_packet(PDF pdf, internal_font_number vf_f, int c, int ex_glyph)
-{
-    eight_bits *vfp;
-    posstructure *save_posstruct, localpos;
-    vf_struct *save_vfstruct, localvfstruct, *vp;
-    int cmd, w, mode;
-    unsigned k;
-    scaledpos size;
-    scaled i;
-    str_number s;
-    float f;
-    packet_stack_record *mat_p;
-
-    vfp = get_charinfo_packets(get_charinfo(vf_f, c));
-    assert(vfp != NULL);
-
-    save_posstruct = pdf->posstruct;
-    pdf->posstruct = &localpos; /* use local structure for recursion */
-    localpos.pos = save_posstruct->pos;
-    localpos.dir = dir_TLT;     /* invariably for vf */
-
-    save_vfstruct = pdf->vfstruct;
-    vp = pdf->vfstruct = &localvfstruct;
-    localvfstruct = *save_vfstruct;
-
-    vp->packet_stack_minlevel = ++(vp->packet_stack_level);
-    vp->lf = 0;
-    vp->fs_f = font_size(vf_f);
-    vp->ex_glyph = ex_glyph;
-    vp->packet_cur_s++;
-    if (vp->packet_cur_s == packet_max_recursion)
-        overflow("max level recursion of virtual fonts", packet_max_recursion);
-    vp->refpos = save_posstruct;
-    vp->vflua = false;
-
-    mat_p = &(vp->packet_stack[vp->packet_stack_level]);
-    mat_p->c0 = 1.0;
-    mat_p->c1 = 0.0;
-    mat_p->c2 = 0.0;
-    mat_p->c3 = 1.0;
-    mat_p->pos.h = 0;
-    mat_p->pos.v = 0;
-
-    while ((cmd = *(vfp++)) != packet_end_code) {
-#ifdef DEBUG
-        if (cmd > packet_end_code) {
-            fprintf(stdout, "do_vf_packet(%i,%i) command code = illegal \n",
-                    vf_f, c);
-        } else {
-            fprintf(stdout, "do_vf_packet(%i,%i) command code = %s\n", vf_f, c,
-                    packet_command_names[cmd]);
-        }
-#endif
-        switch (cmd) {
-        case packet_font_code:
-            packet_number(vp->lf);
-            break;
-        case packet_push_code:
-            vp->packet_stack_level++;
-            if (vp->packet_stack_level == packet_stack_size)
-                normal_error("vf", "packet_stack_level overflow");
-            vp->packet_stack[vp->packet_stack_level] = *mat_p;
-            mat_p = &(vp->packet_stack[vp->packet_stack_level]);
-            break;
-        case packet_pop_code:
-            if (vp->packet_stack_level == vp->packet_stack_minlevel)
-                normal_error("vf", "packet_stack_level underflow");
-            vp->packet_stack_level--;
-            mat_p = &(vp->packet_stack[vp->packet_stack_level]);
-            break;
-        case packet_char_code:
-            packet_number(k);
-            /* we also check if c == k and font(c) == font)k) */
-            if (!char_exists(vp->lf, (int) k)) {
-                char_warning(vp->lf, (int) k);
-            } else if (! ((c == k && vp->lf == vf_f)) && (has_packet(vp->lf, (int) k))) {
-                do_vf_packet(pdf, vp->lf, (int) k, ex_glyph);
-            } else {
-                backend_out[glyph_node] (pdf, vp->lf, (int) k, ex_glyph);
-            }
-            w = char_width(vp->lf, (int) k);
-            mat_p->pos.h += round_xn_over_d(w, 1000 + ex_glyph, 1000);
-            break;
-        case packet_rule_code:
-            packet_scaled(size.v, vp->fs_f);    /* height (where is depth?) */
-            packet_scaled(size.h, vp->fs_f);
-            if (size.h > 0 && size.v > 0)
-                backend_out[rule_node](pdf, 0, size);  /* the 0 is unused */
-            mat_p->pos.h += size.h;
-            break;
-        case packet_right_code:
-            packet_scaled(i, vp->fs_f);
-            mat_p->pos.h += i;
-            break;
-        case packet_down_code:
-            packet_scaled(i, vp->fs_f);
-            mat_p->pos.v += i;
-            break;
-        case packet_pdf_code:
-            packet_number(mode);
-            packet_number(k);
-            str_room(k);
-            while (k > 0) {
-                k--;
-                append_char(*(vfp++));
-            }
-            s = make_string();
-            pdf_literal(pdf, s, mode, false);
-            flush_str(s);
-            break;
-        case packet_pdf_mode:
-            packet_number(mode);
-            pdf_literal_set_mode(pdf, mode);
-            break;
-        case packet_special_code:
-            packet_number(k);
-            str_room(k);
-            while (k > 0) {
-                k--;
-                append_char(*(vfp++));
-            }
-            s = make_string();
-            pdf_literal(pdf, s, scan_special, false);
-            flush_str(s);
-            break;
-        case packet_lua_code:
-            packet_number(k);
-            vp->vflua = true;
-            if (luaL_loadbuffer
-                (Luas, (const char *) vfp, (size_t) k, "packet_lua_code")
-                || lua_pcall(Luas, 0, LUA_MULTRET, 0))
-                lua_error(Luas);
-            vp->vflua = false;
-            vfp += k;
-            break;
-        case packet_image_code:
-            packet_number(k);
-            vf_out_image(pdf, k);
-            break;
-        case packet_node_code:
-            packet_number(k);
-            hlist_out(pdf, (halfword) k, 0);
-            break;
-        case packet_nop_code:
-            break;
-        case packet_scale_code:
-            f = packet_float(&vfp);
-            mat_p->c0 = mat_p->c0 * f;
-            mat_p->c3 = mat_p->c3 * f;
-            /* pdf->pstruct->scale = f; *//* scale is still NOP */
-            pdf->pstruct->need_tm = true;
-            pdf->pstruct->need_tf = true;
-            break;
-        default:
-            normal_error("vf", "invalid DVI command (2)");
-        }
-        synch_pos_with_cur(&localpos, save_posstruct, mat_p->pos);      /* trivial case, always TLT */
-    }
-    pdf->posstruct = save_posstruct;
-    pdf->vfstruct = save_vfstruct;
-}
-
-@ @c
-int *packet_local_fonts(internal_font_number f, int *num)
-{
-    int c, cmd, lf, k, l, i;
-    int localfonts[256] = { 0 };
-    int *lfs;
-    charinfo *co;
-
-    eight_bits *vf_packets, *vfp;
-    k = 0;
-    for (c = font_bc(f); c <= font_ec(f); c++) {
-        if (quick_char_exists(f, c)) {
-            co = get_charinfo(f, c);
-            vfp = vf_packets = get_charinfo_packets(co);
-            if (vf_packets == NULL)
-                continue;
-            while ((cmd = *(vfp++)) != packet_end_code) {
-                switch (cmd) {
-                case packet_font_code:
-                    packet_number(lf);
-                    for (l = 0; l < k; l++) {
-                        if (localfonts[l] == lf) {
-                            break;
-                        }
-                    }
-                    if (l == k) {
-                        localfonts[k++] = lf;
-                    }
-                    break;
-                case packet_nop_code:
-                case packet_pop_code:
-                case packet_push_code:
-                    break;
-                case packet_char_code:
-                case packet_down_code:
-                case packet_image_code:
-                case packet_node_code:
-                case packet_right_code:
-                    vfp += 4;
-                    break;
-                case packet_rule_code:
-                    vfp += 8;
-                    break;
-                case packet_special_code:
-                    packet_number(i);
-                    vfp += i;
-                    break;
-                default:
-                    normal_error("vf", "invalid DVI command (3)");
-                }
-            }
-        }
-    }
-    *num = k;
-    if (k > 0) {
-        lfs = xmalloc((unsigned) ((unsigned) k * sizeof(int)));
-        memcpy(lfs, localfonts, (size_t) ((unsigned) k * sizeof(int)));
-        return lfs;
-    }
-    return NULL;
-}
-
-@ @c
-void
-replace_packet_fonts(internal_font_number f, int *old_fontid,
-                     int *new_fontid, int count)
-{
-    int c, cmd, lf, k, l;
-    charinfo *co;
-    eight_bits *vf_packets, *vfp;
-
-    for (c = font_bc(f); c <= font_ec(f); c++) {
-        if (quick_char_exists(f, c)) {
-            co = get_charinfo(f, c);
-            vfp = vf_packets = get_charinfo_packets(co);
-            if (vf_packets == NULL)
-                continue;
-            while ((cmd = *(vfp++)) != packet_end_code) {
-                switch (cmd) {
-                case packet_font_code:
-                    packet_number(lf);
-                    for (l = 0; l < count; l++) {
-                        if (old_fontid[l] == lf) {
-                            break;
-                        }
-                    }
-                    if (l < count) {
-                        k = new_fontid[l];
-                        *(vfp - 4) = (eight_bits)
-                            ((k & 0xFF000000) >> 24);
-                        *(vfp - 3) = (eight_bits)
-                            ((k & 0x00FF0000) >> 16);
-                        *(vfp - 2) = (eight_bits)
-                            ((k & 0x0000FF00) >> 8);
-                        *(vfp - 1) = (eight_bits) (k & 0x000000FF);
-                    }
-                    break;
-                case packet_nop_code:
-                case packet_pop_code:
-                case packet_push_code:
-                    break;
-                case packet_char_code:
-                case packet_down_code:
-                case packet_image_code:
-                case packet_node_code:
-                case packet_right_code:
-                case packet_rule_code:
-                    vfp += 8;
-                    break;
-                case packet_pdf_mode:
-                    vfp += 4;
-                    break;
-                case packet_pdf_code:
-                    vfp += 4;
-                    /* plus a string so we fall through */
-                case packet_special_code:
-                    packet_number(k);
-                    vfp += k;
-                    break;
-                default:
-                    normal_error("vf", "invalid DVI command (4)");
-                }
-            }
-        }
-    }
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/writecff.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writecff.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writecff.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,3156 @@
+/*
+
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#include "font/writecff.h"
+
+extern int cidset;
+
+#define get_offset(s,n) get_unsigned(s, (n))
+#define get_card8(a)  (card8)(a->stream[a->offset++])
+#define get_card16(a) (card16)(get_unsigned(a,2))
+#define get_card32(a) (get_unsigned(a,4))
+
+#undef b0
+#undef b1
+#undef b2
+#undef b3
+
+#define WORK_BUFFER_SIZE 1024
+
+static char work_buffer[WORK_BUFFER_SIZE];
+
+static unsigned long get_unsigned(cff_font * cff, int n)
+{
+    unsigned long v = 0;
+    while (n-- > 0)
+        v = v * 256 + get_card8(cff);
+    return v;
+}
+
+const char *const cff_stdstr[CFF_STDSTR_MAX] = {
+    ".notdef", "space", "exclam", "quotedbl", "numbersign",
+    "dollar", "percent", "ampersand", "quoteright", "parenleft",
+    "parenright", "asterisk", "plus", "comma", "hyphen",
+    "period", "slash", "zero", "one", "two",
+    "three", "four", "five", "six", "seven",
+    "eight", "nine", "colon", "semicolon", "less",
+    "equal", "greater", "question", "at", "A",
+    "B", "C", "D", "E", "F",
+    "G", "H", "I", "J", "K",
+    "L", "M", "N", "O", "P",
+    "Q", "R", "S", "T", "U",
+    "V", "W", "X", "Y", "Z",
+    "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
+    "quoteleft", "a", "b", "c", "d",
+    "e", "f", "g", "h", "i",
+    "j", "k", "l", "m", "n",
+    "o", "p", "q", "r", "s",
+    "t", "u", "v", "w", "x",
+    "y", "z", "braceleft", "bar", "braceright",
+    "asciitilde", "exclamdown", "cent", "sterling", "fraction",
+    "yen", "florin", "section", "currency", "quotesingle",
+    "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi",
+    "fl", "endash", "dagger", "daggerdbl", "periodcentered",
+    "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
+    "guillemotright", "ellipsis", "perthousand", "questiondown", "grave",
+    "acute", "circumflex", "tilde", "macron", "breve",
+    "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
+    "ogonek", "caron", "emdash", "AE", "ordfeminine",
+    "Lslash", "Oslash", "OE", "ordmasculine", "ae",
+    "dotlessi", "lslash", "oslash", "oe", "germandbls",
+    "onesuperior", "logicalnot", "mu", "trademark", "Eth",
+    "onehalf", "plusminus", "Thorn", "onequarter", "divide",
+    "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
+    "registered", "minus", "eth", "multiply", "threesuperior",
+    "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
+    "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
+    "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
+    "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis",
+    "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
+    "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
+    "aacute", "acircumflex", "adieresis", "agrave", "aring",
+    "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis",
+    "egrave", "iacute", "icircumflex", "idieresis", "igrave",
+    "ntilde", "oacute", "ocircumflex", "odieresis", "ograve",
+    "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
+    "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
+    "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
+    "Acutesmall",
+    "parenleftsuperior", "parenrightsuperior", "twodotenleader",
+    "onedotenleader", "zerooldstyle",
+    "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
+    "fiveoldstyle",
+    "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle",
+    "commasuperior",
+    "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
+    "bsuperior",
+    "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
+    "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
+    "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
+    "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
+    "Asmall",
+    "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
+    "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall",
+    "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
+    "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
+    "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall",
+    "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall",
+    "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall",
+    "Dieresissmall",
+    "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
+    "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
+    "questiondownsmall",
+    "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird",
+    "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
+    "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
+    "oneinferior",
+    "twoinferior", "threeinferior", "fourinferior", "fiveinferior",
+    "sixinferior",
+    "seveninferior", "eightinferior", "nineinferior", "centinferior",
+    "dollarinferior",
+    "periodinferior", "commainferior", "Agravesmall", "Aacutesmall",
+    "Acircumflexsmall",
+    "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
+    "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
+    "Igravesmall",
+    "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
+    "Ntildesmall",
+    "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
+    "Odieresissmall",
+    "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall",
+    "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall",
+    "001.000", "001.001", "001.002", "001.003",
+    "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
+};
+
+/*tex Only read the header part and forget about the body */
+
+cff_index *cff_get_index_header(cff_font * cff)
+{
+    cff_index *idx;
+    card16 i, count;
+    idx = xcalloc(1, sizeof(cff_index));
+    if (cff->header_major == 2) {
+        idx->count = count = get_card32(cff);
+    } else {
+        idx->count = count = get_card16(cff);
+    }
+    if (count > 0) {
+        idx->offsize = get_card8(cff);
+        if (idx->offsize < 1 || idx->offsize > 4)
+            normal_error("cff","invalid offsize data (1)");
+        idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
+        for (i = 0; i <count + 1 ; i++) {
+            (idx->offset)[i] = get_offset(cff, idx->offsize);
+            if (i == USHRT_MAX)
+                break;
+        }
+        if (idx->offset[0] != 1)
+            normal_error("cff","invalid index data");
+        idx->data = NULL;
+    } else {
+        idx->offsize = 0;
+        idx->offset = NULL;
+        idx->data = NULL;
+    }
+    return idx;
+}
+
+cff_index *cff_get_index(cff_font * cff)
+{
+    cff_index *idx;
+    card16 i, count;
+    size_t length;
+    idx = xcalloc(1, sizeof(cff_index));
+    idx->count = count = get_card16(cff);
+    if (count > 0) {
+        idx->offsize = get_card8(cff);
+        if (idx->offsize < 1 || idx->offsize > 4)
+            normal_error("cff","invalid offsize data (2)");
+        idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
+        for (i = 0; i < count + 1; i++) {
+            idx->offset[i] = get_offset(cff, idx->offsize);
+        }
+        if (idx->offset[0] != 1)
+            normal_error("cff","invalid index offset data");
+        length = (size_t) (idx->offset[count] - idx->offset[0]);
+        idx->data = xmalloc((unsigned) length * sizeof(card8));
+        memcpy(idx->data, &cff->stream[cff->offset], length);
+        cff->offset += length;
+    } else {
+        idx->offsize = 0;
+        idx->offset = NULL;
+        idx->data = NULL;
+    }
+    return idx;
+}
+
+static cff_index *cff_empty_index(cff_font * cff)
+{
+    cff_index *idx;
+    idx = xcalloc(1, sizeof(cff_index));
+    idx->count = 0;
+    idx->offsize = 0;
+    idx->offset = NULL;
+    idx->data = NULL;
+    return idx;
+}
+
+static cff_index *cff_get_index2(cff_font * cff)
+{
+    /*tex We fake a dict array. */
+    cff_index *idx;
+    size_t length;
+    idx = xcalloc(1, sizeof(cff_index));
+    length = (size_t) cff->header_offsize;
+    idx->offsize = 2;
+    idx->count = 1;
+    idx->offset = xmalloc((unsigned) (((unsigned) 2) * sizeof(l_offset)));
+    idx->offset[0] = 1;
+    idx->offset[1] = length + 1;
+    idx->data = xmalloc((unsigned) length * sizeof(card8));
+    memcpy(idx->data, &cff->stream[cff->offset], length );
+    cff->offset += length ;
+    return idx;
+}
+
+long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
+{
+    long len = 0;
+    unsigned long datalen;
+    card16 i;
+    if (idx->count < 1) {
+        if (destlen < 2)
+            normal_error("cff","not enough space available");
+        memset(dest, 0, 2);
+        return 2;
+    }
+    len = cff_index_size(idx);
+    datalen = idx->offset[idx->count] - 1;
+    if (destlen < len)
+        normal_error("cff","not enough space available");
+    *(dest++) = (card8) ((idx->count >> 8) & 0xff);
+    *(dest++) = (card8) (idx->count & 0xff);
+    if (datalen < 0xffUL) {
+        idx->offsize = 1;
+        *(dest++) = 1;
+        for (i = 0; i <= idx->count; i++) {
+            *(dest++) = (card8) (idx->offset[i] & 0xff);
+        }
+    } else if (datalen < 0xffffUL) {
+        idx->offsize = 2;
+        *(dest++) = 2;
+        for (i = 0; i <= idx->count; i++) {
+            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+            *(dest++) = (card8) (idx->offset[i] & 0xff);
+        }
+    } else if (datalen < 0xffffffUL) {
+        idx->offsize = 3;
+        *(dest++) = 3;
+        for (i = 0; i <= idx->count; i++) {
+            *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
+            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+            *(dest++) = (card8) (idx->offset[i] & 0xff);
+        }
+    } else {
+        idx->offsize = 4;
+        *(dest++) = 4;
+        for (i = 0; i <= idx->count; i++) {
+            *(dest++) = (card8) ((idx->offset[i] >> 24) & 0xff);
+            *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
+            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
+            *(dest++) = (card8) (idx->offset[i] & 0xff);
+        }
+    }
+    memmove(dest, idx->data, idx->offset[idx->count] - 1);
+    return len;
+}
+
+long cff_index_size(cff_index * idx)
+{
+    if (idx->count > 0) {
+        l_offset datalen;
+        datalen = idx->offset[idx->count] - 1;
+        if (datalen < 0xffUL) {
+            idx->offsize = 1;
+        } else if (datalen < 0xffffUL) {
+            idx->offsize = 2;
+        } else if (datalen < 0xffffffUL) {
+            idx->offsize = 3;
+        } else {
+            idx->offsize = 4;
+        }
+        return (3 + (idx->offsize) * (idx->count + 1) + (long) datalen);
+    } else {
+        return 2;
+    }
+}
+
+cff_index *cff_new_index(card16 count)
+{
+    cff_index *idx;
+    idx = xcalloc(1, sizeof(cff_index));
+    idx->count = count;
+    idx->offsize = 0;
+    if (count > 0) {
+        idx->offset = xcalloc((unsigned) (count + 1), sizeof(l_offset));
+        (idx->offset)[0] = 1;
+    } else {
+        idx->offset = NULL;
+    }
+    idx->data = NULL;
+    return idx;
+}
+
+void cff_release_index(cff_index * idx)
+{
+    if (idx) {
+        xfree(idx->data);
+        xfree(idx->offset);
+        xfree(idx);
+    }
+}
+
+void cff_release_dict(cff_dict * dict)
+{
+    if (dict) {
+        if (dict->entries) {
+            int i;
+            for (i = 0; i < dict->count; i++) {
+                xfree((dict->entries)[i].values);
+            }
+            xfree(dict->entries);
+        }
+        xfree(dict);
+    }
+}
+
+void cff_release_encoding(cff_encoding * encoding)
+{
+    if (encoding) {
+        switch (encoding->format & (~0x80)) {
+        case 0:
+            xfree(encoding->data.codes);
+            break;
+        case 1:
+            xfree(encoding->data.range1);
+            break;
+        default:
+            normal_error("cff","unknown encoding format");
+        }
+        if (encoding->format & 0x80)
+            xfree(encoding->supp);
+        xfree(encoding);
+    }
+}
+
+void cff_release_charsets(cff_charsets * charset)
+{
+    if (charset) {
+        switch (charset->format) {
+        case 0:
+            xfree(charset->data.glyphs);
+            break;
+        case 1:
+            xfree(charset->data.range1);
+            break;
+        case 2:
+            xfree(charset->data.range2);
+            break;
+        default:
+            break;
+        }
+        xfree(charset);
+    }
+}
+
+void cff_release_fdselect(cff_fdselect * fdselect)
+{
+    if (fdselect) {
+        if (fdselect->format == 0) {
+            xfree(fdselect->data.fds);
+        } else if (fdselect->format == 3) {
+            xfree(fdselect->data.ranges);
+        }
+        xfree(fdselect);
+    }
+}
+
+void cff_close(cff_font * cff)
+{
+    card16 i;
+    if (cff) {
+        xfree(cff->fontname);
+        if (cff->name)
+            cff_release_index(cff->name);
+        if (cff->topdict)
+            cff_release_dict(cff->topdict);
+        if (cff->string)
+            cff_release_index(cff->string);
+        if (cff->gsubr)
+            cff_release_index(cff->gsubr);
+        if (cff->encoding)
+            cff_release_encoding(cff->encoding);
+        if (cff->charsets)
+            cff_release_charsets(cff->charsets);
+        if (cff->fdselect)
+            cff_release_fdselect(cff->fdselect);
+        if (cff->cstrings)
+            cff_release_index(cff->cstrings);
+        if (cff->fdarray) {
+            for (i = 0; i < cff->num_fds; i++) {
+                if (cff->fdarray[i])
+                    cff_release_dict(cff->fdarray[i]);
+            }
+            xfree(cff->fdarray);
+        }
+        if (cff->private) {
+            for (i = 0; i < cff->num_fds; i++) {
+                if (cff->private[i])
+                    cff_release_dict(cff->private[i]);
+            }
+            xfree(cff->private);
+        }
+        if (cff->subrs) {
+            for (i = 0; i < cff->num_fds; i++) {
+                if (cff->subrs[i])
+                    cff_release_index(cff->subrs[i]);
+            }
+            xfree(cff->subrs);
+        }
+        if (cff->_string)
+            cff_release_index(cff->_string);
+        xfree(cff);
+    }
+    return;
+}
+
+char *cff_get_name(cff_font * cff)
+{
+    char *fontname;
+    l_offset len;
+    cff_index *idx;
+    idx = cff->name;
+    len = idx->offset[cff->index + 1] - idx->offset[cff->index];
+    fontname = xmalloc((unsigned) (len + 1) * sizeof(char));
+    memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len);
+    fontname[len] = '\0';
+    return fontname;
+}
+
+long cff_set_name(cff_font * cff, char *name)
+{
+    cff_index *idx;
+    if (strlen(name) > 127)
+        normal_error("cff","FontName string length too large");
+    if (cff->name)
+        cff_release_index(cff->name);
+    cff->name = idx = xcalloc(1, sizeof(cff_index));
+    idx->count = 1;
+    idx->offsize = 1;
+    idx->offset = xmalloc(2 * sizeof(l_offset));
+    (idx->offset)[0] = 1;
+    (idx->offset)[1] = strlen(name) + 1;
+    idx->data = xmalloc((unsigned) strlen(name) * sizeof(card8));
+    /*tex No trailing |\0| */
+    memmove(idx->data, name, strlen(name));
+    return (long) (5 + strlen(name));
+}
+
+long cff_put_header(cff_font * cff, card8 * dest, long destlen)
+{
+    if (destlen < 4)
+        normal_error("cff","not enough space available");
+    /*tex cff->header_major */
+    *(dest++) = 1;
+    *(dest++) = cff->header_minor;
+    *(dest++) = 4;
+    /*tex
+        Additional data in between header and Name INDEX is ignored. We will set
+        all offset (0) to a four-byte integer.
+    */
+    *(dest++) = 4;
+    cff->header_offsize = 4;
+    return 4;
+}
+
+#define CFF_PARSE_OK                    0
+#define CFF_CFF_ERROR_PARSE_CFF_ERROR  -1
+#define CFF_CFF_ERROR_STACK_OVERFLOW   -2
+#define CFF_CFF_ERROR_STACK_UNDERFLOW  -3
+#define CFF_CFF_ERROR_STACK_RANGECHECK -4
+
+#define DICT_ENTRY_MAX 16
+
+cff_dict *cff_new_dict(void)
+{
+    cff_dict *dict;
+    dict = xcalloc(1, sizeof(cff_dict));
+    dict->max = DICT_ENTRY_MAX;
+    dict->count = 0;
+    dict->entries = xcalloc((unsigned) dict->max, sizeof(cff_dict_entry));
+    return dict;
+}
+
+/*tex
+
+    Operand stack: only numbers are stored (as double). Operand types are:
+
+    \startitemize
+    \startitem number:  double (integer or real) \stopitem
+    \startitem boolean: stored as a number       \stopitem
+    \startitem SID:     stored as a number       \stopitem
+    \startitem array:   array of numbers         \stopitem
+    \startitem delta:   array of numbers         \stopitem
+    \stopitemize
+
+*/
+
+#define CFF_DICT_STACK_LIMIT 64
+static int stack_top = 0;
+static double arg_stack[CFF_DICT_STACK_LIMIT];
+
+/* The CFF DICT encoding: */
+
+#define CFF_LAST_DICT_OP1 26
+#define CFF_LAST_DICT_OP2 39
+#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
+
+static struct {
+    const char *opname;
+    int argtype;
+} dict_operator[CFF_LAST_DICT_OP] = {
+    { "version", CFF_TYPE_SID },
+    { "Notice", CFF_TYPE_SID },
+    { "FullName", CFF_TYPE_SID },
+    { "FamilyName", CFF_TYPE_SID },
+    { "Weight", CFF_TYPE_SID },
+    { "FontBBox", CFF_TYPE_ARRAY },
+    { "BlueValues", CFF_TYPE_DELTA },
+    { "OtherBlues", CFF_TYPE_DELTA },
+    { "FamilyBlues", CFF_TYPE_DELTA },
+    { "FamilyOtherBlues", CFF_TYPE_DELTA },
+    { "StdHW", CFF_TYPE_NUMBER },
+    { "StdVW", CFF_TYPE_NUMBER },
+    { NULL, -1 },
+    { "UniqueID", CFF_TYPE_NUMBER },
+    { "XUID", CFF_TYPE_ARRAY },
+    { "charset", CFF_TYPE_OFFSET },
+    { "Encoding", CFF_TYPE_OFFSET },
+    { "CharStrings", CFF_TYPE_OFFSET },
+    { "Private", CFF_TYPE_SZOFF },
+    { "Subrs", CFF_TYPE_OFFSET },
+    { "defaultWidthX", CFF_TYPE_NUMBER },
+    { "nominalWidthX", CFF_TYPE_NUMBER },
+    { NULL, -1 },
+    { NULL, -1 },
+    /*tex two CFF2 instructions */
+    { "vstore", CFF_TYPE_OFFSET },
+    { "maxstack", CFF_TYPE_NUMBER },
+    /*tex Here we start with operator 2 of 12. */
+    { "Copyright", CFF_TYPE_SID },
+    { "IsFixedPitch", CFF_TYPE_BOOLEAN },
+    { "ItalicAngle", CFF_TYPE_NUMBER },
+    { "UnderlinePosition", CFF_TYPE_NUMBER },
+    { "UnderlineThickness", CFF_TYPE_NUMBER },
+    { "PaintType", CFF_TYPE_NUMBER },
+    { "CharstringType", CFF_TYPE_NUMBER },
+    { "FontMatrix", CFF_TYPE_ARRAY },
+    { "StrokeWidth", CFF_TYPE_NUMBER },
+    { "BlueScale", CFF_TYPE_NUMBER },
+    { "BlueShift", CFF_TYPE_NUMBER },
+    { "BlueFuzz", CFF_TYPE_NUMBER },
+    { "StemSnapH", CFF_TYPE_DELTA },
+    { "StemSnapV", CFF_TYPE_DELTA },
+    { "ForceBold", CFF_TYPE_BOOLEAN },
+    { NULL, -1 },
+    { NULL, -1 },
+    { "LanguageGroup", CFF_TYPE_NUMBER },
+    { "ExpansionFactor", CFF_TYPE_NUMBER },
+    { "InitialRandomSeed", CFF_TYPE_NUMBER },
+    { "SyntheticBase", CFF_TYPE_NUMBER },
+    { "PostScript", CFF_TYPE_SID },
+    { "BaseFontName", CFF_TYPE_SID },
+    { "BaseFontBlend", CFF_TYPE_DELTA },
+    { NULL, -1 },
+    { NULL, -1 },
+    { NULL, -1 },
+    { NULL, -1 },
+    { NULL, -1 },
+    { NULL, -1 },
+    { "ROS", CFF_TYPE_ROS },
+    { "CIDFontVersion", CFF_TYPE_NUMBER },
+    { "CIDFontRevision", CFF_TYPE_NUMBER },
+    { "CIDFontType", CFF_TYPE_NUMBER },
+    { "CIDCount", CFF_TYPE_NUMBER },
+    { "UIDBase", CFF_TYPE_NUMBER },
+    { "FDArray", CFF_TYPE_OFFSET },
+    { "FDSelect", CFF_TYPE_OFFSET },
+    { "FontName", CFF_TYPE_SID }
+};
+
+/*tex Parse DICT data */
+
+static double get_integer(card8 ** data, card8 * endptr, int *status)
+{
+    long result = 0;
+    card8 b0, b1, b2;
+
+    b0 = *(*data)++;
+    if (b0 == 28 && *data < endptr - 2) {
+        /*tex shortint */
+        b1 = *(*data)++;
+        b2 = *(*data)++;
+        result = b1 * 256 + b2;
+        if (result > 0x7fffL)
+            result -= 0x10000L;
+    } else if (b0 == 29 && *data < endptr - 4) {
+        /*tex longint */
+        int i;
+        result = *(*data)++;
+        if (result > 0x7f)
+            result -= 0x100;
+        for (i = 0; i < 3; i++) {
+            result = result * 256 + (**data);
+            *data += 1;
+        }
+    } else if (b0 >= 32 && b0 <= 246) {
+        /*tex int (1) */
+        result = b0 - 139;
+    } else if (b0 >= 247 && b0 <= 250) {
+        /*tex int (2) */
+        b1 = *(*data)++;
+        result = (b0 - 247) * 256 + b1 + 108;
+    } else if (b0 >= 251 && b0 <= 254) {
+        b1 = *(*data)++;
+        result = -(b0 - 251) * 256 - b1 - 108;
+    } else {
+        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+    }
+    return (double) result;
+}
+
+/*tex Simply uses |strtod|: */
+
+static double get_real(card8 ** data, card8 * endptr, int *status)
+{
+    double result = 0.0;
+    int nibble = 0, pos = 0;
+    int len = 0, fail = 0;
+
+    if (**data != 30 || *data >= endptr - 1) {
+        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+        return 0.0;
+    }
+    /*tex Skip the first byte (30): */
+    *data += 1;
+    pos = 0;
+    while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
+        /*tex Get a nibble. */
+        if (pos % 2) {
+            nibble = **data & 0x0f;
+            *data += 1;
+        } else {
+            nibble = (**data >> 4) & 0x0f;
+        }
+        if (nibble >= 0x00 && nibble <= 0x09) {
+            work_buffer[len++] = (char) (nibble + '0');
+        } else if (nibble == 0x0a) {    /* . */
+            work_buffer[len++] = '.';
+        } else if (nibble == 0x0b || nibble == 0x0c) {
+            /*tex E, E- */
+            work_buffer[len++] = 'e';
+            if (nibble == 0x0c)
+                work_buffer[len++] = '-';
+        } else if (nibble == 0x0e) {
+            /*tex the minus */
+            work_buffer[len++] = '-';
+        } else if (nibble == 0x0d) {
+            /*tex do nothing */
+        } else if (nibble == 0x0f) {
+            /*tex we're done */
+            work_buffer[len++] = '\0';
+            if (((pos % 2) == 0) && (**data != 0xff)) {
+                fail = 1;
+            }
+            break;
+        } else {
+            /*tex invalid */
+            fail = 1;
+        }
+        pos++;
+    }
+    /*tex the returned values */
+    if (fail || nibble != 0x0f) {
+        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+    } else {
+        char *s;
+        errno=0;
+        result = strtod(work_buffer, &s);
+        if ((result==0.0 && work_buffer==s) || errno) {
+              /*tex Conversion is not possible. */
+             *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+         }
+    }
+    return result;
+}
+
+/*tex Operators */
+
+static void add_dict(cff_dict * dict, card8 ** data, card8 * endptr, int *status)
+{
+    int id, argtype, t;
+    id = **data;
+    if (id == 0x0c) {
+        *data += 1;
+        if (*data >= endptr ||
+            (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
+            *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+            return;
+        }
+    } else if (id >= CFF_LAST_DICT_OP1) {
+        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+        return;
+    }
+    argtype = dict_operator[id].argtype;
+    if (dict_operator[id].opname == NULL || argtype < 0) {
+        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
+        return;
+    }
+    if (dict->count >= dict->max) {
+        dict->max += DICT_ENTRY_MAX;
+        /*tex Not zeroed! */
+        dict->entries = xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry)));
+    }
+    (dict->entries)[dict->count].id = id;
+    (dict->entries)[dict->count].key = dict_operator[id].opname;
+    if (argtype == CFF_TYPE_NUMBER ||
+        argtype == CFF_TYPE_BOOLEAN ||
+        argtype == CFF_TYPE_SID || argtype == CFF_TYPE_OFFSET) {
+        /*tex Check for underflow here, as exactly one operand is expected. */
+        if (stack_top < 1) {
+            *status = CFF_CFF_ERROR_STACK_UNDERFLOW;
+            return;
+        }
+        stack_top--;
+        (dict->entries)[dict->count].count = 1;
+        (dict->entries)[dict->count].values = xcalloc(1, sizeof(double));
+        (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
+        dict->count += 1;
+    } else {
+        /*tex
+            Just ignore operator if there were no operands provided. Don't treat
+            this as underflow, e.g. |StemSnapV| in |TemporaLGCUni-Italic.otf|.
+        */
+        if ((t = stack_top) > 0) {
+            (dict->entries)[dict->count].count = stack_top;
+            (dict->entries)[dict->count].values =
+                xmalloc((unsigned) ((unsigned) stack_top * sizeof(double)));
+            while (stack_top > 0) {
+                stack_top--;
+                (dict->entries)[dict->count].values[stack_top] =
+                    arg_stack[stack_top];
+            }
+            if (t > 3 && strcmp(dict_operator[id].opname, "FontMatrix") == 0) {
+                (dict->entries)[dict->count].values[0] = 0.001;
+                (dict->entries)[dict->count].values[3] = 0.001;
+            }
+            dict->count += 1;
+        }
+    }
+    *data += 1;
+    return;
+}
+
+/*tex
+
+    All operands are treated as number or array of numbers.
+
+    \startitemize
+    \startitem |Private|: two numbers, size and offset     \stopitem
+    \startitem |ROS|: hree numbers, SID, SID, and a number \stopitem
+    \stopitemize
+
+*/
+
+cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
+{
+    cff_dict *dict;
+    int status = CFF_PARSE_OK;
+    stack_top = 0;
+    dict = cff_new_dict();
+    while (data < endptr && status == CFF_PARSE_OK) {
+        if (*data < CFF_LAST_DICT_OP1) {
+            /*tex Some operator. */
+            add_dict(dict, &data, endptr, &status);
+        } else if (*data == 30) {
+            /*tex First byte of a sequence (variable). */
+            if (stack_top < CFF_DICT_STACK_LIMIT) {
+                arg_stack[stack_top] = get_real(&data, endptr, &status);
+                stack_top++;
+            } else {
+                status = CFF_CFF_ERROR_STACK_OVERFLOW;
+            }
+        } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) {
+            /*tex Reserved. */
+            data++;
+        } else {
+            /*tex Everything else is an integer. */
+            if (stack_top < CFF_DICT_STACK_LIMIT) {
+                arg_stack[stack_top] = get_integer(&data, endptr, &status);
+                stack_top++;
+            } else {
+                status = CFF_CFF_ERROR_STACK_OVERFLOW;
+            }
+        }
+    }
+    if (status != CFF_PARSE_OK) {
+        formatted_error("cff","parsing DICT failed (error=%d)", status);
+    } else if (stack_top != 0) {
+        normal_warning("cff","garbage in DICT data");
+        stack_top = 0;
+    }
+    return dict;
+}
+
+int cff_dict_known(cff_dict * dict, const char *key)
+{
+    int i;
+    for (i = 0; i < dict->count; i++) {
+        if (key && strcmp(key, (dict->entries)[i].key) == 0
+            && (dict->entries)[i].count > 0)
+            return 1;
+    }
+    return 0;
+}
+
+double cff_dict_get(cff_dict * dict, const char *key, int idx)
+{
+    double value = 0.0;
+    int i;
+    assert(key && dict);
+    for (i = 0; i < dict->count; i++) {
+        if (strcmp(key, (dict->entries)[i].key) == 0) {
+           if ((dict->entries)[i].count > idx)
+                value = (dict->entries)[i].values[idx];
+            else
+                normal_error("cff","invalid index number");
+            break;
+        }
+    }
+    if (i == dict->count)
+        formatted_error("cff","DICT entry '%s' not found", key);
+    return value;
+}
+
+card8 cff_fdselect_lookup(cff_font * cff, card16 gid)
+{
+    card8 fd = 0xff;
+    cff_fdselect *fdsel;
+    if (cff->fdselect == NULL)
+        normal_error("cff","FDSelect not available");
+    fdsel = cff->fdselect;
+    if (gid >= cff->num_glyphs)
+        normal_error("cff","invalid glyph index");
+    switch (fdsel->format) {
+        case 0:
+            fd = fdsel->data.fds[gid];
+            break;
+        case 3:
+            {
+                if (gid == 0) {
+                    fd = (fdsel->data).ranges[0].fd;
+                } else {
+                    card16 i;
+                    for (i = 1; i < (fdsel->num_entries); i++) {
+                        if (gid < (fdsel->data).ranges[i].first)
+                            break;
+                    }
+                    fd = (fdsel->data).ranges[i - 1].fd;
+                }
+            }
+            break;
+        default:
+            normal_error("cff","invalid FDSelect format");
+            break;
+    }
+    if (fd >= cff->num_fds)
+        normal_error("cff","invalid Font DICT index");
+    return fd;
+}
+
+long cff_read_subrs(cff_font * cff)
+{
+    long len = 0;
+    long offset;
+    int i;
+    if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdselect == NULL) {
+        cff_read_fdselect(cff);
+    }
+    if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) {
+        cff_read_fdarray(cff);
+    }
+    if (cff->private == NULL)
+        cff_read_private(cff);
+    if (cff->gsubr == NULL) {
+        cff->offset = cff->gsubr_offset;
+        cff->gsubr = cff_get_index(cff);
+    }
+    cff->subrs = xcalloc(cff->num_fds, sizeof(cff_index *));
+    if (cff->flag & FONTTYPE_CIDFONT) {
+        for (i = 0; i < cff->num_fds; i++) {
+            if (cff->private[i] == NULL ||
+                !cff_dict_known(cff->private[i], "Subrs")) {
+                (cff->subrs)[i] = NULL;
+            } else {
+                offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
+                offset += (long) cff_dict_get(cff->private[i], "Subrs", 0);
+                cff->offset = (l_offset) offset;
+                (cff->subrs)[i] = cff_get_index(cff);
+                len += cff_index_size((cff->subrs)[i]);
+            }
+        }
+    } else if (cff->private[0] == NULL || !cff_dict_known(cff->private[0], "Subrs")) {
+        (cff->subrs)[0] = NULL;
+    } else {
+        offset = (long) cff_dict_get(cff->topdict, "Private", 1);
+        offset += (long) cff_dict_get(cff->private[0], "Subrs", 0);
+        cff->offset = (l_offset) offset;
+        (cff->subrs)[0] = cff_get_index(cff);
+        len += cff_index_size((cff->subrs)[0]);
+    }
+    return len;
+}
+
+long cff_read_fdarray(cff_font * cff)
+{
+    long len = 0;
+    cff_index *idx;
+    long offset, size;
+    card16 i;
+    if (cff->topdict == NULL)
+        normal_error("cff","top DICT not found");
+    if (!(cff->flag & FONTTYPE_CIDFONT))
+        return 0;
+    offset = (long) cff_dict_get(cff->topdict, "FDArray", 0);
+    cff->offset = (l_offset) offset;
+    idx = cff_get_index(cff);
+    cff->num_fds = (card8) idx->count;
+    cff->fdarray = xmalloc((unsigned) (idx->count * sizeof(cff_dict *)));
+    for (i = 0; i < idx->count; i++) {
+        card8 *data = idx->data + (idx->offset)[i] - 1;
+        size = (long) ((idx->offset)[i + 1] - (idx->offset)[i]);
+        if (size > 0) {
+            (cff->fdarray)[i] = cff_dict_unpack(data, data + size);
+        } else {
+            (cff->fdarray)[i] = NULL;
+        }
+    }
+    len = cff_index_size(idx);
+    cff_release_index(idx);
+    return len;
+}
+
+long cff_read_private(cff_font * cff)
+{
+    long len = 0;
+    card8 *data;
+    long offset, size;
+    if (cff->flag & FONTTYPE_CIDFONT) {
+        int i;
+        if (cff->fdarray == NULL)
+            cff_read_fdarray(cff);
+        cff->private = xmalloc((unsigned) (cff->num_fds * sizeof(cff_dict *)));
+        for (i = 0; i < cff->num_fds; i++) {
+            if (cff->fdarray[i] != NULL &&
+                    cff_dict_known(cff->fdarray[i], "Private") &&
+                    (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0)) > 0) {
+                offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
+                cff->offset = (l_offset) offset;
+                data = xmalloc((unsigned) size * sizeof(card8));
+                memcpy(data, &cff->stream[cff->offset], (size_t) size);
+                cff->offset = (l_offset) size;
+                (cff->private)[i] = cff_dict_unpack(data, data + size);
+                xfree(data);
+                len += size;
+            } else {
+                (cff->private)[i] = NULL;
+            }
+        }
+    } else {
+        cff->num_fds = 1;
+        cff->private = xmalloc(sizeof(cff_dict *));
+        if (cff_dict_known(cff->topdict, "Private") &&
+                (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) {
+            offset = (long) cff_dict_get(cff->topdict, "Private", 1);
+            cff->offset = (l_offset) offset;
+            data = xmalloc((unsigned) size * sizeof(card8));
+            memcpy(data, &cff->stream[cff->offset], (size_t) size);
+            cff->offset = (l_offset) size;
+            cff->private[0] = cff_dict_unpack(data, data + size);
+            xfree(data);
+            len += size;
+        } else {
+            (cff->private)[0] = NULL;
+            len = 0;
+        }
+    }
+    return len;
+}
+
+cff_font *read_cff(unsigned char *buf, long buflength, int n)
+{
+    cff_font *cff;
+    cff_index *idx;
+    long offset;
+    cff = xcalloc(1, sizeof(cff_font));
+    cff->stream = buf;
+    cff->stream_size = (l_offset) buflength;
+    cff->index = n;
+    cff->header_major = get_card8(cff);
+    cff->header_minor = get_card8(cff);
+    cff->header_hdr_size = get_card8(cff);
+    if (cff->header_major == 2) {
+        /*tex We have only one top dictionary. */
+        cff->header_offsize = get_card16(cff);
+    } else {
+        cff->header_offsize = get_card8(cff);
+        if (cff->header_offsize < 1 || cff->header_offsize > 4) {
+            normal_warning("cff","invalid offsize data (4)");
+            cff_close(cff);
+            return NULL;
+        }
+    }
+    if (cff->header_major > 2) {
+        formatted_warning("cff","major version %u not supported", cff->header_major);
+        cff_close(cff);
+        return NULL;
+    }
+    cff->offset = cff->header_hdr_size;
+    /*tex The name index. */
+    if (cff->header_major == 2) {
+        cff->name = cff_empty_index(cff);
+    } else {
+        idx = cff_get_index(cff);
+        if (n > idx->count - 1) {
+            normal_warning("cff","invalid fontset index number");
+            cff_close(cff);
+            return NULL;
+        }
+        cff->name = idx;
+        cff->fontname = cff_get_name(cff);
+    }
+    /*tex The top dict index. */
+    if (cff->header_major == 2) {
+        /*tex we fake an index (just one entry) */
+        idx = cff_get_index2(cff);
+    } else {
+        idx = cff_get_index(cff);
+    }
+    if (n > idx->count - 1) {
+        normal_warning("cff","top DICT not exist");
+        cff_close(cff);
+        return NULL;
+    }
+    cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1, idx->data + idx->offset[n + 1] - 1);
+    if (!cff->topdict) {
+        normal_warning("cff","parsing top DICT data failed");
+        cff_close(cff);
+        return NULL;
+    }
+    cff_release_index(idx);
+    if (cff_dict_known(cff->topdict, "CharstringType") &&
+        cff_dict_get(cff->topdict, "CharstringType", 0) != 2) {
+        normal_warning("cff","only type 2 charstrings supported");
+        cff_close(cff);
+        return NULL;
+    }
+    if (cff_dict_known(cff->topdict, "SyntheticBase")) {
+        normal_warning("cff","synthetic font not supported");
+        cff_close(cff);
+        return NULL;
+    }
+    /*tex The string index. */
+    if (cff->header_major == 2) {
+        /*tex do nothing */
+    } else {
+        cff->string = cff_get_index(cff);
+    }
+    /*tex The offset to subroutines. */
+    cff->gsubr_offset = cff->offset;
+    /*tex The number of glyphs. */
+    offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0);
+    cff->offset = (l_offset) offset;
+    cff->num_glyphs = get_card16(cff);
+    /*tex Check for font type. */
+    if (cff_dict_known(cff->topdict, "ROS")) {
+        cff->flag |= FONTTYPE_CIDFONT;
+    } else {
+        cff->flag |= FONTTYPE_FONT;
+    }
+    /*tex Check for the encoding. */
+    if (cff_dict_known(cff->topdict, "Encoding")) {
+        offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
+        if (offset == 0) {      /* predefined */
+            cff->flag |= ENCODING_STANDARD;
+        } else if (offset == 1) {
+            cff->flag |= ENCODING_EXPERT;
+        }
+    } else {
+        cff->flag |= ENCODING_STANDARD;
+    }
+    cff->offset = cff->gsubr_offset;
+    return cff;
+}
+
+/*tex Write CFF data for an \OPENTYPE\ font. We need to pack dictionary data. */
+
+static long pack_integer(card8 * dest, long destlen, long value)
+{
+    long len = 0;
+    if (value >= -107 && value <= 107) {
+        if (destlen < 1)
+            normal_error("cff","buffer overflow (1)");
+        dest[0] = (card8) ((value + 139) & 0xff);
+        len = 1;
+    } else if (value >= 108 && value <= 1131) {
+        if (destlen < 2)
+            normal_error("cff","buffer overflow (2)");
+        value = (long) 0xf700u + value - 108;
+        dest[0] = (card8) ((value >> 8) & 0xff);
+        dest[1] = (card8) (value & 0xff);
+        len = 2;
+    } else if (value >= -1131 && value <= -108) {
+        if (destlen < 2)
+            normal_error("cff","buffer overflow (3)");
+        value = (long) 0xfb00u - value - 108;
+        dest[0] = (card8) ((value >> 8) & 0xff);
+        dest[1] = (card8) (value & 0xff);
+        len = 2;
+    } else if (value >= -32768 && value <= 32767) {
+        /*tex shortint */
+        if (destlen < 3)
+            normal_error("cff","buffer overflow (4)");
+        dest[0] = 28;
+        dest[1] = (card8) ((value >> 8) & 0xff);
+        dest[2] = (card8) (value & 0xff);
+        len = 3;
+    } else {
+        /*tex longint */
+        if (destlen < 5)
+            normal_error("cff","buffer overflow (5)");
+        dest[0] = 29;
+        dest[1] = (card8) ((value >> 24) & 0xff);
+        dest[2] = (card8) ((value >> 16) & 0xff);
+        dest[3] = (card8) ((value >> 8) & 0xff);
+        dest[4] = (card8) (value & 0xff);
+        len = 5;
+    }
+    return len;
+}
+
+static long pack_real(card8 * dest, long destlen, double value)
+{
+    long e;
+    int i = 0, pos = 2;
+    int res;
+#define CFF_REAL_MAX_LEN 17
+    if (destlen < 2)
+        normal_error("cff","buffer overflow (6)");
+    dest[0] = 30;
+    if (value == 0.0) {
+        dest[1] = 0x0f;
+        return 2;
+    }
+    if (value < 0.0) {
+        dest[1] = 0xe0;
+        value *= -1.0;
+        pos++;
+    }
+    e = 0;
+    if (value >= 10.0) {
+        while (value >= 10.0) {
+            value /= 10.0;
+            e++;
+        }
+    } else if (value < 1.0) {
+        while (value < 1.0) {
+            value *= 10.0;
+            e--;
+        }
+    }
+    res = sprintf(work_buffer, "%1.14g", value);
+    if (res<0)
+        normal_error("cff","invalid conversion");
+    if (res>CFF_REAL_MAX_LEN)
+        res=CFF_REAL_MAX_LEN;
+    for (i = 0; i < res; i++) {
+        unsigned char ch = 0;
+        if (work_buffer[i] == '\0') {
+            /*tex In fact |res| should prevent this. */
+            break;
+        } else if (work_buffer[i] == '.') {
+            ch = 0x0a;
+        } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
+            ch = (unsigned char) (work_buffer[i] - '0');
+        } else {
+            normal_error("cff","invalid character");
+        }
+        if (destlen < pos / 2 + 1)
+            normal_error("cff","buffer overflow (7)");
+
+        if (pos % 2) {
+            dest[pos / 2] = (card8) (dest[pos / 2] + ch);
+        } else {
+            dest[pos / 2] = (card8) (ch << 4);
+        }
+        pos++;
+    }
+    if (e > 0) {
+        if (pos % 2) {
+            dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b);
+        } else {
+            if (destlen < pos / 2 + 1)
+                normal_error("cff","buffer overflow (8)");
+            dest[pos / 2] = (card8) (0xb0);
+        }
+        pos++;
+    } else if (e < 0) {
+        if (pos % 2) {
+            dest[pos / 2] = (card8) (dest[pos / 2] + 0x0c);
+        } else {
+            if (destlen < pos / 2 + 1)
+                normal_error("cff","buffer overflow (9)");
+            dest[pos / 2] = (card8) (0xc0);
+        }
+        e *= -1;
+        pos++;
+    }
+    if (e != 0) {
+        sprintf(work_buffer, "%ld", e);
+        for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
+            unsigned char ch = 0;
+            if (work_buffer[i] == '\0') {
+                break;
+            } else if (work_buffer[i] == '.') {
+                ch = 0x0a;
+            } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
+                ch = (unsigned char) (work_buffer[i] - '0');
+            } else {
+                normal_error("cff","invalid character");
+            }
+            if (destlen < pos / 2 + 1)
+                normal_error("cff","buffer overflow (10)");
+            if (pos % 2) {
+                dest[pos / 2] = (card8) (dest[pos / 2] + ch);
+            } else {
+                dest[pos / 2] = (card8) (ch << 4);
+            }
+            pos++;
+        }
+    }
+    if (pos % 2) {
+        dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f);
+        pos++;
+    } else {
+        if (destlen < pos / 2 + 1)
+            normal_error("cff","buffer overflow (11)");
+        dest[pos / 2] = (card8) (0xff);
+        pos += 2;
+    }
+    return pos / 2;
+}
+
+static long cff_dict_put_number(double value, card8 * dest, long destlen, int type)
+{
+    long len = 0;
+    double nearint;
+    nearint = floor(value + 0.5);
+    if (type == CFF_TYPE_OFFSET) {
+        long lvalue;
+        lvalue = (long) value;
+        if (destlen < 5)
+            normal_error("cff","buffer overflow (12)");
+        dest[0] = 29;
+        dest[1] = (card8) ((lvalue >> 24) & 0xff);
+        dest[2] = (card8) ((lvalue >> 16) & 0xff);
+        dest[3] = (card8) ((lvalue >> 8) & 0xff);
+        dest[4] = (card8) (lvalue & 0xff);
+        len = 5;
+    } else if (value > CFF_INT_MAX || value < CFF_INT_MIN || (fabs(value - nearint) > 1.0e-5)) {
+        /*tex A real */
+        len = pack_real(dest, destlen, value);
+    } else {
+        /*tex An integer */
+        len = pack_integer(dest, destlen, (long) nearint);
+    }
+    return len;
+}
+
+static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen)
+{
+    long len = 0;
+    int i, type, id;
+    if (de->count > 0) {
+        id = de->id;
+        if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
+            dict_operator[id].argtype == CFF_TYPE_SZOFF) {
+            type = CFF_TYPE_OFFSET;
+        } else {
+            type = CFF_TYPE_NUMBER;
+        }
+        for (i = 0; i < de->count; i++) {
+            len += cff_dict_put_number(de->values[i], dest + len, destlen - len, type);
+        }
+        if (id >= 0 && id < CFF_LAST_DICT_OP1) {
+            if (len + 1 > destlen)
+                normal_error("cff","buffer overflow (13)");
+            dest[len++] = (card8) id;
+        } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
+            if (len + 2 > destlen)
+                normal_error("cff","buffer overflow (14)");
+            dest[len++] = 12;
+            dest[len++] = (card8) (id - CFF_LAST_DICT_OP1);
+        } else {
+            normal_error("cff","invalid DICT operator ID");
+        }
+    }
+    return len;
+}
+
+long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen)
+{
+    long len = 0;
+    int i;
+    for (i = 0; i < dict->count; i++) {
+        if (!strcmp(dict->entries[i].key, "ROS")) {
+            len += put_dict_entry(&dict->entries[i], dest, destlen);
+            break;
+        }
+    }
+    for (i = 0; i < dict->count; i++) {
+        if (strcmp(dict->entries[i].key, "ROS")) {
+            len += put_dict_entry(&dict->entries[i], dest + len, destlen - len);
+        }
+    }
+    return len;
+}
+
+void cff_dict_add(cff_dict * dict, const char *key, int count)
+{
+    int id, i;
+    for (id = 0; id < CFF_LAST_DICT_OP; id++) {
+        if (key && dict_operator[id].opname &&
+            strcmp(dict_operator[id].opname, key) == 0)
+            break;
+    }
+    if (id == CFF_LAST_DICT_OP)
+        normal_error("cff","unknown DICT operator");
+    for (i = 0; i < dict->count; i++) {
+        if ((dict->entries)[i].id == id) {
+            if ((dict->entries)[i].count != count)
+                normal_error("cff","inconsistent DICT argument number");
+            return;
+        }
+    }
+    if (dict->count + 1 >= dict->max) {
+        dict->max += 8;
+        dict->entries =
+            xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry)));
+    }
+    (dict->entries)[dict->count].id = id;
+    (dict->entries)[dict->count].key = dict_operator[id].opname;
+    (dict->entries)[dict->count].count = count;
+    if (count > 0) {
+        (dict->entries)[dict->count].values = xcalloc((unsigned) count, sizeof(double));
+    } else {
+        (dict->entries)[dict->count].values = NULL;
+    }
+    dict->count += 1;
+    return;
+}
+
+void cff_dict_remove(cff_dict * dict, const char *key)
+{
+    int i;
+    for (i = 0; i < dict->count; i++) {
+        if (key && strcmp(key, (dict->entries)[i].key) == 0) {
+            (dict->entries)[i].count = 0;
+            xfree((dict->entries)[i].values);
+        }
+    }
+}
+
+void cff_dict_set(cff_dict * dict, const char *key, int idx, double value)
+{
+    int i;
+    for (i = 0; i < dict->count; i++) {
+        if (strcmp(key, (dict->entries)[i].key) == 0) {
+            if ((dict->entries)[i].count > idx)
+                (dict->entries)[i].values[idx] = value;
+            else
+                normal_error("cff","invalid index number");
+            break;
+        }
+    }
+    if (i == dict->count)
+        formatted_error("cff","DICT entry '%s' not found", key);
+}
+
+
+/*tex Strings */
+
+char *cff_get_string(cff_font * cff, s_SID id)
+{
+    char *result = NULL;
+    size_t len;
+    if (id < CFF_STDSTR_MAX) {
+        len = strlen(cff_stdstr[id]);
+        result = xmalloc((unsigned) (len + 1) * sizeof(char));
+        memcpy(result, cff_stdstr[id], len);
+        result[len] = '\0';
+    } else if (cff && cff->string) {
+        cff_index *strings = cff->string;
+        id = (s_SID) (id - CFF_STDSTR_MAX);
+        if (id < strings->count) {
+            len = (strings->offset)[id + 1] - (strings->offset)[id];
+            result = xmalloc((unsigned) (len + 1) * sizeof(char));
+            memmove(result, strings->data + (strings->offset)[id] - 1, len);
+            result[len] = '\0';
+        }
+    }
+    return result;
+}
+
+long cff_get_sid(cff_font * cff, const char *str)
+{
+    card16 i;
+    if (!cff || !str)
+        return -1;
+    /*tex We search the string index first. */
+    if (cff && cff->string) {
+        cff_index *idx = cff->string;
+        for (i = 0; i < idx->count; i++) {
+            if (strlen(str) == (idx->offset)[i + 1] - (idx->offset)[i] &&
+                !memcmp(str, (idx->data) + (idx->offset)[i] - 1, strlen(str)))
+                return (i + CFF_STDSTR_MAX);
+        }
+    }
+    for (i = 0; i < CFF_STDSTR_MAX; i++) {
+        if (!strcmp(str, cff_stdstr[i]))
+            return i;
+    }
+    return -1;
+}
+
+void cff_update_string(cff_font * cff)
+{
+    if (cff == NULL)
+        normal_error("cff","CFF font not opened");
+    if (cff->string)
+        cff_release_index(cff->string);
+    cff->string = cff->_string;
+    cff->_string = NULL;
+}
+
+s_SID cff_add_string(cff_font * cff, const char *str)
+{
+    card16 idx;
+    cff_index *strings;
+    l_offset offset, size;
+    if (cff == NULL) {
+        normal_error("cff","CFF font not opened");
+    }
+    if (cff->_string == NULL) {
+        cff->_string = cff_new_index(0);
+    }
+    strings = cff->_string;
+    for (idx = 0; idx < strings->count; idx++) {
+        size = strings->offset[idx + 1] - strings->offset[idx];
+        offset = strings->offset[idx];
+        if (size == strlen(str) && !memcmp(strings->data + offset - 1, str, strlen(str))) {
+            return (s_SID) (idx + CFF_STDSTR_MAX);
+        }
+    }
+    for (idx = 0; idx < CFF_STDSTR_MAX; idx++) {
+        if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str)) {
+            return idx;
+        }
+    }
+    offset = (strings->count > 0) ? strings->offset[strings->count] : 1;
+    strings->offset = xrealloc(strings->offset, (unsigned) (((unsigned) strings->count + 2) * sizeof(l_offset)));
+    if (strings->count == 0)
+        strings->offset[0] = 1;
+    idx = strings->count;
+    strings->count = (card16) (strings->count + 1);
+    strings->offset[strings->count] = offset + strlen(str);
+    strings->data = xrealloc(strings->data, (unsigned) ((offset + strlen(str) - 1) * sizeof(card8)));
+    memcpy(strings->data + offset - 1, str, strlen(str));
+    return (s_SID) (idx + CFF_STDSTR_MAX);
+}
+
+void cff_dict_update(cff_dict * dict, cff_font * cff)
+{
+    int i;
+    for (i = 0; i < dict->count; i++) {
+        if ((dict->entries)[i].count > 0) {
+            char *str;
+            int id;
+            id = (dict->entries)[i].id;
+            if (dict_operator[id].argtype == CFF_TYPE_SID) {
+                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
+                if (str != NULL) {
+                    (dict->entries)[i].values[0] = cff_add_string(cff, str);
+                    xfree(str);
+                }
+            } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
+                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
+                if (str != NULL) {
+                    (dict->entries)[i].values[0] = cff_add_string(cff, str);
+                    xfree(str);
+                }
+                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[1]);
+                if (str != NULL) {
+                    (dict->entries)[i].values[1] = cff_add_string(cff, str);
+                    xfree(str);
+                }
+            }
+        }
+    }
+}
+
+/*tex The charsets. */
+
+long cff_read_charsets(cff_font * cff)
+{
+    cff_charsets *charset;
+    long offset, length;
+    card16 count, i;
+    if (cff->topdict == NULL)
+        normal_error("cff","top DICT not available");
+    if (!cff_dict_known(cff->topdict, "charset")) {
+        cff->flag |= CHARSETS_ISOADOBE;
+        cff->charsets = NULL;
+        return 0;
+    }
+    offset = (long) cff_dict_get(cff->topdict, "charset", 0);
+    if (offset == 0) {
+        /*tex predefined */
+        cff->flag |= CHARSETS_ISOADOBE;
+        cff->charsets = NULL;
+        return 0;
+    } else if (offset == 1) {
+        cff->flag |= CHARSETS_EXPERT;
+        cff->charsets = NULL;
+        return 0;
+    } else if (offset == 2) {
+        cff->flag |= CHARSETS_EXPSUB;
+        cff->charsets = NULL;
+        return 0;
+    }
+    cff->offset = (l_offset) offset;
+    cff->charsets = charset = xcalloc(1, sizeof(cff_charsets));
+    charset->format = get_card8(cff);
+    charset->num_entries = 0;
+    count = (card16) (cff->num_glyphs - 1);
+    length = 1;
+    /*tex Not well documented. */
+    switch (charset->format) {
+        case 0:
+            charset->num_entries = (card16) (cff->num_glyphs - 1);  /* no .notdef */
+            charset->data.glyphs =
+                xmalloc((unsigned) (charset->num_entries * sizeof(s_SID)));
+            length += (charset->num_entries) * 2;
+            for (i = 0; i < (charset->num_entries); i++) {
+                charset->data.glyphs[i] = get_card16(cff);
+            }
+            count = 0;
+            break;
+        case 1:
+            {
+                cff_range1 *ranges = NULL;
+                while (count > 0 && charset->num_entries < cff->num_glyphs) {
+                    ranges =
+                        xrealloc(ranges,
+                                 (unsigned) (((unsigned) charset->num_entries +
+                                              1) * sizeof(cff_range1)));
+                    ranges[charset->num_entries].first = get_card16(cff);
+                    ranges[charset->num_entries].n_left = get_card8(cff);
+                    count = (card16) (count - ranges[charset->num_entries].n_left + 1);     /* no-overrap */
+                    charset->num_entries++;
+                    charset->data.range1 = ranges;
+                }
+                length += (charset->num_entries) * 3;
+            }
+            break;
+        case 2:
+            {
+                cff_range2 *ranges = NULL;
+                while (count > 0 && charset->num_entries < cff->num_glyphs) {
+                    ranges =
+                        xrealloc(ranges,
+                                 (unsigned) (((unsigned) charset->num_entries +
+                                              1) * sizeof(cff_range2)));
+                    ranges[charset->num_entries].first = get_card16(cff);
+                    ranges[charset->num_entries].n_left = get_card16(cff);
+                    count = (card16) (count - (ranges[charset->num_entries].n_left + 1));   /* non-overrapping */
+                    charset->num_entries++;
+                }
+                charset->data.range2 = ranges;
+                length += (charset->num_entries) * 4;
+            }
+            break;
+        default:
+            xfree(charset);
+            normal_error("cff","unknown charset format");
+            break;
+    }
+    if (count > 0) {
+        normal_warning("cff","charset data possibly broken (too many glyphs)");
+    }
+    return length;
+}
+
+long cff_pack_charsets(cff_font * cff, card8 * dest, long destlen)
+{
+    long len = 0;
+    card16 i;
+    cff_charsets *charset;
+    if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL)
+        return 0;
+    if (destlen < 1)
+        normal_error("cff","buffer overflow (15)");
+    charset = cff->charsets;
+    dest[len++] = charset->format;
+    switch (charset->format) {
+        case 0:
+            if (destlen < len + (charset->num_entries) * 2)
+                normal_error("cff","buffer overflow (16)");
+            for (i = 0; i < (charset->num_entries); i++) {
+                s_SID sid = (charset->data).glyphs[i];      /* or CID */
+                dest[len++] = (card8) ((sid >> 8) & 0xff);
+                dest[len++] = (card8) (sid & 0xff);
+            }
+            break;
+        case 1:
+            {
+                if (destlen < len + (charset->num_entries) * 3)
+                    normal_error("cff","buffer overflow (17)");
+                for (i = 0; i < (charset->num_entries); i++) {
+                    dest[len++] = (card8) (((charset->data).range1[i].first >> 8) & 0xff);
+                    dest[len++] = (card8) ((charset->data).range1[i].first & 0xff);
+                    dest[len++] = (card8) ((charset->data).range1[i].n_left);
+                }
+            }
+            break;
+        case 2:
+            {
+                if (destlen < len + (charset->num_entries) * 4)
+                    normal_error("cff","buffer overflow (18)");
+                for (i = 0; i < (charset->num_entries); i++) {
+                    dest[len++] = (card8) (((charset->data).range2[i].first >> 8) & 0xff);
+                    dest[len++] = (card8) ((charset->data).range2[i].first & 0xff);
+                    dest[len++] = (card8) (((charset->data).range2[i].n_left >> 8) & 0xff);
+                    dest[len++] = (card8) ((charset->data).range2[i].n_left & 0xff);
+                }
+            }
+            break;
+        default:
+            normal_error("cff","unknown charset format");
+            break;
+    }
+    return len;
+}
+
+/*tex
+
+    Here we decode and encode Type 2 charstring. All local/global subroutine
+    calls in a given charstring is replace by the content of subroutine
+    charstrings. We do this because some PostScript RIP may have problems with
+    sparse subroutine array. Workaround for this is to re-order subroutine array
+    so that no gap appears in the subroutine array, or put dummy charstrings that
+    contains only `return' in the gap. However, re-ordering of subroutine is
+    rather difficult for Type 2 charstrings due to the bias which depends on the
+    total number of subroutines. Replacing callgsubr/callsubr calls with the
+    content of the corresponding subroutine charstring may be more efficient than
+    putting dummy subroutines in the case of subsetted font. Adobe distiller
+    seems doing same thing.
+
+    And also note that subroutine numbers within subroutines can depend on the
+    content of operand stack as follows:
+
+    \startyping
+    \.{  ... l m callsubr << subr \#(m+bias): n add callsubr >> ...}
+    \stoptyping
+
+    I've not implemented the `random' operator which generates a pseudo-random
+    number in the range (0, 1] and push them into argument stack. How
+    pseudo-random sequences are generated is not documented in the Type 2
+    charstring spec.
+
+*/
+
+#define CS_TYPE2_DEBUG_STR   "Type2 Charstring Parser"
+#define CS_TYPE2_DEBUG       5
+
+#define CS_BUFFER_CFF_ERROR -3
+#define CS_STACK_CFF_ERROR  -2
+#define CS_PARSE_CFF_ERROR  -1
+#define CS_PARSE_OK          0
+#define CS_PARSE_END         1
+#define CS_SUBR_RETURN       2
+#define CS_CHAR_END          3
+
+static int status = CS_PARSE_CFF_ERROR;
+
+#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_CFF_ERROR ; return ; }}
+#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_CFF_ERROR  ; return ; }}
+#define NEED(a,b)     {if ((a) < (b)) { status = CS_STACK_CFF_ERROR  ; return ; }}
+
+/*tex The hintmask and cntrmask need the number of stem zones. */
+
+static int num_stems = 0;
+static int phase = 0;
+
+/*tex Subroutine nesting.
+*/
+static int cs2_nest = 0;
+
+/*tex The advance width. */
+
+static int have_width = 0;
+static double width = 0.0;
+
+/*tex
+
+    Standard Encoding Accented Characters: Optional four arguments for endchar.
+    See, CFF spec., p.35. This is obsolete feature and is no longer supported.
+
+    \starttyping
+    static double seac[4] = { 0.0, 0.0, 0.0, 0.0 }; // gone
+    \stoptyping
+
+*/
+
+/*tex Operand stack and Transient array */
+
+static int cs2_stack_top = 0;
+static double cs2_arg_stack[CS_ARG_STACK_MAX];
+static double trn_array[CS_TRANS_ARRAY_MAX];
+
+/*tex
+
+    Type 2 CharString encoding, first the 1 byte operators:
+
+*/
+
+/*      RESERVED       0 */
+#define cs_hstem       1
+/*      RESERVED       2 */
+#define cs_vstem       3
+#define cs_vmoveto     4
+#define cs_rlineto     5
+#define cs_hlineto     6
+#define cs_vlineto     7
+#define cs_rrcurveto   8
+/*      cs_closepath   9  */
+#define cs_callsubr   10
+#define cs_return     11
+#define cs_escape     12
+/*      cs_hsbw       13 */
+#define cs_endchar    14
+#define cs_setvsindex 15
+#define cs_blend      16
+/*      RESERVED      17 */
+#define cs_hstemhm    18
+#define cs_hintmask   19
+#define cs_cntrmask   20
+#define cs_rmoveto    21
+#define cs_hmoveto    22
+#define cs_vstemhm    23
+#define cs_rcurveline 24
+#define cs_rlinecurve 25
+#define cs_vvcurveto  26
+#define cs_hhcurveto  27
+/*      SHORTINT      28 */
+#define cs_callgsubr  29
+#define cs_vhcurveto  30
+#define cs_hvcurveto  31
+
+/*tex
+
+    Next the two byte CharString operators:
+
+*/
+
+#define cs_dotsection       0
+/*      cs_vstem3           1 */
+/*      cs_hstem3           2 */
+#define cs_and              3
+#define cs_or               4
+#define cs_not              5
+/*      cs_seac             6 */
+/*      cs_sbw              7 */
+/*      RESERVED            8 */
+#define cs_abs              9
+#define cs_add             10
+#define cs_sub             11
+#define cs_div             12
+/*      RESERVED           13 */
+#define cs_neg             14
+#define cs_eq              15
+/*      cs_callothersubr   16 */
+/*      cs_pop|            17 */
+#define cs_drop            18
+/*      RESERVED           19 */
+#define cs_put             20
+#define cs_get             21
+#define cs_ifelse          22
+#define cs_random          23
+#define cs_mul             24
+/*      RESERVED           25 */
+#define cs_sqrt            26
+#define cs_dup             27
+#define cs_exch            28
+#define cs_index           29
+#define cs_roll            30
+/*      cs_setcurrentpoint 31 */
+/*      RESERVED           32 */
+/*      RESERVED           33 */
+#define cs_hflex           34
+#define cs_flex            35
+#define cs_hflex1          36
+#define cs_flex1           37
+
+/*tex  |clear_stack| put all operands sotred in operand stack to dest. */
+
+static void clear_stack(card8 ** dest, card8 * limit)
+{
+    int i;
+    for (i = 0; i < cs2_stack_top; i++) {
+        double value;
+        long ivalue;
+        value = cs2_arg_stack[i];
+        /*tex The nearest integer value. */
+        ivalue = (long) floor(value + 0.5);
+        if (value >= 0x8000L || value <= (-0x8000L - 1)) {
+            /*tex
+                This number cannot be represented as a single operand. We must
+                use |a b mul ...| or |a c div| to represent large values.
+            */
+            normal_error("cff","argument value too large (this is bug)");
+        } else if (fabs(value - (double) ivalue) > 3.0e-5) {
+            /*tex A 16.16-bit signed fixed value  */
+            DST_NEED(limit, *dest + 5);
+            *(*dest)++ = 255;
+            /*tex The mantissa. */
+            ivalue = (long) floor(value);
+            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+            *(*dest)++ = (card8) (ivalue & 0xff);
+            /*tex The fraction. */
+            ivalue = (long) ((value - (double) ivalue) * 0x10000l);
+            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+            *(*dest)++ = (card8) (ivalue & 0xff);
+            /*tex Everything else is integer. */
+        } else if (ivalue >= -107 && ivalue <= 107) {
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = (card8) (ivalue + 139);
+        } else if (ivalue >= 108 && ivalue <= 1131) {
+            DST_NEED(limit, *dest + 2);
+            ivalue = (long) 0xf700u + ivalue - 108;
+            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+            *(*dest)++ = (card8) (ivalue & 0xff);
+        } else if (ivalue >= -1131 && ivalue <= -108) {
+            DST_NEED(limit, *dest + 2);
+            ivalue = (long) 0xfb00u - ivalue - 108;
+            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+            *(*dest)++ = (card8) (ivalue & 0xff);
+        } else if (ivalue >= -32768 && ivalue <= 32767) {
+            /*tex A shortint. */
+            DST_NEED(limit, *dest + 3);
+            *(*dest)++ = 28;
+            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
+            *(*dest)++ = (card8) ((ivalue) & 0xff);
+        } else {
+            normal_error("cff","unexpected error");
+        }
+    }
+    /*tex Clear the stack. */
+    cs2_stack_top = 0;
+    return;
+}
+
+/*tex
+    Single byte operators: Path construction, Operator for finishing a path, Hint
+    operators. Phases:
+
+    \starttabulate
+    \NC \type{0} \NC inital state \NC \NR
+    \NC \type{1} \NC hint declaration, first stack-clearing operator appeared \NC \NR
+    \NC \type{2} \NC in path construction \NC \NR
+    \stoptabulate
+
+*/
+
+static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
+{
+    card8 op = **data;
+
+    *data += 1;
+
+    switch (op) {
+        case cs_hstemhm:
+        case cs_vstemhm:
+            /*tex  A charstring may have a hintmask if the above operator has been seen. */
+        case cs_hstem:
+        case cs_vstem:
+            if (phase == 0 && (cs2_stack_top % 2)) {
+                have_width = 1;
+                width = cs2_arg_stack[0];
+            }
+            num_stems += cs2_stack_top / 2;
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            phase = 1;
+            break;
+        case cs_hintmask:
+        case cs_cntrmask:
+            if (phase < 2) {
+                if (phase == 0 && (cs2_stack_top % 2)) {
+                    have_width = 1;
+                    width = cs2_arg_stack[0];
+                }
+                num_stems += cs2_stack_top / 2;
+            }
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            if (num_stems > 0) {
+                int masklen = (num_stems + 7) / 8;
+                DST_NEED(limit, *dest + masklen);
+                SRC_NEED(endptr, *data + masklen);
+                memmove(*dest, *data, (size_t) masklen);
+                *data += masklen;
+                *dest += masklen;
+            }
+            phase = 2;
+            break;
+        case cs_rmoveto:
+            if (phase == 0 && (cs2_stack_top % 2)) {
+                have_width = 1;
+                width = cs2_arg_stack[0];
+            }
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            phase = 2;
+            break;
+        case cs_hmoveto:
+        case cs_vmoveto:
+            if (phase == 0 && (cs2_stack_top % 2) == 0) {
+                have_width = 1;
+                width = cs2_arg_stack[0];
+            }
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            phase = 2;
+            break;
+        case cs_endchar:
+            if (cs2_stack_top == 1) {
+                have_width = 1;
+                width = cs2_arg_stack[0];
+                clear_stack(dest, limit);
+            } else if (cs2_stack_top == 4 || cs2_stack_top == 5) {
+                normal_warning("cff","'seac' character deprecated in type 2 charstring");
+                status = CS_PARSE_CFF_ERROR;
+                return;
+            } else if (cs2_stack_top > 0) {
+                normal_warning("cff","operand stack not empty");
+            }
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            status = CS_CHAR_END;
+            break;
+            /*tex The above operators are candidate for first stack clearing operator. */
+        case cs_setvsindex:
+            /*
+                vsindex = cs2_arg_stack[cs2_stack_top-1];
+                cs2_stack_top -= 1;
+            */
+            normal_warning("cff2","unsupported setvindex operator");
+            status = CS_PARSE_CFF_ERROR;
+            break;
+        case cs_blend:
+            /*
+                blends = cs2_arg_stack[cs2_stack_top-1];
+                cs2_stack_top -= 1;
+                cs2_stack_top -= blends * regions ;
+            */
+            normal_warning("cff2","unsupported blend operator");
+            status = CS_PARSE_CFF_ERROR;
+            break;
+        case cs_rlineto:
+        case cs_hlineto:
+        case cs_vlineto:
+        case cs_rrcurveto:
+        case cs_rcurveline:
+        case cs_rlinecurve:
+        case cs_vvcurveto:
+        case cs_hhcurveto:
+        case cs_vhcurveto:
+        case cs_hvcurveto:
+            if (phase < 2) {
+                normal_warning("cff","broken type 2 charstring");
+                status = CS_PARSE_CFF_ERROR;
+                return;
+            }
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 1);
+            *(*dest)++ = op;
+            break;
+            /*tex All the operotors above are stack clearing. */
+        case cs_return:
+            normal_error("cff","unexpected return");
+        case cs_callgsubr:
+            normal_error("cff","unexpected callgsubr");
+        case cs_callsubr:
+            normal_error("cff","unexpected callsubr");
+            break;
+        default:
+            formatted_warning("cff","%s: unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op);
+            status = CS_PARSE_CFF_ERROR;
+            break;
+    }
+    return;
+}
+
+/*tex
+
+    Double byte operators: Flex, arithmetic, conditional, and storage operators.
+    The following operators are not supported: random but How random ?
+
+*/
+
+static void do_operator2(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
+{
+    card8 op;
+    *data += 1;
+    SRC_NEED(endptr, *data + 1);
+    op = **data;
+    *data += 1;
+    switch (op) {
+        case cs_dotsection:
+            normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring");
+            status = CS_PARSE_CFF_ERROR;
+            return;
+            break;
+        case cs_hflex:
+        case cs_flex:
+        case cs_hflex1:
+        case cs_flex1:
+            if (phase < 2) {
+                formatted_warning("cff","%s: broken type 2 charstring", CS_TYPE2_DEBUG_STR);
+                status = CS_PARSE_CFF_ERROR;
+                return;
+            }
+            clear_stack(dest, limit);
+            DST_NEED(limit, *dest + 2);
+            *(*dest)++ = cs_escape;
+            *(*dest)++ = op;
+            break;
+            /*tex All operators above are stack clearing. */
+        case cs_and:
+            NEED(cs2_stack_top, 2);
+            cs2_stack_top--;
+            if (cs2_arg_stack[cs2_stack_top] && cs2_arg_stack[cs2_stack_top - 1]) {
+                cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+            } else {
+                cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+            }
+            break;
+        case cs_or:
+            NEED(cs2_stack_top, 2);
+            cs2_stack_top--;
+            if (cs2_arg_stack[cs2_stack_top] || cs2_arg_stack[cs2_stack_top - 1]) {
+                cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+            } else {
+                cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+            }
+            break;
+        case cs_not:
+            NEED(cs2_stack_top, 1);
+            if (cs2_arg_stack[cs2_stack_top - 1]) {
+                cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+            } else {
+                cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+            }
+            break;
+        case cs_abs:
+            NEED(cs2_stack_top, 1);
+            cs2_arg_stack[cs2_stack_top - 1] =
+                fabs(cs2_arg_stack[cs2_stack_top - 1]);
+            break;
+        case cs_add:
+            NEED(cs2_stack_top, 2);
+            cs2_arg_stack[cs2_stack_top - 2] += cs2_arg_stack[cs2_stack_top - 1];
+            cs2_stack_top--;
+            break;
+        case cs_sub:
+            NEED(cs2_stack_top, 2);
+            cs2_arg_stack[cs2_stack_top - 2] -= cs2_arg_stack[cs2_stack_top - 1];
+            cs2_stack_top--;
+            break;
+        case cs_div:
+            NEED(cs2_stack_top, 2);
+            cs2_arg_stack[cs2_stack_top - 2] /= cs2_arg_stack[cs2_stack_top - 1];
+            cs2_stack_top--;
+            break;
+        case cs_neg:
+            NEED(cs2_stack_top, 1);
+            cs2_arg_stack[cs2_stack_top - 1] *= -1.0;
+            break;
+        case cs_eq:
+            NEED(cs2_stack_top, 2);
+            cs2_stack_top--;
+            if (cs2_arg_stack[cs2_stack_top] == cs2_arg_stack[cs2_stack_top - 1]) {
+                cs2_arg_stack[cs2_stack_top - 1] = 1.0;
+            } else {
+                cs2_arg_stack[cs2_stack_top - 1] = 0.0;
+            }
+            break;
+        case cs_drop:
+            NEED(cs2_stack_top, 1);
+            cs2_stack_top--;
+            break;
+        case cs_put:
+            NEED(cs2_stack_top, 2);
+            {
+                int idx = (int) cs2_arg_stack[--cs2_stack_top];
+                NEED(CS_TRANS_ARRAY_MAX, idx);
+                trn_array[idx] = cs2_arg_stack[--cs2_stack_top];
+            }
+            break;
+        case cs_get:
+            NEED(cs2_stack_top, 1);
+            {
+                int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
+                NEED(CS_TRANS_ARRAY_MAX, idx);
+                cs2_arg_stack[cs2_stack_top - 1] = trn_array[idx];
+            }
+            break;
+        case cs_ifelse:
+            NEED(cs2_stack_top, 4);
+            cs2_stack_top -= 3;
+            if (cs2_arg_stack[cs2_stack_top + 1] > cs2_arg_stack[cs2_stack_top + 2]) {
+                cs2_arg_stack[cs2_stack_top - 1] = cs2_arg_stack[cs2_stack_top];
+            }
+            break;
+        case cs_mul:
+            NEED(cs2_stack_top, 2);
+            cs2_arg_stack[cs2_stack_top - 2] =
+                cs2_arg_stack[cs2_stack_top - 2] * cs2_arg_stack[cs2_stack_top - 1];
+            cs2_stack_top--;
+            break;
+        case cs_sqrt:
+            NEED(cs2_stack_top, 1);
+            cs2_arg_stack[cs2_stack_top - 1] =
+                sqrt(cs2_arg_stack[cs2_stack_top - 1]);
+            break;
+        case cs_dup:
+            NEED(cs2_stack_top, 1);
+            NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+            cs2_arg_stack[cs2_stack_top] = cs2_arg_stack[cs2_stack_top - 1];
+            cs2_stack_top++;
+            break;
+        case cs_exch:
+            NEED(cs2_stack_top, 2);
+            {
+                double save = cs2_arg_stack[cs2_stack_top - 2];
+                cs2_arg_stack[cs2_stack_top - 2] = cs2_arg_stack[cs2_stack_top - 1];
+                cs2_arg_stack[cs2_stack_top - 1] = save;
+            }
+            break;
+        case cs_index:
+            NEED(cs2_stack_top, 2);
+            {
+                int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
+                if (idx < 0) {
+                    cs2_arg_stack[cs2_stack_top - 1] =
+                        cs2_arg_stack[cs2_stack_top - 2];
+                } else {
+                    NEED(cs2_stack_top, idx + 2);
+                    cs2_arg_stack[cs2_stack_top - 1] =
+                        cs2_arg_stack[cs2_stack_top - idx - 2];
+                }
+            }
+            break;
+        case cs_roll:
+            NEED(cs2_stack_top, 2);
+            {
+                int N, J;
+                J = (int) cs2_arg_stack[--cs2_stack_top];
+                N = (int) cs2_arg_stack[--cs2_stack_top];
+                NEED(cs2_stack_top, N);
+                if (J > 0) {
+                    J = J % N;
+                    while (J-- > 0) {
+                        double save = cs2_arg_stack[cs2_stack_top - 1];
+                        int i = cs2_stack_top - 1;
+                        while (i > cs2_stack_top - N) {
+                            cs2_arg_stack[i] = cs2_arg_stack[i - 1];
+                            i--;
+                        }
+                        cs2_arg_stack[i] = save;
+                    }
+                } else {
+                    J = (-J) % N;
+                    while (J-- > 0) {
+                        double save = cs2_arg_stack[cs2_stack_top - N];
+                        int i = cs2_stack_top - N;
+                        while (i < cs2_stack_top - 1) {
+                            cs2_arg_stack[i] = cs2_arg_stack[i + 1];
+                            i++;
+                        }
+                        cs2_arg_stack[i] = save;
+                    }
+                }
+            }
+            break;
+        case cs_random:
+            formatted_warning("cff","%s: Charstring operator 'random' found.", CS_TYPE2_DEBUG_STR);
+            NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+            cs2_arg_stack[cs2_stack_top++] = 1.0;
+            break;
+        default:
+            formatted_warning("cff","%s: unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op);
+            status = CS_PARSE_CFF_ERROR;
+            break;
+    }
+    return;
+}
+
+/*tex integer: exactly the same as the DICT encoding (except 29) */
+
+static void cs2_get_integer(card8 ** data, card8 * endptr)
+{
+    long result = 0;
+    card8 b0 = **data, b1, b2;
+    *data += 1;
+    if (b0 == 28) {
+        /*tex shortint */
+        SRC_NEED(endptr, *data + 2);
+        b1 = **data;
+        b2 = *(*data + 1);
+        result = b1 * 256 + b2;
+        if (result > 0x7fff)
+            result -= 0x10000L;
+        *data += 2;
+    } else if (b0 >= 32 && b0 <= 246) {
+        /*tex int (1) */
+        result = b0 - 139;
+    } else if (b0 >= 247 && b0 <= 250) {
+        /*tex int (2) */
+        SRC_NEED(endptr, *data + 1);
+        b1 = **data;
+        result = (b0 - 247) * 256 + b1 + 108;
+        *data += 1;
+    } else if (b0 >= 251 && b0 <= 254) {
+        SRC_NEED(endptr, *data + 1);
+        b1 = **data;
+        result = -(b0 - 251) * 256 - b1 - 108;
+        *data += 1;
+    } else {
+        status = CS_PARSE_CFF_ERROR;
+        return;
+    }
+    NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+    cs2_arg_stack[cs2_stack_top++] = (double) result;
+    return;
+}
+
+/*tex Signed 16.16-bits fixed number for Type 2 charstring encoding. */
+
+static void get_fixed(card8 ** data, card8 * endptr)
+{
+    long ivalue;
+    double rvalue;
+    *data += 1;
+    SRC_NEED(endptr, *data + 4);
+    ivalue = *(*data) * 0x100 + *(*data + 1);
+    rvalue = (double) ((ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue);
+    ivalue = *(*data + 2) * 0x100 + *(*data + 3);
+    rvalue += ((double) ivalue) / 0x10000L;
+    NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
+    cs2_arg_stack[cs2_stack_top++] = rvalue;
+    *data += 4;
+    return;
+}
+
+/*tex
+
+Subroutines: the bias for subroutine number is introduced in type 2
+charstrings.
+
+\starttabulate
+\NC \type {subr}     \NC set to a pointer to the subroutine charstring \NC \NR
+\NC \type {len}      \NC set to the length of subroutine charstring \NC \NR
+\NC \type {subr_idx} \NC CFF INDEX data that contains subroutines \NC \NR
+\NC \type {id}       \NC biased subroutine number \NC \NR
+\stoptabulate
+
+*/
+
+static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id)
+{
+    card16 count;
+    if (subr_idx == NULL)
+        formatted_error("cff","%s: subroutine called but no subroutine found",CS_TYPE2_DEBUG_STR);
+    count = subr_idx->count;
+    /*tex addi the bias number */
+    if (count < 1240) {
+        id += 107;
+    } else if (count < 33900) {
+        id += 1131;
+    } else {
+        id += 32768;
+    }
+    if (id > count)
+        formatted_error("cff","%s: invalid subroutine index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count);
+    *len = (long) ((subr_idx->offset)[id + 1] - (subr_idx->offset)[id]);
+    *subr = subr_idx->data + (subr_idx->offset)[id] - 1;
+    return;
+}
+
+/*tex
+
+    The Type 2 interpretation of a number encoded in five-bytes (those with an
+    initial byte value of 255) differs from how it is interpreted in the Type 1
+    format.
+
+*/
+
+static void do_charstring(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr,
+    cff_index * gsubr_idx, cff_index * subr_idx, int cff2)
+{
+    card8 b0 = 0, *subr;
+    long len;
+    if (cs2_nest > CS_SUBR_NEST_MAX)
+        formatted_error("cff","%s: subroutine nested too deeply", CS_TYPE2_DEBUG_STR);
+    cs2_nest++;
+    while (*data < endptr && status == CS_PARSE_OK) {
+        b0 = **data;
+        if (b0 == 255) {
+            /*tex A 16-bit.16-bit fixed signed number. */
+            get_fixed(data, endptr);
+        } else if (b0 == cs_return) {
+            status = CS_SUBR_RETURN;
+        } else if (b0 == cs_callgsubr) {
+            if (cs2_stack_top < 1) {
+                status = CS_STACK_CFF_ERROR;
+            } else {
+                cs2_stack_top--;
+                get_subr(&subr, &len, gsubr_idx, (long) cs2_arg_stack[cs2_stack_top]);
+                if (*dest + len > limit)
+                    formatted_error("cff","%s: possible buffer overflow (1)", CS_TYPE2_DEBUG_STR);
+                do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
+                *data += 1;
+            }
+        } else if (b0 == cs_callsubr) {
+            if (cs2_stack_top < 1) {
+                status = CS_STACK_CFF_ERROR;
+            } else {
+                cs2_stack_top--;
+                get_subr(&subr, &len, subr_idx, (long) cs2_arg_stack[cs2_stack_top]);
+                if (limit < *dest + len)
+                    formatted_error("cff","%s: possible buffer overflow (2)", CS_TYPE2_DEBUG_STR);
+                do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
+                *data += 1;
+            }
+        } else if (b0 == cs_escape) {
+            do_operator2(dest, limit, data, endptr);
+        } else if (b0 < 32 && b0 != 28) {
+            do_operator1(dest, limit, data, endptr);
+        } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) {
+            status = CS_PARSE_CFF_ERROR;
+        } else {
+            cs2_get_integer(data, endptr);
+        }
+    }
+    if (cff2) {
+        DST_NEED(limit, *dest + 1);
+        ++endptr;
+        *(*dest)++ = cs_endchar;
+    } else if (status == CS_SUBR_RETURN) {
+        status = CS_PARSE_OK;
+    } else if (status == CS_CHAR_END && *data < endptr) {
+        formatted_warning("cff","%s: garbage after endchar", CS_TYPE2_DEBUG_STR);
+    } else if (status < CS_PARSE_OK) {
+        formatted_error("cff","%s: parsing charstring failed: (status=%d, stack=%d)", CS_TYPE2_DEBUG_STR, status, cs2_stack_top);
+    }
+    cs2_nest--;
+    return;
+}
+
+static void cs_parse_init(void)
+{
+    status = CS_PARSE_OK;
+    cs2_nest = 0;
+    phase = 0;
+    num_stems = 0;
+    cs2_stack_top = 0;
+}
+
+/*tex Not just copying \unknown */
+
+static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srclen, cff_index * gsubr,
+    cff_index * subr, double default_width, double nominal_width, cs_ginfo * ginfo, int cff2)
+{
+    card8 *save = dst;
+
+    cs_parse_init();
+
+    width = 0.0;
+    have_width = 0;
+
+    /* expand call(g)subrs */
+    do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr, cff2);
+
+    if (ginfo) {
+        ginfo->flags = 0;       /* not used */
+        if (have_width) {
+            ginfo->wx = nominal_width + width;
+        } else {
+            ginfo->wx = default_width;
+        }
+    }
+
+    return (long) (dst - save);
+}
+
+/*tex CID-Keyed font specific. */
+
+long cff_read_fdselect(cff_font * cff)
+{
+    cff_fdselect *fdsel;
+    long offset, length;
+    card16 i;
+    if (cff->topdict == NULL)
+        normal_error("cff","top DICT not available");
+    if (!(cff->flag & FONTTYPE_CIDFONT))
+        return 0;
+    offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0);
+    cff->offset = (l_offset) offset;
+    cff->fdselect = fdsel = xcalloc(1, sizeof(cff_fdselect));
+    fdsel->format = get_card8(cff);
+    length = 1;
+    switch (fdsel->format) {
+        case 0:
+            fdsel->num_entries = cff->num_glyphs;
+            (fdsel->data).fds = xmalloc(fdsel->num_entries * sizeof(card8));
+            for (i = 0; i < (fdsel->num_entries); i++) {
+                (fdsel->data).fds[i] = get_card8(cff);
+            }
+            length += fdsel->num_entries;
+            break;
+        case 3:
+            {
+                cff_range3 *ranges;
+                fdsel->num_entries = get_card16(cff);
+                fdsel->data.ranges = ranges =
+                    xcalloc(fdsel->num_entries, sizeof(cff_range3));
+                for (i = 0; i < (fdsel->num_entries); i++) {
+                    ranges[i].first = get_card16(cff);
+                    ranges[i].fd = get_card8(cff);
+                }
+                if (ranges[0].first != 0)
+                    normal_error("cff","range not starting with 0");
+                if (cff->num_glyphs != get_card16(cff))
+                    normal_error("cff","sentinel value mismatched with number of glyphs");
+                length += (fdsel->num_entries) * 3 + 4;
+            }
+            break;
+        default:
+            xfree(fdsel);
+            normal_error("cff","unknown FDSelect format");
+            break;
+    }
+    return length;
+}
+
+long cff_pack_fdselect(cff_font * cff, card8 * dest, long destlen)
+{
+    cff_fdselect *fdsel;
+    long len = 0;
+    card16 i;
+    if (cff->fdselect == NULL)
+        return 0;
+    if (destlen < 1)
+        normal_error("cff","buffer overflow (23)");
+    fdsel = cff->fdselect;
+    dest[len++] = fdsel->format;
+    switch (fdsel->format) {
+        case 0:
+            if (fdsel->num_entries != cff->num_glyphs)
+                normal_error("cff","invalid data");
+            if (destlen < len + fdsel->num_entries)
+                normal_error("cff","buffer overflow (24)");
+            for (i = 0; i < fdsel->num_entries; i++) {
+                dest[len++] = (fdsel->data).fds[i];
+            }
+            break;
+        case 3:
+            {
+                if (destlen < len + 2)
+                    normal_error("cff","buffer overflow (25)");
+                len += 2;
+                for (i = 0; i < (fdsel->num_entries); i++) {
+                    if (destlen < len + 3)
+                        normal_error("cff","buffer overflow (26)");
+                    dest[len++] =
+                        (card8) (((fdsel->data).ranges[i].first >> 8) & 0xff);
+                    dest[len++] = (card8) ((fdsel->data).ranges[i].first & 0xff);
+                    dest[len++] = (card8) ((fdsel->data).ranges[i].fd);
+                }
+                if (destlen < len + 2)
+                    normal_error("cff","buffer overflow (27)");
+                dest[len++] = (card8) ((cff->num_glyphs >> 8) & 0xff);
+                dest[len++] = (card8) (cff->num_glyphs & 0xff);
+                dest[1] = (card8) (((len / 3 - 1) >> 8) & 0xff);
+                dest[2] = (card8) ((len / 3 - 1) & 0xff);
+            }
+            break;
+        default:
+            normal_error("cff","unknown FDSelect format");
+            break;
+    }
+    return len;
+}
+
+/*tex Create an instance of embeddable font. */
+
+static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname)
+{
+    cff_index *topdict, *fdarray, *private;
+    unsigned char *dest;
+    long destlen = 0, i, size;
+    long offset, topdict_offset, fdarray_offset;
+    topdict = cff_new_index(1);
+    fdarray = cff_new_index(cffont->num_fds);
+    private = cff_new_index(cffont->num_fds);
+    cff_dict_remove(cffont->topdict, "UniqueID");
+    cff_dict_remove(cffont->topdict, "XUID");
+    /*tex A bad font may have this: */
+    cff_dict_remove(cffont->topdict, "Private");
+    /*tex A bad font may have this: */
+    cff_dict_remove(cffont->topdict, "Encoding");
+    /*tex This is CFF2 specific: */
+    cff_dict_remove(cffont->topdict, "vstore");
+    /*tex This is CFF2 specific: */
+    cff_dict_remove(cffont->topdict, "maxstack");
+    topdict->offset[1] = (l_offset) cff_dict_pack(cffont->topdict, (card8 *) work_buffer, WORK_BUFFER_SIZE) + 1;
+    for (i = 0; i < cffont->num_fds; i++) {
+        size = 0;
+        if (cffont->private && cffont->private[i]) {
+            size = cff_dict_pack(cffont->private[i], (card8 *) work_buffer, WORK_BUFFER_SIZE);
+            if (size < 1) {
+                /*tex |Private| contains only |Subr|: */
+                cff_dict_remove(cffont->fdarray[i], "Private");
+            }
+        }
+        (private->offset)[i + 1] = (unsigned long) ((private->offset)[i] + (unsigned) size);
+        (fdarray->offset)[i + 1] = (unsigned long) ((fdarray->offset)[i]
+            + (unsigned) cff_dict_pack(cffont->fdarray[i], (card8 *) work_buffer, WORK_BUFFER_SIZE));
+    }
+    /*tex The header size: */
+    destlen = 4;
+    destlen += cff_set_name(cffont, fullname);
+    destlen += cff_index_size(topdict);
+    destlen += cff_index_size(cffont->string);
+    destlen += cff_index_size(cffont->gsubr);
+    /*tex |charset| format 0 */
+    destlen += (cffont->charsets->num_entries) * 2 + 1;
+    /*tex |fdselect| format 3 */
+    destlen += (cffont->fdselect->num_entries) * 3 + 5;
+    destlen += cff_index_size(cffont->cstrings);
+    destlen += cff_index_size(fdarray);
+    /* |Private| is not indexed */
+    destlen = (long) (destlen + (long) private->offset[private->count] - 1);
+    dest = xcalloc((unsigned) destlen, sizeof(card8));
+    offset = 0;
+    /*tex |Header| */
+    offset += cff_put_header(cffont, dest + offset, destlen - offset);
+    /*tex |Name| */
+    offset += cff_pack_index(cffont->name, dest + offset, destlen - offset);
+    /*tex |Top DICT| */
+    topdict_offset = offset;
+    offset += cff_index_size(topdict);
+    /*tex |Strings| */
+    offset += cff_pack_index(cffont->string, dest + offset, destlen - offset);
+    /*tex |Global Subrs| */
+    offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset);
+    /*tex |charset| */
+    cff_dict_set(cffont->topdict, "charset", 0, (double) offset);
+    offset += cff_pack_charsets(cffont, dest + offset, destlen - offset);
+    /*tex |FDSelect| */
+    cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset);
+    offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset);
+    /*tex |CharStrings| */
+    cff_dict_set(cffont->topdict, "CharStrings", 0, (double) offset);
+    offset += cff_pack_index(cffont->cstrings, dest + offset, cff_index_size(cffont->cstrings));
+    cff_release_index(cffont->cstrings);
+    /*tex |Charstring|s can consume a lot of memory. */
+    cffont->cstrings = NULL;
+    /*tex |FDArray| and |Private| */
+    cff_dict_set(cffont->topdict, "FDArray", 0, (double) offset);
+    fdarray_offset = offset;
+    offset += cff_index_size(fdarray);
+    fdarray->data = xcalloc((unsigned) (fdarray->offset[fdarray->count] - 1), sizeof(card8));
+    for (i = 0; i < cffont->num_fds; i++) {
+        size = (long) (private->offset[i + 1] - private->offset[i]);
+        if (cffont->private[i] && size > 0) {
+            cff_dict_pack(cffont->private[i], dest + offset, size);
+            cff_dict_set(cffont->fdarray[i], "Private", 0, (double) size);
+            cff_dict_set(cffont->fdarray[i], "Private", 1, (double) offset);
+        }
+        cff_dict_pack(cffont->fdarray[i], fdarray->data + (fdarray->offset)[i] - 1, (long) (fdarray->offset[fdarray->count] - 1));
+        offset += size;
+    }
+    cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray));
+    cff_release_index(fdarray);
+    cff_release_index(private);
+    /*tex Finally the |Top DICT| */
+    topdict->data = xcalloc((unsigned) (topdict->offset[topdict->count] - 1), sizeof(card8));
+    cff_dict_pack(cffont->topdict, topdict->data, (long) (topdict->offset[topdict->count] - 1));
+    cff_pack_index(topdict, dest + topdict_offset, cff_index_size(topdict));
+    cff_release_index(topdict);
+    for (i = 0; i < offset; i++) {
+        strbuf_putchar(pdf->fb, dest[i]);
+    }
+    xfree(dest);
+    return;
+}
+
+void write_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
+{
+    cff_index *charstrings, *cs_idx;
+    long charstring_len, max_len;
+    long size, offset = 0;
+    card8 *data;
+    card16 num_glyphs, cs_count1, code, gid, last_cid;
+    double nominal_width, default_width;
+    char *fontname;
+    char *fullname;
+    glw_entry *glyph, *found;
+    struct avl_traverser t;
+    cffont->_string = NULL;
+    fontname = xcalloc((unsigned) (1 + strlen(fd->fontname)), 1);
+    sprintf(fontname, "%s", fd->fontname);
+    fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
+    sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
+    /*tex Finish parsing the CFF. */
+    cff_read_private(cffont);
+    cff_read_subrs(cffont);
+    /*tex The |Width|s. */
+    if (cffont->private[0] && cff_dict_known(cffont->private[0], "defaultWidthX")) {
+        default_width = (double) cff_dict_get(cffont->private[0], "defaultWidthX", 0);
+    } else {
+        default_width = CFF_DEFAULTWIDTHX_DEFAULT;
+    }
+    if (cffont->private[0] && cff_dict_known(cffont->private[0], "nominalWidthX")) {
+        nominal_width = (double) cff_dict_get(cffont->private[0], "nominalWidthX", 0);
+    } else {
+        nominal_width = CFF_NOMINALWIDTHX_DEFAULT;
+    }
+    num_glyphs = 0;
+    last_cid = 0;
+    glyph = xtalloc(1, glw_entry);
+    /*tex insert |notdef| */
+    glyph->id = 0;
+    if (avl_find(fd->gl_tree, glyph) == NULL) {
+        avl_insert(fd->gl_tree, glyph);
+        glyph = xtalloc(1, glw_entry);
+    }
+    avl_t_init(&t, fd->gl_tree);
+    for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
+         found != NULL; found = (glw_entry *) avl_t_next(&t)) {
+        if (found->id > last_cid)
+            last_cid = (card16) found->id;
+        num_glyphs++;
+    }
+    {
+        cff_fdselect *fdselect;
+        fdselect = xcalloc(1, sizeof(cff_fdselect));
+        fdselect->format = 3;
+        fdselect->num_entries = 1;
+        fdselect->data.ranges = xcalloc(1, sizeof(cff_range3));
+        fdselect->data.ranges[0].first = 0;
+        fdselect->data.ranges[0].fd = 0;
+        cffont->fdselect = fdselect;
+    }
+    {
+        cff_charsets *charset;
+        charset = xcalloc(1, sizeof(cff_charsets));
+        charset->format = 0;
+        charset->num_entries = (card16) (num_glyphs - 1);
+        charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
+        gid = 0;
+        avl_t_init(&t, fd->gl_tree);
+        for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
+             found != NULL; found = (glw_entry *) avl_t_next(&t)) {
+            if (found->id != 0) {
+                charset->data.glyphs[gid] = (s_SID) found->id;
+                gid++;
+            }
+        }
+        cffont->charsets = charset;
+        if (cffont->header_major == 2) {
+            cff_dict_add(cffont->topdict, "charset", 1);
+        }
+    }
+    cff_dict_add(cffont->topdict, "CIDCount", 1);
+    cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1);
+    if (cffont->header_major == 2) {
+        cff_dict_add(cffont->topdict, "FullName", 1);
+        cff_dict_set(cffont->topdict, "FullName", 0, (double) cff_add_string(cffont, fontname));
+        cff_dict_add(cffont->topdict, "FontBBox", 4);
+        cff_dict_set(cffont->topdict, "FontBBox", 0, fd->font_dim[FONTBBOX1_CODE].val);
+        cff_dict_set(cffont->topdict, "FontBBox", 1, fd->font_dim[FONTBBOX2_CODE].val);
+        cff_dict_set(cffont->topdict, "FontBBox", 2, fd->font_dim[FONTBBOX3_CODE].val);
+        cff_dict_set(cffont->topdict, "FontBBox", 3, fd->font_dim[FONTBBOX4_CODE].val);
+    }
+    cffont->fdarray = xcalloc(1, sizeof(cff_dict *));
+    cffont->fdarray[0] = cff_new_dict();
+    cff_dict_add(cffont->fdarray[0], "FontName", 1);
+    /*tex fix: skip XXXXXX+ */
+    cff_dict_set(cffont->fdarray[0], "FontName", 0, (double) cff_add_string(cffont, fullname));
+    cff_dict_add(cffont->fdarray[0], "Private", 2);
+    cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
+    cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
+    /*tex |FDArray| index offset, not known yet */
+    cff_dict_add(cffont->topdict, "FDArray", 1);
+    cff_dict_set(cffont->topdict, "FDArray", 0, 0.0);
+    /*tex |FDSelect| offset, not known yet */
+    cff_dict_add(cffont->topdict, "FDSelect", 1);
+    cff_dict_set(cffont->topdict, "FDSelect", 0, 0.0);
+    cff_dict_remove(cffont->topdict, "UniqueID");
+    cff_dict_remove(cffont->topdict, "XUID");
+    cff_dict_remove(cffont->topdict, "Private");
+    cff_dict_remove(cffont->topdict, "Encoding");
+    cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
+    cs_idx = cff_get_index_header(cffont);
+    offset = (long) cffont->offset;
+    cs_count1 = cs_idx->count;
+    if (cs_count1 < 2) {
+        normal_error("cff","no valid charstring data found");
+    }
+    /*tex Build the new charstrings entry. */
+    charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
+    max_len = 2 * CS_STR_LEN_MAX;
+    charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
+    charstring_len = 0;
+    gid = 0;
+    data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
+    {
+        int i;
+        int tex_font = fd->tex_font;
+        int streamprovider = 0;
+        int callback_id = 0 ;
+        if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
+            streamprovider = font_streamprovider(tex_font);
+            callback_id = callback_defined(glyph_stream_provider_callback);
+        }
+        for (i = 0; i < cs_count1; i++) {
+            code = (card16) i;
+            glyph->id = code;
+            if ((avl_find(fd->gl_tree,glyph) != NULL)) {
+                /*tex This code is the same as below, apart from small details */
+                if (callback_id > 0) {
+                    lstring * result;
+                    run_callback(callback_id, "ddd->L", tex_font, i, streamprovider, &result); /* this call can be sped up */
+                    size = (size_t) result->l ;
+                    if (size > 0) {
+                        if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+                            max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+                            charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+                        }
+                        (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+                        cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
+                        memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t) size);
+                        charstring_len += size;
+                        xfree(result);
+                    }
+                } else {
+                    size = (long)(cs_idx->offset[code+1] - cs_idx->offset[code]);
+                    if (size > CS_STR_LEN_MAX) {
+                        formatted_error("cff","charstring too long: gid=%u, %ld bytes", code, size);
+                    }
+                    if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+                        max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+                        charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+                    }
+                    (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+                    cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
+                    memcpy(data,&cffont->stream[cffont->offset],(size_t)size);
+                    charstring_len += cs_copy_charstring(
+                        charstrings->data + charstring_len,
+                        max_len - charstring_len,
+                        data, size,
+                        cffont->gsubr, (cffont->subrs)[0],
+                        default_width, nominal_width, NULL,
+                        cffont->header_major == 2
+                    );
+                }
+                gid++;
+            }
+        }
+    }
+    /*tex
+        The |CIDSet| is a table of bits indexed by cid, bytes with high order bit
+        first, each (set) bit is a (present) CID.
+    */
+    if (1) {
+        int cid;
+        cidset = pdf_create_obj(pdf, obj_type_others, 0);
+        if (cidset != 0) {
+            size_t l = (last_cid/8)+1;
+            char *stream = xmalloc(l);
+            memset(stream, 0, l);
+            for (cid = 1; cid <= (long) last_cid; cid++) {
+                glyph->id = cid;
+                if (avl_find(fd->gl_tree,glyph) != NULL) {
+                    stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
+                }
+            }
+            pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
+            pdf_begin_dict(pdf);
+            pdf_dict_add_streaminfo(pdf);
+            pdf_end_dict(pdf);
+            pdf_begin_stream(pdf);
+            pdf_out_block(pdf, stream, l);
+            pdf_end_stream(pdf);
+            pdf_end_obj(pdf);
+        }
+    }
+    /*tex
+        This happens if the internal metrics do not agree with the actual disk
+        font.
+    */
+    if (gid < num_glyphs) {
+        formatted_warning("cff","embedded subset is smaller than expected: %d instead of %d glyphs", gid, num_glyphs);
+        num_glyphs = gid;
+    }
+    xfree(data);
+    cff_release_index(cs_idx);
+    (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
+    charstrings->count = num_glyphs;
+    cffont->num_glyphs = num_glyphs;
+    cffont->cstrings = charstrings;
+    /*tex
+        We don't use subroutines at all.
+    */
+    if (cffont->gsubr)
+        cff_release_index(cffont->gsubr);
+    cffont->gsubr = cff_new_index(0);
+    if (cffont->subrs && cffont->subrs[0])
+        cff_release_index(cffont->subrs[0]);
+    cffont->subrs[0] = NULL;
+    if (cffont->private && (cffont->private)[0]) {
+        cff_dict_remove((cffont->private)[0], "Subrs"); /* no Subrs */
+    }
+    cff_dict_update(cffont->topdict, cffont);
+    cff_add_string(cffont, "Adobe");
+    cff_add_string(cffont, "Identity");
+    if (cffont->header_major == 2) {
+        /*tex A crash. */
+    } else {
+        cff_dict_update(cffont->private[0], cffont);
+    }
+    cff_update_string(cffont);
+    /* CFF code need to be rewritten */
+    cff_dict_add(cffont->topdict, "ROS", 3);
+    cff_dict_set(cffont->topdict, "ROS", 0, (double) cff_get_sid(cffont, "Adobe"));
+    cff_dict_set(cffont->topdict, "ROS", 1, (double) cff_get_sid(cffont, "Identity"));
+    cff_dict_set(cffont->topdict, "ROS", 2, 0.0);
+    write_fontfile(pdf, cffont, fullname);
+    xfree(fontname);
+    xfree(fullname);
+    cff_close(cffont);
+}
+
+#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT)
+#define CID_MAX 65535
+
+void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
+{
+    cff_index *charstrings, *cs_idx;
+    long charstring_len, max_len;
+    long size, offset = 0;
+    int tex_font = fd->tex_font;
+    int streamprovider = 0;
+    int callback_id = 0 ;
+    card8 *data;
+    card16 num_glyphs, cs_count1, gid, last_cid;
+    int fdsel, prev_fd, cid_count, cid ;
+    char *fullname;
+    glw_entry *glyph;
+    unsigned char *CIDToGIDMap = NULL;
+    cff_fdselect *fdselect = NULL;
+    cff_charsets *charset = NULL;
+    if (!is_cidfont(cffont)) {
+        normal_error("cff","invalid CIDfont");
+        return;
+    }
+    if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
+        streamprovider = font_streamprovider(tex_font);
+        callback_id = callback_defined(glyph_stream_provider_callback);
+    }
+    fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
+    sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
+    /*tex Finish parsing the CFF. */
+    if (cff_dict_known(cffont->topdict, "CIDCount")) {
+        cid_count = (card16) cff_dict_get(cffont->topdict, "CIDCount", 0);
+    } else {
+        cid_count = CFF_CIDCOUNT_DEFAULT;
+    }
+    if (cffont->header_major == 2) {
+        /*tex hm */
+    } else {
+        cff_read_charsets(cffont);
+    }
+    CIDToGIDMap = xmalloc((unsigned) ((2 * (unsigned) cid_count) * sizeof(unsigned char)));
+    memset(CIDToGIDMap, 0, (size_t) (2 * cid_count));
+    glyph = xtalloc(1, glw_entry);
+    /*tex insert |notdef| */
+    glyph->id = 0;
+    if (avl_find(fd->gl_tree, glyph) == NULL) {
+        avl_insert(fd->gl_tree, glyph);
+        glyph = xtalloc(1, glw_entry);
+    }
+    last_cid = 0;
+    num_glyphs = 0;
+    for (cid = 0; cid <= CID_MAX; cid++) {
+        glyph->id = (unsigned) cid;
+        if (avl_find(fd->gl_tree, glyph) != NULL) {
+            gid = (card16) cid;
+            CIDToGIDMap[2 * cid] = (unsigned char) ((gid >> 8) & 0xff);
+            CIDToGIDMap[2 * cid + 1] = (unsigned char) (gid & 0xff);
+            last_cid = (card16) cid;
+            num_glyphs++;
+        }
+    }
+    if (cffont->header_major == 2) {
+        /*tex hm */
+    } else if (last_cid >= cffont->num_glyphs) {
+        formatted_error("cff font","bad glyph index %i",last_cid);
+    }
+    /*tex
+        The |CIDSet| table is a table of bits indexed by cid, bytes with high
+        order bit first, each (set) bit is a (present) CID.
+    */
+    if (1) {
+        cidset = pdf_create_obj(pdf, obj_type_others, 0);
+        if (cidset != 0) {
+            size_t l = (last_cid / 8) + 1;
+            char *stream = xmalloc(l);
+            memset(stream, 0, l);
+            for (cid = 1; cid <= (long) last_cid; cid++) {
+                if (CIDToGIDMap[2 * cid] || CIDToGIDMap[2 * cid + 1]) {
+                    stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
+                }
+            }
+            pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
+            pdf_begin_dict(pdf);
+            pdf_dict_add_streaminfo(pdf);
+            pdf_end_dict(pdf);
+            pdf_begin_stream(pdf);
+            pdf_out_block(pdf, stream, l);
+            pdf_end_stream(pdf);
+            pdf_end_obj(pdf);
+            xfree(stream);
+        }
+    }
+    cff_read_fdselect(cffont);
+    cff_read_fdarray(cffont);
+    cff_read_private(cffont);
+    cff_read_subrs(cffont);
+    cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
+    cs_idx = cff_get_index_header(cffont);
+    offset = (long) cffont->offset;
+    cs_count1 = cs_idx->count;
+    if (cs_count1 < 2) {
+        normal_error("cff","no valid charstring data found");
+    }
+    charset = xcalloc(1, sizeof(cff_charsets));
+    charset->format = 0;
+    charset->num_entries = 0;
+    charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
+    fdselect = xcalloc(1, sizeof(cff_fdselect));
+    fdselect->format = 3;
+    fdselect->num_entries = 0;
+    fdselect->data.ranges = xcalloc(num_glyphs, sizeof(cff_range3));
+    charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
+    max_len = 2 * CS_STR_LEN_MAX;
+    charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
+    charstring_len = 0;
+    prev_fd = -1;
+    gid = 0;
+    data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
+    for (cid = 0; cid <= last_cid; cid++) {
+        unsigned short gid_org;
+        glyph->id = (unsigned) cid;
+        if (avl_find(fd->gl_tree, glyph) == NULL)
+            continue;
+        gid_org = (short unsigned) ((CIDToGIDMap[2 * cid] << 8) | (CIDToGIDMap[2 * cid + 1]));
+        fdsel = cff_fdselect_lookup(cffont, gid_org);
+        if (callback_id > 0) {
+            /*tex The next blob is not yet tested \unknown\ I need a font. */
+            lstring * result;
+            run_callback(callback_id, "ddd->L", tex_font, gid_org, streamprovider, &result);
+            size = (size_t) result->l ;
+            if (size > 0) {
+                if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+                    max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
+                    charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
+                }
+                (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
+                cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[gid_org] - 1);
+                memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t)size);
+                charstring_len += size;
+                xfree(result);
+            }
+        } else {
+            size = (long) (cs_idx->offset[gid_org + 1] - cs_idx->offset[gid_org]);
+            if (size > CS_STR_LEN_MAX) {
+                formatted_error("cff","charstring too long: gid=%u, %ld bytes", cid, size);
+            }
+            if (charstring_len + CS_STR_LEN_MAX >= max_len) {
+                max_len = charstring_len + 2 * CS_STR_LEN_MAX;
+                charstrings->data = xrealloc(charstrings->data, (unsigned) ((unsigned) max_len * sizeof(card8)));
+            }
+            (charstrings->offset)[gid] = (l_offset) (charstring_len + 1);
+            cffont->offset = (l_offset) ((unsigned) offset + (cs_idx->offset)[gid_org] - 1);
+            memcpy(data, &cffont->stream[cffont->offset], (size_t) size);
+            charstring_len += cs_copy_charstring(
+                charstrings->data + charstring_len,
+                max_len - charstring_len,
+                data, size,
+                cffont->gsubr, (cffont->subrs)[fdsel],
+                0, 0, NULL,
+                cffont->header_major == 2
+            );
+        }
+        if (cid > 0 && gid_org > 0) {
+            charset->data.glyphs[charset->num_entries] = (s_SID) cid;
+            charset->num_entries++;
+        }
+        if (fdsel != prev_fd) {
+            fdselect->data.ranges[fdselect->num_entries].first = gid;
+            fdselect->data.ranges[fdselect->num_entries].fd = (card8) fdsel;
+            fdselect->num_entries++;
+            prev_fd = fdsel;
+        }
+        gid++;
+    }
+    if (gid != num_glyphs)
+        formatted_error("cff","unexpected error: %i != %i", gid, num_glyphs);
+    xfree(data);
+    cff_release_index(cs_idx);
+    xfree(CIDToGIDMap);
+    (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
+    charstrings->count = num_glyphs;
+    cffont->num_glyphs = num_glyphs;
+    cffont->cstrings = charstrings;
+    cff_release_charsets(cffont->charsets);
+    cffont->charsets = charset;
+    cff_release_fdselect(cffont->fdselect);
+    cffont->fdselect = fdselect;
+    /*tex
+        We don't use subroutines at all.
+    */
+    if (cffont->gsubr)
+        cff_release_index(cffont->gsubr);
+    cffont->gsubr = cff_new_index(0);
+    for (fdsel = 0; fdsel < cffont->num_fds; fdsel++) {
+        if (cffont->subrs && cffont->subrs[fdsel]) {
+            cff_release_index(cffont->subrs[fdsel]);
+            cffont->subrs[fdsel] = NULL;
+        }
+        if (cffont->private && (cffont->private)[fdsel]) {
+            cff_dict_remove((cffont->private)[fdsel], "Subrs"); /* no Subrs */
+        }
+    }
+    write_fontfile(pdf, cffont, fullname);
+    xfree(fullname);
+    cff_close(cffont);
+}
+
+/*tex
+
+    Here is a sneaky trick: fontforge knows how to convert Type1 to CFF, so I
+    have defined a utility function in luafflib.c that does exactly that. If it
+    works out ok, I will clean up this code.
+
+*/
+
+void writetype1w(PDF pdf, fd_entry * fd)
+{
+    cff_font *cff;
+    int i;
+    FILE *fp;
+    ff_entry *ff;
+    unsigned char *tfm_buffer = NULL;
+    int tfm_size = 0;
+    ff = check_ff_exist(fd->fm->ff_name, 0);
+    fp = fopen(ff->ff_path, "rb");
+    cur_file_name = ff->ff_path;
+    if (!fp) {
+        formatted_error("cff","could not open Type1 font: %s", cur_file_name);
+    }
+    fclose(fp);
+    if (is_subsetted(fd->fm)) {
+        report_start_file(filetype_subset,cur_file_name);
+    } else {
+        report_start_file(filetype_font,cur_file_name);
+    }
+    (void) ff_createcff(ff->ff_path, &tfm_buffer, &tfm_size);
+    if (tfm_size > 0) {
+        cff = read_cff(tfm_buffer, tfm_size, 0);
+        if (cff != NULL) {
+            write_cff(pdf, cff, fd);
+        } else {
+            for (i = 0; i < tfm_size; i++)
+                strbuf_putchar(pdf->fb, tfm_buffer[i]);
+        }
+        fd->ff_found = 1;
+    } else {
+        formatted_error("cff","could not understand Type1 font: %s",cur_file_name);
+    }
+    if (is_subsetted(fd->fm)) {
+        report_stop_file(filetype_subset);
+    } else {
+        report_stop_file(filetype_font);
+    }
+    cur_file_name = NULL;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writecff.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writecff.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writecff.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,3381 +0,0 @@
-% writecff.w
-%
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-#include "font/writecff.h"
-
-extern int cidset;
-
-@ @c
-#define get_offset(s,n) get_unsigned(s, (n))
-#define get_card8(a)  (card8)(a->stream[a->offset++])
-#define get_card16(a) (card16)(get_unsigned(a,2))
-#define get_card32(a) (get_unsigned(a,4))
-
-#undef b0
-#undef b1
-#undef b2
-#undef b3
-
-#define WORK_BUFFER_SIZE 1024
-
-static char work_buffer[WORK_BUFFER_SIZE];
-
-static unsigned long get_unsigned(cff_font * cff, int n)
-{
-    unsigned long v = 0;
-    while (n-- > 0)
-        v = v * 256 + get_card8(cff);
-    return v;
-}
-
-@ @c
-
-const char *const cff_stdstr[CFF_STDSTR_MAX] = {
-    ".notdef", "space", "exclam", "quotedbl", "numbersign",
-    "dollar", "percent", "ampersand", "quoteright", "parenleft",
-    "parenright", "asterisk", "plus", "comma", "hyphen",
-    "period", "slash", "zero", "one", "two",
-    "three", "four", "five", "six", "seven",
-    "eight", "nine", "colon", "semicolon", "less",
-    "equal", "greater", "question", "at", "A",
-    "B", "C", "D", "E", "F",
-    "G", "H", "I", "J", "K",
-    "L", "M", "N", "O", "P",
-    "Q", "R", "S", "T", "U",
-    "V", "W", "X", "Y", "Z",
-    "bracketleft", "backslash", "bracketright", "asciicircum", "underscore",
-    "quoteleft", "a", "b", "c", "d",
-    "e", "f", "g", "h", "i",
-    "j", "k", "l", "m", "n",
-    "o", "p", "q", "r", "s",
-    "t", "u", "v", "w", "x",
-    "y", "z", "braceleft", "bar", "braceright",
-    "asciitilde", "exclamdown", "cent", "sterling", "fraction",
-    "yen", "florin", "section", "currency", "quotesingle",
-    "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi",
-    "fl", "endash", "dagger", "daggerdbl", "periodcentered",
-    "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
-    "guillemotright", "ellipsis", "perthousand", "questiondown", "grave",
-    "acute", "circumflex", "tilde", "macron", "breve",
-    "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut",
-    "ogonek", "caron", "emdash", "AE", "ordfeminine",
-    "Lslash", "Oslash", "OE", "ordmasculine", "ae",
-    "dotlessi", "lslash", "oslash", "oe", "germandbls",
-    "onesuperior", "logicalnot", "mu", "trademark", "Eth",
-    "onehalf", "plusminus", "Thorn", "onequarter", "divide",
-    "brokenbar", "degree", "thorn", "threequarters", "twosuperior",
-    "registered", "minus", "eth", "multiply", "threesuperior",
-    "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave",
-    "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
-    "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis",
-    "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis",
-    "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex",
-    "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron",
-    "aacute", "acircumflex", "adieresis", "agrave", "aring",
-    "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis",
-    "egrave", "iacute", "icircumflex", "idieresis", "igrave",
-    "ntilde", "oacute", "ocircumflex", "odieresis", "ograve",
-    "otilde", "scaron", "uacute", "ucircumflex", "udieresis",
-    "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall",
-    "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall",
-    "Acutesmall",
-    "parenleftsuperior", "parenrightsuperior", "twodotenleader",
-    "onedotenleader", "zerooldstyle",
-    "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
-    "fiveoldstyle",
-    "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle",
-    "commasuperior",
-    "threequartersemdash", "periodsuperior", "questionsmall", "asuperior",
-    "bsuperior",
-    "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior",
-    "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior",
-    "tsuperior", "ff", "ffi", "ffl", "parenleftinferior",
-    "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall",
-    "Asmall",
-    "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall",
-    "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall",
-    "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall",
-    "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall",
-    "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall",
-    "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall",
-    "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall",
-    "Dieresissmall",
-    "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash",
-    "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall",
-    "questiondownsmall",
-    "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird",
-    "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior",
-    "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior",
-    "oneinferior",
-    "twoinferior", "threeinferior", "fourinferior", "fiveinferior",
-    "sixinferior",
-    "seveninferior", "eightinferior", "nineinferior", "centinferior",
-    "dollarinferior",
-    "periodinferior", "commainferior", "Agravesmall", "Aacutesmall",
-    "Acircumflexsmall",
-    "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall",
-    "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall",
-    "Igravesmall",
-    "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
-    "Ntildesmall",
-    "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall",
-    "Odieresissmall",
-    "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall",
-    "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall",
-    "001.000", "001.001", "001.002", "001.003",
-    "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
-};
-
-@ Only read header part but not body
- at c
-cff_index *cff_get_index_header(cff_font * cff)
-{
-    cff_index *idx;
-    card16 i, count;
-    idx = xcalloc(1, sizeof(cff_index));
-    if (cff->header_major == 2) {
-        idx->count = count = get_card32(cff);
-    } else {
-        idx->count = count = get_card16(cff);
-    }
-    if (count > 0) {
-        idx->offsize = get_card8(cff);
-        if (idx->offsize < 1 || idx->offsize > 4)
-            normal_error("cff","invalid offsize data (1)");
-        idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
-        for (i = 0; i <count + 1 ; i++) {
-            (idx->offset)[i] = get_offset(cff, idx->offsize);
-            if (i == USHRT_MAX)
-                break;
-        }
-        if (idx->offset[0] != 1)
-            normal_error("cff","invalid index data");
-        idx->data = NULL;
-    } else {
-        idx->offsize = 0;
-        idx->offset = NULL;
-        idx->data = NULL;
-    }
-    return idx;
-}
-
-@ @c
-cff_index *cff_get_index(cff_font * cff)
-{
-    cff_index *idx;
-    card16 i, count;
-    size_t length;
-    idx = xcalloc(1, sizeof(cff_index));
-    idx->count = count = get_card16(cff);
-    if (count > 0) {
-        idx->offsize = get_card8(cff);
-        if (idx->offsize < 1 || idx->offsize > 4)
-            normal_error("cff","invalid offsize data (2)");
-        idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset)));
-        for (i = 0; i < count + 1; i++) {
-            idx->offset[i] = get_offset(cff, idx->offsize);
-        }
-        if (idx->offset[0] != 1)
-            normal_error("cff","invalid index offset data");
-        length = (size_t) (idx->offset[count] - idx->offset[0]);
-        idx->data = xmalloc((unsigned) length * sizeof(card8));
-        memcpy(idx->data, &cff->stream[cff->offset], length);
-        cff->offset += length;
-    } else {
-        idx->offsize = 0;
-        idx->offset = NULL;
-        idx->data = NULL;
-    }
-    return idx;
-}
-
-static cff_index *cff_empty_index(cff_font * cff)
-{
-    cff_index *idx;
-    idx = xcalloc(1, sizeof(cff_index));
-    idx->count = 0;
-    idx->offsize = 0;
-    idx->offset = NULL;
-    idx->data = NULL;
-    return idx;
-}
-
-static cff_index *cff_get_index2(cff_font * cff)
-{
-    /* we fake a dict array */
-
-    cff_index *idx;
-    size_t length;
-
-    idx = xcalloc(1, sizeof(cff_index));
-
-    length = (size_t) cff->header_offsize;
-
-    idx->offsize = 2;
-    idx->count = 1;
-    idx->offset = xmalloc((unsigned) (((unsigned) 2) * sizeof(l_offset)));
-    idx->offset[0] = 1; // get_offset(cff, idx->offsize);
-    idx->offset[1] = length + 1; // idx->offset[0] + length;
-
-    idx->data = xmalloc((unsigned) length * sizeof(card8));
-    memcpy(idx->data, &cff->stream[cff->offset], length );
-    cff->offset += length ;
-
-    return idx;
-}
-
-@ @c
-long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
-{
-    long len = 0;
-    unsigned long datalen;
-    card16 i;
-    if (idx->count < 1) {
-        if (destlen < 2)
-            normal_error("cff","not enough space available");
-        memset(dest, 0, 2);
-        return 2;
-    }
-    len = cff_index_size(idx);
-    datalen = idx->offset[idx->count] - 1;
-    if (destlen < len)
-        normal_error("cff","not enough space available");
-    *(dest++) = (card8) ((idx->count >> 8) & 0xff);
-    *(dest++) = (card8) (idx->count & 0xff);
-    if (datalen < 0xffUL) {
-        idx->offsize = 1;
-        *(dest++) = 1;
-        for (i = 0; i <= idx->count; i++) {
-            *(dest++) = (card8) (idx->offset[i] & 0xff);
-        }
-    } else if (datalen < 0xffffUL) {
-        idx->offsize = 2;
-        *(dest++) = 2;
-        for (i = 0; i <= idx->count; i++) {
-            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
-            *(dest++) = (card8) (idx->offset[i] & 0xff);
-        }
-    } else if (datalen < 0xffffffUL) {
-        idx->offsize = 3;
-        *(dest++) = 3;
-        for (i = 0; i <= idx->count; i++) {
-            *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
-            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
-            *(dest++) = (card8) (idx->offset[i] & 0xff);
-        }
-    } else {
-        idx->offsize = 4;
-        *(dest++) = 4;
-        for (i = 0; i <= idx->count; i++) {
-            *(dest++) = (card8) ((idx->offset[i] >> 24) & 0xff);
-            *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff);
-            *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff);
-            *(dest++) = (card8) (idx->offset[i] & 0xff);
-        }
-    }
-    memmove(dest, idx->data, idx->offset[idx->count] - 1);
-    return len;
-}
-
-@ @c
-long cff_index_size(cff_index * idx)
-{
-    if (idx->count > 0) {
-        l_offset datalen;
-        datalen = idx->offset[idx->count] - 1;
-        if (datalen < 0xffUL) {
-            idx->offsize = 1;
-        } else if (datalen < 0xffffUL) {
-            idx->offsize = 2;
-        } else if (datalen < 0xffffffUL) {
-            idx->offsize = 3;
-        } else {
-            idx->offsize = 4;
-        }
-        return (3 + (idx->offsize) * (idx->count + 1) + (long) datalen);
-    } else {
-        return 2;
-    }
-}
-
-@ @c
-cff_index *cff_new_index(card16 count)
-{
-    cff_index *idx;
-    idx = xcalloc(1, sizeof(cff_index));
-    idx->count = count;
-    idx->offsize = 0;
-    if (count > 0) {
-        idx->offset = xcalloc((unsigned) (count + 1), sizeof(l_offset));
-        (idx->offset)[0] = 1;
-    } else {
-        idx->offset = NULL;
-    }
-    idx->data = NULL;
-    return idx;
-}
-
-@ @c
-void cff_release_index(cff_index * idx)
-{
-    if (idx) {
-        xfree(idx->data);
-        xfree(idx->offset);
-        xfree(idx);
-    }
-}
-
-@ @c
-void cff_release_dict(cff_dict * dict)
-{
-    if (dict) {
-        if (dict->entries) {
-            int i;
-            for (i = 0; i < dict->count; i++) {
-                xfree((dict->entries)[i].values);
-            }
-            xfree(dict->entries);
-        }
-        xfree(dict);
-    }
-}
-
-@ @c
-void cff_release_encoding(cff_encoding * encoding)
-{
-    if (encoding) {
-        switch (encoding->format & (~0x80)) {
-        case 0:
-            xfree(encoding->data.codes);
-            break;
-        case 1:
-            xfree(encoding->data.range1);
-            break;
-        default:
-            normal_error("cff","unknown encoding format");
-        }
-        if (encoding->format & 0x80)
-            xfree(encoding->supp);
-        xfree(encoding);
-    }
-}
-
-@ @c
-void cff_release_charsets(cff_charsets * charset)
-{
-    if (charset) {
-        switch (charset->format) {
-        case 0:
-            xfree(charset->data.glyphs);
-            break;
-        case 1:
-            xfree(charset->data.range1);
-            break;
-        case 2:
-            xfree(charset->data.range2);
-            break;
-        default:
-            break;
-        }
-        xfree(charset);
-    }
-}
-
-@ @c
-void cff_release_fdselect(cff_fdselect * fdselect)
-{
-    if (fdselect) {
-        if (fdselect->format == 0) {
-            xfree(fdselect->data.fds);
-        } else if (fdselect->format == 3) {
-            xfree(fdselect->data.ranges);
-        }
-        xfree(fdselect);
-    }
-}
-
-@ @c
-void cff_close(cff_font * cff)
-{
-    card16 i;
-    if (cff) {
-        xfree(cff->fontname);
-        if (cff->name)
-            cff_release_index(cff->name);
-        if (cff->topdict)
-            cff_release_dict(cff->topdict);
-        if (cff->string)
-            cff_release_index(cff->string);
-        if (cff->gsubr)
-            cff_release_index(cff->gsubr);
-        if (cff->encoding)
-            cff_release_encoding(cff->encoding);
-        if (cff->charsets)
-            cff_release_charsets(cff->charsets);
-        if (cff->fdselect)
-            cff_release_fdselect(cff->fdselect);
-        if (cff->cstrings)
-            cff_release_index(cff->cstrings);
-        if (cff->fdarray) {
-            for (i = 0; i < cff->num_fds; i++) {
-                if (cff->fdarray[i])
-                    cff_release_dict(cff->fdarray[i]);
-            }
-            xfree(cff->fdarray);
-        }
-        if (cff->private) {
-            for (i = 0; i < cff->num_fds; i++) {
-                if (cff->private[i])
-                    cff_release_dict(cff->private[i]);
-            }
-            xfree(cff->private);
-        }
-        if (cff->subrs) {
-            for (i = 0; i < cff->num_fds; i++) {
-                if (cff->subrs[i])
-                    cff_release_index(cff->subrs[i]);
-            }
-            xfree(cff->subrs);
-        }
-        if (cff->_string)
-            cff_release_index(cff->_string);
-        xfree(cff);
-    }
-    return;
-}
-
-@ @c
-char *cff_get_name(cff_font * cff)
-{
-    char *fontname;
-    l_offset len;
-    cff_index *idx;
-    idx = cff->name;
-    len = idx->offset[cff->index + 1] - idx->offset[cff->index];
-    fontname = xmalloc((unsigned) (len + 1) * sizeof(char));
-    memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len);
-    fontname[len] = '\0';
-    return fontname;
-}
-
-@ @c
-long cff_set_name(cff_font * cff, char *name)
-{
-    cff_index *idx;
-    if (strlen(name) > 127)
-        normal_error("cff","FontName string length too large");
-    if (cff->name)
-        cff_release_index(cff->name);
-    cff->name = idx = xcalloc(1, sizeof(cff_index));
-    idx->count = 1;
-    idx->offsize = 1;
-    idx->offset = xmalloc(2 * sizeof(l_offset));
-    (idx->offset)[0] = 1;
-    (idx->offset)[1] = strlen(name) + 1;
-    idx->data = xmalloc((unsigned) strlen(name) * sizeof(card8));
-    memmove(idx->data, name, strlen(name)); /* no trailing |'\0'| */
-    return (long) (5 + strlen(name));
-}
-
-long cff_put_header(cff_font * cff, card8 * dest, long destlen)
-{
-    if (destlen < 4)
-        normal_error("cff","not enough space available");
-
-    *(dest++) = 1; /* cff->header_major; */
-    *(dest++) = cff->header_minor;
-    *(dest++) = 4;
-    /*
-        Additional data in between header and Name INDEX is ignored.
-
-        We will set all offset (0) to a four-byte integer.
-    */
-    *(dest++) = 4;
-    cff->header_offsize = 4;
-    return 4;
-}
-
-@ @c
-#define CFF_PARSE_OK                0
-#define CFF_CFF_ERROR_PARSE_CFF_ERROR      -1
-#define CFF_CFF_ERROR_STACK_OVERFLOW   -2
-#define CFF_CFF_ERROR_STACK_UNDERFLOW  -3
-#define CFF_CFF_ERROR_STACK_RANGECHECK -4
-
-#define DICT_ENTRY_MAX 16
-
-cff_dict *cff_new_dict(void)
-{
-    cff_dict *dict;
-    dict = xcalloc(1, sizeof(cff_dict));
-    dict->max = DICT_ENTRY_MAX;
-    dict->count = 0;
-    dict->entries = xcalloc((unsigned) dict->max, sizeof(cff_dict_entry));
-    return dict;
-}
-
-@ Operand stack: only numbers are stored (as double). Operand types are:
-
-\item number:  double (integer or real)
-\item boolean: stored as a number
-\item SID:     stored as a number
-\item array:   array of numbers
-\item delta:   array of numbers
-
- at c
-#define CFF_DICT_STACK_LIMIT 64
-static int stack_top = 0;
-static double arg_stack[CFF_DICT_STACK_LIMIT];
-
-@ CFF DICT encoding.
- at c
-#define CFF_LAST_DICT_OP1 26  /* 22 */
-#define CFF_LAST_DICT_OP2 39
-#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2)
-
-static struct {
-    const char *opname;
-    int argtype;
-} dict_operator[CFF_LAST_DICT_OP] = {
-    { "version", CFF_TYPE_SID },
-    { "Notice", CFF_TYPE_SID },
-    { "FullName", CFF_TYPE_SID },
-    { "FamilyName", CFF_TYPE_SID },
-    { "Weight", CFF_TYPE_SID },
-    { "FontBBox", CFF_TYPE_ARRAY },
-    { "BlueValues", CFF_TYPE_DELTA },
-    { "OtherBlues", CFF_TYPE_DELTA },
-    { "FamilyBlues", CFF_TYPE_DELTA },
-    { "FamilyOtherBlues", CFF_TYPE_DELTA },
-    { "StdHW", CFF_TYPE_NUMBER },
-    { "StdVW", CFF_TYPE_NUMBER },
-    { NULL, -1 },  /* first byte of two-byte operator 12 */
-    { "UniqueID", CFF_TYPE_NUMBER },
-    { "XUID", CFF_TYPE_ARRAY },
-    { "charset", CFF_TYPE_OFFSET },
-    { "Encoding", CFF_TYPE_OFFSET },
-    { "CharStrings", CFF_TYPE_OFFSET },
-    { "Private", CFF_TYPE_SZOFF },  /* two numbers (size and offset) */
-    { "Subrs", CFF_TYPE_OFFSET },
-    { "defaultWidthX", CFF_TYPE_NUMBER },
-    { "nominalWidthX", CFF_TYPE_NUMBER },
-    { NULL, -1 },
-    { NULL, -1 },
-    { "vstore", CFF_TYPE_OFFSET },   /* cff2 */
-    { "maxstack", CFF_TYPE_NUMBER }, /* cff2 */
-    /* Here we start with operator 2 of 12 */
-    { "Copyright", CFF_TYPE_SID },
-    { "IsFixedPitch", CFF_TYPE_BOOLEAN },
-    { "ItalicAngle", CFF_TYPE_NUMBER },
-    { "UnderlinePosition", CFF_TYPE_NUMBER },
-    { "UnderlineThickness", CFF_TYPE_NUMBER },
-    { "PaintType", CFF_TYPE_NUMBER },
-    { "CharstringType", CFF_TYPE_NUMBER },
-    { "FontMatrix", CFF_TYPE_ARRAY },
-    { "StrokeWidth", CFF_TYPE_NUMBER },
-    { "BlueScale", CFF_TYPE_NUMBER },
-    { "BlueShift", CFF_TYPE_NUMBER },
-    { "BlueFuzz", CFF_TYPE_NUMBER },
-    { "StemSnapH", CFF_TYPE_DELTA },
-    { "StemSnapV", CFF_TYPE_DELTA },
-    { "ForceBold", CFF_TYPE_BOOLEAN },
-    { NULL, -1 },
-    { NULL, -1 },
-    { "LanguageGroup", CFF_TYPE_NUMBER },
-    { "ExpansionFactor", CFF_TYPE_NUMBER },
-    { "InitialRandomSeed", CFF_TYPE_NUMBER },
-    { "SyntheticBase", CFF_TYPE_NUMBER },
-    { "PostScript", CFF_TYPE_SID },
-    { "BaseFontName", CFF_TYPE_SID },
-    { "BaseFontBlend", CFF_TYPE_DELTA },
-    { NULL, -1 },
-    { NULL, -1 },
-    { NULL, -1 },
-    { NULL, -1 },
-    { NULL, -1 },
-    { NULL, -1 },
-    { "ROS", CFF_TYPE_ROS },
-    { "CIDFontVersion", CFF_TYPE_NUMBER },
-    { "CIDFontRevision", CFF_TYPE_NUMBER },
-    { "CIDFontType", CFF_TYPE_NUMBER },
-    { "CIDCount", CFF_TYPE_NUMBER },
-    { "UIDBase", CFF_TYPE_NUMBER },
-    { "FDArray", CFF_TYPE_OFFSET },
-    { "FDSelect", CFF_TYPE_OFFSET },
-    { "FontName", CFF_TYPE_SID }
-};
-
-@ Parse DICT data
- at c
-static double get_integer(card8 ** data, card8 * endptr, int *status)
-{
-    long result = 0;
-    card8 b0, b1, b2;
-
-    b0 = *(*data)++;
-    if (b0 == 28 && *data < endptr - 2) {       /* shortint */
-        b1 = *(*data)++;
-        b2 = *(*data)++;
-        result = b1 * 256 + b2;
-        if (result > 0x7fffL)
-            result -= 0x10000L;
-    } else if (b0 == 29 && *data < endptr - 4) {        /* longint */
-        int i;
-        result = *(*data)++;
-        if (result > 0x7f)
-            result -= 0x100;
-        for (i = 0; i < 3; i++) {
-            result = result * 256 + (**data);
-            *data += 1;
-        }
-    } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
-        result = b0 - 139;
-    } else if (b0 >= 247 && b0 <= 250) {        /* int (2) */
-        b1 = *(*data)++;
-        result = (b0 - 247) * 256 + b1 + 108;
-    } else if (b0 >= 251 && b0 <= 254) {
-        b1 = *(*data)++;
-        result = -(b0 - 251) * 256 - b1 - 108;
-    } else {
-        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-    }
-
-    return (double) result;
-}
-
-@ Simply uses strtod
- at c
-static double get_real(card8 ** data, card8 * endptr, int *status)
-{
-    double result = 0.0;
-    int nibble = 0, pos = 0;
-    int len = 0, fail = 0;
-
-    if (**data != 30 || *data >= endptr - 1) {
-        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-        return 0.0;
-    }
-
-    *data += 1;                 /* skip first byte (30) */
-
-    pos = 0;
-    while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
-        /* get nibble */
-        if (pos % 2) {
-            nibble = **data & 0x0f;
-            *data += 1;
-        } else {
-            nibble = (**data >> 4) & 0x0f;
-        }
-        if (nibble >= 0x00 && nibble <= 0x09) {
-            work_buffer[len++] = (char) (nibble + '0');
-        } else if (nibble == 0x0a) {    /* . */
-            work_buffer[len++] = '.';
-        } else if (nibble == 0x0b || nibble == 0x0c) {  /* E, E- */
-            work_buffer[len++] = 'e';
-            if (nibble == 0x0c)
-                work_buffer[len++] = '-';
-        } else if (nibble == 0x0e) {    /* `-' */
-            work_buffer[len++] = '-';
-        } else if (nibble == 0x0d) {    /* skip */
-            /* do nothing */
-        } else if (nibble == 0x0f) {    /* end */
-            work_buffer[len++] = '\0';
-            if (((pos % 2) == 0) && (**data != 0xff)) {
-                fail = 1;
-            }
-            break;
-        } else {                /* invalid */
-            fail = 1;
-        }
-        pos++;
-    }
-
-    /* returned values */
-    if (fail || nibble != 0x0f) {
-        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-    } else {
-        char *s;
-	/* strtod sets errno for  OVERFLOW and _maybe_ UNDERFLOW */
-        /* but not for an invalid  conversion (as for example  if we try to convert "foo" in a double )*/
-        /* At least in glib sets errno also for UNDERFLOW */
-        /* We don't save/restore the prev. errno */
-        errno=0;
-        result = strtod(work_buffer, &s);
-        if ( (result==0.0 && work_buffer==s) || errno ) {
-              /* conversion is not possible */
-             *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-         }
-    }
-    return result;
-}
-
-@ operators
- at c
-static void add_dict(cff_dict * dict,
-                     card8 ** data, card8 * endptr, int *status)
-{
-    int id, argtype, t;
-
-    id = **data;
-    if (id == 0x0c) {
-        *data += 1;
-        if (*data >= endptr ||
-            (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) {
-            *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-            return;
-        }
-    } else if (id >= CFF_LAST_DICT_OP1) {
-        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-        return;
-    }
-
-    argtype = dict_operator[id].argtype;
-    if (dict_operator[id].opname == NULL || argtype < 0) {
-        *status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
-        return;
-    }
-
-    if (dict->count >= dict->max) {
-        dict->max += DICT_ENTRY_MAX;
-        /* not zeroed! */
-        dict->entries =
-            xrealloc(dict->entries,
-                     (unsigned) ((unsigned) dict->max *
-                                 sizeof(cff_dict_entry)));
-    }
-
-    (dict->entries)[dict->count].id = id;
-    (dict->entries)[dict->count].key = dict_operator[id].opname;
-    if (argtype == CFF_TYPE_NUMBER ||
-        argtype == CFF_TYPE_BOOLEAN ||
-        argtype == CFF_TYPE_SID || argtype == CFF_TYPE_OFFSET) {
-        /* check for underflow here, as exactly one operand is expected */
-        if (stack_top < 1) {
-            *status = CFF_CFF_ERROR_STACK_UNDERFLOW;
-            return;
-        }
-        stack_top--;
-        (dict->entries)[dict->count].count = 1;
-        (dict->entries)[dict->count].values = xcalloc(1, sizeof(double));
-        (dict->entries)[dict->count].values[0] = arg_stack[stack_top];
-        dict->count += 1;
-    } else {
-        /* just ignore operator if there were no operands provided;
-           don't treat this as underflow (e.g. StemSnapV in TemporaLGCUni-Italic.otf) */
-        if ((t = stack_top) > 0) {
-            (dict->entries)[dict->count].count = stack_top;
-            (dict->entries)[dict->count].values =
-                xmalloc((unsigned) ((unsigned) stack_top * sizeof(double)));
-            while (stack_top > 0) {
-                stack_top--;
-                (dict->entries)[dict->count].values[stack_top] =
-                    arg_stack[stack_top];
-            }
-            if (t > 3 && strcmp(dict_operator[id].opname, "FontMatrix") == 0) {
-                /* reset FontMatrix to [0.001 * * 0.001 * *],
-                   fix mantis bug \# 0000200 (acroread "feature") */
-                (dict->entries)[dict->count].values[0] = 0.001;
-                (dict->entries)[dict->count].values[3] = 0.001;
-            }
-            dict->count += 1;
-        }
-    }
-
-    *data += 1;
-
-    return;
-}
-
-
-@ All operands are treated as number or array of numbers.
-  Private: two numbers, size and offset
-  ROS    : three numbers, SID, SID, and a number
-
- at c
-cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
-{
-    cff_dict *dict;
-    int status = CFF_PARSE_OK;
-    stack_top = 0;
-    dict = cff_new_dict();
-    while (data < endptr && status == CFF_PARSE_OK) {
-        if (*data < CFF_LAST_DICT_OP1) {       /* operator */
-            add_dict(dict, &data, endptr, &status);
-        } else if (*data == 30) {       /* real - First byte of a sequence (variable) */
-            if (stack_top < CFF_DICT_STACK_LIMIT) {
-                arg_stack[stack_top] = get_real(&data, endptr, &status);
-                stack_top++;
-            } else {
-                status = CFF_CFF_ERROR_STACK_OVERFLOW;
-            }
-        } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) {      /* reserved */
-            data++;
-        } else {                /* everything else are integer */
-            if (stack_top < CFF_DICT_STACK_LIMIT) {
-                arg_stack[stack_top] = get_integer(&data, endptr, &status);
-                stack_top++;
-            } else {
-                status = CFF_CFF_ERROR_STACK_OVERFLOW;
-            }
-        }
-    }
-    if (status != CFF_PARSE_OK) {
-        formatted_error("cff","parsing DICT failed (error=%d)", status);
-    } else if (stack_top != 0) {
-        normal_warning("cff","garbage in DICT data");
-        stack_top = 0;
-    }
-    return dict;
-}
-
-@ @c
-int cff_dict_known(cff_dict * dict, const char *key)
-{
-    int i;
-    for (i = 0; i < dict->count; i++) {
-        if (key && strcmp(key, (dict->entries)[i].key) == 0
-            && (dict->entries)[i].count > 0)
-            return 1;
-    }
-    return 0;
-}
-
-@ @c
-double cff_dict_get(cff_dict * dict, const char *key, int idx)
-{
-    double value = 0.0;
-    int i;
-    assert(key && dict);
-    for (i = 0; i < dict->count; i++) {
-        if (strcmp(key, (dict->entries)[i].key) == 0) {
-           if ((dict->entries)[i].count > idx)
-                value = (dict->entries)[i].values[idx];
-            else
-                normal_error("cff","invalid index number");
-            break;
-        }
-    }
-    if (i == dict->count)
-        formatted_error("cff","DICT entry '%s' not found", key);
-    return value;
-}
-
-@ @c
-card8 cff_fdselect_lookup(cff_font * cff, card16 gid)
-{
-    card8 fd = 0xff;
-    cff_fdselect *fdsel;
-
-    if (cff->fdselect == NULL)
-        normal_error("cff","FDSelect not available");
-
-    fdsel = cff->fdselect;
-
-    if (gid >= cff->num_glyphs)
-        normal_error("cff","invalid glyph index");
-
-    switch (fdsel->format) {
-    case 0:
-        fd = fdsel->data.fds[gid];
-        break;
-    case 3:
-        {
-            if (gid == 0) {
-                fd = (fdsel->data).ranges[0].fd;
-            } else {
-                card16 i;
-                for (i = 1; i < (fdsel->num_entries); i++) {
-                    if (gid < (fdsel->data).ranges[i].first)
-                        break;
-                }
-                fd = (fdsel->data).ranges[i - 1].fd;
-            }
-        }
-        break;
-    default:
-        normal_error("cff","invalid FDSelect format");
-        break;
-    }
-
-    if (fd >= cff->num_fds)
-        normal_error("cff","invalid Font DICT index");
-
-    return fd;
-}
-
-@ @c
-long cff_read_subrs(cff_font * cff)
-{
-    long len = 0;
-    long offset;
-    int i;
-
-    if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdselect == NULL) {
-        cff_read_fdselect(cff);
-    }
-
-    if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) {
-        cff_read_fdarray(cff);
-    }
-
-    if (cff->private == NULL)
-        cff_read_private(cff);
-
-    if (cff->gsubr == NULL) {
-        cff->offset = cff->gsubr_offset;
-        cff->gsubr = cff_get_index(cff);
-    }
-
-    cff->subrs = xcalloc(cff->num_fds, sizeof(cff_index *));
-    if (cff->flag & FONTTYPE_CIDFONT) {
-        for (i = 0; i < cff->num_fds; i++) {
-            if (cff->private[i] == NULL ||
-                !cff_dict_known(cff->private[i], "Subrs")) {
-                (cff->subrs)[i] = NULL;
-            } else {
-                offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
-                offset += (long) cff_dict_get(cff->private[i], "Subrs", 0);
-                cff->offset = (l_offset) offset;
-                (cff->subrs)[i] = cff_get_index(cff);
-                len += cff_index_size((cff->subrs)[i]);
-            }
-        }
-    } else if (cff->private[0] == NULL || !cff_dict_known(cff->private[0], "Subrs")) {
-        (cff->subrs)[0] = NULL;
-    } else {
-        offset = (long) cff_dict_get(cff->topdict, "Private", 1);
-        offset += (long) cff_dict_get(cff->private[0], "Subrs", 0);
-        cff->offset = (l_offset) offset;
-        (cff->subrs)[0] = cff_get_index(cff);
-        len += cff_index_size((cff->subrs)[0]);
-    }
-
-    return len;
-}
-
-@ @c
-long cff_read_fdarray(cff_font * cff)
-{
-    long len = 0;
-    cff_index *idx;
-    long offset, size;
-    card16 i;
-
-    if (cff->topdict == NULL)
-        normal_error("cff","top DICT not found");
-
-    if (!(cff->flag & FONTTYPE_CIDFONT))
-        return 0;
-
-    /* must exist */
-    offset = (long) cff_dict_get(cff->topdict, "FDArray", 0);
-    cff->offset = (l_offset) offset;
-    idx = cff_get_index(cff);
-    cff->num_fds = (card8) idx->count;
-    cff->fdarray = xmalloc((unsigned) (idx->count * sizeof(cff_dict *)));
-    for (i = 0; i < idx->count; i++) {
-        card8 *data = idx->data + (idx->offset)[i] - 1;
-        size = (long) ((idx->offset)[i + 1] - (idx->offset)[i]);
-        if (size > 0) {
-            (cff->fdarray)[i] = cff_dict_unpack(data, data + size);
-        } else {
-            (cff->fdarray)[i] = NULL;
-        }
-    }
-    len = cff_index_size(idx);
-    cff_release_index(idx);
-
-    return len;
-}
-
-
-@ @c
-long cff_read_private(cff_font * cff)
-{
-    long len = 0;
-    card8 *data;
-    long offset, size;
-
-    if (cff->flag & FONTTYPE_CIDFONT) {
-        int i;
-
-        if (cff->fdarray == NULL)
-            cff_read_fdarray(cff);
-
-        cff->private = xmalloc((unsigned) (cff->num_fds * sizeof(cff_dict *)));
-        for (i = 0; i < cff->num_fds; i++) {
-            if (cff->fdarray[i] != NULL &&
-                    cff_dict_known(cff->fdarray[i], "Private") &&
-                    (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0)) > 0) {
-                offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1);
-                cff->offset = (l_offset) offset;
-                data = xmalloc((unsigned) size * sizeof(card8));
-                memcpy(data, &cff->stream[cff->offset], (size_t) size);
-                cff->offset = (l_offset) size;
-                (cff->private)[i] = cff_dict_unpack(data, data + size);
-                xfree(data);
-                len += size;
-            } else {
-                (cff->private)[i] = NULL;
-            }
-        }
-    } else {
-        cff->num_fds = 1;
-        cff->private = xmalloc(sizeof(cff_dict *));
-        if (cff_dict_known(cff->topdict, "Private") &&
-                (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) {
-            offset = (long) cff_dict_get(cff->topdict, "Private", 1);
-            cff->offset = (l_offset) offset;
-            data = xmalloc((unsigned) size * sizeof(card8));
-            memcpy(data, &cff->stream[cff->offset], (size_t) size);
-            cff->offset = (l_offset) size;
-            cff->private[0] = cff_dict_unpack(data, data + size);
-            xfree(data);
-            len += size;
-        } else {
-            (cff->private)[0] = NULL;
-            len = 0;
-        }
-    }
-
-    return len;
-}
-
-
-@ @c
-cff_font *read_cff(unsigned char *buf, long buflength, int n)
-{
-    cff_font *cff;
-    cff_index *idx;
-    long offset;
-
-    cff = xcalloc(1, sizeof(cff_font));
-
-    cff->stream = buf;
-    cff->stream_size = (l_offset) buflength;
-    cff->index = n;
-
-    cff->header_major = get_card8(cff);
-    cff->header_minor = get_card8(cff);
-    cff->header_hdr_size = get_card8(cff);
-    if (cff->header_major == 2) {
-        /* we have only one top dictionary */
-        cff->header_offsize = get_card16(cff);
-    } else {
-        cff->header_offsize = get_card8(cff);
-        if (cff->header_offsize < 1 || cff->header_offsize > 4) {
-            normal_warning("cff","invalid offsize data (4)");
-            cff_close(cff);
-            return NULL;
-        }
-    }
-    if (cff->header_major > 2) {
-        formatted_warning("cff","major version %u not supported", cff->header_major);
-        cff_close(cff);
-        return NULL;
-    }
-    cff->offset = cff->header_hdr_size;
-
-    /* Name INDEX */
-    if (cff->header_major == 2) {
-        cff->name = cff_empty_index(cff);
-    } else {
-        idx = cff_get_index(cff);
-        if (n > idx->count - 1) {
-            normal_warning("cff","invalid fontset index number");
-            cff_close(cff);
-            return NULL;
-        }
-        cff->name = idx;
-        cff->fontname = cff_get_name(cff);
-    }
-
-    /* Top DICT INDEX */
-    if (cff->header_major == 2) {
-        /* we fake an index (just one entry) */
-        idx = cff_get_index2(cff);
-    } else {
-        idx = cff_get_index(cff);
-    }
-
-    if (n > idx->count - 1) {
-        normal_warning("cff","top DICT not exist");
-        cff_close(cff);
-        return NULL;
-    }
-    cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1,
-                                   idx->data + idx->offset[n + 1] - 1);
-    if (!cff->topdict) {
-        normal_warning("cff","parsing top DICT data failed");
-        cff_close(cff);
-        return NULL;
-    }
-    cff_release_index(idx);
-
-    if (cff_dict_known(cff->topdict, "CharstringType") &&
-        cff_dict_get(cff->topdict, "CharstringType", 0) != 2) {
-        normal_warning("cff","only type 2 charstrings supported");
-        cff_close(cff);
-        return NULL;
-    }
-
-    if (cff_dict_known(cff->topdict, "SyntheticBase")) {
-        normal_warning("cff","synthetic font not supported");
-        cff_close(cff);
-        return NULL;
-    }
-
-    /* String INDEX */
-    if (cff->header_major == 2) {
-     //   cff->string = cff_empty_index(cff);
-    } else {
-        cff->string = cff_get_index(cff);
-    }
-
-    /* offset to GSubr */
-    cff->gsubr_offset = cff->offset;
-
-    /* Number of glyphs */
-    offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0);
-    cff->offset = (l_offset) offset;
-    cff->num_glyphs = get_card16(cff);
-
-    /* Check for font type */
-    if (cff_dict_known(cff->topdict, "ROS")) {
-        cff->flag |= FONTTYPE_CIDFONT;
-    } else {
-        cff->flag |= FONTTYPE_FONT;
-    }
-
-    /* Check for encoding */
-    if (cff_dict_known(cff->topdict, "Encoding")) {
-        offset = (long) cff_dict_get(cff->topdict, "Encoding", 0);
-        if (offset == 0) {      /* predefined */
-            cff->flag |= ENCODING_STANDARD;
-        } else if (offset == 1) {
-            cff->flag |= ENCODING_EXPERT;
-        }
-    } else {
-        cff->flag |= ENCODING_STANDARD;
-    }
-
-    cff->offset = cff->gsubr_offset;    /* seek back to GSubr */
-
-    return cff;
-}
-
-@* write a cff for opentype.
-
-@ Pack DICT data
- at c
-static long pack_integer(card8 * dest, long destlen, long value)
-{
-    long len = 0;
-
-    if (value >= -107 && value <= 107) {
-        if (destlen < 1)
-            normal_error("cff","buffer overflow (1)");
-        dest[0] = (card8) ((value + 139) & 0xff);
-        len = 1;
-    } else if (value >= 108 && value <= 1131) {
-        if (destlen < 2)
-            normal_error("cff","buffer overflow (2)");
-        value = (long) 0xf700u + value - 108;
-        dest[0] = (card8) ((value >> 8) & 0xff);
-        dest[1] = (card8) (value & 0xff);
-        len = 2;
-    } else if (value >= -1131 && value <= -108) {
-        if (destlen < 2)
-            normal_error("cff","buffer overflow (3)");
-        value = (long) 0xfb00u - value - 108;
-        dest[0] = (card8) ((value >> 8) & 0xff);
-        dest[1] = (card8) (value & 0xff);
-        len = 2;
-    } else if (value >= -32768 && value <= 32767) {     /* shortint */
-        if (destlen < 3)
-            normal_error("cff","buffer overflow (4)");
-        dest[0] = 28;
-        dest[1] = (card8) ((value >> 8) & 0xff);
-        dest[2] = (card8) (value & 0xff);
-        len = 3;
-    } else {                    /* longint */
-        if (destlen < 5)
-            normal_error("cff","buffer overflow (5)");
-        dest[0] = 29;
-        dest[1] = (card8) ((value >> 24) & 0xff);
-        dest[2] = (card8) ((value >> 16) & 0xff);
-        dest[3] = (card8) ((value >> 8) & 0xff);
-        dest[4] = (card8) (value & 0xff);
-        len = 5;
-    }
-    return len;
-}
-
-@ @c
-static long pack_real(card8 * dest, long destlen, double value)
-{
-    long e;
-    int i = 0, pos = 2;
-    int res;
-#define CFF_REAL_MAX_LEN 17
-
-    if (destlen < 2)
-        normal_error("cff","buffer overflow (6)");
-
-    dest[0] = 30;
-
-    if (value == 0.0) {
-        dest[1] = 0x0f;
-        return 2;
-    }
-
-    if (value < 0.0) {
-        dest[1] = 0xe0;
-        value *= -1.0;
-        pos++;
-    }
-
-    e = 0;
-    if (value >= 10.0) {
-        while (value >= 10.0) {
-            value /= 10.0;
-            e++;
-        }
-    } else if (value < 1.0) {
-        while (value < 1.0) {
-            value *= 10.0;
-            e--;
-        }
-    }
-
-    res=sprintf(work_buffer, "%1.14g", value);
-    if (res<0) normal_error("cff","invalid conversion");
-    if (res>CFF_REAL_MAX_LEN) res=CFF_REAL_MAX_LEN;
-
-    for (i = 0; i < res; i++) {
-        unsigned char ch = 0;
-
-        if (work_buffer[i] == '\0') {
-	  /* res should prevent this.  */
-	  /* normal_error("cff","cannot happen"); */
-            break;
-        } else if (work_buffer[i] == '.') {
-            ch = 0x0a;
-        } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
-            ch = (unsigned char) (work_buffer[i] - '0');
-        } else {
-            normal_error("cff","invalid character");
-        }
-
-        if (destlen < pos / 2 + 1)
-            normal_error("cff","buffer overflow (7)");
-
-        if (pos % 2) {
-            dest[pos / 2] = (card8) (dest[pos / 2] + ch);
-        } else {
-            dest[pos / 2] = (card8) (ch << 4);
-        }
-        pos++;
-    }
-
-    if (e > 0) {
-        if (pos % 2) {
-            dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b);
-        } else {
-            if (destlen < pos / 2 + 1)
-                normal_error("cff","buffer overflow (8)");
-            dest[pos / 2] = (card8) (0xb0);
-        }
-        pos++;
-    } else if (e < 0) {
-        if (pos % 2) {
-            dest[pos / 2] = (card8) (dest[pos / 2] + 0x0c);
-        } else {
-            if (destlen < pos / 2 + 1)
-                normal_error("cff","buffer overflow (9)");
-            dest[pos / 2] = (card8) (0xc0);
-        }
-        e *= -1;
-        pos++;
-    }
-
-    if (e != 0) {
-        sprintf(work_buffer, "%ld", e);
-        for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
-            unsigned char ch = 0;
-            if (work_buffer[i] == '\0') {
-                break;
-            } else if (work_buffer[i] == '.') {
-                ch = 0x0a;
-            } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') {
-                ch = (unsigned char) (work_buffer[i] - '0');
-            } else {
-                normal_error("cff","invalid character");
-            }
-
-            if (destlen < pos / 2 + 1)
-                normal_error("cff","buffer overflow (10)");
-
-            if (pos % 2) {
-                dest[pos / 2] = (card8) (dest[pos / 2] + ch);
-            } else {
-                dest[pos / 2] = (card8) (ch << 4);
-            }
-            pos++;
-        }
-    }
-
-    if (pos % 2) {
-        dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f);
-        pos++;
-    } else {
-        if (destlen < pos / 2 + 1)
-            normal_error("cff","buffer overflow (11)");
-        dest[pos / 2] = (card8) (0xff);
-        pos += 2;
-    }
-
-    return pos / 2;
-}
-
-@ @c
-static long cff_dict_put_number(double value,
-                                card8 * dest, long destlen, int type)
-{
-    long len = 0;
-    double nearint;
-
-    nearint = floor(value + 0.5);
-    /* set offset to longint */
-    if (type == CFF_TYPE_OFFSET) {
-        long lvalue;
-        lvalue = (long) value;
-        if (destlen < 5)
-            normal_error("cff","buffer overflow (12)");
-        dest[0] = 29;
-        dest[1] = (card8) ((lvalue >> 24) & 0xff);
-        dest[2] = (card8) ((lvalue >> 16) & 0xff);
-        dest[3] = (card8) ((lvalue >> 8) & 0xff);
-        dest[4] = (card8) (lvalue & 0xff);
-        len = 5;
-    } else if (value > CFF_INT_MAX || value < CFF_INT_MIN || (fabs(value - nearint) > 1.0e-5)) {        /* real */
-        len = pack_real(dest, destlen, value);
-    } else {                    /* integer */
-        len = pack_integer(dest, destlen, (long) nearint);
-    }
-
-    return len;
-}
-
-@ @c
-static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen)
-{
-    long len = 0;
-    int i, type, id;
-
-    if (de->count > 0) {
-        id = de->id;
-        if (dict_operator[id].argtype == CFF_TYPE_OFFSET ||
-            dict_operator[id].argtype == CFF_TYPE_SZOFF) {
-            type = CFF_TYPE_OFFSET;
-        } else {
-            type = CFF_TYPE_NUMBER;
-        }
-        for (i = 0; i < de->count; i++) {
-            len += cff_dict_put_number(de->values[i], dest + len, destlen - len, type);
-        }
-        if (id >= 0 && id < CFF_LAST_DICT_OP1) {
-            if (len + 1 > destlen)
-                normal_error("cff","buffer overflow (13)");
-            dest[len++] = (card8) id;
-        } else if (id >= 0 && id < CFF_LAST_DICT_OP) {
-            if (len + 2 > destlen)
-                normal_error("cff","buffer overflow (14)");
-            dest[len++] = 12;
-            dest[len++] = (card8) (id - CFF_LAST_DICT_OP1);
-        } else {
-            normal_error("cff","invalid DICT operator ID");
-        }
-    }
-
-    return len;
-}
-
-@ @c
-long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen)
-{
-    long len = 0;
-    int i;
-
-    for (i = 0; i < dict->count; i++) {
-        if (!strcmp(dict->entries[i].key, "ROS")) {
-            len += put_dict_entry(&dict->entries[i], dest, destlen);
-            break;
-        }
-    }
-    for (i = 0; i < dict->count; i++) {
-        if (strcmp(dict->entries[i].key, "ROS")) {
-            len += put_dict_entry(&dict->entries[i], dest + len, destlen - len);
-        }
-    }
-
-    return len;
-}
-
-@ @c
-void cff_dict_add(cff_dict * dict, const char *key, int count)
-{
-    int id, i;
-
-    for (id = 0; id < CFF_LAST_DICT_OP; id++) {
-        if (key && dict_operator[id].opname &&
-            strcmp(dict_operator[id].opname, key) == 0)
-            break;
-    }
-
-    if (id == CFF_LAST_DICT_OP)
-        normal_error("cff","unknown DICT operator");
-
-    for (i = 0; i < dict->count; i++) {
-        if ((dict->entries)[i].id == id) {
-            if ((dict->entries)[i].count != count)
-                normal_error("cff","inconsistent DICT argument number");
-            return;
-        }
-    }
-
-    if (dict->count + 1 >= dict->max) {
-        dict->max += 8;
-        dict->entries =
-            xrealloc(dict->entries,
-                     (unsigned) ((unsigned) dict->max *
-                                 sizeof(cff_dict_entry)));
-    }
-
-    (dict->entries)[dict->count].id = id;
-    (dict->entries)[dict->count].key = dict_operator[id].opname;
-    (dict->entries)[dict->count].count = count;
-    if (count > 0) {
-        (dict->entries)[dict->count].values =
-            xcalloc((unsigned) count, sizeof(double));
-    } else {
-        (dict->entries)[dict->count].values = NULL;
-    }
-    dict->count += 1;
-
-    return;
-}
-
-@ @c
-void cff_dict_remove(cff_dict * dict, const char *key)
-{
-    int i;
-    for (i = 0; i < dict->count; i++) {
-        if (key && strcmp(key, (dict->entries)[i].key) == 0) {
-            (dict->entries)[i].count = 0;
-            xfree((dict->entries)[i].values);
-        }
-    }
-}
-
-@ @c
-void cff_dict_set(cff_dict * dict, const char *key, int idx, double value)
-{
-    int i;
-
-    assert(dict && key);
-
-    for (i = 0; i < dict->count; i++) {
-        if (strcmp(key, (dict->entries)[i].key) == 0) {
-            if ((dict->entries)[i].count > idx)
-                (dict->entries)[i].values[idx] = value;
-            else
-                normal_error("cff","invalid index number");
-            break;
-        }
-    }
-
-    if (i == dict->count)
-        formatted_error("cff","DICT entry '%s' not found", key);
-}
-
-
-@ Strings
- at c
-char *cff_get_string(cff_font * cff, s_SID id)
-{
-    char *result = NULL;
-    size_t len;
-
-    if (id < CFF_STDSTR_MAX) {
-        len = strlen(cff_stdstr[id]);
-        result = xmalloc((unsigned) (len + 1) * sizeof(char));
-        memcpy(result, cff_stdstr[id], len);
-        result[len] = '\0';
-    } else if (cff && cff->string) {
-        cff_index *strings = cff->string;
-        id = (s_SID) (id - CFF_STDSTR_MAX);
-        if (id < strings->count) {
-            len = (strings->offset)[id + 1] - (strings->offset)[id];
-            result = xmalloc((unsigned) (len + 1) * sizeof(char));
-            memmove(result, strings->data + (strings->offset)[id] - 1, len);
-            result[len] = '\0';
-        }
-    }
-
-    return result;
-}
-
-@ @c
-long cff_get_sid(cff_font * cff, const char *str)
-{
-    card16 i;
-
-    if (!cff || !str)
-        return -1;
-
-    /* I search String INDEX first. */
-    if (cff && cff->string) {
-        cff_index *idx = cff->string;
-        for (i = 0; i < idx->count; i++) {
-            if (strlen(str) == (idx->offset)[i + 1] - (idx->offset)[i] &&
-                !memcmp(str, (idx->data) + (idx->offset)[i] - 1, strlen(str)))
-                return (i + CFF_STDSTR_MAX);
-        }
-    }
-
-    for (i = 0; i < CFF_STDSTR_MAX; i++) {
-        if (!strcmp(str, cff_stdstr[i]))
-            return i;
-    }
-
-    return -1;
-}
-
-@ @c
-void cff_update_string(cff_font * cff)
-{
-    if (cff == NULL)
-        normal_error("cff","CFF font not opened");
-    if (cff->string)
-        cff_release_index(cff->string);
-    cff->string = cff->_string;
-    cff->_string = NULL;
-}
-
-@ @c
-s_SID cff_add_string(cff_font * cff, const char *str)
-{
-    card16 idx;
-    cff_index *strings;
-    l_offset offset, size;
-    if (cff == NULL) {
-        normal_error("cff","CFF font not opened");
-    }
-    if (cff->_string == NULL) {
-        cff->_string = cff_new_index(0);
-    }
-    strings = cff->_string;
-    for (idx = 0; idx < strings->count; idx++) {
-        size = strings->offset[idx + 1] - strings->offset[idx];
-        offset = strings->offset[idx];
-        if (size == strlen(str) && !memcmp(strings->data + offset - 1, str, strlen(str))) {
-            return (s_SID) (idx + CFF_STDSTR_MAX);
-        }
-    }
-    for (idx = 0; idx < CFF_STDSTR_MAX; idx++) {
-        if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str)) {
-            return idx;
-        }
-    }
-    offset = (strings->count > 0) ? strings->offset[strings->count] : 1;
-    strings->offset = xrealloc(strings->offset, (unsigned) (((unsigned) strings->count + 2) * sizeof(l_offset)));
-    if (strings->count == 0)
-        strings->offset[0] = 1;
-    idx = strings->count;
-    strings->count = (card16) (strings->count + 1);
-    strings->offset[strings->count] = offset + strlen(str);
-    strings->data = xrealloc(strings->data, (unsigned) ((offset + strlen(str) - 1) * sizeof(card8)));
-    memcpy(strings->data + offset - 1, str, strlen(str));
-    return (s_SID) (idx + CFF_STDSTR_MAX);
-}
-
-@ @c
-void cff_dict_update(cff_dict * dict, cff_font * cff)
-{
-    int i;
-    for (i = 0; i < dict->count; i++) {
-        if ((dict->entries)[i].count > 0) {
-            char *str;
-            int id;
-            id = (dict->entries)[i].id;
-            if (dict_operator[id].argtype == CFF_TYPE_SID) {
-                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
-                if (str != NULL) {
-                    (dict->entries)[i].values[0] = cff_add_string(cff, str);
-                    xfree(str);
-                }
-            } else if (dict_operator[id].argtype == CFF_TYPE_ROS) {
-                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]);
-                if (str != NULL) {
-                    (dict->entries)[i].values[0] = cff_add_string(cff, str);
-                    xfree(str);
-                }
-                str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[1]);
-                if (str != NULL) {
-                    (dict->entries)[i].values[1] = cff_add_string(cff, str);
-                    xfree(str);
-                }
-            }
-        }
-    }
-}
-
-@ charsets
- at c
-long cff_read_charsets(cff_font * cff)
-{
-    cff_charsets *charset;
-    long offset, length;
-    card16 count, i;
-
-    if (cff->topdict == NULL)
-        normal_error("cff","top DICT not available");
-
-    if (!cff_dict_known(cff->topdict, "charset")) {
-        cff->flag |= CHARSETS_ISOADOBE;
-        cff->charsets = NULL;
-        return 0;
-    }
-
-    offset = (long) cff_dict_get(cff->topdict, "charset", 0);
-
-    if (offset == 0) {          /* predefined */
-        cff->flag |= CHARSETS_ISOADOBE;
-        cff->charsets = NULL;
-        return 0;
-    } else if (offset == 1) {
-        cff->flag |= CHARSETS_EXPERT;
-        cff->charsets = NULL;
-        return 0;
-    } else if (offset == 2) {
-        cff->flag |= CHARSETS_EXPSUB;
-        cff->charsets = NULL;
-        return 0;
-    }
-
-    cff->offset = (l_offset) offset;
-    cff->charsets = charset = xcalloc(1, sizeof(cff_charsets));
-    charset->format = get_card8(cff);
-    charset->num_entries = 0;
-
-    count = (card16) (cff->num_glyphs - 1);
-    length = 1;
-
-    /* Not sure. Not well documented. */
-    switch (charset->format) {
-    case 0:
-        charset->num_entries = (card16) (cff->num_glyphs - 1);  /* no .notdef */
-        charset->data.glyphs =
-            xmalloc((unsigned) (charset->num_entries * sizeof(s_SID)));
-        length += (charset->num_entries) * 2;
-        for (i = 0; i < (charset->num_entries); i++) {
-            charset->data.glyphs[i] = get_card16(cff);
-        }
-        count = 0;
-        break;
-    case 1:
-        {
-            cff_range1 *ranges = NULL;
-            while (count > 0 && charset->num_entries < cff->num_glyphs) {
-                ranges =
-                    xrealloc(ranges,
-                             (unsigned) (((unsigned) charset->num_entries +
-                                          1) * sizeof(cff_range1)));
-                ranges[charset->num_entries].first = get_card16(cff);
-                ranges[charset->num_entries].n_left = get_card8(cff);
-                count = (card16) (count - ranges[charset->num_entries].n_left + 1);     /* no-overrap */
-                charset->num_entries++;
-                charset->data.range1 = ranges;
-            }
-            length += (charset->num_entries) * 3;
-        }
-        break;
-    case 2:
-        {
-            cff_range2 *ranges = NULL;
-            while (count > 0 && charset->num_entries < cff->num_glyphs) {
-                ranges =
-                    xrealloc(ranges,
-                             (unsigned) (((unsigned) charset->num_entries +
-                                          1) * sizeof(cff_range2)));
-                ranges[charset->num_entries].first = get_card16(cff);
-                ranges[charset->num_entries].n_left = get_card16(cff);
-                count = (card16) (count - (ranges[charset->num_entries].n_left + 1));   /* non-overrapping */
-                charset->num_entries++;
-            }
-            charset->data.range2 = ranges;
-            length += (charset->num_entries) * 4;
-        }
-        break;
-    default:
-        xfree(charset);
-        normal_error("cff","unknown charset format");
-        break;
-    }
-
-    if (count > 0) {
-        normal_warning("cff","charset data possibly broken (too many glyphs)");
-    }
-
-    return length;
-}
-
-@ @c
-long cff_pack_charsets(cff_font * cff, card8 * dest, long destlen)
-{
-    long len = 0;
-    card16 i;
-    cff_charsets *charset;
-
-    if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL)
-        return 0;
-
-    if (destlen < 1)
-        normal_error("cff","buffer overflow (15)");
-
-    charset = cff->charsets;
-
-    dest[len++] = charset->format;
-    switch (charset->format) {
-    case 0:
-        if (destlen < len + (charset->num_entries) * 2)
-            normal_error("cff","buffer overflow (16)");
-        for (i = 0; i < (charset->num_entries); i++) {
-            s_SID sid = (charset->data).glyphs[i];      /* or CID */
-            dest[len++] = (card8) ((sid >> 8) & 0xff);
-            dest[len++] = (card8) (sid & 0xff);
-        }
-        break;
-    case 1:
-        {
-            if (destlen < len + (charset->num_entries) * 3)
-                normal_error("cff","buffer overflow (17)");
-            for (i = 0; i < (charset->num_entries); i++) {
-                dest[len++] = (card8) (((charset->data).range1[i].first >> 8) & 0xff);
-                dest[len++] = (card8) ((charset->data).range1[i].first & 0xff);
-                dest[len++] = (card8) ((charset->data).range1[i].n_left);
-            }
-        }
-        break;
-    case 2:
-        {
-            if (destlen < len + (charset->num_entries) * 4)
-                normal_error("cff","buffer overflow (18)");
-            for (i = 0; i < (charset->num_entries); i++) {
-                dest[len++] = (card8) (((charset->data).range2[i].first >> 8) & 0xff);
-                dest[len++] = (card8) ((charset->data).range2[i].first & 0xff);
-                dest[len++] = (card8) (((charset->data).range2[i].n_left >> 8) & 0xff);
-                dest[len++] = (card8) ((charset->data).range2[i].n_left & 0xff);
-            }
-        }
-        break;
-    default:
-        normal_error("cff","unknown charset format");
-        break;
-    }
-
-    return len;
-}
-
-
-
-@* Type 2 Charstring support.
-
-Decode and encode Type 2 charstring
-
-All local/global subroutine calls in a given charstring is replace by the
-content of subroutine charstrings. We do this because some PostScript RIP
-may have problems with sparse subroutine array. Workaround for this is to
-re-order subroutine array so that no gap appears in the subroutine array,
-or put dummy charstrings that contains only `return' in the gap. However,
-re-ordering of subroutine is rather difficult for Type 2 charstrings due
-to the bias which depends on the total number of subroutines. Replacing
-callgsubr/callsubr calls with the content of the corresponding subroutine
-charstring may be more efficient than putting dummy subroutines in the
-case of subsetted font. Adobe distiller seems doing same thing.
-
-And also note that subroutine numbers within subroutines can depend on the
-content of operand stack as follows:
-
-\.{  ... l m callsubr << subr \#(m+bias): n add callsubr >> ...}
-
-I've not implemented the `random' operator which generates a pseudo-random
-number in the range (0, 1] and push them into argument stack.
-How pseudo-random sequences are generated is not documented in the Type 2
-charstring spec..
-
- at c
-#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser"
-#define CS_TYPE2_DEBUG     5
-
-/* decoder/encoder status codes */
-#define CS_BUFFER_CFF_ERROR -3
-#define CS_STACK_CFF_ERROR  -2
-#define CS_PARSE_CFF_ERROR  -1
-#define CS_PARSE_OK      0
-#define CS_PARSE_END     1
-#define CS_SUBR_RETURN   2
-#define CS_CHAR_END      3
-
-static int status = CS_PARSE_CFF_ERROR;
-
-#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_CFF_ERROR ; return ; }}
-#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_CFF_ERROR  ; return ; }}
-#define NEED(a,b)     {if ((a) < (b)) { status = CS_STACK_CFF_ERROR  ; return ; }}
-
-/* hintmask and cntrmask need number of stem zones */
-static int num_stems = 0;
-static int phase = 0;
-
-/* subroutine nesting */
-static int cs2_nest = 0;
-
-/* advance width */
-static int have_width = 0;
-static double width = 0.0;
-
-@ Standard Encoding Accented Characters: Optional four arguments for
-endchar. See, CFF spec., p.35. This is obsolete feature and is no longer
-supported.
- at c
-#if 0
-/* adx ady bchar achar endchar */
-static double seac[4] = { 0.0, 0.0, 0.0, 0.0 };
-#endif
-
-@  Operand stack and Transient array
- at c
-static int cs2_stack_top = 0;
-static double cs2_arg_stack[CS_ARG_STACK_MAX];
-static double trn_array[CS_TRANS_ARRAY_MAX];
-
-@ Type 2 CharString encoding
- at c
-
-/*
- 1-byte CharString operators:
- |cs_escape| is first byte of two-byte operator
-*/
-
-/*      RESERVED      0 */
-#define cs_hstem      1
-/*      RESERVED      2 */
-#define cs_vstem      3
-#define cs_vmoveto    4
-#define cs_rlineto    5
-#define cs_hlineto    6
-#define cs_vlineto    7
-#define cs_rrcurveto  8
-/*      |cs_closepath|  9  : TYPE1 */
-#define cs_callsubr   10
-#define cs_return     11
-#define cs_escape     12
-/*      |cs_hsbw|       13 : TYPE1 */
-#define cs_endchar    14
-#define cs_setvsindex 15
-#define cs_blend      16
-/*      RESERVED      17 */
-#define cs_hstemhm    18
-#define cs_hintmask   19
-#define cs_cntrmask   20
-#define cs_rmoveto    21
-#define cs_hmoveto    22
-#define cs_vstemhm    23
-#define cs_rcurveline 24
-#define cs_rlinecurve 25
-#define cs_vvcurveto  26
-#define cs_hhcurveto  27
-/*      SHORTINT      28 : first byte of shortint*/
-#define cs_callgsubr  29
-#define cs_vhcurveto  30
-#define cs_hvcurveto  31
-
-/*
- 2-byte CharString operaotrs:
- "dotsection" is obsoleted in Type 2 charstring.
- */
-
-#define cs_dotsection 0
-/*      |cs_vstem3|     1 : TYPE1 */
-/*      |cs_hstem3|     2 : TYPE1 */
-#define cs_and        3
-#define cs_or         4
-#define cs_not        5
-/*      |cs_seac|       6 : TYPE1 */
-/*      |cs_sbw|        7 : TYPE1 */
-/*      RESERVED      8  */
-#define cs_abs        9
-#define cs_add        10
-#define cs_sub        11
-#define cs_div        12
-/*      RESERVED      13 */
-#define cs_neg        14
-#define cs_eq         15
-/*      |cs_callothersubr| 16 : TYPE1 */
-/*      |cs_pop|           17 : TYPE1 */
-#define cs_drop       18
-/*      RESERVED      19 */
-#define cs_put        20
-#define cs_get        21
-#define cs_ifelse     22
-#define cs_random     23
-#define cs_mul        24
-/*      RESERVED      25 */
-#define cs_sqrt       26
-#define cs_dup        27
-#define cs_exch       28
-#define cs_index      29
-#define cs_roll       30
-/*      |cs_setcurrentpoint| 31 : TYPE1 */
-/*      RESERVED      32 */
-/*      RESERVED      33 */
-#define cs_hflex      34
-#define cs_flex       35
-#define cs_hflex1     36
-#define cs_flex1      37
-
-@ |clear_stack()| put all operands sotred in operand stack to dest.
- at c
-static void clear_stack(card8 ** dest, card8 * limit)
-{
-    int i;
-
-    for (i = 0; i < cs2_stack_top; i++) {
-        double value;
-        long ivalue;
-        value = cs2_arg_stack[i];
-        /* Nearest integer value */
-        ivalue = (long) floor(value + 0.5);
-        if (value >= 0x8000L || value <= (-0x8000L - 1)) {
-            /*
-                This number cannot be represented as a single operand. We must
-                use `a b mul ...' or `a c div' to represent large values.
-            */
-            normal_error("cff","argument value too large (this is bug)");
-        } else if (fabs(value - (double) ivalue) > 3.0e-5) {
-            /* 16.16-bit signed fixed value  */
-            DST_NEED(limit, *dest + 5);
-            *(*dest)++ = 255;
-            ivalue = (long) floor(value); /* mantissa */
-            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
-            *(*dest)++ = (card8) (ivalue & 0xff);
-            ivalue = (long) ((value - (double) ivalue) * 0x10000l); /* fraction */
-            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
-            *(*dest)++ = (card8) (ivalue & 0xff);
-            /* Everything else are integers. */
-        } else if (ivalue >= -107 && ivalue <= 107) {
-            DST_NEED(limit, *dest + 1);
-            *(*dest)++ = (card8) (ivalue + 139);
-        } else if (ivalue >= 108 && ivalue <= 1131) {
-            DST_NEED(limit, *dest + 2);
-            ivalue = (long) 0xf700u + ivalue - 108;
-            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
-            *(*dest)++ = (card8) (ivalue & 0xff);
-        } else if (ivalue >= -1131 && ivalue <= -108) {
-            DST_NEED(limit, *dest + 2);
-            ivalue = (long) 0xfb00u - ivalue - 108;
-            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
-            *(*dest)++ = (card8) (ivalue & 0xff);
-        } else if (ivalue >= -32768 && ivalue <= 32767) {
-            /* shortint */
-            DST_NEED(limit, *dest + 3);
-            *(*dest)++ = 28;
-            *(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
-            *(*dest)++ = (card8) ((ivalue) & 0xff);
-        } else {                /* Shouldn't come here */
-            normal_error("cff","unexpected error");
-        }
-    }
-    cs2_stack_top = 0; /* clear stack */
-    return;
-}
-
-@ Single byte operators: Path construction, Operator for finishing a
-path, Hint operators. Phases:
-
-\item 0: inital state
-\item 1: hint declaration, first stack-clearing operator appeared
-\item 2: in path construction
-
- at c
-/*
-static int vsindex = 0;
-static int blends  = 0;
-static int regions = 5;
-*/
-
-static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
-{
-    card8 op = **data;
-
-    *data += 1;
-
-    switch (op) {
-    case cs_hstemhm:
-    case cs_vstemhm:
-        /* charstring may have hintmask if above operator have seen */
-    case cs_hstem:
-    case cs_vstem:
-        if (phase == 0 && (cs2_stack_top % 2)) {
-            have_width = 1;
-            width = cs2_arg_stack[0];
-        }
-        num_stems += cs2_stack_top / 2;
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        phase = 1;
-        break;
-    case cs_hintmask:
-    case cs_cntrmask:
-        if (phase < 2) {
-            if (phase == 0 && (cs2_stack_top % 2)) {
-                have_width = 1;
-                width = cs2_arg_stack[0];
-            }
-            num_stems += cs2_stack_top / 2;
-        }
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        if (num_stems > 0) {
-            int masklen = (num_stems + 7) / 8;
-            DST_NEED(limit, *dest + masklen);
-            SRC_NEED(endptr, *data + masklen);
-            memmove(*dest, *data, (size_t) masklen);
-            *data += masklen;
-            *dest += masklen;
-        }
-        phase = 2;
-        break;
-    case cs_rmoveto:
-        if (phase == 0 && (cs2_stack_top % 2)) {
-            have_width = 1;
-            width = cs2_arg_stack[0];
-        }
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        phase = 2;
-        break;
-    case cs_hmoveto:
-    case cs_vmoveto:
-        if (phase == 0 && (cs2_stack_top % 2) == 0) {
-            have_width = 1;
-            width = cs2_arg_stack[0];
-        }
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        phase = 2;
-        break;
-    case cs_endchar:
-        if (cs2_stack_top == 1) {
-            have_width = 1;
-            width = cs2_arg_stack[0];
-            clear_stack(dest, limit);
-        } else if (cs2_stack_top == 4 || cs2_stack_top == 5) {
-            normal_warning("cff","'seac' character deprecated in type 2 charstring");
-            status = CS_PARSE_CFF_ERROR;
-            return;
-        } else if (cs2_stack_top > 0) {
-            normal_warning("cff","operand stack not empty");
-        }
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        status = CS_CHAR_END;
-        break;
-        /* above operators are candidate for first stack-clearing operator */
-    case cs_setvsindex:
-        /*
-        vsindex = cs2_arg_stack[cs2_stack_top-1];
-        cs2_stack_top -= 1;
-        */
-        normal_warning("cff2","unsupported setvindex operator");
-        status = CS_PARSE_CFF_ERROR;
-        break;
-    case cs_blend:
-        /*
-        blends = cs2_arg_stack[cs2_stack_top-1];
-        cs2_stack_top -= 1;
-        cs2_stack_top -= blends * regions ;
-        */
-        normal_warning("cff2","unsupported blend operator");
-        status = CS_PARSE_CFF_ERROR;
-        break;
-    case cs_rlineto:
-    case cs_hlineto:
-    case cs_vlineto:
-    case cs_rrcurveto:
-    case cs_rcurveline:
-    case cs_rlinecurve:
-    case cs_vvcurveto:
-    case cs_hhcurveto:
-    case cs_vhcurveto:
-    case cs_hvcurveto:
-        if (phase < 2) {
-            normal_warning("cff","broken type 2 charstring");
-            status = CS_PARSE_CFF_ERROR;
-            return;
-        }
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 1);
-        *(*dest)++ = op;
-        break;
-        /* all operotors above are stack-clearing operator */
-        /* no output */
-    case cs_return:
-    case cs_callgsubr:
-    case cs_callsubr:
-        normal_error("cff","unexpected call(g)subr/return");
-        break;
-    default:
-        /* no-op ? */
-        formatted_warning("cff","%s: unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op);
-        status = CS_PARSE_CFF_ERROR;
-        break;
-    }
-    return;
-}
-
-@ Double byte operators: Flex, arithmetic, conditional, and storage operators.
-The following operators are not supported: random: How random ?
-
- at c
-static void do_operator2(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr)
-{
-    card8 op;
-
-    *data += 1;
-
-    SRC_NEED(endptr, *data + 1);
-
-    op = **data;
-    *data += 1;
-
-    switch (op) {
-    case cs_dotsection:        /* deprecated */
-        normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring");
-        status = CS_PARSE_CFF_ERROR;
-        return;
-        break;
-    case cs_hflex:
-    case cs_flex:
-    case cs_hflex1:
-    case cs_flex1:
-        if (phase < 2) {
-            formatted_warning("cff","%s: broken type 2 charstring", CS_TYPE2_DEBUG_STR);
-            status = CS_PARSE_CFF_ERROR;
-            return;
-        }
-        clear_stack(dest, limit);
-        DST_NEED(limit, *dest + 2);
-        *(*dest)++ = cs_escape;
-        *(*dest)++ = op;
-        break;
-        /* all operator above are stack-clearing */
-        /* no output */
-    case cs_and:
-        NEED(cs2_stack_top, 2);
-        cs2_stack_top--;
-        if (cs2_arg_stack[cs2_stack_top] && cs2_arg_stack[cs2_stack_top - 1]) {
-            cs2_arg_stack[cs2_stack_top - 1] = 1.0;
-        } else {
-            cs2_arg_stack[cs2_stack_top - 1] = 0.0;
-        }
-        break;
-    case cs_or:
-        NEED(cs2_stack_top, 2);
-        cs2_stack_top--;
-        if (cs2_arg_stack[cs2_stack_top] || cs2_arg_stack[cs2_stack_top - 1]) {
-            cs2_arg_stack[cs2_stack_top - 1] = 1.0;
-        } else {
-            cs2_arg_stack[cs2_stack_top - 1] = 0.0;
-        }
-        break;
-    case cs_not:
-        NEED(cs2_stack_top, 1);
-        if (cs2_arg_stack[cs2_stack_top - 1]) {
-            cs2_arg_stack[cs2_stack_top - 1] = 0.0;
-        } else {
-            cs2_arg_stack[cs2_stack_top - 1] = 1.0;
-        }
-        break;
-    case cs_abs:
-        NEED(cs2_stack_top, 1);
-        cs2_arg_stack[cs2_stack_top - 1] =
-            fabs(cs2_arg_stack[cs2_stack_top - 1]);
-        break;
-    case cs_add:
-        NEED(cs2_stack_top, 2);
-        cs2_arg_stack[cs2_stack_top - 2] += cs2_arg_stack[cs2_stack_top - 1];
-        cs2_stack_top--;
-        break;
-    case cs_sub:
-        NEED(cs2_stack_top, 2);
-        cs2_arg_stack[cs2_stack_top - 2] -= cs2_arg_stack[cs2_stack_top - 1];
-        cs2_stack_top--;
-        break;
-    case cs_div:               /* doesn't check overflow */
-        NEED(cs2_stack_top, 2);
-        cs2_arg_stack[cs2_stack_top - 2] /= cs2_arg_stack[cs2_stack_top - 1];
-        cs2_stack_top--;
-        break;
-    case cs_neg:
-        NEED(cs2_stack_top, 1);
-        cs2_arg_stack[cs2_stack_top - 1] *= -1.0;
-        break;
-    case cs_eq:
-        NEED(cs2_stack_top, 2);
-        cs2_stack_top--;
-        if (cs2_arg_stack[cs2_stack_top] == cs2_arg_stack[cs2_stack_top - 1]) {
-            cs2_arg_stack[cs2_stack_top - 1] = 1.0;
-        } else {
-            cs2_arg_stack[cs2_stack_top - 1] = 0.0;
-        }
-        break;
-    case cs_drop:
-        NEED(cs2_stack_top, 1);
-        cs2_stack_top--;
-        break;
-    case cs_put:
-        NEED(cs2_stack_top, 2);
-        {
-            int idx = (int) cs2_arg_stack[--cs2_stack_top];
-            NEED(CS_TRANS_ARRAY_MAX, idx);
-            trn_array[idx] = cs2_arg_stack[--cs2_stack_top];
-        }
-        break;
-    case cs_get:
-        NEED(cs2_stack_top, 1);
-        {
-            int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
-            NEED(CS_TRANS_ARRAY_MAX, idx);
-            cs2_arg_stack[cs2_stack_top - 1] = trn_array[idx];
-        }
-        break;
-    case cs_ifelse:
-        NEED(cs2_stack_top, 4);
-        cs2_stack_top -= 3;
-        if (cs2_arg_stack[cs2_stack_top + 1] > cs2_arg_stack[cs2_stack_top + 2]) {
-            cs2_arg_stack[cs2_stack_top - 1] = cs2_arg_stack[cs2_stack_top];
-        }
-        break;
-    case cs_mul:
-        NEED(cs2_stack_top, 2);
-        cs2_arg_stack[cs2_stack_top - 2] =
-            cs2_arg_stack[cs2_stack_top - 2] * cs2_arg_stack[cs2_stack_top - 1];
-        cs2_stack_top--;
-        break;
-    case cs_sqrt:
-        NEED(cs2_stack_top, 1);
-        cs2_arg_stack[cs2_stack_top - 1] =
-            sqrt(cs2_arg_stack[cs2_stack_top - 1]);
-        break;
-    case cs_dup:
-        NEED(cs2_stack_top, 1);
-        NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
-        cs2_arg_stack[cs2_stack_top] = cs2_arg_stack[cs2_stack_top - 1];
-        cs2_stack_top++;
-        break;
-    case cs_exch:
-        NEED(cs2_stack_top, 2);
-        {
-            double save = cs2_arg_stack[cs2_stack_top - 2];
-            cs2_arg_stack[cs2_stack_top - 2] = cs2_arg_stack[cs2_stack_top - 1];
-            cs2_arg_stack[cs2_stack_top - 1] = save;
-        }
-        break;
-    case cs_index:
-        NEED(cs2_stack_top, 2); /* need two arguments at least */
-        {
-            int idx = (int) cs2_arg_stack[cs2_stack_top - 1];
-            if (idx < 0) {
-                cs2_arg_stack[cs2_stack_top - 1] =
-                    cs2_arg_stack[cs2_stack_top - 2];
-            } else {
-                NEED(cs2_stack_top, idx + 2);
-                cs2_arg_stack[cs2_stack_top - 1] =
-                    cs2_arg_stack[cs2_stack_top - idx - 2];
-            }
-        }
-        break;
-    case cs_roll:
-        NEED(cs2_stack_top, 2);
-        {
-            int N, J;
-            J = (int) cs2_arg_stack[--cs2_stack_top];
-            N = (int) cs2_arg_stack[--cs2_stack_top];
-            NEED(cs2_stack_top, N);
-            if (J > 0) {
-                J = J % N;
-                while (J-- > 0) {
-                    double save = cs2_arg_stack[cs2_stack_top - 1];
-                    int i = cs2_stack_top - 1;
-                    while (i > cs2_stack_top - N) {
-                        cs2_arg_stack[i] = cs2_arg_stack[i - 1];
-                        i--;
-                    }
-                    cs2_arg_stack[i] = save;
-                }
-            } else {
-                J = (-J) % N;
-                while (J-- > 0) {
-                    double save = cs2_arg_stack[cs2_stack_top - N];
-                    int i = cs2_stack_top - N;
-                    while (i < cs2_stack_top - 1) {
-                        cs2_arg_stack[i] = cs2_arg_stack[i + 1];
-                        i++;
-                    }
-                    cs2_arg_stack[i] = save;
-                }
-            }
-        }
-        break;
-    case cs_random:
-        formatted_warning("cff","%s: Charstring operator 'random' found.", CS_TYPE2_DEBUG_STR);
-        NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
-        cs2_arg_stack[cs2_stack_top++] = 1.0;
-        break;
-    default:
-        /* no-op ? */
-        formatted_warning("cff","%s: unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op);
-        status = CS_PARSE_CFF_ERROR;
-        break;
-    }
-    return;
-}
-
-@ integer: exactly the same as the DICT encoding (except 29)
- at c
-static void cs2_get_integer(card8 ** data, card8 * endptr)
-{
-    long result = 0;
-    card8 b0 = **data, b1, b2;
-
-    *data += 1;
-
-    if (b0 == 28) {             /* shortint */
-        SRC_NEED(endptr, *data + 2);
-        b1 = **data;
-        b2 = *(*data + 1);
-        result = b1 * 256 + b2;
-        if (result > 0x7fff)
-            result -= 0x10000L;
-        *data += 2;
-    } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
-        result = b0 - 139;
-    } else if (b0 >= 247 && b0 <= 250) {        /* int (2) */
-        SRC_NEED(endptr, *data + 1);
-        b1 = **data;
-        result = (b0 - 247) * 256 + b1 + 108;
-        *data += 1;
-    } else if (b0 >= 251 && b0 <= 254) {
-        SRC_NEED(endptr, *data + 1);
-        b1 = **data;
-        result = -(b0 - 251) * 256 - b1 - 108;
-        *data += 1;
-    } else {
-        status = CS_PARSE_CFF_ERROR;
-        return;
-    }
-    NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
-    cs2_arg_stack[cs2_stack_top++] = (double) result;
-    return;
-}
-
-@ Signed 16.16-bits fixed number for Type 2 charstring encoding
- at c
-static void get_fixed(card8 ** data, card8 * endptr)
-{
-    long ivalue;
-    double rvalue;
-
-    *data += 1;
-
-    SRC_NEED(endptr, *data + 4);
-
-    ivalue = *(*data) * 0x100 + *(*data + 1);
-    rvalue = (double) ((ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue);
-    ivalue = *(*data + 2) * 0x100 + *(*data + 3);
-    rvalue += ((double) ivalue) / 0x10000L;
-
-    NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1);
-    cs2_arg_stack[cs2_stack_top++] = rvalue;
-    *data += 4;
-
-    return;
-}
-
-@ Subroutines: the bias for subroutine number is introduced in type 2
-charstrings.
-
-\item subr:       set to a pointer to the subroutine charstring.
-\item len:        set to the length of subroutine charstring.
-\item |subr_idx|: CFF INDEX data that contains subroutines.
-\item id:         biased subroutine number.
-
- at c
-static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id)
-{
-    card16 count;
-
-    if (subr_idx == NULL)
-        formatted_error("cff","%s: subroutine called but no subroutine found",CS_TYPE2_DEBUG_STR);
-
-    count = subr_idx->count;
-
-    /* Adding bias number */
-    if (count < 1240) {
-        id += 107;
-    } else if (count < 33900) {
-        id += 1131;
-    } else {
-        id += 32768;
-    }
-
-    if (id > count)
-        formatted_error("cff","%s: invalid subroutine index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count);
-
-    *len = (long) ((subr_idx->offset)[id + 1] - (subr_idx->offset)[id]);
-    *subr = subr_idx->data + (subr_idx->offset)[id] - 1;
-
-    return;
-}
-
-@ The Type 2 interpretation of a number encoded in five-bytes (those with
-an initial byte value of 255) differs from how it is interpreted in the
-Type 1 format.
-
- at c
-static void do_charstring(card8 ** dest, card8 * limit,
-      card8 ** data, card8 * endptr,
-      cff_index * gsubr_idx, cff_index * subr_idx, int cff2)
-{
-    card8 b0 = 0, *subr;
-    long len;
-
-    if (cs2_nest > CS_SUBR_NEST_MAX)
-        formatted_error("cff","%s: subroutine nested too deeply", CS_TYPE2_DEBUG_STR);
-
-    cs2_nest++;
-
-    while (*data < endptr && status == CS_PARSE_OK) {
-        b0 = **data;
-        if (b0 == 255) {        /* 16-bit.16-bit fixed signed number */
-            get_fixed(data, endptr);
-        } else if (b0 == cs_return) {
-            status = CS_SUBR_RETURN;
-        } else if (b0 == cs_callgsubr) {
-            if (cs2_stack_top < 1) {
-                status = CS_STACK_CFF_ERROR;
-            } else {
-                cs2_stack_top--;
-                get_subr(&subr, &len, gsubr_idx,
-                         (long) cs2_arg_stack[cs2_stack_top]);
-                if (*dest + len > limit)
-                    formatted_error("cff","%s: possible buffer overflow (1)", CS_TYPE2_DEBUG_STR);
-                do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
-                *data += 1;
-            }
-        } else if (b0 == cs_callsubr) {
-            if (cs2_stack_top < 1) {
-                status = CS_STACK_CFF_ERROR;
-            } else {
-                cs2_stack_top--;
-                get_subr(&subr, &len, subr_idx,
-                         (long) cs2_arg_stack[cs2_stack_top]);
-                if (limit < *dest + len)
-                    formatted_error("cff","%s: possible buffer overflow (2)", CS_TYPE2_DEBUG_STR);
-                do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2);
-                *data += 1;
-            }
-        } else if (b0 == cs_escape) {
-            do_operator2(dest, limit, data, endptr);
-        } else if (b0 < 32 && b0 != 28) {       /* 19, 20 need mask */
-            do_operator1(dest, limit, data, endptr);
-        } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) {        /* reserved */
-            status = CS_PARSE_CFF_ERROR;        /* not an error ? */
-        } else {                /* integer */
-            cs2_get_integer(data, endptr);
-        }
-    }
-
-    if (cff2) {
-        DST_NEED(limit, *dest + 1);
-        ++endptr;
-        *(*dest)++ = cs_endchar;
-        /* no return and endchar */
-    } else if (status == CS_SUBR_RETURN) {
-        status = CS_PARSE_OK;
-    } else if (status == CS_CHAR_END && *data < endptr) {
-        formatted_warning("cff","%s: garbage after endchar", CS_TYPE2_DEBUG_STR);
-    } else if (status < CS_PARSE_OK) {  /* error */
-        formatted_error("cff","%s: parsing charstring failed: (status=%d, stack=%d)", CS_TYPE2_DEBUG_STR, status, cs2_stack_top);
-    }
-
-    cs2_nest--;
-
-    return;
-}
-
-@ @c
-static void cs_parse_init(void)
-{
-    status = CS_PARSE_OK;
-    cs2_nest = 0;
-    phase = 0;
-    num_stems = 0;
-    cs2_stack_top = 0;
-}
-
-@ Not just copying...
- at c
-static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srclen,
-       cff_index * gsubr, cff_index * subr, double default_width,
-       double nominal_width, cs_ginfo * ginfo, int cff2)
-{
-    card8 *save = dst;
-
-    cs_parse_init();
-
-    width = 0.0;
-    have_width = 0;
-
-    /* expand call(g)subrs */
-    do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr, cff2);
-
-    if (ginfo) {
-        ginfo->flags = 0;       /* not used */
-        if (have_width) {
-            ginfo->wx = nominal_width + width;
-        } else {
-            ginfo->wx = default_width;
-        }
-    }
-
-    return (long) (dst - save);
-}
-
-@ CID-Keyed font specific
- at c
-long cff_read_fdselect(cff_font * cff)
-{
-    cff_fdselect *fdsel;
-    long offset, length;
-    card16 i;
-
-    if (cff->topdict == NULL)
-        normal_error("cff","top DICT not available");
-
-    if (!(cff->flag & FONTTYPE_CIDFONT))
-        return 0;
-
-    offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0);
-    cff->offset = (l_offset) offset;
-    cff->fdselect = fdsel = xcalloc(1, sizeof(cff_fdselect));
-    fdsel->format = get_card8(cff);
-
-    length = 1;
-
-    switch (fdsel->format) {
-    case 0:
-        fdsel->num_entries = cff->num_glyphs;
-        (fdsel->data).fds = xmalloc(fdsel->num_entries * sizeof(card8));
-        for (i = 0; i < (fdsel->num_entries); i++) {
-            (fdsel->data).fds[i] = get_card8(cff);
-        }
-        length += fdsel->num_entries;
-        break;
-    case 3:
-        {
-            cff_range3 *ranges;
-            fdsel->num_entries = get_card16(cff);
-            fdsel->data.ranges = ranges =
-                xcalloc(fdsel->num_entries, sizeof(cff_range3));
-            for (i = 0; i < (fdsel->num_entries); i++) {
-                ranges[i].first = get_card16(cff);
-                ranges[i].fd = get_card8(cff);
-            }
-            if (ranges[0].first != 0)
-                normal_error("cff","range not starting with 0");
-            if (cff->num_glyphs != get_card16(cff))
-                normal_error("cff","sentinel value mismatched with number of glyphs");
-            length += (fdsel->num_entries) * 3 + 4;
-        }
-        break;
-    default:
-        xfree(fdsel);
-        normal_error("cff","unknown FDSelect format");
-        break;
-    }
-
-    return length;
-}
-
-@ @c
-long cff_pack_fdselect(cff_font * cff, card8 * dest, long destlen)
-{
-    cff_fdselect *fdsel;
-    long len = 0;
-    card16 i;
-
-    if (cff->fdselect == NULL)
-        return 0;
-
-    if (destlen < 1)
-        normal_error("cff","buffer overflow (23)");
-
-    fdsel = cff->fdselect;
-
-    dest[len++] = fdsel->format;
-    switch (fdsel->format) {
-    case 0:
-        if (fdsel->num_entries != cff->num_glyphs)
-            normal_error("cff","invalid data");
-        if (destlen < len + fdsel->num_entries)
-            normal_error("cff","buffer overflow (24)");
-        for (i = 0; i < fdsel->num_entries; i++) {
-            dest[len++] = (fdsel->data).fds[i];
-        }
-        break;
-    case 3:
-        {
-            if (destlen < len + 2)
-                normal_error("cff","buffer overflow (25)");
-            len += 2;
-            for (i = 0; i < (fdsel->num_entries); i++) {
-                if (destlen < len + 3)
-                    normal_error("cff","buffer overflow (26)");
-                dest[len++] =
-                    (card8) (((fdsel->data).ranges[i].first >> 8) & 0xff);
-                dest[len++] = (card8) ((fdsel->data).ranges[i].first & 0xff);
-                dest[len++] = (card8) ((fdsel->data).ranges[i].fd);
-            }
-            if (destlen < len + 2)
-                normal_error("cff","buffer overflow (27)");
-            dest[len++] = (card8) ((cff->num_glyphs >> 8) & 0xff);
-            dest[len++] = (card8) (cff->num_glyphs & 0xff);
-            dest[1] = (card8) (((len / 3 - 1) >> 8) & 0xff);
-            dest[2] = (card8) ((len / 3 - 1) & 0xff);
-        }
-        break;
-    default:
-        normal_error("cff","unknown FDSelect format");
-        break;
-    }
-
-    return len;
-}
-
-@ Create an instance of embeddable font.
-
- at c
-static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname)
-{
-    cff_index *topdict, *fdarray, *private;
-    unsigned char *dest;
-    long destlen = 0, i, size;
-    long offset, topdict_offset, fdarray_offset;
-
-    /*  DICT sizes (offset set to long int) */
-    topdict = cff_new_index(1);
-    fdarray = cff_new_index(cffont->num_fds);
-    private = cff_new_index(cffont->num_fds);
-
-    cff_dict_remove(cffont->topdict, "UniqueID");
-    cff_dict_remove(cffont->topdict, "XUID");
-    cff_dict_remove(cffont->topdict, "Private");        /* some bad font may have */
-    cff_dict_remove(cffont->topdict, "Encoding");       /* some bad font may have */
-    cff_dict_remove(cffont->topdict, "vstore");         /* cff2 */
-    cff_dict_remove(cffont->topdict, "maxstack");       /* cff2 */
-
-    topdict->offset[1] = (l_offset) cff_dict_pack(cffont->topdict, (card8 *) work_buffer, WORK_BUFFER_SIZE) + 1;
-    for (i = 0; i < cffont->num_fds; i++) {
-        size = 0;
-        if (cffont->private && cffont->private[i]) {
-            size = cff_dict_pack(cffont->private[i], (card8 *) work_buffer, WORK_BUFFER_SIZE);
-            if (size < 1) {
-                /* Private had contained only Subr. */
-                cff_dict_remove(cffont->fdarray[i], "Private");
-            }
-        }
-        (private->offset)[i + 1] = (unsigned long) ((private->offset)[i]
-            + (unsigned) size);
-        (fdarray->offset)[i + 1] = (unsigned long) ((fdarray->offset)[i]
-            + (unsigned) cff_dict_pack(cffont->fdarray[i], (card8 *) work_buffer, WORK_BUFFER_SIZE));
-    }
-
-    destlen = 4;                /* header size */
-    destlen += cff_set_name(cffont, fullname);
-    destlen += cff_index_size(topdict);
-    destlen += cff_index_size(cffont->string);
-    destlen += cff_index_size(cffont->gsubr);
-    destlen += (cffont->charsets->num_entries) * 2 + 1; /* charset format 0 */
-    destlen += (cffont->fdselect->num_entries) * 3 + 5; /* fdselect format 3 */
-    destlen += cff_index_size(cffont->cstrings);
-    destlen += cff_index_size(fdarray);
-    destlen = (long) (destlen + (long) private->offset[private->count] - 1);    /* Private is not INDEX */
-    dest = xcalloc((unsigned) destlen, sizeof(card8));
-
-    offset = 0;
-    /* Header */
-    offset += cff_put_header(cffont, dest + offset, destlen - offset);
-    /* Name */
-    offset += cff_pack_index(cffont->name, dest + offset, destlen - offset);
-    /* Top DICT */
-    topdict_offset = offset;
-    offset += cff_index_size(topdict);
-    /* Strings */
-    offset += cff_pack_index(cffont->string, dest + offset, destlen - offset);
-    /* Global Subrs */
-    offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset);
-    /* charset */
-    cff_dict_set(cffont->topdict, "charset", 0, (double) offset);
-    offset += cff_pack_charsets(cffont, dest + offset, destlen - offset);
-    /* FDSelect */
-    cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset);
-    offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset);
-    /* CharStrings */
-    cff_dict_set(cffont->topdict, "CharStrings", 0, (double) offset);
-    offset += cff_pack_index(cffont->cstrings, dest + offset, cff_index_size(cffont->cstrings));
-    cff_release_index(cffont->cstrings);
-    cffont->cstrings = NULL;    /* Charstrings cosumes huge memory */
-    /* FDArray and Private */
-    cff_dict_set(cffont->topdict, "FDArray", 0, (double) offset);
-    fdarray_offset = offset;
-    offset += cff_index_size(fdarray);
-
-    fdarray->data = xcalloc((unsigned) (fdarray->offset[fdarray->count] - 1), sizeof(card8));
-    for (i = 0; i < cffont->num_fds; i++) {
-        size = (long) (private->offset[i + 1] - private->offset[i]);
-        if (cffont->private[i] && size > 0) {
-            cff_dict_pack(cffont->private[i], dest + offset, size);
-            cff_dict_set(cffont->fdarray[i], "Private", 0, (double) size);
-            cff_dict_set(cffont->fdarray[i], "Private", 1, (double) offset);
-        }
-        cff_dict_pack(cffont->fdarray[i], fdarray->data + (fdarray->offset)[i] - 1, (long) (fdarray->offset[fdarray->count] - 1));
-        offset += size;
-    }
-    cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray));
-    cff_release_index(fdarray);
-    cff_release_index(private);
-
-    /* Finally Top DICT */
-    topdict->data = xcalloc((unsigned) (topdict->offset[topdict->count] - 1), sizeof(card8));
-    cff_dict_pack(cffont->topdict, topdict->data, (long) (topdict->offset[topdict->count] - 1));
-    cff_pack_index(topdict, dest + topdict_offset, cff_index_size(topdict));
-    cff_release_index(topdict);
-
-    for (i = 0; i < offset; i++) {
-// printf("%i\n",(unsigned char)dest[i]);
-        strbuf_putchar(pdf->fb, dest[i]);
-    }
-    xfree(dest);
-    return;
-}
-
-@ @c
-void write_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
-{
-    cff_index *charstrings, *cs_idx;
-
-    long charstring_len, max_len;
-    long size, offset = 0;
-
-    card8 *data;
-    card16 num_glyphs, cs_count1, code, gid, last_cid;
-
-    double nominal_width, default_width;
-
-    char *fontname;
-    char *fullname;
-
-    glw_entry *glyph, *found;
-    struct avl_traverser t;
-
-cffont->_string = NULL;
-
-    fontname = xcalloc((unsigned) (1 + strlen(fd->fontname)), 1);
-    sprintf(fontname, "%s", fd->fontname);
-
-    fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
-    sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
-
-    /* finish parsing the CFF */
-    cff_read_private(cffont);
-    cff_read_subrs(cffont);
-
-    /* Widths */
-    if (cffont->private[0] && cff_dict_known(cffont->private[0], "defaultWidthX")) {
-        default_width = (double) cff_dict_get(cffont->private[0], "defaultWidthX", 0);
-    } else {
-        default_width = CFF_DEFAULTWIDTHX_DEFAULT;
-    }
-    if (cffont->private[0] && cff_dict_known(cffont->private[0], "nominalWidthX")) {
-        nominal_width = (double) cff_dict_get(cffont->private[0], "nominalWidthX", 0);
-    } else {
-        nominal_width = CFF_NOMINALWIDTHX_DEFAULT;
-    }
-
-    num_glyphs = 0;
-    last_cid = 0;
-    glyph = xtalloc(1, glw_entry);
-
-    /* insert notdef */
-    glyph->id = 0;
-    if (avl_find(fd->gl_tree, glyph) == NULL) {
-        avl_insert(fd->gl_tree, glyph);
-        glyph = xtalloc(1, glw_entry);
-    }
-
-    avl_t_init(&t, fd->gl_tree);
-    for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
-         found != NULL; found = (glw_entry *) avl_t_next(&t)) {
-        if (found->id > last_cid)
-            last_cid = (card16) found->id;
-        num_glyphs++;
-    }
-
-    {
-        cff_fdselect *fdselect;
-
-        fdselect = xcalloc(1, sizeof(cff_fdselect));
-        fdselect->format = 3;
-        fdselect->num_entries = 1;
-        fdselect->data.ranges = xcalloc(1, sizeof(cff_range3));
-        fdselect->data.ranges[0].first = 0;
-        fdselect->data.ranges[0].fd = 0;
-        cffont->fdselect = fdselect;
-    }
-
-    {
-        cff_charsets *charset;
-
-        charset = xcalloc(1, sizeof(cff_charsets));
-        charset->format = 0;
-        charset->num_entries = (card16) (num_glyphs - 1);
-        charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
-
-        gid = 0;
-
-        avl_t_init(&t, fd->gl_tree);
-        for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
-             found != NULL; found = (glw_entry *) avl_t_next(&t)) {
-            if (found->id != 0) {
-                charset->data.glyphs[gid] = (s_SID) found->id;
-                gid++;
-            }
-        }
-        cffont->charsets = charset;
-
-        if (cffont->header_major == 2) {
-            cff_dict_add(cffont->topdict, "charset", 1);
-        }
-    }
-    cff_dict_add(cffont->topdict, "CIDCount", 1);
-    cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1);
-
-    if (cffont->header_major == 2) {
-
-        cff_dict_add(cffont->topdict, "FullName", 1);
-        cff_dict_set(cffont->topdict, "FullName", 0, (double) cff_add_string(cffont, fontname));
-
-        cff_dict_add(cffont->topdict, "FontBBox", 4);
-        cff_dict_set(cffont->topdict, "FontBBox", 0, fd->font_dim[FONTBBOX1_CODE].val);
-        cff_dict_set(cffont->topdict, "FontBBox", 1, fd->font_dim[FONTBBOX2_CODE].val);
-        cff_dict_set(cffont->topdict, "FontBBox", 2, fd->font_dim[FONTBBOX3_CODE].val);
-        cff_dict_set(cffont->topdict, "FontBBox", 3, fd->font_dim[FONTBBOX4_CODE].val);
-    }
-
-    cffont->fdarray = xcalloc(1, sizeof(cff_dict *));
-    cffont->fdarray[0] = cff_new_dict();
-    cff_dict_add(cffont->fdarray[0], "FontName", 1);
-    /* FIXME: Skip XXXXXX+ */
-    cff_dict_set(cffont->fdarray[0], "FontName", 0, (double) cff_add_string(cffont, fullname));
-    cff_dict_add(cffont->fdarray[0], "Private", 2);
-    cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
-    cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0);
-    /* FDArray  - index offset, not known yet */
-    cff_dict_add(cffont->topdict, "FDArray", 1);
-    cff_dict_set(cffont->topdict, "FDArray", 0, 0.0);
-    /* FDSelect - offset, not known yet */
-    cff_dict_add(cffont->topdict, "FDSelect", 1);
-    cff_dict_set(cffont->topdict, "FDSelect", 0, 0.0);
-
-    cff_dict_remove(cffont->topdict, "UniqueID");
-    cff_dict_remove(cffont->topdict, "XUID");
-    cff_dict_remove(cffont->topdict, "Private");
-    cff_dict_remove(cffont->topdict, "Encoding");
-
-    cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
-    cs_idx = cff_get_index_header(cffont);
-
-    offset = (long) cffont->offset;
-    cs_count1 = cs_idx->count;
-    if (cs_count1 < 2) {
-        normal_error("cff","no valid charstring data found");
-    }
-
-    /* build the new charstrings entry */
-    charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
-    max_len = 2 * CS_STR_LEN_MAX;
-    charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
-    charstring_len = 0;
-
-    gid = 0;
-    data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
-
-    {
-        int i;
-        int tex_font = fd->tex_font;
-        int streamprovider = 0;
-        int callback_id = 0 ;
-        if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
-            streamprovider = font_streamprovider(tex_font);
-            callback_id = callback_defined(glyph_stream_provider_callback);
-        }
-        for (i = 0; i < cs_count1; i++) {
-            code = (card16) i;
-            glyph->id = code;
-            if ((avl_find(fd->gl_tree,glyph) != NULL)) {
-                /* this code is the same as below, apart from small details */
-                if (callback_id > 0) {
-                    lstring * result;
-                    run_callback(callback_id, "ddd->L", tex_font, i, streamprovider, &result); /* this call can be sped up */
-                    size = (size_t) result->l ;
-                    if (size > 0) {
-                        if (charstring_len + CS_STR_LEN_MAX >= max_len) {
-                            max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
-                            charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
-                        }
-                        (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
-                cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
-                        memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t) size);
-                        charstring_len += size;
-                        xfree(result);
-                    }
-                } else {
-                    size = (long)(cs_idx->offset[code+1] - cs_idx->offset[code]);
-                    if (size > CS_STR_LEN_MAX) {
-                        formatted_error("cff","charstring too long: gid=%u, %ld bytes", code, size);
-                    }
-                    if (charstring_len + CS_STR_LEN_MAX >= max_len) {
-                        max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
-                        charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
-                    }
-                    (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
-                    cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1);
-                    memcpy(data,&cffont->stream[cffont->offset],(size_t)size);
-                    charstring_len += cs_copy_charstring(
-                        charstrings->data + charstring_len,
-                        max_len - charstring_len,
-                        data, size,
-                        cffont->gsubr, (cffont->subrs)[0],
-                        default_width, nominal_width, NULL,
-                        cffont->header_major == 2
-                    );
-                }
-                gid++;
-            }
-        }
-    }
-    /*
-        CIDSet: a table of bits indexed by cid, bytes with high order bit first,
-        each (set) bit is a (present) CID.
-    */
-    if (1) {
-        int cid;
-        cidset = pdf_create_obj(pdf, obj_type_others, 0);
-        if (cidset != 0) {
-            size_t l = (last_cid/8)+1;
-            char *stream = xmalloc(l);
-            memset(stream, 0, l);
-            for (cid = 1; cid <= (long) last_cid; cid++) {
-                glyph->id = cid;
-                if (avl_find(fd->gl_tree,glyph) != NULL) {
-                    stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
-                }
-            }
-            pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
-            pdf_begin_dict(pdf);
-            pdf_dict_add_streaminfo(pdf);
-            pdf_end_dict(pdf);
-            pdf_begin_stream(pdf);
-            pdf_out_block(pdf, stream, l);
-            pdf_end_stream(pdf);
-            pdf_end_obj(pdf);
-        }
-    }
-    /*
-        This happens if the internal metrics do not agree with the actual
-        disk font.
-    */
-    if (gid < num_glyphs) {
-        formatted_warning("cff","embedded subset is smaller than expected: %d instead of %d glyphs", gid, num_glyphs);
-        num_glyphs = gid;
-    }
-
-    xfree(data);
-    cff_release_index(cs_idx);
-
-    (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
-    charstrings->count = num_glyphs;
-    cffont->num_glyphs = num_glyphs;
-    cffont->cstrings = charstrings;
-    /*
-        We don't use subroutines at all.
-    */
-    if (cffont->gsubr)
-        cff_release_index(cffont->gsubr);
-    cffont->gsubr = cff_new_index(0);
-
-    if (cffont->subrs && cffont->subrs[0])
-        cff_release_index(cffont->subrs[0]);
-    cffont->subrs[0] = NULL;
-
-    if (cffont->private && (cffont->private)[0]) {
-        cff_dict_remove((cffont->private)[0], "Subrs"); /* no Subrs */
-    }
-
-    cff_dict_update(cffont->topdict, cffont);
-
-    cff_add_string(cffont, "Adobe");
-    cff_add_string(cffont, "Identity");
-    if (cffont->header_major == 2) {
-        /* crash */
-    } else {
-        cff_dict_update(cffont->private[0], cffont);
-    }
-    cff_update_string(cffont);
-
-    /* CFF code need to be rewritten */
-    cff_dict_add(cffont->topdict, "ROS", 3);
-    cff_dict_set(cffont->topdict, "ROS", 0, (double) cff_get_sid(cffont, "Adobe"));
-    cff_dict_set(cffont->topdict, "ROS", 1, (double) cff_get_sid(cffont, "Identity"));
-    cff_dict_set(cffont->topdict, "ROS", 2, 0.0);
-
-    write_fontfile(pdf, cffont, fullname);
-    xfree(fontname);
-    xfree(fullname);
-    cff_close(cffont);
-}
-
-@ @c
-#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT)
-#define CID_MAX 65535
-
-void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
-{
-    cff_index *charstrings, *cs_idx;
-
-    long charstring_len, max_len;
-    long size, offset = 0;
-    int tex_font = fd->tex_font;
-    int streamprovider = 0;
-    int callback_id = 0 ;
-
-    card8 *data;
-    card16 num_glyphs, cs_count1, gid, last_cid;
-
-    int fdsel, prev_fd, cid_count, cid ;
-    char *fullname;
-
-    glw_entry *glyph;
-
-    unsigned char *CIDToGIDMap = NULL;
-
-    cff_fdselect *fdselect = NULL;
-    cff_charsets *charset = NULL;
-
-    if (!is_cidfont(cffont)) {
-        normal_error("cff","invalid CIDfont");
-        return;
-    }
-
-    if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) {
-        streamprovider = font_streamprovider(tex_font);
-        callback_id = callback_defined(glyph_stream_provider_callback);
-    }
-
-    fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1);
-    sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname);
-
-    /* finish parsing the CFF */
-
-    if (cff_dict_known(cffont->topdict, "CIDCount")) {
-        cid_count = (card16) cff_dict_get(cffont->topdict, "CIDCount", 0);
-    } else {
-        cid_count = CFF_CIDCOUNT_DEFAULT;
-    }
-    if (cffont->header_major == 2) {
-        /* hm */
-    } else {
-        cff_read_charsets(cffont);
-    }
-    CIDToGIDMap = xmalloc((unsigned) ((2 * (unsigned) cid_count) * sizeof(unsigned char)));
-    memset(CIDToGIDMap, 0, (size_t) (2 * cid_count));
-
-    glyph = xtalloc(1, glw_entry);
-    /* insert notdef */
-    glyph->id = 0;
-    if (avl_find(fd->gl_tree, glyph) == NULL) {
-        avl_insert(fd->gl_tree, glyph);
-        glyph = xtalloc(1, glw_entry);
-    }
-
-    last_cid = 0;
-    num_glyphs = 0;
-    for (cid = 0; cid <= CID_MAX; cid++) {
-        glyph->id = (unsigned) cid;
-        if (avl_find(fd->gl_tree, glyph) != NULL) {
-            gid = (card16) cid;
-            CIDToGIDMap[2 * cid] = (unsigned char) ((gid >> 8) & 0xff);
-            CIDToGIDMap[2 * cid + 1] = (unsigned char) (gid & 0xff);
-            last_cid = (card16) cid;
-            num_glyphs++;
-        }
-    }
-    if (cffont->header_major == 2) {
-        /* hm */
-    } else if (last_cid >= cffont->num_glyphs) {
-        formatted_error("cff font","bad glyph index %i",last_cid);
-    }
-    /*
-        CIDSet: a table of bits indexed by cid, bytes with high order bit
-        first, each (set) bit is a (present) CID.
-    */
-    if (1) {
-        cidset = pdf_create_obj(pdf, obj_type_others, 0);
-        if (cidset != 0) {
-            size_t l = (last_cid / 8) + 1;
-            char *stream = xmalloc(l);
-            memset(stream, 0, l);
-            for (cid = 1; cid <= (long) last_cid; cid++) {
-                if (CIDToGIDMap[2 * cid] || CIDToGIDMap[2 * cid + 1]) {
-                    stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
-                }
-            }
-            pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
-            pdf_begin_dict(pdf);
-            pdf_dict_add_streaminfo(pdf);
-            pdf_end_dict(pdf);
-            pdf_begin_stream(pdf);
-            pdf_out_block(pdf, stream, l);
-            pdf_end_stream(pdf);
-            pdf_end_obj(pdf);
-	    xfree(stream);
-        }
-    }
-
-    cff_read_fdselect(cffont);
-    cff_read_fdarray(cffont);
-    cff_read_private(cffont);
-
-    cff_read_subrs(cffont);
-
-    cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0);
-    cs_idx = cff_get_index_header(cffont);
-
-    offset = (long) cffont->offset;
-    cs_count1 = cs_idx->count;
-    if (cs_count1 < 2) {
-        normal_error("cff","no valid charstring data found");
-    }
-
-    charset = xcalloc(1, sizeof(cff_charsets));
-    charset->format = 0;
-    charset->num_entries = 0;
-    charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID));
-
-    fdselect = xcalloc(1, sizeof(cff_fdselect));
-    fdselect->format = 3;
-    fdselect->num_entries = 0;
-    fdselect->data.ranges = xcalloc(num_glyphs, sizeof(cff_range3));
-
-    charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1));
-    max_len = 2 * CS_STR_LEN_MAX;
-    charstrings->data = xcalloc((unsigned) max_len, sizeof(card8));
-    charstring_len = 0;
-
-    prev_fd = -1;
-    gid = 0;
-    data = xcalloc(CS_STR_LEN_MAX, sizeof(card8));
-    for (cid = 0; cid <= last_cid; cid++) {
-        unsigned short gid_org;
-
-        glyph->id = (unsigned) cid;
-        if (avl_find(fd->gl_tree, glyph) == NULL)
-            continue;
-
-        gid_org = (short unsigned) ((CIDToGIDMap[2 * cid] << 8) | (CIDToGIDMap[2 * cid + 1]));
-        fdsel = cff_fdselect_lookup(cffont, gid_org);
-
-        if (callback_id > 0) {
-            /* the next blob is not yet tested ... i need a font */
-            lstring * result;
-            run_callback(callback_id, "ddd->L", tex_font, gid_org, streamprovider, &result); /* this call can be sped up */
-            size = (size_t) result->l ;
-            if (size > 0) {
-                if (charstring_len + CS_STR_LEN_MAX >= max_len) {
-                    max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX);
-                    charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8)));
-                }
-                (charstrings->offset)[gid] = (unsigned)(charstring_len + 1);
-        cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[gid_org] - 1);
-                memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t)size);
-                charstring_len += size;
-                xfree(result);
-            }
-        } else {
-            size = (long) (cs_idx->offset[gid_org + 1] - cs_idx->offset[gid_org]);
-            if (size > CS_STR_LEN_MAX) {
-                formatted_error("cff","charstring too long: gid=%u, %ld bytes", cid, size);
-            }
-            if (charstring_len + CS_STR_LEN_MAX >= max_len) {
-                max_len = charstring_len + 2 * CS_STR_LEN_MAX;
-                charstrings->data = xrealloc(charstrings->data, (unsigned) ((unsigned) max_len * sizeof(card8)));
-            }
-            (charstrings->offset)[gid] = (l_offset) (charstring_len + 1);
-            cffont->offset = (l_offset) ((unsigned) offset + (cs_idx->offset)[gid_org] - 1);
-            memcpy(data, &cffont->stream[cffont->offset], (size_t) size);
-            charstring_len += cs_copy_charstring(
-                charstrings->data + charstring_len,
-                max_len - charstring_len,
-                data, size,
-                cffont->gsubr, (cffont->subrs)[fdsel],
-                0, 0, NULL,
-                cffont->header_major == 2
-            );
-        }
-        if (cid > 0 && gid_org > 0) {
-            charset->data.glyphs[charset->num_entries] = (s_SID) cid;
-            charset->num_entries++;
-        }
-        if (fdsel != prev_fd) {
-            fdselect->data.ranges[fdselect->num_entries].first = gid;
-            fdselect->data.ranges[fdselect->num_entries].fd = (card8) fdsel;
-            fdselect->num_entries++;
-            prev_fd = fdsel;
-        }
-        gid++;
-    }
-
-    if (gid != num_glyphs)
-        formatted_error("cff","unexpected error: %i != %i", gid, num_glyphs);
-    xfree(data);
-    cff_release_index(cs_idx);
-
-    xfree(CIDToGIDMap);
-
-    (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1);
-    charstrings->count = num_glyphs;
-    cffont->num_glyphs = num_glyphs;
-    cffont->cstrings = charstrings;
-    cff_release_charsets(cffont->charsets);
-    cffont->charsets = charset;
-    cff_release_fdselect(cffont->fdselect);
-    cffont->fdselect = fdselect;
-    /*
-        We don't use subroutines at all.
-    */
-    if (cffont->gsubr)
-        cff_release_index(cffont->gsubr);
-    cffont->gsubr = cff_new_index(0);
-
-    for (fdsel = 0; fdsel < cffont->num_fds; fdsel++) {
-        if (cffont->subrs && cffont->subrs[fdsel]) {
-            cff_release_index(cffont->subrs[fdsel]);
-            cffont->subrs[fdsel] = NULL;
-        }
-        if (cffont->private && (cffont->private)[fdsel]) {
-            cff_dict_remove((cffont->private)[fdsel], "Subrs"); /* no Subrs */
-        }
-    }
-    write_fontfile(pdf, cffont, fullname);
-    xfree(fullname);
-    cff_close(cffont);
-}
-
-@ Here is a sneaky trick: fontforge knows how to convert Type1 to CFF, so
-I have defined a utility function in luafflib.c that does exactly that.
-If it works out ok, I will clean up this code.
-
- at c
-void writetype1w(PDF pdf, fd_entry * fd)
-{
-    cff_font *cff;
-    int i;
-    FILE *fp;
-    ff_entry *ff;
-    unsigned char *tfm_buffer = NULL;
-    int tfm_size = 0;
-
-    ff = check_ff_exist(fd->fm->ff_name, 0);
-
-    fp = fopen(ff->ff_path, "rb");
-    cur_file_name = ff->ff_path;
-
-    if (!fp) {
-        formatted_error("cff","could not open Type1 font: %s", cur_file_name);
-    }
-    fclose(fp);
-
-    if (is_subsetted(fd->fm)) {
-        report_start_file(filetype_subset,cur_file_name);
-    } else {
-        report_start_file(filetype_font,cur_file_name);
-    }
-    (void) ff_createcff(ff->ff_path, &tfm_buffer, &tfm_size);
-
-    if (tfm_size > 0) {
-        cff = read_cff(tfm_buffer, tfm_size, 0);
-        if (cff != NULL) {
-            write_cff(pdf, cff, fd);
-        } else {
-            for (i = 0; i < tfm_size; i++)
-                strbuf_putchar(pdf->fb, tfm_buffer[i]);
-        }
-        fd->ff_found = 1;
-    } else {
-        formatted_error("cff","could not understand Type1 font: %s",cur_file_name);
-    }
-    if (is_subsetted(fd->fm)) {
-        report_stop_file(filetype_subset);
-    } else {
-        report_stop_file(filetype_font);
-    }
-    cur_file_name = NULL;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writeenc.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,164 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2011 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+    All encoding entries go into AVL tree for fast search by name.
+
+*/
+
+struct avl_table *fe_tree = NULL;
+
+/* The AVL sort |fe_entry| into |fe_tree| by name. */
+
+static int comp_fe_entry(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const fe_entry *) pa)->name, ((const fe_entry *) pb)->name);
+}
+
+static fe_entry *new_fe_entry(void)
+{
+    fe_entry *fe;
+    fe = xtalloc(1, fe_entry);
+    fe->name = NULL;
+    fe->fe_objnum = 0;
+    /*tex The encoding file is not yet read in. */
+    fe->glyph_names = NULL;
+    fe->tx_tree = NULL;
+    return fe;
+}
+
+static fe_entry *lookup_fe_entry(char *s)
+{
+    fe_entry fe;
+    assert(s != NULL);
+    fe.name = s;
+    if (fe_tree == NULL) {
+        fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
+        assert(fe_tree != NULL);
+    }
+    return (fe_entry *) avl_find(fe_tree, &fe);
+}
+
+static void register_fe_entry(fe_entry * fe)
+{
+    void **aa;
+    if (fe_tree == NULL) {
+        fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
+        assert(fe_tree != NULL);
+    }
+    assert(fe != NULL);
+    assert(fe->name != NULL);
+    /*tex The encoding is not yet registered. */
+    assert(lookup_fe_entry(fe->name) == NULL);
+    aa = avl_probe(fe_tree, fe);
+    assert(aa != NULL);
+}
+
+fe_entry *get_fe_entry(char *s)
+{
+    fe_entry *fe;
+    char **gl;
+    if ((fe = lookup_fe_entry(s)) == NULL && (gl = load_enc_file(s)) != NULL) {
+        fe = new_fe_entry();
+        fe->name = s;
+        fe->glyph_names = gl;
+        register_fe_entry(fe);
+    }
+    return fe;
+}
+
+static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree, int fe_objnum)
+{
+    int i_old, *p;
+    struct avl_traverser t;
+    assert(glyph_names != NULL);
+    assert(tx_tree != NULL);
+    assert(fe_objnum != 0);
+    pdf_begin_obj(pdf, fe_objnum, OBJSTM_ALWAYS);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_name(pdf, "Type", "Encoding");
+    pdf_add_name(pdf, "Differences");
+    pdf_begin_array(pdf);
+    avl_t_init(&t, tx_tree);
+    for (i_old = -2, p = (int *) avl_t_first(&t, tx_tree); p != NULL;
+         p = (int *) avl_t_next(&t)) {
+        if (*p == i_old + 1) {
+            pdf_add_name(pdf, glyph_names[*p]);
+        } else {
+            pdf_add_int(pdf, *p);
+            pdf_add_name(pdf, glyph_names[*p]);
+        }
+        i_old = *p;
+    }
+    pdf_end_array(pdf);
+    pdf_end_dict(pdf);
+    pdf_end_obj(pdf);
+}
+
+static void write_fontencoding(PDF pdf, fe_entry * fe)
+{
+    assert(fe != NULL);
+    write_enc(pdf, fe->glyph_names, fe->tx_tree, fe->fe_objnum);
+}
+
+void write_fontencodings(PDF pdf)
+{
+    fe_entry *fe;
+    struct avl_traverser t;
+    if (fe_tree == NULL)
+        return;
+    avl_t_init(&t, fe_tree);
+    for (fe = (fe_entry *) avl_t_first(&t, fe_tree); fe != NULL;
+         fe = (fe_entry *) avl_t_next(&t))
+        if (fe->fe_objnum != 0)
+            write_fontencoding(pdf, fe);
+}
+
+/*tex Cleaning up \unknown */
+
+static void destroy_fe_entry(void *pa, void *pb)
+{
+    fe_entry *p;
+    int i;
+    (void) pb;
+    p = (fe_entry *) pa;
+    xfree(p->name);
+    if (p->glyph_names != NULL)
+        for (i = 0; i < 256; i++)
+            if (p->glyph_names[i] != notdef)
+                xfree(p->glyph_names[i]);
+    xfree(p->glyph_names);
+    if (p->tx_tree != NULL)
+        avl_destroy(p->tx_tree,NULL);
+    xfree(p);
+}
+
+void enc_free(void)
+{
+    if (fe_tree != NULL)
+        avl_destroy(fe_tree, destroy_fe_entry);
+    fe_tree = NULL;
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writeenc.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,162 +0,0 @@
-% writeenc.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2011 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ All encoding entries go into AVL tree for fast search by name.
- at c
-struct avl_table *fe_tree = NULL;
-
-@ AVL sort |fe_entry| into |fe_tree| by name
- at c
-static int comp_fe_entry(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const fe_entry *) pa)->name, ((const fe_entry *) pb)->name);
-}
-
-static fe_entry *new_fe_entry(void)
-{
-    fe_entry *fe;
-    fe = xtalloc(1, fe_entry);
-    fe->name = NULL;
-    fe->fe_objnum = 0;
-    fe->glyph_names = NULL;     /* encoding file not yet read in */
-    fe->tx_tree = NULL;
-    return fe;
-}
-
-static fe_entry *lookup_fe_entry(char *s)
-{
-    fe_entry fe;
-    assert(s != NULL);
-    fe.name = s;
-    if (fe_tree == NULL) {
-        fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
-        assert(fe_tree != NULL);
-    }
-    return (fe_entry *) avl_find(fe_tree, &fe);
-}
-
-static void register_fe_entry(fe_entry * fe)
-{
-    void **aa;
-    if (fe_tree == NULL) {
-        fe_tree = avl_create(comp_fe_entry, NULL, &avl_xallocator);
-        assert(fe_tree != NULL);
-    }
-    assert(fe != NULL);
-    assert(fe->name != NULL);
-    assert(lookup_fe_entry(fe->name) == NULL);  /* encoding not yet registered */
-    aa = avl_probe(fe_tree, fe);
-    assert(aa != NULL);
-}
-
-fe_entry *get_fe_entry(char *s)
-{
-    fe_entry *fe;
-    char **gl;
-    if ((fe = lookup_fe_entry(s)) == NULL && (gl = load_enc_file(s)) != NULL) {
-        fe = new_fe_entry();
-        fe->name = s;
-        fe->glyph_names = gl;
-        register_fe_entry(fe);
-    }
-    return fe;
-}
-
-@ @c
-static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree,
-                      int fe_objnum)
-{
-    int i_old, *p;
-    struct avl_traverser t;
-    assert(glyph_names != NULL);
-    assert(tx_tree != NULL);
-    assert(fe_objnum != 0);
-    pdf_begin_obj(pdf, fe_objnum, OBJSTM_ALWAYS);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_name(pdf, "Type", "Encoding");
-    pdf_add_name(pdf, "Differences");
-    pdf_begin_array(pdf);
-    avl_t_init(&t, tx_tree);
-    for (i_old = -2, p = (int *) avl_t_first(&t, tx_tree); p != NULL;
-         p = (int *) avl_t_next(&t)) {
-        if (*p == i_old + 1)    /* consecutive */
-            pdf_add_name(pdf, glyph_names[*p]);
-        else {
-            pdf_add_int(pdf, *p);
-            pdf_add_name(pdf, glyph_names[*p]);
-        }
-        i_old = *p;
-    }
-    pdf_end_array(pdf);
-    pdf_end_dict(pdf);
-    pdf_end_obj(pdf);
-}
-
-static void write_fontencoding(PDF pdf, fe_entry * fe)
-{
-    assert(fe != NULL);
-    write_enc(pdf, fe->glyph_names, fe->tx_tree, fe->fe_objnum);
-}
-
-void write_fontencodings(PDF pdf)
-{
-    fe_entry *fe;
-    struct avl_traverser t;
-    if (fe_tree == NULL)
-        return;
-    avl_t_init(&t, fe_tree);
-    for (fe = (fe_entry *) avl_t_first(&t, fe_tree); fe != NULL;
-         fe = (fe_entry *) avl_t_next(&t))
-        if (fe->fe_objnum != 0)
-            write_fontencoding(pdf, fe);
-}
-
-@ cleaning up...
- at c
-
-static void destroy_fe_entry(void *pa, void *pb)
-{
-    fe_entry *p;
-    int i;
-    (void) pb;
-    p = (fe_entry *) pa;
-    xfree(p->name);
-    if (p->glyph_names != NULL)
-        for (i = 0; i < 256; i++)
-            if (p->glyph_names[i] != notdef)
-                xfree(p->glyph_names[i]);
-    xfree(p->glyph_names);
-    if (p->tx_tree != NULL)
-        avl_destroy(p->tx_tree,NULL);
-    xfree(p);
-}
-
-void enc_free(void)
-{
-    if (fe_tree != NULL)
-        avl_destroy(fe_tree, destroy_fe_entry);
-    fe_tree = NULL;
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/writefont.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writefont.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writefont.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1069 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2010 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f);
+
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f);
+
+const key_entry font_key[FONT_KEYS_NUM] = {
+    { "Ascent",      "Ascender",    1 },
+    { "CapHeight",   "CapHeight",   1 },
+    { "Descent",     "Descender",   1 },
+    { "ItalicAngle", "ItalicAngle", 1 },
+    { "StemV",       "StdVW",       1 },
+    { "XHeight",     "XHeight",     1 },
+    { "FontBBox",    "FontBBox",    1 },
+    { "",            "",            0 },
+    { "",            "",            0 },
+    { "",            "",            0 },
+    { "FontName",    "FontName",    1 }
+};
+
+/*tex A tree of font dictionaries: */
+
+struct avl_table *fo_tree = NULL;
+
+/*tex A tree of font descriptor objects: */
+
+struct avl_table *fd_tree = NULL;
+
+static int comp_fo_entry(const void *pa, const void *pb, void *p)
+{
+    (void) p;
+    return strcmp(((const fo_entry *) pa)->fm->tfm_name, ((const fo_entry *) pb)->fm->tfm_name);
+}
+
+static int comp_fd_entry(const void *pa, const void *pb, void *p)
+{
+    const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb;
+    (void) p;
+    return strcmp(p1->fm->ff_name, p2->fm->ff_name);
+}
+
+/*tex We initialize data structure for |/Type| |/Font|: */
+
+static fo_entry *new_fo_entry(void)
+{
+    fo_entry *fo;
+    fo = xtalloc(1, fo_entry);
+    fo->fo_objnum = 0;
+    fo->tex_font = 0;
+    fo->fm = NULL;
+    fo->fd = NULL;
+    fo->fe = NULL;
+    fo->cw_objnum = 0;
+    fo->first_char = 1;
+    fo->last_char = 0;
+    fo->tx_tree = NULL;
+    fo->tounicode_objnum = 0;
+    return fo;
+}
+
+/*tex We initialize data structure for |/Type| |/FontDescriptor|: */
+
+fd_entry *new_fd_entry(internal_font_number f)
+{
+    fd_entry *fd;
+    int i;
+    fd = xtalloc(1, fd_entry);
+    fd->fd_objnum = 0;
+    fd->fontname = NULL;
+    fd->subset_tag = NULL;
+    fd->ff_found = false;
+    fd->ff_objnum = 0;
+    fd->all_glyphs = false;
+    fd->write_ttf_glyph_names = false;
+    for (i = 0; i < FONT_KEYS_NUM; i++) {
+        fd->font_dim[i].val = 0;
+        fd->font_dim[i].set = false;
+    }
+    fd->fe = NULL;
+    fd->builtin_glyph_names = NULL;
+    fd->fm = NULL;
+    fd->tx_tree = NULL;
+    fd->gl_tree = NULL;
+    fd->tex_font = f;
+    return fd;
+}
+
+/*tex
+
+    Only fallback values of font metrics are taken from the TFM info of |f| by
+    |preset_fontmetrics|. During reading of the font file, these values are
+    replaced by metrics from the font, if available.
+
+*/
+
+static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
+{
+    int i;
+    fd->font_dim[ITALIC_ANGLE_CODE].val = 0;
+    fd->font_dim[ASCENT_CODE].val =
+        divide_scaled(char_height(f, 'h'), font_size(f), 3);
+    fd->font_dim[CAPHEIGHT_CODE].val =
+        divide_scaled(char_height(f, 'H'), font_size(f), 3);
+    i = -divide_scaled(char_depth(f, 'y'), font_size(f), 3);
+    fd->font_dim[DESCENT_CODE].val = i < 0 ? i : 0;
+    fd->font_dim[STEMV_CODE].val =
+        divide_scaled(char_width(f, '.') / 3, font_size(f), 3);
+    fd->font_dim[XHEIGHT_CODE].val =
+        divide_scaled(get_x_height(f), font_size(f), 3);
+    fd->font_dim[FONTBBOX1_CODE].val = 0;
+    fd->font_dim[FONTBBOX2_CODE].val = fd->font_dim[DESCENT_CODE].val;
+    fd->font_dim[FONTBBOX3_CODE].val =
+        divide_scaled(get_quad(f), font_size(f), 3);
+    fd->font_dim[FONTBBOX4_CODE].val =
+        fd->font_dim[CAPHEIGHT_CODE].val > fd->font_dim[ASCENT_CODE].val ?
+        fd->font_dim[CAPHEIGHT_CODE].val : fd->font_dim[ASCENT_CODE].val;
+    for (i = 0; i < INT_KEYS_NUM; i++)
+        fd->font_dim[i].set = true;
+}
+
+static void fix_fontmetrics(fd_entry * fd)
+{
+    int i;
+    intparm *p = (intparm *) fd->font_dim;
+    /*tex Make sure there is a rectangle. */
+    if (p[FONTBBOX3_CODE].val < p[FONTBBOX1_CODE].val) {
+        i = p[FONTBBOX3_CODE].val;
+        p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val;
+        p[FONTBBOX1_CODE].val = i;
+    } else if (p[FONTBBOX3_CODE].val == p[FONTBBOX1_CODE].val)
+        p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val + 1;
+    if (p[FONTBBOX4_CODE].val < p[FONTBBOX2_CODE].val) {
+        i = p[FONTBBOX4_CODE].val;
+        p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val;
+        p[FONTBBOX2_CODE].val = i;
+    } else if (p[FONTBBOX4_CODE].val == p[FONTBBOX2_CODE].val)
+        p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val + 1;
+    if (!p[ASCENT_CODE].set) {
+        p[ASCENT_CODE].val = p[FONTBBOX4_CODE].val;
+        p[ASCENT_CODE].set = true;
+    }
+    if (!p[DESCENT_CODE].set) {
+        p[DESCENT_CODE].val = p[FONTBBOX2_CODE].val;
+        p[DESCENT_CODE].set = true;
+    }
+    if (!p[CAPHEIGHT_CODE].set) {
+        p[CAPHEIGHT_CODE].val = p[FONTBBOX4_CODE].val;
+        p[CAPHEIGHT_CODE].set = true;
+    }
+}
+
+static void write_fontmetrics(PDF pdf, fd_entry * fd)
+{
+    int i;
+    fix_fontmetrics(fd);
+    pdf_add_name(pdf, font_key[FONTBBOX1_CODE].pdfname);
+    pdf_begin_array(pdf);
+    /*
+    pdf_check_space;
+    pdf_printf(pdf, "%i %i %i %i",
+        (int) fd->font_dim[FONTBBOX1_CODE].val,
+        (int) fd->font_dim[FONTBBOX2_CODE].val,
+        (int) fd->font_dim[FONTBBOX3_CODE].val,
+        (int) fd->font_dim[FONTBBOX4_CODE].val);
+    */
+    pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX1_CODE].val);
+    pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX2_CODE].val);
+    pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX3_CODE].val);
+    pdf_add_int(pdf,(int) fd->font_dim[FONTBBOX4_CODE].val);
+    /* */
+    pdf_end_array(pdf);
+    for (i = 0; i < GEN_KEY_NUM; i++)
+        if (fd->font_dim[i].set)
+            pdf_dict_add_int(pdf, font_key[i].pdfname, fd->font_dim[i].val);
+}
+
+static void preset_fontname(fo_entry * fo, internal_font_number f)
+{
+    if (fo->fm->ps_name != NULL) {
+        /*tex We just fallback. */
+        fo->fd->fontname = xstrdup(fo->fm->ps_name);
+    } else if (font_fullname(f) != NULL) {
+        fo->fd->fontname = xstrdup(font_fullname(f));
+    } else {
+        fo->fd->fontname = xstrdup(fo->fm->tfm_name);
+    }
+}
+
+static void pdf_dict_add_fontname(PDF pdf, const char *key, fd_entry * fd)
+{
+    char *s;
+    size_t l1 = 0, l2;
+    if (fd->subset_tag != NULL)
+        l1 = strlen(fd->subset_tag);
+    l2 = strlen(fd->fontname);
+    s = xmalloc(l1 + l2 + 2);
+    if (l1 > 0)
+        snprintf(s, l1 + l2 + 2, "%s+%s", fd->subset_tag, fd->fontname);
+    else
+        snprintf(s, l2 + 1, "%s", fd->fontname);
+    pdf_dict_add_name(pdf, key, s);
+    xfree(s);
+}
+
+fd_entry *lookup_fd_entry(char *s)
+{
+    fd_entry fd;
+    fm_entry fm;
+    fm.ff_name = s;
+    fd.fm = &fm;
+    if (fd_tree == NULL) {
+        fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+    }
+    return (fd_entry *) avl_find(fd_tree, &fd);
+}
+
+static fd_entry *lookup_fontdescriptor(fo_entry * fo)
+{
+    return lookup_fd_entry(fo->fm->ff_name);
+}
+
+void register_fd_entry(fd_entry * fd)
+{
+    void **aa;
+    if (fd_tree == NULL) {
+        fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
+    }
+    /*tex The font descriptor is not yet registered: */
+    if (lookup_fd_entry(fd->fm->ff_name) == NULL) {
+        /*tex Is this a problem? */
+    } else {
+        /*tex The lookup also can create */
+    }
+    aa = avl_probe(fd_tree, fd);
+    if (aa == NULL) {
+        /*tex Is this a problem? */
+    }
+}
+
+static void create_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+    fo->fd = new_fd_entry(f);
+    preset_fontname(fo, f);
+    preset_fontmetrics(fo->fd, f);
+    /*tex An encoding is needed for \TRUETYPE\ writing: */
+    fo->fd->fe = fo->fe;
+    /*tex A map entry is needed for \TRUETYPE\ writing: */
+    fo->fd->fm = fo->fm;
+    fo->fd->gl_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
+}
+
+/*tex
+
+    For all used characters of \TeX font |f|, get corresponding glyph names from
+    external reencoding (.enc) file and collect these in the glyph tree |gl_tree|
+    of font descriptor |fd| referenced by font dictionary |fo|.
+
+*/
+
+static void mark_reenc_glyphs(fo_entry * fo, internal_font_number f)
+{
+    int i;
+    char **g;
+    void **aa;
+    if (is_subsetted(fo->fm)) {
+        /*tex mark glyphs from TeX (externally reencoded characters) */
+        g = fo->fe->glyph_names;
+        for (i = fo->first_char; i <= fo->last_char; i++) {
+            if (pdf_char_marked(f, i)
+                && g[i] != notdef
+                && (char *) avl_find(fo->fd->gl_tree, g[i]) == NULL) {
+                aa = avl_probe(fo->fd->gl_tree, xstrdup(g[i]));
+                if (aa == NULL) {
+                    /*tex Is this a problem? */
+                }
+            }
+        }
+    }
+}
+
+/*tex
+
+    Function |mark_chars| has 2 uses:
+
+    \startitemize[n]
+        \startitem Mark characters as chars on \TeX\ level. \stopitem
+        \startitem Mark encoding pairs used by \TeX\ to optimize encoding vector. \stopitem
+    \stopitemize
+
+*/
+
+static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree, internal_font_number f)
+{
+    int i, *j;
+    void **aa;
+    if (tx_tree == NULL) {
+        tx_tree = avl_create(comp_int_entry, NULL, &avl_xallocator);
+        assert(tx_tree != NULL);
+    }
+    for (i = fo->first_char; i <= fo->last_char; i++) {
+        if (pdf_char_marked(f, i) && (int *) avl_find(tx_tree, &i) == NULL) {
+            j = xtalloc(1, int);
+            *j = i;
+            aa = avl_probe(tx_tree, j);
+            if (aa == NULL) {
+                /*tex Is this a problem? */
+            }
+        }
+    }
+    return tx_tree;
+}
+
+static void get_char_range(fo_entry * fo, internal_font_number f)
+{
+    int i;
+    assert(fo != NULL);
+    /*tex Search for |first_char| and |last_char|. */
+    for (i = font_bc(f); i <= font_ec(f); i++)
+        if (pdf_char_marked(f, i))
+            break;
+    fo->first_char = i;
+    for (i = font_ec(f); i >= font_bc(f); i--)
+        if (pdf_char_marked(f, i))
+            break;
+    fo->last_char = i;
+    if ((fo->first_char > fo->last_char) || !pdf_char_marked(f, fo->first_char)) {
+        /*tex No character has been used from this font. */
+        fo->last_char = 0;
+        fo->first_char = fo->last_char + 1;
+    }
+}
+
+static int font_has_subset(internal_font_number f)
+{
+    int i, s;
+    /*tex Search for |first_char| and |last_char|. */
+    for (i = font_bc(f); i <= font_ec(f); i++)
+        if (pdf_char_marked(f, i))
+            break;
+    s = i;
+    for (i = font_ec(f); i >= font_bc(f); i--)
+        if (pdf_char_marked(f, i))
+            break;
+    if (s > i)
+        return 0;
+    else
+        return 1;
+}
+
+static void write_charwidth_array(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+    int i, j, *ip, *fip;
+    struct avl_traverser t;
+    fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+    pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
+    avl_t_init(&t, fo->tx_tree);
+    fip = (int *) avl_t_first(&t, fo->tx_tree);
+    pdf_begin_array(pdf);
+    for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) {
+        if (ip != fip)
+            pdf_out(pdf, ' ');
+        i = *ip;
+        while (j < i - 1) {
+            pdf_puts(pdf, "0 ");
+            j++;
+        }
+        j = i;
+        pdf_print_charwidth(pdf, f, i);
+    }
+    pdf_end_array(pdf);
+    pdf_end_obj(pdf);
+}
+
+/*tex
+
+    Remark: Font objects from embedded PDF files are never registered into
+    |fo_tree|; they are individually written out.
+
+*/
+
+static fo_entry *lookup_fo_entry(char *s)
+{
+    fo_entry fo;
+    fm_entry fm;
+    fm.tfm_name = s;
+    fo.fm = &fm;
+    if (fo_tree == NULL) {
+        fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+    }
+    return (fo_entry *) avl_find(fo_tree, &fo);
+}
+
+static void register_fo_entry(fo_entry * fo)
+{
+    void **aa;
+    if (fo_tree == NULL) {
+        fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
+    }
+    if (lookup_fo_entry(fo->fm->tfm_name) == NULL) {
+        /*tex Is this a problem? */
+    } else {
+        /*tex The lookup also can create */
+    }
+    aa = avl_probe(fo_tree, fo);
+    if (aa == NULL) {
+        /*tex Is this a problem? */
+    }
+}
+
+/*tex
+
+In principle we could replace the pdftex derived ttf.otf inclusion part by using
+the regular code for this and assigning indices and tounicodes to the character
+blobs, but for the moment we keep the current approach.
+
+*/
+
+static void write_fontfile(PDF pdf, fd_entry * fd)
+{
+    if (is_cidkeyed(fd->fm)) {
+        if (is_opentype(fd->fm)) {
+            writetype0(pdf, fd);
+        } else if (is_truetype(fd->fm)) {
+            if (!writetype2(pdf, fd)) {
+                writetype0(pdf,fd);
+                fd->fm->type |= F_OTF; fd->fm->type ^= F_TRUETYPE;
+            }
+        } else if (is_type1(fd->fm)) {
+            writetype1w(pdf, fd);
+        } else {
+            normal_error("fonts","there is a problem writing the font file (1)");
+        }
+    } else {
+        if (is_type1(fd->fm)) {
+            writet1(pdf, fd);
+        } else if (is_truetype(fd->fm)) {
+            writettf(pdf, fd);
+        } else if (is_opentype(fd->fm)) {
+            writeotf(pdf, fd);
+        } else {
+            normal_error("fonts","there is a problem writing the font file (2)");
+        }
+    }
+    if (!fd->ff_found)
+        return;
+    fd->ff_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+    /*tex The font file stream: */
+    pdf_begin_obj(pdf, fd->ff_objnum, OBJSTM_NEVER);
+    pdf_begin_dict(pdf);
+    if (is_cidkeyed(fd->fm)) {
+        /*tex No subtype is used for |TRUETYPE\ based \OPENTYPE\ fonts. */
+        if (is_opentype(fd->fm) || is_type1(fd->fm)) {
+            pdf_dict_add_name(pdf, "Subtype", "CIDFontType0C");
+        }
+    } else if (is_type1(fd->fm)) {
+        pdf_dict_add_int(pdf, "Length1", (int) t1_length1);
+        pdf_dict_add_int(pdf, "Length2", (int) t1_length2);
+        pdf_dict_add_int(pdf, "Length3", (int) t1_length3);
+    } else if (is_truetype(fd->fm)) {
+        pdf_dict_add_int(pdf, "Length1", (int) ttf_length);
+    } else if (is_opentype(fd->fm)) {
+        pdf_dict_add_name(pdf, "Subtype", "Type1C");
+    } else {
+        normal_error("fonts","there is a problem writing the font file (3)");
+    }
+    pdf_dict_add_streaminfo(pdf);
+    pdf_end_dict(pdf);
+    pdf_begin_stream(pdf);
+    strbuf_flush(pdf, pdf->fb);
+    pdf_end_stream(pdf);
+    pdf_end_obj(pdf);
+}
+
+int cidset = 0;
+
+static void write_fontdescriptor(PDF pdf, fd_entry * fd)
+{
+    static const int std_flags[] = {
+        1 + 2 + (1 << 5),                        /* Courier */
+        1 + 2 + (1 << 5)            + (1 << 18), /* Courier-Bold */
+        1 + 2 + (1 << 5) + (1 << 6),             /* Courier-Oblique */
+        1 + 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Courier-BoldOblique */
+                (1 << 5),                        /* Helvetica */
+                (1 << 5)            + (1 << 18), /* Helvetica-Bold */
+                (1 << 5) + (1 << 6),             /* Helvetica-Oblique */
+                (1 << 5) + (1 << 6) + (1 << 18), /* Helvetica-BoldOblique */
+              4,                                 /* Symbol */
+            2 + (1 << 5),                        /* Times-Roman */
+            2 + (1 << 5)            + (1 << 18), /* Times-Bold */
+            2 + (1 << 5) + (1 << 6),             /* Times-Italic */
+            2 + (1 << 5) + (1 << 6) + (1 << 18), /* Times-BoldItalic */
+              4                                  /* ZapfDingbats */
+    };
+    char *glyph;
+    struct avl_traverser t;
+    int fd_flags;
+    /*tex Possibly updated by |write_fontfile|: */
+    cidset = 0;
+    if (fd->fd_objnum == 0) {
+        int n = 0;
+        int callback_id = callback_defined(font_descriptor_objnum_provider_callback);
+        if (callback_id) {
+            run_callback(callback_id, "S->d", fd->fontname, &n);
+        }
+        if (!n) {
+           n = pdf_create_obj(pdf, obj_type_others, 0);
+        }
+        fd->fd_objnum = n;
+    }
+    if (is_fontfile(fd->fm) && is_included(fd->fm)) {
+        /*tex This will set |fd->ff_found| if font file is found: */
+        write_fontfile(pdf, fd);
+    }
+    pdf_begin_obj(pdf, fd->fd_objnum, OBJSTM_ALWAYS);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_name(pdf, "Type", "FontDescriptor");
+    pdf_dict_add_fontname(pdf, "FontName", fd);
+    if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE) {
+        fd_flags = (int) fd->fm->fd_flags;
+    } else if (fd->ff_found) {
+        fd_flags = FD_FLAGS_DEFAULT_EMBED;
+    } else {
+        fd_flags = is_std_t1font(fd->fm) ? std_flags[check_std_t1font(fd->fm->ps_name)] : FD_FLAGS_DEFAULT_NON_EMBED;
+        formatted_warning("map file",
+             "No flags specified for non-embedded font '%s' (%s), I'm using %i, fix your map entry",
+             fd->fm->ps_name != NULL ? fd->fm->ps_name : "No name given",
+             fd->fm->tfm_name, fd_flags);
+    }
+    pdf_dict_add_int(pdf, "Flags", fd_flags);
+    write_fontmetrics(pdf, fd);
+    if (fd->ff_found) {
+        if (is_cidkeyed(fd->fm)) {
+            if (is_type1(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+            else if (is_truetype(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
+            else if (is_opentype(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+            else
+                normal_error("fonts","there is a problem writing the font file (4)");
+        } else {
+            if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
+                /*tex |/CharSet| is optional; names may appear in any order */
+                if ((! pdf->omit_charset) && (pdf->major_version == 1)) {
+                    avl_t_init(&t, fd->gl_tree);
+                    pdf_add_name(pdf, "CharSet");
+                    pdf_out(pdf, '(');
+                    for (glyph = (char *) avl_t_first(&t, fd->gl_tree); glyph != NULL; glyph = (char *) avl_t_next(&t)) {
+                        pdf_add_name(pdf, glyph);
+                    }
+                    pdf_out(pdf, ')');
+                    pdf_set_space(pdf);
+                }
+            }
+            if (is_type1(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile", (int) fd->ff_objnum);
+            else if (is_truetype(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
+            else if (is_opentype(fd->fm))
+                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
+            else
+                normal_error("fonts","there is a problem writing the font file (5)");
+        }
+    }
+    if ((! pdf->omit_cidset) && (pdf->major_version == 1) && (cidset != 0) ) {
+        pdf_dict_add_ref(pdf, "CIDSet", cidset);
+    }
+    /*tex
+        Currently we don't export the optional keys for CID fonts like |/Style <<
+        /Panose <12-byte string> >>| and we probably never will.
+    */
+    pdf_end_dict(pdf);
+    pdf_end_obj(pdf);
+}
+
+static void write_fontdescriptors(PDF pdf)
+{
+    fd_entry *fd;
+    struct avl_traverser t;
+    if (fd_tree == NULL)
+        return;
+    avl_t_init(&t, fd_tree);
+    for (fd = (fd_entry *) avl_t_first(&t, fd_tree); fd != NULL; fd = (fd_entry *) avl_t_next(&t))
+        write_fontdescriptor(pdf, fd);
+}
+
+static void write_fontdictionary(PDF pdf, fo_entry * fo)
+{
+    /*tex Write the |/ToUnicode| entry if needed. */
+    if (pdf->gen_tounicode > 0 && fo->fd != NULL) {
+        if (fo->fe != NULL) {
+            fo->tounicode_objnum = write_tounicode(pdf, fo->fe->glyph_names, fo->fe->name);
+        } else if (is_type1(fo->fm)) {
+            fo->tounicode_objnum = write_tounicode(pdf, fo->fd->builtin_glyph_names, fo->fm->tfm_name);
+        }
+    }
+    pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_name(pdf, "Type", "Font");
+    if (is_type1(fo->fm))
+        pdf_dict_add_name(pdf, "Subtype", "Type1");
+    else if (is_truetype(fo->fm))
+        pdf_dict_add_name(pdf, "Subtype", "TrueType");
+    else if (is_opentype(fo->fm))
+        pdf_dict_add_name(pdf, "Subtype", "Type1");
+    else
+        normal_error("fonts","there is a problem writing the font file (6)");
+    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+    pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
+    pdf_dict_add_int(pdf, "FirstChar", (int) fo->first_char);
+    pdf_dict_add_int(pdf, "LastChar", (int) fo->last_char);
+    pdf_dict_add_ref(pdf, "Widths", (int) fo->cw_objnum);
+    if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL && fo->fe->fe_objnum != 0)
+        pdf_dict_add_ref(pdf, "Encoding", (int) fo->fe->fe_objnum);
+    if (fo->tounicode_objnum != 0)
+        pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
+    if (pdf_font_attr(fo->tex_font) != get_nullstr() && pdf_font_attr(fo->tex_font) != 0) {
+        pdf_check_space(pdf);
+        pdf_print(pdf, pdf_font_attr(fo->tex_font));
+        pdf_set_space(pdf);
+    }
+    pdf_end_dict(pdf);
+    pdf_end_obj(pdf);
+}
+
+static void write_fontdictionaries(PDF pdf)
+{
+    fo_entry *fo;
+    struct avl_traverser t;
+    if (fo_tree == NULL)
+        return;
+    avl_t_init(&t, fo_tree);
+    for (fo = (fo_entry *) avl_t_first(&t, fo_tree); fo != NULL; fo = (fo_entry *) avl_t_next(&t)) {
+        write_fontdictionary(pdf, fo);
+    }
+}
+
+/*tex
+
+    Final flush of all font related stuff by call from \.{Output fonts
+    definitions} elsewhere.
+
+*/
+
+void write_fontstuff(PDF pdf)
+{
+    write_fontdescriptors(pdf);
+    write_fontencodings(pdf);
+    write_fontdictionaries(pdf);
+}
+
+static void create_fontdictionary(PDF pdf, internal_font_number f)
+{
+    fo_entry *fo = new_fo_entry();
+    fm_entry *fm = font_map(f);
+    /*tex set |fo->first_char| and |fo->last_char| from |f| */
+    get_char_range(fo, f);
+    if (fo->last_char > 255)
+        fo->last_char = 255;
+    fo->fm = fm;
+    fo->fo_objnum = pdf_font_num(f);
+    fo->tex_font = f;
+    if (is_reencoded(fo->fm)) {
+        /*tex
+            At least the map entry tells so but it returns |NULL| if the .enc
+            file couldn't be opened.
+        */
+        fo->fe = get_fe_entry(fo->fm->encname);
+        if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) {
+            /*tex We don't end up here for truetype fonts. */
+            if (fo->fe->fe_objnum == 0) {
+                /*tex It will be written out */
+                fo->fe->fe_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+            }
+            /*tex Mark encoding pairs used by TeX to optimize encoding vector. */
+            fo->fe->tx_tree = mark_chars(fo, fo->fe->tx_tree, f);
+        }
+    }
+    /*tex For |write_charwidth_array|: */
+    fo->tx_tree = mark_chars(fo, fo->tx_tree, f);
+    write_charwidth_array(pdf, fo, f);
+    if (!is_builtin(fo->fm)) {
+        if (is_type1(fo->fm)) {
+            if ((fo->fd = lookup_fontdescriptor(fo)) == NULL) {
+                create_fontdescriptor(fo, f);
+                register_fd_entry(fo->fd);
+            }
+        } else {
+            create_fontdescriptor(fo, f);
+        }
+        if (fo->fe != NULL) {
+            mark_reenc_glyphs(fo, f);
+            if (!is_type1(fo->fm)) {
+                /*tex Mark reencoded characters as chars on TeX level. */
+                assert(fo->fd->tx_tree == NULL);
+                fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+                if (is_truetype(fo->fm)) {
+                    fo->fd->write_ttf_glyph_names = true;
+                }
+            }
+        } else {
+            /*tex Mark non-reencoded characters as chars on TeX level. */
+            fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
+        }
+        if (!is_type1(fo->fm)) {
+            write_fontdescriptor(pdf, fo->fd);
+        }
+    } else {
+        /*tex
+            Builtin fonts still need the \type {/Widths} array and \type
+            {/FontDescriptor} (to avoid error \quotation {font FOO contains bad
+            \type {/BBox}}).
+        */
+        create_fontdescriptor(fo, f);
+        write_fontdescriptor(pdf, fo->fd);
+        if (!is_std_t1font(fo->fm)) {
+            formatted_warning("map file", "font '%s' is not a standard font; I suppose it is available to your PDF viewer then", fo->fm->ps_name);
+        }
+    }
+    if (is_type1(fo->fm)) {
+        register_fo_entry(fo);
+    } else {
+        write_fontdictionary(pdf, fo);
+    }
+}
+
+static int has_ttf_outlines(fm_entry * fm)
+{
+    FILE *f = fopen(fm->ff_name, "rb");
+    if (f != NULL) {
+        int ch1 = getc(f);
+        int ch2 = getc(f);
+        int ch3 = getc(f);
+        int ch4 = getc(f);
+        fclose(f);
+        if (ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O')
+            return 0;
+        return 1;
+    }
+    return 0;
+}
+
+void do_pdf_font(PDF pdf, internal_font_number f)
+{
+    int del_file = 0;
+    fm_entry *fm;
+    /*tex
+        This is not 100\% true: CID is actually needed whenever (and only) there
+        are more than 256 separate glyphs used. But for now, we just assume the
+        user knows what he is doing. In practice this seems to be the case.
+    */
+    if (!font_has_subset(f))
+        return;
+    if (font_encodingbytes(f) == 2) {
+        /*tex
+            Create a virtual font map entry, as this is needed by the rest of the
+            font inclusion mechanism.
+        */
+        fm = font_map(f) = new_fm_entry();
+        /*tex Set this to a name or whatever, not a real \TFM\ anyway: */
+        fm->tfm_name = font_name(f);
+        /*tex The actual file: */
+        fm->ff_name = font_filename(f);
+        /*tex The true (used) name: */
+        if (font_psname(f) != NULL) {
+            fm->ps_name = font_psname(f);
+        } else {
+            fm->ps_name = font_fullname(f);
+        }
+        if (fm->ff_name
+            && strlen(fm->ff_name) >= 6
+            && strstr(fm->ff_name,".dfont") == (fm->ff_name + strlen(fm->ff_name) - 6)) {
+            /*tex
+
+                In case of a .dfont (an obsolete format), we will extract the
+                correct ttf here, and adjust |fm->ff_name| to point to the
+                temporary file. This file will be deleted later. Todo: keep a
+                nicer name somewhere for the terminal message.
+            */
+            char *s = FindResourceTtfFont(fm->ff_name, fm->ps_name);
+            if (s != NULL) {
+                fm->ff_name = s;
+                del_file = 1;
+            } else {
+                formatted_error("font","file '%s' does not contain font '%s'",fm->ff_name, fm->ps_name);
+            }
+        }
+        /*tex Needed for the CIDSystemInfo: */
+        fm->encname = font_encodingname(f);
+        fm->slant = font_slant(f);
+        set_slantset(fm);
+        fm->extend = font_extend(f);
+        set_extendset(fm);
+        /*tex Flags can perhaps be done better. */
+        fm->fd_flags = 4;
+        set_inuse(fm);
+        switch (font_format(f)) {
+            case opentype_format:
+                if (has_ttf_outlines(fm)) {
+                    set_truetype(fm);
+                } else {
+                    set_opentype(fm);
+                }
+                break;
+            case truetype_format:
+                set_truetype(fm);
+                break;
+            case type1_format:
+                set_type1(fm);
+                break;
+            default:
+                formatted_error("font","file format '%s' for '%s' is incompatible with wide characters",
+                    font_format_name(f), font_name(f));
+        }
+        /*tex This makes \quotation {unknown} default to subsetted inclusion. */
+        if (font_embedding(f) != no_embedding) {
+            set_included(fm);
+            if (font_embedding(f) != full_embedding) {
+                set_subsetted(fm);
+            }
+        }
+        set_cidkeyed(fm);
+        create_cid_fontdictionary(pdf, f);
+        if (del_file)
+            unlink(fm->ff_name);
+    } else {
+        /*tex By now |font_map(f)|, if any, should have been set via |pdf_init_font|. */
+        if ((fm = font_map(f)) == NULL || (fm->ps_name == NULL && fm->ff_name == NULL))
+            writet3(pdf, f);
+        else
+            create_fontdictionary(pdf, f);
+    }
+}
+
+/*tex
+
+    The glyph width is included in |glw_entry|, because that width depends on the
+    value it has in the font where it is actually typeset from, not the font that
+    is the owner of the fd entry.
+
+    It is possible that the user messes with the metric width, but handling that
+    properly would require access to the |hmtx| table at this point in the
+    program.
+
+*/
+
+static int comp_glw_entry(const void *pa, const void *pb, void *p
+    __attribute__ ((unused)))
+{
+    unsigned short i, j;
+    i = (unsigned short) (*(const glw_entry *) pa).id;
+    j = (unsigned short) (*(const glw_entry *) pb).id;
+    cmp_return(i, j);
+    return 0;
+}
+
+static void create_cid_fontdescriptor(fo_entry * fo, internal_font_number f)
+{
+    fo->fd = new_fd_entry(f);
+    preset_fontname(fo, f);
+    preset_fontmetrics(fo->fd, f);
+    /*tex Encoding needed by \TRUETYPE\ writing: */
+    fo->fd->fe = fo->fe;
+    /*tex Map entry needed by \TRUETYPE\ writing */
+    fo->fd->fm = fo->fm;
+    fo->fd->gl_tree = avl_create(comp_glw_entry, NULL, &avl_xallocator);
+    assert(fo->fd->gl_tree != NULL);
+}
+
+
+/*tex
+
+    The values |font_bc()| and |font_ec()| are potentially large character ids,
+    but the strings that are written out use CID indexes, and those are limited
+    to 16-bit values.
+
+*/
+
+static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
+{
+    glw_entry *j;
+    void *aa;
+    int l = font_size(f);
+    int i;
+    for (i = font_bc(f); i <= font_ec(f); i++) {
+        if (quick_char_exists(f, i) && char_used(f, i)) {
+            j = xtalloc(1, glw_entry);
+            j->id = (unsigned) char_index(f, i);
+            j->wd = divide_scaled_n(char_width(f, i), l, 10000.0);
+            if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
+                aa = avl_probe(fo->fd->gl_tree, j);
+                if (aa == NULL) {
+                    /*tex Is this a problem? */
+                }
+            } else {
+                xfree(j);
+            }
+        }
+    }
+}
+
+/*tex
+
+    It is possible to compress the widths array even better, by using the
+    alternate 'range' syntax and possibly even using /DW to set a default value.
+
+    There is a some optimization here already: glyphs that are not used do not
+    appear in the widths array at all.
+
+    We have to make sure that we do not output an (incorrect!) width for a
+    character that exists in the font, but is not used in typesetting. An
+    enormous negative width is used as sentinel value
+
+*/
+
+static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
+{
+    int i, j;
+    glw_entry *glyph;
+    struct avl_traverser t;
+    fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
+    pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
+    avl_t_init(&t, fo->fd->gl_tree);
+    glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree);
+    i = (int) glyph->id;
+    pdf_begin_array(pdf);
+    pdf_add_int(pdf, i);
+    pdf_begin_array(pdf);
+    for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) {
+        j = glyph->wd;
+        if (glyph->id > (unsigned) (i + 1)) {
+            pdf_end_array(pdf);
+            pdf_add_int(pdf, glyph->id);
+            pdf_begin_array(pdf);
+            j = glyph->wd;
+        }
+        pdf_check_space(pdf);
+        if (j < 0) {
+            pdf_out(pdf, '-');
+            j = -j;
+        }
+        pdf_printf(pdf, "%i", (j / 10));
+        if ((j % 10) != 0)
+            pdf_printf(pdf, ".%i", (j % 10));
+        i = (int) glyph->id;
+        pdf_set_space(pdf);
+    }
+    pdf_end_array(pdf);
+    pdf_end_array(pdf);
+    pdf_end_obj(pdf);
+}
+
+static void destroy_glw_cid_entry(void *pa, void *pb)
+{
+    glw_entry *e = (glw_entry *) pa;
+    (void) pb;
+    xfree(e);
+}
+
+
+static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
+{
+    fm_entry *fm = font_map(f);
+    fo_entry *fo = new_fo_entry();
+    /*tex set |fo->first_char| and |fo->last_char| from |f| */
+    get_char_range(fo, f);
+    fo->fm = fm;
+    fo->fo_objnum = pdf_font_num(f);
+    fo->tex_font = f;
+    create_cid_fontdescriptor(fo, f);
+    mark_cid_subset_glyphs(fo, f);
+    if (is_subsetted(fo->fm)) {
+        /*tex
+           This is a bit sneaky. |make_subset_tag()| actually expects the glyph
+           tree to contain strings instead of |glw_entry| items. However, all
+           calculations are done using explicit typecasts, so it works out ok.
+        */
+        make_subset_tag(fo->fd);
+    }
+    write_cid_charwidth_array(pdf, fo);
+    write_fontdescriptor(pdf, fo->fd);
+    write_cid_fontdictionary(pdf, fo, f);
+    if (fo->fd) {
+        if (fo->fd->gl_tree) {
+            avl_destroy(fo->fd->gl_tree,destroy_glw_cid_entry);
+        }
+        xfree(fo->fd);
+    }
+    xfree(fo);
+}
+
+void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
+{
+    int i;
+    fo->tounicode_objnum = write_cid_tounicode(pdf, fo, f);
+    pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_name(pdf, "Type", "Font");
+    pdf_dict_add_name(pdf, "Subtype", "Type0");
+    if (font_identity(f) == vertical_identity) {
+        pdf_dict_add_name(pdf, "Encoding", "Identity-V");
+    } else {
+        pdf_dict_add_name(pdf, "Encoding", "Identity-H");
+    }
+    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+    i = pdf_create_obj(pdf, obj_type_others, 0);
+    pdf_add_name(pdf, "DescendantFonts");
+    pdf_begin_array(pdf);
+    pdf_add_ref(pdf, i);
+    pdf_end_array(pdf);
+    if (fo->tounicode_objnum != 0)
+        pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
+    pdf_end_dict(pdf);
+    pdf_end_obj(pdf);
+    pdf_begin_obj(pdf, i, OBJSTM_ALWAYS);
+    pdf_begin_dict(pdf);
+    pdf_dict_add_name(pdf, "Type", "Font");
+    if (is_opentype(fo->fm) || is_type1(fo->fm)) {
+        pdf_dict_add_name(pdf, "Subtype", "CIDFontType0");
+    } else {
+        pdf_dict_add_name(pdf, "Subtype", "CIDFontType2");
+        pdf_dict_add_name(pdf, "CIDToGIDMap", "Identity");
+    }
+    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
+    pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
+    pdf_dict_add_ref(pdf, "W", (int) fo->cw_objnum);
+    pdf_add_name(pdf, "CIDSystemInfo");
+    pdf_begin_dict(pdf);
+    pdf_dict_add_string(pdf, "Registry", (font_cidregistry(f) ? font_cidregistry(f) : "Adobe"));
+    pdf_dict_add_string(pdf, "Ordering", (font_cidordering(f) ? font_cidordering(f) : "Identity"));
+    pdf_dict_add_int(pdf, "Supplement", (int) font_cidsupplement(f));
+    pdf_end_dict(pdf);
+    /*tex
+        I doubt there is anything useful that could be written here so for now we
+        comment this.
+    */
+    /*
+        if (pdf_font_attr(fo->tex_font) != get_nullstr()) {
+            pdf_out(pdf, '\n');
+            pdf_print(pdf_font_attr(fo->tex_font));
+            pdf_out(pdf, '\n');
+        }
+    */
+    pdf_end_dict(pdf);
+    pdf_end_obj(pdf);
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writefont.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writefont.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writefont.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1116 +0,0 @@
-% writefont.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f);
-static void create_cid_fontdictionary(PDF pdf, internal_font_number f);
-
-const key_entry font_key[FONT_KEYS_NUM] = {
-    { "Ascent", "Ascender", 1 },
-    { "CapHeight", "CapHeight", 1 },
-    { "Descent", "Descender", 1 },
-    { "ItalicAngle", "ItalicAngle", 1 },
-    { "StemV", "StdVW", 1 },
-    { "XHeight", "XHeight", 1 },
-    { "FontBBox", "FontBBox", 1 },
-    { "", "", 0 },
-    { "", "", 0 },
-    { "", "", 0 },
-    { "FontName", "FontName", 1 }
-};
-
-@
- at c
-struct avl_table *fo_tree = NULL; /* tree of font dictionaries */
-struct avl_table *fd_tree = NULL; /* tree of font descriptor objects */
-
-static int comp_fo_entry(const void *pa, const void *pb, void *p)
-{
-    (void) p;
-    return strcmp(((const fo_entry *) pa)->fm->tfm_name,
-                  ((const fo_entry *) pb)->fm->tfm_name);
-}
-
-static int comp_fd_entry(const void *pa, const void *pb, void *p)
-{
-    const fd_entry *p1 = (const fd_entry *) pa, *p2 = (const fd_entry *) pb;
-    (void) p;
-    assert(p1->fm != NULL && is_fontfile(p1->fm) &&
-           p2->fm != NULL && is_fontfile(p2->fm));
-    return strcmp(p1->fm->ff_name, p2->fm->ff_name);
-}
-
-@ initialize data structure for /Type /Font
- at c
-static fo_entry *new_fo_entry(void)
-{
-    fo_entry *fo;
-    fo = xtalloc(1, fo_entry);
-    fo->fo_objnum = 0;
-    fo->tex_font = 0;
-    fo->fm = NULL;
-    fo->fd = NULL;
-    fo->fe = NULL;
-    fo->cw_objnum = 0;
-    fo->first_char = 1;
-    fo->last_char = 0;
-    fo->tx_tree = NULL;
-    fo->tounicode_objnum = 0;
-    return fo;
-}
-
-@ initialize data structure for /Type /FontDescriptor
- at c
-fd_entry *new_fd_entry(internal_font_number f)
-{
-    fd_entry *fd;
-    int i;
-    fd = xtalloc(1, fd_entry);
-    fd->fd_objnum = 0;
-    fd->fontname = NULL;
-    fd->subset_tag = NULL;
-    fd->ff_found = false;
-    fd->ff_objnum = 0;
-    fd->all_glyphs = false;
-    fd->write_ttf_glyph_names = false;
-    for (i = 0; i < FONT_KEYS_NUM; i++) {
-        fd->font_dim[i].val = 0;
-        fd->font_dim[i].set = false;
-    }
-    fd->fe = NULL;
-    fd->builtin_glyph_names = NULL;
-    fd->fm = NULL;
-    fd->tx_tree = NULL;
-    fd->gl_tree = NULL;
-    fd->tex_font = f;
-    return fd;
-}
-
-@
-Only fallback values of font metrics are taken from the TFM info
-of |f| by |preset_fontmetrics|. During reading of the font file,
-these values are replaced by metrics from the font, if available.
-
- at c
-static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
-{
-    int i;
-    fd->font_dim[ITALIC_ANGLE_CODE].val = 0;
-    fd->font_dim[ASCENT_CODE].val =
-        divide_scaled(char_height(f, 'h'), font_size(f), 3);
-    fd->font_dim[CAPHEIGHT_CODE].val =
-        divide_scaled(char_height(f, 'H'), font_size(f), 3);
-    i = -divide_scaled(char_depth(f, 'y'), font_size(f), 3);
-    fd->font_dim[DESCENT_CODE].val = i < 0 ? i : 0;
-    fd->font_dim[STEMV_CODE].val =
-        divide_scaled(char_width(f, '.') / 3, font_size(f), 3);
-    fd->font_dim[XHEIGHT_CODE].val =
-        divide_scaled(get_x_height(f), font_size(f), 3);
-    fd->font_dim[FONTBBOX1_CODE].val = 0;
-    fd->font_dim[FONTBBOX2_CODE].val = fd->font_dim[DESCENT_CODE].val;
-    fd->font_dim[FONTBBOX3_CODE].val =
-        divide_scaled(get_quad(f), font_size(f), 3);
-    fd->font_dim[FONTBBOX4_CODE].val =
-        fd->font_dim[CAPHEIGHT_CODE].val > fd->font_dim[ASCENT_CODE].val ?
-        fd->font_dim[CAPHEIGHT_CODE].val : fd->font_dim[ASCENT_CODE].val;
-    for (i = 0; i < INT_KEYS_NUM; i++)
-        fd->font_dim[i].set = true;
-}
-
-static void fix_fontmetrics(fd_entry * fd)
-{
-    int i;
-    intparm *p = (intparm *) fd->font_dim;
-    assert(p[FONTBBOX1_CODE].set && p[FONTBBOX2_CODE].set
-           && p[FONTBBOX3_CODE].set && p[FONTBBOX4_CODE].set);
-    /* make sure there is a rectangle */
-    if (p[FONTBBOX3_CODE].val < p[FONTBBOX1_CODE].val) {
-        i = p[FONTBBOX3_CODE].val;
-        p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val;
-        p[FONTBBOX1_CODE].val = i;
-    } else if (p[FONTBBOX3_CODE].val == p[FONTBBOX1_CODE].val)
-        p[FONTBBOX3_CODE].val = p[FONTBBOX1_CODE].val + 1;
-    if (p[FONTBBOX4_CODE].val < p[FONTBBOX2_CODE].val) {
-        i = p[FONTBBOX4_CODE].val;
-        p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val;
-        p[FONTBBOX2_CODE].val = i;
-    } else if (p[FONTBBOX4_CODE].val == p[FONTBBOX2_CODE].val)
-        p[FONTBBOX4_CODE].val = p[FONTBBOX2_CODE].val + 1;
-    if (!p[ASCENT_CODE].set) {
-        p[ASCENT_CODE].val = p[FONTBBOX4_CODE].val;
-        p[ASCENT_CODE].set = true;
-    }
-    if (!p[DESCENT_CODE].set) {
-        p[DESCENT_CODE].val = p[FONTBBOX2_CODE].val;
-        p[DESCENT_CODE].set = true;
-    }
-    if (!p[CAPHEIGHT_CODE].set) {
-        p[CAPHEIGHT_CODE].val = p[FONTBBOX4_CODE].val;
-        p[CAPHEIGHT_CODE].set = true;
-    }
-}
-
-static void write_fontmetrics(PDF pdf, fd_entry * fd)
-{
-    int i;
-    fix_fontmetrics(fd);
-    pdf_add_name(pdf, font_key[FONTBBOX1_CODE].pdfname);
-    pdf_begin_array(pdf);
-    pdf_printf(pdf, "%i %i %i %i", (int) fd->font_dim[FONTBBOX1_CODE].val,
-               (int) fd->font_dim[FONTBBOX2_CODE].val,
-               (int) fd->font_dim[FONTBBOX3_CODE].val,
-               (int) fd->font_dim[FONTBBOX4_CODE].val);
-    pdf_end_array(pdf);
-    for (i = 0; i < GEN_KEY_NUM; i++)
-        if (fd->font_dim[i].set)
-            pdf_dict_add_int(pdf, font_key[i].pdfname, fd->font_dim[i].val);
-}
-
-@
- at c
-static void preset_fontname(fo_entry * fo, internal_font_number f)
-{
-    if (fo->fm->ps_name != NULL)
-        fo->fd->fontname = xstrdup(fo->fm->ps_name);    /* just fallback */
-    else if (font_fullname(f) != NULL)
-        fo->fd->fontname = xstrdup(font_fullname(f));
-    else
-        fo->fd->fontname = xstrdup(fo->fm->tfm_name);
-}
-
-static void pdf_dict_add_fontname(PDF pdf, const char *key, fd_entry * fd)
-{
-    char *s;
-    size_t l1 = 0, l2;
-    assert(fd->fontname != NULL);
-    assert(key != NULL);
-    if (fd->subset_tag != NULL)
-        l1 = strlen(fd->subset_tag);
-    l2 = strlen(fd->fontname);
-    s = xmalloc(l1 + l2 + 2);
-    if (l1 > 0)
-        snprintf(s, l1 + l2 + 2, "%s+%s", fd->subset_tag, fd->fontname);
-    else
-        snprintf(s, l2 + 1, "%s", fd->fontname);
-    pdf_dict_add_name(pdf, key, s);
-    xfree(s);
-}
-
-@
- at c
-fd_entry *lookup_fd_entry(char *s)
-{
-    fd_entry fd;
-    fm_entry fm;
-    assert(s != NULL);
-    fm.ff_name = s;
-    fd.fm = &fm;
-    if (fd_tree == NULL) {
-        fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
-        assert(fd_tree != NULL);
-    }
-    return (fd_entry *) avl_find(fd_tree, &fd);
-}
-
-static fd_entry *lookup_fontdescriptor(fo_entry * fo)
-{
-    assert(fo != NULL);
-    assert(fo->fm != NULL);
-    assert(is_fontfile(fo->fm));
-    return lookup_fd_entry(fo->fm->ff_name);
-}
-
-void register_fd_entry(fd_entry * fd)
-{
-    void **aa;
-    if (fd_tree == NULL) {
-        fd_tree = avl_create(comp_fd_entry, NULL, &avl_xallocator);
-        assert(fd_tree != NULL);
-    }
-    assert(fd != NULL && fd->fm != NULL && is_fontfile(fd->fm));
-    /* font descriptor not yet registered: */
-    assert(lookup_fd_entry(fd->fm->ff_name) == NULL);
-    aa = avl_probe(fd_tree, fd);
-    assert(aa != NULL);
-}
-
-static void create_fontdescriptor(fo_entry * fo, internal_font_number f)
-{
-    assert(fo != NULL);
-    assert(fo->fm != NULL);
-    assert(fo->fd == NULL);
-    fo->fd = new_fd_entry(f);
-    preset_fontname(fo, f);
-    preset_fontmetrics(fo->fd, f);
-    /* encoding needed by TrueType writing: */
-    fo->fd->fe = fo->fe;
-    /* map entry needed by TrueType writing: */
-    fo->fd->fm = fo->fm;
-    fo->fd->gl_tree = avl_create(comp_string_entry, NULL, &avl_xallocator);
-    assert(fo->fd->gl_tree != NULL);
-}
-
-@
-For all used characters of \TeX font |f|, get corresponding glyph names
-from external reencoding (.enc) file and collect these in the glyph
-tree |gl_tree| of font descriptor |fd| referenced by font dictionary |fo|.
-
- at c
-static void mark_reenc_glyphs(fo_entry * fo, internal_font_number f)
-{
-    int i;
-    char **g;
-    void **aa;
-    assert(fo->fe != NULL);
-    if (is_subsetted(fo->fm)) {
-        assert(is_included(fo->fm));
-        /* mark glyphs from TeX (externally reencoded characters) */
-        g = fo->fe->glyph_names;
-        for (i = fo->first_char; i <= fo->last_char; i++) {
-            if (pdf_char_marked(f, i)
-                && g[i] != notdef
-                && (char *) avl_find(fo->fd->gl_tree, g[i]) == NULL) {
-                aa = avl_probe(fo->fd->gl_tree, xstrdup(g[i]));
-                assert(aa != NULL);
-            }
-        }
-    }
-}
-
-@
-Function |mark_chars| has 2 uses:
-\item 1. Mark characters as chars on \TeX\ level.
-\item 2. Mark encoding pairs used by \TeX\ to optimize encoding vector.
-
- at c
-static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree,
-     internal_font_number f)
-{
-    int i, *j;
-    void **aa;
-    if (tx_tree == NULL) {
-        tx_tree = avl_create(comp_int_entry, NULL, &avl_xallocator);
-        assert(tx_tree != NULL);
-    }
-    for (i = fo->first_char; i <= fo->last_char; i++) {
-        if (pdf_char_marked(f, i) && (int *) avl_find(tx_tree, &i) == NULL) {
-            j = xtalloc(1, int);
-            *j = i;
-            aa = avl_probe(tx_tree, j);
-            assert(aa != NULL);
-        }
-    }
-    return tx_tree;
-}
-
-@
- at c
-static void get_char_range(fo_entry * fo, internal_font_number f)
-{
-    int i;
-    assert(fo != NULL);
-    /* search for |first_char| and |last_char| */
-    for (i = font_bc(f); i <= font_ec(f); i++)
-        if (pdf_char_marked(f, i))
-            break;
-    fo->first_char = i;
-    for (i = font_ec(f); i >= font_bc(f); i--)
-        if (pdf_char_marked(f, i))
-            break;
-    fo->last_char = i;
-    if ((fo->first_char > fo->last_char) || !pdf_char_marked(f, fo->first_char)) {
-        /* no character used from this font */
-        fo->last_char = 0;
-        fo->first_char = fo->last_char + 1;
-    }
-}
-
-static int font_has_subset(internal_font_number f)
-{
-    int i, s;
-    /* search for |first_char| and |last_char| */
-    for (i = font_bc(f); i <= font_ec(f); i++)
-        if (pdf_char_marked(f, i))
-            break;
-    s = i;
-    for (i = font_ec(f); i >= font_bc(f); i--)
-        if (pdf_char_marked(f, i))
-            break;
-    if (s > i)
-        return 0;
-    else
-        return 1;
-}
-
-@
- at c
-static void write_charwidth_array(PDF pdf, fo_entry * fo, internal_font_number f)
-{
-    int i, j, *ip, *fip;
-    struct avl_traverser t;
-    assert(fo->tx_tree != NULL);
-    assert(fo->cw_objnum == 0);
-    fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
-    avl_t_init(&t, fo->tx_tree);
-    fip = (int *) avl_t_first(&t, fo->tx_tree);
-    assert(fip != NULL);
-    pdf_begin_array(pdf);
-    for (ip = fip, j = *ip; ip != NULL; ip = (int *) avl_t_next(&t)) {
-        if (ip != fip)
-            pdf_out(pdf, ' ');
-        i = *ip;
-        while (j < i - 1) {
-            pdf_puts(pdf, "0 ");
-            j++;
-        }
-        j = i;
-        pdf_print_charwidth(pdf, f, i);
-    }
-    pdf_end_array(pdf);
-    pdf_end_obj(pdf);
-}
-
-@ Remark: Font objects from embedded PDF files are never registered
-into |fo_tree|; they are individually written out.
- at c
-static fo_entry *lookup_fo_entry(char *s)
-{
-    fo_entry fo;
-    fm_entry fm;
-    assert(s != NULL);
-    fm.tfm_name = s;
-    fo.fm = &fm;
-    if (fo_tree == NULL) {
-        fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
-        assert(fo_tree != NULL);
-    }
-    return (fo_entry *) avl_find(fo_tree, &fo);
-}
-
-static void register_fo_entry(fo_entry * fo)
-{
-    void **aa;
-    if (fo_tree == NULL) {
-        fo_tree = avl_create(comp_fo_entry, NULL, &avl_xallocator);
-        assert(fo_tree != NULL);
-    }
-    assert(fo != NULL);
-    assert(fo->fm != NULL);
-    assert(fo->fm->tfm_name != NULL);
-    assert(lookup_fo_entry(fo->fm->tfm_name) == NULL);
-    aa = avl_probe(fo_tree, fo);
-    assert(aa != NULL);
-}
-
-@
-In principle we could replace the pdftex derived ttf.otf inclusion part
-by using the regular code for this and assigning indices and tounicodes
-to the character blobs, but for the moment we keep the current approach.
- at c
-static void write_fontfile(PDF pdf, fd_entry * fd)
-{
-    assert(is_included(fd->fm));
-    if (is_cidkeyed(fd->fm)) {
-        if (is_opentype(fd->fm)) {
-            writetype0(pdf, fd);
-	} else if (is_truetype(fd->fm)) {
-            if (!writetype2(pdf, fd)) {
-                writetype0(pdf,fd);
-	        fd->fm->type |= F_OTF; fd->fm->type ^= F_TRUETYPE;
-            }
-	} else if (is_type1(fd->fm))
-	    writetype1w(pdf, fd);
-	else
-	    assert(0);
-    } else {
-	if (is_type1(fd->fm))
-	    writet1(pdf, fd);
-        else if (is_truetype(fd->fm))
-            writettf(pdf, fd);
-        else if (is_opentype(fd->fm))
-            writeotf(pdf, fd);
-        else
-            assert(0);
-    }
-    if (!fd->ff_found)
-        return;
-    assert(fd->ff_objnum == 0);
-    fd->ff_objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, fd->ff_objnum, OBJSTM_NEVER); /* font file stream */
-    pdf_begin_dict(pdf);
-    if (is_cidkeyed(fd->fm)) {
-        /* No subtype is used for TrueType-based OpenType fonts */
-        if (is_opentype(fd->fm) || is_type1(fd->fm))
-            pdf_dict_add_name(pdf, "Subtype", "CIDFontType0C");
-#if 0
-        else
-            pdf_dict_add_name(pdf, "Subtype", "OpenType");
-#endif
-    } else if (is_type1(fd->fm)) {
-        pdf_dict_add_int(pdf, "Length1", (int) t1_length1);
-        pdf_dict_add_int(pdf, "Length2", (int) t1_length2);
-        pdf_dict_add_int(pdf, "Length3", (int) t1_length3);
-    } else if (is_truetype(fd->fm)) {
-        pdf_dict_add_int(pdf, "Length1", (int) ttf_length);
-    } else if (is_opentype(fd->fm)) {
-        pdf_dict_add_name(pdf, "Subtype", "Type1C");
-    } else {
-        assert(0); /* todo: error messages */
-    }
-    pdf_dict_add_streaminfo(pdf);
-    pdf_end_dict(pdf);
-    pdf_begin_stream(pdf);
-    strbuf_flush(pdf, pdf->fb);
-    pdf_end_stream(pdf);
-    pdf_end_obj(pdf);
-}
-
-@
- at c
-int cidset = 0;
-static void write_fontdescriptor(PDF pdf, fd_entry * fd)
-{
-    static const int std_flags[] = {
-        /*
-            The indices for << start with 0, but bits start with 1, so the
-            numbers for << are 1 lower than the bits in table 5.20.
-        */
-        /* *INDENT-OFF* */
-        1 + 2 + (1 << 5),                        /* Courier */
-        1 + 2 + (1 << 5)            + (1 << 18), /* Courier-Bold */
-        1 + 2 + (1 << 5) + (1 << 6),             /* Courier-Oblique */
-        1 + 2 + (1 << 5) + (1 << 6) + (1 << 18), /* Courier-BoldOblique */
-                (1 << 5),                        /* Helvetica */
-                (1 << 5)            + (1 << 18), /* Helvetica-Bold */
-                (1 << 5) + (1 << 6),             /* Helvetica-Oblique */
-                (1 << 5) + (1 << 6) + (1 << 18), /* Helvetica-BoldOblique */
-              4,                                 /* Symbol */
-            2 + (1 << 5),                        /* Times-Roman */
-            2 + (1 << 5)            + (1 << 18), /* Times-Bold */
-            2 + (1 << 5) + (1 << 6),             /* Times-Italic */
-            2 + (1 << 5) + (1 << 6) + (1 << 18), /* Times-BoldItalic */
-              4                                  /* ZapfDingbats */
-        /* *INDENT-ON* */
-    };
-    char *glyph;
-    struct avl_traverser t;
-    int fd_flags;
-    assert(fd != NULL && fd->fm != NULL);
-    cidset = 0; /* possibly updated by |write_fontfile| */
-    if (is_fontfile(fd->fm) && is_included(fd->fm)) {
-        /* this will set |fd->ff_found| if font file is found */
-        write_fontfile(pdf, fd);
-    }
-    if (fd->fd_objnum == 0)
-        fd->fd_objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, fd->fd_objnum, OBJSTM_ALWAYS);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_name(pdf, "Type", "FontDescriptor");
-    pdf_dict_add_fontname(pdf, "FontName", fd);
-    if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE)
-        fd_flags = (int) fd->fm->fd_flags;
-    else if (fd->ff_found)
-        fd_flags = FD_FLAGS_DEFAULT_EMBED;
-    else {
-        fd_flags = is_std_t1font(fd->fm)
-            ? std_flags[check_std_t1font(fd->fm->ps_name)]
-            : FD_FLAGS_DEFAULT_NON_EMBED;
-        formatted_warning("map file",
-             "No flags specified for non-embedded font '%s' (%s), I'm using %i, fix your map entry",
-             fd->fm->ps_name != NULL ? fd->fm->ps_name : "No name given",
-             fd->fm->tfm_name, fd_flags);
-    }
-    pdf_dict_add_int(pdf, "Flags", fd_flags);
-    write_fontmetrics(pdf, fd);
-    if (fd->ff_found) {
-        if (is_cidkeyed(fd->fm)) {
-            if (is_type1(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
-            else if (is_truetype(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
-            else if (is_opentype(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
-            else
-                assert(0);
-        } else {
-            if (is_subsetted(fd->fm) && is_type1(fd->fm)) {
-                /* /CharSet is optional; names may appear in any order */
-                assert(fd->gl_tree != NULL);
-                avl_t_init(&t, fd->gl_tree);
-                pdf_add_name(pdf, "CharSet");
-                pdf_out(pdf, '(');
-                for (glyph = (char *) avl_t_first(&t, fd->gl_tree);
-                     glyph != NULL; glyph = (char *) avl_t_next(&t))
-                    pdf_add_name(pdf, glyph);
-                pdf_out(pdf, ')');
-                pdf->cave = 0;
-            }
-            if (is_type1(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile", (int) fd->ff_objnum);
-            else if (is_truetype(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile2", (int) fd->ff_objnum);
-            else if (is_opentype(fd->fm))
-                pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
-            else
-                assert(0);
-        }
-    }
-    if ((! pdf->omit_cidset) && (pdf->major_version == 1) && (cidset != 0) ) {
-        pdf_dict_add_ref(pdf, "CIDSet", cidset);
-    }
-    /*
-        Currently we don't export the optional keys for CID fonts like
-        \.{/Style << /Panose <12-byte string> >>} and we probably never
-        will.
-    */
-    pdf_end_dict(pdf);
-    pdf_end_obj(pdf);
-}
-
-static void write_fontdescriptors(PDF pdf)
-{
-    fd_entry *fd;
-    struct avl_traverser t;
-    if (fd_tree == NULL)
-        return;
-    avl_t_init(&t, fd_tree);
-    for (fd = (fd_entry *) avl_t_first(&t, fd_tree); fd != NULL; fd = (fd_entry *) avl_t_next(&t))
-        write_fontdescriptor(pdf, fd);
-}
-
-@
- at c
-static void write_fontdictionary(PDF pdf, fo_entry * fo)
-{
-    assert(fo != NULL);
-    assert(fo->fm != NULL);
-    /* reserved as |pdf_font_num(f)| elsewhere: */
-    assert(fo->fo_objnum != 0);
-
-    /* write ToUnicode entry if needed */
-    if (pdf->gen_tounicode > 0 && fo->fd != NULL) {
-        if (fo->fe != NULL) {
-            fo->tounicode_objnum = write_tounicode(pdf, fo->fe->glyph_names, fo->fe->name);
-        } else if (is_type1(fo->fm)) {
-            assert(fo->fd->builtin_glyph_names != NULL);
-            fo->tounicode_objnum = write_tounicode(pdf, fo->fd->builtin_glyph_names, fo->fm->tfm_name);
-        }
-    }
-    pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_name(pdf, "Type", "Font");
-    if (is_type1(fo->fm))
-        pdf_dict_add_name(pdf, "Subtype", "Type1");
-    else if (is_truetype(fo->fm))
-        pdf_dict_add_name(pdf, "Subtype", "TrueType");
-    else if (is_opentype(fo->fm))
-        pdf_dict_add_name(pdf, "Subtype", "Type1");
-    else
-        assert(0);
-    assert(fo->fd != NULL && fo->fd->fd_objnum != 0);
-    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
-    pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
-    assert(fo->cw_objnum != 0);
-    pdf_dict_add_int(pdf, "FirstChar", (int) fo->first_char);
-    pdf_dict_add_int(pdf, "LastChar", (int) fo->last_char);
-    pdf_dict_add_ref(pdf, "Widths", (int) fo->cw_objnum);
-    if ((is_type1(fo->fm) || is_opentype(fo->fm)) && fo->fe != NULL && fo->fe->fe_objnum != 0)
-        pdf_dict_add_ref(pdf, "Encoding", (int) fo->fe->fe_objnum);
-    if (fo->tounicode_objnum != 0)
-        pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
-    if (pdf_font_attr(fo->tex_font) != get_nullstr() && pdf_font_attr(fo->tex_font) != 0) {
-        pdf_print(pdf, pdf_font_attr(fo->tex_font));
-        pdf_out(pdf, '\n');
-    }
-    pdf_end_dict(pdf);
-    pdf_end_obj(pdf);
-}
-
-static void write_fontdictionaries(PDF pdf)
-{
-    fo_entry *fo;
-    struct avl_traverser t;
-    if (fo_tree == NULL)
-        return;
-    avl_t_init(&t, fo_tree);
-    for (fo = (fo_entry *) avl_t_first(&t, fo_tree); fo != NULL; fo = (fo_entry *) avl_t_next(&t))
-        write_fontdictionary(pdf, fo);
-}
-
-@ Final flush of all font related stuff by call from \.{Output fonts
-definitions} elsewhere
- at c
-void write_fontstuff(PDF pdf)
-{
-    write_fontdescriptors(pdf);
-    write_fontencodings(pdf);   /* see \.{writeenc.w} */
-    write_fontdictionaries(pdf);
-}
-
-@
- at c
-static void create_fontdictionary(PDF pdf, internal_font_number f)
-{
-    fo_entry *fo = new_fo_entry();
-    fm_entry *fm = font_map(f);
-    /* set |fo->first_char| and |fo->last_char| from |f| */
-    get_char_range(fo, f);
-    if (fo->last_char > 255)
-        fo->last_char = 255;
-    assert(fo->last_char >= fo->first_char);
-    fo->fm = fm;
-    fo->fo_objnum = pdf_font_num(f);
-    fo->tex_font = f;
-    if (is_reencoded(fo->fm)) {
-        /*
-            At least the map entry tells so but it returns |NULL| if the .enc
-            file couldn't be opened.
-        */
-        fo->fe = get_fe_entry(fo->fm->encname);
-        if (fo->fe != NULL && (is_type1(fo->fm) || is_opentype(fo->fm))) {
-            /* We don't end up here for truetype fonts. */
-            if (fo->fe->fe_objnum == 0)
-                fo->fe->fe_objnum = pdf_create_obj(pdf, obj_type_others, 0);    /* then it will be written out */
-            /* Mark encoding pairs used by TeX to optimize encoding vector. */
-            fo->fe->tx_tree = mark_chars(fo, fo->fe->tx_tree, f);
-        }
-    }
-    /* for |write_charwidth_array|: */
-    fo->tx_tree = mark_chars(fo, fo->tx_tree, f);
-    write_charwidth_array(pdf, fo, f);
-    if (!is_builtin(fo->fm)) {
-        if (is_type1(fo->fm)) {
-            if ((fo->fd = lookup_fontdescriptor(fo)) == NULL) {
-                create_fontdescriptor(fo, f);
-                register_fd_entry(fo->fd);
-            }
-        } else {
-            create_fontdescriptor(fo, f);
-        }
-        if (fo->fe != NULL) {
-            mark_reenc_glyphs(fo, f);
-            if (!is_type1(fo->fm)) {
-                /* mark reencoded characters as chars on TeX level */
-                assert(fo->fd->tx_tree == NULL);
-                fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
-                if (is_truetype(fo->fm)) {
-                    fo->fd->write_ttf_glyph_names = true;
-                }
-            }
-        } else {
-            /* mark non-reencoded characters as chars on TeX level */
-            fo->fd->tx_tree = mark_chars(fo, fo->fd->tx_tree, f);
-        }
-        if (!is_type1(fo->fm)) {
-            write_fontdescriptor(pdf, fo->fd);
-        }
-    } else {
-        /*
-            Builtin fonts still need the /Widths array and /FontDescriptor
-            (to avoid error 'font FOO contains bad /BBox').
-        */
-        create_fontdescriptor(fo, f);
-        write_fontdescriptor(pdf, fo->fd);
-        if (!is_std_t1font(fo->fm)) {
-            formatted_warning("map file", "font '%s' is not a standard font; I suppose it is available to your PDF viewer then", fo->fm->ps_name);
-        }
-    }
-    if (is_type1(fo->fm)) {
-        register_fo_entry(fo);
-    } else {
-        write_fontdictionary(pdf, fo);
-    }
-}
-
-@
- at c
-static int has_ttf_outlines(fm_entry * fm)
-{
-    FILE *f = fopen(fm->ff_name, "rb");
-    if (f != NULL) {
-        int ch1 = getc(f);
-        int ch2 = getc(f);
-        int ch3 = getc(f);
-        int ch4 = getc(f);
-        fclose(f);
-        if (ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O')
-            return 0;
-        return 1;
-    }
-    return 0;
-}
-
-void do_pdf_font(PDF pdf, internal_font_number f)
-{
-    int del_file = 0;
-    fm_entry *fm;
-    /*
-        This is not 100\% true: CID is actually needed whenever (and
-        only) there are more than 256 separate glyphs used. But for
-        now, we just assume the user knows what he is doing. In practice
-        this seems to be the case.
-    */
-    if (!font_has_subset(f))
-        return;
-
-    if (font_encodingbytes(f) == 2) {
-        /*
-            Create a virtual font map entry, as this is needed by the
-            rest of the font inclusion mechanism.
-        */
-        fm = font_map(f) = new_fm_entry();
-        fm->tfm_name = font_name(f);    /* or whatever, not a real tfm */
-        fm->ff_name = font_filename(f); /* the actual file */
-        if (font_psname(f) != NULL)
-            fm->ps_name = font_psname(f);   /* the true name */
-        else
-            fm->ps_name = font_fullname(f); /* the true name */
-        if (fm->ff_name
-            && strlen(fm->ff_name) >= 6
-            && strstr(fm->ff_name,".dfont") == (fm->ff_name + strlen(fm->ff_name) - 6)) {
-            /*
-                In case of a .dfont, we will extract the correct ttf here,
-                and adjust |fm->ff_name| to point to the temporary file.
-                This file will be deleted later. Todo: keep a nicer name
-                somewhere for the terminal message.
-
-                Support for dfonts will be removed at some point anyhow.
-             */
-            char *s = FindResourceTtfFont(fm->ff_name, fm->ps_name);
-            if (s != NULL) {
-                fm->ff_name = s;
-                del_file = 1;
-            } else {
-                formatted_error("font","file '%s' does not contain font '%s'",fm->ff_name, fm->ps_name);
-            }
-        }
-        /* Needed for the CIDSystemInfo: */
-        fm->encname = font_encodingname(f);
-        fm->slant = font_slant(f);
-        set_slantset(fm);
-        fm->extend = font_extend(f);
-        set_extendset(fm);
-        /* Flags can perhaps be done better. */
-        fm->fd_flags = 4;
-        set_inuse(fm);
-
-        switch (font_format(f)) {
-        case opentype_format:
-            if (has_ttf_outlines(fm)) {
-                set_truetype(fm);
-            } else {
-                set_opentype(fm);
-            }
-            break;
-        case truetype_format:
-            set_truetype(fm);
-            break;
-        case type1_format:
-            set_type1(fm);
-            break;
-        default:
-            formatted_error("font","file format '%s' for '%s' is incompatible with wide characters",
-                font_format_name(f), font_name(f));
-        }
-        /* This makes "unknown" default to subsetted inclusion */
-        if (font_embedding(f) != no_embedding) {
-            set_included(fm);
-            if (font_embedding(f) != full_embedding) {
-                set_subsetted(fm);
-            }
-        }
-        set_cidkeyed(fm);
-        create_cid_fontdictionary(pdf, f);
-
-        if (del_file)
-            unlink(fm->ff_name);
-
-    } else {
-        /*
-            By now |font_map(f)|, if any, should have been set via
-            |pdf_init_font()|.
-        */
-        if ((fm = font_map(f)) == NULL
-            || (fm->ps_name == NULL && fm->ff_name == NULL))
-            writet3(pdf, f);
-        else
-            create_fontdictionary(pdf, f);
-    }
-}
-
-@ The glyph width is included in |glw_entry|, because that width
-depends on the value it has in the font where it is actually
-typeset from, not the font that is the 'owner' of the fd entry.
-
-TODO: It is possible that the user messes with the metric width,
-but handling that properly would require access to the 'hmtx' table
-at this point in the program.
-
- at c
-static int comp_glw_entry(const void *pa, const void *pb, void *p
-                   __attribute__ ((unused)))
-{
-    unsigned short i, j;
-
-    i = (unsigned short) (*(const glw_entry *) pa).id;
-    j = (unsigned short) (*(const glw_entry *) pb).id;
-    cmp_return(i, j);
-    return 0;
-}
-
-static void create_cid_fontdescriptor(fo_entry * fo, internal_font_number f)
-{
-    assert(fo != NULL);
-    assert(fo->fm != NULL);
-    assert(fo->fd == NULL);
-    fo->fd = new_fd_entry(f);
-    preset_fontname(fo, f);
-    preset_fontmetrics(fo->fd, f);
-    fo->fd->fe = fo->fe; /* encoding needed by TrueType writing */
-    fo->fd->fm = fo->fm; /* map entry needed by TrueType writing */
-    fo->fd->gl_tree = avl_create(comp_glw_entry, NULL, &avl_xallocator);
-    assert(fo->fd->gl_tree != NULL);
-}
-
-
-@ The values |font_bc()| and |font_ec()| are potentially large character
-ids, but the strings that are written out use CID indexes, and those are
-limited to 16-bit values.
-
- at c
-/*
-    This is old code ... it fails when the order of using the same font at
-    different extends changes. Probably because widths get overwritten or
-    set wrong. The loop also looks kind of weird (why a loop).
-*/
-
-/*
-static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
-{
-    int i, k, l;
-    glw_entry *j;
-    void *aa;
-    for (k = 1; k <= max_font_id(); k++) {
-        if (k == f || -f == pdf_font_num(k)) {
-            l = font_size(k);
-            for (i = font_bc(k); i <= font_ec(k); i++) {
-                if (quick_char_exists(k, i) && char_used(k, i)) {
-                    j = xtalloc(1, glw_entry);
-                    j->id = (unsigned) char_index(k, i);
-                    j->wd = divide_scaled_n(char_width(k, i), l, 10000.0);
-                    if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
-                        aa = avl_probe(fo->fd->gl_tree, j);
-                        assert(aa != NULL);
-                    } else {
-                        xfree(j);
-                    }
-                }
-            }
-        }
-    }
-}
-*/
-
-/*
-    So, let's try the following.
-*/
-
-static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
-{
-    glw_entry *j;
-    void *aa;
-    int l = font_size(f);
-    int i;
-    for (i = font_bc(f); i <= font_ec(f); i++) {
-        if (quick_char_exists(f, i) && char_used(f, i)) {
-            j = xtalloc(1, glw_entry);
-            j->id = (unsigned) char_index(f, i);
-            j->wd = divide_scaled_n(char_width(f, i), l, 10000.0);
-            if ((glw_entry *) avl_find(fo->fd->gl_tree, j) == NULL) {
-                aa = avl_probe(fo->fd->gl_tree, j);
-                assert(aa != NULL);
-            } else {
-                xfree(j);
-            }
-        }
-    }
-}
-
-@ It is possible to compress the widths array even better, by using the
-alternate 'range' syntax and possibly even using /DW to set a default
-value.
-
-There is a some optimization here already: glyphs that are not used do
-not appear in the widths array at all.
-
-We have to make sure that we do not output an (incorrect!) width for a
-character that exists in the font, but is not used in typesetting. An
-enormous negative width is used as sentinel value
-
- at c
-static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
-{
-    int i, j;
-    glw_entry *glyph;
-    struct avl_traverser t;
-
-    assert(fo->cw_objnum == 0);
-    fo->cw_objnum = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_begin_obj(pdf, fo->cw_objnum, OBJSTM_ALWAYS);
-    avl_t_init(&t, fo->fd->gl_tree);
-    glyph = (glw_entry *) avl_t_first(&t, fo->fd->gl_tree);
-    assert(glyph != NULL);
-    i = (int) glyph->id;
-    pdf_begin_array(pdf);
-    pdf_add_int(pdf, i);
-    pdf_begin_array(pdf);
-    for (; glyph != NULL; glyph = (glw_entry *) avl_t_next(&t)) {
-        j = glyph->wd;
-        if (glyph->id > (unsigned) (i + 1)) {
-            pdf_end_array(pdf);
-            pdf_add_int(pdf, glyph->id);
-            pdf_begin_array(pdf);
-            j = glyph->wd;
-        }
-        if (glyph->id == (unsigned) (i + 1))
-            pdf_out(pdf, ' ');
-
-        if (j < 0) {
-            pdf_out(pdf, '-');
-            j = -j;
-        }
-
-        pdf_printf(pdf, "%i", (j / 10));
-        if ((j % 10) != 0)
-            pdf_printf(pdf, ".%i", (j % 10));
-
-        i = (int) glyph->id;
-    }
-    pdf_end_array(pdf);
-    pdf_end_array(pdf);
-    pdf_end_obj(pdf);
-}
-
-static void destroy_glw_cid_entry(void *pa, void *pb)
-{
-    glw_entry *e = (glw_entry *) pa;
-    (void) pb;
-    xfree(e);
-}
-
-
-static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
-{
-    fm_entry *fm = font_map(f);
-    fo_entry *fo = new_fo_entry();
-    get_char_range(fo, f);      /* set |fo->first_char| and |fo->last_char| from |f| */
-    assert(fo->last_char >= fo->first_char);
-    fo->fm = fm;
-    fo->fo_objnum = pdf_font_num(f);
-    fo->tex_font = f;
-    create_cid_fontdescriptor(fo, f);
-    mark_cid_subset_glyphs(fo, f);
-    if (is_subsetted(fo->fm)) {
-        /*
-           This is a bit sneaky. |make_subset_tag()| actually expects the glyph
-           tree to contain strings instead of |glw_entry| items. However, all
-           calculations are done using explicit typecasts, so it works out ok.
-        */
-        make_subset_tag(fo->fd);
-    }
-    write_cid_charwidth_array(pdf, fo);
-    write_fontdescriptor(pdf, fo->fd);
-
-    write_cid_fontdictionary(pdf, fo, f);
-    if (fo->fd) {
-      if (fo->fd->gl_tree){
-	avl_destroy(fo->fd->gl_tree,destroy_glw_cid_entry);
-      }
-      xfree(fo->fd);
-    }
-    xfree(fo);
-}
-
-@ @c
-void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
-{
-    int i;
-
-    fo->tounicode_objnum = write_cid_tounicode(pdf, fo, f);
-
-    pdf_begin_obj(pdf, fo->fo_objnum, OBJSTM_ALWAYS);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_name(pdf, "Type", "Font");
-    pdf_dict_add_name(pdf, "Subtype", "Type0");
-    if (font_identity(f) == vertical_identity) {
-        pdf_dict_add_name(pdf, "Encoding", "Identity-V");
-    } else {
-        pdf_dict_add_name(pdf, "Encoding", "Identity-H");
-    }
-    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
-    i = pdf_create_obj(pdf, obj_type_others, 0);
-    pdf_add_name(pdf, "DescendantFonts");
-    pdf_begin_array(pdf);
-    pdf_add_ref(pdf, i);
-    pdf_end_array(pdf);
-    /* todo: the ToUnicode CMap */
-    if (fo->tounicode_objnum != 0)
-        pdf_dict_add_ref(pdf, "ToUnicode", (int) fo->tounicode_objnum);
-    pdf_end_dict(pdf);
-    pdf_end_obj(pdf);
-
-    pdf_begin_obj(pdf, i, OBJSTM_ALWAYS);
-    pdf_begin_dict(pdf);
-    pdf_dict_add_name(pdf, "Type", "Font");
-    if (is_opentype(fo->fm) || is_type1(fo->fm)) {
-        pdf_dict_add_name(pdf, "Subtype", "CIDFontType0");
-    } else {
-        pdf_dict_add_name(pdf, "Subtype", "CIDFontType2");
-        pdf_dict_add_name(pdf, "CIDToGIDMap", "Identity");
-    }
-    pdf_dict_add_fontname(pdf, "BaseFont", fo->fd);
-    pdf_dict_add_ref(pdf, "FontDescriptor", (int) fo->fd->fd_objnum);
-    pdf_dict_add_ref(pdf, "W", (int) fo->cw_objnum);
-    pdf_add_name(pdf, "CIDSystemInfo");
-    pdf_begin_dict(pdf);
-    pdf_dict_add_string(pdf, "Registry", (font_cidregistry(f) ? font_cidregistry(f) : "Adobe"));
-    pdf_dict_add_string(pdf, "Ordering", (font_cidordering(f) ? font_cidordering(f) : "Identity"));
-    pdf_dict_add_int(pdf, "Supplement", (int) font_cidsupplement(f));
-    pdf_end_dict(pdf);
-
-    /* I doubt there is anything useful that could be written here */
-
-#if 0
-    if (pdf_font_attr(fo->tex_font) != get_nullstr()) {
-        pdf_out(pdf, '\n');
-        pdf_print(pdf_font_attr(fo->tex_font));
-        pdf_out(pdf, '\n');
-    }
-#endif
-
-    pdf_end_dict(pdf);
-    pdf_end_obj(pdf);
-}

Added: trunk/Build/source/texk/web2c/luatexdir/font/writet1.c
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writet1.c	                        (rev 0)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writet1.c	2018-09-05 21:57:30 UTC (rev 48594)
@@ -0,0 +1,1693 @@
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh at pdftex.org>
+Copyright 2006-2009 Taco Hoekwater <taco at luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include <string.h>
+
+#define get_length1()              t1_length1 = t1_offset() - t1_save_offset
+#define get_length2()              t1_length2 = t1_offset() - t1_save_offset
+#define get_length3()              t1_length3 = fixedcontent? t1_offset() - t1_save_offset : 0
+#define save_offset()              t1_save_offset = t1_offset()
+#define t1_putchar(A)              strbuf_putchar(pdf->fb, (A))
+#define t1_offset()                strbuf_offset(pdf->fb)
+#define out_eexec_char             t1_putchar
+#define end_last_eexec_line()      t1_eexec_encrypt = false
+#define t1_char(c)                 c
+#define embed_all_glyphs(tex_font) fm_cur->all_glyphs
+#define extra_charset()            fm_cur->charset
+#define fixedcontent               false
+
+int t1_length1, t1_length2, t1_length3;
+static int t1_save_offset;
+static int t1_fontname_offset;
+
+static unsigned char *t1_buffer = NULL;
+static int t1_size = 0;
+static int t1_curbyte = 0;
+
+#define t1_read_file()   readbinfile(t1_file,&t1_buffer,&t1_size)
+#define t1_close()       xfclose(t1_file,cur_file_name)
+#define t1_getchar()     t1_buffer[t1_curbyte++]
+#define t1_ungetchar(c)  t1_curbyte--
+#define t1_eof()         (t1_curbyte>t1_size)
+
+#define t1_prefix(s)     str_prefix(t1_line_array, s)
+#define t1_buf_prefix(s) str_prefix(t1_buf_array, s)
+#define t1_suffix(s)     str_suffix(t1_line_array, t1_line_ptr, s)
+#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s)
+#define t1_charstrings() strstr(t1_line_array, charstringname)
+#define t1_subrs()       t1_prefix("/Subrs")
+#define t1_end_eexec()   t1_suffix("mark currentfile closefile")
+#define t1_cleartomark() t1_prefix("cleartomark")
+
+static unsigned char *enc_buffer = NULL;
+static int enc_size = 0;
+static int enc_curbyte = 0;
+
+#define enc_open(a)     (enc_file = fopen((char *)(a), FOPEN_RBIN_MODE))
+#define enc_read_file() readbinfile(enc_file,&enc_buffer,&enc_size)
+#define enc_close()     xfclose(enc_file,cur_file_name)
+#define enc_getchar()   enc_buffer[enc_curbyte++]
+#define enc_eof()       (enc_curbyte>enc_size)
+
+#define valid_code(c)  (c >= 0 && c < 256)
+#define fixedcontent    false
+
+static const char *standard_glyph_names[256] = {
+    /* 0x00 */
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    /* 0x10 */
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    /* 0x20 */
+    "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
+    "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
+    "plus", "comma", "hyphen", "period", "slash",
+    /* 0x30 */
+    "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
+    "nine", "colon", "semicolon", "less", "equal", "greater", "question",
+    /* 0x40 */
+    "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+    "O",
+    /* 0x50 */
+    "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
+    "backslash", "bracketright", "asciicircum", "underscore",
+    /* 0x60 */
+    "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
+    "m", "n", "o",
+    /* 0x70 */
+    "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
+    "braceright", "asciitilde", notdef,
+    /* 0x80 */
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    /* 0x90 */
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    /* 0xa0 */
+    notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin",
+    "section", "currency", "quotesingle", "quotedblleft", "guillemotleft",
+    "guilsinglleft", "guilsinglright", "fi", "fl",
+    /* 0xb0 */
+    notdef, "endash", "dagger", "daggerdbl", "periodcentered", notdef,
+    "paragraph", "bullet", "quotesinglbase", "quotedblbase",
+    "quotedblright", "guillemotright", "ellipsis", "perthousand", notdef,
+    "questiondown",
+    /* 0xc0 */
+    notdef, "grave", "acute", "circumflex", "tilde", "macron", "breve",
+    "dotaccent", "dieresis", notdef,
+    "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron",
+    /* 0xd0 */
+    "emdash", notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
+    /* 0xe0 */
+    notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
+    "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef,
+    notdef,
+    /* 0xf0 */
+    notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef, "lslash",
+    "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
+};
+
+static fd_entry *fd_cur;
+
+static char charstringname[] = "/CharStrings";
+
+enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
+
+#define T1_BUF_SIZE   0x0010
+#define ENC_BUF_SIZE  0x1000
+
+#define CS_HSTEM             1
+#define CS_VSTEM             3
+#define CS_VMOVETO           4
+#define CS_RLINETO           5
+#define CS_HLINETO           6
+#define CS_VLINETO           7
+#define CS_RRCURVETO         8
+#define CS_CLOSEPATH         9
+#define CS_CALLSUBR         10
+#define CS_RETURN           11
+#define CS_ESCAPE           12
+#define CS_HSBW             13
+#define CS_ENDCHAR          14
+#define CS_RMOVETO          21
+#define CS_HMOVETO          22
+#define CS_VHCURVETO        30
+#define CS_HVCURVETO        31
+#define CS_1BYTE_MAX        (CS_HVCURVETO + 1)
+
+#define CS_DOTSECTION       CS_1BYTE_MAX +  0
+#define CS_VSTEM3           CS_1BYTE_MAX +  1
+#define CS_HSTEM3           CS_1BYTE_MAX +  2
+#define CS_SEAC             CS_1BYTE_MAX +  6
+#define CS_SBW              CS_1BYTE_MAX +  7
+#define CS_DIV              CS_1BYTE_MAX + 12
+#define CS_CALLOTHERSUBR    CS_1BYTE_MAX + 16
+#define CS_POP              CS_1BYTE_MAX + 17
+#define CS_SETCURRENTPOINT  CS_1BYTE_MAX + 33
+#define CS_2BYTE_MAX        (CS_SETCURRENTPOINT + 1)
+#define CS_MAX              CS_2BYTE_MAX
+
+typedef unsigned char byte;
+
+/*tex A |CharString| command: */
+
+typedef struct {
+    /*tex number of arguments */
+    byte nargs;
+    /*tex take arguments from bottom of stack? */
+    boolean bottom;
+    /*tex clear stack? */
+    boolean clear;
+    boolean valid;
+} cc_entry;
+
+typedef struct {
+    /*tex glyph name (or |notdef| for |Subrs| entry) */
+    char *name;
+    byte *data;
+    /*tex length of the whole string */
+    unsigned short len;
+    /*tex length of the encoded part of the string */
+    unsigned short cslen;
+    boolean used;
+    boolean valid;
+} cs_entry;
+
+static unsigned short t1_dr, t1_er;
+static const unsigned short t1_c1 = 52845, t1_c2 = 22719;
+static unsigned short t1_cslen;
+static short t1_lenIV;
+static char enc_line[ENC_BUF_SIZE];
+
+#define t1_line_entry char
+define_array(t1_line);
+
+#define t1_buf_entry char
+define_array(t1_buf);
+
+static int cs_start;
+
+static cs_entry *cs_tab, *cs_ptr, *cs_notdef;
+static char *cs_dict_start, *cs_dict_end;
+static int cs_counter, cs_size, cs_size_pos;
+
+static cs_entry *subr_tab;
+static char *subr_array_start, *subr_array_end;
+static int subr_max, subr_size, subr_size_pos;
+
+/*tex
+
+    This list contains the begin/end tokens commonly used in the |/Subrs| array of
+    a Type 1 font.
+
+*/
+
+static const char *cs_token_pairs_list[][2] = {
+    { " RD", "NP" },
+    { " -|", "|" },
+    { " RD", "noaccess put" },
+    { " -|", "noaccess put" },
+    { NULL,  NULL }
+};
+
+static const char **cs_token_pair;
+
+static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
+
+/*tex This one becomes 0 before 1 during and 2 after |eexec| encryption. */
+
+static int t1_in_eexec;
+
+static long t1_block_length;
+static int last_hexbyte;
+static FILE *t1_file;
+static FILE *enc_file;
+
+static void enc_getline(void)
+{
+    char *p;
+    char c;
+  restart:
+    if (enc_eof())
+        normal_error("type 1","unexpected end of file");
+    p = enc_line;
+    do {
+        c = (char) enc_getchar();
+        append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
+    }
+    while (c != 10 && !enc_eof());
+    append_eol(p, enc_line, ENC_BUF_SIZE);
+    if (p - enc_line < 2 || *enc_line == '%')
+        goto restart;
+}
+
+/*tex
+
+    Read encoding from .enc file, return |glyph_names array|, or |pdffail|.
+
+*/
+
+char **load_enc_file(char *enc_name)
+{
+    int callback_id = 0;
+    int file_opened = 0;
+    char buf[ENC_BUF_SIZE], *p, *r;
+    int i, names_count;
+    char **glyph_names;
+    cur_file_name = luatex_find_file(enc_name, find_enc_file_callback);
+    if (cur_file_name == NULL) {
+        formatted_error("type 1","cannot find encoding file '%s' for reading", enc_name);
+    }
+    callback_id = callback_defined(read_enc_file_callback);
+    enc_curbyte = 0;
+    enc_size = 0;
+    if (callback_id > 0) {
+        if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &enc_buffer, &enc_size)) {
+            if ((!file_opened) || enc_size == 0) {
+                formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
+            }
+        }
+    } else {
+        if (!enc_open(cur_file_name)) {
+            formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
+        }
+        enc_read_file();
+        enc_close();
+    }
+    glyph_names = xtalloc(256, char *);
+    for (i = 0; i < 256; i++)
+        glyph_names[i] = (char *) notdef;
+    report_start_file(filetype_map,cur_file_name);
+    enc_getline();
+    if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) {
+        remove_eol(r, enc_line);
+        formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line);
+    }
+    names_count = 0;
+    /*tex Skip |[|: */
+    r++;
+    skip_char(r, ' ');
+    for (;;) {
+        while (*r == '/') {
+            for (p = buf, r++;
+                 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
+            *p = 0;
+            skip_char(r, ' ');
+            if (names_count >= 256)
+                normal_error("type 1","encoding vector contains more than 256 names");
+            if (strcmp(buf, notdef) != 0)
+                glyph_names[names_count] = xstrdup(buf);
+            names_count++;
+        }
+        if (*r != 10 && *r != '%') {
+            if (strncmp(r, "] def", strlen("] def")) == 0)
+                goto done;
+            else {
+                remove_eol(r, enc_line);
+                formatted_error("type 1","invalid encoding vector: a name or '] def' expected: `%s'",enc_line);
+            }
+        }
+        enc_getline();
+        r = enc_line;
+    }
+  done:
+    report_stop_file(filetype_map);
+    cur_file_name = NULL;
+    xfree(enc_buffer);
+    return glyph_names;
+}
+
+static void t1_check_pfa(void)
+{
+    const int c = t1_getchar();
+    t1_pfa = (c != 128) ? true : false;
+    t1_ungetchar(c);
+}
+
+static int t1_getbyte(void)
+{
+    int c = t1_getchar();
+    if (t1_pfa)
+        return c;
+    if (t1_block_length == 0) {
+        if (c != 128)
+            normal_error("type 1","invalid marker");
+        c = t1_getchar();
+        if (c == 3) {
+            while (!t1_eof())
+                (void) t1_getchar();
+            return EOF;
+        }
+        t1_block_length = t1_getchar() & 0xff;
+        t1_block_length |= (t1_getchar() & 0xff) << 8;
+        t1_block_length |= (t1_getchar() & 0xff) << 16;
+        t1_block_length |= (t1_getchar() & 0xff) << 24;
+        c = t1_getchar();
+    }
+    t1_block_length--;
+    return c;
+}
+
+static int hexval(int c)
+{
+    if (c >= 'A' && c <= 'F')
+        return c - 'A' + 10;
+    else if (c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    else if (c >= '0' && c <= '9')
+        return c - '0';
+    else
+        return -1;
+}
+
+static byte edecrypt(byte cipher)
+{
+    byte plain;
+    if (t1_pfa) {
+        while (cipher == 10 || cipher == 13)
+            cipher = (byte) t1_getbyte();
+        last_hexbyte = cipher = (byte) ((hexval(cipher) << 4) + hexval(t1_getbyte()));
+    }
+    plain = (byte) (cipher ^ (t1_dr >> 8));
+    t1_dr = (unsigned short) ((cipher + t1_dr) * t1_c1 + t1_c2);
+    return plain;
+}
+
+static byte cdecrypt(byte cipher, unsigned short *cr)
+{
+    const byte plain = (byte) (cipher ^ (*cr >> 8));
+    *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
+    return plain;
+}
+
+static byte eencrypt(byte plain)
+{
+    const byte cipher = (byte) (plain ^ (t1_er >> 8));
+    t1_er = (unsigned short) ((cipher + t1_er) * t1_c1 + t1_c2);
+    return cipher;
+}
+
+static byte cencrypt(byte plain, unsigned short *cr)
+{
+    const byte cipher = (byte) (plain ^ (*cr >> 8));
+    *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
+    return cipher;
+}
+
+static char *eol(char *s)
+{
+    char *p = strend(s);
+    if (p - s > 1 && p[-1] != 10) {
+        *p++ = 10;
+        *p = 0;
+    }
+    return p;
+}
+
+static float t1_scan_num(char *p, char **r)
+{
+    float f;
+    skip_char(p, ' ');
+    if (sscanf(p, "%g", &f) != 1) {
+        remove_eol(p, t1_line_array);
+        formatted_error("type 1","a number expected: '%s'", t1_line_array);
+    }
+    if (r != NULL) {
+        for (; isdigit((unsigned char)*p) || *p == '.' ||
+             *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
+        *r = p;
+    }
+    return f;
+}
+
+static boolean str_suffix(const char *begin_buf, const char *end_buf, const char *s)
+{
+    const char *s1 = end_buf - 1, *s2 = strend(s) - 1;
+    if (*s1 == 10)
+        s1--;
+    while (s1 >= begin_buf && s2 >= s) {
+        if (*s1-- != *s2--)
+            return false;
+    }
+    return s2 < s;
+}
+
+static void t1_getline(void)
+{
+    int c, l, eexec_scan;
+    char *p;
+    static const char eexec_str[] = "currentfile eexec";
+    static int eexec_len = 17;
+  restart:
+    if (t1_eof())
+        normal_error("type 1","unexpected end of file");
+    t1_line_ptr = t1_line_array;
+    alloc_array(t1_line, 1, T1_BUF_SIZE);
+    t1_cslen = 0;
+    eexec_scan = 0;
+    c = t1_getbyte();
+    if (c == EOF)
+        goto exit;
+    while (!t1_eof()) {
+        if (t1_in_eexec == 1)
+            c = edecrypt((byte) c);
+        alloc_array(t1_line, 1, T1_BUF_SIZE);
+        {
+            char cc = (char) c;
+            append_char_to_buf(cc, t1_line_ptr, t1_line_array, t1_line_limit);
+        }
+        if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
+            if (t1_line_array[eexec_scan] == eexec_str[eexec_scan])
+                eexec_scan++;
+            else
+                eexec_scan = -1;
+        }
+        if (c == 10 || c == 13
+            || (t1_pfa && eexec_scan == eexec_len && c == 32)) {
+            break;
+        }
+        if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) &&
+            (t1_suffix(" RD ") || t1_suffix(" -| "))) {
+            p = t1_line_ptr - 5;
+            while (*p != ' ')
+                p--;
+            l = (int) t1_scan_num(p + 1, 0);
+            t1_cslen = (unsigned short) l;
+            /*tex |cs_start| is an index now */
+            cs_start = (int) (t1_line_ptr - t1_line_array);
+            alloc_array(t1_line, l, T1_BUF_SIZE);
+            while (l-- > 0)
+                *t1_line_ptr++ = (t1_line_entry) edecrypt((byte) t1_getbyte());
+        }
+        c = t1_getbyte();
+    }
+    /*tex |append_eol| can append 2 chars */
+    alloc_array(t1_line, 2, T1_BUF_SIZE);
+    append_eol(t1_line_ptr, t1_line_array, t1_line_limit);
+    if (t1_line_ptr - t1_line_array < 2)
+        goto restart;
+    if (eexec_scan == eexec_len)
+        t1_in_eexec = 1;
+  exit:
+    /*tex Ensure that |t1_buf_array| has as much room as |t1_line_array|. */
+    t1_buf_ptr = t1_buf_array;
+    alloc_array(t1_buf, t1_line_limit, t1_line_limit);
+}
+
+static void t1_putline(PDF pdf)
+{
+    char *p = t1_line_array;
+    if (t1_line_ptr - t1_line_array <= 1)
+        return;
+    if (t1_eexec_encrypt) {
+        while (p < t1_line_ptr)
+            t1_putchar((eight_bits) eencrypt((byte) * p++));
+    } else
+        while (p < t1_line_ptr)
+            t1_putchar((eight_bits) * p++);
+}
+
+static void t1_puts(PDF pdf, const char *s)
+{
+    if (s != t1_line_array)
+        strcpy(t1_line_array, s);
+    t1_line_ptr = strend(t1_line_array);
+    t1_putline(pdf);
+}
+
+__attribute__ ((format(printf, 2, 3)))
+static void t1_printf(PDF pdf, const char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    vsprintf(t1_line_array, fmt, args);
+    t1_puts(pdf, t1_line_array);
+    va_end(args);
+}
+
+static void t1_init_params(int open_name_prefix)
+{
+    report_start_file(open_name_prefix,cur_file_name);
+    t1_lenIV = 4;
+    t1_dr = 55665;
+    t1_er = 55665;
+    t1_in_eexec = 0;
+    t1_cs = false;
+    t1_scan = true;
+    t1_synthetic = false;
+    t1_eexec_encrypt = false;
+    t1_block_length = 0;
+    t1_check_pfa();
+}
+
+static void t1_close_font_file(int close_name_suffix)
+{
+    report_stop_file(close_name_suffix);
+    cur_file_name = NULL;
+}
+
+static void t1_check_block_len(boolean decrypt)
+{
+    int l, c;
+    if (t1_block_length == 0)
+        return;
+    c = t1_getbyte();
+    if (decrypt)
+        c = edecrypt((byte) c);
+    l = (int) t1_block_length;
+    if (!(l == 0 && (c == 10 || c == 13))) {
+        formatted_error("type 1","%i bytes more than expected were ignored", l + 1);
+    }
+}
+
+static void t1_start_eexec(PDF pdf)
+{
+    int i;
+    get_length1();
+    save_offset();
+    if (!t1_pfa)
+        t1_check_block_len(false);
+    for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
+        edecrypt((byte) t1_getbyte());
+        *t1_line_ptr++ = 0;
+    }
+    t1_eexec_encrypt = true;
+    /*tex To put the first four bytes: */
+    t1_putline(pdf);
+}
+
+static void t1_stop_eexec(PDF pdf)
+{
+    int c;
+    get_length2();
+    save_offset();
+    t1_eexec_encrypt = false;
+    if (!t1_pfa)
+        t1_check_block_len(true);
+    else {
+        c = edecrypt((byte) t1_getbyte());
+        if (!(c == 10 || c == 13)) {
+            if (last_hexbyte == 0)
+                t1_puts(pdf, "00");
+            else
+                normal_error("type 1","unexpected data after eexec");
+        }
+    }
+    t1_cs = false;
+    t1_in_eexec = 2;
+}
+
+/*tex Macros for various transforms; unused, left for reference: */
+
+#ifdef T1TRANSFORMMACROS
+#  define do_xshift(x,a) {x[4]+=a;}
+#  define do_yshift(x,a) {x[5]+=a;}
+#  define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;}
+#  define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;}
+#  define do_extend(x,a) {do_xscale(x,a);}
+#  define do_scale(x,a)  {do_xscale(x,a); do_yscale(x,a);}
+#  define do_slant(x,a)  {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);}
+#  define do_shear(x,a)  {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);}
+
+#  define do_rotate(x,a) {        \
+    float t, u=cos(a), v=sin(a);  \
+    t    =x[0]*u+x[1]*-v;         \
+    x[1] =x[0]*v+x[1]* u; x[0]=t; \
+    t    =x[2]*u+x[3]*-v;         \
+    x[3] =x[2]*v+x[3]* u; x[2]=t; \
+    t    =x[4]*u+x[5]*-v;         \
+    x[5] =x[4]*v+x[5]* u; x[4]=t; \
+}
+#endif
+
+static void t1_scan_keys(PDF pdf)
+{
+    int i, k;
+    char *p, *q, *r;
+    const key_entry *key;
+    if (t1_prefix("/FontType")) {
+        p = t1_line_array + strlen("FontType") + 1;
+        if ((i = (int) t1_scan_num(p, 0)) != 1)
+            formatted_error("type 1","Type%d fonts unsupported by backend", i);
+        return;
+    }
+    for (key = (const key_entry *) font_key; key - font_key < FONT_KEYS_NUM;
+         key++) {
+        if (key->t1name[0] != '\0'
+            && str_prefix(t1_line_array + 1, key->t1name))
+            break;
+    }
+    if (key - font_key == FONT_KEYS_NUM)
+        return;
+    p = t1_line_array + strlen(key->t1name) + 1;
+    skip_char(p, ' ');
+    if ((k = (int) (key - font_key)) == FONTNAME_CODE) {
+        if (*p != '/') {
+            remove_eol(p, t1_line_array);
+            formatted_error("type 1","a name expected: '%s'", t1_line_array);
+        }
+        /*tex Skip the slash. */
+        r = ++p;
+        for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++);
+        *q = 0;
+        xfree(fd_cur->fontname);
+        fd_cur->fontname = xstrdup(t1_buf_array);
+        /*tex
+
+            At this moment we cannot call |make_subset_tag| yet, as the encoding
+            is not read; thus we mark the offset of the subset tag and write it
+            later.
+
+        */
+        if (is_subsetted(fd_cur->fm)) {
+            t1_fontname_offset = (int) (t1_offset() + (r - t1_line_array));
+            strcpy(t1_buf_array, p);
+            sprintf(r, "ABCDEF+%s%s", fd_cur->fontname, t1_buf_array);
+            t1_line_ptr = eol(r);
+        }
+        return;
+    }
+    if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && (*p == '[' || *p == '{'))
+        p++;
+    if (k == FONTBBOX1_CODE) {
+        for (i = 0; i < 4; i++, k++) {
+            fd_cur->font_dim[k].val = (int) t1_scan_num(p, &r);
+            fd_cur->font_dim[k].set = true;
+            p = r;
+        }
+        return;
+    }
+    fd_cur->font_dim[k].val = (int) t1_scan_num(p, 0);
+    fd_cur->font_dim[k].set = true;
+}
+
+static void t1_scan_param(PDF pdf)
+{
+    static const char *lenIV = "/lenIV";
+    if (!t1_scan || *t1_line_array != '/')
+        return;
+    if (t1_prefix(lenIV)) {
+        t1_lenIV = (short) t1_scan_num(t1_line_array + strlen(lenIV), 0);
+        if (t1_lenIV < 0)
+            normal_error("type 1","negative value of lenIV is not supported");
+        return;
+    }
+    t1_scan_keys(pdf);
+}
+
+static void copy_glyph_names(char **glyph_names, int a, int b)
+{
+    if (glyph_names[b] != notdef) {
+        xfree(glyph_names[b]);
+        glyph_names[b] = (char *) notdef;
+    }
+    if (glyph_names[a] != notdef) {
+        glyph_names[b] = xstrdup(glyph_names[a]);
+    }
+}
+
+/*tex Read encoding from Type1 font file, return |glyph_names| array, or |pdffail|. */
+
+static char **t1_builtin_enc(void)
+{
+    int i, a, b, c, counter = 0;
+    char *r, *p, **glyph_names;
+    /*tex At this moment |/Encoding| is the prefix of |t1_line_array|. */
+    glyph_names = xtalloc(256, char *);
+    for (i = 0; i < 256; i++)
+        glyph_names[i] = (char *) notdef;
+    if (t1_suffix("def")) {
+        /*tex A predefined encoding: */
+        sscanf(t1_line_array + strlen("/Encoding"), "%255s", t1_buf_array);
+        if (strcmp(t1_buf_array, "StandardEncoding") == 0) {
+            t1_encoding = ENC_STANDARD;
+            for (i = 0; i < 256; i++) {
+                if (standard_glyph_names[i] != notdef)
+                    glyph_names[i] = xstrdup(standard_glyph_names[i]);
+            }
+            return glyph_names;
+        } else
+            formatted_error("type 1","cannot subset font (unknown predefined encoding '%s')",t1_buf_array);
+    }
+    /*
+
+        At this moment |/Encoding| is the prefix of |t1_line_array|, and the
+        encoding is not a predefined encoding. We have two possible forms of
+        vector. The first case is
+
+        \starttyping
+        /Encoding [
+            /a /b /c ...
+        ] readonly def
+        \stoptyping
+
+        and the second case can look like
+
+        \starttyping
+        /Encoding 256 array 0 1 255 {
+            1 index exch /.notdef put} for
+            dup 0 /x put
+            dup 1 /y put
+            ...
+        } readonly def
+        \stoptyping
+
+    */
+    t1_encoding = ENC_BUILTIN;
+    if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) {  /* the first case */
+        r = strchr(t1_line_array, '[') + 1;
+        skip_char(r, ' ');
+        for (;;) {
+            while (*r == '/') {
+                for (p = t1_buf_array, r++; *r != 32 && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
+                *p = 0;
+                skip_char(r, ' ');
+                if (counter > 255)
+                    normal_error("type 1","encoding vector contains more than 256 names");
+                if (strcmp(t1_buf_array, notdef) != 0)
+                    glyph_names[counter] = xstrdup(t1_buf_array);
+                counter++;
+            }
+            if (*r != 10 && *r != '%') {
+                if (str_prefix(r, "] def") || str_prefix(r, "] readonly def"))
+                    break;
+                else {
+                    remove_eol(r, t1_line_array);
+                    formatted_error("type 1","a name or '] def' or '] readonly def' expected: '%s'", t1_line_array);
+                }
+            }
+            t1_getline();
+            r = t1_line_array;
+        }
+    } else {
+        /*tex The second case. */
+        p = strchr(t1_line_array, 10);
+        for (;;) {
+            if (*p == 10) {
+                t1_getline();
+                p = t1_line_array;
+            }
+            /*tex Check for |dup <index> <glyph> put|. */
+            if (sscanf(p, "dup %i%255s put", &i, t1_buf_array) == 2 &&
+                *t1_buf_array == '/' && valid_code(i)) {
+                if (strcmp(t1_buf_array + 1, notdef) != 0)
+                    glyph_names[i] = xstrdup(t1_buf_array + 1);
+                p = strstr(p, " put") + strlen(" put");
+                skip_char(p, ' ');
+            }
+            /*tex Check for |dup dup <to> exch <from> get put|. */
+            else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2 && valid_code(a) && valid_code(b)) {
+                copy_glyph_names(glyph_names, a, b);
+                p = strstr(p, " get put") + strlen(" get put");
+                skip_char(p, ' ');
+            }
+            /*tex Check for |dup dup <from> <size> getinterval <to> exch putinterval|. */
+            else if (sscanf(p, "dup dup %i %i getinterval %i exch putinterval",
+                    &a, &c, &b) == 3 && valid_code(a) && valid_code(b) && valid_code(c)) {
+                for (i = 0; i < c; i++)
+                    copy_glyph_names(glyph_names, a + i, b + i);
+                p = strstr(p, " putinterval") + strlen(" putinterval");
+                skip_char(p, ' ');
+            }
+            /*tex Check for |def or |readonly def|. */
+            else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' ')) && strcmp(p, "def\n") == 0) {
+                return glyph_names;
+            } else {
+                /*tex Skip an unrecognizable word. */
+                while (*p != ' ' && *p != 10)
+                    p++;
+                skip_char(p, ' ');
+            }
+        }
+    }
+    return glyph_names;
+}
+
+static void t1_check_end(PDF pdf)
+{
+    if (t1_eof())
+        return;
+    t1_getline();
+    if (t1_prefix("{restore}"))
+        t1_putline(pdf);
+}
+
+static boolean t1_open_fontfile(int open_name_prefix)
+{
+    ff_entry *ff;
+    int callback_id = 0;
+    int file_opened = 0;
+    t1_curbyte = 0;
+    t1_size = 0;
+    ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm));
+    if (ff->ff_path == NULL) {
+        formatted_error("type 1","cannot open file for reading '%s'",fd_cur->fm->ff_name);
+        return false;
+    }
+    cur_file_name = luatex_find_file(ff->ff_path, find_type1_file_callback);
+    if (cur_file_name == NULL) {
+        formatted_error("type 1","cannot open file for reading '%s'", ff->ff_path);
+        return false;
+    }
+    callback_id = callback_defined(read_type1_file_callback);
+    if (callback_id > 0) {
+        if (!run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &t1_buffer, &t1_size)
+            && file_opened && t1_size > 0) {
+            formatted_warning("type 1","cannot open file for reading '%s'",cur_file_name);
+            return false;
+        }
+    } else {
+        t1_file = xfopen(cur_file_name, FOPEN_RBIN_MODE);
+        t1_read_file();
+        t1_close();
+    }
+    recorder_record_input(cur_file_name);
+    t1_init_params(open_name_prefix);
+    return true;
+}
+
+static void t1_include(PDF pdf)
+{
+    do {
+        t1_getline();
+        t1_scan_param(pdf);
+        t1_putline(pdf);
+    }
+    while (t1_in_eexec == 0);
+    t1_start_eexec(pdf);
+    do {
+        t1_getline();
+        t1_scan_param(pdf);
+        t1_putline(pdf);
+    }
+    while (!(t1_charstrings() || t1_subrs()));
+    t1_cs = true;
+    do {
+        t1_getline();
+        t1_putline(pdf);
+    }
+    while (!t1_end_eexec());
+    t1_stop_eexec(pdf);
+    if (fixedcontent) {
+        /*tex Copy 512 zeros (not needed for \PDF). */
+        do {
+            t1_getline();
+            t1_putline(pdf);
+        }
+        while (!t1_cleartomark());
+        /*tex Write |{restore} if| if found. */
+        t1_check_end(pdf);
+    }
+    get_length3();
+}
+
+#define check_subr(subr) \
+    if (subr >= subr_size || subr < 0) \
+        formatted_error("type 1","Subrs array: entry index out of range '%i'", subr);
+
+static const char **check_cs_token_pair(void)
+{
+    const char **p = (const char **) cs_token_pairs_list;
+    for (; p[0] != NULL; ++p)
+        if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1]))
+            return p;
+    return NULL;
+}
+
+static void cs_store(boolean is_subr)
+{
+    char *p;
+    cs_entry *ptr;
+    int subr;
+    for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' ';
+         *t1_buf_ptr++ = *p++);
+    *t1_buf_ptr = 0;
+    if (is_subr) {
+        subr = (int) t1_scan_num(p + 1, 0);
+        check_subr(subr);
+        ptr = subr_tab + subr;
+    } else {
+        ptr = cs_ptr++;
+        if (cs_ptr - cs_tab > cs_size)
+            formatted_error("type 1","CharStrings dict: more entries than dict size '%i'", cs_size);
+        if (strcmp(t1_buf_array + 1, notdef) == 0)      /* skip the slash */
+            ptr->name = (char *) notdef;
+        else
+            ptr->name = xstrdup(t1_buf_array + 1);
+    }
+    /*tex Copy |" RD " + cs data| to |t1_buf_array|. */
+    memcpy(t1_buf_array, t1_line_array + cs_start - 4, (unsigned) (t1_cslen + 4));
+    /*tex Copy the end of cs data to |t1_buf_array|. */
+    for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr =
+         t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++);
+    *t1_buf_ptr++ = 10;
+    if (is_subr && cs_token_pair == NULL)
+        cs_token_pair = check_cs_token_pair();
+    ptr->len = (unsigned short) (t1_buf_ptr - t1_buf_array);
+    ptr->cslen = t1_cslen;
+    xfree(ptr->data);
+    ptr->data = xtalloc(ptr->len, byte);
+    memcpy(ptr->data, t1_buf_array, ptr->len);
+    ptr->valid = true;
+}
+
+#define store_subr() cs_store(true)
+#define store_cs()   cs_store(false)
+
+#define CC_STACK_SIZE 24
+
+static int cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
+static cc_entry cc_tab[CS_MAX];
+static boolean is_cc_init = false;
+
+#define cc_pop(N) \
+    if (stack_ptr - cc_stack < (N)) \
+        stack_error(N); \
+    stack_ptr -= N
+
+#define stack_error(N) { \
+    formatted_error("type 1","CharString: invalid access '%i' to stack, '%i' entries", (int) N, (int)(stack_ptr - cc_stack)); \
+    goto cs_error; \
+}
+
+#define cc_get(N)  ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
+#define cc_push(V) *stack_ptr++ = V
+#define cc_clear() stack_ptr = cc_stack
+
+#define set_cc(N, B, A, C) \
+    cc_tab[N].nargs = A;   \
+    cc_tab[N].bottom = B;  \
+    cc_tab[N].clear = C;   \
+    cc_tab[N].valid = true
+
+static void cc_init(void)
+{
+    int i;
+    if (is_cc_init)
+        return;
+    for (i = 0; i < CS_MAX; i++)
+        cc_tab[i].valid = false;
+    set_cc(CS_HSTEM, true, 2, true);
+    set_cc(CS_VSTEM, true, 2, true);
+    set_cc(CS_VMOVETO, true, 1, true);
+    set_cc(CS_RLINETO, true, 2, true);
+    set_cc(CS_HLINETO, true, 1, true);
+    set_cc(CS_VLINETO, true, 1, true);
+    set_cc(CS_RRCURVETO, true, 6, true);
+    set_cc(CS_CLOSEPATH, false, 0, true);
+    set_cc(CS_CALLSUBR, false, 1, false);
+    set_cc(CS_RETURN, false, 0, false);
+    set_cc(CS_HSBW, true, 2, true);
+    set_cc(CS_ENDCHAR, false, 0, true);
+    set_cc(CS_RMOVETO, true, 2, true);
+    set_cc(CS_HMOVETO, true, 1, true);
+    set_cc(CS_VHCURVETO, true, 4, true);
+    set_cc(CS_HVCURVETO, true, 4, true);
+    set_cc(CS_DOTSECTION, false, 0, true);
+    set_cc(CS_VSTEM3, true, 6, true);
+    set_cc(CS_HSTEM3, true, 6, true);
+    set_cc(CS_SEAC, true, 5, true);
+    set_cc(CS_SBW, true, 4, true);
+    set_cc(CS_DIV, false, 2, false);
+    set_cc(CS_CALLOTHERSUBR, false, 0, false);
+    set_cc(CS_POP, false, 0, false);
+    set_cc(CS_SETCURRENTPOINT, true, 2, true);
+    is_cc_init = true;
+}
+
+#define cs_getchar()    cdecrypt(*data++, &cr)
+
+#define mark_subr(n)    cs_mark(0, n)
+#define mark_cs(s)      cs_mark(s, 0)
+
+static void cs_fail(const char *cs_name, int subr, const char *fmt, ...)
+{
+    char buf[SMALL_BUF_SIZE];
+    va_list args;
+    va_start(args, fmt);
+    vsprintf(buf, fmt, args);
+    va_end(args);
+    if (cs_name == NULL)
+        formatted_error("type 1","Subr '%i': %s", (int) subr, buf);
+    else
+        formatted_error("type 1","CharString (/%s): %s", cs_name, buf);
+}
+
+/*tex Fix a return-less subr by appending |CS_RETURN|. */
+
+static void append_cs_return(cs_entry * ptr)
+{
+    unsigned short cr;
+    int i;
+    byte *p, *q, *data, *new_data;
+    /*tex Decrypt the cs data to |t1_buf_array|, append |CS_RETURN|. */
+    p = (byte *) t1_buf_array;
+    data = ptr->data + 4;
+    cr = 4330;
+    for (i = 0; i < ptr->cslen; i++)
+        *p++ = cs_getchar();
+    *p = CS_RETURN;
+    /*tex Encrypt the new cs data to |new_data|. */
+    new_data = xtalloc((unsigned) (ptr->len + 1), byte);
+    memcpy(new_data, ptr->data, 4);
+    p = new_data + 4;
+    q = (byte *) t1_buf_array;
+    cr = 4330;
+    for (i = 0; i < ptr->cslen + 1; i++)
+        *p++ = cencrypt(*q++, &cr);
+    memcpy(p, ptr->data + 4 + ptr->cslen, (size_t) (ptr->len - ptr->cslen - 4));
+    /*tex Update |*ptr|. */
+    xfree(ptr->data);
+    ptr->data = new_data;
+    ptr->len++;
+    ptr->cslen++;
+}
+
+static void cs_mark(const char *cs_name, int subr)
+{
+    byte *data;
+    int i, b, cs_len;
+    int last_cmd = 0;
+    int a, a1, a2;
+    unsigned short cr;
+    /*tex The argument of last call to |OtherSubrs[3]|. */
+    static int lastargOtherSubr3 = 3;
+    cs_entry *ptr;
+    cc_entry *cc;
+    if (cs_name == NULL) {
+        check_subr(subr);
+        ptr = subr_tab + subr;
+        if (!ptr->valid)
+            return;
+    } else if (cs_notdef != NULL && (cs_name == notdef || strcmp(cs_name, notdef) == 0)) {
+        ptr = cs_notdef;
+    }else {
+        for (ptr = cs_tab; ptr < cs_ptr; ptr++)
+            if (strcmp(ptr->name, cs_name) == 0)
+                break;
+        if (ptr == cs_ptr) {
+            formatted_warning("type 1","glyph '%s' undefined", cs_name);
+            return;
+        }
+        if (ptr->name == notdef)
+            cs_notdef = ptr;
+    }
+    /*tex
+        Only marked CharString entries and invalid entries can be skipped; valid
+        marked subrs must be parsed to keep the stack in sync.
+    */
+    if (!ptr->valid || (ptr->used && cs_name != NULL))
+        return;
+    ptr->used = true;
+    cr = 4330;
+    cs_len = ptr->cslen;
+    data = ptr->data + 4;
+    for (i = 0; i < t1_lenIV; i++, cs_len--)
+        cs_getchar();
+    while (cs_len > 0) {
+        --cs_len;
+        b = cs_getchar();
+        if (b >= 32) {
+            if (b <= 246)
+                a = b - 139;
+            else if (b <= 250) {
+                --cs_len;
+                a = ((b - 247) << 8) + 108 + cs_getchar();
+            } else if (b <= 254) {
+                --cs_len;
+                a = -((b - 251) << 8) - 108 - cs_getchar();
+            } else {
+                cs_len -= 4;
+                a = (cs_getchar() & 0xff) << 24;
+                a |= (cs_getchar() & 0xff) << 16;
+                a |= (cs_getchar() & 0xff) << 8;
+                a |= (cs_getchar() & 0xff) << 0;
+                if (sizeof(int) > 4 && (a & 0x80000000))
+                    a |= ~0x7FFFFFFF;
+            }
+            cc_push(a);
+        } else {
+            if (b == CS_ESCAPE) {
+                b = cs_getchar() + CS_1BYTE_MAX;
+                cs_len--;
+            }
+            if (b >= CS_MAX) {
+                cs_fail(cs_name, subr, "command value out of range: %i", (int) b);
+                goto cs_error;
+            }
+            cc = cc_tab + b;
+            if (!cc->valid) {
+                cs_fail(cs_name, subr, "command not valid: %i", (int) b);
+                goto cs_error;
+            }
+            if (cc->bottom) {
+                if (stack_ptr - cc_stack < cc->nargs)
+                    cs_fail(cs_name, subr,
+                            "less arguments on stack '%i' than required '%i'",
+                            (int) (stack_ptr - cc_stack), (int) cc->nargs);
+                else if (stack_ptr - cc_stack > cc->nargs)
+                    cs_fail(cs_name, subr,
+                            "more arguments on stack '%i' than required '%i'",
+                            (int) (stack_ptr - cc_stack), (int) cc->nargs);
+            }
+            last_cmd = b;
+            switch (cc - cc_tab) {
+                case CS_CALLSUBR:
+                    a1 = cc_get(-1);
+                    cc_pop(1);
+                    mark_subr(a1);
+                    if (!subr_tab[a1].valid) {
+                        cs_fail(cs_name, subr, "cannot call subr '%i'", (int) a1);
+                        goto cs_error;
+                    }
+                    break;
+                case CS_DIV:
+                    cc_pop(2);
+                    cc_push(0);
+                    break;
+                case CS_CALLOTHERSUBR:
+                    if (cc_get(-1) == 3)
+                        lastargOtherSubr3 = cc_get(-3);
+                    a1 = cc_get(-2) + 2;
+                    cc_pop(a1);
+                    break;
+                case CS_POP:
+                    cc_push(lastargOtherSubr3);
+                    /*tex
+                        The only case when we care about the value being pushed
+                        onto stack is when |POP| follows |CALLOTHERSUBR| changing
+                        hints by |OtherSubrs[3]|.
+                    */
+                    break;
+                case CS_SEAC:
+                    a1 = cc_get(3);
+                    a2 = cc_get(4);
+                    cc_clear();
+                    mark_cs(standard_glyph_names[a1]);
+                    mark_cs(standard_glyph_names[a2]);
+                    break;
+                default:
+                    if (cc->clear)
+                        cc_clear();
+            }
+        }
+    }
+    if (cs_name == NULL && last_cmd != CS_RETURN) {
+        formatted_warning("type 1",
+            "last command in subr '%i' is not a RETURN; I will add it now but please consider fixing the font",
+            (int) subr);
+        append_cs_return(ptr);
+    }
+    return;
+    /*tex An error occured during parsing: */
+  cs_error:
+    cc_clear();
+    ptr->valid = false;
+    ptr->used = false;
+}
+
+/* AVL search tree for glyph code by glyph name. */
+
+static int comp_t1_glyphs(const void *pa, const void *pb, void *p
+    __attribute__ ((unused)))
+{
+    return strcmp(*(const char *const *) pa, *(const char *const *) pb);
+}
+
+static struct avl_table *create_t1_glyph_tree(char **glyph_names)
+{
+    int i;
+    void **aa;
+    static struct avl_table *gl_tree;
+    gl_tree = avl_create(comp_t1_glyphs, NULL, &avl_xallocator);
+    for (i = 0; i < 256; i++) {
+        if (glyph_names[i] != notdef &&
+            (char **) avl_find(gl_tree, &glyph_names[i]) == NULL) {
+            /*tex No |strdup| here, just point to the |glyph_names| array members. */
+            aa = avl_probe(gl_tree, &glyph_names[i]);
+            if (aa == NULL) {
+                /*tex Is this a problem? */
+            }
+        }
+    }
+    return gl_tree;
+}
+
+static void destroy_t1_glyph_tree(struct avl_table *gl_tree)
+{
+    avl_destroy(gl_tree, NULL);
+}
+
+static void t1_subset_ascii_part(PDF pdf)
+{
+    int j, *p;
+    char *glyph, **gg, **glyph_names;
+    struct avl_table *gl_tree;
+    struct avl_traverser t;
+    void **aa;
+    t1_getline();
+    while (!t1_prefix("/Encoding")) {
+        t1_scan_param(pdf);
+        t1_putline(pdf);
+        t1_getline();
+    }
+    glyph_names = t1_builtin_enc();
+    fd_cur->builtin_glyph_names = glyph_names;
+    if (is_subsetted(fd_cur->fm)) {
+        if (fd_cur->tx_tree != NULL) {
+            /*tex Take over collected non-reencoded characters from \TeX. */
+            avl_t_init(&t, fd_cur->tx_tree);
+            for (p = (int *) avl_t_first(&t, fd_cur->tx_tree); p != NULL;
+                 p = (int *) avl_t_next(&t)) {
+                if ((char *) avl_find(fd_cur->gl_tree, glyph_names[*p]) == NULL) {
+                    glyph = xstrdup(glyph_names[*p]);
+                    aa = avl_probe(fd_cur->gl_tree, glyph);
+                    assert(aa != NULL);
+                }
+            }
+        }
+        make_subset_tag(fd_cur);
+        strncpy((char *) pdf->fb->data + t1_fontname_offset, fd_cur->subset_tag,6);
+    }
+    /*tex Now really all glyphs needed from this font are in the |fd_cur->gl_tree|. */
+    if (t1_encoding == ENC_STANDARD)
+        t1_puts(pdf, "/Encoding StandardEncoding def\n");
+    else {
+        t1_puts(pdf,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
+        gl_tree = create_t1_glyph_tree(glyph_names);
+        avl_t_init(&t, fd_cur->gl_tree);
+        j = 0;
+        for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL;
+             glyph = (char *) avl_t_next(&t)) {
+            if ((gg = (char **) avl_find(gl_tree, &glyph)) != NULL) {
+                t1_printf(pdf, "dup %i /%s put\n", (int) (gg - glyph_names),*gg);
+                j++;
+            }
+        }
+        destroy_t1_glyph_tree(gl_tree);
+        if (j == 0) {
+            /*tex
+                We didn't mark anything for the Encoding array. We add |{dup 0
+                /.notdef put}| for compatibility with Acrobat 5.0.
+            */
+            t1_puts(pdf, "dup 0 /.notdef put\n");
+        }
+        t1_puts(pdf, "readonly def\n");
+    }
+    do {
+        t1_getline();
+        t1_scan_param(pdf);
+        if (!t1_prefix("/UniqueID")) {
+            /*tex Ignore |/UniqueID| for subsetted fonts. */
+            t1_putline(pdf);
+        }
+    }
+    while (t1_in_eexec == 0);
+}
+
+static void cs_init(void)
+{
+    cs_ptr = cs_tab = NULL;
+    cs_dict_start = cs_dict_end = NULL;
+    cs_counter = cs_size = cs_size_pos = 0;
+    cs_token_pair = NULL;
+    subr_tab = NULL;
+    subr_array_start = subr_array_end = NULL;
+    subr_max = subr_size = subr_size_pos = 0;
+}
+
+static void init_cs_entry(cs_entry * cs)
+{
+    cs->data = NULL;
+    cs->name = NULL;
+    cs->len = 0;
+    cs->cslen = 0;
+    cs->used = false;
+    cs->valid = false;
+}
+
+static void t1_read_subrs(PDF pdf)
+{
+    int i, s;
+    cs_entry *ptr;
+    t1_getline();
+    while (!(t1_charstrings() || t1_subrs())) {
+        t1_scan_param(pdf);
+        if (!t1_prefix("/UniqueID")) {
+            /*tex Ignore |/UniqueID| for subsetted fonts. */
+            t1_putline(pdf);
+        }
+        t1_getline();
+    }
+  found:
+    t1_cs = true;
+    t1_scan = false;
+    if (!t1_subrs())
+        return;
+    subr_size_pos = strlen("/Subrs") + 1;
+    /*tex |subr_size_pos| points to the number indicating dict size after |Subrs|. */
+    subr_size = (int) t1_scan_num(t1_line_array + subr_size_pos, 0);
+    if (subr_size == 0) {
+        while (!t1_charstrings())
+            t1_getline();
+        return;
+    }
+    subr_tab = xtalloc((unsigned) subr_size, cs_entry);
+    for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+        init_cs_entry(ptr);
+    subr_array_start = xstrdup(t1_line_array);
+    t1_getline();
+    while (t1_cslen) {
+        store_subr();
+        t1_getline();
+    }
+    /*tex Mark the first four entries without parsing. */
+    for (i = 0; i < subr_size && i < 4; i++)
+        subr_tab[i].used = true;
+    /*tex
+
+        The end of the |Subrs| array might have more than one line so we need to
+        concatenate them to |subr_array_end|. Unfortunately some fonts don't have
+        the |Subrs| array followed by the |CharStrings| dict immediately (synthetic
+        fonts). If we cannot find |CharStrings| in next |POST_SUBRS_SCAN| lines
+        then we will treat the font as synthetic and ignore everything until next
+        |Subrs| is found.
+
+     */
+#define POST_SUBRS_SCAN 5
+    s = 0;
+    *t1_buf_array = 0;
+    for (i = 0; i < POST_SUBRS_SCAN; i++) {
+        if (t1_charstrings())
+            break;
+        s = (int) (s + t1_line_ptr - t1_line_array);
+        alloc_array(t1_buf, s, T1_BUF_SIZE);
+        strcat(t1_buf_array, t1_line_array);
+        t1_getline();
+    }
+    subr_array_end = xstrdup(t1_buf_array);
+    if (i == POST_SUBRS_SCAN) {
+        /*tex |CharStrings| not found: assume a synthetic font. */
+        for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+            if (ptr->valid)
+                xfree(ptr->data);
+        xfree(subr_tab);
+        xfree(subr_array_start);
+        xfree(subr_array_end);
+        cs_init();
+        t1_cs = false;
+        t1_synthetic = true;
+        while (!(t1_charstrings() || t1_subrs()))
+            t1_getline();
+        goto found;
+    }
+}
+
+#define t1_subr_flush()  t1_flush_cs(pdf, true)
+#define t1_cs_flush()    t1_flush_cs(pdf, false)
+
+static void t1_flush_cs(PDF pdf, boolean is_subr)
+{
+    char *p;
+    byte *r, *return_cs = NULL;
+    cs_entry *tab, *end_tab, *ptr;
+    char *start_line, *line_end;
+    int count, size_pos;
+    unsigned short cr, cs_len;
+    if (is_subr) {
+        start_line = subr_array_start;
+        line_end = subr_array_end;
+        size_pos = subr_size_pos;
+        tab = subr_tab;
+        count = subr_max + 1;
+        end_tab = subr_tab + count;
+    } else {
+        start_line = cs_dict_start;
+        line_end = cs_dict_end;
+        size_pos = cs_size_pos;
+        tab = cs_tab;
+        end_tab = cs_ptr;
+        count = cs_counter;
+    }
+    t1_line_ptr = t1_line_array;
+    for (p = start_line; p - start_line < size_pos;)
+        *t1_line_ptr++ = *p++;
+    while (isdigit((unsigned char)*p))
+        p++;
+    sprintf(t1_line_ptr, "%u", count);
+    strcat(t1_line_ptr, p);
+    t1_line_ptr = eol(t1_line_array);
+    t1_putline(pdf);
+    /*tex For |-Wall|. */
+    cs_len = 0;
+    /*tex Create |return_cs| to replace unsused |subr|s. */
+    if (is_subr) {
+        cr = 4330;
+        cs_len = 0;
+        /*tex
+            At this point we have |t1_lenIV >= 0;| a negative value would be
+            caught in |t1_scan_param|.
+        */
+        return_cs = xtalloc((unsigned) (t1_lenIV + 1), byte);
+        for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++)
+            *r = cencrypt(0x00, &cr);
+        *r = cencrypt(CS_RETURN, &cr);
+        cs_len++;
+    }
+    for (ptr = tab; ptr < end_tab; ptr++) {
+        if (ptr->used) {
+            if (is_subr)
+                sprintf(t1_line_array, "dup %li %u", (long int) (ptr - tab),
+                        ptr->cslen);
+            else
+                sprintf(t1_line_array, "/%s %u", ptr->name, ptr->cslen);
+            p = strend(t1_line_array);
+            memcpy(p, ptr->data, ptr->len);
+            t1_line_ptr = p + ptr->len;
+            t1_putline(pdf);
+        } else {
+            /*tex Replace unsused subr's by |return_cs|. */
+            if (is_subr) {
+                sprintf(t1_line_array, "dup %li %u%s ", (long int) (ptr - tab),
+                        cs_len, cs_token_pair[0]);
+                p = strend(t1_line_array);
+                memcpy(p, return_cs, cs_len);
+                t1_line_ptr = p + cs_len;
+                t1_putline(pdf);
+                sprintf(t1_line_array, " %s", cs_token_pair[1]);
+                t1_line_ptr = eol(t1_line_array);
+                t1_putline(pdf);
+            }
+        }
+        xfree(ptr->data);
+        if (is_subr)
+            ptr->valid = false;
+        if (ptr->name != notdef)
+            xfree(ptr->name);
+    }
+    sprintf(t1_line_array, "%s", line_end);
+    t1_line_ptr = eol(t1_line_array);
+    t1_putline(pdf);
+    if (is_subr) {
+        end_tab = subr_tab + subr_size;
+        for (ptr = tab; ptr < end_tab; ptr++) {
+            if (ptr->valid) {
+                xfree(ptr->data);
+                if (ptr->name != notdef)
+                    xfree(ptr->name);
+            }
+        }
+        xfree(return_cs);
+    }
+    xfree(tab);
+    xfree(start_line);
+    xfree(line_end);
+}
+
+static void t1_mark_glyphs(void)
+{
+    char *glyph;
+    struct avl_traverser t;
+    cs_entry *ptr;
+    if (t1_synthetic || fd_cur->all_glyphs) {
+        /*tex Mark everything. */
+        if (cs_tab != NULL)
+            for (ptr = cs_tab; ptr < cs_ptr; ptr++)
+                if (ptr->valid)
+                    ptr->used = true;
+        if (subr_tab != NULL) {
+            for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+                if (ptr->valid)
+                    ptr->used = true;
+            subr_max = subr_size - 1;
+        }
+        return;
+    }
+    mark_cs(notdef);
+    avl_t_init(&t, fd_cur->gl_tree);
+    for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL;
+         glyph = (char *) avl_t_next(&t)) {
+        mark_cs(glyph);
+    }
+    if (subr_tab != NULL)
+        for (subr_max = -1, ptr = subr_tab; ptr - subr_tab < subr_size; ptr++)
+            if (ptr->used && ptr - subr_tab > subr_max)
+                subr_max = (int) (ptr - subr_tab);
+}
+
+
+/*tex
+
+    When |t1_subset_charstrings| is called, the |t1_line_array| contains
+    |/CharStrings|. When we hit a case like this:
+
+    \starttyping
+     dup/CharStrings
+     229 dict dup begin
+    \stoptyping
+
+    we read the next line and concatenate to |t1_line_array| before moving on.
+    That is what |t1_check_unusual_charstring| is for.
+
+*/
+
+static void t1_check_unusual_charstring(void)
+{
+    char *p = strstr(t1_line_array, charstringname) + strlen(charstringname);
+    int i;
+    /*tex If no number follows |/CharStrings|, let's read the next line. */
+    if (sscanf(p, "%i", &i) != 1) {
+        strcpy(t1_buf_array, t1_line_array);
+        t1_getline();
+        strcat(t1_buf_array, t1_line_array);
+        strcpy(t1_line_array, t1_buf_array);
+        t1_line_ptr = eol(t1_line_array);
+    }
+}
+
+static void t1_subset_charstrings(PDF pdf)
+{
+    cs_entry *ptr;
+    t1_check_unusual_charstring();
+    cs_size_pos = (int) (strstr(t1_line_array, charstringname) + strlen(charstringname) - t1_line_array + 1);
+    /*tex |cs_size_pos| points to the number indicating dict size after |/CharStrings|. */
+    cs_size = (int) t1_scan_num(t1_line_array + cs_size_pos, 0);
+    cs_ptr = cs_tab = xtalloc((unsigned) cs_size, cs_entry);
+    for (ptr = cs_tab; ptr - cs_tab < cs_size; ptr++)
+        init_cs_entry(ptr);
+    cs_notdef = NULL;
+    cs_dict_start = xstrdup(t1_line_array);
+    t1_getline();
+    while (t1_cslen) {
+        store_cs();
+        t1_getline();
+    }
+    cs_dict_end = xstrdup(t1_line_array);
+    t1_mark_glyphs();
+    if (subr_tab != NULL) {
+        if (cs_token_pair == NULL)
+            formatted_error("type 1","mismatched subroutine begin/end token pairs");
+        t1_subr_flush();
+    }
+    for (cs_counter = 0, ptr = cs_tab; ptr < cs_ptr; ptr++)
+        if (ptr->used)
+            cs_counter++;
+    t1_cs_flush();
+}
+
+static void t1_subset_end(PDF pdf)
+{
+    if (t1_synthetic) {
+        /*tex Copy to |dup /FontName get exch definefont pop|. */
+        while (!strstr(t1_line_array, "definefont")) {
+            t1_getline();
+            t1_putline(pdf);
+        }
+        while (!t1_end_eexec()) {
+            /*tex Ignore the rest. */
+            t1_getline();
+        }
+        /*tex Write \.{mark currentfile closefile}. */
+        t1_putline(pdf);
+    } else {
+        while (!t1_end_eexec()) {
+            /*tex Copy to \.{mark currentfile closefile}. */
+            t1_getline();
+            t1_putline(pdf);
+        }
+    }
+    t1_stop_eexec(pdf);
+    if (fixedcontent) {
+        /*tex Copy 512 zeros (not needed for PDF). */
+        while (!t1_cleartomark()) {
+            t1_getline();
+            t1_putline(pdf);
+        }
+        /*tex Don't check \.{{restore}if} for synthetic fonts. */
+        if (!t1_synthetic) {
+            /*tex Write \.{{restore}if} if found. */
+            t1_check_end(pdf);
+        }
+    }
+    get_length3();
+}
+
+void writet1(PDF pdf, fd_entry * fd)
+{
+    /*tex |fd_cur| is global inside |writet1.c|. */
+    fd_cur = fd;
+    assert(fd_cur->fm != NULL);
+    assert(is_type1(fd->fm));
+    assert(is_included(fd->fm));
+
+    t1_save_offset = 0;
+    if (!is_subsetted(fd_cur->fm)) {
+        /*tex Include entire font. */
+        if (!(fd->ff_found = t1_open_fontfile(filetype_font)))
+            return;
+        t1_include(pdf);
+        t1_close_font_file(filetype_font);
+        xfree(t1_buffer);
+        return;
+    }
+    /*tex Partial downloading. */
+    if (!(fd->ff_found = t1_open_fontfile(filetype_subset)))
+        return;
+    t1_subset_ascii_part(pdf);
+    t1_start_eexec(pdf);
+    cc_init();
+    cs_init();
+    t1_read_subrs(pdf);
+    t1_subset_charstrings(pdf);
+    t1_subset_end(pdf);
+    t1_close_font_file(filetype_subset);
+    xfree(t1_buffer);
+}
+
+void t1_free(void)
+{
+    xfree(t1_line_array);
+    xfree(t1_buf_array);
+}

Deleted: trunk/Build/source/texk/web2c/luatexdir/font/writet1.w
===================================================================
--- trunk/Build/source/texk/web2c/luatexdir/font/writet1.w	2018-09-05 21:35:27 UTC (rev 48593)
+++ trunk/Build/source/texk/web2c/luatexdir/font/writet1.w	2018-09-05 21:57:30 UTC (rev 48594)
@@ -1,1739 +0,0 @@
-% writet1.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2009 Taco Hoekwater <taco@@luatex.org>
-%
-% This file is part of LuaTeX.
-%
-% LuaTeX is free software; you can redistribute it and/or modify it under
-% the terms of the GNU General Public License as published by the Free
-% Software Foundation; either version 2 of the License, or (at your
-% option) any later version.
-%
-% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
-% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-% License for more details.
-%
-% You should have received a copy of the GNU General Public License along
-% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include <string.h>
-
-#define get_length1()    t1_length1 = t1_offset() - t1_save_offset
-#define get_length2()    t1_length2 = t1_offset() - t1_save_offset
-#define get_length3()    t1_length3 = fixedcontent? t1_offset() - t1_save_offset : 0
-#define save_offset()    t1_save_offset = t1_offset()
-
-#define t1_putchar(A)       strbuf_putchar(pdf->fb, (A))
-#define t1_offset()         strbuf_offset(pdf->fb)
-#define out_eexec_char      t1_putchar
-
-#define end_last_eexec_line() \
-    t1_eexec_encrypt = false
-#define t1_char(c)          c
-#define embed_all_glyphs(tex_font)  fm_cur->all_glyphs
-#define extra_charset()     fm_cur->charset
-#define fixedcontent        false
-
-int t1_length1, t1_length2, t1_length3;
-static int t1_save_offset;
-static int t1_fontname_offset;
-
-static unsigned char *t1_buffer = NULL;
-static int t1_size = 0;
-static int t1_curbyte = 0;
-@ @c
-#define t1_read_file()  \
-    readbinfile(t1_file,&t1_buffer,&t1_size)
-#define t1_close()      xfclose(t1_file,cur_file_name)
-#define t1_getchar()    t1_buffer[t1_curbyte++]
-#define t1_ungetchar(c) t1_curbyte--
-#define t1_eof()        (t1_curbyte>t1_size)
-
-#define t1_prefix(s)        str_prefix(t1_line_array, s)
-#define t1_buf_prefix(s)    str_prefix(t1_buf_array, s)
-#define t1_suffix(s)        str_suffix(t1_line_array, t1_line_ptr, s)
-#define t1_buf_suffix(s)    str_suffix(t1_buf_array, t1_buf_ptr, s)
-#define t1_charstrings()    strstr(t1_line_array, charstringname)
-#define t1_subrs()          t1_prefix("/Subrs")
-#define t1_end_eexec()      t1_suffix("mark currentfile closefile")
-#define t1_cleartomark()    t1_prefix("cleartomark")
-
-static unsigned char *enc_buffer = NULL;
-static int enc_size = 0;
-static int enc_curbyte = 0;
-
-@ @c
-#define enc_open(a)          \
-    (enc_file = fopen((char *)(a), FOPEN_RBIN_MODE))
-#define enc_read_file()  \
-    readbinfile(enc_file,&enc_buffer,&enc_size)
-#define enc_close()       xfclose(enc_file,cur_file_name)
-#define enc_getchar()    enc_buffer[enc_curbyte++]
-#define enc_eof()        (enc_curbyte>enc_size)
-
-#define valid_code(c)   (c >= 0 && c < 256)
-#define fixedcontent     false
-
-@ @c
-static const char *standard_glyph_names[256] = {
-    /* 0x00 */
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    /* 0x10 */
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    /* 0x20 */
-    "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
-    "ampersand", "quoteright", "parenleft", "parenright", "asterisk",
-    "plus", "comma", "hyphen", "period", "slash",
-    /* 0x30 */
-    "zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
-    "nine", "colon", "semicolon", "less", "equal", "greater", "question",
-    /* 0x40 */
-    "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
-    "O",
-    /* 0x50 */
-    "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
-    "backslash", "bracketright", "asciicircum", "underscore",
-    /* 0x60 */
-    "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l",
-    "m", "n", "o",
-    /* 0x70 */
-    "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar",
-    "braceright", "asciitilde", notdef,
-    /* 0x80 */
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    /* 0x90 */
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    /* 0xa0 */
-    notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin",
-    "section", "currency", "quotesingle", "quotedblleft", "guillemotleft",
-    "guilsinglleft", "guilsinglright", "fi", "fl",
-    /* 0xb0 */
-    notdef, "endash", "dagger", "daggerdbl", "periodcentered", notdef,
-    "paragraph", "bullet", "quotesinglbase", "quotedblbase",
-    "quotedblright", "guillemotright", "ellipsis", "perthousand", notdef,
-    "questiondown",
-    /* 0xc0 */
-    notdef, "grave", "acute", "circumflex", "tilde", "macron", "breve",
-    "dotaccent", "dieresis", notdef,
-    "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron",
-    /* 0xd0 */
-    "emdash", notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    notdef, notdef, notdef, notdef, notdef, notdef, notdef,
-    /* 0xe0 */
-    notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef,
-    "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef,
-    notdef,
-    /* 0xf0 */
-    notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef, "lslash",
-    "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef
-};
-
-@ @c
-static fd_entry *fd_cur;
-
-static char charstringname[] = "/CharStrings";
-
-enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
-
-#define T1_BUF_SIZE   0x10
-#define ENC_BUF_SIZE  0x1000
-
-@ @c
-#define CS_HSTEM            1
-#define CS_VSTEM            3
-#define CS_VMOVETO          4
-#define CS_RLINETO          5
-#define CS_HLINETO          6
-#define CS_VLINETO          7
-#define CS_RRCURVETO        8
-#define CS_CLOSEPATH        9
-#define CS_CALLSUBR         10
-#define CS_RETURN           11
-#define CS_ESCAPE           12
-#define CS_HSBW             13
-#define CS_ENDCHAR          14
-#define CS_RMOVETO          21
-#define CS_HMOVETO          22
-#define CS_VHCURVETO        30
-#define CS_HVCURVETO        31
-#define CS_1BYTE_MAX        (CS_HVCURVETO + 1)
-
-#define CS_DOTSECTION       CS_1BYTE_MAX + 0
-#define CS_VSTEM3           CS_1BYTE_MAX + 1
-#define CS_HSTEM3           CS_1BYTE_MAX + 2
-#define CS_SEAC             CS_1BYTE_MAX + 6
-#define CS_SBW              CS_1BYTE_MAX + 7
-#define CS_DIV              CS_1BYTE_MAX + 12
-#define CS_CALLOTHERSUBR    CS_1BYTE_MAX + 16
-#define CS_POP              CS_1BYTE_MAX + 17
-#define CS_SETCURRENTPOINT  CS_1BYTE_MAX + 33
-#define CS_2BYTE_MAX        (CS_SETCURRENTPOINT + 1)
-#define CS_MAX              CS_2BYTE_MAX
-
-@ @c
-typedef unsigned char byte;
-
-typedef struct {
-    byte nargs;                 /* number of arguments */
-    boolean bottom;             /* take arguments from bottom of stack? */
-    boolean clear;              /* clear stack? */
-    boolean valid;
-} cc_entry;                     /* CharString Command */
-
-typedef struct {
-    char *name;                 /* glyph name (or notdef for Subrs entry) */
-    byte *data;
-    unsigned short len;         /* length of the whole string */
-    unsigned short cslen;       /* length of the encoded part of the string */
-    boolean used;
-    boolean valid;
-} cs_entry;
-
-static unsigned short t1_dr, t1_er;
-static const unsigned short t1_c1 = 52845, t1_c2 = 22719;
-static unsigned short t1_cslen;
-static short t1_lenIV;
-static char enc_line[ENC_BUF_SIZE];
-
-@ define |t1_line_ptr|, |t1_line_array|, and |t1_line_limit|
- at c
-#define t1_line_entry char
-define_array(t1_line);
-
-@ define |t1_buf_ptr|, |t1_buf_array|, and |t1_buf_limit|
- at c
-#define t1_buf_entry char
-define_array(t1_buf);
-
-static int cs_start;
-
-static cs_entry *cs_tab, *cs_ptr, *cs_notdef;
-static char *cs_dict_start, *cs_dict_end;
-static int cs_counter, cs_size, cs_size_pos;
-
-static cs_entry *subr_tab;
-static char *subr_array_start, *subr_array_end;
-static int subr_max, subr_size, subr_size_pos;
-
-@ This list contains the begin/end tokens commonly used in the
-/Subrs array of a Type 1 font.
-
- at c
-static const char *cs_token_pairs_list[][2] = {
-    {" RD", "NP"},
-    {" -|", "|"},
-    {" RD", "noaccess put"},
-    {" -|", "noaccess put"},
-    {NULL, NULL}
-};
-
-@ @c
-static const char **cs_token_pair;
-
-static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
-static int t1_in_eexec;         /* 0 before eexec-encrypted, 1 during, 2 after */
-static long t1_block_length;
-static int last_hexbyte;
-static FILE *t1_file;
-static FILE *enc_file;
-
-@ @c
-static void enc_getline(void)
-{
-    char *p;
-    char c;
-  restart:
-    if (enc_eof())
-        normal_error("type 1","unexpected end of file");
-    p = enc_line;
-    do {
-        c = (char) enc_getchar();
-        append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE);
-    }
-    while (c != 10 && !enc_eof());
-    append_eol(p, enc_line, ENC_BUF_SIZE);
-    if (p - enc_line < 2 || *enc_line == '%')
-        goto restart;
-}
-
-@ read encoding from .enc file, return |glyph_names array|, or |pdffail()|
- at c
-char **load_enc_file(char *enc_name)
-{
-    int callback_id = 0;
-    int file_opened = 0;
-
-    char buf[ENC_BUF_SIZE], *p, *r;
-    int i, names_count;
-    char **glyph_names;
-
-    cur_file_name = luatex_find_file(enc_name, find_enc_file_callback);
-
-    if (cur_file_name == NULL) {
-        formatted_error("type 1","cannot find encoding file '%s' for reading", enc_name);
-    }
-    callback_id = callback_defined(read_enc_file_callback);
-    enc_curbyte = 0;
-    enc_size = 0;
-    if (callback_id > 0) {
-        if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &enc_buffer, &enc_size)) {
-            if ((!file_opened) || enc_size == 0) {
-                formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
-            }
-        }
-    } else {
-        if (!enc_open(cur_file_name)) {
-            formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name);
-        }
-        enc_read_file();
-        enc_close();
-    }
-    glyph_names = xtalloc(256, char *);
-    for (i = 0; i < 256; i++)
-        glyph_names[i] = (char *) notdef;
-    report_start_file(filetype_map,cur_file_name);
-    enc_getline();
-    if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) {
-        remove_eol(r, enc_line);
-        formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line);
-    }
-    names_count = 0;
-    r++;                        /* skip '[' */
-    skip_char(r, ' ');
-    for (;;) {
-        while (*r == '/') {
-            for (p = buf, r++;
-                 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
-            *p = 0;
-            skip_char(r, ' ');
-            if (names_count >= 256)
-                normal_error("type 1","encoding vector contains more than 256 names");
-            if (strcmp(buf, notdef) != 0)
-                glyph_names[names_count] = xstrdup(buf);
-            names_count++;
-        }
-        if (*r != 10 && *r != '%') {
-            if (strncmp(r, "] def", strlen("] def")) == 0)
-                goto done;
-            else {
-                remove_eol(r, enc_line);
-                formatted_error("type 1","invalid encoding vector: a name or '] def' expected: `%s'",enc_line);
-            }
-        }
-        enc_getline();
-        r = enc_line;
-    }
-  done:
-    report_stop_file(filetype_map);
-    cur_file_name = NULL;
-    xfree(enc_buffer);
-    return glyph_names;
-}
-
-@ @c
-#if 0
-static void free_glyph_names(char **glyph_names)
-{
-    int i;
-    assert(glyph_names != NULL);
-    for (i = 0; i < 256; i++)
-        if (glyph_names[i] != notdef)
-            xfree(glyph_names[i]);
-    xfree(glyph_names);
-}
-#endif
-
-static void t1_check_pfa(void)
-{
-    const int c = t1_getchar();
-    t1_pfa = (c != 128) ? true : false;
-    t1_ungetchar(c);
-}
-
-static int t1_getbyte(void)
-{
-    int c = t1_getchar();
-    if (t1_pfa)
-        return c;
-    if (t1_block_length == 0) {
-        if (c != 128)
-            normal_error("type 1","invalid marker");
-        c = t1_getchar();
-        if (c == 3) {
-            while (!t1_eof())
-                (void) t1_getchar();
-            return EOF;
-        }
-        t1_block_length = t1_getchar() & 0xff;
-        t1_block_length |= (t1_getchar() & 0xff) << 8;
-        t1_block_length |= (t1_getchar() & 0xff) << 16;
-        t1_block_length |= (t1_getchar() & 0xff) << 24;
-        c = t1_getchar();
-    }
-    t1_block_length--;
-    return c;
-}
-
-static int hexval(int c)
-{
-    if (c >= 'A' && c <= 'F')
-        return c - 'A' + 10;
-    else if (c >= 'a' && c <= 'f')
-        return c - 'a' + 10;
-    else if (c >= '0' && c <= '9')
-        return c - '0';
-    else
-        return -1;
-}
-
-static byte edecrypt(byte cipher)
-{
-    byte plain;
-    if (t1_pfa) {
-        while (cipher == 10 || cipher == 13)
-            cipher = (byte) t1_getbyte();
-        last_hexbyte = cipher =
-            (byte) ((hexval(cipher) << 4) + hexval(t1_getbyte()));
-    }
-    plain = (byte) (cipher ^ (t1_dr >> 8));
-    t1_dr = (unsigned short) ((cipher + t1_dr) * t1_c1 + t1_c2);
-    return plain;
-}
-
-static byte cdecrypt(byte cipher, unsigned short *cr)
-{
-    const byte plain = (byte) (cipher ^ (*cr >> 8));
-    *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
-    return plain;
-}
-
-static byte eencrypt(byte plain)
-{
-    const byte cipher = (byte) (plain ^ (t1_er >> 8));
-    t1_er = (unsigned short) ((cipher + t1_er) * t1_c1 + t1_c2);
-    return cipher;
-}
-
-static byte cencrypt(byte plain, unsigned short *cr)
-{
-    const byte cipher = (byte) (plain ^ (*cr >> 8));
-    *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2);
-    return cipher;
-}
-
-static char *eol(char *s)
-{
-    char *p = strend(s);
-    if (p - s > 1 && p[-1] != 10) {
-        *p++ = 10;
-        *p = 0;
-    }
-    return p;
-}
-
-static float t1_scan_num(char *p, char **r)
-{
-    float f;
-    skip_char(p, ' ');
-    if (sscanf(p, "%g", &f) != 1) {
-        remove_eol(p, t1_line_array);
-        formatted_error("type 1","a number expected: '%s'", t1_line_array);
-    }
-    if (r != NULL) {
-        for (; isdigit((unsigned char)*p) || *p == '.' ||
-             *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
-        *r = p;
-    }
-    return f;
-}
-
-static boolean str_suffix(const char *begin_buf, const char *end_buf,
-                          const char *s)
-{
-    const char *s1 = end_buf - 1, *s2 = strend(s) - 1;
-    if (*s1 == 10)
-        s1--;
-    while (s1 >= begin_buf && s2 >= s) {
-        if (*s1-- != *s2--)
-            return false;
-    }
-    return s2 < s;
-}
-
-@ @c
-static void t1_getline(void)
-{
-    int c, l, eexec_scan;
-    char *p;
-    static const char eexec_str[] = "currentfile eexec";
-    static int eexec_len = 17;  /* |strlen(eexec_str)| */
-  restart:
-    if (t1_eof())
-        normal_error("type 1","unexpected end of file");
-    t1_line_ptr = t1_line_array;
-    alloc_array(t1_line, 1, T1_BUF_SIZE);
-    t1_cslen = 0;
-    eexec_scan = 0;
-    c = t1_getbyte();
-    if (c == EOF)
-        goto exit;
-    while (!t1_eof()) {
-        if (t1_in_eexec == 1)
-            c = edecrypt((byte) c);
-        alloc_array(t1_line, 1, T1_BUF_SIZE);
-        {
-            char cc = (char) c;
-            append_char_to_buf(cc, t1_line_ptr, t1_line_array, t1_line_limit);
-        }
-        if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
-            if (t1_line_array[eexec_scan] == eexec_str[eexec_scan])
-                eexec_scan++;
-            else
-                eexec_scan = -1;
-        }
-        if (c == 10 || c == 13
-            || (t1_pfa && eexec_scan == eexec_len && c == 32)) {
-            break;
-        }
-        if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) &&
-            (t1_suffix(" RD ") || t1_suffix(" -| "))) {
-            p = t1_line_ptr - 5;
-            while (*p != ' ')
-                p--;
-            l = (int) t1_scan_num(p + 1, 0);
-            t1_cslen = (unsigned short) l;
-            cs_start = (int) (t1_line_ptr - t1_line_array);     /* |cs_start| is an index now */
-            alloc_array(t1_line, l, T1_BUF_SIZE);
-            while (l-- > 0)
-                *t1_line_ptr++ = (t1_line_entry) edecrypt((byte) t1_getbyte());
-        }
-        c = t1_getbyte();
-    }
-    alloc_array(t1_line, 2, T1_BUF_SIZE);       /* |append_eol| can append 2 chars */
-    append_eol(t1_line_ptr, t1_line_array, t1_line_limit);
-    if (t1_line_ptr - t1_line_array < 2)
-        goto restart;
-    if (eexec_scan == eexec_len)
-        t1_in_eexec = 1;
-  exit:
-    /* ensure that |t1_buf_array| has as much room as |t1_line_array| */
-    t1_buf_ptr = t1_buf_array;
-    alloc_array(t1_buf, t1_line_limit, t1_line_limit);
-}
-
-@ @c
-static void t1_putline(PDF pdf)
-{
-    char *p = t1_line_array;
-    if (t1_line_ptr - t1_line_array <= 1)
-        return;
-    if (t1_eexec_encrypt) {
-        while (p < t1_line_ptr)
-            t1_putchar((eight_bits) eencrypt((byte) * p++));
-    } else
-        while (p < t1_line_ptr)
-            t1_putchar((eight_bits) * p++);
-}
-
-static void t1_puts(PDF pdf, const char *s)
-{
-    if (s != t1_line_array)
-        strcpy(t1_line_array, s);
-    t1_line_ptr = strend(t1_line_array);
-    t1_putline(pdf);
-}
-
-__attribute__ ((format(printf, 2, 3)))
-static void t1_printf(PDF pdf, const char *fmt, ...)
-{
-    va_list args;
-    va_start(args, fmt);
-    vsprintf(t1_line_array, fmt, args);
-    t1_puts(pdf, t1_line_array);
-    va_end(args);
-}
-
-@ @c
-static void t1_init_params(int open_name_prefix)
-{
-    report_start_file(open_name_prefix,cur_file_name);
-    t1_lenIV = 4;
-    t1_dr = 55665;
-    t1_er = 55665;
-    t1_in_eexec = 0;
-    t1_cs = false;
-    t1_scan = true;
-    t1_synthetic = false;
-    t1_eexec_encrypt = false;
-    t1_block_length = 0;
-    t1_check_pfa();
-}
-
-static void t1_close_font_file(int close_name_suffix)
-{
-    report_stop_file(close_name_suffix);
-    cur_file_name = NULL;
-}
-
-static void t1_check_block_len(boolean decrypt)
-{
-    int l, c;
-    if (t1_block_length == 0)
-        return;
-    c = t1_getbyte();
-    if (decrypt)
-        c = edecrypt((byte) c);
-    l = (int) t1_block_length;
-    if (!(l == 0 && (c == 10 || c == 13))) {
-        formatted_error("type 1","%i bytes more than expected were ignored", l + 1);
-    }
-}
-
-@ @c
-static void t1_start_eexec(PDF pdf)
-{
-    int i;
-    assert(is_included(fd_cur->fm));
-    get_length1();
-    save_offset();
-
-    if (!t1_pfa)
-        t1_check_block_len(false);
-    for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) {
-        edecrypt((byte) t1_getbyte());
-        *t1_line_ptr++ = 0;
-    }
-    t1_eexec_encrypt = true;
-    t1_putline(pdf);            /* to put the first four bytes */
-}
-
-static void t1_stop_eexec(PDF pdf)
-{
-    int c;
-    assert(is_included(fd_cur->fm));
-    get_length2();
-    save_offset();
-    t1_eexec_encrypt = false;
-    if (!t1_pfa)
-        t1_check_block_len(true);
-    else {
-        c = edecrypt((byte) t1_getbyte());
-        if (!(c == 10 || c == 13)) {
-            if (last_hexbyte == 0)
-                t1_puts(pdf, "00");
-            else
-                normal_error("type 1","unexpected data after eexec");
-        }
-    }
-    t1_cs = false;
-    t1_in_eexec = 2;
-}
-
-@ macros for various transforms; unused, left for reference
-
- at c
-#ifdef T1TRANSFORMMACROS
-#  define do_xshift(x,a) {x[4]+=a;}
-#  define do_yshift(x,a) {x[5]+=a;}
-#  define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;}
-#  define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;}
-#  define do_extend(x,a) {do_xscale(x,a);}
-#  define do_scale(x,a)  {do_xscale(x,a); do_yscale(x,a);}
-#  define do_slant(x,a)  {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);}
-#  define do_shear(x,a)  {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);}
-#  define do_rotate(x,a)          \
-  {float t, u=cos(a), v=sin(a); \
-  t    =x[0]*u+x[1]*-v;         \
-  x[1] =x[0]*v+x[1]* u; x[0]=t; \
-  t    =x[2]*u+x[3]*-v;         \
-  x[3] =x[2]*v+x[3]* u; x[2]=t; \
-  t    =x[4]*u+x[5]*-v;         \
-  x[5] =x[4]*v+x[5]* u; x[4]=t;}
-#endif
-
-@ @c
-static void t1_scan_keys(PDF pdf)
-{
-    int i, k;
-    char *p, *q, *r;
-    const key_entry *key;
-    if (t1_prefix("/FontType")) {
-        p = t1_line_array + strlen("FontType") + 1;
-        if ((i = (int) t1_scan_num(p, 0)) != 1)
-            formatted_error("type 1","Type%d fonts unsupported by backend", i);
-        return;
-    }
-    for (key = (const key_entry *) font_key; key - font_key < FONT_KEYS_NUM;
-         key++) {
-        if (key->t1name[0] != '\0'
-            && str_prefix(t1_line_array + 1, key->t1name))
-            break;
-    }
-    if (key - font_key == FONT_KEYS_NUM)
-        return;
-    p = t1_line_array + strlen(key->t1name) + 1;
-    skip_char(p, ' ');
-    if ((k = (int) (key - font_key)) == FONTNAME_CODE) {
-        if (*p != '/') {
-            remove_eol(p, t1_line_array);
-            formatted_error("type 1","a name expected: '%s'", t1_line_array);
-        }
-        r = ++p;                /* skip the slash */
-        for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++);
-        *q = 0;
-        xfree(fd_cur->fontname);
-        fd_cur->fontname = xstrdup(t1_buf_array);
-        /* at this moment we cannot call |make_subset_tag()| yet, as the encoding
-         is not read; thus we mark the offset of the subset tag and write it
-         later */
-        if (is_subsetted(fd_cur->fm)) {
-            assert(is_included(fd_cur->fm));
-            t1_fontname_offset = (int) (t1_offset() + (r - t1_line_array));
-            strcpy(t1_buf_array, p);
-            sprintf(r, "ABCDEF+%s%s", fd_cur->fontname, t1_buf_array);
-            t1_line_ptr = eol(r);
-        }
-        return;
-    }
-    if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && (*p == '[' || *p == '{'))
-        p++;
-    if (k == FONTBBOX1_CODE) {
-        for (i = 0; i < 4; i++, k++) {
-            fd_cur->font_dim[k].val = (int) t1_scan_num(p, &r);
-            fd_cur->font_dim[k].set = true;
-            p = r;
-        }
-        return;
-    }
-    fd_cur->font_dim[k].val = (int) t1_scan_num(p, 0);
-    fd_cur->font_dim[k].set = true;
-}
-
-@ @c
-static void t1_scan_param(PDF pdf)
-{
-    static const char *lenIV = "/lenIV";
-    if (!t1_scan || *t1_line_array != '/')
-        return;
-    if (t1_prefix(lenIV)) {
-        t1_lenIV = (short) t1_scan_num(t1_line_array + strlen(lenIV), 0);
-        if (t1_lenIV < 0)
-            normal_error("type 1","negative value of lenIV is not supported");
-        return;
-    }
-    t1_scan_keys(pdf);
-}
-
-static void copy_glyph_names(char **glyph_names, int a, int b)
-{
-    if (glyph_names[b] != notdef) {
-        xfree(glyph_names[b]);
-        glyph_names[b] = (char *) notdef;
-    }
-    if (glyph_names[a] != notdef) {
-        glyph_names[b] = xstrdup(glyph_names[a]);
-    }
-}
-
-@ read encoding from Type1 font file, return |glyph_names| array, or |pdffail()|
-
- at c
-static char **t1_builtin_enc(void)
-{
-    int i, a, b, c, counter = 0;
-    char *r, *p, **glyph_names;
-    /* At this moment \.{/Encoding} is the prefix of |t1_line_array| */
-    glyph_names = xtalloc(256, char *);
-    for (i = 0; i < 256; i++)
-        glyph_names[i] = (char *) notdef;
-    if (t1_suffix("def")) {     /* predefined encoding */
-        sscanf(t1_line_array + strlen("/Encoding"), "%255s", t1_buf_array);
-        if (strcmp(t1_buf_array, "StandardEncoding") == 0) {
-            t1_encoding = ENC_STANDARD;
-            for (i = 0; i < 256; i++) {
-                if (standard_glyph_names[i] != notdef)
-                    glyph_names[i] = xstrdup(standard_glyph_names[i]);
-            }
-            return glyph_names;
-        } else
-            formatted_error("type 1","cannot subset font (unknown predefined encoding '%s')",t1_buf_array);
-    }
-    /* At this moment \.{/Encoding} is the prefix of |t1_line_array|, and the encoding is
-     not a predefined encoding.
-
-      We have two possible forms of Encoding vector. The first case is
-
-          \.{/Encoding [/a /b /c...] readonly def}
-
-      and the second case can look like
-
-      {\obeylines
-          \.{/Encoding 256 array 0 1 255 {1 index exch /.notdef put} for}
-          \.{dup 0 /x put}
-          \.{dup 1 /y put}
-          \.{...}
-          \.{readonly def}}
-     */
-    t1_encoding = ENC_BUILTIN;
-    if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) {  /* the first case */
-        r = strchr(t1_line_array, '[') + 1;
-        skip_char(r, ' ');
-        for (;;) {
-            while (*r == '/') {
-                for (p = t1_buf_array, r++;
-                     *r != 32 && *r != 10 && *r != ']' && *r != '/';
-                     *p++ = *r++);
-                *p = 0;
-                skip_char(r, ' ');
-                if (counter > 255)
-                    normal_error("type 1","encoding vector contains more than 256 names");
-                if (strcmp(t1_buf_array, notdef) != 0)
-                    glyph_names[counter] = xstrdup(t1_buf_array);
-                counter++;
-            }
-            if (*r != 10 && *r != '%') {
-                if (str_prefix(r, "] def") || str_prefix(r, "] readonly def"))
-                    break;
-                else {
-                    remove_eol(r, t1_line_array);
-                    formatted_error("type 1","a name or '] def' or '] readonly def' expected: '%s'", t1_line_array);
-                }
-            }
-            t1_getline();
-            r = t1_line_array;
-        }
-    } else {                    /* the second case */
-        p = strchr(t1_line_array, 10);
-        for (;;) {
-            if (*p == 10) {
-                t1_getline();
-                p = t1_line_array;
-            }
-            /*
-               check for \.{dup <index> <glyph> put}
-             */
-            if (sscanf(p, "dup %i%255s put", &i, t1_buf_array) == 2 &&
-                *t1_buf_array == '/' && valid_code(i)) {
-                if (strcmp(t1_buf_array + 1, notdef) != 0)
-                    glyph_names[i] = xstrdup(t1_buf_array + 1);
-                p = strstr(p, " put") + strlen(" put");
-                skip_char(p, ' ');
-            }
-            /*
-               check for \.{dup dup <to> exch <from> get put}
-             */
-            else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2
-                     && valid_code(a) && valid_code(b)) {
-                copy_glyph_names(glyph_names, a, b);
-                p = strstr(p, " get put") + strlen(" get put");
-                skip_char(p, ' ');
-            }
-            /*
-               check for \.{dup dup <from> <size> getinterval <to> exch putinterval}
-             */
-            else if (sscanf
-                     (p, "dup dup %i %i getinterval %i exch putinterval",
-                      &a, &c, &b) == 3 && valid_code(a) && valid_code(b)
-                     && valid_code(c)) {
-                for (i = 0; i < c; i++)
-                    copy_glyph_names(glyph_names, a + i, b + i);
-                p = strstr(p, " putinterval") + strlen(" putinterval");
-                skip_char(p, ' ');
-            }
-            /*
-               check for \.{def} or \.{readonly def}
-             */
-            else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' '))
-                     && strcmp(p, "def\n") == 0)
-                return glyph_names;
-            /*
-               skip an unrecognizable word
-             */
-            else {
-                while (*p != ' ' && *p != 10)
-                    p++;
-                skip_char(p, ' ');
-            }
-        }
-    }
-    return glyph_names;
-}
-
-
-@
- at c
-static void t1_check_end(PDF pdf)
-{
-    if (t1_eof())
-        return;
-    t1_getline();
-    if (t1_prefix("{restore}"))
-        t1_putline(pdf);
-}
-
-@
- at c
-static boolean t1_open_fontfile(int open_name_prefix)
-{
-    ff_entry *ff;
-    int callback_id = 0;
-    int file_opened = 0;
-    t1_curbyte = 0;
-    t1_size = 0;
-    ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm));
-    if (ff->ff_path == NULL) {
-        formatted_error("type 1","cannot open file for reading '%s'",fd_cur->fm->ff_name);
-        return false;
-    }
-    cur_file_name = luatex_find_file(ff->ff_path, find_type1_file_callback);
-    if (cur_file_name == NULL) {
-        formatted_error("type 1","cannot open file for reading '%s'", ff->ff_path);
-        return false;
-    }
-    callback_id = callback_defined(read_type1_file_callback);
-    if (callback_id > 0) {
-        if (!run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &t1_buffer, &t1_size)
-            && file_opened && t1_size > 0) {
-            formatted_warning("type 1","cannot open file for reading '%s'",cur_file_name);
-            return false;
-        }
-    } else {
-        t1_file = xfopen(cur_file_name, FOPEN_RBIN_MODE);
-        t1_read_file();
-        t1_close();
-    }
-    recorder_record_input(cur_file_name);
-    t1_init_params(open_name_prefix);
-    return true;
-}
-
-static void t1_include(PDF pdf)
-{
-    do {
-        t1_getline();
-        t1_scan_param(pdf);
-        t1_putline(pdf);
-    }
-    while (t1_in_eexec == 0);
-    t1_start_eexec(pdf);
-    do {
-        t1_getline();
-        t1_scan_param(pdf);
-        t1_putline(pdf);
-    }
-    while (!(t1_charstrings() || t1_subrs()));
-    t1_cs = true;
-    do {
-        t1_getline();
-        t1_putline(pdf);
-    }
-    while (!t1_end_eexec());
-    t1_stop_eexec(pdf);
-    if (fixedcontent) {         /* copy 512 zeros (not needed for PDF) */
-        do {
-            t1_getline();
-            t1_putline(pdf);
-        }
-        while (!t1_cleartomark());
-        t1_check_end(pdf);      /* write "{restore}if" if found */
-    }
-    get_length3();
-}
-
-@
- at c
-#define check_subr(subr) \
-    if (subr >= subr_size || subr < 0) \
-        formatted_error("type 1","Subrs array: entry index out of range '%i'", subr);
-
-static const char **check_cs_token_pair(void)
-{
-    const char **p = (const char **) cs_token_pairs_list;
-    for (; p[0] != NULL; ++p)
-        if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1]))
-            return p;
-    return NULL;
-}
-
-static void cs_store(boolean is_subr)
-{
-    char *p;
-    cs_entry *ptr;
-    int subr;
-    for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' ';
-         *t1_buf_ptr++ = *p++);
-    *t1_buf_ptr = 0;
-    if (is_subr) {
-        subr = (int) t1_scan_num(p + 1, 0);
-        check_subr(subr);
-        ptr = subr_tab + subr;
-    } else {
-        ptr = cs_ptr++;
-        if (cs_ptr - cs_tab > cs_size)
-            formatted_error("type 1","CharStrings dict: more entries than dict size '%i'", cs_size);
-        if (strcmp(t1_buf_array + 1, notdef) == 0)      /* skip the slash */
-            ptr->name = (char *) notdef;
-        else
-            ptr->name = xstrdup(t1_buf_array + 1);
-    }
-    /* copy |" RD " + cs data| to |t1_buf_array| */
-    memcpy(t1_buf_array, t1_line_array + cs_start - 4,
-           (unsigned) (t1_cslen + 4));
-    /* copy the end of cs data to |t1_buf_array| */
-    for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr =
-         t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++);
-    *t1_buf_ptr++ = 10;
-    if (is_subr && cs_token_pair == NULL)
-        cs_token_pair = check_cs_token_pair();
-    ptr->len = (unsigned short) (t1_buf_ptr - t1_buf_array);
-    ptr->cslen = t1_cslen;
-    xfree(ptr->data);           /* mem leak? */
-    ptr->data = xtalloc(ptr->len, byte);
-    memcpy(ptr->data, t1_buf_array, ptr->len);
-    ptr->valid = true;
-}
-
-@
- at c
-#define store_subr() cs_store(true)
-#define store_cs()   cs_store(false)
-
-#define CC_STACK_SIZE 24
-
-static int cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
-static cc_entry cc_tab[CS_MAX];

@@ Diff output truncated at 1234567 characters. @@


More information about the tex-live-commits mailing list