summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuigi Scarso <luigi.scarso@gmail.com>2018-09-05 21:57:30 +0000
committerLuigi Scarso <luigi.scarso@gmail.com>2018-09-05 21:57:30 +0000
commitecd1605a23ef54d2a4a69e1a361172d350e03b3b (patch)
tree8ea1d9745c24dbc5e755f13d801fa01e88944650
parent04563248956e7059aad4fc4f6bf7da18562f7b8c (diff)
luatex: correct automake file for pplib; replaced cweb files with c files.
git-svn-id: svn://tug.org/texlive/trunk@48594 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Build/source/texk/web2c/luatexdir/am/luapplib.am86
-rw-r--r--Build/source/texk/web2c/luatexdir/dvi/dvigen.c1558
-rw-r--r--Build/source/texk/web2c/luatexdir/dvi/dvigen.w1258
-rw-r--r--Build/source/texk/web2c/luatexdir/font/dofont.c (renamed from Build/source/texk/web2c/luatexdir/font/dofont.w)82
-rw-r--r--Build/source/texk/web2c/luatexdir/font/luafont.c (renamed from Build/source/texk/web2c/luatexdir/font/luafont.w)730
-rw-r--r--Build/source/texk/web2c/luatexdir/font/mapfile.c770
-rw-r--r--Build/source/texk/web2c/luatexdir/font/mapfile.w715
-rw-r--r--Build/source/texk/web2c/luatexdir/font/pkin.c (renamed from Build/source/texk/web2c/luatexdir/font/pkin.w)288
-rw-r--r--Build/source/texk/web2c/luatexdir/font/sfnt.c (renamed from Build/source/texk/web2c/luatexdir/font/sfnt.w)198
-rw-r--r--Build/source/texk/web2c/luatexdir/font/subfont.c (renamed from Build/source/texk/web2c/luatexdir/font/subfont.w)112
-rw-r--r--Build/source/texk/web2c/luatexdir/font/texfont.c (renamed from Build/source/texk/web2c/luatexdir/font/texfont.w)406
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tfmofm.c1186
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tfmofm.w1119
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tounicode.c (renamed from Build/source/texk/web2c/luatexdir/font/tounicode.w)372
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tt_glyf.c (renamed from Build/source/texk/web2c/luatexdir/font/tt_glyf.w)316
-rw-r--r--Build/source/texk/web2c/luatexdir/font/tt_table.c (renamed from Build/source/texk/web2c/luatexdir/font/tt_table.w)152
-rw-r--r--Build/source/texk/web2c/luatexdir/font/vfovf.c1444
-rw-r--r--Build/source/texk/web2c/luatexdir/font/vfovf.w1480
-rw-r--r--Build/source/texk/web2c/luatexdir/font/vfpacket.c445
-rw-r--r--Build/source/texk/web2c/luatexdir/font/vfpacket.w424
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writecff.c (renamed from Build/source/texk/web2c/luatexdir/font/writecff.w)1917
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writeenc.c (renamed from Build/source/texk/web2c/luatexdir/font/writeenc.w)70
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writefont.c (renamed from Build/source/texk/web2c/luatexdir/font/writefont.w)673
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writet1.c (renamed from Build/source/texk/web2c/luatexdir/font/writet1.w)738
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writet3.c (renamed from Build/source/texk/web2c/luatexdir/font/writet3.w)69
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writettf.c (renamed from Build/source/texk/web2c/luatexdir/font/writettf.w)1046
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writetype0.c (renamed from Build/source/texk/web2c/luatexdir/font/writetype0.w)74
-rw-r--r--Build/source/texk/web2c/luatexdir/font/writetype2.c (renamed from Build/source/texk/web2c/luatexdir/font/writetype2.w)256
-rw-r--r--Build/source/texk/web2c/luatexdir/image/pdftoepdf.c1049
-rw-r--r--Build/source/texk/web2c/luatexdir/image/pdftoepdf.w972
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writeimg.c (renamed from Build/source/texk/web2c/luatexdir/image/writeimg.w)415
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writejbig2.c (renamed from Build/source/texk/web2c/luatexdir/image/writejbig2.w)279
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writejp2.c (renamed from Build/source/texk/web2c/luatexdir/image/writejp2.w)85
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writejpg.c (renamed from Build/source/texk/web2c/luatexdir/image/writejpg.w)256
-rw-r--r--Build/source/texk/web2c/luatexdir/image/writepng.c (renamed from Build/source/texk/web2c/luatexdir/image/writepng.w)173
-rw-r--r--Build/source/texk/web2c/luatexdir/lang/hnjalloc.c65
-rw-r--r--Build/source/texk/web2c/luatexdir/lang/hnjalloc.w69
-rw-r--r--Build/source/texk/web2c/luatexdir/lang/hyphen.c (renamed from Build/source/texk/web2c/luatexdir/lang/hyphen.w)471
-rw-r--r--Build/source/texk/web2c/luatexdir/lang/texlang.c (renamed from Build/source/texk/web2c/luatexdir/lang/texlang.w)686
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/helpers.c29
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/helpers.w26
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/llfslibext.c171
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfelib.c1666
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c1110
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luainit.c (renamed from Build/source/texk/web2c/luatexdir/lua/luainit.w)538
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luanode.c (renamed from Build/source/texk/web2c/luatexdir/lua/luanode.w)252
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luastuff.c (renamed from Build/source/texk/web2c/luatexdir/lua/luastuff.w)451
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatoken.c585
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatoken.w424
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/mplibstuff.c115
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/mplibstuff.w93
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluac.c532
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluac.w495
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluajitc.c650
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluajitc.w575
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua329
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c749
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua106
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c301
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua256
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c504
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua134
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c244
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua309
-rw-r--r--Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c554
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfaction.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfaction.w)50
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfannot.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfannot.w)51
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w)127
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfdest.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfdest.w)125
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdffont.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdffont.w)153
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfgen.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfgen.w)1638
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfglyph.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w)165
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfimage.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfimage.w)142
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflink.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdflink.w)91
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflistout.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdflistout.w)748
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfliteral.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w)111
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfobj.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfobj.w)104
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfoutline.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w)86
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfpage.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfpage.w)104
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.w)150
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfrule.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfrule.w)68
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w)49
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w)124
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfshipout.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w)137
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdftables.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdftables.w)92
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfthread.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfthread.w)61
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfxform.c (renamed from Build/source/texk/web2c/luatexdir/pdf/pdfxform.w)55
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/align.c1297
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/align.w1144
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/arithmetic.c815
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/arithmetic.w735
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/backend.c123
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/backend.h54
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/buildpage.c1164
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/buildpage.w1013
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/commands.c (renamed from Build/source/texk/web2c/luatexdir/tex/commands.w)194
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/conditional.c (renamed from Build/source/texk/web2c/luatexdir/tex/conditional.w)348
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/directions.c (renamed from Build/source/texk/web2c/luatexdir/tex/directions.w)113
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/dumpdata.c (renamed from Build/source/texk/web2c/luatexdir/tex/dumpdata.w)403
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/equivalents.c (renamed from Build/source/texk/web2c/luatexdir/tex/equivalents.w)766
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/errors.c1032
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/errors.w972
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/expand.c967
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/expand.w829
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/extensions.c1329
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/extensions.w1211
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/filename.c (renamed from Build/source/texk/web2c/luatexdir/tex/filename.w)230
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/inputstack.c (renamed from Build/source/texk/web2c/luatexdir/tex/inputstack.w)640
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/linebreak.c2520
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/linebreak.w2164
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/mainbody.c769
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/mainbody.w708
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/maincontrol.c (renamed from Build/source/texk/web2c/luatexdir/tex/maincontrol.w)2077
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/mathcodes.c (renamed from Build/source/texk/web2c/luatexdir/tex/mathcodes.w)135
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/memoryword.c29
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/memoryword.w55
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/mlist.c (renamed from Build/source/texk/web2c/luatexdir/tex/mlist.w)2619
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/nesting.c429
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/nesting.w436
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/packaging.c (renamed from Build/source/texk/web2c/luatexdir/tex/packaging.w)1382
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/postlinebreak.c (renamed from Build/source/texk/web2c/luatexdir/tex/postlinebreak.w)466
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/primitive.c785
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/primitive.w664
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/printing.c (renamed from Build/source/texk/web2c/luatexdir/tex/printing.w)672
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/scanning.c2743
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/scanning.w2621
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/stringpool.c (renamed from Build/source/texk/web2c/luatexdir/tex/stringpool.w)248
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texdeffont.c (renamed from Build/source/texk/web2c/luatexdir/tex/texdeffont.w)151
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texfileio.c1509
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texfileio.w1389
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texmath.c (renamed from Build/source/texk/web2c/luatexdir/tex/texmath.w)1589
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texnodes.c4770
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/texnodes.w3910
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/textcodes.c (renamed from Build/source/texk/web2c/luatexdir/tex/textcodes.w)112
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/textoken.c (renamed from Build/source/texk/web2c/luatexdir/tex/textoken.w)2151
-rw-r--r--Build/source/texk/web2c/luatexdir/utils/avlstuff.c63
-rw-r--r--Build/source/texk/web2c/luatexdir/utils/avlstuff.w61
-rw-r--r--Build/source/texk/web2c/luatexdir/utils/managed-sa.c (renamed from Build/source/texk/web2c/luatexdir/utils/managed-sa.w)90
-rw-r--r--Build/source/texk/web2c/luatexdir/utils/unistring.c (renamed from Build/source/texk/web2c/luatexdir/utils/unistring.w)103
-rw-r--r--Build/source/texk/web2c/luatexdir/utils/utils.c (renamed from Build/source/texk/web2c/luatexdir/utils/utils.w)303
140 files changed, 47503 insertions, 43732 deletions
diff --git a/Build/source/texk/web2c/luatexdir/am/luapplib.am b/Build/source/texk/web2c/luatexdir/am/luapplib.am
new file mode 100644
index 00000000000..51306232557
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/am/luapplib.am
@@ -0,0 +1,86 @@
+## texk/web2c/luatexdir/am/luapplib.am: Makefile fragment for libluapplib.
+##
+## Copyright (C) 2018 Luigi Scarso <tex-live@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)
diff --git a/Build/source/texk/web2c/luatexdir/dvi/dvigen.c b/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
new file mode 100644
index 00000000000..8e285917a50
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/dvi/dvigen.c
@@ -0,0 +1,1558 @@
+/*
+
+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/>.
+
+*/
+
+#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;
+}
diff --git a/Build/source/texk/web2c/luatexdir/dvi/dvigen.w b/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
deleted file mode 100644
index d991445a59f..00000000000
--- a/Build/source/texk/web2c/luatexdir/dvi/dvigen.w
+++ /dev/null
@@ -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.
-@c
-#include "ptexlib.h"
-
-@ Here is the start of the actual C file.
-@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.
-
-@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|.
-
-
-@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@>
-
-@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.
-
-@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@>
-
-@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.
-
-@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|.
-
-
-@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.
-
-@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.
-
-@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|.
-
-@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.
-
-
-@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.
-
-@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|.
-
-@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.
-
-@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);
- }
-}
diff --git a/Build/source/texk/web2c/luatexdir/font/dofont.w b/Build/source/texk/web2c/luatexdir/font/dofont.c
index b91bec10689..b23368d834f 100644
--- a/Build/source/texk/web2c/luatexdir/font/dofont.w
+++ b/Build/source/texk/web2c/luatexdir/font/dofont.c
@@ -1,42 +1,42 @@
-% 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
+/*
+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/>.
+
+*/
#include "ptexlib.h"
#include "lua/luatex-api.h"
-@ a bit more interfacing is needed for proper error reporting
+/*tex
+
+ A bit more interfacing is needed for proper error reporting.
+
+*/
-@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);
+ 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);
+ 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);
}
@@ -46,26 +46,22 @@ static char *font_error_message(pointer u, char *nom, scaled s)
static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
{
-
- boolean res; /* was the callback successful? */
- int callback_id;
+ boolean res = 0;
char *cnam;
int r, t;
- res = 0;
-
- callback_id = callback_defined(define_font_callback);
+ 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) { /* success */
+ 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);
- /* |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);
@@ -86,12 +82,16 @@ static int do_define_font(int f, const char *cnom, scaled s, int natural_dir)
}
}
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 */
+ /*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) { /* implies lua */
+ if (font_type(f) != virtual_font_type) {
+ /*tex This implies \LUA. */
do_vf(f);
set_font_natural_dir(f, natural_dir);
}
@@ -112,8 +112,8 @@ int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
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,",
+ 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;",
@@ -129,10 +129,6 @@ int read_font_info(pointer u, char *cnom, scaled s, int natural_dir)
}
}
-@ TODO This function is a placeholder. There can easily appears holes in
- the |font_tables| array, and we could attempt to reuse those
-
-@c
int find_font_id(const char *nom, scaled s)
{
int f;
diff --git a/Build/source/texk/web2c/luatexdir/font/luafont.w b/Build/source/texk/web2c/luatexdir/font/luafont.c
index f63b71a1c15..e64aaffc15d 100644
--- a/Build/source/texk/web2c/luatexdir/font/luafont.w
+++ b/Build/source/texk/web2c/luatexdir/font/luafont.c
@@ -1,29 +1,34 @@
-% 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
+/*
+
+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/>.
+
+*/
+
#include "ptexlib.h"
#include "lua/luatex-api.h"
#define noVERBOSE
-/* todo: also keys */
+/*tex
+
+ Todo: make these keys.
+
+*/
const char *font_type_strings[] = {
"unknown", "virtual", "real", NULL
@@ -116,8 +121,6 @@ const char *MATH_param_names[] = {
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[]) {
@@ -170,13 +173,10 @@ static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * c
{
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));
}
@@ -259,7 +259,7 @@ static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * c
lua_createtable(L, 10, 1);
for (i = 0; !kern_end(ki[i]); i++) {
if (kern_disabled(ki[i])) {
- /* skip like in lookup */
+ /*tex Skip like in lookup. */
} else {
lua_rawgeti(L, -1, kern_char(ki[i]));
if (lua_type(L,-1) == LUA_TNIL) {
@@ -272,7 +272,7 @@ static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * c
lua_pushinteger(L, kern_kern(ki[i]));
lua_rawset(L, -3);
} else {
- /* first one wins */
+ /*tex The first one wins. */
lua_pop(L,1);
}
}
@@ -301,48 +301,47 @@ static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * c
}
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);
+ 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);
}
}
@@ -382,7 +381,6 @@ static void write_lua_parameters(lua_State * L, int f)
lua_rawset(L, -3);
}
-@ @c
static void write_lua_math_parameters(lua_State * L, int f)
{
int k;
@@ -404,14 +402,12 @@ 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()| */
+ /*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));
- /* fontdimens can be changed from tex code */
+ /*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));
@@ -431,7 +427,6 @@ int font_to_lua(lua_State * L, int 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)]);
@@ -439,19 +434,20 @@ int font_to_lua(lua_State * L, int 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));
-
- /* the next one is read only */
+ /*tex The next one is read only: */
if (font_max_shrink(f) != 0) {
dump_intfield(L,shrink,font_max_shrink(f));
}
@@ -466,14 +462,12 @@ int font_to_lua(lua_State * L, int f)
dump_stringfield(L,attributes,s);
free(s);
}
-
- /* params */
+ /*tex Parameters: */
write_lua_parameters(L, f);
write_lua_math_parameters(L, f);
-
- /* chars */
+ /*tex Characters: */
lua_push_string_by_name(L,characters);
- lua_createtable(L, font_tables[f]->charinfo_size, 0); /* all 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);
@@ -495,11 +489,11 @@ int font_to_lua(lua_State * L, int f)
}
}
lua_rawset(L, -3);
-
- if (font_cache_id(f) == 0) { /* renew */
+ if (font_cache_id(f) == 0) {
+ /*tex Renew the cache. */
int r;
lua_pushvalue(L, -1);
- r = luaL_ref(L, LUA_REGISTRYINDEX); /* pops the table */
+ r = luaL_ref(L, LUA_REGISTRYINDEX);
set_font_cache_id(f, r);
}
return 1;
@@ -516,12 +510,11 @@ int font_to_lua(lua_State * L, int f)
} \
} \
if (n) { \
- /* keep table on stack */ \
+ /*tex Keep the 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); }
@@ -533,7 +526,6 @@ int font_to_lua(lua_State * L, int f)
append_packet((l & 0x000000FF)); \
}
-@ @c
static void append_float(eight_bits ** cpp, float a)
{
unsigned int i;
@@ -553,7 +545,8 @@ static int n_enum_field(lua_State * L, int name_index, int dflt, const char **va
int k, t;
const char *s;
int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
+ /*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) {
@@ -576,7 +569,8 @@ static int n_enum_field(lua_State * L, int name_index, int dflt, const char **va
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 */
+ /*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);
@@ -588,7 +582,8 @@ static int n_boolean_field(lua_State * L, int name_index, int dflt)
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 */
+ /*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));
@@ -603,20 +598,20 @@ static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt
static const char *n_string_field(lua_State * L, int name_index)
{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
+ /*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)
{
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
+ /*tex Fetch the string pointer: */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
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;
@@ -646,7 +641,7 @@ static int count_char_packet_bytes(lua_State * L)
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)) {
+ } 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;
@@ -657,9 +652,9 @@ static int count_char_packet_bytes(lua_State * L)
lua_rawgeti(L, -2, 2);
if (ts == 3) {
if (lua_type(L,-1) == LUA_TSTRING) {
- /* no need to do something */
+ /*tex There is no need to do something. */
} else if (lua_type(L,-1) == LUA_TNUMBER) {
- /* no need to do something */
+ /*tex There is no need to do something. */
} else {
normal_error("vf command","invalid packet pdf literal category");
}
@@ -674,7 +669,7 @@ static int count_char_packet_bytes(lua_State * L)
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)) {
+ } else if (lua_key_eq(s, special)) {
size_t len;
lua_rawgeti(L, -2, 2);
if (lua_type(L,-1) == LUA_TSTRING) {
@@ -692,9 +687,11 @@ static int count_char_packet_bytes(lua_State * L)
} else {
normal_error("vf command","no packet command");
}
- lua_pop(L, 1); /* command name */
+ /*tex Pop the command name: */
+ lua_pop(L, 1);
}
- lua_pop(L, 1); /* item */
+ /*tex Pop this item: */
+ lua_pop(L, 1);
}
return l;
}
@@ -707,7 +704,6 @@ static scaled sp_to_dvi(halfword sp, halfword atsize)
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;
@@ -728,7 +724,7 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
for (i = 1; i <= (int) lua_rawlen(L, -1); i++) {
lua_rawgeti(L, -1, i);
if (lua_istable(L, -1)) {
- /* fetch the command code */
+ /*tex fetch the command code */
lua_rawgeti(L, -1, 1);
if (lua_type(L,-1) == LUA_TSTRING) {
s = lua_tostring(L, -1);
@@ -743,7 +739,7 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
do_store_four(ff);
}
} else if (lua_key_eq(s, slot)) {
- /* we could be sparse but no real reason */
+ /*tex we could be sparse but no real reason */
cmd = packet_nop_code;
lua_rawgeti(L, -2, 2);
n = (int) lua_roundnumber(L, -1);
@@ -804,7 +800,7 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
case packet_node_code:
append_packet(cmd);
lua_rawgeti(L, -2, 2);
- n = copy_node_list(nodelist_from_lua(L));
+ n = copy_node_list(nodelist_from_lua(L,-1));
do_store_four(n);
lua_pop(L, 1);
break;
@@ -837,18 +833,18 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
ts = (int) lua_rawlen(L, -2);
lua_rawgeti(L, -2, 2);
if (ts == 3) {
- /* mode on stack */
+ /*tex mode on stack */
s = lua_tostring(L, -1);
if (lua_type(L, -1) == LUA_TSTRING) {
- /* <pdf> <mode> <direct|page|text|raw|origin> */
+ /*tex |<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 */
+ /*tex mode on stack */
s = lua_tostring(L, -1);
}
} else {
- /* <pdf> <direct|page|text|raw|origin> <string> */
+ /*tex |<pdf> <direct|page|text|raw|origin> <string>| */
}
if (lua_type(L, -1) == LUA_TSTRING) {
if (lua_key_eq(s, direct)) {
@@ -864,7 +860,6 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
} else if (lua_key_eq(s, origin)) {
n = set_origin;
} else {
- /* normal_warning("vf command","invalid pdf literal type"); */
n = set_origin ;
}
} else {
@@ -874,8 +869,8 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
}
}
if (cmd == packet_pdf_code) {
+ /*tex string on stack */
lua_rawgeti(L, -3, 3);
- /* string on stack */
}
} else {
n = set_origin;
@@ -897,7 +892,6 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
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);
@@ -912,19 +906,25 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
}
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); /* 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_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);
- } /* img ... */
- luaL_checkudata(L, -1, TYPE_IMG); /* img ... --- just typecheck */
- n = luaL_ref(L, LUA_REGISTRYINDEX); /* ... */
+ }
+ luaL_checkudata(L, -1, TYPE_IMG);
+ n = luaL_ref(L, LUA_REGISTRYINDEX);
do_store_four(n);
break;
case packet_nop_code:
@@ -937,34 +937,32 @@ static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, intern
break;
default:
normal_error("vf command","invalid packet code");
- /* fprintf(stdout, "Unknown char packet code %s\n", s); */
}
}
- lua_pop(L, 1); /* command code */
+ /*tex Command code: */
+ lua_pop(L, 1);
} 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 */
+ /*tex Command table: */
+ lua_pop(L, 1);
}
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 */
+ 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);
@@ -972,38 +970,35 @@ static void read_lua_cidinfo(lua_State * L, int f)
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) */
+ /*tex The number of parameters is the |max(IntegerKeys(L)),7)| */
n = 7;
- lua_pushnil(L); /* first key */
+ 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); /* pop value */
+ lua_pop(L, 1);
}
if (n > 7)
set_font_params(f, n);
- /* sometimes it is handy to have all integer keys */
+ /*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); /* round ? */
+ n = lua_roundnumber(L, -1);
set_font_param(f, i, n);
}
lua_pop(L, 1);
}
- lua_pushnil(L); /* first key */
+ lua_pushnil(L);
while (lua_next(L, -2) != 0) {
t = lua_type(L,-2);
if (t == LUA_TNUMBER) {
@@ -1046,11 +1041,9 @@ static void read_lua_parameters(lua_State * L, int f)
}
-@ @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);
@@ -1065,7 +1058,7 @@ static void read_lua_math_parameters(lua_State * L, int f)
if (i > 0) {
set_font_math_param(f, i, n);
}
- lua_pop(L, 1); /* pop value */
+ lua_pop(L, 1);
}
set_font_oldmath(f,false);
} else {
@@ -1074,7 +1067,6 @@ static void read_lua_math_parameters(lua_State * L, int f)
lua_pop(L, 1);
}
-@ @c
#define MIN_INF -0x7FFFFFFF
static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
@@ -1097,7 +1089,6 @@ static void store_math_kerns(lua_State * L, int index, charinfo * co, int id)
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;
@@ -1106,8 +1097,10 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
liginfo *cligs;
scaled j;
const char *s;
- int nl = 0; /* number of ligature table items */
- int nk = 0; /* number of kern table items */
+ /*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)) {
@@ -1138,7 +1131,7 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
set_charinfo_name(co, xstrdup(s));
else
set_charinfo_name(co, NULL);
- /* n_string_field leaves a value on stack*/
+ /*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) {
@@ -1150,7 +1143,7 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
sprintf(s,"%04X",(unsigned int) u);
set_charinfo_tounicode(co,s);
} else {
- char *s = malloc(9);
+ 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);
@@ -1203,9 +1196,7 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
} 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);
@@ -1216,7 +1207,6 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
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;
@@ -1232,7 +1222,6 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
}
lua_pop(L, 1);
-
lua_key_rawgeti(horiz_variants);
if (lua_istable(L, -1)) {
int glyph, startconnect, endconnect, advance, extender;
@@ -1257,7 +1246,6 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
}
lua_pop(L, 1);
-
lua_key_rawgeti(vert_variants);
if (lua_istable(L, -1)) {
int glyph, startconnect, endconnect, advance, extender;
@@ -1282,19 +1270,19 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
}
lua_pop(L, 1);
-
- /*
+ /*tex
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 } },|
- |}|
+ \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);
@@ -1304,18 +1292,20 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
lua_pop(L, 1);
}
- /* end of |has_math| */
+ /*tex end of |has_math| */
count_hash_items(L, kerns, nk);
if (nk > 0) {
- /* kerns table still on stack */
+ /*tex The kerns table is still on stack. */
ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo));
ctr = 0;
- lua_pushnil(L); /* traverse hash */
+ /*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) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
+ /*tex Adjacent char: */
+ k = (int) lua_tointeger(L, -2);
if (k < 0)
k = non_boundarychar;
} else if (lt == LUA_TSTRING) {
@@ -1326,7 +1316,7 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
set_right_boundary(f, get_charinfo(f, right_boundarychar));
}
}
- j = lua_roundnumber(L, -1); /* movement */
+ j = lua_roundnumber(L, -1);
if (k != non_boundarychar) {
set_kern_item(ckerns[ctr], k, j);
ctr++;
@@ -1335,7 +1325,7 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
lua_pop(L, 1);
}
- /* guard against empty tables */
+ /*tex A guard against empty tables. */
if (ctr > 0) {
set_kern_item(ckerns[ctr], end_kern, 0);
set_charinfo_kerns(co, ckerns);
@@ -1344,31 +1334,30 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
lua_pop(L, 1);
}
-
- /* packet commands */
-
+ /*tex Packet commands. */
lua_key_rawgeti(commands);
if (lua_istable(L, -1)) {
- lua_pushnil(L); /* first key */
+ 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);
-
- /* ligatures */
+ /*tex The ligatures. */
count_hash_items(L, ligatures, nl);
if (nl > 0) {
- /* ligatures table still on stack */
+ /*tex The ligatures table still on stack. */
cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo));
ctr = 0;
- lua_pushnil(L); /* traverse hash */
+ /*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) {
- k = (int) lua_tointeger(L, -2); /* adjacent char */
+ /*tex Adjacent char: */
+ k = (int) lua_tointeger(L, -2);
if (k < 0) {
k = non_boundarychar;
}
@@ -1382,7 +1371,8 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
}
r = -1;
if (lua_istable(L, -1)) {
- r = lua_numeric_field_by_index(L, lua_key_index(char), -1); /* ligature */
+ /*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);
@@ -1391,67 +1381,66 @@ static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int
} 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 */
+ /*tex The iterator value: */
+ lua_pop(L, 1);
}
- /* guard against empty tables */
+ /*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);
}
- lua_pop(L, 1); /* ligatures table */
+ /*tex The ligatures table. */
+ lua_pop(L, 1);
}
}
}
-@ The caller has to fix the state of the lua stack when there is an error!
+/*tex
+
+ The caller has to fix the state of the lua stack when there is an error!
+
+*/
-@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 */
+ int s_top;
+ int bc;
+ int ec;
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" */
+ /*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;
- /* n_string_field leaves a value on stack*/
+ /*tex |n_string_field| leaves a value on stack. */
lua_pop(L,1);
-
- /* the table is at stack index -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);
@@ -1469,34 +1458,48 @@ int font_from_lua(lua_State * L, int f)
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(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);
@@ -1510,11 +1513,10 @@ int font_from_lua(lua_State * L, int f)
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 */
+ /*tex Now fetch the base fonts, if needed. */
count_hash_items(L, fonts, n);
if (n > 0) {
- /* font table still on stack */
+ /*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++) {
@@ -1526,20 +1528,22 @@ int font_from_lua(lua_State * L, int f)
if (l_fonts[i] == 0) {
l_fonts[i] = (int) f;
}
- lua_pop(L, 2); /* pop id and entry */
+ /*tex Pop id and entry. */
+ lua_pop(L, 2);
continue;
}
- lua_pop(L, 1); /* pop id */
+ /*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 */
+ /*tex The 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 */
+ /*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;
@@ -1549,18 +1553,26 @@ int font_from_lua(lua_State * L, int f)
} 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 */
+ /*tex Pop the list entry. */
+ lua_pop(L, 1);
}
- lua_pop(L, 1); /* pop font table */
+ /*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;
}
- /* parameters */
+ /*tex The parameters. */
no_math = n_boolean_field(L, lua_key_index(nomath), 0);
read_lua_parameters(L, f);
if (!no_math) {
@@ -1573,15 +1585,15 @@ int font_from_lua(lua_State * L, int f)
set_font_oldmath(f,true);
}
read_lua_cidinfo(L, f);
-
- /* characters */
+ /*tex The characters. */
lua_key_rawgeti(characters);
if (lua_istable(L, -1)) {
- /* find the array size values */
- int num = 0; /* number of charinfo's to add */
+ /*tex Find the array size values; |num| holds the number of characters to add. */
+ int num = 0;
ec = 0;
bc = -1;
- lua_pushnil(L); /* first key */
+ /*tex The first key: */
+ lua_pushnil(L);
while (lua_next(L, -2) != 0) {
if (lua_isnumber(L, -2)) {
i = (int) lua_tointeger(L, -2);
@@ -1600,10 +1612,12 @@ int font_from_lua(lua_State * L, int f)
lua_pop(L, 1);
}
if (bc != -1) {
+ int fstep;
font_malloc_charinfo(f, num);
set_font_bc(f, bc);
set_font_ec(f, ec);
- lua_pushnil(L); /* first key */
+ /*tex The first key: */
+ lua_pushnil(L);
while (lua_next(L, -2) != 0) {
lt = lua_type(L,-2);
if (lt == LUA_TNUMBER) {
@@ -1622,53 +1636,50 @@ int font_from_lua(lua_State * L, int f)
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|.
- */
+ and that needs to know |bc| and |ec|. We permits virtual fonts to use
+ expansion as one can always turn it off.
- 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);
- }
+ */
+ 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 */
+ /*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 {
- /* 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)
@@ -1683,15 +1694,15 @@ int characters_from_lua(lua_State * L, int f)
int s_top;
const char *ss;
boolean no_math = false;
- /* speedup */
+ /*tex Speedup: */
no_math = n_boolean_field(L, lua_key_index(nomath), 0);
- /* type */
+ /*tex Type: */
i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings);
set_font_type(f, i);
- /* fonts */
+ /*tex Fonts: */
count_hash_items(L, fonts, n);
if (n > 0) {
- /* font table still on stack */
+ /*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++) {
@@ -1703,10 +1714,12 @@ int characters_from_lua(lua_State * L, int f)
if (l_fonts[i] == 0) {
l_fonts[i] = (int) f;
}
- lua_pop(L, 2); /* pop id and entry */
+ /*tex Pop id and entry. */
+ lua_pop(L, 2);
continue;
}
- lua_pop(L, 1); /* pop id */
+ /*tex Pop id. */
+ lua_pop(L, 1);
};
ss = NULL;
if (lua_istable(L, -1)) {
@@ -1716,7 +1729,7 @@ int characters_from_lua(lua_State * L, int f)
}
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 */
+ /*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;
@@ -1726,9 +1739,11 @@ int characters_from_lua(lua_State * L, int f)
} else {
formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f));
}
- lua_pop(L, 1); /* pop list entry */
+ /*tex Pop list entry. */
+ lua_pop(L, 1);
}
- lua_pop(L, 1); /* pop font table */
+ /*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 {
@@ -1737,15 +1752,16 @@ int characters_from_lua(lua_State * L, int f)
l_fonts[1] = f;
l_fonts[2] = 0;
}
- /* characters */
+ /*tex The characters. */
lua_key_rawgeti(characters);
if (lua_istable(L, -1)) {
- /* find the array size values */
- int num = 0; /* number of charinfo's to add */
+ /*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);
- lua_pushnil(L); /* first key */
+ /*tex First key: */
+ lua_pushnil(L);
while (lua_next(L, -2) != 0) {
if (lua_isnumber(L, -2)) {
i = (int) lua_tointeger(L, -2);
@@ -1770,7 +1786,8 @@ int characters_from_lua(lua_State * L, int f)
font_malloc_charinfo(f, num);
set_font_bc(f, bc);
set_font_ec(f, ec);
- lua_pushnil(L); /* first key */
+ /*tex First key: */
+ lua_pushnil(L);
while (lua_next(L, -2) != 0) {
lt = lua_type(L,-2);
if (lt == LUA_TNUMBER) {
@@ -1799,9 +1816,8 @@ int characters_from_lua(lua_State * L, int f)
return true;
}
-@* Ligaturing.
+/*tex Ligaturing starts here */
-@c
static void nesting_append(halfword nest1, halfword newn)
{
halfword tail = tlink(nest1);
@@ -1863,9 +1879,9 @@ static int try_ligature(halfword * frst, halfword fwd)
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 ...
+ /*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);
@@ -1884,13 +1900,13 @@ static int try_ligature(halfword * frst, halfword fwd)
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
+ /*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.
*/
- /* left side */
+ /*tex Left side: */
if (keep_left) {
halfword new_first = copy_node(cur);
lig_ptr(newgl) = new_first;
@@ -1906,10 +1922,10 @@ static int try_ligature(halfword * frst, halfword fwd)
couple_nodes(prev, newgl);
cur = newgl; /* as cur has disappeared */
}
- /* right side */
+ /*tex Right side: */
if (keep_right) {
halfword new_second = copy_node(fwd);
- /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
+ /*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) {
@@ -1919,24 +1935,27 @@ static int try_ligature(halfword * frst, halfword fwd)
} else {
halfword next = vlink(fwd);
uncouple_node(fwd);
- /* correct, because we {\it know\/} |lig_ptr| points to {\it one\/} node */
+ /*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);
}
}
- /* check and return */
+ /*tex 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|.
+/*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|.
+
+*/
-@c
static halfword handle_lig_nest(halfword root, halfword cur)
{
if (cur == null)
@@ -1959,7 +1978,7 @@ static halfword handle_lig_word(halfword cur)
if (type(cur) == boundary_node) {
halfword prev = alink(cur);
halfword fwd = vlink(cur);
- /* no need to uncouple |cur|, it is freed */
+ /*tex There is no need to uncouple |cur|, it is freed. */
flush_node(cur);
if (fwd == null) {
vlink(prev) = fwd;
@@ -1980,80 +1999,82 @@ static halfword handle_lig_word(halfword cur)
right = new_glyph(font(cur), right_boundarychar);
}
while (1) {
- /* A glyph followed by ... */
+ /*tex A glyph followed by \unknown */
if (type(cur) == glyph_node) {
halfword fwd = vlink(cur);
- if (fwd == null) { /* last character of paragraph */
+ if (fwd == null) {
+ /*tex The last character of a paragraph. */
if (right == null)
break;
- /* \.{--\\par} prohibits use of |couple_nodes| here */
+ /*tex |par| prohibits the use of |couple_nodes| here. */
try_couple_nodes(cur, right);
right = null;
continue;
}
- if (type(fwd) == glyph_node) { /* |GLYPH - GLYPH| */
+ 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) { /* |GLYPH - DISC| */
-
- /* if \.{a{bx}{}{y}} and \.{a+b=>B} convert to \.{{Bx}{}{ay}} */
+ } 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;
- /* 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 */
+ /*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);
- /* now ligature the |pre_break| */
+ /*tex Now ligature the |pre_break|. */
nesting_prepend(pre_break(fwd), copy_node(cur));
- /* As we have removed cur, we need to start again ... */
+ /*tex As we have removed cur, we need to start again. */
cur = prev;
}
- /* Check on: a{?}{?}{}b and a+b=>B : {a?}{?b}{B} */
+ /*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)) {
- /* move |cur| from before |disc| to |no_break| part */
+ 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);
- couple_nodes(no_break(fwd), cur); /* we {\it know\/} it's empty */
- /* now copy cur the |pre_break| */
+ /*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));
- /* move next from after disc to |no_break| part */
+ /*tex 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| */
+ /*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));
- /* As we have removed cur, we need to start again ... */
+ /*tex As we have removed cur, we need to start again. */
cur = prev;
}
- /* we are finished with the |pre_break| */
+ /*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) {
- flush_node(right); /* Shame, didn't need it */
- /* no need to reset |right|, we're going to leave the loop anyway */
+ /*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 {
- /* fwd is something unknown */
+ /*tex Is something unknown. */
if (right == null)
break;
couple_nodes(cur, right);
@@ -2061,9 +2082,9 @@ static halfword handle_lig_word(halfword cur)
right = null;
continue;
}
- /* A discretionary followed by ... */
+ /*tex A discretionary followed by \unknown */
} else if (type(cur) == disc_node) {
- /* If \.{{?}{x}{?}} or \.{{?}{?}{y}} then ... */
+ /*tex If |{?}{x}{?}| or |{?}{?}{y}| then: */
if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) {
halfword prev = 0;
halfword fwd;
@@ -2131,35 +2152,32 @@ static halfword handle_lig_word(halfword cur)
&& 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 ;
+ /*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);
- /* \.{{a-}{b}{AB} {-}{c}{}} */
+ /*tex |{a-}{b}{AB} {-}{c}{}| */
nesting_append(post_break(fwd), copy_node(next));
- /* \.{{a-}{b}{AB} {-}{c}{-}} */
+ /*tex |{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}{-}} */
+ /*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)));
- /* \.{{a-}{b}{AB} {b-}{c}{AB-}} */
+ /*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)));
}
- /* \.{{a-}{b}{ABC} {b-}{c}{AB-}} */
+ /*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);
- /* \.{{a-}{BC}{ABC} {b-}{c}{AB-}} */
+ /*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);
- /* and set the subtypes */
+ /*tex Set the subtypes: */
subtype(cur) = init_disc;
subtype(fwd) = select_disc;
}
@@ -2167,39 +2185,33 @@ static halfword handle_lig_word(halfword cur)
}
} else {
- /* NO GLYPH NOR DISC */
+ /*tex We have glyph nor disc. */
return cur;
}
- /* step-to-next-node */
- /* \.{--\\par} allows |vlink(cur)| to be null */
+ /*tex Goto the next node, where |\par| allows |vlink(cur)| to be NULL. */
cur = vlink(cur);
}
-
return cur;
}
-@ Return value is the new tail, head should be a dummy
+/*tex The return value is the new tail, head should be a dummy: */
-@c
halfword handle_ligaturing(halfword head, halfword tail)
{
- halfword save_tail1 = null; /* trick to allow explicit |node==null| tests */
+ /*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);
@@ -2208,10 +2220,8 @@ halfword handle_ligaturing(halfword head, halfword tail)
cur = vlink(cur);
}
if (prev == null) {
- /* hh: looks bad to me */
prev = tail;
}
-
if (tail != null) {
try_couple_nodes(prev, save_tail1);
}
@@ -2219,9 +2229,8 @@ halfword handle_ligaturing(halfword head, halfword tail)
}
-@* Kerning.
+/*tex Kerning starts here: */
-@c
static void add_kern_before(halfword left, halfword right)
{
if ((!is_rightghost(right)) &&
@@ -2232,7 +2241,7 @@ static void add_kern_before(halfword left, halfword right)
halfword prev = alink(right);
couple_nodes(prev, kern);
couple_nodes(kern, right);
- /* update the attribute list (inherit from left) */
+ /*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);
@@ -2250,7 +2259,7 @@ static void add_kern_after(halfword left, halfword right, halfword aft)
halfword next = vlink(aft);
couple_nodes(aft, kern);
try_couple_nodes(kern, next);
- /* update the attribute list (inherit from left == aft) */
+ /*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);
@@ -2298,7 +2307,7 @@ static void do_handle_kerning(halfword root, halfword init_left, halfword init_r
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? */
+ tlink_no_break(cur) = tail_of_list(vlink_no_break(cur));
}
if (left != null) {
if (character(left) < 0 || is_ghost(left)) {
@@ -2331,22 +2340,6 @@ static void do_handle_kerning(halfword root, halfword init_left, halfword init_r
}
}
-/*
-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;
@@ -2366,20 +2359,21 @@ halfword handle_kerning(halfword head, halfword tail)
return tail;
}
-@* ligaturing and kerning : lua-interface.
+/*tex The ligaturing and kerning \LUA\ interface: */
-@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);
+ 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;
}
diff --git a/Build/source/texk/web2c/luatexdir/font/mapfile.c b/Build/source/texk/web2c/luatexdir/font/mapfile.c
new file mode 100644
index 00000000000..5ea1e7ca0a2
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/mapfile.c
@@ -0,0 +1,770 @@
+/*
+
+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/>.
+
+*/
+
+#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;
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/font/mapfile.w b/Build/source/texk/web2c/luatexdir/font/mapfile.w
deleted file mode 100644
index f47c5b50487..00000000000
--- a/Build/source/texk/web2c/luatexdir/font/mapfile.w
+++ /dev/null
@@ -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;
- }
-}
diff --git a/Build/source/texk/web2c/luatexdir/font/pkin.w b/Build/source/texk/web2c/luatexdir/font/pkin.c
index a5d3eb4bccb..afebdef33e4 100644
--- a/Build/source/texk/web2c/luatexdir/font/pkin.w
+++ b/Build/source/texk/web2c/luatexdir/font/pkin.c
@@ -1,63 +1,56 @@
-% 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
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
-pkin.c - implementation of readchar()
+This file is part of LuaTeX.
-DESCRIPTION
+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.
-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.
+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.
-BUGFIXES
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-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
+/*tex
-Piet Tutelaers <rcpt@@urc.tue.nl>
+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.
-Modified for use with pdftex by Han The Thanh <thanh@@fi.muni.cz>.
+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.
-@c
+At some point Piet Tutelaers <rcpt@urc.tue.nl> redesigned the code and later Han
+The Thanh <thanh@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;
-@
-Now we have some routines to get stuff from the pk file. pkbyte returns
-the next byte from the pk file.
+/*tex
+
+Now we have some routines to get stuff from the \PK\ file. |pkbyte| returns the
+next byte from the \PK\ file.
+
+*/
-@c
static shalfword pkbyte(void)
{
register shalfword i;
@@ -70,7 +63,6 @@ static shalfword pkbyte(void)
static int pkduo(void)
{
register int i;
-
i = pkbyte();
if (i > 127)
i -= 256;
@@ -81,7 +73,6 @@ static int pkduo(void)
static int pktrio(void)
{
register int i;
-
i = pkbyte();
if (i > 127)
i -= 256;
@@ -93,7 +84,6 @@ static int pktrio(void)
static int pkquad(void)
{
register int i;
-
i = pkbyte();
if (i > 127)
i -= 256;
@@ -103,14 +93,13 @@ static int pkquad(void)
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.
-@ 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.
+*/
-@c
static halfword inputbyte, flagbyte;
static halfword bitweight;
static halfword dynf;
@@ -154,10 +143,10 @@ static halfword pkpackednum(void)
i++;
} while (!(j != 0));
if (i > 3) {
-/*
- Damn, we got a huge count! We {\it fake} it by giving an artificially
- large repeat count.
- */
+ /*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) {
@@ -175,9 +164,6 @@ static halfword pkpackednum(void)
repeatcount = pkpackednum();
else
repeatcount = 1;
-#ifdef DEBUG
- printf("[%d]", (int) repeatcount);
-#endif
return ((*realfunc) ());
}
}
@@ -185,7 +171,6 @@ static halfword pkpackednum(void)
static halfword rest(void)
{
halfword i;
-
if (pk_remainder < 0) {
pk_remainder = -pk_remainder;
return (0);
@@ -202,13 +187,12 @@ static halfword rest(void)
} 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--;
@@ -219,11 +203,16 @@ static halfword handlehuge(halfword i, halfword k)
}
-@ And now we have our unpacking routine.
+/*tex
+
+ And now we have our unpacking routine.
+
+*/
-@c
-static halfword gpower[17] = { 0, 1, 3, 7, 15, 31, 63, 127,
- 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535
+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)
@@ -236,7 +225,6 @@ static void unpack(chardesc * cd)
shalfword hbit;
halfword count;
shalfword wordwidth;
-
wordwidth = (shalfword) ((cd->cwidth + 15) / 16);
i = (int) (2 * cd->cheight * (long) wordwidth);
if (i <= 0)
@@ -317,80 +305,89 @@ static void unpack(chardesc * cd)
}
}
-@
-|readchar()|: the main routine
-check pk preamble if necessary,
-Reads the character definition of character `c' into `cd' if available,
-return FALSE (0) otherwise.
+/*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.
+
+*/
-@c
int readchar(boolean check_preamble, chardesc * cd)
{
register shalfword i;
register int k;
register int length = 0;
-
-/*
- Check the preamble of the pkfile
- */
+ /*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");
- for (i = pkbyte(); i > 0; i--) /* creator of pkfile */
+ /*tex The creator of the file: */
+ for (i = pkbyte(); i > 0; i--)
(void) pkbyte();
- (void) pkquad(); /* design size */
- k = pkquad(); /* checksum */
- k = pkquad(); /* hppp */
- k = pkquad(); /* vppp */
+ /*tex The design size: */
+ (void) pkquad();
+ /*tex The checksum: */
+ k = pkquad();
+ /*tex The hppp: */
+ k = pkquad();
+ /*tex The vppp: */
+ k = pkquad();
}
-/*
- Now we skip to the desired character definition
- */
+ /*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();
- (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();
+ 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);
@@ -399,28 +396,29 @@ int readchar(boolean check_preamble, chardesc * cd)
} 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);
+ 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 */
+ /*tex Character not found: */
+ return 0;
}
diff --git a/Build/source/texk/web2c/luatexdir/font/sfnt.w b/Build/source/texk/web2c/luatexdir/font/sfnt.c
index 83e38990dd9..c7f4723c407 100644
--- a/Build/source/texk/web2c/luatexdir/font/sfnt.w
+++ b/Build/source/texk/web2c/luatexdir/font/sfnt.c
@@ -1,53 +1,58 @@
-% 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
-@c
+/*
+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
+#if HAVE_CONFIG_H
# include <w2c/config.h>
-#endif /* |HAVE_CONFIG_H_| */
+#endif
#include <string.h>
#include "font/sfnt.h"
-@ type:
-
- `true' (0x74727565): TrueType (Mac)
-
- `typ1' (0x74797031) (Mac): PostScript font housed in a sfnt wrapper
+/*tex
- 0x00010000: TrueType (Win)/OpenType
+ Types:
- `OTTO': PostScript CFF font with OpenType wrapper
+ \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
- `ttcf': TrueType Collection
+*/
-@c
#define SFNT_TRUETYPE 0x00010000UL
-#define SFNT_MAC_TRUE 0x74727565UL
+#define SFNT_MAC_TRUE 0x74727565UL
#define SFNT_OPENTYPE 0x00010000UL
#define SFNT_POSTSCRIPT 0x4f54544fUL
#define SFNT_TTC 0x74746366UL
@@ -56,14 +61,11 @@ 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) {
@@ -73,7 +75,6 @@ sfnt *sfnt_open(unsigned char *buff, int buflen)
} else if (type == SFNT_TTC) {
sfont->type = SFNT_TYPE_TTC;
}
-
sfont->loc = 0;
sfont->directory = NULL;
return sfont;
@@ -82,7 +83,6 @@ sfnt *sfnt_open(unsigned char *buff, int buflen)
static void release_directory(struct sfnt_table_directory *td)
{
long i;
-
if (td) {
if (td->tables) {
for (i = 0; i < td->num_tables; i++) {
@@ -95,19 +95,16 @@ static void release_directory(struct sfnt_table_directory *td)
RELEASE(td->flags);
RELEASE(td);
}
-
return;
}
void sfnt_close(sfnt * sfont)
{
-
if (sfont) {
if (sfont->directory)
release_directory(sfont->directory);
RELEASE(sfont);
}
-
return;
}
@@ -115,70 +112,67 @@ 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.
+/*tex
+
+ Convert four-byte number to big endianess in a machine independent way.
+
+*/
-@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;
}
+/*tex
-@ Computes the max power of 2 <= n
+ Computes the max power of $|2 <= n$:
+
+*/
-@c
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
+ Computes the log2 of the max power of $2 <= n$
+
+*/
-@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) {
@@ -186,61 +180,45 @@ static ULONG sfnt_calc_checksum(void *data, ULONG length)
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)
@@ -248,19 +226,14 @@ ULONG sfnt_find_table_len(sfnt * sfont, const char *tag)
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)
@@ -268,75 +241,51 @@ ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag)
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) {
@@ -346,22 +295,19 @@ int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist)
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.
-@ 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.
+*/
-@c
# include "font/luatexfont.h"
# undef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
@@ -376,14 +322,8 @@ pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
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);
@@ -391,20 +331,15 @@ pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
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).
- */
+ /*tex 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 */
+ /*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;
@@ -412,11 +347,9 @@ pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
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) {
@@ -426,13 +359,11 @@ pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
offset += length;
}
if (!td->tables[i].data) {
- if (!sfont->buffer)
- {
+ 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) {
@@ -453,10 +384,9 @@ pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont)
RELEASE(td->tables[i].data);
td->tables[i].data = NULL;
}
- /* Set offset for next table */
+ /*tex Set offset for next table. */
offset = (long) (offset + (long) td->tables[i].length);
}
}
-
return stream;
}
diff --git a/Build/source/texk/web2c/luatexdir/font/subfont.w b/Build/source/texk/web2c/luatexdir/font/subfont.c
index 0616bdad43c..d2f5f8d2f5e 100644
--- a/Build/source/texk/web2c/luatexdir/font/subfont.w
+++ b/Build/source/texk/web2c/luatexdir/font/subfont.c
@@ -1,30 +1,28 @@
-% 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
+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/>.
+
+*/
#include "ptexlib.h"
#include <string.h>
-@ @c
static struct avl_table *sfd_tree = NULL;
static unsigned char *sfd_buffer = NULL;
@@ -34,12 +32,11 @@ 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_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)
-
+#define sfd_eof() (sfd_curbyte>=sfd_size)
static FILE *sfd_file;
static char sfd_line[SFD_BUF_SIZE];
@@ -50,8 +47,10 @@ static subfont_entry *new_subfont_entry(void)
subfont_entry *subfont;
subfont = xtalloc(1, subfont_entry);
subfont->infix = NULL;
- for (i = 0; i < 256; ++i)
- subfont->charcodes[i] = -1; /* unassigned */
+ for (i = 0; i < 256; ++i) {
+ /*tex Unassigned: */
+ subfont->charcodes[i] = -1;
+ }
subfont->next = NULL;
return subfont;
}
@@ -84,8 +83,7 @@ static void destroy_sfd_entry(void *pa, void *pb)
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);
+ return strcmp(((const sfd_entry *) pa)->name, ((const sfd_entry *) pb)->name);
}
void sfd_free(void)
@@ -117,19 +115,17 @@ static void sfd_getline(boolean expect_eof)
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 */
+ /*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);
@@ -141,7 +137,6 @@ static sfd_entry *read_sfd(char *sfd_name)
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);
@@ -168,30 +163,38 @@ static sfd_entry *read_sfd(char *sfd_name)
sfd->name = xstrdup(sfd_name);
while (!sfd_eof()) {
sfd_getline(true);
- if (*sfd_line == 10) /* empty line indicating eof */
+ 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);
- p = sfd_line + n; /* skip to the next word */
+ /*tex Skip to the next word: */
+ p = sfd_line + n;
k = 0;
read_ranges:
for (;;) {
- if (*p == '\\') { /* continue on next line */
+ if (*p == '\\') {
+ /*tex Continue on the next line: */
sfd_getline(false);
p = sfd_line;
goto read_ranges;
- } else if (*p == 0) /* end of subfont */
+ } 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 == ':') { /* offset */
+ if (*p == ':') {
+ /*tex Variant: offset */
k = i;
p++;
- } else if (*p == '_') { /* range */
+ } 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)
@@ -199,8 +202,10 @@ static sfd_entry *read_sfd(char *sfd_name)
while (i <= j)
sf->charcodes[k++] = i++;
p += n + 1;
- } else /* codepoint */
+ } else {
+ /*tex Variant: codepoint */
sf->charcodes[k++] = i;
+ }
}
}
tex_printf("}");
@@ -209,7 +214,6 @@ static sfd_entry *read_sfd(char *sfd_name)
return sfd;
}
-@ @c
boolean handle_subfont_fm(fm_entry * fm, int mode)
{
size_t l;
@@ -220,16 +224,20 @@ boolean handle_subfont_fm(fm_entry * fm, int mode)
char buf[SMALL_BUF_SIZE];
assert(fm->tfm_name != NULL);
p = fm->tfm_name;
- q = strchr(p, '@@'); /* search for the first '@@' */
+ /*tex Search for the first |@|. */
+ q = strchr(p, '@');
if (q == NULL)
return false;
- r = strchr(q + 1, '@@'); /* search for the second '@@' */
+ /*tex Search for the second |@|: */
+ r = strchr(q + 1, '@');
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 */
+ /*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;
- l = (size_t) (r - (q + 1)); /* length of sfd name */
+ }
+ /*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);
@@ -237,15 +245,16 @@ boolean handle_subfont_fm(fm_entry * fm, int mode)
sfd = read_sfd(buf);
if (sfd == NULL)
return false;
- /* at this point we know fm is a subfont */
+ /*tex At this point we know fm is a subfont. */
set_subfont(fm);
xfree(fm->ps_name);
- /* set default values for PidEid */
+ /*tex Set default values for |Pid| and |Eid|: */
if (fm->pid == -1) {
fm->pid = 3;
fm->eid = 1;
}
- l = (size_t) (q - p); /* length of base tfm name (prefix) */
+ /*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;
@@ -257,8 +266,11 @@ boolean handle_subfont_fm(fm_entry * fm, int mode)
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 */
+ /*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;
diff --git a/Build/source/texk/web2c/luatexdir/font/texfont.w b/Build/source/texk/web2c/luatexdir/font/texfont.c
index ce463326a86..332a8a3446e 100644
--- a/Build/source/texk/web2c/luatexdir/font/texfont.w
+++ b/Build/source/texk/web2c/luatexdir/font/texfont.c
@@ -1,41 +1,52 @@
-% 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|.
-
-@c
+/*
+
+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/>.
+
+*/
+
+/*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"
-@ @c
#define noDEBUG
#define proper_char_index(c) (c<=font_ec(f) && c>=font_bc(f))
@@ -46,7 +57,6 @@ 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;
@@ -89,7 +99,6 @@ void set_max_font_id(int i)
font_id_maxval = i;
}
-@ @c
int new_font(void)
{
int k;
@@ -98,7 +107,7 @@ int new_font(void)
sa_tree_item sa_value = { 0 };
id = new_font_id();
font_bytes += (int) sizeof(texfont);
- /* most stuff is zero */
+ /*tex Most stuff is zero */
font_tables[id] = xcalloc(1, sizeof(texfont));
font_tables[id]->_font_name = NULL;
font_tables[id]->_font_area = NULL;
@@ -112,43 +121,44 @@ int new_font(void)
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 */
+ /*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);
- font_slant(id) = 0; /* vertical */
- font_extend(id) = 1000; /* normal width */
-
- /* allocate eight values including 0 */
+ /*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);
}
- /* 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 */
+ /*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;
}
-@ @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)));
+ 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)
@@ -163,9 +173,10 @@ charinfo *get_charinfo(internal_font_number f, int c)
if (tglyph >= font_tables[f]->charinfo_size) {
font_malloc_charinfo(f, 256);
}
- font_tables[f]->charinfo[tglyph].ef = 1000; /* init */
+ font_tables[f]->charinfo[tglyph].ef = 1000;
sa_value.int_value = tglyph;
- set_sa_item(font_tables[f]->characters, c, sa_value, 1); /* 1 = global */
+ /*tex 1 means global */
+ set_sa_item(font_tables[f]->characters, c, sa_value, 1);
glyph = tglyph;
}
return &(font_tables[f]->charinfo[glyph]);
@@ -187,7 +198,6 @@ charinfo *get_charinfo(internal_font_number f, int c)
return &(font_tables[f]->charinfo[0]);
}
-@ @c
static void set_charinfo(internal_font_number f, int c, charinfo * ci)
{
int glyph;
@@ -205,7 +215,6 @@ static void set_charinfo(internal_font_number f, int c, charinfo * ci)
}
}
-@ @c
charinfo *copy_charinfo(charinfo * ci)
{
int x, k;
@@ -231,7 +240,7 @@ charinfo *copy_charinfo(charinfo * ci)
if (ci->tounicode != NULL) {
co->tounicode = xstrdup(ci->tounicode);
}
- /* kerns */
+ /*tex Kerns */
if ((kern = get_charinfo_kerns(ci)) != NULL) {
x = 0;
while (!kern_end(kern[x])) {
@@ -241,7 +250,7 @@ charinfo *copy_charinfo(charinfo * ci)
co->kerns = xmalloc((unsigned) (x * (int) sizeof(kerninfo)));
memcpy(co->kerns, ci->kerns, (size_t) (x * (int) sizeof(kerninfo)));
}
- /* ligs */
+ /*tex Ligatures */
if ((lig = get_charinfo_ligatures(ci)) != NULL) {
x = 0;
while (!lig_end(lig[x])) {
@@ -252,14 +261,13 @@ charinfo *copy_charinfo(charinfo * ci)
memcpy(co->ligatures, ci->ligatures,
(size_t) (x * (int) sizeof(liginfo)));
}
- /* packets */
+ /*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);
}
-
- /* horizontal and vertical extenders */
+ /*tex Horizontal and vertical extenders */
if (get_charinfo_vert_variants(ci) != NULL) {
set_charinfo_vert_variants(co, copy_variants(get_charinfo_vert_variants(ci)));
}
@@ -320,7 +328,6 @@ charinfo *char_info(internal_font_number f, int c)
return &(font_tables[f]->charinfo[0]);
}
-@ @c
scaled_whd get_charinfo_whd(internal_font_number f, int c)
{
scaled_whd s;
@@ -332,7 +339,6 @@ scaled_whd get_charinfo_whd(internal_font_number f, int c)
return s;
}
-@ @c
int char_exists(internal_font_number f, int c)
{
if (f > font_id_maxval)
@@ -347,35 +353,35 @@ int char_exists(internal_font_number f, int c)
return 0;
}
-@ @c
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_pop(Luas, 2);
+ lua_settop(Luas, top);
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();
+ 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;
}
-@ @c
-extinfo *new_variant(int glyph, int startconnect, int endconnect,
- int advance, int repeater)
+extinfo *new_variant(int glyph, int startconnect, int endconnect, int advance, int repeater)
{
extinfo *ext;
ext = xmalloc(sizeof(extinfo));
@@ -388,8 +394,6 @@ extinfo *new_variant(int glyph, int startconnect, int endconnect,
return ext;
}
-
-@ @c
static extinfo *copy_variant(extinfo * old)
{
extinfo *ext;
@@ -403,7 +407,6 @@ static extinfo *copy_variant(extinfo * old)
return ext;
}
-@ @c
static void dump_variant(extinfo * ext)
{
dump_int(ext->glyph);
@@ -414,8 +417,6 @@ static void dump_variant(extinfo * ext)
return;
}
-
-@ @c
static extinfo *undump_variant(void)
{
int x;
@@ -437,7 +438,6 @@ static extinfo *undump_variant(void)
return ext;
}
-@ @c
void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
{
if (ci->vert_variants == NULL) {
@@ -451,7 +451,6 @@ void add_charinfo_vert_variant(charinfo * ci, extinfo * ext)
}
-@ @c
void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
{
if (ci->hor_variants == NULL) {
@@ -465,7 +464,6 @@ void add_charinfo_hor_variant(charinfo * ci, extinfo * ext)
}
-@ @c
extinfo *copy_variants(extinfo * o)
{
extinfo *c, *t = NULL, *h = NULL;
@@ -482,7 +480,6 @@ extinfo *copy_variants(extinfo * o)
return h;
}
-@ @c
static void dump_charinfo_variants(extinfo * o)
{
while (o != NULL) {
@@ -493,7 +490,6 @@ static void dump_charinfo_variants(extinfo * o)
return;
}
-@ @c
static extinfo *undump_charinfo_variants(void)
{
extinfo *c, *t = NULL, *h = NULL;
@@ -510,9 +506,12 @@ static extinfo *undump_charinfo_variants(void)
}
-@ Note that mant more small things like this are implemented
-as macros in the header file.
-@c
+/*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;
@@ -610,7 +609,6 @@ void set_charinfo_rp(charinfo * ci, scaled val)
ci->rp = val;
}
-@ @c
void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
{
extinfo *c, *lst;
@@ -625,7 +623,6 @@ void set_charinfo_vert_variants(charinfo * ci, extinfo * ext)
ci->vert_variants = ext;
}
-@ @c
void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
{
extinfo *c, *lst;
@@ -641,11 +638,10 @@ void set_charinfo_hor_variants(charinfo * ci, extinfo * ext)
}
-@ @c
int get_charinfo_math_kerns(charinfo * ci, int id)
{
-
- int k = 0; /* all callers check for |result>0| */
+ /*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) {
@@ -660,7 +656,6 @@ int get_charinfo_math_kerns(charinfo * ci, int id)
return k;
}
-@ @c
void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
{
int k;
@@ -693,8 +688,6 @@ void add_charinfo_math_kern(charinfo * ci, int id, scaled ht, scaled krn)
}
}
-
-@ @c
static void dump_math_kerns(charinfo * ci)
{
int k, l;
@@ -724,11 +717,9 @@ static void dump_math_kerns(charinfo * ci)
}
}
-@ @c
static void undump_math_kerns(charinfo * ci)
{
- int k;
- int x;
+ int k, x;
undump_int(x);
ci->top_left_math_kerns = x;
if (x > 0)
@@ -771,21 +762,23 @@ static void undump_math_kerns(charinfo * ci)
}
}
+/*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
+ 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.
- a small complication arises if |rep| is the only non-zero: it needs to be
- doubled as a non-repeatable to avoid mayhem */
+*/
-@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 */
+ /*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);
@@ -815,10 +808,13 @@ void set_charinfo_extensible(charinfo * ci, int top, int bot, int mid, int rep)
}
}
-@ Note that many more simple things like this are implemented as macros
-in the header file.
+/*tex
+
+ Note that many more simple things like this are implemented as macros in the
+ header file.
+
+*/
-@c
scaled get_charinfo_width(charinfo * ci)
{
return ci->width;
@@ -987,7 +983,6 @@ scaled char_bot_accent(internal_font_number f, int c)
return get_charinfo_bot_accent(ci);
}
-
int char_remainder(internal_font_number f, int c)
{
charinfo *ci = char_info(f, c);
@@ -1036,7 +1031,6 @@ eight_bits *char_packets(internal_font_number f, int c)
return get_charinfo_packets(ci);
}
-@ @c
void set_font_params(internal_font_number f, int b)
{
int i;
@@ -1055,7 +1049,6 @@ void set_font_params(internal_font_number f, int b)
}
}
-@ @c
void set_font_math_params(internal_font_number f, int b)
{
int i;
@@ -1074,13 +1067,11 @@ void set_font_math_params(internal_font_number f, int b)
}
}
-@ @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;
@@ -1090,12 +1081,10 @@ int copy_font(int f)
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;
@@ -1106,7 +1095,6 @@ int copy_font(int f)
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)));
@@ -1122,12 +1110,10 @@ int copy_font(int f)
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));
@@ -1135,27 +1121,23 @@ int copy_font(int f)
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: */
+ /*tex Not updated yet: */
font_tables[k]->charinfo_count = font_tables[f]->charinfo_count;
return k;
}
-@ @c
void delete_font(int f)
{
int i;
@@ -1172,7 +1154,6 @@ void delete_font(int f)
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);
@@ -1185,24 +1166,21 @@ void delete_font(int f)
set_charinfo_hor_variants(co, NULL);
}
}
- /* free .notdef */
+ /*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--;
}
}
}
-@ @c
void create_null_font(void)
{
int i = new_font();
@@ -1212,7 +1190,6 @@ void create_null_font(void)
set_font_touched(i, 1);
}
-@ @c
boolean is_valid_font(int id)
{
int ret = 0;
@@ -1221,7 +1198,6 @@ boolean is_valid_font(int id)
return ret;
}
-@ @c
boolean cmp_font_area(int id, str_number t)
{
char *tt = NULL;
@@ -1241,9 +1217,13 @@ boolean cmp_font_area(int id, str_number t)
return 1;
}
-@ Here come some subroutines to deal with expanded fonts for HZ-algorithm.
-return 1 == identical
-@c
+/*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;
@@ -1257,18 +1237,16 @@ static boolean cmp_font_name(int id, char *tt)
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)| */
+ if (has_lig(f, c))
return 0;
}
return 1;
}
-@ @c
int get_tag_code(internal_font_number f, int c)
{
small_number i;
@@ -1286,7 +1264,6 @@ int get_tag_code(internal_font_number f, int c)
return -1;
}
-@ @c
int get_lp_code(internal_font_number f, int c)
{
charinfo *ci = char_info(f, c);
@@ -1305,13 +1282,11 @@ int get_ef_code(internal_font_number f, int 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) {
@@ -1333,7 +1308,6 @@ void set_tag_code(internal_font_number f, int c, int i)
}
}
-@ @c
void set_lp_code(internal_font_number f, int c, int i)
{
charinfo *co;
@@ -1361,7 +1335,6 @@ void set_ef_code(internal_font_number f, int c, int i)
}
}
-@ @c
void set_no_ligatures(internal_font_number f)
{
int c;
@@ -1370,7 +1343,7 @@ void set_no_ligatures(internal_font_number f)
return;
co = char_info(f, left_boundarychar);
set_charinfo_ligatures(co, NULL);
- co = char_info(f, right_boundarychar); /* this is weird */
+ 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;
@@ -1379,7 +1352,6 @@ void set_no_ligatures(internal_font_number f)
font_tables[f]->ligatures_disabled = 1;
}
-@ @c
liginfo get_ligature(internal_font_number f, int lc, int rc)
{
int k = 0;
@@ -1407,7 +1379,6 @@ liginfo get_ligature(internal_font_number f, int lc, int rc)
return t;
}
-@ @c
scaled raw_get_kern(internal_font_number f, int lc, int rc)
{
int k = 0;
@@ -1431,7 +1402,6 @@ scaled raw_get_kern(internal_font_number f, int lc, int rc)
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)))
@@ -1440,15 +1410,14 @@ scaled get_kern(internal_font_number f, int lc, int rc)
}
-@ dumping and undumping fonts
+/*tex Dumping and undumping fonts. */
-@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); \
+#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)
@@ -1476,8 +1445,7 @@ static void dump_charinfo(int f, int c)
dump_int(get_charinfo_index(co));
dump_string(get_charinfo_name(co));
dump_string(get_charinfo_tounicode(co));
-
- /* ligatures */
+ /*tex Ligatures */
x = 0;
if ((lig = get_charinfo_ligatures(co)) != NULL) {
while (!lig_end(lig[x])) {
@@ -1489,7 +1457,7 @@ static void dump_charinfo(int f, int c)
} else {
dump_int(x);
}
- /* kerns */
+ /*tex Kerns */
x = 0;
if ((kern = get_charinfo_kerns(co)) != NULL) {
while (!kern_end(kern[x])) {
@@ -1501,13 +1469,12 @@ static void dump_charinfo(int f, int c)
} else {
dump_int(x);
}
- /* packets */
+ /*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));
@@ -1532,6 +1499,9 @@ static void dump_font_entry(texfont * f)
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);
@@ -1556,7 +1526,6 @@ static void dump_font_entry(texfont * f)
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]);
@@ -1568,9 +1537,7 @@ void dump_font(int 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 ));
}
@@ -1586,7 +1553,6 @@ void dump_font(int f)
} else {
dump_int(0);
}
-
for (i = font_bc(f); i <= font_ec(f); i++) {
if (quick_char_exists(f, i)) {
dump_charinfo(f, i);
@@ -1594,7 +1560,6 @@ void dump_font(int f)
}
}
-@ @c
static int undump_charinfo(int f)
{
charinfo *co;
@@ -1603,7 +1568,6 @@ static int undump_charinfo(int f)
liginfo *lig = NULL;
kerninfo *kern = NULL;
eight_bits *packet = NULL;
-
undump_int(i);
co = get_charinfo(f, i);
undump_int(x);
@@ -1634,8 +1598,7 @@ static int undump_charinfo(int f)
set_charinfo_used(co, x);
undump_int(x);
set_charinfo_index(co, x);
-
- /* name */
+ /*tex Name */
undump_int(x);
if (x > 0) {
font_bytes += x;
@@ -1643,7 +1606,7 @@ static int undump_charinfo(int f)
undump_things(*s, x);
}
set_charinfo_name(co, s);
- /* tounicode */
+ /*tex Tounicode */
undump_int(x);
if (x > 0) {
font_bytes += x;
@@ -1651,7 +1614,7 @@ static int undump_charinfo(int f)
undump_things(*s, x);
}
set_charinfo_tounicode(co, s);
- /* ligatures */
+ /*tex Ligatures */
undump_int(x);
if (x > 0) {
font_bytes += (int) ((unsigned) x * sizeof(liginfo));
@@ -1659,7 +1622,7 @@ static int undump_charinfo(int f)
undump_things(*lig, x);
}
set_charinfo_ligatures(co, lig);
- /* kerns */
+ /*tex Kerns */
undump_int(x);
if (x > 0) {
font_bytes += (int) ((unsigned) x * sizeof(kerninfo));
@@ -1668,7 +1631,7 @@ static int undump_charinfo(int f)
}
set_charinfo_kerns(co, kern);
- /* packets */
+ /*tex Packets */
undump_int(x);
if (x > 0) {
font_bytes += x;
@@ -1676,7 +1639,6 @@ static int undump_charinfo(int f)
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());
@@ -1685,19 +1647,18 @@ static int undump_charinfo(int f)
return i;
}
-#define undump_font_string(a) \
- undump_int (x); \
- if (x>0) { \
- font_bytes += x; \
+#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); \
+ 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;
@@ -1711,6 +1672,9 @@ static void undump_font_entry(texfont * f)
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;
@@ -1730,7 +1694,6 @@ static void undump_font_entry(texfont * f)
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)
@@ -1746,7 +1709,6 @@ void undump_font(int f)
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);
@@ -1755,12 +1717,10 @@ void undump_font(int f)
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));
@@ -1768,35 +1728,40 @@ void undump_font(int f)
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 */
+ /*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) {
- i = undump_charinfo(f); /* left boundary */
+ /*tex left boundary */
+ i = undump_charinfo(f);
}
undump_int(x);
if (x) {
- i = undump_charinfo(f); /* right boundary */
+ /*tex right boundary */
+ i = undump_charinfo(f);
}
-
i = font_bc(f);
while (i < font_ec(f)) {
i = undump_charinfo(f);
}
}
-/* moved from pdffont.w */
+/* The \PK\ pixel density value from |texmf.cnf| */
+
+int pk_dpi;
-@ @c
-int pk_dpi; /* PK pixel density value from \.{texmf.cnf} */
+/*tex
+
+ This one looks up the font for a \TFM\ with name |s| loaded at |fs| size and
+ if found then flushes |s|.
+
+*/
-@ @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++) {
@@ -1814,9 +1779,14 @@ internal_font_number tfm_lookup(char *s, scaled fs)
return null_font;
}
-@ @c
+/*tex
+
+ This returns the multiple of |font_step(f)| that is nearest to |e|.
+
+*/
+
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;
@@ -1842,7 +1812,6 @@ int fix_expand_value(internal_font_number f, int 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);
@@ -1850,19 +1819,20 @@ void set_expand_params(internal_font_number f, int stretch_limit, int shrink_lim
set_font_max_stretch(f, stretch_limit);
}
-@ @c
+/*tex
+
+ This reads font expansion spec and load expanded font.
+
+*/
+
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);
@@ -1882,24 +1852,21 @@ void read_expand_font(void)
normal_error("font expansion", "invalid limit(s)");
if (scan_keyword("autoexpand")) {
normal_warning("font expansion", "autoexpand not supported");
- /* Scan an optional space */
+ /*tex 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 */
+ /*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)))
+ ((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)))
+ ((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))
@@ -1908,11 +1875,17 @@ void read_expand_font(void)
}
}
-@ @c
+/*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)
-{ /* letter-space a font by creating a virtual font */
- pointer u; /* user's font identifier */
- str_number t; /* name for the frozen font identifier */
+{
+ pointer u;
+ str_number t;
internal_font_number f, k;
boolean nolig = false;
get_r_token();
@@ -1934,11 +1907,17 @@ void new_letterspaced_font(small_number a)
font_id_text(f) = t;
}
-@ @c
+/*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)
-{ /* 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 */
+{
+ pointer u;
+ str_number t;
internal_font_number f, k;
get_r_token();
u = cur_cs;
@@ -1956,7 +1935,6 @@ void make_font_copy(small_number a)
font_id_text(f) = t;
}
-@ @c
void glyph_to_unicode(void)
{
str_number s1, s2;
diff --git a/Build/source/texk/web2c/luatexdir/font/tfmofm.c b/Build/source/texk/web2c/luatexdir/font/tfmofm.c
new file mode 100644
index 00000000000..f5d8c2e92f3
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/tfmofm.c
@@ -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;
+}
diff --git a/Build/source/texk/web2c/luatexdir/font/tfmofm.w b/Build/source/texk/web2c/luatexdir/font/tfmofm.w
deleted file mode 100644
index 6eeccdda214..00000000000
--- a/Build/source/texk/web2c/luatexdir/font/tfmofm.w
+++ /dev/null
@@ -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
-@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.
-
-@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@>
-@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.
-
-@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;
-}
diff --git a/Build/source/texk/web2c/luatexdir/font/tounicode.w b/Build/source/texk/web2c/luatexdir/font/tounicode.c
index 441a10dd5cf..f0449aff957 100644
--- a/Build/source/texk/web2c/luatexdir/font/tounicode.w
+++ b/Build/source/texk/web2c/luatexdir/font/tounicode.c
@@ -1,41 +1,46 @@
-% 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
+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/>.
+
+*/
#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()| */
+
+/*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);
+ return strcmp(((const glyph_unicode_entry *) pa)->name, ((const glyph_unicode_entry *) pb)->name);
}
static glyph_unicode_entry *new_glyph_unicode_entry(void)
@@ -54,7 +59,6 @@ static void destroy_glyph_unicode_entry(void *pa, void *pb)
(void) pb;
xfree(e->name);
if (e->code == UNI_STRING) {
- assert(e->unicode_seq != NULL);
xfree(e->unicode_seq);
}
}
@@ -65,31 +69,34 @@ void glyph_unicode_free(void)
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 */
+ /*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++; /* ignore leading spaces */
+ p++;
l = (int) strlen(p);
+ /*tex Ignore traling spaces. */
while (l > 0 && p[l - 1] == ' ')
- l--; /* ignore traling spaces */
- valid_unistr = 1; /* a unicode value is the most common case */
+ 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; /* if a space occurs we treat this entry as a string */
+ valid_unistr = 2;
else if (!isXdigit((unsigned char)p[i])) {
valid_unistr = 0;
break;
@@ -100,23 +107,21 @@ void def_tounicode(str_number glyph, str_number unistr)
return;
}
if (glyph_unicode_tree == NULL) {
- glyph_unicode_tree =
- avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
- assert(glyph_unicode_tree != NULL);
+ glyph_unicode_tree = avl_create(comp_glyph_unicode_entry, NULL, &avl_xallocator);
}
t.name = buf;
- /* allow overriding existing entries */
+ /*tex 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 */
+ } else {
+ /*tex Make a 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 */
+ 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;
@@ -125,28 +130,24 @@ void def_tounicode(str_number glyph, str_number unistr)
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 */
-
+ /*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;
@@ -171,33 +172,33 @@ static long check_unicode_value(char *s, boolean multiple_value)
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.
-@c
+/*
+
+ 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;
-
- /* skip dummy entries */
+ /*tex Skip dummy entries. */
if (s == NULL || s == notdef)
return;
-
- /* strip everything after the first dot */
+ /*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;
-
- /* check for case of multiple components separated by |'_'| */
+ /*tex Check for case of multiple components separated by |_|. */
p = strchr(s, '_');
if (p != NULL) {
assert(strlen(s) < sizeof(buf));
@@ -213,20 +214,26 @@ static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
tmp.code = UNI_UNDEF;
set_glyph_unicode(s, &tmp);
switch (tmp.code) {
- case UNI_UNDEF: /* not found, do nothing */
+ case UNI_UNDEF:
+ /*tex Not found, do nothing. */
break;
- case UNI_STRING: /* s matched an entry with string value in the database */
+ 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: /* s is a multiple value of form "uniXXXX" */
+ 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: /* s matched an entry with numeric value in the
- database, or a value derived from "uXXXX" */
+ 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));
}
@@ -243,8 +250,7 @@ static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
gp->unicode_seq = xstrdup(buf2);
return;
}
-
- /* lookup for glyph name in the database */
+ /*tex Lookup glyph name in the database. */
tmp.name = s;
tmp.code = UNI_UNDEF;
ptmp = (glyph_unicode_entry *) avl_find(glyph_unicode_tree, &tmp);
@@ -253,23 +259,24 @@ static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
gp->unicode_seq = ptmp->unicode_seq;
return;
}
-
- /* check for case of "uniXXXX" (multiple 4-hex-digit values allowed) */
+ /*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) /* single value */
+ if (strlen(p) == 4) {
+ /*tex Single value: */
gp->code = code;
- else { /* multiple value */
+ } else {
+ /*tex Multiple value: */
gp->code = UNI_EXTRA_STRING;
gp->unicode_seq = xstrdup(p);
}
}
- return; /* since the last case cannot happen */
+ /*tex Since the last case cannot happen: */
+ return;
}
-
- /* check for case of "uXXXX" (single value up to 6 hex digits) */
+ /*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);
@@ -280,9 +287,7 @@ static void set_glyph_unicode(char *s, glyph_unicode_entry * gp)
}
}
-@ @c
-static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp,
- internal_font_number f)
+static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp, internal_font_number f)
{
char *s;
if (font_tounicode(f)) {
@@ -290,15 +295,14 @@ static void set_cid_glyph_unicode(long index, glyph_unicode_entry * gp,
gp->code = UNI_EXTRA_STRING;
gp->unicode_seq = xstrdup(s);
} else {
- /* no fallback as we're providing them ourselves */
+ /*tex No fall back as we're providing them ourselves. */
}
} else {
- /* fallback */
+ /*tex Fall back. */
gp->code = index;
}
}
-@ @c
int write_tounicode(PDF pdf, char **glyph_names, char *name)
{
char buf[SMALL_BUF_SIZE], *p;
@@ -314,64 +318,75 @@ int write_tounicode(PDF pdf, char **glyph_names, char *name)
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" */
+ 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);
-
- /* set gtab */
+ 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;
-
- /* set |range_size| */
+ /*tex 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 */
+ /*tex Single entry: */
+ range_size[i] = 1;
i++;
} else if (gtab[i].code == UNI_UNDEF) {
- range_size[i] = 0; /* no entry */
+ /*tex No entry: */
+ range_size[i] = 0;
i++;
- } else { /* gtab[i].code >= 0 */
+ } else {
+ /*tex |gtab[i].code >= 0| */
j = i;
- while (i < 256 && gtab[i + 1].code >= 0 &&
- gtab[i].code + 1 == gtab[i + 1].code)
+ 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 */
+ /*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);
}
}
-
- /* calculate |bfrange_count| and |bfchar_count| */
+ /*tex Calculate |bfrange_count| and |bfchar_count|. */
bfrange_count = 0;
bfchar_count = 0;
for (i = 0; i < 256;) {
@@ -384,8 +399,7 @@ int write_tounicode(PDF pdf, char **glyph_names, char *name)
} else
i++;
}
-
- /* write out bfrange */
+ /*tex Write out |bfrange|. */
i = 0;
write_bfrange:
if (bfrange_count > 100)
@@ -405,8 +419,7 @@ int write_tounicode(PDF pdf, char **glyph_names, char *name)
pdf_printf(pdf, "endbfrange\n");
if (bfrange_count > 0)
goto write_bfrange;
-
- /* write out bfchar */
+ /*tex Write out |bfchar|. */
i = 0;
write_bfchar:
if (bfchar_count > 100)
@@ -421,7 +434,7 @@ int write_tounicode(PDF pdf, char **glyph_names, char *name)
i += range_size[i];
else if (range_size[i] == 0)
i++;
- else /* |range_size[i] == 1| */
+ else
break;
}
assert(i < 256 && gtab[i].code != UNI_UNDEF);
@@ -435,66 +448,63 @@ int write_tounicode(PDF pdf, char **glyph_names, char *name)
pdf_printf(pdf, "endbfchar\n");
if (bfchar_count > 0)
goto write_bfchar;
-
- /* free strings allocated by |set_glyph_unicode()| */
+ /*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_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);
-
+ 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);
+ 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 */
+ /*tex Set up |gtab|: */
for (i = 0; i < 65537; ++i) {
gtab[i].code = UNI_UNDEF;
}
@@ -510,29 +520,33 @@ int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
}
}
}
-
- /* set |range_size| */
+ /*tex 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 */
+ /*tex Single entry. */
+ range_size[i] = 1;
i++;
} else if (gtab[i].code == UNI_UNDEF) {
- range_size[i] = 0; /* no entry */
+ /*tex No entry. */
+ range_size[i] = 0;
i++;
- } else { /* |gtab[i].code >= 0| */
+ } 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++;
}
- /* at this point i is the last entry of the subrange */
- i++; /* move i to the next entry */
+ /* 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;
}
}
-
- /* calculate |bfrange_count| and |bfchar_count| */
+ /*tex Calculate |bfrange_count| and |bfchar_count|. */
bfrange_count = 0;
bfchar_count = 0;
for (i = 0; i < 65536;) {
@@ -545,8 +559,7 @@ int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
} else
i++;
}
-
- /* write out bfrange */
+ /*tex Write out |bfrange|. */
i = 0;
write_bfrange:
if (bfrange_count > 100)
@@ -558,16 +571,13 @@ int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
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));
+ 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 */
+ /*tex Write out |bfchar| */
i = 0;
write_bfchar:
if (bfchar_count > 100)
@@ -582,12 +592,12 @@ int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
i += range_size[i];
else if (range_size[i] == 0)
i++;
- else /* |range_size[i] == 1| */
+ 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));
@@ -596,16 +606,18 @@ int write_cid_tounicode(PDF pdf, fo_entry * fo, internal_font_number f)
pdf_printf(pdf, "endbfchar\n");
if (bfchar_count > 0)
goto write_bfchar;
-
- /* free strings allocated by |set_glyph_unicode()| */
+ /*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_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;
diff --git a/Build/source/texk/web2c/luatexdir/font/tt_glyf.w b/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
index c0f17e5ab59..750e126aa6a 100644
--- a/Build/source/texk/web2c/luatexdir/font/tt_glyf.w
+++ b/Build/source/texk/web2c/luatexdir/font/tt_glyf.c
@@ -1,28 +1,25 @@
-% 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.
+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>
-@ @c
+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"
@@ -31,7 +28,6 @@
#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
@@ -39,55 +35,41 @@
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 {
@@ -102,28 +84,21 @@ USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT 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->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 */
-@ Initialization
-@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;
@@ -134,7 +109,6 @@ struct tt_glyphs *tt_build_init(void)
g->used_slot = NEW(8192, unsigned char);
memset(g->used_slot, 0, 8192);
tt_add_glyph(g, 0, 0);
-
return g;
}
@@ -159,37 +133,33 @@ 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 */
+ /*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;
- /* temp */
+ /*tex Something temporary: */
ULONG *location, offset;
long i;
- USHORT *w_stat; /* Estimate most frequently appeared width */
-
+ /*tex Estimate the most frequently appeared width. */
+ USHORT *w_stat;
int tex_font = fd->tex_font;
int streamprovider = 0;
int callback_id = 0 ;
@@ -197,60 +167,35 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
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! */
+ /*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);
+ 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) {
@@ -262,34 +207,27 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
} 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.
- */
+ memset(w_stat, 0, (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
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.
- */
+ /*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; /* old gid */
+ USHORT gid;
ULONG loc, len;
BYTE *p, *endptr;
SHORT number_of_contours;
-
- if (i >= g->num_glyphs) /* finished */
+ 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;
@@ -306,52 +244,43 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
if (g->gd[i].advw <= g->emsize) {
w_stat[g->gd[i].advw]++;
} else {
- w_stat[g->emsize + 1]++; /* larger than em */
+ /*tex It's larger than em. */
+ w_stat[g->emsize + 1]++;
}
- if (len == 0) { /* Does not contains any data. */
+ if (len == 0) {
+ /*tex Does not contain any data. */
continue;
} else if (len < 10) {
formatted_error("ttf","invalid glyph data (gid %u)", gid);
}
-
-/* todo: no need for this */
+ /*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);
- /* |_FIXME_| */
-#if 1
- if (!vmtx) /* |vertOriginY == sTypeAscender| */
- g->gd[i].tsb =
- (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
+ 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);
-
- /* Read evrything else. */
+ /*tex Read evrything else. */
sfnt_read(p, (int) len - 10, sfont);
- /*
- Fix GIDs of composite glyphs.
- */
+ /*tex Fix GIDs of composite glyphs. */
if (number_of_contours < 0) {
- USHORT flags, cgid, new_gid; /* flag, gid of a component */
+ USHORT flags, cgid, new_gid;
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));
@@ -363,34 +292,38 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
}
p += sfnt_put_ushort(p, new_gid);
- /*
- * Just skip remaining part.
- */
+ /*tex Just skip remaining part. */
p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
- if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
+ if (flags & WE_HAVE_A_SCALE) {
+ /*tex |F2Dot14| */
p += 2;
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 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) /* F2Dot14 x 4 */
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
+ /*tex four times |F2Dot14| */
p += 8;
+ }
} while (flags & MORE_COMPONENTS);
- /*
- TrueType instructions comes here:
+ /*tex
+
+ TrueType instructions comes here. The call pattern is:
- |length_of_instruction| (|ushort|)
+ \starttyping
+ |length_of_instruction| (|ushort|)
+ instruction (|byte * length_of_instruction|)
+ \stoptyping
- instruction (|byte * length_of_instruction|)
*/
}
}
RELEASE(location);
RELEASE(hmtx);
- if (vmtx)
+ 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) {
@@ -400,13 +333,11 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
}
}
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;
@@ -419,17 +350,17 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
num_hm_known = 1;
}
}
- /* All advance widths are same. */
+ /*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);
+ 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.
- /*
- 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);
@@ -437,12 +368,10 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
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++) {
@@ -470,12 +399,10 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
} 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 */
+ 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) {
@@ -487,18 +414,15 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
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 */
+ /*tex We free data here since it consume much memory. */
g->gd[i].length = 0;
g->gd[i].data = NULL;
}
@@ -507,7 +431,6 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
} 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) {
@@ -515,20 +438,17 @@ int tt_build_tables(sfnt * sfont, struct tt_glyphs *g, fd_entry * fd)
}
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)
+ if (os2) {
RELEASE(os2);
-
+ }
return 0;
}
@@ -539,66 +459,33 @@ int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
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
- )
+ 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");
-
- /*
- 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);
+ 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) {
@@ -610,22 +497,16 @@ int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
} 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.
- */
+ /*tex Read glyf table. */
offset = sfnt_locate_table(sfont, "glyf");
for (i = 0; i < g->num_glyphs; i++) {
- USHORT gid; /* old gid */
+ USHORT 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;
@@ -639,33 +520,30 @@ int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
}
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 */
+ /*tex It's larger than em: */
+ w_stat[g->emsize + 1]++;
}
-
- if (len == 0) { /* Does not contains any data. */
+ 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));
- /*number_of_contours = */(void)sfnt_get_short(sfont);
-
- /* BoundingBox: FWord x 4 */
+ /*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);
- /* |_FIXME_| */
-#if 1
- if (!vmtx) /* |vertOriginY == sTypeAscender| */
- g->gd[i].tsb =
- (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
-#endif
+ 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);
@@ -673,13 +551,11 @@ int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
RELEASE(hhea);
RELEASE(head);
RELEASE(os2);
-
- if (vmtx)
+ 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) {
@@ -689,7 +565,5 @@ int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
}
}
RELEASE(w_stat);
-
-
return 0;
}
diff --git a/Build/source/texk/web2c/luatexdir/font/tt_table.w b/Build/source/texk/web2c/luatexdir/font/tt_table.c
index a4164f39d48..dfcd4d650cd 100644
--- a/Build/source/texk/web2c/luatexdir/font/tt_table.w
+++ b/Build/source/texk/web2c/luatexdir/font/tt_table.c
@@ -1,52 +1,41 @@
-% 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
+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.
-#include "ptexlib.h"
+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"
-@ tables contains information refered by other tables
-
- |maxp->numGlyphs, etc --> loca, etc|
-
- |hhea->numberOfHMetrics --> hmtx|
+/*tex
- |head->indexToLocFormat --> loca|
+ Tables contain information referred by other tables.
- |head->glyphDataFormat --> glyf|
+*/
-@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);
@@ -69,7 +58,6 @@ char *tt_pack_head_table(struct tt_head_table *table)
p += sfnt_put_short(p, table->fontDirectionHint);
p += sfnt_put_short(p, table->indexToLocFormat);
p += sfnt_put_short(p, table->glyphDataFormat);
-
return data;
}
@@ -77,11 +65,8 @@ 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);
@@ -103,14 +88,12 @@ struct tt_head_table *tt_read_head_table(sfnt * 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);
@@ -127,16 +110,13 @@ char *tt_pack_maxp_table(struct tt_maxp_table *table)
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);
@@ -153,7 +133,6 @@ struct tt_maxp_table *tt_read_maxp_table(sfnt * sfont)
table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
table->maxComponentElements = sfnt_get_ushort(sfont);
table->maxComponentDepth = sfnt_get_ushort(sfont);
-
return table;
}
@@ -161,7 +140,6 @@ 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);
@@ -178,7 +156,6 @@ char *tt_pack_hhea_table(struct tt_hhea_table *table)
}
p += sfnt_put_short(p, table->metricDataFormat);
p += sfnt_put_ushort(p, table->numberOfHMetrics);
-
return data;
}
@@ -186,9 +163,7 @@ 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);
@@ -207,23 +182,19 @@ struct tt_hhea_table *tt_read_hhea_table(sfnt * sfont)
if (table->metricDataFormat != 0)
normal_error("ttf","unknown metricDaraFormat");
table->numberOfHMetrics = sfnt_get_ushort(sfont);
-
return table;
}
-@ vhea
-@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->advanceHeightMax);
p += sfnt_put_short(p, table->minTopSideBearing);
p += sfnt_put_short(p, table->minBottomSideBearing);
p += sfnt_put_short(p, table->yMaxExtent);
@@ -234,7 +205,6 @@ char *tt_pack_vhea_table(struct tt_vhea_table *table)
p += sfnt_put_short(p, table->reserved[i]);
}
p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
-
return data;
}
@@ -242,15 +212,13 @@ 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->advanceHeightMax = sfnt_get_short(sfont);
table->minTopSideBearing = sfnt_get_short(sfont);
table->minBottomSideBearing = sfnt_get_short(sfont);
table->yMaxExtent = sfnt_get_short(sfont);
@@ -261,34 +229,26 @@ struct tt_vhea_table *tt_read_vhea_table(sfnt * sfont)
(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.
- */
+ 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);
@@ -296,22 +256,20 @@ struct tt_VORG_table *tt_read_VORG_table(sfnt * sfont)
} else {
vorg = NULL;
}
-
return vorg;
}
+/*tex
-@ hmtx and vmtx
+ Reading and writing |hmtx| and |vmtx| depends on other tables, like |maxp|,
+ |hhea| and |vhea|.
-Reading/writing hmtx and vmtx depend on other tables, maxp and hhea/vhea.
+*/
-@c
-struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs,
- USHORT numLongMetrics)
+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)
@@ -319,26 +277,23 @@ struct tt_longMetrics *tt_read_longMetrics(sfnt * sfont, USHORT numGlyphs,
m[gid].sideBearing = sfnt_get_short(sfont);
m[gid].advance = last_adv;
}
-
return m;
}
-@ OS/2 table
+/*tex
+
+ The |OS/2| table may not exist.
+
+*/
-this table may not exist
-@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);
@@ -382,37 +337,31 @@ struct tt_os2__table *tt_read_os2__table(sfnt * 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 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' */
+ /*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) {
@@ -428,33 +377,28 @@ tt_get_name(sfnt * sfont, char *dest, USHORT destlen,
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 */
+ /*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");
- /*
- Wrokaround for some bad TTfonts:
- Language ID value 0xffffu for `accept any language ID'
- */
+ /*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) {
- /*
- Finally falling back to Mac Roman name field.
- Warning: Some bad Japanese TTfonts using SJIS encoded string in the
- Mac Roman name field.
- */
+ /*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;
}
diff --git a/Build/source/texk/web2c/luatexdir/font/vfovf.c b/Build/source/texk/web2c/luatexdir/font/vfovf.c
new file mode 100644
index 00000000000..e1fdb903e42
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/vfovf.c
@@ -0,0 +1,1444 @@
+/*
+
+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/>.
+
+*/
+
+#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);
+}
diff --git a/Build/source/texk/web2c/luatexdir/font/vfovf.w b/Build/source/texk/web2c/luatexdir/font/vfovf.w
deleted file mode 100644
index df970ff4d11..00000000000
--- a/Build/source/texk/web2c/luatexdir/font/vfovf.w
+++ /dev/null
@@ -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
-@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
-@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.
-@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
-@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|.
-
-@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
-
-@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
-
-@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);
-}
diff --git a/Build/source/texk/web2c/luatexdir/font/vfpacket.c b/Build/source/texk/web2c/luatexdir/font/vfpacket.c
new file mode 100644
index 00000000000..41132c54a6d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/font/vfpacket.c
@@ -0,0 +1,445 @@
+/*
+
+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/>.
+
+*/
+
+#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)");
+ }
+ }
+ }
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/font/vfpacket.w b/Build/source/texk/web2c/luatexdir/font/vfpacket.w
deleted file mode 100644
index d2329916a31..00000000000
--- a/Build/source/texk/web2c/luatexdir/font/vfpacket.w
+++ /dev/null
@@ -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.
-@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.
-@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|.
-@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|.
-@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)");
- }
- }
- }
- }
-}
diff --git a/Build/source/texk/web2c/luatexdir/font/writecff.w b/Build/source/texk/web2c/luatexdir/font/writecff.c
index a71e16f6f5c..e6570e070c6 100644
--- a/Build/source/texk/web2c/luatexdir/font/writecff.w
+++ b/Build/source/texk/web2c/luatexdir/font/writecff.c
@@ -1,23 +1,23 @@
-% 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
+/*
+
+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/>.
+
+*/
#include "ptexlib.h"
#include "lua/luatex-api.h"
@@ -25,7 +25,6 @@
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))
@@ -48,8 +47,6 @@ static unsigned long get_unsigned(cff_font * cff, int n)
return v;
}
-@ @c
-
const char *const cff_stdstr[CFF_STDSTR_MAX] = {
".notdef", "space", "exclam", "quotedbl", "numbersign",
"dollar", "percent", "ampersand", "quoteright", "parenleft",
@@ -146,8 +143,8 @@ const char *const cff_stdstr[CFF_STDSTR_MAX] = {
"Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"
};
-@ Only read header part but not body
-@c
+/*tex Only read the header part and forget about the body */
+
cff_index *cff_get_index_header(cff_font * cff)
{
cff_index *idx;
@@ -179,7 +176,6 @@ cff_index *cff_get_index_header(cff_font * cff)
return idx;
}
-@ @c
cff_index *cff_get_index(cff_font * cff)
{
cff_index *idx;
@@ -222,29 +218,22 @@ static cff_index *cff_empty_index(cff_font * cff)
static cff_index *cff_get_index2(cff_font * cff)
{
- /* we fake a dict array */
-
+ /*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; // get_offset(cff, idx->offsize);
- idx->offset[1] = length + 1; // idx->offset[0] + length;
-
+ 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;
}
-@ @c
long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
{
long len = 0;
@@ -297,7 +286,6 @@ long cff_pack_index(cff_index * idx, card8 * dest, long destlen)
return len;
}
-@ @c
long cff_index_size(cff_index * idx)
{
if (idx->count > 0) {
@@ -318,7 +306,6 @@ long cff_index_size(cff_index * idx)
}
}
-@ @c
cff_index *cff_new_index(card16 count)
{
cff_index *idx;
@@ -335,7 +322,6 @@ cff_index *cff_new_index(card16 count)
return idx;
}
-@ @c
void cff_release_index(cff_index * idx)
{
if (idx) {
@@ -345,7 +331,6 @@ void cff_release_index(cff_index * idx)
}
}
-@ @c
void cff_release_dict(cff_dict * dict)
{
if (dict) {
@@ -360,7 +345,6 @@ void cff_release_dict(cff_dict * dict)
}
}
-@ @c
void cff_release_encoding(cff_encoding * encoding)
{
if (encoding) {
@@ -380,7 +364,6 @@ void cff_release_encoding(cff_encoding * encoding)
}
}
-@ @c
void cff_release_charsets(cff_charsets * charset)
{
if (charset) {
@@ -401,7 +384,6 @@ void cff_release_charsets(cff_charsets * charset)
}
}
-@ @c
void cff_release_fdselect(cff_fdselect * fdselect)
{
if (fdselect) {
@@ -414,7 +396,6 @@ void cff_release_fdselect(cff_fdselect * fdselect)
}
}
-@ @c
void cff_close(cff_font * cff)
{
card16 i;
@@ -464,7 +445,6 @@ void cff_close(cff_font * cff)
return;
}
-@ @c
char *cff_get_name(cff_font * cff)
{
char *fontname;
@@ -478,7 +458,6 @@ char *cff_get_name(cff_font * cff)
return fontname;
}
-@ @c
long cff_set_name(cff_font * cff, char *name)
{
cff_index *idx;
@@ -493,7 +472,8 @@ long cff_set_name(cff_font * cff, char *name)
(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'| */
+ /*tex No trailing |\0| */
+ memmove(idx->data, name, strlen(name));
return (long) (5 + strlen(name));
}
@@ -501,23 +481,21 @@ 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; */
+ /*tex cff->header_major */
+ *(dest++) = 1;
*(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.
+ /*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;
}
-@ @c
-#define CFF_PARSE_OK 0
-#define CFF_CFF_ERROR_PARSE_CFF_ERROR -1
+#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
@@ -534,22 +512,27 @@ cff_dict *cff_new_dict(void)
return dict;
}
-@ Operand stack: only numbers are stored (as double). Operand types are:
+/*tex
+
+ 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
+ \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
+
+*/
-@c
#define CFF_DICT_STACK_LIMIT 64
static int stack_top = 0;
static double arg_stack[CFF_DICT_STACK_LIMIT];
-@ CFF DICT encoding.
-@c
-#define CFF_LAST_DICT_OP1 26 /* 22 */
+/* 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)
@@ -569,21 +552,22 @@ static struct {
{ "FamilyOtherBlues", CFF_TYPE_DELTA },
{ "StdHW", CFF_TYPE_NUMBER },
{ "StdVW", CFF_TYPE_NUMBER },
- { NULL, -1 }, /* first byte of two-byte operator 12 */
+ { 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 }, /* two numbers (size and offset) */
+ { "Private", CFF_TYPE_SZOFF },
{ "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 */
+ /*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 },
@@ -625,21 +609,23 @@ static struct {
{ "FontName", CFF_TYPE_SID }
};
-@ Parse DICT data
-@c
+/*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) { /* shortint */
+ 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) { /* longint */
+ } else if (b0 == 29 && *data < endptr - 4) {
+ /*tex longint */
int i;
result = *(*data)++;
if (result > 0x7f)
@@ -648,9 +634,11 @@ static double get_integer(card8 ** data, card8 * endptr, int *status)
result = result * 256 + (**data);
*data += 1;
}
- } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
+ } else if (b0 >= 32 && b0 <= 246) {
+ /*tex int (1) */
result = b0 - 139;
- } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
+ } else if (b0 >= 247 && b0 <= 250) {
+ /*tex int (2) */
b1 = *(*data)++;
result = (b0 - 247) * 256 + b1 + 108;
} else if (b0 >= 251 && b0 <= 254) {
@@ -659,12 +647,11 @@ static double get_integer(card8 ** data, card8 * endptr, int *status)
} else {
*status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
}
-
return (double) result;
}
-@ Simply uses strtod
-@c
+/*tex Simply uses |strtod|: */
+
static double get_real(card8 ** data, card8 * endptr, int *status)
{
double result = 0.0;
@@ -675,12 +662,11 @@ static double get_real(card8 ** data, card8 * endptr, int *status)
*status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
return 0.0;
}
-
- *data += 1; /* skip first byte (30) */
-
+ /*tex Skip the first byte (30): */
+ *data += 1;
pos = 0;
while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) {
- /* get nibble */
+ /*tex Get a nibble. */
if (pos % 2) {
nibble = **data & 0x0f;
*data += 1;
@@ -691,52 +677,49 @@ static double get_real(card8 ** data, card8 * endptr, int *status)
work_buffer[len++] = (char) (nibble + '0');
} else if (nibble == 0x0a) { /* . */
work_buffer[len++] = '.';
- } else if (nibble == 0x0b || nibble == 0x0c) { /* E, E- */
+ } else if (nibble == 0x0b || nibble == 0x0c) {
+ /*tex E, E- */
work_buffer[len++] = 'e';
if (nibble == 0x0c)
work_buffer[len++] = '-';
- } else if (nibble == 0x0e) { /* `-' */
+ } else if (nibble == 0x0e) {
+ /*tex the minus */
work_buffer[len++] = '-';
- } else if (nibble == 0x0d) { /* skip */
- /* do nothing */
- } else if (nibble == 0x0f) { /* end */
+ } 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 { /* invalid */
+ } else {
+ /*tex invalid */
fail = 1;
}
pos++;
}
-
- /* returned values */
+ /*tex the 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 */
+ if ((result==0.0 && work_buffer==s) || errno) {
+ /*tex Conversion is not possible. */
*status = CFF_CFF_ERROR_PARSE_CFF_ERROR;
}
}
return result;
}
-@ operators
-@c
-static void add_dict(cff_dict * dict,
- card8 ** data, card8 * endptr, int *status)
+/*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;
@@ -749,28 +732,22 @@ static void add_dict(cff_dict * dict,
*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)));
+ /*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) {
- /* check for underflow here, as exactly one operand is expected */
+ /*tex Check for underflow here, as exactly one operand is expected. */
if (stack_top < 1) {
*status = CFF_CFF_ERROR_STACK_UNDERFLOW;
return;
@@ -781,8 +758,10 @@ static void add_dict(cff_dict * dict,
(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) */
+ /*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 =
@@ -793,26 +772,27 @@ static void add_dict(cff_dict * dict,
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;
}
+/*tex
+
+ All operands are treated as number or array of numbers.
-@ All operands are treated as number or array of numbers.
- Private: two numbers, size and offset
- ROS : three numbers, SID, SID, and a number
+ \startitemize
+ \startitem |Private|: two numbers, size and offset \stopitem
+ \startitem |ROS|: hree numbers, SID, SID, and a number \stopitem
+ \stopitemize
+
+*/
-@c
cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
{
cff_dict *dict;
@@ -820,18 +800,22 @@ cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
stack_top = 0;
dict = cff_new_dict();
while (data < endptr && status == CFF_PARSE_OK) {
- if (*data < CFF_LAST_DICT_OP1) { /* operator */
+ if (*data < CFF_LAST_DICT_OP1) {
+ /*tex Some operator. */
add_dict(dict, &data, endptr, &status);
- } else if (*data == 30) { /* real - First byte of a sequence (variable) */
+ } 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)) { /* reserved */
+ } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) {
+ /*tex Reserved. */
data++;
- } else { /* everything else are integer */
+ } 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++;
@@ -849,7 +833,6 @@ cff_dict *cff_dict_unpack(card8 * data, card8 * endptr)
return dict;
}
-@ @c
int cff_dict_known(cff_dict * dict, const char *key)
{
int i;
@@ -861,7 +844,6 @@ int cff_dict_known(cff_dict * dict, const char *key)
return 0;
}
-@ @c
double cff_dict_get(cff_dict * dict, const char *key, int idx)
{
double value = 0.0;
@@ -881,72 +863,59 @@ double cff_dict_get(cff_dict * dict, const char *key, int idx)
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;
+ 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;
}
- fd = (fdsel->data).ranges[i - 1].fd;
}
- }
- break;
- default:
- normal_error("cff","invalid FDSelect format");
- break;
+ 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++) {
@@ -970,25 +939,19 @@ long cff_read_subrs(cff_font * cff)
(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);
@@ -1005,24 +968,18 @@ long cff_read_fdarray(cff_font * cff)
}
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 &&
@@ -1058,29 +1015,23 @@ long cff_read_private(cff_font * cff)
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 */
+ /*tex We have only one top dictionary. */
cff->header_offsize = get_card16(cff);
} else {
cff->header_offsize = get_card8(cff);
@@ -1096,8 +1047,7 @@ cff_font *read_cff(unsigned char *buf, long buflength, int n)
return NULL;
}
cff->offset = cff->header_hdr_size;
-
- /* Name INDEX */
+ /*tex The name index. */
if (cff->header_major == 2) {
cff->name = cff_empty_index(cff);
} else {
@@ -1110,65 +1060,55 @@ cff_font *read_cff(unsigned char *buf, long buflength, int n)
cff->name = idx;
cff->fontname = cff_get_name(cff);
}
-
- /* Top DICT INDEX */
+ /*tex The top dict index. */
if (cff->header_major == 2) {
- /* we fake an index (just one entry) */
+ /*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);
+ 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 */
+ /*tex The string index. */
if (cff->header_major == 2) {
- // cff->string = cff_empty_index(cff);
+ /*tex do nothing */
} else {
cff->string = cff_get_index(cff);
}
-
- /* offset to GSubr */
+ /*tex The offset to subroutines. */
cff->gsubr_offset = cff->offset;
-
- /* Number of glyphs */
+ /*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);
-
- /* Check for font type */
+ /*tex Check for font type. */
if (cff_dict_known(cff->topdict, "ROS")) {
cff->flag |= FONTTYPE_CIDFONT;
} else {
cff->flag |= FONTTYPE_FONT;
}
-
- /* Check for encoding */
+ /*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 */
@@ -1179,20 +1119,15 @@ cff_font *read_cff(unsigned char *buf, long buflength, int n)
} else {
cff->flag |= ENCODING_STANDARD;
}
-
- cff->offset = cff->gsubr_offset; /* seek back to GSubr */
-
+ cff->offset = cff->gsubr_offset;
return cff;
}
-@* write a cff for opentype.
+/*tex Write CFF data for an \OPENTYPE\ font. We need to pack dictionary data. */
-@ Pack DICT data
-@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)");
@@ -1212,14 +1147,16 @@ static long pack_integer(card8 * dest, long destlen, long value)
dest[0] = (card8) ((value >> 8) & 0xff);
dest[1] = (card8) (value & 0xff);
len = 2;
- } else if (value >= -32768 && value <= 32767) { /* shortint */
+ } 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 { /* longint */
+ } else {
+ /*tex longint */
if (destlen < 5)
normal_error("cff","buffer overflow (5)");
dest[0] = 29;
@@ -1232,30 +1169,24 @@ static long pack_integer(card8 * dest, long destlen, long value)
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) {
@@ -1268,17 +1199,15 @@ static long pack_real(card8 * dest, long destlen, double value)
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;
-
+ 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"); */
+ /*tex In fact |res| should prevent this. */
break;
} else if (work_buffer[i] == '.') {
ch = 0x0a;
@@ -1287,7 +1216,6 @@ static long pack_real(card8 * dest, long destlen, double value)
} else {
normal_error("cff","invalid character");
}
-
if (destlen < pos / 2 + 1)
normal_error("cff","buffer overflow (7)");
@@ -1298,7 +1226,6 @@ static long pack_real(card8 * dest, long destlen, double value)
}
pos++;
}
-
if (e > 0) {
if (pos % 2) {
dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b);
@@ -1319,7 +1246,6 @@ static long pack_real(card8 * dest, long destlen, double value)
e *= -1;
pos++;
}
-
if (e != 0) {
sprintf(work_buffer, "%ld", e);
for (i = 0; i < CFF_REAL_MAX_LEN; i++) {
@@ -1333,10 +1259,8 @@ static long pack_real(card8 * dest, long destlen, double value)
} 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 {
@@ -1345,7 +1269,6 @@ static long pack_real(card8 * dest, long destlen, double value)
pos++;
}
}
-
if (pos % 2) {
dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f);
pos++;
@@ -1355,19 +1278,14 @@ static long pack_real(card8 * dest, long destlen, double value)
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)
+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;
@@ -1379,21 +1297,20 @@ static long cff_dict_put_number(double value,
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 */
+ } 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 { /* integer */
+ } else {
+ /*tex An 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 ||
@@ -1418,16 +1335,13 @@ static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen)
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);
@@ -1439,24 +1353,19 @@ long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen)
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)
@@ -1464,30 +1373,23 @@ void cff_dict_add(cff_dict * dict, const char *key, int count)
return;
}
}
-
if (dict->count + 1 >= dict->max) {
dict->max += 8;
dict->entries =
- xrealloc(dict->entries,
- (unsigned) ((unsigned) dict->max *
- sizeof(cff_dict_entry)));
+ 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));
+ (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;
@@ -1499,13 +1401,9 @@ void cff_dict_remove(cff_dict * dict, const char *key)
}
}
-@ @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)
@@ -1515,19 +1413,17 @@ void cff_dict_set(cff_dict * dict, const char *key, int idx, double value)
break;
}
}
-
if (i == dict->count)
formatted_error("cff","DICT entry '%s' not found", key);
}
-@ Strings
-@c
+/*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));
@@ -1543,19 +1439,15 @@ char *cff_get_string(cff_font * cff, s_SID id)
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. */
+ /*tex We search the string index first. */
if (cff && cff->string) {
cff_index *idx = cff->string;
for (i = 0; i < idx->count; i++) {
@@ -1564,16 +1456,13 @@ long cff_get_sid(cff_font * cff, const char *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)
@@ -1584,7 +1473,6 @@ void cff_update_string(cff_font * cff)
cff->_string = NULL;
}
-@ @c
s_SID cff_add_string(cff_font * cff, const char *str)
{
card16 idx;
@@ -1621,7 +1509,6 @@ s_SID cff_add_string(cff_font * cff, const char *str)
return (s_SID) (idx + CFF_STDSTR_MAX);
}
-@ @c
void cff_dict_update(cff_dict * dict, cff_font * cff)
{
int i;
@@ -1652,26 +1539,23 @@ void cff_dict_update(cff_dict * dict, cff_font * cff)
}
}
-@ charsets
-@c
+/*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) { /* predefined */
+ if (offset == 0) {
+ /*tex predefined */
cff->flag |= CHARSETS_ISOADOBE;
cff->charsets = NULL;
return 0;
@@ -1684,170 +1568,158 @@ long cff_read_charsets(cff_font * cff)
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. */
+ /*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;
+ 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);
}
- 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++;
+ 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;
}
- charset->data.range2 = ranges;
- length += (charset->num_entries) * 4;
- }
- break;
- default:
- xfree(charset);
- normal_error("cff","unknown charset format");
- break;
+ 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)");
+ case 0:
+ if (destlen < len + (charset->num_entries) * 2)
+ normal_error("cff","buffer overflow (16)");
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);
+ s_SID sid = (charset->data).glyphs[i]; /* or CID */
+ dest[len++] = (card8) ((sid >> 8) & 0xff);
+ dest[len++] = (card8) (sid & 0xff);
}
- }
- 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;
+ 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;
- default:
- normal_error("cff","unknown charset format");
- break;
+ 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.
-@* Type 2 Charstring support.
-
-Decode and encode Type 2 charstring
+ And also note that subroutine numbers within subroutines can depend on the
+ content of operand stack as follows:
-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.
+ \startyping
+ \.{ ... l m callsubr << subr \#(m+bias): n add callsubr >> ...}
+ \stoptyping
-And also note that subroutine numbers within subroutines can depend on the
-content of operand stack as follows:
+ 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.
-\.{ ... 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..
+*/
-@c
-#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser"
-#define CS_TYPE2_DEBUG 5
+#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
+#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;
@@ -1855,54 +1727,57 @@ static int status = CS_PARSE_CFF_ERROR;
#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 */
+/*tex The hintmask and cntrmask need the number of stem zones. */
+
static int num_stems = 0;
static int phase = 0;
-/* subroutine nesting */
+/*tex Subroutine nesting.
+*/
static int cs2_nest = 0;
-/* advance width */
+/*tex The 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.
-@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
-@c
+/*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];
-@ Type 2 CharString encoding
-@c
+/*tex
+
+ Type 2 CharString encoding, first the 1 byte operators:
-/*
- 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 */
+/* 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 : TYPE1 */
+/* cs_hsbw 13 */
#define cs_endchar 14
#define cs_setvsindex 15
#define cs_blend 16
@@ -1917,84 +1792,86 @@ static double trn_array[CS_TRANS_ARRAY_MAX];
#define cs_rlinecurve 25
#define cs_vvcurveto 26
#define cs_hhcurveto 27
-/* SHORTINT 28 : first byte of shortint*/
+/* SHORTINT 28 */
#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.
-@c
+/*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];
- /* Nearest integer value */
+ /*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.
+ 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 */
+ /*tex A 16.16-bit signed fixed value */
DST_NEED(limit, *dest + 5);
*(*dest)++ = 255;
- ivalue = (long) floor(value); /* mantissa */
+ /*tex The mantissa. */
+ ivalue = (long) floor(value);
*(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
*(*dest)++ = (card8) (ivalue & 0xff);
- ivalue = (long) ((value - (double) ivalue) * 0x10000l); /* fraction */
+ /*tex The fraction. */
+ ivalue = (long) ((value - (double) ivalue) * 0x10000l);
*(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
*(*dest)++ = (card8) (ivalue & 0xff);
- /* Everything else are integers. */
+ /*tex Everything else is integer. */
} else if (ivalue >= -107 && ivalue <= 107) {
DST_NEED(limit, *dest + 1);
*(*dest)++ = (card8) (ivalue + 139);
@@ -2009,31 +1886,30 @@ static void clear_stack(card8 ** dest, card8 * limit)
*(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
*(*dest)++ = (card8) (ivalue & 0xff);
} else if (ivalue >= -32768 && ivalue <= 32767) {
- /* shortint */
+ /*tex A shortint. */
DST_NEED(limit, *dest + 3);
*(*dest)++ = 28;
*(*dest)++ = (card8) ((ivalue >> 8) & 0xff);
*(*dest)++ = (card8) ((ivalue) & 0xff);
- } else { /* Shouldn't come here */
+ } else {
normal_error("cff","unexpected error");
}
}
- cs2_stack_top = 0; /* clear stack */
+ /*tex Clear the stack. */
+ cs2_stack_top = 0;
return;
}
-@ Single byte operators: Path construction, Operator for finishing a
-path, Hint operators. Phases:
+/*tex
+ 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
+ \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
-@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)
@@ -2043,351 +1919,347 @@ static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * en
*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) {
+ 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;
- 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");
+ 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;
- 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");
+ 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;
- 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;
+ 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;
}
-@ Double byte operators: Flex, arithmetic, conditional, and storage operators.
-The following operators are not supported: random: How random ?
+/*tex
+
+ Double byte operators: Flex, arithmetic, conditional, and storage operators.
+ The following operators are not supported: random but How random ?
+
+*/
-@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);
+ case cs_dotsection:
+ normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring");
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];
+ 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 {
- NEED(cs2_stack_top, idx + 2);
- cs2_arg_stack[cs2_stack_top - 1] =
- cs2_arg_stack[cs2_stack_top - idx - 2];
+ cs2_arg_stack[cs2_stack_top - 1] = 0.0;
}
- }
- 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;
- }
+ 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 {
- 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[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;
}
- 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;
+ 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;
}
-@ integer: exactly the same as the DICT encoding (except 29)
-@c
+/*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) { /* shortint */
+ if (b0 == 28) {
+ /*tex shortint */
SRC_NEED(endptr, *data + 2);
b1 = **data;
b2 = *(*data + 1);
@@ -2395,9 +2267,11 @@ static void cs2_get_integer(card8 ** data, card8 * endptr)
if (result > 0x7fff)
result -= 0x10000L;
*data += 2;
- } else if (b0 >= 32 && b0 <= 246) { /* int (1) */
+ } else if (b0 >= 32 && b0 <= 246) {
+ /*tex int (1) */
result = b0 - 139;
- } else if (b0 >= 247 && b0 <= 250) { /* int (2) */
+ } else if (b0 >= 247 && b0 <= 250) {
+ /*tex int (2) */
SRC_NEED(endptr, *data + 1);
b1 = **data;
result = (b0 - 247) * 256 + b1 + 108;
@@ -2416,48 +2290,45 @@ static void cs2_get_integer(card8 ** data, card8 * endptr)
return;
}
-@ Signed 16.16-bits fixed number for Type 2 charstring encoding
-@c
+/*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;
}
-@ Subroutines: the bias for subroutine number is introduced in type 2
+/*tex
+
+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.
+\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
+
+*/
-@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 */
+ /*tex addi the bias number */
if (count < 1240) {
id += 107;
} else if (count < 33900) {
@@ -2465,36 +2336,33 @@ static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id)
} 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.
+/*tex
-@c
-static void do_charstring(card8 ** dest, card8 * limit,
- card8 ** data, card8 * endptr,
- cff_index * gsubr_idx, cff_index * subr_idx, int cff2)
+ 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) { /* 16-bit.16-bit fixed signed number */
+ 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;
@@ -2503,8 +2371,7 @@ static void do_charstring(card8 ** dest, card8 * limit,
status = CS_STACK_CFF_ERROR;
} else {
cs2_stack_top--;
- get_subr(&subr, &len, gsubr_idx,
- (long) cs2_arg_stack[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);
@@ -2515,8 +2382,7 @@ static void do_charstring(card8 ** dest, card8 * limit,
status = CS_STACK_CFF_ERROR;
} else {
cs2_stack_top--;
- get_subr(&subr, &len, subr_idx,
- (long) cs2_arg_stack[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);
@@ -2524,34 +2390,29 @@ static void do_charstring(card8 ** dest, card8 * limit,
}
} else if (b0 == cs_escape) {
do_operator2(dest, limit, data, endptr);
- } else if (b0 < 32 && b0 != 28) { /* 19, 20 need mask */
+ } else if (b0 < 32 && b0 != 28) {
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 */
+ } 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;
- /* 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 */
+ } 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;
}
-@ @c
static void cs_parse_init(void)
{
status = CS_PARSE_OK;
@@ -2561,11 +2422,10 @@ static void cs_parse_init(void)
cs2_stack_top = 0;
}
-@ Not just copying...
-@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)
+/*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;
@@ -2589,195 +2449,183 @@ static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srcle
return (long) (dst - save);
}
-@ CID-Keyed font specific
-@c
+/*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));
+ 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++) {
- ranges[i].first = get_card16(cff);
- ranges[i].fd = get_card8(cff);
+ (fdsel->data).fds[i] = 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;
+ 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);
+ 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];
}
- 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;
+ 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.
+/*tex Create an instance of embeddable font. */
-@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 */
-
+ /*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) {
- /* Private had contained only Subr. */
+ /*tex |Private| contains only |Subr|: */
cff_dict_remove(cffont->fdarray[i], "Private");
}
}
- (private->offset)[i + 1] = (unsigned long) ((private->offset)[i]
- + (unsigned) size);
+ (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 */
+ /*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);
- destlen += (cffont->charsets->num_entries) * 2 + 1; /* charset format 0 */
- destlen += (cffont->fdselect->num_entries) * 3 + 5; /* fdselect format 3 */
+ /*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);
- destlen = (long) (destlen + (long) private->offset[private->count] - 1); /* Private is not INDEX */
+ /* |Private| is not indexed */
+ destlen = (long) (destlen + (long) private->offset[private->count] - 1);
dest = xcalloc((unsigned) destlen, sizeof(card8));
-
offset = 0;
- /* Header */
+ /*tex |Header| */
offset += cff_put_header(cffont, dest + offset, destlen - offset);
- /* Name */
+ /*tex |Name| */
offset += cff_pack_index(cffont->name, dest + offset, destlen - offset);
- /* Top DICT */
+ /*tex |Top DICT| */
topdict_offset = offset;
offset += cff_index_size(topdict);
- /* Strings */
+ /*tex |Strings| */
offset += cff_pack_index(cffont->string, dest + offset, destlen - offset);
- /* Global Subrs */
+ /*tex |Global Subrs| */
offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset);
- /* charset */
+ /*tex |charset| */
cff_dict_set(cffont->topdict, "charset", 0, (double) offset);
offset += cff_pack_charsets(cffont, dest + offset, destlen - offset);
- /* FDSelect */
+ /*tex |FDSelect| */
cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset);
offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset);
- /* CharStrings */
+ /*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);
- cffont->cstrings = NULL; /* Charstrings cosumes huge memory */
- /* FDArray and Private */
+ /*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]);
@@ -2792,53 +2640,39 @@ static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname)
cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray));
cff_release_index(fdarray);
cff_release_index(private);
-
- /* Finally Top DICT */
+ /*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++) {
-// 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;
-
+ 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 */
+ /*tex Finish parsing the CFF. */
cff_read_private(cffont);
cff_read_subrs(cffont);
-
- /* Widths */
+ /*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 {
@@ -2849,18 +2683,15 @@ cffont->_string = NULL;
} else {
nominal_width = CFF_NOMINALWIDTHX_DEFAULT;
}
-
num_glyphs = 0;
last_cid = 0;
glyph = xtalloc(1, glw_entry);
-
- /* insert notdef */
+ /*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)) {
@@ -2868,10 +2699,8 @@ cffont->_string = NULL;
last_cid = (card16) found->id;
num_glyphs++;
}
-
{
cff_fdselect *fdselect;
-
fdselect = xcalloc(1, sizeof(cff_fdselect));
fdselect->format = 3;
fdselect->num_entries = 1;
@@ -2880,17 +2709,13 @@ cffont->_string = NULL;
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)) {
@@ -2900,64 +2725,53 @@ cffont->_string = NULL;
}
}
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+ */
+ /*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);
- /* FDArray - index offset, not known yet */
+ /*tex |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 */
+ /*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");
}
-
- /* build the new charstrings entry */
+ /*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;
@@ -2971,7 +2785,7 @@ cffont->_string = NULL;
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 */
+ /*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 */
@@ -2982,7 +2796,7 @@ cffont->_string = NULL;
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);
+ 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);
@@ -3012,9 +2826,9 @@ cffont->_string = NULL;
}
}
}
- /*
- CIDSet: a table of bits indexed by cid, bytes with high order bit first,
- each (set) bit is a (present) CID.
+ /*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;
@@ -3039,123 +2853,101 @@ cffont->_string = NULL;
pdf_end_obj(pdf);
}
}
- /*
- This happens if the internal metrics do not agree with the actual
- disk font.
+ /*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) {
- /* crash */
+ /*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);
}
-@ @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 */
-
+ /*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) {
- /* hm */
+ /*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);
- /* insert notdef */
+ /*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++) {
@@ -3169,13 +2961,13 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
}
}
if (cffont->header_major == 2) {
- /* hm */
+ /*tex 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.
+ /*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);
@@ -3196,57 +2988,46 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
pdf_out_block(pdf, stream, l);
pdf_end_stream(pdf);
pdf_end_obj(pdf);
- xfree(stream);
+ 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 */
+ /*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); /* this call can be sped up */
+ 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) {
@@ -3254,7 +3035,7 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
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);
+ 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);
@@ -3292,14 +3073,11 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
}
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;
@@ -3308,13 +3086,12 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
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]);
@@ -3329,11 +3106,14 @@ void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd)
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.
+/*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.
+
+*/
-@c
void writetype1w(PDF pdf, fd_entry * fd)
{
cff_font *cff;
@@ -3342,24 +3122,19 @@ void writetype1w(PDF pdf, fd_entry * fd)
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) {
diff --git a/Build/source/texk/web2c/luatexdir/font/writeenc.w b/Build/source/texk/web2c/luatexdir/font/writeenc.c
index 1a7ed3891af..554c246a5dc 100644
--- a/Build/source/texk/web2c/luatexdir/font/writeenc.w
+++ b/Build/source/texk/web2c/luatexdir/font/writeenc.c
@@ -1,34 +1,37 @@
-% 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
+/*
+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/>.
+
+*/
#include "ptexlib.h"
-@ All encoding entries go into AVL tree for fast search by name.
-@c
+/*tex
+
+ All encoding entries go into AVL tree for fast search by name.
+
+*/
+
struct avl_table *fe_tree = NULL;
-@ AVL sort |fe_entry| into |fe_tree| by name
-@c
+/* 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;
@@ -41,7 +44,8 @@ static fe_entry *new_fe_entry(void)
fe = xtalloc(1, fe_entry);
fe->name = NULL;
fe->fe_objnum = 0;
- fe->glyph_names = NULL; /* encoding file not yet read in */
+ /*tex The encoding file is not yet read in. */
+ fe->glyph_names = NULL;
fe->tx_tree = NULL;
return fe;
}
@@ -67,7 +71,8 @@ static void register_fe_entry(fe_entry * fe)
}
assert(fe != NULL);
assert(fe->name != NULL);
- assert(lookup_fe_entry(fe->name) == NULL); /* encoding not yet registered */
+ /*tex The encoding is not yet registered. */
+ assert(lookup_fe_entry(fe->name) == NULL);
aa = avl_probe(fe_tree, fe);
assert(aa != NULL);
}
@@ -85,9 +90,7 @@ fe_entry *get_fe_entry(char *s)
return fe;
}
-@ @c
-static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree,
- int fe_objnum)
+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;
@@ -102,9 +105,9 @@ static void write_enc(PDF pdf, char **glyph_names, struct avl_table *tx_tree,
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 */
+ if (*p == i_old + 1) {
pdf_add_name(pdf, glyph_names[*p]);
- else {
+ } else {
pdf_add_int(pdf, *p);
pdf_add_name(pdf, glyph_names[*p]);
}
@@ -134,8 +137,7 @@ void write_fontencodings(PDF pdf)
write_fontencoding(pdf, fe);
}
-@ cleaning up...
-@c
+/*tex Cleaning up \unknown */
static void destroy_fe_entry(void *pa, void *pb)
{
diff --git a/Build/source/texk/web2c/luatexdir/font/writefont.w b/Build/source/texk/web2c/luatexdir/font/writefont.c
index 2ba81d61749..5d75ef80cc7 100644
--- a/Build/source/texk/web2c/luatexdir/font/writefont.w
+++ b/Build/source/texk/web2c/luatexdir/font/writefont.c
@@ -1,69 +1,69 @@
-% 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
+/*
+
+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/>.
+
+*/
#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 },
+ { "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 }
+ { "StemV", "StdVW", 1 },
+ { "XHeight", "XHeight", 1 },
+ { "FontBBox", "FontBBox", 1 },
+ { "", "", 0 },
+ { "", "", 0 },
+ { "", "", 0 },
+ { "FontName", "FontName", 1 }
};
-@
-@c
-struct avl_table *fo_tree = NULL; /* tree of font dictionaries */
-struct avl_table *fd_tree = NULL; /* tree of font descriptor objects */
+/*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);
+ 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
-@c
+/*tex We initialize data structure for |/Type| |/Font|: */
+
static fo_entry *new_fo_entry(void)
{
fo_entry *fo;
@@ -81,8 +81,8 @@ static fo_entry *new_fo_entry(void)
return fo;
}
-@ initialize data structure for /Type /FontDescriptor
-@c
+/*tex We initialize data structure for |/Type| |/FontDescriptor|: */
+
fd_entry *new_fd_entry(internal_font_number f)
{
fd_entry *fd;
@@ -108,12 +108,14 @@ fd_entry *new_fd_entry(internal_font_number 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.
+/*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.
+
+*/
-@c
static void preset_fontmetrics(fd_entry * fd, internal_font_number f)
{
int i;
@@ -143,9 +145,7 @@ 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 */
+ /*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;
@@ -178,34 +178,41 @@ static void write_fontmetrics(PDF pdf, fd_entry * fd)
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_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);
}
-@
-@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)
+ 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
+ } 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);
@@ -218,27 +225,20 @@ static void pdf_dict_add_fontname(PDF pdf, const char *key, fd_entry * fd)
xfree(s);
}
-@
-@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);
}
@@ -247,66 +247,72 @@ 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);
+ /*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);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
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: */
+ /*tex An encoding is needed for \TRUETYPE\ writing: */
fo->fd->fe = fo->fe;
- /* map entry needed by TrueType writing: */
+ /*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);
- 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|.
+/*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|.
+
+*/
-@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) */
+ /*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]));
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
}
}
}
-@
-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.
+/*tex
+
+ Function |mark_chars| has 2 uses:
-@c
-static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree,
- internal_font_number f)
+ \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;
@@ -319,19 +325,19 @@ static struct avl_table *mark_chars(fo_entry * fo, struct avl_table *tx_tree,
j = xtalloc(1, int);
*j = i;
aa = avl_probe(tx_tree, j);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
}
return tx_tree;
}
-@
-@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| */
+ /*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;
@@ -341,7 +347,7 @@ static void get_char_range(fo_entry * fo, internal_font_number f)
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 */
+ /*tex No character has been used from this font. */
fo->last_char = 0;
fo->first_char = fo->last_char + 1;
}
@@ -350,7 +356,7 @@ static void get_char_range(fo_entry * fo, internal_font_number f)
static int font_has_subset(internal_font_number f)
{
int i, s;
- /* search for |first_char| and |last_char| */
+ /*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;
@@ -364,19 +370,14 @@ static int font_has_subset(internal_font_number f)
return 1;
}
-@
-@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)
@@ -393,19 +394,21 @@ static void write_charwidth_array(PDF pdf, fo_entry * fo, internal_font_number f
pdf_end_obj(pdf);
}
-@ Remark: Font objects from embedded PDF files are never registered
-into |fo_tree|; they are individually written out.
-@c
+/*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;
- 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);
}
@@ -415,60 +418,63 @@ 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);
+ 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);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
-@
-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.
-@c
+/*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)
{
- assert(is_included(fd->fm));
if (is_cidkeyed(fd->fm)) {
if (is_opentype(fd->fm)) {
writetype0(pdf, fd);
- } else if (is_truetype(fd->fm)) {
+ } else if (is_truetype(fd->fm)) {
if (!writetype2(pdf, fd)) {
writetype0(pdf,fd);
- fd->fm->type |= F_OTF; fd->fm->type ^= F_TRUETYPE;
+ 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)) {
+ 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))
+ if (is_type1(fd->fm)) {
+ writet1(pdf, fd);
+ } else if (is_truetype(fd->fm)) {
writettf(pdf, fd);
- else if (is_opentype(fd->fm))
+ } else if (is_opentype(fd->fm)) {
writeotf(pdf, fd);
- else
- assert(0);
+ } else {
+ normal_error("fonts","there is a problem writing the font file (2)");
+ }
}
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 */
+ /*tex The font file stream: */
+ pdf_begin_obj(pdf, fd->ff_objnum, OBJSTM_NEVER);
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))
+ /*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");
-#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);
@@ -478,7 +484,7 @@ static void write_fontfile(PDF pdf, fd_entry * fd)
} else if (is_opentype(fd->fm)) {
pdf_dict_add_name(pdf, "Subtype", "Type1C");
} else {
- assert(0); /* todo: error messages */
+ normal_error("fonts","there is a problem writing the font file (3)");
}
pdf_dict_add_streaminfo(pdf);
pdf_end_dict(pdf);
@@ -488,17 +494,11 @@ static void write_fontfile(PDF pdf, fd_entry * fd)
pdf_end_obj(pdf);
}
-@
-@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 */
@@ -513,31 +513,37 @@ static void write_fontdescriptor(PDF pdf, fd_entry * fd)
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| */
+ /*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)) {
- /* this will set |fd->ff_found| if font file is found */
+ /*tex 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)
+ if (fd->fm->fd_flags != FD_FLAGS_NOT_SET_IN_MAPLINE) {
fd_flags = (int) fd->fm->fd_flags;
- else if (fd->ff_found)
+ } 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;
+ } 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",
@@ -554,19 +560,20 @@ static void write_fontdescriptor(PDF pdf, fd_entry * fd)
else if (is_opentype(fd->fm))
pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
else
- assert(0);
+ normal_error("fonts","there is a problem writing the font file (4)");
} 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;
+ /*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);
@@ -575,16 +582,15 @@ static void write_fontdescriptor(PDF pdf, fd_entry * fd)
else if (is_opentype(fd->fm))
pdf_dict_add_ref(pdf, "FontFile3", (int) fd->ff_objnum);
else
- assert(0);
+ 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);
}
- /*
- Currently we don't export the optional keys for CID fonts like
- \.{/Style << /Panose <12-byte string> >>} and we probably never
- will.
+ /*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);
@@ -601,21 +607,13 @@ static void write_fontdescriptors(PDF pdf)
write_fontdescriptor(pdf, fd);
}
-@
-@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 */
+ /*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)) {
- assert(fo->fd->builtin_glyph_names != NULL);
fo->tounicode_objnum = write_tounicode(pdf, fo->fd->builtin_glyph_names, fo->fm->tfm_name);
}
}
@@ -629,11 +627,9 @@ static void write_fontdictionary(PDF pdf, fo_entry * fo)
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);
+ 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);
- 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);
@@ -642,8 +638,9 @@ static void write_fontdictionary(PDF pdf, fo_entry * fo)
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_out(pdf, '\n');
+ pdf_set_space(pdf);
}
pdf_end_dict(pdf);
pdf_end_obj(pdf);
@@ -656,49 +653,53 @@ static void write_fontdictionaries(PDF pdf)
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))
+ 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
-@c
+/*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); /* see \.{writeenc.w} */
+ write_fontencodings(pdf);
write_fontdictionaries(pdf);
}
-@
-@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| */
+ /*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;
- 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)) {
- /*
+ /*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))) {
- /* 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. */
+ /*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);
}
}
- /* for |write_charwidth_array|: */
+ /*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)) {
@@ -713,7 +714,7 @@ static void create_fontdictionary(PDF pdf, internal_font_number f)
if (fo->fe != NULL) {
mark_reenc_glyphs(fo, f);
if (!is_type1(fo->fm)) {
- /* mark reencoded characters as chars on TeX level */
+ /*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)) {
@@ -721,16 +722,17 @@ static void create_fontdictionary(PDF pdf, internal_font_number f)
}
}
} else {
- /* mark non-reencoded characters as chars on TeX level */
+ /*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 {
- /*
- Builtin fonts still need the /Widths array and /FontDescriptor
- (to avoid error 'font FOO contains bad /BBox').
+ /*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);
@@ -745,8 +747,6 @@ static void create_fontdictionary(PDF pdf, internal_font_number f)
}
}
-@
-@c
static int has_ttf_outlines(fm_entry * fm)
{
FILE *f = fopen(fm->ff_name, "rb");
@@ -767,38 +767,39 @@ 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.
+ /*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) {
- /*
- Create a virtual font map entry, as this is needed by the
- rest of the font inclusion mechanism.
+ /*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();
- 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 */
+ /*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)) {
- /*
- 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.
- */
+ /*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;
@@ -807,35 +808,34 @@ void do_pdf_font(PDF pdf, internal_font_number f)
formatted_error("font","file '%s' does not contain font '%s'",fm->ff_name, fm->ps_name);
}
}
- /* Needed for the CIDSystemInfo: */
+ /*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);
- /* Flags can perhaps be done better. */
+ /*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)) {
+ case opentype_format:
+ if (has_ttf_outlines(fm)) {
+ set_truetype(fm);
+ } else {
+ set_opentype(fm);
+ }
+ break;
+ case truetype_format:
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));
+ 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 */
+ /*tex This makes \quotation {unknown} default to subsetted inclusion. */
if (font_embedding(f) != no_embedding) {
set_included(fm);
if (font_embedding(f) != full_embedding) {
@@ -844,37 +844,33 @@ void do_pdf_font(PDF pdf, internal_font_number f)
}
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))
+ /*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);
}
}
-@ 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.
+/*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.
-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.
+ 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.
+
+*/
-@c
static int comp_glw_entry(const void *pa, const void *pb, void *p
- __attribute__ ((unused)))
+ __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);
@@ -883,59 +879,24 @@ static int comp_glw_entry(const void *pa, const void *pb, void *p
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 */
+ /*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);
}
-@ 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.
+/*tex
-@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).
-*/
+ 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)
-{
- 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)
@@ -951,7 +912,9 @@ static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
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);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
} else {
xfree(j);
}
@@ -959,30 +922,29 @@ static void mark_cid_subset_glyphs(fo_entry * fo, internal_font_number f)
}
}
-@ 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.
+/*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.
-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
-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
+*/
-@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);
@@ -995,19 +957,16 @@ static void write_cid_charwidth_array(PDF pdf, fo_entry * fo)
pdf_begin_array(pdf);
j = glyph->wd;
}
- if (glyph->id == (unsigned) (i + 1))
- pdf_out(pdf, ' ');
-
+ 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);
@@ -1026,15 +985,15 @@ 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);
+ /*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.
@@ -1043,24 +1002,20 @@ static void create_cid_fontdictionary(PDF pdf, internal_font_number f)
}
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);
+ 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");
@@ -1076,12 +1031,10 @@ void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
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");
@@ -1100,17 +1053,17 @@ void write_cid_fontdictionary(PDF pdf, fo_entry * fo, internal_font_number f)
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
-
+ /*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);
}
diff --git a/Build/source/texk/web2c/luatexdir/font/writet1.w b/Build/source/texk/web2c/luatexdir/font/writet1.c
index fc1a89cd547..0a0cadcfb93 100644
--- a/Build/source/texk/web2c/luatexdir/font/writet1.w
+++ b/Build/source/texk/web2c/luatexdir/font/writet1.c
@@ -1,44 +1,40 @@
-% 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
+/*
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+Copyright 2006-2009 Taco Hoekwater <taco@luatex.org>
-#include "ptexlib.h"
-#include <string.h>
+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.
-#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()
+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.
-#define t1_putchar(A) strbuf_putchar(pdf->fb, (A))
-#define t1_offset() strbuf_offset(pdf->fb)
-#define out_eexec_char t1_putchar
+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 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
+#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;
@@ -47,40 +43,35 @@ 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")
+
+#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 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
+#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,
@@ -138,25 +129,23 @@ static const char *standard_glyph_names[256] = {
"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 T1_BUF_SIZE 0x0010
#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_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
@@ -168,11 +157,11 @@ enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
#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_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
@@ -180,21 +169,28 @@ enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding;
#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
#define CS_MAX CS_2BYTE_MAX
-@ @c
typedef unsigned char byte;
+/*tex A |CharString| command: */
+
typedef struct {
- byte nargs; /* number of arguments */
- boolean bottom; /* take arguments from bottom of stack? */
- boolean clear; /* clear stack? */
+ /*tex number of arguments */
+ byte nargs;
+ /*tex take arguments from bottom of stack? */
+ boolean bottom;
+ /*tex clear stack? */
+ boolean clear;
boolean valid;
-} cc_entry; /* CharString Command */
+} cc_entry;
typedef struct {
- char *name; /* glyph name (or notdef for Subrs entry) */
+ /*tex glyph name (or |notdef| for |Subrs| entry) */
+ char *name;
byte *data;
- unsigned short len; /* length of the whole string */
- unsigned short cslen; /* length of the encoded part of the string */
+ /*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;
@@ -205,13 +201,9 @@ 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|
-@c
#define t1_line_entry char
define_array(t1_line);
-@ define |t1_buf_ptr|, |t1_buf_array|, and |t1_buf_limit|
-@c
#define t1_buf_entry char
define_array(t1_buf);
@@ -225,29 +217,34 @@ 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.
+/*tex
+
+ This list contains the begin/end tokens commonly used in the |/Subrs| array of
+ a Type 1 font.
+
+*/
-@c
static const char *cs_token_pairs_list[][2] = {
- {" RD", "NP"},
- {" -|", "|"},
- {" RD", "noaccess put"},
- {" -|", "noaccess put"},
- {NULL, NULL}
+ { " 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 */
+
+/*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;
-@ @c
static void enc_getline(void)
{
char *p;
@@ -266,19 +263,20 @@ static void enc_getline(void)
goto restart;
}
-@ read encoding from .enc file, return |glyph_names array|, or |pdffail()|
-@c
+/*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);
}
@@ -308,7 +306,8 @@ char **load_enc_file(char *enc_name)
formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line);
}
names_count = 0;
- r++; /* skip '[' */
+ /*tex Skip |[|: */
+ r++;
skip_char(r, ' ');
for (;;) {
while (*r == '/') {
@@ -340,19 +339,6 @@ char **load_enc_file(char *enc_name)
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();
@@ -402,8 +388,7 @@ static byte edecrypt(byte cipher)
if (t1_pfa) {
while (cipher == 10 || cipher == 13)
cipher = (byte) t1_getbyte();
- last_hexbyte = cipher =
- (byte) ((hexval(cipher) << 4) + hexval(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);
@@ -457,8 +442,7 @@ static float t1_scan_num(char *p, char **r)
return f;
}
-static boolean str_suffix(const char *begin_buf, const char *end_buf,
- const char *s)
+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)
@@ -470,13 +454,12 @@ static boolean str_suffix(const char *begin_buf, const char *end_buf,
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)| */
+ static int eexec_len = 17;
restart:
if (t1_eof())
normal_error("type 1","unexpected end of file");
@@ -512,26 +495,27 @@ static void t1_getline(void)
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 */
+ /*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();
}
- alloc_array(t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
+ /*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:
- /* ensure that |t1_buf_array| has as much room as |t1_line_array| */
+ /*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);
}
-@ @c
static void t1_putline(PDF pdf)
{
char *p = t1_line_array;
@@ -563,7 +547,6 @@ static void t1_printf(PDF pdf, const char *fmt, ...)
va_end(args);
}
-@ @c
static void t1_init_params(int open_name_prefix)
{
report_start_file(open_name_prefix,cur_file_name);
@@ -599,14 +582,11 @@ static void t1_check_block_len(boolean decrypt)
}
}
-@ @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++) {
@@ -614,13 +594,13 @@ static void t1_start_eexec(PDF pdf)
*t1_line_ptr++ = 0;
}
t1_eexec_encrypt = true;
- t1_putline(pdf); /* to put the first four bytes */
+ /*tex To put the first four bytes: */
+ t1_putline(pdf);
}
static void t1_stop_eexec(PDF pdf)
{
int c;
- assert(is_included(fd_cur->fm));
get_length2();
save_offset();
t1_eexec_encrypt = false;
@@ -639,9 +619,8 @@ static void t1_stop_eexec(PDF pdf)
t1_in_eexec = 2;
}
-@ macros for various transforms; unused, left for reference
+/*tex Macros for various transforms; unused, left for reference: */
-@c
#ifdef T1TRANSFORMMACROS
# define do_xshift(x,a) {x[4]+=a;}
# define do_yshift(x,a) {x[5]+=a;}
@@ -651,17 +630,18 @@ static void t1_stop_eexec(PDF pdf)
# 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;}
+
+# 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;
@@ -688,16 +668,20 @@ static void t1_scan_keys(PDF pdf)
remove_eol(p, t1_line_array);
formatted_error("type 1","a name expected: '%s'", t1_line_array);
}
- r = ++p; /* skip the slash */
+ /*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);
- /* 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 */
+ /*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)) {
- 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);
@@ -719,7 +703,6 @@ static void t1_scan_keys(PDF pdf)
fd_cur->font_dim[k].set = true;
}
-@ @c
static void t1_scan_param(PDF pdf)
{
static const char *lenIV = "/lenIV";
@@ -745,18 +728,18 @@ static void copy_glyph_names(char **glyph_names, int a, int b)
}
}
-@ read encoding from Type1 font file, return |glyph_names| array, or |pdffail()|
+/*tex Read encoding from Type1 font file, return |glyph_names| array, or |pdffail|. */
-@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| */
+ /*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")) { /* predefined encoding */
+ 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;
@@ -768,31 +751,37 @@ static char **t1_builtin_enc(void)
} 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}}
- */
+ /*
+
+ 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++);
+ for (p = t1_buf_array, r++; *r != 32 && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
*p = 0;
skip_char(r, ' ');
if (counter > 255)
@@ -812,16 +801,15 @@ static char **t1_builtin_enc(void)
t1_getline();
r = t1_line_array;
}
- } else { /* the second case */
+ } else {
+ /*tex 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}
- */
+ /*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)
@@ -829,37 +817,25 @@ static char **t1_builtin_enc(void)
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)) {
+ /*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, ' ');
}
- /*
- 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)) {
+ /*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, ' ');
}
- /*
- check for \.{def} or \.{readonly def}
- */
- else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' '))
- && strcmp(p, "def\n") == 0)
+ /*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;
- /*
- skip an unrecognizable word
- */
- else {
+ } else {
+ /*tex Skip an unrecognizable word. */
while (*p != ' ' && *p != 10)
p++;
skip_char(p, ' ');
@@ -869,9 +845,6 @@ static char **t1_builtin_enc(void)
return glyph_names;
}
-
-@
-@c
static void t1_check_end(PDF pdf)
{
if (t1_eof())
@@ -881,8 +854,6 @@ static void t1_check_end(PDF pdf)
t1_putline(pdf);
}
-@
-@c
static boolean t1_open_fontfile(int open_name_prefix)
{
ff_entry *ff;
@@ -939,19 +910,19 @@ static void t1_include(PDF pdf)
}
while (!t1_end_eexec());
t1_stop_eexec(pdf);
- if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
+ if (fixedcontent) {
+ /*tex 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 */
+ /*tex Write |{restore} if| if found. */
+ t1_check_end(pdf);
}
get_length3();
}
-@
-@c
#define check_subr(subr) \
if (subr >= subr_size || subr < 0) \
formatted_error("type 1","Subrs array: entry index out of range '%i'", subr);
@@ -986,10 +957,9 @@ static void cs_store(boolean is_subr)
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| */
+ /*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;
@@ -997,14 +967,12 @@ static void cs_store(boolean is_subr)
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? */
+ xfree(ptr->data);
ptr->data = xtalloc(ptr->len, byte);
memcpy(ptr->data, t1_buf_array, ptr->len);
ptr->valid = true;
}
-@
-@c
#define store_subr() cs_store(true)
#define store_cs() cs_store(false)
@@ -1024,10 +992,9 @@ static boolean is_cc_init = false;
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 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; \
@@ -1052,9 +1019,6 @@ static void cc_init(void)
set_cc(CS_CLOSEPATH, false, 0, true);
set_cc(CS_CALLSUBR, false, 1, false);
set_cc(CS_RETURN, false, 0, false);
-#if 0
- set_cc(CS_ESCAPE, false, 0, false);
-#endif
set_cc(CS_HSBW, true, 2, true);
set_cc(CS_ENDCHAR, false, 0, true);
set_cc(CS_RMOVETO, true, 2, true);
@@ -1073,8 +1037,6 @@ static void cc_init(void)
is_cc_init = true;
}
-@
-@c
#define cs_getchar() cdecrypt(*data++, &cr)
#define mark_subr(n) cs_mark(0, n)
@@ -1093,24 +1055,21 @@ static void cs_fail(const char *cs_name, int subr, const char *fmt, ...)
formatted_error("type 1","CharString (/%s): %s", cs_name, buf);
}
-@ fix a return-less subr by appending |CS_RETURN|
-@c
+/*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;
- assert(ptr != NULL && ptr->valid && ptr->used);
-
- /* decrypt the cs data to |t1_buf_array|, append |CS_RETURN| */
+ /*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;
-
- /* encrypt the new cs data to |new_data| */
+ /*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;
@@ -1119,16 +1078,13 @@ static void append_cs_return(cs_entry * ptr)
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));
-
- /* update |*ptr| */
+ /*tex Update |*ptr|. */
xfree(ptr->data);
ptr->data = new_data;
ptr->len++;
ptr->cslen++;
}
-@
-@c
static void cs_mark(const char *cs_name, int subr)
{
byte *data;
@@ -1136,8 +1092,8 @@ static void cs_mark(const char *cs_name, int subr)
int last_cmd = 0;
int a, a1, a2;
unsigned short cr;
- static int lastargOtherSubr3 = 3; /* the argument of last call to
- OtherSubrs[3] */
+ /*tex The argument of last call to |OtherSubrs[3]|. */
+ static int lastargOtherSubr3 = 3;
cs_entry *ptr;
cc_entry *cc;
if (cs_name == NULL) {
@@ -1145,24 +1101,23 @@ static void cs_mark(const char *cs_name, int 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;
+ } 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;
}
- /* only marked CharString entries and invalid entries can be skipped;
- valid marked subrs must be parsed to keep the stack in sync */
+ /*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;
@@ -1219,42 +1174,43 @@ static void cs_mark(const char *cs_name, int subr)
}
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);
- /* 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)
+ 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();
}
}
}
@@ -1265,16 +1221,17 @@ static void cs_mark(const char *cs_name, int subr)
append_cs_return(ptr);
}
return;
- cs_error: /* an error occured during parsing */
+ /*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
-@c
+/* AVL search tree for glyph code by glyph name. */
+
static int comp_t1_glyphs(const void *pa, const void *pb, void *p
- __attribute__ ((unused)))
+ __attribute__ ((unused)))
{
return strcmp(*(const char *const *) pa, *(const char *const *) pb);
}
@@ -1285,13 +1242,14 @@ static struct avl_table *create_t1_glyph_tree(char **glyph_names)
void **aa;
static struct avl_table *gl_tree;
gl_tree = avl_create(comp_t1_glyphs, NULL, &avl_xallocator);
- assert(gl_tree != NULL);
for (i = 0; i < 256; i++) {
if (glyph_names[i] != notdef &&
(char **) avl_find(gl_tree, &glyph_names[i]) == NULL) {
- /* no |strdup| here, just point to the |glyph_names| array members */
+ /*tex No |strdup| here, just point to the |glyph_names| array members. */
aa = avl_probe(gl_tree, &glyph_names[i]);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
}
return gl_tree;
@@ -1299,12 +1257,9 @@ static struct avl_table *create_t1_glyph_tree(char **glyph_names)
static void destroy_t1_glyph_tree(struct avl_table *gl_tree)
{
- assert(gl_tree != NULL);
avl_destroy(gl_tree, NULL);
}
-@
-@c
static void t1_subset_ascii_part(PDF pdf)
{
int j, *p;
@@ -1312,8 +1267,6 @@ static void t1_subset_ascii_part(PDF pdf)
struct avl_table *gl_tree;
struct avl_traverser t;
void **aa;
- assert(fd_cur != NULL);
- assert(fd_cur->gl_tree != NULL);
t1_getline();
while (!t1_prefix("/Encoding")) {
t1_scan_param(pdf);
@@ -1323,9 +1276,8 @@ static void t1_subset_ascii_part(PDF pdf)
glyph_names = t1_builtin_enc();
fd_cur->builtin_glyph_names = glyph_names;
if (is_subsetted(fd_cur->fm)) {
- assert(is_included(fd_cur->fm));
if (fd_cur->tx_tree != NULL) {
- /* take over collected non-reencoded characters from \TeX */
+ /*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)) {
@@ -1337,46 +1289,44 @@ static void t1_subset_ascii_part(PDF pdf)
}
}
make_subset_tag(fd_cur);
- assert(t1_fontname_offset != 0);
strncpy((char *) pdf->fb->data + t1_fontname_offset, fd_cur->subset_tag,6);
}
- /* now really all glyphs needed from this font are in the |fd_cur->gl_tree| */
+ /*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");
+ 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);
+ t1_printf(pdf, "dup %i /%s put\n", (int) (gg - glyph_names),*gg);
j++;
}
}
destroy_t1_glyph_tree(gl_tree);
- if (j == 0)
- /* We didn't mark anything for the Encoding array.
- We add \.{dup 0 /.notdef put} for compatibility with Acrobat 5.0. */
+ 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")) /* ignore UniqueID for subsetted fonts */
+ if (!t1_prefix("/UniqueID")) {
+ /*tex Ignore |/UniqueID| for subsetted fonts. */
t1_putline(pdf);
+ }
}
while (t1_in_eexec == 0);
}
-
-@
-@c
static void cs_init(void)
{
cs_ptr = cs_tab = NULL;
@@ -1398,8 +1348,6 @@ static void init_cs_entry(cs_entry * cs)
cs->valid = false;
}
-@
-@c
static void t1_read_subrs(PDF pdf)
{
int i, s;
@@ -1407,8 +1355,10 @@ static void t1_read_subrs(PDF pdf)
t1_getline();
while (!(t1_charstrings() || t1_subrs())) {
t1_scan_param(pdf);
- if (!t1_prefix("/UniqueID")) /* ignore UniqueID for subsetted fonts */
+ if (!t1_prefix("/UniqueID")) {
+ /*tex Ignore |/UniqueID| for subsetted fonts. */
t1_putline(pdf);
+ }
t1_getline();
}
found:
@@ -1417,7 +1367,7 @@ static void t1_read_subrs(PDF pdf)
if (!t1_subrs())
return;
subr_size_pos = strlen("/Subrs") + 1;
- /* |subr_size_pos| points to the number indicating dict size after |"Subrs"| */
+ /*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())
@@ -1433,17 +1383,20 @@ static void t1_read_subrs(PDF pdf)
store_subr();
t1_getline();
}
- /* mark the first four entries without parsing */
+ /*tex Mark the first four entries without parsing. */
for (i = 0; i < subr_size && i < 4; i++)
subr_tab[i].used = true;
- /* 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
+ /*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
+#define POST_SUBRS_SCAN 5
s = 0;
*t1_buf_array = 0;
for (i = 0; i < POST_SUBRS_SCAN; i++) {
@@ -1455,8 +1408,8 @@ static void t1_read_subrs(PDF pdf)
t1_getline();
}
subr_array_end = xstrdup(t1_buf_array);
- if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
- suppose synthetic font */
+ 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);
@@ -1472,8 +1425,6 @@ static void t1_read_subrs(PDF pdf)
}
}
-@
-@c
#define t1_subr_flush() t1_flush_cs(pdf, true)
#define t1_cs_flush() t1_flush_cs(pdf, false)
@@ -1509,21 +1460,22 @@ static void t1_flush_cs(PDF pdf, boolean is_subr)
strcat(t1_line_ptr, p);
t1_line_ptr = eol(t1_line_array);
t1_putline(pdf);
-
- cs_len = 0; /* for -Wall */
- /* create |return_cs| to replace unsused subr's */
+ /*tex For |-Wall|. */
+ cs_len = 0;
+ /*tex Create |return_cs| to replace unsused |subr|s. */
if (is_subr) {
cr = 4330;
cs_len = 0;
- /* at this point we have |t1_lenIV >= 0;|
- a negative value would be caught in |t1_scan_param| */
+ /*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)
@@ -1536,7 +1488,7 @@ static void t1_flush_cs(PDF pdf, boolean is_subr)
t1_line_ptr = p + ptr->len;
t1_putline(pdf);
} else {
- /* replace unsused subr's by |return_cs| */
+ /*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]);
@@ -1550,8 +1502,8 @@ static void t1_flush_cs(PDF pdf, boolean is_subr)
}
}
xfree(ptr->data);
- if (is_subr)
- ptr->valid=false;
+ if (is_subr)
+ ptr->valid = false;
if (ptr->name != notdef)
xfree(ptr->name);
}
@@ -1560,28 +1512,27 @@ static void t1_flush_cs(PDF pdf, boolean is_subr)
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);
- }
+ for (ptr = tab; ptr < end_tab; ptr++) {
+ if (ptr->valid) {
+ xfree(ptr->data);
+ if (ptr->name != notdef)
+ xfree(ptr->name);
+ }
}
- xfree(return_cs);
+ xfree(return_cs);
}
xfree(tab);
xfree(start_line);
xfree(line_end);
}
-@
-@c
static void t1_mark_glyphs(void)
{
char *glyph;
struct avl_traverser t;
cs_entry *ptr;
- if (t1_synthetic || fd_cur->all_glyphs) { /* mark everything */
+ 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)
@@ -1607,21 +1558,26 @@ static void t1_mark_glyphs(void)
}
-@ When |t1_subset_charstrings| is called, the |t1_line_array| contains \.{/CharStrings}.
-When we hit a case like this:
-{\obeylines \tt
- dup/CharStrings
- 229 dict dup begin
-}
-we read the next line and concatenate to |t1_line_array| before moving on. That is
-what |t1_check_unusual_charstring| is for.
+/*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.
+
+*/
-@c
static void t1_check_unusual_charstring(void)
{
char *p = strstr(t1_line_array, charstringname) + strlen(charstringname);
int i;
- /* if no number follows "/CharStrings", let's read the next line */
+ /*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();
@@ -1634,14 +1590,9 @@ static void t1_check_unusual_charstring(void)
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);
- /* |cs_size_pos| points to the number indicating
- dict size after |"/CharStrings"| */
+ 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++)
@@ -1656,12 +1607,9 @@ static void t1_subset_charstrings(PDF pdf)
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)
@@ -1669,46 +1617,54 @@ static void t1_subset_charstrings(PDF pdf)
t1_cs_flush();
}
-@
-@c
static void t1_subset_end(PDF pdf)
{
- if (t1_synthetic) { /* copy to \.{dup /FontName get exch definefont pop} */
+ 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())
- t1_getline(); /* ignore the rest */
- t1_putline(pdf); /* write \.{mark currentfile closefile} */
- } else
- while (!t1_end_eexec()) { /* copy to \.{mark currentfile closefile} */
+ 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) { /* copy 512 zeros (not needed for PDF) */
+ if (fixedcontent) {
+ /*tex Copy 512 zeros (not needed for PDF). */
while (!t1_cleartomark()) {
t1_getline();
t1_putline(pdf);
}
- if (!t1_synthetic) /* don't check \.{{restore}if} for synthetic fonts */
- t1_check_end(pdf); /* write \.{{restore}if} if found */
+ /*tex Don't check \.{{restore}if} for synthetic fonts. */
+ if (!t1_synthetic) {
+ /*tex Write \.{{restore}if} if found. */
+ t1_check_end(pdf);
+ }
}
get_length3();
}
-@
-@c
void writet1(PDF pdf, fd_entry * fd)
{
- fd_cur = fd; /* |fd_cur| is global inside \.{writet1.w} */
+ /*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)) { /* include entire font */
+ if (!is_subsetted(fd_cur->fm)) {
+ /*tex Include entire font. */
if (!(fd->ff_found = t1_open_fontfile(filetype_font)))
return;
t1_include(pdf);
@@ -1716,7 +1672,7 @@ void writet1(PDF pdf, fd_entry * fd)
xfree(t1_buffer);
return;
}
- /* partial downloading */
+ /*tex Partial downloading. */
if (!(fd->ff_found = t1_open_fontfile(filetype_subset)))
return;
t1_subset_ascii_part(pdf);
@@ -1730,8 +1686,6 @@ void writet1(PDF pdf, fd_entry * fd)
xfree(t1_buffer);
}
-@
-@c
void t1_free(void)
{
xfree(t1_line_array);
diff --git a/Build/source/texk/web2c/luatexdir/font/writet3.w b/Build/source/texk/web2c/luatexdir/font/writet3.c
index 879cef8d5a0..6121c24a1f0 100644
--- a/Build/source/texk/web2c/luatexdir/font/writet3.w
+++ b/Build/source/texk/web2c/luatexdir/font/writet3.c
@@ -1,25 +1,24 @@
-% writet3.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
+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/>.
+
+*/
#include "ptexlib.h"
#include <kpathsea/tex-glyph.h>
@@ -41,7 +40,8 @@ static float t3_font_scale;
static int t3_b0, t3_b1, t3_b2, t3_b3;
static boolean is_pk_font;
-/* not static because used by pkin.c */
+/*tex Not static because used elsewhere. */
+
unsigned char *t3_buffer = NULL;
int t3_size = 0;
int t3_curbyte = 0;
@@ -50,8 +50,6 @@ int t3_curbyte = 0;
if (t3_eof()) \
normal_error("type 3","unexpected end of file");
-@
-@c
static void update_bbox(int llx, int lly, int urx, int ury, boolean is_first_glyph)
{
if (is_first_glyph) {
@@ -71,7 +69,7 @@ static void update_bbox(int llx, int lly, int urx, int ury, boolean is_first_gly
}
}
-/* fixed precision 3 (+5 in pdfgen.w)*/
+/*tex Fixed precision 3 (+5 in |pdfgen.c|)*/
#define get_pk_font_scale(pdf,f,scale_factor) \
divide_scaled(scale_factor, divide_scaled(font_size(f),one_hundred_bp,pk_decimal_digits(pdf,2)), 0)
@@ -79,8 +77,6 @@ static void update_bbox(int llx, int lly, int urx, int ury, boolean is_first_gly
#define pk_char_width(pdf,f,w,scale_factor) \
divide_scaled(divide_scaled(w,font_size(f),pk_decimal_digits(pdf,4)), get_pk_font_scale(pdf,f,scale_factor), 0)
-@
-@c
static boolean writepk(PDF pdf, internal_font_number f)
{
kpse_glyph_file_type font_ret;
@@ -98,17 +94,14 @@ static boolean writepk(PDF pdf, internal_font_number f)
xfree(t3_buffer);
t3_curbyte = 0;
t3_size = 0;
-
callback_id = callback_defined(find_pk_file_callback);
-
if (pdf->pk_fixed_dpi) {
newdpi = pdf->pk_resolution;
} else {
newdpi = dpi;
}
-
if (callback_id > 0) {
- /* <base>.dpi/<fontname>.<tdpi>pk */
+ /*tex |<base>.dpi/<fontname>.<tdpi>pk| */
dpi = round((float) pdf->pk_resolution * (((float) font_size(f)) / (float) font_dsize(f)));
cur_file_name = font_name(f);
run_callback(callback_id, "Sd->S", cur_file_name, (int) newdpi, &name);
@@ -213,8 +206,6 @@ static boolean writepk(PDF pdf, internal_font_number f)
return true;
}
-@
-@c
void writet3(PDF pdf, internal_font_number f)
{
int i;
@@ -224,7 +215,6 @@ void writet3(PDF pdf, internal_font_number f)
int pk_font_scale;
pdffloat pf;
boolean is_notdef;
-
t3_glyph_num = 0;
t3_image_used = false;
for (i = 0; i < 256; i++) {
@@ -232,7 +222,6 @@ void writet3(PDF pdf, internal_font_number f)
t3_char_widths[i] = 0;
}
is_pk_font = false;
-
xfree(t3_buffer);
t3_curbyte = 0;
t3_size = 0;
@@ -246,8 +235,7 @@ void writet3(PDF pdf, internal_font_number f)
if (pdf_char_marked(f, i))
break;
last_char = i;
-
- /* Type 3 font dictionary */
+ /*tex We create a |Type3| font dictionary: */
pdf_begin_obj(pdf, pdf_font_num(f), OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "Font");
@@ -302,8 +290,7 @@ void writet3(PDF pdf, internal_font_number f)
pdf_dict_add_ref(pdf, "CharProcs", (int) cptr);
pdf_end_dict(pdf);
pdf_end_obj(pdf);
-
- /* chars width array */
+ /*tex The |Widths| array: */
pdf_begin_obj(pdf, wptr, OBJSTM_ALWAYS);
pdf_begin_array(pdf);
if (is_pk_font) {
@@ -319,8 +306,7 @@ void writet3(PDF pdf, internal_font_number f)
}
pdf_end_array(pdf);
pdf_end_obj(pdf);
-
- /* encoding dictionary */
+ /*tex The |Encoding| dictionary: */
pdf_begin_obj(pdf, eptr, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "Encoding");
@@ -354,8 +340,7 @@ void writet3(PDF pdf, internal_font_number f)
pdf_end_array(pdf);
pdf_end_dict(pdf);
pdf_end_obj(pdf);
-
- /* CharProcs dictionary */
+ /*tex The |CharProcs| dictionary: */
pdf_begin_obj(pdf, cptr, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
for (i = first_char; i <= last_char; i++) {
diff --git a/Build/source/texk/web2c/luatexdir/font/writettf.w b/Build/source/texk/web2c/luatexdir/font/writettf.c
index 4a016cbe403..cf034e98d0a 100644
--- a/Build/source/texk/web2c/luatexdir/font/writettf.w
+++ b/Build/source/texk/web2c/luatexdir/font/writettf.c
@@ -1,32 +1,31 @@
-% writettf.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
+/*
+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/>.
+
+*/
#include "ptexlib.h"
#include "font/writettf.h"
#include <string.h>
#define DEFAULT_NTABS 14
-#define NEW_CMAP_SIZE 2
+#define NEW_CMAP_SIZE 2
#define ttf_putchar(A) strbuf_putchar(pdf->fb, (A))
#define ttf_offset() strbuf_offset(pdf->fb)
@@ -37,8 +36,10 @@ int ttf_size = 0;
int ttf_curbyte = 0;
typedef struct {
- char *name; /* name of glyph */
- long newindex; /* new index of glyph in output file */
+ /*tex the name of glyph */
+ char *name;
+ /*tex the new index of glyph in output file */
+ long newindex;
} ttfenc_entry;
@@ -87,303 +88,88 @@ static TTF_ULONG checkSumAdjustment_offset;
FILE *ttf_file;
static ttfenc_entry ttfenc_tab[256];
-fd_entry *fd_cur; /* pointer to the current font descriptor */
+/*tex A pointer to the current font descriptor: */
+
+fd_entry *fd_cur;
static struct avl_table *ttf_cmap_tree = NULL;
int ttf_length;
-@ This used to be macnames.c
-
-@c
char notdef[] = ".notdef";
const char *mac_glyph_names[] = {
-/* 0x00 */
- notdef,
- ".null",
- "CR",
- "space",
- "exclam",
- "quotedbl",
- "numbersign",
- "dollar",
- "percent",
- "ampersand",
- "quotesingle",
- "parenleft",
- "parenright",
- "asterisk",
- "plus",
- "comma",
-/* 0x10 */
- "hyphen",
- "period",
- "slash",
- "zero",
- "one",
- "two",
- "three",
- "four",
- "five",
- "six",
- "seven",
- "eight",
- "nine",
- "colon",
- "semicolon",
- "less",
-/* 0x20 */
- "equal",
- "greater",
- "question",
- "at",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- "G",
- "H",
- "I",
- "J",
- "K",
- "L",
-/* 0x30 */
- "M",
- "N",
- "O",
- "P",
- "Q",
- "R",
- "S",
- "T",
- "U",
- "V",
- "W",
- "X",
- "Y",
- "Z",
- "bracketleft",
- "backslash",
-/* 0x40 */
- "bracketright",
- "asciicircum",
- "underscore",
- "grave",
- "a",
- "b",
- "c",
- "d",
- "e",
- "f",
- "g",
- "h",
- "i",
- "j",
- "k",
- "l",
-/* 0x50 */
- "m",
- "n",
- "o",
- "p",
- "q",
- "r",
- "s",
- "t",
- "u",
- "v",
- "w",
- "x",
- "y",
- "z",
- "braceleft",
- "bar",
-/* 0x60 */
- "braceright",
- "asciitilde",
- "Adieresis",
- "Aring",
- "Ccedilla",
- "Eacute",
- "Ntilde",
- "Odieresis",
- "Udieresis",
- "aacute",
- "agrave",
- "acircumflex",
- "adieresis",
- "atilde",
- "aring",
- "ccedilla",
-/* 0x70 */
- "eacute",
- "egrave",
- "ecircumflex",
- "edieresis",
- "iacute",
- "igrave",
- "icircumflex",
- "idieresis",
- "ntilde",
- "oacute",
- "ograve",
- "ocircumflex",
- "odieresis",
- "otilde",
- "uacute",
- "ugrave",
-/* 0x80 */
- "ucircumflex",
- "udieresis",
- "dagger",
- "degree",
- "cent",
- "sterling",
- "section",
- "bullet",
- "paragraph",
- "germandbls",
- "registered",
- "copyright",
- "trademark",
- "acute",
- "dieresis",
- "notequal",
-/* 0x90 */
- "AE",
- "Oslash",
- "infinity",
- "plusminus",
- "lessequal",
- "greaterequal",
- "yen",
- "mu",
- "partialdiff",
- "Sigma",
- "Pi",
- "pi",
- "integral",
- "ordfeminine",
- "ordmasculine",
- "Omega",
-/* 0xa0 */
- "ae",
- "oslash",
- "questiondown",
- "exclamdown",
- "logicalnot",
- "radical",
- "florin",
- "approxequal",
- "Delta",
- "guillemotleft",
- "guillemotright",
- "ellipsis",
- "nbspace",
- "Agrave",
- "Atilde",
- "Otilde",
-/* 0xb0 */
- "OE",
- "oe",
- "endash",
- "emdash",
- "quotedblleft",
- "quotedblright",
- "quoteleft",
- "quoteright",
- "divide",
- "lozenge",
- "ydieresis",
- "Ydieresis",
- "fraction",
- "currency",
- "guilsinglleft",
- "guilsinglright",
-/* 0xc0 */
- "fi",
- "fl",
- "daggerdbl",
- "periodcentered",
- "quotesinglbase",
- "quotedblbase",
- "perthousand",
- "Acircumflex",
- "Ecircumflex",
- "Aacute",
- "Edieresis",
- "Egrave",
- "Iacute",
- "Icircumflex",
- "Idieresis",
- "Igrave",
-/* 0xd0 */
- "Oacute",
- "Ocircumflex",
- "applelogo",
- "Ograve",
- "Uacute",
- "Ucircumflex",
- "Ugrave",
- "dotlessi",
- "circumflex",
- "tilde",
- "macron",
- "breve",
- "dotaccent",
- "ring",
- "cedilla",
- "hungarumlaut",
-/* 0xe0 */
- "ogonek",
- "caron",
- "Lslash",
- "lslash",
- "Scaron",
- "scaron",
- "Zcaron",
- "zcaron",
- "brokenbar",
- "Eth",
- "eth",
- "Yacute",
- "yacute",
- "Thorn",
- "thorn",
+ /* 0x00 */
+ notdef, ".null", "CR", "space", "exclam", "quotedbl", "numbersign", "dollar",
+ "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk",
+ "plus", "comma",
+ /* 0x10 */
+ "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "colon", "semicolon", "less",
+ /* 0x20 */
+ "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H",
+ "I", "J", "K", "L",
+ /* 0x30 */
+ "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
+ "bracketleft", "backslash",
+ /* 0x40 */
+ "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d",
+ "e", "f", "g", "h", "i", "j", "k", "l",
+ /* 0x50 */
+ "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
+ "braceleft", "bar",
+ /* 0x60 */
+ "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute",
+ "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex",
+ "adieresis", "atilde", "aring", "ccedilla",
+ /* 0x70 */
+ "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave",
+ "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex",
+ "odieresis", "otilde", "uacute", "ugrave",
+ /* 0x80 */
+ "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling",
+ "section", "bullet", "paragraph", "germandbls", "registered", "copyright",
+ "trademark", "acute", "dieresis", "notequal",
+ /* 0x90 */
+ "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen",
+ "mu", "partialdiff", "Sigma", "Pi", "pi", "integral", "ordfeminine",
+ "ordmasculine", "Omega",
+ /* 0xa0 */
+ "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical",
+ "florin", "approxequal", "Delta", "guillemotleft", "guillemotright",
+ "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde",
+ /* 0xb0 */
+ "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft",
+ "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction",
+ "currency", "guilsinglleft", "guilsinglright",
+ /* 0xc0 */
+ "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase",
+ "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave",
+ "Iacute", "Icircumflex", "Idieresis", "Igrave",
+ /* 0xd0 */
+ "Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", "Ucircumflex",
+ "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent",
+ "ring", "cedilla", "hungarumlaut",
+ /* 0xe0 */
+ "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron",
+ "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn",
"minus",
-/* 0xf0 */
- "multiply",
- "onesuperior",
- "twosuperior",
- "threesuperior",
- "onehalf",
- "onequarter",
- "threequarters",
- "franc",
- "Gbreve",
- "gbreve",
- "Idot",
- "Scedilla",
- "scedilla",
- "Cacute",
- "cacute",
- "Ccaron",
-/* 0x100 */
- "ccaron",
- "dmacron"
+ /* 0xf0 */
+ "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
+ "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idot",
+ "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron",
+ /* 0x100 */
+ "ccaron", "dmacron"
};
const char *ambiguous_names[] = {
- "Delta", /* increment */
- "Omega", /* Ohm */
- "Pi", /* product */
- "Sigma", /* summation */
- "dmacron", /* dslash */
- "macron", /* overscore */
- "periodcentered", /* middot */
+ "Delta", /* increment */
+ "Omega", /* Ohm */
+ "Pi", /* product */
+ "Sigma", /* summation */
+ "dmacron", /* dslash */
+ "macron", /* overscore */
+ "periodcentered", /* middot */
NULL
};
@@ -404,9 +190,8 @@ static const char *newtabnames[] = {
"prep"
};
-@ Back to code. Low-level helpers first.
+/* Back to code. Low-level helpers first. */
-@c
static ttf_cmap_entry *new_ttf_cmap_entry(void)
{
ttf_cmap_entry *e;
@@ -438,7 +223,6 @@ static int comp_ttf_cmap_entry(const void *pa, const void *pb, void *p)
*p2 = (const ttf_cmap_entry *) pb;
int i;
(void) p;
- assert(p1->ttf_name != NULL && p2->ttf_name != NULL);
if ((i = strcmp(p1->ttf_name, p2->ttf_name)) != 0)
return i;
cmp_return(p1->pid, p2->pid);
@@ -459,8 +243,10 @@ static unsigned char ttf_addchksm(unsigned char b)
static TTF_ULONG ttf_getchksm(PDF pdf)
{
- while (tab_length % 4 != 0)
- ttf_putchar(ttf_addchksm(0)); /* |ttf_addchksm| updates |tab_length| */
+ while (tab_length % 4 != 0) {
+ /*tex |ttf_addchksm| updates |tab_length| */
+ ttf_putchar(ttf_addchksm(0));
+ }
return checksum;
}
@@ -539,48 +325,34 @@ static void ttf_copy_encoding(void)
int i, *q;
void **aa;
char **glyph_names;
- /*long *charcodes;*/
- /*static char buf[SMALL_BUF_SIZE];*/
struct avl_traverser t;
- /*ttfenc_entry *e = ttfenc_tab;*/
-
- assert(fd_cur->tx_tree != NULL); /* this must be set in |create_fontdictionary| */
-
if (fd_cur->fe != NULL) {
glyph_names = fd_cur->fe->glyph_names;
- assert(glyph_names != NULL);
-
for (i = 0; i < 256; i++)
ttfenc_tab[i].name = (char *) notdef;
-
- /* a workaround for a bug of AcroReader 4.0 */
+ /*tex This is a workaround for a bug of AcroReader 4.0: */
if (strcmp(glyph_names[97], "a") == 0) {
q = xtalloc(1, int);
*q = 'a';
aa = avl_probe(fd_cur->tx_tree, q);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
}
- /* end of workaround */
-
- /* take over collected characters from \TeX, reencode them */
+ /*tex Take over collected characters from \TeX, reencode them. */
avl_t_init(&t, fd_cur->tx_tree);
- for (q = (int *) avl_t_first(&t, fd_cur->tx_tree); q != NULL;
- q = (int *) avl_t_next(&t)) {
- assert(*q >= 0 && *q < 256);
+ for (q = (int *) avl_t_first(&t, fd_cur->tx_tree); q != NULL; q = (int *) avl_t_next(&t)) {
ttfenc_tab[*q].name = glyph_names[*q];
}
make_subset_tag(fd_cur);
- } else
- assert(0);
+ }
}
-@
-@c
-#define ttf_append_byte(B)\
-do {\
- if (name_tab[i].platform_id == 3)\
- *q++ = 0;\
- *q++ = B;\
+#define ttf_append_byte(B) do { \
+ if (name_tab[i].platform_id == 3) { \
+ *q++ = 0; \
+ } \
+ *q++ = B; \
} while (0)
static char *strip_spaces_and_delims(char *s, int l)
@@ -588,9 +360,6 @@ static char *strip_spaces_and_delims(char *s, int l)
static char buf[SMALL_BUF_SIZE];
char *p = buf;
int i;
-
- assert(l >= 0 && l < (int) sizeof(buf));
-
for (i = 0; i < l; s++, i++) {
if (*s == '(' || *s == ')' || *s == '<' || *s == '>' ||
*s == '[' || *s == ']' || *s == '{' || *s == '}' ||
@@ -609,9 +378,7 @@ static void ttf_read_name(void)
char *p, buf[SMALL_BUF_SIZE];
name_record_num = get_ushort();
name_tab = xtalloc((unsigned) name_record_num, name_record);
- name_buf_size = (int) ((unsigned) tab->length -
- (3 * TTF_USHORT_SIZE +
- (TTF_ULONG) name_record_num * 6 * TTF_USHORT_SIZE));
+ name_buf_size = (int) ((unsigned) tab->length - (3 * TTF_USHORT_SIZE + (TTF_ULONG) name_record_num * 6 * TTF_USHORT_SIZE));
name_buf = xtalloc((unsigned) name_buf_size, char);
ttf_skip(TTF_USHORT_SIZE);
for (i = 0; i < name_record_num; i++) {
@@ -624,14 +391,12 @@ static void ttf_read_name(void)
}
for (p = name_buf; p - name_buf < name_buf_size; p++)
*p = get_char();
- /* look for PS font name */
+ /*tex Look for the \POSTSCRIPT\ font name. */
for (i = 0; i < name_record_num; i++) {
if (name_tab[i].platform_id == 1 &&
name_tab[i].encoding_id == 0 && name_tab[i].name_id == 6) {
xfree(fd_cur->fontname);
- fd_cur->fontname =
- xstrdup(strip_spaces_and_delims(name_buf + name_tab[i].offset,
- name_tab[i].length));
+ fd_cur->fontname = xstrdup(strip_spaces_and_delims(name_buf + name_tab[i].offset, name_tab[i].length));
fd_cur->font_dim[FONTNAME_CODE].set = true;
break;
}
@@ -639,15 +404,14 @@ static void ttf_read_name(void)
if (!fd_cur->font_dim[FONTNAME_CODE].set) {
for (i = 0; i < name_record_num; i++) {
if (name_tab[i].platform_id == 3 &&
- (name_tab[i].encoding_id == 0 || name_tab[i].encoding_id == 1)
- && name_tab[i].name_id == 6) {
+ (name_tab[i].encoding_id == 0 || name_tab[i].encoding_id == 1)
+ && name_tab[i].name_id == 6) {
xfree(fd_cur->fontname);
assert(name_tab[i].length < sizeof(buf));
for (j = 0, p = buf; j < name_tab[i].length; j += 2)
*p++ = name_buf[name_tab[i].offset + j + 1];
*p = 0;
- fd_cur->fontname =
- xstrdup(strip_spaces_and_delims(buf, (int) strlen(buf)));
+ fd_cur->fontname = xstrdup(strip_spaces_and_delims(buf, (int) strlen(buf)));
fd_cur->font_dim[FONTNAME_CODE].set = true;
break;
}
@@ -659,8 +423,7 @@ static void ttf_read_mapx(void)
{
glyph_entry *glyph;
ttf_seek_tab("maxp", TTF_FIXED_SIZE);
- glyph_tab =
- xtalloc((unsigned) (1 + (glyphs_count = get_ushort())), glyph_entry);
+ glyph_tab = xtalloc((unsigned) (1 + (glyphs_count = get_ushort())), glyph_entry);
for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) {
glyph->newindex = -1;
glyph->newoffset = 0;
@@ -668,14 +431,15 @@ static void ttf_read_mapx(void)
glyph->name = (char *) notdef;
}
glyph_index = xtalloc((unsigned) (glyphs_count + 1), long);
- glyph_index[0] = 0; /* index of ".notdef" glyph */
- glyph_index[1] = 1; /* index of ".null" glyph */
+ /*tex index of the |.notdef| glyph */
+ glyph_index[0] = 0;
+ /*tex index of the |.null| glyph */
+ glyph_index[1] = 1;
}
void ttf_read_head(void)
{
- ttf_seek_tab("head",
- 2 * TTF_FIXED_SIZE + 2 * TTF_ULONG_SIZE + TTF_USHORT_SIZE);
+ ttf_seek_tab("head", 2 * TTF_FIXED_SIZE + 2 * TTF_ULONG_SIZE + TTF_USHORT_SIZE);
upem = get_ushort();
ttf_skip(16);
fd_cur->font_dim[FONTBBOX1_CODE].val = (int) ttf_funit(get_fword());
@@ -697,8 +461,7 @@ void ttf_read_hhea(void)
fd_cur->font_dim[DESCENT_CODE].val = (int) ttf_funit(get_fword());
fd_cur->font_dim[ASCENT_CODE].set = true;
fd_cur->font_dim[DESCENT_CODE].set = true;
- ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE +
- 8 * TTF_SHORT_SIZE);
+ ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE);
nhmtxs = get_ushort();
}
@@ -745,55 +508,57 @@ void ttf_read_post(void)
post_format = get_fixed();
italic_angle = get_fixed();
int_part = (long) (italic_angle >> 16);
- if (int_part > 0x7FFF) { /* a negative number */
+ if (int_part > 0x7FFF) {
+ /*tex a negative number */
int_part = 0x10000 - int_part;
sign = -1;
}
frac_part = (long) (italic_angle % 0x10000);
- fd_cur->font_dim[ITALIC_ANGLE_CODE].val =
- (int) (sign * ((double) int_part + (double) frac_part * 1.0 / 0x10000));
+ fd_cur->font_dim[ITALIC_ANGLE_CODE].val = (int) (sign * ((double) int_part + (double) frac_part * 1.0 / 0x10000));
fd_cur->font_dim[ITALIC_ANGLE_CODE].set = true;
- if (glyph_tab == NULL)
- return; /* being called from writeotf() */
+ if (glyph_tab == NULL) {
+ /*tex We were being called from |writeotf|. */
+ return;
+ }
ttf_skip(2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE);
switch (post_format) {
- case 0x10000:
- for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) {
- glyph->name = (const char *) mac_glyph_names[glyph - glyph_tab];
- glyph->name_index = (TTF_USHORT) (glyph - glyph_tab);
- }
- break;
- case 0x20000:
- nnames = get_ushort(); /* some fonts have this value different from nglyphs */
- for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++)
- glyph->name_index = get_ushort();
- length =
- (long) ((long) tab->length -
- (long) ((long) ttf_curbyte - (long) tab->offset));
- glyph_name_buf = xtalloc((unsigned) length, char);
- for (p = glyph_name_buf; p - glyph_name_buf < length;) {
- for (k = get_byte(); k > 0; k--)
- *p++ = get_char();
- *p++ = 0;
- }
- for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) {
- if (glyph->name_index < NMACGLYPHS)
- glyph->name = mac_glyph_names[glyph->name_index];
- else {
- p = glyph_name_buf;
- k = glyph->name_index - NMACGLYPHS;
- for (; k > 0; k--)
- p = strend(p) + 1;
- glyph->name = p;
+ case 0x10000:
+ for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) {
+ glyph->name = (const char *) mac_glyph_names[glyph - glyph_tab];
+ glyph->name_index = (TTF_USHORT) (glyph - glyph_tab);
+ }
+ break;
+ case 0x20000:
+ /*tex Some fonts have this value different from |nglyphs|: */
+ nnames = get_ushort();
+ for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) {
+ glyph->name_index = get_ushort();
+ }
+ length = (long) ((long) tab->length - (long) ((long) ttf_curbyte - (long) tab->offset));
+ glyph_name_buf = xtalloc((unsigned) length, char);
+ for (p = glyph_name_buf; p - glyph_name_buf < length;) {
+ for (k = get_byte(); k > 0; k--)
+ *p++ = get_char();
+ *p++ = 0;
+ }
+ for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) {
+ if (glyph->name_index < NMACGLYPHS)
+ glyph->name = mac_glyph_names[glyph->name_index];
+ else {
+ p = glyph_name_buf;
+ k = glyph->name_index - NMACGLYPHS;
+ for (; k > 0; k--)
+ p = strend(p) + 1;
+ glyph->name = p;
+ }
+ }
+ break;
+ default:
+ formatted_warning("ttf font", "unsupported format '%.8X' of 'post' table, assuming 3.0", (unsigned int) post_format);
+ case 0x00030000:
+ for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) {
+ glyph->name_index = (TTF_USHORT) (glyph - glyph_tab);
}
- }
- break;
- default:
- formatted_warning("ttf font", "unsupported format '%.8X' of 'post' table, assuming 3.0", (unsigned int) post_format);
- case 0x00030000:
- for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) {
- glyph->name_index = (TTF_USHORT) (glyph - glyph_tab);
- }
}
}
@@ -813,14 +578,17 @@ void otc_read_tabdir(int index)
{
unsigned long i, num, rem=0;
dirtab_entry *tab;
- ttf_skip(TTF_FIXED_SIZE); /* ignore TTCTag 'ttcf' */
- ttf_skip(TTF_ULONG_SIZE); /* ignorethe version number */
+ /*tex Ignore the tag |ttcf|. */
+ ttf_skip(TTF_FIXED_SIZE);
+ /*tex Ignore the version number. */
+ ttf_skip(TTF_ULONG_SIZE);
num = get_ulong();
for (i = 0; i < num; i++) {
if (i==index) rem = get_ulong(); else ttf_skip(TTF_ULONG_SIZE);
}
ttf_skip(rem - TTF_FIXED_SIZE - (num+2)*TTF_ULONG_SIZE);
- ttf_skip(TTF_FIXED_SIZE); /* ignore the sfnt number */
+ /*tex Ignore the |sfnt| number. */
+ ttf_skip(TTF_FIXED_SIZE);
dir_tab = xtalloc(ntabs = get_ushort(), dirtab_entry);
ttf_skip(3 * TTF_USHORT_SIZE);
for (tab = dir_tab; tab - dir_tab < ntabs; tab++) {
@@ -836,7 +604,8 @@ void ttf_read_tabdir(void)
{
int i;
dirtab_entry *tab;
- ttf_skip(TTF_FIXED_SIZE); /* ignore the sfnt number */
+ /*tex Ignore the |sfnt| number. */
+ ttf_skip(TTF_FIXED_SIZE);
dir_tab = xtalloc(ntabs = get_ushort(), dirtab_entry);
ttf_skip(3 * TTF_USHORT_SIZE);
for (tab = dir_tab; tab - dir_tab < ntabs; tab++) {
@@ -848,8 +617,7 @@ void ttf_read_tabdir(void)
}
}
-static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
- boolean warn)
+static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid, boolean warn)
{
seg_entry *seg_tab, *s;
TTF_USHORT *glyphId, format, segCount;
@@ -858,8 +626,7 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
long n, i, k, length, index;
ttf_cmap_entry tmp_e, *p;
void **aa;
-
- /* look up in |ttf_cmap_tree| first, return if found */
+ /*tex Look up in |ttf_cmap_tree| first, return if found. */
tmp_e.ttf_name = ttf_name;
tmp_e.pid = (TTF_USHORT) pid;
tmp_e.eid = (TTF_USHORT) eid;
@@ -870,9 +637,8 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
p = (ttf_cmap_entry *) avl_find(ttf_cmap_tree, &tmp_e);
if (p != NULL)
return p;
-
- /* not found, have to read it */
- ttf_seek_tab("cmap", TTF_USHORT_SIZE); /* skip the table version number (=0) */
+ /*tex It's not found so we have to read it. We skip the table version number (0). */
+ ttf_seek_tab("cmap", TTF_USHORT_SIZE);
ncmapsubtabs = get_ushort();
cmap_offset = (TTF_ULONG) (ttf_curbyte - 2 * TTF_USHORT_SIZE);
cmap_tab = xtalloc(ncmapsubtabs, cmap_entry);
@@ -886,36 +652,46 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
if (format == 4)
goto read_cmap_format_4;
else {
- if (warn)
+ if (warn) {
formatted_warning("ttf font", "cmap format %i unsupported", format);
+ }
return NULL;
}
}
}
- if (warn)
+ if (warn) {
formatted_warning("ttf font", "cannot find cmap subtable for (pid,eid) = (%i,%i)", pid, eid);
+ }
return NULL;
+ /*tex We jump here: */
read_cmap_format_4:
- /* initialize the new entry */
+ /*tex Initialize the new entry. */
p = new_ttf_cmap_entry();
p->ttf_name = xstrdup(ttf_name);
p->pid = (TTF_USHORT) pid;
p->eid = (TTF_USHORT) eid;
p->table = xtalloc(0x10000, long);
- for (i = 0; i < 0x10000; ++i)
- p->table[i] = -1; /* unassigned yet */
-
- /* read the subtable */
- length = get_ushort(); /* length of subtable */
- (void) get_ushort(); /* skip the version number */
+ for (i = 0; i < 0x10000; ++i) {
+ /*tex Yet unassigned: */
+ p->table[i] = -1;
+ }
+ /*tex Read the subtable. */
+ /*tex length of subtable */
+ length = get_ushort();
+ /*tex skip the version number */
+ (void) get_ushort();
segCount = get_ushort() / 2;
- (void) get_ushort(); /* skip searchRange */
- (void) get_ushort(); /* skip entrySelector */
- (void) get_ushort(); /* skip rangeShift */
+ /*tex skip searchRange */
+ (void) get_ushort();
+ /*tex skip entrySelector */
+ (void) get_ushort();
+ /*tex skip rangeShift */
+ (void) get_ushort();
seg_tab = xtalloc(segCount, seg_entry);
for (s = seg_tab; s - seg_tab < segCount; s++)
s->endCode = get_ushort();
- (void) get_ushort(); /* skip reversedPad */
+ /*tex skip reversedPad */
+ (void) get_ushort();
for (s = seg_tab; s - seg_tab < segCount; s++)
s->startCode = get_ushort();
for (s = seg_tab; s - seg_tab < segCount; s++)
@@ -923,7 +699,8 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
for (s = seg_tab; s - seg_tab < segCount; s++)
s->idRangeOffset = get_ushort();
length -= 8 * TTF_USHORT_SIZE + 4 * segCount * TTF_USHORT_SIZE;
- n = length / TTF_USHORT_SIZE; /* number of glyphID's */
+ /*tex number of glyphID's */
+ n = length / TTF_USHORT_SIZE;
glyphId = xtalloc((unsigned) n, TTF_USHORT);
for (i = 0; i < n; i++)
glyphId[i] = get_ushort();
@@ -935,9 +712,7 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
if (s->idRangeOffset == 0)
index = (s->idDelta + i) & 0xFFFF;
else {
- k = (i - s->startCode) + s->idRangeOffset / 2 +
- (s - seg_tab) - segCount;
- assert(k >= 0 && k < n);
+ k = (i - s->startCode) + s->idRangeOffset / 2 + (s - seg_tab) - segCount;
index = glyphId[k];
if (index != 0)
index = (index + s->idDelta) & 0xFFFF;
@@ -958,12 +733,12 @@ static ttf_cmap_entry *ttf_read_cmap(char *ttf_name, int pid, int eid,
xfree(seg_tab);
xfree(glyphId);
aa = avl_probe(ttf_cmap_tree, p);
- assert(aa != NULL);
+ if (aa == NULL) {
+ /*tex Is this a problem? */
+ }
return p;
}
-@
-@c
static void ttf_read_font(void)
{
ttf_read_tabdir();
@@ -995,7 +770,6 @@ static void ttf_reset_chksm(PDF pdf, dirtab_entry * tab)
formatted_warning("ttf font","offset of `%4.4s' is not a multiple of 4", tab->tag);
}
-
static void ttf_set_chksm(PDF pdf, dirtab_entry * tab)
{
tab->length = (TTF_ULONG) ttf_offset() - tab->offset;
@@ -1012,17 +786,17 @@ static void ttf_copytab(PDF pdf, const char *name)
ttf_set_chksm(pdf, tab);
}
-@
-@c
-#define BYTE_ENCODING_LENGTH \
- ((256)*TTF_BYTE_SIZE + 3*TTF_USHORT_SIZE)
+#define BYTE_ENCODING_LENGTH ((256)*TTF_BYTE_SIZE + 3*TTF_USHORT_SIZE)
static void ttf_byte_encoding(PDF pdf)
{
ttfenc_entry *e;
- (void) put_ushort(0); /* format number (0: byte encoding table) */
- (void) put_ushort(BYTE_ENCODING_LENGTH); /* length of table */
- (void) put_ushort(0); /* version number */
+ /*tex Format number (0: byte encoding table) */
+ (void) put_ushort(0);
+ /*tex The length of the table */
+ (void) put_ushort(BYTE_ENCODING_LENGTH);
+ /*tex The version number */
+ (void) put_ushort(0);
for (e = ttfenc_tab; e - ttfenc_tab < 256; e++)
if (e->newindex < 256) {
put_byte(e->newindex);
@@ -1031,67 +805,87 @@ static void ttf_byte_encoding(PDF pdf)
formatted_warning("ttf font",
"glyph '%s' has been mapped to '%s' in 'ttf_byte_encoding' cmap table",
e->name, notdef);
- put_byte(0); /* notdef */
+ /*tex |.notdef|: */
+ put_byte(0);
}
}
-@
-@c
#define TRIMMED_TABLE_MAP_LENGTH (TTF_USHORT_SIZE*(5 + (256)))
static void ttf_trimmed_table_map(PDF pdf)
{
ttfenc_entry *e;
- (void) put_ushort(6); /* format number (6): trimmed table mapping */
+ /*tex format number 6: trimmed table mapping */
+ (void) put_ushort(6);
(void) put_ushort(TRIMMED_TABLE_MAP_LENGTH);
- (void) put_ushort(0); /* version number (0) */
- (void) put_ushort(0); /* first character code */
- (void) put_ushort(256); /* number of character code in table */
- for (e = ttfenc_tab; e - ttfenc_tab < 256; e++)
+ /*tex version number 0 */
+ (void) put_ushort(0);
+ /*tex first character code */
+ (void) put_ushort(0);
+ /*tex number of character code in table: */
+ (void) put_ushort(256);
+ for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) {
(void) put_ushort(e->newindex);
+ }
}
-@
-@c
#define SEG_MAP_DELTA_LENGTH ((16 + (256))*TTF_USHORT_SIZE)
static void ttf_seg_map_delta(PDF pdf)
{
ttfenc_entry *e;
- (void) put_ushort(4); /* format number (4: segment mapping to delta values) */
+ /*tex format number (4: segment mapping to delta values) */
+ (void) put_ushort(4);
(void) put_ushort(SEG_MAP_DELTA_LENGTH);
- (void) put_ushort(0); /* version number */
- (void) put_ushort(4); /* 2*segCount */
- (void) put_ushort(4); /* searchRange */
- (void) put_ushort(1); /* entrySelector */
- (void) put_ushort(0); /* rangeShift */
- (void) put_ushort(0xF0FF); /* endCount[0] */
- (void) put_ushort(0xFFFF); /* endCount[1] */
- (void) put_ushort(0); /* reversedPad */
- (void) put_ushort(0xF000); /* startCount[0] */
- (void) put_ushort(0xFFFF); /* startCount[1] */
- (void) put_ushort(0); /* idDelta[0] */
- (void) put_ushort(1); /* idDelta[1] */
- (void) put_ushort(2 * TTF_USHORT_SIZE); /* idRangeOffset[0] */
- (void) put_ushort(0); /* idRangeOffset[1] */
- for (e = ttfenc_tab; e - ttfenc_tab < 256; e++)
+ /*tex version number */
+ (void) put_ushort(0);
+ /*tex 2*segCount */
+ (void) put_ushort(4);
+ /*tex searchRange */
+ (void) put_ushort(4);
+ /*tex entrySelector */
+ (void) put_ushort(1);
+ /*tex rangeShift */
+ (void) put_ushort(0);
+ /*tex endCount[0] */
+ (void) put_ushort(0xF0FF);
+ /*tex endCount[1] */
+ (void) put_ushort(0xFFFF);
+ /*tex reversedPad */
+ (void) put_ushort(0);
+ /*tex startCount[0] */
+ (void) put_ushort(0xF000);
+ /*tex startCount[1] */
+ (void) put_ushort(0xFFFF);
+ /*tex idDelta[0] */
+ (void) put_ushort(0);
+ /*tex idDelta[1] */
+ (void) put_ushort(1);
+ /*tex idRangeOffset[0] */
+ (void) put_ushort(2 * TTF_USHORT_SIZE);
+ /*tex idRangeOffset[1] */
+ (void) put_ushort(0);
+ for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) {
(void) put_ushort(e->newindex);
+ }
}
-@
-@c
#define CMAP_ENTRY_LENGTH (2*TTF_USHORT_SIZE + TTF_ULONG_SIZE)
static void ttf_select_cmap(void)
{
- assert(sizeof(new_cmap_tab) <= NEW_CMAP_SIZE * sizeof(cmap_entry));
- new_cmap_tab[0].platform_id = 1; /* Macintosh */
- new_cmap_tab[0].encoding_id = 0; /* Symbol; ignore code page */
- new_cmap_tab[0].format = (TTF_USHORT) (new_glyphs_count < 256 ? 0 /* byte encoding */
- : 6); /* trimmed table mapping */
- new_cmap_tab[1].platform_id = 3; /* Microsoft */
- new_cmap_tab[1].encoding_id = 0; /* Symbol; ignore code page */
- new_cmap_tab[1].format = 4; /* segment mapping to delta */
+ /*tex Macintosh */
+ new_cmap_tab[0].platform_id = 1;
+ /*tex Symbol; ignore code page */
+ new_cmap_tab[0].encoding_id = 0;
+ /*tex byte encoding (0) or trimmed table mapping (6) */
+ new_cmap_tab[0].format = (TTF_USHORT) (new_glyphs_count < 256 ? 0 : 6);
+ /*tex Microsoft */
+ new_cmap_tab[1].platform_id = 3;
+ /*tex Symbol; ignore code page */
+ new_cmap_tab[1].encoding_id = 0;
+ /*tex segment mapping to delta */
+ new_cmap_tab[1].format = 4;
}
static void ttf_write_cmap(PDF pdf)
@@ -1101,23 +895,25 @@ static void ttf_write_cmap(PDF pdf)
dirtab_entry *tab = ttf_name_lookup("cmap", true);
ttf_select_cmap();
ttf_reset_chksm(pdf, tab);
- (void) put_ushort(0); /* table version number (0) */
- (void) put_ushort(NEW_CMAP_SIZE); /* number of encoding tables */
+ /*tex Table version number 0. */
+ (void) put_ushort(0);
+ /*tex Number of encoding tables. */
+ (void) put_ushort(NEW_CMAP_SIZE);
offset = 2 * TTF_USHORT_SIZE + NEW_CMAP_SIZE * CMAP_ENTRY_LENGTH;
for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) {
ce->offset = (TTF_ULONG) offset;
switch (ce->format) {
- case 0:
- offset += BYTE_ENCODING_LENGTH;
- break;
- case 4:
- offset += SEG_MAP_DELTA_LENGTH;
- break;
- case 6:
- offset += TRIMMED_TABLE_MAP_LENGTH;
- break;
- default:
- normal_error("ttf font","invalid format (it should not have happened)");
+ case 0:
+ offset += BYTE_ENCODING_LENGTH;
+ break;
+ case 4:
+ offset += SEG_MAP_DELTA_LENGTH;
+ break;
+ case 6:
+ offset += TRIMMED_TABLE_MAP_LENGTH;
+ break;
+ default:
+ normal_error("ttf font","invalid format (it should not have happened)");
}
(void) put_ushort(ce->platform_id);
(void) put_ushort(ce->encoding_id);
@@ -1125,27 +921,24 @@ static void ttf_write_cmap(PDF pdf)
}
for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) {
switch (ce->format) {
- case 0:
- ttf_byte_encoding(pdf);
- break;
- case 4:
- ttf_seg_map_delta(pdf);
- break;
- case 6:
- ttf_trimmed_table_map(pdf);
- break;
- }
+ case 0:
+ ttf_byte_encoding(pdf);
+ break;
+ case 4:
+ ttf_seg_map_delta(pdf);
+ break;
+ case 6:
+ ttf_trimmed_table_map(pdf);
+ break;
+ }
}
ttf_set_chksm(pdf, tab);
}
-@
-@c
static int prepend_subset_tags(int index, char *p)
{
boolean is_unicode;
int i;
- assert(index >= 0 && index < name_record_num && fd_cur->subset_tag != NULL);
is_unicode = (name_tab[index].platform_id == 3);
if (is_unicode) {
for (i = 0; i < 6; ++i) {
@@ -1174,10 +967,12 @@ static void ttf_write_name(PDF pdf)
dirtab_entry *tab = ttf_name_lookup("name", true);
if (is_subsetted(fd_cur->fm)) {
l = 0;
- for (i = 0; i < name_record_num; i++)
- l += name_tab[i].length + 14; /* maximum lengh of new stogare area */
+ for (i = 0; i < name_record_num; i++) {
+ /*tex Maximum lengh of new stogare area. */
+ l += name_tab[i].length + 14;
+ }
new_name_buf = xtalloc((unsigned) l, char);
- /* additional space for subset tags */
+ /*tex Additional space for subset tags. */
p = new_name_buf;
for (i = 0; i < name_record_num; i++) {
n = name_tab + i;
@@ -1201,10 +996,10 @@ static void ttf_write_name(PDF pdf)
new_name_buf_size = name_buf_size;
}
ttf_reset_chksm(pdf, tab);
- (void) put_ushort(0); /* Format selector */
+ (void) put_ushort(0);
+ /*tex Format selector. */
(void) put_ushort(name_record_num);
- (void) put_ushort(3 * TTF_USHORT_SIZE +
- name_record_num * 6 * TTF_USHORT_SIZE);
+ (void) put_ushort(3 * TTF_USHORT_SIZE + name_record_num * 6 * TTF_USHORT_SIZE);
for (i = 0; i < name_record_num; i++) {
(void) put_ushort(name_tab[i].platform_id);
(void) put_ushort(name_tab[i].encoding_id);
@@ -1220,8 +1015,6 @@ static void ttf_write_name(PDF pdf)
xfree(new_name_buf);
}
-@
-@c
static void ttf_write_dirtab(PDF pdf)
{
dirtab_entry *tab;
@@ -1249,7 +1042,7 @@ static void ttf_write_dirtab(PDF pdf)
put_ulong((long) tab->length);
}
}
- /* adjust checkSumAdjustment */
+ /*tex adjust |checkSumAdjustment| */
tmp_ulong = 0;
checksum = 0;
for (p = (char *) pdf->fb->data, i = 0; i < (unsigned) save_offset;) {
@@ -1270,8 +1063,6 @@ static void ttf_write_dirtab(PDF pdf)
ttf_seek_outbuf(save_offset);
}
-@
-@c
static void ttf_write_glyf(PDF pdf)
{
long *id, k;
@@ -1294,9 +1085,9 @@ static void ttf_write_glyf(PDF pdf)
if (glyph_tab[idx].newindex < 0) {
glyph_tab[idx].newindex = (TTF_SHORT) new_glyphs_count;
glyph_index[new_glyphs_count++] = idx;
- /*
- N.B.: Here we change |new_glyphs_count|,
- which appears in the condition of the |for| loop
+ /*tex
+ Here we change |new_glyphs_count|, which appears in
+ the condition of the |for| loop.
*/
}
(void) put_ushort(glyph_tab[idx].newindex);
@@ -1314,21 +1105,22 @@ static void ttf_write_glyf(PDF pdf)
if (flags & WE_HAVE_INSTRUCTIONS)
ttf_ncopy(pdf, copy_ushort());
} else
- ttf_ncopy(pdf, (int)
- (glyph_tab[*id + 1].offset - glyph_tab[*id].offset -
- TTF_USHORT_SIZE - 4 * TTF_FWORD_SIZE));
+ ttf_ncopy(pdf, (int) (glyph_tab[*id + 1].offset - glyph_tab[*id].offset - TTF_USHORT_SIZE - 4 * TTF_FWORD_SIZE));
}
}
last_glyf_offset = (TTF_ULONG) ttf_offset() - (TTF_ULONG) new_glyf_offset;
ttf_set_chksm(pdf, tab);
}
-@ Reindexing glyphs: we append index of used glyphs to |glyph_index|
- while going through |ttfenc_tab|. After appending a new entry to
- |glyph_index| we set field |newindex| of corresponding entries in both
- |glyph_tab| and |ttfenc_tab| to the newly created index.
+/*tex
+
+ Reindexing glyphs: we append index of used glyphs to |glyph_index| while
+ going through |ttfenc_tab|. After appending a new entry to |glyph_index| we
+ set field |newindex| of corresponding entries in both |glyph_tab| and
+ |ttfenc_tab| to the newly created index.
+
+*/
-@c
static void ttf_reindex_glyphs(void)
{
ttfenc_entry *e;
@@ -1337,14 +1129,13 @@ static void ttf_reindex_glyphs(void)
long *t;
ttf_cmap_entry *cmap = NULL;
boolean cmap_not_found = false;
-
for (e = ttfenc_tab; e - ttfenc_tab < 256; e++) {
- e->newindex = 0; /* index of ".notdef" glyph */
-
- /* handle case of reencoded fonts */
+ /*tex The index of the |.notdef| glyph */
+ e->newindex = 0;
+ /*tex Handle the case of reencoded fonts. */
if (e->name == notdef)
continue;
- /* scan form `index123' */
+ /*tex Scan form |index123|. */
if (sscanf(e->name, GLYPH_PREFIX_INDEX "%i", &index) == 1) {
if (index >= glyphs_count) {
formatted_warning("ttf font","'%s' out of valid range [0..%i)", e->name, glyphs_count);
@@ -1353,22 +1144,22 @@ static void ttf_reindex_glyphs(void)
glyph = glyph_tab + index;
goto append_new_glyph;
}
- /* scan form `uniABCD' */
+ /*tex Scan form |uniABCD|. */
if (sscanf(e->name, GLYPH_PREFIX_UNICODE "%X", &index) == 1) {
if (cmap == NULL && !cmap_not_found) {
- /* need to read the unicode mapping, ie (pid,eid) = (3,1) or (0,3) */
+ /*tex Need to read the \UNICODE\ mapping, i.e. |(pid,eid) = (3,1) or (0,3)|. */
cmap = ttf_read_cmap(fd_cur->fm->ff_name, 3, 1, false);
if (cmap == NULL)
cmap = ttf_read_cmap(fd_cur->fm->ff_name, 0, 3, false);
if (cmap == NULL) {
+ /*tex Once only. */
normal_warning("ttf font", "no unicode mapping found, all 'uniXXXX' names will be ignored");
- cmap_not_found = true; /* once only */
+ cmap_not_found = true;
}
}
if (cmap == NULL)
continue;
t = cmap->table;
- assert(t != NULL);
if (t[index] != -1) {
if (t[index] >= glyphs_count) {
formatted_warning("ttf font", "'%s' is mapped to index %li which is out of valid range [0..%i)",
@@ -1382,7 +1173,7 @@ static void ttf_reindex_glyphs(void)
continue;
}
}
- /* look up by name */
+ /*tex Look up by name: */
for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++)
if (glyph->name != notdef && strcmp(glyph->name, e->name) == 0)
break;
@@ -1391,7 +1182,6 @@ static void ttf_reindex_glyphs(void)
continue;
}
append_new_glyph:
- assert(glyph > glyph_tab && glyph - glyph_tab < glyphs_count);
if (glyph->newindex < 0) {
glyph_index[new_glyphs_count] = (short) (glyph - glyph_tab);
glyph->newindex = (TTF_SHORT) new_glyphs_count;
@@ -1401,28 +1191,42 @@ static void ttf_reindex_glyphs(void)
}
}
-@ To calculate the checkSum for the 'head' table which itself includes the
- checkSumAdjustment entry for the entire font, do the following:
+/*tex
+
+ To calculate the checkSum for the 'head' table which itself includes the
+ checkSumAdjustment entry for the entire font, do the following:
+
+ \startitemize
+ \startitem
+ Set the checkSumAdjustment to 0.
+ \stopitem
+ \startitem
+ Calculate the checksum for all the tables including the |head| table
+ and enter that value into the table directory.
+ \stopitem
+ \startitem
+ Calculate the checksum for the entire font.
+ \stopitem
+ \startitem
+ Subtract that value from the hex value B1B0AFBA.
+ \stopitem
+ \startitem
+ Store the result in checkSumAdjustment.
+ \stopitem
+ \startitemize
+
+ The checkSum for the 'head table which includes the checkSumAdjustment entry
+ for the entire font is now incorrect. That is not a problem. Do not change
+ it. An application attempting to verify that the 'head' table has not changed
+ should calculate the checkSum for that table by not including the
+ checkSumAdjustment value, and compare the result with the entry in the table
+ directory.
+
+ The table directory also includes the offset of the associated tagged table
+ from the beginning of the font file and the length of that table.
+
+*/
- \item Set the checkSumAdjustment to 0.
- \item Calculate the checksum for all the tables including the 'head' table
- and enter that value into the table directory.
- \item Calculate the checksum for the entire font.
- \item Subtract that value from the hex value B1B0AFBA.
- \item Store the result in checkSumAdjustment.
-
- The checkSum for the 'head table which includes the checkSumAdjustment
- entry for the entire font is now incorrect. That is not a problem. Do not
- change it. An application attempting to verify that the 'head' table has
- not changed should calculate the checkSum for that table by not including
- the checkSumAdjustment value, and compare the result with the entry in the
- table directory.
-
- The table directory also includes the offset of the associated tagged
- table from the beginning of the font file and the length of that table.
-
-
-@c
static void ttf_write_head(PDF pdf)
{
dirtab_entry *tab;
@@ -1431,9 +1235,9 @@ static void ttf_write_head(PDF pdf)
ttf_ncopy(pdf, 2 * TTF_FIXED_SIZE);
checkSumAdjustment_offset = (TTF_ULONG) ttf_offset();
put_ulong(0);
- ttf_skip(TTF_ULONG_SIZE); /* skip checkSumAdjustment */
- ttf_ncopy(pdf, TTF_ULONG_SIZE + 2 * TTF_USHORT_SIZE + 16 +
- 4 * TTF_FWORD_SIZE + 2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE);
+ /*tex skip |checkSumAdjustment| */
+ ttf_skip(TTF_ULONG_SIZE);
+ ttf_ncopy(pdf, TTF_ULONG_SIZE + 2 * TTF_USHORT_SIZE + 16 + 4 * TTF_FWORD_SIZE + 2 * TTF_USHORT_SIZE + TTF_SHORT_SIZE);
if (is_subsetted(fd_cur->fm)) {
(void) put_short(loca_format);
(void) put_short(0);
@@ -1442,21 +1246,16 @@ static void ttf_write_head(PDF pdf)
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_write_hhea(PDF pdf)
{
dirtab_entry *tab;
tab = ttf_seek_tab("hhea", 0);
ttf_reset_chksm(pdf, tab);
- ttf_ncopy(pdf, TTF_FIXED_SIZE + 3 * TTF_FWORD_SIZE + TTF_UFWORD_SIZE +
- 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE);
+ ttf_ncopy(pdf, TTF_FIXED_SIZE + 3 * TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3 * TTF_FWORD_SIZE + 8 * TTF_SHORT_SIZE);
(void) put_ushort(new_glyphs_count);
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_write_htmx(PDF pdf)
{
long *id;
@@ -1469,8 +1268,6 @@ static void ttf_write_htmx(PDF pdf)
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_write_loca(PDF pdf)
{
long *id;
@@ -1497,8 +1294,6 @@ static void ttf_write_loca(PDF pdf)
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_write_mapx(PDF pdf)
{
dirtab_entry *tab = ttf_seek_tab("maxp", TTF_FIXED_SIZE + TTF_USHORT_SIZE);
@@ -1509,37 +1304,41 @@ static void ttf_write_mapx(PDF pdf)
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_write_OS2(PDF pdf)
{
dirtab_entry *tab = ttf_seek_tab("OS/2", 0);
TTF_USHORT version;
ttf_reset_chksm(pdf, tab);
version = get_ushort();
- if (version > 3)
+ if (version > 3) {
formatted_error("ttf font","unknown version '%.4X' of OS/2 table", version);
- (void) put_ushort(0x0001); /* fix version to 1 */
- ttf_ncopy(pdf,
- 2 * TTF_USHORT_SIZE + 13 * TTF_SHORT_SIZE + 10 * TTF_BYTE_SIZE);
- ttf_skip(4 * TTF_ULONG_SIZE); /* ulUnicodeRange 1--4 */
- put_ulong(0x00000003); /* Basic Latin + Latin-1 Supplement (0x0000--0x00FF) */
- put_ulong(0x10000000); /* Private Use (0xE000--0xF8FF) */
+ }
+ /*tex fix version to 1 */
+ (void) put_ushort(0x0001);
+ ttf_ncopy(pdf,2 * TTF_USHORT_SIZE + 13 * TTF_SHORT_SIZE + 10 * TTF_BYTE_SIZE);
+ /*tex |ulUnicodeRange| 1--4 */
+ ttf_skip(4 * TTF_ULONG_SIZE);
+ /*tex Basic Latin + Latin-1 Supplement (0x0000--0x00FF) */
+ put_ulong(0x00000003);
+ /*tex Private Use (0xE000--0xF8FF) */
+ put_ulong(0x10000000);
put_ulong(0x00000000);
put_ulong(0x00000000);
- ttf_ncopy(pdf, 4 * TTF_CHAR_SIZE + TTF_USHORT_SIZE); /* achVendID + fsSelection */
+ /*tex |achVendID| + |fsSelection| */
+ ttf_ncopy(pdf, 4 * TTF_CHAR_SIZE + TTF_USHORT_SIZE);
ttf_skip(2 * TTF_USHORT_SIZE);
- (void) put_ushort(0x0000); /* usFirstCharIndex */
- (void) put_ushort(0xF0FF); /* usLastCharIndex */
+ /*tex |usFirstCharIndex| */
+ (void) put_ushort(0x0000);
+ /*tex |usLastCharIndex| */
+ (void) put_ushort(0xF0FF);
ttf_ncopy(pdf, 5 * TTF_USHORT_SIZE);
- /* for version 0 the OS/2 table ends here, the rest is for version 1 */
- put_ulong(0x80000000); /* Symbol Character Set---don't use any code page */
+ /*tex For version 0 the OS/2 table ends here, the rest is for version 1. */
+ /*tex Symbol Character Set: don't use any code page */
+ put_ulong(0x80000000);
put_ulong(0x00000000);
ttf_set_chksm(pdf, tab);
}
-@
-@c
static boolean unsafe_name(const char *s)
{
const char **p;
@@ -1559,12 +1358,10 @@ static void ttf_write_post(PDF pdf)
ttf_reset_chksm(pdf, tab);
if (!fd_cur->write_ttf_glyph_names || post_format == 0x00030000) {
put_fixed(0x00030000);
- ttf_ncopy(pdf,
- TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE);
+ ttf_ncopy(pdf, TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE);
} else {
put_fixed(0x00020000);
- ttf_ncopy(pdf,
- TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE);
+ ttf_ncopy(pdf, TTF_FIXED_SIZE + 2 * TTF_FWORD_SIZE + 5 * TTF_ULONG_SIZE);
(void) put_ushort(new_glyphs_count);
k = 0;
for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) {
@@ -1587,22 +1384,23 @@ static void ttf_write_post(PDF pdf)
ttf_set_chksm(pdf, tab);
}
-@
-@c
static void ttf_init_font(PDF pdf, int n)
{
int i, k;
for (i = 1, k = 0; i <= n; i <<= 1, k++);
- put_fixed(0x00010000); /* font version */
- (void) put_ushort(n); /* number of tables */
- (void) put_ushort(i << 3); /* search range */
- (void) put_ushort(k - 1); /* entry selector */
- (void) put_ushort((n << 4) - (i << 3)); /* range shift */
+ /*tex font version */
+ put_fixed(0x00010000);
+ /*tex number of tables */
+ (void) put_ushort(n);
+ /*tex search range */
+ (void) put_ushort(i << 3);
+ /*tex entry selector */
+ (void) put_ushort(k - 1);
+ /*tex range shift */
+ (void) put_ushort((n << 4) - (i << 3));
ttf_seek_outbuf(TABDIR_OFF + n * 4 * TTF_ULONG_SIZE);
}
-@
-@c
static void ttf_subset_font(PDF pdf)
{
ttf_init_font(pdf, new_ntabs);
@@ -1628,8 +1426,6 @@ static void ttf_subset_font(PDF pdf)
ttf_write_dirtab(pdf);
}
-@
-@c
static void ttf_copy_font(PDF pdf)
{
dirtab_entry *tab;
@@ -1643,33 +1439,25 @@ static void ttf_copy_font(PDF pdf)
ttf_write_dirtab(pdf);
}
-@
-@c
void writettf(PDF pdf, fd_entry * fd)
{
int callback_id;
int file_opened = 0;
- fd_cur = fd; /* |fd_cur| is global inside \.{writettf.w} */
- assert(fd_cur->fm != NULL);
- assert(is_truetype(fd_cur->fm));
- assert(is_included(fd_cur->fm));
-
+ /* The next one is global inside |writettf.c| */
+ fd_cur = fd;
if (is_subsetted(fd_cur->fm) && (fd_cur->fe == NULL)) {
normal_error("ttf font","subset must be a reencoded font");
}
ttf_curbyte = 0;
ttf_size = 0;
-
- cur_file_name =
- luatex_find_file(fd_cur->fm->ff_name, find_truetype_file_callback);
+ cur_file_name = luatex_find_file(fd_cur->fm->ff_name, find_truetype_file_callback);
if (cur_file_name == NULL) {
formatted_error("ttf font","cannot find font file for reading '%s'", fd_cur->fm->ff_name);
}
callback_id = callback_defined(read_truetype_file_callback);
if (callback_id > 0) {
- if (run_callback(callback_id, "S->bSd", cur_file_name,
- &file_opened, &ttf_buffer, &ttf_size) &&
- file_opened && ttf_size > 0) {
+ if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &ttf_buffer, &ttf_size) && file_opened && ttf_size > 0) {
+ /* We're okay. */
} else {
formatted_error("ttf font","cannot open font file for reading '%s'", cur_file_name);
}
@@ -1696,7 +1484,6 @@ void writettf(PDF pdf, fd_entry * fd)
name_tab = NULL;
name_buf = NULL;
ttf_read_font();
-
pdf_save_offset(pdf);
pdf_flush(pdf);
if (is_subsetted(fd_cur->fm)) {
@@ -1705,7 +1492,6 @@ void writettf(PDF pdf, fd_entry * fd)
} else
ttf_copy_font(pdf);
ttf_length = ttf_offset();
-
xfree(dir_tab);
xfree(glyph_tab);
xfree(glyph_index);
@@ -1732,7 +1518,7 @@ static void do_writeotf(PDF pdf, fd_entry * fd)
if (tracefilenames)
tex_printf("<<%s", cur_file_name);
ttf_read_tabdir();
- /* read font parameters */
+ /*tex Read teh font parameters. */
if (ttf_name_lookup("head", false) != NULL)
ttf_read_head();
if (ttf_name_lookup("hhea", false) != NULL)
@@ -1741,10 +1527,10 @@ static void do_writeotf(PDF pdf, fd_entry * fd)
ttf_read_pclt();
if (ttf_name_lookup("post", false) != NULL)
ttf_read_post();
- /* copy font file */
- if (ttf_name_lookup("CFF2", false) != NULL) /* HH */
- tab = ttf_seek_tab("CFF2", 0); /* HH */
- else /* HH */
+ /*tex Copy the font file: */
+ if (ttf_name_lookup("CFF2", false) != NULL)
+ tab = ttf_seek_tab("CFF2", 0);
+ else
tab = ttf_seek_tab("CFF ", 0);
for (i = (long) tab->length; i > 0; i--) {
copy_char();
@@ -1754,30 +1540,21 @@ static void do_writeotf(PDF pdf, fd_entry * fd)
tex_printf(">>");
}
-@
-@c
void writeotf(PDF pdf, fd_entry * fd)
{
int callback_id;
int file_opened = 0;
-
fd_cur = fd;
- assert(fd_cur->fm != NULL);
- assert(is_opentype(fd_cur->fm));
- assert(is_included(fd_cur->fm));
-
ttf_curbyte = 0;
ttf_size = 0;
- cur_file_name =
- luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback);
+ cur_file_name = luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback);
if (cur_file_name == NULL) {
formatted_error("otf font","cannot find font file for reading '%s'", fd_cur->fm->ff_name);
}
callback_id = callback_defined(read_opentype_file_callback);
if (callback_id > 0) {
- if (run_callback(callback_id, "S->bSd", cur_file_name,
- &file_opened, &ttf_buffer, &ttf_size) &&
- file_opened && ttf_size > 0) {
+ if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &ttf_buffer, &ttf_size) && file_opened && ttf_size > 0) {
+ /*tex We're okay. */
} else {
formatted_error("otf font","cannot open font file for reading '%s'", cur_file_name);
}
@@ -1788,7 +1565,6 @@ void writeotf(PDF pdf, fd_entry * fd)
ttf_read_file();
ttf_close();
}
-
fd_cur->ff_found = true;
do_writeotf(pdf, fd);
xfree(ttf_buffer);
diff --git a/Build/source/texk/web2c/luatexdir/font/writetype0.w b/Build/source/texk/web2c/luatexdir/font/writetype0.c
index ebf4be66723..7a81d58c992 100644
--- a/Build/source/texk/web2c/luatexdir/font/writetype0.w
+++ b/Build/source/texk/web2c/luatexdir/font/writetype0.c
@@ -1,29 +1,34 @@
-% writetype0.w
-%
-% 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
+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/>.
+
+*/
#include "ptexlib.h"
#include "font/writettf.h"
#include "font/writecff.h"
-@ @c
+/*tex
+
+ Here we also support the newer CFF2 specification,
+
+*/
+
extern unsigned char *ttf_buffer;
void writetype0(PDF pdf, fd_entry * fd)
@@ -34,15 +39,13 @@ void writetype0(PDF pdf, fd_entry * fd)
dirtab_entry *tab;
cff_font *cff;
sfnt *sfont;
-
dir_tab = NULL;
glyph_tab = NULL;
-
- fd_cur = fd; /* |fd_cur| is global inside \.{writettf.w} */
+ /*tex |fd_cur| is global inside |writettf.c| */
+ fd_cur = fd;
assert(fd_cur->fm != NULL);
assert(is_opentype(fd_cur->fm) || is_truetype(fd_cur->fm));
assert(is_included(fd_cur->fm));
-
ttf_curbyte = 0;
ttf_size = 0;
cur_file_name =
@@ -69,9 +72,7 @@ void writetype0(PDF pdf, fd_entry * fd)
ttf_read_file();
ttf_close();
}
-
fd_cur->ff_found = true;
-
sfont = sfnt_open(ttf_buffer, ttf_size);
if (sfont->type == SFNT_TYPE_TTC)
i = ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
@@ -86,7 +87,7 @@ void writetype0(PDF pdf, fd_entry * fd)
else ttf_read_tabdir();
sfnt_close(sfont);
- /* read font parameters */
+ /*tex Read font parameters: */
if (ttf_name_lookup("head", false) != NULL)
ttf_read_head();
if (ttf_name_lookup("hhea", false) != NULL)
@@ -95,32 +96,25 @@ void writetype0(PDF pdf, fd_entry * fd)
ttf_read_pclt();
if (ttf_name_lookup("post", false) != NULL)
ttf_read_post();
-
- /* copy font file */
- if (ttf_name_lookup("CFF2", false) != NULL) /* HH */
- tab = ttf_seek_tab("CFF2", 0); /* HH */
- else /* HH */
+ /*tex Copy font file, including the newer variant: */
+ if (ttf_name_lookup("CFF2", false) != NULL)
+ tab = ttf_seek_tab("CFF2", 0);
+ else
tab = ttf_seek_tab("CFF ", 0);
-
- /* TODO the next 0 is a subfont index */
cff = read_cff(ttf_buffer + ttf_curbyte, (long) tab->length, 0);
if (!is_subsetted(fd_cur->fm)) {
- /* not subsetted, just do a copy */
+ /*tex not subsetted, copy: */
for (i = (long) tab->length; i > 0; i--)
strbuf_putchar(pdf->fb, (unsigned char) ttf_getnum(1));
} else {
if (cff != NULL) {
if (cff_is_cidfont(cff)) {
write_cid_cff(pdf, cff, fd_cur);
-#if 0
- for (i = tab->length; i > 0; i--)
- strbuf_putchar(pdf->fb, (unsigned char) ttf_getnum(1));
-#endif
} else {
write_cff(pdf, cff, fd_cur);
}
} else {
- /* not understood, just do a copy */
+ /*tex Just copy: */
for (i = (long) tab->length; i > 0; i--)
strbuf_putchar(pdf->fb, (unsigned char) ttf_getnum(1));
}
diff --git a/Build/source/texk/web2c/luatexdir/font/writetype2.w b/Build/source/texk/web2c/luatexdir/font/writetype2.c
index 81aefb1fb69..b8a74609007 100644
--- a/Build/source/texk/web2c/luatexdir/font/writetype2.w
+++ b/Build/source/texk/web2c/luatexdir/font/writetype2.c
@@ -1,24 +1,23 @@
-% writetype2.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
+/*
+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"
#include "font/writettf.h"
@@ -28,15 +27,22 @@
#include "font/sfnt.h"
#include "font/tt_glyf.h"
-@ forward declaration
-@c
+/*tex
+
+ Forward declarations
+
+*/
+
boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen);
-@ @c
unsigned long cidtogid_obj = 0;
-@ low-level helpers
-@c
+/*tex
+
+ Low-level helpers (a weird place):
+
+*/
+
#define test_loc(l) \
if ((f->loc + l) > f->buflen) { \
normal_error("type 2","the file ended prematurely"); \
@@ -96,55 +102,23 @@ int do_sfnt_read(unsigned char *dest, int len, sfnt * f)
return len;
}
-pdf_obj *pdf_new_stream(void)
-{
- pdf_obj *stream = xmalloc(sizeof(pdf_obj));
- stream->length = 0;
- stream->data = NULL;
- return stream;
-}
+/*tex
-void pdf_add_stream(pdf_obj * stream, unsigned char *buf, long len)
-{
- int i;
- assert(stream != NULL);
- if (stream->data == NULL) {
- stream->data = xmalloc((unsigned) len);
- } else {
- stream->data =
- xrealloc(stream->data, (unsigned) len + (unsigned) stream->length);
- }
- for (i = 0; i < len; i++) {
- *(stream->data + stream->length + i) = *(buf + i);
- }
- stream->length += (unsigned) len;
-}
+ The main function:
-void pdf_release_obj(pdf_obj * stream)
-{
- if (stream != NULL) {
- if (stream->data != NULL) {
- xfree(stream->data);
- }
- xfree(stream);
- }
-}
+*/
-@ The main function.
-@c
boolean writetype2(PDF pdf, fd_entry * fd)
{
int callback_id;
int file_opened = 0;
boolean ret;
-
glyph_tab = NULL;
-
- fd_cur = fd; /* |fd_cur| is global inside \.{writettf.w} */
+ /*tex |fd_cur| is global inside |writettf.c| */
+ fd_cur = fd;
assert(fd_cur->fm != NULL);
assert(is_truetype(fd_cur->fm));
assert(is_included(fd_cur->fm));
-
ttf_curbyte = 0;
ttf_size = 0;
cur_file_name =
@@ -167,20 +141,13 @@ boolean writetype2(PDF pdf, fd_entry * fd)
ttf_read_file();
ttf_close();
}
-
fd_cur->ff_found = true;
-
if (is_subsetted(fd_cur->fm))
report_start_file(filetype_subset,cur_file_name);
else
report_start_file(filetype_font,cur_file_name);
-
- /* here is the real work */
-
+ /*tex Here is the real work done: */
ret = make_tt_subset(pdf, fd, ttf_buffer, ttf_size);
-#if 0
- xfree (dir_tab);
-#endif
xfree(ttf_buffer);
if (is_subsetted(fd_cur->fm))
report_stop_file(filetype_subset);
@@ -190,72 +157,69 @@ boolean writetype2(PDF pdf, fd_entry * fd)
return ret;
}
-@ PDF viewer applications use following tables (CIDFontType 2)
-
-\.{head, hhea, loca, maxp, glyf, hmtx, fpgm, cvt\_, prep}
-
-\rightline{from PDF Ref. v.1.3, 2nd ed.}
+/*tex
- The \.{fpgm}, \.{cvt\_} and \.{prep} tables appears only when TrueType instructions
- requires them. Those tables must be preserved if they exist.
- We use |must_exist| flag to indicate `preserve it if present'
- and to make sure not to cause an error when it does not exist.
+ The \PDF\ viewer applications use following tables for CIDFontType 2: |head|,
+ |hhea|, |loca|, |maxp|, |glyf|, |hmtx|, |fpgm|, |cvt| and |prep|. According
+ to PDF Ref. v.1.3, 2nd ed. The |fpgm\, |cvt| and |prep| tables appears only
+ when TrueType instructions requires them. Those tables must be preserved if
+ they exist. We use |must_exist| flag to indicate `preserve it if present' and
+ to make sure not to cause an error when it does not exist. The |post\ and
+ |name| tables must exist in ordinary TrueType font file, but when a TrueType
+ font is converted to CIDFontType 2 font, those tables are no longer required.
+ The |OS/2| table (required for TrueType font for Windows and OS/2) contains
+ liscencing information, but PDF viewers seems not using them. The |name|
+ table as been added added too (see comments in |writettf.c|.
- \.{post} and \.{name} table must exist in ordinary TrueType font file,
- but when a TrueType font is converted to CIDFontType 2 font, those tables
- are no longer required.
+*/
- The OS/2 table (required for TrueType font for Windows and OS/2) contains
- liscencing information, but PDF viewers seems not using them.
-
- The \.{name} table added. See comments in \.{writettf.w}.
-
-@c
static struct {
const char *name;
int must_exist;
-} required_table[] = {
- {
- "OS/2", 0}, {
- "cmap", 0}, {
- "head", 1}, {
- "hhea", 1}, {
- "loca", 1}, {
- "maxp", 0}, {
- "name", 1}, {
- "glyf", 1}, {
- "hmtx", 1}, {
- "fpgm", 0}, {
- "cvt ", 0}, {
- "prep", 0}, {
- NULL, 0}
-};
+}
+required_table[] = {
+ { "OS/2", 0 },
+ { "cmap", 0 },
+ { "head", 1 },
+ { "hhea", 1 },
+ { "loca", 1 },
+ { "maxp", 0 },
+ { "name", 1 },
+ { "glyf", 1 },
+ { "hmtx", 1 },
+ { "fpgm", 0 },
+ { "cvt ", 0 },
+ { "prep", 0 },
+ { NULL, 0 }
+};
unsigned long ttc_read_offset(sfnt * sfont, int ttc_idx, fd_entry * fd)
{
- /*ULONG version;*/
unsigned long offset = 0;
unsigned long num_dirs = 0;
-
- sfnt_seek_set(sfont, 4); /* skip version tag */
-
- /*version = */(void)sfnt_get_ulong(sfont);
+ /*tex Skip the |ULONG| version tag: */
+ sfnt_seek_set(sfont, 4);
+ /* version = */ (void)sfnt_get_ulong(sfont);
num_dirs = sfnt_get_ulong(sfont);
if (ttc_idx < 0 || ttc_idx > (int) (num_dirs - 1)) {
- formatted_error("type 2","invalid TTC index number %i (0..%i), using index 0 for font %s",
+ formatted_error("type 2",
+ "invalid TTC index number %i (0..%i), using index 0 for font %s",
ttc_idx,(int) (num_dirs - 1),(fd->fm->ps_name ? fd->fm->ps_name : ""));
return 0 ;
}
sfnt_seek_set(sfont, 12 + ttc_idx * 4);
offset = sfnt_get_ulong(sfont);
-
return offset;
}
-@ Creating the subset.
-@c
+/*tex
+
+ Creating the subset.
+*/
+
extern int cidset;
+
boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
{
@@ -270,48 +234,38 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
sfnt *sfont;
pdf_obj *fontfile;
int error = 0;
-
cidtogidmap = NULL;
-
sfont = sfnt_open(buff, buflen);
-
if (sfont->type == SFNT_TYPE_TTC) {
i = ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, (int) i, fd));
} else {
error = sfnt_read_table_directory(sfont, 0);
}
-
if (error < 0) {
normal_error("type 2","parsing the TTF directory fails");
}
-
if (sfont->type == SFNT_TYPE_TTC && sfnt_find_table_pos(sfont, "CFF ")) {
sfnt_close(sfont);
- return false;
+ return false;
}
-
if (is_subsetted(fd->fm)) {
- /* rebuild the glyph tables and create a fresh cidmap */
+ /*tex Rebuild the glyph tables and create a fresh cidmap :*/
glyphs = tt_build_init();
-
last_cid = 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 > last_cid)
last_cid = found->id;
}
-
#ifndef NO_GHOSTSCRIPT_BUG
cidtogidmap = NULL;
#else
cidtogidmap = xmalloc(((last_cid + 1) * 2) * sizeof(unsigned char));
memset(cidtogidmap, 0, (last_cid + 1) * 2);
#endif
-
- /* fill |used_chars| */
+ /*tex Fill |used_chars|: */
used_chars = xmalloc((last_cid + 1) * sizeof(char));
memset(used_chars, 0, (last_cid + 1));
avl_t_init(&t, fd->gl_tree);
@@ -319,56 +273,44 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
found != NULL; found = (glw_entry *) avl_t_next(&t)) {
used_chars[found->id] = 1;
}
-
- /* Map CIDs to GIDs. */
-
- num_glyphs = 1; /* \.{.notdef} */
+ /*tex Map CIDs to GIDs, with |.notdef| in slot zero: */
+ num_glyphs = 1;
for (cid = 1; cid <= (long) last_cid; cid++) {
if (used_chars[cid] == 0)
continue;
gid = (short unsigned) cid;
-
-
#ifndef NO_GHOSTSCRIPT_BUG
gid = tt_add_glyph(glyphs, (USHORT) gid, (USHORT) cid);
#else
gid = tt_add_glyph(glyphs, (USHORT) gid, (USHORT) num_glyphs);
cidtogidmap[2 * cid] = gid >> 8;
cidtogidmap[2 * cid + 1] = gid & 0xff;
-#endif /* |!NO_GHOSTSCRIPT_BUG| */
-
+#endif
num_glyphs++;
}
if (num_glyphs == 1) {
normal_error("type 2","there are no glyphs in the subset");
}
-
if (tt_build_tables(sfont, glyphs, fd) < 0) {
normal_error("type 2","the TTF buffer can't be parsed");
}
-
tt_build_finish(glyphs);
}
-
- /* Create font file */
-
+ /*tex Create the font file: */
for (i = 0; required_table[i].name; i++) {
if (sfnt_require_table(sfont,required_table[i].name, required_table[i].must_exist) < 0) {
normal_error("type 2","some required TrueType table does not exist");
}
}
-
fontfile = sfnt_create_FontFile_stream(sfont);
-
- /* squeeze in the cidgidmap */
+ /*tex The |cidgidmap|: */
if (cidtogidmap != NULL) {
cidtogid_obj = (unsigned long) pdf_create_obj(pdf, obj_type_others, 0);
pdf_begin_obj(pdf, (int) cidtogid_obj, OBJSTM_NEVER);
pdf_begin_dict(pdf);
pdf_dict_add_int(pdf, "Length", ((last_cid + 1) * 2));
pdf_end_dict(pdf);
- assert(0); /* code unused */
pdf_begin_stream(pdf);
pdf_room(pdf, (int) ((last_cid + 1) * 2));
for (i = 0; i < ((int) (last_cid + 1) * 2); i++) {
@@ -377,15 +319,14 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
pdf_end_stream(pdf);
pdf_end_obj(pdf);
}
-
- /* the tff subset */
+ /*tex The tff subset: */
for (i = 0; i < (int) (fontfile->length); i++)
strbuf_putchar(pdf->fb, fontfile->data[i]);
-
pdf_release_obj(fontfile);
-
- /* CIDSet: a table of bits indexed by cid, bytes with high order bit first,
- each (set) bit is a (present) CID. */
+ /*tex
+ |CIDSet| is a table of bits indexed by cid, bytes with high order bit
+ first, each (set) bit is a (present) CID.
+ */
if (is_subsetted(fd->fm)) {
if ((! pdf->omit_cidset) && (pdf->major_version == 1)) {
cidset = pdf_create_obj(pdf, obj_type_others, 0);
@@ -409,23 +350,6 @@ boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
}
}
}
-
- /* TODO other stuff that needs fixing: */
-
- /* DW, W, DW2, and W2 */
-#if 0
- if (opt_flags & CIDFONT_FORCE_FIXEDPITCH) {
- pdf_add_dict(font->fontdict,
- pdf_new_name("DW"), pdf_new_number(1000.0));
- } else {
- add_TTCIDHMetrics(font->fontdict, glyphs, used_chars, cidtogidmap,
- last_cid);
- if (v_used_chars)
- add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, cidtogidmap,
- last_cid);
- }
-#endif
-
xfree(used_chars);
sfnt_close(sfont);
return true;
diff --git a/Build/source/texk/web2c/luatexdir/image/pdftoepdf.c b/Build/source/texk/web2c/luatexdir/image/pdftoepdf.c
new file mode 100644
index 00000000000..b29493b073d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/image/pdftoepdf.c
@@ -0,0 +1,1049 @@
+/*
+pdftoepdf.w
+
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+Copyright 2006-2015 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/>.
+*/
+
+#define __STDC_FORMAT_MACROS /* for PRId64 etc. */
+
+#include "image/epdf.h"
+
+/* Conflict with pdfgen.h */
+
+#ifndef pdf_out
+
+#define pdf_out(pdf, A) do { pdf_room(pdf, 1); *(pdf->buf->p++) = A; } while (0)
+
+#define pdf_check_space(pdf) do { \
+ if (pdf->cave > 0) { \
+ pdf_out(pdf, ' '); \
+ pdf->cave = 0; \
+ } \
+} while (0)
+
+#define pdf_set_space(pdf) \
+ pdf->cave = 1;
+
+#define pdf_reset_space(pdf) \
+ pdf->cave = 0;
+
+#endif
+
+/* Maintain AVL tree of all PDF files for embedding */
+
+static avl_table *PdfDocumentTree = NULL;
+
+/* AVL sort PdfDocument into PdfDocumentTree by file_path */
+
+static int CompPdfDocument(const void *pa, const void *pb, void *p )
+{
+ return strcmp(((const PdfDocument *) pa)->file_path, ((const PdfDocument *) pb)->file_path);
+}
+
+/* Returns pointer to PdfDocument structure for PDF file. */
+
+static PdfDocument *findPdfDocument(char *file_path)
+{
+ PdfDocument *pdf_doc, tmp;
+ if (file_path == NULL) {
+ normal_error("pdf backend","empty filename when loading pdf file");
+ } else if (PdfDocumentTree == NULL) {
+ return NULL;
+ }
+ tmp.file_path = file_path;
+ pdf_doc = (PdfDocument *) avl_find(PdfDocumentTree, &tmp);
+ return pdf_doc;
+}
+
+#define PDF_CHECKSUM_SIZE 32
+
+static char *get_file_checksum(const char *a, file_error_mode fe)
+{
+ struct stat finfo;
+ char *ck = NULL;
+ if (stat(a, &finfo) == 0) {
+ off_t size = finfo.st_size;
+ time_t mtime = finfo.st_mtime;
+ ck = (char *) malloc(PDF_CHECKSUM_SIZE);
+ if (ck == NULL)
+ formatted_error("pdf inclusion","out of memory while processing '%s'", a);
+ snprintf(ck, PDF_CHECKSUM_SIZE, "%" PRIu64 "_%" PRIu64, (uint64_t) size,(uint64_t) mtime);
+ } else {
+ switch (fe) {
+ case FE_FAIL:
+ formatted_error("pdf inclusion","could not stat() file '%s'", a);
+ break;
+ case FE_RETURN_NULL:
+ if (ck != NULL)
+ free(ck);
+ ck = NULL;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return ck;
+}
+
+static char *get_stream_checksum (const char *str, unsigned long long str_size){
+ /* http://www.cse.yorku.ca/~oz/hash.html */
+ /* djb2 */
+ unsigned long hash ;
+ char *ck = NULL;
+ unsigned int i;
+ hash = 5381;
+ ck = (char *) malloc(STRSTREAM_CHECKSUM_SIZE+1);
+ if (ck == NULL)
+ normal_error("pdf inclusion","out of memory while processing a memstream");
+ for(i=0; i<(unsigned int)(str_size); i++) {
+ hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + str[i] */
+ }
+ snprintf(ck,STRSTREAM_CHECKSUM_SIZE+1,"%lx",hash);
+ ck[STRSTREAM_CHECKSUM_SIZE]='\0';
+ return ck;
+}
+
+/*
+ Returns pointer to PdfDocument structure for PDF file.
+ Creates a new PdfDocument structure if it doesn't exist yet.
+ When fe = FE_RETURN_NULL, the function returns NULL in error case.
+*/
+
+PdfDocument *refPdfDocument(const char *file_path, file_error_mode fe, const char *userpassword, const char *ownerpassword)
+{
+ char *checksum, *path_copy;
+ PdfDocument *pdf_doc;
+ ppdoc *pdfe = NULL;
+ int new_flag = 0;
+ if ((checksum = get_file_checksum(file_path, fe)) == NULL) {
+ return (PdfDocument *) NULL;
+ }
+ path_copy = xstrdup(file_path);
+ if ((pdf_doc = findPdfDocument(path_copy)) == NULL) {
+ new_flag = 1;
+ pdf_doc = (PdfDocument*) xmalloc(sizeof( PdfDocument));
+ pdf_doc->file_path = path_copy;
+ pdf_doc->checksum = checksum;
+ pdf_doc->pdfe = NULL;
+ pdf_doc->inObjList = NULL;
+ pdf_doc->ObjMapTree = NULL;
+ pdf_doc->occurences = 0; /* 0 = unreferenced */
+ pdf_doc->pc = 0;
+ pdf_doc->is_mem = 0;
+ } else {
+ if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
+ formatted_error("pdf inclusion","file has changed '%s'", file_path);
+ }
+ free(checksum);
+ free(path_copy);
+ }
+ if (pdf_doc->pdfe == NULL) {
+ pdfe = ppdoc_load(file_path);
+ pdf_doc->pc++;
+ /* todo: check if we might print the document */
+ if (pdfe == NULL) {
+ switch (fe) {
+ case FE_FAIL:
+ normal_error("pdf inclusion","reading image failed");
+ break;
+ case FE_RETURN_NULL:
+ if (pdf_doc->pdfe != NULL) {
+ ppdoc_free(pdfe);
+ pdf_doc->pdfe = NULL;
+ }
+ /* delete docName */
+ if (new_flag == 1) {
+ if (pdf_doc->file_path != NULL)
+ free(pdf_doc->file_path);
+ if (pdf_doc->checksum != NULL)
+ free(pdf_doc->checksum);
+ free(pdf_doc);
+ }
+ return (PdfDocument *) NULL;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ if (pdfe != NULL) {
+ if (ppdoc_crypt_status(pdfe) < 0) {
+ ppdoc_crypt_pass(pdfe,userpassword,strlen(userpassword),NULL,0);
+ }
+ if (ppdoc_crypt_status(pdfe) < 0) {
+ ppdoc_crypt_pass(pdfe,NULL,0,ownerpassword,strlen(ownerpassword));
+ }
+ if (ppdoc_crypt_status(pdfe) < 0) {
+ formatted_error("pdf inclusion","the pdf file '%s' is encrypted, provide proper passwords",file_path);
+ }
+ }
+ pdf_doc->pdfe = pdfe;
+ }
+ /* PDF file could be opened without problems, checksum ok. */
+ if (PdfDocumentTree == NULL)
+ PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
+ if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
+ avl_probe(PdfDocumentTree, pdf_doc);
+ }
+ pdf_doc->occurences++;
+ return pdf_doc;
+}
+
+/*
+ Returns pointer to PdfDocument structure for a PDF stream in memory of streamsize
+ dimension. As before, creates a new PdfDocument structure if it doesn't exist yet
+ with file_path = file_id
+*/
+
+PdfDocument *refMemStreamPdfDocument(char *docstream, unsigned long long streamsize,const char *file_id)
+{
+ char *checksum;
+ char *file_path;
+ PdfDocument *pdf_doc;
+ ppdoc *pdfe = NULL;
+ size_t cnt = 0;
+ checksum = get_stream_checksum(docstream, streamsize);
+ cnt = strlen(file_id);
+ file_path = (char *) malloc(cnt+STREAM_URI_LEN+STRSTREAM_CHECKSUM_SIZE+1); /* 1 for \0 */
+ strcpy(file_path,STREAM_URI);
+ strcat(file_path,file_id);
+ strcat(file_path,checksum);
+ file_path[cnt+STREAM_URI_LEN+STRSTREAM_CHECKSUM_SIZE]='\0';
+ if ((pdf_doc = findPdfDocument(file_path)) == NULL) {
+ /*new_flag = 1;*/
+ pdf_doc = (PdfDocument*) xmalloc(sizeof( PdfDocument));
+ pdf_doc->file_path = file_path;
+ pdf_doc->checksum = checksum;
+ pdf_doc->pdfe = NULL;
+ pdf_doc->inObjList = NULL;
+ pdf_doc->ObjMapTree = NULL;
+ pdf_doc->occurences = 0; /* 0 = unreferenced */
+ pdf_doc->pc = 0;
+ pdf_doc->is_mem = 1;
+ pdf_doc->memstream = docstream;
+ } else {
+ /* As is now, checksum is in file_path, so this check should be useless. */
+ if (strncmp(pdf_doc->checksum, checksum, STRSTREAM_CHECKSUM_SIZE) != 0) {
+ formatted_error("pdf inclusion","stream has changed '%s'", file_path);
+ }
+ free(file_path);
+ free(checksum);
+ }
+ if (pdf_doc->pdfe == NULL) {
+ pdfe = ppdoc_mem(docstream, streamsize);
+ pdf_doc->pc++;
+ if (pdfe == NULL) {
+ normal_error("pdf inclusion","reading pdf Stream failed");
+ }
+ pdf_doc->pdfe = pdfe;
+ }
+ /* PDF file could be opened without problems, checksum ok. */
+ if (PdfDocumentTree == NULL)
+ PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
+ if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
+ avl_probe(PdfDocumentTree, pdf_doc);
+ }
+ pdf_doc->occurences++;
+ return pdf_doc;
+}
+
+/*
+ AVL sort ObjMap into ObjMapTree by object number and generation keep the ObjMap
+ struct small, as these are accumulated until the end
+*/
+
+typedef struct ObjMap ObjMap ;
+
+struct ObjMap {
+ ppref * in;
+ int out_num;
+};
+
+static int CompObjMap(const void *pa, const void *pb, void *p)
+{
+ const ppref *a = (((const ObjMap *) pa)->in);
+ const ppref *b = (((const ObjMap *) pb)->in);
+ if (a->number > b->number)
+ return 1;
+ else if (a->number < b->number)
+ return -1;
+ else if (a->version == b->version)
+ return 0;
+ else if (a->version < b->version)
+ return -1;
+ return 1;
+}
+
+static ObjMap *findObjMap(PdfDocument * pdf_doc, ppref * in)
+{
+ ObjMap *obj_map, tmp;
+ if (pdf_doc->ObjMapTree == NULL)
+ return NULL;
+ tmp.in = in;
+ obj_map = (ObjMap *) avl_find(pdf_doc->ObjMapTree, &tmp);
+ return obj_map;
+}
+
+static void addObjMap(PdfDocument * pdf_doc, ppref * in, int out_num)
+{
+ ObjMap *obj_map = NULL;
+ if (pdf_doc->ObjMapTree == NULL)
+ pdf_doc->ObjMapTree = avl_create(CompObjMap, NULL, &avl_xallocator);
+ obj_map = (ObjMap*)xmalloc(sizeof(ObjMap));
+ obj_map->in = in;
+ obj_map->out_num = out_num;
+ avl_probe(pdf_doc->ObjMapTree, obj_map);
+}
+
+/*
+ When copying the Resources of the selected page, all objects are
+ copied recursively top-down. The findObjMap() function checks if an
+ object has already been copied; if so, instead of copying just the
+ new object number will be referenced. The ObjMapTree guarantees,
+ that during the entire LuaTeX run any object from any embedded PDF
+ file will end up max. once in the output PDF file. Indirect objects
+ are not fetched during copying, but get a new object number from
+ LuaTeX and then will be appended into a linked list.
+*/
+
+static int addInObj(PDF pdf, PdfDocument * pdf_doc, ppref * ref)
+{
+ ObjMap *obj_map;
+ InObj *p, *q, *n;
+ if (ref->number == 0) {
+ normal_error("pdf inclusion","reference to invalid object (broken pdf)");
+ }
+ if ((obj_map = findObjMap(pdf_doc, ref)) != NULL) {
+ return obj_map->out_num;
+ }
+ n = (InObj*)xmalloc(sizeof(InObj));
+ n->ref = ref;
+ n->next = NULL;
+ n->num = pdf_create_obj(pdf, obj_type_others, 0);
+ addObjMap(pdf_doc, ref, n->num);
+ if (pdf_doc->inObjList == NULL) {
+ pdf_doc->inObjList = n;
+ } else {
+ /*
+ It is important to add new objects at the end of the list,
+ because new objects are being added while the list is being
+ written out by writeRefs().
+ */
+ for (p = pdf_doc->inObjList; p != NULL; p = p->next)
+ q = p;
+ q->next = n;
+ }
+ return n->num;
+}
+
+static void copyObject(PDF, PdfDocument *, ppobj *);
+
+static void copyString(PDF pdf, ppstring str)
+{
+ pdf_check_space(pdf);
+ switch (ppstring_type((void *)(str))) {
+ case PPSTRING_PLAIN:
+ pdf_out(pdf, '(');
+ pdf_out_block(pdf, (const char *) str, ppstring_size((void *)(str)));
+ pdf_out(pdf, ')');
+ break;
+ case PPSTRING_BASE16:
+ pdf_out(pdf, '<');
+ pdf_out_block(pdf, (const char *) str, ppstring_size((void *)(str)));
+ pdf_out(pdf, '>');
+ break;
+ case PPSTRING_BASE85:
+ pdf_out(pdf, '<');
+ pdf_out(pdf, '~');
+ pdf_out_block(pdf, (const char *) str, ppstring_size((void *)(str)));
+ pdf_out(pdf, '~');
+ pdf_out(pdf, '>');
+ break;
+ }
+ pdf_set_space(pdf);
+}
+
+/*
+static void copyName(PDF pdf, ppname *name)
+{
+ pdf_add_name(pdf, (const char *) name);
+}
+*/
+
+static void copyArray(PDF pdf, PdfDocument * pdf_doc, pparray * array)
+{
+ int i;
+ int n = array->size;
+ pdf_begin_array(pdf);
+ for (i=0; i<n; ++i) {
+ copyObject(pdf, pdf_doc, pparray_at(array,i));
+ }
+ pdf_end_array(pdf);
+}
+
+static void copyDict(PDF pdf, PdfDocument * pdf_doc, ppdict *dict)
+{
+ int i;
+ int n = dict->size;
+ pdf_begin_dict(pdf);
+ for (i=0; i<n; ++i) {
+ pdf_add_name(pdf, (const char *) ppdict_key(dict,i));
+ copyObject(pdf, pdf_doc, ppdict_at(dict,i));
+ }
+ pdf_end_dict(pdf);
+}
+
+static void copyStreamStream(PDF pdf, ppstream * stream, int decode)
+{
+ uint8_t *data = NULL;
+ size_t size = 0;
+ if (0) {
+ for (data = ppstream_first(stream, &size, decode); data != NULL; data = ppstream_next(stream, &size)) {
+ pdf_out_block(pdf, (const char *) data, size);
+ }
+ } else {
+ data = ppstream_all(stream,&size,decode);
+ if (data != NULL) {
+ pdf_out_block(pdf, (const char *) data, size);
+ }
+ }
+ ppstream_done(stream);
+}
+
+static void copyStream(PDF pdf, PdfDocument * pdf_doc, ppstream * stream)
+{
+ ppdict *dict = stream->dict; /* bug in: stream_dict(stream) */
+ if (pdf->compress_level == 0 || pdf->recompress) {
+ const char *ignoredkeys[] = {
+ "Filter", "Decode", "Length", "DL", NULL
+ };
+ int i;
+ int n = dict->size;
+ pdf_begin_dict(pdf);
+ for (i=0; i<n; ++i) {
+ const char *key = ppdict_key(dict,i);
+ int okay = 1;
+ int k;
+ for (k = 0; ignoredkeys[k] != NULL; k++) {
+ if (strcmp(key,ignoredkeys[k]) == 0) {
+ okay = 0;
+ break;
+ }
+ }
+ if (okay) {
+ pdf_add_name(pdf, key);
+ copyObject(pdf, pdf_doc, ppdict_at(dict,i));
+ }
+ }
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ copyStreamStream(pdf, stream, 1);
+ pdf_end_stream(pdf);
+ } else {
+ copyDict(pdf, pdf_doc, dict);
+ pdf_begin_stream(pdf);
+ copyStreamStream(pdf, stream, 0);
+ pdf_end_stream(pdf);
+ }
+}
+
+static void copyObject(PDF pdf, PdfDocument * pdf_doc, ppobj * obj)
+{
+ switch (obj->type) {
+ case PPNULL:
+ pdf_add_null(pdf);
+ break;
+ case PPBOOL:
+ pdf_add_bool(pdf,obj->integer); /* ppobj_get_bool_value(obj) */
+ break;
+ case PPINT:
+ pdf_add_int(pdf,obj->integer); /* ppobj_get_int_value(obj) */
+ break;
+ case PPNUM:
+ pdf_add_real(pdf,obj->number); /* ppobj_get_num_value(obj) */
+ break;
+ case PPNAME:
+ pdf_add_name(pdf, (const char *) obj->name); /* ppobj_get_name(obj) */
+ break;
+ case PPSTRING:
+ copyString(pdf, obj->string); /* ppobj_get_string(obj) */
+ break;
+ case PPARRAY:
+ copyArray(pdf, pdf_doc, obj->array); /* ppobj_get_array(obj) */
+ break;
+ case PPDICT:
+ copyDict(pdf, pdf_doc, obj->dict); /* ppobj_get_dict(obj) */
+ break;
+ case PPSTREAM:
+ copyStream(pdf, pdf_doc, obj->stream); /* ppobj_get_stream(obj) */
+ break;
+ case PPREF:
+ pdf_add_ref(pdf, addInObj(pdf, pdf_doc, obj->ref)); /* ppobj_get_ref(obj) */
+ break;
+ default:
+ break;
+ }
+}
+
+static void writeRefs(PDF pdf, PdfDocument * pdf_doc)
+{
+ InObj *r, *n;
+ ppobj * obj;
+ for (r = pdf_doc->inObjList; r != NULL;) {
+ obj = ppref_obj(r->ref);
+ if (obj->type == PPSTREAM)
+ pdf_begin_obj(pdf, r->num, OBJSTM_NEVER);
+ else
+ pdf_begin_obj(pdf, r->num, 2);
+ copyObject(pdf, pdf_doc, obj);
+ pdf_end_obj(pdf);
+ n = r->next;
+ free(r);
+ r = n;
+ pdf_doc->inObjList = n;
+ }
+}
+
+/* get the pagebox coordinates according to the pagebox_spec */
+
+static void somebox(ppdict *page, const char * key, pprect * box)
+{
+ pprect * r = ppdict_get_box(page, key, box);
+ if (r != NULL) {
+ box->lx = r->lx;
+ box->ly = r->ly;
+ box->rx = r->rx;
+ box->ry = r->ry;
+ }
+}
+
+static void get_pagebox(ppdict * page, int pagebox_spec, pprect * box)
+{
+ box->lx = box->rx = box->ly = box->ry = 0;
+ somebox(page,"MediaBox",box);
+ if (pagebox_spec == PDF_BOX_SPEC_MEDIA) {
+ return;
+ }
+ somebox(page,"CropBox",box);
+ if (pagebox_spec == PDF_BOX_SPEC_CROP) {
+ return;
+ }
+ switch (pagebox_spec) {
+ case PDF_BOX_SPEC_BLEED:
+ somebox(page,"BleedBox",box);
+ break;
+ case PDF_BOX_SPEC_TRIM:
+ somebox(page,"TrimBox",box);
+ break;
+ case PDF_BOX_SPEC_ART:
+ somebox(page,"ArtBox",box);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ Reads various information about the PDF and sets it up for later inclusion.
+ This will fail if the PDF version of the PDF is higher than minor_pdf_version_wanted
+ or page_name is given and can not be found. It makes no sense to give page_name and
+ page_num. Returns the page number.
+*/
+
+static ppdict * get_pdf_page_dict(ppdoc *pdfe, int n)
+{
+ ppref *r;
+ int i;
+ for (r=ppdoc_first_page(pdfe), i=1; r != NULL; r = ppdoc_next_page(pdfe), ++i) {
+ if (i == n) {
+ return ppref_obj(r)->dict;
+ }
+ }
+ return NULL;
+}
+
+// static ppdict * get_pdf_page_dict(ppdoc *pdfe, int n)
+// {
+// return ppref_obj(ppdoc_page(pdfe,n))->dict;
+// }
+
+void read_pdf_info(image_dict * idict)
+{
+ PdfDocument *pdf_doc = NULL;
+ ppdoc * pdfe = NULL;
+ ppdict *pageDict, *groupDict;
+ pprect pagebox;
+ ppint rotate = 0;
+ int pdf_major_version_found = 1;
+ int pdf_minor_version_found = 3;
+ float xsize, ysize, xorig, yorig;
+ if (img_type(idict) == IMG_TYPE_PDF) {
+ pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL, img_userpassword(idict), img_ownerpassword(idict));
+ } else if (img_type(idict) == IMG_TYPE_PDFMEMSTREAM) {
+ pdf_doc = findPdfDocument(img_filepath(idict)) ;
+ if (pdf_doc == NULL )
+ normal_error("pdf inclusion", "memstream not initialized");
+ if (pdf_doc->pdfe == NULL)
+ normal_error("pdf inclusion", "memstream document is empty");
+ pdf_doc->occurences++;
+ } else {
+ normal_error("pdf inclusion","unknown document");
+ }
+ pdfe = pdf_doc->pdfe;
+ /*
+ Check PDF version. This works only for PDF 1.x but since any versions of
+ PDF newer than 1.x will not be backwards compatible to PDF 1.x, we will
+ then have to changed drastically anyway.
+ */
+ pdf_major_version_found = ppdoc_version_number(pdfe,&pdf_minor_version_found);
+ if ((100 * pdf_major_version_found + pdf_major_version_found) > (100 * img_pdfmajorversion(idict) + img_pdfminorversion(idict))) {
+ const char *msg = "PDF inclusion: found PDF version '%d.%d', but at most version '%d.%d' allowed";
+ if (img_errorlevel(idict) > 0) {
+ formatted_error("pdf inclusion",msg, pdf_major_version_found, pdf_minor_version_found, img_pdfmajorversion(idict), img_pdfminorversion(idict));
+ } else {
+ formatted_warning("pdf inclusion",msg, pdf_major_version_found, pdf_minor_version_found, img_pdfmajorversion(idict), img_pdfminorversion(idict));
+ }
+ }
+ img_totalpages(idict) = ppdoc_page_count(pdfe);
+ if (img_pagename(idict)) {
+ /*
+ get page by name is obsolete
+ */
+ normal_error("pdf inclusion","named pages are not supported");
+ } else {
+ /*
+ get page by number
+ */
+ if (img_pagenum(idict) <= 0
+ || img_pagenum(idict) > img_totalpages(idict))
+ formatted_error("pdf inclusion","required page '%i' does not exist",(int) img_pagenum(idict));
+ }
+ /*
+ get the required page
+ */
+ pageDict = get_pdf_page_dict(pdfe,img_pagenum(idict));
+ /*
+ get the pagebox coordinates (media, crop,...) to use
+ */
+ get_pagebox(pageDict, img_pagebox(idict), &pagebox);
+ if (pagebox.rx > pagebox.lx) {
+ xorig = pagebox.lx;
+ xsize = pagebox.rx - pagebox.lx;
+ } else {
+ xorig = pagebox.rx;
+ xsize = pagebox.lx - pagebox.rx;
+ }
+ if (pagebox.ry > pagebox.ly) {
+ yorig = pagebox.ly;
+ ysize = pagebox.ry - pagebox.ly;
+ } else {
+ yorig = pagebox.ry;
+ ysize = pagebox.ly - pagebox.ry;
+ }
+ /*
+ The following 4 parameters are raw. Do _not_ modify by /Rotate!
+ */
+ img_xsize(idict) = bp2sp(xsize);
+ img_ysize(idict) = bp2sp(ysize);
+ img_xorig(idict) = bp2sp(xorig);
+ img_yorig(idict) = bp2sp(yorig);
+ /*
+ Handle /Rotate parameter. Only multiples of 90 deg. are allowed (PDF Ref. v1.3,
+ p. 78). We also accept negative angles. Beware: PDF counts clockwise!
+ */
+ if (ppdict_get_int(pageDict, "Rotate", &rotate)) {
+ switch ((((int)rotate % 360) + 360) % 360) {
+ case 0:
+ img_rotation(idict) = 0;
+ break;
+ case 90:
+ img_rotation(idict) = 3;
+ break;
+ case 180:
+ img_rotation(idict) = 2;
+ break;
+ case 270:
+ img_rotation(idict) = 1;
+ break;
+ default:
+ formatted_warning("pdf inclusion","/Rotate parameter in PDF file not multiple of 90 degrees");
+ }
+ }
+ /*
+ currently unused info whether PDF contains a /Group
+ */
+ groupDict = ppdict_get_dict(pageDict, "Group");
+ if (groupDict != NULL) {
+ img_set_group(idict);
+ }
+ /*
+ LuaTeX pre 0.85 versions did this:
+
+ if (readtype == IMG_CLOSEINBETWEEN) {
+ unrefPdfDocument(img_filepath(idict));
+ }
+
+ and also unref'd in the finalizer so we got an extra unrefs when garbage was
+ collected. However it is more efficient to keep the file open so we do that
+ now. The (slower) alternative is to unref here (which in most cases forcing a
+ close of the file) but then we must not call flush_pdf_info.
+
+ A close (unref) can be forced by nilling the dict object at the lua end and
+ forcing a collectgarbage("collect") after that.
+
+ */
+ if (! img_keepopen(idict)) {
+ unrefPdfDocument(img_filepath(idict));
+ }
+}
+
+void flush_pdf_info(image_dict * idict)
+{
+ if (img_keepopen(idict)) {
+ unrefPdfDocument(img_filepath(idict));
+ }
+}
+
+/*
+ Write the current epf_doc. Here the included PDF is copied, so most errors
+ that can happen during PDF inclusion will arise here.
+*/
+
+void write_epdf(PDF pdf, image_dict * idict, int suppress_optional_info)
+{
+ PdfDocument *pdf_doc = NULL;
+ ppdoc *pdfe = NULL;
+ ppdict *pageDict, *infoDict;
+ ppobj *obj, *content, *resources;
+ pprect pagebox;
+ int i;
+ double bbox[4];
+ const char *pagedictkeys[] = {
+ "Group", "LastModified", "Metadata", "PieceInfo", "SeparationInfo", NULL
+ };
+ /*
+ open PDF file
+ */
+ if (img_type(idict) == IMG_TYPE_PDF) {
+ pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL, img_userpassword(idict), img_ownerpassword(idict));
+ } else if (img_type(idict) == IMG_TYPE_PDFMEMSTREAM) {
+ pdf_doc = findPdfDocument(img_filepath(idict)) ;
+ pdf_doc->occurences++;
+ } else {
+ normal_error("pdf inclusion","unknown document");
+ }
+ pdfe = pdf_doc->pdfe;
+ pageDict = get_pdf_page_dict(pdfe,img_pagenum(idict));
+ /*
+ write the Page header
+ */
+ pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "XObject");
+ pdf_dict_add_name(pdf, "Subtype", "Form");
+ pdf_dict_add_int(pdf, "FormType", 1);
+ /*
+ write additional information
+ */
+ pdf_dict_add_img_filename(pdf, idict);
+ if ((suppress_optional_info & 4) == 0) {
+ pdf_dict_add_int(pdf, "PTEX.PageNumber", (int) img_pagenum(idict));
+ }
+ if ((suppress_optional_info & 8) == 0) {
+ infoDict = ppdoc_info(pdfe);
+ if (infoDict != NULL) {
+ /* todo : check this
+ pdf_dict_add_ref(pdf, "PTEX.InfoDict", addInObj(pdf, pdf_doc, infoDict));
+ */
+ pdf_add_name(pdf, "PTEX.InfoDict");
+ copyDict(pdf, pdf_doc, infoDict);
+ }
+ }
+ if (img_is_bbox(idict)) {
+ bbox[0] = sp2bp(img_bbox(idict)[0]);
+ bbox[1] = sp2bp(img_bbox(idict)[1]);
+ bbox[2] = sp2bp(img_bbox(idict)[2]);
+ bbox[3] = sp2bp(img_bbox(idict)[3]);
+ } else {
+ /*
+ get the pagebox coordinates (media, crop,...) to use.
+ */
+ get_pagebox(pageDict, img_pagebox(idict), &pagebox);
+ bbox[0] = pagebox.lx;
+ bbox[1] = pagebox.ly;
+ bbox[2] = pagebox.rx;
+ bbox[3] = pagebox.ry;
+ }
+ pdf_add_name(pdf, "BBox");
+ pdf_begin_array(pdf);
+ pdf_add_real(pdf, bbox[0]);
+ pdf_add_real(pdf, bbox[1]);
+ pdf_add_real(pdf, bbox[2]);
+ pdf_add_real(pdf, bbox[3]);
+ pdf_end_array(pdf);
+ /*
+ Now all relevant parts of the Page dictionary are copied. Metadata validity
+ check is needed(as a stream it must be indirect).
+ */
+ obj = ppdict_get_obj(pageDict, "Metadata");
+ if (obj != NULL && obj->type != PPREF) {
+ formatted_warning("pdf inclusion","/Metadata must be indirect object");
+ }
+ /*
+ copy selected items in Page dictionary
+ */
+ for (i = 0; pagedictkeys[i] != NULL; i++) {
+ obj = ppdict_rget_obj(pageDict, pagedictkeys[i]);
+ if (obj != NULL) {
+ pdf_add_name(pdf, pagedictkeys[i]);
+ /*
+ preserves indirection
+ */
+ copyObject(pdf, pdf_doc, obj);
+ }
+ }
+ resources = ppdict_rget_obj(pageDict, "Resources");
+ if (resources == NULL) {
+ /*
+ If there are no Resources in the Page dict of the embedded page,
+ try to inherit the Resources from the Pages tree of the embedded
+ PDF file, climbing up the tree until the Resources are found.
+ (This fixes a problem with Scribus 1.3.3.14.)
+ */
+ obj = ppdict_rget_obj(pageDict, "Parent");
+ while (obj != NULL && obj->type == PPDICT) {
+ resources = ppdict_rget_obj(obj->dict, "Resources");
+ if (resources != NULL) {
+ break;
+ }
+ obj = ppdict_get_obj(obj->dict, "Parent");
+ }
+ }
+ if (resources != NULL) {
+ pdf_add_name(pdf, "Resources");
+ copyObject(pdf, pdf_doc, resources);
+ } else {
+ formatted_warning("pdf inclusion","Page /Resources missing");
+ }
+ /*
+ User supplied entries.
+ */
+ if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) {
+ pdf_printf(pdf, "\n%s\n", img_attr(idict));
+ }
+ /*
+ Write the Page contents.
+ */
+ content = ppdict_rget_obj(pageDict, "Contents");
+ if (content->type == PPSTREAM) {
+ if (pdf->compress_level == 0 || pdf->recompress) {
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ copyStreamStream(pdf, content->stream,1); /* decompress */
+ } else {
+ /* copies compressed stream */
+ ppstream * stream = content->stream;
+ ppdict *streamDict = stream->dict; /* */
+ obj = ppdict_rget_obj(streamDict, "Length");
+ if (obj != NULL) {
+ pdf_add_name(pdf, "Length");
+ copyObject(pdf, pdf_doc, obj);
+ obj = ppdict_rget_obj(streamDict, "Filter");
+ if (obj != NULL) {
+ pdf_add_name(pdf, "Filter");
+ copyObject(pdf, pdf_doc, obj);
+ /* the next one is irrelevant, only for inline images: */
+ /*
+ obj = ppdict_rget_obj(streamDict, "DecodeParms");
+ if (obj != NULL) {
+ pdf_add_name(pdf, "DecodeParms");
+ copyObject(pdf, pdf_doc, obj);
+ }
+ */
+ }
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ copyStreamStream(pdf, stream,0);
+ } else {
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ copyStreamStream(pdf, stream,1);
+ }
+ }
+ pdf_end_stream(pdf);
+ } else if (content->type == PPARRAY) {
+ /* listens to compresslevel */
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ {
+ int i;
+ int b = 0;
+ int n = content->array->size;
+ for (i=0; i<n; ++i) {
+ ppobj *o = pparray_at(content->array,i);
+ while (o != NULL && o->type == PPREF) {
+ o = ppref_obj((ppref *) o->ref);
+ }
+ if (o != NULL && o->type == PPSTREAM) {
+ if (b) {
+ /*
+ Put a space between streams to be on the safe side (streams
+ should have a trailing space here, but one never knows)
+ */
+ pdf_out(pdf, ' ');
+ } else {
+ b = 1;
+ }
+ copyStreamStream(pdf, (ppstream *) o->stream,1);
+ }
+ }
+ }
+ pdf_end_stream(pdf);
+ } else {
+ /*
+ the contents are optional, but we need to include an empty stream
+ */
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ pdf_end_stream(pdf);
+ }
+ pdf_end_obj(pdf);
+ /*
+ write out all indirect objects
+ */
+ writeRefs(pdf, pdf_doc);
+ /*
+ unrefPdfDocument() must come after freeing whatever is used
+
+ */
+ if (! img_keepopen(idict)) {
+ unrefPdfDocument(img_filepath(idict));
+ }
+}
+
+/* a special simple case of inclusion, e.g. an appearance stream */
+
+int write_epdf_object(PDF pdf, image_dict * idict, int n)
+{
+ int num = 0 ;
+ if (img_type(idict) != IMG_TYPE_PDF) {
+ normal_error("pdf inclusion","unknown document");
+ } else {
+ PdfDocument * pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL, img_userpassword(idict), img_ownerpassword(idict));
+ ppdoc * pdfe = pdf_doc->pdfe;
+ ppref * ref = ppxref_find(ppdoc_xref(pdfe), (ppuint) n);
+ if (ref != NULL) {
+ ppobj *obj;
+ num = pdf->obj_count++;
+ obj = ppref_obj(ref);
+ if (obj->type == PPSTREAM) {
+ pdf_begin_obj(pdf, num, OBJSTM_NEVER);
+ } else {
+ pdf_begin_obj(pdf, num, 2);
+ }
+ copyObject(pdf, pdf_doc, obj);
+ pdf_end_obj(pdf);
+ writeRefs(pdf, pdf_doc);
+ }
+ if (! img_keepopen(idict)) {
+ unrefPdfDocument(img_filepath(idict));
+ }
+ }
+ return num;
+}
+
+/* Deallocate a PdfDocument with all its resources. */
+
+static void deletePdfDocumentPdfDoc(PdfDocument * pdf_doc)
+{
+ InObj *r, *n;
+ /* this may be probably needed for an emergency destroyPdfDocument() */
+ for (r = pdf_doc->inObjList; r != NULL; r = n) {
+ n = r->next;
+ free(r);
+ }
+ if (pdf_doc->pdfe != NULL) {
+ ppdoc_free(pdf_doc->pdfe);
+ pdf_doc->pdfe = NULL;
+ }
+ if (pdf_doc->memstream != NULL) {
+ /* pplib does this: free(pdf_doc->memstream); */
+ pdf_doc->memstream = NULL;
+ }
+ /* pdf_doc->pc++; */
+ pdf_doc->pc = 0;
+}
+
+static void destroyPdfDocument(void *pa, void * p)
+{
+ PdfDocument *pdf_doc = (PdfDocument *) pa;
+ deletePdfDocumentPdfDoc(pdf_doc);
+ /* TODO: delete rest of pdf_doc */
+}
+
+/*
+ Called when an image has been written and its resources in image_tab are
+ freed and it's not referenced anymore.
+*/
+
+void unrefPdfDocument(char *file_path)
+{
+ PdfDocument *pdf_doc = findPdfDocument(file_path);
+ if (pdf_doc == NULL) {
+ /* we're ok */
+ } else if (pdf_doc->occurences > 0) {
+ pdf_doc->occurences--;
+ if (pdf_doc->occurences == 0) {
+ deletePdfDocumentPdfDoc(pdf_doc);
+ }
+ } else {
+ /*
+ We either have a mismatch in ref and unref or we're somehow out of sync
+ which can happen when we mess with the same file in lua and tex.
+ */
+ formatted_warning("pdf inclusion","there can be a mismatch in opening and closing file '%s'",file_path);
+ }
+}
+
+/*
+ For completeness, but it isn't currently used (unreferencing is done by mean
+ of file_path.
+*/
+
+void unrefMemStreamPdfDocument(char *file_id)
+{
+ (void) unrefPdfDocument(file_id);
+
+}
+
+/*
+ Called when PDF embedding system is finalized. We now deallocate all remaining
+ PdfDocuments.
+*/
+
+void epdf_free(void)
+{
+ if (PdfDocumentTree != NULL)
+ avl_destroy(PdfDocumentTree, destroyPdfDocument);
+ PdfDocumentTree = NULL;
+}
diff --git a/Build/source/texk/web2c/luatexdir/image/pdftoepdf.w b/Build/source/texk/web2c/luatexdir/image/pdftoepdf.w
deleted file mode 100644
index d69795926e5..00000000000
--- a/Build/source/texk/web2c/luatexdir/image/pdftoepdf.w
+++ /dev/null
@@ -1,972 +0,0 @@
-% pdftoepdf.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2015 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
-
-#define __STDC_FORMAT_MACROS /* for PRId64 etc. */
-
-#include "image/epdf.h"
-
-/*
- This file is mostly C and not very much C++; it's just used to interface
- the functions of poppler, which happens to be written in C++.
- Patches for the new poppler 0.59 from
- https://www.mail-archive.com/arch-commits@archlinux.org/msg357548.html
- with some modifications to comply the poppler API.
-
-*/
-
-extern void md5(Guchar *msg, int msgLen, Guchar *digest);
-
-static GBool isInit = gFalse;
-
-/* Maintain AVL tree of all PDF files for embedding */
-
-static avl_table *PdfDocumentTree = NULL;
-
-/* AVL sort PdfDocument into PdfDocumentTree by file_path */
-
-static int CompPdfDocument(const void *pa, const void *pb, void * /*p */ )
-{
- return strcmp(((const PdfDocument *) pa)->file_path, ((const PdfDocument *) pb)->file_path);
-}
-
-/* Returns pointer to PdfDocument structure for PDF file. */
-
-static PdfDocument *findPdfDocument(char *file_path)
-{
- PdfDocument *pdf_doc, tmp;
- if (file_path == NULL) {
- normal_error("pdf backend","empty filename when loading pdf file");
- } else if (PdfDocumentTree == NULL) {
- return NULL;
- }
- tmp.file_path = file_path;
- pdf_doc = (PdfDocument *) avl_find(PdfDocumentTree, &tmp);
- return pdf_doc;
-}
-
-#define PDF_CHECKSUM_SIZE 32
-
-static char *get_file_checksum(const char *a, file_error_mode fe)
-{
- struct stat finfo;
- char *ck = NULL;
- if (stat(a, &finfo) == 0) {
- off_t size = finfo.st_size;
- time_t mtime = finfo.st_mtime;
- ck = (char *) malloc(PDF_CHECKSUM_SIZE);
- if (ck == NULL)
- formatted_error("pdf inclusion","out of memory while processing '%s'", a);
- snprintf(ck, PDF_CHECKSUM_SIZE, "%"@= @>PRIu64@= @>"_%"@= @>PRIu64, (uint64_t) size,(uint64_t) mtime);
- } else {
- switch (fe) {
- case FE_FAIL:
- formatted_error("pdf inclusion","could not stat() file '%s'", a);
- break;
- case FE_RETURN_NULL:
- if (ck != NULL)
- free(ck);
- ck = NULL;
- break;
- default:
- assert(0);
- }
- }
- return ck;
-}
-
-
-static char *get_stream_checksum (const char *str, unsigned long long str_size){
- /* http://www.cse.yorku.ca/~oz/hash.html */
- /* djb2 */
- unsigned long hash ;
- char *ck = NULL;
- unsigned int i;
- hash = 5381;
- ck = (char *) malloc(STRSTREAM_CHECKSUM_SIZE+1);
- if (ck == NULL)
- normal_error("pdf inclusion","out of memory while processing a memstream");
- for(i=0; i<(unsigned int)(str_size); i++) {
- hash = ((hash << 5) + hash) + str[i]; /* hash * 33 + str[i] */
- }
- snprintf(ck,STRSTREAM_CHECKSUM_SIZE+1,"%lx",hash);
- ck[STRSTREAM_CHECKSUM_SIZE]='\0';
- return ck;
-}
-
-/*
- Returns pointer to PdfDocument structure for PDF file.
- Creates a new PdfDocument structure if it doesn't exist yet.
- When fe = FE_RETURN_NULL, the function returns NULL in error case.
-*/
-
-PdfDocument *refPdfDocument(const char *file_path, file_error_mode fe)
-{
- char *checksum, *path_copy;
- PdfDocument *pdf_doc;
- PDFDoc *doc = NULL;
- GooString *docName = NULL;
- int new_flag = 0;
- if ((checksum = get_file_checksum(file_path, fe)) == NULL) {
- return (PdfDocument *) NULL;
- }
- path_copy = xstrdup(file_path);
- if ((pdf_doc = findPdfDocument(path_copy)) == NULL) {
- new_flag = 1;
- pdf_doc = new PdfDocument;
- pdf_doc->file_path = path_copy;
- pdf_doc->checksum = checksum;
- pdf_doc->doc = NULL;
- pdf_doc->inObjList = NULL;
- pdf_doc->ObjMapTree = NULL;
- pdf_doc->occurences = 0; /* 0 = unreferenced */
- pdf_doc->pc = 0;
- } else {
- if (strncmp(pdf_doc->checksum, checksum, PDF_CHECKSUM_SIZE) != 0) {
- formatted_error("pdf inclusion","file has changed '%s'", file_path);
- }
- free(checksum);
- free(path_copy);
- }
- if (pdf_doc->doc == NULL) {
- docName = new GooString(file_path);
- doc = new PDFDoc(docName); /* takes ownership of docName */
- pdf_doc->pc++;
-
- if (!doc->isOk() || !doc->okToPrint()) {
- switch (fe) {
- case FE_FAIL:
- normal_error("pdf inclusion","reading image failed");
- break;
- case FE_RETURN_NULL:
- delete doc;
- /* delete docName */
- if (new_flag == 1) {
- if (pdf_doc->file_path != NULL)
- free(pdf_doc->file_path);
- if (pdf_doc->checksum != NULL)
- free(pdf_doc->checksum);
- delete pdf_doc;
- }
- return (PdfDocument *) NULL;
- break;
- default:
- assert(0);
- }
- }
- pdf_doc->doc = doc;
- }
- /* PDF file could be opened without problems, checksum ok. */
- if (PdfDocumentTree == NULL)
- PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
- if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
- avl_probe(PdfDocumentTree, pdf_doc);
- }
- pdf_doc->occurences++;
- return pdf_doc;
-}
-
-/*
- Returns pointer to PdfDocument structure for a PDF stream in memory of streamsize
- dimension. As before, creates a new PdfDocument structure if it doesn't exist yet
- with file_path = file_id
-*/
-
-PdfDocument *refMemStreamPdfDocument(char *docstream, unsigned long long streamsize,const char *file_id)
-{
- char *checksum;
- char *file_path;
- PdfDocument *pdf_doc;
- PDFDoc *doc = NULL;
- Object obj;
- MemStream *docmemstream = NULL;
- /*int new_flag = 0;*/
- size_t cnt = 0;
- checksum = get_stream_checksum(docstream, streamsize);
- cnt = strlen(file_id);
- assert(cnt>0 && cnt <STREAM_FILE_ID_LEN);
- file_path = (char *) malloc(cnt+STREAM_URI_LEN+STRSTREAM_CHECKSUM_SIZE+1); /* 1 for \0 */
- assert(file_path != NULL);
- strcpy(file_path,STREAM_URI);
- strcat(file_path,file_id);
- strcat(file_path,checksum);
- file_path[cnt+STREAM_URI_LEN+STRSTREAM_CHECKSUM_SIZE]='\0';
- if ((pdf_doc = findPdfDocument(file_path)) == NULL) {
- /*new_flag = 1;*/
- pdf_doc = new PdfDocument;
- pdf_doc->file_path = file_path;
- pdf_doc->checksum = checksum;
- pdf_doc->doc = NULL;
- pdf_doc->inObjList = NULL;
- pdf_doc->ObjMapTree = NULL;
- pdf_doc->occurences = 0; /* 0 = unreferenced */
- pdf_doc->pc = 0;
- } else {
- /* As is now, checksum is in file_path, so this check should be useless. */
- if (strncmp(pdf_doc->checksum, checksum, STRSTREAM_CHECKSUM_SIZE) != 0) {
- formatted_error("pdf inclusion","stream has changed '%s'", file_path);
- }
- free(file_path);
- free(checksum);
- }
- if (pdf_doc->doc == NULL) {
- docmemstream = new MemStream( docstream,0,streamsize, Object(objNull) );
- doc = new PDFDoc(docmemstream); /* takes ownership of docmemstream */
- pdf_doc->pc++;
- if (!doc->isOk() || !doc->okToPrint()) {
- normal_error("pdf inclusion","reading pdf Stream failed");
- }
- pdf_doc->doc = doc;
- }
- /* PDF file could be opened without problems, checksum ok. */
- if (PdfDocumentTree == NULL)
- PdfDocumentTree = avl_create(CompPdfDocument, NULL, &avl_xallocator);
- if ((PdfDocument *) avl_find(PdfDocumentTree, pdf_doc) == NULL) {
- avl_probe(PdfDocumentTree, pdf_doc);
- }
- pdf_doc->occurences++;
- return pdf_doc;
-}
-
-/*
- AVL sort ObjMap into ObjMapTree by object number and generation keep the ObjMap
- struct small, as these are accumulated until the end
-*/
-
-struct ObjMap {
- Ref in;
- int out_num;
-};
-
-static int CompObjMap(const void *pa, const void *pb, void * /*p */ )
-{
- const Ref *a = &(((const ObjMap *) pa)->in);
- const Ref *b = &(((const ObjMap *) pb)->in);
- if (a->num > b->num)
- return 1;
- else if (a->num < b->num)
- return -1;
- else if (a->gen == b->gen)
- return 0;
- else if (a->gen < b->gen)
- return -1;
- return 1;
-}
-
-static ObjMap *findObjMap(PdfDocument * pdf_doc, Ref in)
-{
- ObjMap *obj_map, tmp;
- if (pdf_doc->ObjMapTree == NULL)
- return NULL;
- tmp.in = in;
- obj_map = (ObjMap *) avl_find(pdf_doc->ObjMapTree, &tmp);
- return obj_map;
-}
-
-static void addObjMap(PdfDocument * pdf_doc, Ref in, int out_num)
-{
- ObjMap *obj_map = NULL;
- if (pdf_doc->ObjMapTree == NULL)
- pdf_doc->ObjMapTree = avl_create(CompObjMap, NULL, &avl_xallocator);
- obj_map = new ObjMap;
- obj_map->in = in;
- obj_map->out_num = out_num;
- avl_probe(pdf_doc->ObjMapTree, obj_map);
-}
-
-/*
- When copying the Resources of the selected page, all objects are
- copied recursively top-down. The findObjMap() function checks if an
- object has already been copied; if so, instead of copying just the
- new object number will be referenced. The ObjMapTree guarantees,
- that during the entire LuaTeX run any object from any embedded PDF
- file will end up max. once in the output PDF file. Indirect objects
- are not fetched during copying, but get a new object number from
- LuaTeX and then will be appended into a linked list.
-*/
-
-static int addInObj(PDF pdf, PdfDocument * pdf_doc, Ref ref)
-{
- ObjMap *obj_map;
- InObj *p, *q, *n;
- if (ref.num == 0) {
- normal_error("pdf inclusion","reference to invalid object (broken pdf)");
- }
- if ((obj_map = findObjMap(pdf_doc, ref)) != NULL)
- return obj_map->out_num;
- n = new InObj;
- n->ref = ref;
- n->next = NULL;
- n->num = pdf_create_obj(pdf, obj_type_others, 0);
- addObjMap(pdf_doc, ref, n->num);
- if (pdf_doc->inObjList == NULL) {
- pdf_doc->inObjList = n;
- } else {
- /*
- It is important to add new objects at the end of the list,
- because new objects are being added while the list is being
- written out by writeRefs().
- */
- for (p = pdf_doc->inObjList; p != NULL; p = p->next)
- q = p;
- q->next = n;
- }
- return n->num;
-}
-
-/*
- Function converts double to pdffloat; very small and very large numbers
- are NOT converted to scientific notation. Here n must be a number or real
- conforming to the implementation limits of PDF as specified in appendix C.1
- of the PDF Ref. These are:
-
- maximum value of ints is +2^32
- maximum value of reals is +2^15
- smalles values of reals is 1/(2^16)
-*/
-
-static pdffloat conv_double_to_pdffloat(double n)
-{
- pdffloat a;
- a.e = 6;
- a.m = i64round(n * ten_pow[a.e]);
- return a;
-}
-
-static void copyObject(PDF, PdfDocument *, Object *);
-
-void copyReal(PDF pdf, double d)
-{
- if (pdf->cave)
- pdf_out(pdf, ' ');
- print_pdffloat(pdf, conv_double_to_pdffloat(d));
- pdf->cave = true;
-}
-
-static void copyString(PDF pdf, GooString * string)
-{
- char *p;
- unsigned char c;
- size_t i, l;
- p = string->getCString();
- l = (size_t) string->getLength();
- if (pdf->cave)
- pdf_out(pdf, ' ');
- if (strlen(p) == l) {
- pdf_out(pdf, '(');
- for (; *p != 0; p++) {
- c = (unsigned char) *p;
- if (c == '(' || c == ')' || c == '\\')
- pdf_printf(pdf, "\\%c", c);
- else if (c < 0x20 || c > 0x7F)
- pdf_printf(pdf, "\\%03o", (int) c);
- else
- pdf_out(pdf, c);
- }
- pdf_out(pdf, ')');
- } else {
- pdf_out(pdf, '<');
- for (i = 0; i < l; i++) {
- c = (unsigned char) string->getChar(i);
- pdf_printf(pdf, "%.2x", (int) c);
- }
- pdf_out(pdf, '>');
- }
- pdf->cave = true;
-}
-
-static void copyName(PDF pdf, char *s)
-{
- pdf_out(pdf, '/');
- for (; *s != 0; s++) {
- if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' ||
- *s == '.' || *s == '-' || *s == '+')
- pdf_out(pdf, *s);
- else
- pdf_printf(pdf, "#%.2X", *s & 0xFF);
- }
- pdf->cave = true;
-}
-
-static void copyArray(PDF pdf, PdfDocument * pdf_doc, Array * array)
-{
- int i, l;
- Object obj1;
- pdf_begin_array(pdf);
- for (i = 0, l = array->getLength(); i < l; ++i) {
- obj1 = array->getNF(i);
- copyObject(pdf, pdf_doc, &obj1);
- }
- pdf_end_array(pdf);
-}
-
-static void copyDict(PDF pdf, PdfDocument * pdf_doc, Dict * dict)
-{
- int i, l;
- Object obj1;
- pdf_begin_dict(pdf);
- for (i = 0, l = dict->getLength(); i < l; ++i) {
- copyName(pdf, dict->getKey(i));
- obj1 = dict->getValNF(i);
- copyObject(pdf, pdf_doc, &obj1);
- }
- pdf_end_dict(pdf);
-}
-
-static void copyStreamStream(PDF pdf, Stream * str)
-{
- int c, i, len = 1024;
- str->reset();
- i = len;
- while ((c = str->getChar()) != EOF) {
- if (i == len) {
- pdf_room(pdf, len);
- i = 0;
- }
- pdf_quick_out(pdf, c);
- i++;
- }
-}
-
-static void copyStream(PDF pdf, PdfDocument * pdf_doc, Stream * stream)
-{
- copyDict(pdf, pdf_doc, stream->getDict());
- pdf_begin_stream(pdf);
- copyStreamStream(pdf, stream->getUndecodedStream());
- pdf_end_stream(pdf);
-}
-
-static void copyObject(PDF pdf, PdfDocument * pdf_doc, Object * obj)
-{
- switch (obj->getType()) {
- case objBool:
- pdf_add_bool(pdf, (int) obj->getBool());
- break;
- case objInt:
- pdf_add_int(pdf, obj->getInt());
- break;
- case objReal:
- copyReal(pdf, obj->getReal());
- break;
- /*
- case objNum:
- GBool isNum() { return type == objInt || type == objReal; }
- break;
- */
- case objString:
- copyString(pdf, (GooString *)obj->getString());
- break;
- case objName:
- copyName(pdf, (char *)obj->getName());
- break;
- case objNull:
- pdf_add_null(pdf);
- break;
- case objArray:
- copyArray(pdf, pdf_doc, obj->getArray());
- break;
- case objDict:
- copyDict(pdf, pdf_doc, obj->getDict());
- break;
- case objStream:
- copyStream(pdf, pdf_doc, obj->getStream());
- break;
- case objRef:
- pdf_add_ref(pdf, addInObj(pdf, pdf_doc, obj->getRef()));
- break;
- case objCmd:
- case objError:
- case objEOF:
- case objNone:
- formatted_error("pdf inclusion","type '%s' cannot be copied", obj->getTypeName());
- break;
- default:
- /* poppler doesn't have any other types */
- assert(0);
- }
-}
-
-static void writeRefs(PDF pdf, PdfDocument * pdf_doc)
-{
- InObj *r, *n;
- Object obj1;
- XRef *xref;
- PDFDoc *doc = pdf_doc->doc;
- xref = doc->getXRef();
- for (r = pdf_doc->inObjList; r != NULL;) {
- obj1 = xref->fetch(r->ref.num, r->ref.gen);
- if (obj1.isStream())
- pdf_begin_obj(pdf, r->num, OBJSTM_NEVER);
- else
- pdf_begin_obj(pdf, r->num, 2);
- copyObject(pdf, pdf_doc, &obj1);
- pdf_end_obj(pdf);
- n = r->next;
- delete r;
- pdf_doc->inObjList = r = n;
- }
-}
-
-/* get the pagebox coordinates according to the pagebox_spec */
-
-static PDFRectangle *get_pagebox(Page * page, int pagebox_spec)
-{
- switch (pagebox_spec) {
- case PDF_BOX_SPEC_MEDIA:
- return page->getMediaBox();
- break;
- case PDF_BOX_SPEC_CROP:
- return page->getCropBox();
- break;
- case PDF_BOX_SPEC_BLEED:
- return page->getBleedBox();
- break;
- case PDF_BOX_SPEC_TRIM:
- return page->getTrimBox();
- break;
- case PDF_BOX_SPEC_ART:
- return page->getArtBox();
- break;
- default:
- return page->getMediaBox();
- break;
- }
-}
-
-/*
- Reads various information about the PDF and sets it up for later inclusion.
- This will fail if the PDF version of the PDF is higher than minor_pdf_version_wanted
- or page_name is given and can not be found. It makes no sense to give page_name and
- page_num. Returns the page number.
-*/
-
-void flush_pdf_info(image_dict * idict)
-{
- if (img_keepopen(idict)) {
- unrefPdfDocument(img_filepath(idict));
- }
-}
-
-/*
- void flush_pdfstream_info(image_dict * idict)
- {
- if (img_pdfstream_ptr(idict) != NULL) {
- xfree(img_pdfstream_stream(idict));
- xfree(img_pdfstream_ptr(idict));
- img_pdfstream_stream(idict) = NULL;
- img_pdfstream_ptr(idict) = NULL;
- }
- }
-*/
-
-void read_pdf_info(image_dict * idict)
-{
- PdfDocument *pdf_doc = NULL;
- PDFDoc *doc = NULL;
- Catalog *catalog;
- Page *page;
- int rotate;
- PDFRectangle *pagebox;
- int pdf_major_version_found, pdf_minor_version_found;
- float xsize, ysize, xorig, yorig;
- if (isInit == gFalse) {
- if (!(globalParams))
- globalParams = new GlobalParams();
- globalParams->setErrQuiet(gFalse);
- isInit = gTrue;
- }
- if (img_type(idict) == IMG_TYPE_PDF)
- pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
- else if (img_type(idict) == IMG_TYPE_PDFMEMSTREAM) {
- pdf_doc = findPdfDocument(img_filepath(idict)) ;
- if (pdf_doc == NULL )
- normal_error("pdf inclusion", "memstream not initialized");
- if (pdf_doc->doc == NULL)
- normal_error("pdf inclusion", "memstream document is empty");
- pdf_doc->occurences++;
- } else {
- normal_error("pdf inclusion","unknown document");
- }
- doc = pdf_doc->doc;
- catalog = doc->getCatalog();
- /*
- Check PDF version. This works only for PDF 1.x but since any versions of
- PDF newer than 1.x will not be backwards compatible to PDF 1.x, we will
- then have to changed drastically anyway.
- */
- pdf_major_version_found = doc->getPDFMajorVersion();
- pdf_minor_version_found = doc->getPDFMinorVersion();
- if ((100 * pdf_major_version_found + pdf_major_version_found) > (100 * img_pdfmajorversion(idict) + img_pdfminorversion(idict))) {
- const char *msg = "PDF inclusion: found PDF version '%d.%d', but at most version '%d.%d' allowed";
- if (img_errorlevel(idict) > 0) {
- formatted_error("pdf inclusion",msg, pdf_major_version_found, pdf_minor_version_found, img_pdfmajorversion(idict), img_pdfminorversion(idict));
- } else {
- formatted_warning("pdf inclusion",msg, pdf_major_version_found, pdf_minor_version_found, img_pdfmajorversion(idict), img_pdfminorversion(idict));
- }
- }
- img_totalpages(idict) = catalog->getNumPages();
- if (img_pagename(idict)) {
- /* get page by name */
- GooString name(img_pagename(idict));
- LinkDest *link = doc->findDest(&name);
- if (link == NULL || !link->isOk())
- formatted_error("pdf inclusion","invalid destination '%s'",img_pagename(idict));
- Ref ref = link->getPageRef();
- img_pagenum(idict) = catalog->findPage(ref.num, ref.gen);
- if (img_pagenum(idict) == 0)
- formatted_error("pdf inclusion","destination is not a page '%s'",img_pagename(idict));
- delete link;
- } else {
- /* get page by number */
- if (img_pagenum(idict) <= 0
- || img_pagenum(idict) > img_totalpages(idict))
- formatted_error("pdf inclusion","required page '%i' does not exist",(int) img_pagenum(idict));
- }
- /* get the required page */
- page = catalog->getPage(img_pagenum(idict));
- /* get the pagebox coordinates (media, crop,...) to use. */
- pagebox = get_pagebox(page, img_pagebox(idict));
- if (pagebox->x2 > pagebox->x1) {
- xorig = pagebox->x1;
- xsize = pagebox->x2 - pagebox->x1;
- } else {
- xorig = pagebox->x2;
- xsize = pagebox->x1 - pagebox->x2;
- }
- if (pagebox->y2 > pagebox->y1) {
- yorig = pagebox->y1;
- ysize = pagebox->y2 - pagebox->y1;
- } else {
- yorig = pagebox->y2;
- ysize = pagebox->y1 - pagebox->y2;
- }
- /* The following 4 parameters are raw. Do _not_ modify by /Rotate! */
- img_xsize(idict) = bp2sp(xsize);
- img_ysize(idict) = bp2sp(ysize);
- img_xorig(idict) = bp2sp(xorig);
- img_yorig(idict) = bp2sp(yorig);
- /*
- Handle /Rotate parameter. Only multiples of 90 deg. are allowed (PDF Ref. v1.3,
- p. 78). We also accept negative angles. Beware: PDF counts clockwise! */
- rotate = page->getRotate();
- switch (((rotate % 360) + 360) % 360) {
- case 0:
- img_rotation(idict) = 0;
- break;
- case 90:
- img_rotation(idict) = 3;
- break;
- case 180:
- img_rotation(idict) = 2;
- break;
- case 270:
- img_rotation(idict) = 1;
- break;
- default:
- formatted_warning("pdf inclusion","/Rotate parameter in PDF file not multiple of 90 degrees");
- }
- /* currently unused info whether PDF contains a /Group */
- if (page->getGroup() != NULL)
- img_set_group(idict);
- /*
- LuaTeX pre 0.85 versions did this:
-
- if (readtype == IMG_CLOSEINBETWEEN) {
- unrefPdfDocument(img_filepath(idict));
- }
-
- and also unref'd in the finalizer so we got an extra unrefs when garbage was
- collected. However it is more efficient to keep the file open so we do that
- now. The (slower) alternative is to unref here (which in most cases forcing a
- close of the file) but then we must not call flush_pdf_info.
-
- A close (unref) can be forced by nilling the dict object at the lua end and
- forcing a collectgarbage("collect") after that.
-
- */
- if (! img_keepopen(idict)) {
- unrefPdfDocument(img_filepath(idict));
- }
-}
-
-/*
- Write the current epf_doc. Here the included PDF is copied, so most errors
- that can happen during PDF inclusion will arise here.
-*/
-
-void write_epdf(PDF pdf, image_dict * idict, int suppress_optional_info)
-{
- PdfDocument *pdf_doc = NULL;
- PDFDoc *doc = NULL;
- Catalog *catalog;
- Page *page;
- Ref *pageref;
- Dict *pageDict;
- Object obj1, contents, pageobj, pagesobj1, pagesobj2, *op1, *op2, *optmp;
- PDFRectangle *pagebox;
- int i, l;
- double bbox[4];
- /* char s[256]; */
- const char *pagedictkeys[] = {
- "Group", "LastModified", "Metadata", "PieceInfo", "Resources", "SeparationInfo", NULL
- };
- /* open PDF file */
- if (img_type(idict) == IMG_TYPE_PDF) {
- pdf_doc = refPdfDocument(img_filepath(idict), FE_FAIL);
- } else if (img_type(idict) == IMG_TYPE_PDFMEMSTREAM) {
- pdf_doc = findPdfDocument(img_filepath(idict)) ;
- pdf_doc->occurences++;
- } else {
- normal_error("pdf inclusion","unknown document");
- }
- doc = pdf_doc->doc;
- catalog = doc->getCatalog();
- page = catalog->getPage(img_pagenum(idict));
- pageref = catalog->getPageRef(img_pagenum(idict));
- pageobj = doc->getXRef()->fetch(pageref->num, pageref->gen);
- pageDict = pageobj.getDict();
- /* write the Page header */
- pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "XObject");
- pdf_dict_add_name(pdf, "Subtype", "Form");
- if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) {
- pdf_printf(pdf, "\n%s\n", img_attr(idict));
- }
- pdf_dict_add_int(pdf, "FormType", 1);
- /* write additional information */
- pdf_dict_add_img_filename(pdf, idict);
- if ((suppress_optional_info & 4) == 0) {
- pdf_dict_add_int(pdf, "PTEX.PageNumber", (int) img_pagenum(idict));
- }
- if ((suppress_optional_info & 8) == 0) {
- obj1 = doc->getDocInfoNF();
- if (obj1.isRef()) {
- /* the info dict must be indirect (PDF Ref p. 61) */
- pdf_dict_add_ref(pdf, "PTEX.InfoDict", addInObj(pdf, pdf_doc, obj1.getRef()));
- }
- }
- if (img_is_bbox(idict)) {
- bbox[0] = sp2bp(img_bbox(idict)[0]);
- bbox[1] = sp2bp(img_bbox(idict)[1]);
- bbox[2] = sp2bp(img_bbox(idict)[2]);
- bbox[3] = sp2bp(img_bbox(idict)[3]);
- } else {
- /* get the pagebox coordinates (media, crop,...) to use. */
- pagebox = get_pagebox(page, img_pagebox(idict));
- bbox[0] = pagebox->x1;
- bbox[1] = pagebox->y1;
- bbox[2] = pagebox->x2;
- bbox[3] = pagebox->y2;
- }
- pdf_add_name(pdf, "BBox");
- pdf_begin_array(pdf);
- copyReal(pdf, bbox[0]);
- copyReal(pdf, bbox[1]);
- copyReal(pdf, bbox[2]);
- copyReal(pdf, bbox[3]);
- pdf_end_array(pdf);
- /*
- Now all relevant parts of the Page dictionary are copied. Metadata validity
- check is needed(as a stream it must be indirect).
- */
- obj1 = pageDict->lookupNF("Metadata");
- if (!obj1.isNull() && !obj1.isRef())
- formatted_warning("pdf inclusion","/Metadata must be indirect object");
- /* copy selected items in Page dictionary */
- for (i = 0; pagedictkeys[i] != NULL; i++) {
- obj1 = pageDict->lookupNF(pagedictkeys[i]);
- if (!obj1.isNull()) {
- pdf_add_name(pdf, pagedictkeys[i]);
- /* preserves indirection */
- copyObject(pdf, pdf_doc, &obj1);
- }
- }
- /*
- If there are no Resources in the Page dict of the embedded page,
- try to inherit the Resources from the Pages tree of the embedded
- PDF file, climbing up the tree until the Resources are found.
- (This fixes a problem with Scribus 1.3.3.14.)
- */
- obj1 = pageDict->lookupNF("Resources");
- if (obj1.isNull()) {
- op1 = &pagesobj1;
- op2 = &pagesobj2;
- *op1 = pageDict->lookup("Parent");
- while (op1->isDict()) {
- obj1 = op1->dictLookupNF("Resources");
- if (!obj1.isNull()) {
- pdf_add_name(pdf, "Resources");
- copyObject(pdf, pdf_doc, &obj1);
- break;
- }
- *op2 = op1->dictLookup("Parent");
- optmp = op1;
- op1 = op2;
- op2 = optmp;
- };
- if (!op1->isDict())
- formatted_warning("pdf inclusion","Page /Resources missing");
- }
- /* Write the Page contents. */
- contents = page->getContents();
- if (contents.isStream()) {
- /*
- Variant A: get stream and recompress under control of \pdfcompresslevel
-
- pdf_begin_stream();
- copyStreamStream(contents->getStream());
- pdf_end_stream();
-
- Variant B: copy stream without recompressing
- */
- obj1 = contents.streamGetDict()->lookup("F");
- if (!obj1.isNull()) {
- normal_error("pdf inclusion","unsupported external stream");
- }
- obj1 = contents.streamGetDict()->lookup("Length");
- pdf_add_name(pdf, "Length");
- copyObject(pdf, pdf_doc, &obj1);
- obj1 = contents.streamGetDict()->lookup("Filter");
- if (!obj1.isNull()) {
- pdf_add_name(pdf, "Filter");
- copyObject(pdf, pdf_doc, &obj1);
- obj1 = contents.streamGetDict()->lookup("DecodeParms");
- if (!obj1.isNull()) {
- pdf_add_name(pdf, "DecodeParms");
- copyObject(pdf, pdf_doc, &obj1);
- }
- }
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- copyStreamStream(pdf, contents.getStream()->getUndecodedStream());
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- } else if (contents.isArray()) {
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- for (i = 0, l = contents.arrayGetLength(); i < l; ++i) {
- obj1 = contents.arrayGet(i);
- copyStreamStream(pdf, obj1.getStream());
- if (i < (l - 1)) {
- /*
- Put a space between streams to be on the safe side (streams
- should have a trailing space here, but one never knows)
- */
- pdf_out(pdf, ' ');
- }
- }
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- } else {
- /* the contents are optional, but we need to include an empty stream */
- pdf_dict_add_streaminfo(pdf);
- pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- }
- /* write out all indirect objects */
- writeRefs(pdf, pdf_doc);
- /*
- unrefPdfDocument() must come after contents.free() and pageobj.free()!
- TH: The next line makes repeated pdf inclusion unacceptably slow
-
- unrefPdfDocument(img_filepath(idict));
- */
-
-if (! img_keepopen(idict)) {
- unrefPdfDocument(img_filepath(idict));
-}
-
-
-}
-
-/* Deallocate a PdfDocument with all its resources. */
-
-static void deletePdfDocumentPdfDoc(PdfDocument * pdf_doc)
-{
- InObj *r, *n;
- /* this may be probably needed for an emergency destroyPdfDocument() */
- for (r = pdf_doc->inObjList; r != NULL; r = n) {
- n = r->next;
- delete r;
- }
- delete pdf_doc->doc;
- pdf_doc->doc = NULL;
- pdf_doc->pc++;
-}
-
-static void destroyPdfDocument(void *pa, void * /*pb */ )
-{
- PdfDocument *pdf_doc = (PdfDocument *) pa;
- deletePdfDocumentPdfDoc(pdf_doc);
- /* TODO: delete rest of pdf_doc */
-}
-
-/*
- Called when an image has been written and its resources in image_tab are
- freed and it's not referenced anymore.
-*/
-
-void unrefPdfDocument(char *file_path)
-{
- PdfDocument *pdf_doc = findPdfDocument(file_path);
- if (pdf_doc->occurences > 0) {
- pdf_doc->occurences--;
- if (pdf_doc->occurences == 0) {
- deletePdfDocumentPdfDoc(pdf_doc);
- }
- } else {
- /*
- We either have a mismatch in ref and unref or we're somehow out of sync
- which can happen when we mess with the same file in lua and tex.
- */
- formatted_warning("pdf inclusion","there can be a mismatch in opening and closing file '%s'",file_path);
- }
-}
-
-/*
- For completeness, but it isn't currently used (unreferencing is done by mean
- of file_path.
-*/
-
-void unrefMemStreamPdfDocument(char *file_id)
-{
- (void) unrefPdfDocument(file_id);
-
-}
-
-/*
- Called when PDF embedding system is finalized. We now deallocate all remaining
- PdfDocuments.
-*/
-
-void epdf_free()
-{
- if (PdfDocumentTree != NULL)
- avl_destroy(PdfDocumentTree, destroyPdfDocument);
- PdfDocumentTree = NULL;
- if (isInit == gTrue)
- delete globalParams;
- isInit = gFalse;
-}
diff --git a/Build/source/texk/web2c/luatexdir/image/writeimg.w b/Build/source/texk/web2c/luatexdir/image/writeimg.c
index ef414d5d4bb..e3e3f608fea 100644
--- a/Build/source/texk/web2c/luatexdir/image/writeimg.w
+++ b/Build/source/texk/web2c/luatexdir/image/writeimg.c
@@ -1,109 +1,82 @@
-% writeimg.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% 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/>.
-
-@* Image inclusion.
-
-@ @c
+/*
+
+writeimg.c
+
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+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"
#include <kpathsea/c-auto.h>
#include <kpathsea/c-memstr.h>
-@ @c
#include "image/image.h"
#include "image/writejpg.h"
#include "image/writejp2.h"
#include "image/writepng.h"
#include "image/writejbig2.h"
-#include "lua.h" /* for |LUA_NOREF| */
+#include "lua.h"
#include "lauxlib.h"
-@* Patch ImageTypeDetection 2003/02/08 by Heiko Oberdiek.
+/*tex
-Function |readimage| performs some basic initializations. Then it looks at the
-file extension to determine the image type and calls specific code/functions. The
-main disadvantage is that standard file extensions have to be used, otherwise
+The function |readimage| performs some basic initializations. Then it looks at
+the file extension to determine the image type and calls specific code/functions.
+The main disadvantage is that standard file extensions have to be used, otherwise
pdfTeX is not able to detect the correct image type. The patch now looks at the
file header first regardless of the file extension. This is implemented in
function |check_type_by_header|. If this check fails, the traditional test of
standard file extension is tried, done in function |check_type_by_extension|.
-Magic headers:
-
-* "PNG (Portable Network Graphics) Specification", Version 1.2
- (http://www.libpng.org/pub/png):
-
- 3.1. PNG file signature
-
- The first eight bytes of a PNG file always contain the following
- (decimal) values: 137 80 78 71 13 10 26 10
-
-Translation to C: |"\x89PNG\r\n\x1A\n"|
-
-* "JPEG File Interchange Format", Version 1.02:
-
- * you can identify a JFIF file by looking for the following sequence:
- X'FF', SOI X'FF', APP0, <2 bytes to be skipped>, "JFIF", X'00'.
-
-Function |check_type_by_header| only looks at the first two bytes: |"\xFF\xD8"|
-
-* ISO/IEC JTC 1/SC 29/WG 1
- (ITU-T SG8)
- Coding of Still Pictures
- Title: 14492 FCD
- Source: JBIG Committee
- Project: JTC 1.29.10
- Status: Final Committee Draft
-
- D.4.1, ID string
-
- This is an 8-byte sequence containing 0x97 0x4A 0x42 0x32 0x0D 0x0A 0x1A 0x0A.
-
-* "PDF Reference", third edition:
-
- * The first line should contain \%PDF-1.0 -- \%PDF-1.4 (section 3.4.1 "File Header").
- * The "implementation notes" say:
-
- 3.4.1, File Header
- 12. Acrobat viewers require only that the header appear somewhere within the
- first 1024 bytes of the file.
- 13. Acrobat viewers will also accept a header of the form \%!PS-Adobe-N.n PDF-M.m
-
-The check in function |check_type_by_header| only implements the first issue. The
-implementation notes are not considered. Therefore files with garbage at start of
-file must have the standard extension.
+The magic headers are as follows:
+
+\startitemize
+ \startitem
+ \type {png}: 89 50 4E 47 0D 0A 1A 0A or |"\137PNG\013\010\026\010"|
+ \stopitem
+ \startitem
+ \type {jpg}: FF D8 FF or |"\255\216\255"|.
+ \stopitem
+ \startitem
+ \type {jp2}: 00 00 00 0C 6A 50 20 20 0D 0A or |"\000\000\000\012\106\080\032\032\013\010"|
+ \stopitem
+ \startitem
+ \type {pdf}: |"%PDF"| somewhere in the beginning
+ \stopitem
+\stopitemize
Functions |check_type_by_header| and |check_type_by_extension|: |img_type(img)|
is set to |IMG_TYPE_NONE| by |new_image_dict()|. Both functions try to detect a
type and set |img_type(img)|. Thus a value other than |IMG_TYPE_NONE| indicates
that a type has been found.
-@c
-#define HEADER_JPG "\xFF\xD8"
-#define HEADER_PNG "\x89PNG\r\n\x1A\n"
+*/
+
+#define HEADER_JPG "\xFF\xD8"
+#define HEADER_PNG "\x89PNG\r\n\x1A\n"
#define HEADER_JBIG2 "\x97\x4A\x42\x32\x0D\x0A\x1A\x0A"
-#define HEADER_JP2 "\x6A\x50\x20\x20"
-#define HEADER_PDF "%PDF-"
+#define HEADER_JP2 "\x6A\x50\x20\x20"
+#define HEADER_PDF "%PDF-"
+
#define MAX_HEADER (sizeof(HEADER_PNG)-1)
-#define HEADER_PDF_MEMSTREAM "data:application/pdf," /* see epdf.h */
-#define LEN_PDF_MEMSTREAM 21 /* see epdf.h */
+
+#define HEADER_PDF_MEMSTREAM "data:application/pdf,"
+#define LEN_PDF_MEMSTREAM 21
static void check_type_by_header(image_dict * idict)
{
@@ -115,13 +88,13 @@ static void check_type_by_header(image_dict * idict)
return;
if (img_type(idict) != IMG_TYPE_NONE)
return;
- /* here we read the and also check for a memstream object */
+ /*tex Here we read the and also check for a memstream object. */
if (!img_filepath(idict) || !FOPEN_RBIN_MODE) {
normal_error("pdf backend","reading image file failed");
}
file = fopen(img_filepath(idict), FOPEN_RBIN_MODE);
if (file == NULL) {
- /* check the prefix of img_filepath(idict) */
+ /*tex We check the prefix of img_filepath(idict). */
for (i = 0; (unsigned) i < LEN_PDF_MEMSTREAM; i++) {
prefix[i] = (char) (img_filepath(idict)[i]);
}
@@ -133,7 +106,7 @@ static void check_type_by_header(image_dict * idict)
formatted_error("pdf backend","reading image file '%s' failed",img_filepath(idict));
}
}
- /* a valid file, but perhaps unsupported */
+ /*tex Do we have a valid file but perhaps unsupported? */
for (i = 0; (unsigned) i < MAX_HEADER; i++) {
header[i] = (char) xgetc(file);
if (feof(file)) {
@@ -141,7 +114,7 @@ static void check_type_by_header(image_dict * idict)
}
}
xfclose(file, img_filepath(idict));
- /* tests */
+ /*tex Further tests: */
if (strncmp(header, HEADER_JPG, sizeof(HEADER_JPG) - 1) == 0)
img_type(idict) = IMG_TYPE_JPG;
else if (strncmp(header + 4, HEADER_JP2, sizeof(HEADER_JP2) - 1) == 0)
@@ -154,15 +127,13 @@ static void check_type_by_header(image_dict * idict)
img_type(idict) = IMG_TYPE_PDF;
}
-@ @c
static void check_type_by_extension(image_dict * idict)
{
char *image_suffix;
if (idict != NULL)
return;
- if (img_type(idict) != IMG_TYPE_NONE) /* nothing to do */
+ if (img_type(idict) != IMG_TYPE_NONE)
return;
- /* tests */
if ((image_suffix = strrchr(img_filename(idict), '.')) == 0)
img_type(idict) = IMG_TYPE_NONE;
else if (strcasecmp(image_suffix, ".png") == 0)
@@ -179,14 +150,13 @@ static void check_type_by_extension(image_dict * idict)
img_type(idict) = IMG_TYPE_PDF;
}
-@ @c
void new_img_pdfstream_struct(image_dict * p)
{
img_pdfstream_ptr(p) = xtalloc(1, pdf_stream_struct);
img_pdfstream_stream(p) = NULL;
+ img_pdfstream_size(p) = 0;
}
-@ @c
image *new_image(void)
{
image *p = xtalloc(1, image);
@@ -199,7 +169,6 @@ image *new_image(void)
return p;
}
-@ @c
image_dict *new_image_dict(void)
{
image_dict *p = xtalloc(1, image_dict);
@@ -214,7 +183,8 @@ image_dict *new_image_dict(void)
img_unset_bbox(p);
img_unset_group(p);
img_state(p) = DICT_NEW;
- img_index(p) = -1; /* -1 = unused, used count from 0 */
+ /*tex A value of -1 means unused while the used counts from 0 */
+ img_index(p) = -1;
img_luaref(p) = 0;
img_errorlevel(p) = pdf_inclusion_errorlevel;
fix_pdf_version(static_pdf);
@@ -223,7 +193,6 @@ image_dict *new_image_dict(void)
return p;
}
-@ @c
static void free_dict_strings(image_dict * p)
{
xfree(img_filename(p));
@@ -232,12 +201,13 @@ static void free_dict_strings(image_dict * p)
xfree(img_pagename(p));
}
-@ @c
void free_image_dict(image_dict * p)
{
- if (ini_version)
- return; /* The image may be \.{\\dump}ed to a format */
- /* called from limglib.c */
+ if (ini_version) {
+ /*tex The image may be \.{\\dump}ed to a format. */
+ return;
+ }
+ /*tex Called from limglib.c. */
switch (img_type(p)) {
case IMG_TYPE_PDFMEMSTREAM:
case IMG_TYPE_PDF:
@@ -256,7 +226,6 @@ void free_image_dict(image_dict * p)
flush_jbig2_info(p);
break;
case IMG_TYPE_PDFSTREAM:
- /* flush_pdfstream_info(p); */
if (img_pdfstream_ptr(p) != NULL) {
xfree(img_pdfstream_stream(p));
xfree(img_pdfstream_ptr(p));
@@ -271,7 +240,6 @@ void free_image_dict(image_dict * p)
xfree(p);
}
-@ @c
void read_img(image_dict * idict)
{
char *filepath = NULL;
@@ -282,7 +250,7 @@ void read_img(image_dict * idict)
callback_id = callback_defined(find_image_file_callback);
if (img_filepath(idict) == NULL) {
if (callback_id > 0) {
- /* we always callback, also for a mem stream */
+ /*tex We always callback, also for a mem stream. */
if (run_callback(callback_id, "S->S", img_filename(idict),&filepath)) {
if (filepath && (strlen(filepath) > 0)) {
img_filepath(idict) = strdup(filepath);
@@ -290,22 +258,22 @@ void read_img(image_dict * idict)
}
}
if (img_filepath(idict) == NULL && (strstr(img_filename(idict),"data:application/pdf,") != NULL)) {
- /* we need to check here for a pdf memstream */
+ /*tex We need to check here for a pdf memstream. */
img_filepath(idict) = strdup(img_filename(idict));
} else if (callback_id == 0) {
- /* otherwise we use kpse but only when we don't callback */
+ /*tex Otherwise we use kpse but only when we don't callback. */
img_filepath(idict) = kpse_find_file(img_filename(idict), kpse_tex_format, true);
}
if (img_filepath(idict) == NULL) {
- /* in any case we need a name */
+ /*tex In any case we need a name. */
formatted_error("pdf backend","cannot find image file '%s'", img_filename(idict));
}
}
recorder_record_input(img_filepath(idict));
- /* type checks */
+ /*tex A few type checks. */
check_type_by_header(idict);
check_type_by_extension(idict);
- /* read image */
+ /*tex Now we're ready to read the image. */
switch (img_type(idict)) {
case IMG_TYPE_PDFMEMSTREAM:
case IMG_TYPE_PDF:
@@ -340,8 +308,7 @@ void read_img(image_dict * idict)
}
}
-@ @c
-static image_dict *read_image(char *file_name, int page_num, char *page_name, int colorspace, int page_box)
+static image_dict *read_image(char *file_name, int page_num, char *page_name, int colorspace, int page_box, char *user_password, char *owner_password, char *visible_filename)
{
image *a = new_image();
image_dict *idict = img_dict(a) = new_image_dict();
@@ -353,6 +320,9 @@ static image_dict *read_image(char *file_name, int page_num, char *page_name, in
img_colorspace(idict) = colorspace;
img_pagenum(idict) = page_num;
img_pagename(idict) = page_name;
+ img_userpassword(idict) = user_password;
+ img_ownerpassword(idict) = owner_password;
+ img_visiblefilename(idict) = visible_filename;
if (file_name == NULL) {
normal_error("pdf backend","no image filename given");
}
@@ -363,8 +333,12 @@ static image_dict *read_image(char *file_name, int page_num, char *page_name, in
return idict;
}
-@ scans PDF pagebox specification
-@c
+/*tex
+
+ There can be several page boxes. Normally the cropbox is used.
+
+*/
+
static pdfboxspec_e scan_pdf_box_spec(void)
{
if (scan_keyword("mediabox"))
@@ -381,14 +355,13 @@ static pdfboxspec_e scan_pdf_box_spec(void)
return PDF_BOX_SPEC_NONE;
}
-@ @c
-void scan_pdfximage(PDF pdf) /* static_pdf */
+void scan_pdfximage(PDF pdf)
{
scaled_whd alt_rule;
image_dict *idict;
int transform = 0, page = 1, pagebox, colorspace = 0;
- char *named = NULL, *attr = NULL, *file_name = NULL;
- alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */
+ char *named = NULL, *attr = NULL, *file_name = NULL, *user = NULL, *owner = NULL, *visible = NULL;
+ alt_rule = scan_alt_rule();
if (scan_keyword("attr")) {
scan_toks(false, true);
attr = tokenlist_to_cstring(def_ref, true, NULL);
@@ -396,13 +369,33 @@ void scan_pdfximage(PDF pdf) /* static_pdf */
}
if (scan_keyword("named")) {
scan_toks(false, true);
- named = tokenlist_to_cstring(def_ref, true, NULL);
+ if (0) {
+ named = tokenlist_to_cstring(def_ref, true, NULL);
+ page = 0;
+ } else {
+ normal_warning("pdf backend","named pages are not supported, using page 1");
+ page = 1;
+ }
delete_token_ref(def_ref);
- page = 0;
} else if (scan_keyword("page")) {
scan_int();
page = cur_val;
}
+ if (scan_keyword("userpassword")) {
+ scan_toks(false, true);
+ user = tokenlist_to_cstring(def_ref, true, NULL);
+ delete_token_ref(def_ref);
+ }
+ if (scan_keyword("ownerpassword")) {
+ scan_toks(false, true);
+ owner = tokenlist_to_cstring(def_ref, true, NULL);
+ delete_token_ref(def_ref);
+ }
+ if (scan_keyword("visiblefilename")) {
+ scan_toks(false, true);
+ visible = tokenlist_to_cstring(def_ref, true, NULL);
+ delete_token_ref(def_ref);
+ }
if (scan_keyword("colorspace")) {
scan_int();
colorspace = cur_val;
@@ -419,7 +412,7 @@ void scan_pdfximage(PDF pdf) /* static_pdf */
normal_error("pdf backend","no image filename given");
}
delete_token_ref(def_ref);
- idict = read_image(file_name, page, named, colorspace, pagebox);
+ idict = read_image(file_name, page, named, colorspace, pagebox, user, owner, visible);
img_attr(idict) = attr;
img_dimen(idict) = alt_rule;
img_transform(idict) = transform;
@@ -427,33 +420,32 @@ void scan_pdfximage(PDF pdf) /* static_pdf */
last_saved_image_pages = img_totalpages(idict);
}
-@ @c
void scan_pdfrefximage(PDF pdf)
{
- /* one could scan transform as well */
+ /*tex One could scan transform as well. */
int transform = 0;
- /* begin of experiment */
+ /*tex Begin of experiment. */
int open = 0;
- /* end of experiment */
+ /*tex End of experiment. */
image_dict *idict;
- /* scans |<rule spec>| to |alt_rule| */
+ /*tex This scans |<rule spec>| to |alt_rule|. */
scaled_whd alt_rule, dim;
alt_rule = scan_alt_rule();
- /* begin of experiment */
+ /*tex Begin of experiment. */
if (scan_keyword("keepopen")) {
open = 1;
}
- /* end of experiment */
+ /*tex End of experiment. */
scan_int();
check_obj_type(pdf, obj_type_ximage, cur_val);
tail_append(new_rule(image_rule));
idict = idict_array[obj_data_ptr(pdf, cur_val)];
- /* begin of experiment */
+ /*tex Begin of experiment, */
if (open) {
- /* so we keep the original value when no close is given */
+ /*tex So we keep the original value when no close is given. */
idict->keepopen = 1;
}
- /* end of experiment */
+ /*tex End of experiment. */
if (img_state(idict) == DICT_NEW) {
normal_warning("image","don't rely on the image data to be okay");
width(tail_par) = 0;
@@ -473,38 +465,41 @@ void scan_pdfrefximage(PDF pdf)
}
}
-@ |tex_scale()| sequence of decisions:
-
-{\obeylines\obeyspaces\tt
-wd ht dp : res = tex;
-wd ht --
-wd -- dp
-wd -- --
--- ht dp
--- ht --
--- -- dp
--- -- -- : res = nat;
-}
+/*
+ The |tex_scale| function follows a sequence of decisions:
+
+ \starttyping
+ wd ht dp : res = tex;
+ wd ht --
+ wd -- dp
+ wd -- --
+ -- ht dp
+ -- ht --
+ -- -- dp
+ -- -- -- : res = nat;
+ \stoptyping
+
+*/
-@c
scaled_whd tex_scale(scaled_whd nat, scaled_whd tex)
{
scaled_whd res;
if (!is_running(tex.wd) && !is_running(tex.ht) && !is_running(tex.dp)) {
- /* width, height, and depth specified */
+ /*tex width, height, and depth specified */
res = tex;
- } else /* max. 2 dimensions are specified */ if (!is_running(tex.wd)) {
+ } else if (!is_running(tex.wd)) {
+ /*tex max. 2 dimensions are specified */
res.wd = tex.wd;
if (!is_running(tex.ht)) {
res.ht = tex.ht;
- /* width and height specified */
+ /*tex width and height specified */
res.dp = ext_xn_over_d(tex.ht, nat.dp, nat.ht);
} else if (!is_running(tex.dp)) {
res.dp = tex.dp;
- /* width and depth specified */
+ /*tex width and depth specified */
res.ht = ext_xn_over_d(tex.wd, nat.ht + nat.dp, nat.wd) - tex.dp;
} else {
- /* only width specified */
+ /*tex only width specified */
res.ht = ext_xn_over_d(tex.wd, nat.ht, nat.wd);
res.dp = ext_xn_over_d(tex.wd, nat.dp, nat.wd);
}
@@ -512,44 +507,50 @@ scaled_whd tex_scale(scaled_whd nat, scaled_whd tex)
res.ht = tex.ht;
if (!is_running(tex.dp)) {
res.dp = tex.dp;
- /* height and depth specified */
+ /*tex height and depth specified */
res.wd = ext_xn_over_d(tex.ht + tex.dp, nat.wd, nat.ht + nat.dp);
} else {
- /* only height specified */
+ /*tex only height specified */
res.wd = ext_xn_over_d(tex.ht, nat.wd, nat.ht);
res.dp = ext_xn_over_d(tex.ht, nat.dp, nat.ht);
}
} else if (!is_running(tex.dp)) {
res.dp = tex.dp;
- /* only depth specified */
+ /*tex only depth specified */
res.ht = nat.ht - (tex.dp - nat.dp);
res.wd = nat.wd;
} else {
- /* nothing specified */
+ /*tex nothing specified */
res = nat;
}
return res;
}
-@ Within |scale_img()| only image width and height matter;
-the offsets and positioning are not interesting here.
-But one needs rotation info to swap width and height.
-|img_rotation()| comes from the optional /Rotate key in the PDF file.
+/*tex
+
+Within |scale_img| only image width and height matter; the offsets and
+positioning are not interesting here. But one needs rotation info to swap width
+and height. |img_rotation| comes from the optional |/Rotate| key in the PDF file.
+
+*/
-@c
scaled_whd scale_img(image_dict * idict, scaled_whd alt_rule, int transform)
{
- int x, y, xr, yr, tmp; /* size and resolution of image */
- scaled_whd nat; /* natural size corresponding to image resolution */
+ /*tex size and resolution of image */
+ int x, y, xr, yr, tmp;
+ /*tex natural size corresponding to image resolution */
+ scaled_whd nat;
int default_res;
if ((img_type(idict) == IMG_TYPE_PDF || img_type(idict) == IMG_TYPE_PDFMEMSTREAM
|| img_type(idict) == IMG_TYPE_PDFSTREAM) && img_is_bbox(idict)) {
- x = img_xsize(idict) = img_bbox(idict)[2] - img_bbox(idict)[0]; /* dimensions from image.bbox */
+ /*tex dimensions from image.bbox */
+ x = img_xsize(idict) = img_bbox(idict)[2] - img_bbox(idict)[0];
y = img_ysize(idict) = img_bbox(idict)[3] - img_bbox(idict)[1];
img_xorig(idict) = img_bbox(idict)[0];
img_yorig(idict) = img_bbox(idict)[1];
} else {
- x = img_xsize(idict); /* dimensions, resolutions from image file */
+ /*tex dimensions, resolutions from image file */
+ x = img_xsize(idict);
y = img_ysize(idict);
}
xr = img_xres(idict);
@@ -569,7 +570,8 @@ scaled_whd scale_img(image_dict * idict, scaled_whd alt_rule, int transform)
xr = yr;
yr = tmp;
}
- nat.dp = 0; /* always for images */
+ /*tex always for images */
+ nat.dp = 0;
if (img_type(idict) == IMG_TYPE_PDF || img_type(idict) == IMG_TYPE_PDFMEMSTREAM
|| img_type(idict) == IMG_TYPE_PDFSTREAM) {
nat.wd = x;
@@ -591,7 +593,6 @@ scaled_whd scale_img(image_dict * idict, scaled_whd alt_rule, int transform)
return tex_scale(nat, alt_rule);
}
-@ @c
void write_img(PDF pdf, image_dict * idict)
{
if (img_state(idict) < DICT_WRITTEN) {
@@ -628,15 +629,17 @@ void write_img(PDF pdf, image_dict * idict)
img_state(idict) = DICT_WRITTEN;
}
-@ write an image
-@c
+int write_img_object(PDF pdf, image_dict * idict, int n)
+{
+ return write_epdf_object(pdf, idict, n);
+}
+
void pdf_write_image(PDF pdf, int n)
{
if (pdf->draftmode == 0)
write_img(pdf, idict_array[obj_data_ptr(pdf, n)]);
}
-@ @c
void check_pdfstream_dict(image_dict * idict)
{
if (!img_is_bbox(idict))
@@ -645,40 +648,43 @@ void check_pdfstream_dict(image_dict * idict)
img_state(idict) = DICT_FILESCANNED;
}
-@ @c
void write_pdfstream(PDF pdf, image_dict * idict)
{
pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "XObject");
pdf_dict_add_name(pdf, "Subtype", "Form");
- if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0)
- pdf_printf(pdf, "\n%s\n", img_attr(idict));
pdf_dict_add_int(pdf, "FormType", 1);
pdf_add_name(pdf, "BBox");
pdf_begin_array(pdf);
- copyReal(pdf, sp2bp(img_bbox(idict)[0]));
- copyReal(pdf, sp2bp(img_bbox(idict)[1]));
- copyReal(pdf, sp2bp(img_bbox(idict)[2]));
- copyReal(pdf, sp2bp(img_bbox(idict)[3]));
+ pdf_add_real(pdf, sp2bp(img_bbox(idict)[0]));
+ pdf_add_real(pdf, sp2bp(img_bbox(idict)[1]));
+ pdf_add_real(pdf, sp2bp(img_bbox(idict)[2]));
+ pdf_add_real(pdf, sp2bp(img_bbox(idict)[3]));
pdf_end_array(pdf);
- pdf_dict_add_streaminfo(pdf);
+ if (img_attr(idict) != NULL && strlen(img_attr(idict)) > 0) {
+ pdf_printf(pdf, "\n%s\n", img_attr(idict));
+ }
+ if (!img_nolength(idict)) {
+ pdf_dict_add_streaminfo(pdf);
+ }
pdf_end_dict(pdf);
pdf_begin_stream(pdf);
- if (img_pdfstream_stream(idict) != NULL)
- pdf_puts(pdf, img_pdfstream_stream(idict));
+ if (img_pdfstream_stream(idict) != NULL) {
+ pdf_out_block(pdf, (const char *) img_pdfstream_stream(idict), img_pdfstream_size(idict));
+ }
pdf_end_stream(pdf);
pdf_end_obj(pdf);
}
-@ @c
idict_entry *idict_ptr, *idict_array = NULL;
size_t idict_limit;
void idict_to_array(image_dict * idict)
{
- if (idict_ptr - idict_array == 0) { /* align to count from 1 */
- alloc_array(idict, 1, SMALL_BUF_SIZE); /* /Im0 unused */
+ if (idict_ptr - idict_array == 0) {
+ /*tex align to count from 1 */
+ alloc_array(idict, 1, SMALL_BUF_SIZE);
idict_ptr++;
}
alloc_array(idict, 1, SMALL_BUF_SIZE);
@@ -690,53 +696,60 @@ void pdf_dict_add_img_filename(PDF pdf, image_dict * idict)
{
char *p;
if ((pdf_image_addfilename > 0) && ((pdf_suppress_optional_info & 2) == 0)) {
- /* for now PTEX.FileName only for PDF, but prepared for JPG, PNG, ... */
+ /*tex
+ For now |PTEX.FileName| is only used for \PDF, but we're prepared
+ for \JPG, \PNG, ...
+ */
if (! ( (img_type(idict) == IMG_TYPE_PDF) || (img_type(idict) == IMG_TYPE_PDFMEMSTREAM) ))
return;
if (img_visiblefilename(idict) != NULL) {
if (strlen(img_visiblefilename(idict)) == 0) {
- return; /* empty string blocks PTEX.FileName output */
+ /*tex empty string blocks PTEX.FileName output */
+ return;
} else {
p = img_visiblefilename(idict);
}
} else {
- /* unset so let's use the default */
+ /*tex unset so let's use the default */
p = img_filepath(idict);
}
- // write additional information
+ /*tex write additional information */
pdf_add_name(pdf, "PTEX.FileName");
pdf_printf(pdf, " (%s)", convertStringToPDFString(p, strlen(p)));
}
}
-/* hh: why store images in the format ... let's get rid of this */
+/*tex
-@ To allow the use of box resources inside saved boxes in -ini mode,
-the information in the array has to be (un)dumped with the format.
-The next two routines take care of that.
+To allow the use of box resources inside saved boxes in -ini mode, the
+information in the array has to be (un)dumped with the format. The next two
+routines take care of that.
-Most of the work involved in setting up the images is simply
-executed again. This solves the many possible errors resulting from
-the split in two separate runs.
+Most of the work involved in setting up the images is simply executed again. This
+solves the many possible errors resulting from the split in two separate runs.
-There was only one problem remaining: The pdfversion and
-pdfinclusionerrorlevel can have changed inbetween the call to
-|readimage()| and dump time.
+There was only one problem remaining: The |pdfversion| and
+|pdfinclusionerrorlevel| can have changed inbetween the call to |readimage| and
+dump time.
-some of the dumped values are really type int, not integer,
-but since the macro falls back to |generic_dump| anyway, that
-does not matter.
+Some of the dumped values are really type int, not integer,but since the macro
+falls back to |generic_dump| anyway, that does not matter.
+
+We might drop this feature as it makes no sense to store images in the format.
+
+*/
-@c
#define dumpinteger generic_dump
#define undumpinteger generic_undump
-@ (un)dumping a string means dumping the allocation size, followed
- by the bytes. The trailing \.{\\0} is dumped as well, because that
- makes the code simpler.
+/*tex
+
+(Un)dumping a string means dumping the allocation size, followed by the bytes.
+The trailing \.{\\0} is dumped as well, because that makes the code simpler. The
+rule specification ends up in |alt_rule|.
+
+*/
-@ scan rule spec to |alt_rule|
-@c
scaled_whd scan_alt_rule(void)
{
boolean loop;
@@ -763,8 +776,12 @@ scaled_whd scan_alt_rule(void)
return alt_rule;
}
-@ copy file of arbitrary size to PDF buffer and flush as needed
-@c
+/*tex
+
+ This copy a file of arbitrary size to the buffer and flushed as needed.
+
+*/
+
size_t read_file_to_buf(PDF pdf, FILE * f, size_t len)
{
size_t i, j, k = 0;
diff --git a/Build/source/texk/web2c/luatexdir/image/writejbig2.w b/Build/source/texk/web2c/luatexdir/image/writejbig2.c
index a58313ce8d8..77a1ddb07ca 100644
--- a/Build/source/texk/web2c/luatexdir/image/writejbig2.w
+++ b/Build/source/texk/web2c/luatexdir/image/writejbig2.c
@@ -1,27 +1,30 @@
-% writejbig2.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-% Copyright 2003-2013 Hartmut Henkel <hartmut@@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/>.
-
-@
-This is experimental JBIG2 image support to pdfTeX. JBIG2 image decoding
-is part of Adobe PDF-1.4, and requires Acroread 5.0 or later.
+/*
+
+writejbig2.c
+
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+Copyright 2006-2013 Taco Hoekwater <taco@luatex.org>
+Copyright 2003-2013 Hartmut Henkel <hartmut@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 is experimental JBIG2 image support to pdfTeX. JBIG2 image decoding is part
+of Adobe PDF-1.4, and requires Acroread 5.0 or later.
References
==========
@@ -78,7 +81,8 @@ object exists, reference it. Else create fresh one.
09 Dec. 2002: JBIG2 seg. page numbers > 0 are now set to 1, see PDF Ref.
-@ @c
+*/
+
#undef DEBUG
#include "ptexlib.h"
@@ -87,8 +91,8 @@ object exists, reference it. Else create fresh one.
#include <assert.h>
#include "image/image.h"
-@ @c
-/* 7.3 Segment types */
+/*tex Table 7.3: Segment types */
+
#define M_SymbolDictionary 0
#define M_IntermediateTextRegion 4
#define M_ImmediateTextRegion 6
@@ -111,13 +115,12 @@ object exists, reference it. Else create fresh one.
#define M_Tables 53
#define M_Extension 62
-@ @c
typedef enum { INITIAL, HAVEINFO, WRITEPDF } PHASE;
typedef struct _LITEM {
struct _LITEM *prev;
struct _LITEM *next;
- void *d; /* data */
+ void *d;
} LITEM;
typedef struct _LIST {
@@ -130,26 +133,28 @@ typedef struct _SEGINFO {
unsigned long segnum;
boolean isrefered;
boolean refers;
- unsigned int seghdrflags; /* set by readseghdr() */
- boolean pageassocsizeflag; /* set by readseghdr() */
- unsigned int reftosegcount; /* set by readseghdr() */
- unsigned int countofrefered; /* set by readseghdr() */
- unsigned int fieldlen; /* set by readseghdr() */
- unsigned int segnumwidth; /* set by readseghdr() */
- long segpage; /* set by readseghdr() */
- unsigned long segdatalen; /* set by readseghdr() */
- unsigned long hdrstart; /* set by readseghdr() */
- unsigned long hdrend; /* set by readseghdr() */
+ /*tex Set by |readseghdr|: */
+ unsigned int seghdrflags;
+ boolean pageassocsizeflag;
+ unsigned int reftosegcount;
+ unsigned int countofrefered;
+ unsigned int fieldlen;
+ unsigned int segnumwidth;
+ long segpage;
+ unsigned long segdatalen;
+ unsigned long hdrstart;
+ unsigned long hdrend;
unsigned long datastart;
unsigned long dataend;
- boolean endofstripeflag; /* set by checkseghdrflags() */
- boolean endofpageflag; /* set by checkseghdrflags() */
- boolean pageinfoflag; /* set by checkseghdrflags() */
- boolean endoffileflag; /* set by checkseghdrflags() */
+ /*tex Set by |checkseghdrflags|: */
+ boolean endofstripeflag;
+ boolean endofpageflag;
+ boolean pageinfoflag;
+ boolean endoffileflag;
} SEGINFO;
typedef struct _PAGEINFO {
- LIST segments; /* segments associated with page */
+ LIST segments;
unsigned long pagenum;
unsigned int width;
unsigned int height;
@@ -164,17 +169,19 @@ typedef struct _FILEINFO {
FILE *file;
char *filepath;
long filesize;
- LIST pages; /* not including page0 */
+ /*tex Not including |page0|: */
+ LIST pages;
LIST page0;
- unsigned int filehdrflags; /* set by readfilehdr() */
- boolean sequentialaccess; /* set by readfilehdr() */
- unsigned long numofpages; /* set by readfilehdr() */
- unsigned long streamstart; /* set by |get_jbig2_info()| */
+ /*tex Set by |readfilehdr| */
+ unsigned int filehdrflags;
+ boolean sequentialaccess;
+ unsigned long numofpages;
+ /*tex Set by |get_jbig2_info| */
+ unsigned long streamstart;
unsigned long pdfpage0objnum;
PHASE phase;
} FILEINFO;
-@ @c
static struct avl_table *file_tree = NULL;
static int comp_file_entry(const void *pa, const void *pb, void *p)
@@ -195,7 +202,6 @@ static int comp_segment_entry(const void *pa, const void *pb, void *p)
return (int) (((const SEGINFO *) pa)->segnum - ((const SEGINFO *) pb)->segnum);
}
-@ @c
static int ygetc(FILE * stream)
{
int c = getc(stream);
@@ -208,7 +214,6 @@ static int ygetc(FILE * stream)
return c;
}
-@ @c
static void initlinkedlist(LIST * lp)
{
lp->first = NULL;
@@ -233,7 +238,6 @@ static LIST *litem_append(LIST * lp)
return lp;
}
-@ @c
static FILEINFO *new_fileinfo(void)
{
FILEINFO *fip;
@@ -252,7 +256,6 @@ static FILEINFO *new_fileinfo(void)
return fip;
}
-@ @c
static PAGEINFO *new_pageinfo(void)
{
PAGEINFO *pip;
@@ -269,7 +272,6 @@ static PAGEINFO *new_pageinfo(void)
return pip;
}
-@ @c
static void init_seginfo(SEGINFO * sip)
{
sip->segnum = 0;
@@ -293,7 +295,6 @@ static void init_seginfo(SEGINFO * sip)
sip->endoffileflag = false;
}
-@ @c
static void pages_maketree(LIST * plp)
{
LITEM *ip;
@@ -307,7 +308,6 @@ static void pages_maketree(LIST * plp)
}
}
-@ @c
static void segments_maketree(LIST * slp)
{
LITEM *ip;
@@ -321,7 +321,6 @@ static void segments_maketree(LIST * slp)
}
}
-@ @c
static PAGEINFO *find_pageinfo(LIST * plp, unsigned long pagenum)
{
PAGEINFO tmp;
@@ -330,7 +329,6 @@ static PAGEINFO *find_pageinfo(LIST * plp, unsigned long pagenum)
return (PAGEINFO *) avl_find(plp->tree, &tmp);
}
-@ @c
static SEGINFO *find_seginfo(LIST * slp, unsigned long segnum)
{
SEGINFO tmp;
@@ -339,21 +337,18 @@ static SEGINFO *find_seginfo(LIST * slp, unsigned long segnum)
return (SEGINFO *) avl_find(slp->tree, &tmp);
}
-@ @c
unsigned int read2bytes(FILE * f)
{
unsigned int c = (unsigned int) ygetc(f);
return (c << 8) + (unsigned int) ygetc(f);
}
-@ @c
unsigned int read4bytes(FILE * f)
{
unsigned int l = read2bytes(f);
return (l << 16) + read2bytes(f);
}
-@ @c
static unsigned long getstreamlen(LITEM * slip, boolean refer)
{
SEGINFO *sip;
@@ -366,39 +361,40 @@ static unsigned long getstreamlen(LITEM * slip, boolean refer)
return len;
}
-@ @c
static void readfilehdr(FILEINFO * fip)
{
unsigned int i;
- /* Annex D.4 File header syntax */
- /* Annex D.4.1 ID string */
+ /*tex Annex D.4: File header syntax */
+ /*tex Annex D.4.1: ID string */
unsigned char jbig2_id[] = { 0x97, 'J', 'B', '2', 0x0d, 0x0a, 0x1a, 0x0a };
xfseek(fip->file, 0, SEEK_SET, fip->filepath);
for (i = 0; i < 8; i++)
if (ygetc(fip->file) != jbig2_id[i])
normal_error("readjbig2","ID string missing");
- /* Annex D.4.2 File header flags */
+ /*tex Annex D.4.2: File header flags */
fip->filehdrflags = (unsigned int) ygetc(fip->file);
fip->sequentialaccess = (fip->filehdrflags & 0x01) ? true : false;
- if (fip->sequentialaccess) { /* Annex D.1 vs. Annex D.2 */
+ if (fip->sequentialaccess) {
+ /*tex Annex D.1 vs. Annex D.2 */
xfseek(fip->file, 0, SEEK_END, fip->filepath);
fip->filesize = (long) xftello(fip->file, fip->filepath);
xfseek(fip->file, 9, SEEK_SET, fip->filepath);
}
- /* Annex D.4.3 Number of pages */
- if (!(fip->filehdrflags >> 1) & 0x01) /* known number of pages */
+ /*tex Annex D.4.3: Number of pages */
+ if (( !(fip->filehdrflags >> 1)) & 0x01) {
+ /*tex The known number of pages: */
fip->numofpages = read4bytes(fip->file);
- /* --- at end of file header --- */
+ }
+ /*tex End of file header */
}
-@ @c
static void checkseghdrflags(SEGINFO * sip)
{
sip->endofstripeflag = false;
sip->endofpageflag = false;
sip->pageinfoflag = false;
sip->endoffileflag = false;
- /* 7.3 Segment types */
+ /*tex Table 7.3: Segment types */
switch (sip->seghdrflags & 0x3f) {
case M_SymbolDictionary:
case M_IntermediateTextRegion:
@@ -437,24 +433,34 @@ static void checkseghdrflags(SEGINFO * sip)
}
}
-@ for first reading of file; return value tells if header been read
+/*tex
+
+ For first reading of file; return value tells if header been read.
+
+*/
-@c
static boolean readseghdr(FILEINFO * fip, SEGINFO * sip)
{
unsigned int i;
sip->hdrstart = xftell(fip->file, fip->filepath);
- if (fip->sequentialaccess && sip->hdrstart == (unsigned) fip->filesize)
- return false; /* no endoffileflag is ok for sequentialaccess */
- /* 7.2.2 Segment number */
+ if (fip->sequentialaccess && sip->hdrstart == (unsigned) fip->filesize) {
+ /*tex No endoffileflag is ok for sequential access. */
+ return false;
+ }
+ /*tex Table 7.2.2: Segment number */
sip->segnum = read4bytes(fip->file);
- /* 7.2.3 Segment header flags */
+ /*tex Table 7.2.3: Segment header flags */
sip->seghdrflags = (unsigned int) ygetc(fip->file);
checkseghdrflags(sip);
- if (fip->sequentialaccess && sip->endoffileflag) /* accept shorter segment, */
- return true; /* makes it compliant with Example 3.4 of PDFRef. 5th ed. */
+ if (fip->sequentialaccess && sip->endoffileflag) {
+ /*
+ Accept shorter segment, makes it compliant with Example 3.4 of
+ PDFRef. 5th ed.
+ */
+ return true;
+ }
sip->pageassocsizeflag = ((sip->seghdrflags >> 6) & 0x01) ? true : false;
- /* 7.2.4 Referred-to segment count and retention flags */
+ /*tex Table 7.2.4: Referred-to segment count and retention flags */
sip->reftosegcount = (unsigned int) ygetc(fip->file);
sip->countofrefered = sip->reftosegcount >> 5;
if (sip->countofrefered < 5)
@@ -463,7 +469,7 @@ static boolean readseghdr(FILEINFO * fip, SEGINFO * sip)
sip->fieldlen = 5 + sip->countofrefered / 8;
xfseek(fip->file, sip->fieldlen - 1, SEEK_CUR, fip->filepath);
}
- /* 7.2.5 Referred-to segment numbers */
+ /*tex Table 7.2.5: Referred-to segment numbers */
if (sip->segnum <= 256)
sip->segnumwidth = 1;
else if (sip->segnum <= 65536)
@@ -483,19 +489,18 @@ static boolean readseghdr(FILEINFO * fip, SEGINFO * sip)
break;
}
}
- /* 7.2.6 Segment page association */
+ /*tex Table 7.2.6: Segment page association */
if (sip->pageassocsizeflag)
sip->segpage = read4bytes(fip->file);
else
sip->segpage = ygetc(fip->file);
- /* 7.2.7 Segment data length */
+ /*tex Table 7.2.7: Segment data length */
sip->segdatalen = read4bytes(fip->file);
sip->hdrend = (unsigned long) xftello(fip->file, fip->filepath);
- /* ---- at end of segment header ---- */
+ /*tex End of segment header. */
return true;
}
-@ @c
static void checkseghdr(FILEINFO * fip, SEGINFO * sip);
static void markpage0seg(FILEINFO * fip, unsigned long referedseg)
@@ -511,19 +516,23 @@ static void markpage0seg(FILEINFO * fip, unsigned long referedseg)
}
}
-@ for writing, marks refered page0 segments, sets segpage > 0 to 1
+/*tex
+
+ For writing, marks refered page0 segments, sets segpage larger than
+ zero to one.
+
+*/
-@c
static void writeseghdr(PDF pdf, FILEINFO * fip, SEGINFO * sip)
{
unsigned int i;
unsigned long referedseg = 0;
- /* 7.2.2 Segment number */
- /* 7.2.3 Segment header flags */
- /* 7.2.4 Referred-to segment count and retention flags */
+ /*tex Table 7.2.2: Segment number */
+ /*tex Table 7.2.3: Segment header flags */
+ /*tex Table 7.2.4: Referred-to segment count and retention flags */
for (i = 0; i < 5 + sip->fieldlen; i++)
pdf_out(pdf, ygetc(fip->file));
- /* 7.2.5 Referred-to segment numbers */
+ /*tex Table 7.2.5: Referred-to segment numbers */
for (i = 0; i < sip->countofrefered; i++) {
switch (sip->segnumwidth) {
case 1:
@@ -548,7 +557,7 @@ static void writeseghdr(PDF pdf, FILEINFO * fip, SEGINFO * sip)
}
if (sip->countofrefered > 0)
sip->refers = true;
- /* 7.2.6 Segment page association */
+ /*tex Table 7.2.6: Segment page association */
if (sip->pageassocsizeflag)
for (i = 0; i < 3; i++) {
(void) ygetc(fip->file);
@@ -556,23 +565,27 @@ static void writeseghdr(PDF pdf, FILEINFO * fip, SEGINFO * sip)
}
(void) ygetc(fip->file);
pdf_out(pdf, (unsigned char) ((sip->segpage > 0) ? 1 : 0));
- /* 7.2.7 Segment data length */
+ /*tex Table 7.2.7: Segment data length */
for (i = 0; i < 4; i++)
pdf_out(pdf, ygetc(fip->file));
- /* ---- at end of segment header ---- */
+ /* End of segment header. */
}
-@ for recursive marking of refered page0 segments
-@c
+/*tex
+
+ For recursive marking of refered page0 segments:
+
+*/
+
static void checkseghdr(FILEINFO * fip, SEGINFO * sip)
{
unsigned int i;
unsigned long referedseg = 0;
- /* 7.2.2 Segment number */
- /* 7.2.3 Segment header flags */
- /* 7.2.4 Referred-to segment count and retention flags */
+ /*tex Table 7.2.2: Segment number */
+ /*tex Table 7.2.3: Segment header flags */
+ /*tex Table 7.2.4: Referred-to segment count and retention flags */
xfseek(fip->file, 5 + sip->fieldlen, SEEK_CUR, fip->filepath);
- /* 7.2.5 Referred-to segment numbers */
+ /*tex Table 7.2.5: Referred-to segment numbers */
for (i = 0; i < sip->countofrefered; i++) {
switch (sip->segnumwidth) {
case 1:
@@ -590,33 +603,34 @@ static void checkseghdr(FILEINFO * fip, SEGINFO * sip)
}
if (sip->countofrefered > 0)
sip->refers = true;
- /* 7.2.6 Segment page association */
- /* 7.2.7 Segment data length */
+ /*tex Table 7.2.6: Segment page association */
+ /*tex Table 7.2.7: Segment data length */
if (sip->pageassocsizeflag)
xfseek(fip->file, 8, SEEK_CUR, fip->filepath);
else
xfseek(fip->file, 5, SEEK_CUR, fip->filepath);
- /* ---- at end of segment header ---- */
+ /*tex End of segment header. */
}
-@ @c
static unsigned long findstreamstart(FILEINFO * fip)
{
SEGINFO tmp;
- assert(!fip->sequentialaccess); /* D.2 Random-access organisation */
- do /* find random-access stream start */
+ /*tex Table D.2: Random-access organisation */
+ do {
+ /*tex Find random-access stream start. */
(void) readseghdr(fip, &tmp);
- while (!tmp.endoffileflag);
+ } while (!tmp.endoffileflag);
fip->streamstart = tmp.hdrend;
readfilehdr(fip);
return fip->streamstart;
}
-@ @c
static void rd_jbig2_info(FILEINFO * fip)
{
- unsigned long seekdist = 0; /* for sequential-access only */
- unsigned long streampos = 0; /* for random-access only */
+ /*tex For sequential-access only: */
+ unsigned long seekdist = 0;
+ /*tex For random-access only: */
+ unsigned long streampos = 0;
unsigned long currentpage = 0;
boolean sipavail = false;
PAGEINFO *pip;
@@ -624,9 +638,12 @@ static void rd_jbig2_info(FILEINFO * fip)
LIST *plp, *slp;
fip->file = xfopen(fip->filepath, FOPEN_RBIN_MODE);
readfilehdr(fip);
- if (!fip->sequentialaccess) /* D.2 Random-access organisation */
+ if (!fip->sequentialaccess) {
+ /*tex Table D.2: Random-access organisation */
streampos = findstreamstart(fip);
- while (true) { /* loop over segments */
+ }
+ while (true) {
+ /*tex Loop over segments: */
if (!sipavail) {
sip = xtalloc(1, SEGINFO);
sipavail = true;
@@ -658,11 +675,10 @@ static void rd_jbig2_info(FILEINFO * fip)
else
sip->datastart = sip->hdrend;
sip->dataend = sip->datastart + sip->segdatalen;
- if (!fip->sequentialaccess
- && (sip->pageinfoflag || sip->endofstripeflag))
+ if (!fip->sequentialaccess && (sip->pageinfoflag || sip->endofstripeflag))
xfseeko(fip->file, (off_t) sip->datastart, SEEK_SET, fip->filepath);
seekdist = sip->segdatalen;
- /* 7.4.8 Page information segment syntax */
+ /*tex Table 7.4.8: Page information segment syntax */
if (sip->pageinfoflag) {
pip->pagenum = (unsigned long) sip->segpage;
pip->width = read4bytes(fip->file);
@@ -670,7 +686,7 @@ static void rd_jbig2_info(FILEINFO * fip)
pip->xres = read4bytes(fip->file);
pip->yres = read4bytes(fip->file);
pip->pagesegmentflags = (unsigned) ygetc(fip->file);
- /* 7.4.8.6 Page striping information */
+ /*tex Table 7.4.8.6: Page striping information */
pip->stripinginfo = read2bytes(fip->file);
seekdist -= 19;
}
@@ -694,9 +710,7 @@ static void rd_jbig2_info(FILEINFO * fip)
xfclose(fip->file, fip->filepath);
}
-@ @c
-static void wr_jbig2(PDF pdf, image_dict * idict, FILEINFO * fip,
- unsigned long page)
+static void wr_jbig2(PDF pdf, image_dict * idict, FILEINFO * fip, unsigned long page)
{
LITEM *slip;
PAGEINFO *pip;
@@ -743,11 +757,12 @@ static void wr_jbig2(PDF pdf, image_dict * idict, FILEINFO * fip,
}
pdf_begin_stream(pdf);
fip->file = xfopen(fip->filepath, FOPEN_RBIN_MODE);
- for (slip = pip->segments.first; slip != NULL; slip = slip->next) { /* loop over page segments */
+ for (slip = pip->segments.first; slip != NULL; slip = slip->next) {
+ /*tex Loop over page segments. */
sip = slip->d;
if (sip->isrefered || page > 0) {
xfseeko(fip->file, (off_t) sip->hdrstart, SEEK_SET, fip->filepath);
- /* mark refered-to page 0 segments, change segpages > 1 to 1 */
+ /*tex Mark refered-to page 0 segments, change segpages > 1 to 1. */
writeseghdr(pdf, fip, sip);
xfseeko(fip->file, (off_t) sip->datastart, SEEK_SET, fip->filepath);
for (i = sip->datastart; i < sip->dataend; i++)
@@ -759,7 +774,6 @@ static void wr_jbig2(PDF pdf, image_dict * idict, FILEINFO * fip,
xfclose(fip->file, fip->filepath);
}
-@ @c
boolean supported_jbig2(image_dict * idict)
{
if (img_pdfmajorversion(idict) < 2 && img_pdfminorversion(idict) < 4) {
@@ -770,20 +784,19 @@ boolean supported_jbig2(image_dict * idict)
}
}
-@ @c
void flush_jbig2_info(image_dict * idict)
{
- /* todo */
+ /*tex Todo (or not). */
}
-@ @c
void read_jbig2_info(image_dict * idict)
{
FILEINFO *fip, tmp;
PAGEINFO *pip;
- img_type(idict) = IMG_TYPE_JBIG2; /* already set probably, see other read_... */
+ /*tex Already set probably, see other |read_|. */
+ img_type(idict) = IMG_TYPE_JBIG2;
if (! supported_jbig2(idict)) {
- /* already an error done */
+ /*tex Already an error seen? */
}
if (img_pagenum(idict) < 1) {
normal_error("readjbig2","page must be > 0");
@@ -819,24 +832,19 @@ void read_jbig2_info(image_dict * idict)
img_colordepth(idict) = 1;
}
-@ @c
void write_jbig2(PDF pdf, image_dict * idict)
{
FILEINFO *fip, tmp;
PAGEINFO *pip;
- assert(idict != NULL);
- assert(file_tree != NULL);
tmp.filepath = img_filepath(idict);
fip = (FILEINFO *) avl_find(file_tree, &tmp);
- assert(fip != NULL);
- assert(fip->phase == HAVEINFO); /* don't write before |rd_jbig2_info()| call */
+ /*tex Don't write before |rd_jbig2_info()| call. */
pip = find_pageinfo(&(fip->pages), (unsigned long) img_pagenum(idict));
assert(pip != NULL);
wr_jbig2(pdf, idict, fip, pip->pagenum);
img_file(idict) = NULL;
}
-@ @c
void flush_jbig2_page0_objects(PDF pdf)
{
FILEINFO *fip;
@@ -846,7 +854,8 @@ void flush_jbig2_page0_objects(PDF pdf)
for (fip = avl_t_first(&t, file_tree); fip != NULL;
fip = avl_t_next(&t)) {
if (fip->page0.last != NULL)
- wr_jbig2(pdf, NULL, fip, 0); /* NULL: page0 */
+ /*tex |NULL|: page0 */
+ wr_jbig2(pdf, NULL, fip, 0);
}
}
}
diff --git a/Build/source/texk/web2c/luatexdir/image/writejp2.w b/Build/source/texk/web2c/luatexdir/image/writejp2.c
index cb317e11928..0ea0017084a 100644
--- a/Build/source/texk/web2c/luatexdir/image/writejp2.w
+++ b/Build/source/texk/web2c/luatexdir/image/writejp2.c
@@ -1,38 +1,42 @@
-% writejp2.w
-%
-% Copyright 2011-2013 Taco Hoekwater <taco@@luatex.org>
-% Copyright 2011-2013 Hartmut Henkel <hartmut@@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
+writejp2.c
-@ Basic JPEG~2000 image support. Section and Table references below:
-Information technology --- JPEG~2000 image coding system: Core coding system.
-ISO/IEC 15444-1, Second edition, 2004-09-15, file |15444-1annexi.pdf|.
+Copyright 2011-2013 Taco Hoekwater <taco@luatex.org>
+Copyright 2011-2013 Hartmut Henkel <hartmut@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
+
+ Basic JPEG~2000 image support. Section and Table references below:
+ Information technology --- JPEG~2000 image coding system: Core coding system.
+ ISO/IEC 15444-1, Second edition, 2004-09-15, file |15444-1annexi.pdf|.
+
+*/
-@c
#include "ptexlib.h"
#include <math.h>
#include <assert.h>
#include "image/image.h"
#include "image/writejp2.h"
-#include "image/writejbig2.h" /* read2bytes(), read4bytes() */
+#include "image/writejbig2.h"
+
+/*tex Table 1.2: Defined boxes */
-/* Table 1.2 -- Defined boxes */
#define BOX_JP 0x6A502020
#define BOX_FTYP 0x66747970
#define BOX_JP2H 0x6a703268
@@ -45,7 +49,8 @@ ISO/IEC 15444-1, Second edition, 2004-09-15, file |15444-1annexi.pdf|.
#define BOX_RESD 0x72657364
#define BOX_JP2C 0x6A703263
-/* 1.4 Box definition */
+/*tex Table 1.4: Box definition */
+
typedef struct {
uint64_t lbox;
unsigned int tbox;
@@ -71,7 +76,8 @@ static hdr_struct read_boxhdr(image_dict * idict)
return hdr;
}
-/* 1.5.3.1 Image Header box */
+/*tex Table 1.5.3.1: Image Header box */
+
static void scan_ihdr(image_dict * idict)
{
unsigned int height, width;
@@ -88,8 +94,9 @@ static void scan_ihdr(image_dict * idict)
(void) xgetc(img_file(idict)); /* ipr */
}
-/* 1.5.3.7.1 Capture Resolution box */
-/* 1.5.3.7.2 Default Display Resolution box */
+/*tex Table 1.5.3.7.1: Capture Resolution box */
+
+/*tex Table 1.5.3.7.2: Default Display Resolution box */
static void scan_resc_resd(image_dict * idict)
{
@@ -108,7 +115,7 @@ static void scan_resc_resd(image_dict * idict)
img_yres(idict) = (int) (vr_ + 0.5);
}
-/* 1.5.3.7 Resolution box (superbox) */
+/*tex Table 1.5.3.7: Resolution box (superbox) */
static void scan_res(image_dict * idict, uint64_t epos_s)
{
@@ -121,7 +128,7 @@ static void scan_res(image_dict * idict, uint64_t epos_s)
epos = spos + hdr.lbox;
switch (hdr.tbox) {
case (BOX_RESC):
- /* arbitrarily: let BOX_RESD have precedence */
+ /*tex arbitrary: let BOX_RESD have precedence */
if (img_xres(idict) == 0 && img_yres(idict) == 0) {
scan_resc_resd(idict);
if (xftell(img_file(idict), img_filepath(idict)) != (long)epos)
@@ -143,7 +150,7 @@ static void scan_res(image_dict * idict, uint64_t epos_s)
}
}
-/* 1.5.3 JP2 Header box (superbox) */
+/*tex Table 1.5.3: JP2 Header box (superbox) */
static boolean scan_jp2h(image_dict * idict, uint64_t epos_s)
{
@@ -178,7 +185,7 @@ static boolean scan_jp2h(image_dict * idict, uint64_t epos_s)
static void close_and_cleanup_jp2(image_dict * idict)
{
- /* if one of then is not NULL we already cleaned up */
+ /*tex If one of then is not NULL we already cleaned up. */
if (img_file(idict) != NULL) {
xfclose(img_file(idict), img_filepath(idict));
img_file(idict) = NULL;
@@ -216,11 +223,11 @@ void read_jp2_info(image_dict * idict)
normal_error("readjp2","size problem");
}
spos = epos = 0;
- /* 1.5.1 JPEG 2000 Signature box */
+ /*tex Table 1.5.1: JPEG 2000 Signature box */
hdr = read_boxhdr(idict);
epos = spos + hdr.lbox;
xfseek(img_file(idict), (long) epos, SEEK_SET, img_filepath(idict));
- /* 1.5.2 File Type box */
+ /*tex Table 1.5.2: File Type box */
spos = epos;
hdr = read_boxhdr(idict);
if (hdr.tbox != BOX_FTYP) {
@@ -256,9 +263,7 @@ static void reopen_jp2(image_dict * idict)
height = img_ysize(idict);
xres = img_xres(idict);
yres = img_yres(idict);
- /*
- we need to make sure that the file kept open
- */
+ /*tex We need to make sure that the file kept open. */
img_keepopen(idict) = 1;
read_jp2_info(idict);
if (width != img_xsize(idict) || height != img_ysize(idict)
@@ -292,6 +297,6 @@ void write_jp2(PDF pdf, image_dict * idict)
normal_error("writejp2","fread failed");
pdf_end_stream(pdf);
pdf_end_obj(pdf);
- /* always */
+ /*tex We always:*/
close_and_cleanup_jp2(idict);
}
diff --git a/Build/source/texk/web2c/luatexdir/image/writejpg.w b/Build/source/texk/web2c/luatexdir/image/writejpg.c
index 54ed47f0f92..f58dc2aa642 100644
--- a/Build/source/texk/web2c/luatexdir/image/writejpg.w
+++ b/Build/source/texk/web2c/luatexdir/image/writejpg.c
@@ -1,31 +1,30 @@
-% writejpg.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
+/*
+
+writejpg.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/>.
+
+*/
#include "ptexlib.h"
#include <assert.h>
#include "image/image.h"
#include "image/writejpg.h"
-@ @c
#define JPG_GRAY 1 /* Gray color space, use /DeviceGray */
#define JPG_RGB 3 /* RGB color space, use /DeviceRGB */
#define JPG_CMYK 4 /* CMYK color space, use /DeviceCMYK */
@@ -97,7 +96,6 @@ typedef enum {
M_ERROR = 0x100 /* dummy marker, internal use only */
} JPEG_MARKER;
-@ @c
static unsigned int read_exif_bytes(unsigned char **p, int n, int b)
{
unsigned int rval = 0;
@@ -128,28 +126,31 @@ static unsigned int read_exif_bytes(unsigned char **p, int n, int b)
return rval;
}
-@ The Exif block can contain the data on the resolution in two forms:
-XResolution, YResolution and ResolutionUnit (tag 282, 283 and 296)
-as well as PixelPerUnitX, PixelPerUnitY and PixelUnit (tag 0x5111,
-0x5112 and 0x5110). Tags 282, 293 and 296 have the priority,
-with ResolutionUnit set to inch by default, then
-tag 0x5110, 0x5111 and 0x5112, where the only valid value for PixelUnit is 0.0254,
-and finally the given value xx and yy,
-choosen if the Exif x and y resolution are not strictly positive.
+/*tex
+
+ The Exif block can contain the data on the resolution in two forms:
+ XResolution, YResolution and ResolutionUnit (tag 282, 283 and 296) as well as
+ PixelPerUnitX, PixelPerUnitY and PixelUnit (tag 0x5111, 0x5112 and 0x5110).
+ Tags 282, 293 and 296 have the priority, with ResolutionUnit set to inch by
+ default, then tag 0x5110, 0x5111 and 0x5112, where the only valid value for
+ PixelUnit is 0.0254, and finally the given value xx and yy, choosen if the
+ Exif x and y resolution are not strictly positive.
+ The next one doesn't save the data, just reads the tags we need based on info
+ from \typ {http://www.exif.org/Exif2-2.PDF}.
+
+*/
-@ @c
static void read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy, int *or)
{
- /* this doesn't save the data, just reads the tags we need */
- /* based on info from http://www.exif.org/Exif2-2.PDF */
unsigned char *buffer = (unsigned char *)xmalloc(length);
unsigned char *p, *rp;
unsigned char *tiff_header;
char bigendian;
int i;
int num_fields, tag, type;
- int value = 0;/* silence uninitialized warnings */
+ /*tex silence uninitialized warnings */
+ int value = 0;
unsigned int num = 0;
unsigned int den = 0;
boolean found_x = false;
@@ -165,7 +166,6 @@ static void read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy, i
boolean found_x_ms = false;
boolean found_y_ms = false;
boolean found_res= false;
-
int orientation = 1;
size_t ret_len;
ret_len = fread(buffer, length, 1, fp);
@@ -193,52 +193,65 @@ static void read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy, i
type = read_exif_bytes(&p, 2, bigendian);
read_exif_bytes(&p, 4, bigendian);
switch (type) {
- case 1: /* byte */
+ case 1:
+ /*tex byte */
value = *p++;
p += 3;
break;
- case 3: /* unsigned short */
- case 8: /* signed short */
+ case 3:
+ /*tex unsigned short */
+ case 8:
+ /*tex signed short */
value = read_exif_bytes(&p, 2, bigendian);
p += 2;
break;
- case 4: /* unsigned long */
- case 9: /* signed long */
+ case 4:
+ /*tex unsigned long */
+ case 9:
+ /*tex signed long */
value = read_exif_bytes(&p, 4, bigendian);
break;
- case 5: /* rational */
- case 10: /* srational */
+ case 5:
+ /*tex rational */
+ case 10:
+ /*tex srational */
value = read_exif_bytes(&p, 4, bigendian);
rp = tiff_header + value;
num = read_exif_bytes(&rp, 4, bigendian);
den = read_exif_bytes(&rp, 4, bigendian);
break;
- case 7: /* undefined */
+ case 7:
+ /*tex undefined */
value = *p++;
p += 3;
break;
- case 2: /* ascii */
+ case 2:
+ /*tex ascii */
default:
p += 4;
break;
}
switch (tag) {
- case 274: /* orientation */
+ case 274:
+ /*tex orientation */
orientation = value;
break;
- case 282: /* x res */
+ case 282:
+ /*tex x res */
if (den != 0) {
xres = num / den;
found_x = true;
- }
+ }
break;
- case 283: /* y res */
+ case 283:
+ /*tex y res */
if (den != 0) {
yres = num / den;
found_y = true ;
- }
+ }
break;
- case 296: /* res unit */
+ case 296:
+ /*tex res unit */
switch (value) {
case 2:
res_unit = 1.0;
@@ -250,69 +263,69 @@ static void read_APP1_Exif (FILE *fp, unsigned short length, int *xx, int *yy, i
res_unit = 0;
break;
}
- case 0x5110: /* PixelUnit */
- switch (value) {
+ break;
+ case 0x5110:
+ /*tex PixelUnit */
+ switch (value) {
case 1:
- res_unit_ms = 0.0254; /* Unit is meter */
- break;
- default:
- res_unit_ms = 0;
- }
- case 0x5111: /* PixelPerUnitX */
+ res_unit_ms = 0.0254; /* Unit is meter */
+ break;
+ default:
+ res_unit_ms = 0;
+ }
+ break;
+ case 0x5111:
+ /*tex PixelPerUnitX */
found_x_ms = true ;
- xres_ms = value;
- break;
- case 0x5112: /* PixelPerUnitY */
+ xres_ms = value;
+ break;
+ case 0x5112:
+ /*tex PixelPerUnitY */
found_y_ms = true ;
- yres_ms = value ;
- break;
- }
-
-
+ yres_ms = value ;
+ break;
+ }
}
if (found_x && found_y && res_unit>0) {
- found_res = true;
- tempx = (int)(xres * res_unit+0.5);
- tempy = (int)(yres * res_unit+0.5);
+ found_res = true;
+ tempx = (int)(xres * res_unit+0.5);
+ tempy = (int)(yres * res_unit+0.5);
} else if (found_x_ms && found_y_ms && res_unit_ms==0.0254) {
- found_res = true;
- tempx = (int)(xres_ms * res_unit_ms+0.5);
- tempy = (int)(yres_ms * res_unit_ms+0.5);
+ found_res = true;
+ tempx = (int)(xres_ms * res_unit_ms+0.5);
+ tempy = (int)(yres_ms * res_unit_ms+0.5);
}
if (found_res) {
- if (tempx>0 && tempy>0) {
- if ((tempx!=(*xx) || tempy!=(*yy)) && (*xx!=0 && (*yy!=0) ) ) {
- formatted_warning("readjpg","Exif resolution %ddpi x %ddpi differs from the input resolution %ddpi x %ddpi",tempx,tempy,*xx,*yy);
- }
- if (tempx==1 || tempy==1) {
- formatted_warning("readjpg","Exif resolution %ddpi x %ddpi looks weird", tempx, tempy);
- }
- *xx = tempx;
- *yy = tempy;
- }else {
- formatted_warning("readjpg","Bad Exif resolution %ddpi x %ddpi (zero or negative value of a signed integer)",tempx,tempy);
- }
+ if (tempx>0 && tempy>0) {
+ if ((tempx!=(*xx) || tempy!=(*yy)) && (*xx!=0 && (*yy!=0) ) ) {
+ formatted_warning("readjpg","Exif resolution %ddpi x %ddpi differs from the input resolution %ddpi x %ddpi",tempx,tempy,*xx,*yy);
+ }
+ if (tempx==1 || tempy==1) {
+ formatted_warning("readjpg","Exif resolution %ddpi x %ddpi looks weird", tempx, tempy);
+ }
+ *xx = tempx;
+ *yy = tempy;
+ } else {
+ formatted_warning("readjpg","Bad Exif resolution %ddpi x %ddpi (zero or negative value of a signed integer)",tempx,tempy);
+ }
}
-
*or = orientation;
-
err:
free(buffer);
return;
}
-/*
+/*tex
- Contrary to pdf where several parallel usage can happen (epdf, tex, lua) with
- bitmaps we care less about keeping files open. So, we can keep files open in
- the img lib but then they are closed after inclusion anyway.
+ Contrary to \PDF\ where several parallel usage can happen (\PDF, |TEX, \LUA)
+ with bitmaps we care less about keeping files open. So, we can keep files
+ open in the img lib but then they are closed after inclusion anyway.
*/
-@ @c
static void close_and_cleanup_jpg(image_dict * idict)
{
- /* if one of then is not NULL we already cleaned up */
+ /*tex if one of then is not NULL we already cleaned up */
if (img_file(idict) != NULL) {
xfclose(img_file(idict), img_filepath(idict));
img_file(idict) = NULL;
@@ -322,19 +335,21 @@ static void close_and_cleanup_jpg(image_dict * idict)
}
}
-@ @c
void flush_jpg_info(image_dict * idict)
{
close_and_cleanup_jpg(idict);
}
-@ The jpeg images are scanned for resolution, colorspace, depth, dimensions and
-orientation. We need to look at the exif blob for that. The original version did
-a quick test for jfif and exif but there can be more blobs later on. The current
-approach is to run over the linked list of blobs which is somewhat less efficient
-but not noticeable.
+/*tex
+
+ The jpeg images are scanned for resolution, colorspace, depth, dimensions and
+ orientation. We need to look at the exif blob for that. The original version
+ did a quick test for jfif and exif but there can be more blobs later on. The
+ current approach is to run over the linked list of blobs which is somewhat
+ less efficient but not noticeable.
+
+*/
-@ @c
void read_jpg_info(image_dict * idict)
{
int i, position, units = 0;
@@ -381,16 +396,20 @@ void read_jpg_info(image_dict * idict)
position = ftell(fp);
length = 0 ;
switch (i) {
- case M_SOF3: /* lossless */
+ case M_SOF3:
+ /*tex lossless */
case M_SOF5:
case M_SOF6:
- case M_SOF7: /* lossless */
+ case M_SOF7:
+ /*tex lossless */
case M_SOF9:
case M_SOF10:
- case M_SOF11: /* lossless */
+ case M_SOF11:
+ /*tex lossless */
case M_SOF13:
case M_SOF14:
- case M_SOF15: /* lossless */
+ case M_SOF15:
+ /*tex lossless */
formatted_error("readjpg","unsupported compression SOF_%d", i - M_SOF0);
break;
case M_SOF2:
@@ -399,7 +418,8 @@ void read_jpg_info(image_dict * idict)
}
case M_SOF0:
case M_SOF1:
- length = (int) read2bytes(fp); /* read segment length */
+ /*tex read segment length */
+ length = (int) read2bytes(fp);
img_colordepth(idict) = xgetc(fp);
img_ysize(idict) = (int) read2bytes(fp);
img_xsize(idict) = (int) read2bytes(fp);
@@ -427,19 +447,20 @@ void read_jpg_info(image_dict * idict)
if (fread(app_sig, sizeof(char), 5, fp) != 5)
return;
if (!memcmp(app_sig, "JFIF\000", 5)) {
- units = (int) read2bytes(fp); /*skip two bytes, compiler is also happy*/
+ /*tex skip two bytes, compiler is also happy*/
+ units = (int) read2bytes(fp);
units = xgetc(fp);
img_xres(idict) = (int) read2bytes(fp);
img_yres(idict) = (int) read2bytes(fp);
switch (units) {
case 1:
- /* pixels per inch */
+ /*tex pixels per inch */
if ((img_xres(idict) == 1) || (img_yres(idict) == 1)) {
formatted_warning("readjpg","unusual resolution of %ddpi by %ddpi", img_xres(idict), img_yres(idict));
}
break;
case 2:
- /* pixels per cm */
+ /*tex pixels per cm */
img_xres(idict) = (int) ((double) img_xres(idict) * 2.54);
img_yres(idict) = (int) ((double) img_yres(idict) * 2.54);
break;
@@ -448,7 +469,10 @@ void read_jpg_info(image_dict * idict)
break;
}
}
- /* if either xres or yres is 0 but the other isn't, set it to the value of the other */
+ /*tex
+ If either xres or yres is 0 but the other isn't, set
+ it to the value of the other.
+ */
}
}
break;
@@ -471,7 +495,7 @@ void read_jpg_info(image_dict * idict)
}
}
break;
- /* ignore markers without parameters */
+ /*tex ignore markers without parameters */
case M_SOI:
case M_EOI:
case M_TEM:
@@ -485,23 +509,18 @@ void read_jpg_info(image_dict * idict)
case M_RST7:
break;
default:
- /* skip variable length markers */
+ /*tex skip variable length markers */
length = (int) read2bytes(fp);
break;
}
- /*
- printf("marker %X : %i %i\n",i,position,length);
- */
if (length > 0) {
xfseek(fp, position + length, SEEK_SET, img_filepath(idict));
}
}
- /* moved */
xfseek(fp, 0, SEEK_SET, img_filepath(idict));
if (! img_keepopen(idict)) {
close_and_cleanup_jpg(idict);
}
- /* */
if (okay){
if ((img_xres(idict) == 0) && (img_yres(idict) != 0)) {
img_xres(idict) = img_yres(idict);
@@ -514,14 +533,13 @@ void read_jpg_info(image_dict * idict)
}
}
-@ @c
static void reopen_jpg(image_dict * idict)
{
int width = img_xsize(idict);
int height = img_ysize(idict);
int xres = img_xres(idict);
int yres = img_yres(idict);
- /*
+ /*tex
we need to make sure that the file kept open
*/
img_keepopen(idict) = 1;
@@ -531,7 +549,6 @@ static void reopen_jpg(image_dict * idict)
}
}
-@ @c
void write_jpg(PDF pdf, image_dict * idict)
{
size_t l;
@@ -588,6 +605,5 @@ void write_jpg(PDF pdf, image_dict * idict)
}
pdf_end_stream(pdf);
pdf_end_obj(pdf);
- /* always */
close_and_cleanup_jpg(idict);
}
diff --git a/Build/source/texk/web2c/luatexdir/image/writepng.w b/Build/source/texk/web2c/luatexdir/image/writepng.c
index 412000c427f..165e202f4e3 100644
--- a/Build/source/texk/web2c/luatexdir/image/writepng.w
+++ b/Build/source/texk/web2c/luatexdir/image/writepng.c
@@ -1,36 +1,32 @@
-% writepng.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
+/*
+
+writepng.c
+
+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/>.
+
+*/
#include "ptexlib.h"
#include <assert.h>
#include "image/image.h"
#include "image/writepng.h"
-@ @c
-static int transparent_page_group = -1;
-
static void close_and_cleanup_png(image_dict * idict)
{
- /* if one of then is not NULL we already cleaned up */
if (img_file(idict) != NULL) {
xfclose(img_file(idict), img_filepath(idict));
img_file(idict) = NULL;
@@ -41,16 +37,16 @@ static void close_and_cleanup_png(image_dict * idict)
}
}
-@ @c
void flush_png_info(image_dict * idict)
{
close_and_cleanup_png(idict);
}
-@ @c
+/*tex A dummy function: */
+
static void warn(png_structp png_ptr, png_const_charp msg)
{
- (void)png_ptr; (void)msg; /* Make compiler happy */
+ (void)png_ptr; (void)msg;
}
void read_png_info(image_dict * idict)
@@ -80,12 +76,12 @@ void read_png_info(image_dict * idict)
normal_error("readpng","internal error");
}
#if PNG_LIBPNG_VER >= 10603
- /* ignore possibly incorrect CMF bytes */
+ /*tex ignore possibly incorrect CMF bytes */
png_set_option(png_p, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
#endif
png_init_io(png_p, img_file(idict));
png_read_info(png_p, info_p);
- /* resolution support */
+ /*tex resolution support */
img_xsize(idict) = (int) png_get_image_width(png_p, info_p);
img_ysize(idict) = (int) png_get_image_height(png_p, info_p);
if (png_get_valid(png_p, info_p, PNG_INFO_pHYs)) {
@@ -108,15 +104,12 @@ void read_png_info(image_dict * idict)
formatted_error("readpng","unsupported type of color_type '%i'",(int) png_get_color_type(png_p, info_p));
}
img_colordepth(idict) = png_get_bit_depth(png_p, info_p);
- /*
- So we can optionally keep open a file in img.
- */
+ /*tex So we can optionally keep open a file in |img|. */
if (! img_keepopen(idict)) {
close_and_cleanup_png(idict);
}
}
-@ @c
#define write_gray_pixel_16(r) \
if (j % 4 == 0 || j % 4 == 1) \
pdf_quick_out(pdf, *r++); \
@@ -173,7 +166,6 @@ void read_png_info(image_dict * idict)
xfree(rows[i]); \
}
-@ @c
static void write_palette_streamobj(PDF pdf, int palette_objnum, png_colorp palette, int num_palette)
{
int i;
@@ -195,7 +187,6 @@ static void write_palette_streamobj(PDF pdf, int palette_objnum, png_colorp pale
pdf_end_obj(pdf);
}
-@ @c
static void write_smask_streamobj(PDF pdf, image_dict * idict, int smask_objnum, png_bytep smask, int smask_size)
{
int i;
@@ -227,7 +218,6 @@ static void write_smask_streamobj(PDF pdf, image_dict * idict, int smask_objnum,
pdf_end_obj(pdf);
}
-@ @c
static void write_png_gray(PDF pdf, image_dict * idict)
{
int i;
@@ -258,7 +248,6 @@ static void write_png_gray(PDF pdf, image_dict * idict)
pdf_end_obj(pdf);
}
-@ @c
static void write_png_gray_alpha(PDF pdf, image_dict * idict)
{
int i;
@@ -307,7 +296,6 @@ static void write_png_gray_alpha(PDF pdf, image_dict * idict)
xfree(smask);
}
-@ @c
static void write_png_rgb_alpha(PDF pdf, image_dict * idict)
{
int i;
@@ -356,20 +344,21 @@ static void write_png_rgb_alpha(PDF pdf, image_dict * idict)
xfree(smask);
}
-@ The |copy_png| code is cheerfully gleaned from Thomas Merz' PDFlib,
-file |p_png.c| ``SPNG - Simple PNG''.
-The goal is to use pdf's native FlateDecode support, if that is possible.
-Only a subset of the png files allows this, but for these it greatly
-improves inclusion speed.
+/*tex
-In the ``PNG Copy'' mode only the IDAT chunks are copied;
-all other chunks from the PNG file are discarded.
-If there are any other chunks in the PNG file,
-which might influence the visual appearance of the image,
-or if image processing like gamma change is requested,
-the ``PNG Copy'' function must be skipped; therefore the lengthy tests.
+The |copy_png| code is cheerfully gleaned from Thomas Merz' PDFlib, file
+|p_png.c| ``SPNG - Simple PNG''. The goal is to use pdf's native FlateDecode
+support, if that is possible. Only a subset of the png files allows this, but for
+these it greatly improves inclusion speed.
+
+In the ``PNG Copy'' mode only the IDAT chunks are copied; all other chunks from
+the PNG file are discarded. If there are any other chunks in the PNG file, which
+might influence the visual appearance of the image, or if image processing like
+gamma change is requested, the ``PNG Copy'' function must be skipped; therefore
+the lengthy tests.
+
+*/
-@c
static int spng_getint(FILE * f)
{
unsigned char buf[4];
@@ -394,7 +383,7 @@ static void copy_png(PDF pdf, image_dict * idict)
png_p = img_png_png_ptr(idict);
info_p = img_png_info_ptr(idict);
f = (FILE *) png_get_io_ptr(png_p);
- /* 1st pass to find overall stream /Length */
+ /*tex 1st pass to find overall stream /Length */
if (fseek(f, 8, SEEK_SET) != 0)
normal_error("writepng", "fseek in file failed");
do {
@@ -423,8 +412,7 @@ static void copy_png(PDF pdf, image_dict * idict)
pdf_end_dict(pdf);
pdf_end_dict(pdf);
pdf_begin_stream(pdf);
- assert(pdf->zip_write_state == NO_ZIP); /* the PNG stream is already compressed */
- /* 2nd pass to copy data */
+ /*tex 2nd pass to copy data */
endflag = false;
if (fseek(f, 8, SEEK_SET) != 0)
normal_error("writepng", "fseek in file failed");
@@ -433,7 +421,7 @@ static void copy_png(PDF pdf, image_dict * idict)
type = spng_getint(f);
switch (type) {
case SPNG_CHUNK_IDAT:
- /* do copy */
+ /*tex do copy */
if (idat == 2) {
normal_error("writepng", "IDAT chunk sequence broken");
}
@@ -445,7 +433,7 @@ static void copy_png(PDF pdf, image_dict * idict)
}
break;
case SPNG_CHUNK_IEND:
- /* done */
+ /*tex done */
endflag = true;
break;
default:
@@ -459,17 +447,15 @@ static void copy_png(PDF pdf, image_dict * idict)
pdf_end_obj(pdf);
}
-@ @c
static void reopen_png(image_dict * idict)
{
int width, height, xres, yres;
- width = img_xsize(idict); /* do consistency check */
+ /*tex A consistency check: */
+ width = img_xsize(idict);
height = img_ysize(idict);
xres = img_xres(idict);
yres = img_yres(idict);
- /*
- we need to ake sure that the file kept open
- */
+ /*tex We need to ake sure that the file kept open. */
img_keepopen(idict) = 1;
read_png_info(idict);
if (width != img_xsize(idict) || height != img_ysize(idict) || xres != img_xres(idict) || yres != img_yres(idict)) {
@@ -477,13 +463,10 @@ static void reopen_png(image_dict * idict)
}
}
-@ @c
-static boolean last_png_needs_page_group;
-
void write_png(PDF pdf, image_dict * idict)
{
#ifndef PNG_FP_1
- /* for libpng < 1.5.0 */
+ /*tex for libpng < 1.5.0 */
# define PNG_FP_1 100000
#endif
int num_palette, palette_objnum = 0;
@@ -494,31 +477,30 @@ void write_png(PDF pdf, image_dict * idict)
png_infop info_p;
png_colorp palette;
assert(idict != NULL);
- last_png_needs_page_group = false;
if (img_file(idict) == NULL)
reopen_png(idict);
assert(img_png_ptr(idict) != NULL);
png_p = img_png_png_ptr(idict);
info_p = img_png_info_ptr(idict);
- /* simple transparency support */
+ /*tex simple transparency support */
if (png_get_valid(png_p, info_p, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_p);
png_copy = false;
}
- /* alpha channel support */
+ /*tex alpha channel support */
if (pdf->minor_version < 4
&& png_get_color_type(png_p, info_p) | PNG_COLOR_MASK_ALPHA) {
png_set_strip_alpha(png_p);
png_copy = false;
}
- /* 16 bit depth support */
+ /*tex 16 bit depth support */
if (pdf->minor_version < 5)
pdf->image_hicolor = 0;
if ((png_get_bit_depth(png_p, info_p) == 16) && (pdf->image_hicolor == 0)) {
png_set_strip_16(png_p);
png_copy = false;
}
- /* gamma support */
+ /*tex gamma support */
if (png_get_valid(png_p, info_p, PNG_INFO_gAMA)) {
png_get_gAMA(png_p, info_p, &gamma);
png_get_gAMA_fixed(png_p, info_p, &int_file_gamma);
@@ -527,11 +509,10 @@ void write_png(PDF pdf, image_dict * idict)
if (png_get_valid(png_p, info_p, PNG_INFO_gAMA))
png_set_gamma(png_p, (pdf->gamma / 1000.0), gamma);
else
- png_set_gamma(png_p, (pdf->gamma / 1000.0),
- (1000.0 / pdf->image_gamma));
+ png_set_gamma(png_p, (pdf->gamma / 1000.0), (1000.0 / pdf->image_gamma));
png_copy = false;
}
- /* reset structure */
+ /*tex reset structure */
(void) png_set_interlace_handling(png_p);
png_read_update_info(png_p, info_p);
pdf_begin_obj(pdf, img_objnum(idict), OBJSTM_NEVER);
@@ -555,9 +536,11 @@ void write_png(PDF pdf, image_dict * idict)
pdf_add_name(pdf, "ColorSpace");
pdf_begin_array(pdf);
pdf_add_name(pdf, "Indexed");
- pdf_add_name(pdf, "DeviceRGB"); /* base; PDFRef. 4.5.5 */
- pdf_add_int(pdf, (int) (num_palette - 1)); /* hival */
- pdf_add_ref(pdf, (int) palette_objnum); /* lookup */
+ pdf_add_name(pdf, "DeviceRGB");
+ /*tex hival */
+ pdf_add_int(pdf, (int) (num_palette - 1));
+ /*tex lookup */
+ pdf_add_ref(pdf, (int) palette_objnum);
pdf_end_array(pdf);
break;
case PNG_COLOR_TYPE_GRAY:
@@ -629,14 +612,12 @@ void write_png(PDF pdf, image_dict * idict)
case PNG_COLOR_TYPE_GRAY_ALPHA:
if (pdf->minor_version >= 4) {
write_png_gray_alpha(pdf, idict);
- last_png_needs_page_group = true;
} else
write_png_gray(pdf, idict);
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
if (pdf->minor_version >= 4) {
write_png_rgb_alpha(pdf, idict);
- last_png_needs_page_group = true;
} else
write_png_gray(pdf, idict);
break;
@@ -645,42 +626,20 @@ void write_png(PDF pdf, image_dict * idict)
}
}
write_palette_streamobj(pdf, palette_objnum, palette, num_palette);
- /* always */
+ /*tex always */
close_and_cleanup_png(idict);
}
-@ @c
-static boolean transparent_page_group_was_written = false;
-@ Called after the xobject generated by |write_png| has been finished; used to
-write out additional objects
+/*tex
+
+ Called after the xobject generated by |write_png| has been finished; used to
+ write out additional objects.
+
+*/
-@c
void write_additional_png_objects(PDF pdf)
{
(void) pdf;
- (void) transparent_page_group;
- (void) transparent_page_group_was_written;
return;
- /* this interferes with current macro-based usage and cannot be configured */
-#if 0
- if (last_png_needs_page_group) {
- if (!transparent_page_group_was_written && transparent_page_group > 1) {
- /* create new group object */
- transparent_page_group_was_written = true;
- pdf_begin_obj(pdf, transparent_page_group, 2);
- if (pdf->compress_level == 0) {
- pdf_puts(pdf, "%PTEX Group needed for transparent pngs\n");
- }
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Group");
- pdf_dict_add_name(pdf, "S", "Transparency");
- pdf_dict_add_name(pdf, "CS", "DeviceRGB");
- pdf_dict_add_bool(pdf, "I", 1);
- pdf_dict_add_bool(pdf, "K", 1);
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
- }
- }
-#endif
}
diff --git a/Build/source/texk/web2c/luatexdir/lang/hnjalloc.c b/Build/source/texk/web2c/luatexdir/lang/hnjalloc.c
new file mode 100644
index 00000000000..3ebeee9e4d5
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lang/hnjalloc.c
@@ -0,0 +1,65 @@
+/*
+
+hnjalloc.w
+
+LibHnj is dual licensed under LGPL and MPL. Boilerplate for both licenses
+follows.
+
+LibHnj - a library for high quality hyphenation and justification Copyright (C)
+1998 Raph Levien, (C) 2001 ALTLinux, Moscow
+
+This library is free software; you can redistribute it and/or modify it under the
+terms of the GNU Library General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This library 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 Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307 USA.
+
+The contents of this file are subject to the Mozilla Public License Version 1.0
+(the "MPL"); you may not use this file except in compliance with the MPL. You may
+obtain a copy of the MPL at http://www.mozilla.org/MPL/
+
+Software distributed under the MPL is distributed on an "AS IS" basis, WITHOUT
+WARRANTY OF ANY KIND, either express or implied. See the MPL for the specific
+language governing rights and limitations under the MPL.
+
+*/
+
+/*tex The wrappers for malloc */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "lang/hnjalloc.h"
+
+void *hnj_malloc(int size)
+{
+ void *p;
+
+ p = malloc((size_t) size);
+ if (p == NULL) {
+ fprintf(stderr, "can't allocate %d bytes\n", size);
+ exit(1);
+ }
+ return p;
+}
+
+void *hnj_realloc(void *p, int size)
+{
+ p = realloc(p, (size_t) size);
+ if (p == NULL) {
+ fprintf(stderr, "can't allocate %d bytes\n", size);
+ exit(1);
+ }
+ return p;
+}
+
+void hnj_free(void *p)
+{
+ free(p);
+}
diff --git a/Build/source/texk/web2c/luatexdir/lang/hnjalloc.w b/Build/source/texk/web2c/luatexdir/lang/hnjalloc.w
deleted file mode 100644
index 91fefec9e5d..00000000000
--- a/Build/source/texk/web2c/luatexdir/lang/hnjalloc.w
+++ /dev/null
@@ -1,69 +0,0 @@
-% hnjalloc.w
-%
-% LibHnj is dual licensed under LGPL and MPL. Boilerplate for both
-% licenses follows.
-%
-%
-% LibHnj - a library for high quality hyphenation and justification
-% Copyright (C) 1998 Raph Levien, (C) 2001 ALTLinux, Moscow
-%
-% This library is free software; you can redistribute it and/or
-% modify it under the terms of the GNU Library General Public
-% License as published by the Free Software Foundation; either
-% version 2 of the License, or (at your option) any later version.
-%
-% This library 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
-% Library General Public License for more details.
-%
-% You should have received a copy of the GNU Library General Public
-% License along with this library; if not, write to the
-% Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-% Boston, MA 02111-1307 USA.
-%
-%
-%
-% The contents of this file are subject to the Mozilla Public License
-% Version 1.0 (the "MPL"); you may not use this file except in
-% compliance with the MPL. You may obtain a copy of the MPL at
-% http://www.mozilla.org/MPL/
-%
-% Software distributed under the MPL is distributed on an "AS IS" basis,
-% WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
-% for the specific language governing rights and limitations under the
-% MPL.
-
-@ wrappers for malloc
-@c
-
-#include <stdlib.h>
-#include <stdio.h>
-#include "lang/hnjalloc.h"
-
-void *hnj_malloc(int size)
-{
- void *p;
-
- p = malloc((size_t) size);
- if (p == NULL) {
- fprintf(stderr, "can't allocate %d bytes\n", size);
- exit(1);
- }
- return p;
-}
-
-void *hnj_realloc(void *p, int size)
-{
- p = realloc(p, (size_t) size);
- if (p == NULL) {
- fprintf(stderr, "can't allocate %d bytes\n", size);
- exit(1);
- }
- return p;
-}
-
-void hnj_free(void *p)
-{
- free(p);
-}
diff --git a/Build/source/texk/web2c/luatexdir/lang/hyphen.w b/Build/source/texk/web2c/luatexdir/lang/hyphen.c
index 35befb743de..3a96f195b2f 100644
--- a/Build/source/texk/web2c/luatexdir/lang/hyphen.w
+++ b/Build/source/texk/web2c/luatexdir/lang/hyphen.c
@@ -1,57 +1,51 @@
-% hyphen.w
-%
-% Libhnj is dual licensed under LGPL and MPL. Boilerplate for both
-% licenses follows.
-%
-%
-% LibHnj - a library for high quality hyphenation and justification
-% Copyright (C) 1998 Raph Levien,
-% (C) 2001 ALTLinux, Moscow (http://www.alt-linux.org),
-% (C) 2001 Peter Novodvorsky (nidd@@cs.msu.su)
-%
-% This library is free software; you can redistribute it and/or
-% modify it under the terms of the GNU Library General Public
-% License as published by the Free Software Foundation; either
-% version 2 of the License, or (at your option) any later version.
-%
-% This library 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
-% Library General Public License for more details.
-%
-% You should have received a copy of the GNU Library General Public
-% License along with this library; if not, write to the
-% Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-% Boston, MA 02111-1307 USA.
-%
-%
-%
-% The contents of this file are subject to the Mozilla Public License
-% Version 1.0 (the "MPL"); you may not use this file except in
-% compliance with the MPL. You may obtain a copy of the MPL at
-% http://www.mozilla.org/MPL/
-%
-% Software distributed under the MPL is distributed on an "AS IS" basis,
-% WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
-% for the specific language governing rights and limitations under the
-% MPL.
-
-
-@ @c
+/*
+hyphen.c
+
+This file is derived from libhnj which is is dual licensed under LGPL and MPL.
+Boilerplate for both licenses follows.
+
+LibHnj - a library for high quality hyphenation and justification
+
+(C) 1998 Raph Levien,
+(C) 2001 ALTLinux, Moscow (http://www.alt-linux.org),
+(C) 2001 Peter Novodvorsky (nidd@cs.msu.su)
+
+This library is free software; you can redistribute it and/or modify it under the
+terms of the GNU Library General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This library 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 Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public License along
+with this library; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA 02111-1307 USA.
+
+The contents of this file are subject to the Mozilla Public License Version 1.0
+(the "MPL"); you may not use this file except in compliance with the MPL. You may
+obtain a copy of the MPL at http://www.mozilla.org/MPL/
+
+Software distributed under the MPL is distributed on an "AS IS" basis, WITHOUT
+WARRANTY OF ANY KIND, either express or implied. See the MPL for the specific
+language governing rights and limitations under the MPL.
+
+*/
#include "ptexlib.h"
#include "lua/luatex-api.h"
-#include <stdlib.h> /* for NULL, malloc */
-#include <stdio.h> /* for fprintf */
-#include <string.h> /* for strdup */
-#include <stdlib.h> /* for malloc used by substring inclusion */
+#include <stdlib.h> /* for NULL, malloc */
+#include <stdio.h> /* for fprintf */
+#include <string.h> /* for strdup */
+#include <stdlib.h> /* for malloc used by substring inclusion */
#define MAXPATHS 40960
#ifdef UNX
-# include <unistd.h> /* for exit */
+# include <unistd.h> /* for exit */
#endif
#include <kpathsea/c-ctype.h>
@@ -60,9 +54,8 @@
#include "lang/hnjalloc.h"
-@ TODO: should be moved to separate library
+/*tex This could be moved to separate library. */
-@c
static unsigned char *hnj_strdup(const unsigned char *s)
{
unsigned char *new;
@@ -75,18 +68,20 @@ static unsigned char *hnj_strdup(const unsigned char *s)
return new;
}
-@* Type definitions.
+/*tex
-@ a little bit of a hash table implementation. This simply maps strings
- to state numbers
+ First some type definitions and a little bit of a hash table implementation.
+ This simply maps strings to state numbers
-@c
-typedef struct _HashTab HashTab;
+*/
+
+typedef struct _HashTab HashTab;
typedef struct _HashEntry HashEntry;
-typedef struct _HashIter HashIter;
-typedef union _HashVal HashVal;
+typedef struct _HashIter HashIter;
+typedef union _HashVal HashVal;
+
+/*tex A cheap, but effective, hack. */
-/* A cheap, but effective, hack. */
#define HASH_SIZE 31627
struct _HashTab {
@@ -110,13 +105,13 @@ struct _HashIter {
int ndx;
};
-@ State machine
+/* The state state machine. */
-@c
typedef struct _HyphenState HyphenState;
typedef struct _HyphenTrans HyphenTrans;
+
#define MAX_CHARS 256
-#define MAX_NAME 20
+#define MAX_NAME 20
struct _HyphenDict {
int num_states;
@@ -130,9 +125,14 @@ struct _HyphenDict {
struct _HyphenState {
char *match;
- /*char *repl; */
- /*signed char replindex; */
- /*signed char replcut; */
+ /*tex Removed:
+
+ \starttyping
+ char *repl;
+ signed char replindex;
+ signed char replcut;
+ \stoptyping
+ */
int fallback_state;
int num_trans;
HyphenTrans *trans;
@@ -143,20 +143,21 @@ struct _HyphenTrans {
int new_state;
};
+/*tex
+
+ Combine two right-aligned number patterns, 04000 + 020 becomes 04020. This
+ works also for utf8 sequences because the substring is identical to the last
+ substring-length bytes of expr except for the (single byte) hyphenation
+ encoders
-@ Combine two right-aligned number patterns, 04000 + 020 becomes 04020
+*/
-@c
static char *combine(char *expr, const char *subexpr)
{
size_t l1 = strlen(expr);
size_t l2 = strlen(subexpr);
size_t off = l1 - l2;
unsigned j;
- /* this works also for utf8 sequences because the substring is identical
- to the last substring-length bytes of expr except for the (single byte)
- hyphenation encoders
- */
for (j = 0; j < l2; j++) {
if (expr[off + j] < subexpr[j])
expr[off + j] = subexpr[j];
@@ -164,9 +165,8 @@ static char *combine(char *expr, const char *subexpr)
return expr;
}
+/*tex Some original code: */
-@ ORIGINAL CODE
-@c
static HashIter *new_HashIter(HashTab * h)
{
HashIter *i = hnj_malloc(sizeof(HashIter));
@@ -176,7 +176,6 @@ static HashIter *new_HashIter(HashTab * h)
return i;
}
-
static int nextHashStealPattern(HashIter * i, unsigned char **word, char **pattern)
{
while (i->cur == NULL) {
@@ -204,7 +203,6 @@ static int nextHash(HashIter * i, unsigned char **word)
return 1;
}
-
static int eachHash(HashIter * i, unsigned char **word, char **pattern)
{
while (i->cur == NULL) {
@@ -218,16 +216,17 @@ static int eachHash(HashIter * i, unsigned char **word, char **pattern)
return 1;
}
-
static void delete_HashIter(HashIter * i)
{
hnj_free(i);
}
+/*tex
-@ a |char*| hash function from ASU - adapted from Gtk+
+A |char*| hash function from ASU, adapted from |Gtk+|:
+
+*/
-@c
static unsigned int hnj_string_hash(const unsigned char *s)
{
const unsigned char *p;
@@ -240,18 +239,15 @@ static unsigned int hnj_string_hash(const unsigned char *s)
h = h ^ g;
}
}
- return h /* \% M */ ;
+ return h;
}
+/*tex This assumes that key is not already present! */
-@ assumes that key is not already present!
-
-@c
static void state_insert(HashTab * hashtab, unsigned char *key, int state)
{
int i;
HashEntry *e;
-
i = (int) (hnj_string_hash(key) % HASH_SIZE);
e = hnj_malloc(sizeof(HashEntry));
e->next = hashtab->entries[i];
@@ -260,23 +256,18 @@ static void state_insert(HashTab * hashtab, unsigned char *key, int state)
hashtab->entries[i] = e;
}
+/*tex This also assumes that key is not already present! */
-@ assumes that key is not already present!
-
-@c
static void hyppat_insert(HashTab * hashtab, unsigned char *key, char *hyppat)
{
int i;
HashEntry *e;
-
i = (int) (hnj_string_hash(key) % HASH_SIZE);
for (e = hashtab->entries[i]; e; e = e->next) {
if (strcmp((char *) e->key, (char *) key) == 0) {
if (e->u.hyppat) {
- if (hyppat
- && strcmp((char *) e->u.hyppat, (char *) hyppat) != 0) {
- print_err("Conflicting pattern ignored");
- error();
+ if (hyppat && strcmp((char *) e->u.hyppat, (char *) hyppat) != 0) {
+ normal_warning("hyphenation","a conflicting pattern has been ignored");
}
hnj_free(e->u.hyppat);
}
@@ -292,15 +283,12 @@ static void hyppat_insert(HashTab * hashtab, unsigned char *key, char *hyppat)
hashtab->entries[i] = e;
}
+/*tex We return |state| if found, otherwise |-1|. */
-@ return state if found, otherwise $-1$
-
-@c
static int state_lookup(HashTab * hashtab, const unsigned char *key)
{
int i;
HashEntry *e;
-
i = (int) (hnj_string_hash(key) % HASH_SIZE);
for (e = hashtab->entries[i]; e; e = e->next) {
if (!strcmp((const char *) key, (const char *) e->key)) {
@@ -310,15 +298,14 @@ static int state_lookup(HashTab * hashtab, const unsigned char *key)
return -1;
}
+/*tex We return |state| if found, otherwise |-1|. */
-@ return state if found, otherwise $-1$
-
-@c
static char *hyppat_lookup(HashTab * hashtab, const unsigned char *chars, int l)
{
int i;
HashEntry *e;
- unsigned char key[256]; /* should be ample */
+ /*tex The 256 should be enough. */
+ unsigned char key[256];
strncpy((char *) key, (const char *) chars, (size_t) l);
key[l] = 0;
i = (int) (hnj_string_hash(key) % HASH_SIZE);
@@ -330,24 +317,18 @@ static char *hyppat_lookup(HashTab * hashtab, const unsigned char *chars, int l)
return NULL;
}
+/*tex Get the state number, allocating a new state if necessary. */
-@ Get the state number, allocating a new state if necessary.
-
-@c
-static int hnj_get_state(HyphenDict * dict,
- const unsigned char *str, int *state_num)
+static int hnj_get_state(HyphenDict * dict, const unsigned char *str, int *state_num)
{
*state_num = state_lookup(dict->state_num, str);
-
if (*state_num >= 0)
return *state_num;
-
state_insert(dict->state_num, hnj_strdup(str), dict->num_states);
- /* predicate is true if |dict->num_states| is a power of two */
+ /*tex The predicate is true if |dict->num_states| is a power of two: */
if (!(dict->num_states & (dict->num_states - 1))) {
dict->states = hnj_realloc(dict->states,
- (int) ((dict->num_states << 1) *
- (int) sizeof(HyphenState)));
+ (int) ((dict->num_states << 1) * (int) sizeof(HyphenState)));
}
dict->states[dict->num_states].match = NULL;
dict->states[dict->num_states].fallback_state = -1;
@@ -356,70 +337,59 @@ static int hnj_get_state(HyphenDict * dict,
return dict->num_states++;
}
+/*tex
-@ Add a transition from state1 to state2 through ch - assumes that the
- transition does not already exist
+ Add a transition from state1 to state2 through ch - assumes that the
+ transition does not already exist.
+
+*/
-@c
static void hnj_add_trans(HyphenDict * dict, int state1, int state2, int uni_ch)
{
int num_trans;
- /* TH: this test was a bit too strict, it is quite normal for old
- patterns to have chars in the range 0-31 or 127-159 (inclusive).
- To ease the transition, let's only disallow NUL for now
- (this is probably a requirement of the code anyway).
- */
+ /*
+ TH: this test was a bit too strict, it is quite normal for old patterns
+ to have chars in the range 0-31 or 127-159 (inclusive). To ease the
+ transition, let's only disallow |NUL| for now, which probably is a
+ requirement of the code anyway.
+ */
if (uni_ch == 0) {
- char errmsg[256]; /* temp hack ... we will have a formatted error */
- snprintf(errmsg, 255, "character out of bounds: u%04x", uni_ch);
- errmsg[255] = '\0';
- normal_error("hyphenation",errmsg); /* todo */
+ formatted_error("hyphenation","a character is out of bounds: u%04x", uni_ch);
}
num_trans = dict->states[state1].num_trans;
if (num_trans == 0) {
dict->states[state1].trans = hnj_malloc(sizeof(HyphenTrans));
} else {
- /* TH: The old version did
- } else if (!(num_trans & (num_trans - 1))) {
- ... hnj_realloc(dict->states[state1].trans,
- (int) ((num_trans << 1) *
- sizeof(HyphenTrans)));
- but that is incredibly nasty when adding patters one-at-a-time.
- Controlled growth would be nicer than the current +1, but if
- noone complains, this is good enough ;)
- */
+ /*
+ TH: The old version did:
+
+ \starttyping
+ } else if (!(num_trans & (num_trans - 1))) {
+ ... =hnj_realloc(dict->states[state1].trans,
+ (int) ((num_trans << 1) * sizeof(HyphenTrans)));
+ \stoptyping
+
+ but that is incredibly nasty when adding patters one-at-a-time.
+ Controlled growth would be nicer than the current +1, but if no one
+ complains, and no one did in a decade, this is good enough.
+
+ */
dict->states[state1].trans = hnj_realloc(dict->states[state1].trans,
- (int) ((num_trans + 1) *
- sizeof(HyphenTrans)));
+ (int) ((num_trans + 1) * sizeof(HyphenTrans)));
}
dict->states[state1].trans[num_trans].uni_ch = uni_ch;
dict->states[state1].trans[num_trans].new_state = state2;
dict->states[state1].num_trans++;
}
+/*tex
-#ifdef VERBOSE
-
-static unsigned char *get_state_str(int state)
-{
- int i;
- HashEntry *e;
-
- for (i = 0; i < HASH_SIZE; i++)
- for (e = global->entries[i]; e; e = e->next)
- if (e->u.state == state)
- return e->key;
- return NULL;
-}
-#endif
+ We did change the semantics a bit here: |hnj_hyphen_load| used to operate on
+ a file, but now the argument is a string buffer.
+*/
-@ I've changed the semantics a bit here: |hnj_hyphen_load| used to
- operate on a file, but now the argument is a string buffer.
-
-@c
-static const unsigned char *next_pattern(size_t * length,
- const unsigned char **buf)
+static const unsigned char *next_pattern(size_t * length, const unsigned char **buf)
{
const unsigned char *here, *rover = *buf;
while (*rover && isspace(*rover))
@@ -435,25 +405,28 @@ static const unsigned char *next_pattern(size_t * length,
}
*length = (size_t) (rover - here);
*buf = rover;
- return *length ? here : NULL; /* zero sensed */
+ /*tex Zero sensed: */
+ return *length ? here : NULL;
}
static void init_hash(HashTab ** h)
{
int i;
- if (*h)
+ if (*h) {
return;
+ }
*h = hnj_malloc(sizeof(HashTab));
- for (i = 0; i < HASH_SIZE; i++)
+ for (i = 0; i < HASH_SIZE; i++) {
(*h)->entries[i] = NULL;
+ }
}
-
static void clear_state_hash(HashTab ** h)
{
int i;
- if (*h == NULL)
+ if (*h == NULL) {
return;
+ }
for (i = 0; i < HASH_SIZE; i++) {
HashEntry *e, *next;
for (e = (*h)->entries[i]; e; e = next) {
@@ -466,19 +439,20 @@ static void clear_state_hash(HashTab ** h)
*h = NULL;
}
-
static void clear_hyppat_hash(HashTab ** h)
{
int i;
- if (*h == NULL)
+ if (*h == NULL) {
return;
+ }
for (i = 0; i < HASH_SIZE; i++) {
HashEntry *e, *next;
for (e = (*h)->entries[i]; e; e = next) {
next = e->next;
hnj_free(e->key);
- if (e->u.hyppat)
+ if (e->u.hyppat) {
hnj_free(e->u.hyppat);
+ }
hnj_free(e);
}
}
@@ -486,7 +460,6 @@ static void clear_hyppat_hash(HashTab ** h)
*h = NULL;
}
-
static void init_dict(HyphenDict * dict)
{
dict->num_states = 1;
@@ -502,7 +475,6 @@ static void init_dict(HyphenDict * dict)
init_hash(&dict->patterns);
}
-
static void clear_dict(HyphenDict * dict)
{
int state_num;
@@ -519,8 +491,6 @@ static void clear_dict(HyphenDict * dict)
clear_state_hash(&dict->state_num);
}
-
-
HyphenDict *hnj_hyphen_new(void)
{
HyphenDict *dict = hnj_malloc(sizeof(HyphenDict));
@@ -528,14 +498,12 @@ HyphenDict *hnj_hyphen_new(void)
return dict;
}
-
void hnj_hyphen_clear(HyphenDict * dict)
{
clear_dict(dict);
init_dict(dict);
}
-
void hnj_hyphen_free(HyphenDict * dict)
{
clear_dict(dict);
@@ -568,29 +536,30 @@ unsigned char *hnj_serialize(HyphenDict * dict)
return buf;
}
-
void hnj_free_serialize(unsigned char *c)
{
hnj_free(c);
}
+/*tex
-@ hyphenation pattern:
-
-signed bytes
-
-0 indicates end (actually any negative number)
+ In hyphenation patterns we use signed bytes where |0|, or actually any
+ negative number, indicates end:
-: prio(1+),startpos,length,len1,[replace],len2,[replace]
+ \starttyping
+ prio(1+),startpos,length,len1,[replace],len2,[replace]
+ \starttyping
-most basic example is:
+ A basic example is:
-p n 0 0 0
+ \starttyping
+ p n 0 0 0
+ \starttyping
-for a hyphenation point between characters
+ for a hyphenation point between characters.
+*/
-@c
void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
{
int state_num, last_state;
@@ -601,7 +570,6 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
unsigned char *word;
char *pattern;
size_t l = 0;
-
const unsigned char *format;
const unsigned char *begin = f;
unsigned char *pat;
@@ -609,46 +577,23 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
while ((format = next_pattern(&l, &f)) != NULL) {
int i, j, e1;
if (l>=255) {
- help1("Individual patterns should not be longer than 254 bytes total.");
- print_err("Pattern of enormous length ignored");
- error();
+ normal_warning("hyphenation","a pattern of more than 254 bytes ignored");
continue;
}
-#if 0
- printf("%s\n",format);
- char* repl = strnchr(format, '/',l);
- int replindex = 0;
- int replcut = 0;
- if (repl) {
- int clen = l-(repl-format);
- l = repl-format;
- char * index = strnchr(repl + 1, ',',clen);
- if (index) {
- char * index2 = strnchr(index + 1, ',',clen-(index-repl));
- if (index2) {
- replindex = (signed char) atoi(index + 1) - 1;
- replcut = (signed char) atoi(index2 + 1);
- }
- } else {
- hnj_strchomp(repl + 1);
- replindex = 0;
- replcut = strlen(buf);
- }
- repl = hnj_strdup(repl + 1);
- }
-#endif
for (i = 0, j = 0, e1 = 0; (unsigned) i < l; i++) {
if (format[i] >= '0' && format[i] <= '9')
j++;
if (is_utf8_follow(format[i]))
e1++;
}
- /* |l-e1| => number of {\it characters} not {\it bytes} */
- /* |l-j| => number of pattern bytes */
- /* |l-e1-j| => number of pattern characters */
+ /*tex
+ Here |l-e1| is the number of {\em characters} not {\em bytes}, |l-j|
+ the number of pattern bytes and |l-e1-j| the number of pattern
+ characters.
+ */
pat = (unsigned char *) malloc((1 + l - (size_t) j));
org = (char *) malloc((size_t) (2 + l - (size_t) e1 - (size_t) j));
- /* remove hyphenation encoders (digits) from pat */
+ /*tex Remove hyphenation encoders (digits) from pat. */
org[0] = '0';
for (i = 0, j = 0, e1 = 0; (unsigned) i < l; i++) {
unsigned char c = format[i];
@@ -665,20 +610,25 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
org[j + 1] = 0;
hyppat_insert(dict->patterns, pat, org);
}
- dict->pat_length += (int) ((f - begin) + 2); /* 2 for spurious spaces */
+ /*tex We add 2 bytes for spurious spaces. */
+ dict->pat_length += (int) ((f - begin) + 2);
init_hash(&dict->merged);
v = new_HashIter(dict->patterns);
while (nextHash(v, &word)) {
int wordsize = (int) strlen((char *) word);
int j1, l1;
for (l1 = 1; l1 <= wordsize; l1++) {
- if (is_utf8_follow(word[l1]))
- continue; /* Do not clip an utf8 sequence */
+ if (is_utf8_follow(word[l1])) {
+ /*tex Do not clip an utf8 sequence. */
+ continue;
+ }
for (j1 = 1; j1 <= l1; j1++) {
char *subpat_pat;
int i1 = l1 - j1;
- if (is_utf8_follow(word[i1]))
- continue; /* Do not start halfway an utf8 sequence */
+ if (is_utf8_follow(word[i1])) {
+ /*tex Do not start halfway an utf8 sequence. */
+ continue;
+ }
if ((subpat_pat =
hyppat_lookup(dict->patterns, word + i1, j1)) != NULL) {
char *newpat_pat;
@@ -694,7 +644,8 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
if (is_utf8_follow(newword[i1]))
e1++;
neworg = malloc((size_t) (l1 + 2 - e1));
- sprintf(neworg, "%0*d", l1 + 1 - e1, 0); /* fill with right amount of '0' */
+ /*tex Fill with right amount of zeros: */
+ sprintf(neworg, "%0*d", l1 + 1 - e1, 0);
hyppat_insert(dict->merged, newword, combine(neworg, subpat_pat));
} else {
combine(newpat_pat, subpat_pat);
@@ -704,20 +655,15 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
}
}
delete_HashIter(v);
-
init_hash(&dict->state_num);
state_insert(dict->state_num, hnj_strdup((const unsigned char *) ""), 0);
v = new_HashIter(dict->merged);
while (nextHashStealPattern(v, &word, &pattern)) {
static unsigned char mask[] = { 0x3F, 0x1F, 0xF, 0x7 };
int j1 = (int) strlen((char *) word);
-#ifdef VERBOSE
- printf("word %s pattern %s, j = %d\n", word, pattern, j1);
-#endif
state_num = hnj_get_state(dict, word, &found);
dict->states[state_num].match = pattern;
-
- /* now, put in the prefix transitions */
+ /*tex Now, put in the prefix transitions. */
while (found < 0) {
j1--;
last_state = state_num;
@@ -741,71 +687,48 @@ void hnj_hyphen_load(HyphenDict * dict, const unsigned char *f)
}
delete_HashIter(v);
clear_hyppat_hash(&dict->merged);
-
- /* put in the fallback states */
+ /*tex Put in the fallback states. */
{
- int i, j = 0;
- for (i = 0; i < HASH_SIZE; i++) {
- for (e = dict->state_num->entries[i]; e; e = e->next) {
- /* do not do state==0 otherwise things get confused */
- if (e->u.state) {
- for (j = 1; 1; j++) {
- state_num = state_lookup(dict->state_num, e->key + j);
- if (state_num >= 0)
- break;
+ int i, j = 0;
+ for (i = 0; i < HASH_SIZE; i++) {
+ for (e = dict->state_num->entries[i]; e; e = e->next) {
+ /*tex Do not do |state==0| otherwise things get confused. */
+ if (e->u.state) {
+ for (j = 1; 1; j++) {
+ state_num = state_lookup(dict->state_num, e->key + j);
+ if (state_num >= 0)
+ break;
+ }
+ dict->states[e->u.state].fallback_state = state_num;
}
- dict->states[e->u.state].fallback_state = state_num;
}
}
}
-#ifdef VERBOSE
- for (i = 0; i < HASH_SIZE; i++) {
- for (e = dict->state_num->entries[i]; e; e = e->next) {
- printf("%d string %s state %d, fallback=%d\n",
- i, e->key, e->u.state, dict->states[e->u.state].fallback_state);
- for (j = 0; j < dict->states[e->u.state].num_trans; j++) {
- printf(" u%4x->%d\n",
- (int) dict->states[e->u.state].trans[j].uni_ch,
- dict->states[e->u.state].trans[j].new_state);
- }
- }
- }
-#endif
- }
clear_state_hash(&dict->state_num);
}
-@ @c
extern halfword insert_syllable_discretionary(halfword t, lang_variables * lan);
-void hnj_hyphen_hyphenate(HyphenDict * dict,
- halfword first1,
- halfword last1,
- int length,
- halfword left, halfword right, lang_variables * lan)
+void hnj_hyphen_hyphenate(HyphenDict * dict, halfword first1, halfword last1,
+ int length, halfword left, halfword right, lang_variables * lan)
{
int char_num;
halfword here;
int state = 0;
- /* +2 for dots at each end, +1 for points /outside/ characters */
+ /*tex +2 for dots at each end, +1 for points outside characters. */
int ext_word_len = length + 2;
int hyphen_len = ext_word_len + 1;
char *hyphens = hnj_malloc(hyphen_len + 1);
-
- /* Add a '.' to beginning and end to facilitate matching */
+ /*tex Add a '.' to beginning and end to facilitate matching. */
vlink(begin_point) = first1;
vlink(end_point) = vlink(last1);
vlink(last1) = end_point;
-
for (char_num = 0; char_num < hyphen_len; char_num++) {
hyphens[char_num] = '0';
}
hyphens[hyphen_len] = 0;
-
- /* now, run the finite state machine */
- for (char_num = 0, here = begin_point; here != vlink(end_point);
- here = vlink(here)) {
-
+ /*tex Now, run the finite state machine. */
+ for (char_num = 0, here = begin_point; here != vlink(end_point); here = vlink(here)) {
int ch;
if (here == begin_point || here == end_point) {
ch = '.';
@@ -816,28 +739,20 @@ void hnj_hyphen_hyphenate(HyphenDict * dict,
}
}
while (state != -1) {
-#if 0
- printf("%*s%s%c",char_num-strlen(get_state_str(state)),"",get_state_str(state),(char)ch);
-#endif
HyphenState *hstate = &dict->states[state];
int k;
for (k = 0; k < hstate->num_trans; k++) {
if (hstate->trans[k].uni_ch == ch) {
char *match;
state = hstate->trans[k].new_state;
-#if 0
- printf(" state %d\n",state);
-#endif
match = dict->states[state].match;
if (match) {
- /* +2 because:
- 1 string length is one bigger than offset
- 1 hyphenation starts before first character
- */
+ /*tex
+
+ We add +2 because 1 string length is one bigger than offset
+ and 1 hyphenation starts before first character.
+ */
int offset = (int) (char_num + 2 - (int) strlen(match));
-#if 0
- printf("%*s%s\n", offset,"", match);
-#endif
int m;
for (m = 0; match[m]; m++) {
if (hyphens[offset + m] < match[m])
@@ -848,21 +763,19 @@ void hnj_hyphen_hyphenate(HyphenDict * dict,
}
}
state = hstate->fallback_state;
-#if 0
- printf(" back to %d\n", state);
-#endif
}
- /* nothing worked, let's go to the next character */
+ /*tex Nothing worked, let's go to the next character. */
state = 0;
- try_next_letter:;
+ try_next_letter:;
char_num++;
}
-
- /* restore the correct pointers */
+ /*tex Restore the correct pointers. */
vlink(last1) = vlink(end_point);
+ /*tex
- /* pattern is \.{\^.\^w\^o\^r\^d\^.\^} |word_len|=4, |ext_word_len|=6, |hyphens|=7
- * check \.{ \^ \^ \^ } so drop first two and stop after |word_len-1|
+ Pattern is \.{\^.\^w\^o\^r\^d\^.\^} and |word_len|=4, |ext_word_len|=6,
+ |hyphens|=7; check \.{ \^ \^ \^ } and therefore drop first two and stop
+ after |word_len-1|
*/
for (here = first1, char_num = 2; here != left; here = vlink(here))
char_num++;
diff --git a/Build/source/texk/web2c/luatexdir/lang/texlang.w b/Build/source/texk/web2c/luatexdir/lang/texlang.c
index 337d2eca51d..04f96660f5e 100644
--- a/Build/source/texk/web2c/luatexdir/lang/texlang.w
+++ b/Build/source/texk/web2c/luatexdir/lang/texlang.c
@@ -1,31 +1,32 @@
-% texlang.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
+/*
+
+texlang.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/>.
+
+*/
#include "ptexlib.h"
#include <string.h>
#include "lua/luatex-api.h"
-@ Low-level helpers
+/*tex Low-level helpers */
-@ @c
#define unVERBOSE
#define MAX_TEX_LANGUAGES 16384
@@ -60,7 +61,9 @@ struct tex_language *new_language(int n)
lang->post_exhyphen_char = 0;
lang->hyphenation_min = -1;
if (saving_hyph_codes_par) {
- /* for now, we might just use specific value for whatever task */
+ /*tex
+ For now, we might just use specific value for whatever task.
+ */
hj_codes_from_lc_codes(l);
}
return lang;
@@ -82,7 +85,6 @@ struct tex_language *get_language(int n)
}
}
-@ @c
void set_pre_hyphen_char(int n, int v)
{
struct tex_language *l = get_language((int) n);
@@ -183,7 +185,6 @@ void load_tex_patterns(int curlang, halfword head)
load_patterns(get_language(curlang), (unsigned char *) s);
}
-@ @c
#define STORE_CHAR(l,x) do { \
unsigned xx = get_hj_code(l,x); \
if (!xx || xx <= 32) { \
@@ -192,17 +193,24 @@ void load_tex_patterns(int curlang, halfword head)
uindex = uni2string(uindex, xx); \
} while (0)
-@ Cleans one word which is returned in |cleaned|, returns the new offset into
-|buffer|
+/*
+
+ This cleans one word which is returned in |cleaned|, returns the new offset
+ into |buffer|.
+
+*/
-@c
const char *clean_hyphenation(int id, const char *buff, char **cleaned)
{
int items = 0;
- unsigned char word[MAX_WORD_LEN + 1]; /* work buffer for bytes */
- unsigned uword[MAX_WORD_LEN + 1] = { 0 }; /* work buffer for unicode */
- int u = 0; /* unicode buffer value */
- int i = 0; /* index into buffer */
+ /*tex Work buffer for bytes: */
+ unsigned char word[MAX_WORD_LEN + 1];
+ /*tex Work buffer for \UNICODE: */
+ unsigned uword[MAX_WORD_LEN + 1] = { 0 };
+ /*tex The \UNICODE\ buffer value: */
+ int u = 0;
+ /*tex The index into buffer: */
+ int i = 0;
char *uindex = (char *)word;
const char *s = buff;
@@ -210,21 +218,21 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned)
word[i++] = (unsigned)*s;
s++;
if ((s-buff)>MAX_WORD_LEN) {
- /* todo: this is too strict, should count unicode, not bytes */
+ /*tex Todo: this is too strict, should count \UNICODE, not bytes. */
*cleaned = NULL;
tex_error("exception too long", NULL);
return s;
}
}
- /* now convert the input to unicode */
+ /*tex Now convert the input to \UNICODE. */
word[i] = '\0';
utf2uni_strcpy(uword, (const char *)word);
- /* build the new word string */
+ /*tex Build the new word string. */
i = 0;
while (uword[i]>0) {
u = uword[i++];
if (u == '-') {
- /* skip */
+ /*tex Skip. */
} else if (u == '=') {
STORE_CHAR(id,'-');
} else if (u == '{') {
@@ -259,6 +267,9 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned)
tex_error("exception syntax error", NULL);
return s;
}
+ if (uword[i] == '[' && uword[i+1] >= '0' && uword[i+1] <= '9' && uword[i+2] == ']') {
+ i += 3;
+ }
} else {
STORE_CHAR(id,u);
}
@@ -268,7 +279,6 @@ const char *clean_hyphenation(int id, const char *buff, char **cleaned)
return s;
}
-@ @c
void load_hyphenation(struct tex_language *lang, const unsigned char *buff)
{
const char *s;
@@ -322,7 +332,6 @@ void load_tex_hyphenation(int curlang, halfword head)
load_hyphenation(get_language(curlang), (unsigned char *) s);
}
-@ @c
static halfword insert_discretionary(halfword t, halfword pre, halfword post, halfword replace, int penalty)
{
halfword g;
@@ -331,21 +340,21 @@ static halfword insert_discretionary(halfword t, halfword pre, halfword post, ha
int attr = node_attr(t) ;
disc_penalty(d) = penalty;
if (t == replace) {
- /* prev disc next-next */
+ /*tex We have |prev disc next-next|. */
try_couple_nodes(d, vlink(t));
try_couple_nodes(alink(t), d);
alink(t) = null;
vlink(t) = null;
replace = t ;
} else {
- /* prev disc next */
+ /*tex We have |prev disc next|. */
try_couple_nodes(d, vlink(t));
couple_nodes(t, d);
}
if (replace != null) {
f = font(replace);
} else {
- /* For compound words following explicit hyphens. */
+ /*tex For compound words following explicit hyphens. */
f = get_cur_font();
}
for (g = pre; g != null; g = vlink(g)) {
@@ -406,7 +415,6 @@ halfword insert_syllable_discretionary(halfword t, lang_variables * lan)
}
set_disc_field(pre_break(n), g);
}
-
if (lan->post_hyphen_char > 0) {
t = vlink(n);
g = raw_glyph_node();
@@ -423,7 +431,6 @@ halfword insert_syllable_discretionary(halfword t, lang_variables * lan)
return n;
}
-@ @c
static halfword insert_character(halfword t, int c)
{
halfword p;
@@ -456,12 +463,12 @@ static halfword compound_word_break(halfword t, int clang)
return disc;
}
-@ @c
void set_disc_field(halfword f, halfword t)
{
if (t != null) {
- /*
- couple_nodes(f, t); // better not expose f as prev pointer
+ /*tex
+ No |couple_nodes(f, t);| as we can better not expose |f| as |prev|
+ pointer.
*/
vlink(f) = t ;
alink(t) = null ;
@@ -472,14 +479,14 @@ void set_disc_field(halfword f, halfword t)
}
}
-@ @c
static char *hyphenation_exception(int exceptions, char *w)
{
char *ret = NULL;
lua_checkstack(Luas, 2);
lua_rawgeti(Luas, LUA_REGISTRYINDEX, exceptions);
- if (lua_istable(Luas, -1)) { /* ?? */
- lua_pushstring(Luas, w); /* word table */
+ if (lua_istable(Luas, -1)) {
+ /*tex Word table: */
+ lua_pushstring(Luas, w);
lua_rawget(Luas, -2);
if (lua_type(Luas, -1) == LUA_TSTRING) {
ret = xstrdup(lua_tostring(Luas, -1));
@@ -491,7 +498,6 @@ static char *hyphenation_exception(int exceptions, char *w)
return ret;
}
-@ @c
char *exception_strings(struct tex_language *lang)
{
const char *value;
@@ -503,8 +509,8 @@ char *exception_strings(struct tex_language *lang)
lua_checkstack(Luas, 2);
lua_rawgeti(Luas, LUA_REGISTRYINDEX, lang->exceptions);
if (lua_istable(Luas, -1)) {
- /* iterate and join */
- lua_pushnil(Luas); /* first key */
+ /*tex Iterate and join. */
+ lua_pushnil(Luas);
while (lua_next(Luas, -2) != 0) {
value = lua_tolstring(Luas, -1, &l);
if (current + 2 + l > size) {
@@ -520,15 +526,19 @@ char *exception_strings(struct tex_language *lang)
return ret;
}
-@ the sequence from |wordstart| to |r| can contain only normal characters it
-could be faster to modify a halfword pointer and return an integer
+/*tex
+
+ The sequence from |wordstart| to |r| can contain only normal characters it
+ could be faster to modify a halfword pointer and return an integer
+
+*/
-@c
static halfword find_exception_part(unsigned int *j, unsigned int *uword, int len)
{
halfword g = null, gg = null;
register unsigned i = *j;
- i++; /* this puts uword[i] on the |{| */
+ /*tex This puts uword[i] on the |{|. */
+ i++;
while (i < (unsigned) len && uword[i + 1] != '}') {
if (g == null) {
gg = new_char(0, (int) uword[i + 1]);
@@ -548,7 +558,8 @@ static int count_exception_part(unsigned int *j, unsigned int *uword, int len)
{
int ret = 0;
register unsigned i = *j;
- i++; /* this puts uword[i] on the |{| */
+ /*tex This puts uword[i] on the |{|. */
+ i++;
while (i < (unsigned) len && uword[i + 1] != '}') {
ret++;
i++;
@@ -557,22 +568,23 @@ static int count_exception_part(unsigned int *j, unsigned int *uword, int len)
return ret;
}
-@ @c
static const char *PAT_ERROR[] = {
"Exception discretionaries should contain three pairs of braced items.",
"No intervening spaces are allowed.",
NULL
};
-/*
+/*tex
+
The exceptions are taken as-is: no min values are taken into account. One can
add normal patterns on-the-fly if needed.
+
*/
static void do_exception(halfword wordstart, halfword r, char *replacement)
{
unsigned i;
- halfword t;
+ halfword t, pen;
unsigned len;
int clang;
lang_variables langdata;
@@ -584,126 +596,191 @@ static void do_exception(halfword wordstart, halfword r, char *replacement)
clang = char_lang(wordstart);
langdata.pre_hyphen_char = get_pre_hyphen_char(clang);
langdata.post_hyphen_char = get_post_hyphen_char(clang);
-
for (i = 0; i < len; i++) {
- if (uword[i + 1] == '-') { /* a hyphen follows */
- while (vlink(t) != r && (type(t) != glyph_node || !is_simple_character(t)))
- t = vlink(t);
+ if (uword[i + 1] == 0 ) {
+ /*tex We ran out of the exception pattern. */
+ break;
+ } else if (uword[i + 1] == '-') {
+ /*tex A hyphen follows. */
if (vlink(t) == r)
break;
insert_syllable_discretionary(t, &langdata);
t = vlink(t); /* skip the new disc */
} else if (uword[i + 1] == '=') {
- /* do nothing ? */
+ /*tex We skip a disc. */
t = vlink(t);
} else if (uword[i + 1] == '{') {
+ /*tex We ran into an exception |{}{}{}| or |{}{}{}[]|. */
halfword gg, hh, replace = null;
int repl;
+ /*tex |pre| */
gg = find_exception_part(&i, uword, (int) len);
if (i == len || uword[i + 1] != '{') {
tex_error("broken pattern 1", PAT_ERROR);
}
+ /*tex |post| */
hh = find_exception_part(&i, uword, (int) len);
if (i == len || uword[i + 1] != '{') {
tex_error("broken pattern 2", PAT_ERROR);
}
+ /*tex |replace| */
repl = count_exception_part(&i, uword, (int) len);
if (i == len) {
tex_error("broken pattern 3", PAT_ERROR);
}
- /*i++; *//* jump over the last right brace */
+ /*tex Play safe. */
if (vlink(t) == r)
break;
+ /*tex Let's deal with an (optional) replacement. */
if (repl > 0) {
+ /*tex Assemble the replace stream. */
halfword q = t;
replace = vlink(q);
while (repl > 0 && q != null) {
q = vlink(q);
- if (type(q) == glyph_node) {
+ if (type(q) == glyph_node || type(q) == disc_node) {
repl--;
+ } else {
+ break ;
}
}
+ /*tex Remove it from the main stream */
try_couple_nodes(t, vlink(q));
+ /*tex and finish it in the replace. */
vlink(q) = null;
+ /*tex Sanitize the replace stream (we could use the flattener instead). */
+ q = replace ;
+ while (q != null) {
+ halfword n = vlink(q);
+ if (type(q) == disc_node) {
+ /*tex Beware: the replacement starts after the no_break pointer. */
+ halfword r = vlink(no_break(q));
+ vlink(no_break(q)) = null;
+ alink(r) = null ;
+ /*tex Insert the replacement glyph. */
+ if (q == replace) {
+ replace = r;
+ } else {
+ try_couple_nodes(alink(q),r);
+ }
+ /*tex Append the glyph (one). */
+ try_couple_nodes(r,n);
+ /*tex Flush the disc. */
+ flush_node(q);
+ }
+ q = n ;
+ }
+ }
+ /*tex Let's check if we have a penalty spec. */
+ if (((i+3) < len) && uword[i+1] == '[' && uword[i+2] >= '0' && uword[i+2] <= '9' && uword[i+3] == ']') {
+ if (exception_penalty_par > 0) {
+ if (exception_penalty_par > 100000) {
+ pen = (uword[i+2] - '0') * exception_penalty_par ;
+ } else {
+ pen = exception_penalty_par;
+ }
+ } else {
+ pen = hyphen_penalty_par;
+ }
+ i += 3;
+ } else {
+ pen = hyphen_penalty_par;
+ }
+ /*tex And now we insert a disc node. */
+ t = insert_discretionary(t, gg, hh, replace, pen);
+ /*tex We skip the new disc node. */
+ t = vlink(t);
+ /*tex check if we have two exceptions in a row */
+ if (uword[i + 1] == '{') {
+ i--;
}
- t = insert_discretionary(t, gg, hh, replace, hyphen_penalty_par);
- t = vlink(t); /* skip the new disc */
} else {
t = vlink(t);
}
+ /*tex Again we play safe. */
+ if (t == null || vlink(t) == r) {
+ break;
+ }
}
}
-@ This is a documentation section from the pascal web file. It is not true any
-more, but I do not have time right now to rewrite it -- Taco
-
-When the line-breaking routine is unable to find a feasible sequence of
-breakpoints, it makes a second pass over the paragraph, attempting to hyphenate
-the hyphenatable words. The goal of hyphenation is to insert discretionary
-material into the paragraph so that there are more potential places to break.
-
-The general rules for hyphenation are somewhat complex and technical, because we
-want to be able to hyphenate words that are preceded or followed by punctuation
-marks, and because we want the rules to work for languages other than English. We
-also must contend with the fact that hyphens might radically alter the ligature
-and kerning structure of a word.
-
-A sequence of characters will be considered for hyphenation only if it belongs to
-a ``potentially hyphenatable part'' of the current paragraph. This is a sequence
-of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node, $p_1\ldots p_{m-1}$ are
-either character or ligature or whatsit or implicit kern nodes, and $p_m$ is a
-glue or penalty or insertion or adjust or mark or whatsit or explicit kern node.
-(Therefore hyphenation is disabled by boxes, math formulas, and discretionary
-nodes already inserted by the user.) The ligature nodes among $p_1\ldots p_{m-1}$
-are effectively expanded into the original non-ligature characters; the kern
-nodes and whatsits are ignored. Each character |c| is now classified as either a
-nonletter (if |lc_code(c)=0|), a lowercase letter (if |lc_code(c)=c|), or an
-uppercase letter (otherwise); an uppercase letter is treated as if it were
-|lc_code(c)| for purposes of hyphenation. The characters generated by $p_1\ldots
-p_{m-1}$ may begin with nonletters; let $c_1$ be the first letter that is not in
-the middle of a ligature. Whatsit nodes preceding $c_1$ are ignored; a whatsit
-found after $c_1$ will be the terminating node $p_m$. All characters that do not
-have the same font as $c_1$ will be treated as nonletters. The |hyphen_char| for
-that font must be between 0 and 255, otherwise hyphenation will not be attempted.
-\TeX\ looks ahead for as many consecutive letters $c_1\ldots c_n$ as possible;
-however, |n| must be less than 64, so a character that would otherwise be
-$c_{64}$ is effectively not a letter. Furthermore $c_n$ must not be in the middle
-of a ligature. In this way we obtain a string of letters $c_1\ldots c_n$ that are
-generated by nodes $p_a\ldots p_b$, where |1<=a<=b+1<=m|. If |n>=l_hyf+r_hyf|,
-this string qualifies for hyphenation; however, |uc_hyph| must be positive, if
-$c_1$ is uppercase.
-
-The hyphenation process takes place in three stages. First, the candidate
-sequence $c_1\ldots c_n$ is found; then potential positions for hyphens are
-determined by referring to hyphenation tables; and finally, the nodes $p_a\ldots
-p_b$ are replaced by a new sequence of nodes that includes the discretionary
-breaks found.
-
-Fortunately, we do not have to do all this calculation very often, because of the
-way it has been taken out of \TeX's inner loop. For example, when the second
-edition of the author's 700-page book {\sl Seminumerical Algorithms} was typeset
-by \TeX, only about 1.2 hyphenations needed to be @^Knuth, Donald Ervin@> tried
-per paragraph, since the line breaking algorithm needed to use two passes on only
-about 5 per cent of the paragraphs.
-
-When a word been set up to contain a candidate for hyphenation, \TeX\ first looks
-to see if it is in the user's exception dictionary. If not, hyphens are inserted
-based on patterns that appear within the given word, using an algorithm due to
-Frank~M. Liang. @^Liang, Franklin Mark@>
-
-@ This is incompatible with TEX because the first word of a paragraph can be
-hyphenated, but most european users seem to agree that prohibiting hyphenation
-there was not the best idea ever.
-
-@c
-/*
- More strict: \hyphenationbounds
-
- 0 = not strict
- 1 = strict start
- 2 = strict end
- 3 = strict start and strict end
-
+/*tex
+
+ This is a documentation section from the pascal web file. It is not true any
+ more, but I (Taco) do not have time right now to rewrite it.
+
+ When the line-breaking routine is unable to find a feasible sequence of
+ breakpoints, it makes a second pass over the paragraph, attempting to
+ hyphenate the hyphenatable words. The goal of hyphenation is to insert
+ discretionary material into the paragraph so that there are more potential
+ places to break.
+
+ The general rules for hyphenation are somewhat complex and technical, because
+ we want to be able to hyphenate words that are preceded or followed by
+ punctuation marks, and because we want the rules to work for languages other
+ than English. We also must contend with the fact that hyphens might radically
+ alter the ligature and kerning structure of a word.
+
+ A sequence of characters will be considered for hyphenation only if it
+ belongs to a ``potentially hyphenatable part'' of the current paragraph. This
+ is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node,
+ $p_1\ldots p_{m-1}$ are either character or ligature or whatsit or implicit
+ kern nodes, and $p_m$ is a glue or penalty or insertion or adjust or mark or
+ whatsit or explicit kern node. (Therefore hyphenation is disabled by boxes,
+ math formulas, and discretionary nodes already inserted by the user.) The
+ ligature nodes among $p_1\ldots p_{m-1}$ are effectively expanded into the
+ original non-ligature characters; the kern nodes and whatsits are ignored.
+ Each character |c| is now classified as either a nonletter (if
+ |lc_code(c)=0|), a lowercase letter (if |lc_code(c)=c|), or an uppercase
+ letter (otherwise); an uppercase letter is treated as if it were |lc_code(c)|
+ for purposes of hyphenation. The characters generated by $p_1\ldots p_{m-1}$
+ may begin with nonletters; let $c_1$ be the first letter that is not in the
+ middle of a ligature. Whatsit nodes preceding $c_1$ are ignored; a whatsit
+ found after $c_1$ will be the terminating node $p_m$. All characters that do
+ not have the same font as $c_1$ will be treated as nonletters. The
+ |hyphen_char| for that font must be between 0 and 255, otherwise hyphenation
+ will not be attempted. \TeX\ looks ahead for as many consecutive letters
+ $c_1\ldots c_n$ as possible; however, |n| must be less than 64, so a
+ character that would otherwise be $c_{64}$ is effectively not a letter.
+ Furthermore $c_n$ must not be in the middle of a ligature. In this way we
+ obtain a string of letters $c_1\ldots c_n$ that are generated by nodes
+ $p_a\ldots p_b$, where |1<=a<=b+1<=m|. If |n>=l_hyf+r_hyf|, this string
+ qualifies for hyphenation; however, |uc_hyph| must be positive, if $c_1$ is
+ uppercase.
+
+ The hyphenation process takes place in three stages. First, the candidate
+ sequence $c_1\ldots c_n$ is found; then potential positions for hyphens are
+ determined by referring to hyphenation tables; and finally, the nodes
+ $p_a\ldots p_b$ are replaced by a new sequence of nodes that includes the
+ discretionary breaks found.
+
+ Fortunately, we do not have to do all this calculation very often, because of
+ the way it has been taken out of \TeX's inner loop. For example, when the
+ second edition of the author's 700-page book {\sl Seminumerical Algorithms}
+ was typeset by \TeX, only about 1.2 hyphenations needed to be tried per
+ paragraph, since the line breaking algorithm needed to use two passes on only
+ about 5 per cent of the paragraphs.
+
+ When a word been set up to contain a candidate for hyphenation, \TeX\ first
+ looks to see if it is in the user's exception dictionary. If not, hyphens are
+ inserted based on patterns that appear within the given word, using an
+ algorithm due to Frank~M. Liang.
+
+ This is incompatible with \TEX\ because the first word of a paragraph can be
+ hyphenated, but most European users seem to agree that prohibiting
+ hyphenation there was not the best idea ever.
+
+ We have some variants available that are controlled by the paremeter
+ \type {\hyphenationbounds}:
+
+ \starttabulate
+ \NC \type {0} \NC not strict \NC \NR
+ \NC \type {1} \NC strict start \NC \NR
+ \NC \type {2} \NC strict end \NC \NR
+ \NC \type {3} \NC strict start and strict end \NC \NR
+ \stoptabulate
+
+ \startbuffer
\parindent0pt \hsize=1.1cm
12-34-56 \par
12-34-\hbox{56} \par
@@ -716,20 +793,24 @@ there was not the best idea ever.
12-34-\vrule width 1em height 1.5ex \par
12-\hbox{34}-56 \par
12-\vrule width 1em height 1.5ex-56 \par
+ \stopbuffer
-*/
+ \typebuffer
-/*
- We only accept an explicit hyphen when there is a preceding glyph and we skip a sequence of
- explicit hyphens as that normally indicates a -- or --- ligature in which case we can in a
- worse case usage get bad node lists later on due to messed up ligature building as these
- dashes are ligatures in base fonts. This is a side effect of the separating the hyphenation,
- ligaturing and kerning steps. A test is cmr with ------.
+ \startpacked \getbuffer \stopbuffer
+
+ We only accept an explicit hyphen when there is a preceding glyph and we skip
+ a sequence of explicit hyphens as that normally indicates a \type {--} or
+ \type {---} ligature in which case we can in a worse case usage get bad node
+ lists later on due to messed up ligature building as these dashes are
+ ligatures in base fonts. This is a side effect of the separating the
+ hyphenation, ligaturing and kerning steps. A test is cmr with \type {------}.
- A font handler can collapse successive hyphens but it's not nice to put the burden there. A
- somewhat messy border case is ---- but in LuaTeX we don't treat -- and --- special. Also,
- traditional TeX will break a line at -foo but this can be disabled by setting the automatic
- mode to 1.
+ A font handler can collapse successive hyphens but it's not nice to put the
+ burden there. A somewhat messy border case is \type {----} but in \LUATEX\ we
+ don't treat \type {--} and \type {---} special. Also, traditional \TEX\ will
+ break a line at \type {-foo} but this can be disabled by setting the
+ automatic mode to \type {1}.
*/
@@ -742,79 +823,78 @@ static halfword find_next_wordstart(halfword r, halfword first_language, halfwor
halfword t ;
while (r != null) {
switch (type(r)) {
- case boundary_node:
- if (subtype(r) == word_boundary) {
+ case boundary_node:
+ if (subtype(r) == word_boundary) {
+ start_ok = 1;
+ }
+ break;
+ case hlist_node:
+ case vlist_node:
+ case rule_node:
+ case dir_node:
+ case whatsit_node:
+ if (strict_bound == 1 || strict_bound == 3) {
+ start_ok = 0;
+ }
+ break;
+ case glue_node:
start_ok = 1;
- }
- break;
- case hlist_node: /* new > 0.95 */
- case vlist_node: /* new > 0.95 */
- case rule_node: /* new > 0.95 */
- case dir_node:
- case whatsit_node:
- if (strict_bound == 1 || strict_bound == 3) {
- start_ok = 0;
- }
- break;
- case glue_node:
- start_ok = 1;
- break;
- case math_node:
- while (mathlevel > 0) {
- r = vlink(r);
- if (r == null)
- return r;
- if (type(r) == math_node) {
- if (subtype(r) == before) {
- mathlevel++;
- } else {
- mathlevel--;
+ break;
+ case math_node:
+ while (mathlevel > 0) {
+ r = vlink(r);
+ if (r == null)
+ return r;
+ if (type(r) == math_node) {
+ if (subtype(r) == before) {
+ mathlevel++;
+ } else {
+ mathlevel--;
+ }
}
}
- }
- break;
- case glyph_node:
- if (is_simple_character(r)) {
- chr = character(r) ;
- if (chr == ex_hyphen_char_par) {
- t = vlink(r) ;
- if ((automatic_hyphen_mode_par == 0) && (t != null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) {
- /* we have no word yet and the next character is a non hyphen */
- r = compound_word_break(r, char_lang(r));
- } else {
- /* we jump over the sequence of hyphens */
- while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
- r = t ;
- t = vlink(r) ;
+ break;
+ case glyph_node:
+ if (is_simple_character(r)) {
+ chr = character(r) ;
+ if (chr == ex_hyphen_char_par) {
+ t = vlink(r) ;
+ if ((automatic_hyphen_mode_par == 0) && (t != null) && (type(t) == glyph_node) && (character(t) != ex_hyphen_char_par)) {
+ /*tex We have no word yet and the next character is a non hyphen. */
+ r = compound_word_break(r, char_lang(r));
+ } else {
+ /*tex We jump over the sequence of hyphens. */
+ while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
+ r = t ;
+ t = vlink(r) ;
+ }
+ if (t == null) {
+ /*tex We reached the end of the list so we have no word start. */
+ return null;
+ }
}
- if (t == null) {
- /* we reached the end of the list so we have no word start */
- return null;
+ /*tex We need a restart. */
+ start_ok = 0;
+ } else if (start_ok && (char_lang(r)>=first_language) && ((l = get_hj_code(char_lang(r),chr)) > 0)) {
+ if (char_uchyph(r) || l == chr || l <= 32) {
+ return r;
+ } else {
+ start_ok = 0;
}
- }
- /* we need a restart */
- start_ok = 0;
- } else if (start_ok && (char_lang(r)>=first_language) && ((l = get_hj_code(char_lang(r),chr)) > 0)) {
- if (char_uchyph(r) || l == chr || l <= 32) {
- return r;
} else {
- start_ok = 0;
+ /*tex We go on. */
}
- } else {
- /* go on */
}
- }
- break;
- default:
- start_ok = 0;
- break;
+ break;
+ default:
+ start_ok = 0;
+ break;
}
r = vlink(r);
}
return r;
}
-@ @c
static int valid_wordend(halfword s, halfword strict_bound)
{
register halfword r = s;
@@ -831,16 +911,16 @@ static int valid_wordend(halfword s, halfword strict_bound)
if (r == null || (type(r) == glyph_node && is_simple_character(r) && clang != char_lang(r))
|| type(r) == glue_node
|| type(r) == penalty_node
- || (type(r) == kern_node && (subtype(r) == explicit_kern || /* so why not italic correction ? */
+ || (type(r) == kern_node && (subtype(r) == explicit_kern ||
subtype(r) == italic_kern ||
subtype(r) == accent_kern ))
- || ((type(r) == hlist_node || /* new > 0.95 */
- type(r) == vlist_node || /* new > 0.95 */
- type(r) == rule_node || /* new > 0.95 */
- type(r) == dir_node || /* new > 0.97 */
+ || ((type(r) == hlist_node ||
+ type(r) == vlist_node ||
+ type(r) == rule_node ||
+ type(r) == dir_node ||
type(r) == whatsit_node ||
- type(r) == ins_node || /* yes or no strict test */
- type(r) == adjust_node /* yes or no strict test */
+ type(r) == ins_node ||
+ type(r) == adjust_node
) && ! (strict_bound == 2 || strict_bound == 3))
|| type(r) == boundary_node
)
@@ -848,7 +928,6 @@ static int valid_wordend(halfword s, halfword strict_bound)
return 0;
}
-@ @c
void hnj_hyphenation(halfword head, halfword tail)
{
int lchar, i;
@@ -859,37 +938,43 @@ void hnj_hyphenation(halfword head, halfword tail)
char *hy = utf8word;
char *replacement = NULL;
boolean explicit_hyphen = false;
+ boolean valid_word = false;
halfword first_language = first_valid_language_par;
halfword strict_bound = hyphenation_bounds_par;
halfword s, r = head, wordstart = null, save_tail1 = null, left = null, right = null;
-
- /*
+ halfword expstart = null;
+ boolean compound_hyphen = compound_hyphen_mode_par;
+ /*tex
This first movement assures two things:
- \item{a)} that we won't waste lots of time on something that has been handled already
- (in that case, none of the glyphs match |simple_character|).
-
- \item{b)} that the first word can be hyphenated. if the movement was not explicit,
- then the indentation at the start of a paragraph list would make |find_next_wordstart()|
- look too far ahead.
+ \startitemize
+ \startitem
+ That we won't waste lots of time on something that has been
+ handled already (in that case, none of the glyphs match
+ |simple_character|).
+ \stopitem
+ \startitem
+ That the first word can be hyphenated. if the movement was not
+ explicit, then the indentation at the start of a paragraph list
+ would make |find_next_wordstart()| look too far ahead.
+ \stopitem
+ \stopitemize
*/
-
while (r != null && (type(r) != glyph_node || !is_simple_character(r))) {
r = vlink(r);
}
- /*
+ /*tex
This will make |r| a glyph node with subtype character.
*/
r = find_next_wordstart(r,first_language,strict_bound);
if (r == null)
return;
-
assert(tail != null);
save_tail1 = vlink(tail);
s = new_penalty(0,word_penalty);
couple_nodes(tail, s);
-
- while (r != null) { /* could be while(1), but let's be paranoid */
+ while (r != null) {
+ /*tex This could be |while(1)|, but let's be paranoid: */
int clang, lhmin, rhmin, hmin;
halfword hyf_font;
halfword end_word = r;
@@ -897,7 +982,7 @@ void hnj_hyphenation(halfword head, halfword tail)
assert(is_simple_character(wordstart));
hyf_font = font(wordstart);
if (hyphen_char(hyf_font) < 0) {
- /* For backward compatibility: */
+ /*tex For backward compatibility we set: */
hyf_font = 0;
}
clang = char_lang(wordstart);
@@ -947,19 +1032,28 @@ void hnj_hyphenation(halfword head, halfword tail)
r = vlink(r);
}
if (explicit_hyphen == true) {
- /* we are not at the start, so we only need to look ahead */
+ /*tex we are not at the start, so we only need to look ahead */
halfword t = vlink(r) ;
if ((automatic_hyphen_mode_par == 0 || automatic_hyphen_mode_par == 1) && (t != null) && ((type(t) == glyph_node) && (character(t) != ex_hyphen_char_par))) {
- /* we have a word already but the next character may not be a hyphen too */
+ /*tex we have a word already but the next character may not be a hyphen too */
r = compound_word_break(r, char_lang(r));
+ if (compound_hyphen) {
+ if (expstart == null) {
+ expstart = wordstart;
+ }
+ explicit_hyphen = false;
+ hy = uni2string(hy, '-');
+ r = t;
+ continue;
+ }
} else {
- /* we jump over the sequence of hyphens */
- while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
+ /*tex we jump over the sequence of hyphens */
+ while ((t != null) && (type(t) == glyph_node) && (character(t) == ex_hyphen_char_par)) {
r = t ;
t = vlink(r) ;
}
if (t == null) {
- /* we reached the end of the list and will quit the loop later */
+ /*tex we reached the end of the list and will quit the loop later */
r = null;
}
}
@@ -971,32 +1065,67 @@ void hnj_hyphenation(halfword head, halfword tail)
&& (lang = tex_languages[clang]) != NULL
) {
*hy = 0;
+ /*tex
+ this is messy and nasty: we can have a word with a - in it which
+ is why we have two branches
+ */
if (lang->exceptions != 0 && (replacement = hyphenation_exception(lang->exceptions, utf8word)) != NULL) {
- /* handle the exception and go on to the next word */
- do_exception(wordstart, r, replacement);
+ /*tex handle the exception and go on to the next word */
+ if (expstart == null) {
+ do_exception(wordstart, r, replacement);
+ } else {
+ do_exception(expstart,r,replacement);
+ }
free(replacement);
+ } else if (expstart != null) {
+ /*tex We're done already */
} else if (lang->patterns != NULL) {
+ /*tex A safeguard, not needed but doesn't hurt either: */
+ valid_word = true;
left = wordstart;
for (i = lhmin; i > 1; i--) {
left = vlink(left);
+ if (left == null) {
+ valid_word = false;
+ break ;
+ }
while (!is_simple_character(left)) {
left = vlink(left);
+ if (left == null) {
+ valid_word = false;
+ break ;
+ }
}
- /* if (!left) break; */
- /* what is left overruns right .. a bit messy */
}
- right = r;
- for (i = rhmin; i > 0; i--) {
- right = alink(right);
- while (!is_simple_character(right)) {
+ if (valid_word) {
+ right = r;
+ if (right == left) {
+ valid_word = false;
+ break ;
+ }
+ for (i = rhmin; i > 0; i--) {
right = alink(right);
+ if (right == null || right == left) {
+ valid_word = false;
+ break ;
+ }
+ while (!is_simple_character(right)) {
+ right = alink(right);
+ if (right == null || right == left) {
+ valid_word = false;
+ break ;
+ }
+ }
+ }
+ if (valid_word && expstart == null) {
+ (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata);
+ } else {
+ /*tex nothing yet */
}
- /* if (!right) break; */
- /* what is right overruns left .. a bit messy */
}
- (void) hnj_hyphen_hyphenate(lang->patterns, wordstart, end_word, wordlen, left, right, &langdata);
}
}
+ expstart = null ;
explicit_hyphen = false;
wordlen = 0;
hy = utf8word;
@@ -1008,36 +1137,40 @@ void hnj_hyphenation(halfword head, halfword tail)
vlink(tail) = save_tail1;
}
-@ @c
void new_hyphenation(halfword head, halfword tail)
{
+ int i, top;
register int callback_id = 0;
if (head == null || vlink(head) == null)
return;
fix_node_list(head);
callback_id = callback_defined(hyphenate_callback);
if (callback_id > 0) {
+ top = lua_gettop(Luas);
if (!get_callback(Luas, callback_id)) {
- lua_pop(Luas, 2);
+ lua_settop(Luas, top);
return;
}
nodelist_to_lua(Luas, head);
nodelist_to_lua(Luas, tail);
- if (lua_pcall(Luas, 2, 0, 0) != 0) {
+ if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) {
formatted_warning("hyphenation","bad specification: %s",lua_tostring(Luas, -1));
- lua_pop(Luas, 2);
- lua_error(Luas);
+ lua_settop(Luas, top);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return;
}
- lua_pop(Luas, 1);
+ lua_settop(Luas, top);
} else if (callback_id == 0) {
hnj_hyphenation(head, tail);
}
}
-@ Dumping and undumping languages.
+/*tex
+
+ Dumping and undumping languages:
+
+*/
-@c
#define dump_string(a) \
if (a!=NULL) { \
x = (int)strlen(a)+1; \
@@ -1106,7 +1239,7 @@ static void undump_one_language(int i)
lang->post_exhyphen_char = x;
undump_int(x);
lang->hyphenation_min = x;
- /* patterns */
+ /*tex patterns */
undump_int(x);
if (x > 0) {
s = xmalloc((unsigned) x);
@@ -1114,7 +1247,7 @@ static void undump_one_language(int i)
load_patterns(lang, (unsigned char *) s);
free(s);
}
- /* exceptions */
+ /*tex exceptions */
undump_int(x);
if (x > 0) {
s = xmalloc((unsigned) x);
@@ -1137,21 +1270,26 @@ void undump_language_data(void)
}
}
-@ When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named
-|new_hyph_exceptions| to do the right thing.
+/*tex
+
+ When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named
+ |new_hyph_exceptions| to do the right thing.
+
+*/
-@c
void new_hyph_exceptions(void)
-{ /* enters new exceptions */
+{
(void) scan_toks(false, true);
load_tex_hyphenation(language_par, def_ref);
flush_list(def_ref);
}
-@ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a procedure named
-|new_patterns|.
+/*
+ Similarly, when \TeX\ has scanned `\.{\\patterns}', it calls on a procedure
+ named |new_patterns|.
+
+*/
-@c
void new_patterns(void)
{
(void) scan_toks(false, true);
@@ -1159,10 +1297,14 @@ void new_patterns(void)
flush_list(def_ref);
}
-@ `\.{\\prehyphenchar}', sets the |pre_break| character, and `\.{\\posthyphenchar}' the
-|post_break| character. Their respective defaults are ascii hyphen ("-") and zero (nul).
+/*tex
+
+ `\.{\\prehyphenchar}', sets the |pre_break| character, and
+ `\.{\\posthyphenchar}' the |post_break| character. Their respective defaults
+ are ascii hyphen ("-") and zero (nul).
+
+*/
-@c
void new_pre_hyphen_char(void)
{
scan_optional_equals();
@@ -1177,10 +1319,14 @@ void new_post_hyphen_char(void)
set_post_hyphen_char(language_par, cur_val);
}
-@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and `\.{\\postexhyphenchar}' the
-|post_break| character. Their defaults are both zero (nul).
+/*tex
+
+ `\.{\\preexhyphenchar}', sets the |pre_break| character, and
+ `\.{\\postexhyphenchar}' the |post_break| character. Their defaults are both
+ zero (nul).
+
+*/
-@c
void new_pre_exhyphen_char(void)
{
scan_optional_equals();
diff --git a/Build/source/texk/web2c/luatexdir/lua/helpers.c b/Build/source/texk/web2c/luatexdir/lua/helpers.c
new file mode 100644
index 00000000000..e7be7a2c2fe
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/helpers.c
@@ -0,0 +1,29 @@
+/*
+
+helpers.w
+
+Copyright 2017 LuaTeX team <bugs@@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
+
+We might move here some helpers common to code that are now in weird places,
+probably organized in texhelpers, luahelpers, pdfhelpers.
+
+*/
diff --git a/Build/source/texk/web2c/luatexdir/lua/helpers.w b/Build/source/texk/web2c/luatexdir/lua/helpers.w
deleted file mode 100644
index d12e476909d..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/helpers.w
+++ /dev/null
@@ -1,26 +0,0 @@
-% helpers.w
-%
-% Copyright 2017 LuaTeX team <bugs@@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/>.
-
-@ We will move here some helpers common to code that are now in weird places,
-probably organized in texhelpers, luahelpers, pdfhelpers.
-
-
-
-@c
-/* to fill... */
diff --git a/Build/source/texk/web2c/luatexdir/lua/llfslibext.c b/Build/source/texk/web2c/luatexdir/lua/llfslibext.c
deleted file mode 100644
index eba5778dfc7..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/llfslibext.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/* llfslibext.c
-
- Copyright 2010-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/>. */
-
-#include "ptexlib.h"
-#include "lua/luatex-api.h"
-
-#include <kpathsea/c-stat.h>
-#include <kpathsea/c-dir.h>
-#include <time.h>
-
-
-#ifdef _WIN32
-# include <windows.h>
-#else
-#endif
-
-#ifdef _WIN32
-
-static int get_short_name(lua_State * L)
-{
- long length = 0;
- TCHAR *buffer = NULL;
- const char *lpszPath = luaL_checkstring(L, 1);
- length = GetShortPathName(lpszPath, NULL, 0);
- if (length == 0) {
- lua_pushnil(L);
- lua_pushfstring(L, "operating system error: %d", (int) GetLastError());
- return 2;
- }
- buffer = (TCHAR *) xmalloc(length * sizeof(TCHAR));
- length = GetShortPathName(lpszPath, buffer, length);
- if (length == 0) {
- lua_pushnil(L);
- lua_pushfstring(L, "operating system error: %d", (int) GetLastError());
- return 2;
- }
- lua_pushlstring(L, (const char *) buffer, (size_t) length);
- return 1;
-}
-
-static int read_link(lua_State * L)
-{
- lua_pushboolean(L, 0);
- lua_pushliteral(L, "readlink not supported on this platform");
- return 2;
-}
-
-#else
-
-static int pusherror(lua_State * L, const char *info)
-{
- lua_pushnil(L);
- if (info == NULL)
- lua_pushstring(L, strerror(errno));
- else
- lua_pushfstring(L, "%s: %s", info, strerror(errno));
- lua_pushinteger(L, errno);
- return 3;
-}
-
-static int Preadlink(lua_State * L)
-{
-/** readlink(path) */
- const char *path = luaL_checkstring(L, 1);
- char *b = NULL;
- int allocated = 128;
- int n;
- while (1) {
- b = malloc(allocated);
- if (!b)
- return pusherror(L, path);
- n = readlink(path, b, allocated);
- if (n == -1) {
- free(b);
- return pusherror(L, path);
- }
- if (n < allocated)
- break;
- /* Not enough room, try bigger */
- allocated *= 2;
- free(b);
- }
- lua_pushlstring(L, b, n);
- free(b);
- return 1;
-}
-
-
-static int read_link(lua_State * L)
-{
- return Preadlink(L);
-}
-
-static int get_short_name(lua_State * L __attribute__ ((unused)))
-{
- /* simply do nothing */
- return 1;
-}
-#endif
-
-
-/*
-** Get file information
-*/
-static int file_is_directory(lua_State * L)
-{
- struct stat info;
- const char *file = luaL_checkstring(L, 1);
-
- if (stat(file, &info)) {
- lua_pushnil(L);
- lua_pushfstring(L, "cannot obtain information from file `%s'", file);
- return 2;
- }
- if (S_ISDIR(info.st_mode))
- lua_pushboolean(L, 1);
- else
- lua_pushboolean(L, 0);
-
- return 1;
-}
-
-static int file_is_file(lua_State * L)
-{
- struct stat info;
- const char *file = luaL_checkstring(L, 1);
-
- if (stat(file, &info)) {
- lua_pushnil(L);
- lua_pushfstring(L, "cannot obtain information from file `%s'", file);
- return 2;
- }
- if (S_ISREG(info.st_mode))
- lua_pushboolean(L, 1);
- else
- lua_pushboolean(L, 0);
-
- return 1;
-}
-
-
-void open_lfslibext(lua_State * L)
-{
-
- lua_getglobal(L, "lfs");
- lua_pushcfunction(L, file_is_directory);
- lua_setfield(L, -2, "isdir");
- lua_pushcfunction(L, file_is_file);
- lua_setfield(L, -2, "isfile");
- lua_pushcfunction(L, read_link);
- lua_setfield(L, -2, "readlink");
- lua_pushcfunction(L, get_short_name);
- lua_setfield(L, -2, "shortname");
- lua_pop(L, 1); /* pop the table */
-}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c b/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
new file mode 100644
index 00000000000..31fad9f632d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
@@ -0,0 +1,1666 @@
+/*tex
+
+ This file will host the encapsulated \PDF\ support code used for inclusion
+ and access from \LUA.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+ We need to avoid collision with some defines in |cpascal.h|.
+
+*/
+
+#undef lpdfelib_orig_input
+#undef lpdfelib_orig_output
+
+#ifdef input
+#define lpdfelib_orig_input input
+#undef input
+#endif
+
+#ifdef output
+#define lpdfelib_orig_output output
+#undef output
+#endif
+
+#include "luapplib/pplib.h"
+
+#include "image/epdf.h"
+
+#ifdef lpdfelib_orig_input
+#define input lpdfelib_orig_input
+#undef lpdfelib_orig_input
+#endif
+
+#ifdef lpdfelib_orig_output
+#define output lpdfelib_orig_output
+#undef lpdfelib_orig_output
+#endif
+
+#include "lua/luatex-api.h"
+
+/*tex
+
+ We start with some housekeeping. Dictionaries, arrays, streams and references
+ get userdata, while strings, names, integers, floats and booleans become regular
+ \LUA\ objects. We need to define a few metatable identifiers too.
+
+*/
+
+#define PDFE_METATABLE "luatex.pdfe"
+#define PDFE_METATABLE_DICTIONARY "luatex.pdfe.dictionary"
+#define PDFE_METATABLE_ARRAY "luatex.pdfe.array"
+#define PDFE_METATABLE_STREAM "luatex.pdfe.stream"
+#define PDFE_METATABLE_REFERENCE "luatex.pdfe.reference"
+
+typedef struct {
+ ppdoc *document;
+ boolean open;
+ boolean isfile;
+ char *memstream;
+ int pages;
+ int index;
+} pdfe_document ;
+
+typedef struct {
+ ppdict *dictionary;
+ ppref *ref;
+} pdfe_dictionary;
+
+typedef struct {
+ pparray *array;
+ ppref *ref;
+} pdfe_array;
+
+typedef struct {
+ ppstream *stream;
+ ppref *ref;
+ int decode;
+ int open;
+} pdfe_stream;
+
+typedef struct {
+ ppref *reference;
+} pdfe_reference;
+
+/*tex
+
+ We need to check if we have the right userdata. A similar warning is issued
+ when encounter a problem. We don't exit.
+
+*/
+
+static void pdfe_invalid_object_warning(const char * detail)
+{
+ formatted_warning("pdfe lib","lua <pdfe %s> expected",detail);
+}
+
+static pdfe_document *check_isdocument(lua_State * L, int n)
+{
+ pdfe_document *p = (pdfe_document *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("document");
+ return NULL;
+}
+
+static pdfe_dictionary *check_isdictionary(lua_State * L, int n)
+{
+ pdfe_dictionary *p = (pdfe_dictionary *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_dictionary);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("dictionary");
+ return NULL;
+}
+
+static pdfe_array *check_isarray(lua_State * L, int n)
+{
+ pdfe_array *p = (pdfe_array *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_array);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("array");
+ return NULL;
+}
+
+static pdfe_stream *check_isstream(lua_State * L, int n)
+{
+ pdfe_stream *p = (pdfe_stream *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_stream);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("stream");
+ return NULL;
+}
+
+static pdfe_reference *check_isreference(lua_State * L, int n)
+{
+ pdfe_reference *p = (pdfe_reference *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_reference);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("reference");
+ return NULL;
+}
+
+/*tex
+
+ Reporting the type of a userdata is just a sequence of tests till we find the
+ right one. We return nothing is it is no pdfe type.
+
+ \starttyping
+ t = pdfe.type(<pdfe document|dictionary|array|reference|stream>)
+ \stoptyping
+
+*/
+
+#define check_type(field,meta,name) do { \
+ lua_get_metatablelua(luatex_##meta); \
+ if (lua_rawequal(L, -1, -2)) { \
+ lua_pushstring(L,name); \
+ return 1; \
+ } \
+ lua_pop(L, 1); \
+} while (0)
+
+static int pdfelib_type(lua_State * L)
+{
+ void *p = lua_touserdata(L, 1);
+ if (p != NULL && lua_getmetatable(L, 1)) {
+ check_type(document, pdfe, "pdfe");
+ check_type(dictionary,pdfe_dictionary,"pdfe.dictionary");
+ check_type(array, pdfe_array, "pdfe.array");
+ check_type(reference, pdfe_reference, "pdfe.reference");
+ check_type(stream, pdfe_stream, "pdfe.stream");
+ }
+ return 0;
+}
+
+/*tex
+
+ The \type {tostring} metamethods are similar and report a pdfe type plus a
+ pointer value, as is rather usual in \LUA.
+
+*/
+
+#define define_to_string(field,what) \
+static int pdfelib_tostring_##field(lua_State * L) { \
+ pdfe_##field *p = check_is##field(L, 1); \
+ if (p != NULL) { \
+ lua_pushfstring(L, "<" what " %p>", (ppdoc *) p->field); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+define_to_string(document, "pdfe")
+define_to_string(dictionary,"pdfe.dictionary")
+define_to_string(array, "pdfe.array")
+define_to_string(reference, "pdfe.reference")
+define_to_string(stream, "pdfe.stream")
+
+/*tex
+
+ The pushers look rather similar. We have two variants, one that just pushes
+ the object, and another that also pushes some extra information.
+
+*/
+
+#define pdfe_push_dictionary do { \
+ pdfe_dictionary *d = (pdfe_dictionary *)lua_newuserdata(L, sizeof(pdfe_dictionary)); \
+ luaL_getmetatable(L, PDFE_METATABLE_DICTIONARY); \
+ lua_setmetatable(L, -2); \
+ d->dictionary = dictionary; \
+} while(0)
+
+static int pushdictionary(lua_State * L, ppdict *dictionary)
+{
+ if (dictionary != NULL) {
+ pdfe_push_dictionary;
+ lua_pushinteger(L,dictionary->size);
+ return 2;
+ }
+ return 0;
+}
+
+static int pushdictionaryonly(lua_State * L, ppdict *dictionary)
+{
+ if (dictionary != NULL) {
+ pdfe_push_dictionary;
+ return 1;
+ }
+ return 0;
+}
+
+#define pdfe_push_array do { \
+ pdfe_array *a = (pdfe_array *)lua_newuserdata(L, sizeof(pdfe_array)); \
+ luaL_getmetatable(L, PDFE_METATABLE_ARRAY); \
+ lua_setmetatable(L, -2); \
+ a->array = array; \
+ } while (0)
+
+static int pusharray(lua_State * L, pparray * array)
+{
+ if (array != NULL) {
+ pdfe_push_array;
+ lua_pushinteger(L,array->size);
+ return 2;
+ }
+ return 0;
+}
+
+static int pusharrayonly(lua_State * L, pparray * array)
+{
+ if (array != NULL) {
+ pdfe_push_array;
+ return 1;
+ }
+ return 0;
+}
+
+#define pdfe_push_stream do { \
+ pdfe_stream *s = (pdfe_stream *)lua_newuserdata(L, sizeof(pdfe_stream)); \
+ luaL_getmetatable(L, PDFE_METATABLE_STREAM); \
+ lua_setmetatable(L, -2); \
+ s->stream = stream; \
+ s->open = 0; \
+ s->decode = 0; \
+} while(0)
+
+static int pushstream(lua_State * L, ppstream * stream)
+{
+ if (stream != NULL) {
+ pdfe_push_stream;
+ if (pushdictionary(L, stream->dict) > 0)
+ return 3;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int pushstreamonly(lua_State * L, ppstream * stream)
+{
+ if (stream != NULL) {
+ pdfe_push_stream;
+ if (pushdictionaryonly(L, stream->dict) > 0)
+ return 2;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+#define pdfe_push_reference do { \
+ pdfe_reference *r = (pdfe_reference *)lua_newuserdata(L, sizeof(pdfe_reference)); \
+ luaL_getmetatable(L, PDFE_METATABLE_REFERENCE); \
+ lua_setmetatable(L, -2); \
+ r->reference = reference; \
+ } while (0)
+
+static int pushreference(lua_State * L, ppref * reference)
+{
+ if (reference != NULL) {
+ pdfe_push_reference;
+ lua_pushinteger(L,reference->number);
+ return 2;
+ }
+ return 0;
+}
+
+/*tex
+
+ The next function checks for the type and then pushes the matching data on
+ the stack.
+
+ \starttabulate[|c|l|l|l|]
+ \BC type \BC meaning \BC value \BC detail \NC \NR
+ \NC \type {0} \NC none \NC nil \NC \NC \NR
+ \NC \type {1} \NC null \NC nil \NC \NC \NR
+ \NC \type {2} \NC boolean \NC boolean \NC \NC \NR
+ \NC \type {3} \NC boolean \NC integer \NC \NC \NR
+ \NC \type {4} \NC number \NC float \NC \NC \NR
+ \NC \type {5} \NC name \NC string \NC \NC \NR
+ \NC \type {6} \NC string \NC string \NC type \NC \NR
+ \NC \type {7} \NC array \NC arrayobject \NC size \NC \NR
+ \NC \type {8} \NC dictionary \NC dictionaryobject \NC size \NC \NR
+ \NC \type {9} \NC stream \NC streamobject \NC dictionary size \NC \NR
+ \NC \type {10} \NC reference \NC integer \NC \NC \NR
+ \LL
+ \stoptabulate
+
+ A name and string can be distinguished by the extra type value that a string
+ has.
+
+*/
+
+static int pushvalue(lua_State * L, ppobj *object)
+{
+ switch (object->type) {
+ case PPNONE:
+ case PPNULL:
+ lua_pushnil(L);
+ return 1;
+ break;
+ case PPBOOL:
+ lua_pushboolean(L,object->integer);
+ return 1;
+ break;
+ case PPINT:
+ lua_pushinteger(L, object-> integer);
+ return 1;
+ break;
+ case PPNUM:
+ lua_pushnumber(L, object->number);
+ return 1;
+ break;
+ case PPNAME:
+ lua_pushstring(L, (const char *) ppname_decoded(object->name));
+ return 1;
+ break;
+ case PPSTRING:
+ lua_pushlstring(L,(const char *) object->string, ppstring_size((void *)object->string));
+ lua_pushboolean(L, ppstring_hex((void *)object->string));
+ return 2;
+ break;
+ case PPARRAY:
+ return pusharray(L, object->array);
+ break;
+ case PPDICT:
+ return pushdictionary(L, object->dict);
+ break;
+ case PPSTREAM:
+ return pushstream(L, object->stream);
+ break;
+ case PPREF:
+ return pushreference(L, object->ref);
+ break;
+ }
+ return 0;
+}
+
+/*tex
+
+ We need to start someplace when we traverse a document's tree. There are
+ three places:
+
+ \starttyping
+ catalogdictionary = getcatalog(documentobject)
+ trailerdictionary = gettrailer(documentobject)
+ infodictionary = getinfo (documentobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getcatalog(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ return pushdictionaryonly(L,ppdoc_catalog(p->document));
+}
+
+static int pdfelib_gettrailer(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ return pushdictionaryonly(L,ppdoc_trailer(p->document));
+}
+
+static int pdfelib_getinfo(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ return pushdictionaryonly(L,ppdoc_info(p->document));
+}
+
+/*tex
+
+ We have three more helpers.
+
+ \starttyping
+ [key,] type, value, detail = getfromdictionary(dictionaryobject,name|index)
+ type, value, detail = getfromarray (arrayobject,index)
+ [key,] type, value, detail = getfromstream (streamobject,name|index)
+ \stoptyping
+
+*/
+
+static int pdfelib_getfromarray(lua_State * L)
+{
+ pdfe_array *a = check_isarray(L, 1);
+ if (a != NULL) {
+ int index = luaL_checkint(L, 2) - 1;
+ if (index < a->array->size) {
+ ppobj *object = pparray_at(a->array,index);
+ lua_pushinteger(L,(int) object->type);
+ return 1 + pushvalue(L,object);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getfromdictionary(lua_State * L)
+{
+ pdfe_dictionary *d = check_isdictionary(L, 1);
+ if (d != NULL) {
+ if (lua_type(L,2) == LUA_TSTRING) {
+ const char *name = luaL_checkstring(L, 2);
+ ppobj *object = ppdict_get_obj(d->dictionary,name);
+ if (object != NULL) {
+ lua_pushinteger(L,(int) object->type);
+ return 1 + pushvalue(L,object);
+ }
+ } else {
+ int index = luaL_checkint(L, 2) - 1;
+ if (index < d->dictionary->size) {
+ ppobj *object = ppdict_at(d->dictionary,index);
+ ppname key = ppdict_key(d->dictionary,index);
+ lua_pushstring(L,(const char *) key);
+ lua_pushinteger(L,(int) object->type);
+ return 2 + pushvalue(L,object);
+ }
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getfromstream(lua_State * L)
+{
+ pdfe_stream *s = (pdfe_stream *)lua_touserdata(L, 1);
+ if (s != NULL) {
+ ppdict *d = s->stream->dict;
+ if (lua_type(L,2) == LUA_TSTRING) {
+ const char *name = luaL_checkstring(L, 2);
+ ppobj *object = ppdict_get_obj(d,name);
+ if (object != NULL) {
+ lua_pushinteger(L,(int) object->type);
+ return 1 + pushvalue(L,object);
+ }
+ } else {
+ int index = luaL_checkint(L, 2) - 1;
+ if (index < d->size) {
+ ppobj *object = ppdict_at(d,index);
+ ppname key = ppdict_key(d,index);
+ lua_pushstring(L,(const char *) key);
+ lua_pushinteger(L,(int) object->type);
+ return 2 + pushvalue(L,object);
+ }
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ An indexed table with all entries in an array can be fetched with::
+
+ \starttyping
+ t = arraytotable(arrayobject)
+ \stoptyping
+
+ An hashed table with all entries in an dictionary can be fetched with::
+
+ \starttyping
+ t = dictionarytotable(arrayobject)
+ \stoptyping
+
+*/
+
+static void pdfelib_totable(lua_State * L, ppobj * object, int flat)
+{
+ int n = pushvalue(L,object);
+ if (flat && n < 2) {
+ return;
+ }
+ /* [value] [extra] [more] */
+ lua_createtable(L,n+1,0);
+ if (n == 1) {
+ /* value { nil, nil } */
+ lua_insert(L,-2);
+ /* { nil, nil } value */
+ lua_rawseti(L,-2,2);
+ /* { nil , value } */
+ } else if (n == 2) {
+ /* value extra { nil, nil, nil } */
+ lua_insert(L,-3);
+ /* { nil, nil, nil } value extra */
+ lua_rawseti(L,-3,3);
+ /* { nil, nil, extra } value */
+ lua_rawseti(L,-2,2);
+ /* { nil, value, extra } */
+ } else if (n == 3) {
+ /* value extra more { nil, nil, nil, nil } */
+ lua_insert(L,-4);
+ /* { nil, nil, nil, nil, nil } value extra more */
+ lua_rawseti(L,-4,4);
+ /* { nil, nil, nil, more } value extra */
+ lua_rawseti(L,-3,3);
+ /* { nil, nil, extra, more } value */
+ lua_rawseti(L,-2,2);
+ /* { nil, value, extra, more } */
+ }
+ lua_pushinteger(L,(int) object->type);
+ /* { nil, [value], [extra], [more] } type */
+ lua_rawseti(L,-2,1);
+ /* { type, [value], [extra], [more] } */
+ return;
+}
+
+static int pdfelib_arraytotable(lua_State * L)
+{
+ pdfe_array *a = check_isarray(L, 1);
+ if (a != NULL) {
+ int flat = lua_isboolean(L,2);
+ int i = 0;
+ lua_createtable(L,i,0);
+ /* table */
+ for (i=0;i<a->array->size;i++) {
+ ppobj *object = pparray_at(a->array,i);
+ pdfelib_totable(L,object,flat);
+ /* table { type, [value], [extra], [more] } */
+ lua_rawseti(L,-2,i+1);
+ /* table[i] = { type, [value], [extra], [more] } */
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_dictionarytotable(lua_State * L)
+{
+ pdfe_dictionary *d = check_isdictionary(L, 1);
+ if (d != NULL) {
+ int flat = lua_isboolean(L,2);
+ int i = 0;
+ lua_createtable(L,0,i);
+ /* table */
+ for (i=0;i<d->dictionary->size;i++) {
+ ppobj *object = ppdict_at(d->dictionary,i);
+ ppname key = ppdict_key(d->dictionary,i);
+ lua_pushstring(L,(const char *) key);
+ /* table key */
+ pdfelib_totable(L,object,flat);
+ /* table key { type, [value], [extra], [more] } */
+ lua_rawset(L,-3);
+ /* table[key] = { type, [value], [extra] } */
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*tex
+
+ All pages are collected with:
+
+ \starttyping
+ { { dict, size, objnum }, ... } = pagestotable(document)
+ \stoptyping
+
+*/
+
+static int pdfelib_pagestotable(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL) {
+ ppdoc *d = p->document;
+ ppref *r = NULL;
+ int i = 0;
+ lua_createtable(L,ppdoc_page_count(d),0);
+ /* pages[1..n] */
+ for (r = ppdoc_first_page(d), i = 1; r != NULL; r = ppdoc_next_page(d), ++i) {
+ lua_createtable(L,3,0);
+ pushdictionary(L,ppref_obj(r)->dict);
+ /* table dictionary n */
+ lua_rawseti(L,-3,2);
+ /* table dictionary */
+ lua_rawseti(L,-2,1);
+ /* table */
+ lua_pushinteger(L,r->number);
+ /* table reference */
+ lua_rawseti(L,-2,3);
+ /* table */
+ lua_rawseti(L,-2,i);
+ /* pages[i] = { dictionary, size, objnum } */
+ }
+ return 1;
+ }
+ return 0;
+}
+
+/*tex
+
+ Streams can be fetched on one go:
+
+ \starttyping
+ string, n = readwholestream(streamobject,decode)
+ \stoptyping
+
+*/
+
+static int pdfelib_readwholestream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ uint8_t *b = NULL;
+ int decode = 0;
+ size_t n = 0;
+ if (s->open > 0) {
+ ppstream_done(s->stream);
+ s->open = 0;
+ s->decode = 0;
+ }
+ if (lua_gettop(L) > 1 && lua_isboolean(L, 2)) {
+ decode = lua_toboolean(L, 2);
+ }
+ b = ppstream_all(s->stream,&n,decode);
+ lua_pushlstring(L, (const char *) b, n);
+ lua_pushinteger(L, (int) n);
+ ppstream_done(s->stream);
+ return 2;
+ }
+ return 0;
+}
+
+/*tex
+
+ Alternatively streams can be fetched stepwise:
+
+ okay = openstream(streamobject,[decode])
+ string, n = readfromstream(streamobject)
+ closestream(streamobject)
+
+*/
+
+static int pdfelib_openstream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ if (s->open == 0) {
+ if (lua_gettop(L) > 1) {
+ s->decode = lua_isboolean(L, 2);
+ }
+ s->open = 1;
+ }
+ lua_pushboolean(L,1);
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_closestream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ if (s->open >0) {
+ ppstream_done(s->stream);
+ s->open = 0;
+ s->decode = 0;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_readfromstream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ size_t n = 0;
+ uint8_t *d = NULL;
+ if (s->open == 1) {
+ d = ppstream_first(s->stream,&n,s->decode);
+ s->open = 2;
+ } else if (s->open == 2) {
+ d = ppstream_next(s->stream,&n);
+ } else {
+ return 0;
+ }
+ lua_pushlstring(L, (const char *) d, n);
+ lua_pushinteger(L, (int) n);
+ return 2;
+ }
+ return 0;
+}
+
+/*tex
+
+ There are two methods for opening a document: files and strings.
+
+ \starttyping
+ documentobject = open(filename)
+ documentobject = new(string,length)
+ \stoptyping
+
+ Closing happens with:
+
+ \starttyping
+ close(documentobject)
+ \stoptyping
+
+ When the \type {new} function gets a peudo filename as third argument,
+ no user data will be created but the stream is accessible as image.
+
+*/
+
+static int pdfelib_open(lua_State * L)
+{
+ const char *filename = luaL_checkstring(L, 1);
+ ppdoc *d = ppdoc_load(filename);
+ if (d == NULL) {
+ formatted_warning("pdfe lib","no valid pdf file '%s'",filename);
+ } else {
+ pdfe_document *p = (pdfe_document *) lua_newuserdata(L, sizeof(pdfe_document));
+ luaL_getmetatable(L, PDFE_METATABLE);
+ lua_setmetatable(L, -2);
+ p->document = d;
+ p->open = true;
+ p->isfile = true;
+ p->memstream = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_new(lua_State * L)
+{
+ const char *docstream = NULL;
+ char *memstream = NULL ;
+ unsigned long long streamsize;
+ switch (lua_type(L, 1)) {
+ case LUA_TSTRING:
+ /* stream as Lua string */
+ docstream = luaL_checkstring(L, 1);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ /* stream as sequence of bytes */
+ docstream = (const char *) lua_touserdata(L, 1);
+ break;
+ default:
+ luaL_error(L, "bad <pdfe> argument: string or lightuserdata expected");
+ break;
+ }
+ if (docstream == NULL) {
+ luaL_error(L, "bad <pdfe> document");
+ }
+ /* size of the stream */
+ streamsize = (unsigned long long) luaL_checkint(L, 2);
+ memstream = xmalloc((unsigned) (streamsize + 1));
+ if (! memstream) {
+ luaL_error(L, "no room for <pdfe> stream");
+ }
+ memcpy(memstream, docstream, (streamsize + 1));
+ memstream[streamsize]='\0';
+ if (lua_gettop(L) == 2) {
+ /* we stay at the lua end */
+ ppdoc *d = ppdoc_mem(memstream, streamsize);
+ if (d == NULL) {
+ normal_warning("pdfe lib","no valid pdf mem stream");
+ } else {
+ pdfe_document *p = (pdfe_document *) lua_newuserdata(L, sizeof(pdfe_document));
+ luaL_getmetatable(L, PDFE_METATABLE);
+ lua_setmetatable(L, -2);
+ p->document = d;
+ p->open = true;
+ p->isfile = false;
+ p->memstream = memstream;
+ return 1;
+ }
+ } else {
+ /* pseudo file name */
+ PdfDocument *pdf_doc;
+ const char *file_id = luaL_checkstring(L, 3);
+ if (file_id == NULL) {
+ luaL_error(L, "<pdfe> stream has an invalid id");
+ }
+ if (strlen(file_id) > STREAM_FILE_ID_LEN ) {
+ /* a limit to the length of the string */
+ luaL_error(L, "<pdfe> stream has a too long id");
+ }
+ pdf_doc = refMemStreamPdfDocument(memstream, streamsize, file_id);
+ if (pdf_doc != NULL) {
+ lua_pushstring(L,pdf_doc->file_path);
+ return 1;
+ } else {
+ /* pplib does this: xfree(memstream); */
+ }
+ }
+ return 0;
+}
+
+/*
+
+ There is no garbage collection needed as the library itself manages the
+ objects. Normally objects don't take much space. Streams use buffers so (I
+ assume) that they are not persistent. The only collector is in the parent
+ object (the document).
+
+*/
+
+static int pdfelib_free(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL && p->open) {
+ if (p->document != NULL) {
+ ppdoc_free(p->document);
+ p->document = NULL;
+ }
+ if (p->memstream != NULL) {
+ /* pplib does this: xfree(p->memstream); */
+ p->memstream = NULL;
+ }
+ p->open = false;
+ }
+ return 0;
+}
+
+static int pdfelib_close(lua_State * L)
+{
+ return pdfelib_free(L);
+}
+
+/*tex
+
+ A document is can be uncrypted with:
+
+ \starttyping
+ status = unencrypt(documentobject,user,owner)
+ \stoptyping
+
+ Instead of a password \type {nil} can be passed, so there are three possible
+ useful combinations.
+
+*/
+
+static int pdfelib_unencrypt(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL) {
+ size_t u = 0;
+ size_t o = 0;
+ const char* user = NULL;
+ const char* owner = NULL;
+ int top = lua_gettop(L);
+ if (top > 1) {
+ if (lua_type(L,2) == LUA_TSTRING) {
+ user = lua_tolstring(L, 2, &u);
+ } else {
+ /*tex we're not too picky but normally it will be nil or false */
+ }
+ if (top > 2) {
+ if (lua_type(L,3) == LUA_TSTRING) {
+ owner = lua_tolstring(L, 3, &o);
+ } else {
+ /*tex we're not too picky but normally it will be nil or false */
+ }
+ }
+ lua_pushinteger(L, (int) ppdoc_crypt_pass(p->document,user,u,owner,o));
+ return 1;
+ }
+ }
+ lua_pushinteger(L, (int) PPCRYPT_FAIL);
+ return 1;
+}
+
+/*tex
+
+ There are a couple of ways to get information about the document:
+
+ \starttyping
+ n = getsize (documentobject)
+ major, minor = getversion (documentobject)
+ status = getstatus (documentobject)
+ n = getnofobjects (documentobject)
+ n = getnofpages (documentobject)
+ bytes, waste = getmemoryusage(documentobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getsize(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_file_size(p->document));
+ return 1;
+}
+
+
+static int pdfelib_getversion(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ int minor;
+ int major = ppdoc_version_number(p->document, &minor);
+ lua_pushinteger(L,(int) major);
+ lua_pushinteger(L,(int) minor);
+ return 2;
+ }
+}
+
+static int pdfelib_getstatus(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_crypt_status(p->document));
+ return 1;
+}
+
+static int pdfelib_getnofobjects(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_objects(p->document));
+ return 1;
+}
+
+static int pdfelib_getnofpages(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_page_count(p->document));
+ return 1;
+}
+
+static int pdfelib_getmemoryusage(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL) {
+ size_t w = 0;
+ size_t m = ppdoc_memory(p->document,&w);
+ lua_pushinteger(L,(int) m);
+ lua_pushinteger(L,(int) w);
+ return 2;
+ }
+ return 0;
+}
+
+/*
+ A specific page dictionary can be filtered with the next command. So, there
+ is no need to parse the document page tree (with these \type {kids} arrays).
+
+ \starttyping
+ dictionaryobject = getpage(documentobject,pagenumber)
+ \stoptyping
+
+*/
+
+static int pushpage(lua_State * L, ppdoc * d, int page)
+{
+ if (page <= 0 || page > ppdoc_page_count(d)) {
+ return 0;
+ } else {
+ ppref *pp = ppdoc_page(d,page);
+ return pushdictionaryonly(L, ppref_obj(pp)->dict);
+ }
+}
+
+static int pdfelib_getpage(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ return pushpage(L, p->document, luaL_checkint(L, 2));
+ }
+}
+
+static int pushpages(lua_State * L, ppdoc * d)
+{
+ int i = 0;
+ ppref *r;
+ lua_createtable(L,ppdoc_page_count(d),0);
+ /* pages[1..n] */
+ for (r = ppdoc_first_page(d), i = 1; r != NULL; r = ppdoc_next_page(d), ++i) {
+ pushdictionaryonly(L,ppref_obj(r)->dict);
+ lua_rawseti(L,-2,i);
+ }
+ return 1 ;
+}
+
+static int pdfelib_getpages(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ return pushpages(L, p->document);
+ }
+}
+
+/*tex
+
+ The boundingbox (\type {MediaBox) and similar boxes can be available in a
+ (page) doctionary but also in a parent object. Therefore a helper is
+ available that does the (backtracked) lookup.
+
+ \starttyping
+ { lx, ly, rx, ry } = getbox(dictionaryobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getbox(lua_State * L)
+{
+ if (lua_gettop(L) > 1 && lua_type(L,2) == LUA_TSTRING) {
+ pdfe_dictionary *p = check_isdictionary(L, 1);
+ if (p != NULL) {
+ const char *key = lua_tostring(L,2);
+ pprect box;
+ pprect *r;
+ box.lx = box.rx = box.ly = box.ry = 0;
+ r = ppdict_get_box(p->dictionary,key,&box);
+ if (r != NULL) {
+ lua_createtable(L,4,0);
+ lua_pushnumber(L,r->lx);
+ lua_rawseti(L,-2,1);
+ lua_pushnumber(L,r->ly);
+ lua_rawseti(L,-2,2);
+ lua_pushnumber(L,r->rx);
+ lua_rawseti(L,-2,3);
+ lua_pushnumber(L,r->ry);
+ lua_rawseti(L,-2,4);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ This one is needed when you use the detailed getters and run into an
+ object reference. The regular getters resolve this automatically.
+
+ \starttyping
+ [dictionary|array|stream]object = getfromreference(referenceobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getfromreference(lua_State * L)
+{
+ pdfe_reference *r = check_isreference(L, 1);
+ if (r != NULL) {
+ ppobj *o = ppref_obj(r->reference);
+ lua_pushinteger(L,o->type);
+ return 1 + pushvalue(L,o);
+ }
+ return 0;
+}
+
+/*tex
+
+ Here are some convenient getters:
+
+ \starttyping
+ <string> = getstring (array|dict|ref,index|key)
+ <integer> = getinteger (array|dict|ref,index|key)
+ <number> = getnumber (array|dict|ref,index|key)
+ <boolan> = getboolean (array|dict|ref,index|key)
+ <string> = getname (array|dict|ref,index|key)
+ <dictionary> = getdictionary(array|dict|ref,index|key)
+ <array> = getarray (array|dict|ref,index|key)
+ <stream>, <dict> = getstream (array|dict|ref,index|key)
+ \stoptyping
+
+ We report issues when reasonable but are silent when it makes sense. We don't
+ error on this because we expect the user code to act reasonable on a return
+ value.
+
+*/
+
+#define pdfelib_get_value_check_1 do { \
+ if (p == NULL) { \
+ if (t == LUA_TSTRING) { \
+ normal_warning("pdfe lib","lua <pdfe dictionary> expected"); \
+ } else if (t == LUA_TNUMBER) { \
+ normal_warning("pdfe lib","lua <pdfe array> expected"); \
+ } else { \
+ normal_warning("pdfe lib","invalid arguments"); \
+ } \
+ return 0; \
+ } else if (! lua_getmetatable(L, 1)) { \
+ normal_warning("pdfe lib","first argument should be a <pde array> or <pde dictionary>"); \
+ } \
+} while (0)
+
+#define pdfelib_get_value_check_2 \
+ normal_warning("pdfe lib","second argument should be integer or string");
+
+/*tex
+
+ The direct fetcher returns the result or |NULL| when there is nothing
+ found.
+
+*/
+
+#define pdfelib_get_value_direct(get_d,get_a) do { \
+ int t = lua_type(L,2); \
+ void *p = lua_touserdata(L, 1); \
+ pdfelib_get_value_check_1; \
+ if (t == LUA_TSTRING) { \
+ const char *key = lua_tostring(L,-2); \
+ lua_get_metatablelua(luatex_pdfe_dictionary); \
+ if (lua_rawequal(L, -1, -2)) { \
+ value = get_d(((pdfe_dictionary *) p)->dictionary, key); \
+ } else { \
+ lua_pop(L,1); \
+ lua_get_metatablelua(luatex_pdfe_reference); \
+ if (lua_rawequal(L, -1, -2)) { \
+ ppobj * o = ppref_obj((ppref *) (((pdfe_reference *) p)->reference)); \
+ if (o != NULL && o->type == PPDICT) { \
+ value = get_d((ppdict *)o->dict, key); \
+ } \
+ } \
+ } \
+ } else if (t == LUA_TNUMBER) { \
+ size_t index = lua_tointeger(L,-2); \
+ lua_get_metatablelua(luatex_pdfe_array); \
+ if (lua_rawequal(L, -1, -2)) { \
+ value = get_a(((pdfe_array *) p)->array, index); \
+ } else { \
+ lua_pop(L,1); \
+ lua_get_metatablelua(luatex_pdfe_reference); \
+ if (lua_rawequal(L, -1, -2)) { \
+ ppobj * o = ppref_obj((ppref *) (((pdfe_reference *) p)->reference)); \
+ if (o != NULL && o->type == PPARRAY) { \
+ value = get_a((pparray *) o->array, index); \
+ } \
+ } \
+ } \
+ } else { \
+ pdfelib_get_value_check_2; \
+ } \
+} while (0)
+
+/*tex
+
+ The indirect fetcher passes a pointer to the target variable and returns
+ success state.
+
+*/
+
+#define pdfelib_get_value_indirect(get_d,get_a) do { \
+ int t = lua_type(L,2); \
+ void *p = lua_touserdata(L, 1); \
+ pdfelib_get_value_check_1; \
+ if (t == LUA_TSTRING) { \
+ const char *key = lua_tostring(L,-2); \
+ lua_get_metatablelua(luatex_pdfe_dictionary); \
+ if (lua_rawequal(L, -1, -2)) { \
+ okay = get_d(((pdfe_dictionary *) p)->dictionary, key, &value); \
+ } else { \
+ lua_pop(L,1); \
+ lua_get_metatablelua(luatex_pdfe_reference); \
+ if (lua_rawequal(L, -1, -2)) { \
+ ppobj * o = ppref_obj((ppref *) (((pdfe_reference *) p)->reference)); \
+ if (o != NULL && o->type == PPDICT) \
+ okay = get_d(o->dict, key, &value); \
+ } \
+ } \
+ } else if (t == LUA_TNUMBER) { \
+ size_t index = lua_tointeger(L,-2); \
+ lua_get_metatablelua(luatex_pdfe_array); \
+ if (lua_rawequal(L, -1, -2)) { \
+ okay = get_a(((pdfe_array *) p)->array, index, &value); \
+ } else { \
+ lua_pop(L,1); \
+ lua_get_metatablelua(luatex_pdfe_reference); \
+ if (lua_rawequal(L, -1, -2)) { \
+ ppobj * o = ppref_obj((ppref *) (((pdfe_reference *) p)->reference)); \
+ if (o != NULL && o->type == PPARRAY) \
+ okay = get_a(o->array, index, &value); \
+ } \
+ } \
+ } else { \
+ pdfelib_get_value_check_2; \
+ } \
+} while (0)
+
+static int pdfelib_getstring(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppstring value = NULL;
+ pdfelib_get_value_direct(ppdict_rget_string,pparray_rget_string);
+ if (value != NULL) {
+ lua_pushstring(L,(const char *) value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getinteger(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppint value = 0;
+ int okay = 0;
+ pdfelib_get_value_indirect(ppdict_rget_int,pparray_rget_int);
+ if (okay) {
+ lua_pushinteger(L,(int) value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getnumber(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppnum value = 0;
+ int okay = 0;
+ pdfelib_get_value_indirect(ppdict_rget_num,pparray_rget_num);
+ if (okay) {
+ lua_pushnumber(L,value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getboolean(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ int value = 0;
+ int okay = 0;
+ pdfelib_get_value_indirect(ppdict_rget_bool,pparray_rget_bool);
+ if (okay) {
+ lua_pushboolean(L,value);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getname(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppname value = NULL;
+ pdfelib_get_value_direct(ppdict_rget_name,pparray_rget_name);
+ if (value != NULL) {
+ lua_pushstring(L,(const char *) ppname_decoded(value));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getdictionary(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppdict * value = NULL;
+ pdfelib_get_value_direct(ppdict_rget_dict,pparray_rget_dict);
+ if (value != NULL) {
+ return pushdictionaryonly(L,value);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getarray(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ pparray * value = NULL;
+ pdfelib_get_value_direct(ppdict_rget_array,pparray_rget_array);
+ if (value != NULL) {
+ return pusharrayonly(L,value);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_getstream(lua_State * L)
+{
+ if (lua_gettop(L) > 1) {
+ ppobj * value = NULL;
+ pdfelib_get_value_direct(ppdict_rget_obj,pparray_rget_obj);
+ if (value != NULL && value->type == PPSTREAM) {
+ return pushstreamonly(L,(ppstream *) value->stream);
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ The generic pushed that does a similar job as the previous getters acts upon
+ the type.
+
+*/
+
+static int pdfelib_pushvalue(lua_State * L, ppobj *object)
+{
+ switch (object->type) {
+ case PPNONE:
+ case PPNULL:
+ lua_pushnil(L);
+ break;
+ case PPBOOL:
+ lua_pushboolean(L, object->integer);
+ break;
+ case PPINT:
+ lua_pushinteger(L, object->integer);
+ break;
+ case PPNUM:
+ lua_pushnumber(L, object->number);
+ break;
+ case PPNAME:
+ lua_pushstring(L, (const char *) ppname_decoded(object->name));
+ break;
+ case PPSTRING:
+ lua_pushlstring(L,(const char *) object->string, ppstring_size((void *)object->string));
+ break;
+ case PPARRAY:
+ return pusharrayonly(L, object->array);
+ break;
+ case PPDICT:
+ return pushdictionary(L, object->dict);
+ break;
+ case PPSTREAM:
+ return pushstream(L, object->stream);
+ break;
+ case PPREF:
+ pushreference(L, object->ref);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+ return 1;
+}
+
+/*tex
+
+ Finally we arrived at the acessors for the userdata objects. The use
+ previously defined helpers.
+
+*/
+
+static int pdfelib_access(lua_State * L)
+{
+ if (lua_type(L,2) == LUA_TSTRING) {
+ pdfe_document *p = (pdfe_document *)lua_touserdata(L, 1);
+ const char *s = lua_tostring(L,2);
+ if (lua_key_eq(s,catalog) || lua_key_eq(s,Catalog)) {
+ return pushdictionaryonly(L,ppdoc_catalog(p->document));
+ } else if (lua_key_eq(s,info) || lua_key_eq(s,Info)) {
+ return pushdictionaryonly(L,ppdoc_info(p->document));
+ } else if (lua_key_eq(s,trailer) || lua_key_eq(s,Trailer)) {
+ return pushdictionaryonly(L,ppdoc_trailer(p->document));
+ } else if (lua_key_eq(s,pages) || lua_key_eq(s,Pages)) {
+ return pushpages(L,p->document);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_array_access(lua_State * L)
+{
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ pdfe_array *p = (pdfe_array *)lua_touserdata(L, 1);
+ ppint index = lua_tointeger(L,2) - 1;
+ ppobj *o = pparray_rget_obj(p->array,index);
+ if (o != NULL) {
+ return pdfelib_pushvalue(L,o);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_dictionary_access(lua_State * L)
+{
+ pdfe_dictionary *p = (pdfe_dictionary *)lua_touserdata(L, 1);
+ if (lua_type(L,2) == LUA_TSTRING) {
+ const char *key = lua_tostring(L,2);
+ ppobj *o = ppdict_rget_obj(p->dictionary,key);
+ if (o != NULL) {
+ return pdfelib_pushvalue(L,o);
+ }
+ } else if (lua_type(L,2) == LUA_TNUMBER) {
+ ppint index = lua_tointeger(L,2) - 1;
+ ppobj *o = ppdict_at(p->dictionary,index);
+ if (o != NULL) {
+ return pdfelib_pushvalue(L,o);
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_stream_access(lua_State * L)
+{
+ pdfe_stream *p = (pdfe_stream *)lua_touserdata(L, 1);
+ if (lua_type(L,2) == LUA_TSTRING) {
+ const char *key = lua_tostring(L,2);
+ ppobj *o = ppdict_rget_obj(p->stream->dict,key);
+ if (o != NULL) {
+ return pdfelib_pushvalue(L,o);
+ }
+ } else if (lua_type(L,2) == LUA_TNUMBER) {
+ ppint index = lua_tointeger(L,2) - 1;
+ ppobj *o = ppdict_at(p->stream->dict,index);
+ if (o != NULL) {
+ return pdfelib_pushvalue(L,o);
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ The length metamethods are defined last.
+
+*/
+
+static int pdfelib_array_size(lua_State * L)
+{
+ pdfe_array *p = (pdfe_array *)lua_touserdata(L, 1);
+ lua_pushinteger(L,p->array->size);
+ return 1;
+}
+
+static int pdfelib_dictionary_size(lua_State * L)
+{
+ pdfe_dictionary *p = (pdfe_dictionary *)lua_touserdata(L, 1);
+ lua_pushinteger(L,p->dictionary->size);
+ return 1;
+}
+
+static int pdfelib_stream_size(lua_State * L)
+{
+ pdfe_stream *p = (pdfe_stream *)lua_touserdata(L, 1);
+ lua_pushinteger(L,p->stream->dict->size);
+ return 1;
+}
+
+/*tex
+
+ We now initialize the main interface. We might aa few more
+ informational helpers but this is it.
+
+*/
+
+static const struct luaL_Reg pdfelib[] = {
+ /* management */
+ { "type", pdfelib_type },
+ { "open", pdfelib_open },
+ { "new", pdfelib_new },
+ { "close", pdfelib_close },
+ { "unencrypt", pdfelib_unencrypt },
+ /* statistics */
+ { "getversion", pdfelib_getversion },
+ { "getstatus", pdfelib_getstatus },
+ { "getsize", pdfelib_getsize },
+ { "getnofobjects", pdfelib_getnofobjects },
+ { "getnofpages", pdfelib_getnofpages },
+ { "getmemoryusage", pdfelib_getmemoryusage },
+ /* getters */
+ { "getcatalog", pdfelib_getcatalog },
+ { "gettrailer", pdfelib_gettrailer },
+ { "getinfo", pdfelib_getinfo },
+ { "getpage", pdfelib_getpage },
+ { "getpages", pdfelib_getpages },
+ { "getbox", pdfelib_getbox },
+ { "getfromreference", pdfelib_getfromreference },
+ { "getfromdictionary", pdfelib_getfromdictionary },
+ { "getfromarray", pdfelib_getfromarray },
+ { "getfromstream", pdfelib_getfromstream },
+ /* collectors */
+ { "dictionarytotable", pdfelib_dictionarytotable },
+ { "arraytotable", pdfelib_arraytotable },
+ { "pagestotable", pdfelib_pagestotable },
+ /* more getters */
+ { "getstring", pdfelib_getstring },
+ { "getinteger", pdfelib_getinteger },
+ { "getnumber", pdfelib_getnumber },
+ { "getboolean", pdfelib_getboolean },
+ { "getname", pdfelib_getname },
+ { "getdictionary", pdfelib_getdictionary },
+ { "getarray", pdfelib_getarray },
+ { "getstream", pdfelib_getstream },
+ /* streams */
+ { "readwholestream", pdfelib_readwholestream },
+ /* not really needed */
+ { "openstream", pdfelib_openstream },
+ { "readfromstream", pdfelib_readfromstream },
+ { "closestream", pdfelib_closestream },
+ /* done */
+ { NULL, NULL}
+};
+
+/*tex
+
+ The user data metatables are defined as follows. Watch how only the
+ document needs a garbage collector.
+
+*/
+
+static const struct luaL_Reg pdfelib_m[] = {
+ { "__tostring", pdfelib_tostring_document },
+ { "__gc", pdfelib_free },
+ { "__index", pdfelib_access },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_dictionary[] = {
+ { "__tostring", pdfelib_tostring_dictionary },
+ { "__index", pdfelib_dictionary_access },
+ { "__len", pdfelib_dictionary_size },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_array[] = {
+ { "__tostring", pdfelib_tostring_array },
+ { "__index", pdfelib_array_access },
+ { "__len", pdfelib_array_size },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_stream[] = {
+ { "__tostring", pdfelib_tostring_stream },
+ { "__index", pdfelib_stream_access },
+ { "__len", pdfelib_stream_size },
+ { "__call", pdfelib_readwholestream },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_reference[] = {
+ { "__tostring", pdfelib_tostring_reference },
+ { NULL, NULL}
+};
+
+/*tex
+
+ Finally we hav earrived at the main initialiser that will be called as part
+ of \LUATEX's initializer.
+
+*/
+
+/*tex
+
+ Here we hook in the error handler.
+
+*/
+
+static void pdfelib_message(const char *message, void *alien)
+{
+ normal_warning("pdfe",message);
+}
+
+int luaopen_pdfe(lua_State * L)
+{
+ /*tex First the four userdata object get their metatables defined. */
+
+ luaL_newmetatable(L, PDFE_METATABLE_DICTIONARY);
+ luaL_openlib(L, NULL, pdfelib_m_dictionary, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_ARRAY);
+ luaL_openlib(L, NULL, pdfelib_m_array, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_STREAM);
+ luaL_openlib(L, NULL, pdfelib_m_stream, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_REFERENCE);
+ luaL_openlib(L, NULL, pdfelib_m_reference, 0);
+
+ /*tex Then comes the main (document) metatable: */
+
+ luaL_newmetatable(L, PDFE_METATABLE);
+ luaL_openlib(L, NULL, pdfelib_m, 0);
+
+ /*tex Last the library opens up itself to the world. */
+
+ luaL_openlib(L, "pdfe", pdfelib, 0);
+
+ pplog_callback(pdfelib_message, stderr);
+
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
new file mode 100644
index 00000000000..6c3bc8876ee
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
@@ -0,0 +1,1110 @@
+/* lpdfscannerlib.c
+
+ Copyright 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/>.
+
+*/
+
+/*tex
+
+ The scanner can read from a string or stream. Streams can be given directly as
+ |ppstream| object or as a |pparray| of streams. Here is an example of usage:
+
+ \starttyping
+ local operatortable = { }
+
+ operatortable.Do = function(scanner,info)
+ local resources = info.resources
+ if resources then
+ local val = scanner:pop()
+ local name = val[2]
+ local xobject = resources.XObject
+ print(info.space .. "Uses XObject " .. name)
+ local resources = xobject.Resources
+ if resources then
+ local newinfo = {
+ space = info.space .. " ",
+ resources = resources,
+ }
+ pdfscanner.scan(entry, operatortable, newinfo)
+ end
+ end
+ end
+
+ local function Analyze(filename)
+ local doc = pdfe.open(filename)
+ if doc then
+ local pages = doc.Pages
+ for i=1,#pages do
+ local page = pages[i]
+ local info = {
+ space = " " ,
+ resources = page.Resources,
+ }
+ print("Page " .. i)
+ pdfscanner.scan(page.Contents,operatortable,info)
+ pdfscanner.scan(page.Contents(),operatortable,info)
+ end
+ end
+ end
+
+ Analyze("foo.pdf")
+ \stoptyping
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "luapplib/pplib.h"
+
+#include <lua/luatex-api.h>
+
+#define SCANNER "pdfscanner"
+
+#define MAXOPERANDS 1000
+
+typedef enum {
+ pdf_integer = 1,
+ pdf_real,
+ pdf_boolean,
+ pdf_name,
+ pdf_operator,
+ pdf_string,
+ pdf_startarray,
+ pdf_stoparray,
+ pdf_startdict,
+ pdf_stopdict,
+} pdf_token_type;
+
+typedef struct Token {
+ pdf_token_type type;
+ double value;
+ char *string;
+} Token;
+
+typedef struct ObjectList {
+ struct ObjectList *next;
+ ppstream *stream;
+} ObjectList;
+
+typedef struct scannerdata {
+ int _ininlineimage;
+ int _nextoperand;
+ Token **_operandstack;
+ ppstream *_stream;
+ ObjectList *_streams;
+ const char *buffer;
+ size_t position;
+ size_t size;
+ int uses_stream;
+} scannerdata;
+
+#define PDFE_METATABLE_ARRAY "luatex.pdfe.array"
+#define PDFE_METATABLE_STREAM "luatex.pdfe.stream"
+
+typedef struct {
+ void *d;
+ /*tex reference to |PdfDocument|, or |NULL| */
+ void *pd;
+ /*tex counter to detect |PDFDoc| change */
+ unsigned long pc;
+} udstruct;
+
+static void clear_operand_stack(scannerdata * self, int from);
+static Token *_parseToken(scannerdata * self, int c);
+static void push_token(lua_State * L, scannerdata * self);
+
+static void *priv_xmalloc(size_t size)
+{
+ void *new_mem = (void *) malloc(size);
+ if (new_mem == NULL) {
+ luaL_error(Luas, "no room for <pdfscanned> stream");
+ }
+ return new_mem;
+}
+
+static void *priv_xrealloc(void *old_ptr, size_t size)
+{
+ void *new_mem = (void *) realloc(old_ptr, size);
+ if (new_mem == NULL) {
+ luaL_error(Luas, "no room for <pdfscanned> stream");
+ }
+ return new_mem;
+}
+
+#define xreallocarray(ptr,type,size) ((type*)priv_xrealloc(ptr,(size+1)*sizeof(type)))
+
+#define INITBUFSIZE 64
+
+#define define_buffer(a) \
+ char *a = (char *)priv_xmalloc (INITBUFSIZE); \
+ int a##_size = INITBUFSIZE; \
+ int a##index = 0; \
+ memset (a,0,INITBUFSIZE)
+
+#define check_overflow(a, wsize) do { \
+ if (wsize >= a##_size) { \
+ int nsize = a##_size + a##_size / 4; \
+ a = (char *) xreallocarray(a, char, (unsigned) nsize); \
+ memset (a+a##_size, 0, a##_size / 4); \
+ a##_size = nsize; \
+ } \
+} while (0)
+
+
+static scannerdata *scanner_push(lua_State * L)
+{
+ scannerdata *a = (scannerdata *) lua_newuserdata(L, sizeof(scannerdata));
+ luaL_getmetatable(L, SCANNER);
+ lua_setmetatable(L, -2);
+ return a;
+}
+
+static scannerdata *scanner_check(lua_State * L, int index)
+{
+ scannerdata *bar;
+ luaL_checktype(L, index, LUA_TUSERDATA);
+ bar = (scannerdata *) luaL_checkudata(L, index, SCANNER);
+ if (bar == NULL)
+ luaL_argerror(L, index, SCANNER " expected");
+ return bar;
+}
+
+static void free_token(Token * token)
+{
+ if (token->string) {
+ free(token->string);
+ }
+ free(token);
+}
+
+static void clear_operand_stack(scannerdata * self, int from)
+{
+ int i = self->_nextoperand - 1;
+ while (i >= from) {
+ if (self->_operandstack[i]) {
+ free_token(self->_operandstack[i]);
+ self->_operandstack[i] = NULL;
+ }
+ i--;
+ }
+ self->_nextoperand = from;
+}
+
+static void push_operand(scannerdata * self, Token * token)
+{
+ if (self->_nextoperand + 1 > MAXOPERANDS) {
+ fprintf(stderr, "out of operand stack space");
+ exit(1);
+ }
+ self->_operandstack[self->_nextoperand++] = token;
+}
+
+static Token *new_operand(pdf_token_type c)
+{
+ Token *token = (Token *) priv_xmalloc(sizeof(Token));
+ memset(token, 0, sizeof(Token));
+ token->type = c;
+ return token;
+}
+
+static void _nextStream(scannerdata * self)
+{
+ ObjectList *rover = NULL;
+ if (self->uses_stream && self->buffer != NULL) {
+ if (self->uses_stream) {
+ ppstream_done(self->_stream);
+ } else {
+ free(self->_stream);
+ }
+ }
+ rover = self->_streams;
+ self->_stream = rover->stream;
+ if (self->uses_stream) {
+ self->buffer = (const char *) ppstream_all(self->_stream, &self->size, 1);
+ }
+ self->position = 0;
+ self->_streams = rover->next;
+ free(rover);
+}
+
+static int streamGetChar(scannerdata * self)
+{
+ int i = EOF;
+ if (self->position < self->size) {
+ const char c = self->buffer[self->position];
+ ++self->position;
+ i = (int) c;
+ }
+ if (i < 0 && self->_streams) {
+ _nextStream(self);
+ i = streamGetChar(self);
+ }
+ return i;
+}
+
+static int streamLookChar(scannerdata * self)
+{
+ int i = EOF;
+ if (self->position < self->size) {
+ const char c = self->buffer[self->position];
+ /*not |++self->position;| */
+ i = (int) c;
+ }
+ if (i < 0 && self->_streams) {
+ _nextStream(self);
+ i = streamGetChar(self);
+ }
+ return i;
+}
+
+static void streamReset(scannerdata * self)
+{
+ if (self->uses_stream) {
+ self->buffer = (const char *) ppstream_all(self->_stream, &self->size, 1);
+ }
+ self->position = 0;
+}
+
+static void streamClose(scannerdata * self)
+{
+ if (self->uses_stream) {
+ ppstream_done(self->_stream);
+ } else {
+ free(self->_stream);
+ }
+ self->buffer = NULL;
+ self->_stream = NULL;
+}
+
+/*tex end of stream interface */
+
+static Token *_parseSpace(scannerdata * self)
+{
+ return _parseToken(self, streamGetChar(self));
+}
+
+static Token *_parseString(scannerdata * self, int c)
+{
+ int level;
+ Token *token = NULL;
+ define_buffer(found);
+ level = 1;
+ while (1) {
+ c = streamGetChar(self);
+ if (c == '(') {
+ level = level + 1;
+ } else if (c == ')') {
+ level = level - 1;
+ if (level < 1)
+ break;
+ } else if (c == '\\') {
+ int next = streamGetChar(self);
+ if (next == '(' || next == ')' || next == '\\') {
+ c = next;
+ } else if (next == '\n' || next == '\r') {
+ c = '\0';
+ } else if (next == 'n') {
+ c = '\n';
+ } else if (next == 'r') {
+ c = '\r';
+ } else if (next == 't') {
+ c = '\t';
+ } else if (next == 'b') {
+ c = '\b';
+ } else if (next == 'f') {
+ c = '\f';
+ } else if (next >= '0' && next <= '7') {
+ int next2;
+ next = next - '0';
+ next2 = streamLookChar(self);
+ if (next2 >= '0' && next2 <= '7') {
+ int next3;
+ next2 = streamGetChar(self);
+ next2 = next2 - '0';
+ next3 = streamLookChar(self);
+ if (next3 >= '0' && next3 <= '7') {
+ next3 = streamGetChar(self);
+ next3 = next3 - '0';
+ c = (next * 64 + next2 * 8 + next3);
+ } else {
+ c = (next * 8 + next2);
+ }
+ } else {
+ c = next;
+ }
+ } else {
+ c = next;
+ }
+ }
+ check_overflow(found, foundindex);
+ if (c >= 0) {
+ found[foundindex++] = c;
+ }
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+static Token *_parseNumber(scannerdata * self, int c)
+{
+ double value = 0;
+ pdf_token_type type = pdf_integer;
+ int isfraction = 0;
+ int isnegative = 0;
+ int i = 0;
+ Token *token = NULL;
+ if (c == '-') {
+ isnegative = 1;
+ c = streamGetChar(self);
+ }
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ value = c - '0';
+ }
+ c = streamLookChar(self);
+ if ((c >= '0' && c <= '9') || c == '.') {
+ c = streamGetChar(self);
+ while (1) {
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ i = c - '0';
+ if (isfraction > 0) {
+ value = value + (i / (pow(10.0, isfraction)));
+ isfraction = isfraction + 1;
+ } else {
+ value = (value * 10) + i;
+ }
+ }
+ c = streamLookChar(self);
+ if (!((c >= '0' && c <= '9') || c == '.'))
+ break;
+ c = streamGetChar(self);
+ }
+ }
+ if (isnegative) {
+ value = -value;
+ }
+ token = new_operand(type);
+ token->value = value;
+ return token;
+}
+
+static Token *_parseName(scannerdata * self, int c)
+{
+ Token *token = NULL;
+ define_buffer(found);
+ c = streamGetChar(self);
+ while (1) {
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<')
+ break;
+ c = streamGetChar(self);
+ }
+ token = new_operand(pdf_name);
+ token->string = found;
+ token->value = strlen(found);
+ return token;
+}
+
+#define hexdigit(c) \
+ (c>= '0' && c<= '9') ? (c - '0') : ((c>= 'A' && c<= 'F') ? (c - 'A' + 10) : (c - 'a' + 10))
+
+static Token *_parseHexstring(scannerdata * self, int c)
+{
+ int isodd = 1;
+ int hexval = 0;
+ Token *token = NULL;
+ define_buffer(found);
+ while (c != '>') {
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
+ if (isodd == 1) {
+ int v = hexdigit(c);
+ hexval = 16 * v;
+ } else {
+ hexval += hexdigit(c);
+ check_overflow(found, foundindex);
+ found[foundindex++] = hexval;
+ }
+ isodd = (isodd == 1 ? 0 : 1);
+ }
+ c = streamGetChar(self);
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+#define pdf_isspace(a) (a == '\0' || a == ' ' || a == '\n' || a == '\r' || a == '\t' || a == '\v')
+
+/*tex this is rather horrible */
+
+static Token *_parseInlineImage(scannerdata * self, int c)
+{
+ Token *token = NULL;
+ define_buffer(found);
+ if (c == ' ') {
+ /*tex first space can be ignored */
+ c = streamGetChar(self);
+ }
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ while (1) {
+ c = streamLookChar(self);
+ if (c == 'E'
+ && (found[foundindex - 1] == '\n'
+ || found[foundindex - 1] == '\r')) {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == 'I') {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (pdf_isspace(c)) {
+ /*tex |I| */
+ found[--foundindex] = '\0';
+ /*tex |E| */
+ found[--foundindex] = '\0';
+ /*tex remove end-of-line before |EI| */
+ if (found[foundindex - 1] == '\n') {
+ found[--foundindex] = '\0';
+ }
+ if (found[foundindex - 1] == '\r') {
+ found[--foundindex] = '\0';
+ }
+ break;
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+static Token *_parseOperator(scannerdata * self, int c)
+{
+ define_buffer(found);
+ while (1) {
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if ((c < 0) || (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<'))
+ break;
+ c = streamGetChar(self);
+ }
+ /*tex |print| (found) */
+ if (strcmp(found, "ID") == 0) {
+ self->_ininlineimage = 1;
+ }
+ if (strcmp(found, "false") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 0;
+ free(found);
+ return token;
+ } else if (strcmp(found, "true") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 1.0;
+ free(found);
+ return token;
+ } else {
+ Token *token = new_operand(pdf_operator);
+ token->string = found;
+ return token;
+ }
+}
+
+static Token *_parseComment(scannerdata * self, int c)
+{
+ do {
+ c = streamGetChar(self);
+ } while (c != '\n' && c != '\r' && c != -1);
+ return _parseToken(self, streamGetChar(self));
+}
+
+static Token *_parseLt(scannerdata * self, int c)
+{
+ c = streamGetChar(self);
+ if (c == '<') {
+ return new_operand(pdf_startdict);
+ } else {
+ return _parseHexstring(self, c);
+ }
+}
+
+static Token *_parseGt(scannerdata * self, int c)
+{
+ c = streamGetChar(self);
+ if (c == '>') {
+ return new_operand(pdf_stopdict);
+ } else {
+ fprintf(stderr, "stray > in stream");
+ return NULL;
+ }
+}
+
+static Token *_parseError(int c)
+{
+ fprintf(stderr, "stray %c [%d] in stream", c, c);
+ return NULL;
+}
+
+static Token *_parseStartarray(void)
+{
+ return new_operand(pdf_startarray);
+}
+
+static Token *_parseStoparray(void)
+{
+ return new_operand(pdf_stoparray);
+}
+
+static Token *_parseToken(scannerdata * self, int c)
+{
+ if (self->_ininlineimage == 1) {
+ self->_ininlineimage = 2;
+ return _parseInlineImage(self, c);
+ } else if (self->_ininlineimage == 2) {
+ Token *token = NULL;
+ self->_ininlineimage = 0;
+ token = new_operand(pdf_operator);
+ token->string = strdup("EI");
+ return token;
+ }
+ if (c < 0)
+ return NULL;
+ switch (c) {
+ case '(':
+ return _parseString(self, c);
+ break;
+ case ')':
+ return _parseError(c);
+ break;
+ case '[':
+ return _parseStartarray();
+ break;
+ case ']':
+ return _parseStoparray();
+ break;
+ case '/':
+ return _parseName(self, c);
+ break;
+ case '<':
+ return _parseLt(self, c);
+ break;
+ case '>':
+ return _parseGt(self, c);
+ break;
+ case '%':
+ return _parseComment(self, c);
+ break;
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ return _parseSpace(self);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '.':
+ return _parseNumber(self, c);
+ break;
+ default:
+ if (c <= 127) {
+ return _parseOperator(self, c);
+ } else {
+ return _parseError(c);
+ }
+ }
+}
+
+static int scanner_scan(lua_State * L)
+{
+ Token *token;
+ scannerdata *self;
+ if (lua_gettop(L) != 3) {
+ return 0;
+ }
+ luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checktype(L, 3, LUA_TTABLE);
+ self = scanner_push(L);
+ memset(self, 0, sizeof(scannerdata));
+ self->_operandstack = (Token **) priv_xmalloc(MAXOPERANDS * sizeof(Token));
+ memset(self->_operandstack, 0, (MAXOPERANDS * sizeof(Token)));
+ /*tex stack slot 4 = self */
+ self->uses_stream = 1;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ /*tex
+ We could make a temporary copy on the stack (or in the registry)
+ which saves memory.
+ */
+ char *buf = NULL;
+ const char *s = lua_tolstring(L, 1, &self->size);
+ if (s==NULL){
+ fprintf(stderr,"fatal: cannot convert the token to string.");
+ exit(1);
+ }
+ buf = priv_xmalloc(self->size+1);
+ buf[self->size]='\0';
+ self->uses_stream = 0;
+ memcpy(buf,s,self->size);
+ self->buffer = buf;
+ } else if (lua_type(L, 1) == LUA_TTABLE) {
+ udstruct *uin;
+ void *ud;
+ int i = 1;
+ while (1) {
+ lua_rawgeti(L, 1, i);
+ if (lua_type(L, -1) == LUA_TUSERDATA) {
+ ud = luaL_checkudata(L, -1, PDFE_METATABLE_STREAM);
+ if (ud != NULL) {
+ ObjectList *rover = NULL;
+ ObjectList *item = NULL;
+ uin = (udstruct *) ud;
+ rover = self->_streams;
+ item = (ObjectList *) priv_xmalloc(sizeof(ObjectList));
+ item->stream = ((ppstream *) uin->d);
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ } else {
+ ObjectList *rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ free(rover);
+ lua_pop(L, 1);
+ break;
+ }
+ lua_pop(L, 1);
+ i++;
+ }
+ } else {
+ udstruct *uin;
+ void *ud;
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ ud = luaL_checkudata(L, 1, PDFE_METATABLE_STREAM);
+ if (ud != NULL) {
+ uin = (udstruct *) ud;
+ self->_stream = ((ppstream *) uin->d);
+ } else {
+ ud = luaL_checkudata(L, 1, PDFE_METATABLE_ARRAY);
+ if (ud != NULL) {
+ ObjectList *rover = NULL;
+ pparray *array = NULL;
+ int count;
+ int i;
+ uin = (udstruct *) ud;
+ array = (pparray *) uin->d;
+ count = array->size;
+ for (i = 0; i < count; i++) {
+ ppobj *obj = pparray_at(array, i);
+ if (obj->type == PPSTREAM) {
+ ObjectList *rover = self->_streams;
+ ObjectList *item =
+ (ObjectList *)
+ priv_xmalloc(sizeof(ObjectList));
+ item->stream = obj->stream;
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ }
+ rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ }
+ }
+ }
+ streamReset(self);
+ token = _parseToken(self, streamGetChar(self));
+ while (token) {
+ if (token->type == pdf_operator) {
+ lua_pushstring(L, token->string);
+ free_token(token);
+ /*tex fetch operator table */
+ lua_rawget(L, 2);
+ if (lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 4);
+ lua_pushvalue(L, 3);
+ (void) lua_call(L, 2, 0);
+ } else {
+ /*tex nil */
+ lua_pop(L, 1);
+ }
+ clear_operand_stack(self, 0);
+ } else {
+ push_operand(self, token);
+ }
+ if (self->uses_stream) {
+ if (!self->_stream) {
+ break;
+ }
+ } else {
+ if (self->buffer == NULL) {
+ break;
+ }
+ }
+ token = _parseToken(self, streamGetChar(self));
+ }
+ /*tex wrap up */
+ if (self->_stream) {
+ streamClose(self);
+ }
+ clear_operand_stack(self, 0);
+ free(self->_operandstack);
+ return 0;
+}
+
+static int scanner_done(lua_State * L)
+{
+ int c;
+ scannerdata *self = scanner_check(L, 1);
+ while ((c = streamGetChar(self)) >= 0);
+ return 0;
+}
+
+/*tex here are the stack popping functions, and their helpers */
+
+static void operandstack_backup(scannerdata * self)
+{
+ int i = self->_nextoperand - 1;
+ int balance = 0;
+ int backupstart = 0;
+ int backupstop = self->_operandstack[i]->type;
+ if (backupstop == pdf_stopdict) {
+ backupstart = pdf_startdict;
+ } else if (backupstop == pdf_stoparray) {
+ backupstart = pdf_startarray;
+ } else {
+ return;
+ }
+ for (; i >= 0; i--) {
+ if (self->_operandstack[i]->type == backupstop) {
+ balance++;
+ } else if (self->_operandstack[i]->type == backupstart) {
+ balance--;
+ }
+ if (balance == 0) {
+ break;
+ }
+ }
+ self->_nextoperand = i + 1;
+}
+
+static void push_array(lua_State * L, scannerdata * self)
+{
+ /*tex nesting tracking */
+ int balance = 1;
+ /*tex \LUA\ array index */
+ int index = 1;
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stoparray)
+ balance--;
+ if (token->type == pdf_startarray)
+ balance++;
+ if (!balance) {
+ break;
+ } else {
+ push_token(L, self);
+ lua_rawseti(L, -2, index++);
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+
+static void push_dict(lua_State * L, scannerdata * self)
+{
+ /*tex nesting tracking */
+ int balance = 1;
+ /*tex toggle between \LUA\ value and \LUA\ key */
+ int needskey = 1;
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stopdict)
+ balance--;
+ if (token->type == pdf_startdict)
+ balance++;
+ if (!balance) {
+ break;
+ } else if (needskey) {
+ lua_pushlstring(L, token->string, token->value);
+ needskey = 0;
+ } else {
+ push_token(L, self);
+ needskey = 1;
+ lua_rawset(L, -3);
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+const char *typenames[pdf_stopdict + 1] = {
+ "unknown", "integer", "real", "boolean", "name", "operator",
+ "string", "array", "array", "dict", "dict"
+};
+
+static void push_token(lua_State * L, scannerdata * self)
+{
+ Token *token = self->_operandstack[self->_nextoperand - 1];
+ lua_createtable(L, 2, 0);
+ lua_pushstring(L, typenames[token->type]);
+ lua_rawseti(L, -2, 1);
+ if (token->type == pdf_string || token->type == pdf_name) {
+ lua_pushlstring(L, token->string, token->value);
+ } else if (token->type == pdf_real || token->type == pdf_integer) {
+ /*tex This is an integer or float. */
+ lua_pushnumber(L, token->value);
+ } else if (token->type == pdf_boolean) {
+ lua_pushboolean(L, (int) token->value);
+ } else if (token->type == pdf_startarray) {
+ push_array(L, self);
+ } else if (token->type == pdf_startdict) {
+ push_dict(L, self);
+ } else {
+ lua_pushnil(L);
+ }
+ lua_rawseti(L, -2, 2);
+}
+
+static int scanner_popsingular(lua_State * L, int token_type)
+{
+ Token *token = NULL;
+ /*tex this keeps track of how much of the operand stack needs deleting: */
+ int clear = 0;
+ scannerdata *self = scanner_check(L, 1);
+ if (self->_nextoperand == 0) {
+ return 0;
+ }
+ clear = self->_nextoperand - 1;
+ token = self->_operandstack[self->_nextoperand - 1];
+ if (token == NULL || (token->type != token_type)) {
+ return 0;
+ }
+ /*tex
+ The simple cases can be written out directly, but dicts and
+ arrays are better done via the recursive function.
+ */
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand - 1;
+ push_token(L, self);
+ lua_rawgeti(L, -1, 2);
+ } else if (token_type == pdf_real || token_type == pdf_integer) {
+ /*tex the number can be an integer or float */
+ lua_pushnumber(L, token->value);
+ } else if (token_type == pdf_boolean) {
+ lua_pushboolean(L, (int) token->value);
+ } else if (token_type == pdf_name || token_type == pdf_string) {
+ lua_pushlstring(L, token->string, token->value);
+ } else {
+ return 0;
+ }
+ clear_operand_stack(self, clear);
+ return 1;
+}
+
+static int scanner_popanything(lua_State * L)
+{
+ Token *token = NULL;
+ /*tex how much of the operand stack needs deleting: */
+ int clear = 0;
+ int token_type;
+ scannerdata *self = scanner_check(L, 1);
+ if (self->_nextoperand == 0) {
+ return 0;
+ }
+ clear = self->_nextoperand - 1;
+ token = self->_operandstack[self->_nextoperand - 1];
+ if (token == NULL) {
+ return 0;
+ }
+ token_type = token->type;
+ /*tex
+ The simple cases can be written out directly, but dicts and
+ arrays are better done via the recursive function.
+ */
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand - 1;
+ push_token(L, self);
+ } else {
+ push_token(L, self);
+ }
+ clear_operand_stack(self, clear);
+ return 1;
+}
+
+static int scanner_popnumber(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_real))
+ return 1;
+ if (scanner_popsingular(L, pdf_integer))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popboolean(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_boolean))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popstring(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_string))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popname(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_name))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_poparray(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_stoparray))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popdictionary(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_stopdict))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popany(lua_State * L)
+{
+ if (scanner_popanything(L))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static const luaL_Reg scannerlib_meta[] = {
+ {0, 0}
+};
+
+static const struct luaL_Reg scannerlib_m[] = {
+ { "done", scanner_done },
+ { "pop", scanner_popany },
+ { "popnumber", scanner_popnumber },
+ { "popname", scanner_popname },
+ { "popstring", scanner_popstring },
+ { "poparray", scanner_poparray },
+ { "popdictionary", scanner_popdictionary },
+ { "popboolean", scanner_popboolean },
+ /*tex For old times sake: */
+ { "popNumber", scanner_popnumber },
+ { "popName", scanner_popname },
+ { "popString", scanner_popstring },
+ { "popArray", scanner_poparray },
+ { "popDict", scanner_popdictionary },
+ { "popBool", scanner_popboolean },
+ /*tex Sentinel: */
+ { NULL, NULL }
+};
+
+static const luaL_Reg scannerlib[] = {
+ { "scan", scanner_scan },
+ /*tex Sentinel: */
+ { NULL, NULL }
+};
+
+LUALIB_API int luaopen_pdfscanner(lua_State * L)
+{
+ luaL_newmetatable(L, SCANNER);
+ luaL_openlib(L, 0, scannerlib_meta, 0);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_openlib(L, NULL, scannerlib_m, 0);
+ luaL_openlib(L, "pdfscanner", scannerlib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luainit.w b/Build/source/texk/web2c/luatexdir/lua/luainit.c
index dec76b0216b..60c654aa0a0 100644
--- a/Build/source/texk/web2c/luatexdir/lua/luainit.w
+++ b/Build/source/texk/web2c/luatexdir/lua/luainit.c
@@ -1,23 +1,25 @@
-% luainit.w
-%
-% Copyright 2006-2018 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
+/*
+
+luainit.w
+
+Copyright 2006-2018 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"
@@ -29,27 +31,23 @@
extern int load_luatex_core_lua (lua_State * L);
-/* internalized strings: see luatex-api.h */
-set_make_keys;
+/*tex internalized strings: see luatex-api.h */
-@
-This file is getting a bit messy, but it is not simple to fix unilaterally.
+set_make_keys;
-Better to wait until Karl has some time (after texlive 2008) so we can
-synchronize with kpathsea. One problem, for instance, is that I would
-like to resolve the full executable path. |kpse_set_program_name()| does
-that, indirectly (by setting SELFAUTOLOC in the environment), but it
-does much more, making it hard to use for our purpose.
+/*tex
-In fact, it sets three C variables:
+This file is getting a bit messy, but it is not simple to fix unilaterally. In
+fact, it sets three C variables:
- |kpse_invocation_name| |kpse_invocation_short_name| |kpse->program_name|
+ |kpse_invocation_name| |kpse_invocation_short_name| |kpse->program_name|
and five environment variables:
- SELFAUTOLOC SELFAUTODIR SELFAUTOPARENT SELFAUTOGRANDPARENT progname
+ |SELFAUTOLOC| |SELFAUTODIR| |SELFAUTOPARENT| |SELFAUTOGRANDPARENT| |progname|
+
+*/
-@c
const_string LUATEX_IHELP[] = {
"Usage: " my_name " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]",
" or: " my_name " --lua=FILE [OPTION]... \\FIRST-LINE",
@@ -109,9 +107,13 @@ const_string LUATEX_IHELP[] = {
NULL
};
-@ Later we will put on environment |LC_CTYPE|, |LC_COLLATE| and
-|LC_NUMERIC| set to |C|, so we need a place where to store the old values.
-@c
+/*tex
+
+Later we will put on environment |LC_CTYPE|, |LC_COLLATE| and |LC_NUMERIC| set to
+|C|, so we need a place where to store the old values.
+
+*/
+
const char *lc_ctype;
const char *lc_collate;
const char *lc_numeric;
@@ -126,26 +128,28 @@ const char *lc_numeric;
" --translate-file=FILE ignored, input is assumed to be in UTF-8 encoding",
*/
-@ The return value will be the directory of the executable, e.g.: \.{c:/TeX/bin}
-@c
+/*tex
+
+The return value will be the directory of the executable, e.g.: \.{c:/TeX/bin}
+
+*/
+
static char *ex_selfdir(char *argv0)
{
#if defined(WIN32)
#if defined(__MINGW32__)
char path[PATH_MAX], *fp;
-
- /* SearchPath() always gives back an absolute directory */
+ /*tex SearchPath() always gives back an absolute directory */
if (SearchPath(NULL, argv0, ".exe", PATH_MAX, path, NULL) == 0)
FATAL1("Can't determine where the executable %s is.\n", argv0);
- /* slashify the dirname */
+ /*tex slashify the dirname */
for (fp = path; fp && *fp; fp++)
if (IS_DIR_SEP(*fp))
*fp = DIR_SEP;
#else /* __MINGW32__ */
#define PATH_MAX 512
char short_path[PATH_MAX], path[PATH_MAX], *fp;
-
- /* SearchPath() always gives back an absolute directory */
+ /*tex SearchPath() always gives back an absolute directory */
if (SearchPath(NULL, argv0, ".exe", PATH_MAX, short_path, &fp) == 0)
FATAL1("Can't determine where the executable %s is.\n", argv0);
if (getlongpath(path, short_path, sizeof(path)) == 0) {
@@ -158,7 +162,6 @@ static char *ex_selfdir(char *argv0)
#endif
}
-@ @c
static void prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
{
int i;
@@ -178,11 +181,8 @@ static void prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
return;
}
-
-@ @c
int kpse_init = -1;
-@ @c
string input_name = NULL;
static string user_progname = NULL;
@@ -201,22 +201,20 @@ int safer_option = 0;
int nosocket_option = 0;
int utc_option = 0;
-@ Reading the options.
+/*tex
-@ Test whether getopt found an option ``A''.
-Assumes the option index is in the variable |option_index|, and the
-option table in a variable |long_options|.
+Test whether getopt found an option ``A''. Assumes the option index is in the
+variable |option_index|, and the option table in a variable |long_options|.
-@c
-#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
-
-/*
- SunOS cc can't initialize automatic structs, so make this static.
*/
-/*
+#define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
+
+/*tex
Nota Bene: we still intercept some options that other engines handle
so that existing scripted usage will not fail.
+
+ SunOS cc can't initialize automatic structs, so make this static.
*/
static struct option long_options[] = {
@@ -253,9 +251,7 @@ static struct option long_options[] = {
{"debug-format", 0, &debug_format_file, 1},
{"file-line-error-style", 0, &filelineerrorstylep, 1},
{"no-file-line-error-style", 0, &filelineerrorstylep, -1},
-
- /* Shorter option names for the above. */
-
+ /*tex Shorter option names for the above. */
{"file-line-error", 0, &filelineerrorstylep, 1},
{"no-file-line-error", 0, &filelineerrorstylep, -1},
{"jobname", 1, 0, 0},
@@ -266,18 +262,16 @@ static struct option long_options[] = {
{"8bit", 0, 0, 0},
{"mktex", 1, 0, 0},
{"no-mktex", 1, 0, 0},
-
- /* Synchronization: just like "interaction" above */
-
+ /*tex Synchronization: just like ``interaction'' above */
{"synctex", 1, 0, 0},
{0, 0, 0, 0}
};
-@ @c
int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
{
register int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
+ /*tex fetch the stringptr */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
lua_rawget(L, -2);
if (lua_type(L, -1) == LUA_TNUMBER) {
i = lua_roundnumber(L, -1);
@@ -286,11 +280,11 @@ int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
return i;
}
-@ @c
unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index, int dflt)
{
register unsigned int i = dflt;
- lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); /* fetch the stringptr */
+ /*tex fetch the stringptr */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index);
lua_rawget(L, -2);
if (lua_type(L, -1) == LUA_TNUMBER) {
i = lua_uroundnumber(L, -1);
@@ -299,20 +293,21 @@ unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index,
return i;
}
-@ @c
static int recorderoption = 0;
static void parse_options(int ac, char **av)
{
#ifdef WIN32
-/* save argc and argv */
+ /*tex We save |argc| and |argv|. */
int sargc = argc;
char **sargv = argv;
#endif
- int g; /* `getopt' return code. */
+ /*tex The `getopt' return code. */
+ int g;
int option_index;
char *firstfile = NULL;
- opterr = 0; /* dont whine */
+ /*tex Dont whine. */
+ opterr = 0;
#ifdef LuajitTeX
if ((strstr(argv[0], "luajittexlua") != NULL) ||
(strstr(argv[0], "texluajit") != NULL)) {
@@ -326,37 +321,39 @@ static void parse_options(int ac, char **av)
for (;;) {
g = getopt_long_only(ac, av, "+", long_options, &option_index);
- if (g == -1) /* End of arguments, exit the loop. */
+ if (g == -1) {
+ /*tex End of arguments, exit the loop. */
break;
- if (g == '?') { /* Unknown option. */
- if (!luainit)
- fprintf(stderr,"%s: unrecognized option '%s'\n", argv[0], argv[optind-1]);
- continue;
}
-
- assert(g == 0); /* We have no short option names. */
-
+ if (g == '?') {
+ /*tex Unknown option. */
+ if (!luainit)
+ fprintf(stderr,"%s: unrecognized option '%s'\n", argv[0], argv[optind-1]);
+ continue;
+ }
+ /* We have no short option names. */
+ assert(g == 0);
if (ARGUMENT_IS("luaonly")) {
lua_only = 1;
lua_offset = optind;
luainit = 1;
} else if (ARGUMENT_IS("lua")) {
- startup_filename = xstrdup(optarg);
+ startup_filename = optarg;
lua_offset = (optind - 1);
luainit = 1;
#ifdef LuajitTeX
} else if (ARGUMENT_IS("jiton")) {
luajiton = 1;
} else if (ARGUMENT_IS("jithash")) {
- size_t len = strlen(optarg);
- if (len<16) {
- jithash_hashname = optarg;
- } else {
- WARNING2("hash name truncated to 15 characters from %d. (%s)", (int) len, optarg);
- jithash_hashname = (string) xmalloc(16);
- strncpy(jithash_hashname, optarg, 15);
- jithash_hashname[15] = 0;
- }
+ size_t len = strlen(optarg);
+ if (len<16) {
+ jithash_hashname = optarg;
+ } else {
+ WARNING2("hash name truncated to 15 characters from %d. (%s)", (int) len, optarg);
+ jithash_hashname = (string) xmalloc(16);
+ strncpy(jithash_hashname, optarg, 15);
+ jithash_hashname[15] = 0;
+ }
#endif
} else if (ARGUMENT_IS("luahashchars")) {
show_luahashchars = 1;
@@ -414,7 +411,7 @@ static void parse_options(int ac, char **av)
WARNING1("Ignoring unknown argument `%s' to --interaction", optarg);
}
} else if (ARGUMENT_IS("synctex")) {
- /* Synchronize TeXnology: catching the command line option as a long */
+ /*tex Synchronize TeXnology: catching the command line option as a long */
synctexoption = (int) strtol(optarg, NULL, 0);
} else if (ARGUMENT_IS("recorder")) {
recorderoption = 1 ;
@@ -445,8 +442,8 @@ static void parse_options(int ac, char **av)
"pdftex : Han The Thanh and friends\n"
"kpathsea : Karl Berry, Olaf Weber and others\n"
"lua : Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo\n"
- "metapost : John Hobby, Taco Hoekwater and friends\n"
- "poppler : Derek Noonburg, Kristian Hogsberg (partial)\n"
+ "metapost : John Hobby, Taco Hoekwater, Luigi Scarso, Hans Hagen and friends\n"
+ "pplib : Paweł Jackowski\n"
"fontforge : George Williams (partial)\n"
"luajit : Mike Pall (used in LuajitTeX)\n");
/* *INDENT-ON* */
@@ -454,7 +451,7 @@ static void parse_options(int ac, char **av)
uexit(0);
}
}
- /* attempt to find |input_name| / |dump_name| */
+ /*tex attempt to find |input_name| and |dump_name| */
if (lua_only) {
if (argv[optind]) {
startup_filename = xstrdup(argv[optind]);
@@ -502,20 +499,23 @@ static void parse_options(int ac, char **av)
return;
#endif
}
- if (safer_option) /* --safer implies --nosocket */
+ /*tex |--safer| implies |--nosocket| */
+ if (safer_option)
nosocket_option = 1;
- /* Finalize the input filename. */
+ /*tex Finalize the input filename. */
if (input_name != NULL) {
argv[optind] = normalize_quotes(input_name, "argument");
}
}
-@ test for readability
-@c
-#define is_readable(a) (stat(a,&finfo)==0) && S_ISREG(finfo.st_mode) && \
- (f=fopen(a,"r")) != NULL && !fclose(f)
+/*tex
+ Test for readability.
+*/
+
+#define is_readable(a) (stat(a,&finfo)==0) \
+ && S_ISREG(finfo.st_mode) \
+ && (f=fopen(a,"r")) != NULL && !fclose(f)
-@ @c
static char *find_filename(char *name, const char *envkey)
{
struct stat finfo;
@@ -543,8 +543,6 @@ static char *find_filename(char *name, const char *envkey)
return NULL;
}
-@ @c
-
static void init_kpse(void)
{
if (!user_progname) {
@@ -576,11 +574,10 @@ static void init_kpse(void)
user_progname = dump_name;
}
}
- kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT,
- kpse_src_compile);
-
+ kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT, kpse_src_compile);
kpse_set_program_name(argv[0], user_progname);
- init_shell_escape(); /* set up 'restrictedshell' */
+ /*tex set up 'restrictedshell' */
+ init_shell_escape();
init_start_time();
program_name_set = 1 ;
if (recorderoption) {
@@ -588,19 +585,18 @@ static void init_kpse(void)
}
}
-@ @c
static void fix_dumpname(void)
{
int dist;
if (dump_name) {
- /* adjust array for Pascal and provide extension, if needed */
+ /*tex Adjust array for Pascal and provide extension, if needed. */
dist = (int) (strlen(dump_name) - strlen(DUMP_EXT));
if (strstr(dump_name, DUMP_EXT) == dump_name + dist)
TEX_format_default = dump_name;
else
TEX_format_default = concat(dump_name, DUMP_EXT);
} else {
- /* For |dump_name| to be NULL is a bug. */
+ /*tex For |dump_name| to be NULL is a bug. */
if (!ini_version) {
fprintf(stdout, "no format given, quitting\n");
exit(1);
@@ -608,17 +604,17 @@ static void fix_dumpname(void)
}
}
-@ lua require patch
-
-@ Auxiliary function for kpse search
+/*tex
+ Auxiliary function for kpse search.
+*/
-@c
static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
- kpse_file_format_type format, const char *errname)
+ kpse_file_format_type format, const char *errname)
{
const char *filename;
const char *altname;
- altname = luaL_gsub(L, name, ".", "/"); /* Lua convention */
+ /*tex Lua convention */
+ altname = luaL_gsub(L, name, ".", "/");
filename = kpse_find_file(altname, format, false);
if (filename == NULL) {
filename = kpse_find_file(name, format, false);
@@ -629,16 +625,17 @@ static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
return filename;
}
-@ The lua search function.
+/*tex
+
+ Here comes the \LUA\ search function. When kpathsea is not initialized, then it
+ runs the normal \LUA\ function that is saved in the registry, otherwise it uses
+ kpathsea.
-When kpathsea is not initialized, then it runs the
-normal lua function that is saved in the registry, otherwise
-it uses kpathsea.
+ Two registry ref variables are needed: one for the actual \LUA\ function, the
+ other for its environment .
-two registry ref variables are needed: one for the actual lua
-function, the other for its environment .
+*/
-@c
static int lua_loader_function = 0;
static int luatex_kpse_lua_find(lua_State * L)
@@ -653,16 +650,18 @@ static int luatex_kpse_lua_find(lua_State * L)
return 1;
}
filename = luatex_kpse_find_aux(L, name, kpse_lua_format, "lua");
- if (filename == NULL)
- return 1; /* library not found in this path */
+ if (filename == NULL) {
+ /*tex library not found in this path */
+ return 1;
+ }
if (luaL_loadfile(L, filename) != 0) {
luaL_error(L, "error loading module %s from file %s:\n\t%s",
- lua_tostring(L, 1), filename, lua_tostring(L, -1));
+ lua_tostring(L, 1), filename, lua_tostring(L, -1));
}
- return 1; /* library loaded successfully */
+ /*tex library loaded successfully */
+ return 1;
}
-@ @c
static int clua_loader_function = 0;
extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename);
@@ -671,8 +670,9 @@ static int luatex_kpse_clua_find(lua_State * L)
const char *filename;
const char *name;
if (safer_option) {
+ /*tex library not found in this path */
lua_pushliteral(L, "\n\t[C searcher disabled in safer mode]");
- return 1; /* library not found in this path */
+ return 1;
}
name = luaL_checkstring(L, 1);
if (program_name_set == 0) {
@@ -687,12 +687,16 @@ static int luatex_kpse_clua_find(lua_State * L)
char *temp_name;
int j;
filename = luatex_kpse_find_aux(L, name, kpse_clua_format, "C");
- if (filename == NULL)
- return 1; /* library not found in this path */
+ if (filename == NULL) {
+ /*tex library not found in this path */
+ return 1;
+ }
extensionless = strdup(filename);
- if (!extensionless)
- return 1; /* allocation failure */
- /* Fix Issue 850: replace '.' with LUA_DIRSEP */
+ if (!extensionless) {
+ /*tex allocation failure */
+ return 1;
+ }
+ /*tex Replace '.' with |LUA_DIRSEP| */
temp_name = strdup(name);
for(j=0; ; j++){
if ((unsigned char)temp_name[j]=='\0') {
@@ -703,33 +707,44 @@ static int luatex_kpse_clua_find(lua_State * L)
}
}
p = strstr(extensionless, temp_name);
- if (!p) return 1; /* this would be exceedingly weird */
+ if (!p) {
+ /*tex this would be exceedingly weird */
+ return 1;
+ }
*p = '\0';
prefix = strdup(extensionless);
- if (!prefix) return 1; /* allocation failure */
+ if (!prefix) {
+ /*tex allocation failure */
+ return 1;
+ }
postfix = strdup(p+strlen(name));
- if (!postfix) return 1; /* allocation failure */
+ if (!postfix) {
+ /*tex allocation failure */
+ return 1;
+ }
total = malloc(strlen(prefix)+strlen(postfix)+2);
if (!total) return 1; /* allocation failure */
snprintf(total,strlen(prefix)+strlen(postfix)+2, "%s?%s", prefix, postfix);
- /* save package.path */
+ /*tex save package.path */
lua_getglobal(L,"package");
lua_getfield(L,-1,"cpath");
path_saved = lua_tostring(L,-1);
lua_pop(L,1);
- /* set package.path = "?" */
+ /*tex set package.path = "?" */
lua_pushstring(L,total);
lua_setfield(L,-2,"cpath");
- lua_pop(L,1); /* pop "package" */
- /* run function */
+ /*tex pop ``package'' */
+ lua_pop(L,1);
+ /*tex run function */
lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
lua_pushstring(L, name);
lua_call(L, 1, 1);
- /* restore package.path */
+ /*tex restore package.path */
lua_getglobal(L,"package");
lua_pushstring(L,path_saved);
lua_setfield(L,-2,"cpath");
- lua_pop(L,1); /* pop "package" */
+ /*tex pop ``package'' */
+ lua_pop(L,1);
free(extensionless);
free(total);
free(temp_name);
@@ -737,12 +752,13 @@ static int luatex_kpse_clua_find(lua_State * L)
}
}
-@ Setting up the new search functions.
+/*tex
+
+ Setting up the new search functions. This replaces package.searchers[2] and
+ package.searchers[3] with the functions defined above.
-This replaces package.searchers[2] and package.searchers[3] with the
-functions defined above.
+*/
-@c
static void setup_lua_path(lua_State * L)
{
lua_getglobal(L, "package");
@@ -751,46 +767,45 @@ static void setup_lua_path(lua_State * L)
#else
lua_getfield(L, -1, "searchers");
#endif
- lua_rawgeti(L, -1, 2); /* package.searchers[2] */
+ /*tex package.searchers[2] */
+ lua_rawgeti(L, -1, 2);
lua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcfunction(L, luatex_kpse_lua_find);
- lua_rawseti(L, -2, 2); /* replace the normal lua loader */
-
- lua_rawgeti(L, -1, 3); /* package.searchers[3] */
+ /*tex replace the normal lua loader */
+ lua_rawseti(L, -2, 2);
+ /*tex package.searchers[3] */
+ lua_rawgeti(L, -1, 3);
clua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcfunction(L, luatex_kpse_clua_find);
- lua_rawseti(L, -2, 3); /* replace the normal lua lib loader */
-
- lua_pop(L, 2); /* pop the array and table */
+ /*tex replace the normal lua lib loader */
+ lua_rawseti(L, -2, 3);
+ /*tex pop the array and table */
+ lua_pop(L, 2);
}
-@ helper variables for the safe keeping of table ids
+/*tex
+
+ Helper variables for the safe keeping of table ids.
-@c
-/*
-int tex_table_id;
-int pdf_table_id;
-int token_table_id;
-int node_table_id;
*/
-@ @c
int l_pack_type_index [PACK_TYPE_SIZE] ;
int l_group_code_index [GROUP_CODE_SIZE];
int l_local_par_index [LOCAL_PAR_SIZE];
int l_math_style_name_index [MATH_STYLE_NAME_SIZE];
int l_dir_par_index [DIR_PAR_SIZE];
-int l_dir_text_index [DIR_TEXT_SIZE];
+int l_dir_text_index_normal [DIR_TEXT_SIZE];
+int l_dir_text_index_cancel [DIR_TEXT_SIZE];
int img_parms [img_parms_max];
int img_pageboxes [img_pageboxes_max];
-int lua_show_valid_list(lua_State *L, const char **list, int max)
+int lua_show_valid_list(lua_State *L, const char **list, int offset, int max)
{
int i;
lua_newtable(L);
for (i = 0; i < max; i++) {
- lua_pushinteger(L,i+1);
+ lua_pushinteger(L,i+offset);
lua_pushstring(L, list[i]);
lua_settable(L, -3);
}
@@ -812,28 +827,31 @@ int lua_show_valid_keys(lua_State *L, int *list, int max)
#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
char **suffixlist;
-# define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw"
+/* Why do we add script stuff to this weird incomplete. Let's go more minimal. */
+
+/*
+ #define EXE_SUFFIXES ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.ws;.tcl;.py;.pyw"
+*/
+
+#define EXE_SUFFIXES ".com;.exe;.bat;.cmd"
-@ @c
static void mk_suffixlist(void)
{
char **p;
char *q, *r, *v;
int n;
-
# if defined(__CYGWIN__)
v = xstrdup(EXE_SUFFIXES);
# else
v = (char *) getenv("PATHEXT");
- if (v) /* strlwr() exists also in MingW */
+ /*tex strlwr() exists also in MingW */
+ if (v)
v = (char *) strlwr(xstrdup(v));
else
v = xstrdup(EXE_SUFFIXES);
# endif
-
q = v;
n = 0;
-
while ((r = strchr(q, ';')) != NULL) {
n++;
r++;
@@ -862,12 +880,10 @@ static void mk_suffixlist(void)
}
#endif
-@ @c
void lua_initialize(int ac, char **av)
{
char *given_file = NULL;
char *banner;
- /*int kpse_init;*/
size_t len;
int starttime;
int utc;
@@ -878,7 +894,7 @@ void lua_initialize(int ac, char **av)
char *old_locale = NULL;
char *env_locale = NULL;
char *tmp = NULL;
- /* Save to pass along to topenin. */
+ /*tex Save to pass along to topenin. */
const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION;
argc = ac;
argv = av;
@@ -887,8 +903,7 @@ void lua_initialize(int ac, char **av)
sprintf(banner, fmt, luatex_version_string);
luatex_banner = banner;
kpse_invocation_name = kpse_program_basename(argv[0]);
-
- /* be 'luac' */
+ /*tex be `luac' */
if (argc >1) {
#ifdef LuajitTeX
if (FILESTRCASEEQ(kpse_invocation_name, "texluajitc"))
@@ -911,106 +926,104 @@ void lua_initialize(int ac, char **av)
#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
mk_suffixlist();
#endif
-
- /* Must be initialized before options are parsed. */
+ /*tex Must be initialized before options are parsed. */
interactionoption = 4;
dump_name = NULL;
-
- /* 0 means "disable Synchronize TeXnology".
- synctexoption is a *.web variable.
- We initialize it to a weird value to catch the -synctex command line flag
- At runtime, if synctexoption is not |INT_MAX|, then it contains the command line option provided,
- otherwise no such option was given by the user. */
+ /*tex
+ In the next option 0 means ``disable Synchronize TeXnology''. The
+ |synctexoption| is a *.web variable. We initialize it to a weird value to
+ catch the -synctex command line flag At runtime, if synctexoption is not
+ |INT_MAX|, then it contains the command line option provided, otherwise
+ no such option was given by the user.
+ */
#define SYNCTEX_NO_OPTION INT_MAX
synctexoption = SYNCTEX_NO_OPTION;
-
- /* parse commandline */
+ /*tex parse commandline */
parse_options(ac, av);
if (lua_only) {
- /* Shell has no restrictions. */
+ /*tex Shell has no restrictions. */
shellenabledp = true;
restrictedshell = false;
safer_option = 0;
}
- /* Get the current locale (it should be C ) */
- /* and save LC_CTYPE, LC_COLLATE and LC_NUMERIC. */
- /* Later luainterpreter() will consciously use them. */
+ /*tex
+ Get the current locale (it should be |C|) and save |LC_CTYPE|, |LC_COLLATE|
+ and |LC_NUMERIC|. Later |luainterpreter()| will consciously use them.
+ */
old_locale = xstrdup(setlocale (LC_ALL, NULL));
lc_ctype = NULL;
lc_collate = NULL;
lc_numeric = NULL;
if (old_locale) {
- /* If setlocale fails here, then the state */
- /* could be compromised, and we exit. */
+ /*tex
+ If |setlocale| fails here, then the state could be compromised, and
+ we exit.
+ */
env_locale = setlocale (LC_ALL, "");
- if (!env_locale && !lua_only) {
- fprintf(stderr,"Unable to read environment locale: exit now.\n");
- exit(1);
- }
+ if (!env_locale && !lua_only) {
+ fprintf(stderr,"Unable to read environment locale: exit now.\n");
+ exit(1);
+ }
tmp = setlocale (LC_CTYPE, NULL);
- if (tmp) {
- lc_ctype = xstrdup(tmp);
+ if (tmp) {
+ lc_ctype = xstrdup(tmp);
}
- tmp = setlocale (LC_COLLATE, NULL);
- if (tmp){
- lc_collate = xstrdup(tmp);
+ tmp = setlocale (LC_COLLATE, NULL);
+ if (tmp) {
+ lc_collate = xstrdup(tmp);
}
- tmp = setlocale (LC_NUMERIC, NULL);
- if (tmp){
- lc_numeric = xstrdup(tmp);
+ tmp = setlocale (LC_NUMERIC, NULL);
+ if (tmp) {
+ lc_numeric = xstrdup(tmp);
+ }
+ /*tex
+ Return to the previous locale if possible, otherwise it's a serious
+ error and we exit: we can't ensure a 'sane' locale for lua.
+ */
+ env_locale = setlocale (LC_ALL, old_locale);
+ if (!env_locale) {
+ fprintf(stderr,"Unable to restore original locale %s: exit now.\n",old_locale);
+ exit(1);
}
- /* Back to the previous locale if possible, */
- /* otherwise it's a serious error and we exit:*/
- /* we can't ensure a 'sane' locale for lua. */
- env_locale = setlocale (LC_ALL, old_locale);
- if (!env_locale) {
- fprintf(stderr,"Unable to restore original locale %s: exit now.\n",old_locale);
- exit(1);
- }
xfree(old_locale);
} else {
fprintf(stderr,"Unable to store environment locale.\n");
}
-
- /* make sure that the locale is 'sane' (for lua) */
+ /*tex make sure that the locale is 'sane' (for lua) */
putenv(LC_CTYPE_C);
putenv(LC_COLLATE_C);
putenv(LC_NUMERIC_C);
-
- /* this is sometimes needed */
+ /*tex this is sometimes needed */
putenv(engine_luatex);
-
luainterpreter();
-
- /* init internalized strings */
+ /*tex init internalized strings */
set_init_keys;
-
lua_pushstring(Luas,"lua.functions");
lua_newtable(Luas);
lua_settable(Luas,LUA_REGISTRYINDEX);
-
- /* here start the key definitions */
+ /*tex here start the key definitions */
set_l_pack_type_index;
set_l_group_code_index;
set_l_local_par_index;
set_l_math_style_name_index;
set_l_dir_par_index;
set_l_dir_text_index;
-
+ l_set_node_data();
+ l_set_whatsit_data();
+ l_set_token_data();
set_l_img_keys_index;
set_l_img_pageboxes_index;
-
- prepare_cmdline(Luas, argv, argc, lua_offset); /* collect arguments */
+ /*tex collect arguments */
+ prepare_cmdline(Luas, argv, argc, lua_offset);
setup_lua_path(Luas);
-
if (startup_filename != NULL) {
given_file = xstrdup(startup_filename);
if (lua_only) {
- xfree(startup_filename);
+ xfree(startup_filename);
}
startup_filename = find_filename(given_file, "LUATEXDIR");
}
- /* now run the file */
+ /*tex now run the file */
if (startup_filename != NULL) {
char *v1;
int tex_table_id = hide_lua_table(Luas, "tex");
@@ -1018,7 +1031,7 @@ void lua_initialize(int ac, char **av)
int node_table_id = hide_lua_table(Luas, "node");
int pdf_table_id = hide_lua_table(Luas, "pdf");
if (lua_only) {
- /* hide the 'tex' and 'pdf' table */
+ /*tex hide the 'tex' and 'pdf' table */
if (load_luatex_core_lua(Luas)) {
fprintf(stderr, "Error in execution of luatex-core.lua .\n");
}
@@ -1026,20 +1039,20 @@ void lua_initialize(int ac, char **av)
fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
exit(1);
}
- init_tex_table(Luas); /* needed ? */
+ init_tex_table(Luas);
if (lua_pcall(Luas, 0, 0, 0)) {
fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
lua_traceback(Luas);
- /* lua_close(Luas); */
+ /*tex lua_close(Luas); */
exit(1);
} else {
if (given_file)
free(given_file);
- /* lua_close(Luas); */
+ /*tex lua_close(Luas); */
exit(0);
}
}
- /* a normal tex run */
+ /*tex a normal tex run */
init_tex_table(Luas);
unhide_lua_table(Luas, "tex", tex_table_id);
unhide_lua_table(Luas, "pdf", pdf_table_id);
@@ -1060,28 +1073,25 @@ void lua_initialize(int ac, char **av)
if (!dump_name) {
get_lua_string("texconfig", "formatname", &dump_name);
}
- /* |kpse_init| */
kpse_init = -1;
get_lua_boolean("texconfig", "kpse_init", &kpse_init);
if (kpse_init != 0) {
- luainit = 0; /* re-enable loading of texmf.cnf values, see luatex.ch */
+ /*tex re-enable loading of texmf.cnf values, see luatex.ch */
+ luainit = 0;
init_kpse();
kpse_init = 1;
}
- /* |prohibit_file_trace| (boolean) */
+ /*tex |prohibit_file_trace| (boolean) */
tracefilenames = 1;
get_lua_boolean("texconfig", "trace_file_names", &tracefilenames);
-
- /* |file_line_error| */
+ /*tex |file_line_error| */
filelineerrorstylep = false;
get_lua_boolean("texconfig", "file_line_error", &filelineerrorstylep);
-
- /* |halt_on_error| */
+ /*tex |halt_on_error| */
haltonerrorp = false;
get_lua_boolean("texconfig", "halt_on_error", &haltonerrorp);
-
- /* |restrictedshell| */
+ /*tex |restrictedshell| */
v1 = NULL;
get_lua_string("texconfig", "shell_escape", &v1);
if (v1) {
@@ -1093,7 +1103,7 @@ void lua_initialize(int ac, char **av)
}
free(v1);
}
- /* If shell escapes are restricted, get allowed cmds from cnf. */
+ /*tex If shell escapes are restricted, get allowed cmds from cnf. */
if (shellenabledp && restrictedshell == 1) {
v1 = NULL;
get_lua_string("texconfig", "shell_escape_commands", &v1);
@@ -1102,11 +1112,10 @@ void lua_initialize(int ac, char **av)
free(v1);
}
}
-
starttime = -1 ;
get_lua_number("texconfig", "start_time", &starttime);
if (starttime < 0) {
- /*
+ /*tex
We provide this one for compatibility reasons and therefore also in
uppercase.
*/
@@ -1115,38 +1124,32 @@ void lua_initialize(int ac, char **av)
if (starttime >= 0) {
set_start_time(starttime);
}
-
utc = -1 ;
get_lua_boolean("texconfig", "use_utc_time", &utc);
if (utc >= 0 && utc <= 1) {
utc_option = utc;
}
-
fix_dumpname();
- } else {
- if (luainit) {
- if (given_file) {
- fprintf(stdout, "%s file %s not found\n", (lua_only ? "Script" : "Configuration"), given_file);
- free(given_file);
- } else {
- fprintf(stdout, "No %s file given\n", (lua_only ? "script" : "configuration"));
- }
- exit(1);
+ } else if (luainit) {
+ if (given_file) {
+ fprintf(stdout, "%s file %s not found\n", (lua_only ? "Script" : "Configuration"), given_file);
+ free(given_file);
} else {
- /* init */
- init_kpse();
- kpse_init = 1;
- fix_dumpname();
+ fprintf(stdout, "No %s file given\n", (lua_only ? "script" : "configuration"));
}
+ exit(1);
+ } else {
+ /* init */
+ init_kpse();
+ kpse_init = 1;
+ fix_dumpname();
+ }
+ /*tex Here we load luatex-core.lua which takes care of some protection on demand. */
+ if (load_luatex_core_lua(Luas)) {
+ fprintf(stderr, "Error in execution of luatex-core.lua .\n");
}
-
- /* Here we load luatex-core.lua which takes care of some protection on demand. */
- if (load_luatex_core_lua(Luas))
- fprintf(stderr, "Error in execution of luatex-core.lua .\n");
- /* Done. */
}
-@ @c
void check_texconfig_init(void)
{
if (Luas != NULL) {
@@ -1156,7 +1159,10 @@ void check_texconfig_init(void)
if (lua_isfunction(Luas, -1)) {
int i = lua_pcall(Luas, 0, 0, 0);
if (i != 0) {
- /* Can't be more precise here, called before TeX initialization */
+ /*tex
+ We can't be more precise hereas it's called before \TEX\
+ initialization happens.
+ */
fprintf(stderr, "This went wrong: %s\n", lua_tostring(Luas, -1));
error();
}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luanode.w b/Build/source/texk/web2c/luatexdir/lua/luanode.c
index ef2f0b92655..3182b609773 100644
--- a/Build/source/texk/web2c/luatexdir/lua/luanode.w
+++ b/Build/source/texk/web2c/luatexdir/lua/luanode.c
@@ -1,33 +1,32 @@
-% luanode.w
-%
-% 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/>.
+/*
-/* hh-ls: we make sure that lua never sees prev of head but also that when
-nodes are removed or inserted, temp nodes don't interfere */
+luanode.w
-@ @c
+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/>.
+
+*/
#include "ptexlib.h"
#include "lua/luatex-api.h"
-@ @c
void lua_node_filter_s(int filterid, int extrainfo)
{
+ int i;
int callback_id = callback_defined(filterid);
int s_top = lua_gettop(Luas);
if (callback_id <= 0) {
@@ -38,20 +37,20 @@ void lua_node_filter_s(int filterid, int extrainfo)
lua_settop(Luas, s_top);
return;
}
- lua_push_string_by_index(Luas,extrainfo); /* arg 1 */
- if (lua_pcall(Luas, 1, 0, 0) != 0) {
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ lua_push_string_by_index(Luas,extrainfo);
+ if ((i=lua_pcall(Luas, 1, 0, 0)) != 0) {
+ formatted_warning("node filter","error: %s", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return;
}
lua_settop(Luas, s_top);
return;
}
-@ @c
void lua_node_filter(int filterid, int extrainfo, halfword head_node, halfword * tail_node)
{
+ int i;
halfword start_node, start_done, last_node;
int s_top = lua_gettop(Luas);
int callback_id = callback_defined(filterid);
@@ -59,45 +58,45 @@ void lua_node_filter(int filterid, int extrainfo, halfword head_node, halfword *
lua_settop(Luas, s_top);
return;
}
- /* we start after head */
+ /*tex We start after head. */
start_node = vlink(head_node);
if (start_node == null || !get_callback(Luas, callback_id)) {
lua_settop(Luas, s_top);
return;
}
- /* we make sure we have no prev */
+ /*tex We make sure we have no prev */
alink(start_node) = null ;
- /* the action */
+ /*tex the action */
nodelist_to_lua(Luas, start_node);
lua_push_group_code(Luas,extrainfo);
- if (lua_pcall(Luas, 2, 1, 0) != 0) {
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ if ((i=lua_pcall(Luas, 2, 1, 0)) != 0) {
+ formatted_warning("node filter", "error: %s\n", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return;
}
- /* the result */
+ /*tex the result */
if (lua_isboolean(Luas, -1)) {
if (lua_toboolean(Luas, -1) != 1) {
- /* discard */
+ /*tex discard */
flush_node_list(start_node);
vlink(head_node) = null;
} else {
- /* keep */
+ /*tex keep */
}
} else {
- /* append to old head */
- start_done = nodelist_from_lua(Luas);
+ /*tex append to old head */
+ start_done = nodelist_from_lua(Luas,-1);
try_couple_nodes(head_node,start_done);
}
- /* redundant as we set top anyway */
+ /*tex redundant as we set top anyway */
lua_pop(Luas, 2);
- /* find tail in order to update tail */
+ /*tex find tail in order to update tail */
start_node = vlink(head_node);
if (start_node != null) {
- /* maybe just always slide (harmless and fast) */
+ /*tex maybe just always slide (harmless and fast) */
if (fix_node_lists) {
- /* slides and returns last node */
+ /*tex slides and returns last node */
*tail_node = fix_node_list(start_node);
} else {
last_node = vlink(start_node);
@@ -105,24 +104,23 @@ void lua_node_filter(int filterid, int extrainfo, halfword head_node, halfword *
start_node = last_node;
last_node = vlink(start_node);
}
- /* we're at the end now */
+ /*tex we're at the end now */
*tail_node = start_node;
}
} else {
- /* we're already at the end */
+ /*tex we're already at the end */
*tail_node = head_node;
}
- /* clean up */
+ /*tex clean up */
lua_settop(Luas, s_top);
return;
}
-@ @c
int lua_linebreak_callback(int is_broken, halfword head_node, halfword * new_head)
{
- int a;
+ int a, i;
register halfword *p;
- int ret = 0; /* failure */
+ int ret = 0;
int s_top = lua_gettop(Luas);
int callback_id = callback_defined(linebreak_filter_callback);
if (head_node == null || vlink(head_node) == null || callback_id <= 0) {
@@ -130,32 +128,33 @@ int lua_linebreak_callback(int is_broken, halfword head_node, halfword * new_hea
return ret;
}
if (!get_callback(Luas, callback_id)) {
- lua_settop(Luas, s_top);
+ lua_settop(Luas, s_top);
return ret;
}
- alink(vlink(head_node)) = null ; /* hh-ls */
- nodelist_to_lua(Luas, vlink(head_node)); /* arg 1 */
- lua_pushboolean(Luas, is_broken); /* arg 2 */
- if (lua_pcall(Luas, 2, 1, 0) != 0) { /* no arg, 1 result */
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ alink(vlink(head_node)) = null ;
+ nodelist_to_lua(Luas, vlink(head_node));
+ lua_pushboolean(Luas, is_broken);
+ if ((i=lua_pcall(Luas, 2, 1, 0)) != 0) {
+ formatted_warning("linebreak", "error: %s", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return ret;
}
+ lua_settop(Luas, s_top);
p = lua_touserdata(Luas, -1);
if (p != NULL) {
- a = nodelist_from_lua(Luas);
+ a = nodelist_from_lua(Luas,-1);
try_couple_nodes(*new_head,a);
ret = 1;
}
- lua_settop(Luas, s_top);
return ret;
}
-@ @c
-int lua_appendtovlist_callback(halfword box, int location, halfword prev_depth, boolean is_mirrored, halfword * result, int * next_depth, boolean * prev_set)
+int lua_appendtovlist_callback(halfword box, int location, halfword prev_depth,
+ boolean is_mirrored, halfword * result, int * next_depth, boolean * prev_set)
{
register halfword *p;
+ int i;
int s_top = lua_gettop(Luas);
int callback_id = callback_defined(append_to_vlist_filter_callback);
if (box == null || callback_id <= 0) {
@@ -170,10 +169,10 @@ int lua_appendtovlist_callback(halfword box, int location, halfword prev_depth,
lua_push_string_by_index(Luas,location);
lua_pushinteger(Luas, (int) prev_depth);
lua_pushboolean(Luas, is_mirrored);
- if (lua_pcall(Luas, 4, 2, 0) != 0) {
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ if ((i=lua_pcall(Luas, 4, 2, 0)) != 0) {
+ formatted_warning("append to vlist","error: %s", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return 0;
}
if (lua_type(Luas,-1) == LUA_TNUMBER) {
@@ -187,13 +186,13 @@ int lua_appendtovlist_callback(halfword box, int location, halfword prev_depth,
p = check_isnode(Luas, -1);
*result = *p;
}
- lua_settop(Luas, s_top);
return 1;
}
-@ @c
-halfword lua_hpack_filter(halfword head_node, scaled size, int pack_type, int extrainfo, int pack_direction, halfword attr)
+halfword lua_hpack_filter(halfword head_node, scaled size, int pack_type, int extrainfo,
+ int pack_direction, halfword attr)
{
+ int i;
halfword ret;
int s_top = lua_gettop(Luas);
int callback_id = callback_defined(hpack_filter_callback);
@@ -205,7 +204,7 @@ halfword lua_hpack_filter(halfword head_node, scaled size, int pack_type, int ex
lua_settop(Luas, s_top);
return head_node;
}
- alink(head_node) = null ; /* hh-ls */
+ alink(head_node) = null ;
nodelist_to_lua(Luas, head_node);
lua_push_group_code(Luas,extrainfo);
lua_pushinteger(Luas, size);
@@ -220,10 +219,10 @@ halfword lua_hpack_filter(halfword head_node, scaled size, int pack_type, int ex
} else {
lua_pushnil(Luas);
}
- if (lua_pcall(Luas, 6, 1, 0) != 0) {
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ if ((i=lua_pcall(Luas, 6, 1, 0)) != 0) {
+ formatted_warning("hpack filter", "error: %s\n", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return head_node;
}
ret = head_node;
@@ -233,29 +232,26 @@ halfword lua_hpack_filter(halfword head_node, scaled size, int pack_type, int ex
ret = null;
}
} else {
- ret = nodelist_from_lua(Luas);
+ ret = nodelist_from_lua(Luas,-1);
}
lua_settop(Luas, s_top);
-#if 0
- lua_gc(Luas,LUA_GCSTEP, LUA_GC_STEP_SIZE);
-#endif
if (fix_node_lists)
fix_node_list(ret);
return ret;
}
-@ @c
halfword lua_vpack_filter(halfword head_node, scaled size, int pack_type, scaled maxd,
- int extrainfo, int pack_direction, halfword attr)
+ int extrainfo, int pack_direction, halfword attr)
{
halfword ret;
+ int i;
int callback_id;
int s_top = lua_gettop(Luas);
if (head_node == null) {
lua_settop(Luas, s_top);
return head_node;
}
- if (extrainfo == 8) { /* output */
+ if (extrainfo == 8) {
callback_id = callback_defined(pre_output_filter_callback);
} else {
callback_id = callback_defined(vpack_filter_callback);
@@ -268,7 +264,7 @@ halfword lua_vpack_filter(halfword head_node, scaled size, int pack_type, scaled
lua_settop(Luas, s_top);
return head_node;
}
- alink(head_node) = null ; /* hh-ls */
+ alink(head_node) = null ;
nodelist_to_lua(Luas, head_node);
lua_push_group_code(Luas, extrainfo);
lua_pushinteger(Luas, size);
@@ -284,10 +280,10 @@ halfword lua_vpack_filter(halfword head_node, scaled size, int pack_type, scaled
} else {
lua_pushnil(Luas);
}
- if (lua_pcall(Luas, 7, 1, 0) != 0) {
- fprintf(stdout, "error: %s\n", lua_tostring(Luas, -1));
+ if ((i=lua_pcall(Luas, 7, 1, 0)) != 0) {
+ formatted_warning("vpack filter", "error: %s", lua_tostring(Luas, -1));
lua_settop(Luas, s_top);
- error();
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return head_node;
}
ret = head_node;
@@ -297,76 +293,84 @@ halfword lua_vpack_filter(halfword head_node, scaled size, int pack_type, scaled
ret = null;
}
} else {
- ret = nodelist_from_lua(Luas);
+ ret = nodelist_from_lua(Luas,-1);
}
lua_settop(Luas, s_top);
-#if 0
- lua_gc(Luas,LUA_GCSTEP, LUA_GC_STEP_SIZE);
-#endif
if (fix_node_lists)
fix_node_list(ret);
return ret;
}
-@ This is a quick hack to fix etex's \.{\\lastnodetype} now that
- there are many more visible node types. TODO: check the
- eTeX manual for the expected return values.
+/*tex
+
+ This is a quick hack to fix \ETEX's \.{\\lastnodetype} now that there are many
+ more visible node types.
+
+*/
-@c
int visible_last_node_type(int n)
{
int i = type(n);
if (i != glyph_node) {
return get_etex_code(i);
} else if (is_ligature(n)) {
- return 7; /* old ligature value */
+ /*tex old ligature value */
+ return 7;
} else {
- return 0; /* old character value */
+ /*tex old character value */
+ return 0;
}
}
-@ @c
-void lua_pdf_literal(PDF pdf, int i)
+void lua_pdf_literal(PDF pdf, int i, int noline)
{
const char *s = NULL;
size_t l = 0;
lua_rawgeti(Luas, LUA_REGISTRYINDEX, i);
s = lua_tolstring(Luas, -1, &l);
- pdf_out_block(pdf, s, l);
- pdf_out(pdf, 10); /* |pdf_print_nl| */
+ if (noline) {
+ pdf_check_space(pdf);
+ pdf_out_block(pdf, s, l);
+ pdf_set_space(pdf);
+ } else {
+ pdf_out_block(pdf, s, l);
+ pdf_out(pdf, 10);
+ }
lua_pop(Luas, 1);
}
-@ @c
void copy_pdf_literal(pointer r, pointer p)
{
- pdf_literal_type(r) = pdf_literal_type(p);
+ int t = pdf_literal_type(p);
+ pdf_literal_type(r) = t;
pdf_literal_mode(r) = pdf_literal_mode(p);
- if (pdf_literal_type(p) == normal) {
+ if (t == normal) {
pdf_literal_data(r) = pdf_literal_data(p);
add_token_ref(pdf_literal_data(p));
- } else {
+ } else if (t == lua_refid_literal) {
lua_rawgeti(Luas, LUA_REGISTRYINDEX, pdf_literal_data(p));
pdf_literal_data(r) = luaL_ref(Luas, LUA_REGISTRYINDEX);
+ } else {
+ /* maybe something user, we don't support a call here but best keep it sane anyway. */
+ pdf_literal_data(r) = pdf_literal_data(p);
}
}
-@ @c
void copy_late_lua(pointer r, pointer p)
{
- late_lua_type(r) = late_lua_type(p);
+ int t = late_lua_type(p);
+ late_lua_type(r) = t;
if (late_lua_name(p) > 0)
add_token_ref(late_lua_name(p));
- if (late_lua_type(p) == normal) {
+ if (t == normal) {
late_lua_data(r) = late_lua_data(p);
add_token_ref(late_lua_data(p));
- } else {
+ } else if (t == lua_refid_literal) {
lua_rawgeti(Luas, LUA_REGISTRYINDEX, late_lua_data(p));
late_lua_data(r) = luaL_ref(Luas, LUA_REGISTRYINDEX);
}
}
-@ @c
void copy_user_lua(pointer r, pointer p)
{
if (user_node_value(p) != 0) {
@@ -375,28 +379,28 @@ void copy_user_lua(pointer r, pointer p)
}
}
-@ @c
void free_pdf_literal(pointer p)
{
- if (pdf_literal_type(p) == normal) {
+ int t = pdf_literal_type(p);
+ if (t == normal) {
delete_token_ref(pdf_literal_data(p));
- } else {
+ } else if (t == lua_refid_literal) {
luaL_unref(Luas, LUA_REGISTRYINDEX, pdf_literal_data(p));
}
}
void free_late_lua(pointer p)
{
+ int t = late_lua_type(p);
if (late_lua_name(p) > 0)
delete_token_ref(late_lua_name(p));
- if (late_lua_type(p) == normal) {
+ if (t == normal) {
delete_token_ref(late_lua_data(p));
- } else {
+ } else if (t == lua_refid_literal) {
luaL_unref(Luas, LUA_REGISTRYINDEX, late_lua_data(p));
}
}
-@ @c
void free_user_lua(pointer p)
{
if (user_node_value(p) != 0) {
@@ -404,9 +408,9 @@ void free_user_lua(pointer p)
}
}
-@ @c
void show_pdf_literal(pointer p)
{
+ int t = pdf_literal_type(p);
tprint_esc("pdfliteral");
switch (pdf_literal_mode(p)) {
case set_origin:
@@ -422,30 +426,36 @@ void show_pdf_literal(pointer p)
tprint(" raw");
break;
default:
- confusion("literal2");
+ tprint(" <invalid mode>");
break;
}
- if (pdf_literal_type(p) == normal) {
+ if (t == normal) {
print_mark(pdf_literal_data(p));
+ } else if (t == lua_refid_literal) {
+ tprint(" <lua data reference ");
+ print_int(pdf_literal_data(p));
+ tprint(">");
} else {
- lua_rawgeti(Luas, LUA_REGISTRYINDEX, pdf_literal_data(p));
- tprint("\"");
- tprint(lua_tostring(Luas, -1));
- tprint("\"");
- lua_pop(Luas, 1);
+ tprint(" <invalid data>");
}
}
-@ @c
void show_late_lua(pointer p)
{
+ int t = late_lua_type(p);
tprint_esc("latelua");
print_int(late_lua_reg(p));
- if (late_lua_type(p) == normal) {
+ if (t == normal) {
print_mark(late_lua_data(p));
- } else {
- tprint(" <function ");
+ } else if (t == lua_refid_literal) {
+ tprint(" <function reference ");
print_int(late_lua_data(p));
tprint(">");
+ } else if (t == lua_refid_call) {
+ tprint(" <functioncall reference ");
+ print_int(late_lua_data(p));
+ tprint(">");
+ } else {
+ tprint(" <invalid data>");
}
}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luastuff.w b/Build/source/texk/web2c/luatexdir/lua/luastuff.c
index a2b1dd14327..0d9342223df 100644
--- a/Build/source/texk/web2c/luatexdir/lua/luastuff.w
+++ b/Build/source/texk/web2c/luatexdir/lua/luastuff.c
@@ -1,30 +1,32 @@
-% luastuff.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/>.
-
-@ @c
+/*
+
+luastuff.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/>.
+
+*/
+
#include "ptexlib.h"
#include "lua/luatex-api.h"
#ifdef LuajitTeX
#include "lua/lauxlib_bridge.h"
#endif
-@ @c
lua_State *Luas = NULL;
int luastate_bytes = 0;
@@ -45,31 +47,44 @@ int lua_active = 0;
lua_pop(L, 1);
#endif
-@ @c
void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc, const char *setfunc)
{
- /* make the table *//* |[{<tex>}]| */
- lua_pushstring(L, tab); /* |[{<tex>},"dimen"]| */
- lua_newtable(L); /* |[{<tex>},"dimen",{}]| */
- lua_settable(L, -3); /* |[{<tex>}]| */
- /* fetch it back */
- lua_pushstring(L, tab); /* |[{<tex>},"dimen"]| */
- lua_gettable(L, -2); /* |[{<tex>},{<dimen>}]| */
- /* make the meta entries */
- luaL_newmetatable(L, mttab); /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
- lua_pushstring(L, "__index"); /* |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
- lua_pushstring(L, getfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
- lua_gettable(L, -5); /* |[{<tex>},{<dimen>},{<dimen_m>},"__index",<tex.getdimen>]| */
- lua_settable(L, -3); /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
- lua_pushstring(L, "__newindex"); /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
- lua_pushstring(L, setfunc); /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
- lua_gettable(L, -5); /* |[{<tex>},{<dimen>},{<dimen_m>},"__newindex",<tex.setdimen>]| */
- lua_settable(L, -3); /* |[{<tex>},{<dimen>},{<dimen_m>}]| */
- lua_setmetatable(L, -2); /* |[{<tex>},{<dimen>}]| : assign the metatable */
- lua_pop(L, 1); /* |[{<tex>}]| : clean the stack */
+ /*tex make the table *//* |[{<tex>}]| */
+ /*tex |[{<tex>},"dimen"]| */
+ lua_pushstring(L, tab);
+ /*tex |[{<tex>},"dimen",{}]| */
+ lua_newtable(L);
+ /*tex |[{<tex>}]| */
+ lua_settable(L, -3);
+ /*tex fetch it back */
+ /*tex |[{<tex>},"dimen"]| */
+ lua_pushstring(L, tab);
+ /*tex |[{<tex>},{<dimen>}]| */
+ lua_gettable(L, -2);
+ /*tex make the meta entries */
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ luaL_newmetatable(L, mttab);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
+ lua_pushstring(L, "__index");
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
+ lua_pushstring(L, getfunc);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index",<tex.getdimen>]| */
+ lua_gettable(L, -5);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ lua_settable(L, -3);
+ lua_pushstring(L, "__newindex"); /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
+ lua_pushstring(L, setfunc);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex",<tex.setdimen>]| */
+ lua_gettable(L, -5);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ lua_settable(L, -3);
+ /*tex |[{<tex>},{<dimen>}]| : assign the metatable */
+ lua_setmetatable(L, -2);
+ /*tex |[{<tex>}]| : clean the stack */
+ lua_pop(L, 1);
}
-@ @c
static const char *getS(lua_State * L, void *ud, size_t * size)
{
LoadS *ls = (LoadS *) ud;
@@ -81,18 +96,19 @@ static const char *getS(lua_State * L, void *ud, size_t * size)
return ls->s;
}
-@ @c
#ifdef LuajitTeX
- /* Luatex has its own memory allocator, LuajitTeX uses the */
- /* standard one from the stock. We left this space as */
- /* reference, but be careful: memory allocator is a key */
- /* component in luajit, it's easy to get sub-optimal */
- /* performances. */
+ /*
+ \LUATEX\ has its own memory allocator, \LUAJIITEX\ uses the standard one
+ from the stock. We left this space as reference, but be careful: memory
+ allocator is a key component in \LUAJIT, it's easy to get sub-optimal
+ performances.
+ */
#else
static void *my_luaalloc(void *ud, void *ptr, size_t osize, size_t nsize)
{
void *ret = NULL;
- (void) ud; /* for -Wunused */
+ /*tex define |ud| for -Wunused */
+ (void) ud;
if (nsize == 0)
free(ptr);
else
@@ -102,15 +118,14 @@ static void *my_luaalloc(void *ud, void *ptr, size_t osize, size_t nsize)
}
#endif
-@ @c
static int my_luapanic(lua_State * L)
{
- (void) L; /* to avoid warnings */
+ /*tex define |L| to avoid warnings */
+ (void) L;
fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1));
return 0;
}
-@ @c
void luafunctioncall(int slot)
{
int i ;
@@ -120,12 +135,17 @@ void luafunctioncall(int slot)
lua_gettable(Luas, LUA_REGISTRYINDEX);
lua_rawgeti(Luas, -1,slot);
if (lua_isfunction(Luas,-1)) {
- int base = lua_gettop(Luas); /* function index */
+ /*tex function index */
+ int base = lua_gettop(Luas);
lua_pushinteger(Luas, slot);
- lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
- lua_insert(Luas, base); /* put it under chunk */
+ /* push traceback function */
+ lua_pushcfunction(Luas, lua_traceback);
+ /*tex put it under chunk */
+ lua_insert(Luas, base);
+ ++function_callback_count;
i = lua_pcall(Luas, 1, 0, base);
- lua_remove(Luas, base); /* remove traceback function */
+ /*tex remove traceback function */
+ lua_remove(Luas, base);
if (i != 0) {
lua_gc(Luas, LUA_GCCOLLECT, 0);
Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
@@ -135,9 +155,8 @@ void luafunctioncall(int slot)
lua_active--;
}
-@ @c
static const luaL_Reg lualibs[] = {
- /* standard lua libraries */
+ /*tex standard \LUA\ libraries */
{ "_G", luaopen_base },
{ "package", luaopen_package },
{ "table", luaopen_table },
@@ -149,32 +168,30 @@ static const luaL_Reg lualibs[] = {
{ "lpeg", luaopen_lpeg },
{ "bit32", luaopen_bit32 },
#ifdef LuajitTeX
- /* bit is only in luajit, */
- /* coroutine is loaded in a special way */
- { "bit", luaopen_bit },
+ /*tex |bit| is only in \LUAJIT */
+ /*tex |coroutine| is loaded in a special way */
+ { "bit", luaopen_bit },
#else
#if LUA_VERSION_NUM == 503
{ "utf8", luaopen_utf8 },
#endif
{ "coroutine", luaopen_coroutine },
#endif
- /* additional (public) libraries */
+ /*tex additional (public) libraries */
{ "unicode", luaopen_unicode },
{ "zip", luaopen_zip },
{ "md5", luaopen_md5 },
+ { "sha2", luaopen_sha2 },
{ "lfs", luaopen_lfs },
- /* extra standard lua libraries */
+ /*tex extra standard lua libraries */
#ifdef LuajitTeX
{ "jit", luaopen_jit },
#endif
{ "ffi", luaopen_ffi },
- /* obsolete, undocumented and for oru own testing only */
- /*{ "profiler", luaopen_profiler }, */
- /* more libraries will be loaded later */
+ /*tex more libraries will be loaded later */
{ NULL, NULL }
};
-@ @c
static void do_openlibs(lua_State * L)
{
const luaL_Reg *lib = lualibs;
@@ -183,22 +200,23 @@ static void do_openlibs(lua_State * L)
}
}
-@ @c
#ifdef LuajitTeX
- /* in luajit load_aux is not used.*/
+ /*tex in \LUAJIT\ |load_aux| is not used.*/
#else
static int load_aux (lua_State *L, int status) {
- if (status == 0) /* OK? */
+ if (status == 0)
+ /*tex okay */
return 1;
else {
+ /*tex return nil plus error message */
lua_pushnil(L);
- lua_insert(L, -2); /* put before error message */
- return 2; /* return nil plus error message */
+ /*tex put before error message */
+ lua_insert(L, -2);
+ return 2;
}
}
#endif
-@ @c
static int luatex_loadfile (lua_State *L) {
int status = 0;
const char *fname = luaL_optstring(L, 1, NULL);
@@ -206,12 +224,14 @@ static int luatex_loadfile (lua_State *L) {
#ifdef LuajitTeX
/* 5.1 */
#else
- int env = !lua_isnone(L, 3); /* 'env' parameter? */
+ /*tex the |env| parameter */
+ int env = !lua_isnone(L, 3);
#endif
if (!lua_only && !fname && interaction == batch_mode) {
+ /*tex return |nil| plus error message */
lua_pushnil(L);
lua_pushstring(L, "reading from stdin is disabled in batch mode");
- return 2; /* return nil plus error message */
+ return 2;
}
status = luaL_loadfilex(L, fname, mode);
if (status == LUA_OK) {
@@ -219,9 +239,11 @@ static int luatex_loadfile (lua_State *L) {
#ifdef LuajitTeX
/* 5.1 */
#else
- if (env) { /* 'env' parameter? */
+ if (env) {
+ /*tex the |env| parameter */
lua_pushvalue(L, 3);
- lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */
+ /*tex set it as first upvalue of loaded chunk */
+ lua_setupvalue(L, -2, 1);
}
#endif
}
@@ -232,15 +254,15 @@ static int luatex_loadfile (lua_State *L) {
#endif
}
-@ @c
static int luatex_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
int n = lua_gettop(L);
if (!lua_only && !fname) {
if (interaction == batch_mode) {
+ /*tex return |nil| plus error message */
lua_pushnil(L);
lua_pushstring(L, "reading from stdin is disabled in batch mode");
- return 2; /* return nil plus error message */
+ return 2;
} else {
tprint_nl("lua> ");
}
@@ -252,13 +274,12 @@ static int luatex_dofile (lua_State *L) {
return lua_gettop(L) - n;
}
-@ @c
void luainterpreter(void)
{
lua_State *L;
#ifdef LuajitTeX
if (jithash_hashname == NULL) {
- /* default lua51 */
+ /*tex default lua51 */
luajittex_choose_hash_function = 0;
jithash_hashname = (char *) xmalloc(strlen("lua51") + 1);
jithash_hashname = strcpy ( jithash_hashname, "lua51");
@@ -267,7 +288,7 @@ void luainterpreter(void)
} else if (strcmp((const char*)jithash_hashname,"luajit20") == 0) {
luajittex_choose_hash_function = 1;
} else {
- /* default lua51 */
+ /*tex default lua51 */
luajittex_choose_hash_function = 0;
jithash_hashname = strcpy ( jithash_hashname, "lua51");
}
@@ -280,8 +301,8 @@ void luainterpreter(void)
return;
}
lua_atpanic(L, &my_luapanic);
-
- do_openlibs(L); /* does all the 'simple' libraries */
+ /*tex This initializes all the `simple' libraries: */
+ do_openlibs(L);
#ifdef LuajitTeX
if (luajiton){
luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_ON);
@@ -290,22 +311,17 @@ void luainterpreter(void)
luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_OFF);
}
#endif
-
lua_pushcfunction(L,luatex_dofile);
lua_setglobal(L, "dofile");
lua_pushcfunction(L,luatex_loadfile);
lua_setglobal(L, "loadfile");
-
open_oslibext(L);
open_strlibext(L);
- open_lfslibext(L);
-
- /*
- The socket and mime libraries are a bit tricky to open because they use a load-time
- dependency that has to be worked around for luatex, where the C module is loaded
- way before the lua module.
+ /*tex
+ The socket and mime libraries are a bit tricky to open because they use a
+ load-time dependency that has to be worked around for luatex, where the C
+ module is loaded way before the lua module.
*/
-
if (!nosocket_option) {
/* todo: move this to common */
lua_getglobal(L, "package");
@@ -315,28 +331,26 @@ void luainterpreter(void)
lua_setfield(L, -2, "loaded");
lua_getfield(L, -1, "loaded");
}
+ /*tex |package.loaded.socket = nil| */
luaopen_socket_core(L);
lua_setfield(L, -2, "socket.core");
lua_pushnil(L);
- lua_setfield(L, -2, "socket"); /* package.loaded.socket = nil */
-
+ lua_setfield(L, -2, "socket");
+ /*tex |package.loaded.mime = nil| */
luaopen_mime_core(L);
lua_setfield(L, -2, "mime.core");
lua_pushnil(L);
- lua_setfield(L, -2, "mime"); /* package.loaded.mime = nil */
- lua_pop(L, 2); /* pop the tables */
-
- luatex_socketlua_open(L); /* preload the pure lua modules */
+ lua_setfield(L, -2, "mime");
+ /*tex pop the tables */
+ lua_pop(L, 2);
+ /*tex preload the pure \LUA\ modules */
+ luatex_socketlua_open(L);
}
-
- /* zlib. slightly odd calling convention */
+ /*tex |zlib|'s slightly odd calling convention */
luaopen_zlib(L);
lua_setglobal(L, "zlib");
-
luaopen_gzip(L);
-
- /* our own libraries register themselves */
-
+ /*tex our own libraries register themselves */
luaopen_fio(L);
luaopen_ff(L);
luaopen_tex(L);
@@ -345,29 +359,25 @@ void luainterpreter(void)
luaopen_texio(L);
luaopen_kpse(L);
luaopen_callback(L);
-
+ /*tex now we plug in extra \LUA\ startup code */
luaopen_lua(L, startup_filename);
-
+ /*tex and open some \TEX\ ones */
luaopen_stats(L);
luaopen_font(L);
luaopen_lang(L);
luaopen_mplib(L);
luaopen_vf(L);
luaopen_pdf(L);
- luaopen_epdf(L);
+ luaopen_pdfe(L);
luaopen_pdfscanner(L);
-
if (!lua_only) {
luaopen_img(L);
}
-
lua_createtable(L, 0, 0);
lua_setglobal(L, "texconfig");
-
Luas = L;
}
-@ @c
int hide_lua_table(lua_State * L, const char *name)
{
int r = 0;
@@ -380,7 +390,6 @@ int hide_lua_table(lua_State * L, const char *name)
return r;
}
-@ @c
void unhide_lua_table(lua_State * L, const char *name, int r)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, r);
@@ -388,7 +397,6 @@ void unhide_lua_table(lua_State * L, const char *name, int r)
luaL_unref(L, LUA_REGISTRYINDEX, r);
}
-@ @c
int hide_lua_value(lua_State * L, const char *name, const char *item)
{
int r = 0;
@@ -402,7 +410,6 @@ int hide_lua_value(lua_State * L, const char *name, const char *item)
return r;
}
-@ @c
void unhide_lua_value(lua_State * L, const char *name, const char *item, int r)
{
lua_getglobal(L, name);
@@ -413,7 +420,6 @@ void unhide_lua_value(lua_State * L, const char *name, const char *item, int r)
}
}
-@ @c
int lua_traceback(lua_State * L)
{
lua_getglobal(L, "debug");
@@ -426,21 +432,23 @@ int lua_traceback(lua_State * L)
lua_pop(L, 2);
return 1;
}
- lua_pushvalue(L, 1); /* pass error message */
- lua_pushinteger(L, 2); /* skip this function and traceback */
- lua_call(L, 2, 1); /* call debug.traceback */
+ /*tex pass error message */
+ lua_pushvalue(L, 1);
+ /*tex skip this function and traceback */
+ lua_pushinteger(L, 2);
+ /*tex call |debug.traceback| */
+ lua_call(L, 2, 1);
return 1;
}
-@ @c
-static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized lua_id resolving */
+static void luacall(int p, int nameptr, boolean is_string)
{
LoadS ls;
int i;
size_t ll = 0;
char *lua_id;
char *s = NULL;
-
+ int stacktop = lua_gettop(Luas);
if (Luas == NULL) {
luainterpreter();
}
@@ -449,16 +457,22 @@ static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized l
const char *ss = NULL;
lua_rawgeti(Luas, LUA_REGISTRYINDEX, p);
if (lua_isfunction(Luas,-1)) {
- int base = lua_gettop(Luas); /* function index */
+ /*tex function index */
+ int base = lua_gettop(Luas);
lua_checkstack(Luas, 1);
- lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
- lua_insert(Luas, base); /* put it under chunk */
+ /*tex push traceback function */
+ lua_pushcfunction(Luas, lua_traceback);
+ /*tex put it under chunk */
+ lua_insert(Luas, base);
+ ++late_callback_count;
i = lua_pcall(Luas, 0, 0, base);
- lua_remove(Luas, base); /* remove traceback function */
+ /*tex remove traceback function */
+ lua_remove(Luas, base);
if (i != 0) {
lua_gc(Luas, LUA_GCCOLLECT, 0);
Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
}
+ lua_settop(Luas,stacktop);
lua_active--;
return ;
}
@@ -475,7 +489,8 @@ static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized l
ls.size = ll;
if (ls.size > 0) {
if (nameptr > 0) {
- int l = 0; /* not used */
+ /*tex |l| is not used */
+ int l = 0;
lua_id = tokenlist_to_cstring(nameptr, 1, &l);
i = Luas_load(Luas, getS, &ls, lua_id);
xfree(lua_id);
@@ -492,12 +507,17 @@ static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized l
if (i != 0) {
Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
} else {
- int base = lua_gettop(Luas); /* function index */
+ /*tex function index */
+ int base = lua_gettop(Luas);
lua_checkstack(Luas, 1);
- lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
- lua_insert(Luas, base); /* put it under chunk */
+ /*tex push traceback function */
+ lua_pushcfunction(Luas, lua_traceback);
+ /*tex put it under chunk */
+ lua_insert(Luas, base);
+ ++late_callback_count;
i = lua_pcall(Luas, 0, 0, base);
- lua_remove(Luas, base); /* remove traceback function */
+ /*tex remove traceback function */
+ lua_remove(Luas, base);
if (i != 0) {
lua_gc(Luas, LUA_GCCOLLECT, 0);
Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
@@ -505,31 +525,99 @@ static void luacall(int p, int nameptr, boolean is_string) /* hh-ls: optimized l
}
xfree(ls.s);
}
+ lua_settop(Luas,stacktop);
+ lua_active--;
+}
+
+void luacall_vf(int p, int f, int c)
+{
+ int i;
+ int stacktop = lua_gettop(Luas);
+ if (Luas == NULL) {
+ luainterpreter();
+ }
+ lua_active++;
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, p);
+ if (lua_isfunction(Luas,-1)) {
+ /*tex function index */
+ int base = lua_gettop(Luas);
+ lua_checkstack(Luas, 1);
+ /*tex push traceback function */
+ lua_pushcfunction(Luas, lua_traceback);
+ /*tex put it under chunk */
+ lua_insert(Luas, base);
+ lua_pushinteger(Luas, f);
+ lua_pushinteger(Luas, c);
+ ++late_callback_count;
+ i = lua_pcall(Luas, 2, 0, base);
+ /*tex remove traceback function */
+ lua_remove(Luas, base);
+ if (i != 0) {
+ lua_gc(Luas, LUA_GCCOLLECT, 0);
+ Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ }
+ } else {
+ LoadS ls;
+ size_t ll = 0;
+ char *s = NULL;
+ const char *ss = NULL;
+ ss = lua_tolstring(Luas, -1, &ll);
+ s = xmalloc(ll+1);
+ memcpy(s,ss,ll+1);
+ lua_pop(Luas,1);
+ ls.s = s;
+ ls.size = ll;
+ if (ls.size > 0) {
+ i = Luas_load(Luas, getS, &ls, "=[vf command]");
+ if (i != 0) {
+ Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
+ } else {
+ int base = lua_gettop(Luas); /* function index */
+ lua_checkstack(Luas, 1);
+ lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
+ lua_insert(Luas, base); /* put it under chunk */
+ ++late_callback_count;
+ i = lua_pcall(Luas, 0, 0, base);
+ lua_remove(Luas, base); /* remove traceback function */
+ if (i != 0) {
+ lua_gc(Luas, LUA_GCCOLLECT, 0);
+ Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ }
+ }
+ xfree(ls.s);
+ }
+ }
+ lua_settop(Luas,stacktop);
lua_active--;
}
-@ @c
void late_lua(PDF pdf, halfword p)
{
+ halfword t;
(void) pdf;
- if (late_lua_type(p)==normal) {
- expand_macros_in_tokenlist(p); /* sets |def_ref| */
+ t = late_lua_type(p);
+ if (t == normal) {
+ /*tex sets |def_ref| */
+ expand_macros_in_tokenlist(p);
luacall(def_ref, late_lua_name(p), false);
flush_list(def_ref);
- } else {
+ } else if (t == lua_refid_call) {
+ luafunctioncall(late_lua_data(p));
+ } else if (t == lua_refid_literal) {
luacall(late_lua_data(p), late_lua_name(p), true);
+ } else {
+ /*tex Let's just ignore it, could be some user specific thing. */
}
}
-@ @c
-void luatokencall(int p, int nameptr) /* hh-ls: optimized lua_id resolving */
+void luatokencall(int p, int nameptr)
{
LoadS ls;
- int i, l;
+ int i;
+ int l = 0;
char *s = NULL;
char *lua_id;
- assert(Luas);
- l = 0;
+ int stacktop = lua_gettop(Luas);
lua_active++;
s = tokenlist_to_cstring(p, 1, &l);
ls.s = s;
@@ -538,7 +626,7 @@ void luatokencall(int p, int nameptr) /* hh-ls: optimized lua_id resolving */
if (nameptr > 0) {
lua_id = tokenlist_to_cstring(nameptr, 1, &l);
i = Luas_load(Luas, getS, &ls, lua_id);
- xfree(lua_id);
+ xfree(lua_id);
} else if (nameptr < 0) {
lua_id = get_lua_name((nameptr + 65536));
if (lua_id != NULL) {
@@ -553,40 +641,53 @@ void luatokencall(int p, int nameptr) /* hh-ls: optimized lua_id resolving */
if (i != 0) {
Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
} else {
- int base = lua_gettop(Luas); /* function index */
+ /*tex function index */
+ int base = lua_gettop(Luas);
lua_checkstack(Luas, 1);
- lua_pushcfunction(Luas, lua_traceback); /* push traceback function */
- lua_insert(Luas, base); /* put it under chunk */
+ /*tex push traceback function */
+ lua_pushcfunction(Luas, lua_traceback);
+ /*tex put it under chunk */
+ lua_insert(Luas, base);
+ ++direct_callback_count;
i = lua_pcall(Luas, 0, 0, base);
- lua_remove(Luas, base); /* remove traceback function */
+ /*tex remove traceback function */
+ lua_remove(Luas, base);
if (i != 0) {
lua_gc(Luas, LUA_GCCOLLECT, 0);
Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
}
}
}
+ lua_settop(Luas,stacktop);
lua_active--;
}
-@ @c
lua_State *luatex_error(lua_State * L, int is_fatal)
{
-
const_lstring luaerr;
char *err = NULL;
if (lua_type(L, -1) == LUA_TSTRING) {
luaerr.s = lua_tolstring(L, -1, &luaerr.l);
- /* free last one ? */
+ /*tex
+ Free the last one.
+ */
err = (char *) xmalloc((unsigned) (luaerr.l + 1));
snprintf(err, (luaerr.l + 1), "%s", luaerr.s);
- last_lua_error = err; /* hm, what if we have several .. not freed */
+ /*tex
+ What if we have several .. not freed?
+ */
+ last_lua_error = err;
}
if (is_fatal > 0) {
- /* Normally a memory error from lua.
- The pool may overflow during the |maketexlstring()|, but we
- are crashing anyway so we may as well abort on the pool size */
+ /*
+ Normally a memory error from lua. The pool may overflow during the
+ |maketexlstring()|, but we are crashing anyway so we may as well
+ abort on the pool size
+ */
normal_error("lua",err);
- /* never reached */
+ /*tex
+ This is never reached.
+ */
lua_close(L);
return (lua_State *) NULL;
} else {
@@ -595,35 +696,41 @@ lua_State *luatex_error(lua_State * L, int is_fatal)
}
}
-@ @c
void preset_environment(lua_State * L, const parm_struct * p, const char *s)
{
int i;
assert(L != NULL);
- /* double call with same s gives assert(0) */
- lua_pushstring(L, s); /* s */
- lua_gettable(L, LUA_REGISTRYINDEX); /* t */
+ /*tex double call with same s gives assert(0) */
+ lua_pushstring(L, s);
+ /*tex state: s */
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ /*tex state: t */
assert(lua_isnil(L, -1));
- lua_pop(L, 1); /* - */
- lua_pushstring(L, s); /* s */
- lua_newtable(L); /* t s */
+ lua_pop(L, 1);
+ /*tex state: - */
+ lua_pushstring(L, s);
+ /*tex state: s */
+ lua_newtable(L);
+ /*tex state: t s */
for (i = 1, ++p; p->name != NULL; i++, p++) {
assert(i == p->idx);
- lua_pushstring(L, p->name); /* k t s */
- lua_pushinteger(L, p->idx); /* v k t s */
- lua_settable(L, -3); /* t s */
+ lua_pushstring(L, p->name);
+ /*tex state: k t s */
+ lua_pushinteger(L, p->idx);
+ /*tex state: v k t s */
+ lua_settable(L, -3);
+ /*tex state: t s */
}
- lua_settable(L, LUA_REGISTRYINDEX); /* - */
+ lua_settable(L, LUA_REGISTRYINDEX);
+ /* tex state: - */
}
-
-@ @c
-/*
- luajit compatibility layer for luatex lua5.2
+/*tex
+ Here comes a \LUAJIT\ compatibility layer for \LUATEX\ \LUA5.2:
*/
+
#ifdef LuajitTeX
-@ @c
LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
lua_State *L = B->L;
if (sz > LUAL_BUFFERSIZE )
@@ -631,24 +738,22 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
return luaL_prepbuffer(B) ;
}
-@ @c
LUA_API int lua_compare (lua_State *L, int o1, int o2, int op) {
/*StkId o1, o2;*/
int i = 0;
lua_lock(L); /* may call tag method */
/* o1 = index2addr(L, index1); */
/* o2 = index2addr(L, index2); */
- /*if (isvalid(o1) && isvalid(o2)) {*/
+ /* if (isvalid(o1) && isvalid(o2)) {*/
switch (op) {
case LUA_OPEQ: i = lua_equal(L, o1, o2); break;
case LUA_OPLT: i = lua_lessthan(L, o1, o2); break;
case LUA_OPLE: i = (lua_lessthan(L, o1, o2) || lua_equal(L, o1, o2)) ; break;
default: luaL_error(L, "invalid option");
}
- /*}*/
+ /* } */
lua_unlock(L);
return i;
}
-@ @c
#endif
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatoken.c b/Build/source/texk/web2c/luatexdir/lua/luatoken.c
new file mode 100644
index 00000000000..fb197b68f7b
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luatoken.c
@@ -0,0 +1,585 @@
+/*
+
+luatoken.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/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+command_item command_names[] = {
+ { relax_cmd, NULL, 0},
+ { left_brace_cmd, NULL, 0},
+ { right_brace_cmd, NULL, 0},
+ { math_shift_cmd, NULL, 0},
+ { tab_mark_cmd, NULL, 0},
+ { car_ret_cmd, NULL, 0},
+ { mac_param_cmd, NULL, 0},
+ { sup_mark_cmd, NULL, 0},
+ { sub_mark_cmd, NULL, 0},
+ { endv_cmd, NULL, 0},
+ { spacer_cmd, NULL, 0},
+ { letter_cmd, NULL, 0},
+ { other_char_cmd, NULL, 0},
+ { par_end_cmd, NULL, 0},
+ { stop_cmd, NULL, 0},
+ { delim_num_cmd, NULL, 0},
+ { char_num_cmd, NULL, 0},
+ { math_char_num_cmd, NULL, 0},
+ { mark_cmd, NULL, 0},
+ { node_cmd, NULL, 0},
+ { xray_cmd, NULL, 0},
+ { make_box_cmd, NULL, 0},
+ { hmove_cmd, NULL, 0},
+ { vmove_cmd, NULL, 0},
+ { un_hbox_cmd, NULL, 0},
+ { un_vbox_cmd, NULL, 0},
+ { remove_item_cmd, NULL, 0},
+ { hskip_cmd, NULL, 0},
+ { vskip_cmd, NULL, 0},
+ { mskip_cmd, NULL, 0},
+ { kern_cmd, NULL, 0},
+ { mkern_cmd, NULL, 0},
+ { leader_ship_cmd, NULL, 0},
+ { halign_cmd, NULL, 0},
+ { valign_cmd, NULL, 0},
+ { no_align_cmd, NULL, 0},
+ { no_vrule_cmd, NULL, 0},
+ { no_hrule_cmd, NULL, 0},
+ { vrule_cmd, NULL, 0},
+ { hrule_cmd, NULL, 0},
+ { insert_cmd, NULL, 0},
+ { vadjust_cmd, NULL, 0},
+ { ignore_spaces_cmd, NULL, 0},
+ { after_assignment_cmd, NULL, 0},
+ { after_group_cmd, NULL, 0},
+ { break_penalty_cmd, NULL, 0},
+ { start_par_cmd, NULL, 0},
+ { ital_corr_cmd, NULL, 0},
+ { accent_cmd, NULL, 0},
+ { math_accent_cmd, NULL, 0},
+ { discretionary_cmd, NULL, 0},
+ { eq_no_cmd, NULL, 0},
+ { left_right_cmd, NULL, 0},
+ { math_comp_cmd, NULL, 0},
+ { limit_switch_cmd, NULL, 0},
+ { above_cmd, NULL, 0},
+ { math_style_cmd, NULL, 0},
+ { math_choice_cmd, NULL, 0},
+ { non_script_cmd, NULL, 0},
+ { vcenter_cmd, NULL, 0},
+ { case_shift_cmd, NULL, 0},
+ { message_cmd, NULL, 0},
+ { normal_cmd, NULL, 0},
+ { extension_cmd, NULL, 0},
+ { option_cmd, NULL, 0},
+ { lua_function_call_cmd, NULL, 0},
+ { lua_bytecode_call_cmd, NULL, 0},
+ { lua_call_cmd, NULL, 0},
+ { in_stream_cmd, NULL, 0},
+ { begin_group_cmd, NULL, 0},
+ { end_group_cmd, NULL, 0},
+ { omit_cmd, NULL, 0},
+ { ex_space_cmd, NULL, 0},
+ { boundary_cmd, NULL, 0},
+ { radical_cmd, NULL, 0},
+ { super_sub_script_cmd, NULL, 0},
+ { no_super_sub_script_cmd, NULL, 0},
+ { math_shift_cs_cmd, NULL, 0},
+ { end_cs_name_cmd, NULL, 0},
+ { char_ghost_cmd, NULL, 0},
+ { assign_local_box_cmd, NULL, 0},
+ { char_given_cmd, NULL, 0},
+ { math_given_cmd, NULL, 0},
+ { xmath_given_cmd, NULL, 0},
+ { last_item_cmd, NULL, 0},
+ { toks_register_cmd, NULL, 0},
+ { assign_toks_cmd, NULL, 0},
+ { assign_int_cmd, NULL, 0},
+ { assign_attr_cmd, NULL, 0},
+ { assign_dimen_cmd, NULL, 0},
+ { assign_glue_cmd, NULL, 0},
+ { assign_mu_glue_cmd, NULL, 0},
+ { assign_font_dimen_cmd, NULL, 0},
+ { assign_font_int_cmd, NULL, 0},
+ { assign_hang_indent_cmd, NULL, 0},
+ { set_aux_cmd, NULL, 0},
+ { set_prev_graf_cmd, NULL, 0},
+ { set_page_dimen_cmd, NULL, 0},
+ { set_page_int_cmd, NULL, 0},
+ { set_box_dimen_cmd, NULL, 0},
+ { set_tex_shape_cmd, NULL, 0},
+ { set_etex_shape_cmd, NULL, 0},
+ { def_char_code_cmd, NULL, 0},
+ { def_del_code_cmd, NULL, 0},
+ { extdef_math_code_cmd, NULL, 0},
+ { extdef_del_code_cmd, NULL, 0},
+ { def_family_cmd, NULL, 0},
+ { set_math_param_cmd, NULL, 0},
+ { set_font_cmd, NULL, 0},
+ { def_font_cmd, NULL, 0},
+ { register_cmd, NULL, 0},
+ { assign_box_direction_cmd, NULL, 0},
+ { assign_box_dir_cmd, NULL, 0},
+ { assign_direction_cmd, NULL, 0},
+ { assign_dir_cmd, NULL, 0},
+ { advance_cmd, NULL, 0},
+ { multiply_cmd, NULL, 0},
+ { divide_cmd, NULL, 0},
+ { prefix_cmd, NULL, 0},
+ { let_cmd, NULL, 0},
+ { shorthand_def_cmd, NULL, 0},
+ { def_lua_call_cmd, NULL, 0},
+ { read_to_cs_cmd, NULL, 0},
+ { def_cmd, NULL, 0},
+ { set_box_cmd, NULL, 0},
+ { hyph_data_cmd, NULL, 0},
+ { set_interaction_cmd, NULL, 0},
+ { letterspace_font_cmd, NULL, 0},
+ { expand_font_cmd, NULL, 0},
+ { copy_font_cmd, NULL, 0},
+ { set_font_id_cmd, NULL, 0},
+ { undefined_cs_cmd, NULL, 0},
+ { expand_after_cmd, NULL, 0},
+ { no_expand_cmd, NULL, 0},
+ { input_cmd, NULL, 0},
+ { lua_expandable_call_cmd, NULL, 0},
+ { lua_local_call_cmd, NULL, 0},
+ { if_test_cmd, NULL, 0},
+ { fi_or_else_cmd, NULL, 0},
+ { cs_name_cmd, NULL, 0},
+ { convert_cmd, NULL, 0},
+ { variable_cmd, NULL, 0},
+ { feedback_cmd, NULL, 0},
+ { the_cmd, NULL, 0},
+ { combine_toks_cmd, NULL, 0},
+ { top_bot_mark_cmd, NULL, 0},
+ { call_cmd, NULL, 0},
+ { long_call_cmd, NULL, 0},
+ { outer_call_cmd, NULL, 0},
+ { long_outer_call_cmd, NULL, 0},
+ { end_template_cmd, NULL, 0},
+ { dont_expand_cmd, NULL, 0},
+ { glue_ref_cmd, NULL, 0},
+ { shape_ref_cmd, NULL, 0},
+ { box_ref_cmd, NULL, 0},
+ { data_cmd, NULL, 0},
+ { -1, NULL, 0}
+};
+
+# define init_token_key(target,n,key) \
+ target[n].lua = luaS_##key##_index; \
+ target[n].name = luaS_##key##_ptr;
+
+void l_set_token_data(void)
+{
+ init_token_key(command_names, relax_cmd, relax);
+ init_token_key(command_names, left_brace_cmd, left_brace);
+ init_token_key(command_names, right_brace_cmd, right_brace);
+ init_token_key(command_names, math_shift_cmd, math_shift);
+ init_token_key(command_names, tab_mark_cmd, tab_mark);
+ init_token_key(command_names, car_ret_cmd, car_ret);
+ init_token_key(command_names, mac_param_cmd, mac_param);
+ init_token_key(command_names, sup_mark_cmd, sup_mark);
+ init_token_key(command_names, sub_mark_cmd, sub_mark);
+ init_token_key(command_names, endv_cmd, endv);
+ init_token_key(command_names, spacer_cmd, spacer);
+ init_token_key(command_names, letter_cmd, letter);
+ init_token_key(command_names, other_char_cmd, other_char);
+ init_token_key(command_names, par_end_cmd, par_end);
+ init_token_key(command_names, stop_cmd, stop);
+ init_token_key(command_names, delim_num_cmd, delim_num);
+ init_token_key(command_names, char_num_cmd, char_num);
+ init_token_key(command_names, math_char_num_cmd, math_char_num);
+ init_token_key(command_names, mark_cmd, mark);
+ init_token_key(command_names, node_cmd, node);
+ init_token_key(command_names, xray_cmd, xray);
+ init_token_key(command_names, make_box_cmd, make_box);
+ init_token_key(command_names, hmove_cmd, hmove);
+ init_token_key(command_names, vmove_cmd, vmove);
+ init_token_key(command_names, un_hbox_cmd, un_hbox);
+ init_token_key(command_names, un_vbox_cmd, un_vbox);
+ init_token_key(command_names, remove_item_cmd, remove_item);
+ init_token_key(command_names, hskip_cmd, hskip);
+ init_token_key(command_names, vskip_cmd, vskip);
+ init_token_key(command_names, mskip_cmd, mskip);
+ init_token_key(command_names, kern_cmd, kern);
+ init_token_key(command_names, mkern_cmd, mkern);
+ init_token_key(command_names, leader_ship_cmd, leader_ship);
+ init_token_key(command_names, halign_cmd, halign);
+ init_token_key(command_names, valign_cmd, valign);
+ init_token_key(command_names, no_align_cmd, no_align);
+ init_token_key(command_names, vrule_cmd, vrule);
+ init_token_key(command_names, hrule_cmd, hrule);
+ init_token_key(command_names, no_vrule_cmd, novrule);
+ init_token_key(command_names, no_hrule_cmd, nohrule);
+ init_token_key(command_names, insert_cmd, insert);
+ init_token_key(command_names, vadjust_cmd, vadjust);
+ init_token_key(command_names, ignore_spaces_cmd, ignore_spaces);
+ init_token_key(command_names, after_assignment_cmd, after_assignment);
+ init_token_key(command_names, after_group_cmd, after_group);
+ init_token_key(command_names, break_penalty_cmd, break_penalty);
+ init_token_key(command_names, start_par_cmd, start_par);
+ init_token_key(command_names, ital_corr_cmd, ital_corr);
+ init_token_key(command_names, accent_cmd, accent);
+ init_token_key(command_names, math_accent_cmd, math_accent);
+ init_token_key(command_names, discretionary_cmd, discretionary);
+ init_token_key(command_names, eq_no_cmd, eq_no);
+ init_token_key(command_names, left_right_cmd, left_right);
+ init_token_key(command_names, math_comp_cmd, math_comp);
+ init_token_key(command_names, limit_switch_cmd, limit_switch);
+ init_token_key(command_names, above_cmd, above);
+ init_token_key(command_names, math_style_cmd, math_style);
+ init_token_key(command_names, math_choice_cmd, math_choice);
+ init_token_key(command_names, non_script_cmd, non_script);
+ init_token_key(command_names, vcenter_cmd, vcenter);
+ init_token_key(command_names, case_shift_cmd, case_shift);
+ init_token_key(command_names, message_cmd, message);
+ init_token_key(command_names, normal_cmd, normal);
+ init_token_key(command_names, extension_cmd, extension);
+ init_token_key(command_names, option_cmd, option);
+ init_token_key(command_names, lua_function_call_cmd, lua_function_call);
+ init_token_key(command_names, lua_bytecode_call_cmd, lua_bytecode_call);
+ init_token_key(command_names, lua_call_cmd, lua_call);
+ init_token_key(command_names, in_stream_cmd, in_stream);
+ init_token_key(command_names, begin_group_cmd, begin_group);
+ init_token_key(command_names, end_group_cmd, end_group);
+ init_token_key(command_names, omit_cmd, omit);
+ init_token_key(command_names, ex_space_cmd, ex_space);
+ init_token_key(command_names, boundary_cmd, boundary);
+ init_token_key(command_names, radical_cmd, radical);
+ init_token_key(command_names, super_sub_script_cmd, super_sub_script);
+ init_token_key(command_names, no_super_sub_script_cmd, no_super_sub_script);
+ init_token_key(command_names, math_shift_cs_cmd, math_shift_cs);
+ init_token_key(command_names, end_cs_name_cmd, end_cs_name);
+ init_token_key(command_names, char_ghost_cmd, char_ghost);
+ init_token_key(command_names, assign_local_box_cmd, assign_local_box);
+ init_token_key(command_names, char_given_cmd, char_given);
+ init_token_key(command_names, math_given_cmd, math_given);
+ init_token_key(command_names, xmath_given_cmd, xmath_given);
+ init_token_key(command_names, last_item_cmd, last_item);
+ init_token_key(command_names, toks_register_cmd, toks_register);
+ init_token_key(command_names, assign_toks_cmd, assign_toks);
+ init_token_key(command_names, assign_int_cmd, assign_int);
+ init_token_key(command_names, assign_attr_cmd, assign_attr);
+ init_token_key(command_names, assign_dimen_cmd, assign_dimen);
+ init_token_key(command_names, assign_glue_cmd, assign_glue);
+ init_token_key(command_names, assign_mu_glue_cmd, assign_mu_glue);
+ init_token_key(command_names, assign_font_dimen_cmd, assign_font_dimen);
+ init_token_key(command_names, assign_font_int_cmd, assign_font_int);
+ init_token_key(command_names, assign_hang_indent_cmd, assign_hang_indent);
+ init_token_key(command_names, set_aux_cmd, set_aux);
+ init_token_key(command_names, set_prev_graf_cmd, set_prev_graf);
+ init_token_key(command_names, set_page_dimen_cmd, set_page_dimen);
+ init_token_key(command_names, set_page_int_cmd, set_page_int);
+ init_token_key(command_names, set_box_dimen_cmd, set_box_dimen);
+ init_token_key(command_names, set_tex_shape_cmd, set_tex_shape);
+ init_token_key(command_names, set_etex_shape_cmd, set_etex_shape);
+ init_token_key(command_names, def_char_code_cmd, def_char_code);
+ init_token_key(command_names, def_del_code_cmd, def_del_code);
+ init_token_key(command_names, extdef_math_code_cmd, extdef_math_code);
+ init_token_key(command_names, extdef_del_code_cmd, extdef_del_code);
+ init_token_key(command_names, def_family_cmd, def_family);
+ init_token_key(command_names, set_math_param_cmd, set_math_param);
+ init_token_key(command_names, set_font_cmd, set_font);
+ init_token_key(command_names, def_font_cmd, def_font);
+ init_token_key(command_names, def_lua_call_cmd, def_lua_call);
+ init_token_key(command_names, register_cmd, register);
+ init_token_key(command_names, assign_box_direction_cmd, assign_box_direction);
+ init_token_key(command_names, assign_box_dir_cmd, assign_box_dir);
+ init_token_key(command_names, assign_direction_cmd, assign_direction);
+ init_token_key(command_names, assign_dir_cmd, assign_dir);
+ init_token_key(command_names, advance_cmd, advance);
+ init_token_key(command_names, multiply_cmd, multiply);
+ init_token_key(command_names, divide_cmd, divide);
+ init_token_key(command_names, prefix_cmd, prefix);
+ init_token_key(command_names, let_cmd, let);
+ init_token_key(command_names, shorthand_def_cmd, shorthand_def);
+ init_token_key(command_names, read_to_cs_cmd, read_to_cs);
+ init_token_key(command_names, def_cmd, def);
+ init_token_key(command_names, set_box_cmd, set_box);
+ init_token_key(command_names, hyph_data_cmd, hyph_data);
+ init_token_key(command_names, set_interaction_cmd, set_interaction);
+ init_token_key(command_names, letterspace_font_cmd, letterspace_font);
+ init_token_key(command_names, expand_font_cmd, expand_font);
+ init_token_key(command_names, copy_font_cmd, copy_font);
+ init_token_key(command_names, set_font_id_cmd, set_font_id);
+ init_token_key(command_names, undefined_cs_cmd, undefined_cs);
+ init_token_key(command_names, expand_after_cmd, expand_after);
+ init_token_key(command_names, no_expand_cmd, no_expand);
+ init_token_key(command_names, input_cmd, input);
+ init_token_key(command_names, lua_expandable_call_cmd, lua_expandable_call);
+ init_token_key(command_names, lua_local_call_cmd, lua_local_call);
+ init_token_key(command_names, if_test_cmd, if_test);
+ init_token_key(command_names, fi_or_else_cmd, fi_or_else);
+ init_token_key(command_names, cs_name_cmd, cs_name);
+ init_token_key(command_names, convert_cmd, convert);
+ init_token_key(command_names, variable_cmd, variable);
+ init_token_key(command_names, feedback_cmd, feedback);
+ init_token_key(command_names, the_cmd, the);
+ init_token_key(command_names, combine_toks_cmd, combinetoks);
+ init_token_key(command_names, top_bot_mark_cmd, top_bot_mark);
+ init_token_key(command_names, call_cmd, call);
+ init_token_key(command_names, long_call_cmd, long_call);
+ init_token_key(command_names, outer_call_cmd, outer_call);
+ init_token_key(command_names, long_outer_call_cmd, long_outer_call);
+ init_token_key(command_names, end_template_cmd, end_template);
+ init_token_key(command_names, dont_expand_cmd, dont_expand);
+ init_token_key(command_names, glue_ref_cmd, glue_ref);
+ init_token_key(command_names, shape_ref_cmd, shape_ref);
+ init_token_key(command_names, box_ref_cmd, box_ref);
+ init_token_key(command_names, data_cmd, data);
+}
+
+int get_command_id(const char *s)
+{
+ int i;
+ for (i = 0; command_names[i].id != -1; i++) {
+ if (s == command_names[i].name)
+ return i;
+ }
+ return -1;
+}
+
+/*
+static int get_cur_cmd(lua_State * L)
+{
+ int r = 0;
+ size_t len = lua_rawlen(L, -1);
+ cur_cs = 0;
+ if (len == 3 || len == 2) {
+ r = 1;
+ lua_rawgeti(L, -1, 1);
+ cur_cmd = (int) lua_tointeger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ cur_chr = (halfword) lua_tointeger(L, -1);
+ if (len == 3) {
+ lua_rawgeti(L, -3, 3);
+ cur_cs = (halfword) lua_tointeger(L, -1);
+ }
+ lua_pop(L, (int) len);
+ if (cur_cs == 0)
+ cur_tok = token_val(cur_cmd, cur_chr);
+ else
+ cur_tok = cs_token_flag + cur_cs;
+ }
+ return r;
+}
+*/
+
+static int token_from_lua(lua_State * L)
+{
+ int cmd, chr;
+ int cs = 0;
+ size_t len = lua_rawlen(L, -1);
+ if (len == 3 || len == 2) {
+ lua_rawgeti(L, -1, 1);
+ cmd = (int) lua_tointeger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ chr = (int) lua_tointeger(L, -1);
+ if (len == 3) {
+ lua_rawgeti(L, -3, 3);
+ cs = (int) lua_tointeger(L, -1);
+ }
+ lua_pop(L, (int) len);
+ if (cs == 0) {
+ return token_val(cmd, chr);
+ } else {
+ return cs_token_flag + cs;
+ }
+ }
+ return -1;
+}
+
+/*
+static int get_cur_cs(lua_State * L)
+{
+ const char *s;
+ unsigned j;
+ size_t l;
+ int cs;
+ int save_nncs;
+ int ret;
+ ret = 0;
+ cur_cs = 0;
+ lua_getfield(L, -1, "name");
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ s = lua_tolstring(L, -1, &l);
+ if (l > 0) {
+ if ((last + (int) l) > buf_size)
+ check_buffer_overflow((last + (int) l));
+ for (j = 0; j < l; j++) {
+ buffer[(unsigned) last + 1 + j] = (packed_ASCII_code) * s++;
+ }
+ save_nncs = no_new_control_sequence;
+ no_new_control_sequence = false;
+ cs = id_lookup((last + 1), (int) l);
+ cur_tok = cs_token_flag + cs;
+ cur_cmd = eq_type(cs);
+ cur_chr = equiv(cs);
+ no_new_control_sequence = save_nncs;
+ ret = 1;
+ }
+ }
+ lua_pop(L, 1);
+ return ret;
+}
+*/
+
+void tokenlist_to_lua(lua_State * L, int p)
+{
+ int cmd, chr, cs;
+ int v;
+ int i = 1;
+ v = p;
+ while (v != null && v < (int) fix_mem_end) {
+ i++;
+ v = token_link(v);
+ }
+ i = 1;
+ lua_createtable(L, i, 0);
+ while (p != null && p < (int) fix_mem_end) {
+ if (token_info(p) >= cs_token_flag) {
+ cs = token_info(p) - cs_token_flag;
+ cmd = eq_type(cs);
+ chr = equiv(cs);
+ make_token_table(L, cmd, chr, cs);
+ } else {
+ cmd = token_cmd(token_info(p));
+ chr = token_chr(token_info(p));
+ make_token_table(L, cmd, chr, 0);
+ }
+ lua_rawseti(L, -2, i++);
+ p = token_link(p);
+ }
+}
+
+void tokenlist_to_luastring(lua_State * L, int p)
+{
+ int l;
+ char *s;
+ s = tokenlist_to_cstring(p, 1, &l);
+ lua_pushlstring(L, s, (size_t) l);
+ free(s);
+}
+
+int tokenlist_from_lua(lua_State * L)
+{
+ const char *s;
+ int tok, t;
+ size_t i, j;
+ halfword p, q, r;
+ r = get_avail();
+ token_info(r) = 0;
+ token_link(r) = null;
+ p = r;
+ t = lua_type(L, -1);
+ if (t == LUA_TTABLE) {
+ j = lua_rawlen(L, -1);
+ if (j > 0) {
+ for (i = 1; i <= j; i++) {
+ lua_rawgeti(L, -1, (int) i);
+ tok = token_from_lua(L);
+ if (tok >= 0) {
+ store_new_token(tok);
+ }
+ lua_pop(L, 1);
+ };
+ }
+ return r;
+ } else if (t == LUA_TSTRING) {
+ s = lua_tolstring(L, -1, &j);
+ for (i = 0; i < j; i++) {
+ if (s[i] == 32) {
+ tok = token_val(10, s[i]);
+ } else {
+ int j1 = (int) str2uni((const unsigned char *) (s + i));
+ i = i + (size_t) (utf8_size(j1) - 1);
+ tok = token_val(12, j1);
+ }
+ store_new_token(tok);
+ }
+ return r;
+ } else {
+ free_avail(r);
+ return null;
+ }
+}
+
+/*
+static void do_get_token_lua(int callback_id)
+{
+ while (1) {
+ if (!get_callback(Luas, callback_id)) {
+ get_next();
+ lua_pop(Luas, 2);
+ break;
+ }
+ if (lua_pcall(Luas, 0, 1, 0) != 0) {
+ tex_error(lua_tostring(Luas, -1), NULL);
+ lua_pop(Luas, 2);
+ break;
+ }
+ if (lua_istable(Luas, -1)) {
+ lua_rawgeti(Luas, -1, 1);
+ if (lua_istable(Luas, -1)) {
+ int p, q, r;
+ size_t i, j;
+ lua_pop(Luas, 1);
+ r = get_avail();
+ p = r;
+ j = lua_rawlen(Luas, -1);
+ if (j > 0) {
+ for (i = 1; i <= j; i++) {
+ lua_rawgeti(Luas, -1, (int) i);
+ if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
+ store_new_token(cur_tok);
+ }
+ lua_pop(Luas, 1);
+ }
+ }
+ if (p != r) {
+ p = token_link(r);
+ free_avail(r);
+ begin_token_list(p, inserted);
+ cur_input.nofilter_field = true;
+ get_next();
+ } else {
+ tex_error("error: illegal or empty token list returned", NULL);
+ }
+ lua_pop(Luas, 2);
+ break;
+ } else {
+ lua_pop(Luas, 1);
+ if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
+ lua_pop(Luas, 2);
+ break;
+ } else {
+ lua_pop(Luas, 2);
+ continue;
+ }
+ }
+ } else {
+ lua_pop(Luas, 2);
+ }
+ }
+ return;
+}
+*/
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatoken.w b/Build/source/texk/web2c/luatexdir/lua/luatoken.w
deleted file mode 100644
index e9740ffc676..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/luatoken.w
+++ /dev/null
@@ -1,424 +0,0 @@
-% luatoken.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"
-#include "lua/luatex-api.h"
-
-@ @c
-command_item command_names[] = {
- {"relax", relax_cmd, NULL},
- {"left_brace", left_brace_cmd, NULL},
- {"right_brace", right_brace_cmd, NULL},
- {"math_shift", math_shift_cmd, NULL},
- {"tab_mark", tab_mark_cmd, NULL},
- {"car_ret", car_ret_cmd, NULL},
- {"mac_param", mac_param_cmd, NULL},
- {"sup_mark", sup_mark_cmd, NULL},
- {"sub_mark", sub_mark_cmd, NULL},
- {"endv", endv_cmd, NULL},
- {"spacer", spacer_cmd, NULL},
- {"letter", letter_cmd, NULL},
- {"other_char", other_char_cmd, NULL},
- {"par_end", par_end_cmd, NULL},
- {"stop", stop_cmd, NULL},
- {"delim_num", delim_num_cmd, NULL},
- {"char_num", char_num_cmd, NULL},
- {"math_char_num", math_char_num_cmd, NULL},
- {"mark", mark_cmd, NULL},
- {"xray", xray_cmd, NULL},
- {"make_box", make_box_cmd, NULL},
- {"hmove", hmove_cmd, NULL},
- {"vmove", vmove_cmd, NULL},
- {"un_hbox", un_hbox_cmd, NULL},
- {"un_vbox", un_vbox_cmd, NULL},
- {"remove_item", remove_item_cmd, NULL},
- {"hskip", hskip_cmd, NULL},
- {"vskip", vskip_cmd, NULL},
- {"mskip", mskip_cmd, NULL},
- {"kern", kern_cmd, NULL},
- {"mkern", mkern_cmd, NULL},
- {"leader_ship", leader_ship_cmd, NULL},
- {"halign", halign_cmd, NULL},
- {"valign", valign_cmd, NULL},
- {"no_align", no_align_cmd, NULL},
- {"novrule", no_vrule_cmd, NULL},
- {"nohrule", no_hrule_cmd, NULL},
- {"vrule", vrule_cmd, NULL},
- {"hrule", hrule_cmd, NULL},
- {"insert", insert_cmd, NULL},
- {"vadjust", vadjust_cmd, NULL},
- {"ignore_spaces", ignore_spaces_cmd, NULL},
- {"after_assignment", after_assignment_cmd, NULL},
- {"after_group", after_group_cmd, NULL},
- {"break_penalty", break_penalty_cmd, NULL},
- {"start_par", start_par_cmd, NULL},
- {"ital_corr", ital_corr_cmd, NULL},
- {"accent", accent_cmd, NULL},
- {"math_accent", math_accent_cmd, NULL},
- {"discretionary", discretionary_cmd, NULL},
- {"eq_no", eq_no_cmd, NULL},
- {"left_right", left_right_cmd, NULL},
- {"math_comp", math_comp_cmd, NULL},
- {"limit_switch", limit_switch_cmd, NULL},
- {"above", above_cmd, NULL},
- {"math_style", math_style_cmd, NULL},
- {"math_choice", math_choice_cmd, NULL},
- {"non_script", non_script_cmd, NULL},
- {"vcenter", vcenter_cmd, NULL},
- {"case_shift", case_shift_cmd, NULL},
- {"message", message_cmd, NULL},
- {"normal", normal_cmd, NULL},
- {"extension", extension_cmd, NULL},
- {"option", option_cmd, NULL},
- {"in_stream", in_stream_cmd, NULL},
- {"begin_group", begin_group_cmd, NULL},
- {"end_group", end_group_cmd, NULL},
- {"omit", omit_cmd, NULL},
- {"ex_space", ex_space_cmd, NULL},
- {"boundary", boundary_cmd, NULL},
- {"radical", radical_cmd, NULL},
- {"super_sub_script", super_sub_script_cmd, NULL},
- {"no_super_sub_script", no_super_sub_script_cmd, NULL},
- {"math_shift_cs", math_shift_cs_cmd, NULL},
- {"end_cs_name", end_cs_name_cmd, NULL},
- {"char_ghost", char_ghost_cmd, NULL},
- {"assign_local_box", assign_local_box_cmd, NULL},
- {"char_given", char_given_cmd, NULL},
- {"math_given", math_given_cmd, NULL},
- {"xmath_given", xmath_given_cmd, NULL},
- {"last_item", last_item_cmd, NULL},
- {"toks_register", toks_register_cmd, NULL},
- {"assign_toks", assign_toks_cmd, NULL},
- {"assign_int", assign_int_cmd, NULL},
- {"assign_attr", assign_attr_cmd, NULL},
- {"assign_dimen", assign_dimen_cmd, NULL},
- {"assign_glue", assign_glue_cmd, NULL},
- {"assign_mu_glue", assign_mu_glue_cmd, NULL},
- {"assign_font_dimen", assign_font_dimen_cmd, NULL},
- {"assign_font_int", assign_font_int_cmd, NULL},
- {"assign_hang_indent", assign_hang_indent_cmd, NULL},
- {"set_aux", set_aux_cmd, NULL},
- {"set_prev_graf", set_prev_graf_cmd, NULL},
- {"set_page_dimen", set_page_dimen_cmd, NULL},
- {"set_page_int", set_page_int_cmd, NULL},
- {"set_box_dimen", set_box_dimen_cmd, NULL},
- {"set_tex_shape", set_tex_shape_cmd, NULL},
- {"set_etex_shape", set_etex_shape_cmd, NULL},
- {"def_char_code", def_char_code_cmd, NULL},
- {"def_del_code", def_del_code_cmd, NULL},
- {"extdef_math_code", extdef_math_code_cmd, NULL},
- {"extdef_del_code", extdef_del_code_cmd, NULL},
- {"def_family", def_family_cmd, NULL},
- {"set_math_param", set_math_param_cmd, NULL},
- {"set_font", set_font_cmd, NULL},
- {"def_font", def_font_cmd, NULL},
- {"register", register_cmd, NULL},
- {"assign_box_dir", assign_box_dir_cmd, NULL},
- {"assign_dir", assign_dir_cmd, NULL},
- {"advance", advance_cmd, NULL},
- {"multiply", multiply_cmd, NULL},
- {"divide", divide_cmd, NULL},
- {"prefix", prefix_cmd, NULL},
- {"let", let_cmd, NULL},
- {"shorthand_def", shorthand_def_cmd, NULL},
- {"read_to_cs", read_to_cs_cmd, NULL},
- {"def", def_cmd, NULL},
- {"set_box", set_box_cmd, NULL},
- {"hyph_data", hyph_data_cmd, NULL},
- {"set_interaction", set_interaction_cmd, NULL},
- {"letterspace_font", letterspace_font_cmd, NULL},
- {"expand_font",expand_font_cmd, NULL},
- {"copy_font", copy_font_cmd, NULL},
- {"set_font_id", set_font_id_cmd, NULL},
- {"undefined_cs", undefined_cs_cmd, NULL},
- {"expand_after", expand_after_cmd, NULL},
- {"no_expand", no_expand_cmd, NULL},
- {"input", input_cmd, NULL},
- {"if_test", if_test_cmd, NULL},
- {"fi_or_else", fi_or_else_cmd, NULL},
- {"cs_name", cs_name_cmd, NULL},
- {"convert", convert_cmd, NULL},
- {"variable", variable_cmd, NULL},
- {"feedback", feedback_cmd, NULL},
- {"the", the_cmd, NULL},
- {"combinetoks", combine_toks_cmd, NULL},
- {"top_bot_mark", top_bot_mark_cmd, NULL},
- {"call", call_cmd, NULL},
- {"long_call", long_call_cmd, NULL},
- {"outer_call", outer_call_cmd, NULL},
- {"long_outer_call", long_outer_call_cmd, NULL},
- {"end_template", end_template_cmd, NULL},
- {"dont_expand", dont_expand_cmd, NULL},
- {"glue_ref", glue_ref_cmd, NULL},
- {"shape_ref", shape_ref_cmd, NULL},
- {"box_ref", box_ref_cmd, NULL},
- {"data", data_cmd, NULL},
- {NULL, 0, NULL}
-};
-
-
-@ @c
-int get_command_id(const char *s)
-{
- int i;
- int cmd = -1;
- for (i = 0; command_names[i].cmd_name != NULL; i++) {
- if (strcmp(s, command_names[i].cmd_name) == 0)
- break;
- }
- if (command_names[i].cmd_name != NULL) {
- cmd = i;
- }
- return cmd;
-}
-
-/*
-static int get_cur_cmd(lua_State * L)
-{
- int r = 0;
- size_t len = lua_rawlen(L, -1);
- cur_cs = 0;
- if (len == 3 || len == 2) {
- r = 1;
- lua_rawgeti(L, -1, 1);
- cur_cmd = (int) lua_tointeger(L, -1);
- lua_rawgeti(L, -2, 2);
- cur_chr = (halfword) lua_tointeger(L, -1);
- if (len == 3) {
- lua_rawgeti(L, -3, 3);
- cur_cs = (halfword) lua_tointeger(L, -1);
- }
- lua_pop(L, (int) len);
- if (cur_cs == 0)
- cur_tok = token_val(cur_cmd, cur_chr);
- else
- cur_tok = cs_token_flag + cur_cs;
- }
- return r;
-}
-*/
-
-@ @c
-static int token_from_lua(lua_State * L)
-{
- int cmd, chr;
- int cs = 0;
- size_t len = lua_rawlen(L, -1);
- if (len == 3 || len == 2) {
- lua_rawgeti(L, -1, 1);
- cmd = (int) lua_tointeger(L, -1);
- lua_rawgeti(L, -2, 2);
- chr = (int) lua_tointeger(L, -1);
- if (len == 3) {
- lua_rawgeti(L, -3, 3);
- cs = (int) lua_tointeger(L, -1);
- }
- lua_pop(L, (int) len);
- if (cs == 0) {
- return token_val(cmd, chr);
- } else {
- return cs_token_flag + cs;
- }
- }
- return -1;
-}
-
-/*
-static int get_cur_cs(lua_State * L)
-{
- const char *s;
- unsigned j;
- size_t l;
- int cs;
- int save_nncs;
- int ret;
- ret = 0;
- cur_cs = 0;
- lua_getfield(L, -1, "name");
- if (lua_type(L, -1) == LUA_TSTRING) {
- s = lua_tolstring(L, -1, &l);
- if (l > 0) {
- if ((last + (int) l) > buf_size)
- check_buffer_overflow((last + (int) l));
- for (j = 0; j < l; j++) {
- buffer[(unsigned) last + 1 + j] = (packed_ASCII_code) * s++;
- }
- save_nncs = no_new_control_sequence;
- no_new_control_sequence = false;
- cs = id_lookup((last + 1), (int) l);
- cur_tok = cs_token_flag + cs;
- cur_cmd = eq_type(cs);
- cur_chr = equiv(cs);
- no_new_control_sequence = save_nncs;
- ret = 1;
- }
- }
- lua_pop(L, 1);
- return ret;
-}
-*/
-
-@ @c
-void tokenlist_to_lua(lua_State * L, int p)
-{
- int cmd, chr, cs;
- int v;
- int i = 1;
- v = p;
- while (v != null && v < (int) fix_mem_end) {
- i++;
- v = token_link(v);
- }
- i = 1;
- lua_createtable(L, i, 0);
- while (p != null && p < (int) fix_mem_end) {
- if (token_info(p) >= cs_token_flag) {
- cs = token_info(p) - cs_token_flag;
- cmd = eq_type(cs);
- chr = equiv(cs);
- make_token_table(L, cmd, chr, cs);
- } else {
- cmd = token_cmd(token_info(p));
- chr = token_chr(token_info(p));
- make_token_table(L, cmd, chr, 0);
- }
- lua_rawseti(L, -2, i++);
- p = token_link(p);
- }
-}
-
-@ @c
-void tokenlist_to_luastring(lua_State * L, int p)
-{
- int l;
- char *s;
- s = tokenlist_to_cstring(p, 1, &l);
- lua_pushlstring(L, s, (size_t) l);
- free(s);
-}
-
-
-@ @c
-int tokenlist_from_lua(lua_State * L)
-{
- const char *s;
- int tok, t;
- size_t i, j;
- halfword p, q, r;
- r = get_avail();
- token_info(r) = 0; /* ref count */
- token_link(r) = null;
- p = r;
- t = lua_type(L, -1);
- if (t == LUA_TTABLE) {
- j = lua_rawlen(L, -1);
- if (j > 0) {
- for (i = 1; i <= j; i++) {
- lua_rawgeti(L, -1, (int) i);
- tok = token_from_lua(L);
- if (tok >= 0) {
- store_new_token(tok);
- }
- lua_pop(L, 1);
- };
- }
- return r;
- } else if (t == LUA_TSTRING) {
- s = lua_tolstring(L, -1, &j);
- for (i = 0; i < j; i++) {
- if (s[i] == 32) {
- tok = token_val(10, s[i]);
- } else {
- int j1 = (int) str2uni((const unsigned char *) (s + i));
- i = i + (size_t) (utf8_size(j1) - 1);
- tok = token_val(12, j1);
- }
- store_new_token(tok);
- }
- return r;
- } else {
- free_avail(r);
- return null;
- }
-}
-
-/*
-
-static void do_get_token_lua(int callback_id)
-{
- while (1) {
- if (!get_callback(Luas, callback_id)) {
- get_next();
- lua_pop(Luas, 2);
- break;
- }
- if (lua_pcall(Luas, 0, 1, 0) != 0) {
- tex_error(lua_tostring(Luas, -1), NULL);
- lua_pop(Luas, 2);
- break;
- }
- if (lua_istable(Luas, -1)) {
- lua_rawgeti(Luas, -1, 1);
- if (lua_istable(Luas, -1)) {
- int p, q, r;
- size_t i, j;
- lua_pop(Luas, 1);
- r = get_avail();
- p = r;
- j = lua_rawlen(Luas, -1);
- if (j > 0) {
- for (i = 1; i <= j; i++) {
- lua_rawgeti(Luas, -1, (int) i);
- if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
- store_new_token(cur_tok);
- }
- lua_pop(Luas, 1);
- }
- }
- if (p != r) {
- p = token_link(r);
- free_avail(r);
- begin_token_list(p, inserted);
- cur_input.nofilter_field = true;
- get_next();
- } else {
- tex_error("error: illegal or empty token list returned", NULL);
- }
- lua_pop(Luas, 2);
- break;
- } else {
- lua_pop(Luas, 1);
- if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
- lua_pop(Luas, 2);
- break;
- } else {
- lua_pop(Luas, 2);
- continue;
- }
- }
- } else {
- lua_pop(Luas, 2);
- }
- }
- return;
-}
-
-*/
diff --git a/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c b/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
new file mode 100644
index 00000000000..f1713ae0e6e
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
@@ -0,0 +1,115 @@
+/*
+
+mplibstuff.w
+
+Copyright 2017 LuaTeX team <bugs@@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 \PNG\ and \SVG\ backends are not available in \LUATEX, because it's complex
+to manage the math formulas at run time. In this respect \POSTSCRIPT\ and the
+highlevel |objects| are better, and they are the standard way. Another problem is
+how to emit the warning: the |normal_warning| function is not available when
+\LUATEX\ is called as \LUA\ only.
+
+*/
+
+#include <stdio.h>
+
+extern void normal_warning(const char *t, const char *p);
+
+extern int lua_only;
+
+#define mplibstuff_message(MSG) do { \
+ if (lua_only) { \
+ fprintf(stdout,"mplib: " #MSG " not available.\n"); \
+ } else { \
+ normal_warning("mplib", #MSG " not available."); \
+ } \
+} while (0)
+
+void mp_png_backend_initialize (void *mp);
+void mp_png_backend_free (void *mp);
+int mp_png_gr_ship_out (void *hh, void *options, int standalone);
+int mp_png_ship_out (void *hh, const char *options);
+
+void mp_svg_backend_initialize (void *mp);
+void mp_svg_backend_free (void *mp);
+int mp_svg_ship_out (void *hh, int prologues);
+int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone);
+
+void *mp_initialize_binary_math(void *mp);
+
+
+void mp_png_backend_initialize (void *mp) { return; }
+void mp_png_backend_free (void *mp) { return; }
+int mp_png_gr_ship_out (void *hh, void *options, int standalone) { mplibstuff_message(png backend); return 1; }
+int mp_png_ship_out (void *hh, const char *options) { mplibstuff_message(png backend); return 1; }
+
+void mp_svg_backend_initialize (void *mp) { return; }
+void mp_svg_backend_free (void *mp) { return; }
+int mp_svg_ship_out (void *hh, int prologues) { mplibstuff_message(svg bakend); return 1; }
+int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone) { mplibstuff_message(svg backend); return 1; }
+
+
+void *mp_initialize_binary_math(void *mp) {mplibstuff_message(math binary);return NULL; }
+
+const char* cairo_version_string (void);
+const char* mpfr_get_version(void);
+const char* pixman_version_string (void);
+
+
+#define CAIRO_VERSION_STRING "CAIRO NOT AVAILABLE"
+const char *COMPILED_CAIRO_VERSION_STRING = CAIRO_VERSION_STRING;
+
+#define MPFR_VERSION_STRING "MPFR NOT AVAILABLE"
+const char *COMPILED_MPFR_VERSION_STRING = MPFR_VERSION_STRING;
+
+
+#define __GNU_MP_VERSION -1
+#define __GNU_MP_VERSION_MINOR -1
+#define __GNU_MP_VERSION_PATCHLEVEL -1
+int COMPILED__GNU_MP_VERSION = __GNU_MP_VERSION ;
+int COMPILED__GNU_MP_VERSION_MINOR = __GNU_MP_VERSION_MINOR ;
+int COMPILED__GNU_MP_VERSION_PATCHLEVEL = __GNU_MP_VERSION_PATCHLEVEL ;
+const char * const COMPILED_gmp_version="GMP NOT AVAILABLE";
+
+#define PIXMAN_VERSION_STRING "PIXMAN NOT AVAILABLE"
+const char *COMPILED_PIXMAN_VERSION_STRING = PIXMAN_VERSION_STRING;
+
+const char* cairo_version_string (void)
+{
+ return CAIRO_VERSION_STRING;
+}
+
+const char* mpfr_get_version(void)
+{
+ return MPFR_VERSION_STRING;
+}
+
+const char* pixman_version_string (void)
+{
+ return PIXMAN_VERSION_STRING;
+}
+
+char png_libpng_ver[] = "PNG NOT AVAILABLE";
+
+
+
diff --git a/Build/source/texk/web2c/luatexdir/lua/mplibstuff.w b/Build/source/texk/web2c/luatexdir/lua/mplibstuff.w
deleted file mode 100644
index 3104a287007..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/mplibstuff.w
+++ /dev/null
@@ -1,93 +0,0 @@
-% mplibstuff.w
-%
-% Copyright 2017 LuaTeX team <bugs@@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/>.
-
-@ PNG and SVG backends are not available in \LuaTeX, because it's complex
-to manage the math formulas at run time. In this respect |PostScript| and the highlevel |objects|
-are better, and they are the standard way. Another problem is how to emit the warning:
-the |normal\_warning| function is not available when \LuaTeX\ is called as LUA only.
-
-
-
-@c
-#include <stdio.h>
-
-extern void normal_warning(const char *t, const char *p);
-extern int lua_only;
-#define mplibstuff_message(BACKEND) do { \
- if (lua_only) { \
- fprintf(stdout,"mplib: " #BACKEND " backend not available.\n"); \
- } else { \
- normal_warning("mplib", #BACKEND " backend not available."); \
- } \
-} while (0)
-
-
-@ @c
-void mp_png_backend_initialize (void *mp);
-void mp_png_backend_free (void *mp);
-int mp_png_gr_ship_out (void *hh, void *options, int standalone);
-int mp_png_ship_out (void *hh, const char *options);
-
-@ @c
-void mp_svg_backend_initialize (void *mp);
-void mp_svg_backend_free (void *mp);
-int mp_svg_ship_out (void *hh, int prologues);
-int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone);
-
-@ @c
-void mp_png_backend_initialize (void *mp) {return; } /*{mplibstuff_message(1png);return;}*/
-void mp_png_backend_free (void *mp) {return; } /*{mplibstuff_message(png);return;}*/
-int mp_png_gr_ship_out (void *hh, void *options, int standalone) {mplibstuff_message(png);return 1;}
-int mp_png_ship_out (void *hh, const char *options) {mplibstuff_message(png);return 1;}
-
-@ @c
-void mp_svg_backend_initialize (void *mp) {return;} /*{mplibstuff_message(svg);return;}*/
-void mp_svg_backend_free (void *mp) {return;} /*{mplibstuff_message(svg);return;}*/
-int mp_svg_ship_out (void *hh, int prologues) {mplibstuff_message(svg);return 1;}
-int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone) {mplibstuff_message(svg);return 1;}
-
-@ @c
-const char*
-cairo_version_string (void);
-const char*
-pixman_version_string (void);
-#define CAIRO_VERSION_STRING "CAIRO NOT AVAILABLE"
-const char *COMPILED_CAIRO_VERSION_STRING = CAIRO_VERSION_STRING;
-#define PIXMAN_VERSION_STRING "PIXMAN NOT AVAILABLE"
-const char *COMPILED_PIXMAN_VERSION_STRING = PIXMAN_VERSION_STRING;
-
-const char*
-cairo_version_string (void)
-{
- return CAIRO_VERSION_STRING;
-}
-
-const char*
-pixman_version_string (void)
-{
- return PIXMAN_VERSION_STRING;
-}
-
-
-
-
-
-@ @c
-char png_libpng_ver[] = "PNG NOT AVAILABLE";
-
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluac.c b/Build/source/texk/web2c/luatexdir/lua/texluac.c
new file mode 100644
index 00000000000..61016cfdb5b
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/texluac.c
@@ -0,0 +1,532 @@
+/*
+
+texluac.w
+
+Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved.
+Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+This file is part of LuaTeX.
+
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define luac_c
+#define LUA_CORE
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+
+#include "lua/luatex-api.h"
+
+static void PrintFunction(const Proto* f, int full);
+
+#define luaU_print PrintFunction
+
+/*tex A fix for non-gcc compilation: */
+
+#if !defined(__GNUC__) || (__GNUC__ < 2)
+# define __attribute__(x)
+#endif
+
+/*tex default program name */
+
+#define PROGNAME "texluac"
+
+/*tex default output file */
+
+#define OUTPUT PROGNAME ".out"
+
+/*tex list bytecodes? */
+
+static int listing = 0;
+
+/*tex dump bytecodes? */
+
+static int dumping = 1;
+
+/*tex strip debug information? */
+
+static int stripping = 0;
+
+/*tex default output file name */
+
+static char Output[] = { OUTPUT };
+
+/*tex actual output file name */
+
+static const char *output = Output;
+
+/*tex actual program name */
+
+static const char *progname = PROGNAME;
+
+__attribute__ ((noreturn))
+static void fatal(const char *message) {
+ fprintf(stderr,"%s: %s\n",progname,message);
+ exit(EXIT_FAILURE);
+}
+
+__attribute__ ((noreturn))
+static void cannot(const char *what) {
+ fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
+ exit(EXIT_FAILURE);
+}
+
+__attribute__ ((noreturn))
+static void usage(const char* message)
+{
+ if (*message=='-')
+ fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
+ else
+ fprintf(stderr,"%s: %s\n",progname,message);
+ fprintf(stderr,
+ "usage: %s [options] [filenames]\n"
+ "Available options are:\n"
+ " -l list (use -l -l for full listing)\n"
+ " -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
+ " -p parse only\n"
+ " -s strip debug information\n"
+ " -v show version information\n"
+ " -- stop handling options\n"
+ " - stop handling options and process stdin\n"
+ ,progname,Output);
+ exit(EXIT_FAILURE);
+}
+
+#define IS(s) (strcmp(argv[i],s)==0)
+
+static int doargs(int argc, char* argv[])
+{
+ int i;
+ int version=0;
+ if (argv[0]!=NULL && *argv[0]!=0)
+ progname=argv[0];
+ for (i=1; i<argc; i++) {
+ if (*argv[i]!='-') {
+ /* end of options; keep it */
+ break;
+ } else if (IS("--")) {
+ /* end of options; skip it */
+ ++i;
+ if (version) ++version;
+ break;
+ } else if (IS("-")) {
+ /* end of options; use stdin */
+ break;
+ } else if (IS("-l")) {
+ /* list */
+ ++listing;
+ } else if (IS("-o")) {
+ /* output file */
+ output=argv[++i];
+ if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
+ usage(LUA_QL("-o") " needs argument");
+ if (IS("-"))
+ output=NULL;
+ } else if (IS("-p")) {
+ /* parse only */
+ dumping=0;
+ } else if (IS("-s")) {
+ /* strip debug information */
+ stripping=1;
+ } else if (IS("-v")) {
+ /* show version */
+ ++version;
+ } else {
+ /* unknown option */
+ usage(argv[i]);
+ }
+ }
+ if (i==argc && (listing || !dumping)) {
+ dumping=0;
+ argv[--i]=Output;
+ }
+ if (version) {
+ printf("%s\n",LUA_COPYRIGHT);
+ if (version==argc-1)
+ exit(EXIT_SUCCESS);
+ }
+ return i;
+}
+
+#define FUNCTION "(function()end)();"
+
+static const char* reader(lua_State *L, void *ud, size_t *size)
+{
+ UNUSED(L);
+ if ((*(int*)ud)--) {
+ *size=sizeof(FUNCTION)-1;
+ return FUNCTION;
+ } else {
+ *size=0;
+ return NULL;
+ }
+}
+
+#define toproto(L,i) getproto(L->top+(i))
+
+static const Proto* combine(lua_State* L, int n)
+{
+ if (n==1) {
+ return toproto(L,-1);
+ } else {
+ Proto* f;
+ int i=n;
+ if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ f=toproto(L,-1);
+ for (i=0; i<n; i++) {
+ f->p[i]=toproto(L,i-n-1);
+ if (f->p[i]->sizeupvalues>0)
+ f->p[i]->upvalues[0].instack=0;
+ }
+ f->sizelineinfo=0;
+ return f;
+ }
+}
+
+static int writer(lua_State* L, const void* p, size_t size, void* u)
+{
+ UNUSED(L);
+ return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
+}
+
+static int pmain(lua_State* L)
+{
+ int argc=(int)lua_tointeger(L,1);
+ char** argv=(char**)lua_touserdata(L,2);
+ const Proto* f;
+ int i;
+ if (!lua_checkstack(L,argc))
+ fatal("too many input files");
+ /*tex
+ Open standard libraries: we need to to this to keep the symbol
+ |luaL_openlibs|.
+ */
+ luaL_checkversion(L);
+ /*tex stop collector during initialization */
+ lua_gc(L, LUA_GCSTOP, 0);
+ /*tex open libraries */
+ luaL_openlibs(L);
+ lua_gc(L, LUA_GCRESTART, 0);
+ for (i=0; i<argc; i++) {
+ const char* filename=IS("-") ? NULL : argv[i];
+ if (luaL_loadfile(L,filename)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ }
+ f=combine(L,argc);
+ if (listing)
+ luaU_print(f,listing>1);
+ if (dumping) {
+ FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
+ if (D==NULL)
+ cannot("open");
+ lua_lock(L);
+ luaU_dump(L,f,writer,D,stripping);
+ lua_unlock(L);
+ if (ferror(D))
+ cannot("write");
+ if (fclose(D))
+ cannot("close");
+ }
+ return 0;
+}
+
+int luac_main(int ac, char *av[])
+{
+ lua_State *L;
+ int i = doargs(ac, av);
+ ac -= i;
+ av += i;
+ if (ac <= 0)
+ usage("no input files given");
+ L=luaL_newstate();
+ if (L == NULL)
+ fatal("not enough memory for state");
+ lua_pushcfunction(L,&pmain);
+ lua_pushinteger(L,ac);
+ lua_pushlightuserdata(L,av);
+ if (lua_pcall(L,2,0,0)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ lua_close(L);
+ return EXIT_SUCCESS;
+}
+
+/*
+ See Copyright Notice in |lua.h|.
+*/
+
+#define VOID(p) ((const void*)(p))
+
+#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
+#define TSVALUE(o) rawtsvalue(o)
+#endif
+#if (LUA_VERSION_NUM == 503)
+#define TSVALUE(o) tsvalue(o)
+#endif
+
+static void PrintString(const TString* ts)
+{
+ const char* s=getstr(ts);
+ size_t i,n;
+#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
+ n=ts->tsv.len;
+#endif
+#if (LUA_VERSION_NUM == 503)
+ n=(ts->tt == LUA_TSHRSTR ? ts->shrlen : ts->u.lnglen);
+#endif
+ printf("%c",'"');
+ for (i=0; i<n; i++) {
+ int c=(int)(unsigned char)s[i];
+ switch (c) {
+ case '"':
+ printf("\\\"");
+ break;
+ case '\\':
+ printf("\\\\");
+ break;
+ case '\a':
+ printf("\\a");
+ break;
+ case '\b':
+ printf("\\b");
+ break;
+ case '\f':
+ printf("\\f");
+ break;
+ case '\n':
+ printf("\\n");
+ break;
+ case '\r':
+ printf("\\r");
+ break;
+ case '\t':
+ printf("\\t");
+ break;
+ case '\v':
+ printf("\\v");
+ break;
+ default :
+ if (isprint(c))
+ printf("%c",c);
+ else
+ printf("\\%03d",c);
+ break;
+ }
+ }
+ printf("%c",'"');
+}
+
+static void PrintConstant(const Proto* f, int i)
+{
+ const TValue* o=&f->k[i];
+ switch (ttype(o)) {
+ case LUA_TNIL:
+ printf("nil");
+ break;
+ case LUA_TBOOLEAN:
+ printf(bvalue(o) ? "true" : "false");
+ break;
+ case LUA_TNUMBER:
+ printf(LUA_NUMBER_FMT,nvalue(o));
+ break;
+ case LUA_TSTRING:
+ PrintString(TSVALUE(o));
+ break;
+ default:
+ /*tex This cannot happen. */
+ printf("? type=%d",ttype(o));
+ break;
+ }
+}
+
+#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
+#define MYK(x) (-1-(x))
+
+static void PrintCode(const Proto* f)
+{
+ const Instruction* code=f->code;
+ int pc,n=f->sizecode;
+ for (pc=0; pc<n; pc++) {
+ Instruction i=code[pc];
+ OpCode o=GET_OPCODE(i);
+ int a=GETARG_A(i);
+ int b=GETARG_B(i);
+ int c=GETARG_C(i);
+ int ax=GETARG_Ax(i);
+ int bx=GETARG_Bx(i);
+ int sbx=GETARG_sBx(i);
+ int line=getfuncline(f,pc);
+ printf("\t%d\t",pc+1);
+ if (line>0)
+ printf("[%d]\t",line);
+ else
+ printf("[-]\t");
+ printf("%-9s\t",luaP_opnames[o]);
+ switch (getOpMode(o)) {
+ case iABC:
+ printf("%d",a);
+ if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
+ if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
+ break;
+ case iABx:
+ printf("%d",a);
+ if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
+ if (getBMode(o)==OpArgU) printf(" %d",bx);
+ break;
+ case iAsBx:
+ printf("%d %d",a,sbx);
+ break;
+ case iAx:
+ printf("%d",MYK(ax));
+ break;
+ }
+ switch (o) {
+ case OP_LOADK:
+ printf("\t; "); PrintConstant(f,bx);
+ break;
+ case OP_GETUPVAL:
+ case OP_SETUPVAL:
+ printf("\t; %s",UPVALNAME(b));
+ break;
+ case OP_GETTABUP:
+ printf("\t; %s",UPVALNAME(b));
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABUP:
+ printf("\t; %s",UPVALNAME(a));
+ if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_GETTABLE:
+ case OP_SELF:
+ if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABLE:
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_POW:
+ case OP_EQ:
+ case OP_LT:
+ case OP_LE:
+ if (ISK(b) || ISK(c)) {
+ printf("\t; ");
+ if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
+ printf(" ");
+ if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
+ }
+ break;
+ case OP_JMP:
+ case OP_FORLOOP:
+ case OP_FORPREP:
+ case OP_TFORLOOP:
+ printf("\t; to %d",sbx+pc+2);
+ break;
+ case OP_CLOSURE:
+ printf("\t; %p",VOID(f->p[bx]));
+ break;
+ case OP_SETLIST:
+ if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
+ break;
+ case OP_EXTRAARG:
+ printf("\t; "); PrintConstant(f,ax);
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+}
+
+#define SS(x) ((x==1)?"":"s")
+#define S(x) (int)(x),SS(x)
+
+static void PrintHeader(const Proto* f)
+{
+ const char* s=f->source ? getstr(f->source) : "=?";
+ if (*s=='@' || *s=='=')
+ s++;
+ else if (*s==LUA_SIGNATURE[0])
+ s="(bstring)";
+ else
+ s="(string)";
+ printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
+ (f->linedefined==0)?"main":"function",s,
+ f->linedefined,f->lastlinedefined,
+ S(f->sizecode),VOID(f));
+ printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
+ (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
+ S(f->maxstacksize),S(f->sizeupvalues));
+ printf("%d local%s, %d constant%s, %d function%s\n",
+ S(f->sizelocvars),S(f->sizek),S(f->sizep));
+}
+
+static void PrintDebug(const Proto* f)
+{
+ int i,n;
+ n=f->sizek;
+ printf("constants (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t",i+1);
+ PrintConstant(f,i);
+ printf("\n");
+ }
+ n=f->sizelocvars;
+ printf("locals (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
+ }
+ n=f->sizeupvalues;
+ printf("upvalues (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
+ }
+}
+
+static void PrintFunction(const Proto* f, int full)
+{
+ int i,n=f->sizep;
+ PrintHeader(f);
+ PrintCode(f);
+ if (full)
+ PrintDebug(f);
+ for (i=0; i<n; i++)
+ PrintFunction(f->p[i],full);
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluac.w b/Build/source/texk/web2c/luatexdir/lua/texluac.w
deleted file mode 100644
index 424c74c77fd..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/texluac.w
+++ /dev/null
@@ -1,495 +0,0 @@
-% texluac.w
-%
-% Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved.
-% Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
-%
-% Permission is hereby granted, free of charge, to any person obtaining
-% a copy of this software and associated documentation files (the
-% "Software"), to deal in the Software without restriction, including
-% without limitation the rights to use, copy, modify, merge, publish,
-% distribute, sublicense, and/or sell copies of the Software, and to
-% permit persons to whom the Software is furnished to do so, subject to
-% the following conditions:
-%
-% The above copyright notice and this permission notice shall be
-% included in all copies or substantial portions of the Software.
-%
-% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-% IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-% CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-% TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-% SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-%
-% This file is part of LuaTeX.
-
-@ @c
-
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define luac_c
-#define LUA_CORE
-
-#include "lua.h"
-#include "lauxlib.h"
-
-#include "ldebug.h"
-#include "ldo.h"
-#include "lfunc.h"
-#include "lmem.h"
-#include "lobject.h"
-#include "lopcodes.h"
-#include "lstring.h"
-#include "lundump.h"
-
-#include "lua/luatex-api.h"
-
-static void PrintFunction(const Proto* f, int full);
-#define luaU_print PrintFunction
-
-@ @c
-/* fix for non-gcc compilation: */
-#if !defined(__GNUC__) || (__GNUC__ < 2)
-# define __attribute__(x)
-#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
-
-@ @c
-#define PROGNAME "texluac" /* default program name */
-#define OUTPUT PROGNAME ".out" /* default output file */
-
-static int listing=0; /* list bytecodes? */
-static int dumping = 1; /* dump bytecodes? */
-static int stripping = 0; /* strip debug information? */
-static char Output[] = { OUTPUT }; /* default output file name */
-
-static const char *output = Output; /* actual output file name */
-static const char *progname = PROGNAME; /* actual program name */
-
-@ @c
-__attribute__ ((noreturn))
-static void fatal(const char *message)
-{
- fprintf(stderr,"%s: %s\n",progname,message);
- exit(EXIT_FAILURE);
-}
-
-@ @c
-__attribute__ ((noreturn))
-static void cannot(const char *what)
-{
- fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
- exit(EXIT_FAILURE);
-}
-
-@ @c
-__attribute__ ((noreturn))
-static void usage(const char* message)
-{
- if (*message=='-')
- fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
- else
- fprintf(stderr,"%s: %s\n",progname,message);
- fprintf(stderr,
- "usage: %s [options] [filenames]\n"
- "Available options are:\n"
- " -l list (use -l -l for full listing)\n"
- " -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
- " -p parse only\n"
- " -s strip debug information\n"
- " -v show version information\n"
- " -- stop handling options\n"
- " - stop handling options and process stdin\n"
- ,progname,Output);
- exit(EXIT_FAILURE);
-}
-
-@ @c
-#define IS(s) (strcmp(argv[i],s)==0)
-
-static int doargs(int argc, char* argv[])
-{
- int i;
- int version=0;
- if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
- for (i=1; i<argc; i++)
- {
- if (*argv[i]!='-') /* end of options; keep it */
- break;
- else if (IS("--")) /* end of options; skip it */
- {
- ++i;
- if (version) ++version;
- break;
- }
- else if (IS("-")) /* end of options; use stdin */
- break;
- else if (IS("-l")) /* list */
- ++listing;
- else if (IS("-o")) /* output file */
- {
- output=argv[++i];
- if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
- usage(LUA_QL("-o") " needs argument");
- if (IS("-")) output=NULL;
- }
- else if (IS("-p")) /* parse only */
- dumping=0;
- else if (IS("-s")) /* strip debug information */
- stripping=1;
- else if (IS("-v")) /* show version */
- ++version;
- else /* unknown option */
- usage(argv[i]);
- }
- if (i==argc && (listing || !dumping))
- {
- dumping=0;
- argv[--i]=Output;
- }
- if (version)
- {
- printf("%s\n",LUA_COPYRIGHT);
- if (version==argc-1) exit(EXIT_SUCCESS);
- }
- return i;
-}
-
-@ @c
-#define FUNCTION "(function()end)();"
-
-static const char* reader(lua_State *L, void *ud, size_t *size)
-{
- UNUSED(L);
- if ((*(int*)ud)--)
- {
- *size=sizeof(FUNCTION)-1;
- return FUNCTION;
- }
- else
- {
- *size=0;
- return NULL;
- }
-}
-
-#define toproto(L,i) getproto(L->top+(i))
-
-static const Proto* combine(lua_State* L, int n)
-{
- if (n==1)
- return toproto(L,-1);
- else
- {
- Proto* f;
- int i=n;
- if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
- f=toproto(L,-1);
- for (i=0; i<n; i++)
- {
- f->p[i]=toproto(L,i-n-1);
- if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
- }
- f->sizelineinfo=0;
- return f;
- }
-}
-
-@ @c
-static int writer(lua_State* L, const void* p, size_t size, void* u)
-{
- UNUSED(L);
- return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
-}
-
-static int pmain(lua_State* L)
-{
- int argc=(int)lua_tointeger(L,1);
- char** argv=(char**)lua_touserdata(L,2);
- const Proto* f;
- int i;
- if (!lua_checkstack(L,argc)) fatal("too many input files");
- /* open standard libraries: */
- /* we need to to this to keep */
- /* the symbol luaL_openlibs */
- luaL_checkversion(L);
- lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
- luaL_openlibs(L); /* open libraries */
- lua_gc(L, LUA_GCRESTART, 0);
- for (i=0; i<argc; i++)
- {
- const char* filename=IS("-") ? NULL : argv[i];
- if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1));
- }
- f=combine(L,argc);
- if (listing) luaU_print(f,listing>1);
- if (dumping)
- {
- FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
- if (D==NULL) cannot("open");
- lua_lock(L);
- luaU_dump(L,f,writer,D,stripping);
- lua_unlock(L);
- if (ferror(D)) cannot("write");
- if (fclose(D)) cannot("close");
- }
- return 0;
-}
-
-@ @c
-int luac_main(int ac, char *av[])
-{
- lua_State *L;
- int i = doargs(ac, av);
- ac -= i;
- av += i;
- if (ac <= 0)
- usage("no input files given");
- L=luaL_newstate();
- if (L == NULL)
- fatal("not enough memory for state");
- lua_pushcfunction(L,&pmain);
- lua_pushinteger(L,ac);
- lua_pushlightuserdata(L,av);
- if (lua_pcall(L,2,0,0)!=LUA_OK)
- fatal(lua_tostring(L,-1));
- lua_close(L);
- return EXIT_SUCCESS;
-}
-
-/*
-** print bytecodes
-** See Copyright Notice in lua.h
-*/
-
-#define VOID(p) ((const void*)(p))
-
-#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
-#define TSVALUE(o) rawtsvalue(o)
-#endif
-#if (LUA_VERSION_NUM == 503)
-#define TSVALUE(o) tsvalue(o)
-#endif
-
-
-static void PrintString(const TString* ts)
-{
- const char* s=getstr(ts);
- size_t i,n;
-#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
- n=ts->tsv.len;
-#endif
-#if (LUA_VERSION_NUM == 503)
- n=(ts->tt == LUA_TSHRSTR ? ts->shrlen : ts->u.lnglen);
-#endif
- printf("%c",'"');
- for (i=0; i<n; i++)
- {
- int c=(int)(unsigned char)s[i];
- switch (c)
- {
- case '"': printf("\\\""); break;
- case '\\': printf("\\\\"); break;
- case '\a': printf("\\a"); break;
- case '\b': printf("\\b"); break;
- case '\f': printf("\\f"); break;
- case '\n': printf("\\n"); break;
- case '\r': printf("\\r"); break;
- case '\t': printf("\\t"); break;
- case '\v': printf("\\v"); break;
- default: if (isprint(c))
- printf("%c",c);
- else
- printf("\\%03d",c);
- }
- }
- printf("%c",'"');
-}
-
-static void PrintConstant(const Proto* f, int i)
-{
- const TValue* o=&f->k[i];
- switch (ttype(o))
- {
- case LUA_TNIL:
- printf("nil");
- break;
- case LUA_TBOOLEAN:
- printf(bvalue(o) ? "true" : "false");
- break;
- case LUA_TNUMBER:
- printf(LUA_NUMBER_FMT,nvalue(o));
- break;
- case LUA_TSTRING:
- PrintString(TSVALUE(o));
- break;
- default: /* cannot happen */
- printf("? type=%d",ttype(o));
- break;
- }
-}
-
-#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
-#define MYK(x) (-1-(x))
-
-static void PrintCode(const Proto* f)
-{
- const Instruction* code=f->code;
- int pc,n=f->sizecode;
- for (pc=0; pc<n; pc++)
- {
- Instruction i=code[pc];
- OpCode o=GET_OPCODE(i);
- int a=GETARG_A(i);
- int b=GETARG_B(i);
- int c=GETARG_C(i);
- int ax=GETARG_Ax(i);
- int bx=GETARG_Bx(i);
- int sbx=GETARG_sBx(i);
- int line=getfuncline(f,pc);
- printf("\t%d\t",pc+1);
- if (line>0) printf("[%d]\t",line); else printf("[-]\t");
- printf("%-9s\t",luaP_opnames[o]);
- switch (getOpMode(o))
- {
- case iABC:
- printf("%d",a);
- if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
- if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
- break;
- case iABx:
- printf("%d",a);
- if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
- if (getBMode(o)==OpArgU) printf(" %d",bx);
- break;
- case iAsBx:
- printf("%d %d",a,sbx);
- break;
- case iAx:
- printf("%d",MYK(ax));
- break;
- }
- switch (o)
- {
- case OP_LOADK:
- printf("\t; "); PrintConstant(f,bx);
- break;
- case OP_GETUPVAL:
- case OP_SETUPVAL:
- printf("\t; %s",UPVALNAME(b));
- break;
- case OP_GETTABUP:
- printf("\t; %s",UPVALNAME(b));
- if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
- break;
- case OP_SETTABUP:
- printf("\t; %s",UPVALNAME(a));
- if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
- if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
- break;
- case OP_GETTABLE:
- case OP_SELF:
- if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
- break;
- case OP_SETTABLE:
- case OP_ADD:
- case OP_SUB:
- case OP_MUL:
- case OP_DIV:
- case OP_POW:
- case OP_EQ:
- case OP_LT:
- case OP_LE:
- if (ISK(b) || ISK(c))
- {
- printf("\t; ");
- if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
- printf(" ");
- if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
- }
- break;
- case OP_JMP:
- case OP_FORLOOP:
- case OP_FORPREP:
- case OP_TFORLOOP:
- printf("\t; to %d",sbx+pc+2);
- break;
- case OP_CLOSURE:
- printf("\t; %p",VOID(f->p[bx]));
- break;
- case OP_SETLIST:
- if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
- break;
- case OP_EXTRAARG:
- printf("\t; "); PrintConstant(f,ax);
- break;
- default:
- break;
- }
- printf("\n");
- }
-}
-
-#define SS(x) ((x==1)?"":"s")
-#define S(x) (int)(x),SS(x)
-
-static void PrintHeader(const Proto* f)
-{
- const char* s=f->source ? getstr(f->source) : "=?";
- if (*s=='@@' || *s=='=')
- s++;
- else if (*s==LUA_SIGNATURE[0])
- s="(bstring)";
- else
- s="(string)";
- printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
- (f->linedefined==0)?"main":"function",s,
- f->linedefined,f->lastlinedefined,
- S(f->sizecode),VOID(f));
- printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
- (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
- S(f->maxstacksize),S(f->sizeupvalues));
- printf("%d local%s, %d constant%s, %d function%s\n",
- S(f->sizelocvars),S(f->sizek),S(f->sizep));
-}
-
-static void PrintDebug(const Proto* f)
-{
- int i,n;
- n=f->sizek;
- printf("constants (%d) for %p:\n",n,VOID(f));
- for (i=0; i<n; i++)
- {
- printf("\t%d\t",i+1);
- PrintConstant(f,i);
- printf("\n");
- }
- n=f->sizelocvars;
- printf("locals (%d) for %p:\n",n,VOID(f));
- for (i=0; i<n; i++)
- {
- printf("\t%d\t%s\t%d\t%d\n",
- i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
- }
- n=f->sizeupvalues;
- printf("upvalues (%d) for %p:\n",n,VOID(f));
- for (i=0; i<n; i++)
- {
- printf("\t%d\t%s\t%d\t%d\n",
- i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
- }
-}
-
-static void PrintFunction(const Proto* f, int full)
-{
- int i,n=f->sizep;
- PrintHeader(f);
- PrintCode(f);
- if (full) PrintDebug(f);
- for (i=0; i<n; i++) PrintFunction(f->p[i],full);
-}
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluajitc.c b/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
new file mode 100644
index 00000000000..5cac5d65ab1
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
@@ -0,0 +1,650 @@
+/*
+
+ LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc.
+ Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
+
+ Major portions taken verbatim or adapted from the Lua interpreter.
+ Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define luajit_c
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "luajit.h"
+
+#include "lj_arch.h"
+
+#if LJ_TARGET_POSIX
+#include <unistd.h>
+#define lua_stdin_is_tty() isatty(0)
+#elif LJ_TARGET_WINDOWS
+#include <io.h>
+#ifdef __BORLANDC__
+#define lua_stdin_is_tty() isatty(_fileno(stdin))
+#else
+#define lua_stdin_is_tty() _isatty(_fileno(stdin))
+#endif
+#else
+#define lua_stdin_is_tty() 1
+#endif
+
+#if !LJ_TARGET_CONSOLE
+#include <signal.h>
+#endif
+
+#include "lua/luatex-api.h"
+
+static lua_State *globalL = NULL;
+static const char *progname = LUA_PROGNAME;
+
+#if !LJ_TARGET_CONSOLE
+
+static void lstop(lua_State *L, lua_Debug *ar)
+{
+ /*tex Unused arg. */
+ (void)ar;
+ lua_sethook(L, NULL, 0, 0);
+ /*tex Avoid luaL_error -- a C hook doesn't add an extra frame. */
+ luaL_where(L, 0);
+ lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1));
+ lua_error(L);
+}
+
+/*tex if another SIGINT happens before lstop, terminate process (default action) */
+
+static void laction(int i)
+{
+ signal(i, SIG_DFL);
+ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+}
+
+#endif
+
+static void print_usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [options]... [script [args]...].\n"
+ "Available options are:\n"
+ " -e chunk Execute string " LUA_QL("chunk") ".\n"
+ " -l name Require library " LUA_QL("name") ".\n"
+ " -b ... Save or list bytecode.\n"
+ " -j cmd Perform LuaJIT control command.\n"
+ " -O[opt] Control LuaJIT optimizations.\n"
+ " -i Enter interactive mode after executing " LUA_QL("script") ".\n"
+ " -v Show version information.\n"
+ " -E Ignore environment variables.\n"
+ " -- Stop handling options.\n"
+ " - Execute stdin and stop handling options.\n"
+ ,
+ progname);
+ fflush(stderr);
+}
+
+static void l_message(const char *pname, const char *msg)
+{
+ if (pname) fprintf(stderr, "%s: ", pname);
+ fprintf(stderr, "%s\n", msg);
+ fflush(stderr);
+}
+
+static int report(lua_State *L, int status)
+{
+ if (status && !lua_isnil(L, -1)) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg == NULL)
+ msg = "(error object is not a string)";
+ l_message(progname, msg);
+ lua_pop(L, 1);
+ }
+ return status;
+}
+
+static int traceback(lua_State *L)
+{
+ if (!lua_isstring(L, 1)) {
+ /*tex Non-string error object? Try metamethod. */
+ if (lua_isnoneornil(L, 1) || !luaL_callmeta(L, 1, "__tostring") || !lua_isstring(L, -1)) {
+ /*tex Return non-string error object. */
+ return 1;
+ }
+ /*tex Replace object by result of __tostring metamethod. */
+ lua_remove(L, 1);
+ }
+ luaL_traceback(L, L, lua_tostring(L, 1), 1);
+ return 1;
+}
+
+static int docall(lua_State *L, int narg, int clear)
+{
+ int status;
+ /*tex function index */
+ int base = lua_gettop(L) - narg;
+ /*tex push traceback function */
+ lua_pushcfunction(L, traceback);
+ /*tex put it under chunk and args */
+ lua_insert(L, base);
+#if !LJ_TARGET_CONSOLE
+ signal(SIGINT, laction);
+#endif
+ status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
+#if !LJ_TARGET_CONSOLE
+ signal(SIGINT, SIG_DFL);
+#endif
+ /*tex remove traceback function */
+ lua_remove(L, base);
+ /*tex force a complete garbage collection in case of errors */
+ if (status != 0)
+ lua_gc(L, LUA_GCCOLLECT, 0);
+ return status;
+}
+
+static void print_version(void)
+{
+ fputs(LUAJIT_VERSION " -- " LUAJIT_COPYRIGHT ". " LUAJIT_URL "\n", stdout);
+}
+
+static void print_jit_status(lua_State *L)
+{
+ int n;
+ const char *s;
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ /*tex Get jit.* module table. */
+ lua_getfield(L, -1, "jit");
+ lua_remove(L, -2);
+ lua_getfield(L, -1, "status");
+ lua_remove(L, -2);
+ n = lua_gettop(L);
+ lua_call(L, 0, LUA_MULTRET);
+ fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stdout);
+ for (n++; (s = lua_tostring(L, n)); n++) {
+ putc(' ', stdout);
+ fputs(s, stdout);
+ }
+ putc('\n', stdout);
+}
+
+static int getargs(lua_State *L, char **argv, int n)
+{
+ int narg = 0;
+ int i;
+ /*tex count total number of arguments */
+ while (argv[argc]) argc++;
+ /*tex number of arguments to the script */
+ narg = argc - (n + 1);
+ luaL_checkstack(L, narg + 3, "too many arguments to script");
+ for (i = n+1; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ }
+ lua_createtable(L, narg, n + 1);
+ for (i = 0; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i - n);
+ }
+ return narg;
+}
+
+static int dofile(lua_State *L, const char *name)
+{
+ int status = luaL_loadfile(L, name) || docall(L, 0, 1);
+ return report(L, status);
+}
+
+static int dostring(lua_State *L, const char *s, const char *name)
+{
+ int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
+ return report(L, status);
+}
+
+static int dolibrary(lua_State *L, const char *name)
+{
+ lua_getglobal(L, "require");
+ lua_pushstring(L, name);
+ return report(L, docall(L, 1, 1));
+}
+
+static void write_prompt(lua_State *L, int firstline)
+{
+ const char *p;
+ lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
+ p = lua_tostring(L, -1);
+ if (p == NULL) p = firstline ? LUA_PROMPT : LUA_PROMPT2;
+ fputs(p, stdout);
+ fflush(stdout);
+ /*tex remove global */
+ lua_pop(L, 1);
+}
+
+static int incomplete(lua_State *L, int status)
+{
+ if (status == LUA_ERRSYNTAX) {
+ size_t lmsg;
+ const char *msg = lua_tolstring(L, -1, &lmsg);
+ const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
+ if (strstr(msg, LUA_QL("<eof>")) == tp) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pushline(lua_State *L, int firstline)
+{
+ char buf[LUA_MAXINPUT];
+ write_prompt(L, firstline);
+ if (fgets(buf, LUA_MAXINPUT, stdin)) {
+ size_t len = strlen(buf);
+ if (len > 0 && buf[len-1] == '\n')
+ buf[len-1] = '\0';
+ if (firstline && buf[0] == '=')
+ lua_pushfstring(L, "return %s", buf+1);
+ else
+ lua_pushstring(L, buf);
+ return 1;
+ }
+ return 0;
+}
+
+static int loadline(lua_State *L)
+{
+ int status;
+ lua_settop(L, 0);
+ if (!pushline(L, 1)) {
+ /*tex no input */
+ return -1;
+ }
+ for (;;) {
+ /*tex repeat until gets a complete line */
+ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
+ /*tex cannot try to add lines? */
+ if (!incomplete(L, status))
+ break;
+ /*tex no more input? */
+ if (!pushline(L, 0))
+ return -1;
+ /*tex add a new line... */
+ lua_pushliteral(L, "\n");
+ /*tex ...between the two lines */
+ lua_insert(L, -2);
+ /*tex join them */
+ lua_concat(L, 3);
+ }
+ /*tex remove line */
+ lua_remove(L, 1);
+ return status;
+}
+
+static void dotty(lua_State *L)
+{
+ int status;
+ const char *oldprogname = progname;
+ progname = NULL;
+ while ((status = loadline(L)) != -1) {
+ if (status == 0)
+ status = docall(L, 0, 0);
+ report(L, status);
+ if (status == 0 && lua_gettop(L) > 0) {
+ /*tex any result to print? */
+ lua_getglobal(L, "print");
+ lua_insert(L, 1);
+ if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
+ l_message(progname,
+ lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)",
+ lua_tostring(L, -1)));
+ }
+ }
+ /*tex clear stack */
+ lua_settop(L, 0);
+ fputs("\n", stdout);
+ fflush(stdout);
+ progname = oldprogname;
+}
+
+static int handle_script(lua_State *L, char **argv, int n)
+{
+ int status;
+ const char *fname;
+ /*tex collect arguments */
+ int narg = getargs(L, argv, n);
+ lua_setglobal(L, "arg");
+ fname = argv[n];
+ if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) {
+ /*tex use stdin */
+ fname = NULL;
+ }
+ status = luaL_loadfile(L, fname);
+ lua_insert(L, -(narg+1));
+ if (status == 0)
+ status = docall(L, narg, 0);
+ else
+ lua_pop(L, narg);
+ return report(L, status);
+}
+
+/*tex Load add-on module. */
+
+static int loadjitmodule(lua_State *L)
+{
+ lua_getglobal(L, "require");
+ lua_pushliteral(L, "jit.");
+ lua_pushvalue(L, -3);
+ lua_concat(L, 2);
+ if (lua_pcall(L, 1, 1, 0)) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg && !strncmp(msg, "module ", 7)) {
+ err:
+ l_message(progname,
+ "unknown luaJIT command or jit.* modules not installed");
+ return 1;
+ } else {
+ return report(L, 1);
+ }
+ }
+ lua_getfield(L, -1, "start");
+ if (lua_isnil(L, -1))
+ goto err;
+ /*tex Drop module table. */
+ lua_remove(L, -2);
+ return 0;
+}
+
+/*tex Run command with options. */
+
+static int runcmdopt(lua_State *L, const char *opt)
+{
+ int narg = 0;
+ if (opt && *opt) {
+ /*tex Split arguments. */
+ for (;;) {
+ const char *p = strchr(opt, ',');
+ narg++;
+ if (!p)
+ break;
+ if (p == opt)
+ lua_pushnil(L);
+ else
+ lua_pushlstring(L, opt, (size_t)(p - opt));
+ opt = p + 1;
+ }
+ if (*opt)
+ lua_pushstring(L, opt);
+ else
+ lua_pushnil(L);
+ }
+ return report(L, lua_pcall(L, narg, 0, 0));
+}
+
+/*tex JIT engine control command: try jit library first or load add-on module. */
+
+static int dojitcmd(lua_State *L, const char *cmd)
+{
+ const char *opt = strchr(cmd, '=');
+ lua_pushlstring(L, cmd, opt ? (size_t)(opt - cmd) : strlen(cmd));
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ /*tex Get jit.* module table. */
+ lua_getfield(L, -1, "jit");
+ lua_remove(L, -2);
+ /*tex Lookup library function. */
+ lua_pushvalue(L, -2);
+ lua_gettable(L, -2);
+ if (!lua_isfunction(L, -1)) {
+ /*tex Drop non-function and jit.* table, keep module name. */
+ lua_pop(L, 2);
+ if (loadjitmodule(L))
+ return 1;
+ } else {
+ /*tex Drop jit.* table. */
+ lua_remove(L, -2);
+ }
+ /*tex Drop module name. */
+ lua_remove(L, -2);
+ return runcmdopt(L, opt ? opt+1 : opt);
+}
+
+/*tex Optimization flags. */
+
+static int dojitopt(lua_State *L, const char *opt)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, -1, "jit.opt");
+ lua_remove(L, -2);
+ lua_getfield(L, -1, "start");
+ lua_remove(L, -2);
+ return runcmdopt(L, opt);
+}
+
+/*tex Save or list bytecode. */
+
+static int dobytecode(lua_State *L, char **argv)
+{
+ int narg = 0;
+ lua_pushliteral(L, "bcsave");
+ if (loadjitmodule(L))
+ return 1;
+ if (argv[0][2]) {
+ narg++;
+ argv[0][1] = '-';
+ lua_pushstring(L, argv[0]+1);
+ }
+ for (argv++; *argv != NULL; narg++, argv++)
+ lua_pushstring(L, *argv);
+ return report(L, lua_pcall(L, narg, 0, 0));
+}
+
+/*tex Check that argument has no extra characters at the end */
+
+#define notail(x) {if ((x)[2] != '\0') return -1;}
+
+#define FLAGS_INTERACTIVE 1
+#define FLAGS_VERSION 2
+#define FLAGS_EXEC 4
+#define FLAGS_OPTION 8
+#define FLAGS_NOENV 16
+
+static int collectargs(char **argv, int *flags)
+{
+ int i;
+ for (i = 1; argv[i] != NULL; i++) {
+ /*tex Not an option? */
+ if (argv[i][0] != '-')
+ return i;
+ /*tex Check option. */
+ switch (argv[i][1]) {
+ case '-':
+ notail(argv[i]);
+ return (argv[i+1] != NULL ? i+1 : 0);
+ case '\0':
+ return i;
+ case 'i':
+ notail(argv[i]);
+ *flags |= FLAGS_INTERACTIVE;
+ /*tex fallthrough */
+ case 'v':
+ notail(argv[i]);
+ *flags |= FLAGS_VERSION;
+ break;
+ case 'e':
+ *flags |= FLAGS_EXEC;
+ case 'j':
+ /*tex LuaJIT extension */
+ case 'l':
+ *flags |= FLAGS_OPTION;
+ if (argv[i][2] == '\0') {
+ i++;
+ if (argv[i] == NULL)
+ return -1;
+ }
+ break;
+ case 'O':
+ /*tex LuaJIT extension */
+ break;
+ case 'b':
+ /*tex LuaJIT extension */
+ if (*flags) return -1;
+ *flags |= FLAGS_EXEC;
+ return 0;
+ case 'E':
+ *flags |= FLAGS_NOENV;
+ break;
+ default:
+ /*tex invalid option */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int runargs(lua_State *L, char **argv, int n)
+{
+ int i;
+ for (i = 1; i < n; i++) {
+ if (argv[i] == NULL)
+ continue;
+ lua_assert(argv[i][0] == '-');
+ switch (argv[i][1]) {
+ /*tex Options */
+ case 'e': {
+ const char *chunk = argv[i] + 2;
+ if (*chunk == '\0')
+ chunk = argv[++i];
+ lua_assert(chunk != NULL);
+ if (dostring(L, chunk, "=(command line)") != 0)
+ return 1;
+ break;
+ }
+ case 'l': {
+ const char *filename = argv[i] + 2;
+ if (*filename == '\0')
+ filename = argv[++i];
+ lua_assert(filename != NULL);
+ if (dolibrary(L, filename)) {
+ /*tex stop if file fails */
+ return 1;
+ }
+ break;
+ }
+ case 'j': {
+ /*tex LuaJIT extension */
+ const char *cmd = argv[i] + 2;
+ if (*cmd == '\0')
+ cmd = argv[++i];
+ lua_assert(cmd != NULL);
+ if (dojitcmd(L, cmd))
+ return 1;
+ break;
+ }
+ case 'O':
+ /*tex LuaJIT extension */
+ if (dojitopt(L, argv[i] + 2))
+ return 1;
+ break;
+ case 'b':
+ /*tex LuaJIT extension */
+ return dobytecode(L, argv+i);
+ default: break;
+ }
+ }
+ return 0;
+}
+
+static int handle_luainit(lua_State *L)
+{
+#if LJ_TARGET_CONSOLE
+ const char *init = NULL;
+#else
+ const char *init = getenv(LUA_INIT);
+#endif
+ if (init == NULL) {
+ /*tex status OK */
+ return 0;
+ } else if (init[0] == 64) {
+ return dofile(L, init+1);
+ } else {
+ return dostring(L, init, "=" LUA_INIT);
+ }
+}
+
+struct Smain {
+ char **argv;
+ int argc;
+ int status;
+};
+
+static int pmain(lua_State *L)
+{
+ struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
+ char **argv = s->argv;
+ int script;
+ int flags = 0;
+ globalL = L;
+ if (argv[0] && argv[0][0])
+ progname = argv[0];
+ /*tex linker-enforced version check */
+ LUAJIT_VERSION_SYM();
+ script = collectargs(argv, &flags);
+ if (script < 0) {
+ /*tex invalid args? */
+ print_usage();
+ s->status = 1;
+ return 0;
+ }
+ if ((flags & FLAGS_NOENV)) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ }
+ /*tex stop collector during initialization */
+ lua_gc(L, LUA_GCSTOP, 0);
+ /*tex open libraries */
+ luaL_openlibs(L);
+ lua_gc(L, LUA_GCRESTART, -1);
+ if (!(flags & FLAGS_NOENV)) {
+ s->status = handle_luainit(L);
+ if (s->status != 0) return 0;
+ }
+ if ((flags & FLAGS_VERSION)) print_version();
+ s->status = runargs(L, argv, (script > 0) ? script : s->argc);
+ if (s->status != 0) return 0;
+ if (script) {
+ s->status = handle_script(L, argv, script);
+ if (s->status != 0) return 0;
+ }
+ if ((flags & FLAGS_INTERACTIVE)) {
+ print_jit_status(L);
+ dotty(L);
+ } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
+ if (lua_stdin_is_tty()) {
+ print_version();
+ print_jit_status(L);
+ dotty(L);
+ } else {
+ /*tex executes stdin as a file */
+ dofile(L, NULL);
+ }
+ }
+ return 0;
+}
+
+int luac_main(int argc, char **argv)
+{
+ int status;
+ struct Smain s;
+ lua_State *L = lua_open(); /* create state */
+ if (L == NULL) {
+ l_message(argv[0], "cannot create state: not enough memory");
+ return EXIT_FAILURE;
+ }
+ s.argc = argc;
+ s.argv = argv;
+ status = lua_cpcall(L, pmain, &s);
+ report(L, status);
+ lua_close(L);
+ return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluajitc.w b/Build/source/texk/web2c/luatexdir/lua/texluajitc.w
deleted file mode 100644
index f54f9c8d4a4..00000000000
--- a/Build/source/texk/web2c/luatexdir/lua/texluajitc.w
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
-** LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc.
-** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
-**
-** Major portions taken verbatim or adapted from the Lua interpreter.
-** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
-*/
-
-@ @c
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define luajit_c
-
-#include "lua.h"
-#include "lauxlib.h"
-#include "lualib.h"
-#include "luajit.h"
-
-#include "lj_arch.h"
-
-#if LJ_TARGET_POSIX
-#include <unistd.h>
-#define lua_stdin_is_tty() isatty(0)
-#elif LJ_TARGET_WINDOWS
-#include <io.h>
-#ifdef __BORLANDC__
-#define lua_stdin_is_tty() isatty(_fileno(stdin))
-#else
-#define lua_stdin_is_tty() _isatty(_fileno(stdin))
-#endif
-#else
-#define lua_stdin_is_tty() 1
-#endif
-
-#if !LJ_TARGET_CONSOLE
-#include <signal.h>
-#endif
-
-#include "lua/luatex-api.h"
-
-static lua_State *globalL = NULL;
-static const char *progname = LUA_PROGNAME;
-
-#if !LJ_TARGET_CONSOLE
-static void lstop(lua_State *L, lua_Debug *ar)
-{
- (void)ar; /* unused arg. */
- lua_sethook(L, NULL, 0, 0);
- /* Avoid luaL_error -- a C hook doesn't add an extra frame. */
- luaL_where(L, 0);
- lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1));
- lua_error(L);
-}
-
-static void laction(int i)
-{
- signal(i, SIG_DFL); /* if another SIGINT happens before lstop,
- terminate process (default action) */
- lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
-}
-#endif
-
-static void print_usage(void)
-{
- fprintf(stderr,
- "usage: %s [options]... [script [args]...].\n"
- "Available options are:\n"
- " -e chunk Execute string " LUA_QL("chunk") ".\n"
- " -l name Require library " LUA_QL("name") ".\n"
- " -b ... Save or list bytecode.\n"
- " -j cmd Perform LuaJIT control command.\n"
- " -O[opt] Control LuaJIT optimizations.\n"
- " -i Enter interactive mode after executing " LUA_QL("script") ".\n"
- " -v Show version information.\n"
- " -E Ignore environment variables.\n"
- " -- Stop handling options.\n"
- " - Execute stdin and stop handling options.\n"
- ,
- progname);
- fflush(stderr);
-}
-
-static void l_message(const char *pname, const char *msg)
-{
- if (pname) fprintf(stderr, "%s: ", pname);
- fprintf(stderr, "%s\n", msg);
- fflush(stderr);
-}
-
-static int report(lua_State *L, int status)
-{
- if (status && !lua_isnil(L, -1)) {
- const char *msg = lua_tostring(L, -1);
- if (msg == NULL) msg = "(error object is not a string)";
- l_message(progname, msg);
- lua_pop(L, 1);
- }
- return status;
-}
-
-static int traceback(lua_State *L)
-{
- if (!lua_isstring(L, 1)) { /* Non-string error object? Try metamethod. */
- if (lua_isnoneornil(L, 1) ||
- !luaL_callmeta(L, 1, "__tostring") ||
- !lua_isstring(L, -1))
- return 1; /* Return non-string error object. */
- lua_remove(L, 1); /* Replace object by result of __tostring metamethod. */
- }
- luaL_traceback(L, L, lua_tostring(L, 1), 1);
- return 1;
-}
-
-static int docall(lua_State *L, int narg, int clear)
-{
- int status;
- int base = lua_gettop(L) - narg; /* function index */
- lua_pushcfunction(L, traceback); /* push traceback function */
- lua_insert(L, base); /* put it under chunk and args */
-#if !LJ_TARGET_CONSOLE
- signal(SIGINT, laction);
-#endif
- status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
-#if !LJ_TARGET_CONSOLE
- signal(SIGINT, SIG_DFL);
-#endif
- lua_remove(L, base); /* remove traceback function */
- /* force a complete garbage collection in case of errors */
- if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
- return status;
-}
-
-static void print_version(void)
-{
- fputs(LUAJIT_VERSION " -- " LUAJIT_COPYRIGHT ". " LUAJIT_URL "\n", stdout);
-}
-
-static void print_jit_status(lua_State *L)
-{
- int n;
- const char *s;
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, -1, "jit"); /* Get jit.* module table. */
- lua_remove(L, -2);
- lua_getfield(L, -1, "status");
- lua_remove(L, -2);
- n = lua_gettop(L);
- lua_call(L, 0, LUA_MULTRET);
- fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stdout);
- for (n++; (s = lua_tostring(L, n)); n++) {
- putc(' ', stdout);
- fputs(s, stdout);
- }
- putc('\n', stdout);
-}
-
-static int getargs(lua_State *L, char **argv, int n)
-{
- int narg;
- int i;
- int argc = 0;
- while (argv[argc]) argc++; /* count total number of arguments */
- narg = argc - (n + 1); /* number of arguments to the script */
- luaL_checkstack(L, narg + 3, "too many arguments to script");
- for (i = n+1; i < argc; i++)
- lua_pushstring(L, argv[i]);
- lua_createtable(L, narg, n + 1);
- for (i = 0; i < argc; i++) {
- lua_pushstring(L, argv[i]);
- lua_rawseti(L, -2, i - n);
- }
- return narg;
-}
-
-static int dofile(lua_State *L, const char *name)
-{
- int status = luaL_loadfile(L, name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-static int dostring(lua_State *L, const char *s, const char *name)
-{
- int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
- return report(L, status);
-}
-
-static int dolibrary(lua_State *L, const char *name)
-{
- lua_getglobal(L, "require");
- lua_pushstring(L, name);
- return report(L, docall(L, 1, 1));
-}
-
-static void write_prompt(lua_State *L, int firstline)
-{
- const char *p;
- lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
- p = lua_tostring(L, -1);
- if (p == NULL) p = firstline ? LUA_PROMPT : LUA_PROMPT2;
- fputs(p, stdout);
- fflush(stdout);
- lua_pop(L, 1); /* remove global */
-}
-
-static int incomplete(lua_State *L, int status)
-{
- if (status == LUA_ERRSYNTAX) {
- size_t lmsg;
- const char *msg = lua_tolstring(L, -1, &lmsg);
- const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
- if (strstr(msg, LUA_QL("<eof>")) == tp) {
- lua_pop(L, 1);
- return 1;
- }
- }
- return 0; /* else... */
-}
-
-static int pushline(lua_State *L, int firstline)
-{
- char buf[LUA_MAXINPUT];
- write_prompt(L, firstline);
- if (fgets(buf, LUA_MAXINPUT, stdin)) {
- size_t len = strlen(buf);
- if (len > 0 && buf[len-1] == '\n')
- buf[len-1] = '\0';
- if (firstline && buf[0] == '=')
- lua_pushfstring(L, "return %s", buf+1);
- else
- lua_pushstring(L, buf);
- return 1;
- }
- return 0;
-}
-
-static int loadline(lua_State *L)
-{
- int status;
- lua_settop(L, 0);
- if (!pushline(L, 1))
- return -1; /* no input */
- for (;;) { /* repeat until gets a complete line */
- status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
- if (!incomplete(L, status)) break; /* cannot try to add lines? */
- if (!pushline(L, 0)) /* no more input? */
- return -1;
- lua_pushliteral(L, "\n"); /* add a new line... */
- lua_insert(L, -2); /* ...between the two lines */
- lua_concat(L, 3); /* join them */
- }
- lua_remove(L, 1); /* remove line */
- return status;
-}
-
-static void dotty(lua_State *L)
-{
- int status;
- const char *oldprogname = progname;
- progname = NULL;
- while ((status = loadline(L)) != -1) {
- if (status == 0) status = docall(L, 0, 0);
- report(L, status);
- if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
- lua_getglobal(L, "print");
- lua_insert(L, 1);
- if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
- l_message(progname,
- lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)",
- lua_tostring(L, -1)));
- }
- }
- lua_settop(L, 0); /* clear stack */
- fputs("\n", stdout);
- fflush(stdout);
- progname = oldprogname;
-}
-
-static int handle_script(lua_State *L, char **argv, int n)
-{
- int status;
- const char *fname;
- int narg = getargs(L, argv, n); /* collect arguments */
- lua_setglobal(L, "arg");
- fname = argv[n];
- if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0)
- fname = NULL; /* stdin */
- status = luaL_loadfile(L, fname);
- lua_insert(L, -(narg+1));
- if (status == 0)
- status = docall(L, narg, 0);
- else
- lua_pop(L, narg);
- return report(L, status);
-}
-
-/* Load add-on module. */
-static int loadjitmodule(lua_State *L)
-{
- lua_getglobal(L, "require");
- lua_pushliteral(L, "jit.");
- lua_pushvalue(L, -3);
- lua_concat(L, 2);
- if (lua_pcall(L, 1, 1, 0)) {
- const char *msg = lua_tostring(L, -1);
- if (msg && !strncmp(msg, "module ", 7)) {
- err:
- l_message(progname,
- "unknown luaJIT command or jit.* modules not installed");
- return 1;
- } else {
- return report(L, 1);
- }
- }
- lua_getfield(L, -1, "start");
- if (lua_isnil(L, -1)) goto err;
- lua_remove(L, -2); /* Drop module table. */
- return 0;
-}
-
-/* Run command with options. */
-static int runcmdopt(lua_State *L, const char *opt)
-{
- int narg = 0;
- if (opt && *opt) {
- for (;;) { /* Split arguments. */
- const char *p = strchr(opt, ',');
- narg++;
- if (!p) break;
- if (p == opt)
- lua_pushnil(L);
- else
- lua_pushlstring(L, opt, (size_t)(p - opt));
- opt = p + 1;
- }
- if (*opt)
- lua_pushstring(L, opt);
- else
- lua_pushnil(L);
- }
- return report(L, lua_pcall(L, narg, 0, 0));
-}
-
-/* JIT engine control command: try jit library first or load add-on module. */
-static int dojitcmd(lua_State *L, const char *cmd)
-{
- const char *opt = strchr(cmd, '=');
- lua_pushlstring(L, cmd, opt ? (size_t)(opt - cmd) : strlen(cmd));
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, -1, "jit"); /* Get jit.* module table. */
- lua_remove(L, -2);
- lua_pushvalue(L, -2);
- lua_gettable(L, -2); /* Lookup library function. */
- if (!lua_isfunction(L, -1)) {
- lua_pop(L, 2); /* Drop non-function and jit.* table, keep module name. */
- if (loadjitmodule(L))
- return 1;
- } else {
- lua_remove(L, -2); /* Drop jit.* table. */
- }
- lua_remove(L, -2); /* Drop module name. */
- return runcmdopt(L, opt ? opt+1 : opt);
-}
-
-/* Optimization flags. */
-static int dojitopt(lua_State *L, const char *opt)
-{
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, -1, "jit.opt"); /* Get jit.opt.* module table. */
- lua_remove(L, -2);
- lua_getfield(L, -1, "start");
- lua_remove(L, -2);
- return runcmdopt(L, opt);
-}
-
-/* Save or list bytecode. */
-static int dobytecode(lua_State *L, char **argv)
-{
- int narg = 0;
- lua_pushliteral(L, "bcsave");
- if (loadjitmodule(L))
- return 1;
- if (argv[0][2]) {
- narg++;
- argv[0][1] = '-';
- lua_pushstring(L, argv[0]+1);
- }
- for (argv++; *argv != NULL; narg++, argv++)
- lua_pushstring(L, *argv);
- return report(L, lua_pcall(L, narg, 0, 0));
-}
-
-/* check that argument has no extra characters at the end */
-#define notail(x) {if ((x)[2] != '\0') return -1;}
-
-#define FLAGS_INTERACTIVE 1
-#define FLAGS_VERSION 2
-#define FLAGS_EXEC 4
-#define FLAGS_OPTION 8
-#define FLAGS_NOENV 16
-
-static int collectargs(char **argv, int *flags)
-{
- int i;
- for (i = 1; argv[i] != NULL; i++) {
- if (argv[i][0] != '-') /* Not an option? */
- return i;
- switch (argv[i][1]) { /* Check option. */
- case '-':
- notail(argv[i]);
- return (argv[i+1] != NULL ? i+1 : 0);
- case '\0':
- return i;
- case 'i':
- notail(argv[i]);
- *flags |= FLAGS_INTERACTIVE;
- /* fallthrough */
- case 'v':
- notail(argv[i]);
- *flags |= FLAGS_VERSION;
- break;
- case 'e':
- *flags |= FLAGS_EXEC;
- case 'j': /* LuaJIT extension */
- case 'l':
- *flags |= FLAGS_OPTION;
- if (argv[i][2] == '\0') {
- i++;
- if (argv[i] == NULL) return -1;
- }
- break;
- case 'O': break; /* LuaJIT extension */
- case 'b': /* LuaJIT extension */
- if (*flags) return -1;
- *flags |= FLAGS_EXEC;
- return 0;
- case 'E':
- *flags |= FLAGS_NOENV;
- break;
- default: return -1; /* invalid option */
- }
- }
- return 0;
-}
-
-static int runargs(lua_State *L, char **argv, int n)
-{
- int i;
- for (i = 1; i < n; i++) {
- if (argv[i] == NULL) continue;
- lua_assert(argv[i][0] == '-');
- switch (argv[i][1]) { /* option */
- case 'e': {
- const char *chunk = argv[i] + 2;
- if (*chunk == '\0') chunk = argv[++i];
- lua_assert(chunk != NULL);
- if (dostring(L, chunk, "=(command line)") != 0)
- return 1;
- break;
- }
- case 'l': {
- const char *filename = argv[i] + 2;
- if (*filename == '\0') filename = argv[++i];
- lua_assert(filename != NULL);
- if (dolibrary(L, filename))
- return 1; /* stop if file fails */
- break;
- }
- case 'j': { /* LuaJIT extension */
- const char *cmd = argv[i] + 2;
- if (*cmd == '\0') cmd = argv[++i];
- lua_assert(cmd != NULL);
- if (dojitcmd(L, cmd))
- return 1;
- break;
- }
- case 'O': /* LuaJIT extension */
- if (dojitopt(L, argv[i] + 2))
- return 1;
- break;
- case 'b': /* LuaJIT extension */
- return dobytecode(L, argv+i);
- default: break;
- }
- }
- return 0;
-}
-
-static int handle_luainit(lua_State *L)
-{
-#if LJ_TARGET_CONSOLE
- const char *init = NULL;
-#else
- const char *init = getenv(LUA_INIT);
-#endif
- if (init == NULL)
- return 0; /* status OK */
- else if (init[0] == 64)
- return dofile(L, init+1);
- else
- return dostring(L, init, "=" LUA_INIT);
-}
-
-struct Smain {
- char **argv;
- int argc;
- int status;
-};
-
-static int pmain(lua_State *L)
-{
- struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
- char **argv = s->argv;
- int script;
- int flags = 0;
- globalL = L;
- if (argv[0] && argv[0][0]) progname = argv[0];
- LUAJIT_VERSION_SYM(); /* linker-enforced version check */
- script = collectargs(argv, &flags);
- if (script < 0) { /* invalid args? */
- print_usage();
- s->status = 1;
- return 0;
- }
- if ((flags & FLAGS_NOENV)) {
- lua_pushboolean(L, 1);
- lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
- }
- lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
- luaL_openlibs(L); /* open libraries */
- lua_gc(L, LUA_GCRESTART, -1);
- if (!(flags & FLAGS_NOENV)) {
- s->status = handle_luainit(L);
- if (s->status != 0) return 0;
- }
- if ((flags & FLAGS_VERSION)) print_version();
- s->status = runargs(L, argv, (script > 0) ? script : s->argc);
- if (s->status != 0) return 0;
- if (script) {
- s->status = handle_script(L, argv, script);
- if (s->status != 0) return 0;
- }
- if ((flags & FLAGS_INTERACTIVE)) {
- print_jit_status(L);
- dotty(L);
- } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
- if (lua_stdin_is_tty()) {
- print_version();
- print_jit_status(L);
- dotty(L);
- } else {
- dofile(L, NULL); /* executes stdin as a file */
- }
- }
- return 0;
-}
-
-int luac_main(int argc, char **argv)
-{
- int status;
- struct Smain s;
- lua_State *L = lua_open(); /* create state */
- if (L == NULL) {
- l_message(argv[0], "cannot create state: not enough memory");
- return EXIT_FAILURE;
- }
- s.argc = argc;
- s.argv = argv;
- status = lua_cpcall(L, pmain, &s);
- report(L, status);
- lua_close(L);
- return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
-}
-
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua b/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua
deleted file mode 100644
index 7340a7b605f..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp.lua
+++ /dev/null
@@ -1,329 +0,0 @@
------------------------------------------------------------------------------
--- FTP support for the Lua language
--- LuaSocket toolkit.
--- Author: Diego Nehab
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- Declare module and import dependencies
------------------------------------------------------------------------------
-local base = _G
-local table = require("table")
-local string = require("string")
-local math = require("math")
-local socket = socket or require("socket")
-local url = socket.url or require("socket.url")
-local tp = socket.tp or require("socket.tp")
-local ltn12 = ltn12 or require("ltn12")
-socket.ftp = {}
-local _M = socket.ftp
------------------------------------------------------------------------------
--- Program constants
------------------------------------------------------------------------------
--- timeout in seconds before the program gives up on a connection
-_M.TIMEOUT = 60
--- default port for ftp service
-local PORT = 21
--- this is the default anonymous password. used when no password is
--- provided in url. should be changed to your e-mail.
-_M.USER = "ftp"
-_M.PASSWORD = "anonymous@anonymous.org"
-
------------------------------------------------------------------------------
--- Low level FTP API
------------------------------------------------------------------------------
-local metat = { __index = {} }
-
-function _M.open(server, port, create)
- local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create))
- local f = base.setmetatable({ tp = tp }, metat)
- -- make sure everything gets closed in an exception
- f.try = socket.newtry(function() f:close() end)
- return f
-end
-
-function metat.__index:portconnect()
- self.try(self.server:settimeout(_M.TIMEOUT))
- self.data = self.try(self.server:accept())
- self.try(self.data:settimeout(_M.TIMEOUT))
-end
-
-function metat.__index:pasvconnect()
- self.data = self.try(socket.tcp())
- self.try(self.data:settimeout(_M.TIMEOUT))
- self.try(self.data:connect(self.pasvt.address, self.pasvt.port))
-end
-
-function metat.__index:login(user, password)
- self.try(self.tp:command("user", user or _M.USER))
- local code, reply = self.try(self.tp:check{"2..", 331})
- if code == 331 then
- self.try(self.tp:command("pass", password or _M.PASSWORD))
- self.try(self.tp:check("2.."))
- end
- return 1
-end
-
-function metat.__index:pasv()
- self.try(self.tp:command("pasv"))
- local code, reply = self.try(self.tp:check("2.."))
- local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
- local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
- self.try(a and b and c and d and p1 and p2, reply)
- self.pasvt = {
- address = string.format("%d.%d.%d.%d", a, b, c, d),
- port = p1*256 + p2
- }
- if self.server then
- self.server:close()
- self.server = nil
- end
- return self.pasvt.address, self.pasvt.port
-end
-
-function metat.__index:epsv()
- self.try(self.tp:command("epsv"))
- local code, reply = self.try(self.tp:check("229"))
- local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)"
- local d, prt, address, port = string.match(reply, pattern)
- self.try(port, "invalid epsv response")
- self.pasvt = {
- address = self.tp:getpeername(),
- port = port
- }
- if self.server then
- self.server:close()
- self.server = nil
- end
- return self.pasvt.address, self.pasvt.port
-end
-
-
-function metat.__index:port(address, port)
- self.pasvt = nil
- if not address then
- address, port = self.try(self.tp:getsockname())
- self.server = self.try(socket.bind(address, 0))
- address, port = self.try(self.server:getsockname())
- self.try(self.server:settimeout(_M.TIMEOUT))
- end
- local pl = math.mod(port, 256)
- local ph = (port - pl)/256
- local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",")
- self.try(self.tp:command("port", arg))
- self.try(self.tp:check("2.."))
- return 1
-end
-
-function metat.__index:eprt(family, address, port)
- self.pasvt = nil
- if not address then
- address, port = self.try(self.tp:getsockname())
- self.server = self.try(socket.bind(address, 0))
- address, port = self.try(self.server:getsockname())
- self.try(self.server:settimeout(_M.TIMEOUT))
- end
- local arg = string.format("|%s|%s|%d|", family, address, port)
- self.try(self.tp:command("eprt", arg))
- self.try(self.tp:check("2.."))
- return 1
-end
-
-
-function metat.__index:send(sendt)
- self.try(self.pasvt or self.server, "need port or pasv first")
- -- if there is a pasvt table, we already sent a PASV command
- -- we just get the data connection into self.data
- if self.pasvt then self:pasvconnect() end
- -- get the transfer argument and command
- local argument = sendt.argument or
- url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
- if argument == "" then argument = nil end
- local command = sendt.command or "stor"
- -- send the transfer command and check the reply
- self.try(self.tp:command(command, argument))
- local code, reply = self.try(self.tp:check{"2..", "1.."})
- -- if there is not a pasvt table, then there is a server
- -- and we already sent a PORT command
- if not self.pasvt then self:portconnect() end
- -- get the sink, source and step for the transfer
- local step = sendt.step or ltn12.pump.step
- local readt = { self.tp }
- local checkstep = function(src, snk)
- -- check status in control connection while downloading
- local readyt = socket.select(readt, nil, 0)
- if readyt[tp] then code = self.try(self.tp:check("2..")) end
- return step(src, snk)
- end
- local sink = socket.sink("close-when-done", self.data)
- -- transfer all data and check error
- self.try(ltn12.pump.all(sendt.source, sink, checkstep))
- if string.find(code, "1..") then self.try(self.tp:check("2..")) end
- -- done with data connection
- self.data:close()
- -- find out how many bytes were sent
- local sent = socket.skip(1, self.data:getstats())
- self.data = nil
- return sent
-end
-
-function metat.__index:receive(recvt)
- self.try(self.pasvt or self.server, "need port or pasv first")
- if self.pasvt then self:pasvconnect() end
- local argument = recvt.argument or
- url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
- if argument == "" then argument = nil end
- local command = recvt.command or "retr"
- self.try(self.tp:command(command, argument))
- local code,reply = self.try(self.tp:check{"1..", "2.."})
- if (code >= 200) and (code <= 299) then
- recvt.sink(reply)
- return 1
- end
- if not self.pasvt then self:portconnect() end
- local source = socket.source("until-closed", self.data)
- local step = recvt.step or ltn12.pump.step
- self.try(ltn12.pump.all(source, recvt.sink, step))
- if string.find(code, "1..") then self.try(self.tp:check("2..")) end
- self.data:close()
- self.data = nil
- return 1
-end
-
-function metat.__index:cwd(dir)
- self.try(self.tp:command("cwd", dir))
- self.try(self.tp:check(250))
- return 1
-end
-
-function metat.__index:type(type)
- self.try(self.tp:command("type", type))
- self.try(self.tp:check(200))
- return 1
-end
-
-function metat.__index:greet()
- local code = self.try(self.tp:check{"1..", "2.."})
- if string.find(code, "1..") then self.try(self.tp:check("2..")) end
- return 1
-end
-
-function metat.__index:quit()
- self.try(self.tp:command("quit"))
- self.try(self.tp:check("2.."))
- return 1
-end
-
-function metat.__index:close()
- if self.data then self.data:close() end
- if self.server then self.server:close() end
- return self.tp:close()
-end
-
------------------------------------------------------------------------------
--- High level FTP API
------------------------------------------------------------------------------
-local function override(t)
- if t.url then
- local u = url.parse(t.url)
- for i,v in base.pairs(t) do
- u[i] = v
- end
- return u
- else return t end
-end
-
-local function tput(putt)
- putt = override(putt)
- socket.try(putt.host, "missing hostname")
- local f = _M.open(putt.host, putt.port, putt.create)
- f:greet()
- f:login(putt.user, putt.password)
- if putt.type then f:type(putt.type) end
- f:epsv()
- local sent = f:send(putt)
- f:quit()
- f:close()
- return sent
-end
-
-local default = {
- path = "/",
- scheme = "ftp"
-}
-
-local function genericform(u)
- local t = socket.try(url.parse(u, default))
- socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
- socket.try(t.host, "missing hostname")
- local pat = "^type=(.)$"
- if t.params then
- t.type = socket.skip(2, string.find(t.params, pat))
- socket.try(t.type == "a" or t.type == "i",
- "invalid type '" .. t.type .. "'")
- end
- return t
-end
-
-_M.genericform = genericform
-
-local function sput(u, body)
- local putt = genericform(u)
- putt.source = ltn12.source.string(body)
- return tput(putt)
-end
-
-_M.put = socket.protect(function(putt, body)
- if base.type(putt) == "string" then return sput(putt, body)
- else return tput(putt) end
-end)
-
-local function tget(gett)
- gett = override(gett)
- socket.try(gett.host, "missing hostname")
- local f = _M.open(gett.host, gett.port, gett.create)
- f:greet()
- f:login(gett.user, gett.password)
- if gett.type then f:type(gett.type) end
- f:epsv()
- f:receive(gett)
- f:quit()
- return f:close()
-end
-
-local function sget(u)
- local gett = genericform(u)
- local t = {}
- gett.sink = ltn12.sink.table(t)
- tget(gett)
- return table.concat(t)
-end
-
-_M.command = socket.protect(function(cmdt)
- cmdt = override(cmdt)
- socket.try(cmdt.host, "missing hostname")
- socket.try(cmdt.command, "missing command")
- local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
- f:greet()
- f:login(cmdt.user, cmdt.password)
- if type(cmdt.command) == "table" then
- local argument = cmdt.argument or {}
- local check = cmdt.check or {}
- for i,cmd in ipairs(cmdt.command) do
- f.try(f.tp:command(cmd, argument[i]))
- if check[i] then f.try(f.tp:check(check[i])) end
- end
- else
- f.try(f.tp:command(cmdt.command, cmdt.argument))
- if cmdt.check then f.try(f.tp:check(cmdt.check)) end
- end
- f:quit()
- return f:close()
-end)
-
-_M.get = socket.protect(function(gett)
- if base.type(gett) == "string" then return sget(gett)
- else return tget(gett) end
-end)
-
-return _M
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c b/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c
deleted file mode 100644
index ec38cb10786..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_ftp_lua.c
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * This file is generated with xxd -i and bit of bash script.
-*/
-#include "lua.h"
-#include "lauxlib.h"
-
-int luatex_ftp_lua_open (lua_State *L) {
- static unsigned char B[] = {
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d,
- 0x20, 0x5f, 0x47, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
- 0x65, 0x28, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x29, 0x0a, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20,
- 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71,
- 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x74, 0x68, 0x22, 0x29,
- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6f,
- 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b,
- 0x65, 0x74, 0x2e, 0x75, 0x72, 0x6c, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65,
- 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x2e, 0x75, 0x72, 0x6c, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x74, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x2e, 0x74, 0x70, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75,
- 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
- 0x74, 0x70, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c,
- 0x74, 0x6e, 0x31, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32,
- 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28,
- 0x22, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x22, 0x29, 0x0a, 0x73, 0x6f, 0x63,
- 0x6b, 0x65, 0x74, 0x2e, 0x66, 0x74, 0x70, 0x20, 0x3d, 0x20, 0x7b, 0x7d,
- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x4d, 0x20, 0x3d, 0x20,
- 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x66, 0x74, 0x70, 0x0a, 0x5f,
- 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x20, 0x3d, 0x20,
- 0x36, 0x30, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x50, 0x4f, 0x52,
- 0x54, 0x20, 0x3d, 0x20, 0x32, 0x31, 0x0a, 0x5f, 0x4d, 0x2e, 0x55, 0x53,
- 0x45, 0x52, 0x20, 0x3d, 0x20, 0x22, 0x66, 0x74, 0x70, 0x22, 0x0a, 0x5f,
- 0x4d, 0x2e, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x20, 0x3d,
- 0x20, 0x22, 0x61, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x40,
- 0x61, 0x6e, 0x6f, 0x6e, 0x79, 0x6d, 0x6f, 0x75, 0x73, 0x2e, 0x6f, 0x72,
- 0x67, 0x22, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74,
- 0x61, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64,
- 0x65, 0x78, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x20, 0x7d, 0x0a, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x6f, 0x70,
- 0x65, 0x6e, 0x28, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x70,
- 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74,
- 0x70, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74,
- 0x72, 0x79, 0x28, 0x74, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
- 0x74, 0x28, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x6f,
- 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x50, 0x4f, 0x52, 0x54, 0x2c, 0x20,
- 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x2c, 0x20,
- 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x62,
- 0x61, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74,
- 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x20, 0x74, 0x70, 0x20, 0x3d, 0x20,
- 0x74, 0x70, 0x20, 0x7d, 0x2c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x20, 0x3d,
- 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6e, 0x65, 0x77, 0x74,
- 0x72, 0x79, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
- 0x29, 0x20, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x20,
- 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x66, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74,
- 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x70, 0x6f, 0x72,
- 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a,
- 0x73, 0x65, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x5f,
- 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74,
- 0x61, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x3a, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x28, 0x29, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x73, 0x65,
- 0x74, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x5f, 0x4d, 0x2e,
- 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x29, 0x29, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d,
- 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
- 0x3a, 0x70, 0x61, 0x73, 0x76, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
- 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74,
- 0x63, 0x70, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x64, 0x61, 0x74, 0x61, 0x3a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6d, 0x65,
- 0x6f, 0x75, 0x74, 0x28, 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f,
- 0x55, 0x54, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64,
- 0x61, 0x74, 0x61, 0x3a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74, 0x2e, 0x61,
- 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x29,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x28, 0x75,
- 0x73, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
- 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a,
- 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x75, 0x73, 0x65,
- 0x72, 0x22, 0x2c, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x20,
- 0x5f, 0x4d, 0x2e, 0x55, 0x53, 0x45, 0x52, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65,
- 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x3d, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x7b, 0x22, 0x32, 0x2e,
- 0x2e, 0x22, 0x2c, 0x20, 0x33, 0x33, 0x31, 0x7d, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d,
- 0x20, 0x33, 0x33, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63,
- 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x70, 0x61, 0x73, 0x73,
- 0x22, 0x2c, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20,
- 0x6f, 0x72, 0x20, 0x5f, 0x4d, 0x2e, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f,
- 0x52, 0x44, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28,
- 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e,
- 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x70, 0x61, 0x73, 0x76,
- 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a,
- 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x70, 0x61, 0x73,
- 0x76, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x70,
- 0x6c, 0x79, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72,
- 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68,
- 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61,
- 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x3d, 0x20, 0x22, 0x28, 0x25, 0x64,
- 0x2b, 0x29, 0x25, 0x44, 0x28, 0x25, 0x64, 0x2b, 0x29, 0x25, 0x44, 0x28,
- 0x25, 0x64, 0x2b, 0x29, 0x25, 0x44, 0x28, 0x25, 0x64, 0x2b, 0x29, 0x25,
- 0x44, 0x28, 0x25, 0x64, 0x2b, 0x29, 0x25, 0x44, 0x28, 0x25, 0x64, 0x2b,
- 0x29, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x2c, 0x20, 0x64, 0x2c,
- 0x20, 0x70, 0x31, 0x2c, 0x20, 0x70, 0x32, 0x20, 0x3d, 0x20, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6b, 0x69, 0x70, 0x28, 0x32, 0x2c,
- 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64,
- 0x28, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x74,
- 0x65, 0x72, 0x6e, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x61, 0x20, 0x61, 0x6e, 0x64,
- 0x20, 0x62, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x20, 0x61, 0x6e, 0x64,
- 0x20, 0x64, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x31, 0x20, 0x61, 0x6e,
- 0x64, 0x20, 0x70, 0x32, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61,
- 0x73, 0x76, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20,
- 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72,
- 0x6d, 0x61, 0x74, 0x28, 0x22, 0x25, 0x64, 0x2e, 0x25, 0x64, 0x2e, 0x25,
- 0x64, 0x2e, 0x25, 0x64, 0x22, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c,
- 0x20, 0x63, 0x2c, 0x20, 0x64, 0x29, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x70,
- 0x31, 0x2a, 0x32, 0x35, 0x36, 0x20, 0x2b, 0x20, 0x70, 0x32, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
- 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65,
- 0x72, 0x76, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70,
- 0x61, 0x73, 0x76, 0x74, 0x2e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
- 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74,
- 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74,
- 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x65, 0x70, 0x73,
- 0x76, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x65, 0x70,
- 0x73, 0x76, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72, 0x65,
- 0x70, 0x6c, 0x79, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x32, 0x39, 0x22, 0x29, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70,
- 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x3d, 0x20, 0x22, 0x25, 0x28,
- 0x28, 0x2e, 0x29, 0x28, 0x2e, 0x2d, 0x29, 0x25, 0x31, 0x28, 0x2e, 0x2d,
- 0x29, 0x25, 0x31, 0x28, 0x2e, 0x2d, 0x29, 0x25, 0x31, 0x25, 0x29, 0x22,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64,
- 0x2c, 0x20, 0x70, 0x72, 0x74, 0x2c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
- 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28,
- 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65,
- 0x72, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x22,
- 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x65, 0x70, 0x73, 0x76,
- 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73,
- 0x76, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x3d,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x67, 0x65, 0x74,
- 0x70, 0x65, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x6f, 0x72, 0x74,
- 0x20, 0x3d, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x63, 0x6c,
- 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76,
- 0x74, 0x2e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74, 0x2e, 0x70, 0x6f,
- 0x72, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f,
- 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x70, 0x6f, 0x72, 0x74, 0x28, 0x61,
- 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70,
- 0x61, 0x73, 0x76, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x64,
- 0x64, 0x72, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
- 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x70, 0x3a, 0x67, 0x65, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x6e,
- 0x61, 0x6d, 0x65, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76,
- 0x65, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72,
- 0x79, 0x28, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x62, 0x69, 0x6e,
- 0x64, 0x28, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x30,
- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61,
- 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74,
- 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a,
- 0x67, 0x65, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x28,
- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x73, 0x65, 0x74, 0x74,
- 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x28, 0x5f, 0x4d, 0x2e, 0x54, 0x49,
- 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x70, 0x6c, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x2e,
- 0x6d, 0x6f, 0x64, 0x28, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x32, 0x35,
- 0x36, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x70, 0x68, 0x20, 0x3d, 0x20, 0x28, 0x70, 0x6f, 0x72, 0x74, 0x20,
- 0x2d, 0x20, 0x70, 0x6c, 0x29, 0x2f, 0x32, 0x35, 0x36, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67, 0x20,
- 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
- 0x62, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72,
- 0x6d, 0x61, 0x74, 0x28, 0x22, 0x25, 0x73, 0x2c, 0x25, 0x64, 0x2c, 0x25,
- 0x64, 0x22, 0x2c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c,
- 0x20, 0x70, 0x68, 0x2c, 0x20, 0x70, 0x6c, 0x29, 0x2c, 0x20, 0x22, 0x25,
- 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x2c, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
- 0x64, 0x28, 0x22, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x2c, 0x20, 0x61, 0x72,
- 0x67, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22,
- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x65, 0x70, 0x72, 0x74, 0x28,
- 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x2c, 0x20, 0x61, 0x64, 0x64, 0x72,
- 0x65, 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76,
- 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
- 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c,
- 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x67, 0x65, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65,
- 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20,
- 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x62, 0x69, 0x6e, 0x64, 0x28, 0x61,
- 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x30, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x64, 0x64, 0x72,
- 0x65, 0x73, 0x73, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x67, 0x65, 0x74,
- 0x73, 0x6f, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65,
- 0x72, 0x76, 0x65, 0x72, 0x3a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6d, 0x65,
- 0x6f, 0x75, 0x74, 0x28, 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f,
- 0x55, 0x54, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61,
- 0x72, 0x67, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x7c, 0x25, 0x73, 0x7c,
- 0x25, 0x73, 0x7c, 0x25, 0x64, 0x7c, 0x22, 0x2c, 0x20, 0x66, 0x61, 0x6d,
- 0x69, 0x6c, 0x79, 0x2c, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
- 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
- 0x28, 0x22, 0x65, 0x70, 0x72, 0x74, 0x22, 0x2c, 0x20, 0x61, 0x72, 0x67,
- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a,
- 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f,
- 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x73,
- 0x65, 0x6e, 0x64, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x70, 0x61, 0x73, 0x76, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x22, 0x6e,
- 0x65, 0x65, 0x64, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20,
- 0x70, 0x61, 0x73, 0x76, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x22, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x70, 0x61, 0x73, 0x76, 0x63, 0x6f, 0x6e,
- 0x6e, 0x65, 0x63, 0x74, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67,
- 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6e, 0x64,
- 0x74, 0x2e, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f,
- 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72,
- 0x6c, 0x2e, 0x75, 0x6e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x28, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73,
- 0x65, 0x6e, 0x64, 0x74, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72,
- 0x20, 0x22, 0x22, 0x2c, 0x20, 0x22, 0x5e, 0x5b, 0x2f, 0x5c, 0x5c, 0x5d,
- 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20,
- 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x61,
- 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x69,
- 0x6c, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20,
- 0x3d, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
- 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x73, 0x74, 0x6f, 0x72,
- 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63,
- 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74,
- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79,
- 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63,
- 0x6b, 0x7b, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x31, 0x2e,
- 0x2e, 0x22, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73,
- 0x76, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x3a, 0x70, 0x6f, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
- 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20,
- 0x73, 0x65, 0x6e, 0x64, 0x74, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x20, 0x6f,
- 0x72, 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x70, 0x75, 0x6d, 0x70,
- 0x2e, 0x73, 0x74, 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x61, 0x64, 0x74, 0x20, 0x3d, 0x20,
- 0x7b, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x20, 0x7d, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x68,
- 0x65, 0x63, 0x6b, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x73, 0x72, 0x63, 0x2c, 0x20,
- 0x73, 0x6e, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
- 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73,
- 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x72, 0x65, 0x61, 0x64, 0x74, 0x2c,
- 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x72, 0x65, 0x61, 0x64,
- 0x79, 0x74, 0x5b, 0x74, 0x70, 0x5d, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a,
- 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29,
- 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x65,
- 0x70, 0x28, 0x73, 0x72, 0x63, 0x2c, 0x20, 0x73, 0x6e, 0x6b, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x69, 0x6e, 0x6b, 0x20, 0x3d,
- 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x69, 0x6e, 0x6b,
- 0x28, 0x22, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x2d, 0x77, 0x68, 0x65, 0x6e,
- 0x2d, 0x64, 0x6f, 0x6e, 0x65, 0x22, 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x64, 0x61, 0x74, 0x61, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x6c, 0x74, 0x6e, 0x31,
- 0x32, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x73,
- 0x65, 0x6e, 0x64, 0x74, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c,
- 0x20, 0x73, 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6b,
- 0x73, 0x74, 0x65, 0x70, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e,
- 0x64, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x22, 0x31, 0x2e, 0x2e,
- 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22,
- 0x29, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x63, 0x6c, 0x6f,
- 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6b, 0x69, 0x70, 0x28, 0x31, 0x2c,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x67,
- 0x65, 0x74, 0x73, 0x74, 0x61, 0x74, 0x73, 0x28, 0x29, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61,
- 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x0a, 0x65,
- 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
- 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65,
- 0x78, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x72, 0x65,
- 0x63, 0x76, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70,
- 0x61, 0x73, 0x76, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x22, 0x6e, 0x65,
- 0x65, 0x64, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x70,
- 0x61, 0x73, 0x76, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x22, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x70, 0x61, 0x73, 0x76, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x3a, 0x70, 0x61, 0x73, 0x76, 0x63, 0x6f, 0x6e, 0x6e,
- 0x65, 0x63, 0x74, 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x72, 0x67, 0x75,
- 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x63, 0x76, 0x74,
- 0x2e, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x72,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c,
- 0x2e, 0x75, 0x6e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x28, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x72, 0x65,
- 0x63, 0x76, 0x74, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20,
- 0x22, 0x22, 0x2c, 0x20, 0x22, 0x5e, 0x5b, 0x2f, 0x5c, 0x5c, 0x5d, 0x22,
- 0x2c, 0x20, 0x22, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d,
- 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x61, 0x72,
- 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d,
- 0x20, 0x72, 0x65, 0x63, 0x76, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x72, 0x65, 0x74, 0x72, 0x22,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72,
- 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f,
- 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
- 0x64, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x29,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x3d,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x7b,
- 0x22, 0x31, 0x2e, 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x32, 0x2e, 0x2e, 0x22,
- 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x63,
- 0x6f, 0x64, 0x65, 0x20, 0x3e, 0x3d, 0x20, 0x32, 0x30, 0x30, 0x29, 0x20,
- 0x61, 0x6e, 0x64, 0x20, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3c, 0x3d,
- 0x20, 0x32, 0x39, 0x39, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x63, 0x76, 0x74,
- 0x2e, 0x73, 0x69, 0x6e, 0x6b, 0x28, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x61, 0x73, 0x76, 0x74, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x70, 0x6f,
- 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x29, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
- 0x28, 0x22, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x2d, 0x63, 0x6c, 0x6f, 0x73,
- 0x65, 0x64, 0x22, 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61,
- 0x74, 0x61, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x63,
- 0x76, 0x74, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x20, 0x6f, 0x72, 0x20, 0x6c,
- 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x2e, 0x73, 0x74,
- 0x65, 0x70, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x70, 0x75,
- 0x6d, 0x70, 0x2e, 0x61, 0x6c, 0x6c, 0x28, 0x73, 0x6f, 0x75, 0x72, 0x63,
- 0x65, 0x2c, 0x20, 0x72, 0x65, 0x63, 0x76, 0x74, 0x2e, 0x73, 0x69, 0x6e,
- 0x6b, 0x2c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x66, 0x69, 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x22,
- 0x31, 0x2e, 0x2e, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32,
- 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3a,
- 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x20, 0x3d, 0x20,
- 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e,
- 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x63, 0x77, 0x64, 0x28,
- 0x64, 0x69, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x63,
- 0x77, 0x64, 0x22, 0x2c, 0x20, 0x64, 0x69, 0x72, 0x29, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63,
- 0x6b, 0x28, 0x32, 0x35, 0x30, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64,
- 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65,
- 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a,
- 0x74, 0x79, 0x70, 0x65, 0x28, 0x74, 0x79, 0x70, 0x65, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d,
- 0x61, 0x6e, 0x64, 0x28, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x20,
- 0x74, 0x79, 0x70, 0x65, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x32, 0x30,
- 0x30, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e,
- 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x67, 0x72, 0x65, 0x65,
- 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x7b, 0x22, 0x31, 0x2e, 0x2e,
- 0x22, 0x2c, 0x20, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x7d, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20,
- 0x22, 0x31, 0x2e, 0x2e, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22,
- 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a,
- 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64,
- 0x65, 0x78, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x28, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65,
- 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a,
- 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64,
- 0x65, 0x78, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x64,
- 0x61, 0x74, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65,
- 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65,
- 0x28, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64,
- 0x65, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x74, 0x2e, 0x75, 0x72, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x75, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x28, 0x74, 0x2e, 0x75, 0x72, 0x6c, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c,
- 0x76, 0x20, 0x69, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x61,
- 0x69, 0x72, 0x73, 0x28, 0x74, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x5b,
- 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x75, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x70, 0x75, 0x74, 0x28, 0x70, 0x75,
- 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x75, 0x74, 0x74,
- 0x20, 0x3d, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x28,
- 0x70, 0x75, 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x70, 0x75, 0x74,
- 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x73,
- 0x73, 0x69, 0x6e, 0x67, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d,
- 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x6f, 0x70, 0x65,
- 0x6e, 0x28, 0x70, 0x75, 0x74, 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c,
- 0x20, 0x70, 0x75, 0x74, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20,
- 0x70, 0x75, 0x74, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x67, 0x72, 0x65, 0x65, 0x74,
- 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x6c, 0x6f, 0x67,
- 0x69, 0x6e, 0x28, 0x70, 0x75, 0x74, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72,
- 0x2c, 0x20, 0x70, 0x75, 0x74, 0x74, 0x2e, 0x70, 0x61, 0x73, 0x73, 0x77,
- 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x70, 0x75, 0x74, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x20, 0x66, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x28, 0x70, 0x75,
- 0x74, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x29, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x65, 0x70, 0x73, 0x76, 0x28,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x73, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x3a, 0x73, 0x65, 0x6e,
- 0x64, 0x28, 0x70, 0x75, 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65,
- 0x6e, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x7b,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20,
- 0x22, 0x2f, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x63, 0x68,
- 0x65, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x22, 0x66, 0x74, 0x70, 0x22, 0x0a,
- 0x7d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63,
- 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x75, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x75, 0x72, 0x6c,
- 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x75, 0x2c, 0x20, 0x64, 0x65,
- 0x66, 0x61, 0x75, 0x6c, 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x74,
- 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22,
- 0x66, 0x74, 0x70, 0x22, 0x2c, 0x20, 0x22, 0x77, 0x72, 0x6f, 0x6e, 0x67,
- 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x27, 0x22, 0x20, 0x2e,
- 0x2e, 0x20, 0x74, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x2e,
- 0x2e, 0x20, 0x22, 0x27, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x74, 0x2e,
- 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x73, 0x73, 0x69,
- 0x6e, 0x67, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x70, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x22, 0x5e, 0x74, 0x79, 0x70, 0x65,
- 0x3d, 0x28, 0x2e, 0x29, 0x24, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x74, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63,
- 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6b, 0x69, 0x70, 0x28, 0x32, 0x2c, 0x20,
- 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28,
- 0x74, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x2c, 0x20, 0x70, 0x61,
- 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x74,
- 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x61, 0x22,
- 0x20, 0x6f, 0x72, 0x20, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d,
- 0x3d, 0x20, 0x22, 0x69, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x69, 0x6e, 0x76, 0x61,
- 0x6c, 0x69, 0x64, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x27, 0x22, 0x20,
- 0x2e, 0x2e, 0x20, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x2e, 0x2e,
- 0x20, 0x22, 0x27, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x5f, 0x4d, 0x2e, 0x67, 0x65,
- 0x6e, 0x65, 0x72, 0x69, 0x63, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x3d, 0x20,
- 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x66, 0x6f, 0x72, 0x6d, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x73, 0x70, 0x75, 0x74, 0x28, 0x75, 0x2c, 0x20, 0x62,
- 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x70, 0x75, 0x74, 0x74, 0x20, 0x3d, 0x20, 0x67, 0x65,
- 0x6e, 0x65, 0x72, 0x69, 0x63, 0x66, 0x6f, 0x72, 0x6d, 0x28, 0x75, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x75, 0x74, 0x74, 0x2e, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32,
- 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x73, 0x74, 0x72, 0x69,
- 0x6e, 0x67, 0x28, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x70, 0x75, 0x74,
- 0x28, 0x70, 0x75, 0x74, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x5f,
- 0x4d, 0x2e, 0x70, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b,
- 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x28, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x75, 0x74, 0x74,
- 0x2c, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65,
- 0x28, 0x70, 0x75, 0x74, 0x74, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x70, 0x75, 0x74, 0x28,
- 0x70, 0x75, 0x74, 0x74, 0x2c, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x74, 0x70, 0x75, 0x74, 0x28, 0x70, 0x75, 0x74,
- 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x29, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x74, 0x67, 0x65, 0x74, 0x28, 0x67, 0x65, 0x74, 0x74,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x67, 0x65, 0x74, 0x74, 0x20, 0x3d,
- 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x28, 0x67, 0x65,
- 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x63, 0x6b,
- 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x67, 0x65, 0x74, 0x74, 0x2e,
- 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x73, 0x73, 0x69,
- 0x6e, 0x67, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x22,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x66, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x28,
- 0x67, 0x65, 0x74, 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x67,
- 0x65, 0x74, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x67, 0x65,
- 0x74, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x66, 0x3a, 0x67, 0x72, 0x65, 0x65, 0x74, 0x28, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x6c, 0x6f, 0x67, 0x69, 0x6e,
- 0x28, 0x67, 0x65, 0x74, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20,
- 0x67, 0x65, 0x74, 0x74, 0x2e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
- 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x67, 0x65,
- 0x74, 0x74, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x20, 0x66, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x28, 0x67, 0x65, 0x74, 0x74,
- 0x2e, 0x74, 0x79, 0x70, 0x65, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x66, 0x3a, 0x65, 0x70, 0x73, 0x76, 0x28, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76,
- 0x65, 0x28, 0x67, 0x65, 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x3a, 0x63, 0x6c,
- 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x73, 0x67, 0x65, 0x74, 0x28, 0x75, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x65, 0x74, 0x74, 0x20,
- 0x3d, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x66, 0x6f, 0x72,
- 0x6d, 0x28, 0x75, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x74, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x67, 0x65, 0x74, 0x74, 0x2e, 0x73, 0x69, 0x6e, 0x6b, 0x20,
- 0x3d, 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x73, 0x69, 0x6e, 0x6b,
- 0x2e, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x74, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x74, 0x67, 0x65, 0x74, 0x28, 0x67, 0x65, 0x74, 0x74, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74,
- 0x28, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x5f, 0x4d, 0x2e, 0x63,
- 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63,
- 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x28,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x6d, 0x64,
- 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6d, 0x64, 0x74, 0x20,
- 0x3d, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x28, 0x63,
- 0x6d, 0x64, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x63,
- 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x63, 0x6d, 0x64, 0x74,
- 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x73, 0x73,
- 0x69, 0x6e, 0x67, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65,
- 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63,
- 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x22, 0x6d, 0x69, 0x73,
- 0x73, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
- 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x66, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x6f, 0x70, 0x65, 0x6e,
- 0x28, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20,
- 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x63,
- 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x67, 0x72, 0x65, 0x65, 0x74, 0x28,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x6c, 0x6f, 0x67, 0x69,
- 0x6e, 0x28, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2c,
- 0x20, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
- 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74,
- 0x79, 0x70, 0x65, 0x28, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
- 0x6d, 0x61, 0x6e, 0x64, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61,
- 0x62, 0x6c, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x63,
- 0x6d, 0x64, 0x74, 0x2e, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74,
- 0x20, 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x68, 0x65,
- 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x68,
- 0x65, 0x63, 0x6b, 0x20, 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c,
- 0x63, 0x6d, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x70, 0x61, 0x69, 0x72,
- 0x73, 0x28, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
- 0x64, 0x28, 0x63, 0x6d, 0x64, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d,
- 0x65, 0x6e, 0x74, 0x5b, 0x69, 0x5d, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5b, 0x69, 0x5d, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x63, 0x68, 0x65, 0x63, 0x6b,
- 0x5b, 0x69, 0x5d, 0x29, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x63, 0x6d,
- 0x64, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2c, 0x20,
- 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e,
- 0x74, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x68, 0x65, 0x63,
- 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28,
- 0x63, 0x6d, 0x64, 0x74, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x29, 0x29,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x65,
- 0x6e, 0x64, 0x29, 0x0a, 0x5f, 0x4d, 0x2e, 0x67, 0x65, 0x74, 0x20, 0x3d,
- 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
- 0x65, 0x63, 0x74, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x28, 0x67, 0x65, 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x28,
- 0x67, 0x65, 0x74, 0x74, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x67, 0x65, 0x74, 0x28, 0x67,
- 0x65, 0x74, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73,
- 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x67, 0x65,
- 0x74, 0x28, 0x67, 0x65, 0x74, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x5f, 0x4d, 0x0a,0x0};
- return luaL_dostring(L, (const char*)B);
-} /* end of embedded lua code */
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua b/Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua
deleted file mode 100644
index 875bbf6d562..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_headers.lua
+++ /dev/null
@@ -1,106 +0,0 @@
------------------------------------------------------------------------------
--- Canonic header field capitalization
--- LuaSocket toolkit.
--- Author: Diego Nehab
------------------------------------------------------------------------------
-if not(socket) then
- local socket = require("socket")
-end
-socket.headers = {}
-local _M = socket.headers
-
-_M.canonic = {
- ["accept"] = "Accept",
- ["accept-charset"] = "Accept-Charset",
- ["accept-encoding"] = "Accept-Encoding",
- ["accept-language"] = "Accept-Language",
- ["accept-ranges"] = "Accept-Ranges",
- ["action"] = "Action",
- ["alternate-recipient"] = "Alternate-Recipient",
- ["age"] = "Age",
- ["allow"] = "Allow",
- ["arrival-date"] = "Arrival-Date",
- ["authorization"] = "Authorization",
- ["bcc"] = "Bcc",
- ["cache-control"] = "Cache-Control",
- ["cc"] = "Cc",
- ["comments"] = "Comments",
- ["connection"] = "Connection",
- ["content-description"] = "Content-Description",
- ["content-disposition"] = "Content-Disposition",
- ["content-encoding"] = "Content-Encoding",
- ["content-id"] = "Content-ID",
- ["content-language"] = "Content-Language",
- ["content-length"] = "Content-Length",
- ["content-location"] = "Content-Location",
- ["content-md5"] = "Content-MD5",
- ["content-range"] = "Content-Range",
- ["content-transfer-encoding"] = "Content-Transfer-Encoding",
- ["content-type"] = "Content-Type",
- ["cookie"] = "Cookie",
- ["date"] = "Date",
- ["diagnostic-code"] = "Diagnostic-Code",
- ["dsn-gateway"] = "DSN-Gateway",
- ["etag"] = "ETag",
- ["expect"] = "Expect",
- ["expires"] = "Expires",
- ["final-log-id"] = "Final-Log-ID",
- ["final-recipient"] = "Final-Recipient",
- ["from"] = "From",
- ["host"] = "Host",
- ["if-match"] = "If-Match",
- ["if-modified-since"] = "If-Modified-Since",
- ["if-none-match"] = "If-None-Match",
- ["if-range"] = "If-Range",
- ["if-unmodified-since"] = "If-Unmodified-Since",
- ["in-reply-to"] = "In-Reply-To",
- ["keywords"] = "Keywords",
- ["last-attempt-date"] = "Last-Attempt-Date",
- ["last-modified"] = "Last-Modified",
- ["location"] = "Location",
- ["max-forwards"] = "Max-Forwards",
- ["message-id"] = "Message-ID",
- ["mime-version"] = "MIME-Version",
- ["original-envelope-id"] = "Original-Envelope-ID",
- ["original-recipient"] = "Original-Recipient",
- ["pragma"] = "Pragma",
- ["proxy-authenticate"] = "Proxy-Authenticate",
- ["proxy-authorization"] = "Proxy-Authorization",
- ["range"] = "Range",
- ["received"] = "Received",
- ["received-from-mta"] = "Received-From-MTA",
- ["references"] = "References",
- ["referer"] = "Referer",
- ["remote-mta"] = "Remote-MTA",
- ["reply-to"] = "Reply-To",
- ["reporting-mta"] = "Reporting-MTA",
- ["resent-bcc"] = "Resent-Bcc",
- ["resent-cc"] = "Resent-Cc",
- ["resent-date"] = "Resent-Date",
- ["resent-from"] = "Resent-From",
- ["resent-message-id"] = "Resent-Message-ID",
- ["resent-reply-to"] = "Resent-Reply-To",
- ["resent-sender"] = "Resent-Sender",
- ["resent-to"] = "Resent-To",
- ["retry-after"] = "Retry-After",
- ["return-path"] = "Return-Path",
- ["sender"] = "Sender",
- ["server"] = "Server",
- ["smtp-remote-recipient"] = "SMTP-Remote-Recipient",
- ["status"] = "Status",
- ["subject"] = "Subject",
- ["te"] = "TE",
- ["to"] = "To",
- ["trailer"] = "Trailer",
- ["transfer-encoding"] = "Transfer-Encoding",
- ["upgrade"] = "Upgrade",
- ["user-agent"] = "User-Agent",
- ["vary"] = "Vary",
- ["via"] = "Via",
- ["warning"] = "Warning",
- ["will-retry-until"] = "Will-Retry-Until",
- ["www-authenticate"] = "WWW-Authenticate",
- ["x-mailer"] = "X-Mailer",
-}
-
-return _M \ No newline at end of file
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c b/Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c
deleted file mode 100644
index 6121dd13204..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_headers_lua.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * This file is generated with xxd -i and bit of bash script.
-*/
-#include "lua.h"
-#include "lauxlib.h"
-
-int luatex_headers_lua_open (lua_State *L) {
- static unsigned char B[] = {
- 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x28, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x0a, 0x20, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d,
- 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x22, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x5f, 0x4d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
- 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x0a, 0x5f, 0x4d, 0x2e,
- 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,
- 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x63, 0x63,
- 0x65, 0x70, 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
- 0x43, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x65,
- 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, 0x6e, 0x63, 0x6f,
- 0x64, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67,
- 0x75, 0x61, 0x67, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x63,
- 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67,
- 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x63,
- 0x63, 0x65, 0x70, 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d,
- 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e,
- 0x61, 0x74, 0x65, 0x2d, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e,
- 0x74, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x6c, 0x74, 0x65, 0x72,
- 0x6e, 0x61, 0x74, 0x65, 0x2d, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65,
- 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61,
- 0x67, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x67, 0x65, 0x22,
- 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x6c, 0x6c, 0x6f,
- 0x77, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x6c, 0x6c, 0x6f, 0x77,
- 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x61, 0x72, 0x72,
- 0x69, 0x76, 0x61, 0x6c, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x41, 0x72, 0x72, 0x69, 0x76, 0x61, 0x6c, 0x2d, 0x44,
- 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x41, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x62, 0x63, 0x63, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x42, 0x63, 0x63, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74,
- 0x72, 0x6f, 0x6c, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x61, 0x63,
- 0x68, 0x65, 0x2d, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x2c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x63, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x43, 0x63, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x5d,
- 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73,
- 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e,
- 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22,
- 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
- 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6e,
- 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
- 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x64, 0x69, 0x73,
- 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x44, 0x69,
- 0x73, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
- 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5d,
- 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
- 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
- 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6e,
- 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x49, 0x44, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
- 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x61,
- 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c,
- 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43,
- 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74,
- 0x68, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69,
- 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e,
- 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4d, 0x44,
- 0x35, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
- 0x2d, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74,
- 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
- 0x64, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66,
- 0x65, 0x72, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x22,
- 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79,
- 0x70, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x63,
- 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x43,
- 0x6f, 0x6f, 0x6b, 0x69, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x64, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x44, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x64, 0x69, 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x2d,
- 0x63, 0x6f, 0x64, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x44, 0x69,
- 0x61, 0x67, 0x6e, 0x6f, 0x73, 0x74, 0x69, 0x63, 0x2d, 0x43, 0x6f, 0x64,
- 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x64, 0x73,
- 0x6e, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x44, 0x53, 0x4e, 0x2d, 0x47, 0x61, 0x74, 0x65, 0x77,
- 0x61, 0x79, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x65,
- 0x74, 0x61, 0x67, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x45, 0x54, 0x61,
- 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x65, 0x78,
- 0x70, 0x65, 0x63, 0x74, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x45, 0x78,
- 0x70, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x2d,
- 0x6c, 0x6f, 0x67, 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x2d, 0x4c, 0x6f, 0x67, 0x2d, 0x49, 0x44,
- 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x66, 0x69, 0x6e,
- 0x61, 0x6c, 0x2d, 0x72, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x2d,
- 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x66, 0x72, 0x6f, 0x6d, 0x22, 0x5d,
- 0x20, 0x3d, 0x20, 0x22, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x48, 0x6f, 0x73, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x69, 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x49, 0x66, 0x2d, 0x4d, 0x61, 0x74,
- 0x63, 0x68, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x69,
- 0x66, 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
- 0x69, 0x6e, 0x63, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x49, 0x66,
- 0x2d, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x53, 0x69,
- 0x6e, 0x63, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, 0x6d, 0x61, 0x74, 0x63,
- 0x68, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x49, 0x66, 0x2d, 0x4e, 0x6f,
- 0x6e, 0x65, 0x2d, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,
- 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x49, 0x66, 0x2d, 0x52, 0x61,
- 0x6e, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x69, 0x66, 0x2d, 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
- 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x49, 0x66, 0x2d, 0x55, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
- 0x65, 0x64, 0x2d, 0x53, 0x69, 0x6e, 0x63, 0x65, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x69, 0x6e, 0x2d, 0x72, 0x65, 0x70, 0x6c,
- 0x79, 0x2d, 0x74, 0x6f, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x49, 0x6e,
- 0x2d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2d, 0x54, 0x6f, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72,
- 0x64, 0x73, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4b, 0x65, 0x79, 0x77,
- 0x6f, 0x72, 0x64, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x6c, 0x61, 0x73, 0x74, 0x2d, 0x61, 0x74, 0x74, 0x65, 0x6d, 0x70,
- 0x74, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x4c, 0x61, 0x73, 0x74, 0x2d, 0x41, 0x74, 0x74, 0x65, 0x6d, 0x70, 0x74,
- 0x2d, 0x44, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66,
- 0x69, 0x65, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4c, 0x61, 0x73,
- 0x74, 0x2d, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x22, 0x2c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4c, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72,
- 0x64, 0x73, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4d, 0x61, 0x78, 0x2d,
- 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
- 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4d, 0x65, 0x73,
- 0x73, 0x61, 0x67, 0x65, 0x2d, 0x49, 0x44, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x6d, 0x69, 0x6d, 0x65, 0x2d, 0x76, 0x65, 0x72,
- 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4d, 0x49,
- 0x4d, 0x45, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x2c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x6f, 0x72, 0x69, 0x67, 0x69,
- 0x6e, 0x61, 0x6c, 0x2d, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65,
- 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x4f, 0x72, 0x69,
- 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x2d, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f,
- 0x70, 0x65, 0x2d, 0x49, 0x44, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x2d, 0x72,
- 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x2d, 0x52,
- 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x50, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x22,
- 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x70, 0x72, 0x6f, 0x78,
- 0x79, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
- 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x50, 0x72, 0x6f, 0x78,
- 0x79, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
- 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x70,
- 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
- 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
- 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x5d, 0x20,
- 0x3d, 0x20, 0x22, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
- 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x63, 0x65, 0x69,
- 0x76, 0x65, 0x64, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x2d, 0x66, 0x72, 0x6f,
- 0x6d, 0x2d, 0x6d, 0x74, 0x61, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52,
- 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x2d, 0x46, 0x72, 0x6f, 0x6d,
- 0x2d, 0x4d, 0x54, 0x41, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
- 0x63, 0x65, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2d,
- 0x6d, 0x74, 0x61, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x6d,
- 0x6f, 0x74, 0x65, 0x2d, 0x4d, 0x54, 0x41, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x2d, 0x74, 0x6f,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2d,
- 0x54, 0x6f, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x72,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x74, 0x61,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74,
- 0x69, 0x6e, 0x67, 0x2d, 0x4d, 0x54, 0x41, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x62,
- 0x63, 0x63, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65,
- 0x6e, 0x74, 0x2d, 0x42, 0x63, 0x63, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x63, 0x63,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x74,
- 0x2d, 0x43, 0x63, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x64, 0x61, 0x74, 0x65, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d,
- 0x44, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b,
- 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x66, 0x72, 0x6f, 0x6d,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x74,
- 0x2d, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x6d, 0x65, 0x73,
- 0x73, 0x61, 0x67, 0x65, 0x2d, 0x69, 0x64, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x4d, 0x65, 0x73, 0x73,
- 0x61, 0x67, 0x65, 0x2d, 0x49, 0x44, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x72, 0x65,
- 0x70, 0x6c, 0x79, 0x2d, 0x74, 0x6f, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x52, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x52, 0x65, 0x70, 0x6c, 0x79,
- 0x2d, 0x54, 0x6f, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22,
- 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d, 0x73, 0x65, 0x6e, 0x64, 0x65,
- 0x72, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65, 0x6e,
- 0x74, 0x2d, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x2d,
- 0x74, 0x6f, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x73, 0x65,
- 0x6e, 0x74, 0x2d, 0x54, 0x6f, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x72, 0x65, 0x74, 0x72, 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65,
- 0x72, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x74, 0x72, 0x79,
- 0x2d, 0x41, 0x66, 0x74, 0x65, 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x2d, 0x70, 0x61,
- 0x74, 0x68, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x52, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x2d, 0x50, 0x61, 0x74, 0x68, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x5d,
- 0x20, 0x3d, 0x20, 0x22, 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x2c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x53, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x73, 0x6d,
- 0x74, 0x70, 0x2d, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x2d, 0x72, 0x65,
- 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x53, 0x4d, 0x54, 0x50, 0x2d, 0x52, 0x65, 0x6d, 0x6f, 0x74, 0x65,
- 0x2d, 0x52, 0x65, 0x63, 0x69, 0x70, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x2c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x73, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x53, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x73, 0x75,
- 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x53,
- 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x54,
- 0x45, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x74, 0x6f,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x54, 0x6f, 0x22, 0x2c, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x5b, 0x22, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72,
- 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x54, 0x72, 0x61, 0x69, 0x6c, 0x65,
- 0x72, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x74, 0x72,
- 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, 0x6e, 0x63, 0x6f, 0x64,
- 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x54, 0x72, 0x61,
- 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x45, 0x6e, 0x63, 0x6f, 0x64, 0x69,
- 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x75,
- 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x75, 0x73, 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65,
- 0x6e, 0x74, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x55, 0x73, 0x65, 0x72,
- 0x2d, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x76, 0x61, 0x72, 0x79, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x56, 0x61, 0x72, 0x79, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x76, 0x69, 0x61, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x56,
- 0x69, 0x61, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x5b, 0x22, 0x77,
- 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22,
- 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x5b, 0x22, 0x77, 0x69, 0x6c, 0x6c, 0x2d, 0x72, 0x65, 0x74,
- 0x72, 0x79, 0x2d, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0x5d, 0x20, 0x3d,
- 0x20, 0x22, 0x57, 0x69, 0x6c, 0x6c, 0x2d, 0x52, 0x65, 0x74, 0x72, 0x79,
- 0x2d, 0x55, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x5b, 0x22, 0x77, 0x77, 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65,
- 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20,
- 0x22, 0x57, 0x57, 0x57, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x5b, 0x22, 0x78, 0x2d, 0x6d, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x22, 0x5d,
- 0x20, 0x3d, 0x20, 0x22, 0x58, 0x2d, 0x4d, 0x61, 0x69, 0x6c, 0x65, 0x72,
- 0x22, 0x2c, 0x0a, 0x7d, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x5f, 0x4d,0x0};
- return luaL_dostring(L, (const char*)B);
-} /* end of embedded lua code */
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua b/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua
deleted file mode 100644
index c19838b841c..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp.lua
+++ /dev/null
@@ -1,256 +0,0 @@
------------------------------------------------------------------------------
--- SMTP client support for the Lua language.
--- LuaSocket toolkit.
--- Author: Diego Nehab
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- Declare module and import dependencies
------------------------------------------------------------------------------
-local base = _G
-local coroutine = require("coroutine")
-local string = require("string")
-local math = require("math")
-local os = require("os")
-local socket = socket or require("socket") ;
-local tp = socket.tp or require("socket.tp");
-local ltn12 = ltn12 or require("ltn12");
-local headers = socket.headers or require("socket.headers");
-local mime = mime or require("mime");
-
-socket.smtp = {}
-local _M = socket.smtp
-
------------------------------------------------------------------------------
--- Program constants
------------------------------------------------------------------------------
--- timeout for connection
-_M.TIMEOUT = 60
--- default server used to send e-mails
-_M.SERVER = "localhost"
--- default port
-_M.PORT = 25
--- domain used in HELO command and default sendmail
--- If we are under a CGI, try to get from environment
-_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost"
--- default time zone (means we don't know)
-_M.ZONE = "-0000"
-
----------------------------------------------------------------------------
--- Low level SMTP API
------------------------------------------------------------------------------
-local metat = { __index = {} }
-
-function metat.__index:greet(domain)
- self.try(self.tp:check("2.."))
- self.try(self.tp:command("EHLO", domain or _M.DOMAIN))
- return socket.skip(1, self.try(self.tp:check("2..")))
-end
-
-function metat.__index:mail(from)
- self.try(self.tp:command("MAIL", "FROM:" .. from))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:rcpt(to)
- self.try(self.tp:command("RCPT", "TO:" .. to))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:data(src, step)
- self.try(self.tp:command("DATA"))
- self.try(self.tp:check("3.."))
- self.try(self.tp:source(src, step))
- self.try(self.tp:send("\r\n.\r\n"))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:quit()
- self.try(self.tp:command("QUIT"))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:close()
- return self.tp:close()
-end
-
-function metat.__index:login(user, password)
- self.try(self.tp:command("AUTH", "LOGIN"))
- self.try(self.tp:check("3.."))
- self.try(self.tp:send(mime.b64(user) .. "\r\n"))
- self.try(self.tp:check("3.."))
- self.try(self.tp:send(mime.b64(password) .. "\r\n"))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:plain(user, password)
- local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
- self.try(self.tp:command("AUTH", auth))
- return self.try(self.tp:check("2.."))
-end
-
-function metat.__index:auth(user, password, ext)
- if not user or not password then return 1 end
- if string.find(ext, "AUTH[^\n]+LOGIN") then
- return self:login(user, password)
- elseif string.find(ext, "AUTH[^\n]+PLAIN") then
- return self:plain(user, password)
- else
- self.try(nil, "authentication not supported")
- end
-end
-
--- send message or throw an exception
-function metat.__index:send(mailt)
- self:mail(mailt.from)
- if base.type(mailt.rcpt) == "table" then
- for i,v in base.ipairs(mailt.rcpt) do
- self:rcpt(v)
- end
- else
- self:rcpt(mailt.rcpt)
- end
- self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
-end
-
-function _M.open(server, port, create)
- local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT,
- _M.TIMEOUT, create))
- local s = base.setmetatable({tp = tp}, metat)
- -- make sure tp is closed if we get an exception
- s.try = socket.newtry(function()
- s:close()
- end)
- return s
-end
-
--- convert headers to lowercase
-local function lower_headers(headers)
- local lower = {}
- for i,v in base.pairs(headers or lower) do
- lower[string.lower(i)] = v
- end
- return lower
-end
-
----------------------------------------------------------------------------
--- Multipart message source
------------------------------------------------------------------------------
--- returns a hopefully unique mime boundary
-local seqno = 0
-local function newboundary()
- seqno = seqno + 1
- return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
- math.random(0, 99999), seqno)
-end
-
--- send_message forward declaration
-local send_message
-
--- yield the headers all at once, it's faster
-local function send_headers(tosend)
- local canonic = headers.canonic
- local h = "\r\n"
- for f,v in base.pairs(tosend) do
- h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h
- end
- coroutine.yield(h)
-end
-
--- yield multipart message body from a multipart message table
-local function send_multipart(mesgt)
- -- make sure we have our boundary and send headers
- local bd = newboundary()
- local headers = lower_headers(mesgt.headers or {})
- headers['content-type'] = headers['content-type'] or 'multipart/mixed'
- headers['content-type'] = headers['content-type'] ..
- '; boundary="' .. bd .. '"'
- send_headers(headers)
- -- send preamble
- if mesgt.body.preamble then
- coroutine.yield(mesgt.body.preamble)
- coroutine.yield("\r\n")
- end
- -- send each part separated by a boundary
- for i, m in base.ipairs(mesgt.body) do
- coroutine.yield("\r\n--" .. bd .. "\r\n")
- send_message(m)
- end
- -- send last boundary
- coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
- -- send epilogue
- if mesgt.body.epilogue then
- coroutine.yield(mesgt.body.epilogue)
- coroutine.yield("\r\n")
- end
-end
-
--- yield message body from a source
-local function send_source(mesgt)
- -- make sure we have a content-type
- local headers = lower_headers(mesgt.headers or {})
- headers['content-type'] = headers['content-type'] or
- 'text/plain; charset="iso-8859-1"'
- send_headers(headers)
- -- send body from source
- while true do
- local chunk, err = mesgt.body()
- if err then coroutine.yield(nil, err)
- elseif chunk then coroutine.yield(chunk)
- else break end
- end
-end
-
--- yield message body from a string
-local function send_string(mesgt)
- -- make sure we have a content-type
- local headers = lower_headers(mesgt.headers or {})
- headers['content-type'] = headers['content-type'] or
- 'text/plain; charset="iso-8859-1"'
- send_headers(headers)
- -- send body from string
- coroutine.yield(mesgt.body)
-end
-
--- message source
-function send_message(mesgt)
- if base.type(mesgt.body) == "table" then send_multipart(mesgt)
- elseif base.type(mesgt.body) == "function" then send_source(mesgt)
- else send_string(mesgt) end
-end
-
--- set defaul headers
-local function adjust_headers(mesgt)
- local lower = lower_headers(mesgt.headers)
- lower["date"] = lower["date"] or
- os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE)
- lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
- -- this can't be overriden
- lower["mime-version"] = "1.0"
- return lower
-end
-
-function _M.message(mesgt)
- mesgt.headers = adjust_headers(mesgt)
- -- create and return message source
- local co = coroutine.create(function() send_message(mesgt) end)
- return function()
- local ret, a, b = coroutine.resume(co)
- if ret then return a, b
- else return nil, a end
- end
-end
-
----------------------------------------------------------------------------
--- High level SMTP API
------------------------------------------------------------------------------
-_M.send = socket.protect(function(mailt)
- local s = _M.open(mailt.server, mailt.port, mailt.create)
- local ext = s:greet(mailt.domain)
- s:auth(mailt.user, mailt.password, ext)
- s:send(mailt)
- s:quit()
- return s:close()
-end)
-
-return _M \ No newline at end of file
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c b/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c
deleted file mode 100644
index 6e7ec8bb4a7..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_smtp_lua.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * This file is generated with xxd -i and bit of bash script.
-*/
-#include "lua.h"
-#include "lauxlib.h"
-
-int luatex_smtp_lua_open (lua_State *L) {
- static unsigned char B[] = {
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d,
- 0x20, 0x5f, 0x47, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f,
- 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x20, 0x3d, 0x20, 0x72, 0x65,
- 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x63, 0x6f, 0x72, 0x6f, 0x75,
- 0x74, 0x69, 0x6e, 0x65, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x72, 0x65,
- 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61,
- 0x74, 0x68, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65,
- 0x28, 0x22, 0x6d, 0x61, 0x74, 0x68, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x6f, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75,
- 0x69, 0x72, 0x65, 0x28, 0x22, 0x6f, 0x73, 0x22, 0x29, 0x0a, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d,
- 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x72,
- 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b,
- 0x65, 0x74, 0x22, 0x29, 0x20, 0x3b, 0x20, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x74, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x2e, 0x74, 0x70, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75,
- 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
- 0x74, 0x70, 0x22, 0x29, 0x3b, 0x20, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x74, 0x6e,
- 0x31, 0x32, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72,
- 0x65, 0x28, 0x22, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x22, 0x29, 0x3b, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x68,
- 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65,
- 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x29, 0x3b,
- 0x20, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x69, 0x6d, 0x65,
- 0x20, 0x3d, 0x20, 0x6d, 0x69, 0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x72,
- 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x6d, 0x69, 0x6d, 0x65,
- 0x22, 0x29, 0x3b, 0x20, 0x0a, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
- 0x73, 0x6d, 0x74, 0x70, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x6c, 0x6f,
- 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x4d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63,
- 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6d, 0x74, 0x70, 0x0a, 0x5f, 0x4d, 0x2e,
- 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x20, 0x3d, 0x20, 0x36, 0x30,
- 0x0a, 0x5f, 0x4d, 0x2e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x20, 0x3d,
- 0x20, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x22,
- 0x0a, 0x5f, 0x4d, 0x2e, 0x50, 0x4f, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x32,
- 0x35, 0x0a, 0x5f, 0x4d, 0x2e, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x20,
- 0x3d, 0x20, 0x6f, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x28,
- 0x22, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x4e, 0x41, 0x4d, 0x45,
- 0x22, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x68, 0x6f, 0x73, 0x74, 0x22, 0x0a, 0x5f, 0x4d, 0x2e, 0x5a, 0x4f, 0x4e,
- 0x45, 0x20, 0x3d, 0x20, 0x22, 0x2d, 0x30, 0x30, 0x30, 0x30, 0x22, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x20,
- 0x3d, 0x20, 0x7b, 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20,
- 0x3d, 0x20, 0x7b, 0x7d, 0x20, 0x7d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f,
- 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x67, 0x72, 0x65, 0x65, 0x74, 0x28,
- 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22,
- 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28,
- 0x22, 0x45, 0x48, 0x4c, 0x4f, 0x22, 0x2c, 0x20, 0x64, 0x6f, 0x6d, 0x61,
- 0x69, 0x6e, 0x20, 0x6f, 0x72, 0x20, 0x5f, 0x4d, 0x2e, 0x44, 0x4f, 0x4d,
- 0x41, 0x49, 0x4e, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
- 0x73, 0x6b, 0x69, 0x70, 0x28, 0x31, 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22,
- 0x29, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x6d, 0x61, 0x69, 0x6c, 0x28,
- 0x66, 0x72, 0x6f, 0x6d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22,
- 0x4d, 0x41, 0x49, 0x4c, 0x22, 0x2c, 0x20, 0x22, 0x46, 0x52, 0x4f, 0x4d,
- 0x3a, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x29, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22,
- 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61,
- 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x72, 0x63,
- 0x70, 0x74, 0x28, 0x74, 0x6f, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28,
- 0x22, 0x52, 0x43, 0x50, 0x54, 0x22, 0x2c, 0x20, 0x22, 0x54, 0x4f, 0x3a,
- 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x74, 0x6f, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e,
- 0x22, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x64, 0x61, 0x74, 0x61, 0x28,
- 0x73, 0x72, 0x63, 0x2c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d,
- 0x61, 0x6e, 0x64, 0x28, 0x22, 0x44, 0x41, 0x54, 0x41, 0x22, 0x29, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72,
- 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68,
- 0x65, 0x63, 0x6b, 0x28, 0x22, 0x33, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x73, 0x6f, 0x75,
- 0x72, 0x63, 0x65, 0x28, 0x73, 0x72, 0x63, 0x2c, 0x20, 0x73, 0x74, 0x65,
- 0x70, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70,
- 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x2e,
- 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a,
- 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79,
- 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d,
- 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x51, 0x55, 0x49, 0x54, 0x22, 0x29,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28,
- 0x22, 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74,
- 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x63,
- 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d,
- 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78,
- 0x3a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x28, 0x75, 0x73, 0x65, 0x72, 0x2c,
- 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d,
- 0x61, 0x6e, 0x64, 0x28, 0x22, 0x41, 0x55, 0x54, 0x48, 0x22, 0x2c, 0x20,
- 0x22, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b,
- 0x28, 0x22, 0x33, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65,
- 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x6d,
- 0x69, 0x6d, 0x65, 0x2e, 0x62, 0x36, 0x34, 0x28, 0x75, 0x73, 0x65, 0x72,
- 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63,
- 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x33, 0x2e, 0x2e, 0x22, 0x29, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72,
- 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x73, 0x65,
- 0x6e, 0x64, 0x28, 0x6d, 0x69, 0x6d, 0x65, 0x2e, 0x62, 0x36, 0x34, 0x28,
- 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x29, 0x20, 0x2e, 0x2e,
- 0x20, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22, 0x32, 0x2e, 0x2e,
- 0x22, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x70, 0x6c, 0x61, 0x69, 0x6e,
- 0x28, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77,
- 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x61, 0x75, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x22, 0x50,
- 0x4c, 0x41, 0x49, 0x4e, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6d, 0x69,
- 0x6d, 0x65, 0x2e, 0x62, 0x36, 0x34, 0x28, 0x22, 0x5c, 0x30, 0x22, 0x20,
- 0x2e, 0x2e, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x2e, 0x2e, 0x20, 0x22,
- 0x5c, 0x30, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77,
- 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74,
- 0x70, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x28, 0x22, 0x41,
- 0x55, 0x54, 0x48, 0x22, 0x2c, 0x20, 0x61, 0x75, 0x74, 0x68, 0x29, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x73, 0x65, 0x6c,
- 0x66, 0x2e, 0x74, 0x70, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x22,
- 0x32, 0x2e, 0x2e, 0x22, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61,
- 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x61, 0x75,
- 0x74, 0x68, 0x28, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61, 0x73,
- 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x65, 0x78, 0x74, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75,
- 0x73, 0x65, 0x72, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x70,
- 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x65, 0x78, 0x74,
- 0x2c, 0x20, 0x22, 0x41, 0x55, 0x54, 0x48, 0x5b, 0x5e, 0x5c, 0x6e, 0x5d,
- 0x2b, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x6c, 0x6f,
- 0x67, 0x69, 0x6e, 0x28, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61,
- 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x65, 0x78, 0x74, 0x2c, 0x20,
- 0x22, 0x41, 0x55, 0x54, 0x48, 0x5b, 0x5e, 0x5c, 0x6e, 0x5d, 0x2b, 0x50,
- 0x4c, 0x41, 0x49, 0x4e, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x70, 0x6c, 0x61, 0x69,
- 0x6e, 0x28, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x70, 0x61, 0x73, 0x73,
- 0x77, 0x6f, 0x72, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x74, 0x72, 0x79, 0x28, 0x6e, 0x69, 0x6c, 0x2c,
- 0x20, 0x22, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x75, 0x70,
- 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e,
- 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x73, 0x65, 0x6e, 0x64,
- 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x6d, 0x61, 0x69, 0x6c, 0x28, 0x6d, 0x61,
- 0x69, 0x6c, 0x74, 0x2e, 0x66, 0x72, 0x6f, 0x6d, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79,
- 0x70, 0x65, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x72, 0x63, 0x70,
- 0x74, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x76, 0x20, 0x69,
- 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x69, 0x70, 0x61, 0x69, 0x72,
- 0x73, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x72, 0x63, 0x70, 0x74,
- 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x3a, 0x72, 0x63,
- 0x70, 0x74, 0x28, 0x76, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x3a, 0x72, 0x63, 0x70, 0x74, 0x28, 0x6d, 0x61, 0x69,
- 0x6c, 0x74, 0x2e, 0x72, 0x63, 0x70, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c,
- 0x66, 0x3a, 0x64, 0x61, 0x74, 0x61, 0x28, 0x6c, 0x74, 0x6e, 0x31, 0x32,
- 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x63, 0x68, 0x61, 0x69,
- 0x6e, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x73, 0x6f, 0x75, 0x72,
- 0x63, 0x65, 0x2c, 0x20, 0x6d, 0x69, 0x6d, 0x65, 0x2e, 0x73, 0x74, 0x75,
- 0x66, 0x66, 0x28, 0x29, 0x29, 0x2c, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x74,
- 0x2e, 0x73, 0x74, 0x65, 0x70, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x6f,
- 0x70, 0x65, 0x6e, 0x28, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x20,
- 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x74, 0x70, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e,
- 0x74, 0x72, 0x79, 0x28, 0x74, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
- 0x63, 0x74, 0x28, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x6f, 0x72,
- 0x20, 0x5f, 0x4d, 0x2e, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x2c, 0x20,
- 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x5f, 0x4d, 0x2e, 0x50,
- 0x4f, 0x52, 0x54, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x2c,
- 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20,
- 0x62, 0x61, 0x73, 0x65, 0x2e, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x74, 0x70, 0x20, 0x3d, 0x20,
- 0x74, 0x70, 0x7d, 0x2c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x73, 0x2e, 0x74, 0x72, 0x79, 0x20, 0x3d, 0x20,
- 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x6e, 0x65, 0x77, 0x74, 0x72,
- 0x79, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x3a, 0x63,
- 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x73, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
- 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x28, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x77,
- 0x65, 0x72, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x62,
- 0x61, 0x73, 0x65, 0x2e, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x68, 0x65,
- 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x77,
- 0x65, 0x72, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x73, 0x74, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x28, 0x69, 0x29,
- 0x5d, 0x20, 0x3d, 0x20, 0x76, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x71, 0x6e, 0x6f, 0x20, 0x3d,
- 0x20, 0x30, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6e, 0x65, 0x77, 0x62, 0x6f, 0x75,
- 0x6e, 0x64, 0x61, 0x72, 0x79, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x73, 0x65, 0x71, 0x6e, 0x6f, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x71, 0x6e,
- 0x6f, 0x20, 0x2b, 0x20, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x27, 0x25, 0x73, 0x25, 0x30,
- 0x35, 0x64, 0x3d, 0x3d, 0x25, 0x30, 0x35, 0x75, 0x27, 0x2c, 0x20, 0x6f,
- 0x73, 0x2e, 0x64, 0x61, 0x74, 0x65, 0x28, 0x27, 0x25, 0x64, 0x25, 0x6d,
- 0x25, 0x59, 0x25, 0x48, 0x25, 0x4d, 0x25, 0x53, 0x27, 0x29, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x74, 0x68,
- 0x2e, 0x72, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x28, 0x30, 0x2c, 0x20, 0x39,
- 0x39, 0x39, 0x39, 0x39, 0x29, 0x2c, 0x20, 0x73, 0x65, 0x71, 0x6e, 0x6f,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x68, 0x65, 0x61,
- 0x64, 0x65, 0x72, 0x73, 0x28, 0x74, 0x6f, 0x73, 0x65, 0x6e, 0x64, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63,
- 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x3d, 0x20, 0x68, 0x65, 0x61,
- 0x64, 0x65, 0x72, 0x73, 0x2e, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68,
- 0x20, 0x3d, 0x20, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x2c, 0x76, 0x20, 0x69, 0x6e,
- 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28,
- 0x74, 0x6f, 0x73, 0x65, 0x6e, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x20, 0x3d, 0x20, 0x28,
- 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x5b, 0x66, 0x5d, 0x20, 0x6f,
- 0x72, 0x20, 0x66, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x27, 0x3a, 0x20, 0x27,
- 0x20, 0x2e, 0x2e, 0x20, 0x76, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5c, 0x72,
- 0x5c, 0x6e, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x68, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x72,
- 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64,
- 0x28, 0x68, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73,
- 0x65, 0x6e, 0x64, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72,
- 0x74, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x64, 0x20, 0x3d, 0x20,
- 0x6e, 0x65, 0x77, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x28,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f,
- 0x77, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x28,
- 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x20, 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b, 0x27, 0x63, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x27, 0x5d,
- 0x20, 0x3d, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b, 0x27,
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65,
- 0x27, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x6d, 0x75, 0x6c, 0x74, 0x69,
- 0x70, 0x61, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x27, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b,
- 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70,
- 0x65, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x5b, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74,
- 0x79, 0x70, 0x65, 0x27, 0x5d, 0x20, 0x2e, 0x2e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x3b, 0x20, 0x62, 0x6f, 0x75, 0x6e,
- 0x64, 0x61, 0x72, 0x79, 0x3d, 0x22, 0x27, 0x20, 0x2e, 0x2e, 0x20, 0x20,
- 0x62, 0x64, 0x20, 0x2e, 0x2e, 0x20, 0x27, 0x22, 0x27, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65,
- 0x72, 0x73, 0x28, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6d, 0x65, 0x73, 0x67, 0x74,
- 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x65, 0x61, 0x6d, 0x62,
- 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e,
- 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x6d, 0x65, 0x73, 0x67,
- 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e, 0x70, 0x72, 0x65, 0x61, 0x6d,
- 0x62, 0x6c, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79,
- 0x69, 0x65, 0x6c, 0x64, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x20, 0x6d, 0x20, 0x69, 0x6e,
- 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73,
- 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29,
- 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69,
- 0x65, 0x6c, 0x64, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x2d, 0x2d, 0x22,
- 0x20, 0x2e, 0x2e, 0x20, 0x62, 0x64, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5c,
- 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
- 0x67, 0x65, 0x28, 0x6d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74,
- 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x22, 0x5c,
- 0x72, 0x5c, 0x6e, 0x2d, 0x2d, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x62, 0x64,
- 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2d, 0x2d, 0x5c, 0x72, 0x5c, 0x6e, 0x5c,
- 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2e,
- 0x65, 0x70, 0x69, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f,
- 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c,
- 0x64, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79,
- 0x2e, 0x65, 0x70, 0x69, 0x6c, 0x6f, 0x67, 0x75, 0x65, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75,
- 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x22,
- 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65,
- 0x6e, 0x64, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x28, 0x6d, 0x65,
- 0x73, 0x67, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d,
- 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65,
- 0x72, 0x73, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x68, 0x65, 0x61,
- 0x64, 0x65, 0x72, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b,
- 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70,
- 0x65, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
- 0x73, 0x5b, 0x27, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74,
- 0x79, 0x70, 0x65, 0x27, 0x5d, 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x27, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70,
- 0x6c, 0x61, 0x69, 0x6e, 0x3b, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
- 0x74, 0x3d, 0x22, 0x69, 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,
- 0x31, 0x22, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6e, 0x64,
- 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x28, 0x68, 0x65, 0x61,
- 0x64, 0x65, 0x72, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77, 0x68,
- 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x2c, 0x20, 0x65, 0x72, 0x72,
- 0x20, 0x3d, 0x20, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64,
- 0x79, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x79, 0x69,
- 0x65, 0x6c, 0x64, 0x28, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x65, 0x72, 0x72,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x69, 0x66, 0x20, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e,
- 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x63, 0x68, 0x75, 0x6e,
- 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6c, 0x73, 0x65, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x65,
- 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x77, 0x65,
- 0x72, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x28, 0x6d, 0x65,
- 0x73, 0x67, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20,
- 0x6f, 0x72, 0x20, 0x7b, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x68,
- 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b, 0x27, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x27, 0x5d, 0x20, 0x3d,
- 0x20, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x5b, 0x27, 0x63, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x27, 0x5d,
- 0x20, 0x6f, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x27, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x3b,
- 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x22, 0x69, 0x73,
- 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, 0x31, 0x22, 0x27, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x68, 0x65, 0x61, 0x64,
- 0x65, 0x72, 0x73, 0x28, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69,
- 0x6e, 0x65, 0x2e, 0x79, 0x69, 0x65, 0x6c, 0x64, 0x28, 0x6d, 0x65, 0x73,
- 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x65, 0x6e, 0x64,
- 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65,
- 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28, 0x6d,
- 0x65, 0x73, 0x67, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6d,
- 0x65, 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x20, 0x3d,
- 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x6d, 0x75, 0x6c, 0x74,
- 0x69, 0x70, 0x61, 0x72, 0x74, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20,
- 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6d, 0x65,
- 0x73, 0x67, 0x74, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x20, 0x3d, 0x3d,
- 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x73, 0x6f,
- 0x75, 0x72, 0x63, 0x65, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x73, 0x65, 0x6e,
- 0x64, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x6d, 0x65, 0x73,
- 0x67, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x5f, 0x68, 0x65,
- 0x61, 0x64, 0x65, 0x72, 0x73, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c,
- 0x6f, 0x77, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72,
- 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x28, 0x6d, 0x65, 0x73,
- 0x67, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x22, 0x64,
- 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x77, 0x65,
- 0x72, 0x5b, 0x22, 0x64, 0x61, 0x74, 0x65, 0x22, 0x5d, 0x20, 0x6f, 0x72,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e,
- 0x64, 0x61, 0x74, 0x65, 0x28, 0x22, 0x21, 0x25, 0x61, 0x2c, 0x20, 0x25,
- 0x64, 0x20, 0x25, 0x62, 0x20, 0x25, 0x59, 0x20, 0x25, 0x48, 0x3a, 0x25,
- 0x4d, 0x3a, 0x25, 0x53, 0x20, 0x22, 0x29, 0x20, 0x2e, 0x2e, 0x20, 0x28,
- 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x7a, 0x6f, 0x6e, 0x65, 0x20, 0x6f,
- 0x72, 0x20, 0x5f, 0x4d, 0x2e, 0x5a, 0x4f, 0x4e, 0x45, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x22, 0x78, 0x2d,
- 0x6d, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x6c,
- 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x22, 0x78, 0x2d, 0x6d, 0x61, 0x69, 0x6c,
- 0x65, 0x72, 0x22, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x6f, 0x63, 0x6b,
- 0x65, 0x74, 0x2e, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x22, 0x6d,
- 0x69, 0x6d, 0x65, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22,
- 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x77,
- 0x65, 0x72, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61,
- 0x67, 0x65, 0x28, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x6d, 0x65, 0x73, 0x67, 0x74, 0x2e, 0x68, 0x65, 0x61, 0x64,
- 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74,
- 0x5f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x28, 0x6d, 0x65, 0x73,
- 0x67, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x63, 0x6f, 0x20, 0x3d, 0x20, 0x63, 0x6f, 0x72, 0x6f, 0x75,
- 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x20, 0x73,
- 0x65, 0x6e, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x28,
- 0x6d, 0x65, 0x73, 0x67, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x72, 0x65, 0x74, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x20, 0x3d, 0x20,
- 0x63, 0x6f, 0x72, 0x6f, 0x75, 0x74, 0x69, 0x6e, 0x65, 0x2e, 0x72, 0x65,
- 0x73, 0x75, 0x6d, 0x65, 0x28, 0x63, 0x6f, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x72, 0x65, 0x74, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x61, 0x2c, 0x20, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x61, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
- 0x5f, 0x4d, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x6f,
- 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
- 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x61,
- 0x69, 0x6c, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x6f, 0x70,
- 0x65, 0x6e, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x73, 0x65, 0x72,
- 0x76, 0x65, 0x72, 0x2c, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x70,
- 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x2e, 0x63,
- 0x72, 0x65, 0x61, 0x74, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x3a, 0x67, 0x72, 0x65, 0x65, 0x74, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74,
- 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x28, 0x6d, 0x61, 0x69, 0x6c,
- 0x74, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2c, 0x20, 0x6d, 0x61, 0x69, 0x6c,
- 0x74, 0x2e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, 0x20,
- 0x65, 0x78, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x3a, 0x73,
- 0x65, 0x6e, 0x64, 0x28, 0x6d, 0x61, 0x69, 0x6c, 0x74, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x73, 0x3a, 0x71, 0x75, 0x69, 0x74, 0x28, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
- 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x65, 0x6e, 0x64,
- 0x29, 0x0a, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x4d,0x0};
- return luaL_dostring(L, (const char*)B);
-} /* end of embedded lua code */
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua b/Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua
deleted file mode 100644
index ea88353838d..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_tp.lua
+++ /dev/null
@@ -1,134 +0,0 @@
------------------------------------------------------------------------------
--- Unified SMTP/FTP subsystem
--- LuaSocket toolkit.
--- Author: Diego Nehab
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- Declare module and import dependencies
------------------------------------------------------------------------------
-local base = _G
-local string = require("string")
-local socket = socket or require("socket")
-local ltn12 = ltn12 or require("ltn12")
-
-socket.tp = {}
-local _M = socket.tp
-
------------------------------------------------------------------------------
--- Program constants
------------------------------------------------------------------------------
-_M.TIMEOUT = 60
-
------------------------------------------------------------------------------
--- Implementation
------------------------------------------------------------------------------
--- gets server reply (works for SMTP and FTP)
-local function get_reply(c)
- local code, current, sep
- local line, err = c:receive()
- local reply = line
- if err then return nil, err end
- code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
- if not code then return nil, "invalid server reply" end
- if sep == "-" then -- reply is multiline
- repeat
- line, err = c:receive()
- if err then return nil, err end
- current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
- reply = reply .. "\n" .. line
- -- reply ends with same code
- until code == current and sep == " "
- end
- return code, reply
-end
-
--- metatable for sock object
-local metat = { __index = {} }
-
-function metat.__index:getpeername()
- return self.c:getpeername()
-end
-
-function metat.__index:getsockname()
- return self.c:getpeername()
-end
-
-function metat.__index:check(ok)
- local code, reply = get_reply(self.c)
- if not code then return nil, reply end
- if base.type(ok) ~= "function" then
- if base.type(ok) == "table" then
- for i, v in base.ipairs(ok) do
- if string.find(code, v) then
- return base.tonumber(code), reply
- end
- end
- return nil, reply
- else
- if string.find(code, ok) then return base.tonumber(code), reply
- else return nil, reply end
- end
- else return ok(base.tonumber(code), reply) end
-end
-
-function metat.__index:command(cmd, arg)
- cmd = string.upper(cmd)
- if arg then
- return self.c:send(cmd .. " " .. arg.. "\r\n")
- else
- return self.c:send(cmd .. "\r\n")
- end
-end
-
-function metat.__index:sink(snk, pat)
- local chunk, err = self.c:receive(pat)
- return snk(chunk, err)
-end
-
-function metat.__index:send(data)
- return self.c:send(data)
-end
-
-function metat.__index:receive(pat)
- return self.c:receive(pat)
-end
-
-function metat.__index:getfd()
- return self.c:getfd()
-end
-
-function metat.__index:dirty()
- return self.c:dirty()
-end
-
-function metat.__index:getcontrol()
- return self.c
-end
-
-function metat.__index:source(source, step)
- local sink = socket.sink("keep-open", self.c)
- local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
- return ret, err
-end
-
--- closes the underlying c
-function metat.__index:close()
- self.c:close()
- return 1
-end
-
--- connect with server and return c object
-function _M.connect(host, port, timeout, create)
- local c, e = (create or socket.tcp)()
- if not c then return nil, e end
- c:settimeout(timeout or _M.TIMEOUT)
- local r, e = c:connect(host, port)
- if not r then
- c:close()
- return nil, e
- end
- return base.setmetatable({c = c}, metat)
-end
-
-return _M
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c b/Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c
deleted file mode 100644
index 02c7e005310..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_tp_lua.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * This file is generated with xxd -i and bit of bash script.
-*/
-#include "lua.h"
-#include "lauxlib.h"
-
-int luatex_tp_lua_open (lua_State *L) {
- static unsigned char B[] = {
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d,
- 0x20, 0x5f, 0x47, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
- 0x72, 0x65, 0x28, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x29,
- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65,
- 0x74, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6f,
- 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x74,
- 0x6e, 0x31, 0x32, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69,
- 0x72, 0x65, 0x28, 0x22, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x22, 0x29, 0x0a,
- 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x70, 0x20, 0x3d, 0x20,
- 0x7b, 0x7d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x4d, 0x20,
- 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x74, 0x70, 0x0a,
- 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x20, 0x3d,
- 0x20, 0x36, 0x30, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x72,
- 0x65, 0x70, 0x6c, 0x79, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20,
- 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x70,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c,
- 0x69, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x63,
- 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70,
- 0x6c, 0x79, 0x20, 0x3d, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c,
- 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x73, 0x65, 0x70, 0x20,
- 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73, 0x6b, 0x69,
- 0x70, 0x28, 0x32, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x66, 0x69, 0x6e, 0x64, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x2c, 0x20, 0x22,
- 0x5e, 0x28, 0x25, 0x64, 0x25, 0x64, 0x25, 0x64, 0x29, 0x28, 0x2e, 0x3f,
- 0x29, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c,
- 0x2c, 0x20, 0x22, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x20, 0x73,
- 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x22,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x73, 0x65, 0x70, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x2d, 0x22, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79,
- 0x20, 0x69, 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x6c, 0x69, 0x6e,
- 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x70, 0x65, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x2c, 0x20, 0x65,
- 0x72, 0x72, 0x20, 0x3d, 0x20, 0x63, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69,
- 0x76, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x72, 0x72, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x73, 0x65,
- 0x70, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x73,
- 0x6b, 0x69, 0x70, 0x28, 0x32, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x2c,
- 0x20, 0x22, 0x5e, 0x28, 0x25, 0x64, 0x25, 0x64, 0x25, 0x64, 0x29, 0x28,
- 0x2e, 0x3f, 0x29, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79,
- 0x20, 0x3d, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x2e, 0x2e, 0x20,
- 0x22, 0x5c, 0x6e, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6c, 0x69, 0x6e, 0x65,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x6e, 0x74,
- 0x69, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x63,
- 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x73,
- 0x65, 0x70, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x20, 0x22, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72,
- 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x7b,
- 0x20, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x7b,
- 0x7d, 0x20, 0x7d, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64,
- 0x65, 0x78, 0x3a, 0x67, 0x65, 0x74, 0x70, 0x65, 0x65, 0x72, 0x6e, 0x61,
- 0x6d, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a, 0x67,
- 0x65, 0x74, 0x70, 0x65, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x29,
- 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e,
- 0x64, 0x65, 0x78, 0x3a, 0x67, 0x65, 0x74, 0x73, 0x6f, 0x63, 0x6b, 0x6e,
- 0x61, 0x6d, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a,
- 0x67, 0x65, 0x74, 0x70, 0x65, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x28,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x28, 0x6f,
- 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79,
- 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x79,
- 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f, 0x64, 0x65,
- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62,
- 0x61, 0x73, 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6f, 0x6b, 0x29,
- 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e,
- 0x74, 0x79, 0x70, 0x65, 0x28, 0x6f, 0x6b, 0x29, 0x20, 0x3d, 0x3d, 0x20,
- 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x20, 0x76, 0x20, 0x69, 0x6e,
- 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73,
- 0x28, 0x6f, 0x6b, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69,
- 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x76, 0x29, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65,
- 0x2e, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x63, 0x6f,
- 0x64, 0x65, 0x29, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x72,
- 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x63, 0x6f, 0x64,
- 0x65, 0x2c, 0x20, 0x6f, 0x6b, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e,
- 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x63, 0x6f, 0x64,
- 0x65, 0x29, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69,
- 0x6c, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x6b, 0x28, 0x62, 0x61, 0x73, 0x65,
- 0x2e, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x63, 0x6f,
- 0x64, 0x65, 0x29, 0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x29, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f,
- 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
- 0x6e, 0x64, 0x28, 0x63, 0x6d, 0x64, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6d, 0x64, 0x20, 0x3d, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28,
- 0x63, 0x6d, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x61, 0x72, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x28,
- 0x63, 0x6d, 0x64, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x20, 0x22, 0x20, 0x2e,
- 0x2e, 0x20, 0x61, 0x72, 0x67, 0x2e, 0x2e, 0x20, 0x22, 0x5c, 0x72, 0x5c,
- 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a, 0x73,
- 0x65, 0x6e, 0x64, 0x28, 0x63, 0x6d, 0x64, 0x20, 0x2e, 0x2e, 0x20, 0x22,
- 0x5c, 0x72, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f,
- 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x73, 0x69, 0x6e, 0x6b, 0x28, 0x73,
- 0x6e, 0x6b, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x63, 0x68, 0x75, 0x6e, 0x6b,
- 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x63, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x70,
- 0x61, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x73, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x75, 0x6e, 0x6b,
- 0x2c, 0x20, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61,
- 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x73, 0x65,
- 0x6e, 0x64, 0x28, 0x64, 0x61, 0x74, 0x61, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66,
- 0x2e, 0x63, 0x3a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x64, 0x61, 0x74, 0x61,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
- 0x28, 0x70, 0x61, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a,
- 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x70, 0x61, 0x74, 0x29,
- 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e,
- 0x64, 0x65, 0x78, 0x3a, 0x67, 0x65, 0x74, 0x66, 0x64, 0x28, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
- 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a, 0x67, 0x65, 0x74, 0x66, 0x64, 0x28,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x64, 0x69, 0x72, 0x74, 0x79, 0x28, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a, 0x64, 0x69, 0x72, 0x74, 0x79,
- 0x28, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f,
- 0x69, 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x67, 0x65, 0x74, 0x63, 0x6f, 0x6e,
- 0x74, 0x72, 0x6f, 0x6c, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63,
- 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69, 0x6e,
- 0x64, 0x65, 0x78, 0x3a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x28, 0x73,
- 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73,
- 0x69, 0x6e, 0x6b, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
- 0x2e, 0x73, 0x69, 0x6e, 0x6b, 0x28, 0x22, 0x6b, 0x65, 0x65, 0x70, 0x2d,
- 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e,
- 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x72, 0x65, 0x74, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20,
- 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x2e, 0x61,
- 0x6c, 0x6c, 0x28, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2c, 0x20, 0x73,
- 0x69, 0x6e, 0x6b, 0x2c, 0x20, 0x73, 0x74, 0x65, 0x70, 0x20, 0x6f, 0x72,
- 0x20, 0x6c, 0x74, 0x6e, 0x31, 0x32, 0x2e, 0x70, 0x75, 0x6d, 0x70, 0x2e,
- 0x73, 0x74, 0x65, 0x70, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x2c, 0x20, 0x65, 0x72,
- 0x72, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x2e, 0x5f, 0x5f, 0x69,
- 0x6e, 0x64, 0x65, 0x78, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x3a,
- 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x0a, 0x65, 0x6e, 0x64,
- 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d,
- 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x28, 0x68, 0x6f, 0x73,
- 0x74, 0x2c, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x74, 0x69, 0x6d,
- 0x65, 0x6f, 0x75, 0x74, 0x2c, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x63, 0x2c, 0x20, 0x65, 0x20, 0x3d, 0x20, 0x28, 0x63, 0x72, 0x65, 0x61,
- 0x74, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
- 0x2e, 0x74, 0x63, 0x70, 0x29, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c,
- 0x2c, 0x20, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x63, 0x3a, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
- 0x28, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x20, 0x6f, 0x72, 0x20,
- 0x5f, 0x4d, 0x2e, 0x54, 0x49, 0x4d, 0x45, 0x4f, 0x55, 0x54, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x2c,
- 0x20, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x3a, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
- 0x63, 0x74, 0x28, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x6f, 0x72,
- 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f,
- 0x74, 0x20, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65,
- 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x65,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65,
- 0x2e, 0x73, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c,
- 0x65, 0x28, 0x7b, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x7d, 0x2c, 0x20, 0x6d,
- 0x65, 0x74, 0x61, 0x74, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x4d, 0x0a,0x0};
- return luaL_dostring(L, (const char*)B);
-} /* end of embedded lua code */
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua b/Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua
deleted file mode 100644
index 2dd90545cfd..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_url.lua
+++ /dev/null
@@ -1,309 +0,0 @@
------------------------------------------------------------------------------
--- URI parsing, composition and relative URL resolution
--- LuaSocket toolkit.
--- Author: Diego Nehab
------------------------------------------------------------------------------
-
------------------------------------------------------------------------------
--- Declare module
------------------------------------------------------------------------------
-local string = require("string")
-local base = _G
-local table = require("table")
-local socket = socket or require("socket")
-
-socket.url = {}
-local _M = socket.url
-
------------------------------------------------------------------------------
--- Module version
------------------------------------------------------------------------------
-_M._VERSION = "URL 1.0.3"
-
------------------------------------------------------------------------------
--- Encodes a string into its escaped hexadecimal representation
--- Input
--- s: binary string to be encoded
--- Returns
--- escaped representation of string binary
------------------------------------------------------------------------------
-function _M.escape(s)
- return (string.gsub(s, "([^A-Za-z0-9_])", function(c)
- return string.format("%%%02x", string.byte(c))
- end))
-end
-
------------------------------------------------------------------------------
--- Protects a path segment, to prevent it from interfering with the
--- url parsing.
--- Input
--- s: binary string to be encoded
--- Returns
--- escaped representation of string binary
------------------------------------------------------------------------------
-local function make_set(t)
- local s = {}
- for i,v in base.ipairs(t) do
- s[t[i]] = 1
- end
- return s
-end
-
--- these are allowed within a path segment, along with alphanum
--- other characters must be escaped
-local segment_set = make_set {
- "-", "_", ".", "!", "~", "*", "'", "(",
- ")", ":", "@", "&", "=", "+", "$", ",",
-}
-
-local function protect_segment(s)
- return string.gsub(s, "([^A-Za-z0-9_])", function (c)
- if segment_set[c] then return c
- else return string.format("%%%02X", string.byte(c)) end
- end)
-end
-
------------------------------------------------------------------------------
--- Unencodes a escaped hexadecimal string into its binary representation
--- Input
--- s: escaped hexadecimal string to be unencoded
--- Returns
--- unescaped binary representation of escaped hexadecimal binary
------------------------------------------------------------------------------
-function _M.unescape(s)
- return (string.gsub(s, "%%(%x%x)", function(hex)
- return string.char(base.tonumber(hex, 16))
- end))
-end
-
------------------------------------------------------------------------------
--- Builds a path from a base path and a relative path
--- Input
--- base_path
--- relative_path
--- Returns
--- corresponding absolute path
------------------------------------------------------------------------------
-local function absolute_path(base_path, relative_path)
- if string.sub(relative_path, 1, 1) == "/" then return relative_path end
- local path = string.gsub(base_path, "[^/]*$", "")
- path = path .. relative_path
- path = string.gsub(path, "([^/]*%./)", function (s)
- if s ~= "./" then return s else return "" end
- end)
- path = string.gsub(path, "/%.$", "/")
- local reduced
- while reduced ~= path do
- reduced = path
- path = string.gsub(reduced, "([^/]*/%.%./)", function (s)
- if s ~= "../../" then return "" else return s end
- end)
- end
- path = string.gsub(reduced, "([^/]*/%.%.)$", function (s)
- if s ~= "../.." then return "" else return s end
- end)
- return path
-end
-
------------------------------------------------------------------------------
--- Parses a url and returns a table with all its parts according to RFC 2396
--- The following grammar describes the names given to the URL parts
--- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
--- <authority> ::= <userinfo>@<host>:<port>
--- <userinfo> ::= <user>[:<password>]
--- <path> :: = {<segment>/}<segment>
--- Input
--- url: uniform resource locator of request
--- default: table with default values for each field
--- Returns
--- table with the following fields, where RFC naming conventions have
--- been preserved:
--- scheme, authority, userinfo, user, password, host, port,
--- path, params, query, fragment
--- Obs:
--- the leading '/' in {/<path>} is considered part of <path>
------------------------------------------------------------------------------
-function _M.parse(url, default)
- -- initialize default parameters
- local parsed = {}
- for i,v in base.pairs(default or parsed) do parsed[i] = v end
- -- empty url is parsed to nil
- if not url or url == "" then return nil, "invalid url" end
- -- remove whitespace
- -- url = string.gsub(url, "%s", "")
- -- get fragment
- url = string.gsub(url, "#(.*)$", function(f)
- parsed.fragment = f
- return ""
- end)
- -- get scheme
- url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
- function(s) parsed.scheme = s; return "" end)
- -- get authority
- url = string.gsub(url, "^//([^/]*)", function(n)
- parsed.authority = n
- return ""
- end)
- -- get query string
- url = string.gsub(url, "%?(.*)", function(q)
- parsed.query = q
- return ""
- end)
- -- get params
- url = string.gsub(url, "%;(.*)", function(p)
- parsed.params = p
- return ""
- end)
- -- path is whatever was left
- if url ~= "" then parsed.path = url end
- local authority = parsed.authority
- if not authority then return parsed end
- authority = string.gsub(authority,"^([^@]*)@",
- function(u) parsed.userinfo = u; return "" end)
- authority = string.gsub(authority, ":([^:%]]*)$",
- function(p) parsed.port = p; return "" end)
- if authority ~= "" then
- -- IPv6?
- parsed.host = string.match(authority, "^%[(.+)%]$") or authority
- end
- local userinfo = parsed.userinfo
- if not userinfo then return parsed end
- userinfo = string.gsub(userinfo, ":([^:]*)$",
- function(p) parsed.password = p; return "" end)
- parsed.user = userinfo
- return parsed
-end
-
------------------------------------------------------------------------------
--- Rebuilds a parsed URL from its components.
--- Components are protected if any reserved or unallowed characters are found
--- Input
--- parsed: parsed URL, as returned by parse
--- Returns
--- a stringing with the corresponding URL
------------------------------------------------------------------------------
-function _M.build(parsed)
- --local ppath = _M.parse_path(parsed.path or "")
- --local url = _M.build_path(ppath)
- local url = parsed.path or ""
- if parsed.params then url = url .. ";" .. parsed.params end
- if parsed.query then url = url .. "?" .. parsed.query end
- local authority = parsed.authority
- if parsed.host then
- authority = parsed.host
- if string.find(authority, ":") then -- IPv6?
- authority = "[" .. authority .. "]"
- end
- if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end
- local userinfo = parsed.userinfo
- if parsed.user then
- userinfo = parsed.user
- if parsed.password then
- userinfo = userinfo .. ":" .. parsed.password
- end
- end
- if userinfo then authority = userinfo .. "@" .. authority end
- end
- if authority then url = "//" .. authority .. url end
- if parsed.scheme then url = parsed.scheme .. ":" .. url end
- if parsed.fragment then url = url .. "#" .. parsed.fragment end
- -- url = string.gsub(url, "%s", "")
- return url
-end
-
------------------------------------------------------------------------------
--- Builds a absolute URL from a base and a relative URL according to RFC 2396
--- Input
--- base_url
--- relative_url
--- Returns
--- corresponding absolute url
------------------------------------------------------------------------------
-function _M.absolute(base_url, relative_url)
- local base_parsed
- if base.type(base_url) == "table" then
- base_parsed = base_url
- base_url = _M.build(base_parsed)
- else
- base_parsed = _M.parse(base_url)
- end
- local relative_parsed = _M.parse(relative_url)
- if not base_parsed then return relative_url
- elseif not relative_parsed then return base_url
- elseif relative_parsed.scheme then return relative_url
- else
- relative_parsed.scheme = base_parsed.scheme
- if not relative_parsed.authority then
- relative_parsed.authority = base_parsed.authority
- if not relative_parsed.path then
- relative_parsed.path = base_parsed.path
- if not relative_parsed.params then
- relative_parsed.params = base_parsed.params
- if not relative_parsed.query then
- relative_parsed.query = base_parsed.query
- end
- end
- else
- relative_parsed.path = absolute_path(base_parsed.path or "",
- relative_parsed.path)
- end
- end
- return _M.build(relative_parsed)
- end
-end
-
------------------------------------------------------------------------------
--- Breaks a path into its segments, unescaping the segments
--- Input
--- path
--- Returns
--- segment: a table with one entry per segment
------------------------------------------------------------------------------
-function _M.parse_path(path)
- local parsed = {}
- path = path or ""
- --path = string.gsub(path, "%s", "")
- string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end)
- for i = 1, #parsed do
- parsed[i] = _M.unescape(parsed[i])
- end
- if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
- if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
- return parsed
-end
-
------------------------------------------------------------------------------
--- Builds a path component from its segments, escaping protected characters.
--- Input
--- parsed: path segments
--- unsafe: if true, segments are not protected before path is built
--- Returns
--- path: corresponding path stringing
------------------------------------------------------------------------------
-function _M.build_path(parsed, unsafe)
- local path = ""
- local n = #parsed
- if unsafe then
- for i = 1, n-1 do
- path = path .. parsed[i]
- path = path .. "/"
- end
- if n > 0 then
- path = path .. parsed[n]
- if parsed.is_directory then path = path .. "/" end
- end
- else
- for i = 1, n-1 do
- path = path .. protect_segment(parsed[i])
- path = path .. "/"
- end
- if n > 0 then
- path = path .. protect_segment(parsed[n])
- if parsed.is_directory then path = path .. "/" end
- end
- end
- if parsed.is_absolute then path = "/" .. path end
- return path
-end
-
-return _M
diff --git a/Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c b/Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c
deleted file mode 100644
index 372691b82d1..00000000000
--- a/Build/source/texk/web2c/luatexdir/luasocket/src/_url_lua.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * This file is generated with xxd -i and bit of bash script.
-*/
-#include "lua.h"
-#include "lauxlib.h"
-
-int luatex_url_lua_open (lua_State *L) {
- static unsigned char B[] = {
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22,
- 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x20, 0x3d, 0x20, 0x5f, 0x47,
- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22,
- 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71,
- 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
- 0x22, 0x29, 0x0a, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x75, 0x72,
- 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x5f, 0x4d, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74,
- 0x2e, 0x75, 0x72, 0x6c, 0x0a, 0x5f, 0x4d, 0x2e, 0x5f, 0x56, 0x45, 0x52,
- 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x3d, 0x20, 0x22, 0x55, 0x52, 0x4c, 0x20,
- 0x31, 0x2e, 0x30, 0x2e, 0x33, 0x22, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x65, 0x73, 0x63, 0x61, 0x70,
- 0x65, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x22, 0x28, 0x5b, 0x5e,
- 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x29,
- 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
- 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x25, 0x25, 0x25,
- 0x30, 0x32, 0x78, 0x22, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, 0x29, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x28,
- 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x62,
- 0x61, 0x73, 0x65, 0x2e, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x74,
- 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x5b, 0x74, 0x5b, 0x69, 0x5d, 0x5d, 0x20, 0x3d, 0x20, 0x31,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x0a, 0x65, 0x6e,
- 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x67, 0x6d,
- 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x6d, 0x61,
- 0x6b, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x22, 0x2d, 0x22, 0x2c, 0x20, 0x22, 0x5f, 0x22, 0x2c, 0x20, 0x22,
- 0x2e, 0x22, 0x2c, 0x20, 0x22, 0x21, 0x22, 0x2c, 0x20, 0x22, 0x7e, 0x22,
- 0x2c, 0x20, 0x22, 0x2a, 0x22, 0x2c, 0x20, 0x22, 0x27, 0x22, 0x2c, 0x20,
- 0x22, 0x28, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x22, 0x29, 0x22,
- 0x2c, 0x20, 0x22, 0x3a, 0x22, 0x2c, 0x20, 0x22, 0x40, 0x22, 0x2c, 0x20,
- 0x22, 0x26, 0x22, 0x2c, 0x20, 0x22, 0x3d, 0x22, 0x2c, 0x20, 0x22, 0x2b,
- 0x22, 0x2c, 0x20, 0x22, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x2c, 0x22, 0x2c,
- 0x0a, 0x7d, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63,
- 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x73, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28,
- 0x73, 0x2c, 0x20, 0x22, 0x28, 0x5b, 0x5e, 0x41, 0x2d, 0x5a, 0x61, 0x2d,
- 0x7a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x63, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x65,
- 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x74, 0x5b, 0x63, 0x5d,
- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x63, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74,
- 0x28, 0x22, 0x25, 0x25, 0x25, 0x30, 0x32, 0x58, 0x22, 0x2c, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63,
- 0x29, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x75, 0x6e, 0x65, 0x73,
- 0x63, 0x61, 0x70, 0x65, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x73, 0x74, 0x72, 0x69,
- 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x2c, 0x20, 0x22,
- 0x25, 0x25, 0x28, 0x25, 0x78, 0x25, 0x78, 0x29, 0x22, 0x2c, 0x20, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x68, 0x65, 0x78, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x63,
- 0x68, 0x61, 0x72, 0x28, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x6f, 0x6e,
- 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x68, 0x65, 0x78, 0x2c, 0x20, 0x31,
- 0x36, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29,
- 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x62, 0x73,
- 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x28, 0x62,
- 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x72, 0x65,
- 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69,
- 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x72, 0x65, 0x6c, 0x61, 0x74,
- 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x31, 0x2c,
- 0x20, 0x31, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x2f, 0x22, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72,
- 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63,
- 0x61, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x62, 0x61,
- 0x73, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x22, 0x5b, 0x5e,
- 0x2f, 0x5d, 0x2a, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61,
- 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
- 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x70, 0x61, 0x74, 0x68, 0x2c,
- 0x20, 0x22, 0x28, 0x5b, 0x5e, 0x2f, 0x5d, 0x2a, 0x25, 0x2e, 0x2f, 0x29,
- 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
- 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x73, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x2e, 0x2f, 0x22,
- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x73, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75,
- 0x72, 0x6e, 0x20, 0x22, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70,
- 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20,
- 0x22, 0x2f, 0x25, 0x2e, 0x24, 0x22, 0x2c, 0x20, 0x22, 0x2f, 0x22, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72,
- 0x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x77,
- 0x68, 0x69, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64,
- 0x20, 0x7e, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x64, 0x6f, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x64, 0x75,
- 0x63, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20,
- 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
- 0x62, 0x28, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x2c, 0x20, 0x22,
- 0x28, 0x5b, 0x5e, 0x2f, 0x5d, 0x2a, 0x2f, 0x25, 0x2e, 0x25, 0x2e, 0x2f,
- 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x20, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x20, 0x7e, 0x3d,
- 0x20, 0x22, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x22, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22,
- 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x73, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68,
- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
- 0x75, 0x62, 0x28, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x64, 0x2c, 0x20,
- 0x22, 0x28, 0x5b, 0x5e, 0x2f, 0x5d, 0x2a, 0x2f, 0x25, 0x2e, 0x25, 0x2e,
- 0x29, 0x24, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x20, 0x28, 0x73, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x2e,
- 0x2e, 0x2f, 0x2e, 0x2e, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72,
- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x20, 0x65, 0x6c, 0x73,
- 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x20, 0x65,
- 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70,
- 0x61, 0x74, 0x68, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75,
- 0x6c, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x7b,
- 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x2c,
- 0x76, 0x20, 0x69, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x61,
- 0x69, 0x72, 0x73, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20,
- 0x6f, 0x72, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x29, 0x20, 0x64,
- 0x6f, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x5b, 0x69, 0x5d, 0x20,
- 0x3d, 0x20, 0x76, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x6f,
- 0x72, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x22, 0x69, 0x6e, 0x76, 0x61, 0x6c, 0x69,
- 0x64, 0x20, 0x75, 0x72, 0x6c, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c,
- 0x2c, 0x20, 0x22, 0x23, 0x28, 0x2e, 0x2a, 0x29, 0x24, 0x22, 0x2c, 0x20,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x66, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20,
- 0x3d, 0x20, 0x66, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75,
- 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x67, 0x73, 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x22, 0x5e,
- 0x28, 0x5b, 0x25, 0x77, 0x5d, 0x5b, 0x25, 0x77, 0x25, 0x2b, 0x25, 0x2d,
- 0x25, 0x2e, 0x5d, 0x2a, 0x29, 0x25, 0x3a, 0x22, 0x2c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x28, 0x73, 0x29, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x3b,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x20, 0x65,
- 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c, 0x20,
- 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
- 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x22, 0x5e, 0x2f, 0x2f, 0x28,
- 0x5b, 0x5e, 0x2f, 0x5d, 0x2a, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e,
- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e,
- 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20,
- 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c,
- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
- 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x22, 0x25, 0x3f, 0x28,
- 0x2e, 0x2a, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x28, 0x71, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x71, 0x75, 0x65,
- 0x72, 0x79, 0x20, 0x3d, 0x20, 0x71, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69,
- 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c,
- 0x20, 0x22, 0x25, 0x3b, 0x28, 0x2e, 0x2a, 0x29, 0x22, 0x2c, 0x20, 0x66,
- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x70,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x75,
- 0x72, 0x6c, 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x74,
- 0x68, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x75,
- 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
- 0x74, 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f,
- 0x74, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73,
- 0x75, 0x62, 0x28, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x2c, 0x22, 0x5e, 0x28, 0x5b, 0x5e, 0x40, 0x5d, 0x2a, 0x29, 0x40, 0x22,
- 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75,
- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x75, 0x29, 0x20, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66,
- 0x6f, 0x20, 0x3d, 0x20, 0x75, 0x3b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
- 0x6e, 0x20, 0x22, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20,
- 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75,
- 0x62, 0x28, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2c,
- 0x20, 0x22, 0x3a, 0x28, 0x5b, 0x5e, 0x3a, 0x25, 0x5d, 0x5d, 0x2a, 0x29,
- 0x24, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x29, 0x20,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x20,
- 0x3d, 0x20, 0x70, 0x3b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x22, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x20, 0x7e, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x73,
- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28,
- 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x22,
- 0x5e, 0x25, 0x5b, 0x28, 0x2e, 0x2b, 0x29, 0x25, 0x5d, 0x24, 0x22, 0x29,
- 0x20, 0x6f, 0x72, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x75, 0x73, 0x65,
- 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75,
- 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75,
- 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x3d, 0x20, 0x73, 0x74,
- 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x28, 0x75, 0x73,
- 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x2c, 0x20, 0x22, 0x3a, 0x28, 0x5b,
- 0x5e, 0x3a, 0x5d, 0x2a, 0x29, 0x24, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
- 0x6e, 0x28, 0x70, 0x29, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e,
- 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20, 0x3d, 0x20, 0x70,
- 0x3b, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x20,
- 0x65, 0x6e, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x75,
- 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x28,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x2d, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x70, 0x61, 0x74,
- 0x68, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x5f, 0x70, 0x61, 0x74, 0x68, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x22, 0x29,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x62, 0x75,
- 0x69, 0x6c, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x28, 0x70, 0x70, 0x61,
- 0x74, 0x68, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20, 0x22,
- 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x75, 0x72,
- 0x6c, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x3b, 0x22, 0x20, 0x2e, 0x2e, 0x20,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d,
- 0x73, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d,
- 0x20, 0x75, 0x72, 0x6c, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x3f, 0x22, 0x20,
- 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x71, 0x75,
- 0x65, 0x72, 0x79, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
- 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
- 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72,
- 0x69, 0x74, 0x79, 0x2c, 0x20, 0x22, 0x3a, 0x22, 0x29, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x49, 0x50, 0x76, 0x36, 0x3f, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20,
- 0x22, 0x5b, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x74, 0x79, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x5d, 0x22, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x3d, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x3a, 0x22, 0x20, 0x2e, 0x2e, 0x20,
- 0x62, 0x61, 0x73, 0x65, 0x2e, 0x74, 0x6f, 0x73, 0x74, 0x72, 0x69, 0x6e,
- 0x67, 0x28, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x6f, 0x72,
- 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x75, 0x73, 0x65,
- 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f,
- 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x75, 0x73,
- 0x65, 0x72, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x20, 0x74, 0x68,
- 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x75, 0x73, 0x65, 0x72, 0x69,
- 0x6e, 0x66, 0x6f, 0x20, 0x3d, 0x20, 0x75, 0x73, 0x65, 0x72, 0x69, 0x6e,
- 0x66, 0x6f, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x3a, 0x22, 0x20, 0x2e, 0x2e,
- 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x73, 0x73,
- 0x77, 0x6f, 0x72, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x75, 0x73, 0x65, 0x72,
- 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x61, 0x75,
- 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x75, 0x73,
- 0x65, 0x72, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x40,
- 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
- 0x74, 0x79, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65,
- 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x61, 0x75,
- 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e,
- 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x22, 0x2f, 0x2f, 0x22, 0x20,
- 0x2e, 0x2e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
- 0x20, 0x2e, 0x2e, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x2e, 0x2e,
- 0x20, 0x22, 0x3a, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x75, 0x72, 0x6c, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65,
- 0x6e, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x75, 0x72, 0x6c, 0x20,
- 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x23, 0x22,
- 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x66,
- 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x75,
- 0x72, 0x6c, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74,
- 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e, 0x61, 0x62, 0x73, 0x6f, 0x6c,
- 0x75, 0x74, 0x65, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c,
- 0x2c, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x75,
- 0x72, 0x6c, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61,
- 0x6c, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x61, 0x73,
- 0x65, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x28, 0x62, 0x61, 0x73, 0x65, 0x5f,
- 0x75, 0x72, 0x6c, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x74, 0x61, 0x62,
- 0x6c, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f,
- 0x75, 0x72, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x5f,
- 0x4d, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x28, 0x62, 0x61, 0x73, 0x65,
- 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x20, 0x3d, 0x20, 0x5f, 0x4d, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x28, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x29, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c,
- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76,
- 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x5f,
- 0x4d, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x72, 0x65, 0x6c, 0x61,
- 0x74, 0x69, 0x76, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x29, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x61, 0x73,
- 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x6c,
- 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74,
- 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65,
- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x75, 0x72,
- 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66,
- 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x75, 0x72, 0x6c,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
- 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x63,
- 0x68, 0x65, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d,
- 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76,
- 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x61, 0x75, 0x74,
- 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
- 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x6c,
- 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20,
- 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
- 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61,
- 0x72, 0x61, 0x6d, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69,
- 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61,
- 0x72, 0x61, 0x6d, 0x73, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65, 0x5f,
- 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x70, 0x61, 0x72, 0x61, 0x6d,
- 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76,
- 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x71, 0x75, 0x65,
- 0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61,
- 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e,
- 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x73, 0x65,
- 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x71, 0x75, 0x65, 0x72,
- 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
- 0x73, 0x65, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
- 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2e, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x61, 0x62,
- 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x28,
- 0x62, 0x61, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e,
- 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x22, 0x2c, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x6c, 0x61,
- 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e,
- 0x70, 0x61, 0x74, 0x68, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x5f, 0x4d, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x28, 0x72, 0x65,
- 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x73, 0x65,
- 0x64, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65,
- 0x6e, 0x64, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
- 0x5f, 0x4d, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x74,
- 0x68, 0x28, 0x70, 0x61, 0x74, 0x68, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64,
- 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61,
- 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x6f, 0x72,
- 0x20, 0x22, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x70, 0x61,
- 0x74, 0x68, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
- 0x67, 0x73, 0x75, 0x62, 0x28, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x22,
- 0x25, 0x73, 0x22, 0x2c, 0x20, 0x22, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62,
- 0x28, 0x70, 0x61, 0x74, 0x68, 0x2c, 0x20, 0x22, 0x28, 0x5b, 0x5e, 0x2f,
- 0x5d, 0x2b, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
- 0x6f, 0x6e, 0x20, 0x28, 0x73, 0x29, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65,
- 0x2e, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x28, 0x70, 0x61, 0x72, 0x73,
- 0x65, 0x64, 0x2c, 0x20, 0x73, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20,
- 0x31, 0x2c, 0x20, 0x23, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x20, 0x64,
- 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x5b, 0x69, 0x5d, 0x20, 0x3d, 0x20, 0x5f, 0x4d,
- 0x2e, 0x75, 0x6e, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x28, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x5b, 0x69, 0x5d, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20,
- 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x70,
- 0x61, 0x74, 0x68, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x20, 0x3d,
- 0x3d, 0x20, 0x22, 0x2f, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x69, 0x73, 0x5f, 0x61, 0x62, 0x73,
- 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x73, 0x74, 0x72,
- 0x69, 0x6e, 0x67, 0x2e, 0x73, 0x75, 0x62, 0x28, 0x70, 0x61, 0x74, 0x68,
- 0x2c, 0x20, 0x2d, 0x31, 0x2c, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x3d, 0x3d,
- 0x20, 0x22, 0x2f, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x2e, 0x69, 0x73, 0x5f, 0x64, 0x69, 0x72, 0x65,
- 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x3d, 0x20, 0x31, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
- 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x5f, 0x4d, 0x2e,
- 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x28, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2c, 0x20, 0x75, 0x6e, 0x73, 0x61, 0x66,
- 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x22, 0x22, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x20, 0x3d,
- 0x20, 0x23, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x69, 0x66, 0x20, 0x75, 0x6e, 0x73, 0x61, 0x66, 0x65, 0x20, 0x74,
- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x66, 0x6f, 0x72, 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x20, 0x6e,
- 0x2d, 0x31, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d,
- 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x5b, 0x69, 0x5d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20,
- 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2f,
- 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e,
- 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66,
- 0x20, 0x6e, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20,
- 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x5b, 0x6e, 0x5d,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x69, 0x66, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x69,
- 0x73, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20,
- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20,
- 0x70, 0x61, 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x2f, 0x22, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72,
- 0x20, 0x69, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x20, 0x6e, 0x2d, 0x31, 0x20,
- 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61,
- 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63,
- 0x74, 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x70, 0x61,
- 0x72, 0x73, 0x65, 0x64, 0x5b, 0x69, 0x5d, 0x29, 0x0a, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x74,
- 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x2e, 0x2e, 0x20,
- 0x22, 0x2f, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x69, 0x66, 0x20, 0x6e, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74,
- 0x68, 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74,
- 0x5f, 0x73, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x28, 0x70, 0x61, 0x72,
- 0x73, 0x65, 0x64, 0x5b, 0x6e, 0x5d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70,
- 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x69, 0x73, 0x5f, 0x64, 0x69, 0x72,
- 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20,
- 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20,
- 0x2e, 0x2e, 0x20, 0x22, 0x2f, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20,
- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69,
- 0x66, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x69, 0x73, 0x5f,
- 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65,
- 0x6e, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x22, 0x2f, 0x22,
- 0x20, 0x2e, 0x2e, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x65, 0x6e, 0x64,
- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
- 0x70, 0x61, 0x74, 0x68, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x72, 0x65, 0x74,
- 0x75, 0x72, 0x6e, 0x20, 0x5f, 0x4d, 0x0a,0x0};
- return luaL_dostring(L, (const char*)B);
-} /* end of embedded lua code */
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
index bb0d6e06d50..2909ac6ad74 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.c
@@ -1,29 +1,29 @@
-% pdfaction.w
-%
-% Copyright 2009-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
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ read an action specification
+/*tex Read an action specification. */
-@c halfword scan_action(PDF pdf)
+halfword scan_action(PDF pdf)
{
int p = new_node(whatsit_node, pdf_action_node);
(void) pdf;
@@ -73,13 +73,13 @@
}
if (scan_keyword("newwindow")) {
set_pdf_action_new_window(p, pdf_window_new);
- /* Scan an optional space */
+ /*tex Scan an optional space. */
get_x_token();
if (cur_cmd != spacer_cmd)
back_input();
} else if (scan_keyword("nonewwindow")) {
set_pdf_action_new_window(p, pdf_window_nonew);
- /* Scan an optional space */
+ /*tex Scan an optional space. */
get_x_token();
if (cur_cmd != spacer_cmd)
back_input();
@@ -94,9 +94,9 @@
return p;
}
-@ write an action specification
+/*tex Write an action specification. */
-@c void write_action(PDF pdf, halfword p)
+void write_action(PDF pdf, halfword p)
{
char *s;
int d = 0;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
index 43ee3692bd1..e501947c78f 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.c
@@ -1,27 +1,26 @@
-% pdfannot.w
-%
-% Copyright 2009-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
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ @c
void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
{
scaled_whd alt_rule;
@@ -43,13 +42,13 @@ void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
addto_page_resources(pdf, obj_type_annot, pdf_annot_objnum(p));
}
-@ create a new whatsit node for annotation
+/*tex Create a new whatsit node for annotation. */
-@c void new_annot_whatsit(small_number w)
+void new_annot_whatsit(small_number w)
{
scaled_whd alt_rule;
new_whatsit(w);
- alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */
+ alt_rule = scan_alt_rule();
set_width(tail_par, alt_rule.wd);
set_height(tail_par, alt_rule.ht);
set_depth(tail_par, alt_rule.dp);
@@ -63,14 +62,14 @@ void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
}
}
-@ scanning at the \TeX\ end
+/*tex Scanning at the \TEX\ end: */
-@c void scan_annot(PDF pdf)
+void scan_annot(PDF pdf)
{
int k;
if (scan_keyword("reserveobjnum")) {
k = pdf_create_obj(pdf, obj_type_annot, 0);
- /* Scan an optional space */
+ /*tex Scan an optional space. */
get_x_token();
if (cur_cmd != spacer_cmd)
back_input();
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.c
index ac117d6ba05..fbb88692fe9 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.c
@@ -1,43 +1,53 @@
-% pdfcolorstack.w
-%
-% Copyright 2009-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"
+Copyright 2009-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.
-@* Color Stack and Matrix Transformation Support.
+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.
-@ In the following array and especially stack data structures are used.
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-They have the following properties:
+*/
+
+#include "ptexlib.h"
-\item{-} They automatically grow dynamically.
-\item{-} The size never decreases.
-\item{-} The variable with name ending in "size" contains the number how many
- entries the data structure can hold.
-\item{-} The variable with name ending in "used" contains the number of
- actually used entries.
-\item{-} Memory of strings in stack entries must be allocated and
- freed if the stack is cleared.
+/*tex
+
+ This module implements color stack support. The following array and
+ especially stack data structures are used.
+
+ \startitemize
+ \startitem
+ They automatically grow dynamically.
+ \stopitem
+ \startitem
+ The size never decreases.
+ \stopitem
+ \startitem
+ The variable with name ending in "size" contains the number how many
+ entries the data structure can hold.
+ \stopitem
+ \startitem
+ The variable with name ending in "used" contains the number of
+ actually used entries.
+ \stopitem
+ \startitem
+ Memory of strings in stack entries must be allocated and freed if the
+ stack is cleared.
+ \stopitem
+ \stopitemize
-@ Color Stack
-@c
+*/
#define MAX_COLORSTACKS 32768
@@ -66,10 +76,13 @@ static colstack_type *colstacks = NULL;
static int colstacks_size = 0;
static int colstacks_used = 0;
-@ Initialization is done, if the color stacks are used, |init_colorstacks()| is defined
-as macro to avoid unnecessary procedure calls.
+/*tex
+
+ Initialization is done, if the color stacks are used, |init_colorstacks()| is
+ defined as macro to avoid unnecessary procedure calls.
+
+*/
-@c
#define init_colorstacks() if (colstacks_size == 0) colstacks_first_init();
static void colstacks_first_init(void)
@@ -90,38 +103,40 @@ static void colstacks_first_init(void)
colstacks[0].page_start = true;
}
-@ @c
int colorstackused(void)
{
init_colorstacks();
return colstacks_used;
}
-@ A new color stack is setup with the given parameters. The stack number is returned
-or -1 in case of error (no room).
+/*tex
+
+ A new color stack is setup with the given parameters. The stack number is
+ returned or -1 in case of error (no room).
+
+*/
-@c
int newcolorstack(const char *str, int literal_mode, boolean page_start)
{
colstack_type *colstack;
int colstack_num;
init_colorstacks();
- /* make room */
+ /*tex Make room: */
if (colstacks_used == MAX_COLORSTACKS) {
return -1;
}
if (colstacks_used == colstacks_size) {
colstacks_size += STACK_INCREMENT;
- /*
+ /*tex
If |(MAX_COLORSTACKS mod STACK_INCREMENT = 0)| then we don't
need to check the case that size overruns |MAX_COLORSTACKS|.
*/
colstacks = xreallocarray(colstacks, colstack_type, (unsigned) colstacks_size);
}
- /* claim new color stack */
+ /*tex Claim new color stack. */
colstack_num = colstacks_used++;
colstack = &colstacks[colstack_num];
- /* configure the new color stack */
+ /*tex Configure the new color stack. */
colstack->page_stack = NULL;
colstack->form_stack = NULL;
colstack->page_size = 0;
@@ -141,12 +156,11 @@ int newcolorstack(const char *str, int literal_mode, boolean page_start)
return colstack_num;
}
-@ @c
#define get_colstack(n) (&colstacks[n])
-@ Puts a string on top of the string pool and updates |pool_ptr|.
+/*tex Put a string on top of the string pool and updates |pool_ptr|. */
-@c static void put_cstring_on_str_pool(char *str)
+static void put_cstring_on_str_pool(char *str)
{
int save_selector = selector;
selector = new_string;
@@ -157,7 +171,6 @@ int newcolorstack(const char *str, int literal_mode, boolean page_start)
selector = save_selector;
}
-@ @c
static int colorstackset(int colstack_no, str_number s)
{
colstack_type *colstack = get_colstack(colstack_no);
@@ -172,7 +185,6 @@ static int colorstackset(int colstack_no, str_number s)
return colstack->literal_mode;
}
-@ @c
int colorstackcurrent(int colstack_no)
{
colstack_type *colstack = get_colstack(colstack_no);
@@ -185,7 +197,6 @@ int colorstackcurrent(int colstack_no)
return colstack->literal_mode;
}
-@ @c
static int colorstackpush(int colstack_no, str_number s)
{
colstack_type *colstack = get_colstack(colstack_no);
@@ -220,7 +231,6 @@ static int colorstackpush(int colstack_no, str_number s)
return colstack->literal_mode;
}
-@ @c
int colorstackpop(int colstack_no)
{
colstack_type *colstack = get_colstack(colstack_no);
@@ -244,16 +254,13 @@ int colorstackpop(int colstack_no)
return colstack->literal_mode;
}
-@ @c
void colorstackpagestart(void)
{
int i, j;
colstack_type *colstack;
if (global_shipping_mode == SHIPPING_PAGE) {
- /* see procedure |pdf_out_colorstack_startpage| */
return;
}
-
for (i = 0; i < colstacks_used; i++) {
colstack = &colstacks[i];
for (j = 0; j < colstack->form_used; j++) {
@@ -269,7 +276,6 @@ void colorstackpagestart(void)
}
}
-@ @c
int colorstackskippagestart(int colstack_no)
{
colstack_type *colstack = get_colstack(colstack_no);
@@ -285,8 +291,6 @@ int colorstackskippagestart(int colstack_no)
return 0;
}
-
-@ @c
void pdf_out_colorstack(PDF pdf, halfword p)
{
int old_setting;
@@ -295,11 +299,7 @@ void pdf_out_colorstack(PDF pdf, halfword p)
int stack_no = pdf_colorstack_stack(p);
int literal_mode = 0;
if (stack_no >= colorstackused()) {
- tprint_nl("");
- tprint("Color stack ");
- print_int(stack_no);
- tprint(" is not initialized for use!");
- tprint_nl("");
+ formatted_warning("pdf backend","color stack %u is not initialized",(unsigned int) stack_no);
return;
}
switch (cmd) {
@@ -335,7 +335,6 @@ void pdf_out_colorstack(PDF pdf, halfword p)
}
}
-@ @c
void pdf_out_colorstack_startpage(PDF pdf)
{
int start_status;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
index 74e8e4b1f13..346cd26e031 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.c
@@ -1,37 +1,40 @@
-% pdfdest.w
-%
-% Copyright 2009-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
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ Here we implement subroutines for work with objects and related things. Some of
-them are used in former parts too, so we need to declare them forward.
+/*tex
+
+ Here we implement subroutines for work with objects and related things. Some
+ of them are used in former parts too, so we need to declare them forward.
+ Memory will grow dynamically.
+
+*/
-@c
void init_dest_names(PDF pdf)
{
pdf->dest_names_size = inf_dest_names_size;
- pdf->dest_names = xmallocarray(dest_name_entry, inf_dest_names_size); /* will grow dynamically */
+ pdf->dest_names = xmallocarray(dest_name_entry, inf_dest_names_size);
}
-@ @c
void append_dest_name(PDF pdf, char *s, int n)
{
int a;
@@ -50,10 +53,13 @@ void append_dest_name(PDF pdf, char *s, int n)
pdf->dest_names_ptr++;
}
-@ When a destination is created we need to check whether another destination
-with the same identifier already exists and give a warning if needed.
+/*tex
+
+ When a destination is created we need to check whether another destination
+ with the same identifier already exists and give a warning if needed.
+
+*/
-@c
static void warn_dest_dup(int id, small_number byname)
{
if (byname > 0) {
@@ -62,10 +68,8 @@ static void warn_dest_dup(int id, small_number byname)
} else {
formatted_warning("pdf backend", "ignoring duplicate destination with the num '%d'",id);
}
- /* no longer the annoying context */
}
-@ @c
void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
{
scaledpos pos = pdf->posstruct->pos;
@@ -85,7 +89,10 @@ void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
alt_rule.wd = width(p);
alt_rule.ht = height(p);
alt_rule.dp = depth(p);
- /* the different branches for matrixused is somewhat strange and should always be used */
+ /*tex
+ The different branches for matrixused is somewhat strange and should
+ always be used
+ */
switch (pdf_dest_type(p)) {
case pdf_dest_xyz:
if (matrixused())
@@ -117,7 +124,6 @@ void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
}
}
-@ @c
void write_out_pdf_mark_destinations(PDF pdf)
{
pdf_object_list *k;
@@ -143,12 +149,11 @@ void write_out_pdf_mark_destinations(PDF pdf)
if (pdf_dest_xyz_zoom(i) == null) {
pdf_add_null(pdf);
} else {
- if (pdf->cave == 1)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_print_int(pdf, pdf_dest_xyz_zoom(i) / 1000);
pdf_out(pdf, '.');
pdf_print_int(pdf, (pdf_dest_xyz_zoom(i) % 1000));
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
break;
case pdf_dest_fit:
@@ -191,7 +196,6 @@ void write_out_pdf_mark_destinations(PDF pdf)
}
}
-@ @c
void scan_pdfdest(PDF pdf)
{
halfword q;
@@ -242,13 +246,12 @@ void scan_pdfdest(PDF pdf)
} else {
normal_error("pdf backend", "destination type missing");
}
- /* Scan an optional space */
+ /*tex Scan an optional space. */
get_x_token();
if (cur_cmd != spacer_cmd)
back_input();
-
if (pdf_dest_type(cur_list.tail_field) == pdf_dest_fitr) {
- alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */
+ alt_rule = scan_alt_rule();
set_width(cur_list.tail_field, alt_rule.wd);
set_height(cur_list.tail_field, alt_rule.ht);
set_depth(cur_list.tail_field, alt_rule.dp);
@@ -268,8 +271,8 @@ void scan_pdfdest(PDF pdf)
}
}
-@ sorts |dest_names| by names
-@c
+/*tex Sort |dest_names| by names: */
+
static int dest_cmp(const void *a, const void *b)
{
dest_name_entry aa = *(const dest_name_entry *) a;
@@ -277,24 +280,30 @@ static int dest_cmp(const void *a, const void *b)
return strcmp(aa.objname, bb.objname);
}
-@ @c
void sort_dest_names(PDF pdf)
{
qsort(pdf->dest_names, (size_t) pdf->dest_names_ptr, sizeof(dest_name_entry), dest_cmp);
}
-@ Output the name tree. The tree nature of the destination list forces the
-storing of intermediate data in |obj_info| and |obj_aux| fields, which
-is further uglified by the fact that |obj_tab| entries do not accept char
-pointers.
+/*tex
+
+ Output the name tree. The tree nature of the destination list forces the
+ storing of intermediate data in |obj_info| and |obj_aux| fields, which is
+ further uglified by the fact that |obj_tab| entries do not accept char
+ pointers.
+
+*/
-@c
int output_name_tree(PDF pdf)
{
- boolean is_names = true; /* flag for name tree output: is it Names or Kids? */
- int k = 0; /* index of current child of |l|; if |k < pdf_dest_names_ptr|
- then this is pointer to |dest_names| array;
- otherwise it is the pointer to |obj_tab| (object number) */
+ /*tex A flag for name tree output: is it |/Names| or |/Kids|: */
+ boolean is_names = true;
+ /*tex
+ The index of current child of |l|; if |k < pdf_dest_names_ptr| then this
+ is pointer to |dest_names| array; otherwise it is the pointer to
+ |obj_tab| (object number).
+ */
+ int k = 0;
int b = 0;
int m, j, l;
int dests = 0;
@@ -306,9 +315,12 @@ int output_name_tree(PDF pdf)
sort_dest_names(pdf);
while (true) {
do {
- l = pdf_create_obj(pdf, obj_type_others, 0); /* create a new node */
- if (b == 0)
- b = l; /* first in this level */
+ /*tex Create a new node: */
+ l = pdf_create_obj(pdf, obj_type_others, 0);
+ if (b == 0) {
+ /*tex First in this level: */
+ b = l;
+ }
if (names_head == 0) {
names_head = l;
names_tail = l;
@@ -317,7 +329,7 @@ int output_name_tree(PDF pdf)
names_tail = l;
}
set_obj_link(pdf, names_tail, 0);
- /* Output the current node in this level */
+ /*tex Output the current node in this level. */
pdf_begin_obj(pdf, l, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
j = 0;
@@ -332,13 +344,13 @@ int output_name_tree(PDF pdf)
k++;
} while (j != name_tree_kids_max && k != pdf->dest_names_ptr);
pdf_end_array(pdf);
- set_obj_stop(pdf, l, pdf->dest_names[k - 1].objname); /* for later */
+ /*tex For later use: */
+ set_obj_stop(pdf, l, pdf->dest_names[k - 1].objname);
if (k == pdf->dest_names_ptr) {
is_names = false;
k = names_head;
b = 0;
}
-
} else {
set_obj_start(pdf, l, obj_start(pdf, k));
pdf_add_name(pdf, "Kids");
@@ -362,7 +374,6 @@ int output_name_tree(PDF pdf)
pdf_end_dict(pdf);
pdf_end_obj(pdf);
} while (b != 0);
-
if (k == l) {
dests = l;
goto DONE;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdffont.w b/Build/source/texk/web2c/luatexdir/pdf/pdffont.c
index 278efa9d6fa..1e1f0f8d9da 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdffont.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdffont.c
@@ -1,48 +1,50 @@
-% pdffont.w
-%
-% Copyright 2009-2014 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\pdfTeX{pdf\TeX}
-
-@ @c
+/*
+
+Copyright 2009-2014 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"
-@ As \pdfTeX{} should also act as a back-end driver, it needs to support virtual
-fonts too. Information about virtual fonts can be found in the source of some
-\.{DVI}-related programs.
+/*tex
-Whenever we want to write out a character in a font to PDF output, we
-should check whether the used character is a virtual or real character.
-The |has_packet()| C macro checks for this condition.
+ As \LUATEX\ should also act as a back-end driver, it needs to support virtual
+ fonts too. Information about virtual fonts can be found in the source of some
+ \DVI-related programs.
-@ The following code typesets a character to PDF output
+ Whenever we want to write out a character in a font to \PDF\ output, we
+ should check whether the used character is a virtual or real character. The
+ |has_packet| C macro checks for this condition.
+
+ The following code typesets a character to \PDF\ output
+
+*/
-@c
scaled_whd output_one_char(PDF pdf, halfword p)
{
internal_font_number f = font(p);
int c = character(p);
int ex_glyph = ex_glyph(p)/1000;
- scaled_whd ci = get_charinfo_whd(f, c); /* the real width, height and depth of the character */
+ /*tex The real width, height and depth of the character: */
+ scaled_whd ci = get_charinfo_whd(f, c);
if (!(char_exists(f,c))) {
lua_glyph_not_found_callback(f,c);
- /* char_warning(f,c); */
+ /*tex Not here |char_warning(f,c);| */
return ci;
}
ci.wd = ext_xn_over_d(ci.wd, 1000000 + ex_glyph(p), 1000000);
@@ -66,14 +68,18 @@ scaled_whd output_one_char(PDF pdf, halfword p)
if (has_packet(f, c)) {
do_vf_packet(pdf, f, c, ex_glyph);
} else {
- /* |pdf_place_glyph(pdf, f, c, ex_glyph);| */
backend_out[glyph_node] (pdf, f, c, ex_glyph);
}
return ci;
}
-@ Mark |f| as a used font; set |font_used(f)|, |font_size(f)| and |pdf_font_num(f)|
-@c
+/*tex
+
+ Mark |f| as a used font; set |font_used(f)|, |font_size(f)| and
+ |pdf_font_num(f)|.
+
+*/
+
static void pdf_use_font(internal_font_number f, int fontnum)
{
set_font_used(f, true);
@@ -84,19 +90,24 @@ static void pdf_use_font(internal_font_number f, int fontnum)
}
}
-@ To set PDF font we need to find out fonts with the same name, because \TeX\ can
-load the same font several times for various sizes. For such fonts we define only
-one font resource. The array |pdf_font_num| holds the object number of font
-resource. A negative value of an entry of |pdf_font_num| indicates that the
-corresponding font shares the font resource with the font
+/*tex
+
+ To set PDF font we need to find out fonts with the same name, because \TeX\
+ can load the same font several times for various sizes. For such fonts we
+ define only one font resource. The array |pdf_font_num| holds the object
+ number of font resource. A negative value of an entry of |pdf_font_num|
+ indicates that the corresponding font shares the font resource with the font.
+
+*/
-@c
#define same(n,f,k) (n(f) != NULL && n(k) != NULL && strcmp(n(f), n(k)) == 0)
-/*
- For some lua-loaded (for instance AFM) fonts, it is normal to have
- a zero cidregistry, and such fonts do not have a fontmap entry yet
- at this point, so the test should use the other branch
+/*tex
+
+ For some \LUA-loaded (for instance \AFM) fonts, it is normal to have a zero
+ cidregistry, and such fonts do not have a fontmap entry yet at this point, so
+ the test should use the other branch.
+
*/
static boolean font_shareable(internal_font_number f, internal_font_number k)
@@ -111,8 +122,21 @@ static boolean font_shareable(internal_font_number f, internal_font_number k)
return 0;
}
-@ create a font object
-@c
+/*tex
+
+ We will create a font object. We check whether |f| can share the font object
+ with some |k|: we have 2 cases here: |f| and |k| have the same tfm name, so
+ they have been loaded at different sizes, eg 'cmr10' and 'cmr10 at 11pt'.
+
+ We optionally take over slant and extend from map entry, if not already set;
+ this should also be the only place where getfontmap() may be called.
+
+ Beware, \LUATEX\ is different from \PDFTEX\ in dealing with expanded and
+ slanted fonts and expansion and protrusion as it will use the same font but a
+ different transformation which is way more efficient and also cleaner.
+
+*/
+
void pdf_init_font(PDF pdf, internal_font_number f)
{
internal_font_number k;
@@ -121,15 +145,6 @@ void pdf_init_font(PDF pdf, internal_font_number f)
if (font_used(f)) {
formatted_error("pdf backend","font %i gets initialized twice",(int) f);
}
- /*
- check whether |f| can share the font object with some |k|: we have 2 cases
- here: 1) |f| and |k| have the same tfm name (so they have been loaded at
- different sizes, eg 'cmr10' and 'cmr10 at 11pt'); 2) |f| has been auto
- expanded from |k|
-
- take over slant and extend from map entry, if not already set;
- this should also be the only place where getfontmap() may be called.
- */
fm = getfontmap(font_name(f));
if (font_map(f) == NULL && fm != NULL) {
font_map(f) = fm;
@@ -150,38 +165,42 @@ void pdf_init_font(PDF pdf, internal_font_number f)
}
i = obj_link(pdf, i);
}
- /* create a new font object for |f| */
+ /*tex Create a new font object for |f|: */
l = pdf_create_obj(pdf, obj_type_font, f);
pdf_use_font(f, l);
}
-@ set the actual font on PDF page; sets |ff| to the tfm number of the base font
-sharing the font object with |f|; |ff| is either |f| itself (then it is its own
-base font), or some font with the same tfm name at different size and/or
-expansion.
+/*tex
+
+ Set the actual font on PDF page; sets |ff| to the tfm number of the base font
+ sharing the font object with |f|; |ff| is either |f| itself (then it is its
+ own base font), or some font with the same tfm name at different size and/or
+ expansion.
+
+*/
-@c
internal_font_number pdf_set_font(PDF pdf, internal_font_number f)
{
- int ff; /* for use with |set_ff| */
+ /*tex For use with |set_ff|: */
+ int ff;
if (!font_used(f))
pdf_init_font(pdf, f);
- ff = pdf_font_num(f) < 0 ? -pdf_font_num(f) : f; /* aka |set_ff(f)| */
+ /*tex Also known as |set_ff(f)|: */
+ ff = pdf_font_num(f) < 0 ? -pdf_font_num(f) : f;
addto_page_resources(pdf, obj_type_font, pdf_font_num(ff));
return ff;
}
-@ @c
void pdf_include_chars(PDF pdf)
{
str_number s;
- unsigned char *k, *j; /* running index */
+ unsigned char *k, *j;
internal_font_number f;
scan_font_ident();
f = cur_val;
if (f == null_font)
normal_error("pdf backend", "invalid font identifier for 'includechars'");
- pdf_check_vf(cur_val);
+ /* pdf_check_vf(c); */
if (!font_used(f))
pdf_init_font(pdf, f);
scan_toks(false, true);
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
index 26b7112ed09..0409dbc33dc 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.c
@@ -1,26 +1,26 @@
-% pdfgen.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/>.
-
-@ @c
+/*
+
+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/>.
+
+*/
+
#include "ptexlib.h"
-@ @c
#include <kpathsea/c-dir.h>
#include <kpathsea/c-ctype.h>
#include "lua/luatex-api.h"
@@ -32,43 +32,60 @@
PDF static_pdf = NULL;
-@ commandline interface
+/*tex The commandline interface: */
-@c
int output_mode_used;
int output_mode_option;
int output_mode_value;
int draft_mode_option;
int draft_mode_value;
-halfword pdf_info_toks; /* additional keys of Info dictionary */
-halfword pdf_catalog_toks; /* additional keys of Catalog dictionary */
+/*tex Additional keys of the |/Info| dictionary: */
+
+halfword pdf_info_toks;
+
+/*tex Additional keys of the |/Catalog| and its |/OpenAction| dictionary: */
+
+halfword pdf_catalog_toks;
+
halfword pdf_catalog_openaction;
-halfword pdf_names_toks; /* additional keys of Names dictionary */
-halfword pdf_trailer_toks; /* additional keys of Trailer dictionary */
-shipping_mode_e global_shipping_mode = NOT_SHIPPING; /* set to |shipping_mode| when |ship_out| starts */
+/*tex Additional keys of the |/Names| dictionary: */
+
+halfword pdf_names_toks;
+
+/*tex Additional keys of the |/Trailer| dictionary" */
+
+halfword pdf_trailer_toks;
+
+/*tex Set to |shipping_mode| when |ship_out| starts */
+
+shipping_mode_e global_shipping_mode = NOT_SHIPPING;
+
+/*tex
+
+ Create a new buffer |strbuf_s| of size |size| and maximum allowed size
+ |limit|. Initialize it and set |p| to begin of data.
-@ Create a new buffer |strbuf_s| of size |size| and maximum allowed size |limit|.
-Initialize it and set |p| to begin of data.
+*/
-@c
strbuf_s *new_strbuf(size_t size, size_t limit)
{
strbuf_s *b;
b = xtalloc(1, strbuf_s);
b->size = size;
b->limit = limit;
- if (size > 0)
+ if (size > 0) {
b->p = b->data = xtalloc(b->size, unsigned char);
- else
- b->p = b->data = NULL; /* for other alloc */
+ } else {
+ /*tex For other alloc: */
+ b->p = b->data = NULL;
+ }
return b;
}
-@ Check that |n| bytes more fit into buffer; increase it if required.
+/*tex Check that |n| bytes more fit into buffer; increase it if required. */
-@c
static void strbuf_room(strbuf_s * b, size_t n)
{
unsigned int a;
@@ -88,25 +105,22 @@ static void strbuf_room(strbuf_s * b, size_t n)
}
}
-@ Seek to position |offset| within buffer. Position must be valid.
+/*tex Seek to position |offset| within buffer. Position must be valid. */
-@c
void strbuf_seek(strbuf_s * b, off_t offset)
{
b->p = b->data + offset;
}
-@ Get the current buffer fill level, the number of characters.
+/*tex Get the current buffer fill level, the number of characters.*/
-@c
size_t strbuf_offset(strbuf_s * b)
{
return (size_t) (b->p - b->data);
}
-@ Put one character into buffer. Make room before if needed.
+/*tex Put one character into buffer. Make room before if needed. */
-@c
void strbuf_putchar(strbuf_s * b, unsigned char c)
{
if ((size_t) (b->p - b->data + 1) > b->size)
@@ -114,81 +128,71 @@ void strbuf_putchar(strbuf_s * b, unsigned char c)
*b->p++ = c;
}
-@ Dump filled buffer part to PDF.
+/*tex Dump filled buffer part to the \PDF\ file. */
-@c
void strbuf_flush(PDF pdf, strbuf_s * b)
{
pdf_out_block(pdf, (const char *) b->data, strbuf_offset(b));
strbuf_seek(b, 0);
}
-@ Free all dynamically allocated buffer structures.
+/*tex We free all dynamically allocated buffer structures. */
-@c
void strbuf_free(strbuf_s * b)
{
xfree(b->data);
xfree(b);
}
-@ |init_pdf_struct()| is called early, only once, from maincontrol.w
+/*tex This |init_pdf_struct| is called early and only once. */
-@c
PDF init_pdf_struct(PDF pdf)
{
os_struct *os;
pdf = xtalloc(1, pdf_output_file);
memset(pdf, 0, sizeof(pdf_output_file));
pdf->job_name = makecstring(job_name);
-
- output_mode_used = OMODE_NONE; /* will be set by |fix_o_mode()| */
- pdf->o_mode = output_mode_used; /* used by synctex, we need to use output_mode_used there */
+ /*tex This will be set by |fix_o_mode|: */
+ output_mode_used = OMODE_NONE;
+ /*tex Used by synctex, we need to use output_mode_used there. */
+ pdf->o_mode = output_mode_used;
pdf->o_state = ST_INITIAL;
-
- /* init PDF and object stream writing */
+ /*tex Initialize \PDF\ and object stream writing */
pdf->os = os = xtalloc(1, os_struct);
memset(pdf->os, 0, sizeof(os_struct));
os->buf[PDFOUT_BUF] = new_strbuf(inf_pdfout_buf_size, sup_pdfout_buf_size);
os->buf[OBJSTM_BUF] = new_strbuf(inf_objstm_buf_size, sup_objstm_buf_size);
os->obj = xtalloc(PDF_OS_MAX_OBJS, os_obj_data);
os->cur_objstm = 0;
-
os->curbuf = PDFOUT_BUF;
pdf->buf = os->buf[os->curbuf];
- /*
- Later ttf_seek_outbuf(TABDIR_OFF + n * 4 * TTF_ULONG_SIZE); in ttf_init_font
- we need 236 bytes, so we start with 256 bytes as in pdftex.
+ /*tex
+ Later ttf_seek_outbuf(TABDIR_OFF + n * 4 * TTF_ULONG_SIZE); in
+ ttf_init_font we need 236 bytes, so we start with 256 bytes as in \PDFTEX.
*/
pdf->fb = new_strbuf(256, 100000000);
-
pdf->stream_deflate = false;
pdf->stream_writing = false;
-
- /*
+ /*tex
Sometimes it is neccesary to allocate memory for PDF output that cannot be
deallocated then, so we use |mem| for this purpose.
*/
pdf->mem_size = inf_pdf_mem_size;
pdf->mem = xtalloc(pdf->mem_size, int);
- /*
+ /*tex
The first word is not used so we can use zero as a value for testing
whether a pointer to |mem| is valid.
*/
pdf->mem_ptr = 1;
-
pdf->pstruct = NULL;
-
pdf->posstruct = xtalloc(1, posstructure);
pdf->posstruct->pos.h = 0;
pdf->posstruct->pos.v = 0;
pdf->posstruct->dir = dir_TLT;
-
- /* allocated size of |obj_tab| array */
+ /*tex Allocated size of |obj_tab| array> */
pdf->obj_tab_size = (unsigned) inf_obj_tab_size;
pdf->obj_tab = xtalloc(pdf->obj_tab_size + 1, obj_entry);
memset(pdf->obj_tab, 0, sizeof(obj_entry));
-
pdf->minor_version = -1;
pdf->major_version = -1;
pdf->decimal_digits = 4;
@@ -198,25 +202,22 @@ PDF init_pdf_struct(PDF pdf)
pdf->image_apply_gamma = 0;
pdf->objcompresslevel = 0;
pdf->compress_level = 0;
+ pdf->force_file = 0;
+ pdf->recompress = 0;
pdf->draftmode = 0;
pdf->inclusion_copy_font = 1;
pdf->pk_resolution = 0;
pdf->pk_fixed_dpi = 0;
pdf->pk_scale_factor = 0;
-
init_dest_names(pdf);
pdf->page_resources = NULL;
-
init_pdf_pagecalculations(pdf);
-
pdf->vfstruct = new_vfstruct();
-
return pdf;
}
-@ We use |pdf_get_mem| to allocate memory in |mem|.
+/*tex We use |pdf_get_mem| to allocate memory in |mem|. */
-@c
int pdf_get_mem(PDF pdf, int s)
{
int a;
@@ -239,39 +240,19 @@ int pdf_get_mem(PDF pdf, int s)
return ret;
}
-@ there are defined in |luatex-api.h|, so we need |luatex-api.c|:
-
-@c
-output_mode get_o_mode(void)
-{
- output_mode o_mode;
- if (output_mode_par > 0) {
- o_mode = OMODE_PDF;
- } else
- o_mode = OMODE_DVI;
- return o_mode;
-}
+/*tex
-void fix_o_mode(void)
-{
- output_mode o_mode = get_o_mode();
- if (output_mode_used == OMODE_NONE) {
- output_mode_used = o_mode;
- static_pdf->o_mode = output_mode_used; /* used by synctex, we need to use output_mode_used there */
- } else if (output_mode_used != o_mode) {
- normal_error("pdf backend", "\\outputmode can only be changed before anything is written to the output");
- }
-}
+ This ensures that |pdfmajorversion| and |pdfminorversion| are set only before
+ any bytes have been written to the generated \PDF\ file. Here also all
+ variables for \PDF\ output are initialized, the \PDF\ file is opened by
+ |ensure_pdf_open|, and the \PDF\ header is written.
-@ This ensures that |pdfmajorversion| and |pdfminorversion| are set only before any
-bytes have been written to the generated \.{PDF} file. Here also all variables for
-\.{PDF} output are initialized, the \.{PDF} file is opened by |ensure_pdf_open|, and
-the \.{PDF} header is written.
+*/
-@c
void fix_pdf_version(PDF pdf)
{
- if (pdf->major_version < 0) { /* unset */
+ if (pdf->major_version < 0) {
+ /*tex It is unset. */
if (pdf_major_version == 0) {
normal_warning("pdf backend","unset major version, using 1 instead");
pdf->major_version = 1;
@@ -284,7 +265,8 @@ void fix_pdf_version(PDF pdf)
} else if (pdf->major_version != pdf_major_version) {
normal_warning("pdf backend", "the major version cannot be changed after data is written to the PDF file");
}
- if (pdf->minor_version < 0) { /* unset */
+ if (pdf->minor_version < 0) {
+ /*tex It is unset. */
if ((pdf_minor_version < 0) || (pdf_minor_version > 9)) {
formatted_warning("pdf backend","illegal minor version %d, using 4 instead",pdf_minor_version);
pdf->minor_version = 4;
@@ -301,19 +283,18 @@ static void fix_pdf_draftmode(PDF pdf)
if (pdf->draftmode != draft_mode_par)
normal_warning("pdf backend", "draftmode cannot be changed after data is written to the PDF file");
if (pdf->draftmode != 0) {
- pdf->compress_level = 0; /* re-fix it, might have been changed inbetween */
+ /*tex Fix these as they might have been changed in between. */
+ pdf->compress_level = 0;
pdf->objcompresslevel = 0;
}
}
-@ @c
#define ZIP_BUF_SIZE 32768
#define check_err(f, fn) \
if (f != Z_OK) \
formatted_error("pdf backend","zlib %s() failed (error code %d)", fn, f)
-@ @c
static void write_zip(PDF pdf)
{
int flush, err = Z_OK;
@@ -363,7 +344,6 @@ static void write_zip(PDF pdf)
pdf->stream_length = (off_t) s->total_out;
}
-@ @c
void zip_free(PDF pdf)
{
if (pdf->zipbuf != NULL) {
@@ -373,7 +353,6 @@ void zip_free(PDF pdf)
xfree(pdf->c_stream);
}
-@ @c
static void write_nozip(PDF pdf)
{
strbuf_s *buf = pdf->buf;
@@ -385,12 +364,15 @@ static void write_nozip(PDF pdf)
pdf->last_byte = *(buf->p - 1);
}
-@ The PDF buffer is flushed by calling |pdf_flush|, which checks the
-variable |zip_write_state| and will compress the buffer before flushing if
-neccesary. We call |pdf_begin_stream| to begin a stream and |pdf_end_stream|
-to finish it. The stream contents will be compressed if compression is turn on.
+/*tex
+
+ The PDF buffer is flushed by calling |pdf_flush|, which checks the variable
+ |zip_write_state| and will compress the buffer before flushing if neccesary.
+ We call |pdf_begin_stream| to begin a stream and |pdf_end_stream| to finish
+ it. The stream contents will be compressed if compression is turn on.
+
+*/
-@c
void pdf_flush(PDF pdf)
{
os_struct *os = pdf->os;
@@ -422,20 +404,25 @@ void pdf_flush(PDF pdf)
}
}
-@ @c
static void pdf_buffer_select(PDF pdf, buffer_e buf)
{
os_struct *os = pdf->os;
- if (pdf->os_enable && buf == OBJSTM_BUF)
- os->curbuf = OBJSTM_BUF; /* switch to object stream */
- else
- os->curbuf = PDFOUT_BUF; /* switch to PDF stream */
+ if (pdf->os_enable && buf == OBJSTM_BUF) {
+ /*tex Switch to object stream: */
+ os->curbuf = OBJSTM_BUF;
+ } else {
+ /*tex Switch to \PDF\ stream: */
+ os->curbuf = PDFOUT_BUF;
+ }
pdf->buf = os->buf[pdf->os->curbuf];
}
-@ create new \.{/ObjStm} object if required, and set up cross reference info
+/*tex
+
+ We create new |/ObjStm| object if required, and set up cross reference info.
+
+*/
-@c
static void pdf_prepare_obj(PDF pdf, int k, int pdf_os_threshold)
{
os_struct *os = pdf->os;
@@ -447,15 +434,18 @@ static void pdf_prepare_obj(PDF pdf, int k, int pdf_os_threshold)
switch (os->curbuf) {
case PDFOUT_BUF:
obj_offset(pdf, k) = pdf_offset(pdf);
- obj_os_idx(pdf, k) = PDF_OS_MAX_OBJS; /* mark it as not included in any ObjStm */
+ /*tex Mark it as not included in any |ObjStm|. */
+ obj_os_idx(pdf, k) = PDF_OS_MAX_OBJS;
break;
case OBJSTM_BUF:
if (os->cur_objstm == 0) {
os->cur_objstm =
(unsigned int) pdf_create_obj(pdf, obj_type_objstm, 0);
os->idx = 0;
- obuf->p = obuf->data; /* start fresh object stream */
- os->ostm_ctr++; /* only for statistics */
+ /*tex Start a fresh object stream. */
+ obuf->p = obuf->data;
+ /*tex Keep some statistics. */
+ os->ostm_ctr++;
}
obj_os_idx(pdf, k) = (int) os->idx;
obj_os_objnum(pdf, k) = (int) os->cur_objstm;
@@ -467,12 +457,13 @@ static void pdf_prepare_obj(PDF pdf, int k, int pdf_os_threshold)
}
}
-@* Low-level buffer checkers.
+/*tex
+
+ We set the active buffer pointer and make sure that there are at least |n|
+ bytes free in that buffer, flushing happens if needed.
-@ Set the active buffer pointer. Make sure that there are at least |n| bytes free
-in that buffer, flush if needed.
+*/
-@c
inline void pdf_room(PDF pdf, int n)
{
strbuf_s *buf = pdf->buf;
@@ -490,7 +481,6 @@ inline void pdf_room(PDF pdf, int n)
}
}
-@ @c
void pdf_out_block(PDF pdf, const char *s, size_t n)
{
size_t l;
@@ -507,7 +497,6 @@ void pdf_out_block(PDF pdf, const char *s, size_t n)
} while (n > 0);
}
-@ @c
__attribute__ ((format(printf, 2, 3)))
void pdf_printf(PDF pdf, const char *fmt, ...)
{
@@ -521,9 +510,6 @@ void pdf_printf(PDF pdf, const char *fmt, ...)
va_end(args);
}
-@ print out a string to PDF buffer
-
-@c
void pdf_print(PDF pdf, str_number s)
{
const char *ss;
@@ -537,9 +523,6 @@ void pdf_print(PDF pdf, str_number s)
}
}
-@ print out a integer to PDF buffer
-
-@c
void pdf_print_int(PDF pdf, longinteger n)
{
char s[24];
@@ -549,33 +532,6 @@ void pdf_print_int(PDF pdf, longinteger n)
pdf_out_block(pdf, (const char *) s, (size_t) w);
}
-@ @c
-/*
-void print_pdffloat(PDF pdf, pdffloat f)
-{
- char a[24];
- int e = f.e, i, l;
- int64_t m = f.m;
- if (m < 0) {
- pdf_out(pdf, '-');
- m *= -1;
- }
- l = m / ten_pow[e];
- pdf_print_int(pdf, l);
- l = m % ten_pow[e];
- if (l != 0) {
- pdf_out(pdf, '.');
- snprintf(a, 23, "%d", l + ten_pow[e]);
- for (i = e; i > 0; i--) {
- if (a[i] != '0')
- break;
- a[i] = '\0';
- }
- pdf_puts(pdf, (a + 1));
- }
-}
-*/
-
void print_pdffloat(PDF pdf, pdffloat f)
{
int64_t m = f.m;
@@ -584,7 +540,7 @@ void print_pdffloat(PDF pdf, pdffloat f)
} else {
int e = f.e;
if (e == 0) {
- /* division by ten_pow[0] == 1 */
+ /*tex division by |ten_pow[0] == 1| */
if (m == 1) {
pdf_out(pdf, '1');
} else {
@@ -622,18 +578,19 @@ void print_pdffloat(PDF pdf, pdffloat f)
}
}
-@ print out |s| as string in PDF output
-
-@c
void pdf_print_str(PDF pdf, const char *s)
{
const char *orig = s;
- int l = (int) strlen(s) - 1; /* last string index */
+ /*tex This initializes at the last string index. */
+ int l = (int) strlen(s) - 1;
if (l < 0) {
pdf_puts(pdf, "()");
return;
}
- /* the next is not really safe, the string could be "(a)xx(b)" */
+ /*tex
+ The next might not really be safe as the string could be ``(a)xx(b)'' but
+ so far we never had an issue.
+ */
if ((s[0] == '(') && (s[l] == ')')) {
pdf_puts(pdf, s);
return;
@@ -653,12 +610,11 @@ void pdf_print_str(PDF pdf, const char *s)
pdf_out(pdf, ')');
return;
}
- pdf_puts(pdf, orig); /* it was a hex string after all */
+ pdf_puts(pdf, orig);
}
-@ begin a stream (needs to have a stream dictionary also)
+/*tex A stream needs to have a stream dictionary also. */
-@c
void pdf_begin_stream(PDF pdf)
{
pdf_puts(pdf, "\nstream\n");
@@ -672,9 +628,6 @@ void pdf_begin_stream(PDF pdf)
pdf->last_byte = 0;
}
-@ end a stream
-
-@c
void pdf_end_stream(PDF pdf)
{
os_struct *os = pdf->os;
@@ -682,7 +635,8 @@ void pdf_end_stream(PDF pdf)
case PDFOUT_BUF:
if (pdf->zip_write_state == ZIP_WRITING)
pdf->zip_write_state = ZIP_FINISH;
- pdf_flush(pdf); /* sets pdf->last_byte */
+ /*tex This sets| pdf->last_byte|. */
+ pdf_flush(pdf);
break;
case OBJSTM_BUF:
normal_error("pdf backend", "bad buffer in end stream, case 1");
@@ -692,43 +646,71 @@ void pdf_end_stream(PDF pdf)
}
pdf->stream_deflate = false;
pdf->stream_writing = false;
- pdf_out(pdf, '\n'); /* doesn't really belong to the stream */
+ /*tex This doesn't really belong to the stream: */
+ pdf_out(pdf, '\n');
pdf_puts(pdf, "endstream");
- /* write stream /Length */
+ /*tex Write the stream |/Length|. */
+
if (pdf->seek_write_length && pdf->draftmode == 0) {
+ xfseeko(pdf->file, (off_t)pdf->stream_length_offset+12, SEEK_SET, pdf->job_name);
+ fprintf(pdf->file, " ");
xfseeko(pdf->file, (off_t)pdf->stream_length_offset, SEEK_SET, pdf->job_name);
- fprintf(pdf->file, "%" LONGINTEGER_PRI "i", (LONGINTEGER_TYPE) pdf->stream_length);
+ fprintf(pdf->file, "%" LONGINTEGER_PRI "i >>", (LONGINTEGER_TYPE) pdf->stream_length);
xfseeko(pdf->file, 0, SEEK_END, pdf->job_name);
}
pdf->seek_write_length = false;
}
-@ To print |scaled| value to PDF output we need some subroutines to ensure
-accurary.
+/*tex
+
+ To print |scaled| value to \PDF\ output we need some subroutines to ensure
+ accurary.
-@c
-#define max_integer 0x7FFFFFFF /* $2^{31}-1$ */
+*/
-scaled one_hundred_inch = 7227 * 65536; /* scaled value corresponds to 100in, exact, 473628672 */
-scaled one_inch = (7227 * 65536 + 50) / 100; /* scaled value corresponds to 1in (rounded to 4736287) */
-scaled one_true_inch = (7227 * 65536 + 50) / 100; /* scaled value corresponds to 1truein (rounded!) */
-scaled one_hundred_bp = (7227 * 65536) / 72; /* scaled value corresponds to 100bp */
-scaled one_bp = 65781; /* scaled value corresponds to 1bp (rounded to 65782) */
-/*
- one_bp is changed on 20110411 to be exactly 65781, as in tex itself, because this value
- is also used for \pdfpxdimen
+/*tex We max out at $2^{31}-1$. */
+
+#define max_integer 0x7FFFFFFF
+
+/*tex scaled value corresponds to 100in, exact, 473628672 */
+
+scaled one_hundred_inch = 7227 * 65536;
+
+/*tex scaled value corresponds to 1in (rounded to 4736287) */
+
+scaled one_inch = (7227 * 65536 + 50) / 100;
+
+/*tex scaled value corresponds to 1truein (rounded!) */
+
+scaled one_true_inch = (7227 * 65536 + 50) / 100;
+
+/*tex scaled value corresponds to 100bp */
+
+scaled one_hundred_bp = (7227 * 65536) / 72;
+
+/*tex scaled value corresponds to 1bp (rounded to 65782) */
+
+scaled one_bp = 65781;
+
+/*tex
+
+ One basepoint is set to exactly 65781, as in \TEX\ itself, because this value
+ is also used for |\pdfpxdimen|.
+
*/
int ten_pow[10] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 /* $10^0..10^9$ */
};
-@ The function |divide_scaled| divides |s| by |m| using |dd| decimal
-digits of precision. It is defined in C because it is a good candidate
-for optimizations that are not possible in pascal.
+/*tex
+
+ The function |divide_scaled| divides |s| by |m| using |dd| decimal digits of
+ precision.
+
+*/
-@c
scaled round_xn_over_d(scaled x, int n, unsigned int d)
{
boolean positive = true;
@@ -757,28 +739,22 @@ scaled round_xn_over_d(scaled x, int n, unsigned int d)
return (-(scaled) u);
}
-@ @c
void pdf_add_bp(PDF pdf, scaled s)
{
pdffloat a;
pdfstructure *p = pdf->pstruct;
a.m = i64round(s * p->k1);
a.e = pdf->decimal_digits;
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
print_pdffloat(pdf, a);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
-@* handling page resources.
-
-@c
typedef struct {
int obj_type;
pdf_object_list *list;
} pr_entry;
-@ @c
static int comp_page_resources(const void *pa, const void *pb, void *p)
{
int a = ((const pr_entry *) pa)->obj_type;
@@ -791,7 +767,6 @@ static int comp_page_resources(const void *pa, const void *pb, void *p)
return 0;
}
-@ @c
void addto_page_resources(PDF pdf, pdf_obj_type t, int k)
{
pdf_resource_struct *re;
@@ -819,8 +794,10 @@ void addto_page_resources(PDF pdf, pdf_obj_type t, int k)
item->link = NULL;
item->info = k;
pr->list = item;
- if (obj_type(pdf, k) == (int)t)
- set_obj_scheduled(pdf, k); /* k is an object number */
+ if (obj_type(pdf, k) == (int)t) {
+ /*tex |k| is an object number. */
+ set_obj_scheduled(pdf, k);
+ }
} else {
for (p = pr->list; p->info != k && p->link != NULL; p = p->link);
if (p->info != k) {
@@ -834,7 +811,6 @@ void addto_page_resources(PDF pdf, pdf_obj_type t, int k)
}
}
-@ @c
pdf_object_list *get_page_resources_list(PDF pdf, pdf_obj_type t)
{
pdf_resource_struct *re = pdf->page_resources;
@@ -848,7 +824,6 @@ pdf_object_list *get_page_resources_list(PDF pdf, pdf_obj_type t)
return pr->list;
}
-@ @c
static void reset_page_resources(PDF pdf)
{
pdf_resource_struct *re = pdf->page_resources;
@@ -864,19 +839,18 @@ static void reset_page_resources(PDF pdf)
l2 = l1->link;
free(l1);
}
- p->list = NULL; /* but the AVL tree remains */
+ /*tex We reset but the AVL tree remains! */
+ p->list = NULL;
}
}
}
-@ @c
static void destroy_pg_res_tree(void *pa, void *param)
{
(void) param;
xfree(pa);
}
-@ @c
static void destroy_page_resources_tree(PDF pdf)
{
pdf_resource_struct *re = pdf->page_resources;
@@ -886,11 +860,6 @@ static void destroy_page_resources_tree(PDF pdf)
re->resources_tree = NULL;
}
-@* Subroutines to print out various PDF objects.
-
-@ print out an integer |n| with fixed width |w|; used for outputting cross-reference table. The
-specification says that an offset must take 10 bytes.
-@c
static void pdf_print_fw_int(PDF pdf, longinteger n)
{
unsigned char digits[11];
@@ -901,20 +870,26 @@ static void pdf_print_fw_int(PDF pdf, longinteger n)
digits[k] = (unsigned char) ('0' + (n % 10));
n /= 10;
} while (k != 0);
- if (n!=0)
- /* the absolute value of $n$ is greater than 9999999999 */
- normal_error("pdf backend", "offset exceeds 10 bytes, try enabling object compression.");
+ if (n!=0) {
+ /*tex The absolute value of $n$ is greater than 9999999999. */
+ normal_error("pdf backend", "offset exceeds 10 bytes, try enabling object compression.");
+ }
digits[10]='\0';
pdf_puts(pdf, (const char *) digits);
}
-@ print out an integer |n| as a fixed number |w| of bytes; used for outputting \.{/XRef} cross-reference stream
-@c
+/*tex
+
+ We print out an integer |n| as a fixed number |w| of bytes,. This is used in
+ the |XRef| cross-reference stream creator.
+
+*/
+
static void pdf_out_bytes(PDF pdf, longinteger n, size_t w)
{
- int k;
- unsigned char bytes[8]; /* digits in a number being output */
- k = (int) w;
+ /*tex The number of digits in a number being output. */
+ unsigned char bytes[8];
+ int k = (int) w;
do {
k--;
bytes[k] = (unsigned char) (n % 256);
@@ -923,32 +898,24 @@ static void pdf_out_bytes(PDF pdf, longinteger n, size_t w)
pdf_out_block(pdf, (const char *) bytes, w);
}
-@ print out |s| as string in PDF output
-
-@c
void pdf_print_str_ln(PDF pdf, const char *s)
{
pdf_print_str(pdf, s);
pdf_out(pdf, '\n');
}
-@ @c
void pdf_print_toks(PDF pdf, halfword p)
{
int len = 0;
char *s = tokenlist_to_cstring(p, true, &len);
if (len > 0) {
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_puts(pdf, s);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
xfree(s);
}
-@ prints a rect spec
-
-@c
void pdf_add_rect_spec(PDF pdf, halfword r)
{
pdf_add_bp(pdf, pdf_ann_left(r));
@@ -957,9 +924,6 @@ void pdf_add_rect_spec(PDF pdf, halfword r)
pdf_add_bp(pdf, pdf_ann_top(r));
}
-@ output a rectangle specification to PDF file
-
-@c
void pdf_rectangle(PDF pdf, halfword r)
{
pdf_add_name(pdf, "Rect");
@@ -968,7 +932,6 @@ void pdf_rectangle(PDF pdf, halfword r)
pdf_end_array(pdf);
}
-@ @c
static void init_pdf_outputparameters(PDF pdf)
{
int pk_mode;
@@ -980,6 +943,7 @@ static void init_pdf_outputparameters(PDF pdf)
pdf->image_hicolor = fix_int(pdf_image_hicolor, 0, 1);
pdf->image_apply_gamma = fix_int(pdf_image_apply_gamma, 0, 1);
pdf->objcompresslevel = fix_int(pdf_obj_compress_level, 0, MAX_OBJ_COMPRESS_LEVEL);
+ pdf->recompress = fix_int(pdf_recompress, 0, 1);
pdf->inclusion_copy_font = fix_int(pdf_inclusion_copy_font, 0, 1);
pdf->pk_resolution = fix_int(pdf_pk_resolution, 72, 8000);
pdf->pk_fixed_dpi = fix_int(pdf_pk_fixed_dpi, 0, 1);
@@ -992,19 +956,19 @@ static void init_pdf_outputparameters(PDF pdf)
}
pdf->os_enable = false;
}
- if (pdf->pk_resolution == 0) /* if not set from format file or by user */
- pdf->pk_resolution = pk_dpi; /* take it from \.{texmf.cnf} */
+ if (pdf->pk_resolution == 0) {
+ /*tex If not set from format file or by user take it from \.{texmf.cnf}. */
+ pdf->pk_resolution = pk_dpi;
+ }
pdf->pk_scale_factor = divide_scaled(72, pdf->pk_resolution, pk_decimal_digits(pdf,5));
if (!callback_defined(read_pk_file_callback)) {
- pk_mode = pdf_pk_mode; /* lookup once */
+ pk_mode = pdf_pk_mode;
if (pk_mode != null) {
char *s = tokenlist_to_cstring(pk_mode, true, NULL);
- /* This will become LUATEX in 1.0. */
- kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, s, nil);
+ kpse_init_prog("LUATEX", (unsigned) pdf->pk_resolution, s, nil);
xfree(s);
} else {
- /* This will become LUATEX in 1.0. */
- kpse_init_prog("PDFTEX", (unsigned) pdf->pk_resolution, nil, nil);
+ kpse_init_prog("LUATEX", (unsigned) pdf->pk_resolution, nil, nil);
}
if (!kpse_var_value("MKTEXPK"))
kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
@@ -1014,75 +978,54 @@ static void init_pdf_outputparameters(PDF pdf)
pdf->resname_prefix = get_resname_prefix(pdf);
}
-@ Checks that we have a name for the generated PDF file and that it's open.
+/*tex
-@c
-static void ensure_output_file_open(PDF pdf, const char *ext)
-{
- char *fn;
- if (pdf->file_name != NULL)
- return;
- if (job_name == 0)
- open_log_file();
- fn = pack_job_name(ext);
- if (pdf->draftmode == 0 || output_mode_used == OMODE_DVI) {
- while (!lua_b_open_out(&pdf->file, fn))
- fn = prompt_file_name("file name for output", ext);
- }
- pdf->file_name = fn;
-}
+ This checks that we have a name for the generated PDF file and that it's
+ open.
-@ @c
-static void ensure_pdf_header_written(PDF pdf)
+*/
+
+void pdf_write_header(PDF pdf)
{
- /* Initialize variables for \.{PDF} output */
+ /*tex Initialize variables for \PDF\ output. */
fix_pdf_version(pdf);
init_pdf_outputparameters(pdf);
fix_pdf_draftmode(pdf);
- /* Write \.{PDF} header */
+ /*tex Write \PDF\ header */
pdf_printf(pdf, "%%PDF-%d.%d\n", pdf->major_version, pdf->minor_version);
- /* The next blob will be removed 1.0. */
+ /* Some binary crap. */
pdf_out(pdf, '%');
- pdf_out(pdf, 'P' + 128);
+ pdf_out(pdf, 'L' + 128);
+ pdf_out(pdf, 'U' + 128);
+ pdf_out(pdf, 'A' + 128);
pdf_out(pdf, 'T' + 128);
pdf_out(pdf, 'E' + 128);
pdf_out(pdf, 'X' + 128);
+ pdf_out(pdf, 'P' + 128);
+ pdf_out(pdf, 'D' + 128);
+ pdf_out(pdf, 'F' + 128);
pdf_out(pdf, '\n');
}
-@ @c
+void pdf_open_file(PDF pdf) {
+ ensure_output_file_open(pdf, ".pdf");
+}
+
void ensure_output_state(PDF pdf, output_state s)
{
if (pdf->o_state < s) {
- if (s > ST_INITIAL)
+ if (s > ST_INITIAL) {
ensure_output_state(pdf, s - 1);
+ }
switch (s - 1) {
case ST_INITIAL:
fix_o_mode();
break;
case ST_OMODE_FIX:
- switch (output_mode_used) {
- case OMODE_DVI:
- ensure_output_file_open(pdf, ".dvi");
- break;
- case OMODE_PDF:
- ensure_output_file_open(pdf, ".pdf");
- break;
- default:
- normal_error("pdf backend","weird output state");
- }
+ backend_out_control[backend_control_open_file](pdf);
break;
case ST_FILE_OPEN:
- switch (output_mode_used) {
- case OMODE_DVI:
- ensure_dvi_header_written(pdf);
- break;
- case OMODE_PDF:
- ensure_pdf_header_written(pdf);
- break;
- default:
- normal_error("pdf backend","weird output state");
- }
+ backend_out_control[backend_control_write_header](pdf);
break;
case ST_HEADER_WRITTEN:
break;
@@ -1095,29 +1038,37 @@ void ensure_output_state(PDF pdf, output_state s)
}
}
-@ Write out an accumulated object stream.
+/*tex
-First the object number and byte offset pairs are generated and appended to the
-ready buffered object stream. By this the value of \.{/First} can be calculated.
-Then a new \.{/ObjStm} object is generated, and everything is copied to the PDF
-output buffer, where also compression is done. When calling this procedure,
-|pdf_os_mode| must be |true|.
+ Write out an accumulated object stream. The object number and byte offset
+ pairs are generated and appended to the ready buffered object stream. By this
+ the value of \.{/First} can be calculated. Then a new \.{/ObjStm} object is
+ generated, and everything is copied to the PDF output buffer, where also
+ compression is done. When calling this procedure, |pdf_os_mode| must be
+ |true|.
+
+*/
-@c
static void pdf_os_write_objstream(PDF pdf)
{
os_struct *os = pdf->os;
- unsigned int i, j, n1, n2; /* n1, n2: ObjStm buffer may be reallocated! */
+ /*tex |n1|, |n2|: |ObjStm| buffer may be reallocated! */
+ unsigned int i, j, n1, n2;
strbuf_s *obuf = os->buf[OBJSTM_BUF];
- if (os->cur_objstm == 0) /* no object stream started */
+ if (os->cur_objstm == 0) {
+ /*tex No object stream started. */
return;
- n1 = (unsigned int) strbuf_offset(obuf); /* remember end of collected object stream contents */
- /* this is needed here to calculate /First for the ObjStm dict */
- for (i = 0, j = 0; i < os->idx; i++) { /* add object-number/byte-offset list to buffer */
+ }
+ /*tex Remember end of collected object stream contents. */
+ n1 = (unsigned int) strbuf_offset(obuf);
+ /*tex This is needed here to calculate |/First| for the |ObjStm| dict */
+ for (i = 0, j = 0; i < os->idx; i++) {
+ /*tex Add object-number/byte-offset list to buffer. */
pdf_print_int(pdf, (int) os->obj[i].num);
pdf_out(pdf, ' ');
pdf_print_int(pdf, (int) os->obj[i].off);
- if (j == 9 || i == os->idx - 1) { /* print out in groups of ten for better readability */
+ if (j == 9 || i == os->idx - 1) {
+ /*tex Print out in groups of ten for better readability. */
pdf_out(pdf, '\n');
j = 0;
} else {
@@ -1125,192 +1076,168 @@ static void pdf_os_write_objstream(PDF pdf)
j++;
}
}
- n2 = (unsigned int) strbuf_offset(obuf); /* remember current buffer end */
- pdf_begin_obj(pdf, (int) os->cur_objstm, OBJSTM_NEVER); /* switch to PDF stream writing */
+ /*tex Remember current buffer end. */
+ n2 = (unsigned int) strbuf_offset(obuf);
+ /*tex Switch to \PDF\ stream writing. */
+ pdf_begin_obj(pdf, (int) os->cur_objstm, OBJSTM_NEVER);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "ObjStm");
- pdf_dict_add_int(pdf, "N", (int) os->idx); /* number of objects in ObjStm */
+ /*tex The number of objects in |ObjStm|. */
+ pdf_dict_add_int(pdf, "N", (int) os->idx);
pdf_dict_add_int(pdf, "First", (int) (n2 - n1));
pdf_dict_add_streaminfo(pdf);
pdf_end_dict(pdf);
pdf_begin_stream(pdf);
- /* write object-number/byte-offset list */
+ /*tex Write object-number/byte-offset list. */
pdf_out_block(pdf, (const char *) (obuf->data + n1), (size_t) (n2 - n1));
- /* write collected object stream contents */
+ /*tex Write collected object stream contents. */
pdf_out_block(pdf, (const char *) obuf->data, (size_t) n1);
pdf_end_stream(pdf);
pdf_end_obj(pdf);
- os->cur_objstm = 0; /* to force object stream generation next time */
+ /*tex We force object stream generation next time. */
+ os->cur_objstm = 0;
}
-@ begin a PDF dictionary
+/*tex Here comes a bunch of flushers: */
-@c
void pdf_begin_dict(PDF pdf)
{
+ pdf_check_space(pdf);
pdf_puts(pdf, "<<");
- pdf->cave = 0;
+ pdf_set_space(pdf);
}
-@ end a PDF dictionary
-
-@c
void pdf_end_dict(PDF pdf)
{
+ pdf_check_space(pdf);
pdf_puts(pdf, ">>");
- pdf->cave = 0;
+ pdf_set_space(pdf);
}
-@ add integer object to dict
-
-@c
void pdf_dict_add_bool(PDF pdf, const char *key, int i)
{
pdf_add_name(pdf, key);
pdf_add_bool(pdf, i);
}
-@ add integer object to dict
-
-@c
void pdf_dict_add_int(PDF pdf, const char *key, int i)
{
pdf_add_name(pdf, key);
pdf_add_int(pdf, i);
}
-@ add name object to dict
-
-@c
void pdf_dict_add_name(PDF pdf, const char *key, const char *val)
{
pdf_add_name(pdf, key);
pdf_add_name(pdf, val);
}
-@ add string object to dict
-
-@c
void pdf_dict_add_string(PDF pdf, const char *key, const char *val)
{
if (val == NULL)
return;
pdf_add_name(pdf, key);
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
- pdf->cave = 0;
+ pdf_check_space(pdf);
pdf_print_str(pdf, val);
+ pdf_set_space(pdf);
}
-@ add name reference to dict
-
-@c
void pdf_dict_add_ref(PDF pdf, const char *key, int num)
{
pdf_add_name(pdf, key);
pdf_add_ref(pdf, num);
}
-@ add objects of different types
-
-@c
void pdf_add_null(PDF pdf)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_puts(pdf, "null");
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_bool(PDF pdf, int i)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
if (i == 0)
pdf_puts(pdf, "false");
else
pdf_puts(pdf, "true");
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_int(PDF pdf, int i)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_print_int(pdf, i);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_longint(PDF pdf, longinteger n)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_print_int(pdf, n);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_string(PDF pdf, const char *s)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_print_str(pdf, s);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_name(PDF pdf, const char *name)
{
+ pdf_check_space(pdf);
pdf_out(pdf, '/');
pdf_puts(pdf, name);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
void pdf_add_ref(PDF pdf, int num)
{
- if (pdf->cave > 0)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_print_int(pdf, num);
pdf_puts(pdf, " 0 R");
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
-@ add stream length and filter entries to a stream dictionary,
-remember file position for seek
+/*tex
+
+ When we add the stream length and filter entries to a stream dictionary,
+ remember file position for seek.
+
+*/
-@c
void pdf_dict_add_streaminfo(PDF pdf)
{
- pdf_add_name(pdf, "Length");
- pdf->stream_length_offset = pdf_offset(pdf) + 1;
- pdf->seek_write_length = true; /* fill in length at |pdf_end_stream| call */
- pdf_puts(pdf, " x "); /* space for 10 decimal digits */
- pdf->cave = 1;
if (pdf->compress_level > 0) {
pdf_dict_add_name(pdf, "Filter", "FlateDecode");
pdf->stream_deflate = true;
}
+ pdf_add_name(pdf, "Length");
+ pdf->stream_length_offset = pdf_offset(pdf) + 1;
+ /*tex Fill in length at |pdf_end_stream| call. */
+ pdf->seek_write_length = true;
+ /*tex We reserve space for 10 decimal digits plus space. */
+ pdf_puts(pdf, " x ");
+ pdf_set_space(pdf);
}
-@ begin a PDF array
-
-@c
void pdf_begin_array(PDF pdf)
{
+ pdf_check_space(pdf);
pdf_out(pdf, '[');
- pdf->cave = 0;
+ pdf_set_space(pdf);
}
-@ end a PDF array
-
-@c
void pdf_end_array(PDF pdf)
{
+ pdf_check_space(pdf);
pdf_out(pdf, ']');
- pdf->cave = 0;
+ pdf_set_space(pdf);
}
-@ begin a PDF object
-
-@c
void pdf_begin_obj(PDF pdf, int i, int pdf_os_threshold)
{
os_struct *os = pdf->os;
@@ -1321,45 +1248,90 @@ void pdf_begin_obj(PDF pdf, int i, int pdf_os_threshold)
pdf_printf(pdf, "%d 0 obj\n", (int) i);
break;
case OBJSTM_BUF:
- if (pdf->compress_level == 0)
- pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */
+ if (pdf->compress_level == 0) {
+ /*tex Some debugging help. */
+ pdf_printf(pdf, "%% %d 0 obj\n", (int) i);
+ }
break;
default:
normal_error("pdf backend","weird begin object");
}
- pdf->cave = 0;
+ pdf_reset_space(pdf);
}
-@ end a PDF object
-
-@c
void pdf_end_obj(PDF pdf)
{
os_struct *os = pdf->os;
switch (os->curbuf) {
case PDFOUT_BUF:
- pdf_puts(pdf, "\nendobj\n"); /* end a PDF object */
+ /*tex End a \PDF\ object. */
+ pdf_puts(pdf, "\nendobj\n");
break;
case OBJSTM_BUF:
- os->idx++; /* = number of objects collected so far in ObjStm */
- os->o_ctr++; /* only for statistics */
- if (os->idx == PDF_OS_MAX_OBJS)
+ /*tex Tthe number of objects collected so far in ObjStm: */
+ os->idx++;
+ /*tex Only for statistics: */
+ os->o_ctr++;
+ if (os->idx == PDF_OS_MAX_OBJS) {
pdf_os_write_objstream(pdf);
- else
- pdf_out(pdf, '\n'); /* Adobe Reader seems to need this */
+ } else {
+ /*tex Adobe Reader seems to need this. */
+ pdf_out(pdf, '\n');
+ }
break;
default:
normal_error("pdf backend","weird end object");
}
}
-@ Converts any string given in in in an allowed PDF string which can be
- handled by printf et.al.: \.{\\} is escaped to \.{\\\\}, parenthesis are escaped and
- control characters are octal encoded.
- This assumes that the string does not contain any already escaped
- characters!
+/*
+ Needed for embedding fonts.
+
+*/
+
+pdf_obj *pdf_new_stream(void)
+{
+ pdf_obj *stream = xmalloc(sizeof(pdf_obj));
+ stream->length = 0;
+ stream->data = NULL;
+ return stream;
+}
+
+void pdf_add_stream(pdf_obj * stream, unsigned char *buf, long len)
+{
+ int i;
+ assert(stream != NULL);
+ if (stream->data == NULL) {
+ stream->data = xmalloc((unsigned) len);
+ } else {
+ stream->data =
+ xrealloc(stream->data, (unsigned) len + (unsigned) stream->length);
+ }
+ for (i = 0; i < len; i++) {
+ *(stream->data + stream->length + i) = *(buf + i);
+ }
+ stream->length += (unsigned) len;
+}
+
+void pdf_release_obj(pdf_obj * stream)
+{
+ if (stream != NULL) {
+ if (stream->data != NULL) {
+ xfree(stream->data);
+ }
+ xfree(stream);
+ }
+}
+
+/*
+
+ This one converts any string given in in in an allowed PDF string which can
+ be handled by printf et.al.: \.{\\} is escaped to \.{\\\\}, parenthesis are
+ escaped and control characters are octal encoded. This assumes that the
+ string does not contain any already escaped characters!
+
+*/
-@c
char *convertStringToPDFString(const char *in, int len)
{
static char pstrbuf[MAX_PSTRING_LEN];
@@ -1370,7 +1342,7 @@ char *convertStringToPDFString(const char *in, int len)
for (i = 0; i < len; i++) {
check_buf((unsigned) j + sizeof(buf), MAX_PSTRING_LEN);
if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) {
- /* convert control characters into oct */
+ /*tex Convert control characters into octal. */
k = snprintf(buf, sizeof(buf), "\\%03o", (unsigned int) (unsigned char) in[i]);
check_nprintf(k, sizeof(buf));
out[j++] = buf[0];
@@ -1378,15 +1350,15 @@ char *convertStringToPDFString(const char *in, int len)
out[j++] = buf[2];
out[j++] = buf[3];
} else if ((in[i] == '(') || (in[i] == ')')) {
- /* escape paranthesis */
+ /*tex Escape parenthesis: */
out[j++] = '\\';
out[j++] = in[i];
} else if (in[i] == '\\') {
- /* escape backslash */
+ /*tex Escape backslash: */
out[j++] = '\\';
out[j++] = '\\';
} else {
- /* copy char :-) */
+ /* Copy char : */
out[j++] = in[i];
}
}
@@ -1394,10 +1366,13 @@ char *convertStringToPDFString(const char *in, int len)
return pstrbuf;
}
-@ Converts any string given in in in an allowed PDF string which is hexadecimal
-encoded; |sizeof(out)| should be at least $|lin|*2+1$.
+/*tex
+
+ This one converts any string given in in in an allowed PDF string which is
+ hexadecimal encoded; |sizeof(out)| should be at least $|lin|*2+1$.
+
+*/
-@c
static void convertStringToHexString(const char *in, char *out, int lin)
{
int i, k;
@@ -1412,40 +1387,18 @@ static void convertStringToHexString(const char *in, char *out, int lin)
out[j] = '\0';
}
-@ Compute the ID string as per PDF1.4 9.3:
-
-File identifers are defined by the optional ID entry in a PDF file's trailer
-dictionary (see Section 3.4.4, "File Trailer"; see also implementation note 105
-in Appendix H). The value of this entry is an array of two strings. The first
-string is a permanent identifier based on the contents of the file at the time it
-was originally created, and does not change when the file is incrementally
-updated. The second string is a changing identifier based on the file's contents
-at the time it was last updated. When a file is first written, both identifiers
-are set to the same value. If both identifiers match when a file reference is
-resolved, it is very likely that the correct file has been found; if only the
-first identifier matches, then a different version of the correct file has been
-found. To help ensure the uniqueness of file identifiers, it is recommend that
-they be computed using a message digest algorithm such as MD5 (described in
-Internet RFC 1321, The MD5 Message-Digest Algorithm; see the Bibliography), using
-the following information (see implementation note 106 in Appendix H): - The
-current time
-
-- A string representation of the file's location, usually a pathname
-- The size of the file in bytes
-- The values of all entries in the file's document information
- dictionary (see Section 9.2.1, Document Information Dictionary )
-
-This stipulates only that the two IDs must be identical when the file is created
-and that they should be reasonably unique. Since it's difficult to get the file
-size at this point in the execution of pdfTeX and scanning the info dict is also
-difficult, we start with a simpler implementation using just the first two items.
+/*tex
+ We compute the ID string as per PDF specification 1.4 9.3 that stipulates
+ only that the two IDs must be identical when the file is created and that
+ they should be reasonably unique. Since it's difficult to get the file size
+ at this point in the execution of pdfTeX and scanning the info dict is also
+ difficult, we start with a simpler implementation using just the first two
+ items.
-@c
-
-/*
A user supplied trailerid had better be an array! So maybe we need to check
- for [] and error otherwise.
+ for |[]| and error otherwise.
+
*/
static void print_ID(PDF pdf)
@@ -1457,10 +1410,10 @@ static void print_ID(PDF pdf)
if (p && strlen(p) > 0) {
pdf_puts(pdf,p);
} else if (pdf_trailer_id != 0) {
- /* user provided one */
+ /*tex The user provided one: */
pdf_print_toks(pdf, pdf_trailer_id);
} else {
- /* system provided one */
+ /*tex The system provided one: */
time_t t;
size_t size;
char time_str[32];
@@ -1468,13 +1421,10 @@ static void print_ID(PDF pdf)
md5_byte_t digest[16];
char id[64];
char pwd[4096];
- /* start md5 */
md5_init(&state);
- /* get the time */
t = pdf->start_time;
size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t));
md5_append(&state, (const md5_byte_t *) time_str, (int) size);
- /* get the file name */
if (getcwd(pwd, sizeof(pwd)) == NULL) {
formatted_error("pdf backend","getcwd() failed (%s), (path too long?)", strerror(errno));
}
@@ -1492,63 +1442,27 @@ static void print_ID(PDF pdf)
md5_append(&state, (const md5_byte_t *) pwd, (int) strlen(pwd));
md5_append(&state, (const md5_byte_t *) "/", 1);
md5_append(&state, (const md5_byte_t *) pdf->file_name, (int) strlen(pdf->file_name));
- /* finish md5 */
md5_finish(&state, digest);
- /* write the IDs */
convertStringToHexString((char *) digest, id, 16);
pdf_begin_array(pdf);
+ pdf_check_space(pdf);
pdf_printf(pdf, "<%s> <%s>", id, id);
+ pdf_set_space(pdf);
pdf_end_array(pdf);
}
}
}
-@ Print the /CreationDate entry.
-
-PDF Reference, third edition says about the expected date format:
-
-3.8.2 Dates
-
-PDF defines a standard date format, which closely follows that of the
-international standard ASN.1 (Abstract Syntax Notation One), defined in ISO/IEC
-8824 (see the Bibliography). A date is a string of the form
-
-(D:YYYYMMDDHHmmSSOHH'mm')
-
-where
-
-YYYY is the year
-MM is the month
-DD is the day (01-31)
-HH is the hour (00-23)
-mm is the minute (00-59)
-SS is the second (00-59)
-O is the relationship of local time to Universal Time (UT), denoted by one
- of the characters +, -, or Z (see below)
-HH followed by ' is the absolute value of the offset from UT in hours (00-23)
-mm followed by ' is the absolute value of the offset from UT in minutes (00-59)
-
-The apostrophe character (') after HH and mm is part of the syntax. All fields
-after the year are optional. (The prefix D:, although also optional, is strongly
-recommended.) The default values for MM and DD are both 01; all other numerical
-fields default to zero values. A plus sign (+) as the value of the O field
-signifies that local time is later than UT, a minus sign (-) that local time is
-earlier than UT, and the letter Z that local time is equal to UT. If no UT
-information is specified, the relationship of the specified time to UT is
-considered to be unknown. Whether or not the time zone is known, the rest of the
-date should be specified in local time.
+/*tex
-For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard Time, is
-represented by the string
+ Here we print the |/CreationDate| entry in the form
+ |(D:YYYYMMDDHHmmSSOHH'mm')|. The main difficulty is get the time zone offset.
+ |strftime()| does this in ISO C99 (e.g. newer glibc) with \%z, but we have to
+ work with other systems (e.g. Solaris 2.5).
-D:199812231952-08'00'
-
-The main difficulty is get the time zone offset. |strftime()| does this in ISO
-C99 (e.g. newer glibc) with \%z, but we have to work with other systems (e.g.
-Solaris 2.5).
+*/
-@c
-#define TIME_STR_SIZE 30 /* minimum size for |time_str| is 24: |"D:YYYYmmddHHMMSS+HH'MM'"| */
+#define TIME_STR_SIZE 30
static void makepdftime(PDF pdf)
{
@@ -1557,32 +1471,31 @@ static void makepdftime(PDF pdf)
int i, off, off_hours, off_mins;
time_t t = pdf->start_time;
char *time_str = pdf->start_time_str;
- /* get the time */
+ /*tex Get the time. */
if (utc_option) {
lt = *gmtime(&t);
} else {
lt = *localtime(&t);
}
size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", &lt);
- /* expected format: "YYYYmmddHHMMSS" */
+ /*tex Expected format: |YYYYmmddHHMMSS|. */
if (size == 0) {
- /* unexpected, contents of |time_str| is undefined */
+ /*tex Unexpected, contents of |time_str| is undefined .*/
time_str[0] = '\0';
return;
}
- /*
- correction for seconds: \%S can be in range 00..61, the PDF reference
- expects 00..59, therefore we map "60" and "61" to "59"
+ /*tex
+ A correction for seconds. the PDF reference expects 00..59, therefore we
+ map 60 and 61 to 59.
*/
if (time_str[14] == '6') {
time_str[14] = '5';
time_str[15] = '9';
- /* for safety */
+ /*tex For safety: */
time_str[16] = '\0';
}
- /* get the time zone offset */
+ /*tex Get the time zone offset. */
gmt = *gmtime(&t);
- /* this calculation method was found in exim's tod.c */
off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
if (lt.tm_year != gmt.tm_year) {
off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440;
@@ -1601,7 +1514,6 @@ static void makepdftime(PDF pdf)
pdf->start_time = t;
}
-@ @c
void initialize_start_time(PDF pdf)
{
if (pdf->start_time == 0) {
@@ -1611,14 +1523,12 @@ void initialize_start_time(PDF pdf)
}
}
-@ @c
char *getcreationdate(PDF pdf)
{
initialize_start_time(pdf);
return pdf->start_time_str;
}
-@ @c
void remove_pdffile(PDF pdf)
{
if (pdf != NULL) {
@@ -1629,10 +1539,9 @@ void remove_pdffile(PDF pdf)
}
}
-@ Use |check_o_mode()| in the backend-specific "Implement..." chunks
+/*tex We use this checker in other modules. It is not pdf specific. */
-@c
-void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict) /* s ignored now */
+void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict)
{
output_mode o_mode;
@@ -1641,16 +1550,13 @@ void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict)
normal_error("lua only","no backend present, needed for what you asked for");
return ;
}
- /*
- in warn mode (strict == false): only check, don't do |fix_o_mode()| here! |output_mode_used|
- is left in possibly wrong state until real output, ok.
- */
if (output_mode_used == OMODE_NONE)
o_mode = get_o_mode();
else
o_mode = output_mode_used;
- pdf->o_mode = output_mode_used; /* used by synctex, we need to use output_mode_used there */
- if (!((1 << o_mode) & o_mode_bitpattern)) { /* warning or error */
+ /*tex This is used by synctex, we need to use output_mode_used there. */
+ pdf->o_mode = output_mode_used;
+ if (!((1 << o_mode) & o_mode_bitpattern)) {
switch (o_mode) {
case OMODE_DVI:
m = "DVI";
@@ -1669,7 +1575,23 @@ void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict)
ensure_output_state(pdf, ST_HEADER_WRITTEN);
}
-@ @c
+void ensure_output_file_open(PDF pdf, const char *ext)
+{
+ char *fn;
+ if (pdf->file_name != NULL)
+ return;
+ if (job_name == 0)
+ open_log_file();
+ fn = pack_job_name(ext);
+ if (pdf->draftmode == 0 || output_mode_used == OMODE_DVI) {
+ while (!lua_b_open_out(&pdf->file, fn))
+ fn = prompt_file_name("file name for output", ext);
+ }
+ pdf->file_name = fn;
+}
+
+/*tex till here */
+
void set_job_id(PDF pdf, int year, int month, int day, int time)
{
char *name_string, *format_string, *s;
@@ -1681,7 +1603,7 @@ void set_job_id(PDF pdf, int year, int month, int day, int time)
format_string = makecstring(format_ident);
slen = SMALL_BUF_SIZE + strlen(name_string) + strlen(format_string) + strlen(luatex_banner);
s = xtalloc(slen, char);
- /* The Web2c version string starts with a space. */
+ /*tex The \WEBC\ version string starts with a space. (Really?) */
i = snprintf(s, slen, "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s", year, month, day, time / 60, time % 60, name_string, format_string, luatex_banner);
check_nprintf(i, slen);
pdf->job_id_string = xstrdup(s);
@@ -1690,11 +1612,11 @@ void set_job_id(PDF pdf, int year, int month, int day, int time)
xfree(format_string);
}
-@ @c
char *get_resname_prefix(PDF pdf)
{
static char name_str[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- static char prefix[7]; /* make a tag of 6 chars long */
+ /*tex We make a tag of 6 characters long. */
+ static char prefix[7];
short i;
size_t base = strlen(name_str);
unsigned long crc = crc32(0L, Z_NULL, 0);
@@ -1707,12 +1629,11 @@ char *get_resname_prefix(PDF pdf)
return prefix;
}
-@ @c
void pdf_begin_page(PDF pdf)
{
int xform_attributes;
int xform_type = 0;
- scaled form_margin = pdf_xform_margin; /* was one_bp until SVN4066 */
+ scaled form_margin = pdf_xform_margin;
ensure_output_state(pdf, ST_HEADER_WRITTEN);
init_pdf_pagecalculations(pdf);
if (pdf->page_resources == NULL) {
@@ -1724,7 +1645,8 @@ void pdf_begin_page(PDF pdf)
if (global_shipping_mode == SHIPPING_PAGE) {
pdf->last_page = pdf_get_obj(pdf, obj_type_page, total_pages + 1, 0);
- set_obj_aux(pdf, pdf->last_page, 1); /* mark that this page has been created */
+ /*tex Mark that this page has been created. */
+ set_obj_aux(pdf, pdf->last_page, 1);
pdf->last_stream = pdf_create_obj(pdf, obj_type_pagestream, 0);
pdf_begin_obj(pdf, pdf->last_stream, OBJSTM_NEVER);
pdf->last_thread = null;
@@ -1733,15 +1655,16 @@ void pdf_begin_page(PDF pdf)
xform_type = obj_xform_type(pdf, pdf_cur_form) ;
pdf_begin_obj(pdf, pdf_cur_form, OBJSTM_NEVER);
pdf->last_stream = pdf_cur_form;
- /* Write out Form stream header */
+ /*tex Write out the |Form| stream header */
pdf_begin_dict(pdf);
if (xform_type == 0) {
pdf_dict_add_name(pdf, "Type", "XObject");
pdf_dict_add_name(pdf, "Subtype", "Form");
pdf_dict_add_int(pdf, "FormType", 1);
}
- xform_attributes = pdf_xform_attr; /* lookup once */
- form_margin = obj_xform_margin(pdf, pdf_cur_form); /* now stored in object */
+ xform_attributes = pdf_xform_attr;
+ /*tex Now stored in the object: */
+ form_margin = obj_xform_margin(pdf, pdf_cur_form);
if (xform_attributes != null)
pdf_print_toks(pdf, xform_attributes);
if (obj_xform_attr(pdf, pdf_cur_form) != null) {
@@ -1750,7 +1673,7 @@ void pdf_begin_page(PDF pdf)
set_obj_xform_attr(pdf, pdf_cur_form, null);
}
if (obj_xform_attr_str(pdf, pdf_cur_form) != null) {
- lua_pdf_literal(pdf, obj_xform_attr_str(pdf, pdf_cur_form));
+ lua_pdf_literal(pdf, obj_xform_attr_str(pdf, pdf_cur_form),1);
luaL_unref(Luas, LUA_REGISTRYINDEX, obj_xform_attr_str(pdf, pdf_cur_form));
set_obj_xform_attr_str(pdf, pdf_cur_form, null);
}
@@ -1776,11 +1699,12 @@ void pdf_begin_page(PDF pdf)
}
pdf_dict_add_ref(pdf, "Resources", pdf->page_resources->last_resources);
}
- /* Start stream of page/form contents */
+ /*tex Start a stream of page or form contents: */
pdf_dict_add_streaminfo(pdf);
pdf_end_dict(pdf);
pdf_begin_stream(pdf);
- pos_stack_used = 0; /* start with empty stack */
+ /*tex Start with an empty stack: */
+ pos_stack_used = 0;
if (global_shipping_mode == SHIPPING_PAGE) {
colorstackpagestart();
}
@@ -1788,40 +1712,37 @@ void pdf_begin_page(PDF pdf)
pdf_out_colorstack_startpage(pdf);
}
-@ @c
void print_pdf_table_string(PDF pdf, const char *s)
{
size_t len;
const char *ls;
lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
lua_rawget(Luas, LUA_REGISTRYINDEX);
- lua_pushstring(Luas, s); /* s t ... */
- lua_rawget(Luas, -2); /* s? t ... */
- if (lua_type(Luas, -1) == LUA_TSTRING) { /* s t ... */
+ lua_pushstring(Luas, s);
+ lua_rawget(Luas, -2);
+ if (lua_type(Luas, -1) == LUA_TSTRING) {
ls = lua_tolstring(Luas, -1, &len);
if (len > 0) {
- if (pdf->cave == 1)
- pdf_out(pdf, ' ');
+ pdf_check_space(pdf);
pdf_out_block(pdf, ls, len);
- pdf->cave = 1;
+ pdf_set_space(pdf);
}
}
lua_pop(Luas, 2);
}
-@ @c
const char *get_pdf_table_string(const char *s)
{
const_lstring ls;
lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(pdf_data));
lua_rawget(Luas, LUA_REGISTRYINDEX);
- lua_pushstring(Luas, s); /* s t ... */
- lua_rawget(Luas, -2); /* s? t ... */
- if (lua_type(Luas, -1) == LUA_TSTRING) { /* s t ... */
+ lua_pushstring(Luas, s);
+ lua_rawget(Luas, -2);
+ if (lua_type(Luas, -1) == LUA_TSTRING) {
ls.s = lua_tolstring(Luas, -1, &ls.l);
- /*
- s is supposed to be anchored (e.g in the registry)
- so it's not garbage collected
+ /*tex
+ Here |s| is supposed to be anchored (e.g.\ in the registry) so it's
+ not garbage collected.
*/
lua_pop(Luas, 2);
return ls.s;
@@ -1830,7 +1751,6 @@ const char *get_pdf_table_string(const char *s)
return NULL ;
}
-@ @c
void pdf_end_page(PDF pdf)
{
char s[64], *p;
@@ -1838,12 +1758,14 @@ void pdf_end_page(PDF pdf)
pdf_resource_struct *res_p = pdf->page_resources;
pdf_resource_struct local_page_resources;
pdf_object_list *annot_list, *bead_list, *link_list, *ol, *ol1;
- scaledpos save_cur_page_size; /* to save |pdf->page_size| during flushing pending forms */
+ /*tex We save |pdf->page_size| during flushing pending forms: */
+ scaledpos save_cur_page_size;
shipping_mode_e save_shipping_mode;
+ int save_pdf_cur_form;
int xform_resources;
int page_resources, page_attributes;
int procset = PROCSET_PDF;
- /* Finish stream of page/form contents */
+ /*tex Finish the stream of page or form contents: */
pdf_goto_pagemode(pdf);
if (pos_stack_used > 0) {
formatted_error("pdf backend","%u unmatched 'save' after %s shipout", (unsigned int) pos_stack_used,
@@ -1856,7 +1778,7 @@ void pdf_end_page(PDF pdf)
run_callback(callback_id, "b->",(global_shipping_mode == SHIPPING_PAGE));
if (global_shipping_mode == SHIPPING_PAGE) {
pdf->last_pages = pdf_do_page_divert(pdf, pdf->last_page, 0);
- /* Write out /Page object */
+ /*tex Write out the |/Page| object. */
pdf_begin_obj(pdf, pdf->last_page, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "Page");
@@ -1869,7 +1791,7 @@ void pdf_end_page(PDF pdf)
pdf_add_bp(pdf, pdf->page_size.h);
pdf_add_bp(pdf, pdf->page_size.v);
pdf_end_array(pdf);
- page_attributes = pdf_page_attr ; /* lookup once */
+ page_attributes = pdf_page_attr ;
if (page_attributes != null)
pdf_print_toks(pdf, page_attributes);
print_pdf_table_string(pdf, "pageattributes");
@@ -1891,7 +1813,7 @@ void pdf_end_page(PDF pdf)
pdf_end_dict(pdf);
pdf_end_obj(pdf);
pdf->img_page_group_val = 0;
- /* Generate array of annotations or beads in page */
+ /*tex Generate an array of annotations or beads in page. */
if (annot_list != NULL || link_list != NULL) {
pdf_begin_obj(pdf, annots, OBJSTM_ALWAYS);
pdf_begin_array(pdf);
@@ -1917,37 +1839,38 @@ void pdf_end_page(PDF pdf)
pdf_end_obj(pdf);
}
}
- /* Write out resource lists and pending raw objects */
+ /*tex Write out the resource lists and pending raw objects. */
ol = get_page_resources_list(pdf, obj_type_obj);
while (ol != NULL) {
if (!is_obj_written(pdf, ol->info))
pdf_write_obj(pdf, ol->info);
ol = ol->link;
}
-
- /*
+ /*tex
When flushing pending forms we need to save and restore resource lists
which are also used by page shipping. Saving and restoring
- |pdf->page_size| is needed for proper writing out pending PDF marks.
+ |pdf->page_size| is needed for proper writing out pending \PDF\ marks.
*/
ol = get_page_resources_list(pdf, obj_type_xform);
while (ol != NULL) {
if (!is_obj_written(pdf, ol->info)) {
+ save_pdf_cur_form = pdf_cur_form;
pdf_cur_form = ol->info;
save_cur_page_size = pdf->page_size;
save_shipping_mode = global_shipping_mode;
pdf->page_resources = &local_page_resources;
local_page_resources.resources_tree = NULL;
ship_out(pdf, obj_xform_box(pdf, pdf_cur_form), SHIPPING_FORM);
- /* Restore page size and page resources */
+ /*tex Restore the page size and page resources. */
pdf->page_size = save_cur_page_size;
global_shipping_mode = save_shipping_mode;
destroy_page_resources_tree(pdf);
pdf->page_resources = res_p;
+ pdf_cur_form = save_pdf_cur_form;
}
ol = ol->link;
}
- /* Write out pending images */
+ /*tex Write out pending images. */
ol = get_page_resources_list(pdf, obj_type_ximage);
while (ol != NULL) {
if (!is_obj_written(pdf, ol->info))
@@ -1955,11 +1878,12 @@ void pdf_end_page(PDF pdf)
ol = ol->link;
}
if (global_shipping_mode == SHIPPING_PAGE) {
- /* Write out pending PDF marks and annotations */
+ /*tex Write out pending \PDF\ marks and annotations. */
ol = get_page_resources_list(pdf, obj_type_annot);
while (ol != NULL) {
if (ol->info > 0 && obj_type(pdf, ol->info) == obj_type_annot) {
- j = obj_annot_ptr(pdf, ol->info); /* |j| points to |pdf_annot_node| */
+ /*tex Here |j| points to |pdf_annot_node|: */
+ j = obj_annot_ptr(pdf, ol->info);
pdf_begin_obj(pdf, ol->info, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "Annot");
@@ -1970,7 +1894,7 @@ void pdf_end_page(PDF pdf)
}
ol = ol->link;
}
- /* Write out PDF link annotations */
+ /*tex Write out PDF link annotations. */
if ((ol = get_page_resources_list(pdf, obj_type_link)) != NULL) {
while (ol != NULL) {
j = obj_annot_ptr(pdf, ol->info);
@@ -1989,49 +1913,52 @@ void pdf_end_page(PDF pdf)
pdf_end_obj(pdf);
ol = ol->link;
}
- /* Flush |pdf_start_link_node|'s created by |append_link| */
+ /*tex Flush |pdf_start_link_node|'s created by |append_link|. */
ol = get_page_resources_list(pdf, obj_type_link);
while (ol != NULL) {
j = obj_annot_ptr(pdf, ol->info);
- /*
- nodes with |subtype = pdf_link_data_node| were created by |append_link| and
- must be flushed here, as they are not linked in any list
+ /*tex
+ Nodes with |subtype = pdf_link_data_node| were created by
+ |append_link| and must be flushed here, as they are not
+ linked in any list.
*/
if (subtype(j) == pdf_link_data_node)
flush_node(j);
ol = ol->link;
}
}
- /* Write out PDF mark destinations */
+ /*tex Write out \PDF\ mark destinations. */
write_out_pdf_mark_destinations(pdf);
- /* Write out PDF bead rectangle specifications */
+ /*tex Write out \PDF\ bead rectangle specifications. */
print_bead_rectangles(pdf);
}
- /* Write out resources dictionary */
+ /*tex Write out resources dictionary. */
pdf_begin_obj(pdf, res_p->last_resources, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
- /* Print additional resources */
+ /*tex Print additional resources. */
if (global_shipping_mode == SHIPPING_PAGE) {
- page_resources = pdf_page_resources; /* lookup once */
- if (page_resources != null)
+ page_resources = pdf_page_resources;
+ if (page_resources != null) {
pdf_print_toks(pdf, page_resources);
+ }
print_pdf_table_string(pdf, "pageresources");
} else {
- xform_resources = pdf_xform_resources; /* lookup once */
- if (xform_resources != null)
+ xform_resources = pdf_xform_resources;
+ if (xform_resources != null) {
pdf_print_toks(pdf, xform_resources);
+ }
if (obj_xform_resources(pdf, pdf_cur_form) != null) {
pdf_print_toks(pdf, obj_xform_resources(pdf, pdf_cur_form));
delete_token_ref(obj_xform_resources(pdf, pdf_cur_form));
set_obj_xform_resources(pdf, pdf_cur_form, null);
}
if (obj_xform_resources_str(pdf, pdf_cur_form) != null) {
- lua_pdf_literal(pdf, obj_xform_resources_str(pdf, pdf_cur_form));
+ lua_pdf_literal(pdf, obj_xform_resources_str(pdf, pdf_cur_form),1);
luaL_unref(Luas, LUA_REGISTRYINDEX, obj_xform_resources_str(pdf, pdf_cur_form));
set_obj_xform_resources_str(pdf, pdf_cur_form, null);
}
}
- /* Generate font resources */
+ /*tex Generate font resources. */
if ((ol = get_page_resources_list(pdf, obj_type_font)) != NULL) {
pdf_add_name(pdf, "Font");
pdf_begin_dict(pdf);
@@ -2046,7 +1973,7 @@ void pdf_end_page(PDF pdf)
pdf_end_dict(pdf);
procset |= PROCSET_TEXT;
}
- /* Generate XObject resources */
+ /*tex Generate |XObject| resources. */
ol = get_page_resources_list(pdf, obj_type_xform);
ol1 = get_page_resources_list(pdf, obj_type_ximage);
if (ol != NULL || ol1 != NULL) {
@@ -2071,7 +1998,7 @@ void pdf_end_page(PDF pdf)
}
pdf_end_dict(pdf);
}
- /* Generate ProcSet */
+ /*tex Generate |ProcSet| in version 1.*/
if (pdf->major_version == 1) {
pdf_add_name(pdf, "ProcSet");
pdf_begin_array(pdf);
@@ -2091,13 +2018,15 @@ void pdf_end_page(PDF pdf)
pdf_end_obj(pdf);
}
-@* Finishing the PDF output file.
+/*tex
-@ Destinations that have been referenced but don't exists have
-|obj_dest_ptr=null|. Leaving them undefined might cause troubles for PDF
-browsers, so we need to fix them; they point to the last page.
+ We're now ready to wrap up the output file. Destinations that have been
+ referenced but don't exists have |obj_dest_ptr=null|. Leaving them undefined
+ might cause troubles for PDF browsers, so we need to fix them; they point to
+ the last page.
+
+*/
-@c
static void check_nonexisting_destinations(PDF pdf)
{
int k;
@@ -2120,25 +2049,27 @@ static void check_nonexisting_destinations(PDF pdf)
}
}
-@ @c
static void check_nonexisting_pages(PDF pdf)
{
struct avl_traverser t;
oentry *p;
struct avl_table *page_tree = pdf->obj_tree[obj_type_page];
avl_t_init(&t, page_tree);
- /* search from the end backward until the last real page is found */
+ /*tex Search from the end backward until the last real page is found. */
for (p = avl_t_last(&t, page_tree); p != NULL && obj_aux(pdf, p->objptr) == 0; p = avl_t_prev(&t)) {
formatted_warning("pdf backend", "page %d has been referenced but does not exist",obj_info(pdf, p->objptr));
}
}
-@ If the same keys in a dictionary are given several times, then it is not
-defined which value is choosen by an application. Therefore the keys |/Producer|
-and |/Creator| are only set if the token list |pdf_info_toks| converted to a
-string does not contain these key strings.
+/*tex
+
+ If the same keys in a dictionary are given several times, then it is not
+ defined which value is choosen by an application. Therefore the keys
+ |/Producer| and |/Creator| are only set if the token list |pdf_info_toks|
+ converted to a string does not contain these key strings.
+
+*/
-@c
static boolean substr_of_str(const char *s, const char *t)
{
if (strstr(t, s) == NULL)
@@ -2146,9 +2077,8 @@ static boolean substr_of_str(const char *s, const char *t)
return true;
}
-static int pdf_print_info(PDF pdf, int luatexversion,
- str_number luatexrevision)
-{ /* print info object */
+static int pdf_print_info(PDF pdf, int luatexversion, str_number luatexrevision)
+{
boolean creator_given = false;
boolean producer_given = false;
boolean creationdate_given = false;
@@ -2158,7 +2088,7 @@ static int pdf_print_info(PDF pdf, int luatexversion,
const char *p = NULL;
int k, len = 0;
k = pdf_create_obj(pdf, obj_type_info, 0);
- pdf_begin_obj(pdf, k, 3); /* keep Info readable unless explicitely forced */
+ pdf_begin_obj(pdf, k, 3);
pdf_begin_dict(pdf);
if (pdf_info_toks != 0) {
s = tokenlist_to_cstring(pdf_info_toks, true, &len);
@@ -2178,18 +2108,18 @@ static int pdf_print_info(PDF pdf, int luatexversion,
}
if (pdf_info_toks != null) {
if (len > 0) {
- pdf_out(pdf, '\n');
+ pdf_check_space(pdf);
pdf_puts(pdf, s);
- pdf_out(pdf, '\n');
+ pdf_set_space(pdf);
xfree(s);
}
delete_token_ref(pdf_info_toks);
pdf_info_toks = null;
}
if (p && strlen(p) > 0) {
- pdf_out(pdf, '\n');
- pdf_puts(pdf, p); /* no free, pointer */
- pdf_out(pdf, '\n');
+ pdf_check_space(pdf);
+ pdf_puts(pdf, p);
+ pdf_set_space(pdf);
}
if ((pdf_suppress_optional_info & 128) == 0 && !producer_given) {
pdf_add_name(pdf, "Producer");
@@ -2223,7 +2153,8 @@ static void build_free_object_list(PDF pdf)
{
int k;
int l = 0;
- set_obj_fresh(pdf, l); /* null object at begin of list of free objects */
+ /*tex A |null| object at the begin of a list of free objects. */
+ set_obj_fresh(pdf, l);
for (k = 1; k <= pdf->obj_ptr; k++) {
if (!is_obj_written(pdf, k)) {
set_obj_link(pdf, l, k);
@@ -2233,272 +2164,297 @@ static void build_free_object_list(PDF pdf)
set_obj_link(pdf, l, 0);
}
-@ Now the finish of PDF output file. At this moment all Page objects
-are already written completely to PDF output file.
+/*tex
-@c
-void finish_pdf_file(PDF pdf, int luatexversion, str_number luatexrevision)
-{
- int i, j, k;
- int root, info, xref_stm = 0, outlines, threads, names_tree;
- size_t xref_offset_width;
- int callback_id = callback_defined(stop_run_callback);
- int callback_id1 = callback_defined(finish_pdffile_callback);
- if (total_pages == 0) {
- if (callback_id == 0) {
- normal_warning("pdf backend","no pages of output.");
- } else if (callback_id > 0) {
- run_callback(callback_id, "->");
- }
- if (pdf->gone > 0)
- normal_error("pdf backend","dangling objects discarded, no output file produced.");
+ Now we can the finish of \PDF\ output file. At this moment all |/Page|
+ objects are already written completely to \PDF\ output file.
+
+*/
+
+void pdf_finish_file(PDF pdf, int fatal_error) {
+ if (fatal_error) {
+ remove_pdffile(static_pdf); /* will become remove_output_file */
+ print_err(" ==> Fatal error occurred, no output PDF file produced!");
} else {
- if (pdf->draftmode == 0) {
- pdf_flush(pdf); /* to make sure that the output file name has been already created */
- flush_jbig2_page0_objects(pdf); /* flush page 0 objects from JBIG2 images, if any */
- if (callback_id1 > 0)
- run_callback(callback_id1, "->");
- check_nonexisting_pages(pdf);
- check_nonexisting_destinations(pdf);
- /* Output fonts definition */
- for (k = 1; k <= max_font_id(); k++) {
- if (font_used(k) && (pdf_font_num(k) < 0)) {
- i = -pdf_font_num(k);
- for (j = font_bc(k); j <= font_ec(k); j++)
- if (quick_char_exists(k, j) && pdf_char_marked(k, j))
- pdf_mark_char(i, j);
- if ((pdf_font_attr(i) == 0) && (pdf_font_attr(k) != 0)) {
- set_pdf_font_attr(i, pdf_font_attr(k));
- } else if ((pdf_font_attr(k) == 0) && (pdf_font_attr(i) != 0)) {
- set_pdf_font_attr(k, pdf_font_attr(i));
- } else if ((pdf_font_attr(i) != 0) && (pdf_font_attr(k) != 0) && (!str_eq_str(pdf_font_attr(i), pdf_font_attr(k)))) {
- formatted_warning("pdf backend","fontattr of font %d and %d are conflicting, %k is used",i,k,i);
- }
- }
+ int i, j, k;
+ int root, info;
+ int xref_stm = 0;
+ int outlines = 0;
+ int threads = 0;
+ int names_tree = 0;
+ size_t xref_offset_width;
+ int luatexversion = luatex_version;
+ str_number luatexrevision = get_luatexrevision();
+ int callback_id = callback_defined(stop_run_callback);
+ int callback_id1 = callback_defined(finish_pdffile_callback);
+ if (total_pages == 0 && !pdf->force_file) {
+ if (callback_id == 0) {
+ normal_warning("pdf backend","no pages of output.");
+ } else if (callback_id > 0) {
+ run_callback(callback_id, "->");
}
- pdf->gen_tounicode = pdf_gen_tounicode;
- pdf->omit_cidset = pdf_omit_cidset;
- k = pdf->head_tab[obj_type_font];
- while (k != 0) {
- int f = obj_info(pdf, k);
- do_pdf_font(pdf, f);
- k = obj_link(pdf, k);
+ if (pdf->gone > 0) {
+ /* number of bytes gone */
+ normal_error("pdf backend","already written content discarded, no output file produced.");
}
- write_fontstuff(pdf);
- pdf->last_pages = output_pages_tree(pdf);
- /* Output outlines */
- outlines = print_outlines(pdf);
- /*
- Output name tree. The name tree is very similiar to Pages tree so
- its construction should be certain from Pages tree construction.
- For intermediate node |obj_info| will be the first name and
- |obj_link| will be the last name in \.{\\Limits} array. Note that
- |pdf_dest_names_ptr| will be less than |obj_ptr|, so we test if
- |k < pdf_dest_names_ptr| then |k| is index of leaf in
- |dest_names|; else |k| will be index in |obj_tab| of some
- intermediate node.
- */
- names_tree = output_name_tree(pdf);
-
- /* Output article threads */
- if (pdf->head_tab[obj_type_thread] != 0) {
- threads = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, threads, OBJSTM_ALWAYS);
- pdf_begin_array(pdf);
- k = pdf->head_tab[obj_type_thread];
- while (k != 0) {
- pdf_add_ref(pdf, k);
- k = obj_link(pdf, k);
+ } else {
+ if (pdf->draftmode == 0) {
+ /*tex We make sure that the output file name has been already created. */
+ pdf_flush(pdf);
+ /*tex Flush page 0 objects from JBIG2 images, if any. */
+ flush_jbig2_page0_objects(pdf);
+ if (callback_id1 > 0) {
+ run_callback(callback_id1, "->");
}
- pdf_end_array(pdf);
- pdf_end_obj(pdf);
- k = pdf->head_tab[obj_type_thread];
+ if (total_pages > 0) {
+ check_nonexisting_pages(pdf);
+ check_nonexisting_destinations(pdf);
+ }
+ /*tex Output fonts definition. */
+ for (k = 1; k <= max_font_id(); k++) {
+ if (font_used(k) && (pdf_font_num(k) < 0)) {
+ i = -pdf_font_num(k);
+ for (j = font_bc(k); j <= font_ec(k); j++)
+ if (quick_char_exists(k, j) && pdf_char_marked(k, j))
+ pdf_mark_char(i, j);
+ if ((pdf_font_attr(i) == 0) && (pdf_font_attr(k) != 0)) {
+ set_pdf_font_attr(i, pdf_font_attr(k));
+ } else if ((pdf_font_attr(k) == 0) && (pdf_font_attr(i) != 0)) {
+ set_pdf_font_attr(k, pdf_font_attr(i));
+ } else if ((pdf_font_attr(i) != 0) && (pdf_font_attr(k) != 0) && (!str_eq_str(pdf_font_attr(i), pdf_font_attr(k)))) {
+ formatted_warning("pdf backend","fontattr of font %d and %d are conflicting, %k is used",i,k,i);
+ }
+ }
+ }
+ pdf->gen_tounicode = pdf_gen_tounicode;
+ pdf->omit_cidset = pdf_omit_cidset;
+ pdf->omit_charset = pdf_omit_charset;
+ k = pdf->head_tab[obj_type_font];
while (k != 0) {
- out_thread(pdf, k);
+ int f = obj_info(pdf, k);
+ do_pdf_font(pdf, f);
k = obj_link(pdf, k);
}
- } else {
- threads = 0;
- }
- /* Output the /Catalog object */
- root = pdf_create_obj(pdf, obj_type_catalog, 0);
- pdf_begin_obj(pdf, root, OBJSTM_ALWAYS);
- pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "Catalog");
- pdf_dict_add_ref(pdf, "Pages", pdf->last_pages);
- if (threads != 0)
- pdf_dict_add_ref(pdf, "Threads", threads);
- if (outlines != 0)
- pdf_dict_add_ref(pdf, "Outlines", outlines);
- if (names_tree != 0)
- pdf_dict_add_ref(pdf, "Names", names_tree);
- if (pdf_catalog_toks != null) {
- pdf_print_toks(pdf, pdf_catalog_toks);
- delete_token_ref(pdf_catalog_toks);
- pdf_catalog_toks = null;
- }
- print_pdf_table_string(pdf, "catalog");
- if (pdf_catalog_openaction != 0)
- pdf_dict_add_ref(pdf, "OpenAction", pdf_catalog_openaction);
- pdf_end_dict(pdf);
- pdf_end_obj(pdf);
- /* last candidate for object stream */
- info = pdf_print_info(pdf, luatexversion, luatexrevision);
- /* final object for pdf->os_enable == false */
- if (pdf->os_enable) {
- pdf_buffer_select(pdf, OBJSTM_BUF);
- pdf_os_write_objstream(pdf);
- pdf_flush(pdf);
- pdf_buffer_select(pdf, PDFOUT_BUF);
- /* Output the cross-reference stream dictionary */
- xref_stm = pdf_create_obj(pdf, obj_type_others, 0);
- pdf_begin_obj(pdf, xref_stm, OBJSTM_NEVER); /* final object for pdf->os_enable == true */
- if ((obj_offset(pdf, pdf->obj_ptr) / 256) > 16777215)
- xref_offset_width = 5;
- else if (obj_offset(pdf, pdf->obj_ptr) > 16777215)
- xref_offset_width = 4;
- else if (obj_offset(pdf, pdf->obj_ptr) > 65535)
- xref_offset_width = 3;
- else
- xref_offset_width = 2;
- /* Build a linked list of free objects */
- build_free_object_list(pdf);
+ write_fontstuff(pdf);
+ if (total_pages > 0) {
+ pdf->last_pages = output_pages_tree(pdf);
+ /*tex Output outlines. */
+ outlines = print_outlines(pdf);
+ /*tex
+ The name tree is very similiar to Pages tree so its construction
+ should be certain from Pages tree construction. For intermediate
+ node |obj_info| will be the first name and |obj_link| will be the
+ last name in \.{\\Limits} array. Note that |pdf_dest_names_ptr|
+ will be less than |obj_ptr|, so we test if |k <
+ pdf_dest_names_ptr| then |k| is index of leaf in |dest_names|;
+ else |k| will be index in |obj_tab| of some intermediate node.
+ */
+ names_tree = output_name_tree(pdf);
+ /*tex Output article threads. */
+ if (pdf->head_tab[obj_type_thread] != 0) {
+ threads = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, threads, OBJSTM_ALWAYS);
+ pdf_begin_array(pdf);
+ k = pdf->head_tab[obj_type_thread];
+ while (k != 0) {
+ pdf_add_ref(pdf, k);
+ k = obj_link(pdf, k);
+ }
+ pdf_end_array(pdf);
+ pdf_end_obj(pdf);
+ k = pdf->head_tab[obj_type_thread];
+ while (k != 0) {
+ out_thread(pdf, k);
+ k = obj_link(pdf, k);
+ }
+ } else {
+ threads = 0;
+ }
+ }
+ /*tex Output the |/Catalog| object. */
+ root = pdf_create_obj(pdf, obj_type_catalog, 0);
+ pdf_begin_obj(pdf, root, OBJSTM_ALWAYS);
pdf_begin_dict(pdf);
- pdf_dict_add_name(pdf, "Type", "XRef");
- pdf_add_name(pdf, "Index");
- pdf_begin_array(pdf);
- pdf_add_int(pdf, 0);
- pdf_add_int(pdf, pdf->obj_ptr + 1);
- pdf_end_array(pdf);
- pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
- pdf_add_name(pdf, "W");
- pdf_begin_array(pdf);
- pdf_add_int(pdf, 1);
- pdf_add_int(pdf, (int) xref_offset_width);
- pdf_add_int(pdf, 1);
- pdf_end_array(pdf);
- pdf_dict_add_ref(pdf, "Root", root);
- pdf_dict_add_ref(pdf, "Info", info);
- if (pdf_trailer_toks != null) {
- pdf_print_toks(pdf, pdf_trailer_toks);
- delete_token_ref(pdf_trailer_toks);
- pdf_trailer_toks = null;
+ pdf_dict_add_name(pdf, "Type", "Catalog");
+ if (total_pages > 0) {
+ pdf_dict_add_ref(pdf, "Pages", pdf->last_pages);
+ if (threads != 0) {
+ pdf_dict_add_ref(pdf, "Threads", threads);
+ }
+ if (outlines != 0) {
+ pdf_dict_add_ref(pdf, "Outlines", outlines);
+ }
+ if (names_tree != 0) {
+ pdf_dict_add_ref(pdf, "Names", names_tree);
+ }
+ if (pdf_catalog_toks != null) {
+ pdf_print_toks(pdf, pdf_catalog_toks);
+ delete_token_ref(pdf_catalog_toks);
+ pdf_catalog_toks = null;
+ }
}
- print_pdf_table_string(pdf, "trailer");
- print_ID(pdf);
- pdf_dict_add_streaminfo(pdf);
+ if (pdf_catalog_openaction != 0) {
+ pdf_dict_add_ref(pdf, "OpenAction", pdf_catalog_openaction);
+ }
+ print_pdf_table_string(pdf, "catalog");
pdf_end_dict(pdf);
- pdf_begin_stream(pdf);
- for (k = 0; k <= pdf->obj_ptr; k++) {
- if (!is_obj_written(pdf, k)) { /* a free object */
- pdf_out(pdf, 0);
- pdf_out_bytes(pdf, obj_link(pdf, k), xref_offset_width);
- pdf_out(pdf, 255);
- } else if (obj_os_idx(pdf, k) == PDF_OS_MAX_OBJS) { /* object not in object stream */
- pdf_out(pdf, 1);
- pdf_out_bytes(pdf, obj_offset(pdf, k),
- xref_offset_width);
- pdf_out(pdf, 0);
- } else { /* object in object stream */
- pdf_out(pdf, 2);
- pdf_out_bytes(pdf, obj_offset(pdf, k),
- xref_offset_width);
- pdf_out(pdf, obj_os_idx(pdf, k));
+ pdf_end_obj(pdf);
+ info = pdf_print_info(pdf, luatexversion, luatexrevision);
+ if (pdf->os_enable) {
+ pdf_buffer_select(pdf, OBJSTM_BUF);
+ pdf_os_write_objstream(pdf);
+ pdf_flush(pdf);
+ pdf_buffer_select(pdf, PDFOUT_BUF);
+ /*tex Output the cross-reference stream dictionary. */
+ xref_stm = pdf_create_obj(pdf, obj_type_others, 0);
+ pdf_begin_obj(pdf, xref_stm, OBJSTM_NEVER);
+ if ((obj_offset(pdf, pdf->obj_ptr) / 256) > 16777215)
+ xref_offset_width = 5;
+ else if (obj_offset(pdf, pdf->obj_ptr) > 16777215)
+ xref_offset_width = 4;
+ else if (obj_offset(pdf, pdf->obj_ptr) > 65535)
+ xref_offset_width = 3;
+ else
+ xref_offset_width = 2;
+ /*tex Build a linked list of free objects. */
+ build_free_object_list(pdf);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_name(pdf, "Type", "XRef");
+ pdf_add_name(pdf, "Index");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 0);
+ pdf_add_int(pdf, pdf->obj_ptr + 1);
+ pdf_end_array(pdf);
+ pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
+ pdf_add_name(pdf, "W");
+ pdf_begin_array(pdf);
+ pdf_add_int(pdf, 1);
+ pdf_add_int(pdf, (int) xref_offset_width);
+ pdf_add_int(pdf, 1);
+ pdf_end_array(pdf);
+ pdf_dict_add_ref(pdf, "Root", root);
+ pdf_dict_add_ref(pdf, "Info", info);
+ if (pdf_trailer_toks != null) {
+ pdf_print_toks(pdf, pdf_trailer_toks);
+ delete_token_ref(pdf_trailer_toks);
+ pdf_trailer_toks = null;
+ }
+ print_pdf_table_string(pdf, "trailer");
+ print_ID(pdf);
+ pdf_dict_add_streaminfo(pdf);
+ pdf_end_dict(pdf);
+ pdf_begin_stream(pdf);
+ for (k = 0; k <= pdf->obj_ptr; k++) {
+ if (!is_obj_written(pdf, k)) {
+ /*tex A free object: */
+ pdf_out(pdf, 0);
+ pdf_out_bytes(pdf, obj_link(pdf, k), xref_offset_width);
+ pdf_out(pdf, 255);
+ } else if (obj_os_idx(pdf, k) == PDF_OS_MAX_OBJS) {
+ /*tex An object not in object stream: */
+ pdf_out(pdf, 1);
+ pdf_out_bytes(pdf, obj_offset(pdf, k), xref_offset_width);
+ pdf_out(pdf, 0);
+ } else {
+ /*tex An object in object stream: */
+ pdf_out(pdf, 2);
+ pdf_out_bytes(pdf, obj_offset(pdf, k), xref_offset_width);
+ pdf_out(pdf, obj_os_idx(pdf, k));
+ }
+ }
+ pdf_end_stream(pdf);
+ pdf_end_obj(pdf);
+ pdf_flush(pdf);
+ } else {
+ /*tex Output the |obj_tab| and build a linked list of free objects. */
+ build_free_object_list(pdf);
+ pdf_save_offset(pdf);
+ pdf_puts(pdf, "xref\n");
+ pdf_puts(pdf, "0 ");
+ pdf_print_int_ln(pdf, pdf->obj_ptr + 1);
+ pdf_print_fw_int(pdf, obj_link(pdf, 0));
+ pdf_puts(pdf, " 65535 f \n");
+ for (k = 1; k <= pdf->obj_ptr; k++) {
+ if (!is_obj_written(pdf, k)) {
+ pdf_print_fw_int(pdf, obj_link(pdf, k));
+ pdf_puts(pdf, " 00000 f \n");
+ } else {
+ pdf_print_fw_int(pdf, obj_offset(pdf, k));
+ pdf_puts(pdf, " 00000 n \n");
+ }
}
}
- pdf_end_stream(pdf);
- pdf_end_obj(pdf);
- pdf_flush(pdf);
- } else {
- /* Output the |obj_tab| and build a linked list of free objects */
- build_free_object_list(pdf);
- pdf_save_offset(pdf);
- pdf_puts(pdf, "xref\n");
- pdf_puts(pdf, "0 ");
- pdf_print_int_ln(pdf, pdf->obj_ptr + 1);
- pdf_print_fw_int(pdf, obj_link(pdf, 0));
- pdf_puts(pdf, " 65535 f \n");
- for (k = 1; k <= pdf->obj_ptr; k++) {
- if (!is_obj_written(pdf, k)) {
- pdf_print_fw_int(pdf, obj_link(pdf, k));
- pdf_puts(pdf, " 00000 f \n");
- } else {
- pdf_print_fw_int(pdf, obj_offset(pdf, k));
- pdf_puts(pdf, " 00000 n \n");
+ /*tex Output the trailer. */
+ if (!pdf->os_enable) {
+ pdf_puts(pdf, "trailer\n");
+ pdf_reset_space(pdf);
+ pdf_begin_dict(pdf);
+ pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
+ pdf_dict_add_ref(pdf, "Root", root);
+ pdf_dict_add_ref(pdf, "Info", info);
+ if (pdf_trailer_toks != null) {
+ pdf_print_toks(pdf, pdf_trailer_toks);
+ delete_token_ref(pdf_trailer_toks);
+ pdf_trailer_toks = null;
}
+ print_ID(pdf);
+ pdf_end_dict(pdf);
+ pdf_out(pdf, '\n');
}
- }
- /* Output the trailer */
- if (!pdf->os_enable) {
- pdf_puts(pdf, "trailer\n");
- pdf_begin_dict(pdf);
- pdf_dict_add_int(pdf, "Size", pdf->obj_ptr + 1);
- pdf_dict_add_ref(pdf, "Root", root);
- pdf_dict_add_ref(pdf, "Info", info);
- if (pdf_trailer_toks != null) {
- pdf_print_toks(pdf, pdf_trailer_toks);
- delete_token_ref(pdf_trailer_toks);
- pdf_trailer_toks = null;
+ pdf_puts(pdf, "startxref\n");
+ pdf_reset_space(pdf);
+ if (pdf->os_enable)
+ pdf_add_longint(pdf, (longinteger) obj_offset(pdf, xref_stm));
+ else
+ pdf_add_longint(pdf, (longinteger) pdf->save_offset);
+ pdf_puts(pdf, "\n%%EOF\n");
+ pdf_flush(pdf);
+ 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(pdf_offset(pdf));
+ tprint(" bytes).");
+ print_ln();
+ } else if (callback_id > 0) {
+ run_callback(callback_id, "->");
}
- print_ID(pdf);
- pdf_end_dict(pdf);
- pdf_out(pdf, '\n');
- }
- pdf_puts(pdf, "startxref\n");
- pdf->cave = 0;
- if (pdf->os_enable)
- pdf_add_longint(pdf, (longinteger) obj_offset(pdf, xref_stm));
- else
- pdf_add_longint(pdf, (longinteger) pdf->save_offset);
- pdf_puts(pdf, "\n%%EOF\n");
- pdf_flush(pdf);
- 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(pdf_offset(pdf));
- tprint(" bytes).");
- print_ln();
- } else if (callback_id > 0) {
- run_callback(callback_id, "->");
- }
- } else {
- if (callback_id > 0) {
- run_callback(callback_id, "->");
+ libpdffinish(pdf);
+ close_file(pdf->file);
+ } else {
+ if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ }
+ libpdffinish(pdf);
+ normal_warning("pdf backend","draftmode enabled, not changing output pdf");
}
}
- libpdffinish(pdf);
- if (pdf->draftmode == 0)
- close_file(pdf->file);
- else
- normal_warning("pdf backend","draftmode enabled, not changing output pdf");
- }
- if (callback_id == 0) {
- if (log_opened_global) {
- fprintf(log_file, "\nPDF statistics: %d PDF objects out of %d (max. %d)\n",
- (int) pdf->obj_ptr, (int) pdf->obj_tab_size,
- (int) sup_obj_tab_size);
- if (pdf->os->ostm_ctr > 0) {
- fprintf(log_file, " %d compressed objects within %d object stream%s\n",
- (int) pdf->os->o_ctr, (int) pdf->os->ostm_ctr,
- (pdf->os->ostm_ctr > 1 ? "s" : ""));
+ if (callback_id == 0) {
+ if (log_opened_global) {
+ fprintf(log_file, "\nPDF statistics: %d PDF objects out of %d (max. %d)\n",
+ (int) pdf->obj_ptr, (int) pdf->obj_tab_size,
+ (int) sup_obj_tab_size);
+ if (pdf->os->ostm_ctr > 0) {
+ fprintf(log_file, " %d compressed objects within %d object stream%s\n",
+ (int) pdf->os->o_ctr, (int) pdf->os->ostm_ctr,
+ (pdf->os->ostm_ctr > 1 ? "s" : ""));
+ }
+ fprintf(log_file, " %d named destinations out of %d (max. %d)\n",
+ (int) pdf->dest_names_ptr, (int) pdf->dest_names_size,
+ (int) sup_dest_names_size);
+ fprintf(log_file, " %d words of extra memory for PDF output out of %d (max. %d)\n",
+ (int) pdf->mem_ptr, (int) pdf->mem_size,
+ (int) sup_pdf_mem_size);
}
- fprintf(log_file, " %d named destinations out of %d (max. %d)\n",
- (int) pdf->dest_names_ptr, (int) pdf->dest_names_size,
- (int) sup_dest_names_size);
- fprintf(log_file, " %d words of extra memory for PDF output out of %d (max. %d)\n",
- (int) pdf->mem_ptr, (int) pdf->mem_size,
- (int) sup_pdf_mem_size);
}
}
}
-@ @c
void scan_pdfcatalog(PDF pdf)
{
halfword p;
@@ -2518,3 +2474,43 @@ void scan_pdfcatalog(PDF pdf)
}
}
}
+
+/*tex
+
+ This function converts double to pdffloat; very small and very large numbers
+ are {\em not} converted to scientific notation. Here n must be a number or
+ real conforming to the implementation limits of \PDF\ as specified in
+ appendix C.1 of the \PDF\ standard. The maximum value of ints is |+2^32|, the
+ maximum value of reals is |+2^15| and the smallest values of reals is
+ |1/(2^16)|.
+
+*/
+
+static pdffloat conv_double_to_pdffloat(double n)
+{
+ pdffloat a;
+ a.e = 6;
+ a.m = i64round(n * ten_pow[a.e]);
+ return a;
+}
+
+void pdf_add_real(PDF pdf, double d)
+{
+ pdf_check_space(pdf);
+ print_pdffloat(pdf, conv_double_to_pdffloat(d));
+ pdf_set_space(pdf);
+}
+
+void pdf_push_list(PDF pdf, scaledpos *saved_pos, int *saved_loc) {
+ /* nothing */
+}
+
+void pdf_pop_list(PDF pdf, scaledpos *saved_pos, int *saved_loc) {
+ /* nothing */
+}
+
+extern void pdf_set_reference_point(PDF pdf, posstructure *refpoint)
+{
+ refpoint->pos.h = pdf_h_origin;
+ refpoint->pos.v = pdf->page_size.v - pdf_v_origin;
+}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.c
index 0703beed22c..c7cf0439212 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.c
@@ -1,40 +1,47 @@
-% pdfglyph.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
#include "pdf/pdfpage.h"
-@ eternal constants
+/*tex
-@c
-#define e_tj 3 /* must be 3; movements in []TJ are in fontsize/$10^3$ units */
+ The |e_tj| step must be 3 because movements in |[]TJ| are in fontsize/$10^3$
+ units.
+
+*/
+
+#define e_tj 3
+
+/*tex
+
+ Use exactly this formula also for calculating the |/Width| array values.
+
+*/
-@ @c
static int64_t pdf_char_width(pdfstructure * p, internal_font_number f, int i)
{
- /* use exactly this formula also for calculating the /Width array values */
return i64round((double) char_width(f, i) / font_size(f) * ten_pow[e_tj + p->cw.e]);
}
-@ @c
void pdf_print_charwidth(PDF pdf, internal_font_number f, int i)
{
pdffloat cw;
@@ -44,13 +51,11 @@ void pdf_print_charwidth(PDF pdf, internal_font_number f, int i)
print_pdffloat(pdf, cw);
}
-@ @c
static void setup_fontparameters(PDF pdf, internal_font_number f, int ex_glyph)
{
- float slant, extend, expand, scale = 1.0;
+ float slant, extend, squeeze, expand, scale = 1.0;
float u = 1.0;
pdfstructure *p = pdf->pstruct;
- /* fix mantis bug \# 0000200 (acroread "feature") */
if ((font_format(f) == opentype_format || (font_format(f) == type1_format && font_encodingbytes(f) == 2)) && font_units_per_em(f) > 0)
u = font_units_per_em(f) / 1000.0;
pdf->f_cur = f;
@@ -58,35 +63,55 @@ static void setup_fontparameters(PDF pdf, internal_font_number f, int ex_glyph)
p->fs.m = i64round(font_size(f) / u / by_one_bp * ten_pow[p->fs.e]);
slant = font_slant(f) / 1000.0;
extend = font_extend(f) / 1000.0;
+ squeeze = font_squeeze(f) / 1000.0;
expand = 1.0 + (ex_glyph/1) / 1000.0;
- p->tj_delta.e = p->cw.e - 1; /* "- 1" makes less corrections inside []TJ */
- /* no need to be more precise than TeX (1sp) */
- while (p->tj_delta.e > 0 && (double) font_size(f) / ten_pow[p->tj_delta.e + e_tj] < 0.5)
- p->tj_delta.e--; /* happens for very tiny fonts */
+ /*tex The |-1| makes less corrections inside |[]TJ|: */
+ p->tj_delta.e = p->cw.e - 1;
+ /*tex There is no need to be more precise than \TEX\ (1sp). */
+ while (p->tj_delta.e > 0 && (double) font_size(f) / ten_pow[p->tj_delta.e + e_tj] < 0.5) {
+ /*tex This happens for very tiny fonts. */
+ p->tj_delta.e--;
+ }
p->tm[0].m = i64round(scale * expand * extend * ten_pow[p->tm[0].e]);
p->tm[2].m = i64round(slant * ten_pow[p->tm[2].e]);
- p->tm[3].m = i64round(scale * ten_pow[p->tm[3].e]);
+ p->tm[3].m = i64round(scale * squeeze * ten_pow[p->tm[3].e]);
p->k2 = ten_pow[e_tj + p->cw.e] * scale / (ten_pow[p->pdf.h.e] * pdf2double(p->fs) * pdf2double(p->tm[0]));
- p->cur_ex = ex_glyph ; /* we keep track of the state of ex */
+ /*tex We keep track of the state of ex. */
+ p->cur_ex = ex_glyph ;
+ p->need_width = font_width(f);
+ p->need_mode = font_mode(f);
}
-
-@ @c
static void set_font(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
+
+ if (p->need_width != 0) {
+ pdf_printf(pdf, "%0.3f w\n",((7227.0/7200.0)/1000.0) * p->need_width );
+ p->done_width = 1;
+ } else if (p->done_width) {
+ pdf_puts(pdf, "0 w\n");
+ p->done_width = 0;
+ }
+ if (p->need_mode != 0) {
+ pdf_printf(pdf, "%d Tr\n", (int) p->need_mode);
+ p->done_mode = 1;
+ } else if (p->done_mode) {
+ pdf_puts(pdf, "0 Tr\n");
+ p->done_mode = 0;
+ }
pdf_printf(pdf, "/F%d", (int) p->f_pdf);
pdf_print_resname_prefix(pdf);
pdf_out(pdf, ' ');
print_pdffloat(pdf, p->fs);
- pdf_puts(pdf, " Tf ");
+ pdf_puts(pdf, " Tf\n");
p->f_pdf_cur = p->f_pdf;
p->fs_cur.m = p->fs.m;
p->need_tf = false;
- p->need_tm = true; /* always follow Tf by Tm */
+ /*tex Always follow |Tf| by |Tm|: */
+ p->need_tm = true;
}
-@ @c
static void set_textmatrix(PDF pdf, scaledpos pos)
{
boolean move;
@@ -97,24 +122,27 @@ static void set_textmatrix(PDF pdf, scaledpos pos)
if (p->need_tm || move) {
print_pdf_matrix(pdf, p->tm);
pdf_puts(pdf, " Tm ");
- p->pdf.h.m = p->pdf_bt_pos.h.m + p->tm[4].m; /* Tm replaces */
+ /*tex |Tm| replaces */
+ p->pdf.h.m = p->pdf_bt_pos.h.m + p->tm[4].m;
p->pdf.v.m = p->pdf_bt_pos.v.m + p->tm[5].m;
p->need_tm = false;
}
p->tm0_cur.m = p->tm[0].m;
}
-@ Print out a character to PDF buffer; the character will be printed in octal
-form in the following cases: chars <= 32, backslash (92), left parenthesis
-(40), and right parenthesis (41).
+/*tex
+
+ Print out a character to PDF buffer; the character will be printed in octal
+ form in the following cases: chars <= 32, backslash (92), left parenthesis
+ (40), and right parenthesis (41).
+
+*/
-@c
static void pdf_print_char(PDF pdf, int c)
{
- if (c > 255)
+ if (c > 255) {
return;
- /* pdf_print_escaped(c) */
- if (c <= 32 || c == '\\' || c == '(' || c == ')' || c > 127) {
+ } else if (c <= 32 || c == '\\' || c == '(' || c == ')' || c > 127) {
pdf_room(pdf, 4);
pdf_quick_out(pdf, '\\');
pdf_quick_out(pdf, (unsigned char) ('0' + ((c >> 6) & 0x3)));
@@ -131,7 +159,6 @@ static void pdf_print_wide_char(PDF pdf, int c)
pdf_out_block(pdf, (const char *) hex, 4);
}
-@ @c
static void begin_charmode(PDF pdf, internal_font_number f, pdfstructure * p)
{
if (!is_chararraymode(p))
@@ -146,7 +173,6 @@ static void begin_charmode(PDF pdf, internal_font_number f, pdfstructure * p)
p->mode = PMODE_CHAR;
}
-@ @c
void end_charmode(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
@@ -161,7 +187,6 @@ void end_charmode(PDF pdf)
p->mode = PMODE_CHARARRAY;
}
-@ @c
static void begin_chararray(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
@@ -173,7 +198,6 @@ static void begin_chararray(PDF pdf)
p->mode = PMODE_CHARARRAY;
}
-@ @c
void end_chararray(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
@@ -184,23 +208,32 @@ void end_chararray(PDF pdf)
p->mode = PMODE_TEXT;
}
-@ We need to adapt the tm when a font changes. A change can be a change in id
-(frontend) or pdf reference (backend, as we share font resources). At such a
-change we also need to adapt to the slant and extend. Initially we also need to
-take the exfactor of a glyph into account. When the font is unchanged, we still
-need to check each glyph for a change in exfactor. We store the current one on
-the state record so that we can minimize testing.
+/*tex
+
+ We need to adapt the tm when a font changes. A change can be a change in id
+ (frontend) or pdf reference (backend, as we share font resources). At such a
+ change we also need to adapt to the slant and extend. Initially we also need
+ to take the exfactor of a glyph into account. When the font is unchanged, we
+ still need to check each glyph for a change in exfactor. We store the current
+ one on the state record so that we can minimize testing.
+
+*/
-@c
void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
{
boolean move;
pdfstructure *p = pdf->pstruct;
scaledpos pos = pdf->posstruct->pos;
- /* already done:
+ /*tex
+
+ This is already done:
+
+ \startyping
if (!char_exists(f, c)) {
return;
}
+ \stoptyping
+
*/
if (font_writingmode(f) == vertical_writingmode) {
if (p->wmode != WMODE_V) {
@@ -221,8 +254,8 @@ void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
setup_fontparameters(pdf, f, ex);
p->need_tm = true;
}
- /* all movements */
- move = calc_pdfpos(p, pos); /* within text or chararray or char mode */
+ /*tex All movements within text or chararray or char mode: */
+ move = calc_pdfpos(p, pos);
if (move || p->need_tm) {
if (p->need_tm
|| (p->wmode == WMODE_H && (p->pdf_bt_pos.v.m + p->tm[5].m) != p->pdf.v.m)
@@ -231,7 +264,8 @@ void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
pdf_goto_textmode(pdf);
set_textmatrix(pdf, pos);
begin_chararray(pdf);
- move = calc_pdfpos(p, pos); /* for fine adjustment */
+ /*tex For fine adjustment: */
+ move = calc_pdfpos(p, pos);
}
if (move) {
if (is_charmode(p))
@@ -240,7 +274,7 @@ void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
p->cw.m -= p->tj_delta.m * ten_pow[p->cw.e - p->tj_delta.e];
}
}
- /* glyph output */
+ /*tex Glyph output: */
if (is_chararraymode(p))
begin_charmode(pdf, f, p);
else if (!is_charmode(p))
@@ -250,5 +284,6 @@ void pdf_place_glyph(PDF pdf, internal_font_number f, int c, int ex)
pdf_print_wide_char(pdf, char_index(f, c));
else
pdf_print_char(pdf, c);
- p->cw.m += pdf_char_width(p, p->f_pdf, c); /* aka |adv_char_width()| */
+ /*tex Also known as |adv_char_width()|: */
+ p->cw.m += pdf_char_width(p, p->f_pdf, c);
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.c
index fd364243804..a8cffb0c871 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.c
@@ -1,38 +1,39 @@
-% pdfimage.w
-%
-% Copyright 2009-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
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ @c
void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform)
{
- float a[6]; /* transformation matrix */
+ /*tex A transformation matrix: */
+ float a[6];
float xoff, yoff, tmp;
pdfstructure *p = pdf->pstruct;
scaledpos pos = pdf->posstruct->pos;
- int r; /* number of digits after the decimal point */
+ /*tex The number of digits after the decimal point: */
+ int r;
int k;
scaledpos tmppos;
pdffloat cm[6];
- int groupref; /* added from web for 1.40.8 */
+ int groupref;
a[0] = a[3] = 1.0e6;
a[1] = a[2] = 0;
if (img_type(idict) == IMG_TYPE_PDF || img_type(idict) == IMG_TYPE_PDFMEMSTREAM
@@ -43,48 +44,51 @@ void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform)
yoff = (float) img_yorig(idict) / (float) img_ysize(idict);
r = 6;
} else {
- /* added from web for 1.40.8 */
if (img_type(idict) == IMG_TYPE_PNG) {
groupref = img_group_ref(idict);
if ((groupref > 0) && (pdf->img_page_group_val == 0))
pdf->img_page_group_val = groupref;
}
- /* /added from web */
a[0] /= (float) one_hundred_bp;
a[3] = a[0];
xoff = yoff = 0;
r = 4;
}
- if ((transform & 7) > 3) { /* mirror cases */
+ if ((transform & 7) > 3) {
+ /*tex Mirror cases: */
a[0] *= -1;
xoff *= -1;
}
switch ((transform + img_rotation(idict)) & 3) {
- case 0: /* no transform */
- break;
- case 1: /* rot. 90 deg. (counterclockwise) */
- a[1] = a[0];
- a[2] = -a[3];
- a[3] = a[0] = 0;
- tmp = yoff;
- yoff = xoff;
- xoff = -tmp;
- break;
- case 2: /* rot. 180 deg. (counterclockwise) */
- a[0] *= -1;
- a[3] *= -1;
- xoff *= -1;
- yoff *= -1;
- break;
- case 3: /* rot. 270 deg. (counterclockwise) */
- a[1] = -a[0];
- a[2] = a[3];
- a[3] = a[0] = 0;
- tmp = yoff;
- yoff = -xoff;
- xoff = tmp;
- break;
- default:;
+ case 0:
+ /*tex No transform. */
+ break;
+ case 1:
+ /*tex rotation over 90 degrees (counterclockwise) */
+ a[1] = a[0];
+ a[2] = -a[3];
+ a[3] = a[0] = 0;
+ tmp = yoff;
+ yoff = xoff;
+ xoff = -tmp;
+ break;
+ case 2:
+ /*tex rotation over 180 degrees (counterclockwise) */
+ a[0] *= -1;
+ a[3] *= -1;
+ xoff *= -1;
+ yoff *= -1;
+ break;
+ case 3:
+ /*tex rotation over 270 degrees (counterclockwise) */
+ a[1] = -a[0];
+ a[2] = a[3];
+ a[3] = a[0] = 0;
+ tmp = yoff;
+ yoff = -xoff;
+ xoff = tmp;
+ break;
+ default:;
}
xoff *= (float) dim.wd;
yoff *= (float) (dim.ht + dim.dp);
@@ -98,21 +102,24 @@ void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform)
if ((transform & 7) > 3)
k++;
switch (k & 3) {
- case 0: /* no transform */
- break;
- case 1: /* rot. 90 deg. (counterclockwise) */
- a[4] += (float) dim.wd;
- break;
- case 2: /* rot. 180 deg. */
- a[4] += (float) dim.wd;
- a[5] += (float) (dim.ht + dim.dp);
- break;
- case 3: /* rot. 270 deg. */
- a[5] += (float) (dim.ht + dim.dp);
- break;
- default:;
+ case 0:
+ /*tex No transform */
+ break;
+ case 1:
+ /*tex rotation over 90 degrees (counterclockwise) */
+ a[4] += (float) dim.wd;
+ break;
+ case 2:
+ /*tex rotation over 180 degrees (counterclockwise) */
+ a[4] += (float) dim.wd;
+ a[5] += (float) (dim.ht + dim.dp);
+ break;
+ case 3:
+ /*tex rotation over 270 degrees (counterclockwise) */
+ a[5] += (float) (dim.ht + dim.dp);
+ break;
+ default:;
}
- /* the following is a kludge, TODO: use pdfpage.c functions */
setpdffloat(cm[0], i64round(a[0]), r);
setpdffloat(cm[1], i64round(a[1]), r);
setpdffloat(cm[2], i64round(a[2]), r);
@@ -124,7 +131,7 @@ void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform)
cm[4] = p->cm[4];
cm[5] = p->cm[5];
if (pdf->img_page_group_val == 0)
- pdf->img_page_group_val = img_group_ref(idict); /* added from web for 1.40.8 */
+ pdf->img_page_group_val = img_group_ref(idict);
pdf_puts(pdf, "q\n");
pdf_print_cm(pdf, cm);
pdf_puts(pdf, "/Im");
@@ -136,9 +143,8 @@ void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform)
img_state(idict) = DICT_OUTIMG;
}
-@ for normal output, see \.{pdflistout.w}
+/*tex For normal output see |pdflistout.c|: */
-@c
void pdf_place_image(PDF pdf, halfword p)
{
scaled_whd dim;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflink.w b/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
index b21d0774ecd..55521b17692 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdflink.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdflink.c
@@ -1,31 +1,34 @@
-% pdflink.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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"
-@ To implement nested link annotations, we need a stack to hold copy of
-|pdf_start_link_node|'s that are being written out, together with their box
-nesting level.
+/*tex
+
+ To implement nested link annotations, we need a stack to hold copy of
+ |pdf_start_link_node|'s that are being written out, together with their box
+ nesting level.
+
+*/
-@c
void push_link_level(PDF pdf, halfword p)
{
if (pdf->link_stack_ptr >= pdf_max_link_level)
@@ -36,14 +39,12 @@ void push_link_level(PDF pdf, halfword p)
pdf->link_stack[pdf->link_stack_ptr].ref_link_node = p;
}
-@ @c
void pop_link_level(PDF pdf)
{
flush_node_list(pdf->link_stack[pdf->link_stack_ptr].link_node);
pdf->link_stack_ptr--;
}
-@ @c
void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
{
scaled_whd alt_rule;
@@ -59,13 +60,13 @@ void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
alt_rule.ht = height(p);
alt_rule.dp = depth(p);
set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin);
- obj_annot_ptr(pdf, pdf_link_objnum(p)) = p; /* the reference for the pdf annot object must be set here */
+ /*tex The reference for the annot object must be set here. */
+ obj_annot_ptr(pdf, pdf_link_objnum(p)) = p;
k = pdf_link_objnum(p);
set_obj_scheduled(pdf, pdf_link_objnum(p));
addto_page_resources(pdf, obj_type_link, k);
}
-@ @c
void end_link(PDF pdf, halfword p)
{
halfword q;
@@ -76,10 +77,10 @@ void end_link(PDF pdf, halfword p)
normal_error("pdf backend","pdf link_stack empty, 'endlink' used without 'startlink'");
if (pdf->link_stack[pdf->link_stack_ptr].nesting_level != cur_s)
normal_error("pdf backend","'endlink' ended up in different nesting level than 'startlink'");
- /*
- NOTA BENE: test for running link must be done on |link_node| and not
+ /*tex
+ The test for running link must be done on |link_node| and not
|ref_link_node|, as |ref_link_node| can be set by |do_link| or
- |append_link| already
+ |append_link| already.
*/
if (is_running(width(pdf->link_stack[pdf->link_stack_ptr].link_node))) {
q = pdf->link_stack[pdf->link_stack_ptr].ref_link_node;
@@ -110,15 +111,16 @@ void end_link(PDF pdf, halfword p)
pop_link_level(pdf);
}
-@ For ``running'' annotations we must append a new node when the end of
-annotation is in other box than its start. The new created node is identical to
-corresponding whatsit node representing the start of annotation, but its |info|
-field is |max_halfword|. We set |info| field just before destroying the node, in
-order to use |flush_node_list| to do the job.
+/*tex
+
+ For ``running'' annotations we must append a new node when the end of
+ annotation is in other box than its start. The new created node is identical
+ to corresponding whatsit node representing the start of annotation, but its
+ |info| field is |max_halfword|. We set |info| field just before destroying
+ the node, in order to use |flush_node_list| to do the job.
-@ Append a new pdf annot to |pdf_link_list|.
+*/
-@c
void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i)
{
halfword p;
@@ -126,7 +128,8 @@ void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i)
scaled_whd alt_rule;
p = copy_node(pdf->link_stack[(int) i].link_node);
pdf->link_stack[(int) i].ref_link_node = p;
- subtype(p) = pdf_link_data_node; /* this node is not a normal link node */
+ /*tex This node is not a normal link node. */
+ subtype(p) = pdf_link_data_node;
alt_rule.wd = width(p);
alt_rule.ht = height(p);
alt_rule.dp = depth(p);
@@ -137,7 +140,6 @@ void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i)
addto_page_resources(pdf, obj_type_link, k);
}
-@ @c
void scan_startlink(PDF pdf)
{
int k;
@@ -155,10 +157,9 @@ void scan_startlink(PDF pdf)
set_pdf_link_action(cur_list.tail_field, r);
set_pdf_link_objnum(cur_list.tail_field, k);
pdf_last_link = k;
- /*
- NOTA BENE: although it is possible to set |obj_annot_ptr(k) := tail|
- here, it is not safe if nodes are later copied/destroyed/moved; a better
- place to do this is inside |do_link|, when the whatsit node is written
- out
+ /*tex
+ Although it is possible to set |obj_annot_ptr(k) := tail| here, it is not
+ safe if nodes are later copied/destroyed/moved; a better place to do this
+ is inside |do_link|, when the whatsit node is written out.
*/
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
index 53ed24af64a..9dbdaeefa28 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.c
@@ -1,120 +1,48 @@
-% pdflistout.w
-%
-% Copyright 2009-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/>.
+/*
-\def\pdfTeX{pdf\TeX}
+Copyright 2009-2010 Taco Hoekwater <taco@luatex.org>
-@ @c
-#include "ptexlib.h"
+This file is part of LuaTeX.
-@ @c
-#define kern_width(q) width(q) + ex_kern(q)
+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.
-/*
- ext_xn_over_d(width(q), 1000000+ex_kern(q), 1000000);
-*/
+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.
-@ @c
-pos_info_structure pos_info; /* to be accessed from Lua */
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-static backend_struct *backend = NULL;
-backend_function *backend_out, *backend_out_whatsit;
+*/
-@ @c
-static void missing_backend_function(PDF pdf, halfword p)
-{
- const char *n = get_node_name(type(p), subtype(p));
- if (type(p) == whatsit_node)
- formatted_error("pdf backend","no output function for whatsit %s",n);
- else
- formatted_error("pdf backend","no output function for node %s",n);
-}
+#include "ptexlib.h"
-@ @c
-static void init_none_backend_functions(void)
-{
- backend_struct *p = &backend[OMODE_NONE];
- p->name = strdup("(None)");
-}
+#define kern_width(q) width(q) + ex_kern(q)
-@ @c
-static void init_pdf_backend_functions(void)
-{
- backend_struct *p = &backend[OMODE_PDF];
- p->name = strdup("PDF");
- p->node_fu[rule_node] = &pdf_place_rule;
- p->node_fu[glyph_node] = &pdf_place_glyph;
- p->whatsit_fu[special_node] = &pdf_special;
- p->whatsit_fu[pdf_literal_node] = &pdf_out_literal;
- p->whatsit_fu[pdf_refobj_node] = &pdf_ref_obj;
- p->whatsit_fu[pdf_annot_node] = &do_annot;
- p->whatsit_fu[pdf_start_link_node] = &do_link;
- p->whatsit_fu[pdf_end_link_node] = &end_link;
- p->whatsit_fu[pdf_dest_node] = &do_dest;
- p->whatsit_fu[pdf_thread_node] = &do_thread;
- p->whatsit_fu[pdf_end_thread_node] = &end_thread;
- p->whatsit_fu[late_lua_node] = &late_lua;
- p->whatsit_fu[pdf_colorstack_node] = &pdf_out_colorstack;
- p->whatsit_fu[pdf_setmatrix_node] = &pdf_out_setmatrix;
- p->whatsit_fu[pdf_save_node] = &pdf_out_save;
- p->whatsit_fu[pdf_restore_node] = &pdf_out_restore;
-}
+#define billion 1000000000.0
-@ @c
-static void init_dvi_backend_functions(void)
-{
- backend_struct *p = &backend[OMODE_DVI];
- p->name = strdup("DVI");
- p->node_fu[rule_node] = &dvi_place_rule;
- p->node_fu[glyph_node] = &dvi_place_glyph;
- p->whatsit_fu[special_node] = &dvi_special;
- p->whatsit_fu[late_lua_node] = &late_lua;
-}
+#define vet_glue(A) do { \
+ glue_temp=A; \
+ if (glue_temp>billion) \
+ glue_temp=billion; \
+ else if (glue_temp<-billion) \
+ glue_temp=-billion; \
+ } while (0)
-@ @c
-void init_backend_functionpointers(output_mode o_mode)
-{
- int i, j;
- if (backend == NULL) {
- backend = xmalloc((MAX_OMODE + 1) * sizeof(backend_struct));
- for (i = 0; i <= MAX_OMODE; i++) {
- backend[i].node_fu = xmalloc((MAX_NODE_TYPE + 1) * sizeof(backend_function));
- backend[i].whatsit_fu = xmalloc((MAX_WHATSIT_TYPE + 1) * sizeof(backend_function));
- for (j = 0; j < MAX_NODE_TYPE + 1; j++)
- backend[i].node_fu[j] = &missing_backend_function;
- for (j = 0; j < MAX_WHATSIT_TYPE + 1; j++)
- backend[i].whatsit_fu[j] = &missing_backend_function;
- }
- init_none_backend_functions();
- init_dvi_backend_functions();
- init_pdf_backend_functions();
- }
- backend_out = backend[o_mode].node_fu;
- backend_out_whatsit = backend[o_mode].whatsit_fu;
-}
+/*tex
+
+ This code scans forward to the ending |dir_node| while keeping track of the
+ needed width in |w|. When it finds the node that will end this segment, it
+ stores the accumulated with in the |dir_dvi_h| field of that end node, so
+ that when that node is found later in the processing, the correct glue
+ correction can be applied (obsolete).
-@ This code scans forward to the ending |dir_node| while keeping
-track of the needed width in |w|. When it finds the node that will end
-this segment, it stores the accumulated with in the |dir_dvi_h| field
-of that end node, so that when that node is found later in the
-processing, the correct glue correction can be applied (obsolete).
+*/
-@c
static scaled simple_advance_width(halfword p)
{
halfword q = p;
@@ -124,8 +52,6 @@ static scaled simple_advance_width(halfword p)
switch (type(q)) {
case glyph_node:
w += glyph_width(q);
-/* experimental */
-w += x_advance(q);
break;
case hlist_node:
case vlist_node:
@@ -134,11 +60,11 @@ w += x_advance(q);
w += width(q);
break;
case kern_node:
- /* officially we should check the subtype */
+ /*tex Officially we should check the subtype. */
w += kern_width(q);
break;
case disc_node:
- /* hh: the frontend should append already */
+ /* (HH): The frontend should append already. */
if (vlink(no_break(q)) != null)
w += simple_advance_width(no_break(q));
default:
@@ -148,13 +74,13 @@ w += x_advance(q);
return w;
}
-@ @c
static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_g, halfword this_box)
{
int dir_nest = 1;
halfword q = p, enddir_ptr = p;
scaled w = 0;
- real glue_temp; /* glue value before rounding */
+ /*tex The glue value before rounding: */
+ real glue_temp;
int g_sign = glue_sign(this_box);
int g_order = glue_order(this_box);
while ((q != null) && (vlink(q) != null)) {
@@ -172,18 +98,18 @@ static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_
w += width(q);
break;
case kern_node:
- /* officially we should check the subtype */
+ /*tex Officially we should check the subtype. */
w += kern_width(q);
break;
case math_node:
- /* begin mathskip code */
+ /*tex Begin of |mathskip| code. */
if (glue_is_zero(q)) {
w += surround(q);
break;
} else {
- /* fall through: mathskip */
+ /*tex Fall through |mathskip|. */
}
- /* end mathskip code */
+ /*tex End of |mathskip| code. */
case glue_node:
w += width(q) - cur_g;
if (g_sign != normal) {
@@ -202,12 +128,12 @@ static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_
w += cur_g;
break;
case disc_node:
- /* hh: the frontend should append already */
+ /* (HH): The frontend should append already. */
if (vlink(no_break(q)) != null)
w += simple_advance_width(no_break(q));
break;
case dir_node:
- if (dir_dir(q) >= 0)
+ if (subtype(q) == normal_dir)
dir_nest++;
else
dir_nest--;
@@ -223,123 +149,115 @@ static halfword calculate_width_to_enddir(halfword p, real cur_glue, scaled cur_
}
}
if (enddir_ptr == p)
- /* no enddir found, just transport w by begindir */
+ /*tex No enddir found, just transport |w| by |begindir|. */
dir_cur_h(enddir_ptr) = w;
return enddir_ptr;
}
-@ The |out_what| procedure takes care of outputting the whatsit nodes for
-|vlist_out| and |hlist_out|, which are similar for either case.
+/*tex
+
+ The |out_what| procedure takes care of outputting the whatsit nodes for
+ |vlist_out| and |hlist_out|, which are similar for either case.
-We don't implement \.{\\write} inside of leaders. (The reason is that
-the number of times a leader box appears might be different in different
-implementations, due to machine-dependent rounding in the glue calculations.)
-@^leaders@>
+ We don't implement \.{\\write} inside of leaders. (The reason is that the
+ number of times a leader box appears might be different in different
+ implementations, due to machine-dependent rounding in the glue calculations.)
+
+*/
-@c
-void out_what(PDF pdf, halfword p)
+static void handle_backend_whatsit(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
{
- switch (subtype(p)) {
- case special_node: /* |pdf_special(pdf, p)|; */
- case late_lua_node: /* |late_lua(pdf, p)|; */
- case pdf_save_node: /* |pdf_out_save(pdf, p)|; */
- case pdf_restore_node: /* |pdf_out_restore(pdf, p)|; */
- case pdf_end_link_node: /* |end_link(pdf, p)|; */
- case pdf_end_thread_node: /* |end_thread(pdf, p)|; */
- case pdf_literal_node: /* |pdf_out_literal(pdf, p)|; */
- case pdf_colorstack_node: /* |pdf_out_colorstack(pdf, p)|; */
- case pdf_setmatrix_node: /* |pdf_out_setmatrix(pdf, p)|; */
- case pdf_refobj_node: /* |pdf_ref_obj(pdf, p)| */
- backend_out_whatsit[subtype(p)] (pdf, p);
- break;
- case open_node:
- case write_node:
- case close_node:
- /* do some work that has been queued up for \.{\\write} */
- if (!doing_leaders) {
- int j = write_stream(p);
- if (subtype(p) == write_node) {
- write_out(p);
- } else if (subtype(p) == close_node) {
- close_write_file(j);
- } else if (valid_write_file(j)) {
- char *fn;
- close_write_file(j);
- cur_name = open_name(p);
- cur_area = open_area(p);
- cur_ext = open_ext(p);
- if (cur_ext == get_nullstr())
- cur_ext = maketexstring(".tex");
- fn = pack_file_name(cur_name, cur_area, cur_ext);
- while (! open_write_file(j,fn)) {
- fn = prompt_file_name("output file name", ".tex");
- }
- }
- }
- break;
- case user_defined_node:
- break;
- default:
- /* this should give an error about missing whatsit backend function */
- backend_out_whatsit[subtype(p)] (pdf, p);
+ if (output_mode_used == OMODE_PDF) {
+ switch (subtype(p)) {
+ case pdf_literal_node:
+ case pdf_save_node:
+ case pdf_restore_node:
+ case pdf_setmatrix_node:
+ case pdf_colorstack_node:
+ case pdf_refobj_node:
+ case pdf_end_link_node:
+ case pdf_end_thread_node:
+ backend_out_whatsit[subtype(p)](pdf, p);
+ break;
+ case pdf_annot_node:
+ case pdf_start_link_node:
+ case pdf_dest_node:
+ case pdf_start_thread_node:
+ case pdf_thread_node:
+ backend_out_whatsit[subtype(p)](pdf, p, parent_box, cur);
+ break;
+ default:
+ /*tex We ignore bad ones. */
+ break;
+ }
}
}
-@ @c
void hlist_out(PDF pdf, halfword this_box, int rule_callback_id)
{
- posstructure localpos; /* the position structure local within this function */
- posstructure *refpos; /* the list origin pos. on the page, provided by the caller */
+ /*tex the position structure local within this function */
+ posstructure localpos;
+ /*tex the list origin pos. on the page, provided by the caller */
+ posstructure *refpos;
+ /*tex A few status variables. */
scaledpos cur = { 0, 0 }, tmpcur, basepoint;
- scaledpos size = { 0, 0 }; /* rule dimensions */
+ /*tex rule dimensions */
+ scaledpos size = { 0, 0 };
scaled effective_horizontal;
- scaled save_h; /* what |cur.h| should pop to */
- scaled edge; /* right edge of sub-box or leader space */
- halfword enddir_ptr; /* temporary pointer to enddir node */
- int g_order; /* applicable order of infinity for glue */
- int g_sign; /* selects type of glue */
- halfword p, q; /* current position in the hlist */
- halfword leader_box; /* the leader box being replicated */
- scaled leader_wd; /* width of leader box being replicated */
- scaled lx; /* extra space between leader boxes */
- boolean outer_doing_leaders; /* were we doing leaders? */
- real glue_temp; /* glue value before rounding */
- real cur_glue = 0.0; /* glue seen so far */
- scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */
+ /*tex what |cur.h| should pop to */
+ scaled save_h;
+ /*tex right edge of sub-box or leader space */
+ scaled edge;
+ /*tex temporary pointer to enddir node */
+ halfword enddir_ptr;
+ /*tex applicable order of infinity for glue */
+ int g_order;
+ /*tex selects type of glue */
+ int g_sign;
+ /*tex glue variables */
+ int lq, lr;
+ /*tex current position in the hlist */
+ halfword p, q;
+ /*tex the leader box being replicated */
+ halfword leader_box;
+ /*tex width of leader box being replicated */
+ scaled leader_wd;
+ /*tex extra space between leader boxes */
+ scaled lx;
+ /*tex were we doing leaders? */
+ boolean outer_doing_leaders;
+ /*tex glue value before rounding */
+ real glue_temp;
+ /*tex glue seen so far */
+ real cur_glue = 0.0;
+ /*tex rounded equivalent of |cur_glue| times the glue ratio */
+ scaled cur_g = 0;
scaled_whd rule, ci;
- int i; /* index to scan |pdf_link_stack| */
- int save_loc = 0; /* DVI! \.{DVI} byte location upon entry */
- scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */
+ /*tex index to scan |pdf_link_stack| */
+ int i;
+ /*tex DVI! \.{DVI} byte location upon entry */
+ int saved_loc = 0;
+ /*tex DVI! what |dvi| should pop to */
+ scaledpos saved_pos = { 0, 0 };
int synctex = synctex_par ;
-
+ scaled rleft, rright;
g_order = glue_order(this_box);
g_sign = glue_sign(this_box);
p = list_ptr(this_box);
-
refpos = pdf->posstruct;
- pdf->posstruct = &localpos; /* use local structure for recursion */
+ /*tex use local structure for recursion */
+ pdf->posstruct = &localpos;
localpos.pos = refpos->pos;
localpos.dir = box_dir(this_box);
-
cur_s++;
- if (cur_s > max_push)
- max_push = cur_s;
-
- if (output_mode_used == OMODE_DVI) {
- if (cur_s > 0) {
- dvi_push();
- save_dvi = dvi;
- }
- save_loc = dvi_offset + dvi_ptr;
- }
-
+ backend_out_control[backend_control_push_list](pdf,&saved_pos,&saved_loc);
for (i = 1; i <= pdf->link_stack_ptr; i++) {
if (pdf->link_stack[i].nesting_level == cur_s)
append_link(pdf, this_box, cur, (small_number) i);
}
-
- if (synctex)
+ if (synctex) {
synctexhlist(this_box);
+ }
while (p != null) {
if (is_char_node(p)) {
do {
@@ -351,8 +269,6 @@ void hlist_out(PDF pdf, halfword this_box, int rule_callback_id)
ci = output_one_char(pdf, p);
if (textdir_parallel(localpos.dir, dir_TLT)) {
cur.h += ci.wd;
-/* experimental */
-cur.h += x_advance(p);
} else {
cur.h += ci.ht + ci.dp;
}
@@ -362,7 +278,10 @@ cur.h += x_advance(p);
if (synctex)
synctexcurrent();
} else {
- /* output the non-|char_node| |p| for |hlist_out| and move to the next node */
+ /*tex
+ Output the non-|char_node| |p| for |hlist_out| and move to the
+ next node.
+ */
switch (type(p)) {
case hlist_node:
case vlist_node:
@@ -387,26 +306,36 @@ cur.h += x_advance(p);
basepoint.h = height(p);
}
if (is_rotated(localpos.dir)) {
- if (partextdir_eq(localpos.dir, box_dir(p)))
- basepoint.v = -width(p) / 2; /* up */
- else
- basepoint.v = width(p) / 2; /* down */
+ if (partextdir_eq(localpos.dir, box_dir(p))) {
+ /*tex up */
+ basepoint.v = -width(p) / 2;
+ } else {
+ /*tex down */
+ basepoint.v = width(p) / 2;
+ }
} else if (is_mirrored(localpos.dir)) {
- if (partextdir_eq(localpos.dir, box_dir(p)))
+ if (partextdir_eq(localpos.dir, box_dir(p))) {
basepoint.v = 0;
- else
- basepoint.v = width(p); /* down */
+ } else {
+ /*tex down */
+ basepoint.v = width(p);
+ }
} else {
- if (partextdir_eq(localpos.dir, box_dir(p)))
- basepoint.v = -width(p); /* up */
- else
+ if (partextdir_eq(localpos.dir, box_dir(p))) {
+ /*tex up */
+ basepoint.v = -width(p);
+ } else {
basepoint.v = 0;
+ }
}
}
- if (!is_mirrored(localpos.dir))
- basepoint.v = basepoint.v + shift_amount(p); /* shift the box down */
- else
- basepoint.v = basepoint.v - shift_amount(p); /* shift the box up */
+ if (!is_mirrored(localpos.dir)) {
+ /*tex Shift the box down. */
+ basepoint.v = basepoint.v + shift_amount(p);
+ } else {
+ /*tex Shift the box up. */
+ basepoint.v = basepoint.v - shift_amount(p);
+ }
if (list_ptr(p) == null) {
if (synctex) {
if (type(p) == vlist_node)
@@ -426,10 +355,11 @@ cur.h += x_advance(p);
cur.h += effective_horizontal;
break;
case disc_node:
- /* hh: the frontend should append already */
+ /*tex (HH): the frontend should append already */
if (vlink(no_break(p)) != null) {
if (subtype(p) != select_disc) {
- q = tail_of_list(vlink(no_break(p))); /* this could be a tlink */
+ /*tex This could be a |tlink|. */
+ q = tail_of_list(vlink(no_break(p)));
vlink(q) = vlink(p);
q = vlink(no_break(p));
vlink(no_break(p)) = null;
@@ -441,17 +371,20 @@ cur.h += x_advance(p);
if (synctex) {
synctexmath(p, this_box);
}
- /* begin mathskip code */
+ /*tex Begin |mathskip| code. */
if (glue_is_zero(p)) {
cur.h += surround(p);
break;
} else {
- /* fall through: mathskip */
+ /*tex Fall through |mathskip|. */
}
- /* end mathskip code */
+ /*tex End |mathskip| code. */
case glue_node:
{
- /* move right or output leaders, we use real multiplication */
+ /*tex
+ Move right or output leaders, we use real
+ multiplication.
+ */
rule.wd = width(p) - cur_g;
if (g_sign != normal) {
if (g_sign == stretching) {
@@ -468,11 +401,16 @@ cur.h += x_advance(p);
}
rule.wd = rule.wd + cur_g;
if (subtype(p) >= a_leaders) {
- /* output leaders in an hlist, |goto fin_rule| if a rule or to |next_p| if done */
+ /*tex
+ Output leaders in an hlist, |goto fin_rule| if a rule
+ or to |next_p| if done.
+ */
leader_box = leader_ptr(p);
if (type(leader_box) == rule_node) {
rule.ht = height(leader_box);
rule.dp = depth(leader_box);
+ rleft = 0;
+ rright = 0;
goto FIN_RULE;
}
if (textdir_parallel(box_dir(leader_box), localpos.dir))
@@ -480,12 +418,14 @@ cur.h += x_advance(p);
else
leader_wd = height(leader_box) + depth(leader_box);
if ((leader_wd > 0) && (rule.wd > 0)) {
- rule.wd = rule.wd + 10; /* compensate for floating-point rounding */
+ /*tex Compensate for floating-point rounding. */
+ rule.wd = rule.wd + 10;
edge = cur.h + rule.wd;
lx = 0;
- /*
- let |cur.h| be the position of the first box, and set |leader_wd+lx|
- to the spacing between corresponding parts of boxes
+ /*tex
+ Let |cur.h| be the position of the first box, and
+ set |leader_wd+lx| to the spacing between
+ corresponding parts of boxes.
*/
if (subtype(p) == g_leaders) {
save_h = cur.h;
@@ -522,8 +462,10 @@ cur.h += x_advance(p);
if (cur.h < save_h)
cur.h += leader_wd;
} else {
- lq = rule.wd / leader_wd; /* the number of box copies */
- lr = rule.wd % leader_wd; /* the remaining space */
+ /*tex The number of box copies: */
+ lq = rule.wd / leader_wd;
+ /*tex The remaining space: */
+ lr = rule.wd % leader_wd;
if (subtype(p) == c_leaders) {
cur.h += lr / 2;
} else {
@@ -532,7 +474,10 @@ cur.h += x_advance(p);
}
}
while (cur.h + leader_wd <= edge) {
- /* output a leader box at |cur.h|, then advance |cur.h| by |leader_wd+lx| */
+ /*tex
+ Output a leader box at |cur.h|, then advance
+ |cur.h| by |leader_wd+lx|.
+ */
if (pardir_parallel(box_dir(leader_box), localpos.dir)) {
basepoint.v = 0;
if (textdir_opposite(box_dir(leader_box), localpos.dir))
@@ -582,7 +527,7 @@ cur.h += x_advance(p);
case kern_node:
if (synctex)
synctexkern(p, this_box);
- /* officially we should check the subtype */
+ /*tex officially we should check the subtype */
cur.h += kern_width(p);
break;
case rule_node:
@@ -597,14 +542,18 @@ cur.h += x_advance(p);
rule.dp = width(p) / 2;
rule.wd = height(p) + depth(p);
}
+ rleft = rule_left(p);
+ rright = rule_right(p);
goto FIN_RULE;
break;
case dir_node:
- /* output a reflection instruction if the direction has changed */
- if (dir_dir(p) >= 0) {
- /*
+ /*tex
+ Output a reflection instruction if the direction has changed.
+ */
+ if (subtype(p) == normal_dir) {
+ /*tex
Calculate the needed width to the matching |enddir|, return the
- |enddir| node, with width info
+ |enddir| node, with width info.
*/
enddir_ptr = calculate_width_to_enddir(p, cur_glue, cur_g, this_box);
if (textdir_parallel(dir_dir(p), localpos.dir)) {
@@ -614,14 +563,14 @@ cur.h += x_advance(p);
} else
dir_cur_h(enddir_ptr) = cur.h;
if (enddir_ptr != p) {
- /* only if it is an enddir */
+ /*tex Only if it is an |enddir|. */
dir_cur_v(enddir_ptr) = cur.v;
dir_refpos_h(enddir_ptr) = refpos->pos.h;
dir_refpos_v(enddir_ptr) = refpos->pos.v;
- /* negative: mark it as |enddir| */
- dir_dir(enddir_ptr) = localpos.dir - dir_swap;
+ /*tex Negative: mark it as |enddir|. */
+ dir_dir(enddir_ptr) = localpos.dir;
}
- /* fake a nested |hlist_out| */
+ /*tex fake a nested |hlist_out|. */
synch_pos_with_cur(pdf->posstruct, refpos, cur);
refpos->pos = pdf->posstruct->pos;
localpos.dir = dir_dir(p);
@@ -630,32 +579,44 @@ cur.h += x_advance(p);
} else {
refpos->pos.h = dir_refpos_h(p);
refpos->pos.v = dir_refpos_v(p);
- localpos.dir = dir_dir(p) + dir_swap;
+ localpos.dir = dir_dir(p);
cur.h = dir_cur_h(p);
cur.v = dir_cur_v(p);
}
break;
case whatsit_node:
- /* output the whatsit node |p| in |hlist_out| */
- switch (subtype(p)) {
- case save_pos_node:
- last_position = pdf->posstruct->pos;
- pos_info.curpos = pdf->posstruct->pos;
- pos_info.boxpos.pos = refpos->pos;
- pos_info.boxpos.dir = localpos.dir;
- pos_info.boxdim.wd = width(this_box);
- pos_info.boxdim.ht = height(this_box);
- pos_info.boxdim.dp = depth(this_box);
- break;
- case pdf_annot_node:
- case pdf_start_link_node:
- case pdf_dest_node:
- case pdf_start_thread_node:
- case pdf_thread_node:
- backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur);
- break;
- default:
- out_what(pdf, p);
+ /*tex Output the whatsit node |p| in |hlist_out|. */
+ if (subtype(p) <= last_common_whatsit) {
+ switch (subtype(p)) {
+ case save_pos_node:
+ last_position = pdf->posstruct->pos;
+ /*
+ pos_info.curpos = pdf->posstruct->pos;
+ pos_info.boxpos.pos = refpos->pos;
+ pos_info.boxpos.dir = localpos.dir;
+ pos_info.boxdim.wd = width(this_box);
+ pos_info.boxdim.ht = height(this_box);
+ pos_info.boxdim.dp = depth(this_box);
+ */
+ break;
+ case user_defined_node:
+ break;
+ case open_node:
+ case write_node:
+ case close_node:
+ wrapup_leader(p);
+ break;
+ case special_node:
+ /*tex |pdf_special(pdf, p)| */
+ case late_lua_node:
+ /*tex |late_lua(pdf, p)| */
+ backend_out_whatsit[subtype(p)] (pdf, p);
+ break;
+ default:
+ break;
+ }
+ } else {
+ handle_backend_whatsit(pdf, p, this_box, cur);
}
break;
case margin_kern_node:
@@ -666,12 +627,21 @@ cur.h += x_advance(p);
}
goto NEXTP;
FIN_RULE:
- /* output a rule in an hlist */
- if (is_running(rule.ht))
+ /*tex Output a rule in an hlist. */
+ if (is_running(rule.ht)) {
rule.ht = height(this_box);
- if (is_running(rule.dp))
+ }
+ if (rleft != 0) {
+ rule.ht -= rleft;
+ pos_down(-rleft);
+ }
+ if (is_running(rule.dp)) {
rule.dp = depth(this_box);
- /* we don't output empty rules */
+ }
+ if (rright != 0) {
+ rule.dp -= rright;
+ }
+ /*tex We don't output empty rules. */
if ((rule.ht + rule.dp) > 0 && rule.wd > 0) {
switch (localpos.dir) {
case dir_TLT:
@@ -725,92 +695,85 @@ cur.h += x_advance(p);
synch_pos_with_cur(pdf->posstruct, refpos, cur);
}
}
- if (synctex)
+ if (synctex) {
synctextsilh(this_box);
- if (output_mode_used == OMODE_DVI) {
- prune_movements(save_loc);
- if (cur_s > 0) {
- dvi_pop(save_loc);
- dvi = save_dvi;
- }
}
+ backend_out_control[backend_control_pop_list](pdf,&saved_pos,&saved_loc);
cur_s--;
pdf->posstruct = refpos;
}
-@ @c
void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
{
- posstructure localpos; /* the position structure local within this function */
- posstructure *refpos; /* the list origin pos. on the page, provided by the caller */
-
+ /*tex The position structure local within this function: */
+ posstructure localpos;
+ /*tex The list origin pos. on the page, provided by the caller: */
+ posstructure *refpos;
+ /*tex a few status variables */
scaledpos cur, tmpcur, basepoint;
- scaledpos size = { 0, 0 }; /* rule dimensions */
+ /*tex rule dimensions */
+ scaledpos size = { 0, 0 };
scaled effective_vertical;
- scaled save_v; /* what |cur.v| should pop to */
- scaled top_edge; /* the top coordinate for this box */
- scaled edge; /* bottom boundary of leader space */
- glue_ord g_order; /* applicable order of infinity for glue */
- int g_sign; /* selects type of glue */
- halfword p; /* current position in the vlist */
- halfword q; /* temp */
- halfword leader_box; /* the leader box being replicated */
- scaled leader_ht; /* height of leader box being replicated */
- scaled lx; /* extra space between leader boxes */
- boolean outer_doing_leaders; /* were we doing leaders? */
- real glue_temp; /* glue value before rounding */
- real cur_glue = 0.0; /* glue seen so far */
- scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */
+ /*tex what |cur.v| should pop to */
+ scaled save_v;
+ /*tex the top coordinate for this box */
+ scaled top_edge;
+ /*tex bottom boundary of leader space */
+ scaled edge;
+ /*tex applicable order of infinity for glue */
+ glue_ord g_order;
+ /*tex selects type of glue */
+ int g_sign;
+ /*tex glue variables */
+ int lq, lr;
+ /*tex current position in the vlist */
+ halfword p;
+ /*tex temp */
+ halfword q;
+ /*tex the leader box being replicated */
+ halfword leader_box;
+ /*tex height of leader box being replicated */
+ scaled leader_ht;
+ /*tex extra space between leader boxes */
+ scaled lx;
+ /*tex were we doing leaders? */
+ boolean outer_doing_leaders;
+ /*tex glue value before rounding */
+ real glue_temp;
+ /*tex glue seen so far */
+ real cur_glue = 0.0;
+ /*tex rounded equivalent of |cur_glue| times the glue ratio */
+ scaled cur_g = 0;
scaled_whd rule;
- int save_loc = 0; /* DVI byte location upon entry */
- scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */
+ /*tex \DVI\ byte location upon entry */
+ int saved_loc = 0;
+ /*tex \DVI\ what |dvi| should pop to */
+ scaledpos saved_pos = { 0, 0 };
int synctex = synctex_par ;
-
+ int rleft, rright;
g_order = (glue_ord) glue_order(this_box);
g_sign = glue_sign(this_box);
p = list_ptr(this_box);
-
cur.h = 0;
cur.v = -height(this_box);
top_edge = cur.v;
-
refpos = pdf->posstruct;
- pdf->posstruct = &localpos; /* use local structure for recursion */
+ /*tex Use local structure for recursion. */
+ pdf->posstruct = &localpos;
localpos.dir = box_dir(this_box);
synch_pos_with_cur(pdf->posstruct, refpos, cur);
-
cur_s++;
- if (cur_s > max_push)
- max_push = cur_s;
-
- if (output_mode_used == OMODE_DVI) {
- if (cur_s > 0) {
- dvi_push();
- save_dvi = dvi;
- }
- save_loc = dvi_offset + dvi_ptr;
- }
-
- if (synctex)
+ backend_out_control[backend_control_push_list](pdf,&saved_pos,&saved_loc);
+ if (synctex) {
synctexvlist(this_box);
-
- /* create thread for the current vbox if needed */
+ }
+ /*tex Create thread for the current vbox if needed. */
check_running_thread(pdf, this_box, cur);
-
while (p != null) {
switch (type(p)) {
case hlist_node:
case vlist_node:
- /*
- output a box in a vlist:
-
- todo: the direct test to switch between |width(p)| and |-width(p)|
- is definately wrong, because it does not nest properly. But at least
- it fixes a very obvious problem that otherwise occured with
- \.{\\pardir TLT} in a document with \.{\\bodydir TRT}, and so it
- will have to do for now. (hh: is this still true?)
-
- */
+ /*tex Output a box in a vlist. */
if (pardir_parallel(box_dir(p), localpos.dir)) {
effective_vertical = height(p) + depth(p);
if ((type(p) == hlist_node) && is_mirrored(box_dir(p)))
@@ -839,7 +802,8 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
else
basepoint.v = width(p);
}
- basepoint.h = basepoint.h + shift_amount(p); /* shift the box right */
+ /*tex Shift the box right. */
+ basepoint.h = basepoint.h + shift_amount(p);
if (list_ptr(p) == null) {
cur.v += effective_vertical;
if (synctex) {
@@ -872,11 +836,15 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
rule.dp = width(p) / 2;
rule.wd = height(p) + depth(p);
}
+ rleft = rule_left(p);
+ rright = rule_right(p);
goto FIN_RULE;
break;
case glue_node:
{
- /* move down or output leaders, we use real multiplication */
+ /*tex
+ Move down or output leaders, we use real multiplication.
+ */
rule.ht = width(p) - cur_g;
if (g_sign != normal) {
if (g_sign == stretching) {
@@ -893,25 +861,38 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
}
rule.ht = rule.ht + cur_g;
if (subtype(p) >= a_leaders) {
- /* output leaders in a vlist, |goto fin_rulefin_rule| if a rule or to |next_p| if done */
+ /*tex
+ Output leaders in a vlist, |goto fin_rulefin_rule| if a
+ rule or to |next_p| if done.
+ */
leader_box = leader_ptr(p);
if (type(leader_box) == rule_node) {
rule.wd = width(leader_box);
rule.dp = 0;
+ rleft = 0;
+ rright = 0;
goto FIN_RULE;
}
leader_ht = height(leader_box) + depth(leader_box);
if ((leader_ht > 0) && (rule.ht > 0)) {
- rule.ht = rule.ht + 10; /* compensate for floating-point rounding */
+ /*tex Compensate for floating-point rounding: */
+ rule.ht = rule.ht + 10;
edge = cur.v + rule.ht;
lx = 0;
- /*
- let |cur.v| be the position of the first box, and set |leader_ht+lx|
- to the spacing between corresponding parts of boxes
+ /*tex
+ Let |cur.v| be the position of the first box, and set
+ |leader_ht+lx| to the spacing between corresponding
+ parts of boxes.
*/
if (subtype(p) == g_leaders) {
save_v = cur.v;
switch (localpos.dir) {
+ case dir_TLT:
+ case dir_TRT:
+ cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
+ cur.v = leader_ht * (cur.v / leader_ht);
+ cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
+ break;
case dir_LTL:
cur.v += refpos->pos.h - shipbox_refpos.h;
cur.v = leader_ht * (cur.v / leader_ht);
@@ -922,12 +903,6 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
cur.v = leader_ht * (cur.v / leader_ht);
cur.v = refpos->pos.h - shipbox_refpos.h - cur.v;
break;
- case dir_TLT:
- case dir_TRT:
- cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
- cur.v = leader_ht * (cur.v / leader_ht);
- cur.v = refpos->pos.v - shipbox_refpos.v - cur.v;
- break;
default:
formatted_warning("pdf backend","forcing bad dir %i to TLT in vlist case 1",localpos.dir);
localpos.dir = dir_TLT;
@@ -944,8 +919,10 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
if (cur.v < save_v)
cur.v += leader_ht;
} else {
- lq = rule.ht / leader_ht; /* the number of box copies */
- lr = rule.ht % leader_ht; /* the remaining space */
+ /*tex The number of box copies. */
+ lq = rule.ht / leader_ht;
+ /*tex The remaining space. */
+ lr = rule.ht % leader_ht;
if (subtype(p) == c_leaders) {
cur.v += lr / 2;
} else {
@@ -953,9 +930,11 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
cur.v += (lr - (lq - 1) * lx) / 2;
}
}
-
while (cur.v + leader_ht <= edge) {
- /* output a leader box at |cur.v|, then advance |cur.v| by |leader_ht+lx| */
+ /*tex
+ Output a leader box at |cur.v|, then advance
+ |cur.v| by |leader_ht+lx|.
+ */
tmpcur.h = shift_amount(leader_box);
tmpcur.v = cur.v + height(leader_box);
synch_pos_with_cur(pdf->posstruct, refpos, tmpcur);
@@ -979,41 +958,62 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
cur.v += width(p);
break;
case whatsit_node:
- /* output the whatsit node |p| in |vlist_out| */
- switch (subtype(p)) {
- case save_pos_node:
- last_position = pdf->posstruct->pos;
- pos_info.curpos = pdf->posstruct->pos;
- pos_info.boxpos.pos = refpos->pos;
- pos_info.boxpos.dir = localpos.dir;
- pos_info.boxdim.wd = width(this_box);
- pos_info.boxdim.ht = height(this_box);
- pos_info.boxdim.dp = depth(this_box);
- break;
- case pdf_annot_node:
- case pdf_start_link_node:
- case pdf_dest_node:
- case pdf_start_thread_node:
- case pdf_thread_node:
- backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur);
- break;
- default:
- out_what(pdf, p);
+ /*tex Output the whatsit node |p| in |vlist_out|. */
+ if (subtype(p) <= last_common_whatsit) {
+ switch (subtype(p)) {
+ case save_pos_node:
+ last_position = pdf->posstruct->pos;
+ /*
+ pos_info.curpos = pdf->posstruct->pos;
+ pos_info.boxpos.pos = refpos->pos;
+ pos_info.boxpos.dir = localpos.dir;
+ pos_info.boxdim.wd = width(this_box);
+ pos_info.boxdim.ht = height(this_box);
+ pos_info.boxdim.dp = depth(this_box);
+ */
+ break;
+ case user_defined_node:
+ break;
+ case open_node:
+ case write_node:
+ case close_node:
+ wrapup_leader(p);
+ break;
+ case special_node:
+ /*tex |pdf_special(pdf, p)|; */
+ case late_lua_node:
+ /*tex |late_lua(pdf, p)|; */
+ backend_out_whatsit[subtype(p)] (pdf, p);
+ break;
+ default:
+ break;
+ }
+ } else {
+ handle_backend_whatsit(pdf, p, this_box, cur);
}
break;
case glyph_node:
case disc_node:
- confusion("vlistout"); /* this can't happen */
+ /*tex This can't happen unless one messes up in \LUA. */
+ confusion("vlistout");
break;
default:
break;
}
goto NEXTP;
FIN_RULE:
- /* output a rule in a vlist, |goto next_p| */
- if (is_running(rule.wd))
+ /*tex Output a rule in a vlist and |goto next_p|. */
+ if (is_running(rule.wd)) {
rule.wd = width(this_box);
- /* we don't output empty rules */
+ }
+ if (rleft != 0) {
+ rule.wd -= rleft;
+ pos_left(-rleft);
+ }
+ if (rright != 0) {
+ rule.wd -= rright;
+ }
+ /*tex We don't output empty rules. */
if ((rule.ht + rule.dp) > 0 && rule.wd > 0) {
switch (localpos.dir) {
case dir_TLT:
@@ -1063,16 +1063,10 @@ void vlist_out(PDF pdf, halfword this_box, int rule_callback_id)
p = vlink(p);
synch_pos_with_cur(pdf->posstruct, refpos, cur);
}
- if (synctex)
+ if (synctex) {
synctextsilv(this_box);
-
- if (output_mode_used == OMODE_DVI) {
- prune_movements(save_loc);
- if (cur_s > 0) {
- dvi_pop(save_loc);
- dvi = save_dvi;
- }
}
+ backend_out_control[backend_control_pop_list](pdf,&saved_pos,&saved_loc);
cur_s--;
pdf->posstruct = refpos;
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.c
index 94bb2c93c4a..e8b00a64ef5 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.c
@@ -1,27 +1,26 @@
-% pdfliteral.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ @c
void pdf_special(PDF pdf, halfword p)
{
int old_setting = selector;
@@ -34,18 +33,22 @@ void pdf_special(PDF pdf, halfword p)
flush_str(s);
}
-@ To ship out a \TeX\ box to PDF page description we need to implement
-|hlist_out|, |vlist_out| and |ship_out|, which are equivalent to the \TeX'
-original |hlist_out|, |vlist_out| and |ship_out| resp. But first we need to
-declare some procedures needed in |hlist_out| and |vlist_out|.
+/*tex
+
+ To ship out a \TeX\ box to PDF page description we need to implement
+ |hlist_out|, |vlist_out| and |ship_out|, which are equivalent to the \TeX'
+ original |hlist_out|, |vlist_out| and |ship_out| resp. But first we need to
+ declare some procedures needed in |hlist_out| and |vlist_out|.
+
+*/
-@c
void pdf_out_literal(PDF pdf, halfword p)
{
- int old_setting; /* holds print |selector| */
+ int old_setting;
str_number s;
+ int t = pdf_literal_type(p);
pdfstructure *ps = pdf->pstruct;
- if (pdf_literal_type(p) == normal) {
+ if (t == normal) {
old_setting = selector;
selector = new_string;
show_token_list(token_link(pdf_literal_data(p)), null, -1);
@@ -53,7 +56,7 @@ void pdf_out_literal(PDF pdf, halfword p)
s = make_string();
pdf_literal(pdf, s, pdf_literal_mode(p), false);
flush_str(s);
- } else {
+ } else if (t == lua_refid_literal) {
switch (pdf_literal_mode(p)) {
case set_origin:
pdf_goto_pagemode(pdf);
@@ -79,12 +82,12 @@ void pdf_out_literal(PDF pdf, halfword p)
normal_error("pdf backend","bad literal mode");
break;
}
- lua_pdf_literal(pdf, pdf_literal_data(p));
+ lua_pdf_literal(pdf, pdf_literal_data(p), 0);
}
}
-@ test equality of start of strings
-@c
+/*tex Test equality of start of strings: */
+
static boolean str_in_cstr(str_number s, const char *r, unsigned i)
{
const unsigned char *k, *l;
@@ -99,38 +102,50 @@ static boolean str_in_cstr(str_number s, const char *r, unsigned i)
return true;
}
-@ @c
void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn)
{
unsigned char *ss;
size_t l;
- pool_pointer j = 0; /* current character code position, initialized to make the compiler happy */
+ /*tex
+ The current character code position, initialized to make the compiler
+ happy:
+ */
+ pool_pointer j = 0;
pdfstructure *p = pdf->pstruct;
if (s >= STRING_OFFSET) {
- /* needed for |out_save| */
+ /*tex Needed for |out_save|: */
j = 0;
- /* unfortunately we always go through this when we have vf specials (and also via temp strings) */
+ /*tex
+ Unfortunately we always go through this when we have vf specials (and
+ also via temp strings):
+ */
if (literal_mode == scan_special) {
if (!(str_in_cstr(s, "pdf:", 0) || str_in_cstr(s, "PDF:", 0))) {
if (warn && ((!(str_in_cstr(s, "src:", 0) || str_in_cstr(s, "SRC:", 0))) || (str_length(s) == 0)))
tprint_nl("Non-PDF special ignored!");
return;
}
- j = j + (pool_pointer) 4; /* strlen("PDF:") */
- if (str_in_cstr(s, "direct:", 4)) { /* strlen("PDF:") */
- j = j + (pool_pointer) 7; /* strlen("direct:") */
+ /*tex |strlen("PDF:")| */
+ j = j + (pool_pointer) 4;
+ if (str_in_cstr(s, "direct:", 4)) {
+ /*tex |strlen("direct:")| */
+ j = j + (pool_pointer) 7;
literal_mode = direct_always;
- } else if (str_in_cstr(s, "page:", 4)) { /* strlen("PDF:") */
- j = j + (pool_pointer) 5; /* strlen("page:") */
+ } else if (str_in_cstr(s, "page:", 4)) {
+ /*tex |strlen("page:")| */
+ j = j + (pool_pointer) 5;
literal_mode = direct_page;
- } else if (str_in_cstr(s, "text:", 4)) { /* strlen("PDF:") */
- j = j + (pool_pointer) 5; /* strlen("text:") */
+ } else if (str_in_cstr(s, "text:", 4)) {
+ /*tex |strlen("text:")| */
+ j = j + (pool_pointer) 5;
literal_mode = direct_text;
- } else if (str_in_cstr(s, "raw:", 4)) { /* strlen("PDF:") */
- j = j + (pool_pointer) 4; /* strlen("raw:") */
+ } else if (str_in_cstr(s, "raw:", 4)) {
+ /*tex |strlen("raw:")| */
+ j = j + (pool_pointer) 4;
literal_mode = direct_raw;
- } else if (str_in_cstr(s, "origin:", 4)) { /* strlen("PDF:") */
- j = j + (pool_pointer) 7; /* strlen("origin:") */
+ } else if (str_in_cstr(s, "origin:", 4)) {
+ /*tex |strlen("origin:")| */
+ j = j + (pool_pointer) 7;
literal_mode = set_origin;
} else {
literal_mode = set_origin;
@@ -147,7 +162,7 @@ void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn)
break;
case direct_text:
pdf_goto_fontmode(pdf);
-// pdf_goto_textmode(pdf);
+ /*tex not: |pdf_goto_textmode(pdf);| */
break;
case direct_always:
pdf_end_string_nl(pdf);
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.c
index e5ca09de624..71d6a943f57 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.c
@@ -1,44 +1,48 @@
-% pdfobj.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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/>.
+
+*/
+
#include "ptexlib.h"
#include "lua/luatex-api.h"
-@ write a raw PDF object
+/*tex Write a raw \PDF\ object: */
-@c
void pdf_write_obj(PDF pdf, int k)
{
lstring data;
const_lstring st;
- size_t li; /* index into |data.s| */
+ /*tex The index into |data.s|: */
+ size_t li;
int saved_compress_level ;
- int os_threshold = OBJSTM_ALWAYS; /* gives compressed objects for \.{\\pdfvariable objcompresslevel} >= |OBJSTM_ALWAYS| */
- int l = 0; /* possibly a lua registry reference */
+ /*tex Gives compressed objects for |\pdfvariable objcompresslevel| >= |OBJSTM_ALWAYS|: */
+ int os_threshold = OBJSTM_ALWAYS;
+ /*tex Possibly a \LUA\ registry reference: */
+ int l = 0;
int ll = 0;
data.s = NULL;
- /* we can have an immediate object before we are initialized */
+ /*tex We can have an immediate object before we are initialized. */
ensure_output_state(pdf, ST_HEADER_WRITTEN);
saved_compress_level = pdf->compress_level;
- /* end of ugly hack */
- if (obj_obj_pdfcompresslevel(pdf, k) > -1) { /* -1 = "unset" */
+ /*tex End of a ugly hack. */
+ if (obj_obj_pdfcompresslevel(pdf, k) > -1) {
+ /*tex A value of |-1| means ``unset''. */
pdf->compress_level = obj_obj_pdfcompresslevel(pdf, k);
if (pdf->compress_level == 0) {
pdf->objcompresslevel = 0;
@@ -56,9 +60,10 @@ void pdf_write_obj(PDF pdf, int k)
normal_error("pdf backend","invalid object");
st.s = lua_tolstring(Luas, -1, &li);
st.l = li;
+ lua_pop(Luas,1);
+ pdf_check_space(pdf);
pdf_out_block(pdf, st.s, st.l);
- if (st.s[st.l - 1] != '\n')
- pdf_out(pdf, '\n');
+ pdf_set_space(pdf);
luaL_unref(Luas, LUA_REGISTRYINDEX, l);
obj_obj_stream_attr(pdf, k) = LUA_NOREF;
}
@@ -75,10 +80,12 @@ void pdf_write_obj(PDF pdf, int k)
st.l = li;
lua_pop(Luas, 1);
if (obj_obj_is_file(pdf, k)) {
- boolean res = false; /* callback status value */
- const char *fnam = NULL; /* callback found filename */
+ /*tex The callback status value: */
+ boolean res = false;
+ /*tex The callback found filename: */
+ const char *fnam = NULL;
int callback_id;
- /* st.s is also |\0|-terminated, even as lstring */
+ /*tex |st.s| is also |\0|-terminated, even as |lstring| */
fnam = luatex_find_file(st.s, find_data_file_callback);
callback_id = callback_defined(read_data_file_callback);
if (fnam && callback_id > 0) {
@@ -88,7 +95,8 @@ void pdf_write_obj(PDF pdf, int k)
if (!file_opened)
normal_error("pdf backend", "cannot open file for embedding");
} else {
- byte_file f; /* the data file's FILE* */
+ /*tex The data file's |FILE*|: */
+ byte_file f;
if (!fnam)
fnam = st.s;
if (!luatex_open_input(&f, fnam, kpse_tex_format, FOPEN_RBIN_MODE, true))
@@ -112,32 +120,37 @@ void pdf_write_obj(PDF pdf, int k)
if (obj_obj_is_stream(pdf, k)) {
pdf_end_stream(pdf);
pdf_end_obj(pdf);
- } else /* here we do the \n */
+ } else {
+ /*tex Here we do the |\n|. */
pdf_end_obj(pdf);
+ }
luaL_unref(Luas, LUA_REGISTRYINDEX, l);
obj_obj_data(pdf, k) = LUA_NOREF;
pdf->compress_level = saved_compress_level;
}
-@ @c
void init_obj_obj(PDF pdf, int k)
{
obj_obj_stream_attr(pdf, k) = LUA_NOREF;
obj_obj_data(pdf, k) = LUA_NOREF;
unset_obj_obj_is_stream(pdf, k);
unset_obj_obj_is_file(pdf, k);
+ unset_obj_obj_no_length(pdf, k);
obj_obj_pdfcompresslevel(pdf, k) = -1; /* unset */
obj_obj_objstm_threshold(pdf, k) = OBJSTM_UNSET; /* unset */
}
-@ The \.{\\pdfextension obj} primitive is used to create a ``raw'' object in the
-PDF output file. The object contents will be hold in memory and will be written
-out only when the object is referenced by \.{\\pdfextension refobj}. When
-\.{\\pdfextension obj} is used with \.{\\immediate}, the object contents will be
-written out immediately. Objects referenced in the current page are appended into
-|pdf_obj_list|.
+/*tex
+
+ The |\pdfextension obj| primitive is used to create a ``raw'' object in
+ the PDF output file. The object contents will be hold in memory and will be
+ written out only when the object is referenced by |\pdfextension refobj|.
+ When |\pdfextension obj| is used with |\immediate|, the object contents
+ will be written out immediately. Objects referenced in the current page are
+ appended into |pdf_obj_list|.
+
+*/
-@c
void scan_obj(PDF pdf)
{
int k;
@@ -154,7 +167,7 @@ void scan_obj(PDF pdf)
k = cur_val;
check_obj_type(pdf, obj_type_obj, k);
if (is_obj_scheduled(pdf, k) || obj_data_ptr(pdf, k) != 0)
- luaL_error(Luas, "object in use");
+ normal_error("pdf backend", "scheduled object is already used");
} else {
pdf->obj_count++;
k = pdf_create_obj(pdf, obj_type_obj, 0);
@@ -190,7 +203,6 @@ void scan_obj(PDF pdf)
pdf_last_obj = k;
}
-@ @c
void scan_refobj(PDF pdf)
{
scan_int();
@@ -206,14 +218,12 @@ void scan_refobj_lua(PDF pdf, int k)
pdf_obj_objnum(tail_par) = k;
}
-@ @c
void pdf_ref_obj(PDF pdf, halfword p)
{
if (!is_obj_scheduled(pdf, pdf_obj_objnum(p)))
addto_page_resources(pdf, obj_type_obj, pdf_obj_objnum(p));
}
-@ @c
void pdf_ref_obj_lua(PDF pdf, int k)
{
if (!is_obj_scheduled(pdf, k))
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.c
index 6c0a30a88d9..ae17e29dac3 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.c
@@ -1,36 +1,46 @@
-% pdfoutline.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ Data structure of outlines; it's not able to write out outline entries before
-all outline entries are defined, so memory allocated for outline entries can't
-not be deallocated and will stay in memory. For this reason we will store data of
-outline entries in |pdf->mem| instead of |mem|
+/*tex
+
+ Data structure of outlines; it's not able to write out outline entries before
+ all outline entries are defined, so memory allocated for outline entries
+ can't not be deallocated and will stay in memory. For this reason we will
+ store data of outline entries in |pdf->mem| instead of |mem|.
+
+*/
-@c
-#define pdfmem_outline_size 8 /* size of memory in |pdf->mem| which |obj_outline_ptr| points to */
+/*tex The size of memory in |pdf->mem| which |obj_outline_ptr| points to: */
-#define obj_outline_count obj_info /* count of all opened children */
-#define obj_outline_ptr obj_aux /* pointer to |pdf->mem| */
+#define pdfmem_outline_size 8
+
+/*tex The count of all opened children: */
+
+#define obj_outline_count obj_info
+
+/*tex The pointer to |pdf->mem|: */
+
+#define obj_outline_ptr obj_aux
#define obj_outline_title(pdf,A) pdf->mem[obj_outline_ptr(pdf,A)]
#define obj_outline_parent(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 1]
@@ -38,7 +48,7 @@ outline entries in |pdf->mem| instead of |mem|
#define obj_outline_next(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 3]
#define obj_outline_first(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 4]
#define obj_outline_last(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 5]
-#define obj_outline_action_objnum(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 6] /* object number of action */
+#define obj_outline_action_objnum(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 6]
#define obj_outline_attr(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 7]
#define set_obj_outline_count(pdf,A,B) obj_outline_count(pdf,A)=B
@@ -52,7 +62,6 @@ outline entries in |pdf->mem| instead of |mem|
#define set_obj_outline_parent(pdf,A,B) obj_outline_parent(pdf,A)=B
#define set_obj_outline_attr(pdf,A,B) obj_outline_attr(pdf,A)=B
-@ @c
static int open_subentries(PDF pdf, halfword p)
{
int c, l, r;
@@ -78,9 +87,8 @@ static int open_subentries(PDF pdf, halfword p)
return k;
}
-@ return number of outline entries in the same level with |p|
+/*tex Return the number of outline entries in the same level with |p|: */
-@c
static int outline_list_count(PDF pdf, pointer p)
{
int k = 1;
@@ -91,7 +99,6 @@ static int outline_list_count(PDF pdf, pointer p)
return k;
}
-@ @c
void scan_pdfoutline(PDF pdf)
{
halfword q, r;
@@ -178,10 +185,13 @@ void scan_pdfoutline(PDF pdf)
}
}
-@ In the end we must flush PDF objects that cannot be written out immediately
-after shipping out pages.
+/*tex
+
+ In the end we must flush \PDF\F objects that cannot be written out
+ immediately after shipping out pages.
+
+*/
-@c
int print_outlines(PDF pdf)
{
int k, l, a;
@@ -206,8 +216,7 @@ int print_outlines(PDF pdf)
pdf_dict_add_int(pdf, "Count", k);
pdf_end_dict(pdf);
pdf_end_obj(pdf);
- /* Output PDF outline entries */
-
+ /*tex Output \PDF\ outline entries. */
k = pdf->head_tab[obj_type_outline];
while (k != 0) {
if (obj_outline_parent(pdf, k) == pdf->parent_outline) {
@@ -243,7 +252,6 @@ int print_outlines(PDF pdf)
pdf_end_obj(pdf);
k = obj_link(pdf, k);
}
-
} else {
outlines = 0;
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c
index ecc51ddfd63..211248a02d3 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c
@@ -1,23 +1,23 @@
-% pdfpage.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
+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"
@@ -26,7 +26,6 @@
#include <assert.h>
#include <math.h>
-@ @c
void init_pdf_pagecalculations(PDF pdf)
{
pdfstructure *p;
@@ -37,23 +36,30 @@ void init_pdf_pagecalculations(PDF pdf)
setpdffloat(p->pdf.h, 0, decimal_digits);
setpdffloat(p->pdf.v, 0, decimal_digits);
p->cw.e = 1;
- p->fs_cur.e = p->fs.e = (decimal_digits < 4 ? 5 : 6); /* "+ 2" makes less corrections inside []TJ */
- /* for placement outside BT...ET */
+ /*tex |+ 2| makes less corrections inside []TJ */
+ p->fs_cur.e = p->fs.e = (decimal_digits < 4 ? 5 : 6);
+ /*tex for placement outside BT...ET */
setpdffloat(p->cm[0], 1, 0);
setpdffloat(p->cm[1], 0, 0);
setpdffloat(p->cm[2], 0, 0);
setpdffloat(p->cm[3], 1, 0);
- setpdffloat(p->cm[4], 0, decimal_digits); /* horizontal movement on page */
- setpdffloat(p->cm[5], 0, decimal_digits); /* vertical movement on page */
- /* for placement inside BT...ET */
- setpdffloat(p->tm0_cur, 0, 6); /* mantissa holds HZ expand * ExtendFont */
- setpdffloat(p->tm[0], ten_pow[6], 6); /* mantissa holds HZ expand * ExtendFont */
+ /*tex horizontal movement on page */
+ setpdffloat(p->cm[4], 0, decimal_digits);
+ /*tex vertical movement on page */
+ setpdffloat(p->cm[5], 0, decimal_digits);
+ /*tex for placement inside BT...ET */
+ /*tex mantissa holds HZ expand * ExtendFont */
+ setpdffloat(p->tm0_cur, 0, 6);
+ /*tex mantissa holds HZ expand * ExtendFont */
+ setpdffloat(p->tm[0], ten_pow[6], 6);
setpdffloat(p->tm[1], 0, 0);
- setpdffloat(p->tm[2], 0, 3); /* mantissa holds SlantFont, 0 = default */
+ /*tex mantissa holds SlantFont, 0 = default */
+ setpdffloat(p->tm[2], 0, 3);
setpdffloat(p->tm[3], ten_pow[6], 6);
- setpdffloat(p->tm[4], 0, decimal_digits); /* mantissa holds delta from |pdf_bt_pos.h| */
- setpdffloat(p->tm[5], 0, decimal_digits); /* mantissa holds delta from |pdf_bt_pos.v| */
- /* */
+ /*tex mantissa holds delta from |pdf_bt_pos.h| */
+ setpdffloat(p->tm[4], 0, decimal_digits);
+ /*tex mantissa holds delta from |pdf_bt_pos.v| */
+ setpdffloat(p->tm[5], 0, decimal_digits);
p->f_pdf_cur = p->f_pdf = null_font;
p->fs_cur.m = p->fs.m = 0;
p->wmode = WMODE_H;
@@ -61,10 +67,11 @@ void init_pdf_pagecalculations(PDF pdf)
p->ishex = 0;
p->need_tf = false;
p->need_tm = false;
+ p->done_width = false;
+ p->done_mode = false;
p->k1 = ten_pow[p->pdf.h.e] / by_one_bp;
}
-@ @c
void synch_pos_with_cur(posstructure * pos, posstructure * refpos, scaledpos cur)
{
switch (pos->dir) {
@@ -93,7 +100,6 @@ void synch_pos_with_cur(posstructure * pos, posstructure * refpos, scaledpos cur
}
}
-@ @c
boolean calc_pdfpos(pdfstructure * p, scaledpos pos)
{
scaledpos new;
@@ -102,7 +108,8 @@ boolean calc_pdfpos(pdfstructure * p, scaledpos pos)
case PMODE_PAGE:
new.h = i64round(pos.h * p->k1);
new.v = i64round(pos.v * p->k1);
- p->cm[4].m = new.h - p->pdf.h.m; /* cm is concatenated */
+ /*tex cm is concatenated */
+ p->cm[4].m = new.h - p->pdf.h.m;
p->cm[5].m = new.v - p->pdf.v.m;
if (new.h != p->pdf.h.m || new.v != p->pdf.v.m)
move_pdfpos = true;
@@ -110,7 +117,8 @@ boolean calc_pdfpos(pdfstructure * p, scaledpos pos)
case PMODE_TEXT:
new.h = i64round(pos.h * p->k1);
new.v = i64round(pos.v * p->k1);
- p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* Tm replaces */
+ /*tex Tm replaces */
+ p->tm[4].m = new.h - p->pdf_bt_pos.h.m;
p->tm[5].m = new.v - p->pdf_bt_pos.v.m;
if (new.h != p->pdf.h.m || new.v != p->pdf.v.m)
move_pdfpos = true;
@@ -122,14 +130,16 @@ boolean calc_pdfpos(pdfstructure * p, scaledpos pos)
new.h = i64round((pos.h * p->k1 - (double) p->pdf_tj_pos.h.m) * p->k2);
new.v = i64round(pos.v * p->k1);
p->tj_delta.m = -i64round((double) ((new.h - p->cw.m) / ten_pow[p->cw.e - p->tj_delta.e]));
- p->tm[5].m = new.v - p->pdf_bt_pos.v.m; /* p->tm[4] is meaningless */
+ /*tex p->tm[4] is meaningless */
+ p->tm[5].m = new.v - p->pdf_bt_pos.v.m;
if (p->tj_delta.m != 0 || new.v != p->pdf.v.m)
move_pdfpos = true;
break;
case WMODE_V:
new.h = i64round(pos.h * p->k1);
new.v = i64round(((double) p->pdf_tj_pos.v.m - pos.v * p->k1) * p->k2);
- p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* p->tm[5] is meaningless */
+ /*tex p->tm[5] is meaningless */
+ p->tm[4].m = new.h - p->pdf_bt_pos.h.m;
p->tj_delta.m = -i64round((double) ((new.v - p->cw.m) / ten_pow[p->cw.e - p->tj_delta.e]));
if (p->tj_delta.m != 0 || new.h != p->pdf.h.m)
move_pdfpos = true;
@@ -145,7 +155,6 @@ boolean calc_pdfpos(pdfstructure * p, scaledpos pos)
return move_pdfpos;
}
-@ @c
void print_pdf_matrix(PDF pdf, pdffloat * tm)
{
int i;
@@ -156,14 +165,12 @@ void print_pdf_matrix(PDF pdf, pdffloat * tm)
print_pdffloat(pdf, tm[i]);
}
-@ @c
void pdf_print_cm(PDF pdf, pdffloat * cm)
{
print_pdf_matrix(pdf, cm);
pdf_puts(pdf, " cm\n");
}
-@ @c
void pdf_set_pos(PDF pdf, scaledpos pos)
{
boolean move;
@@ -178,7 +185,6 @@ void pdf_set_pos(PDF pdf, scaledpos pos)
}
}
-@ @c
void pdf_set_pos_temp(PDF pdf, scaledpos pos)
{
boolean move;
@@ -191,7 +197,6 @@ void pdf_set_pos_temp(PDF pdf, scaledpos pos)
}
}
-@ @c
static void begin_text(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
@@ -201,6 +206,8 @@ static void begin_text(PDF pdf)
pdf_puts(pdf, "BT\n");
p->mode = PMODE_TEXT;
p->need_tf = true;
+ p->need_width = 0;
+ p->need_mode = 0;
}
static void end_text(PDF pdf)
@@ -208,6 +215,16 @@ static void end_text(PDF pdf)
pdfstructure *p = pdf->pstruct;
if (!is_textmode(p))
normal_error("pdf backend","text mode expected in end_text");
+
+ if (p->done_width != 0) {
+ pdf_puts(pdf, "0 w\n");
+ p->done_width = 0;
+ }
+ if (p->done_mode != 0) {
+ pdf_puts(pdf, "0 Tr\n");
+ p->done_mode = 0;
+ }
+
pdf_puts(pdf, "ET\n");
p->pdf = p->pdf_bt_pos;
p->mode = PMODE_PAGE;
@@ -222,7 +239,6 @@ void pdf_end_string_nl(PDF pdf)
end_chararray(pdf);
}
-@ @c
void pdf_goto_pagemode(PDF pdf)
{
pdfstructure *p = pdf->pstruct;
@@ -245,7 +261,7 @@ void pdf_goto_textmode(PDF pdf)
0, 0
};
if (is_pagemode(p)) {
- /* reset to page origin */
+ /*tex Reset to the page origin: */
pdf_set_pos(pdf, origin);
begin_text(pdf);
} else if (!is_textmode(p)) {
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.w b/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.c
index 76d008c4359..4fcd48e341f 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfpagetree.c
@@ -1,38 +1,39 @@
-% pdfpagetree.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"
+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.
-@* Page diversions.
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
-@ @c
-# define PAGES_TREE_KIDSMAX 10
+*/
+
+#include "ptexlib.h"
+
+#define PAGES_TREE_KIDSMAX 10
static struct avl_table *divert_list_tree = NULL;
typedef struct pages_entry_ {
- int objnum; /* object number of this /Pages object */
- int number_of_pages; /* total number of all pages below */
- int number_of_kids; /* number of direct kid objects */
- int kids[PAGES_TREE_KIDSMAX]; /* array of kid object numbers */
+ /*tex The object number of this |/Pages| object. */
+ int objnum;
+ /*tex The total number of all pages below. */
+ int number_of_pages;
+ /*tex The number of direct kid objects. */
+ int number_of_kids;
+ /*tex The array of kid object numbers. */
+ int kids[PAGES_TREE_KIDSMAX];
struct pages_entry_ *next;
} pages_entry;
@@ -52,7 +53,6 @@ static int comp_divert_list_entry(const void *pa, const void *pb, void *p)
return 0;
}
-@ @c
static pages_entry *new_pages_entry(PDF pdf)
{
int i;
@@ -65,7 +65,6 @@ static pages_entry *new_pages_entry(PDF pdf)
return p;
}
-@ @c
static divert_list_entry *new_divert_list_entry(void)
{
divert_list_entry *d;
@@ -74,7 +73,6 @@ static divert_list_entry *new_divert_list_entry(void)
return d;
}
-@ @c
static void ensure_list_tree(void)
{
if (divert_list_tree == NULL) {
@@ -82,7 +80,6 @@ static void ensure_list_tree(void)
}
}
-@ @c
static divert_list_entry *get_divert_list(int divnum)
{
divert_list_entry *d, tmp;
@@ -92,7 +89,7 @@ static divert_list_entry *get_divert_list(int divnum)
if (d == NULL) {
d = new_divert_list_entry();
d->divnum = divnum;
- /* the next bit of code can actually be removed */
+ /*tex The next bit of code can actually be removed. */
aa = avl_probe(divert_list_tree, d);
if (aa==NULL) {
normal_error("pdf backend","page list lookup error");
@@ -101,18 +98,18 @@ static divert_list_entry *get_divert_list(int divnum)
return d;
}
-@ |pdf_do_page_divert()| returns the current /Parent object number
-@c
+/*tex |pdf_do_page_divert| returns the current |/Parent| object number. */
+
int pdf_do_page_divert(PDF pdf, int objnum, int divnum)
{
divert_list_entry *d;
pages_entry *p;
- /* initialize the tree */
+ /*tex Initialize the tree. */
ensure_list_tree();
- /* make sure we have a list for this diversion */
+ /*tex Make sure we have a list for this diversion. */
d = get_divert_list(divnum);
if (d->first == NULL || d->last->number_of_kids == PAGES_TREE_KIDSMAX) {
- /* append a new |pages_entry| */
+ /*tex Append a new |pages_entry|. */
p = new_pages_entry(pdf);
if (d->first == NULL)
d->first = p;
@@ -126,33 +123,32 @@ int pdf_do_page_divert(PDF pdf, int objnum, int divnum)
return p->objnum;
}
-@ @c
static void movelist(divert_list_entry * d, divert_list_entry * dto)
{
if (d != NULL && d->first != NULL && d->divnum != dto->divnum) {
- /* no undivert of empty list or into self */
+ /*tex No undivert of empty list or into self. */
if (dto->first == NULL)
dto->first = d->first;
else
dto->last->next = d->first;
dto->last = d->last;
- /* one could as well remove this |divert_list_entry| */
+ /*tex One could as well remove this |divert_list_entry|. */
d->first = d->last = NULL;
}
}
-@ undivert from diversion |divnum| into diversion |curdivnum|
-@c
+/*tex Undivert from diversion |divnum| into diversion |curdivnum|. */
+
void pdf_do_page_undivert(int divnum, int curdivnum)
{
divert_list_entry *d, *dto, tmp;
struct avl_traverser t;
- /* initialize the tree */
+ /*tex Initialize the tree. */
ensure_list_tree();
- /* find the diversion |curdivnum| list where diversion |divnum| should go */
+ /*tex Find the diversion |curdivnum| list where diversion |divnum| should go. */
dto = get_divert_list(curdivnum);
if (divnum == 0) {
- /* 0 = special case: undivert {\it all\/} lists */
+ /*tex Zero is a special case: undivert {\em all} lists. */
avl_t_init(&t, divert_list_tree);
for (d = avl_t_first(&t, divert_list_tree); d != NULL;
d = avl_t_next(&t))
@@ -164,10 +160,9 @@ void pdf_do_page_undivert(int divnum, int curdivnum)
}
}
-@ write a /Pages object
-@c
+/*tex Write a |/Pages| object. */
-static void write_pages(PDF pdf, pages_entry * p, int parent)
+static void write_pages(PDF pdf, pages_entry * p, int parent, int callback_id)
{
int i;
int pages_attributes ;
@@ -175,39 +170,57 @@ static void write_pages(PDF pdf, pages_entry * p, int parent)
pdf_begin_dict(pdf);
pdf_dict_add_name(pdf, "Type", "Pages");
if (parent == 0) {
- /* it's root */
- pages_attributes = pdf_pages_attr; /* lookup once */
+ /*tex It's root. Lookup the attributes once. */
+ pages_attributes = pdf_pages_attr;
if (pages_attributes != null) {
pdf_print_toks(pdf, pages_attributes);
pdf_out(pdf, ' ');
}
print_pdf_table_string(pdf, "pagesattributes");
pdf_out(pdf, ' ');
- } else
+ } else {
pdf_dict_add_ref(pdf, "Parent", parent);
+ }
pdf_dict_add_int(pdf, "Count", (int) p->number_of_pages);
pdf_add_name(pdf, "Kids");
pdf_begin_array(pdf);
- for (i = 0; i < p->number_of_kids; i++)
- pdf_add_ref(pdf, (int) p->kids[i]);
+ for (i = 0; i < p->number_of_kids; i++) {
+ if (callback_id) {
+ /* new */
+ int objnum = (int) p->kids[i];
+ if (obj_type(pdf, objnum) == obj_type_page) {
+ run_callback(callback_id, "d->d", objnum, &objnum);
+ check_obj_exists(pdf, objnum);
+ pdf_add_ref(pdf, (int) objnum);
+ } else {
+ pdf_add_ref(pdf, (int) p->kids[i]);
+ }
+ } else {
+ pdf_add_ref(pdf, (int) p->kids[i]);
+ }
+ }
pdf_end_array(pdf);
pdf_end_dict(pdf);
pdf_end_obj(pdf);
}
-@ loop over all /Pages objects, output them, create their parents,
-recursing bottom up, return the /Pages root object number
+/*tex
+
+ Loop over all |/Pages| objects, output them, create their parents, recursing
+ bottom up, return the |/Pages| root object number.
+
+*/
-@c
-static int output_pages_list(PDF pdf, pages_entry * pe)
+static int output_pages_list(PDF pdf, pages_entry * pe, int callback_id)
{
pages_entry *p, *q, *r;
if (pe->next == NULL) {
- /* everything fits into one |pages_entry| */
- write_pages(pdf, pe, 0); /* /Pages root found */
+ /*tex Everything fits into one |pages_entry|. */
+ write_pages(pdf, pe, 0, callback_id);
return pe->objnum;
}
- q = r = new_pages_entry(pdf); /* one level higher needed */
+ /*tex One level higher needed. */
+ q = r = new_pages_entry(pdf);
for (p = pe; p != NULL; p = p->next) {
if (q->number_of_kids == PAGES_TREE_KIDSMAX) {
q->next = new_pages_entry(pdf);
@@ -215,16 +228,19 @@ static int output_pages_list(PDF pdf, pages_entry * pe)
}
q->kids[q->number_of_kids++] = p->objnum;
q->number_of_pages += p->number_of_pages;
- write_pages(pdf, p, q->objnum);
+ write_pages(pdf, p, q->objnum, callback_id);
}
- return output_pages_list(pdf, r); /* recurse through next higher level */
+ /*tex Recurse through next higher level. */
+ return output_pages_list(pdf, r, callback_id);
}
-@ @c
int output_pages_tree(PDF pdf)
{
+ int callback_id = callback_defined(page_objnum_provider_callback);
divert_list_entry *d;
- pdf_do_page_undivert(0, 0); /* concatenate all diversions into diversion 0 */
- d = get_divert_list(0); /* get diversion 0 */
- return output_pages_list(pdf, d->first);
+ /*tex Concatenate all diversions into diversion 0. */
+ pdf_do_page_undivert(0, 0);
+ /*tex Get diversion 0. */
+ d = get_divert_list(0);
+ return output_pages_list(pdf, d->first, callback_id);
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.c
index df4979088c8..de689a1471f 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.c
@@ -1,29 +1,26 @@
-% pdfrule.w
-%
-% Copyright 2010-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 "pdf/pdfpage.h"
+Copyright 2010-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.
-@ @c
+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.
-/* maybe we should have an extra callback on normal rules or on any rule in 2.0+ */
+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 "pdf/pdfpage.h"
void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
{
@@ -31,7 +28,6 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
pdfstructure *p = pdf->pstruct;
scaledpos pos = pdf->posstruct->pos;
halfword s = subtype(q);
- /* (void) q; */
if (s >= math_over_rule && s <= math_radical_rule) {
if (callback_id == 0) {
s = normal_rule;
@@ -44,7 +40,7 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
} else if (s == image_rule) {
pdf_place_image(pdf,q);
} else if (s == empty_rule) {
- /* place nothing, only take space */
+ /*tex Place nothing, only take space. */
} else if (s == user_rule) {
if (callback_id != 0) {
pdf_goto_pagemode(pdf);
@@ -54,7 +50,7 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
pdf_puts(pdf, "\nQ\n");
}
} else {
- /* normal_rule or >= 100 being a leader rule */
+ /*tex |normal_rule| or >= 100 being a leader rule */
pdf_goto_pagemode(pdf);
dim.h.m = i64round(size.h * p->k1);
dim.h.e = p->pdf.h.e;
@@ -64,7 +60,7 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
if (size.v <= one_bp) {
pos.v += i64round(0.5 * size.v);
pdf_set_pos_temp(pdf, pos);
- pdf_puts(pdf, "[]0 d 0 J ");
+ pdf_puts(pdf, "[] 0 d 0 J ");
print_pdffloat(pdf, dim.v);
pdf_puts(pdf, " w 0 0 m ");
print_pdffloat(pdf, dim.h);
@@ -72,18 +68,32 @@ void pdf_place_rule(PDF pdf, halfword q, scaledpos size, int callback_id)
} else if (size.h <= one_bp) {
pos.h += i64round(0.5 * size.h);
pdf_set_pos_temp(pdf, pos);
- pdf_puts(pdf, "[]0 d 0 J ");
+ pdf_puts(pdf, "[] 0 d 0 J ");
print_pdffloat(pdf, dim.h);
pdf_puts(pdf, " w 0 0 m 0 ");
print_pdffloat(pdf, dim.v);
pdf_puts(pdf, " l S\n");
} else {
pdf_set_pos_temp(pdf, pos);
+ if (s == outline_rule) {
+ pdf_puts(pdf, "[] 0 d 0 J ");
+ if (rule_transform(q) > 0) {
+ pdfpos temp ;
+ temp.h.m = i64round(rule_transform(q) * p->k1);
+ temp.h.e = p->pdf.h.e;
+ print_pdffloat(pdf, temp.h);
+ pdf_puts(pdf, " w ");
+ }
+ }
pdf_puts(pdf, "0 0 ");
print_pdffloat(pdf, dim.h);
pdf_out(pdf, ' ');
print_pdffloat(pdf, dim.v);
- pdf_puts(pdf, " re f\n");
+ if (s == outline_rule) {
+ pdf_puts(pdf, " re S\n");
+ } else {
+ pdf_puts(pdf, " re f\n");
+ }
}
pdf_puts(pdf, "Q\n");
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.c
index 0d91de54496..abfb4814201 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.c
@@ -1,32 +1,30 @@
-% pdfsaverestore.w
-%
-% Copyright 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
+Copyright 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/>.
+
+*/
#include "ptexlib.h"
-@ @c
-pos_entry *pos_stack = 0; /* the stack */
-int pos_stack_size = 0; /* initially empty */
-int pos_stack_used = 0; /* used entries */
+pos_entry *pos_stack = 0;
+int pos_stack_size = 0;
+int pos_stack_used = 0;
-@ @c
static void checkpdfsave(scaledpos pos)
{
pos_entry *new_stack;
@@ -45,7 +43,6 @@ static void checkpdfsave(scaledpos pos)
pos_stack_used++;
}
-@ @c
static void checkpdfrestore(scaledpos pos)
{
scaledpos diff;
@@ -64,7 +61,6 @@ static void checkpdfrestore(scaledpos pos)
}
}
-@ @c
void pdf_out_save(PDF pdf, halfword p)
{
(void) p;
@@ -72,7 +68,6 @@ void pdf_out_save(PDF pdf, halfword p)
pdf_literal(pdf, 'q', set_origin, false);
}
-@ @c
void pdf_out_restore(PDF pdf, halfword p)
{
(void) p;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.c
index b107033b984..f19c1721d5d 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.c
@@ -1,34 +1,36 @@
-% pdfsetmatrix.w
-%
-% Copyright 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
+/*
+
+Copyright 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/>.
+
+*/
#include "ptexlib.h"
-@ stack for \.{\\pdfextension setmatrix}
+/*tex
+
+ We keep a stack for |pdfextension setmatrix|:
+
+*/
-@c
matrix_entry *matrix_stack = NULL;
int matrix_stack_size = 0;
int matrix_stack_used = 0;
-@ @c
boolean matrixused(void)
{
return matrix_stack_used > 0;
@@ -46,40 +48,40 @@ static void matrix_stack_room(void)
}
}
-@ \.{\\pdfextension setmatrix{a b c d}}
-
-|e| := pos.h
+/*tex
-|f| := pos.v
+ The matrix specification has four entries and gets translated to |e| being
+ |pos.h and |f| being pos.v. The current active matrix at the top of the
+ matrix stack is kept in |M_top|.
-|M_top|: current active matrix at the top of the matrix stack
+ The origin of \.{\\pdfextension setmatrix} is the current point. The
+ annotation coordinate system is the original page coordinate system. When
+ pdfTeX calculates annotation rectangles it does not take into account this
+ transformations, it uses the original coordinate system. To get the corrected
+ values, first we go back to the origin, perform the transformation and go
+ back:
-The origin of \.{\\pdfextension setmatrix} is the current point. The annotation
-coordinate system is the original page coordinate system. When pdfTeX calculates
-annotation rectangles it does not take into account this transformations, it uses
-the original coordinate system. To get the corrected values, first we go back to
-the origin, perform the transformation and go back:
+ \starttyping
+ ( 1 0 0 ) ( a b 0 ) ( 1 0 0 )
+ ( 0 1 0 ) x ( c d 0 ) x ( 0 1 0 ) x M\_top
+ ( -e -f 1 ) ( 0 0 1 ) ( e f 1 )
-{\obeylines\obeyspaces\tt
- ( 1 0 0 ) ( a b 0 ) ( 1 0 0 )
- ( 0 1 0 ) x ( c d 0 ) x ( 0 1 0 ) x M\_top
- ( -e -f 1 ) ( 0 0 1 ) ( e f 1 )
+ ( 1 0 0 ) ( a b 0 )
+ = ( 0 1 0 ) x ( c d 0 ) x M\_top
+ ( e f 1 ) ( -e -f 1 )
- ( 1 0 0 ) ( a b 0 )
- = ( 0 1 0 ) x ( c d 0 ) x M\_top
- ( e f 1 ) ( -e -f 1 )
+ ( a b 0 )
+ = ( c d 0 ) x M\_top
+ ( e(1-a)-fc f(1-d)-eb 1 )
+ \stoptyping
- ( a b 0 )
- = ( c d 0 ) x M\_top
- ( e(1-a)-fc f(1-d)-eb 1 )
-}
+*/
-@c
static void pdfsetmatrix(const char *in, scaledpos pos)
{
- /*
- Argument of \.{\\pdfextension setmatrix} starts with |str_pool[in]| and ends
- before |str_pool[pool_ptr]|.
+ /*tex
+ The argument of |pdfextension setmatrix| starts with |str_pool[in]|
+ and ends before |str_pool[pool_ptr]|.
*/
matrix_entry x, *y, *z;
if (global_shipping_mode == SHIPPING_PAGE) {
@@ -87,7 +89,7 @@ static void pdfsetmatrix(const char *in, scaledpos pos)
formatted_warning("pdf backend","unrecognized format of setmatrix: %s", in);
return;
}
- /* calculate this transformation matrix */
+ /*tex Calculate this transformation matrix. */
x.e = (double) pos.h * (1.0 - x.a) - (double) pos.v * x.c;
x.f = (double) pos.v * (1.0 - x.d) - (double) pos.h * x.b;
matrix_stack_room();
@@ -112,19 +114,21 @@ static void pdfsetmatrix(const char *in, scaledpos pos)
}
}
-@ Apply matrix to point (x,y)
+/*tex
-{\obeylines\obeyspaces\tt
- ( a b 0 )
- ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 )
- ( e f 1 )
-}
+ Apply matrix to point (x,y)
+
+ \starttyping
+ ( a b 0 )
+ ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 )
+ ( e f 1 )
+ \stoptyping
-If \.{\\pdfextension setmatrix} wasn't used, then return the value unchanged.
+ If \.{\\pdfextension setmatrix} wasn't used, then return the value unchanged.
+ The return values for matrix tranform functions are:
-@ Return values for matrix tranform functions:
+*/
-@c
static scaled ret_llx;
static scaled ret_lly;
static scaled ret_urx;
@@ -150,7 +154,6 @@ scaled getury(void)
return ret_ury;
}
-@ @c
static int last_llx;
static int last_lly;
static int last_urx;
@@ -210,11 +213,10 @@ void matrixrecalculate(scaled urx)
matrixtransformrect(last_llx, last_lly, urx, last_ury);
}
-@ @c
void pdf_out_setmatrix(PDF pdf, halfword p)
{
scaledpos pos = pdf->posstruct->pos;
- int old_setting; /* holds print |selector| */
+ int old_setting;
str_number s;
old_setting = selector;
selector = new_string;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.c
index 8665f685e1f..084efc08626 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.c
@@ -1,51 +1,55 @@
-% pdfshipout.w
-%
-% Copyright 2010-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
+Copyright 2010-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"
-@ @c
scaledpos shipbox_refpos;
-@ |ship_out| is used to shipout a box to PDF or DVI mode. If |shipping_mode| is
-set to |SHIPPING_FORM| then the output will be a Form object (only PDF), and if
-it is set to |SHIPPING_PAGE| it will be a Page object.
+/*tex
+
+ |ship_out| is used to shipout a box to PDF or DVI mode. If |shipping_mode| is
+ set to |SHIPPING_FORM| then the output will be a |Form| object (only PDF), and
+ if it is set to |SHIPPING_PAGE| it will be a |Page| object.
+
+*/
-@c
void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
{
- int j, k; /* indices to first ten count registers */
+ /*tex Indices to first ten count registers: */
+ int j, k;
int post_callback_id;
int pre_callback_id;
- posstructure refpoint; /* the origin pos. on the page */
+ /*tex The origin position on the page: */
+ posstructure refpoint;
int rule_callback_id = 0;
scaledpos cur = { 0, 0 };
refpoint.pos.h = 0;
refpoint.pos.v = 0;
ensure_output_state(pdf, ST_HEADER_WRITTEN);
- fix_o_mode(); /* this is only for complaining if \.{\\outputmode} has changed */
- init_backend_functionpointers(output_mode_used);
+ /*tex This is only for complaining if \.{\\outputmode} has changed: */
+ fix_o_mode();
pdf->f_cur = null_font;
- /*
- Start sheet {\sl Sync\TeX} information record; we assume that |pdf_output| is
- properly set up.
+ /*tex
+ Start sheet {\sl Sync\TeX} information record. We assume that
+ |pdf_output| is properly set up.
*/
if (synctex_par) {
if (output_mode_used == OMODE_DVI) {
@@ -82,16 +86,18 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
}
}
if ((tracing_output_par > 0) && shipping_mode == SHIPPING_PAGE) {
- print_char(']');
+ if (pre_callback_id == 0) {
+ print_char(']');
+ }
update_terminal();
begin_diagnostic();
show_box(p);
end_diagnostic(true);
}
- /* Ship box |p| out */
+ /*tex Ship out box |p|:*/
if (shipping_mode == SHIPPING_PAGE && box_dir(p) != page_direction_par)
normal_warning("backend","pagedir differs from bodydir, the output may be placed wrongly on the page");
- /*
+ /*tex
Update the values of |max_h| and |max_v|; but if the page is too large,
|goto done|. Sometimes the user will generate a huge page because other
error messages are being ignored. Such pages are not output to the
@@ -116,7 +122,7 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
max_v = height(p) + depth(p) + v_offset_par;
if (width(p) + h_offset_par > max_h)
max_h = width(p) + h_offset_par;
- /* Calculate page dimensions and margins */
+ /*tex Calculate page dimensions and margins. */
if (global_shipping_mode == SHIPPING_PAGE) {
if (page_width_par > 0)
pdf->page_size.h = page_width_par;
@@ -156,28 +162,14 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
normal_warning("pdf backend","bad page direction, assuming TLT, case 2");
}
}
- /*
+ /*tex
Think in upright page/paper coordinates (page origin = lower left edge).
First preset |refpoint.pos| to the DVI origin (near upper left page edge).
*/
- switch (output_mode_used) {
- case OMODE_DVI:
- /* hh: how can we end up here? */
- refpoint.pos.h = one_true_inch;
- refpoint.pos.v = pdf->page_size.v - one_true_inch;
- dvi = refpoint.pos;
- break;
- case OMODE_PDF:
- refpoint.pos.h = pdf_h_origin;
- refpoint.pos.v = pdf->page_size.v - pdf_v_origin;
- break;
- default:
- normal_error("pdf backend", "unknown output mode");
- }
-
- /*
+ backend_out_control[backend_control_set_reference_point](pdf,&refpoint);
+ /*tex
Then shift |refpoint.pos| of the DVI origin depending on the
- |page_direction| within the upright (TLT) page coordinate system
+ |page_direction| within the upright (TLT) page coordinate system.
*/
switch (page_direction_par) {
case dir_TLT:
@@ -195,7 +187,7 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
refpoint.pos.v -= v_offset_par;
normal_warning("pdf backend","bad page direction, assuming TLT, case 3");
}
- /*
+ /*tex
Then switch to page box coordinate system; do |height(p)| movement,
to get the location of the box origin.
*/
@@ -204,7 +196,7 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
cur.v = height(p);
synch_pos_with_cur(pdf->posstruct, &refpoint, cur);
} else {
- /* shipping a /Form */
+ /*tex We're shipping out a |/Form|. */
pdf->posstruct->dir = box_dir(p);
switch (pdf->posstruct->dir) {
case dir_TLT:
@@ -245,18 +237,12 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
normal_warning("pdf backend","bad page direction, assuming TLT, case 5");
}
}
- /* Now we are at the point on the page where the origin of the page box should go. */
- shipbox_refpos = pdf->posstruct->pos; /* for \.{\\gleaders} */
- switch (output_mode_used) {
- case OMODE_DVI:
- dvi_begin_page(pdf);
- break;
- case OMODE_PDF:
- pdf_begin_page(pdf);
- break;
- default:
- normal_error("pdf backend", "unknown output mode");
- }
+ /*tex
+ Now we are at the point on the page where the origin of the page box
+ should go. First we register the poisition for \.{\\gleaders}.
+ */
+ shipbox_refpos = pdf->posstruct->pos;
+ backend_out_control[backend_control_begin_page](pdf);
rule_callback_id = callback_defined(process_rule_callback);
switch (type(p)) {
case vlist_node:
@@ -271,24 +257,15 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
if (shipping_mode == SHIPPING_PAGE)
total_pages++;
cur_s = -1;
- /* Finish shipping */
- switch (output_mode_used) {
- case OMODE_DVI:
- dvi_end_page(pdf);
- break;
- case OMODE_PDF:
- pdf_end_page(pdf);
- break;
- default:
- normal_error("pdf backend", "unknown output mode");
- }
+ /*tex Finish shipping */
+ backend_out_control[backend_control_end_page](pdf);
DONE:
if ((tracing_output_par <= 0) && (post_callback_id == 0) && shipping_mode == SHIPPING_PAGE) {
print_char(']');
update_terminal();
}
dead_cycles = 0;
- /* Flush the box from memory, showing statistics if requested */
+ /*tex Flush the box from memory, showing statistics if requested. */
if ((tracing_stats_par > 1) && (pre_callback_id == 0)) {
tprint_nl("Memory usage before: ");
print_int(var_used);
@@ -306,7 +283,7 @@ void ship_out(PDF pdf, halfword p, shipping_mode_e shipping_mode)
}
if (shipping_mode == SHIPPING_PAGE && (post_callback_id > 0))
(void) run_callback(post_callback_id, "->");
- /* Finish sheet {\sl Sync\TeX} information record */
+ /*tex Finish sheet {\sl Sync\TeX} information record. */
if (synctex_par)
synctexteehs();
global_shipping_mode = NOT_SHIPPING;
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdftables.w b/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
index 31fc2c9ad4e..180c232341d 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdftables.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdftables.c
@@ -1,27 +1,26 @@
-% pdftables.w
-%
-% Copyright 2009-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
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ @c
const char *pdf_obj_typenames[PDF_OBJ_TYPE_MAX + 1] = {
"font", "outline", "dest", "obj", "xform", "ximage", "thread",
"pagestream", "page", "pages", "catalog", "info", "link", "annot", "annots",
@@ -31,21 +30,26 @@ const char *pdf_obj_typenames[PDF_OBJ_TYPE_MAX + 1] = {
int pdf_last_annot;
int pdf_last_link;
int pdf_last_obj;
-int pdf_retval; /* global multi-purpose return value */
-int pdf_cur_form; /* the form being output */
+int pdf_retval;
+int pdf_cur_form;
+
+/*tex
+
+ AVL sort entry into |avl_table[]|.
+*/
-@ AVL sort entry into |avl_table[]|
-@c
static int compare_info(const void *pa, const void *pb, void *param)
{
const oentry *a = (const oentry *) pa;
const oentry *b = (const oentry *) pb;
(void) param;
if (a->u_type == b->u_type) {
- if (a->u_type == union_type_int)
+ if (a->u_type == union_type_int) {
return ((a->u.int0 < b->u.int0 ? -1 : (a->u.int0 > b->u.int0 ? 1 : 0)));
- else /* string type */
+ } else {
+ /*tex String type: */
return strcmp(a->u.str0, b->u.str0);
+ }
} else if (a->u_type == union_type_int) {
return -1;
} else {
@@ -78,7 +82,8 @@ static void avl_put_int_obj(PDF pdf, int int0, int objptr, int t)
static void avl_put_str_obj(PDF pdf, char *str0, int objptr, int t)
{
oentry *oe = xtalloc(1, oentry);
- oe->u.str0 = str0; /* no xstrdup() here */
+ /*tex No |xstrdup| here! */
+ oe->u.str0 = str0;
oe->u_type = union_type_cstring;
oe->objptr = objptr;
avl_put_obj(pdf, t, oe);
@@ -112,9 +117,8 @@ static int avl_find_str_obj(PDF pdf, int t, char *s)
return p->objptr;
}
-@ Create an object with type |t| and identifier |i|
+/*tex Create an object with type |t| and identifier |i|: */
-@c
int pdf_create_obj(PDF pdf, int t, int i)
{
int a;
@@ -148,7 +152,6 @@ int pdf_create_obj(PDF pdf, int t, int i)
return pdf->obj_ptr;
}
-@ @c
int find_obj(PDF pdf, int t, int i, boolean byname)
{
char *ss = NULL;
@@ -163,14 +166,17 @@ int find_obj(PDF pdf, int t, int i, boolean byname)
return ret;
}
-@ The following function finds an object with identifier |i| and type |t|.
-Identifier |i| is either an integer or a token list index. If no such object
-exists then it will be created. This function is used mainly to find destination
-for link annotations and outlines; however it is also used in |ship_out| (to
-check whether a Page object already exists) so we need to declare it together
-with subroutines needed in |hlist_out| and |vlist_out|.
+/*tex
+
+ The following function finds an object with identifier |i| and type |t|.
+ Identifier |i| is either an integer or a token list index. If no such object
+ exists then it will be created. This function is used mainly to find
+ destination for link annotations and outlines; however it is also used in
+ |ship_out| (to check whether a Page object already exists) so we need to
+ declare it together with subroutines needed in |hlist_out| and |vlist_out|.
+
+*/
-@c
int pdf_get_obj(PDF pdf, int t, int i, boolean byname)
{
int r;
@@ -197,8 +203,8 @@ int pdf_get_obj(PDF pdf, int t, int i, boolean byname)
return r;
}
-@ object checking
-@c
+/*tex Some object checking: */
+
void check_obj_exists(PDF pdf, int objnum)
{
if (objnum < 0 || objnum > pdf->obj_ptr)
@@ -216,14 +222,15 @@ void check_obj_type(PDF pdf, int t, int objnum)
}
}
-@ @c
void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, scaled_whd alt_rule, scaled margin)
{
- scaledpos ll, ur; /* positions relative to cur */
+ /*tex The positions relative to cur: */
+ scaledpos ll, ur;
scaledpos pos_ll, pos_ur, tmp;
posstructure localpos;
localpos.dir = pdf->posstruct->dir;
- ll.h = 0; /* pdf contains current point on page */
+ /*tex |pdf| contains current point on page: */
+ ll.h = 0;
if (is_running(alt_rule.dp))
ll.v = depth(parent_box) - cur.v;
else
@@ -263,7 +270,6 @@ void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, scaledpos cur, sc
pdf_ann_top(p) = pos_ur.v + margin;
}
-@ @c
void libpdffinish(PDF pdf)
{
strbuf_free(pdf->fb);
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
index 6b3dd4b9432..20cc7bf0a45 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.c
@@ -1,28 +1,32 @@
-% pdfthread.w
-%
-% Copyright 2009-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
+Copyright 2009-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"
-@ Threads are handled in similar way as link annotations
-@c
+/*tex
+
+ Threads are handled in similar way as link annotations.
+
+*/
+
void append_bead(PDF pdf, halfword p)
{
int a, b, c, t;
@@ -52,7 +56,6 @@ void append_bead(PDF pdf, halfword p)
addto_page_resources(pdf, obj_type_bead, b);
}
-@ @c
void do_thread(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
{
scaled_whd alt_rule;
@@ -78,7 +81,6 @@ void do_thread(PDF pdf, halfword p, halfword parent_box, scaledpos cur)
pdf->last_thread = p;
}
-@ @c
void append_thread(PDF pdf, halfword parent_box, scaledpos cur)
{
scaled_whd alt_rule;
@@ -102,7 +104,6 @@ void append_thread(PDF pdf, halfword parent_box, scaledpos cur)
pdf->last_thread = p;
}
-@ @c
void end_thread(PDF pdf, halfword p)
{
scaledpos pos = pdf->posstruct->pos;
@@ -131,8 +132,8 @@ void end_thread(PDF pdf, halfword p)
pdf->last_thread = null;
}
-@ The following function are needed for outputing article thread.
-@c
+/*tex The following function are needed for outputing article thread. */
+
void thread_title(PDF pdf, int t)
{
pdf_add_name(pdf, "Title");
@@ -224,7 +225,6 @@ void out_thread(PDF pdf, int t)
} while (a != b);
}
-@ @c
void scan_thread_id(void)
{
if (scan_keyword("num")) {
@@ -251,7 +251,6 @@ void check_running_thread(PDF pdf, halfword this_box, scaledpos cur)
append_thread(pdf, this_box, cur);
}
-@ @c
void print_bead_rectangles(PDF pdf)
{
halfword i;
@@ -262,13 +261,15 @@ void print_bead_rectangles(PDF pdf)
l = pdf_create_obj(pdf, obj_type_others, 0);
pdf_begin_obj(pdf, l, OBJSTM_ALWAYS);
pdf_begin_array(pdf);
- i = obj_bead_data(pdf, k->info); /* pointer to a whatsit or whatsit-like node */
+ /*tex A pointer to a whatsit or whatsit-like node: */
+ i = obj_bead_data(pdf, k->info);
pdf_add_rect_spec(pdf, i);
if (subtype(i) == pdf_thread_data_node)
flush_node(i);
pdf_end_array(pdf);
pdf_end_obj(pdf);
- set_obj_bead_rect(pdf, k->info, l); /* rewrite |obj_bead_data| */
+ /*tex Rewrite |obj_bead_data|: */
+ set_obj_bead_rect(pdf, k->info, l);
k = k->link;
}
}
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.c
index 731dc229080..7fd4eef1d82 100644
--- a/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w
+++ b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.c
@@ -1,28 +1,30 @@
-% pdfxform.w
-%
-% Copyright 2009-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/>.
+/*
+
+Copyright 2009-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 "pdf/pdfpage.h"
-@ @c
-int pdf_cur_form; /* the form being output */
+/*tex The form being output: */
+
+int pdf_cur_form;
void pdf_place_form(PDF pdf, halfword p)
{
@@ -35,7 +37,7 @@ void pdf_place_form(PDF pdf, halfword p)
nat.wd = obj_xform_width(pdf, objnum);
nat.ht = obj_xform_height(pdf, objnum);
nat.dp = obj_xform_depth(pdf, objnum);
- /* no transform yet */
+ /*tex No transform yet: */
tex.wd = width(p);
tex.ht = height(p);
tex.dp = depth(p);
@@ -60,9 +62,8 @@ void pdf_place_form(PDF pdf, halfword p)
addto_page_resources(pdf, obj_type_xform, objnum);
}
-/* we will store token lists as strings too */
+/*tex We will store token lists as strings too. */
-@ @c
void scan_pdfxform(PDF pdf)
{
int k;
@@ -100,7 +101,8 @@ void scan_pdfxform(PDF pdf)
p = box(cur_val);
if (p == null)
normal_error("pdf backend", "xforms cannot be used with a void box");
- set_obj_xform_box(pdf, k, p); /* save pointer to the box */
+ /*tex Save the pointer to the box: */
+ set_obj_xform_box(pdf, k, p);
set_obj_xform_width(pdf, k, width(p));
set_obj_xform_height(pdf, k, height(p));
set_obj_xform_depth(pdf, k, depth(p));
@@ -108,11 +110,10 @@ void scan_pdfxform(PDF pdf)
last_saved_box_index = k;
}
-@ @c
void scan_pdfrefxform(PDF pdf)
{
scaled_whd alt_rule, dim, nat;
- alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */
+ alt_rule = scan_alt_rule();
scan_int();
check_obj_type(pdf, obj_type_xform, cur_val);
tail_append(new_rule(box_rule));
diff --git a/Build/source/texk/web2c/luatexdir/tex/align.c b/Build/source/texk/web2c/luatexdir/tex/align.c
new file mode 100644
index 00000000000..b2384cc6290
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/align.c
@@ -0,0 +1,1297 @@
+/*
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+void fin_align(void);
+void init_row(void);
+void init_col(void);
+
+#define noDEBUG
+
+/*tex
+
+ It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
+ they cut across so many of the control structures of \TeX. Therefore the
+ present page is probably not the best place for a beginner to start reading
+ this program; it is better to master everything else first.
+
+ Let us focus our thoughts on an example of what the input might be, in order
+ to get some idea about how the alignment miracle happens. The example doesn't
+ do anything useful, but it is sufficiently general to indicate all of the
+ special cases that must be dealt with; please do not be disturbed by its
+ apparent complexity and meaninglessness.
+
+ \starttyping
+ \tabskip 2pt plus 3pt
+ \halign to 300pt{u1#v1&
+ \hskip 50pt \tabskip 1pt plus 1fil u2#v2&
+ \hskip 50pt u3#v3\cr
+ \hskip 25pt a1&\omit a2&\vrule\cr
+ \hskip 25pt \noalign\{\vskip 3pt}
+ \hskip 25pt b1\span b2\cr
+ \hskip 25pt \omit&c2\span\omit\cr}
+ \stoptyping
+
+ Here's what happens:
+
+ \startitemize
+
+ \startitem
+ When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
+ places the 300pt dimension onto the |save_stack|, and an
+ |align_group| code is placed above it. This will make it possible to
+ complete the alignment when the matching `\.\}' is found.
+ \stopitem
+
+ \startitem
+ The preamble is scanned next. Macros in the preamble are not
+ expanded, except as part of a tabskip specification. For example, if
+ \.{u2} had been a macro in the preamble above, it would have been
+ expanded, since \TeX\ must look for `\.{minus...}' as part of the
+ tabskip glue. A ``preamble list'' is constructed based on the user's
+ preamble; in our case it contains the following seven items:
+
+ \starttabulate
+ \NC \type{\glue 2pt plus 3pt} \NC the tabskip preceding column 1 \NC \NR
+ \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 1 \NC \NR
+ \NC \type{\glue 2pt plus 3pt} \NC the tabskip between columns 1 and 2 \NC \NR
+ \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 2 \NC \NR
+ \NC \type{\glue 1pt plus 1fil} \NC the tabskip between columns 2 and 3 \NC \NR
+ \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 3 \NC \NR
+ \NC \type{\glue 1pt plus 1fil} \NC the tabskip following column 3 \NC \NR
+ \stoptabulate
+
+ These ``alignrecord'' entries have the same size as an |unset_node|,
+ since they will later be converted into such nodes. These alignrecord
+ nodes have no |depth| field; this is split into |u_part| and
+ |v_part|, and they point to token lists for the templates of the
+ alignment. For example, the |u_part| field in the first alignrecord
+ points to the token list `\.{u1}', i.e., the template preceding the
+ `\.\#' for column~1. Furthermore, They have a |span_ptr| instead of a
+ |node_attr| field, and these |span_ptr| fields are initially set to
+ the value |end_span|, for reasons explained below.
+ \stopitem
+
+ \startitem
+ \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
+ It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back
+ to be read again, and the template `\.{u1}' is fed to the scanner.
+ Just before reading `\.{u1}', \TeX\ goes into restricted horizontal
+ mode. Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then
+ (when the {\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans
+ an |endv| token, indicating the end of a column. At this point an
+ |unset_node| is created, containing the contents of the current hlist
+ (i.e., `\.{u1a1v1}'). The natural width of this unset node replaces
+ the |width| field of the alignrecord for column~1; in general, the
+ alignrecords will record the maximum natural width that has occurred
+ so far in a given column.
+ \stopitem
+
+ \startitem
+ Since `\.{\\omit}' follows the `\.\&', the templates for column~2 are
+ now bypassed. Again \TeX\ goes into restricted horizontal mode and
+ makes an |unset_node| from the resulting hlist; but this time the
+ hlist contains simply `\.{a2}'. The natural width of the new unset
+ box is remembered in the |width| field of the alignrecord for
+ column~2.
+ \stopitem
+
+ \startitem
+ A third |unset_node| is created for column 3, using essentially the
+ mechanism that worked for column~1; this unset box contains
+ `\.{u3\\vrule v3}'. The vertical rule in this case has running
+ dimensions that will later extend to the height and depth of the
+ whole first row, since each |unset_node| in a row will eventually
+ inherit the height and depth of its enclosing box.
+ \stopitem
+
+ \startitem
+ The first row has now ended; it is made into a single unset box
+ comprising the following seven items:
+
+ \starttyping
+ \glue 2pt plus 3pt
+ \unsetbox for 1 column: u1a1v1
+ \glue 2pt plus 3pt
+ \unsetbox for 1 column: a2
+ \glue 1pt plus 1fil
+ \unsetbox for 1 column: u3\vrule v3
+ \glue 1pt plus 1fil
+ \stoptyping
+
+ The width of this unset row is unimportant, but it has the correct
+ height and depth, so the correct baselineskip glue will be computed
+ as the row is inserted into a vertical list.
+ \stopitem
+
+ \startitem
+ Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
+ additional material (in this case \.{\\vskip 3pt}) to the vertical
+ list. While processing this material, \TeX\ will be in internal
+ vertical mode, and |no_align_group| will be on |save_stack|.
+ \stopitem
+
+ \startitem
+ The next row produces an unset box that looks like this:
+
+ \starttyping
+ \glue 2pt plus 3pt
+ \unsetbox for 2 columns: u1b1v1u2b2v2
+ \glue 1pt plus 1fil
+ \unsetbox for 1 column: {(empty)}
+ \glue 1pt plus 1fil
+ \stoptyping
+
+ The natural width of the unset box that spans columns 1~and~2 is
+ stored in a ``span node,'' which we will explain later; the
+ |span_ptr| field of the alignrecord for column~1 now points to the
+ new span node, and the |span_ptr| of the span node points to
+ |end_span|.
+ \stopitem
+
+ \startitem
+
+ The final row produces the unset box
+
+ \starttyping
+ \glue 2pt plus 3pt\cr
+ \unsetbox for 1 column: {(empty)}
+ \glue 2pt plus 3pt\cr
+ \unsetbox for 2 columns: u2c2v2
+ \glue 1pt plus 1fil
+ \stoptyping
+
+ A new span node is attached to the alignrecord for column 2.
+ \stopitem
+
+ \startitem
+ The last step is to compute the true column widths and to change all
+ the unset boxes to hboxes, appending the whole works to the vertical
+ list that encloses the \.{\\halign}. The rules for deciding on the
+ final widths of each unset column box will be explained below.
+ \stopitem
+
+ \stopitemize
+
+ Note that as \.{\\halign} is being processed, we fearlessly give up control
+ to the rest of \TeX. At critical junctures, an alignment routine is called
+ upon to step in and do some little action, but most of the time these
+ routines just lurk in the background. It's something like post-hypnotic
+ suggestion.
+
+ We have mentioned that alignrecords contain no |height| or |depth| fields.
+ Their |glue_sign| and |glue_order| are pre-empted as well, since it is
+ necessary to store information about what to do when a template ends. This
+ information is called the |extra_info| field.
+
+*/
+
+/*tex The pointer to \<u_j> token list: */
+
+#define u_part(A) vlink((A)+depth_offset)
+
+/*tex The pointer to \<v_j> token list */
+
+#define v_part(A) vinfo((A)+depth_offset)
+
+/*tex A column spanning list */
+
+#define span_ptr(A) vinfo((A)+1)
+
+/*tex Info to remember during template */
+
+#define extra_info(A) vinfo((A)+list_offset)
+
+/*tex
+
+ Alignments can occur within alignments, so a small stack is used to access
+ the alignrecord information. At each level we have a |preamble| pointer,
+ indicating the beginning of the preamble list; a |cur_align| pointer,
+ indicating the current position in the preamble list; a |cur_span| pointer,
+ indicating the value of |cur_align| at the beginning of a sequence of spanned
+ columns; a |cur_loop| pointer, indicating the tabskip glue before an
+ alignrecord that should be copied next if the current list is extended; and
+ the |align_state| variable, which indicates the nesting of braces so that
+ \.{\\cr} and \.{\\span} and tab marks are properly intercepted. There also
+ are pointers |cur_head| and |cur_tail| to the head and tail of a list of
+ adjustments being moved out from horizontal mode to vertical~mode, and alike
+ |cur_pre_head| and |cur_pre_tail| for pre-adjust lists.
+
+ The current values of these nine quantities appear in global variables; when
+ they have to be pushed down, they are stored in 6-word nodes, and |align_ptr|
+ points to the topmost such node.
+
+*/
+
+/*tex This could be in |texnodes.h| but it's documented here. */
+
+/*tex The current preamble list: */
+
+#define preamble vlink(align_head)
+
+/*tex The current position in the preamble list: */
+
+pointer cur_align = null;
+
+/*tex The start of the currently spanned columns in the preamble list: */
+
+pointer cur_span = null;
+
+/*tex A place to copy when extending a periodic preamble: */
+
+pointer cur_loop = null;
+
+/*tex The most recently pushed-down alignment stack node: */
+
+pointer align_ptr = null;
+
+/*tex Adjustment list pointers: */
+
+pointer cur_head = null, cur_tail = null;
+
+/*tex Pre-adjustment list pointers: */
+
+pointer cur_pre_head = null, cur_pre_tail = null;
+
+/*tex
+
+ The |align_state| and |preamble| variables are initialized elsewhere.
+
+ Alignment stack maintenance is handled by a pair of trivial routines called
+ |push_alignment| and |pop_alignment|.
+
+ (HH:) It makes not much sense to add support for an \.{attr} keyword to
+ \.{\\halign} and \.{\\valign} because then we need to decide if we tag rows
+ or cells or both or come up with \.{cellattr} and \.{rowattr} and such. But
+ then it even makes sense to have explicit commands (in addition to the
+ seperator) to tags individual cells. Too muss hassle for now and the
+ advantages are not that large.
+
+*/
+
+static void push_alignment(void)
+{
+ /*tex The new alignment stack node: */
+ pointer p;
+ p = new_node(align_stack_node, 0);
+ vinfo(p + 1) = align_ptr;
+ vlink(p + 1) = cur_align;
+ vinfo(p + 2) = preamble;
+ vlink(p + 2) = cur_span;
+ vinfo(p + 3) = cur_loop;
+ vlink(p + 3) = align_state;
+ vinfo(p + 4) = cur_head;
+ vlink(p + 4) = cur_tail;
+ vinfo(p + 5) = cur_pre_head;
+ vlink(p + 5) = cur_pre_tail;
+ align_ptr = p;
+ cur_head = new_node(temp_node, 0);
+ cur_pre_head = new_node(temp_node, 0);
+}
+
+static void pop_alignment(void)
+{
+ /*tex The top alignment stack node: */
+ pointer p;
+ flush_node(cur_head);
+ flush_node(cur_pre_head);
+ p = align_ptr;
+ cur_pre_tail = vlink(p + 5);
+ cur_pre_head = vinfo(p + 5);
+ cur_tail = vlink(p + 4);
+ cur_head = vinfo(p + 4);
+ align_state = vlink(p + 3);
+ cur_loop = vinfo(p + 3);
+ cur_span = vlink(p + 2);
+ preamble = vinfo(p + 2);
+ cur_align = vlink(p + 1);
+ align_ptr = vinfo(p + 1);
+ flush_node(p);
+}
+
+/*tex
+
+ \TeX\ has eight procedures that govern alignments: |init_align| and
+ |fin_align| are used at the very beginning and the very end; |init_row| and
+ |fin_row| are used at the beginning and end of individual rows; |init_span|
+ is used at the beginning of a sequence of spanned columns (possibly involving
+ only one column); |init_col| and |fin_col| are used at the beginning and end
+ of individual columns; and |align_peek| is used after \.{\\cr} to see whether
+ the next item is \.{\\noalign}.
+
+ We shall consider these routines in the order they are first used during the
+ course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
+ |init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
+
+ The preamble is copied directly, except that \.{\\tabskip} causes a change to
+ the tabskip glue, thereby possibly expanding macros that immediately follow
+ it. An appearance of \.{\\span} also causes such an expansion.
+
+ Note that if the preamble contains `\.{\\global\\tabskip}', the
+ `\.{\\global}' token survives in the preamble and the `\.{\\tabskip}' defines
+ new tabskip glue (locally).
+
+*/
+
+static void get_preamble_token(void)
+{
+ RESTART:
+ get_token();
+ while ((cur_chr == span_code) && (cur_cmd == tab_mark_cmd)) {
+ /*tex This token will be expanded once. */
+ get_token();
+ if (cur_cmd > max_command_cmd) {
+ expand();
+ get_token();
+ }
+ }
+ if (cur_cmd == endv_cmd)
+ fatal_error("(interwoven alignment preambles are not allowed)");
+ if ((cur_cmd == assign_glue_cmd)
+ && (cur_chr == glue_base + tab_skip_code)) {
+ scan_optional_equals();
+ scan_glue(glue_val_level);
+ if (global_defs_par > 0)
+ geq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
+ else
+ eq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
+ goto RESTART;
+ }
+}
+
+/*tex
+
+ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate mode,
+ \TeX\ calls |init_align|, whose task is to get everything off to a good
+ start. This mostly involves scanning the preamble and putting its information
+ into the preamble list.
+
+*/
+
+void init_align(void)
+{
+ /*tex |warning_index| value for error messages */
+ pointer save_cs_ptr;
+ /*tex for short-term temporary use */
+ pointer p, r;
+ /*tex \.{\\halign} or \.{\\valign}, usually */
+ save_cs_ptr = cur_cs;
+ push_alignment();
+ /*tex enter a new alignment level */
+ align_state = -1000000;
+ /*tex
+
+ When \.{\\halign} is used as a displayed formula, there should be no
+ other pieces of mlists present.
+
+ */
+ if ((cur_list.mode_field == mmode) && ((cur_list.tail_field != cur_list.head_field) || (incompleat_noad_par != null))) {
+ const char *hlp[] = {
+ "Displays can use special alignments (like \\eqalignno)",
+ "only if nothing but the alignment itself is between $$'s.",
+ "So I've deleted the formulas that preceded this alignment.",
+ NULL
+ };
+ tex_error("Improper \\halign inside $$'s", hlp);
+ flush_math();
+ }
+ /*tex Enter a new semantic level. */
+ push_nest();
+ /*tex
+
+ In vertical modes, |prev_depth| already has the correct value. But if we
+ are in |mmode| (displayed formula mode), we reach out to the enclosing
+ vertical mode for the |prev_depth| value that produces the correct
+ baseline calculations.
+ */
+ if (cur_list.mode_field == mmode) {
+ cur_list.mode_field = -vmode;
+ prev_depth_par = nest[nest_ptr - 2].prev_depth_field;
+ } else if (cur_list.mode_field > 0) {
+ cur_list.mode_field = -(cur_list.mode_field);
+ }
+ scan_spec(align_group);
+ /*tex Scan the preamble. */
+ preamble = null;
+ cur_align = align_head;
+ cur_loop = null;
+ scanner_status = aligning;
+ warning_index = save_cs_ptr;
+ align_state = -1000000;
+ /*tex At this point, |cur_cmd=left_brace|. */
+ while (true) {
+ /*tex Append the current tabskip glue to the preamble list. */
+ r = new_param_glue(tab_skip_code);
+ vlink(cur_align) = r;
+ cur_align = vlink(cur_align);
+ if (cur_cmd == car_ret_cmd) {
+ /*tex \.{\\cr} ends the preamble. */
+ break;
+ }
+ /*tex
+
+ Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret| and
+ then scan the template \<u_j>, putting the resulting token list in
+ |hold_token_head|. Spaces are eliminated from the beginning of a
+ template.
+
+ */
+ p = hold_token_head;
+ token_link(p) = null;
+ while (1) {
+ get_preamble_token();
+ if (cur_cmd == mac_param_cmd)
+ break;
+ if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd)
+ && (align_state == -1000000)) {
+ if ((p == hold_token_head) && (cur_loop == null) && (cur_cmd == tab_mark_cmd)) {
+ cur_loop = cur_align;
+ } else {
+ const char *hlp[] = {
+ "There should be exactly one # between &'s, when an",
+ "\\halign or \\valign is being set up. In this case you had",
+ "none, so I've put one in; maybe that will work.",
+ NULL
+ };
+ back_input();
+ tex_error("Missing # inserted in alignment preamble", hlp);
+ break;
+ }
+ } else if ((cur_cmd != spacer_cmd) || (p != hold_token_head)) {
+ r = get_avail();
+ token_link(p) = r;
+ p = token_link(p);
+ token_info(p) = cur_tok;
+ }
+ }
+ r = new_node(align_record_node, 0);
+ vlink(cur_align) = r;
+ /*tex A new align record: */
+ cur_align = vlink(cur_align);
+ span_ptr(cur_align) = end_span;
+ width(cur_align) = null_flag;
+ u_part(cur_align) = token_link(hold_token_head);
+ /*tex
+
+ Scan the template \<v_j>, putting the resulting token list in
+ |hold_token_head|.
+
+ */
+ p = hold_token_head;
+ token_link(p) = null;
+ while (1) {
+ CONTINUE:
+ get_preamble_token();
+ if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd) && (align_state == -1000000))
+ break;
+ if (cur_cmd == mac_param_cmd) {
+ const char *hlp[] = {
+ "There should be exactly one # between &'s, when an",
+ "\\halign or \\valign is being set up. In this case you had",
+ "more than one, so I'm ignoring all but the first.",
+ NULL
+ };
+ tex_error("Only one # is allowed per tab", hlp);
+ goto CONTINUE;
+ }
+ r = get_avail();
+ token_link(p) = r;
+ p = token_link(p);
+ token_info(p) = cur_tok;
+ }
+ r = get_avail();
+ token_link(p) = r;
+ p = token_link(p);
+ /*tex Put \.{\\endtemplate} at the end: */
+ token_info(p) = end_template_token;
+ v_part(cur_align) = token_link(hold_token_head);
+ }
+ scanner_status = normal;
+ new_save_level(align_group);
+ if (every_cr_par != null)
+ begin_token_list(every_cr_par, every_cr_text);
+ /*tex Look for \.{\\noalign} or \.{\\omit}. */
+ align_peek();
+}
+
+/*tex
+
+ The tricky part about alignments is getting the templates into the scanner at
+ the right time, and recovering control when a row or column is finished.
+
+ We usually begin a row after each \.{\\cr} has been sensed, unless that
+ \.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
+ the alignment. The |align_peek| routine is used to look ahead and do the
+ right thing; it either gets a new row started, or gets a \.{\\noalign}
+ started, or finishes off the alignment.
+
+*/
+
+void align_peek(void)
+{
+ RESTART:
+ align_state = 1000000;
+ do {
+ get_x_or_protected();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_cmd == no_align_cmd) {
+ scan_left_brace();
+ new_save_level(no_align_group);
+ if (cur_list.mode_field == -vmode)
+ normal_paragraph();
+ } else if (cur_cmd == right_brace_cmd) {
+ fin_align();
+ } else if ((cur_cmd == car_ret_cmd) && (cur_chr == cr_cr_code)) {
+ /*tex Ignore \.{\\crcr}. */
+ goto RESTART;
+ } else {
+ /*tex Start a new row. */
+ init_row();
+ /*tex Start a new column and replace what we peeked at. */
+ init_col();
+ }
+}
+
+
+/*tex
+
+ The parameter to |init_span| is a pointer to the alignrecord where the next
+ column or group of columns will begin. A new semantic level is entered, so
+ that the columns will generate a list for subsequent packaging.
+
+*/
+
+static void init_span(pointer p)
+{
+ push_nest();
+ if (cur_list.mode_field == -hmode) {
+ space_factor_par = 1000;
+ } else {
+ prev_depth_par = ignore_depth;
+ normal_paragraph();
+ }
+ cur_span = p;
+}
+
+/*tex
+
+ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
+ we enter a new semantic level, copy the first tabskip glue, and change from
+ internal vertical mode to restricted horizontal mode or vice versa. The
+ |space_factor| and |prev_depth| are not used on this semantic level, but we
+ clear them to zero just to be tidy.
+
+*/
+
+void init_row(void)
+{
+ push_nest();
+ cur_list.mode_field = (-hmode - vmode) - cur_list.mode_field;
+ if (cur_list.mode_field == -hmode)
+ space_factor_par = 0;
+ else
+ prev_depth_par = 0;
+ tail_append(new_glue(preamble));
+ subtype(cur_list.tail_field) = tab_skip_code + 1;
+ cur_align = vlink(preamble);
+ cur_tail = cur_head;
+ cur_pre_tail = cur_pre_head;
+ init_span(cur_align);
+}
+
+/*tex
+
+ When a column begins, we assume that |cur_cmd| is either |omit| or else the
+ current token should be put back into the input until the \<u_j> template has
+ been scanned. (Note that |cur_cmd| might be |tab_mark| or |car_ret|.) We also
+ assume that |align_state| is approximately 1000000 at this time. We remain in
+ the same mode, and start the template if it is called for.
+
+*/
+
+void init_col(void)
+{
+ extra_info(cur_align) = cur_cmd;
+ if (cur_cmd == omit_cmd)
+ align_state = 0;
+ else {
+ back_input();
+ begin_token_list(u_part(cur_align), u_template);
+ }
+ /*tex now |align_state=1000000| */
+}
+
+
+/*tex
+
+ The scanner sets |align_state| to zero when the \<u_j> template ends. When a
+ subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state=0|,
+ the scanner activates the following code, which fires up the \<v_j> template.
+ We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
+ |span_code|, or a character code, depending on how the column text has ended.
+
+ This part of the program had better not be activated when the preamble to
+ another alignment is being scanned, or when no alignment preamble is active.
+
+*/
+
+void insert_vj_template(void)
+{
+ if ((scanner_status == aligning) || (cur_align == null))
+ fatal_error("(interwoven alignment preambles are not allowed)");
+ cur_cmd = extra_info(cur_align);
+ extra_info(cur_align) = cur_chr;
+ if (cur_cmd == omit_cmd)
+ begin_token_list(omit_template, v_template);
+ else
+ begin_token_list(v_part(cur_align), v_template);
+ align_state = 1000000;
+}
+
+/*tex Determine the stretch order */
+
+#define determine_stretch_order() do { \
+ if (total_stretch[filll]!= 0) o = filll; \
+ else if (total_stretch[fill] != 0) o = fill; \
+ else if (total_stretch[fil] != 0) o = fil; \
+ else if (total_stretch[sfi] != 0) o = sfi; \
+ else o=normal; \
+} while (0)
+
+/*tex Determine the shrink order */
+
+#define determine_shrink_order() do { \
+ if (total_shrink[filll] != 0) o = filll; \
+ else if (total_shrink[fill] != 0) o = fill; \
+ else if (total_shrink[fil] != 0) o = fil; \
+ else if (total_shrink[sfi] != 0) o = sfi; \
+ else o=normal; \
+} while (0)
+
+/*tex
+
+ When the |endv| command at the end of a \<v_j> template comes through the
+ scanner, things really start to happen; and it is the |fin_col| routine that
+ makes them happen. This routine returns |true| if a row as well as a column
+ has been finished.
+
+*/
+
+boolean fin_col(void)
+{
+ /*tex the alignrecord after the current one */
+ pointer p;
+ /*tex temporary pointers for list manipulation */
+ pointer q, r;
+ /*tex a new span node */
+ pointer s;
+ /*tex a new unset box */
+ pointer u;
+ /*tex natural width */
+ scaled w;
+ /*tex order of infinity */
+ unsigned char o;
+ /*tex span counter */
+ halfword n;
+ if (cur_align == null)
+ confusion("endv");
+ q = vlink(cur_align);
+ if (q == null)
+ confusion("endv");
+ if (align_state < 500000)
+ fatal_error("(interwoven alignment preambles are not allowed)");
+ p = vlink(q);
+ /*tex If the preamble list has been traversed, check that the row has ended. */
+ if ((p == null) && (extra_info(cur_align) < cr_code)) {
+ if (cur_loop != null) {
+ /*tex Lengthen the preamble periodically: */
+ r = new_node(align_record_node, 0);
+ vlink(q) = r;
+ /*tex A new align record: */
+ p = vlink(q);
+ span_ptr(p) = end_span;
+ width(p) = null_flag;
+ cur_loop = vlink(cur_loop);
+ /*tex Copy the templates from node |cur_loop| into node |p|. */
+ q = hold_token_head;
+ r = u_part(cur_loop);
+ while (r != null) {
+ s = get_avail();
+ token_link(q) = s;
+ q = token_link(q);
+ token_info(q) = token_info(r);
+ r = token_link(r);
+ }
+ token_link(q) = null;
+ u_part(p) = token_link(hold_token_head);
+ q = hold_token_head;
+ r = v_part(cur_loop);
+ while (r != null) {
+ s = get_avail();
+ token_link(q) = s;
+ q = token_link(q);
+ token_info(q) = token_info(r);
+ r = token_link(r);
+ }
+ token_link(q) = null;
+ v_part(p) = token_link(hold_token_head);
+ cur_loop = vlink(cur_loop);
+ r = new_glue(cur_loop);
+ vlink(p) = r;
+ } else {
+ const char *hlp[] = {
+ "You have given more \\span or & marks than there were",
+ "in the preamble to the \\halign or \\valign now in progress.",
+ "So I'll assume that you meant to type \\cr instead.",
+ NULL
+ };
+ extra_info(cur_align) = cr_code;
+ tex_error("Extra alignment tab has been changed to \\cr", hlp);
+ }
+ }
+ if (extra_info(cur_align) != span_code) {
+ unsave();
+ new_save_level(align_group);
+ /*tex Package an unset box for the current column and record its width. */
+ if (cur_list.mode_field == -hmode) {
+ adjust_tail = cur_tail;
+ pre_adjust_tail = cur_pre_tail;
+ u = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0, additional, align_set_group, -1, 0, 0);
+ w = width(u);
+ cur_tail = adjust_tail;
+ adjust_tail = null;
+ cur_pre_tail = pre_adjust_tail;
+ pre_adjust_tail = null;
+ } else {
+ u = filtered_vpackage(vlink(cur_list.head_field), 0, additional, 0, align_set_group, -1, 0, 0);
+ w = height(u);
+ }
+ /*tex This represents a span count of 1: */
+ n = min_quarterword;
+ if (cur_span != cur_align) {
+ /*tex Update width entry for spanned columns. */
+ q = cur_span;
+ do {
+ incr(n);
+ q = vlink(vlink(q));
+ } while (q != cur_align);
+ if (n > max_quarterword) {
+ /*tex This can happen, but won't. */
+ confusion("too many spans");
+ }
+ q = cur_span;
+ while (span_span(span_ptr(q)) < n) {
+ q = span_ptr(q);
+ }
+ if (span_span(span_ptr(q)) > n) {
+ s = new_span_node(span_ptr(q), n, w);
+ span_ptr(q) = s;
+ } else if (width(span_ptr(q)) < w) {
+ width(span_ptr(q)) = w;
+ }
+ } else if (w > width(cur_align)) {
+ width(cur_align) = w;
+ }
+ type(u) = unset_node;
+ span_count(u) = (quarterword) n;
+ determine_stretch_order();
+ glue_order(u) = o;
+ glue_stretch(u) = total_stretch[o];
+ determine_shrink_order();
+ glue_sign(u) = o;
+ glue_shrink(u) = total_shrink[o];
+ pop_nest();
+ vlink(cur_list.tail_field) = u;
+ cur_list.tail_field = u;
+ /*tex Copy the tabskip glue between columns. */
+ tail_append(new_glue(vlink(cur_align)));
+ subtype(cur_list.tail_field) = tab_skip_code + 1;
+ if (extra_info(cur_align) >= cr_code) {
+ return true;
+ }
+ init_span(p);
+ }
+ align_state = 1000000;
+ do {
+ get_x_or_protected();
+ } while (cur_cmd == spacer_cmd);
+ cur_align = p;
+ init_col();
+ return false;
+}
+
+/*tex
+
+ A span node is a 3-word record containing |width|, |span_span|, and
+ |span_ptr| fields. The |span_span| field indicates the number of spanned
+ columns; the |span_ptr| field points to a span node for the same starting
+ column, having a greater extent of spanning, or to |end_span|, which has the
+ largest possible |span_span| field; the |width| field holds the largest
+ natural width corresponding to a particular set of spanned columns.
+
+ A list of the maximum widths so far, for spanned columns starting at a given
+ column, begins with the |span_ptr| field of the alignrecord for that column.
+ The code has to make sure that there is room for |span_ptr| in both the
+ alignrecord and the span nodes, which is why |span_ptr| replaces |node_attr|.
+
+ The |new_span_node| function is defined in |texnodes.c|.
+
+*/
+
+/*tex This is normally |alink|: */
+
+#ifndef span_span
+# define span_span(A) vlink((A)+1)
+#endif
+
+/*tex
+
+ At the end of a row, we append an unset box to the current vlist (for
+ \.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
+ contains the unset boxes for the columns, separated by the tabskip glue.
+ Everything will be set later.
+
+*/
+
+void fin_row(void)
+{
+ /*tex The new unset box: */
+ pointer p;
+ if (cur_list.mode_field == -hmode) {
+ p = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0,
+ additional, fin_row_group, -1, 0, 0);
+ pop_nest();
+ if (cur_pre_head != cur_pre_tail)
+ append_list(cur_pre_head, cur_pre_tail);
+ append_to_vlist(p,lua_key_index(alignment));
+ if (cur_head != cur_tail)
+ append_list(cur_head, cur_tail);
+ } else {
+ p = filtered_vpackage(vlink(cur_list.head_field),
+ 0, additional, max_depth_par, fin_row_group, -1, 0, 0);
+ pop_nest();
+ vlink(cur_list.tail_field) = p;
+ cur_list.tail_field = p;
+ space_factor_par = 1000;
+ }
+ type(p) = unset_node;
+ glue_stretch(p) = 0;
+ if (every_cr_par != null)
+ begin_token_list(every_cr_par, every_cr_text);
+ align_peek();
+ /*tex Note that |glue_shrink(p)=0| since |glue_shrink==shift_amount|. */
+}
+
+/*tex
+
+ Finally, we will reach the end of the alignment, and we can breathe a sigh of
+ relief that memory hasn't overflowed. All the unset boxes will now be set so
+ that the columns line up, taking due account of spanned columns.
+
+*/
+
+void fin_align(void)
+{
+ /*tex registers for the list operations */
+ pointer p, q, r, s, u, rr;
+ /*tex width of column */
+ scaled t, w;
+ /*tex shift offset for unset boxes */
+ scaled o;
+ /*tex matching span amount */
+ halfword n;
+ /*tex temporary storage for |overfull_rule| */
+ scaled rule_save;
+ /*tex temporary storage for |prev_depth| */
+ halfword pd;
+ /*tex temporary storage for |new_glue| */
+ halfword ng;
+ /*tex The |align_group| was for individual entries: */
+ if (cur_group != align_group)
+ confusion("align1");
+ unsave();
+ /*tex The |align_group| was for the whole alignment: */
+ if (cur_group != align_group)
+ confusion("align0");
+ unsave();
+ if (nest[nest_ptr - 1].mode_field == mmode) {
+ o = display_indent_par;
+ } else {
+ o = 0;
+ }
+ /*tex
+
+ Go through the preamble list, determining the column widths and
+ changing the alignrecords to dummy unset boxes.
+
+ It's time now to dismantle the preamble list and to compute the
+ column widths. Let $w_{ij}$ be the maximum of the natural widths of
+ all entries that span columns $i$ through $j$, inclusive. The
+ alignrecord for column~$i$ contains $w_{ii}$ in its |width| field,
+ and there is also a linked list of the nonzero $w_{ij}$ for
+ increasing $j$, accessible via the |info| field; these span nodes
+ contain the value $j-i+|min_quarterword|$ in their |link| fields. The
+ values of $w_{ii}$ were initialized to |null_flag|, which we regard
+ as $-\infty$.
+
+ The final column widths are defined by the formula $$w_j=\max_{1\L
+ i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$ where $t_k$ is
+ the natural width of the tabskip glue between columns $k$ and~$k+1$.
+ However, if $w_{ij}=-\infty$ for all |i| in the range |1<=i<=j|
+ (i.e., if every entry that involved column~|j| also involved
+ column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after
+ column~|j|.
+
+ \TeX\ computes these values by using the following scheme: First
+ $w_1=w_{11}$. Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$,
+ for all $j>1$. Then $w_2=w_{22}$. Then replace $w_{3j}$ by
+ $\max(w_{3j},w_{2j}-t_2-w_2)$ for all $j>2$; and so on. If any $w_j$
+ turns out to be $-\infty$, its value is changed to zero and so is the
+ next tabskip.
+
+ */
+ q = vlink(preamble);
+ do {
+ flush_list(u_part(q));
+ flush_list(v_part(q));
+ p = vlink(vlink(q));
+ if (width(q) == null_flag) {
+ /*tex Nullify |width(q)| and the tabskip glue following this column. */
+ width(q) = 0;
+ r = vlink(q);
+ reset_glue_to_zero(r);
+ }
+ if (span_ptr(q) != end_span) {
+ /*tex
+
+ Merge the widths in the span nodes of |q| with those of |p|,
+ destroying the span nodes of |q|.
+
+ Merging of two span-node lists is a typical exercise in the
+ manipulation of linearly linked data structures. The essential
+ invariant in the following |repeat| loop is that we want to
+ dispense with node |r|, in |q|'s list, and |u| is its successor;
+ all nodes of |p|'s list up to and including |s| have been
+ processed, and the successor of |s| matches |r| or precedes |r|
+ or follows |r|, according as |link(r)=n| or |link(r)>n| or
+ |link(r)<n|.
+
+ */
+ t = width(q) + width(vlink(q));
+ r = span_ptr(q);
+ s = end_span;
+ span_ptr(s) = p;
+ n = min_quarterword + 1;
+ do {
+ width(r) = width(r) - t;
+ u = span_ptr(r);
+ while (span_span(r) > n) {
+ s = span_ptr(s);
+ n = span_span(span_ptr(s)) + 1;
+ }
+ if (span_span(r) < n) {
+ span_ptr(r) = span_ptr(s);
+ span_ptr(s) = r;
+ decr(span_span(r));
+ s = r;
+ } else {
+ if (width(r) > width(span_ptr(s)))
+ width(span_ptr(s)) = width(r);
+ flush_node(r);
+ }
+ r = u;
+ } while (r != end_span);
+ }
+ type(q) = unset_node;
+ span_count(q) = min_quarterword;
+ height(q) = 0;
+ depth(q) = 0;
+ glue_order(q) = normal;
+ glue_sign(q) = normal;
+ glue_stretch(q) = 0;
+ glue_shrink(q) = 0;
+ q = p;
+ } while (q != null);
+ /*tex
+
+ Package the preamble list, to determine the actual tabskip glue amounts,
+ and let |p| point to this prototype box.
+
+ Now the preamble list has been converted to a list of alternating unset
+ boxes and tabskip glue, where the box widths are equal to the final
+ column sizes. In case of \.{\\valign}, we change the widths to heights,
+ so that a correct error message will be produced if the alignment is
+ overfull or underfull.
+
+ */
+ decr(save_ptr);
+ pack_begin_line = -cur_list.ml_field;
+ if (cur_list.mode_field == -vmode) {
+ rule_save = overfull_rule_par;
+ /*tex Prevent the rule from being packaged. */
+ overfull_rule_par = 0;
+ p = hpack(preamble, saved_value(0), saved_level(0), -1);
+ overfull_rule_par = rule_save;
+ } else {
+ q = vlink(preamble);
+ do {
+ height(q) = width(q);
+ width(q) = 0;
+ q = vlink(vlink(q));
+ } while (q != null);
+ p = filtered_vpackage(preamble,
+ saved_value(0), saved_level(0), max_depth_par, preamble_group, -1, 0, 0);
+ q = vlink(preamble);
+ do {
+ width(q) = height(q);
+ height(q) = 0;
+ q = vlink(vlink(q));
+ } while (q != null);
+ }
+ pack_begin_line = 0;
+ /*tex Set the glue in all the unset boxes of the current list. */
+ q = vlink(cur_list.head_field);
+ s = cur_list.head_field;
+ while (q != null) {
+ if (!is_char_node(q)) {
+ if (type(q) == unset_node) {
+ /*tex
+
+ We set the unset box |q| and the unset boxes in it. The unset
+ box |q| represents a row that contains one or more unset
+ boxes, depending on how soon \.{\\cr} occurred in that row.
+
+ */
+ if (cur_list.mode_field == -vmode) {
+ type(q) = hlist_node;
+ subtype(q) = align_row_list;
+ width(q) = width(p);
+ } else {
+ type(q) = vlist_node;
+ subtype(q) = align_row_list;
+ height(q) = height(p);
+ }
+ glue_order(q) = glue_order(p);
+ glue_sign(q) = glue_sign(p);
+ glue_set(q) = glue_set(p);
+ shift_amount(q) = o;
+ r = vlink(list_ptr(q));
+ assert (type(r) == unset_node);
+ s = vlink(list_ptr(p));
+ do {
+ /*tex
+
+ We set the glue in node |r| and change it from an unset
+ node. A box made from spanned columns will be followed by
+ tabskip glue nodes and by empty boxes as if there were no
+ spanning. This permits perfect alignment of subsequent
+ entries, and it prevents values that depend on floating
+ point arithmetic from entering into the dimensions of any
+ boxes.
+
+ */
+ n = span_count(r);
+ t = width(s);
+ w = t;
+ u = hold_head;
+ while (n > min_quarterword) {
+ decr(n);
+ /*tex
+
+ Append tabskip glue and an empty box to list |u|, and
+ update |s| and |t| as the prototype nodes are passed.
+
+ */
+ s = vlink(s);
+ ng = new_glue(s);
+ vlink(u) = ng;
+ u = vlink(u);
+ subtype(u) = tab_skip_code + 1;
+ t = t + width(s);
+ if (glue_sign(p) == stretching) {
+ if (stretch_order(s) == glue_order(p))
+ t = t + round(float_cast(glue_set(p)) * float_cast(stretch(s)));
+ } else if (glue_sign(p) == shrinking) {
+ if (shrink_order(s) == glue_order(p))
+ t = t - round(float_cast(glue_set(p)) * float_cast(shrink(s)));
+ }
+ s = vlink(s);
+ rr = new_null_box();
+ vlink(u) = rr;
+ u = vlink(u);
+ t = t + width(s);
+ subtype(u) = align_cell_list;
+ if (cur_list.mode_field == -vmode) {
+ width(u) = width(s);
+ } else {
+ type(u) = vlist_node;
+ height(u) = width(s);
+ }
+ }
+ if (cur_list.mode_field == -vmode) {
+ /*tex
+
+ Make the unset node |r| into an |hlist_node| of width
+ |w|, setting the glue as if the width were |t|.
+
+ */
+ height(r) = height(q);
+ depth(r) = depth(q);
+ if (t == width(r)) {
+ glue_sign(r) = normal;
+ glue_order(r) = normal;
+ set_glue_ratio_zero(glue_set(r));
+ } else if (t > width(r)) {
+ glue_sign(r) = stretching;
+ if (glue_stretch(r) == 0)
+ set_glue_ratio_zero(glue_set(r));
+ else
+ glue_set(r) = unfloat((double) (t - width(r)) / glue_stretch(r));
+ } else {
+ glue_order(r) = glue_sign(r);
+ glue_sign(r) = shrinking;
+ if (glue_shrink(r) == 0)
+ set_glue_ratio_zero(glue_set(r));
+ else if ((glue_order(r) == normal) && (width(r) - t > glue_shrink(r)))
+ set_glue_ratio_one(glue_set(r));
+ else
+ glue_set(r) = unfloat((double) (width(r) - t) / glue_shrink(r));
+ }
+ width(r) = w;
+ type(r) = hlist_node;
+ subtype(r) = align_cell_list;
+
+ } else {
+ /*tex
+
+ Make the unset node |r| into a |vlist_node| of height
+ |w|, setting the glue as if the height were |t|.
+
+ */
+ width(r) = width(q);
+ if (t == height(r)) {
+ glue_sign(r) = normal;
+ glue_order(r) = normal;
+ set_glue_ratio_zero(glue_set(r));
+ } else if (t > height(r)) {
+ glue_sign(r) = stretching;
+ if (glue_stretch(r) == 0)
+ set_glue_ratio_zero(glue_set(r));
+ else
+ glue_set(r) = unfloat((t - height(r)) / glue_stretch(r));
+ } else {
+ glue_order(r) = glue_sign(r);
+ glue_sign(r) = shrinking;
+ if (glue_shrink(r) == 0)
+ set_glue_ratio_zero(glue_set(r));
+ else if ((glue_order(r) == normal) && (height(r) - t > glue_shrink(r)))
+ set_glue_ratio_one(glue_set(r));
+ else
+ glue_set(r) = unfloat((height(r) - t) / glue_shrink(r));
+ }
+ height(r) = w;
+ type(r) = vlist_node;
+ subtype(r) = align_cell_list;
+ }
+ shift_amount(r) = 0;
+ if (u != hold_head) {
+ /*tex Append blank boxes to account for spanned nodes. */
+ vlink(u) = vlink(r);
+ vlink(r) = vlink(hold_head);
+ r = u;
+ }
+
+ r = vlink(vlink(r));
+ s = vlink(vlink(s));
+ } while (r != null);
+
+ } else if (type(q) == rule_node) {
+ /*tex
+
+ Make the running dimensions in rule |q| extend to the
+ boundaries of the alignment.
+
+ */
+ if (is_running(width(q)))
+ width(q) = width(p);
+ if (is_running(height(q)))
+ height(q) = height(p);
+ if (is_running(depth(q)))
+ depth(q) = depth(p);
+ if (o != 0) {
+ r = vlink(q);
+ vlink(q) = null;
+ q = hpack(q, 0, additional, -1);
+ shift_amount(q) = o;
+ subtype(q) = align_cell_list;
+ vlink(q) = r;
+ vlink(s) = q;
+ }
+ }
+ }
+ s = q;
+ q = vlink(q);
+ }
+ flush_node_list(p);
+ pop_alignment();
+ /*tex
+
+ We now have a completed alignment, in the list that starts at
+ |cur_list.head_field| and ends at |cur_list.tail_field|. This list will
+ be merged with the one that encloses it. (In case the enclosing mode is
+ |mmode|, for displayed formulas, we will need to insert glue before and
+ after the display; that part of the program will be deferred until we're
+ more familiar with such operations.)
+
+ */
+ pd = prev_depth_par;
+ p = vlink(cur_list.head_field);
+ q = cur_list.tail_field;
+ pop_nest();
+ if (cur_list.mode_field == mmode) {
+ finish_display_alignment(p, q, pd);
+ } else {
+ prev_depth_par = pd;
+ vlink(cur_list.tail_field) = p;
+ if (p != null)
+ cur_list.tail_field = q;
+ if (cur_list.mode_field == vmode) {
+ if (!output_active)
+ lua_node_filter_s(buildpage_filter_callback,lua_key_index(alignment));
+ build_page();
+ }
+ }
+}
+
+/*tex
+
+ The token list |omit_template| just referred to is a constant token list that
+ contains the special control sequence \.{\\endtemplate} only.
+
+*/
+
+void initialize_alignments(void)
+{
+ token_info(omit_template) = end_template_token;
+ span_span(end_span) = max_quarterword + 1;
+ span_ptr(end_span) = null;
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/align.w b/Build/source/texk/web2c/luatexdir/tex/align.w
deleted file mode 100644
index dd0ed10338e..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/align.w
+++ /dev/null
@@ -1,1144 +0,0 @@
-% align.w
-%
-% Copyright 2009-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/>.
-
-\def\<#1>{$#1$}
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ @c
-void fin_align(void);
-void init_row(void);
-void init_col(void);
-
-#define noDEBUG
-
-@ It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
-they cut across so many of the control structures of \TeX.
-
-Therefore the present page is probably not the best place for a beginner to
-start reading this program; it is better to master everything else first.
-
-Let us focus our thoughts on an example of what the input might be, in order
-to get some idea about how the alignment miracle happens. The example doesn't
-do anything useful, but it is sufficiently general to indicate all of the
-special cases that must be dealt with; please do not be disturbed by its
-apparent complexity and meaninglessness.
-$$\vbox{\halign{\.{#}\hfil\cr
-{}\\tabskip 2pt plus 3pt\cr
-{}\\halign to 300pt\{u1\#v1\&\cr
-\hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
-\hskip 50pt u3\#v3\\cr\cr
-\hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
-\hskip 25pt \\noalign\{\\vskip 3pt\}\cr
-\hskip 25pt b1\\span b2\\cr\cr
-\hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
-Here's what happens:
-
-\yskip
-(0) When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
-places the 300pt dimension onto the |save_stack|, and an |align_group|
-code is placed above it. This will make it possible to complete the alignment
-when the matching `\.\}' is found.
-
-(1) The preamble is scanned next. Macros in the preamble are not expanded,
-@^preamble@>
-except as part of a tabskip specification. For example, if \.{u2} had been
-a macro in the preamble above, it would have been expanded, since \TeX\
-must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
-is constructed based on the user's preamble; in our case it contains the
-following seven items:
-$$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
-{}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
-{}\\alignrecord, width $-\infty$&preamble info for column 1\cr
-{}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
-{}\\alignrecord, width $-\infty$&preamble info for column 2\cr
-{}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
-{}\\alignrecord, width $-\infty$&preamble info for column 3\cr
-{}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
-These ``alignrecord'' entries have the same size as an |unset_node|,
-since they will later be converted into such nodes. These alignrecord
-nodes have no |depth| field; this is split into |u_part| and |v_part|,
-and they point to token lists for the templates of the alignment. For
-example, the |u_part| field in the first alignrecord points to the
-token list `\.{u1}', i.e., the template preceding the `\.\#' for
-column~1. Furthermore, They have a |span_ptr| instead of a |node_attr|
-field, and these |span_ptr| fields are initially set to the value
-|end_span|, for reasons explained below.
-
-(2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
-It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
-be read again, and the template `\.{u1}' is fed to the scanner. Just
-before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
-Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
-{\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an |endv|
-token, indicating the end of a column. At this point an |unset_node| is
-created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
-The natural width of this unset node replaces the |width| field of the
-alignrecord for column~1; in general, the alignrecords will record the
-maximum natural width that has occurred so far in a given column.
-
-(3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
-are now bypassed. Again \TeX\ goes into restricted horizontal mode and
-makes an |unset_node| from the resulting hlist; but this time the
-hlist contains simply `\.{a2}'. The natural width of the new unset box
-is remembered in the |width| field of the alignrecord for column~2.
-
-(4) A third |unset_node| is created for column 3, using essentially the
-mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
-v3}'. The vertical rule in this case has running dimensions that will later
-extend to the height and depth of the whole first row, since each |unset_node|
-in a row will eventually inherit the height and depth of its enclosing box.
-
-(5) The first row has now ended; it is made into a single unset box
-comprising the following seven items:
-$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
-{}\\glue 2pt plus 3pt\cr
-{}\\unsetbox for 1 column: u1a1v1\cr
-{}\\glue 2pt plus 3pt\cr
-{}\\unsetbox for 1 column: a2\cr
-{}\\glue 1pt plus 1fil\cr
-{}\\unsetbox for 1 column: u3\\vrule v3\cr
-{}\\glue 1pt plus 1fil\cr}}$$
-The width of this unset row is unimportant, but it has the correct height
-and depth, so the correct baselineskip glue will be computed as the row
-is inserted into a vertical list.
-
-(6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
-additional material (in this case \.{\\vskip 3pt}) to the vertical list.
-While processing this material, \TeX\ will be in internal vertical
-mode, and |no_align_group| will be on |save_stack|.
-
-(7) The next row produces an unset box that looks like this:
-$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
-{}\\glue 2pt plus 3pt\cr
-{}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
-{}\\glue 1pt plus 1fil\cr
-{}\\unsetbox for 1 column: {\rm(empty)}\cr
-{}\\glue 1pt plus 1fil\cr}}$$
-The natural width of the unset box that spans columns 1~and~2 is stored
-in a ``span node,'' which we will explain later; the |span_ptr| field of the
-alignrecord for column~1 now points to the new span node, and the |span_ptr|
-of the span node points to |end_span|.
-
-(8) The final row produces the unset box
-$$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
-{}\\glue 2pt plus 3pt\cr
-{}\\unsetbox for 1 column: {\rm(empty)}\cr
-{}\\glue 2pt plus 3pt\cr
-{}\\unsetbox for 2 columns: u2c2v2\cr
-{}\\glue 1pt plus 1fil\cr}}$$
-A new span node is attached to the alignrecord for column 2.
-
-(9) The last step is to compute the true column widths and to change all the
-unset boxes to hboxes, appending the whole works to the vertical list that
-encloses the \.{\\halign}. The rules for deciding on the final widths of
-each unset column box will be explained below.
-
-\yskip\noindent
-Note that as \.{\\halign} is being processed, we fearlessly give up control
-to the rest of \TeX. At critical junctures, an alignment routine is
-called upon to step in and do some little action, but most of the time
-these routines just lurk in the background. It's something like
-post-hypnotic suggestion.
-
-@ We have mentioned that alignrecords contain no |height| or |depth| fields.
-Their |glue_sign| and |glue_order| are pre-empted as well, since it
-is necessary to store information about what to do when a template ends.
-This information is called the |extra_info| field.
-
-@c
-/* could be in texnodes.h, but documented here*/
-
-#define u_part(A) vlink((A)+depth_offset) /* pointer to \<u_j> token list */
-#define v_part(A) vinfo((A)+depth_offset) /* pointer to \<v_j> token list */
-#define span_ptr(A) vinfo((A)+1) /* column spanning list */
-#define extra_info(A) vinfo((A)+list_offset) /* info to remember during template */
-
-@ Alignments can occur within alignments, so a small stack is used to access
-the alignrecord information. At each level we have a |preamble| pointer,
-indicating the beginning of the preamble list; a |cur_align| pointer,
-indicating the current position in the preamble list; a |cur_span| pointer,
-indicating the value of |cur_align| at the beginning of a sequence of
-spanned columns; a |cur_loop| pointer, indicating the tabskip glue before
-an alignrecord that should be copied next if the current list is extended;
-and the |align_state| variable, which indicates the nesting of braces so
-that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
-There also are pointers |cur_head| and |cur_tail| to the head and tail
-of a list of adjustments being moved out from horizontal mode to
-vertical~mode, and alike |cur_pre_head| and |cur_pre_tail| for pre-adjust
-lists.
-
-The current values of these nine quantities appear in global variables;
-when they have to be pushed down, they are stored in 6-word nodes, and
-|align_ptr| points to the topmost such node.
-
-@c
-/* could be in texnodes.h but documented here*/
-
-#define preamble vlink(align_head) /* the current preamble list */
-
-pointer cur_align = null; /* current position in preamble list */
-pointer cur_span = null; /* start of currently spanned columns in preamble list */
-pointer cur_loop = null; /* place to copy when extending a periodic preamble */
-pointer align_ptr = null; /* most recently pushed-down alignment stack node */
-pointer cur_head = null, cur_tail = null; /* adjustment list pointers */
-pointer cur_pre_head = null, cur_pre_tail = null; /* pre-adjustment list pointers */
-
-/* The |align_state| and |preamble| variables are initialized elsewhere. */
-
-@ Alignment stack maintenance is handled by a pair of trivial routines
-called |push_alignment| and |pop_alignment|.
-
-(HH:) It makes not much sense to add support for an \.{attr} keyword to
-\.{\\halign} and \.{\\valign} because then we need to decide if we tag
-rows or cells or both or come up with \.{cellattr} and \.{rowattr} and
-such. But then it even makes sense to have explicit commands (in addition
-to the seperator) to tags individual cells. Too muss hassle for now and the
-advantages are not that large.
-
-@c
-static void push_alignment(void)
-{
- pointer p; /* the new alignment stack node */
- p = new_node(align_stack_node, 0);
- vinfo(p + 1) = align_ptr;
- vlink(p + 1) = cur_align;
- vinfo(p + 2) = preamble;
- vlink(p + 2) = cur_span;
- vinfo(p + 3) = cur_loop;
- vlink(p + 3) = align_state;
- vinfo(p + 4) = cur_head;
- vlink(p + 4) = cur_tail;
- vinfo(p + 5) = cur_pre_head;
- vlink(p + 5) = cur_pre_tail;
- align_ptr = p;
- cur_head = new_node(temp_node, 0);
- cur_pre_head = new_node(temp_node, 0);
-}
-
-static void pop_alignment(void)
-{
- pointer p; /* the top alignment stack node */
- flush_node(cur_head);
- flush_node(cur_pre_head);
- p = align_ptr;
- cur_pre_tail = vlink(p + 5);
- cur_pre_head = vinfo(p + 5);
- cur_tail = vlink(p + 4);
- cur_head = vinfo(p + 4);
- align_state = vlink(p + 3);
- cur_loop = vinfo(p + 3);
- cur_span = vlink(p + 2);
- preamble = vinfo(p + 2);
- cur_align = vlink(p + 1);
- align_ptr = vinfo(p + 1);
- flush_node(p);
-}
-
-
-@ \TeX\ has eight procedures that govern alignments: |init_align| and
-|fin_align| are used at the very beginning and the very end; |init_row| and
-|fin_row| are used at the beginning and end of individual rows; |init_span|
-is used at the beginning of a sequence of spanned columns (possibly involving
-only one column); |init_col| and |fin_col| are used at the beginning and
-end of individual columns; and |align_peek| is used after \.{\\cr} to see
-whether the next item is \.{\\noalign}.
-
-We shall consider these routines in the order they are first used during
-the course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
-|init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
-
-
-@ The preamble is copied directly, except that \.{\\tabskip} causes a change
-to the tabskip glue, thereby possibly expanding macros that immediately
-follow it. An appearance of \.{\\span} also causes such an expansion.
-
-Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
-token survives in the preamble and the `\.{\\tabskip}' defines new
-tabskip glue (locally).
-
-@c
-static void get_preamble_token(void)
-{
- RESTART:
- get_token();
- while ((cur_chr == span_code) && (cur_cmd == tab_mark_cmd)) {
- get_token(); /* this token will be expanded once */
- if (cur_cmd > max_command_cmd) {
- expand();
- get_token();
- }
- }
- if (cur_cmd == endv_cmd)
- fatal_error("(interwoven alignment preambles are not allowed)");
- if ((cur_cmd == assign_glue_cmd)
- && (cur_chr == glue_base + tab_skip_code)) {
- scan_optional_equals();
- scan_glue(glue_val_level);
- if (global_defs_par > 0)
- geq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
- else
- eq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
- goto RESTART;
- }
-}
-
-
-
-@ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
-mode, \TeX\ calls |init_align|, whose task is to get everything off to a
-good start. This mostly involves scanning the preamble and putting its
-information into the preamble list.
-@^preamble@>
-
-@c
-void init_align(void)
-{
- /* label done, done1, done2, continue; */
- pointer save_cs_ptr; /* |warning_index| value for error messages */
- pointer p, r; /* for short-term temporary use */
- save_cs_ptr = cur_cs; /* \.{\\halign} or \.{\\valign}, usually */
- push_alignment();
- align_state = -1000000; /* enter a new alignment level */
-
- /* When \.{\\halign} is used as a displayed formula, there should be
- no other pieces of mlists present. */
-
- if ((cur_list.mode_field == mmode)
- && ((cur_list.tail_field != cur_list.head_field)
- || (incompleat_noad_par != null))) {
- const char *hlp[] =
- { "Displays can use special alignments (like \\eqalignno)",
- "only if nothing but the alignment itself is between $$'s.",
- "So I've deleted the formulas that preceded this alignment.",
- NULL
- };
- tex_error("Improper \\halign inside $$'s", hlp);
- flush_math();
- }
- push_nest(); /* enter a new semantic level */
- /* In vertical modes, |prev_depth| already has the correct value. But
- if we are in |mmode| (displayed formula mode), we reach out to the
- enclosing vertical mode for the |prev_depth| value that produces the
- correct baseline calculations. */
- if (cur_list.mode_field == mmode) {
- cur_list.mode_field = -vmode;
- prev_depth_par = nest[nest_ptr - 2].prev_depth_field;
- } else if (cur_list.mode_field > 0) {
- cur_list.mode_field = -(cur_list.mode_field);
- }
- scan_spec(align_group);
- /* Scan the preamble */
- preamble = null;
- cur_align = align_head;
- cur_loop = null;
- scanner_status = aligning;
- warning_index = save_cs_ptr;
- align_state = -1000000;
- /* at this point, |cur_cmd=left_brace| */
- while (true) {
- /* Append the current tabskip glue to the preamble list */
- r = new_param_glue(tab_skip_code);
- vlink(cur_align) = r;
- cur_align = vlink(cur_align);
-
- if (cur_cmd == car_ret_cmd)
- break; /* \.{\\cr} ends the preamble */
-
- /* Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret| */
- /* Scan the template \<u_j>, putting the resulting token list in |hold_token_head| */
- /* Spaces are eliminated from the beginning of a template. */
-
- p = hold_token_head;
- token_link(p) = null;
- while (1) {
- get_preamble_token();
- if (cur_cmd == mac_param_cmd)
- break;
- if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd)
- && (align_state == -1000000)) {
- if ((p == hold_token_head) && (cur_loop == null)
- && (cur_cmd == tab_mark_cmd)) {
- cur_loop = cur_align;
- } else {
- const char *hlp[] =
- { "There should be exactly one # between &'s, when an",
- "\\halign or \\valign is being set up. In this case you had",
- "none, so I've put one in; maybe that will work.",
- NULL
- };
- back_input();
- tex_error("Missing # inserted in alignment preamble", hlp);
- break;
- }
- } else if ((cur_cmd != spacer_cmd) || (p != hold_token_head)) {
- r = get_avail();
- token_link(p) = r;
- p = token_link(p);
- token_info(p) = cur_tok;
- }
- }
- r = new_node(align_record_node, 0);
- vlink(cur_align) = r;
- cur_align = vlink(cur_align); /* a new alignrecord */
- span_ptr(cur_align) = end_span;
- width(cur_align) = null_flag;
- u_part(cur_align) = token_link(hold_token_head);
- /* Scan the template \<v_j>, putting the resulting token list in |hold_token_head| */
-
- p = hold_token_head;
- token_link(p) = null;
- while (1) {
- CONTINUE:
- get_preamble_token();
- if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd)
- && (align_state == -1000000))
- break;
- if (cur_cmd == mac_param_cmd) {
- const char *hlp[] =
- { "There should be exactly one # between &'s, when an",
- "\\halign or \\valign is being set up. In this case you had",
- "more than one, so I'm ignoring all but the first.",
- NULL
- };
- tex_error("Only one # is allowed per tab", hlp);
- goto CONTINUE;
- }
- r = get_avail();
- token_link(p) = r;
- p = token_link(p);
- token_info(p) = cur_tok;
- }
- r = get_avail();
- token_link(p) = r;
- p = token_link(p);
- token_info(p) = end_template_token; /* put \.{\\endtemplate} at the end */
-
- v_part(cur_align) = token_link(hold_token_head);
- }
- scanner_status = normal;
-
- new_save_level(align_group);
- if (every_cr_par != null)
- begin_token_list(every_cr_par, every_cr_text);
- align_peek(); /* look for \.{\\noalign} or \.{\\omit} */
-}
-
-
-@ The tricky part about alignments is getting the templates into the
-scanner at the right time, and recovering control when a row or column
-is finished.
-
-We usually begin a row after each \.{\\cr} has been sensed, unless that
-\.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
-the alignment. The |align_peek| routine is used to look ahead and do
-the right thing; it either gets a new row started, or gets a \.{\\noalign}
-started, or finishes off the alignment.
-
-@c
-void align_peek(void)
-{
- RESTART:
- align_state = 1000000;
- do {
- get_x_or_protected();
- } while (cur_cmd == spacer_cmd);
- if (cur_cmd == no_align_cmd) {
- scan_left_brace();
- new_save_level(no_align_group);
- if (cur_list.mode_field == -vmode)
- normal_paragraph();
- } else if (cur_cmd == right_brace_cmd) {
- fin_align();
- } else if ((cur_cmd == car_ret_cmd) && (cur_chr == cr_cr_code)) {
- goto RESTART; /* ignore \.{\\crcr} */
- } else {
- init_row(); /* start a new row */
- init_col(); /* start a new column and replace what we peeked at */
- }
-}
-
-
-@ The parameter to |init_span| is a pointer to the alignrecord where the
-next column or group of columns will begin. A new semantic level is
-entered, so that the columns will generate a list for subsequent packaging.
-
-@c
-static void init_span(pointer p)
-{
- push_nest();
- if (cur_list.mode_field == -hmode) {
- space_factor_par = 1000;
- } else {
- prev_depth_par = ignore_depth;
- normal_paragraph();
- }
- cur_span = p;
-}
-
-
-@ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
-we enter a new semantic level, copy the first tabskip glue, and change
-from internal vertical mode to restricted horizontal mode or vice versa.
-The |space_factor| and |prev_depth| are not used on this semantic level,
-but we clear them to zero just to be tidy.
-
-@c
-void init_row(void)
-{
- push_nest();
- cur_list.mode_field = (-hmode - vmode) - cur_list.mode_field;
- if (cur_list.mode_field == -hmode)
- space_factor_par = 0;
- else
- prev_depth_par = 0;
- tail_append(new_glue(preamble));
- subtype(cur_list.tail_field) = tab_skip_code + 1;
- cur_align = vlink(preamble);
- cur_tail = cur_head;
- cur_pre_tail = cur_pre_head;
- init_span(cur_align);
-}
-
-
-@ When a column begins, we assume that |cur_cmd| is either |omit| or else
-the current token should be put back into the input until the \<u_j>
-template has been scanned. (Note that |cur_cmd| might be |tab_mark| or
-|car_ret|.) We also assume that |align_state| is approximately 1000000 at
-this time. We remain in the same mode, and start the template if it is
-called for.
-
-@c
-void init_col(void)
-{
- extra_info(cur_align) = cur_cmd;
- if (cur_cmd == omit_cmd)
- align_state = 0;
- else {
- back_input();
- begin_token_list(u_part(cur_align), u_template);
- } /* now |align_state=1000000| */
-}
-
-
-@ The scanner sets |align_state| to zero when the \<u_j> template ends. When
-a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state=0|,
-the scanner activates the following code, which fires up the \<v_j> template.
-We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
-|span_code|, or a character code, depending on how the column text has ended.
-
-This part of the program had better not be activated when the preamble
-to another alignment is being scanned, or when no alignment preamble is active.
-
-@c
-void insert_vj_template(void)
-{
- if ((scanner_status == aligning) || (cur_align == null))
- fatal_error("(interwoven alignment preambles are not allowed)");
- cur_cmd = extra_info(cur_align);
- extra_info(cur_align) = cur_chr;
- if (cur_cmd == omit_cmd)
- begin_token_list(omit_template, v_template);
- else
- begin_token_list(v_part(cur_align), v_template);
- align_state = 1000000;
-}
-
-/* Determine the stretch order */
-#define determine_stretch_order() do { \
- if (total_stretch[filll]!=0) o=filll; \
- else if (total_stretch[fill]!=0) o=fill; \
- else if (total_stretch[fil]!=0) o=fil; \
- else if (total_stretch[sfi]!=0) o=sfi; \
- else o=normal; \
- } while (0)
-
-
-/* Determine the shrink order */
-#define determine_shrink_order() do { \
- if (total_shrink[filll]!=0) o=filll; \
- else if (total_shrink[fill]!=0) o=fill; \
- else if (total_shrink[fil]!=0) o=fil; \
- else if (total_shrink[sfi]!=0) o=sfi; \
- else o=normal; \
- } while (0)
-
-
-
-@ When the |endv| command at the end of a \<v_j> template comes through the
-scanner, things really start to happen; and it is the |fin_col| routine
-that makes them happen. This routine returns |true| if a row as well as a
-column has been finished.
-
-@c
-boolean fin_col(void)
-{
- pointer p; /* the alignrecord after the current one */
- pointer q, r; /* temporary pointers for list manipulation */
- pointer s; /* a new span node */
- pointer u; /* a new unset box */
- scaled w; /* natural width */
- unsigned char o; /* order of infinity */
- halfword n; /* span counter */
- if (cur_align == null)
- confusion("endv");
- q = vlink(cur_align);
- if (q == null)
- confusion("endv");
- if (align_state < 500000)
- fatal_error("(interwoven alignment preambles are not allowed)");
- p = vlink(q);
- /* If the preamble list has been traversed, check that the row has ended */
- if ((p == null) && (extra_info(cur_align) < cr_code)) {
- if (cur_loop != null) {
- /* Lengthen the preamble periodically */
- r = new_node(align_record_node, 0);
- vlink(q) = r;
- p = vlink(q); /* a new alignrecord */
- span_ptr(p) = end_span;
- width(p) = null_flag;
- cur_loop = vlink(cur_loop);
-
- /* Copy the templates from node |cur_loop| into node |p| */
- q = hold_token_head;
- r = u_part(cur_loop);
- while (r != null) {
- s = get_avail();
- token_link(q) = s;
- q = token_link(q);
- token_info(q) = token_info(r);
- r = token_link(r);
- }
- token_link(q) = null;
- u_part(p) = token_link(hold_token_head);
- q = hold_token_head;
- r = v_part(cur_loop);
- while (r != null) {
- s = get_avail();
- token_link(q) = s;
- q = token_link(q);
- token_info(q) = token_info(r);
- r = token_link(r);
- }
- token_link(q) = null;
- v_part(p) = token_link(hold_token_head);
-
- cur_loop = vlink(cur_loop);
- r = new_glue(cur_loop);
- vlink(p) = r;
- } else {
- const char *hlp[] =
- { "You have given more \\span or & marks than there were",
- "in the preamble to the \\halign or \\valign now in progress.",
- "So I'll assume that you meant to type \\cr instead.",
- NULL
- };
- extra_info(cur_align) = cr_code;
- tex_error("Extra alignment tab has been changed to \\cr", hlp);
- }
- }
- if (extra_info(cur_align) != span_code) {
- unsave();
- new_save_level(align_group);
- /* Package an unset box for the current column and record its width */
- if (cur_list.mode_field == -hmode) {
- adjust_tail = cur_tail;
- pre_adjust_tail = cur_pre_tail;
- u = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0,
- additional, align_set_group, -1, 0, 0);
- w = width(u);
- cur_tail = adjust_tail;
- adjust_tail = null;
- cur_pre_tail = pre_adjust_tail;
- pre_adjust_tail = null;
- } else {
- u = filtered_vpackage(vlink(cur_list.head_field),
- 0, additional, 0, align_set_group, -1, 0, 0);
- w = height(u);
- }
- n = min_quarterword; /* this represents a span count of 1 */
- if (cur_span != cur_align) {
- /* Update width entry for spanned columns */
- q = cur_span;
- do {
- incr(n);
- q = vlink(vlink(q));
- } while (q != cur_align);
- if (n > max_quarterword)
- confusion("too many spans"); /* this can happen, but won't */
- q = cur_span;
- while (span_span(span_ptr(q)) < n) {
- q = span_ptr(q);
- }
- if (span_span(span_ptr(q)) > n) {
- s = new_span_node(span_ptr(q), n, w);
- span_ptr(q) = s;
- } else if (width(span_ptr(q)) < w) {
- width(span_ptr(q)) = w;
- }
-
- } else if (w > width(cur_align)) {
- width(cur_align) = w;
- }
- type(u) = unset_node;
- span_count(u) = (quarterword) n;
- determine_stretch_order();
- glue_order(u) = o;
- glue_stretch(u) = total_stretch[o];
- determine_shrink_order();
- glue_sign(u) = o;
- glue_shrink(u) = total_shrink[o];
- pop_nest();
- vlink(cur_list.tail_field) = u;
- cur_list.tail_field = u;
-
- /* Copy the tabskip glue between columns */
- tail_append(new_glue(vlink(cur_align)));
- subtype(cur_list.tail_field) = tab_skip_code + 1;
-
- if (extra_info(cur_align) >= cr_code) {
- return true;
- }
- init_span(p);
- }
- align_state = 1000000;
- do {
- get_x_or_protected();
- } while (cur_cmd == spacer_cmd);
- cur_align = p;
- init_col();
- return false;
-}
-
-
-
-@ A span node is a 3-word record containing |width|, |span_span|, and
-|span_ptr| fields. The |span_span| field indicates the number of
-spanned columns; the |span_ptr| field points to a span node for the same
-starting column, having a greater extent of spanning, or to
-|end_span|, which has the largest possible |span_span| field; the |width|
-field holds the largest natural width corresponding to a particular
-set of spanned columns.
-
-A list of the maximum widths so far, for spanned columns starting at a
-given column, begins with the |span_ptr| field of the alignrecord for
-that column. The code has to make sure that there is room for
-|span_ptr| in both the alignrecord and the span nodes, which is why
-|span_ptr| replaces |node_attr|.
-@^data structure assumptions@>
-
-The |new_span_node| function is defined in |texnodes.c|.
-
-@c
-#ifndef span_span
-# define span_span(A) vlink((A)+1) /* that is normally |alink| */
-#endif
-
-
-@ At the end of a row, we append an unset box to the current vlist (for
-\.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
-contains the unset boxes for the columns, separated by the tabskip glue.
-Everything will be set later.
-
-@c
-void fin_row(void)
-{
- pointer p; /* the new unset box */
- if (cur_list.mode_field == -hmode) {
- p = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0,
- additional, fin_row_group, -1, 0, 0);
- pop_nest();
- if (cur_pre_head != cur_pre_tail)
- append_list(cur_pre_head, cur_pre_tail);
- append_to_vlist(p,lua_key_index(alignment));
- if (cur_head != cur_tail)
- append_list(cur_head, cur_tail);
- } else {
- p = filtered_vpackage(vlink(cur_list.head_field),
- 0, additional, max_depth_par, fin_row_group, -1, 0, 0);
- pop_nest();
- vlink(cur_list.tail_field) = p;
- cur_list.tail_field = p;
- space_factor_par = 1000;
- }
- type(p) = unset_node;
- glue_stretch(p) = 0;
- if (every_cr_par != null)
- begin_token_list(every_cr_par, every_cr_text);
- align_peek();
- /* note that |glue_shrink(p)=0| since |glue_shrink==shift_amount| */
-}
-
-
-@ Finally, we will reach the end of the alignment, and we can breathe a
-sigh of relief that memory hasn't overflowed. All the unset boxes will now be
-set so that the columns line up, taking due account of spanned columns.
-
-@c
-void fin_align(void)
-{
- pointer p, q, r, s, u, rr; /* registers for the list operations */
- scaled t, w; /* width of column */
- scaled o; /* shift offset for unset boxes */
- halfword n; /* matching span amount */
- scaled rule_save; /* temporary storage for |overfull_rule| */
- halfword pd; /* temporary storage for |prev_depth| */
- halfword ng; /* temporary storage for |new_glue| */
- if (cur_group != align_group)
- confusion("align1");
- unsave(); /* that |align_group| was for individual entries */
- if (cur_group != align_group)
- confusion("align0");
- unsave(); /* that |align_group| was for the whole alignment */
- if (nest[nest_ptr - 1].mode_field == mmode)
- o = display_indent_par;
- else
- o = 0;
- /* Go through the preamble list, determining the column widths and
- * changing the alignrecords to dummy unset boxes
- */
-
-/* It's time now to dismantle the preamble list and to compute the column
-widths. Let $w_{ij}$ be the maximum of the natural widths of all entries
-that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$
-contains $w_{ii}$ in its |width| field, and there is also a linked list of
-the nonzero $w_{ij}$ for increasing $j$, accessible via the |info| field;
-these span nodes contain the value $j-i+|min_quarterword|$ in their
-|link| fields. The values of $w_{ii}$ were initialized to |null_flag|, which
-we regard as $-\infty$.
-
-The final column widths are defined by the formula
-$$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$
-where $t_k$ is the natural width of the tabskip glue between columns
-$k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all |i| in the range
-|1<=i<=j| (i.e., if every entry that involved column~|j| also involved
-column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after
-column~|j|.
-
-\TeX\ computes these values by using the following scheme: First $w_1=w_{11}$.
-Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$.
-Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$
-for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its
-value is changed to zero and so is the next tabskip.
-*/
- q = vlink(preamble);
- do {
- flush_list(u_part(q));
- flush_list(v_part(q));
- p = vlink(vlink(q));
- if (width(q) == null_flag) {
- /* Nullify |width(q)| and the tabskip glue following this column */
- width(q) = 0;
- r = vlink(q);
- reset_glue_to_zero(r); /* is a lready copy */
- }
- if (span_ptr(q) != end_span) {
- /* Merge the widths in the span nodes of |q| with those of |p|,
- destroying the span nodes of |q| */
- /*
- Merging of two span-node lists is a typical exercise in the manipulation of
- linearly linked data structures. The essential invariant in the following
- |repeat| loop is that we want to dispense with node |r|, in |q|'s list,
- and |u| is its successor; all nodes of |p|'s list up to and including |s|
- have been processed, and the successor of |s| matches |r| or precedes |r|
- or follows |r|, according as |link(r)=n| or |link(r)>n| or |link(r)<n|.
- */
- t = width(q) + width(vlink(q));
- r = span_ptr(q);
- s = end_span;
- span_ptr(s) = p;
- n = min_quarterword + 1;
- do {
- width(r) = width(r) - t;
- u = span_ptr(r);
- while (span_span(r) > n) {
- s = span_ptr(s);
- n = span_span(span_ptr(s)) + 1;
- }
- if (span_span(r) < n) {
- span_ptr(r) = span_ptr(s);
- span_ptr(s) = r;
- decr(span_span(r));
- s = r;
- } else {
- if (width(r) > width(span_ptr(s)))
- width(span_ptr(s)) = width(r);
- flush_node(r);
- }
- r = u;
- } while (r != end_span);
- }
- type(q) = unset_node;
- span_count(q) = min_quarterword;
- height(q) = 0;
- depth(q) = 0;
- glue_order(q) = normal;
- glue_sign(q) = normal;
- glue_stretch(q) = 0;
- glue_shrink(q) = 0;
- q = p;
- } while (q != null);
-
- /* Package the preamble list, to determine the actual tabskip glue amounts,
- and let |p| point to this prototype box */
- /* Now the preamble list has been converted to a list of alternating unset
- boxes and tabskip glue, where the box widths are equal to the final
- column sizes. In case of \.{\\valign}, we change the widths to heights,
- so that a correct error message will be produced if the alignment is
- overfull or underfull.
- */
-
- decr(save_ptr);
- pack_begin_line = -cur_list.ml_field;
- if (cur_list.mode_field == -vmode) {
- rule_save = overfull_rule_par;
- overfull_rule_par = 0; /* prevent rule from being packaged */
- p = hpack(preamble, saved_value(0), saved_level(0), -1);
- overfull_rule_par = rule_save;
- } else {
- q = vlink(preamble);
- do {
- height(q) = width(q);
- width(q) = 0;
- q = vlink(vlink(q));
- } while (q != null);
- p = filtered_vpackage(preamble,
- saved_value(0), saved_level(0), max_depth_par, preamble_group, -1, 0, 0);
- q = vlink(preamble);
- do {
- width(q) = height(q);
- height(q) = 0;
- q = vlink(vlink(q));
- } while (q != null);
- }
- pack_begin_line = 0;
-
- /* Set the glue in all the unset boxes of the current list */
- q = vlink(cur_list.head_field);
- s = cur_list.head_field;
- while (q != null) {
- if (!is_char_node(q)) {
- if (type(q) == unset_node) {
- /* Set the unset box |q| and the unset boxes in it */
- /* The unset box |q| represents a row that contains one or more unset boxes,
- depending on how soon \.{\\cr} occurred in that row. */
-
- if (cur_list.mode_field == -vmode) {
- type(q) = hlist_node;
- subtype(q) = align_row_list;
- width(q) = width(p);
- } else {
- type(q) = vlist_node;
- subtype(q) = align_row_list;
- height(q) = height(p);
- }
- glue_order(q) = glue_order(p);
- glue_sign(q) = glue_sign(p);
- glue_set(q) = glue_set(p);
- shift_amount(q) = o;
- r = vlink(list_ptr(q));
- assert (type(r) == unset_node);
- s = vlink(list_ptr(p));
- do {
- /* Set the glue in node |r| and change it from an unset node */
- /* A box made from spanned columns will be followed by tabskip glue nodes and
- by empty boxes as if there were no spanning. This permits perfect alignment
- of subsequent entries, and it prevents values that depend on floating point
- arithmetic from entering into the dimensions of any boxes.
- */
- n = span_count(r);
- t = width(s);
- w = t;
- u = hold_head;
- while (n > min_quarterword) {
- decr(n);
- /* Append tabskip glue and an empty box to list |u|,
- and update |s| and |t| as the prototype nodes are passed */
-
- s = vlink(s);
- ng = new_glue(s);
- vlink(u) = ng;
- u = vlink(u);
- subtype(u) = tab_skip_code + 1;
- t = t + width(s);
- if (glue_sign(p) == stretching) {
- if (stretch_order(s) == glue_order(p))
- t = t + round(float_cast(glue_set(p)) * float_cast(stretch(s)));
- } else if (glue_sign(p) == shrinking) {
- if (shrink_order(s) == glue_order(p))
- t = t - round(float_cast(glue_set(p)) * float_cast(shrink(s)));
- }
- s = vlink(s);
- rr = new_null_box();
- vlink(u) = rr;
- u = vlink(u);
- t = t + width(s);
- subtype(u) = align_cell_list;
- if (cur_list.mode_field == -vmode) {
- width(u) = width(s);
- } else {
- type(u) = vlist_node;
- height(u) = width(s);
- }
-
- }
- if (cur_list.mode_field == -vmode) {
- /* Make the unset node |r| into an |hlist_node| of width |w|,
- setting the glue as if the width were |t| */
-
- height(r) = height(q);
- depth(r) = depth(q);
- if (t == width(r)) {
- glue_sign(r) = normal;
- glue_order(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- } else if (t > width(r)) {
- glue_sign(r) = stretching;
- if (glue_stretch(r) == 0)
- set_glue_ratio_zero(glue_set(r));
- else
- glue_set(r) =
- unfloat((double) (t - width(r)) /
- glue_stretch(r));
- } else {
- glue_order(r) = glue_sign(r);
- glue_sign(r) = shrinking;
- if (glue_shrink(r) == 0)
- set_glue_ratio_zero(glue_set(r));
- else if ((glue_order(r) == normal)
- && (width(r) - t > glue_shrink(r)))
- set_glue_ratio_one(glue_set(r));
- else
- glue_set(r) =
- unfloat((double) (width(r) - t) /
- glue_shrink(r));
- }
- width(r) = w;
- type(r) = hlist_node;
- subtype(r) = align_cell_list;
-
- } else {
- /* Make the unset node |r| into a |vlist_node| of height |w|,
- setting the glue as if the height were |t| */
-
- width(r) = width(q);
- if (t == height(r)) {
- glue_sign(r) = normal;
- glue_order(r) = normal;
- set_glue_ratio_zero(glue_set(r));
- } else if (t > height(r)) {
- glue_sign(r) = stretching;
- if (glue_stretch(r) == 0)
- set_glue_ratio_zero(glue_set(r));
- else
- glue_set(r) =
- unfloat((t - height(r)) / glue_stretch(r));
- } else {
- glue_order(r) = glue_sign(r);
- glue_sign(r) = shrinking;
- if (glue_shrink(r) == 0)
- set_glue_ratio_zero(glue_set(r));
- else if ((glue_order(r) == normal)
- && (height(r) - t > glue_shrink(r)))
- set_glue_ratio_one(glue_set(r));
- else
- glue_set(r) =
- unfloat((height(r) - t) / glue_shrink(r));
- }
- height(r) = w;
- type(r) = vlist_node;
- subtype(r) = align_cell_list;
-
- }
- /* subtype(r) = 0; */
- shift_amount(r) = 0;
- if (u != hold_head) { /* append blank boxes to account for spanned nodes */
- vlink(u) = vlink(r);
- vlink(r) = vlink(hold_head);
- r = u;
- }
-
- r = vlink(vlink(r));
- s = vlink(vlink(s));
- } while (r != null);
-
- } else if (type(q) == rule_node) {
- /* Make the running dimensions in rule |q| extend to the
- boundaries of the alignment */
- if (is_running(width(q)))
- width(q) = width(p);
- if (is_running(height(q)))
- height(q) = height(p);
- if (is_running(depth(q)))
- depth(q) = depth(p);
- if (o != 0) {
- r = vlink(q);
- vlink(q) = null;
- q = hpack(q, 0, additional, -1);
- shift_amount(q) = o;
- subtype(q) = align_cell_list;
- vlink(q) = r;
- vlink(s) = q;
- }
- }
- }
- s = q;
- q = vlink(q);
- }
- flush_node_list(p);
- pop_alignment();
- /* Insert the current list into its environment */
- /* We now have a completed alignment, in the list that starts at |cur_list.head_field|
- and ends at |cur_list.tail_field|. This list will be merged with the one that encloses
- it. (In case the enclosing mode is |mmode|, for displayed formulas,
- we will need to insert glue before and after the display; that part of the
- program will be deferred until we're more familiar with such operations.)
- */
- pd = prev_depth_par;
- p = vlink(cur_list.head_field);
- q = cur_list.tail_field;
- pop_nest();
- if (cur_list.mode_field == mmode) {
- finish_display_alignment(p, q, pd);
- } else {
- prev_depth_par = pd; /* aux:=aux_save; */
- vlink(cur_list.tail_field) = p;
- if (p != null)
- cur_list.tail_field = q;
- if (cur_list.mode_field == vmode) {
- if (!output_active)
- lua_node_filter_s(buildpage_filter_callback,lua_key_index(alignment));
- build_page();
- }
- }
-}
-
-@ The token list |omit_template| just referred to is a constant token
-list that contains the special control sequence \.{\\endtemplate} only.
-
-@c
-void initialize_alignments(void)
-{
- token_info(omit_template) = end_template_token; /* |link(omit_template)=null| */
- span_span(end_span) = max_quarterword + 1;
- span_ptr(end_span) = null;
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/arithmetic.c b/Build/source/texk/web2c/luatexdir/tex/arithmetic.c
new file mode 100644
index 00000000000..2782c253400
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/arithmetic.c
@@ -0,0 +1,815 @@
+/*
+
+arithmetic.w
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+The principal computations performed by \TeX\ are done entirely in terms of
+integers less than $2^{31}$ in magnitude; and divisions are done only when both
+dividend and divisor are nonnegative. Thus, the arithmetic specified in this
+program can be carried out in exactly the same way on a wide variety of
+computers, including some small ones. Why? Because the arithmetic calculations
+need to be spelled out precisely in order to guarantee that \TeX\ will produce
+identical output on different machines. If some quantities were rounded
+differently in different implementations, we would find that line breaks and even
+page breaks might occur in different places. Hence the arithmetic of \TeX\ has
+been designed with care, and systems that claim to be implementations of \TeX82
+should follow precisely the @:TeX82}{\TeX82@> calculations as they appear in the
+present program.
+
+Actually there are three places where \TeX\ uses |div| with a possibly negative
+numerator. These are harmless; see |div| in the index. Also if the user sets the
+\.{\\time} or the \.{\\year} to a negative value, some diagnostic information
+will involve negative-numerator division. The same remarks apply for |mod| as
+well as for |div|.
+
+Here is a routine that calculates half of an integer, using an unambiguous
+convention with respect to signed odd numbers.
+
+*/
+
+int half(int x)
+{
+ if (odd(x))
+ return ((x + 1) / 2);
+ else
+ return (x / 2);
+}
+
+/*tex
+
+The following function is used to create a scaled integer from a given decimal
+fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
+given in |dig[i]|, and the calculation produces a correctly rounded result.
+
+*/
+
+scaled round_decimals(int k)
+{
+ int a = 0;
+ while (k-- > 0) {
+ a = (a + dig[k] * two) / 10;
+ }
+ return ((a + 1) / 2);
+}
+
+/*tex
+
+Conversely, here is a procedure analogous to |print_int|. If the output of this
+procedure is subsequently read by \TeX\ and converted by the |round_decimals|
+routine above, it turns out that the original value will be reproduced exactly;
+the ``simplest'' such decimal number is output, but there is always at least one
+digit following the decimal point.
+
+The invariant relation in the \&{repeat} loop is that a sequence of decimal
+digits yet to be printed will yield the original number if and only if they form
+a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$. We can stop if and only
+if $f=0$ satisfies this condition; the loop will terminate before $s$ can
+possibly become zero.
+
+The next one prints a scaled real, rounded to five digits.
+
+*/
+
+void print_scaled(scaled s)
+{
+ /*tex The amount of allowable inaccuracy: */
+ scaled delta;
+ char buffer[20];
+ int i = 0;
+ if (s < 0) {
+ /*tex Print the sign, if negative. */
+ print_char('-');
+ negate(s);
+ }
+ /*tex Print the integer part. */
+ print_int(s / unity);
+ buffer[i++] = '.';
+ s = 10 * (s % unity) + 5;
+ delta = 10;
+ do {
+ if (delta > unity) {
+ /*tex Round the last digit. */
+ s = s + 0100000 - 50000;
+ }
+ buffer[i++] = '0' + (s / unity);
+ s = 10 * (s % unity);
+ delta = delta * 10;
+ } while (s > delta);
+ buffer[i++] = '\0';
+ tprint(buffer);
+}
+
+/*tex
+
+Physical sizes that a \TeX\ user specifies for portions of documents are
+represented internally as scaled points. Thus, if we define an `sp' (scaled
+@^sp@> point) as a unit equal to $2^{-16}$ printer's points, every dimension
+inside of \TeX\ is an integer number of sp. There are exactly 4,736,286.72 sp per
+inch. Users are not allowed to specify dimensions larger than $2^{30}-1$ sp,
+which is a distance of about 18.892 feet (5.7583 meters); two such quantities can
+be added without overflow on a 32-bit computer.
+
+The present implementation of \TeX\ does not check for overflow when @^overflow
+in arithmetic@> dimensions are added or subtracted. This could be done by
+inserting a few dozen tests of the form `\ignorespaces|if x>=010000000000 then
+@t\\{report\_overflow}@>|', but the chance of overflow is so remote that such
+tests do not seem worthwhile.
+
+\TeX\ needs to do only a few arithmetic operations on scaled quantities, other
+than addition and subtraction, and the following subroutines do most of the work.
+A single computation might use several subroutine calls, and it is desirable to
+avoid producing multiple error messages in case of arithmetic overflow; so the
+routines set the global variable |arith_error| to |true| instead of reporting
+errors directly to the user. Another global variable, |tex_remainder|, holds the
+remainder after a division.
+
+*/
+
+/*tex Has arithmetic overflow occurred recently? */
+
+boolean arith_error;
+
+/*tex The amount subtracted to get an exact division. */
+
+scaled tex_remainder;
+
+/*tex
+
+ The first arithmetical subroutine we need computes $nx+y$, where |x|
+and~|y| are |scaled| and |n| is an integer. We will also use it to
+multiply integers.
+
+*/
+
+scaled mult_and_add(int n, scaled x, scaled y, scaled max_answer)
+{
+ if (n == 0)
+ return y;
+ if (n < 0) {
+ negate(x);
+ negate(n);
+ }
+ if (((x <= (max_answer - y) / n) && (-x <= (max_answer + y) / n))) {
+ return (n * x + y);
+ } else {
+ arith_error = true;
+ return 0;
+ }
+}
+
+/*tex
+
+We also need to divide scaled dimensions by integers.
+
+*/
+
+scaled x_over_n(scaled x, int n)
+{
+ /*tex Should |tex_remainder| be negated? */
+ boolean negative = false;
+ if (n == 0) {
+ arith_error = true;
+ tex_remainder = x;
+ return 0;
+ } else {
+ if (n < 0) {
+ negate(x);
+ negate(n);
+ negative = true;
+ }
+ if (x >= 0) {
+ tex_remainder = x % n;
+ if (negative)
+ negate(tex_remainder);
+ return (x / n);
+ } else {
+ tex_remainder = -((-x) % n);
+ if (negative)
+ negate(tex_remainder);
+ return (-((-x) / n));
+ }
+ }
+}
+
+/*tex
+
+Then comes the multiplication of a scaled number by a fraction |n/d|, where |n|
+and |d| are nonnegative integers |<=@t$2^{16}$@>| and |d| is positive. It would
+be too dangerous to multiply by~|n| and then divide by~|d|, in separate
+operations, since overflow might well occur; and it would be too inaccurate to
+divide by |d| and then multiply by |n|. Hence this subroutine simulates
+1.5-precision arithmetic.
+
+*/
+
+scaled xn_over_d(scaled x, int n, int d)
+{
+ nonnegative_integer t, u, v, xx, dd;
+ boolean positive = true;
+ if (x < 0) {
+ negate(x);
+ positive = false;
+ }
+ xx = (nonnegative_integer) x;
+ dd = (nonnegative_integer) d;
+ t = ((xx % 0100000) * (nonnegative_integer) n);
+ u = ((xx / 0100000) * (nonnegative_integer) n + (t / 0100000));
+ v = (u % dd) * 0100000 + (t % 0100000);
+ if (u / dd >= 0100000)
+ arith_error = true;
+ else
+ u = 0100000 * (u / dd) + (v / dd);
+ if (positive) {
+ tex_remainder = (int) (v % dd);
+ return (scaled) u;
+ } else {
+ /*tex The casts are for ms cl. */
+ tex_remainder = -(int) (v % dd);
+ return -(scaled) (u);
+ }
+}
+
+/*tex
+
+The next subroutine is used to compute the ``badness'' of glue, when a total~|t|
+is supposed to be made from amounts that sum to~|s|. According to {\sl The \TeX
+book}, the badness of this situation is $100(t/s)^3$; however, badness is simply
+a heuristic, so we need not squeeze out the last drop of accuracy when computing
+it. All we really want is an approximation that has similar properties.
+@:TeXbook}{\sl The \TeX book@>
+
+The actual method used to compute the badness is easier to read from the program
+than to describe in words. It produces an integer value that is a reasonably
+close approximation to $100(t/s)^3$, and all implementations of \TeX\ should use
+precisely this method. Any badness of $2^{13}$ or more is treated as infinitely
+bad, and represented by 10000.
+
+It is not difficult to prove that $$\hbox{|badness(t+1,s)>=badness(t,s)
+>= badness(t,s+1)|}.$$ The badness function defined here is capable of computing
+at most 1095 distinct values, but that is plenty.
+
+*/
+
+halfword badness(scaled t, scaled s)
+{
+ /*tex Approximation to $\alpha t/s$, where $\alpha^3\approx 100\cdot2^{18}$ */
+ int r;
+ if (t == 0) {
+ return 0;
+ } else if (s <= 0) {
+ return inf_bad;
+ } else {
+ /*tex $297^3=99.94\times2^{18}$ */
+ if (t <= 7230584) {
+ r = (t * 297) / s;
+ } else if (s >= 1663497) {
+ r = t / (s / 297);
+ } else {
+ r = t;
+ }
+ if (r > 1290) {
+ /*tex $1290^3<2^{31}<1291^3$ */
+ return inf_bad;
+ } else {
+ /*tex This is $r^3/2^{18}$, rounded to the nearest integer. */
+ return ((r * r * r + 0400000) / 01000000);
+ }
+ }
+}
+
+/*tex
+
+When \TeX\ ``packages'' a list into a box, it needs to calculate the
+proportionality ratio by which the glue inside the box should stretch or shrink.
+This calculation does not affect \TeX's decision making, so the precise details
+of rounding, etc., in the glue calculation are not of critical importance for the
+consistency of results on different computers.
+
+We shall use the type |glue_ratio| for such proportionality ratios. A glue ratio
+should take the same amount of memory as an |integer| (usually 32 bits) if it is
+to blend smoothly with \TeX's other data structures. Thus |glue_ratio| should be
+equivalent to |short_real| in some implementations of PASCAL. Alternatively, it
+is possible to deal with glue ratios using nothing but fixed-point arithmetic;
+see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the routines cited there must
+be modified to allow negative glue ratios.) @^system dependencies@>
+
+*/
+
+/*
+
+This section is (almost) straight from MetaPost. I (Taco) had to change the types
+(use |integer| instead of |fraction|), but that should not have any influence on
+the actual calculations (the original comments refer to quantities like
+|fraction_four| ($2^{30}$), and that is the same as the numeric representation of
+|max_dimen|).
+
+I've copied the low-level variables and routines that are needed, but only those
+(e.g. |m_log|), not the accompanying ones like |m_exp|. Most of the following
+low-level numeric routines are only needed within the calculation of |norm_rand|.
+I've been forced to rename |make_fraction| to |make_frac| because TeX already has
+a routine by that name with a wholly different function (it creates a
+|fraction_noad| for math typesetting)
+
+And now let's complete our collection of numeric utility routines by considering
+random number generation. \MP{} generates pseudo-random numbers with the additive
+scheme recommended in Section 3.6 of {\sl The Art of Computer Programming};
+however, the results are random fractions between 0 and |fraction_one-1|,
+inclusive.
+
+There's an auxiliary array |randoms| that contains 55 pseudo-random fractions.
+Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$, we generate batches
+of 55 new $x_n$'s at a time by calling |new_randoms|. The global variable
+|j_random| tells which element has most recently been consumed.
+
+*/
+
+/*tex The last 55 random values generated: */
+
+static int randoms[55];
+
+/*tex The number of unused |randoms|: */
+
+static int j_random;
+
+/*tex The default random seed: */
+
+scaled random_seed;
+
+/*tex A small bit of \METAPOST\ is needed. */
+
+#define fraction_half 01000000000 /* $2^{27} $, represents 0.50000000 */
+#define fraction_one 02000000000 /* $2^{28} $, represents 1.00000000 */
+#define fraction_four 010000000000 /* $2^{30} $, represents 4.00000000 */
+#define el_gordo 017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
+
+/*tex
+
+The |make_frac| routine produces the |fraction| equivalent of |p/q|, given
+integers |p| and~|q|; it computes the integer
+$f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are positive. If |p| and
+|q| are both of the same scaled type |t|, the ``type relation''
+|make_frac(t,t)=fraction| is valid; and it's also possible to use the subroutine
+``backwards,'' using the relation |make_frac(t,fraction)=t| between scaled types.
+
+If the result would have magnitude $2^{31}$ or more, |make_frac| sets
+|arith_error:=true|. Most of \MP's internal computations have been designed to
+avoid this sort of error.
+
+If this subroutine were programmed in assembly language on a typical machine, we
+could simply compute |(@t$2^{28}$@>*p)div q|, since a double-precision product
+can often be input to a fixed-point division instruction. But when we are
+restricted to PASCAL arithmetic it is necessary either to resort to
+multiple-precision maneuvering or to use a simple but slow iteration. The
+multiple-precision technique would be about three times faster than the code
+adopted here, but it would be comparatively long and tricky, involving about
+sixteen additional multiplications and divisions.
+
+This operation is part of \MP's ``inner loop''; indeed, it will consume nearly
+10\%! of the running time (exclusive of input and output) if the code below is
+left unchanged. A machine-dependent recoding will therefore make \MP\ run faster.
+The present implementation is highly portable, but slow; it avoids multiplication
+and division except in the initial stage. System wizards should be careful to
+replace it with a routine that is guaranteed to produce identical results in all
+cases. @^system dependencies@>
+
+As noted below, a few more routines should also be replaced by machine-dependent
+code, for efficiency. But when a procedure is not part of the ``inner loop,''
+such changes aren't advisable; simplicity and robustness are preferable to
+trickery, unless the cost is too high.
+
+*/
+
+static int make_frac(int p, int q)
+{
+ /*tex The fraction bits, with a leading 1 bit: */
+ int f;
+ /*tex The integer part of $\vert p/q\vert$: */
+ int n;
+ /*tex Disables certain compiler optimizations: */
+ register int be_careful;
+ /*tex Should the result be negated? */
+ boolean negative = false;
+ if (p < 0) {
+ negate(p);
+ negative = true;
+ }
+ if (q <= 0) {
+ negate(q);
+ negative = !negative;
+ }
+ n = p / q;
+ p = p % q;
+ if (n >= 8) {
+ arith_error = true;
+ if (negative)
+ return (-el_gordo);
+ else
+ return el_gordo;
+ } else {
+ n = (n - 1) * fraction_one;
+ /*tex_remainder
+
+ Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$. The |repeat| loop
+ here preserves the following invariant relations between |f|, |p|,
+ and~|q|: (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an
+ integer and $p_0$ is the original value of~$p$.
+
+ Notice that the computation specifies |(p-q)+p| instead of |(p+p)-q|,
+ because the latter could overflow. Let us hope that optimizing
+ compilers do not miss this point; a special variable |be_careful| is
+ used to emphasize the necessary order of computation. Optimizing
+ compilers should keep |be_careful| in a register, not store it in
+ memory.
+
+ */
+ f = 1;
+ do {
+ be_careful = p - q;
+ p = be_careful + p;
+ if (p >= 0)
+ f = f + f + 1;
+ else {
+ f += f;
+ p = p + q;
+ }
+ } while (f < fraction_one);
+ be_careful = p - q;
+ if (be_careful + p >= 0)
+ incr(f);
+
+ if (negative)
+ return (-(f + n));
+ else
+ return (f + n);
+ }
+}
+
+static int take_frac(int q, int f)
+{
+ /*tex The fraction so far: */
+ int p;
+ /*tex Additional multiple of $q$: */
+ int n;
+ /*tex Disables certain compiler optimizations. */
+ register int be_careful;
+ /*tex Should the result be negated? */
+ boolean negative = false;
+ /*tex Reduce to the case that |f>=0| and |q>0|. */
+ if (f < 0) {
+ negate(f);
+ negative = true;
+ }
+ if (q < 0) {
+ negate(q);
+ negative = !negative;
+ }
+ if (f < fraction_one) {
+ n = 0;
+ } else {
+ n = f / fraction_one;
+ f = f % fraction_one;
+ if (q <= el_gordo / n) {
+ n = n * q;
+ } else {
+ arith_error = true;
+ n = el_gordo;
+ }
+ }
+ f = f + fraction_one;
+ /*tex
+
+ Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$. The invariant relations
+ in this case are (i)~$\lfloor(qf+p)/2^k\rfloor =\lfloor
+ qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and $f_0$ is the
+ original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
+
+ Here |p| becomes $2^{27}$; the invariants hold now with $k=28$:
+
+ */
+ p = fraction_half;
+ if (q < fraction_four) {
+ do {
+ if (odd(f))
+ p = halfp(p + q);
+ else
+ p = halfp(p);
+ f = halfp(f);
+ } while (f != 1);
+ } else {
+ do {
+ if (odd(f))
+ p = p + halfp(q - p);
+ else
+ p = halfp(p);
+ f = halfp(f);
+ } while (f != 1);
+ }
+ be_careful = n - el_gordo;
+ if (be_careful + p > 0) {
+ arith_error = true;
+ n = el_gordo - p;
+ }
+ if (negative)
+ return (-(n + p));
+ else
+ return (n + p);
+}
+
+/*tex
+
+The subroutines for logarithm and exponential involve two tables. The first is
+simple: |two_to_the[k]| equals $2^k$. The second involves a bit more calculation,
+which the author claims to have done correctly: |spec_log[k]| is $2^{27}$ times
+$\ln\bigl(1/(1-2^{-k})\bigr)= 2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$,
+rounded to the nearest integer.
+
+*/
+
+/*tex The powers of two: */
+
+static int two_to_the[31];
+
+/*tex Special logarithms: */
+
+static int spec_log[29];
+
+void initialize_arithmetic(void)
+{
+ int k;
+ two_to_the[0] = 1;
+ for (k = 1; k <= 30; k++) {
+ two_to_the[k] = 2 * two_to_the[k - 1];
+ }
+ spec_log [1] = 93032640;
+ spec_log [2] = 38612034;
+ spec_log [3] = 17922280;
+ spec_log [4] = 8662214;
+ spec_log [5] = 4261238;
+ spec_log [6] = 2113709;
+ spec_log [7] = 1052693;
+ spec_log [8] = 525315;
+ spec_log [9] = 262400;
+ spec_log[10] = 131136;
+ spec_log[11] = 65552;
+ spec_log[12] = 32772;
+ spec_log[13] = 16385;
+ for (k = 14; k <= 27; k++) {
+ spec_log[k] = two_to_the[27 - k];
+ }
+ spec_log[28] = 1;
+}
+
+static int m_log(int x)
+{
+ /*tex Auxiliary registers: */
+ int y, z;
+ /*tex Iteration counter: */
+ int k;
+ if (x <= 0) {
+ /*tex Handle non-positive logarithm. */
+ print_err("Logarithm of ");
+ print_scaled(x);
+ tprint(" has been replaced by 0");
+ help2(
+ "Since I don't take logs of non-positive numbers,",
+ "I'm zeroing this one. Proceed, with fingers crossed."
+ );
+ error();
+ return 0;
+ } else {
+ /*tex $14\times2^{27}\ln2\approx1302456956.421063$ */
+ y = 1302456956 + 4 - 100;
+ /*tex $2^{16}\times .421063\approx 27595$ */
+ z = 27595 + 6553600;
+ while (x < fraction_four) {
+ x += x;
+ /*tex $2^{27}\ln2\approx 93032639.74436163$ */
+ y = y - 93032639;
+ /*tex $2^{16}\times.74436163\approx 48782$ */
+ z = z - 48782;
+ }
+
+ y = y + (z / unity);
+ k = 2;
+ while (x > fraction_four + 4) {
+ /*tex
+ Increase |k| until |x| can be multiplied by a factor of $2^{-k}$,
+ and adjust $y$ accordingly. Here $z=\lceil x/2^k\rceil$.
+ */
+ z = ((x - 1) / two_to_the[k]) + 1;
+ while (x < fraction_four + z) {
+ z = halfp(z + 1);
+ k = k + 1;
+ }
+ y = y + spec_log[k];
+ x = x - z;
+ }
+ return (y / 8);
+ }
+}
+
+/*tex
+
+The following somewhat different subroutine tests rigorously if $ab$ is greater
+than, equal to, or less than~$cd$, given integers $(a,b,c,d)$. In most cases a
+quick decision is reached. The result is $+1$, 0, or~$-1$ in the three respective
+cases.
+
+*/
+
+static int ab_vs_cd(int a, int b, int c, int d)
+{
+ int q, r;
+ /*tex Reduce to the case that |a,c>=0| and |b,d>0|. */
+ if (a < 0) {
+ negate(a);
+ negate(b);
+ }
+ if (c < 0) {
+ negate(c);
+ negate(d);
+ }
+ if (d <= 0) {
+ if (b >= 0)
+ return (((a == 0 || b == 0) && (c == 0 || d == 0)) ? 0 : 1);
+ if (d == 0)
+ return (a == 0 ? 0 : -1);
+ q = a;
+ a = c;
+ c = q;
+ q = -b;
+ b = -d;
+ d = q;
+ } else if (b <= 0) {
+ if (b < 0 && a > 0)
+ return -1;
+ return (c == 0 ? 0 : -1);
+ }
+ while (1) {
+ q = a / d;
+ r = c / b;
+ if (q != r)
+ return (q > r ? 1 : -1);
+ q = a % d;
+ r = c % b;
+ if (r == 0)
+ return (q == 0 ? 0 : 1);
+ if (q == 0)
+ return -1;
+ a = b;
+ b = q;
+ c = d;
+ d = r;
+ /*tex Now |a>d>0| and |c>b>0|. */
+ }
+}
+
+/*tex
+
+To consume a random integer, the program below will say `|next_random|' and then
+it will fetch |randoms[j_random]|.
+
+*/
+
+#define next_random() do { \
+ if (j_random==0) \
+ new_randoms(); \
+ else \
+ decr(j_random); \
+} while (0)
+
+static void new_randoms(void)
+{
+ /*tex The index into |randoms|. */
+ int k;
+ /*tex The accumulator. */
+ int x;
+ for (k = 0; k <= 23; k++) {
+ x = randoms[k] - randoms[k + 31];
+ if (x < 0)
+ x = x + fraction_one;
+ randoms[k] = x;
+ }
+ for (k = 24; k <= 54; k++) {
+ x = randoms[k] - randoms[k - 24];
+ if (x < 0)
+ x = x + fraction_one;
+ randoms[k] = x;
+ }
+ j_random = 54;
+}
+
+/*tex
+
+To initialize the |randoms| table, we call the following routine.
+
+*/
+
+void init_randoms(int seed)
+{
+ /*tex Three more or less random integers. */
+ int j, jj, k;
+ /*tex The index into |randoms|. */
+ int i;
+ j = abs(seed);
+ while (j >= fraction_one)
+ j = halfp(j);
+ k = 1;
+ for (i = 0; i <= 54; i++) {
+ jj = k;
+ k = j - k;
+ j = jj;
+ if (k < 0)
+ k = k + fraction_one;
+ randoms[(i * 21) % 55] = j;
+ }
+ /*tex We ``warm up'' the array. */
+ new_randoms();
+ new_randoms();
+ new_randoms();
+}
+
+/*tex
+
+To produce a uniform random number in the range |0<=u<x| or |0>=u>x| or |0=u=x|,
+given a |scaled| value~|x|, we proceed as shown here.
+
+Note that the call of |take_frac| will produce the values 0 and~|x| with about
+half the probability that it will produce any other particular values between 0
+and~|x|, because it rounds its answers.
+
+*/
+
+int unif_rand(int x)
+{
+ int y;
+ next_random();
+ y = take_frac(abs(x), randoms[j_random]);
+ if (y == abs(x))
+ return 0;
+ else if (x > 0)
+ return y;
+ else
+ return -y;
+}
+
+/*tex
+
+Finally, a normal deviate with mean zero and unit standard deviation can readily
+be obtained with the ratio method (Algorithm 3.4.1R in {\sl The Art of Computer
+Programming\/}.
+
+*/
+
+int norm_rand(void)
+{
+ /*tex What the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$. */
+ int x, u, l;
+ do {
+ do {
+ next_random();
+ x = take_frac(112429, randoms[j_random] - fraction_half);
+ /*tex Which is $2^{16}\sqrt{8/e}\approx 112428.82793$. */
+ next_random();
+ u = randoms[j_random];
+ } while (abs(x) >= u);
+ x = make_frac(x, u);
+ /*tex More fuzzyness: $2^{24}\cdot12\ln2\approx139548959.6165$. */
+ l = 139548960 - m_log(u);
+ } while (ab_vs_cd(1024, l, x, x) < 0);
+ return x;
+}
+
+/*tex
+
+This function could also be expressed as a macro, but it is a useful breakpoint
+for debugging.
+
+*/
+
+int fix_int(int val, int min, int max)
+{
+ return (val < min ? min : (val > max ? max : val));
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/arithmetic.w b/Build/source/texk/web2c/luatexdir/tex/arithmetic.w
deleted file mode 100644
index 56fb9568acb..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/arithmetic.w
+++ /dev/null
@@ -1,735 +0,0 @@
-% arithmetic.w
-%
-% Copyright 2009-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/>.
-
-\def\MP{MetaPost}
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@ The principal computations performed by \TeX\ are done entirely in terms of
-integers less than $2^{31}$ in magnitude; and divisions are done only when both
-dividend and divisor are nonnegative. Thus, the arithmetic specified in this
-program can be carried out in exactly the same way on a wide variety of
-computers, including some small ones. Why? Because the arithmetic
-calculations need to be spelled out precisely in order to guarantee that
-\TeX\ will produce identical output on different machines. If some
-quantities were rounded differently in different implementations, we would
-find that line breaks and even page breaks might occur in different places.
-Hence the arithmetic of \TeX\ has been designed with care, and systems that
-claim to be implementations of \TeX82 should follow precisely the
-@:TeX82}{\TeX82@>
-calculations as they appear in the present program.
-
-(Actually there are three places where \TeX\ uses |div| with a possibly negative
-numerator. These are harmless; see |div| in the index. Also if the user
-sets the \.{\\time} or the \.{\\year} to a negative value, some diagnostic
-information will involve negative-numerator division. The same remarks
-apply for |mod| as well as for |div|.)
-
-Here is a routine that calculates half of an integer, using an
-unambiguous convention with respect to signed odd numbers.
-
-@c
-int half(int x)
-{
- if (odd(x))
- return ((x + 1) / 2);
- else
- return (x / 2);
-}
-
-
-@ The following function is used to create a scaled integer from a given decimal
-fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is
-given in |dig[i]|, and the calculation produces a correctly rounded result.
-
-@c
-scaled round_decimals(int k)
-{ /* converts a decimal fraction */
- int a; /* the accumulator */
- a = 0;
- while (k-- > 0) {
- a = (a + dig[k] * two) / 10;
- }
- return ((a + 1) / 2);
-}
-
-
-@ Conversely, here is a procedure analogous to |print_int|. If the output
-of this procedure is subsequently read by \TeX\ and converted by the
-|round_decimals| routine above, it turns out that the original value will
-be reproduced exactly; the ``simplest'' such decimal number is output,
-but there is always at least one digit following the decimal point.
-
-The invariant relation in the \&{repeat} loop is that a sequence of
-decimal digits yet to be printed will yield the original number if and only if
-they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$.
-We can stop if and only if $f=0$ satisfies this condition; the loop will
-terminate before $s$ can possibly become zero.
-
-@c
-void print_scaled(scaled s)
-{ /* prints scaled real, rounded to five digits */
- scaled delta; /* amount of allowable inaccuracy */
- char buffer[20];
- int i = 0;
- if (s < 0) {
- print_char('-');
- negate(s); /* print the sign, if negative */
- }
- print_int(s / unity); /* print the integer part */
- buffer[i++] = '.';
- s = 10 * (s % unity) + 5;
- delta = 10;
- do {
- if (delta > unity)
- s = s + 0100000 - 50000; /* round the last digit */
- buffer[i++] = '0' + (s / unity);
- s = 10 * (s % unity);
- delta = delta * 10;
- } while (s > delta);
- buffer[i++] = '\0';
- tprint(buffer);
-}
-
-@ Physical sizes that a \TeX\ user specifies for portions of documents are
-represented internally as scaled points. Thus, if we define an `sp' (scaled
-@^sp@>
-point) as a unit equal to $2^{-16}$ printer's points, every dimension
-inside of \TeX\ is an integer number of sp. There are exactly
-4,736,286.72 sp per inch. Users are not allowed to specify dimensions
-larger than $2^{30}-1$ sp, which is a distance of about 18.892 feet (5.7583
-meters); two such quantities can be added without overflow on a 32-bit
-computer.
-
-The present implementation of \TeX\ does not check for overflow when
-@^overflow in arithmetic@>
-dimensions are added or subtracted. This could be done by inserting a
-few dozen tests of the form `\ignorespaces|if x>=010000000000 then
-@t\\{report\_overflow}@>|', but the chance of overflow is so remote that
-such tests do not seem worthwhile.
-
-\TeX\ needs to do only a few arithmetic operations on scaled quantities,
-other than addition and subtraction, and the following subroutines do most of
-the work. A single computation might use several subroutine calls, and it is
-desirable to avoid producing multiple error messages in case of arithmetic
-overflow; so the routines set the global variable |arith_error| to |true|
-instead of reporting errors directly to the user. Another global variable,
-|tex_remainder|, holds the remainder after a division.
-
-@c
-boolean arith_error; /* has arithmetic overflow occurred recently? */
-scaled tex_remainder; /* amount subtracted to get an exact division */
-
-
-@ The first arithmetical subroutine we need computes $nx+y$, where |x|
-and~|y| are |scaled| and |n| is an integer. We will also use it to
-multiply integers.
-
-@c
-scaled mult_and_add(int n, scaled x, scaled y, scaled max_answer)
-{
- if (n == 0)
- return y;
- if (n < 0) {
- negate(x);
- negate(n);
- }
- if (((x <= (max_answer - y) / n) && (-x <= (max_answer + y) / n))) {
- return (n * x + y);
- } else {
- arith_error = true;
- return 0;
- }
-}
-
-@ We also need to divide scaled dimensions by integers.
-@c
-scaled x_over_n(scaled x, int n)
-{
- boolean negative; /* should |tex_remainder| be negated? */
- negative = false;
- if (n == 0) {
- arith_error = true;
- tex_remainder = x;
- return 0;
- } else {
- if (n < 0) {
- negate(x);
- negate(n);
- negative = true;
- }
- if (x >= 0) {
- tex_remainder = x % n;
- if (negative)
- negate(tex_remainder);
- return (x / n);
- } else {
- tex_remainder = -((-x) % n);
- if (negative)
- negate(tex_remainder);
- return (-((-x) / n));
- }
- }
-}
-
-
-@ Then comes the multiplication of a scaled number by a fraction |n/d|,
-where |n| and |d| are nonnegative integers |<=@t$2^{16}$@>| and |d| is
-positive. It would be too dangerous to multiply by~|n| and then divide
-by~|d|, in separate operations, since overflow might well occur; and it
-would be too inaccurate to divide by |d| and then multiply by |n|. Hence
-this subroutine simulates 1.5-precision arithmetic.
-
-@c
-scaled xn_over_d(scaled x, int n, int d)
-{
- nonnegative_integer t, u, v, xx, dd; /* intermediate quantities */
- boolean positive = true; /* was |x>=0|? */
- if (x < 0) {
- negate(x);
- positive = false;
- }
- xx = (nonnegative_integer) x;
- dd = (nonnegative_integer) d;
- t = ((xx % 0100000) * (nonnegative_integer) n);
- u = ((xx / 0100000) * (nonnegative_integer) n + (t / 0100000));
- v = (u % dd) * 0100000 + (t % 0100000);
- if (u / dd >= 0100000)
- arith_error = true;
- else
- u = 0100000 * (u / dd) + (v / dd);
- if (positive) {
- tex_remainder = (int) (v % dd);
- return (scaled) u;
- } else {
- /* casts are for ms cl */
- tex_remainder = -(int) (v % dd);
- return -(scaled) (u);
- }
-}
-
-
-@ The next subroutine is used to compute the ``badness'' of glue, when a
-total~|t| is supposed to be made from amounts that sum to~|s|. According
-to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$;
-however, badness is simply a heuristic, so we need not squeeze out the
-last drop of accuracy when computing it. All we really want is an
-approximation that has similar properties.
-@:TeXbook}{\sl The \TeX book@>
-
-The actual method used to compute the badness is easier to read from the
-program than to describe in words. It produces an integer value that is a
-reasonably close approximation to $100(t/s)^3$, and all implementations
-of \TeX\ should use precisely this method. Any badness of $2^{13}$ or more is
-treated as infinitely bad, and represented by 10000.
-
-It is not difficult to prove that $$\hbox{|badness(t+1,s)>=badness(t,s)
->=badness(t,s+1)|}.$$ The badness function defined here is capable of
-computing at most 1095 distinct values, but that is plenty.
-
-@c
-halfword badness(scaled t, scaled s)
-{ /* compute badness, given |t>=0| */
- int r; /* approximation to $\alpha t/s$, where $\alpha^3\approx
- 100\cdot2^{18}$ */
- if (t == 0) {
- return 0;
- } else if (s <= 0) {
- return inf_bad;
- } else {
- if (t <= 7230584)
- r = (t * 297) / s; /* $297^3=99.94\times2^{18}$ */
- else if (s >= 1663497)
- r = t / (s / 297);
- else
- r = t;
- if (r > 1290)
- return inf_bad; /* $1290^3<2^{31}<1291^3$ */
- else
- return ((r * r * r + 0400000) / 01000000);
- /* that was $r^3/2^{18}$, rounded to the nearest integer */
- }
-}
-
-
-@ When \TeX\ ``packages'' a list into a box, it needs to calculate the
-proportionality ratio by which the glue inside the box should stretch
-or shrink. This calculation does not affect \TeX's decision making,
-so the precise details of rounding, etc., in the glue calculation are not
-of critical importance for the consistency of results on different computers.
-
-We shall use the type |glue_ratio| for such proportionality ratios.
-A glue ratio should take the same amount of memory as an
-|integer| (usually 32 bits) if it is to blend smoothly with \TeX's
-other data structures. Thus |glue_ratio| should be equivalent to
-|short_real| in some implementations of PASCAL. Alternatively,
-it is possible to deal with glue ratios using nothing but fixed-point
-arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the
-routines cited there must be modified to allow negative glue ratios.)
-@^system dependencies@>
-
-
-@ This section is (almost) straight from MetaPost. I had to change
-the types (use |integer| instead of |fraction|), but that should
-not have any influence on the actual calculations (the original
-comments refer to quantities like |fraction_four| ($2^{30}$), and
-that is the same as the numeric representation of |max_dimen|).
-
-I've copied the low-level variables and routines that are needed, but
-only those (e.g. |m_log|), not the accompanying ones like |m_exp|. Most
-of the following low-level numeric routines are only needed within the
-calculation of |norm_rand|. I've been forced to rename |make_fraction|
-to |make_frac| because TeX already has a routine by that name with
-a wholly different function (it creates a |fraction_noad| for math
-typesetting) -- Taco
-
-And now let's complete our collection of numeric utility routines
-by considering random number generation.
-\MP{} generates pseudo-random numbers with the additive scheme recommended
-in Section 3.6 of {\sl The Art of Computer Programming}; however, the
-results are random fractions between 0 and |fraction_one-1|, inclusive.
-
-There's an auxiliary array |randoms| that contains 55 pseudo-random
-fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$,
-we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|.
-The global variable |j_random| tells which element has most recently
-been consumed.
-
-@c
-static int randoms[55]; /* the last 55 random values generated */
-static int j_random; /* the number of unused |randoms| */
-scaled random_seed; /* the default random seed */
-
-@ A small bit of metafont is needed.
-
-@c
-#define fraction_half 01000000000 /* $2^{27}$, represents 0.50000000 */
-#define fraction_one 02000000000 /* $2^{28}$, represents 1.00000000 */
-#define fraction_four 010000000000 /* $2^{30}$, represents 4.00000000 */
-#define el_gordo 017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */
-
-@ The |make_frac| routine produces the |fraction| equivalent of
-|p/q|, given integers |p| and~|q|; it computes the integer
-$f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are
-positive. If |p| and |q| are both of the same scaled type |t|,
-the ``type relation'' |make_frac(t,t)=fraction| is valid;
-and it's also possible to use the subroutine ``backwards,'' using
-the relation |make_frac(t,fraction)=t| between scaled types.
-
-If the result would have magnitude $2^{31}$ or more, |make_frac|
-sets |arith_error:=true|. Most of \MP's internal computations have
-been designed to avoid this sort of error.
-
-If this subroutine were programmed in assembly language on a typical
-machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a
-double-precision product can often be input to a fixed-point division
-instruction. But when we are restricted to PASCAL arithmetic it
-is necessary either to resort to multiple-precision maneuvering
-or to use a simple but slow iteration. The multiple-precision technique
-would be about three times faster than the code adopted here, but it
-would be comparatively long and tricky, involving about sixteen
-additional multiplications and divisions.
-
-This operation is part of \MP's ``inner loop''; indeed, it will
-consume nearly 10\%! of the running time (exclusive of input and output)
-if the code below is left unchanged. A machine-dependent recoding
-will therefore make \MP\ run faster. The present implementation
-is highly portable, but slow; it avoids multiplication and division
-except in the initial stage. System wizards should be careful to
-replace it with a routine that is guaranteed to produce identical
-results in all cases.
-@^system dependencies@>
-
-As noted below, a few more routines should also be replaced by machine-dependent
-code, for efficiency. But when a procedure is not part of the ``inner loop,''
-such changes aren't advisable; simplicity and robustness are
-preferable to trickery, unless the cost is too high.
-
-@c
-static int make_frac(int p, int q)
-{
- int f; /* the fraction bits, with a leading 1 bit */
- int n; /* the integer part of $\vert p/q\vert$ */
- register int be_careful; /* disables certain compiler optimizations */
- boolean negative = false; /* should the result be negated? */
- if (p < 0) {
- negate(p);
- negative = true;
- }
- if (q <= 0) {
-#ifdef DEBUG
- if (q == 0)
- confusion("/");
-#endif
- negate(q);
- negative = !negative;
- }
- n = p / q;
- p = p % q;
- if (n >= 8) {
- arith_error = true;
- if (negative)
- return (-el_gordo);
- else
- return el_gordo;
- } else {
- n = (n - 1) * fraction_one;
- /* Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$ */
- /* The |repeat| loop here preserves the following invariant relations
- between |f|, |p|, and~|q|:
- (i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and
- $p_0$ is the original value of~$p$.
-
- Notice that the computation specifies
- |(p-q)+p| instead of |(p+p)-q|, because the latter could overflow.
- Let us hope that optimizing compilers do not miss this point; a
- special variable |be_careful| is used to emphasize the necessary
- order of computation. Optimizing compilers should keep |be_careful|
- in a register, not store it in memory.
- */
- f = 1;
- do {
- be_careful = p - q;
- p = be_careful + p;
- if (p >= 0)
- f = f + f + 1;
- else {
- f += f;
- p = p + q;
- }
- } while (f < fraction_one);
- be_careful = p - q;
- if (be_careful + p >= 0)
- incr(f);
-
- if (negative)
- return (-(f + n));
- else
- return (f + n);
- }
-}
-
-@ @c
-static int take_frac(int q, int f)
-{
- int p; /* the fraction so far */
- int n; /* additional multiple of $q$ */
- register int be_careful; /* disables certain compiler optimizations */
- boolean negative = false; /* should the result be negated? */
- /* Reduce to the case that |f>=0| and |q>0| */
- if (f < 0) {
- negate(f);
- negative = true;
- }
- if (q < 0) {
- negate(q);
- negative = !negative;
- }
-
- if (f < fraction_one) {
- n = 0;
- } else {
- n = f / fraction_one;
- f = f % fraction_one;
- if (q <= el_gordo / n) {
- n = n * q;
- } else {
- arith_error = true;
- n = el_gordo;
- }
- }
- f = f + fraction_one;
- /* Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$ */
- /* The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor
- =\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and
- $f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$.
- */
- p = fraction_half; /* that's $2^{27}$; the invariants hold now with $k=28$ */
- if (q < fraction_four) {
- do {
- if (odd(f))
- p = halfp(p + q);
- else
- p = halfp(p);
- f = halfp(f);
- } while (f != 1);
- } else {
- do {
- if (odd(f))
- p = p + halfp(q - p);
- else
- p = halfp(p);
- f = halfp(f);
- } while (f != 1);
- }
-
- be_careful = n - el_gordo;
- if (be_careful + p > 0) {
- arith_error = true;
- n = el_gordo - p;
- }
- if (negative)
- return (-(n + p));
- else
- return (n + p);
-}
-
-
-
-@ The subroutines for logarithm and exponential involve two tables.
-The first is simple: |two_to_the[k]| equals $2^k$. The second involves
-a bit more calculation, which the author claims to have done correctly:
-|spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)=
-2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the
-nearest integer.
-
-@c
-static int two_to_the[31]; /* powers of two */
-static int spec_log[29]; /* special logarithms */
-
-@ @c
-void initialize_arithmetic(void)
-{
- int k;
- two_to_the[0] = 1;
- for (k = 1; k <= 30; k++)
- two_to_the[k] = 2 * two_to_the[k - 1];
- spec_log[1] = 93032640;
- spec_log[2] = 38612034;
- spec_log[3] = 17922280;
- spec_log[4] = 8662214;
- spec_log[5] = 4261238;
- spec_log[6] = 2113709;
- spec_log[7] = 1052693;
- spec_log[8] = 525315;
- spec_log[9] = 262400;
- spec_log[10] = 131136;
- spec_log[11] = 65552;
- spec_log[12] = 32772;
- spec_log[13] = 16385;
- for (k = 14; k <= 27; k++)
- spec_log[k] = two_to_the[27 - k];
- spec_log[28] = 1;
-}
-
-@ @c
-static int m_log(int x)
-{
- int y, z; /* auxiliary registers */
- int k; /* iteration counter */
- if (x <= 0) {
- /* Handle non-positive logarithm */
- print_err("Logarithm of ");
- print_scaled(x);
- tprint(" has been replaced by 0");
- help2("Since I don't take logs of non-positive numbers,",
- "I'm zeroing this one. Proceed, with fingers crossed.");
- error();
- return 0;
- } else {
- y = 1302456956 + 4 - 100; /* $14\times2^{27}\ln2\approx1302456956.421063$ */
- z = 27595 + 6553600; /* and $2^{16}\times .421063\approx 27595$ */
- while (x < fraction_four) {
- x += x;
- y = y - 93032639;
- z = z - 48782;
- } /* $2^{27}\ln2\approx 93032639.74436163$
- and $2^{16}\times.74436163\approx 48782$ */
- y = y + (z / unity);
- k = 2;
- while (x > fraction_four + 4) {
- /* Increase |k| until |x| can be multiplied by a
- factor of $2^{-k}$, and adjust $y$ accordingly */
- z = ((x - 1) / two_to_the[k]) + 1; /* $z=\lceil x/2^k\rceil$ */
- while (x < fraction_four + z) {
- z = halfp(z + 1);
- k = k + 1;
- }
- y = y + spec_log[k];
- x = x - z;
- }
- return (y / 8);
- }
-}
-
-
-
-@ The following somewhat different subroutine tests rigorously if $ab$ is
-greater than, equal to, or less than~$cd$,
-given integers $(a,b,c,d)$. In most cases a quick decision is reached.
-The result is $+1$, 0, or~$-1$ in the three respective cases.
-
-@c
-static int ab_vs_cd(int a, int b, int c, int d)
-{
- int q, r; /* temporary registers */
- /* Reduce to the case that |a,c>=0|, |b,d>0| */
- if (a < 0) {
- negate(a);
- negate(b);
- }
- if (c < 0) {
- negate(c);
- negate(d);
- }
- if (d <= 0) {
- if (b >= 0)
- return (((a == 0 || b == 0) && (c == 0 || d == 0)) ? 0 : 1);
- if (d == 0)
- return (a == 0 ? 0 : -1);
- q = a;
- a = c;
- c = q;
- q = -b;
- b = -d;
- d = q;
- } else if (b <= 0) {
- if (b < 0 && a > 0)
- return -1;
- return (c == 0 ? 0 : -1);
- }
-
- while (1) {
- q = a / d;
- r = c / b;
- if (q != r)
- return (q > r ? 1 : -1);
- q = a % d;
- r = c % b;
- if (r == 0)
- return (q == 0 ? 0 : 1);
- if (q == 0)
- return -1;
- a = b;
- b = q;
- c = d;
- d = r; /* now |a>d>0| and |c>b>0| */
- }
-}
-
-
-
-@ To consume a random integer, the program below will say `|next_random|'
-and then it will fetch |randoms[j_random]|.
-
-@c
-#define next_random() do { \
- if (j_random==0) new_randoms(); else decr(j_random); \
- } while (0)
-
-static void new_randoms(void)
-{
- int k; /* index into |randoms| */
- int x; /* accumulator */
- for (k = 0; k <= 23; k++) {
- x = randoms[k] - randoms[k + 31];
- if (x < 0)
- x = x + fraction_one;
- randoms[k] = x;
- }
- for (k = 24; k <= 54; k++) {
- x = randoms[k] - randoms[k - 24];
- if (x < 0)
- x = x + fraction_one;
- randoms[k] = x;
- }
- j_random = 54;
-}
-
-
-@ To initialize the |randoms| table, we call the following routine.
-
-@c
-void init_randoms(int seed)
-{
- int j, jj, k; /* more or less random integers */
- int i; /* index into |randoms| */
- j = abs(seed);
- while (j >= fraction_one)
- j = halfp(j);
- k = 1;
- for (i = 0; i <= 54; i++) {
- jj = k;
- k = j - k;
- j = jj;
- if (k < 0)
- k = k + fraction_one;
- randoms[(i * 21) % 55] = j;
- }
- new_randoms();
- new_randoms();
- new_randoms(); /* ``warm up'' the array */
-}
-
-
-@ To produce a uniform random number in the range |0<=u<x| or |0>=u>x|
-or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here.
-
-Note that the call of |take_frac| will produce the values 0 and~|x|
-with about half the probability that it will produce any other particular
-values between 0 and~|x|, because it rounds its answers.
-
-@c
-int unif_rand(int x)
-{
- int y; /* trial value */
- next_random();
- y = take_frac(abs(x), randoms[j_random]);
- if (y == abs(x))
- return 0;
- else if (x > 0)
- return y;
- else
- return -y;
-}
-
-
-@ Finally, a normal deviate with mean zero and unit standard deviation
-can readily be obtained with the ratio method (Algorithm 3.4.1R in
-{\sl The Art of Computer Programming\/}).
-
-@c
-int norm_rand(void)
-{
- int x, u, l; /* what the book would call $2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$ */
- do {
- do {
- next_random();
- x = take_frac(112429, randoms[j_random] - fraction_half);
- /* $2^{16}\sqrt{8/e}\approx 112428.82793$ */
- next_random();
- u = randoms[j_random];
- } while (abs(x) >= u);
- x = make_frac(x, u);
- l = 139548960 - m_log(u); /* $2^{24}\cdot12\ln2\approx139548959.6165$ */
- } while (ab_vs_cd(1024, l, x, x) < 0);
- return x;
-}
-
-@ This function could also be expressed as a macro, but it is a useful
- breakpoint for debugging.
-
-@c
-int fix_int(int val, int min, int max)
-{
- return (val < min ? min : (val > max ? max : val));
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/backend.c b/Build/source/texk/web2c/luatexdir/tex/backend.c
new file mode 100644
index 00000000000..d8c7daed251
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/backend.c
@@ -0,0 +1,123 @@
+/* to fill */
+
+#include "ptexlib.h"
+
+scaled max_v = 0; /* maximum height-plus-depth of pages shipped so far */
+scaled max_h = 0; /* maximum width of pages shipped so far */
+boolean doing_leaders = false; /* are we inside a leader box? */
+int cur_s = -1; /* current depth of output box nesting, initially $-1$ */
+
+static backend_struct *backend = NULL;
+backend_function *backend_out, *backend_out_whatsit, *backend_out_control;
+
+static void missing_backend_function(PDF pdf, halfword p)
+{
+ const char *n = get_node_name(type(p), subtype(p));
+ if (type(p) == whatsit_node)
+ formatted_error("pdf backend","no output function for whatsit %s",n);
+ else
+ formatted_error("pdf backend","no output function for node %s",n);
+}
+
+static void init_none_backend_functions(void)
+{
+ backend_struct *p = &backend[OMODE_NONE];
+ p->name = strdup("NONE");
+}
+
+static void init_pdf_backend_functions(void)
+{
+ backend_struct *p = &backend[OMODE_PDF];
+ p->name = strdup("PDF");
+ p->node_fu[rule_node] = &pdf_place_rule;
+ p->node_fu[glyph_node] = &pdf_place_glyph;
+ p->whatsit_fu[special_node] = &pdf_special;
+ p->whatsit_fu[pdf_literal_node] = &pdf_out_literal;
+ p->whatsit_fu[pdf_refobj_node] = &pdf_ref_obj;
+ p->whatsit_fu[pdf_annot_node] = &do_annot;
+ p->whatsit_fu[pdf_start_link_node] = &do_link;
+ p->whatsit_fu[pdf_end_link_node] = &end_link;
+ p->whatsit_fu[pdf_dest_node] = &do_dest;
+ p->whatsit_fu[pdf_thread_node] = &do_thread;
+ p->whatsit_fu[pdf_end_thread_node] = &end_thread;
+ p->whatsit_fu[late_lua_node] = &late_lua;
+ p->whatsit_fu[pdf_colorstack_node] = &pdf_out_colorstack;
+ p->whatsit_fu[pdf_setmatrix_node] = &pdf_out_setmatrix;
+ p->whatsit_fu[pdf_save_node] = &pdf_out_save;
+ p->whatsit_fu[pdf_restore_node] = &pdf_out_restore;
+ p->control_fu[backend_control_push_list] = &pdf_push_list;
+ p->control_fu[backend_control_pop_list] = &pdf_pop_list;
+ p->control_fu[backend_control_begin_page] = &pdf_begin_page;
+ p->control_fu[backend_control_end_page] = &pdf_end_page;
+ p->control_fu[backend_control_open_file] = &pdf_open_file;
+ p->control_fu[backend_control_write_header] = &pdf_write_header;
+ p->control_fu[backend_control_finish_file] = &pdf_finish_file;
+ p->control_fu[backend_control_set_reference_point] = &pdf_set_reference_point;
+}
+
+static void init_dvi_backend_functions(void)
+{
+ backend_struct *p = &backend[OMODE_DVI];
+ p->name = strdup("DVI");
+ p->node_fu[rule_node] = &dvi_place_rule;
+ p->node_fu[glyph_node] = &dvi_place_glyph;
+ p->whatsit_fu[special_node] = &dvi_special;
+ p->whatsit_fu[late_lua_node] = &late_lua;
+ p->control_fu[backend_control_push_list] = &dvi_push_list;
+ p->control_fu[backend_control_pop_list] = &dvi_pop_list;
+ p->control_fu[backend_control_begin_page] = &dvi_begin_page;
+ p->control_fu[backend_control_end_page] = &dvi_end_page;
+ p->control_fu[backend_control_open_file] = &dvi_open_file;
+ p->control_fu[backend_control_write_header] = &dvi_write_header;
+ p->control_fu[backend_control_finish_file] = &dvi_finish_file;
+ p->control_fu[backend_control_set_reference_point] = &dvi_set_reference_point;
+}
+
+
+void init_backend_functionpointers(output_mode o_mode)
+{
+ int i, j;
+ if (backend == NULL) {
+ backend = xmalloc((MAX_OMODE + 1) * sizeof(backend_struct));
+ for (i = 0; i <= MAX_OMODE; i++) {
+ backend[i].node_fu = xmalloc((MAX_NODE_TYPE + 1) * sizeof(backend_function));
+ backend[i].whatsit_fu = xmalloc((MAX_WHATSIT_TYPE + 1) * sizeof(backend_function));
+ backend[i].control_fu = xmalloc((MAX_CONTROL_TYPE + 1) * sizeof(backend_function));
+ for (j = 0; j < MAX_NODE_TYPE + 1; j++)
+ backend[i].node_fu[j] = &missing_backend_function;
+ for (j = 0; j < MAX_WHATSIT_TYPE + 1; j++)
+ backend[i].whatsit_fu[j] = &missing_backend_function;
+ for (j = 0; j < MAX_CONTROL_TYPE + 1; j++)
+ backend[i].control_fu[j] = &missing_backend_function;
+ }
+ init_none_backend_functions();
+ init_dvi_backend_functions();
+ init_pdf_backend_functions();
+ }
+ backend_out = backend[o_mode].node_fu;
+ backend_out_whatsit = backend[o_mode].whatsit_fu;
+ backend_out_control = backend[o_mode].control_fu;
+}
+
+output_mode get_o_mode(void)
+{
+ output_mode o_mode;
+ if (output_mode_par > 0) {
+ o_mode = OMODE_PDF;
+ } else
+ o_mode = OMODE_DVI;
+ return o_mode;
+}
+
+void fix_o_mode(void)
+{
+ output_mode o_mode = get_o_mode();
+ if (output_mode_used == OMODE_NONE) {
+ output_mode_used = o_mode;
+ /*tex Used by synctex, we need to use output_mode_used there: */
+ static_pdf->o_mode = output_mode_used;
+ } else if (output_mode_used != o_mode) {
+ normal_error("pdf backend", "\\outputmode can only be changed before anything is written to the output");
+ }
+ init_backend_functionpointers(output_mode_used);
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/backend.h b/Build/source/texk/web2c/luatexdir/tex/backend.h
new file mode 100644
index 00000000000..5cfbd06fb90
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/backend.h
@@ -0,0 +1,54 @@
+/* to fill */
+
+#ifndef BACKEND_H
+# define BACKEND_H
+
+#include "ptexlib.h"
+
+extern scaled max_v;
+extern scaled max_h;
+extern boolean doing_leaders;
+extern int cur_s;
+
+# define MAX_CONTROL_TYPE 7
+
+typedef enum {
+ backend_control_push_list = 0,
+ backend_control_pop_list,
+ backend_control_begin_page,
+ backend_control_end_page,
+ backend_control_open_file,
+ backend_control_write_header,
+ backend_control_finish_file,
+ backend_control_set_reference_point
+} backend_control_types ;
+
+typedef void (*backend_function) (); /* variadic arguments */
+
+typedef struct {
+ char *name; /* name of the backend */
+ backend_function *node_fu; /* array of node output functions */
+ backend_function *whatsit_fu; /* array of whatsit output functions */
+ backend_function *control_fu; /* array of whatsit output functions */
+} backend_struct;
+
+/* extern pos_info_structure pos_info; */
+
+extern backend_function *backend_out;
+extern backend_function *backend_out_whatsit;
+extern backend_function *backend_out_control;
+
+/* get_o_mode translates from output_mode to output_mode_used */
+/* fix_o_mode freezes output_mode as soon as anything goes through the backend */
+
+/*
+ extern void check_o_mode(PDF pdf, const char *s, int o_mode, boolean errorflag);
+ extern void ensure_output_file_open(PDF pdf, const char *ext);
+*/
+
+extern void fix_o_mode(void);
+extern output_mode get_o_mode(void);
+
+extern void init_backend_functionpointers(output_mode o_mode);
+
+#endif
diff --git a/Build/source/texk/web2c/luatexdir/tex/buildpage.c b/Build/source/texk/web2c/luatexdir/tex/buildpage.c
new file mode 100644
index 00000000000..81e69dc3b2a
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/buildpage.c
@@ -0,0 +1,1164 @@
+/*
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+
+#define mode mode_par
+#define head head_par
+#define tail tail_par
+
+/*tex
+
+ When \TeX\ appends new material to its main vlist in vertical mode, it uses a
+ method something like |vsplit| to decide where a page ends, except that the
+ calculations are done ``on line'' as new items come in. The main complication
+ in this process is that insertions must be put into their boxes and removed
+ from the vlist, in a more-or-less optimum manner.
+
+ We shall use the term ``current page'' for that part of the main vlist that
+ is being considered as a candidate for being broken off and sent to the
+ user's output routine. The current page starts at |vlink(page_head)|, and it
+ ends at |page_tail|. We have |page_head=page_tail| if this list is empty.
+
+ Utter chaos would reign if the user kept changing page specifications while a
+ page is being constructed, so the page builder keeps the pertinent
+ specifications frozen as soon as the page receives its first box or
+ insertion. The global variable |page_contents| is |empty| when the current
+ page contains only mark nodes and content-less whatsit nodes; it is
+ |inserts_only| if the page contains only insertion nodes in addition to marks
+ and whatsits. Glue nodes, kern nodes, and penalty nodes are discarded until a
+ box or rule node appears, at which time |page_contents| changes to
+ |box_there|. As soon as |page_contents| becomes non-|empty|, the current
+ |vsize| and |max_depth| are squirreled away into |page_goal| and
+ |page_max_depth|; the latter values will be used until the page has been
+ forwarded to the user's output routine. The \.{\\topskip} adjustment is made
+ when |page_contents| changes to |box_there|.
+
+ Although |page_goal| starts out equal to |vsize|, it is decreased by the
+ scaled natural height-plus-depth of the insertions considered so far, and by
+ the \.{\\skip} corrections for those insertions. Therefore it represents the
+ size into which the non-inserted material should fit, assuming that all
+ insertions in the current page have been made.
+
+ The global variables |best_page_break| and |least_page_cost| correspond
+ respectively to the local variables |best_place| and |least_cost| in the
+ |vert_break| routine that we have already studied; i.e., they record the
+ location and value of the best place currently known for breaking the current
+ page. The value of |page_goal| at the time of the best break is stored in
+ |best_size|.
+
+*/
+
+/*tex the final node on the current page */
+
+halfword page_tail;
+
+/*tex what is on the current page so far? */
+
+int page_contents;
+
+/*tex maximum box depth on page being built */
+
+scaled page_max_depth;
+
+/*tex break here to get the best page known so far */
+
+halfword best_page_break;
+
+/*tex the score for this currently best page */
+
+int least_page_cost;
+
+/*tex its |page_goal| */
+
+scaled best_size;
+
+/*tex
+
+ The page builder has another data structure to keep track of insertions. This
+ is a list of four-word nodes, starting and ending at |page_ins_head|. That
+ is, the first element of the list is node |t$_1$=vlink(page_ins_head)|;
+ node $r_j$ is followed by |t$_{j+1}$=vlink(t$_j$)|; and if there are
+ |n| items we have |$_{n+1}$>=page_ins_head|. The |subtype| field of each
+ node in this list refers to an insertion number; for example, `\.{\\insert
+ 250}' would correspond to a node whose |subtype| is |qi(250)| (the same as
+ the |subtype| field of the relevant |ins_node|). These |subtype| fields are
+ in increasing order, and |subtype(page_ins_head)=65535|, so |page_ins_head|
+ serves as a convenient sentinel at the end of the list. A record is present
+ for each insertion number that appears in the current page.
+
+ The |type| field in these nodes distinguishes two possibilities that might
+ occur as we look ahead before deciding on the optimum page break. If
+ |type(r)=inserting_node|, then |height(r)| contains the total of the
+ height-plus-depth dimensions of the box and all its inserts seen so far.
+ |type(r)=split_up_node|, then no more insertions will be made into this box,
+ because at least one previous insertion was too big to fit on the current
+ page; |broken_ptr(r)| points to the node where that insertion will be split,
+ if \TeX\ decides to split it, |broken_ins(r)| points to the insertion node
+ that was tentatively split, and |height(r)| includes also the natural height
+ plus depth of the part that would be split off.
+
+ In both cases, |last_ins_ptr(r)| points to the last |ins_node| encountered
+ for box |qo(subtype(r))| that would be at least partially inserted on the
+ next page; and |best_ins_ptr(r)| points to the last such |ins_node| that
+ should actually be inserted, to get the page with minimum badness among all
+ page breaks considered so far. We have |best_ins_ptr(r)=null| if and only if
+ no insertion for this box should be made to produce this optimum page.
+
+ Pages are built by appending nodes to the current list in \TeX's vertical
+ mode, which is at the outermost level of the semantic nest. This vlist is
+ split into two parts; the ``current page'' that we have been talking so much
+ about already, and the ``contribution list'' that receives new nodes as they
+ are created. The current page contains everything that the page builder has
+ accounted for in its data structures, as described above, while the
+ contribution list contains other things that have been generated by other
+ parts of \TeX\ but have not yet been seen by the page builder. The
+ contribution list starts at |vlink(contrib_head)|, and it ends at the current
+ node in \TeX's vertical mode.
+
+ When \TeX\ has appended new material in vertical mode, it calls the procedure
+ |build_page|, which tries to catch up by moving nodes from the contribution
+ list to the current page. This procedure will succeed in its goal of emptying
+ the contribution list, unless a page break is discovered, i.e., unless the
+ current page has grown to the point where the optimum next page break has
+ been determined. In the latter case, the nodes after the optimum break will
+ go back onto the contribution list, and control will effectively pass to the
+ user's output routine.
+
+ We make |type(page_head)=glue_node|, so that an initial glue node on the
+ current page will not be considered a valid breakpoint.
+
+*/
+
+void initialize_buildpage(void)
+{
+ subtype(page_ins_head) = 65535;
+ type(page_ins_head) = split_up_node;
+ vlink(page_ins_head) = page_ins_head;
+
+ type(page_head) = glue_node;
+ subtype(page_head) = normal;
+}
+
+/*tex
+
+ An array |page_so_far| records the heights and depths of everything on the
+ current page. This array contains six |scaled| numbers, like the similar
+ arrays already considered in |line_break| and |vert_break|; and it also
+ contains |page_goal| and |page_depth|, since these values are all accessible
+ to the user via |set_page_dimen| commands. The value of |page_so_far[1]| is
+ also called |page_total|. The stretch and shrink components of the \.{\\skip}
+ corrections for each insertion are included in |page_so_far|, but the natural
+ space components of these corrections are not, since they have been
+ subtracted from |page_goal|.
+
+ The variable |page_depth| records the depth of the current page; it has been
+ adjusted so that it is at most |page_max_depth|. The variable |last_glue|
+ points to the glue specification of the most recent node contributed from the
+ contribution list, if this was a glue node; otherwise
+ |last_glue=max_halfword|. (If the contribution list is nonempty, however, the
+ value of |last_glue| is not necessarily accurate.) The variables
+ |last_penalty|, |last_kern|, and |last_node_type| are similar. And finally,
+ |insert_penalties| holds the sum of the penalties associated with all split
+ and floating insertions.
+
+*/
+
+/*tex height and glue of the current page */
+
+scaled page_so_far[8];
+
+/*tex used to implement \.{\\lastskip} */
+
+halfword last_glue;
+
+/*tex used to implement \.{\\lastpenalty} */
+
+int last_penalty;
+
+/*tex used to implement \.{\\lastkern} */
+
+scaled last_kern;
+
+/*tex used to implement \.{\\lastnodetype} */
+
+int last_node_type;
+
+/*tex sum of the penalties for held-over insertions */
+
+int insert_penalties;
+
+#define print_plus(A,B) do { \
+ if (page_so_far[(A)]!=0) { \
+ tprint(" plus "); \
+ print_scaled(page_so_far[(A)]); \
+ tprint((B)); \
+ } \
+} while (0)
+
+void print_totals(void)
+{
+ print_scaled(page_total);
+ print_plus(2, "");
+ print_plus(3, "fil");
+ print_plus(4, "fill");
+ print_plus(5, "filll");
+ if (page_shrink != 0) {
+ tprint(" minus ");
+ print_scaled(page_shrink);
+ }
+}
+
+/*tex
+
+ Here is a procedure that is called when the |page_contents| is changing from
+ |empty| to |inserts_only| or |box_there|.
+
+*/
+
+#define do_all_six(A) A(1);A(2);A(3);A(4);A(5);A(6);A(7)
+#define set_page_so_far_zero(A) page_so_far[(A)]=0
+
+void freeze_page_specs(int s)
+{
+ page_contents = s;
+ page_goal = vsize_par;
+ page_max_depth = max_depth_par;
+ page_depth = 0;
+ do_all_six(set_page_so_far_zero);
+ least_page_cost = awful_bad;
+ if (tracing_pages_par > 0) {
+ begin_diagnostic();
+ tprint_nl("%% goal height=");
+ print_scaled(page_goal);
+ tprint(", max depth=");
+ print_scaled(page_max_depth);
+ end_diagnostic(false);
+ }
+}
+
+/*tex
+
+ The global variable |output_active| is true during the time the user's output
+ routine is driving \TeX.
+
+*/
+
+/*tex Are we in the midst of an output routine? */
+
+boolean output_active;
+
+/*tex
+
+ The page builder is ready to start a fresh page if we initialize the
+ following state variables. (However, the page insertion list is initialized
+ elsewhere.)
+
+*/
+
+void start_new_page(void)
+{
+ page_contents = empty;
+ page_tail = page_head;
+ vlink(page_head) = null;
+ last_glue = max_halfword;
+ last_penalty = 0;
+ last_kern = 0;
+ last_node_type = -1;
+ page_depth = 0;
+ page_max_depth = 0;
+}
+
+/*tex
+
+ At certain times box \.{\\outputbox} is supposed to be void (i.e., |null|),
+ or an insertion box is supposed to be ready to accept a vertical list. If
+ not, an error message is printed, and the following subroutine flushes the
+ unwanted contents, reporting them to the user.
+
+*/
+
+static void box_error(int n)
+{
+ error();
+ begin_diagnostic();
+ tprint_nl("The following box has been deleted:");
+ show_box(box(n));
+ end_diagnostic(true);
+ flush_node_list(box(n));
+ box(n) = null;
+}
+
+/*tex
+
+ The following procedure guarantees that a given box register does not contain
+ an \.{\\hbox}.
+
+*/
+
+static void ensure_vbox(int n)
+{
+ halfword p = box(n);
+ if (p != null && type(p) == hlist_node) {
+ print_err("Insertions can only be added to a vbox");
+ help3(
+ "Tut tut: You're trying to \\insert into a",
+ "\\box register that now contains an \\hbox.",
+ "Proceed, and I'll discard its present contents."
+ );
+ box_error(n);
+ }
+}
+
+/*tex
+
+ \TeX\ is not always in vertical mode at the time |build_page| is called; the
+ current mode reflects what \TeX\ should return to, after the contribution
+ list has been emptied. A call on |build_page| should be immediately followed
+ by `|goto big_switch|', which is \TeX's central control point.
+
+*/
+
+/*tex Append contributions to the current page. */
+
+void build_page(void)
+{
+ /*tex the node being appended */
+ halfword p;
+ /*tex nodes being examined */
+ halfword q, r;
+ /*tex badness and cost of current page */
+ int b, c;
+ /*tex penalty to be added to the badness */
+ int pi = 0;
+ /*tex insertion box number */
+ int n;
+ /*tex sizes used for insertion calculations */
+ scaled delta, h, w;
+ int id, sk, i;
+ if ((vlink(contrib_head) == null) || output_active)
+ return;
+ do {
+ CONTINUE:
+ p = vlink(contrib_head);
+ /*tex Update the values of |last_glue|, |last_penalty|, and |last_kern|. */
+ if (last_glue != max_halfword) {
+ flush_node(last_glue);
+ last_glue = max_halfword;
+ }
+ last_penalty = 0;
+ last_kern = 0;
+ last_node_type = type(p) + 1;
+ if (type(p) == glue_node) {
+ last_glue = new_glue(p);
+ } else if (type(p) == penalty_node) {
+ last_penalty = penalty(p);
+ } else if (type(p) == kern_node) {
+ last_kern = width(p);
+ }
+ /*tex
+
+ Move node |p| to the current page; if it is time for a page break,
+ put the nodes following the break back onto the contribution list,
+ and |return| to the users output routine if there is one.
+
+ The code here is an example of a many-way switch into routines that
+ merge together in different places. Some people call this
+ unstructured programming, but the author doesn't see much wrong with
+ it, as long as the various labels have a well-understood meaning.
+
+ If the current page is empty and node |p| is to be deleted, |goto
+ done1|; otherwise use node |p| to update the state of the current
+ page; if this node is an insertion, |goto contribute|; otherwise if
+ this node is not a legal breakpoint, |goto contribute| or
+ |update_heights|; otherwise set |pi| to the penalty associated with
+ this breakpoint.
+
+ The title of this section is already so long, it seems best to avoid
+ making it more accurate but still longer, by mentioning the fact that
+ a kern node at the end of the contribution list will not be
+ contributed until we know its successor.
+
+ */
+ switch (type(p)) {
+ case hlist_node:
+ case vlist_node:
+ case rule_node:
+ if (page_contents < box_there) {
+ /*tex
+
+ Initialize the current page, insert the \.{\\topskip}
+ glue ahead of |p|, and |goto continue|.
+
+ */
+ if (page_contents == empty)
+ freeze_page_specs(box_there);
+ else
+ page_contents = box_there;
+ q = new_skip_param(top_skip_code);
+ if ((type(p) == hlist_node) && is_mirrored(body_direction_par)) {
+ if (width(q) > depth(p))
+ width(q) = width(q) - depth(p);
+ else
+ width(q) = 0;
+ } else {
+ if (width(q) > height(p))
+ width(q) = width(q) - height(p);
+ else
+ width(q) = 0;
+ }
+ couple_nodes(q, p);
+ couple_nodes(contrib_head, q);
+ goto CONTINUE;
+ } else {
+ /*tex
+
+ Prepare to move a box or rule node to the current page,
+ then |goto contribute|.
+
+ */
+ if ((type(p) == hlist_node) && is_mirrored(body_direction_par)) {
+ page_total = page_total + page_depth + depth(p);
+ page_depth = height(p);
+ } else {
+ page_total = page_total + page_depth + height(p);
+ page_depth = depth(p);
+ }
+ goto CONTRIBUTE;
+
+ }
+ break;
+ case boundary_node:
+ case whatsit_node:
+ goto CONTRIBUTE;
+ break;
+ case glue_node:
+ if (page_contents < box_there)
+ goto DONE1;
+ else if (precedes_break(page_tail))
+ pi = 0;
+ else
+ goto UPDATE_HEIGHTS;
+ break;
+ case kern_node:
+ if (page_contents < box_there)
+ goto DONE1;
+ else if (vlink(p) == null)
+ goto EXIT;
+ else if (type(vlink(p)) == glue_node)
+ pi = 0;
+ else
+ goto UPDATE_HEIGHTS;
+ break;
+ case penalty_node:
+ if (page_contents < box_there)
+ goto DONE1;
+ else
+ pi = penalty(p);
+ break;
+ case mark_node:
+ goto CONTRIBUTE;
+ break;
+ case ins_node:
+ /*tex Append an insertion to the current page and |goto contribute|. */
+ if (page_contents == empty)
+ freeze_page_specs(inserts_only);
+ n = subtype(p);
+ r = page_ins_head;
+ i = 1 ;
+ while (n >= subtype(vlink(r))) {
+ r = vlink(r);
+ i = i + 1 ;
+ }
+ if (subtype(r) != n) {
+ /*tex
+
+ Create a page insertion node with |subtype(r)=qi(n)|, and
+ include the glue correction for box |n| in the current
+ page state.
+
+ We take note of the value of \.{\\skip} |n| and the
+ height plus depth of \.{\\box}~|n| only when the first
+ \.{\\insert}~|n| node is encountered for a new page. A
+ user who changes the contents of \.{\\box}~|n| after that
+ first \.{\\insert}~|n| had better be either extremely
+ careful or extremely lucky, or both.
+
+ */
+ id = callback_defined(build_page_insert_callback);
+ if (id != 0) {
+ run_callback(id, "dd->d",n,i,&sk);
+ } else {
+ sk = n;
+ }
+ q = new_node(inserting_node, n);
+ try_couple_nodes(q, vlink(r));
+ couple_nodes(r, q);
+ r = q;
+ ensure_vbox(n);
+ if (box(n) == null)
+ height(r) = 0;
+ else
+ height(r) = height(box(n)) + depth(box(n));
+ best_ins_ptr(r) = null;
+ q = skip(sk);
+ if (count(n) == 1000)
+ h = height(r);
+ else
+ h = x_over_n(height(r), 1000) * count(n);
+ page_goal = page_goal - h - width(q);
+ if (stretch_order(q) > 1)
+ page_so_far[1 + stretch_order(q)] = page_so_far[1 + stretch_order(q)] + stretch(q);
+ else
+ page_so_far[2 + stretch_order(q)] = page_so_far[2 + stretch_order(q)] + stretch(q);
+ page_shrink = page_shrink + shrink(q);
+ if ((shrink_order(q) != normal) && (shrink(q) != 0)) {
+ print_err("Infinite glue shrinkage inserted from \\skip");
+ print_int(n);
+ help3(
+ "The correction glue for page breaking with insertions",
+ "must have finite shrinkability. But you may proceed,",
+ "since the offensive shrinkability has been made finite."
+ );
+ error();
+ }
+
+ }
+ if (type(r) == split_up_node) {
+ insert_penalties = insert_penalties + float_cost(p);
+ } else {
+ last_ins_ptr(r) = p;
+ delta = page_goal - page_total - page_depth + page_shrink;
+ /*tex This much room is left if we shrink the maximum. */
+ if (count(n) == 1000) {
+ h = height(p);
+ } else {
+ /*tex This much room is needed. */
+ h = x_over_n(height(p), 1000) * count(n);
+ }
+ if (((h <= 0) || (h <= delta))
+ && (height(p) + height(r) <= dimen(n))) {
+ page_goal = page_goal - h;
+ height(r) = height(r) + height(p);
+ } else {
+ /*tex
+
+ Find the best way to split the insertion, and change
+ |type(r)| to |split_up_node|.
+
+ Here is the code that will split a long footnote
+ between pages, in an emergency. The current situation
+ deserves to be recapitulated: Node |p| is an
+ insertion into box |n|; the insertion will not fit,
+ in its entirety, either because it would make the
+ total contents of box |n| greater than \.{\\dimen}
+ |n|, or because it would make the incremental amount
+ of growth |h| greater than the available space
+ |delta|, or both. (This amount |h| has been weighted
+ by the insertion scaling factor, i.e., by \.{\\count}
+ |n| over 1000.) Now we will choose the best way to
+ break the vlist of the insertion, using the same
+ criteria as in the \.{\\vsplit} operation.
+
+ */
+ if (count(n) <= 0) {
+ w = max_dimen;
+ } else {
+ w = page_goal - page_total - page_depth;
+ if (count(n) != 1000)
+ w = x_over_n(w, count(n)) * 1000;
+ }
+ if (w > dimen(n) - height(r))
+ w = dimen(n) - height(r);
+ q = vert_break(ins_ptr(p), w, depth(p));
+ height(r) = height(r) + best_height_plus_depth;
+ if (tracing_pages_par > 0) {
+ /*tex Display the insertion split cost. */
+ begin_diagnostic();
+ tprint_nl("% split");
+ print_int(n);
+ tprint(" to ");
+ print_scaled(w);
+ print_char(',');
+ print_scaled(best_height_plus_depth);
+ tprint(" p=");
+ if (q == null)
+ print_int(eject_penalty);
+ else if (type(q) == penalty_node)
+ print_int(penalty(q));
+ else
+ print_char('0');
+ end_diagnostic(false);
+ }
+ if (count(n) != 1000)
+ best_height_plus_depth = x_over_n(best_height_plus_depth, 1000) * count(n);
+ page_goal = page_goal - best_height_plus_depth;
+ type(r) = split_up_node;
+ broken_ptr(r) = q;
+ broken_ins(r) = p;
+ if (q == null)
+ insert_penalties = insert_penalties + eject_penalty;
+ else if (type(q) == penalty_node)
+ insert_penalties = insert_penalties + penalty(q);
+ }
+ }
+ goto CONTRIBUTE;
+
+ break;
+ default:
+ formatted_error("pagebuilder","invalid node of type %d in vertical mode", type(p));
+ break;
+ }
+ /*tex
+
+ Check if node |p| is a new champion breakpoint; then if it is time
+ for a page break, prepare for output, and either fire up the users
+ output routine and |return| or ship out the page and |goto done|.
+
+ */
+ if (pi < inf_penalty) {
+ /*tex
+
+ Compute the badness, |b|, of the current page, using |awful_bad|
+ if the box is too full.
+
+ */
+ if (page_total < page_goal) {
+ if ((page_so_far[3] != 0) || (page_so_far[4] != 0) ||
+ (page_so_far[5] != 0))
+ b = 0;
+ else
+ b = badness(page_goal - page_total, page_so_far[2]);
+ } else if (page_total - page_goal > page_shrink) {
+ b = awful_bad;
+ } else {
+ b = badness(page_total - page_goal, page_shrink);
+ }
+ if (b < awful_bad) {
+ if (pi <= eject_penalty)
+ c = pi;
+ else if (b < inf_bad)
+ c = b + pi + insert_penalties;
+ else
+ c = deplorable;
+ } else {
+ c = b;
+ }
+ if (insert_penalties >= 10000)
+ c = awful_bad;
+ if (tracing_pages_par > 0) {
+ /*tex Display the page break cost. */
+ begin_diagnostic();
+ tprint_nl("%");
+ tprint(" t=");
+ print_totals();
+ tprint(" g=");
+ print_scaled(page_goal);
+ tprint(" b=");
+ if (b == awful_bad)
+ print_char('*');
+ else
+ print_int(b);
+ tprint(" p=");
+ print_int(pi);
+ tprint(" c=");
+ if (c == awful_bad)
+ print_char('*');
+ else
+ print_int(c);
+ if (c <= least_page_cost)
+ print_char('#');
+ end_diagnostic(false);
+ }
+ if (c <= least_page_cost) {
+ best_page_break = p;
+ best_size = page_goal;
+ least_page_cost = c;
+ r = vlink(page_ins_head);
+ while (r != page_ins_head) {
+ best_ins_ptr(r) = last_ins_ptr(r);
+ r = vlink(r);
+ }
+ }
+ if ((c == awful_bad) || (pi <= eject_penalty)) {
+ /*tex Output the current page at the best place. */
+ fire_up(p);
+ if (output_active) {
+ /*tex User's output routine will act. */
+ goto EXIT;
+ }
+ /*tex The page has been shipped out by default output routine. */
+ goto DONE;
+ }
+ }
+ if ((type(p) < glue_node) || (type(p) > kern_node))
+ goto CONTRIBUTE;
+ UPDATE_HEIGHTS:
+ /*tex
+
+ Go here to record glue in the |active_height| table. Update the
+ current page measurements with respect to the glue or kern specified
+ by node~|p|.
+
+ */
+ if (type(p) != kern_node) {
+ if (stretch_order(p) > 1)
+ page_so_far[1 + stretch_order(p)] = page_so_far[1 + stretch_order(p)] + stretch(p);
+ else
+ page_so_far[2 + stretch_order(p)] = page_so_far[2 + stretch_order(p)] + stretch(p);
+ page_shrink = page_shrink + shrink(p);
+ if ((shrink_order(p) != normal) && (shrink(p) != 0)) {
+ print_err("Infinite glue shrinkage found on current page");
+ help4(
+ "The page about to be output contains some infinitely",
+ "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
+ "Such glue doesn't belong there; but you can safely proceed,",
+ "since the offensive shrinkability has been made finite."
+ );
+ error();
+ reset_glue_to_zero(p);
+ shrink_order(p) = normal;
+ }
+ }
+ page_total = page_total + page_depth + width(p);
+ page_depth = 0;
+ CONTRIBUTE:
+ /*tex
+
+ Go here to link a node into the current page. Make sure that
+ |page_max_depth| is not exceeded.
+
+ */
+ if (page_depth > page_max_depth) {
+ page_total = page_total + page_depth - page_max_depth;
+ page_depth = page_max_depth;
+ }
+ /*tex Link node |p| into the current page and |goto done|. */
+ couple_nodes(page_tail, p);
+ page_tail = p;
+ try_couple_nodes(contrib_head,vlink(p));
+ vlink(p) = null;
+ goto DONE;
+ DONE1:
+ /*tex Recycle node |p|. */
+ try_couple_nodes(contrib_head,vlink(p));
+ vlink(p) = null;
+ if (saving_vdiscards_par > 0) {
+ if (page_disc == null) {
+ page_disc = p;
+ } else {
+ couple_nodes(tail_page_disc, p);
+ }
+ tail_page_disc = p;
+ } else {
+ flush_node_list(p);
+ }
+ DONE:
+ ;
+ } while (vlink(contrib_head) != null);
+ /*tex Make the contribution list empty by setting its tail to |contrib_head|. */
+ contrib_tail = contrib_head;
+ EXIT:
+ ;
+}
+
+/*tex
+
+ When the page builder has looked at as much material as could appear before
+ the next page break, it makes its decision. The break that gave minimum
+ badness will be used to put a completed ``page'' into box \.{\\outputbox},
+ with insertions appended to their other boxes.
+
+ We also set the values of |top_mark|, |first_mark|, and |bot_mark|. The
+ program uses the fact that |bot_mark(x)<>null| implies |first_mark(x)<>null|;
+ it also knows that |bot_mark(x)=null| implies
+ |top_mark(x)=first_mark(x)=null|.
+
+ The |fire_up| subroutine prepares to output the current page at the best
+ place; then it fires up the user's output routine, if there is one, or it
+ simply ships out the page. There is one parameter, |c|, which represents the
+ node that was being contributed to the page when the decision to force an
+ output was made.
+
+*/
+
+void fire_up(halfword c)
+{
+ /*tex nodes being examined and/or changed */
+ halfword p, q, r, s;
+ /*tex predecessor of |p| */
+ halfword prev_p;
+ /*tex insertion box number */
+ int n;
+ /*tex should the present insertion be held over? */
+ boolean wait;
+ /*tex saved value of |vbadness| */
+ int save_vbadness;
+ /*tex saved value of |vfuzz| */
+ scaled save_vfuzz;
+ /*tex saved value of |split_top_skip| */
+ halfword save_split_top_skip;
+ /*tex for looping through the marks */
+ halfword i;
+ /*tex Set the value of |output_penalty|. */
+ if (type(best_page_break) == penalty_node) {
+ geq_word_define(int_base + output_penalty_code,
+ penalty(best_page_break));
+ penalty(best_page_break) = inf_penalty;
+ } else {
+ geq_word_define(int_base + output_penalty_code, inf_penalty);
+ }
+
+ for (i = 0; i <= biggest_used_mark; i++) {
+ if (bot_mark(i) != null) {
+ if (top_mark(i) != null)
+ delete_token_ref(top_mark(i));
+ set_top_mark(i, bot_mark(i));
+ add_token_ref(top_mark(i));
+ delete_first_mark(i);
+ }
+ }
+ /*tex
+
+ Put the optimal current page into box |output_box|, update |first_mark|
+ and |bot_mark|, append insertions to their boxes, and put the remaining
+ nodes back on the contribution list.
+
+ As the page is finally being prepared for output, pointer |p| runs
+ through the vlist, with |prev_p| trailing behind; pointer |q| is the tail
+ of a list of insertions that are being held over for a subsequent page.
+
+ */
+ if (c == best_page_break) {
+ /*tex |c| not yet linked in */
+ best_page_break = null;
+ }
+ /*tex Ensure that box |output_box| is empty before output. */
+ if (box(output_box_par) != null) {
+ print_err("\\box");
+ print_int(output_box_par);
+ tprint(" is not void");
+ help2(
+ "You shouldn't use \\box\\outputbox except in \\output routines.",
+ "Proceed, and I'll discard its present contents."
+ );
+ box_error(output_box_par);
+ }
+ /*tex This will count the number of insertions held over. */
+ insert_penalties = 0;
+ save_split_top_skip = split_top_skip_par;
+ if (holding_inserts_par <= 0) {
+ /*tex
+
+ Prepare all the boxes involved in insertions to act as queues. If
+ many insertions are supposed to go into the same box, we want to know
+ the position of the last node in that box, so that we don't need to
+ waste time when linking further information into it. The
+ |last_ins_ptr| fields of the page insertion nodes are therefore used
+ for this purpose during the packaging phase.
+
+ */
+ r = vlink(page_ins_head);
+ while (r != page_ins_head) {
+ if (best_ins_ptr(r) != null) {
+ n = subtype(r);
+ ensure_vbox(n);
+ if (box(n) == null)
+ box(n) = new_null_box();
+ p = box(n) + list_offset;
+ while (vlink(p) != null)
+ p = vlink(p);
+ last_ins_ptr(r) = p;
+ }
+ r = vlink(r);
+ }
+
+ }
+ q = hold_head;
+ vlink(q) = null;
+ prev_p = page_head;
+ p = vlink(prev_p);
+ while (p != best_page_break) {
+ if (type(p) == ins_node) {
+ if (holding_inserts_par <= 0) {
+ /*tex
+
+ Either insert the material specified by node |p| into the
+ appropriate box, or hold it for the next page; also delete
+ node |p| from the current page.
+
+ We will set |best_ins_ptr:=null| and package the box
+ corresponding to insertion node~|r|, just after making the
+ final insertion into that box. If this final insertion is
+ `|split_up_node|', the remainder after splitting and pruning
+ (if any) will be carried over to the next page.
+
+ */
+ r = vlink(page_ins_head);
+ while (subtype(r) != subtype(p))
+ r = vlink(r);
+ if (best_ins_ptr(r) == null) {
+ wait = true;
+ } else {
+ wait = false;
+ s = last_ins_ptr(r);
+ vlink(s) = ins_ptr(p);
+ if (best_ins_ptr(r) == p) {
+ halfword t;
+ /*tex
+
+ Wrap up the box specified by node |r|, splitting node
+ |p| if called for; set |wait:=true| if node |p| holds
+ a remainder after splitting.
+
+ */
+ if (type(r) == split_up_node) {
+ if ((broken_ins(r) == p) && (broken_ptr(r) != null)) {
+ while (vlink(s) != broken_ptr(r))
+ s = vlink(s);
+ vlink(s) = null;
+ split_top_skip_par = split_top_ptr(p);
+ ins_ptr(p) =
+ prune_page_top(broken_ptr(r), false);
+ if (ins_ptr(p) != null) {
+ t = vpack(ins_ptr(p), 0, additional, -1);
+ height(p) = height(t) + depth(t);
+ list_ptr(t) = null;
+ flush_node(t);
+ wait = true;
+ }
+ }
+ }
+ best_ins_ptr(r) = null;
+ n = subtype(r);
+ t = list_ptr(box(n));
+ list_ptr(box(n)) = null;
+ flush_node(box(n));
+ box(n) = vpack(t, 0, additional, body_direction_par);
+
+ } else {
+ while (vlink(s) != null)
+ s = vlink(s);
+ last_ins_ptr(r) = s;
+ }
+ }
+ /*tex
+
+ Either append the insertion node |p| after node |q|, and
+ remove it from the current page, or delete |node(p)|.
+
+ */
+ try_couple_nodes(prev_p, vlink(p));
+ vlink(p) = null;
+ if (wait) {
+ couple_nodes(q, p);
+ q = p;
+ incr(insert_penalties);
+ } else {
+ ins_ptr(p) = null;
+ flush_node(p);
+ }
+ p = prev_p;
+
+ }
+ } else if (type(p) == mark_node) {
+ /*tex Update the values of |first_mark| and |bot_mark|. */
+ if (first_mark(mark_class(p)) == null) {
+ set_first_mark(mark_class(p), mark_ptr(p));
+ add_token_ref(first_mark(mark_class(p)));
+ }
+ if (bot_mark(mark_class(p)) != null)
+ delete_token_ref(bot_mark(mark_class(p)));
+ set_bot_mark(mark_class(p), mark_ptr(p));
+ add_token_ref(bot_mark(mark_class(p)));
+
+ }
+ prev_p = p;
+ p = vlink(prev_p);
+ }
+ split_top_skip_par = save_split_top_skip;
+ /*tex
+
+ Break the current page at node |p|, put it in box~|output_box|, and put
+ the remaining nodes on the contribution list.
+
+ When the following code is executed, the current page runs from node
+ |vlink(page_head)| to node |prev_p|, and the nodes from |p| to
+ |page_tail| are to be placed back at the front of the contribution list.
+ Furthermore the heldover insertions appear in a list from
+ |vlink(hold_head)| to |q|; we will put them into the current page list
+ for safekeeping while the user's output routine is active. We might have
+ |q=hold_head|; and |p=null| if and only if |prev_p=page_tail|. Error
+ messages are suppressed within |vpackage|, since the box might appear to
+ be overfull or underfull simply because the stretch and shrink from the
+ \.{\\skip} registers for inserts are not actually present in the box.
+
+ */
+ if (p != null) {
+ if (vlink(contrib_head) == null) {
+ contrib_tail = page_tail;
+ }
+ couple_nodes(page_tail,vlink(contrib_head));
+ couple_nodes(contrib_head, p);
+ vlink(prev_p) = null;
+ }
+ save_vbadness = vbadness_par;
+ vbadness_par = inf_bad;
+ save_vfuzz = vfuzz_par;
+ /*tex Inhibit error messages. */
+ vfuzz_par = max_dimen;
+ box(output_box_par) = filtered_vpackage(vlink(page_head),
+ best_size, exactly, page_max_depth, output_group, body_direction_par, 0, 0);
+ vbadness_par = save_vbadness;
+ vfuzz_par = save_vfuzz;
+ if (last_glue != max_halfword)
+ flush_node(last_glue);
+ /*tex Start a new current page. This sets |last_glue:=max_halfword|. */
+ start_new_page();
+ if (q != hold_head) {
+ vlink(page_head) = vlink(hold_head);
+ page_tail = q;
+ }
+ /*tex Delete the page-insertion nodes. */
+ r = vlink(page_ins_head);
+ while (r != page_ins_head) {
+ /*tex Todo: couple. */
+ q = vlink(r);
+ flush_node(r);
+ r = q;
+ }
+ vlink(page_ins_head) = page_ins_head;
+ for (i = 0; i <= biggest_used_mark; i++) {
+ if ((top_mark(i) != null) && (first_mark(i) == null)) {
+ set_first_mark(i, top_mark(i));
+ add_token_ref(top_mark(i));
+ }
+ }
+ if (output_routine_par != null) {
+ if (dead_cycles >= max_dead_cycles_par) {
+ /*tex Explain that too many dead cycles have occurred in a row. */
+ print_err("Output loop---");
+ print_int(dead_cycles);
+ tprint(" consecutive dead cycles");
+ help3(
+ "I've concluded that your \\output is awry; it never does a",
+ "\\shipout, so I'm shipping \\box\\outputbox out myself. Next time",
+ "increase \\maxdeadcycles if you want me to be more patient!"
+ );
+ error();
+ } else {
+ /*tex Fire up the users output routine and |return|. */
+ output_active = true;
+ incr(dead_cycles);
+ push_nest();
+ mode = -vmode;
+ prev_depth_par = ignore_depth;
+ mode_line_par = -line;
+ begin_token_list(output_routine_par, output_text);
+ new_save_level(output_group);
+ normal_paragraph();
+ scan_left_brace();
+ return;
+ }
+ }
+ /*tex
+
+ Perform the default output routine. The list of heldover insertions,
+ running from |vlink(page_head)| to |page_tail|, must be moved to the
+ contribution list when the user has specified no output routine.
+
+ */
+ if (vlink(page_head) != null) {
+ if (vlink(contrib_head) == null) {
+ contrib_tail = page_tail;
+ } else {
+ vlink(page_tail) = vlink(contrib_head);
+ }
+ vlink(contrib_head) = vlink(page_head);
+ vlink(page_head) = null;
+ page_tail = page_head;
+ }
+ flush_node_list(page_disc);
+ page_disc = null;
+ ship_out(static_pdf, box(output_box_par), SHIPPING_PAGE);
+ box(output_box_par) = null;
+}
+
+/*tex
+
+ When the user's output routine finishes, it has constructed a vlist in
+ internal vertical mode, and \TeX\ will do the following:
+
+*/
+
+void resume_after_output(void)
+{
+ if ((iloc != null) || ((token_type != output_text) && (token_type != backed_up))) {
+ /*tex Recover from an unbalanced output routine */
+ print_err("Unbalanced output routine");
+ help2(
+ "Your sneaky output routine has problematic {'s and/or }'s.",
+ "I can't handle that very well; good luck."
+ );
+ error();
+ /*tex Loops forever if reading from a file, since |null=min_halfword<=0|. */
+ do {
+ get_token();
+ } while (iloc != null);
+ }
+ /*tex Conserve stack space in case more outputs are triggered. */
+ end_token_list();
+ end_graf(bottom_level);
+ unsave();
+ output_active = false;
+ insert_penalties = 0;
+ /*tex Ensure that box |output_box| is empty after output. */
+ if (box(output_box_par) != null) {
+ print_err("Output routine didn't use all of \\box");
+ print_int(output_box_par);
+ help3(
+ "Your \\output commands should empty \\box\\outputbox,",
+ "e.g., by saying `\\shipout\\box\\outputbox'.",
+ "Proceed; I'll discard its present contents."
+ );
+ box_error(output_box_par);
+ }
+ if (tail != head) {
+ /*tex Current list goes after heldover insertions. */
+ try_couple_nodes(page_tail, vlink(head));
+ page_tail = tail;
+ }
+ if (vlink(page_head) != null) {
+ /* Both go before heldover contributions. */
+ if (vlink(contrib_head) == null)
+ contrib_tail = page_tail;
+ try_couple_nodes(page_tail, vlink(contrib_head));
+ try_couple_nodes(contrib_head, vlink(page_head));
+ vlink(page_head) = null;
+ page_tail = page_head;
+ }
+ flush_node_list(page_disc);
+ page_disc = null;
+ pop_nest();
+ normal_page_filter(after_output);
+ build_page();
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/buildpage.w b/Build/source/texk/web2c/luatexdir/tex/buildpage.w
deleted file mode 100644
index cba07cbf6f6..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/buildpage.w
+++ /dev/null
@@ -1,1013 +0,0 @@
-% buildpage.w
-%
-% Copyright 2009-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 mode mode_par
-#define head head_par
-#define tail tail_par
-
-@ When \TeX\ appends new material to its main vlist in vertical mode, it uses
-a method something like |vsplit| to decide where a page ends, except that
-the calculations are done ``on line'' as new items come in.
-The main complication in this process is that insertions must be put
-into their boxes and removed from the vlist, in a more-or-less optimum manner.
-
-We shall use the term ``current page'' for that part of the main vlist that
-is being considered as a candidate for being broken off and sent to the
-user's output routine. The current page starts at |vlink(page_head)|, and
-it ends at |page_tail|. We have |page_head=page_tail| if this list is empty.
-@^current page@>
-
-Utter chaos would reign if the user kept changing page specifications
-while a page is being constructed, so the page builder keeps the pertinent
-specifications frozen as soon as the page receives its first box or
-insertion. The global variable |page_contents| is |empty| when the
-current page contains only mark nodes and content-less whatsit nodes; it
-is |inserts_only| if the page contains only insertion nodes in addition to
-marks and whatsits. Glue nodes, kern nodes, and penalty nodes are
-discarded until a box or rule node appears, at which time |page_contents|
-changes to |box_there|. As soon as |page_contents| becomes non-|empty|,
-the current |vsize| and |max_depth| are squirreled away into |page_goal|
-and |page_max_depth|; the latter values will be used until the page has
-been forwarded to the user's output routine. The \.{\\topskip} adjustment
-is made when |page_contents| changes to |box_there|.
-
-Although |page_goal| starts out equal to |vsize|, it is decreased by the
-scaled natural height-plus-depth of the insertions considered so far, and by
-the \.{\\skip} corrections for those insertions. Therefore it represents
-the size into which the non-inserted material should fit, assuming that
-all insertions in the current page have been made.
-
-The global variables |best_page_break| and |least_page_cost| correspond
-respectively to the local variables |best_place| and |least_cost| in the
-|vert_break| routine that we have already studied; i.e., they record the
-location and value of the best place currently known for breaking the
-current page. The value of |page_goal| at the time of the best break is
-stored in |best_size|.
-
-@c
-halfword page_tail; /* the final node on the current page */
-int page_contents; /* what is on the current page so far? */
-scaled page_max_depth; /* maximum box depth on page being built */
-halfword best_page_break; /* break here to get the best page known so far */
-int least_page_cost; /* the score for this currently best page */
-scaled best_size; /* its |page_goal| */
-
-@ The page builder has another data structure to keep track of insertions.
-This is a list of four-word nodes, starting and ending at |page_ins_head|.
-That is, the first element of the list is node |r@t$_1$@>=vlink(page_ins_head)|;
-node $r_j$ is followed by |r@t$_{j+1}$@>=vlink(r@t$_j$@>)|; and if there are
-|n| items we have |r@t$_{n+1}$@>=page_ins_head|. The |subtype| field of
-each node in this list refers to an insertion number; for example, `\.{\\insert
-250}' would correspond to a node whose |subtype| is |qi(250)|
-(the same as the |subtype| field of the relevant |ins_node|). These |subtype|
-fields are in increasing order, and |subtype(page_ins_head)=65535|, so
-|page_ins_head| serves as a convenient sentinel
-at the end of the list. A record is present for each insertion number that
-appears in the current page.
-
-The |type| field in these nodes distinguishes two possibilities that
-might occur as we look ahead before deciding on the optimum page break.
-If |type(r)=inserting_node|, then |height(r)| contains the total of the
-height-plus-depth dimensions of the box and all its inserts seen so far.
- |type(r)=split_up_node|, then no more insertions will be made into this box,
-because at least one previous insertion was too big to fit on the current
-page; |broken_ptr(r)| points to the node where that insertion will be
-split, if \TeX\ decides to split it, |broken_ins(r)| points to the
-insertion node that was tentatively split, and |height(r)| includes also the
-natural height plus depth of the part that would be split off.
-
-In both cases, |last_ins_ptr(r)| points to the last |ins_node|
-encountered for box |qo(subtype(r))| that would be at least partially
-inserted on the next page; and |best_ins_ptr(r)| points to the last
-such |ins_node| that should actually be inserted, to get the page with
-minimum badness among all page breaks considered so far. We have
-|best_ins_ptr(r)=null| if and only if no insertion for this box should
-be made to produce this optimum page.
-
-@ Pages are built by appending nodes to the current list in \TeX's
-vertical mode, which is at the outermost level of the semantic nest. This
-vlist is split into two parts; the ``current page'' that we have been
-talking so much about already, and the ``contribution list'' that receives
-new nodes as they are created. The current page contains everything that
-the page builder has accounted for in its data structures, as described
-above, while the contribution list contains other things that have been
-generated by other parts of \TeX\ but have not yet been
-seen by the page builder.
-The contribution list starts at |vlink(contrib_head)|, and it ends at the
-current node in \TeX's vertical mode.
-
-When \TeX\ has appended new material in vertical mode, it calls the procedure
-|build_page|, which tries to catch up by moving nodes from the contribution
-list to the current page. This procedure will succeed in its goal of
-emptying the contribution list, unless a page break is discovered, i.e.,
-unless the current page has grown to the point where the optimum next
-page break has been determined. In the latter case, the nodes after the
-optimum break will go back onto the contribution list, and control will
-effectively pass to the user's output routine.
-
-We make |type(page_head)=glue_node|, so that an initial glue node on
-the current page will not be considered a valid breakpoint.
-
-@c
-void initialize_buildpage(void)
-{
- subtype(page_ins_head) = 65535;
- type(page_ins_head) = split_up_node;
- vlink(page_ins_head) = page_ins_head;
-
- type(page_head) = glue_node;
- subtype(page_head) = normal;
-}
-
-
-@ An array |page_so_far| records the heights and depths of everything
-on the current page. This array contains six |scaled| numbers, like the
-similar arrays already considered in |line_break| and |vert_break|; and it
-also contains |page_goal| and |page_depth|, since these values are
-all accessible to the user via |set_page_dimen| commands. The
-value of |page_so_far[1]| is also called |page_total|. The stretch
-and shrink components of the \.{\\skip} corrections for each insertion are
-included in |page_so_far|, but the natural space components of these
-corrections are not, since they have been subtracted from |page_goal|.
-
-The variable |page_depth| records the depth of the current page; it has been
-adjusted so that it is at most |page_max_depth|. The variable
-|last_glue| points to the glue specification of the most recent node
-contributed from the contribution list, if this was a glue node; otherwise
-|last_glue=max_halfword|. (If the contribution list is nonempty,
-however, the value of |last_glue| is not necessarily accurate.)
-The variables |last_penalty|, |last_kern|, and |last_node_type|
-are similar. And
-finally, |insert_penalties| holds the sum of the penalties associated with
-all split and floating insertions.
-
-@c
-scaled page_so_far[8]; /* height and glue of the current page */
-halfword last_glue; /* used to implement \.{\\lastskip} */
-int last_penalty; /* used to implement \.{\\lastpenalty} */
-scaled last_kern; /* used to implement \.{\\lastkern} */
-int last_node_type; /* used to implement \.{\\lastnodetype} */
-int insert_penalties; /* sum of the penalties for held-over insertions */
-
-#define print_plus(A,B) do { \
- if (page_so_far[(A)]!=0) { \
- tprint(" plus "); \
- print_scaled(page_so_far[(A)]); \
- tprint((B)); \
- } \
-} while (0)
-
-void print_totals(void)
-{
- print_scaled(page_total);
- print_plus(2, "");
- print_plus(3, "fil");
- print_plus(4, "fill");
- print_plus(5, "filll");
- if (page_shrink != 0) {
- tprint(" minus ");
- print_scaled(page_shrink);
- }
-}
-
-@ Here is a procedure that is called when the |page_contents| is changing
-from |empty| to |inserts_only| or |box_there|.
-
-@c
-#define do_all_six(A) A(1);A(2);A(3);A(4);A(5);A(6);A(7)
-#define set_page_so_far_zero(A) page_so_far[(A)]=0
-
-void freeze_page_specs(int s)
-{
- page_contents = s;
- page_goal = vsize_par;
- page_max_depth = max_depth_par;
- page_depth = 0;
- do_all_six(set_page_so_far_zero);
- least_page_cost = awful_bad;
- if (tracing_pages_par > 0) {
- begin_diagnostic();
- tprint_nl("%% goal height=");
- print_scaled(page_goal);
- tprint(", max depth=");
- print_scaled(page_max_depth);
- end_diagnostic(false);
- }
-}
-
-@ The global variable |output_active| is true during the time the
-user's output routine is driving \TeX.
-
-@c
-boolean output_active; /* are we in the midst of an output routine? */
-
-@ The page builder is ready to start a fresh page if we initialize
-the following state variables. (However, the page insertion list is initialized
-elsewhere.)
-
-@c
-void start_new_page(void)
-{
- page_contents = empty;
- page_tail = page_head;
- vlink(page_head) = null;
- last_glue = max_halfword;
- last_penalty = 0;
- last_kern = 0;
- last_node_type = -1;
- page_depth = 0;
- page_max_depth = 0;
-}
-
-@ At certain times box \.{\\outputbox} is supposed to be void (i.e., |null|),
-or an insertion box is supposed to be ready to accept a vertical list.
-If not, an error message is printed, and the following subroutine
-flushes the unwanted contents, reporting them to the user.
-
-@c
-static void box_error(int n)
-{
- error();
- begin_diagnostic();
- tprint_nl("The following box has been deleted:");
- show_box(box(n));
- end_diagnostic(true);
- flush_node_list(box(n));
- box(n) = null;
-}
-
-@ The following procedure guarantees that a given box register
-does not contain an \.{\\hbox}.
-
-@c
-static void ensure_vbox(int n)
-{
- halfword p; /* the box register contents */
- p = box(n);
- if (p != null && type(p) == hlist_node) {
- print_err("Insertions can only be added to a vbox");
- help3("Tut tut: You're trying to \\insert into a",
- "\\box register that now contains an \\hbox.",
- "Proceed, and I'll discard its present contents.");
- box_error(n);
- }
-}
-
-@ \TeX\ is not always in vertical mode at the time |build_page|
-is called; the current mode reflects what \TeX\ should return to, after
-the contribution list has been emptied. A call on |build_page| should
-be immediately followed by `|goto big_switch|', which is \TeX's central
-control point.
-
-@c
-void build_page(void)
-{ /* append contributions to the current page */
- halfword p; /* the node being appended */
- halfword q, r; /* nodes being examined */
- int b, c; /* badness and cost of current page */
- int pi = 0; /* penalty to be added to the badness */
- int n; /* insertion box number */
- scaled delta, h, w; /* sizes used for insertion calculations */
- int id, sk, i;
- if ((vlink(contrib_head) == null) || output_active)
- return;
- do {
- CONTINUE:
- p = vlink(contrib_head);
- /* Update the values of |last_glue|, |last_penalty|, and |last_kern| */
- if (last_glue != max_halfword) {
- flush_node(last_glue);
- last_glue = max_halfword;
- }
- last_penalty = 0;
- last_kern = 0;
- last_node_type = type(p) + 1;
- if (type(p) == glue_node) {
- last_glue = new_glue(p);
- } else if (type(p) == penalty_node) {
- last_penalty = penalty(p);
- } else if (type(p) == kern_node) {
- last_kern = width(p);
- }
-
- /* Move node |p| to the current page; if it is time for a page break,
- put the nodes following the break back onto the contribution list,
- and |return| to the users output routine if there is one */
-
- /* The code here is an example of a many-way switch into routines that
- merge together in different places. Some people call this unstructured
- programming, but the author doesn't see much wrong with it, as long as
- the various labels have a well-understood meaning.
- */
- /* If the current page is empty and node |p| is to be deleted, |goto done1|;
- otherwise use node |p| to update the state of the current page;
- if this node is an insertion, |goto contribute|; otherwise if this node
- is not a legal breakpoint, |goto contribute| or |update_heights|;
- otherwise set |pi| to the penalty associated with this breakpoint */
- /* The title of this section is already so long, it seems best to avoid
- making it more accurate but still longer, by mentioning the fact that a
- kern node at the end of the contribution list will not be contributed until
- we know its successor. */
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- if (page_contents < box_there) {
- /* Initialize the current page, insert the \.{\\topskip} glue
- ahead of |p|, and |goto continue| */
- if (page_contents == empty)
- freeze_page_specs(box_there);
- else
- page_contents = box_there;
- q = new_skip_param(top_skip_code);
- if ((type(p) == hlist_node) && is_mirrored(body_direction_par)) {
- if (width(q) > depth(p))
- width(q) = width(q) - depth(p);
- else
- width(q) = 0;
- } else {
- if (width(q) > height(p))
- width(q) = width(q) - height(p);
- else
- width(q) = 0;
- }
- couple_nodes(q, p);
- couple_nodes(contrib_head, q);
- goto CONTINUE;
-
- } else {
- /* Prepare to move a box or rule node to the current page,
- then |goto contribute| */
- if ((type(p) == hlist_node) && is_mirrored(body_direction_par)) {
- page_total = page_total + page_depth + depth(p);
- page_depth = height(p);
- } else {
- page_total = page_total + page_depth + height(p);
- page_depth = depth(p);
- }
- goto CONTRIBUTE;
-
- }
- break;
- case boundary_node:
- case whatsit_node:
- goto CONTRIBUTE;
- break;
- case glue_node:
- if (page_contents < box_there)
- goto DONE1;
- else if (precedes_break(page_tail))
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case kern_node:
- if (page_contents < box_there)
- goto DONE1;
- else if (vlink(p) == null)
- goto EXIT;
- else if (type(vlink(p)) == glue_node)
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case penalty_node:
- if (page_contents < box_there)
- goto DONE1;
- else
- pi = penalty(p);
- break;
- case mark_node:
- goto CONTRIBUTE;
- break;
- case ins_node:
- /* Append an insertion to the current page and |goto contribute| */
- if (page_contents == empty)
- freeze_page_specs(inserts_only);
- n = subtype(p);
- r = page_ins_head;
- i = 1 ;
- while (n >= subtype(vlink(r))) {
- r = vlink(r);
- i = i + 1 ;
- }
- if (subtype(r) != n) {
- /* Create a page insertion node with |subtype(r)=qi(n)|, and
- include the glue correction for box |n| in the
- current page state */
- /* We take note of the value of \.{\\skip} |n| and the height plus depth
- of \.{\\box}~|n| only when the first \.{\\insert}~|n| node is
- encountered for a new page. A user who changes the contents of \.{\\box}~|n|
- after that first \.{\\insert}~|n| had better be either extremely careful
- or extremely lucky, or both. */
-id = callback_defined(build_page_insert_callback);
-if (id != 0) {
- run_callback(id, "dd->d",n,i,&sk);
-} else {
- sk = n;
-}
- q = new_node(inserting_node, n);
- try_couple_nodes(q, vlink(r));
- couple_nodes(r, q);
- r = q;
- ensure_vbox(n);
- if (box(n) == null)
- height(r) = 0;
- else
- height(r) = height(box(n)) + depth(box(n));
- best_ins_ptr(r) = null;
- /* q = skip(n); */
-q = skip(sk);
- if (count(n) == 1000)
- h = height(r);
- else
- h = x_over_n(height(r), 1000) * count(n);
- page_goal = page_goal - h - width(q);
- if (stretch_order(q) > 1)
- page_so_far[1 + stretch_order(q)] = page_so_far[1 + stretch_order(q)] + stretch(q);
- else
- page_so_far[2 + stretch_order(q)] = page_so_far[2 + stretch_order(q)] + stretch(q);
- page_shrink = page_shrink + shrink(q);
- if ((shrink_order(q) != normal) && (shrink(q) != 0)) {
- print_err("Infinite glue shrinkage inserted from \\skip");
- print_int(n);
- help3
- ("The correction glue for page breaking with insertions",
- "must have finite shrinkability. But you may proceed,",
- "since the offensive shrinkability has been made finite.");
- error();
- }
-
- }
- if (type(r) == split_up_node) {
- insert_penalties = insert_penalties + float_cost(p);
- } else {
- last_ins_ptr(r) = p;
- delta = page_goal - page_total - page_depth + page_shrink;
- /* this much room is left if we shrink the maximum */
- if (count(n) == 1000)
- h = height(p);
- else
- h = x_over_n(height(p), 1000) * count(n); /* this much room is needed */
- if (((h <= 0) || (h <= delta))
- && (height(p) + height(r) <= dimen(n))) {
- page_goal = page_goal - h;
- height(r) = height(r) + height(p);
- } else {
- /* Find the best way to split the insertion, and change
- |type(r)| to |split_up_node| */
- /* Here is the code that will split a long footnote between pages, in an
- emergency. The current situation deserves to be recapitulated: Node |p|
- is an insertion into box |n|; the insertion will not fit, in its entirety,
- either because it would make the total contents of box |n| greater than
- \.{\\dimen} |n|, or because it would make the incremental amount of growth
- |h| greater than the available space |delta|, or both. (This amount |h| has
- been weighted by the insertion scaling factor, i.e., by \.{\\count} |n|
- over 1000.) Now we will choose the best way to break the vlist of the
- insertion, using the same criteria as in the \.{\\vsplit} operation.
- */
- if (count(n) <= 0) {
- w = max_dimen;
- } else {
- w = page_goal - page_total - page_depth;
- if (count(n) != 1000)
- w = x_over_n(w, count(n)) * 1000;
- }
- if (w > dimen(n) - height(r))
- w = dimen(n) - height(r);
- q = vert_break(ins_ptr(p), w, depth(p));
- height(r) = height(r) + best_height_plus_depth;
- if (tracing_pages_par > 0) {
- /* Display the insertion split cost */
- begin_diagnostic();
- tprint_nl("% split");
- print_int(n);
- tprint(" to ");
- print_scaled(w);
- print_char(',');
- print_scaled(best_height_plus_depth);
- tprint(" p=");
- if (q == null)
- print_int(eject_penalty);
- else if (type(q) == penalty_node)
- print_int(penalty(q));
- else
- print_char('0');
- end_diagnostic(false);
-
- }
- if (count(n) != 1000)
- best_height_plus_depth =
- x_over_n(best_height_plus_depth, 1000) * count(n);
- page_goal = page_goal - best_height_plus_depth;
- type(r) = split_up_node;
- broken_ptr(r) = q;
- broken_ins(r) = p;
- if (q == null)
- insert_penalties = insert_penalties + eject_penalty;
- else if (type(q) == penalty_node)
- insert_penalties = insert_penalties + penalty(q);
- }
- }
- goto CONTRIBUTE;
-
- break;
- default:
- fprintf(stderr, "type(p)=%d\n", type(p));
- confusion("page");
- break;
- }
-
- /* Check if node |p| is a new champion breakpoint; then if it is time for
- a page break, prepare for output, and either fire up the users
- output routine and |return| or ship out the page and |goto done| */
-
- if (pi < inf_penalty) {
- /* Compute the badness, |b|, of the current page,
- using |awful_bad| if the box is too full */
- if (page_total < page_goal) {
- if ((page_so_far[3] != 0) || (page_so_far[4] != 0) ||
- (page_so_far[5] != 0))
- b = 0;
- else
- b = badness(page_goal - page_total, page_so_far[2]);
- } else if (page_total - page_goal > page_shrink) {
- b = awful_bad;
- } else {
- b = badness(page_total - page_goal, page_shrink);
- }
-
- if (b < awful_bad) {
- if (pi <= eject_penalty)
- c = pi;
- else if (b < inf_bad)
- c = b + pi + insert_penalties;
- else
- c = deplorable;
- } else {
- c = b;
- }
- if (insert_penalties >= 10000)
- c = awful_bad;
- if (tracing_pages_par > 0) {
- /* Display the page break cost */
- begin_diagnostic();
- tprint_nl("%");
- tprint(" t=");
- print_totals();
- tprint(" g=");
- print_scaled(page_goal);
- tprint(" b=");
- if (b == awful_bad)
- print_char('*');
- else
- print_int(b);
- tprint(" p=");
- print_int(pi);
- tprint(" c=");
- if (c == awful_bad)
- print_char('*');
- else
- print_int(c);
- if (c <= least_page_cost)
- print_char('#');
- end_diagnostic(false);
-
- }
- if (c <= least_page_cost) {
- best_page_break = p;
- best_size = page_goal;
- least_page_cost = c;
- r = vlink(page_ins_head);
- while (r != page_ins_head) {
- best_ins_ptr(r) = last_ins_ptr(r);
- r = vlink(r);
- }
- }
- if ((c == awful_bad) || (pi <= eject_penalty)) {
- fire_up(p); /* output the current page at the best place */
- if (output_active)
- goto EXIT; /* user's output routine will act */
- goto DONE; /* the page has been shipped out by default output routine */
- }
- }
-
- if ((type(p) < glue_node) || (type(p) > kern_node))
- goto CONTRIBUTE;
-
- UPDATE_HEIGHTS: /* go here to record glue in the |active_height| table */
-
- /* Update the current page measurements with respect to the
- glue or kern specified by node~|p| */
- if (type(p) != kern_node) {
- if (stretch_order(p) > 1)
- page_so_far[1 + stretch_order(p)] = page_so_far[1 + stretch_order(p)] + stretch(p);
- else
- page_so_far[2 + stretch_order(p)] = page_so_far[2 + stretch_order(p)] + stretch(p);
- page_shrink = page_shrink + shrink(p);
- if ((shrink_order(p) != normal) && (shrink(p) != 0)) {
- print_err("Infinite glue shrinkage found on current page");
- help4("The page about to be output contains some infinitely",
- "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
- "Such glue doesn't belong there; but you can safely proceed,",
- "since the offensive shrinkability has been made finite.");
- error();
- reset_glue_to_zero(p);
- shrink_order(p) = normal;
- }
- }
- page_total = page_total + page_depth + width(p);
- page_depth = 0;
-
- CONTRIBUTE: /* go here to link a node into the current page */
-
- /* Make sure that |page_max_depth| is not exceeded */
- if (page_depth > page_max_depth) {
- page_total = page_total + page_depth - page_max_depth;
- page_depth = page_max_depth;
- }
-
- /* Link node |p| into the current page and |goto done| */
- couple_nodes(page_tail, p);
- page_tail = p;
- try_couple_nodes(contrib_head,vlink(p));
- vlink(p) = null;
- goto DONE;
- DONE1:
- /* Recycle node |p| */
- try_couple_nodes(contrib_head,vlink(p));
- vlink(p) = null;
- if (saving_vdiscards_par > 0) {
- if (page_disc == null) {
- page_disc = p;
- } else {
- couple_nodes(tail_page_disc, p);
- }
- tail_page_disc = p;
- } else {
- flush_node_list(p);
- }
- DONE:
- ;
- } while (vlink(contrib_head) != null);
- /* Make the contribution list empty by setting its tail to |contrib_head| */
- contrib_tail = contrib_head;
- EXIT:
- ;
-}
-
-@ When the page builder has looked at as much material as could appear before
-the next page break, it makes its decision. The break that gave minimum
-badness will be used to put a completed ``page'' into box \.{\\outputbox}, with insertions
-appended to their other boxes.
-
-We also set the values of |top_mark|, |first_mark|, and |bot_mark|. The
-program uses the fact that |bot_mark(x)<>null| implies |first_mark(x)<>null|;
-it also knows that |bot_mark(x)=null| implies |top_mark(x)=first_mark(x)=null|.
-
-The |fire_up| subroutine prepares to output the current page at the best
-place; then it fires up the user's output routine, if there is one,
-or it simply ships out the page. There is one parameter, |c|, which represents
-the node that was being contributed to the page when the decision to
-force an output was made.
-
-@c
-void fire_up(halfword c)
-{
- halfword p, q, r, s; /* nodes being examined and/or changed */
- halfword prev_p; /* predecessor of |p| */
- int n; /* insertion box number */
- boolean wait; /* should the present insertion be held over? */
- int save_vbadness; /* saved value of |vbadness| */
- scaled save_vfuzz; /* saved value of |vfuzz| */
- halfword save_split_top_skip; /* saved value of |split_top_skip| */
- halfword i; /* for looping through the marks */
-
- /* Set the value of |output_penalty| */
- if (type(best_page_break) == penalty_node) {
- geq_word_define(int_base + output_penalty_code,
- penalty(best_page_break));
- penalty(best_page_break) = inf_penalty;
- } else {
- geq_word_define(int_base + output_penalty_code, inf_penalty);
- }
-
- for (i = 0; i <= biggest_used_mark; i++) {
- if (bot_mark(i) != null) {
- if (top_mark(i) != null)
- delete_token_ref(top_mark(i));
- set_top_mark(i, bot_mark(i));
- add_token_ref(top_mark(i));
- delete_first_mark(i);
- }
- }
- /* Put the optimal current page into box |output_box|, update |first_mark| and
- |bot_mark|, append insertions to their boxes, and put the
- remaining nodes back on the contribution list; */
-
- /* As the page is finally being prepared for output,
- pointer |p| runs through the vlist, with |prev_p| trailing behind;
- pointer |q| is the tail of a list of insertions that
- are being held over for a subsequent page. */
-
- if (c == best_page_break)
- best_page_break = null; /* |c| not yet linked in */
- /* Ensure that box |output_box| is empty before output */
- if (box(output_box_par) != null) {
- print_err("\\box");
- print_int(output_box_par);
- tprint(" is not void");
- help2("You shouldn't use \\box\\outputbox except in \\output routines.",
- "Proceed, and I'll discard its present contents.");
- box_error(output_box_par);
- }
-
- insert_penalties = 0; /* this will count the number of insertions held over */
- save_split_top_skip = split_top_skip_par;
- if (holding_inserts_par <= 0) {
- /* Prepare all the boxes involved in insertions to act as queues */
- /* If many insertions are supposed to go into the same box, we want to know
- the position of the last node in that box, so that we don't need to waste time
- when linking further information into it. The |last_ins_ptr| fields of the
- page insertion nodes are therefore used for this purpose during the
- packaging phase. */
-
- r = vlink(page_ins_head);
- while (r != page_ins_head) {
- if (best_ins_ptr(r) != null) {
- n = subtype(r);
- ensure_vbox(n);
- if (box(n) == null)
- box(n) = new_null_box();
- p = box(n) + list_offset;
- while (vlink(p) != null)
- p = vlink(p);
- last_ins_ptr(r) = p;
- }
- r = vlink(r);
- }
-
- }
- q = hold_head;
- vlink(q) = null;
- prev_p = page_head;
- p = vlink(prev_p);
- while (p != best_page_break) {
- if (type(p) == ins_node) {
- if (holding_inserts_par <= 0) {
- /* Either insert the material specified by node |p| into the
- appropriate box, or hold it for the next page;
- also delete node |p| from the current page */
- /* We will set |best_ins_ptr:=null| and package the box corresponding to
- insertion node~|r|, just after making the final insertion into that box.
- If this final insertion is `|split_up_node|', the remainder after splitting
- and pruning (if any) will be carried over to the next page. */
- r = vlink(page_ins_head);
- while (subtype(r) != subtype(p))
- r = vlink(r);
- if (best_ins_ptr(r) == null) {
- wait = true;
- } else {
- wait = false;
- s = last_ins_ptr(r);
- vlink(s) = ins_ptr(p);
- if (best_ins_ptr(r) == p) {
- halfword t; /* was a global temp_ptr */
- /* Wrap up the box specified by node |r|, splitting node |p| if
- called for; set |wait:=true| if node |p| holds a remainder after
- splitting */
- if (type(r) == split_up_node) {
- if ((broken_ins(r) == p) && (broken_ptr(r) != null)) {
- while (vlink(s) != broken_ptr(r))
- s = vlink(s);
- vlink(s) = null;
- split_top_skip_par = split_top_ptr(p);
- ins_ptr(p) =
- prune_page_top(broken_ptr(r), false);
- if (ins_ptr(p) != null) {
- t = vpack(ins_ptr(p), 0, additional, -1);
- height(p) = height(t) + depth(t);
- list_ptr(t) = null;
- flush_node(t);
- wait = true;
- }
- }
- }
- best_ins_ptr(r) = null;
- n = subtype(r);
- t = list_ptr(box(n));
- list_ptr(box(n)) = null;
- flush_node(box(n));
- box(n) = vpack(t, 0, additional, body_direction_par);
-
- } else {
- while (vlink(s) != null)
- s = vlink(s);
- last_ins_ptr(r) = s;
- }
- }
- /* Either append the insertion node |p| after node |q|, and remove it
- from the current page, or delete |node(p)| */
- try_couple_nodes(prev_p, vlink(p));
- vlink(p) = null;
- if (wait) {
- couple_nodes(q, p);
- q = p;
- incr(insert_penalties);
- } else {
- ins_ptr(p) = null;
- flush_node(p);
- }
- p = prev_p;
-
- }
- } else if (type(p) == mark_node) {
- /* Update the values of |first_mark| and |bot_mark| */
- if (first_mark(mark_class(p)) == null) {
- set_first_mark(mark_class(p), mark_ptr(p));
- add_token_ref(first_mark(mark_class(p)));
- }
- if (bot_mark(mark_class(p)) != null)
- delete_token_ref(bot_mark(mark_class(p)));
- set_bot_mark(mark_class(p), mark_ptr(p));
- add_token_ref(bot_mark(mark_class(p)));
-
- }
- prev_p = p;
- p = vlink(prev_p);
- }
- split_top_skip_par = save_split_top_skip;
- /* Break the current page at node |p|, put it in box~|output_box|,
- and put the remaining nodes on the contribution list */
- /* When the following code is executed, the current page runs from node
- |vlink(page_head)| to node |prev_p|, and the nodes from |p| to |page_tail|
- are to be placed back at the front of the contribution list. Furthermore
- the heldover insertions appear in a list from |vlink(hold_head)| to |q|; we
- will put them into the current page list for safekeeping while the user's
- output routine is active. We might have |q=hold_head|; and |p=null| if
- and only if |prev_p=page_tail|. Error messages are suppressed within
- |vpackage|, since the box might appear to be overfull or underfull simply
- because the stretch and shrink from the \.{\\skip} registers for inserts
- are not actually present in the box. */
-
- if (p != null) {
- if (vlink(contrib_head) == null) {
- contrib_tail = page_tail;
- }
- couple_nodes(page_tail,vlink(contrib_head));
- couple_nodes(contrib_head, p);
- vlink(prev_p) = null;
- }
- save_vbadness = vbadness_par;
- vbadness_par = inf_bad;
- save_vfuzz = vfuzz_par;
- vfuzz_par = max_dimen; /* inhibit error messages */
- box(output_box_par) = filtered_vpackage(vlink(page_head),
- best_size, exactly, page_max_depth, output_group, body_direction_par, 0, 0);
- vbadness_par = save_vbadness;
- vfuzz_par = save_vfuzz;
- if (last_glue != max_halfword)
- flush_node(last_glue);
- /* Start a new current page */
- start_new_page(); /* this sets |last_glue:=max_halfword| */
- if (q != hold_head) {
- vlink(page_head) = vlink(hold_head);
- page_tail = q;
- }
-
- /* Delete the page-insertion nodes */
- r = vlink(page_ins_head);
- while (r != page_ins_head) {
- /* todo: couple */
- q = vlink(r);
- flush_node(r);
- r = q;
- }
- vlink(page_ins_head) = page_ins_head;
-
- for (i = 0; i <= biggest_used_mark; i++) {
- if ((top_mark(i) != null) && (first_mark(i) == null)) {
- set_first_mark(i, top_mark(i));
- add_token_ref(top_mark(i));
- }
- }
- if (output_routine_par != null) {
- if (dead_cycles >= max_dead_cycles_par) {
- /* Explain that too many dead cycles have occurred in a row */
- print_err("Output loop---");
- print_int(dead_cycles);
- tprint(" consecutive dead cycles");
- help3("I've concluded that your \\output is awry; it never does a",
- "\\shipout, so I'm shipping \\box\\outputbox out myself. Next time",
- "increase \\maxdeadcycles if you want me to be more patient!");
- error();
-
- } else {
- /* Fire up the users output routine and |return| */
- output_active = true;
- incr(dead_cycles);
- push_nest();
- mode = -vmode;
- prev_depth_par = ignore_depth;
- mode_line_par = -line;
- begin_token_list(output_routine_par, output_text);
- new_save_level(output_group);
- normal_paragraph();
- scan_left_brace();
- return;
-
- }
- }
- /* Perform the default output routine */
- /* The list of heldover insertions, running from |vlink(page_head)| to
- |page_tail|, must be moved to the contribution list when the user has
- specified no output routine. */
- if (vlink(page_head) != null) {
- if (vlink(contrib_head) == null) {
- contrib_tail = page_tail;
- } else {
- vlink(page_tail) = vlink(contrib_head);
- }
- vlink(contrib_head) = vlink(page_head);
- vlink(page_head) = null;
- page_tail = page_head;
- }
- flush_node_list(page_disc);
- page_disc = null;
- ship_out(static_pdf, box(output_box_par), SHIPPING_PAGE);
- box(output_box_par) = null;
-}
-
-@ When the user's output routine finishes, it has constructed a vlist
-in internal vertical mode, and \TeX\ will do the following:
-
-@c
-void resume_after_output(void)
-{
- if ((iloc != null)
- || ((token_type != output_text) && (token_type != backed_up))) {
- /* Recover from an unbalanced output routine */
- print_err("Unbalanced output routine");
- help2("Your sneaky output routine has problematic {'s and/or }'s.",
- "I can't handle that very well; good luck.");
- error();
- do {
- get_token();
- } while (iloc != null);
- /* loops forever if reading from a file, since |null=min_halfword<=0| */
-
- }
- end_token_list(); /* conserve stack space in case more outputs are triggered */
- end_graf(bottom_level);
- unsave();
- output_active = false;
- insert_penalties = 0;
- /* Ensure that box |output_box| is empty after output */
- if (box(output_box_par) != null) {
- print_err("Output routine didn't use all of \\box");
- print_int(output_box_par);
- help3("Your \\output commands should empty \\box\\outputbox,",
- "e.g., by saying `\\shipout\\box\\outputbox'.",
- "Proceed; I'll discard its present contents.");
- box_error(output_box_par);
- }
-
- if (tail != head) { /* current list goes after heldover insertions */
- try_couple_nodes(page_tail, vlink(head));
- page_tail = tail;
- }
- if (vlink(page_head) != null) { /* and both go before heldover contributions */
- if (vlink(contrib_head) == null)
- contrib_tail = page_tail;
- try_couple_nodes(page_tail, vlink(contrib_head));
- try_couple_nodes(contrib_head, vlink(page_head));
- vlink(page_head) = null;
- page_tail = page_head;
- }
- flush_node_list(page_disc);
- page_disc = null;
- pop_nest();
- normal_page_filter(after_output);
- build_page();
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/commands.w b/Build/source/texk/web2c/luatexdir/tex/commands.c
index 38975eb1699..aceb0eb093d 100644
--- a/Build/source/texk/web2c/luatexdir/tex/commands.w
+++ b/Build/source/texk/web2c/luatexdir/tex/commands.c
@@ -1,34 +1,36 @@
-% commands.w
-%
-% Copyright 2009-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/>.
-
-\def\eTeX{e-\TeX}
-
-@ @c
+/*
+commands.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ The symbolic names for glue parameters are put into \TeX's hash table
-by using the routine called |primitive|, defined below. Let us enter them
-now, so that we don't have to list all those parameter names anywhere else.
+/*tex
+
+The symbolic names for glue parameters are put into \TeX's hash table by using
+the routine called |primitive|, defined below. Let us enter them now, so that we
+don't have to list all those parameter names anywhere else.
+
+*/
-@c
void initialize_commands(void)
{
@@ -53,6 +55,9 @@ void initialize_commands(void)
primitive_luatex("mathsurroundskip", assign_glue_cmd, glue_base + math_skip_code, glue_base);
primitive_luatex("mathsurroundmode", assign_int_cmd, int_base + math_skip_mode_code, int_base);
primitive_luatex("mathscriptboxmode", assign_int_cmd, int_base + math_script_box_mode_code, int_base);
+ primitive_luatex("mathscriptcharmode", assign_int_cmd, int_base + math_script_char_mode_code, int_base);
+ primitive_luatex("mathrulethicknessmode", assign_int_cmd, int_base + math_rule_thickness_mode_code, int_base);
+ primitive_luatex("mathflattenmode", assign_int_cmd, int_base + math_flatten_mode_code, int_base);
primitive_tex("output", assign_toks_cmd, output_routine_loc, local_base);
primitive_tex("everypar", assign_toks_cmd, every_par_loc, local_base);
primitive_tex("everymath", assign_toks_cmd, every_math_loc, local_base);
@@ -63,7 +68,7 @@ void initialize_commands(void)
primitive_tex("everycr", assign_toks_cmd, every_cr_loc, local_base);
primitive_tex("errhelp", assign_toks_cmd, err_help_loc, local_base);
- /* The integer parameter names must be entered into the hash table */
+ /*tex The integer parameter names must be entered into the hash table */
primitive_tex("pretolerance", assign_int_cmd, int_base + pretolerance_code, int_base);
primitive_tex("tolerance", assign_int_cmd, int_base + tolerance_code, int_base);
@@ -166,11 +171,18 @@ void initialize_commands(void)
primitive_luatex("automatichyphenpenalty", assign_int_cmd, int_base + automatic_hyphen_penalty_code, int_base);
primitive_luatex("explicithyphenpenalty", assign_int_cmd, int_base + explicit_hyphen_penalty_code, int_base);
primitive_luatex("automatichyphenmode", assign_int_cmd, int_base + automatic_hyphen_mode_code, int_base);
+ primitive_luatex("compoundhyphenmode", assign_int_cmd, int_base + compound_hyphen_mode_code, int_base);
primitive_luatex("breakafterdirmode", assign_int_cmd, int_base + break_after_dir_mode_code, int_base);
+ primitive_luatex("exceptionpenalty", assign_int_cmd, int_base + exception_penalty_code, int_base);
+ primitive_luatex("fixupboxesmode", assign_int_cmd, int_base + fixup_boxes_code, int_base);
+
+ /*tex
+
+ Many of \TeX's primitives need no |equiv|, since they are identifiable by
+ their |eq_type| alone. These primitives are loaded into the hash table as
+ follows:
- /* Many of \TeX's primitives need no |equiv|, since they are identifiable
- by their |eq_type| alone. These primitives are loaded into the hash table
- as follows: */
+ */
primitive_tex(" ", ex_space_cmd, 0, 0);
primitive_tex("/", ital_corr_cmd, 0, 0);
@@ -240,29 +252,27 @@ void initialize_commands(void)
primitive_tex("setbox", set_box_cmd, 0, 0);
primitive_tex("the", the_cmd, 0, 0);
primitive_luatex("toksapp", combine_toks_cmd, 0, 0);
- primitive_luatex("tokspre", combine_toks_cmd, 1, 0);
- primitive_luatex("etoksapp", combine_toks_cmd, 2, 0);
+ primitive_luatex("etoksapp", combine_toks_cmd, 1, 0);
+ primitive_luatex("tokspre", combine_toks_cmd, 2, 0);
primitive_luatex("etokspre", combine_toks_cmd, 3, 0);
+ primitive_luatex("gtoksapp", combine_toks_cmd, 4, 0);
+ primitive_luatex("xtoksapp", combine_toks_cmd, 5, 0);
+ primitive_luatex("gtokspre", combine_toks_cmd, 6, 0);
+ primitive_luatex("xtokspre", combine_toks_cmd, 7, 0);
primitive_tex("toks", toks_register_cmd, 0, 0);
primitive_tex("vadjust", vadjust_cmd, 0, 0);
primitive_tex("valign", valign_cmd, 0, 0);
primitive_tex("vcenter", vcenter_cmd, 0, 0);
primitive_tex("vrule", vrule_cmd, 0, 0);
primitive_luatex("novrule", no_vrule_cmd, 0, 0);
- primitive_tex("par", par_end_cmd, too_big_char, too_big_char); /* cf.\ |scan_file_name| */
+ primitive_luatex("luafunctioncall", lua_function_call_cmd, 0, 0);
+ primitive_luatex("luabytecodecall", lua_bytecode_call_cmd, 0, 0);
+ primitive_luatex("luadef", def_lua_call_cmd, 0, 0);
+ primitive_tex("par", par_end_cmd, too_big_char, too_big_char);
par_loc = cur_val;
par_token = cs_token_flag + par_loc;
- @<Create a bunch of primitives@>;
- @<Create the math param primitives@>;
- @<Create another bunch of primitives@>;
-}
-
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create a bunch of primitives@>=
-
- /*
+ /*tex
The processing of \.{\\input} involves the |start_input| subroutine,
which will be declared later; the processing of \.{\\endinput} is trivial.
*/
@@ -318,7 +328,7 @@ void initialize_commands(void)
primitive_tex("number", convert_cmd, number_code, 0);
primitive_tex("romannumeral", convert_cmd, roman_numeral_code, 0);
primitive_tex("string", convert_cmd, string_code, 0);
- primitive_tex("csstring", convert_cmd, cs_string_code, 0);
+ primitive_luatex("csstring", convert_cmd, cs_string_code, 0);
primitive_tex("meaning", convert_cmd, meaning_code, 0);
primitive_etex("eTeXVersion", convert_cmd, etex_code, 0);
primitive_tex("fontname", convert_cmd, font_name_code, 0);
@@ -331,9 +341,12 @@ void initialize_commands(void)
primitive_luatex("normaldeviate", convert_cmd, normal_deviate_code, 0);
primitive_core("directlua", convert_cmd, lua_code, 0);
primitive_luatex("luafunction", convert_cmd, lua_function_code, 0);
+ primitive_luatex("luabytecode", convert_cmd, lua_bytecode_code, 0);
primitive_luatex("luaescapestring", convert_cmd, lua_escape_string_code, 0);
primitive_luatex("mathstyle", convert_cmd, math_style_code, 0);
primitive_luatex("expanded", convert_cmd, expanded_code, 0);
+ primitive_luatex("immediateassignment", convert_cmd, immediate_assignment_code, 0);
+ primitive_luatex("immediateassigned", convert_cmd, immediate_assigned_code, 0);
primitive_tex("jobname", convert_cmd, job_name_code, 0);
primitive_luatex("formatname", convert_cmd, format_name_code, 0);
primitive_luatex("Uchar", convert_cmd, uchar_code, 0);
@@ -352,15 +365,15 @@ void initialize_commands(void)
primitive_tex("ifmmode", if_test_cmd, if_mmode_code, 0);
primitive_tex("ifinner", if_test_cmd, if_inner_code, 0);
primitive_tex("ifvoid", if_test_cmd, if_void_code, 0);
-
primitive_tex("ifhbox", if_test_cmd, if_hbox_code, 0);
primitive_tex("ifvbox", if_test_cmd, if_vbox_code, 0);
- primitive_tex("ifx", if_test_cmd, ifx_code, 0);
+ primitive_tex("ifx", if_test_cmd, if_x_code, 0);
primitive_tex("ifeof", if_test_cmd, if_eof_code, 0);
primitive_tex("iftrue", if_test_cmd, if_true_code, 0);
primitive_tex("iffalse", if_test_cmd, if_false_code, 0);
primitive_tex("ifcase", if_test_cmd, if_case_code, 0);
primitive_luatex("ifprimitive", if_test_cmd, if_primitive_code, 0);
+ primitive_luatex("ifcondition", if_test_cmd, if_condition_code, 0);
primitive_tex("fi", fi_or_else_cmd, fi_code, 0);
cs_text(frozen_fi) = maketexstring("fi");
eqtb[frozen_fi] = eqtb[cur_val];
@@ -435,12 +448,13 @@ void initialize_commands(void)
primitive_tex("vtop", make_box_cmd, vtop_code, 0);
primitive_tex("vbox", make_box_cmd, vtop_code + vmode, 0);
primitive_tex("hbox", make_box_cmd, vtop_code + hmode, 0);
- primitive_tex("shipout", leader_ship_cmd, a_leaders - 1, 0); /* |ship_out_flag=leader_flag-1| */
+ primitive_tex("shipout", leader_ship_cmd, a_leaders - 2, 0); /* |ship_out_flag=leader_flag-2| */
primitive_tex("leaders", leader_ship_cmd, a_leaders, 0);
primitive_tex("cleaders", leader_ship_cmd, c_leaders, 0);
primitive_tex("xleaders", leader_ship_cmd, x_leaders, 0);
primitive_luatex("gleaders", leader_ship_cmd, g_leaders, 0);
primitive_luatex("boxdir", assign_box_dir_cmd, 0, 0);
+ primitive_luatex("boxdirection", assign_box_direction_cmd, 0, 0);
primitive_tex("indent", start_par_cmd, 1, 0);
primitive_tex("noindent", start_par_cmd, 0, 0);
primitive_luatex("quitvmode", start_par_cmd, 2, 0);
@@ -514,9 +528,10 @@ void initialize_commands(void)
primitive_tex("gdef", def_cmd, 1, 0);
primitive_tex("edef", def_cmd, 2, 0);
primitive_tex("xdef", def_cmd, 3, 0);
- primitive_tex("let", let_cmd, normal, 0);
- primitive_tex("futurelet", let_cmd, normal + 1, 0);
- primitive_luatex("letcharcode", let_cmd, normal + 2, 0);
+ primitive_tex("glet", let_cmd, 0, 0);
+ primitive_tex("let", let_cmd, 1, 0);
+ primitive_tex("futurelet", let_cmd, 2, 0);
+ primitive_luatex("letcharcode", let_cmd, 3, 0);
primitive_tex("chardef", shorthand_def_cmd, char_def_code, 0);
primitive_tex("mathchardef", shorthand_def_cmd, math_char_def_code, 0);
primitive_luatex("Umathchardef", shorthand_def_cmd, xmath_char_def_code, 0);
@@ -539,9 +554,6 @@ void initialize_commands(void)
primitive_luatex("Umathquad", set_math_param_cmd, math_param_quad, 0);
primitive_luatex("Umathaxis", set_math_param_cmd, math_param_axis, 0);
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create the math param primitives@>=
primitive_luatex("Umathoperatorsize", set_math_param_cmd, math_param_operator_size, 0);
primitive_luatex("Umathoverbarkern", set_math_param_cmd, math_param_overbar_kern, 0);
primitive_luatex("Umathoverbarrule", set_math_param_cmd, math_param_overbar_rule, 0);
@@ -654,9 +666,6 @@ void initialize_commands(void)
primitive_luatex("Umathinnerpunctspacing", set_math_param_cmd, math_param_inner_punct_spacing, 0);
primitive_luatex("Umathinnerinnerspacing", set_math_param_cmd, math_param_inner_inner_spacing, 0);
-@ These are in a separate module due to a CWEAVE limitation.
-
-@<Create another bunch of primitives@>=
primitive_luatex("Umathcode", extdef_math_code_cmd, math_code_base, math_code_base);
primitive_luatex("Udelcode", extdef_del_code_cmd, del_code_base, del_code_base);
primitive_luatex("Umathcodenum", extdef_math_code_cmd, math_code_base + 1, math_code_base);
@@ -695,6 +704,7 @@ void initialize_commands(void)
primitive_tex("write", extension_cmd, write_code, 0);
write_loc = cur_val;
primitive_tex("closeout", extension_cmd, close_code, 0);
+ primitive_luatex("endlocalcontrol", extension_cmd, end_local_code, 0);
primitive_tex("special", extension_cmd, special_code, 0);
cs_text(frozen_special) = maketexstring("special");
eqtb[frozen_special] = eqtb[cur_val];
@@ -720,6 +730,7 @@ void initialize_commands(void)
primitive_luatex("initcatcodetable", normal_cmd, init_cat_code_table_code, 0);
primitive_luatex("setrandomseed", normal_cmd, set_random_seed_code, 0);
primitive_luatex("latelua", normal_cmd, late_lua_code, 0);
+ primitive_luatex("lateluafunction", normal_cmd, late_lua_call_code, 0);
primitive_luatex("insertht", convert_cmd, insert_ht_code, 0);
primitive_luatex("dviextension", extension_cmd, dvi_extension_code, 0);
primitive_luatex("dvifeedback", feedback_cmd, dvi_feedback_code, 0);
@@ -729,6 +740,15 @@ void initialize_commands(void)
primitive_luatex("pdfvariable", variable_cmd, pdf_variable_code, 0);
primitive_luatex("mathoption", option_cmd, math_option_code, 0);
+ primitive_luatex("luacopyinputnodes", assign_int_cmd, int_base + copy_lua_input_nodes_code, int_base);
+
+ primitive_luatex("pagedirection", assign_direction_cmd, int_base + page_direction_code, dir_base);
+ primitive_luatex("bodydirection", assign_direction_cmd, int_base + body_direction_code, dir_base);
+ primitive_luatex("pardirection", assign_direction_cmd, int_base + par_direction_code, dir_base);
+ primitive_luatex("textdirection", assign_direction_cmd, int_base + text_direction_code, dir_base);
+ primitive_luatex("mathdirection", assign_direction_cmd, int_base + math_direction_code, dir_base);
+ primitive_luatex("linedirection", assign_direction_cmd, int_base + line_direction_code, dir_base);
+
/*
some of the internal integer parameters are not associated with actual
primitives at all.
@@ -737,8 +757,8 @@ void initialize_commands(void)
primitive_no("nolocalwhatsits", assign_int_cmd, int_base + no_local_whatsits_code, int_base);
primitive_no("nolocaldirs", assign_int_cmd, int_base + no_local_dirs_code, int_base);
+}
-@ @c
void initialize_etex_commands(void)
{
primitive_etex("lastnodetype", last_item_cmd, last_node_type_code, 0);
@@ -746,8 +766,10 @@ void initialize_etex_commands(void)
primitive_etex("eTeXminorversion", last_item_cmd, eTeX_minor_version_code, 0);
primitive_etex("eTeXrevision", convert_cmd, eTeX_revision_code, 0);
- /*
- First we implement the additional \eTeX\ parameters in the table of equivalents.
+ /*tex
+
+ First we implement the additional \eTeX\ parameters in the table of
+ equivalents.
*/
primitive_etex("everyeof", assign_toks_cmd, every_eof_loc, local_base);
@@ -795,39 +817,48 @@ void initialize_etex_commands(void)
primitive_etex("showgroups", xray_cmd, show_groups, 0);
- /*
+ /*tex
+
The \.{\\showtokens} command displays a token list.
+
*/
primitive_etex("showtokens", xray_cmd, show_tokens, 0);
- /*
- The \.{\\unexpanded} primitive prevents expansion of tokens much as
- the result from \.{\\the} applied to a token variable. The
- \.{\\detokenize} primitive converts a token list into a list of
- character tokens much as if the token list were written to a file. We
- use the fact that the command modifiers for \.{\\unexpanded} and
- \.{\\detokenize} are odd whereas those for \.{\\the} and \.{\\showthe}
- are even.
+ /*tex
+
+ The \.{\\unexpanded} primitive prevents expansion of tokens much as the
+ result from \.{\\the} applied to a token variable. The \.{\\detokenize}
+ primitive converts a token list into a list of character tokens much as
+ if the token list were written to a file. We use the fact that the
+ command modifiers for \.{\\unexpanded} and \.{\\detokenize} are odd
+ whereas those for \.{\\the} and \.{\\showthe} are even.
+
*/
primitive_etex("unexpanded", the_cmd, 1, 0);
primitive_etex("detokenize", the_cmd, show_tokens, 0);
- /*
+ /*tex
+
The \.{\\showifs} command displays all currently active conditionals.
+
*/
primitive_etex("showifs", xray_cmd, show_ifs, 0);
- /*
+ /*tex
+
The \.{\\interactionmode} primitive allows to query and set the interaction mode.
+
*/
primitive_etex("interactionmode", set_page_int_cmd, 2, 0);
- /*
+ /*tex
+
The |scan_tokens| feature of \eTeX\ defines the \.{\\scantokens} primitive.
+
*/
primitive_etex("scantokens", input_cmd, 2, 0);
@@ -843,7 +874,8 @@ void initialize_etex_commands(void)
primitive_luatex("ifabsnum", if_test_cmd, if_abs_num_code, 0);
primitive_luatex("ifabsdim", if_test_cmd, if_abs_dim_code, 0);
- /*
+ /*tex
+
The |protected| feature of \eTeX\ defines the \.{\\protected} prefix
command for macro definitions. Such macros are protected against
expansions when lists of expanded tokens are built, e.g., for \.{\\edef}
@@ -852,8 +884,10 @@ void initialize_etex_commands(void)
primitive_etex("protected", prefix_cmd, 8, 0);
- /*
+ /*tex
+
Here are the additional \eTeX\ primitives for expressions.
+
*/
primitive_etex("numexpr", last_item_cmd, eTeX_expr - int_val_level + int_val_level, 0);
@@ -869,21 +903,25 @@ void initialize_etex_commands(void)
primitive_etex("mutoglue", last_item_cmd, mu_to_glue_code, 0);
primitive_etex("gluetomu", last_item_cmd, glue_to_mu_code, 0);
- /*
- The \.{\\pagediscards} and \.{\\splitdiscards} commands share the
- command code |un_vbox| with \.{\\unvbox} and \.{\\unvcopy}, they are
+ /*tex
+
+ The \.{\\pagediscards} and \.{\\splitdiscards} commands share the command
+ code |un_vbox| with \.{\\unvbox} and \.{\\unvcopy}, they are
distinguished by their |chr_code| values |last_box_code| and
- |vsplit_code|. These |chr_code| values are larger than |box_code| and
+ |vsplit_code|. These |chr_code| values are larger than |box_code| and
|copy_code|.
+
*/
primitive_etex("pagediscards", un_vbox_cmd, last_box_code, 0);
primitive_etex("splitdiscards", un_vbox_cmd, vsplit_code, 0);
- /*
+ /*tex
+
The \.{\\interlinepenalties}, \.{\\clubpenalties}, \.{\\widowpenalties},
and \.{\\displaywidowpenalties} commands allow to define arrays of
penalty values to be used instead of the corresponding single values.
+
*/
primitive_etex("interlinepenalties", set_etex_shape_cmd, inter_line_penalties_loc, etex_pen_base);
diff --git a/Build/source/texk/web2c/luatexdir/tex/conditional.w b/Build/source/texk/web2c/luatexdir/tex/conditional.c
index 318775141a8..948db580340 100644
--- a/Build/source/texk/web2c/luatexdir/tex/conditional.w
+++ b/Build/source/texk/web2c/luatexdir/tex/conditional.c
@@ -1,67 +1,73 @@
-% conditional.w
-%
-% Copyright 2009-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
+/*
+
+conditional.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
+/*tex
+
@* We consider now the way \TeX\ handles various kinds of \.{\\if} commands.
-@ Conditions can be inside conditions, and this nesting has a stack
-that is independent of the |save_stack|.
-
-Four global variables represent the top of the condition stack:
-|cond_ptr| points to pushed-down entries, if any; |if_limit| specifies
-the largest code of a |fi_or_else| command that is syntactically legal;
-|cur_if| is the name of the current type of conditional; and |if_line|
-is the line number at which it began.
-
-If no conditions are currently in progress, the condition stack has the
-special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|.
-Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and
-|link| fields of the first word contain |if_limit|, |cur_if|, and
-|cond_ptr| at the next level, and the second word contains the
-corresponding |if_line|.
-
-@c
-halfword cond_ptr; /* top of the condition stack */
-int if_limit; /* upper bound on |fi_or_else| codes */
-int cur_if; /* type of conditional being worked on */
-int if_line; /* line where that conditional began */
-
-@ When we skip conditional text, we keep track of the line number
-where skipping began, for use in error messages.
-
-@c
-int skip_line; /* skipping began here */
-
-@ Here is a procedure that ignores text until coming to an \.{\\or},
-\.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$
-nesting. After it has acted, |cur_chr| will indicate the token that
-was found, but |cur_tok| will not be set (because this makes the
-procedure run faster).
-
-@c
+Conditions can be inside conditions, and this nesting has a stack that is
+independent of the |save_stack|.
+
+Four global variables represent the top of the condition stack: |cond_ptr| points
+to pushed-down entries, if any; |if_limit| specifies the largest code of a
+|fi_or_else| command that is syntactically legal; |cur_if| is the name of the
+current type of conditional; and |if_line| is the line number at which it began.
+
+If no conditions are currently in progress, the condition stack has the special
+state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|. Otherwise
+|cond_ptr| points to a two-word node; the |type|, |subtype|, and |link| fields of
+the first word contain |if_limit|, |cur_if|, and |cond_ptr| at the next level,
+and the second word contains the corresponding |if_line|.
+
+In |cond_ptr| we keep track of the top of the condition stack while |if_limit|
+holds the upper bound on |fi_or_else| codes. The type of conditional being worked
+on is stored in cur_if and |if_line| keeps track of the line where that
+conditional began. When we skip conditional text, |skip_line| keeps track of the
+line number where skipping began, for use in error messages.
+
+*/
+
+halfword cond_ptr;
+int if_limit, cur_if, if_line, skip_line;
+
+/*tex
+
+Here is a procedure that ignores text until coming to an \.{\\or}, \.{\\else}, or
+\.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$ nesting. After it has acted,
+|cur_chr| will indicate the token that was found, but |cur_tok| will not be set
+(because this makes the procedure run faster).
+
+With |l| we keep track of the level of $\.{\\if}\ldots\.{\\fi}$ nesting and
+|scanner_status| let us return to the entry status.
+
+*/
+
void pass_text(void)
{
- int l = 0; /* level of $\.{\\if}\ldots\.{\\fi}$ nesting */
- int save_scanner_status = scanner_status; /* |scanner_status| upon entry */
+ int l = 0;
+ int save_scanner_status = scanner_status;
scanner_status = skipping;
skip_line = line;
while (1) {
@@ -80,13 +86,16 @@ void pass_text(void)
show_cur_cmd_chr();
}
-@ When we begin to process a new \.{\\if}, we set |if_limit:=if_code|; then
-if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
-condition has been evaluated, \.{\\relax} will be inserted.
-For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}'
-would otherwise require something after the `\.1'.
+/*tex
+
+When we begin to process a new \.{\\if}, we set |if_limit:=if_code|; then if\/
+\.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if} condition
+has been evaluated, \.{\\relax} will be inserted. For example, a sequence of
+commands like `\.{\\ifvoid1\\else...\\fi}' would otherwise require something
+after the `\.1'.
+
+*/
-@c
void push_condition_stack(void)
{
halfword p = new_node(if_node, 0);
@@ -103,9 +112,10 @@ void push_condition_stack(void)
void pop_condition_stack(void)
{
halfword p;
- if (if_stack[in_open] == cond_ptr)
+ if (if_stack[in_open] == cond_ptr) {
+ /*tex Conditionals are possibly not properly nested with files. */
if_warning();
- /* conditionals possibly not properly nested with files */
+ }
p = cond_ptr;
if_line = if_line_field(p);
cur_if = if_limit_subtype(p);
@@ -114,14 +124,16 @@ void pop_condition_stack(void)
flush_node(p);
}
-@ Here's a procedure that changes the |if_limit| code corresponding to
-a given value of |cond_ptr|.
+/*tex
+
+Here's a procedure that changes the |if_limit| code corresponding to a given
+value of |cond_ptr|.
+
+*/
-@c
void change_if_limit(int l, halfword p)
{
if (p == cond_ptr) {
- /* that's the easy case */
if_limit = l;
} else {
halfword q = cond_ptr;
@@ -137,22 +149,29 @@ void change_if_limit(int l, halfword p)
}
}
-@ The conditional \.{\\ifcsname} is equivalent to \.{\\expandafter}
-\.{\\expandafter} \.{\\ifdefined} \.{\\csname}, except that no new
-control sequence will be entered into the hash table (once all tokens
-preceding the mandatory \.{\\endcsname} have been expanded).
+/*tex
+
+The conditional \.{\\ifcsname} is equivalent to \.{\\expandafter}
+\.{\\expandafter} \.{\\ifdefined} \.{\\csname}, except that no new control
+sequence will be entered into the hash table (once all tokens preceding the
+mandatory \.{\\endcsname} have been expanded).
+
+*/
-@c
static halfword last_tested_cs ;
static boolean test_for_cs(void)
{
- boolean b = false; /*is the condition true? */
- int m, s; /*to be tested against the second operand */
- halfword q; /*for traversing token lists in \.{\\ifx} tests */
+ /*tex Is the condition true? */
+ boolean b = false;
+ /*tex To be tested against the second operand: */
+ int m, s;
+ /*tex For traversing token lists in \.{\\ifx} tests: */
+ halfword q;
halfword n = get_avail();
- halfword p = n; /*head of the list of characters */
-is_in_csname += 1;
+ /*tex Head of the list of characters: */
+ halfword p = n;
+ is_in_csname += 1;
while (1) {
get_x_token();
if (cur_cs != 0)
@@ -166,13 +185,13 @@ is_in_csname += 1;
get_x_token();
} while (cur_cmd != end_cs_name_cmd);
flush_list(n);
-is_in_csname -= 1;
+ is_in_csname -= 1;
return b;
} else {
complain_missing_csname();
}
}
- /* Look up the characters of list |n| in the hash table, and set |cur_cs| */
+ /*tex Look up the characters of list |n| in the hash table, and set |cur_cs|. */
m = first;
p = token_link(n);
while (p != null) {
@@ -200,21 +219,26 @@ is_in_csname -= 1;
p = token_link(p);
}
if (m > first) {
- cur_cs = id_lookup(first, m - first); /* |no_new_control_sequence| is |true| */
+ /*tex |no_new_control_sequence| is |true| */
+ cur_cs = id_lookup(first, m - first);
} else if (m == first) {
- cur_cs = null_cs; /* the list is empty */
+ /*tex the list is empty */
+ cur_cs = null_cs;
}
b = (eq_type(cur_cs) != undefined_cs_cmd);
flush_list(n);
last_cs_name = cur_cs;
-is_in_csname -= 1;
+ is_in_csname -= 1;
return b;
}
-@ An active character will be treated as category 13 following
-\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}.
+/*tex
+
+An active character will be treated as category 13 following \.{\\if\\noexpand}
+or following \.{\\ifcat\\noexpand}.
+
+*/
-@c
#define get_x_token_or_active_char() do { \
get_x_token(); \
if (cur_cmd==relax_cmd && cur_chr==no_expand_flag) { \
@@ -225,36 +249,47 @@ is_in_csname -= 1;
} \
} while (0)
-@ A condition is started when the |expand| procedure encounters
-an |if_test| command; in that case |expand| reduces to |conditional|,
-which is a recursive procedure.
-@^recursion@>
+/*tex
+
+A condition is started when the |expand| procedure encounters an |if_test|
+command; in that case |expand| reduces to |conditional|, which is a recursive
+procedure. @^recursion@>
+
+*/
-@c
void conditional(void)
{
- boolean b = false; /*is the condition true? */
- int r; /*relation to be evaluated */
- int m, n; /*to be tested against the second operand */
- halfword p, q; /*for traversing token lists in \.{\\ifx} tests */
- int save_scanner_status; /*|scanner_status| upon entry */
- halfword save_cond_ptr; /*|cond_ptr| corresponding to this conditional */
- int this_if; /*type of this conditional */
- boolean is_unless; /*was this if preceded by `\.{\\unless}' ? */
- if ((tracing_ifs_par > 0) && (tracing_commands_par <= 1))
+ /*tex Is the condition true? */
+ boolean b = false;
+ /*tex The relation to be evaluated: */
+ int r;
+ /*tex To be tested against the second operand: */
+ int m, n;
+ /*tex For traversing token lists in \.{\\ifx} tests: */
+ halfword p, q;
+ /*tex The |scanner_status| upon entry: */
+ int save_scanner_status;
+ /*tex The |cond_ptr| corresponding to this conditional: */
+ halfword save_cond_ptr;
+ /*tex The type of this conditional: */
+ int this_if;
+ /*tex Was this \.{\\if} preceded by \.{\\unless}? */
+ boolean is_unless;
+ if ((tracing_ifs_par > 0) && (tracing_commands_par <= 1)) {
show_cur_cmd_chr();
+ }
push_condition_stack();
save_cond_ptr = cond_ptr;
is_unless = (cur_chr >= unless_code);
this_if = cur_chr % unless_code;
- /* Either process \.{\\ifcase} or set |b| to the value of a boolean condition */
+ /*tex Either process \.{\\ifcase} or set |b| to the value of a boolean condition. */
switch (this_if) {
case if_char_code:
case if_cat_code:
- /* Test if two characters match */
+ /*tex Test if two characters match. */
get_x_token_or_active_char();
if ((cur_cmd > active_char_cmd) || (cur_chr > biggest_char)) {
- /*not a character */
+ /*tex It's not a character. */
m = relax_cmd;
n = too_big_char;
} else {
@@ -275,8 +310,10 @@ void conditional(void)
case if_dim_code:
case if_abs_dim_code:
case if_abs_num_code:
- /* Test relation between integers or dimensions */
- /* Here we use the fact that |"<"|, |"="|, and |">"| are consecutive ASCII codes. */
+ /*tex
+ Test the relation between integers or dimensions. Here we use the fact
+ that |<|, |=|, and |>| are consecutive ASCII codes.
+ */
if (this_if == if_int_code || this_if == if_abs_num_code)
scan_int();
else
@@ -284,15 +321,10 @@ void conditional(void)
n = cur_val;
if ((n < 0) && (this_if == if_abs_dim_code || this_if == if_abs_num_code))
negate(n);
- /* Get the next non-blank non-call... */
+ /*tex Get the next non-blank non-call... */
do {
get_x_token();
} while (cur_cmd == spacer_cmd);
- /*
- if ((cur_tok >= other_token + '<') && (cur_tok <= other_token + '>')) {
- r = cur_tok - other_token;
- } else {
- */
r = cur_tok - other_token;
if ((r < '<') || (r > '>')) {
print_err("Missing = inserted for ");
@@ -318,13 +350,13 @@ void conditional(void)
b = (n > cur_val);
break;
default:
- /* can't happen */
+ /*tex This can't happen. */
b = false;
break;
}
break;
case if_odd_code:
- /* Test if an integer is odd */
+ /*tex Test if an integer is odd. */
scan_int();
b = odd(cur_val);
break;
@@ -340,22 +372,6 @@ void conditional(void)
case if_inner_code:
b = (cur_list.mode_field < 0);
break;
- /*
- case if_void_code:
- case if_hbox_code:
- case if_vbox_code:
- scan_register_num();
- p = box(cur_val);
- if (this_if == if_void_code)
- b = (p == null);
- else if (p == null)
- b = false;
- else if (this_if == if_hbox_code)
- b = (type(p) == hlist_node);
- else
- b = (type(p) == vlist_node);
- break;
- */
case if_void_code:
scan_register_num();
p = box(cur_val);
@@ -371,16 +387,15 @@ void conditional(void)
p = box(cur_val);
b = (p != null) && (type(p) == vlist_node);
break;
- case ifx_code:
- /*
- Test if two tokens match
-
- Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
- or \\{outer} and the other isn't, even though the texts of the macros are
- the same.
+ case if_x_code:
+ /*tex
+ Test if two tokens match. Note that `\.{\\ifx}' will declare two
+ macros different if one is \\{long} or \\{outer} and the other
+ isn't, even though the texts of the macros are the same.
- We need to reset |scanner_status|, since \.{\\outer} control sequences
- are allowed, but we might be scanning a macro definition or preamble.
+ We need to reset |scanner_status|, since \.{\\outer} control
+ sequences are allowed, but we might be scanning a macro
+ definition or preamble.
*/
save_scanner_status = scanner_status;
scanner_status = normal;
@@ -394,11 +409,10 @@ void conditional(void)
} else if (cur_cmd < call_cmd) {
b = (cur_chr == q);
} else {
- /*
- Test if two macro texts match
-
- Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
- different in examples like this:
+ /*tex
+ Test if two macro texts match. Note also that `\.{\\ifx}'
+ decides that macros \.{\\a} and \.{\\b} are different in
+ examples like this:
$$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
{}\\def\\a\{\\c\}&
@@ -407,7 +421,7 @@ void conditional(void)
{}\\def\\d\{\}\cr}}$$
*/
p = token_link(cur_chr);
- /*omit reference counts */
+ /*tex Omit reference counts. */
q = token_link(equiv(n));
if (p == q) {
b = true;
@@ -437,9 +451,9 @@ void conditional(void)
b = false;
break;
case if_case_code:
- /* Select the appropriate case and |return| or |goto common_ending| */
+ /*tex Select the appropriate case and |return| or |goto common_ending|. */
scan_int();
- /* |n| is the number of cases to pass */
+ /*tex |n| is the number of cases to pass. */
n = cur_val;
if (tracing_commands_par > 1) {
begin_diagnostic();
@@ -460,7 +474,7 @@ void conditional(void)
}
}
change_if_limit(or_code, save_cond_ptr);
- /*wait for \.{\\or}, \.{\\else}, or \.{\\fi} */
+ /*tex Wait for \.{\\or}, \.{\\else}, or \.{\\fi}. */
return;
break;
case if_primitive_code:
@@ -475,10 +489,11 @@ void conditional(void)
(cur_chr == get_prim_equiv(m)));
break;
case if_def_code:
- /*
- The conditional \.{\\ifdefined} tests if a control sequence is defined.
- We need to reset |scanner_status|, since \.{\\outer} control sequences
- are allowed, but we might be scanning a macro definition or preamble.
+ /*tex
+ The conditional \.{\\ifdefined} tests if a control sequence is
+ defined. We need to reset |scanner_status|, since \.{\\outer}
+ control sequences are allowed, but we might be scanning a macro
+ definition or preamble.
*/
save_scanner_status = scanner_status;
scanner_status = normal;
@@ -493,9 +508,9 @@ void conditional(void)
b = is_in_csname;
break;
case if_font_char_code:
- /*
- The conditional \.{\\iffontchar} tests the existence of a character in
- a font.
+ /*tex
+ The conditional \.{\\iffontchar} tests the existence of a
+ character in a font.
*/
scan_font_ident();
n = cur_val;
@@ -503,13 +518,13 @@ void conditional(void)
b = char_exists(n, cur_val);
break;
default:
- /* there are no other cases, but for -Wall: */
+ /*tex there are no other cases, but we need to please |-Wall|. */
b = false;
}
if (is_unless)
b = !b;
if (tracing_commands_par > 1) {
- /* Display the value of |b| */
+ /*tex Display the value of |b|. */
begin_diagnostic();
if (b)
tprint("{true}");
@@ -519,16 +534,15 @@ void conditional(void)
}
if (b) {
change_if_limit(else_code, save_cond_ptr);
- /*wait for \.{\\else} or \.{\\fi} */
+ /*tex Wait for \.{\\else} or \.{\\fi}. */
return;
}
- /*
- Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|
-
- In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+ /*tex
+ Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|. In a
+ construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
\.{\\else} that we come to after learning that the \.{\\if} is false is
- not the \.{\\else} we're looking for. Hence the following curious
- logic is needed.
+ not the \.{\\else} we're looking for. Hence the following curious logic
+ is needed.
*/
while (1) {
pass_text();
@@ -536,7 +550,9 @@ void conditional(void)
if (cur_chr != or_code)
goto COMMON_ENDING;
print_err("Extra \\or");
- help1("I'm ignoring this; it doesn't match any \\if.");
+ help1(
+ "I'm ignoring this; it doesn't match any \\if."
+ );
error();
} else if (cur_chr == fi_code) {
pop_condition_stack();
@@ -546,7 +562,7 @@ void conditional(void)
if (cur_chr == fi_code) {
pop_condition_stack();
} else {
- /*wait for \.{\\fi} */
+ /*tex Wait for \.{\\fi}. */
if_limit = fi_code;
}
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/directions.w b/Build/source/texk/web2c/luatexdir/tex/directions.c
index c844e934c0d..59b2f7dcd85 100644
--- a/Build/source/texk/web2c/luatexdir/tex/directions.w
+++ b/Build/source/texk/web2c/luatexdir/tex/directions.c
@@ -1,27 +1,28 @@
-% directions.w
-%
-% Copyright 2009-2014 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
+/*
+
+directions.w
+
+Copyright 2009-2014 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"
-@ @c
void scan_direction(void)
{
int save_cur_cmd = cur_cmd;
@@ -53,9 +54,12 @@ void scan_direction(void)
cur_chr = save_cur_chr;
}
-@ the next two are used by postlinebreak.c
+/*tex
+
+ The next two are used by |postlinebreak.c|:
+
+*/
-@c
halfword do_push_dir_node(halfword p, halfword a)
{
halfword n = copy_node(a);
@@ -70,18 +74,14 @@ halfword do_pop_dir_node(halfword p)
return n;
}
-@ @c
halfword dir_ptr;
-
halfword text_dir_ptr;
-@ There is no need to do anything here at the moment.
-@c
void initialize_directions(void)
{
+ /*tex There is no need to do anything here at the moment. */
}
-@ @c
halfword new_dir(int s)
{
halfword p = new_node(dir_node, 0);
@@ -90,55 +90,32 @@ halfword new_dir(int s)
return p;
}
-@ The global static array variable |dir_strings| is also used
-by the lua nodelib interface, so it cannot be static. Putting
-it here instead of there avoid the nodelib having to know
-about the actual values of |dir_TRT| etc.
-
-@c
-
-/*
-const char *dir_strings[128] = {
- "-TLT","???", "???", "???", "-TRT","???", "???", "???",
- "???", "-LTL","???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "-RTT","???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "+TLT","???", "???", "???", "+TRT","???", "???", "???",
- "???", "+LTL","???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "+RTT","???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???",
- "???", "???", "???", "???", "???", "???", "???", "???"
+const char *dir_strings_par[4] = { [0] =
+ "TLT","TRT","LTL","RTT",
};
-int dir_swap = 64;
-*/
-
-const char *dir_strings[8] = {
- "-TLT","-TRT","-LTL","-RTT",
+const char *dir_strings_text_normal[4] = { [0] =
"+TLT","+TRT","+LTL","+RTT",
};
-int dir_swap = 4;
+const char *dir_strings_text_cancel[4] = { [0] =
+ "-TLT","-TRT","-LTL","-RTT",
+};
-const char *string_dir(int d)
+void print_dir_par(int d)
{
- return (dir_strings[d+dir_swap]+1);
+ tprint(dir_strings_par[d]);
}
-@ @c
-void print_dir(int d)
+void print_dir_text(halfword d)
{
- tprint(string_dir(d));
+ if (subtype(d) == cancel_dir) {
+ tprint(dir_strings_text_cancel[dir_dir(d)]);
+ } else {
+ tprint(dir_strings_text_normal[dir_dir(d)]);
+ }
}
-@ @c
scaled pack_width(int curdir, int pdir, halfword p, boolean isglyph)
{
scaled wd = 0;
@@ -153,9 +130,7 @@ scaled pack_width(int curdir, int pdir, halfword p, boolean isglyph)
} else {
wd = glyph_depth(p) + glyph_height(p);
}
-/* experimental */
-wd += x_advance(p);
- } else { /* hlist, vlist, image, form, rule */
+ } else {
if (textdir_parallel(pdir, curdir))
wd = width(p);
else
@@ -164,7 +139,6 @@ wd += x_advance(p);
return wd;
}
-@ @c
scaled_whd pack_width_height_depth(int curdir, int pdir, halfword p, boolean isglyph)
{
scaled_whd whd = { 0, 0, 0 };
@@ -208,7 +182,6 @@ scaled_whd pack_width_height_depth(int curdir, int pdir, halfword p, boolean isg
return whd;
}
-@ @c
void update_text_dir_ptr(int val)
{
if (dir_level(text_dir_ptr) == cur_level) {
diff --git a/Build/source/texk/web2c/luatexdir/tex/dumpdata.w b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
index 9d06f1c8ed4..0091685fb74 100644
--- a/Build/source/texk/web2c/luatexdir/tex/dumpdata.w
+++ b/Build/source/texk/web2c/luatexdir/tex/dumpdata.c
@@ -1,84 +1,97 @@
-% dumpdata.w
-%
-% Copyright 2009-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
+/*
+
+dumpdata.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-/* we start with 907: the sum of the values of the bytes of "don knuth" */
+/*tex
+
+ We use a magic number to register the version of the format. Normally this
+ number only increments when we add a new primitive of change command codes.
+ We start with 907 which is the sum of the values of the bytes of \quote
+ {don knuth}.
-#define FORMAT_ID (907+37)
+*/
+
+#define FORMAT_ID (907+48)
#if ((FORMAT_ID>=0) && (FORMAT_ID<=256))
#error Wrong value for FORMAT_ID.
#endif
+/*tex
+
+After \.{INITEX} has seen a collection of fonts and macros, it can write all the
+necessary information on an auxiliary file so that production versions of \TeX\
+are able to initialize their memory at high speed. The present section of the
+program takes care of such output and input. We shall consider simultaneously the
+processes of storing and restoring, so that the inverse relation between them is
+clear. @.INITEX@>
+
+The global variable |format_ident| is a string that is printed right after the
+|banner| line when \TeX\ is ready to start. For \.{INITEX} this string says
+simply `\.{(INITEX)}'; for other versions of \TeX\ it says, for example,
+`\.{(preloaded format=plain 1982.11.19)}', showing the year, month, and day that
+the format file was created. We have |format_ident=0| before \TeX's tables are
+loaded. |FORMAT_ID| is a new field of type int suitable for the identification of
+a format: values between 0 and 256 (included) can not be used because in the
+previous format they are used for the length of the name of the engine.
+
+*/
-@ After \.{INITEX} has seen a collection of fonts and macros, it
-can write all the necessary information on an auxiliary file so
-that production versions of \TeX\ are able to initialize their
-memory at high speed. The present section of the program takes
-care of such output and input. We shall consider simultaneously
-the processes of storing and restoring,
-so that the inverse relation between them is clear.
-@.INITEX@>
-
-The global variable |format_ident| is a string that is printed right
-after the |banner| line when \TeX\ is ready to start. For \.{INITEX} this
-string says simply `\.{(INITEX)}'; for other versions of \TeX\ it says,
-for example, `\.{(preloaded format=plain 1982.11.19)}', showing the year,
-month, and day that the format file was created. We have |format_ident=0|
-before \TeX's tables are loaded. |FORMAT_ID| is a new field of type int
-suitable for the identification of a format: values between 0 and 256
-(included) can not be used because in the previous format they are used
-for the length of the name of the engine.
-@c
str_number format_ident;
-str_number format_name; /* principal file name */
+str_number format_name;
-@ Format files consist of |memory_word| items, and we use the following
-macros to dump words of different types:
+/*tex
-@c
-FILE *fmt_file; /* for input or output of format information */
+Format files consist of |memory_word| items, and we use the following macros to
+dump words of different types:
+
+*/
+
+FILE *fmt_file;
-@ @c
void store_fmt_file(void)
{
- int j, k, l; /* all-purpose indices */
- halfword p; /* all-purpose pointer */
- int x; /* something to dump */
+ int j, k, l, x;
+ halfword p;
char *format_engine;
- int callback_id; /* |pre_dump| callback */
+ int callback_id;
char *fmtname = NULL;
- /* If dumping is not allowed, abort */
- /* The user is not allowed to dump a format file unless |save_ptr=0|.
- This condition implies that |cur_level=level_one|, hence
- the |xeq_level| array is constant and it need not be dumped. */
+ /*tex
+ If dumping is not allowed, abort. The user is not allowed to dump a
+ format file unless |save_ptr=0|. This condition implies that
+ |cur_level=level_one|, hence the |xeq_level| array is constant and it
+ need not be dumped.
+ */
if (save_ptr != 0) {
print_err("You can't dump inside a group");
help1("`{...\\dump}' is a no-no.");
succumb();
}
-
- /* Create the |format_ident|, open the format file, and inform the user
- that dumping has begun */
+ /*tex
+ Create the |format_ident|, open the format file, and inform the user that
+ dumping has begun.
+ */
callback_id = callback_defined(pre_dump_callback);
if (callback_id > 0) {
(void) run_callback(callback_id, "->");
@@ -97,11 +110,11 @@ void store_fmt_file(void)
format_ident = make_string();
print(job_name);
format_name = make_string();
- if (interaction == batch_mode)
+ if (interaction == batch_mode) {
selector = log_only;
- else
+ } else {
selector = term_and_log;
-
+ }
fmtname = pack_job_name(format_extension);
while (!zopen_w_output(&fmt_file, fmtname, FOPEN_WBIN_MODE)) {
fmtname = prompt_file_name("format file name", format_extension);
@@ -111,15 +124,16 @@ void store_fmt_file(void)
free(fmtname);
tprint_nl("");
print(format_ident);
-
- /* Dump constants for consistency check */
- /* The next few sections of the program should make it clear how we use the
- dump/undump macros. */
-
- dump_int(0x57325458); /* Web2C \TeX's magic constant: "W2TX" */
+ /*tex
+ Dump constants for consistency check. The next few sections of the
+ program should make it clear how we use the dump/undump macros. First
+ comes Web2C \TeX's magic constant: "W2TX"
+ */
+ dump_int(0x57325458);
dump_int(FORMAT_ID);
-
- /* Align engine to 4 bytes with one or more trailing NUL */
+ /*tex
+ We align |engine_name| to 4 bytes with one or more trailing |NUL|.
+ */
x = (int) strlen(engine_name);
format_engine = xmalloc((unsigned) (x + 4));
strcpy(format_engine, engine_name);
@@ -129,28 +143,26 @@ void store_fmt_file(void)
dump_int(x);
dump_things(format_engine[0], x);
xfree(format_engine);
- dump_int(0x57325458); /* TODO HM, what checksum would make sense? */
+ dump_int(0x57325458);
dump_int(max_halfword);
dump_int(hash_high);
dump_int(eqtb_size);
dump_int(hash_prime);
-
- /* Dump the string pool */
+ /*tex Dump the string pool. */
k = dump_string_pool();
print_ln();
print_int(k);
tprint(" strings using ");
print_int((longinteger) pool_size);
tprint(" bytes");
-
- /* Dump the dynamic memory */
- /* By sorting the list of available spaces in the variable-size portion of
- |mem|, we are usually able to get by without having to dump very much
- of the dynamic memory.
-
- We recompute |var_used| and |dyn_used|, so that \.{INITEX} dumps valid
- information even when it has not been gathering statistics.
- */
+ /*tex
+ Dump the dynamic memory. By sorting the list of available spaces in the
+ variable-size portion of |mem|, we are usually able to get by without
+ having to dump very much of the dynamic memory.
+
+ We recompute |var_used| and |dyn_used|, so that \.{INITEX} dumps valid
+ information even when it has not been gathering statistics.
+ */
dump_node_mem();
dump_int(temp_token_head);
dump_int(hold_token_head);
@@ -180,14 +192,13 @@ void store_fmt_file(void)
print_int(var_used);
print_char('&');
print_int(dyn_used);
-
- /* Dump the table of equivalents */
- /* Dump regions 1 to 4 of |eqtb| */
- /*The table of equivalents usually contains repeated information, so we dump it
- in compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in the
- format file represents $n+m$ consecutive entries of |eqtb|, with |m| extra
- copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$.
- */
+ /*tex
+ Dump regions 1 to 4 of |eqtb|, the table of equivalents. The table of
+ equivalents usually contains repeated information, so we dump it in
+ compressed form: The sequence of $n+2$ values $(n,x_1,\ldots,x_n,m)$ in
+ the format file represents $n+m$ consecutive entries of |eqtb|, with |m|
+ extra copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$.
+ */
k = null_cs;
do {
j = k;
@@ -198,7 +209,8 @@ void store_fmt_file(void)
incr(j);
}
l = int_base;
- goto DONE1; /* |j=int_base-1| */
+ /*tex |j=int_base-1| */
+ goto DONE1;
FOUND1:
incr(j);
l = j;
@@ -214,8 +226,7 @@ void store_fmt_file(void)
k = j + 1;
dump_int(k - l);
} while (k != int_base);
-
- /* Dump regions 5 and 6 of |eqtb| */
+ /*tex Dump regions 5 and 6 of |eqtb|. */
do {
j = k;
while (j < eqtb_size) {
@@ -224,7 +235,8 @@ void store_fmt_file(void)
incr(j);
}
l = eqtb_size + 1;
- goto DONE2; /* |j=eqtb_size| */
+ /*tex |j=eqtb_size| */
+ goto DONE2;
FOUND2:
incr(j);
l = j;
@@ -239,18 +251,20 @@ void store_fmt_file(void)
k = j + 1;
dump_int(k - l);
} while (k <= eqtb_size);
- if (hash_high > 0)
- dump_things(eqtb[eqtb_size + 1], hash_high); /* dump |hash_extra| part */
-
+ if (hash_high > 0) {
+ /*tex Dump the |hash_extra| part: */
+ dump_things(eqtb[eqtb_size + 1], hash_high);
+ }
dump_int(par_loc);
dump_int(write_loc);
dump_math_codes();
dump_text_codes();
- /* Dump the hash table */
- /* A different scheme is used to compress the hash table, since its lower
- region is usually sparse. When |text(p)<>0| for |p<=hash_used|, we output
- two words, |p| and |hash[p]|. The hash table is, of course, densely packed
- for |p>=hash_used|, so the remaining entries are output in a~block.
+ /*tex
+ Dump the hash table, A different scheme is used to compress the hash
+ table, since its lower region is usually sparse. When |text(p)<>0| for
+ |p<=hash_used|, we output two words, |p| and |hash[p]|. The hash table
+ is, of course, densely packed for |p>=hash_used|, so the remaining
+ entries are output in a~block.
*/
dump_primitives();
dump_int(hash_used);
@@ -262,19 +276,18 @@ void store_fmt_file(void)
incr(cs_count);
}
}
- dump_things(hash[hash_used + 1],
- undefined_control_sequence - 1 - hash_used);
- if (hash_high > 0)
+ dump_things(hash[hash_used + 1],undefined_control_sequence - 1 - hash_used);
+ if (hash_high > 0) {
dump_things(hash[eqtb_size + 1], hash_high);
+ }
dump_int(cs_count);
print_ln();
print_int(cs_count);
tprint(" multiletter control sequences");
-
- /* Dump the font information */
+ /*tex Dump the font information. */
dump_int(max_font_id());
for (k = 0; k <= max_font_id(); k++) {
- /* Dump the array info for internal font number |k| */
+ /*tex Dump the array info for internal font number |k|. */
dump_font(k);
tprint_nl("\\font");
print_esc(font_id_text(k));
@@ -293,73 +306,78 @@ void store_fmt_file(void)
if (max_font_id() != 1)
print_char('s');
dump_math_data();
-
- /* Dump the hyphenation tables */
+ /*tex Dump the hyphenation tables. */
dump_language_data();
-
- /* Dump a couple more things and the closing check word */
+ /*tex Dump a couple more things and the closing check word. */
dump_int(interaction);
dump_int(format_ident);
dump_int(format_name);
dump_int(69069);
- /* We have already printed a lot of statistics, so we set |tracing_stats:=0|
- to prevent them from appearing again. */
+ /*tex
+ We have already printed a lot of statistics, so we set |tracing_stats:=0|
+ to prevent them from appearing again.
+ */
tracing_stats_par = 0;
-
- /* Dump the lua bytecodes */
+ /*tex Dump the \LUA\ bytecodes. */
dump_luac_registers();
-
- /* Close the format file */
+ /*tex Close the format file. */
zwclose(fmt_file);
}
-@ Corresponding to the procedure that dumps a format file, we have a function
-that reads one in. The function returns |false| if the dumped format is
-incompatible with the present \TeX\ table sizes, etc.
-
-@c
-#define too_small(A) do { \
- wake_up_terminal(); \
- wterm_cr(); \
- fprintf(term_out,"---! Must increase the %s",(A)); \
- goto BAD_FMT; \
- } while (0)
-
-@ The inverse macros are slightly more complicated, since we need to check
-the range of the values we are reading in. We say `|undump(a)(b)(x)|' to
-read an integer value |x| that is supposed to be in the range |a<=x<=b|.
-
-@c
-#define undump(A,B,C) do { \
- undump_int(x); \
- if (x<(A) || x>(B)) goto BAD_FMT; \
- else (C) = x; \
- } while (0)
-
-
-#define format_debug(A,B) do { \
- if (debug_format_file) { \
- fprintf (stderr, "fmtdebug: %s=%d", (A), (int)(B)); \
- } \
- } while (0)
-
-#define undump_size(A,B,C,D) do { \
- undump_int(x); \
- if (x<(A)) goto BAD_FMT; \
- if (x>(B)) too_small(C); \
- else format_debug (C,x); \
- (D) = x; \
- } while (0)
-
-
-@ @c
+/*tex
+
+Corresponding to the procedure that dumps a format file, we have a function that
+reads one in. The function returns |false| if the dumped format is incompatible
+with the present \TeX\ table sizes, etc.
+
+*/
+
+#define too_small(A) do { \
+ wake_up_terminal(); \
+ wterm_cr(); \
+ fprintf(term_out,"---! Must increase the %s",(A)); \
+ goto BAD_FMT; \
+} while (0)
+
+/*tex
+
+ The inverse macros are slightly more complicated, since we need to check the
+ range of the values we are reading in. We say `|undump(a)(b)(x)|' to read an
+ integer value |x| that is supposed to be in the range |a<=x<=b|.
+
+*/
+
+#define undump(A,B,C) do { \
+ undump_int(x); \
+ if (x<(A) || x>(B)) \
+ goto BAD_FMT; \
+ else \
+ (C) = x; \
+} while (0)
+
+#define format_debug(A,B) do { \
+ if (debug_format_file) { \
+ fprintf (stderr, "fmtdebug: %s=%d", (A), (int)(B)); \
+ } \
+} while (0)
+
+#define undump_size(A,B,C,D) do { \
+ undump_int(x); \
+ if (x<(A)) \
+ goto BAD_FMT; \
+ if (x>(B)) \
+ too_small(C); \
+ else \
+ format_debug (C,x); \
+ (D) = x; \
+} while (0)
+
boolean load_fmt_file(const char *fmtname)
{
- int j, k; /* all-purpose indices */
- halfword p; /* all-purpose pointer */
- int x; /* something undumped */
+ int j, k, x;
+ halfword p;
char *format_engine;
- /* Undump constants for consistency check */
+ /*tex Undump constants for consistency check .*/
if (ini_version) {
libcfree(hash);
libcfree(eqtb);
@@ -368,22 +386,25 @@ boolean load_fmt_file(const char *fmtname)
}
undump_int(x);
format_debug("format magic number", x);
- if (x != 0x57325458)
- goto BAD_FMT; /* not a format file */
-
+ if (x != 0x57325458) {
+ /*tex it's not a format file. */
+ goto BAD_FMT;
+ }
undump_int(x);
format_debug("format id", x);
- if (x != FORMAT_ID)
- goto BAD_FMT; /* FORMAT_ID mismatch */
-
+ if (x != FORMAT_ID) {
+ /*tex We have a |FORMAT_ID| mismatch. */
+ goto BAD_FMT;
+ }
undump_int(x);
format_debug("engine name size", x);
- if ((x < 0) || (x > 256))
- goto BAD_FMT; /* corrupted format file */
-
+ if ((x < 0) || (x > 256)) {
+ /*tex The format file is corrupt. */
+ goto BAD_FMT;
+ }
format_engine = xmalloc((unsigned) x);
undump_things(format_engine[0], x);
- format_engine[x - 1] = 0; /* force string termination, just in case */
+ format_engine[x - 1] = 0;
if (strcmp(engine_name, format_engine)) {
wake_up_terminal();
wterm_cr();
@@ -394,7 +415,7 @@ boolean load_fmt_file(const char *fmtname)
xfree(format_engine);
undump_int(x);
format_debug("string pool checksum", x);
- if (x != 0x57325458) { /* todo: @@\$ *//* check that strings are the same */
+ if (x != 0x57325458) {
wake_up_terminal();
wterm_cr();
fprintf(term_out, "---! %s was written by a different version",
@@ -403,7 +424,7 @@ boolean load_fmt_file(const char *fmtname)
}
undump_int(x);
if (x != max_halfword)
- goto BAD_FMT; /* check |max_halfword| */
+ goto BAD_FMT;
undump_int(hash_high);
if ((hash_high < 0) || (hash_high > sup_hash_extra))
goto BAD_FMT;
@@ -428,10 +449,9 @@ boolean load_fmt_file(const char *fmtname)
undump_int(x);
if (x != hash_prime)
goto BAD_FMT;
-
- /* Undump the string pool */
+ /*tex Undump the string pool */
str_ptr = undump_string_pool();
- /* Undump the dynamic memory */
+ /*tex Undump the dynamic memory */
undump_node_mem();
undump_int(temp_token_head);
undump_int(hold_token_head);
@@ -447,9 +467,7 @@ boolean load_fmt_file(const char *fmtname)
undump_int(avail);
undump_things(fixmem[fix_mem_min], fix_mem_end - fix_mem_min + 1);
undump_int(dyn_used);
-
- /* Undump the table of equivalents */
- /* Undump regions 1 to 6 of |eqtb| */
+ /*tex Undump regions 1 to 6 of the table of equivalents |eqtb|. */
k = null_cs;
do {
undump_int(x);
@@ -464,15 +482,16 @@ boolean load_fmt_file(const char *fmtname)
eqtb[j] = eqtb[k - 1];
k = k + x;
} while (k <= eqtb_size);
- if (hash_high > 0) /* undump |hash_extra| part */
+ if (hash_high > 0) {
+ /*tex undump |hash_extra| part */
undump_things(eqtb[eqtb_size + 1], hash_high);
-
+ }
undump(hash_base, hash_top, par_loc);
par_token = cs_token_flag + par_loc;
undump(hash_base, hash_top, write_loc);
undump_math_codes();
undump_text_codes();
- /* Undump the hash table */
+ /*tex Undump the hash table */
undump_primitives();
undump(hash_base, frozen_control_sequence, hash_used);
p = hash_base - 1;
@@ -480,8 +499,7 @@ boolean load_fmt_file(const char *fmtname)
undump(p + 1, hash_used, p);
undump_hh(hash[p]);
} while (p != hash_used);
- undump_things(hash[hash_used + 1],
- undefined_control_sequence - 1 - hash_used);
+ undump_things(hash[hash_used + 1], undefined_control_sequence - 1 - hash_used);
if (debug_format_file)
print_csnames(hash_base, undefined_control_sequence - 1);
if (hash_high > 0) {
@@ -490,20 +508,17 @@ boolean load_fmt_file(const char *fmtname)
print_csnames(eqtb_size + 1, hash_high - (eqtb_size + 1));
}
undump_int(cs_count);
-
- /* Undump the font information */
+ /*tex Undump the font information */
undump_int(x);
set_max_font_id(x);
for (k = 0; k <= max_font_id(); k++) {
- /* Undump the array info for internal font number |k| */
+ /*tex Undump the array info for internal font number |k| */
undump_font(k);
}
undump_math_data();
-
- /* Undump the hyphenation tables */
+ /*tex Undump the hyphenation tables */
undump_language_data();
-
- /* Undump a couple more things and the closing check word */
+ /*tex Undump a couple more things and the closing check word */
undump(batch_mode, error_stop_mode, interaction);
if (interactionoption != unspecified_mode)
interaction = interactionoption;
@@ -512,12 +527,10 @@ boolean load_fmt_file(const char *fmtname)
undump_int(x);
if (x != 69069)
goto BAD_FMT;
-
- /* Undump the lua bytecodes */
+ /*tex Undump the lua bytecodes. */
undump_luac_registers();
-
prev_depth_par = ignore_depth;
- return true; /* it worked! */
+ return true;
BAD_FMT:
wake_up_terminal();
wterm_cr();
diff --git a/Build/source/texk/web2c/luatexdir/tex/equivalents.w b/Build/source/texk/web2c/luatexdir/tex/equivalents.c
index 271fc67ffbd..3d260d5c5ee 100644
--- a/Build/source/texk/web2c/luatexdir/tex/equivalents.w
+++ b/Build/source/texk/web2c/luatexdir/tex/equivalents.c
@@ -1,29 +1,31 @@
-% equivalents.w
-%
-% Copyright 2009-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
+/*
+
+equivalents.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
halfword last_cs_name = null_cs;
-/* |eqtb[p]| has just been restored or retained */
+/*tex |eqtb[p]| has just been restored or retained. */
static void diagnostic_trace(halfword p, const char *s)
{
@@ -36,60 +38,54 @@ static void diagnostic_trace(halfword p, const char *s)
end_diagnostic(false);
}
-@ @c
-void show_eqtb_meaning(halfword n); /* forward */
+void show_eqtb_meaning(halfword n);
+
+/*tex
+
+Now that we have studied the data structures for \TeX's semantic routines, we
+ought to consider the data structures used by its syntactic routines. In other
+words, our next concern will be the tables that \TeX\ looks at when it is
+scanning what the user has written.
-@ Now that we have studied the data structures for \TeX's semantic routines,
-we ought to consider the data structures used by its syntactic routines. In
-other words, our next concern will be
-the tables that \TeX\ looks at when it is scanning
-what the user has written.
+The biggest and most important such table is called |eqtb|. It holds the current
+``equivalents'' of things; i.e., it explains what things mean or what their
+current values are, for all quantities that are subject to the nesting structure
+provided by \TeX's grouping mechanism. There are six parts to |eqtb|:
-The biggest and most important such table is called |eqtb|. It holds the
-current ``equivalents'' of things; i.e., it explains what things mean
-or what their current values are, for all quantities that are subject to
-the nesting structure provided by \TeX's grouping mechanism. There are six
-parts to |eqtb|:
+1) |eqtb[null_cs]| holds the current equivalent of the zero-length control
+sequence.
-\yskip\hang 1) |eqtb[null_cs]| holds the current equivalent of the
-zero-length control sequence.
+2) |eqtb[hash_base..(glue_base-1)]| holds the current equivalents of single- and
+multiletter control sequences.
-\yskip\hang 2) |eqtb[hash_base..(glue_base-1)]| holds the current
-equivalents of single- and multiletter control sequences.
+3) |eqtb[glue_base..(local_base-1)]| holds the current equivalents of glue
+parameters like the current baselineskip.
-\yskip\hang 3) |eqtb[glue_base..(local_base-1)]| holds the current
-equivalents of glue parameters like the current baselineskip.
+4) |eqtb[local_base..(int_base-1)]| holds the current equivalents of local
+halfword quantities like the current box registers, the current ``catcodes,'' the
+current font, and a pointer to the current paragraph shape.
-\yskip\hang 4) |eqtb[local_base..(int_base-1)]| holds the current
-equivalents of local halfword quantities like the current box registers,
-the current ``catcodes,'' the current font, and a pointer to the current
-paragraph shape.
+5) |eqtb[int_base..(dimen_base-1)]| holds the current equivalents of fullword
+integer parameters like the current hyphenation penalty.
-\yskip\hang 5) |eqtb[int_base..(dimen_base-1)]| holds the current
-equivalents of fullword integer parameters like the current hyphenation
-penalty.
+6) |eqtb[dimen_base..eqtb_size]| holds the current equivalents of fullword
+dimension parameters like the current hsize or amount of hanging indentation.
-\yskip\hang 6) |eqtb[dimen_base..eqtb_size]| holds the current equivalents
-of fullword dimension parameters like the current hsize or amount of
-hanging indentation.
+Note that, for example, the current amount of baselineskip glue is determined by
+the setting of a particular location in region~3 of |eqtb|, while the current
+meaning of the control sequence `\.{\\baselineskip}' (which might have been
+changed by \.{\\def} or \.{\\let}) appears in region~2.
-\yskip\noindent Note that, for example, the current amount of
-baselineskip glue is determined by the setting of a particular location
-in region~3 of |eqtb|, while the current meaning of the control sequence
-`\.{\\baselineskip}' (which might have been changed by \.{\\def} or
-\.{\\let}) appears in region~2.
+The last two regions of |eqtb| have fullword values instead of the three fields
+|eq_level|, |eq_type|, and |equiv|. An |eq_type| is unnecessary, but \TeX\ needs
+to store the |eq_level| information in another array called |xeq_level|.
-@ The last two regions of |eqtb| have fullword values instead of the
-three fields |eq_level|, |eq_type|, and |equiv|. An |eq_type| is unnecessary,
-but \TeX\ needs to store the |eq_level| information in another array
-called |xeq_level|.
+*/
-@c
memory_word *eqtb;
-halfword eqtb_top; /* maximum of the |eqtb| */
+halfword eqtb_top;
quarterword xeq_level[(eqtb_size + 1)];
-@ @c
void initialize_equivalents(void)
{
int k;
@@ -97,48 +93,45 @@ void initialize_equivalents(void)
xeq_level[k] = level_one;
}
-@ The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups
-in \TeX\ means that |eqtb| entries valid in outer groups should be saved
-and restored later if they are overridden inside the braces. When a new |eqtb|
-value is being assigned, the program therefore checks to see if the previous
-entry belongs to an outer level. In such a case, the old value is placed
-on the |save_stack| just before the new value enters |eqtb|. At the
-end of a grouping level, i.e., when the right brace is sensed, the
-|save_stack| is used to restore the outer values, and the inner ones are
-destroyed.
-
-Entries on the |save_stack| are of type |save_record|. The top item on
-this stack is |save_stack[p]|, where |p=save_ptr-1|; it contains three
-fields called |save_type|, |save_level|, and |save_value|, and it is
-interpreted in one of four ways:
-
-\yskip\hang 1) If |save_type(p)=restore_old_value|, then
-|save_value(p)| is a location in |eqtb| whose current value should
-be destroyed at the end of the current group and replaced by |save_word(p-1)|
-(|save_type(p-1)==saved_eqtb|).
-Furthermore if |save_value(p)>=int_base|, then |save_level(p)| should
-replace the corresponding entry in |xeq_level| (if |save_value(p)<int_base|,
-then the level is part of |save_word(p-1)|).
-
-\yskip\hang 2) If |save_type(p)=restore_zero|, then |save_value(p)|
-is a location in |eqtb| whose current value should be destroyed at the end
-of the current group, when it should be
-replaced by the current value of |eqtb[undefined_control_sequence]|.
-
-\yskip\hang 3) If |save_type(p)=insert_token|, then |save_value(p)|
-is a token that should be inserted into \TeX's input when the current
-group ends.
-
-\yskip\hang 4) If |save_type(p)=level_boundary|, then |save_level(p)|
-is a code explaining what kind of group we were previously in, and
-|save_value(p)| points to the level boundary word at the bottom of
-the entries for that group. Furthermore, |save_value(p-1)| contains the
-source line number at which the current level of grouping was entered,
-this field has itself a type: |save_type(p-1)==saved_line|.
-
-Besides this `official' use, various subroutines push temporary
-variables on the save stack when it is handy to do so. These all have
-an explicit |save_type|, and they are:
+/*tex
+
+The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups in
+\TeX\ means that |eqtb| entries valid in outer groups should be saved and
+restored later if they are overridden inside the braces. When a new |eqtb| value
+is being assigned, the program therefore checks to see if the previous entry
+belongs to an outer level. In such a case, the old value is placed on the
+|save_stack| just before the new value enters |eqtb|. At the end of a grouping
+level, i.e., when the right brace is sensed, the |save_stack| is used to restore
+the outer values, and the inner ones are destroyed.
+
+Entries on the |save_stack| are of type |save_record|. The top item on this stack
+is |save_stack[p]|, where |p=save_ptr-1|; it contains three fields called
+|save_type|, |save_level|, and |save_value|, and it is interpreted in one of four
+ways:
+
+1) If |save_type(p)=restore_old_value|, then |save_value(p)| is a location in
+|eqtb| whose current value should be destroyed at the end of the current group
+and replaced by |save_word(p-1)| (|save_type(p-1)==saved_eqtb|). Furthermore if
+|save_value(p)>=int_base|, then |save_level(p)| should replace the corresponding
+entry in |xeq_level| (if |save_value(p)<int_base|, then the level is part of
+|save_word(p-1)|).
+
+2) If |save_type(p)=restore_zero|, then |save_value(p)| is a location in |eqtb|
+whose current value should be destroyed at the end of the current group, when it
+should be replaced by the current value of |eqtb[undefined_control_sequence]|.
+
+3) If |save_type(p)=insert_token|, then |save_value(p)| is a token that should be
+inserted into \TeX's input when the current group ends.
+
+4) If |save_type(p)=level_boundary|, then |save_level(p)| is a code explaining
+what kind of group we were previously in, and |save_value(p)| points to the level
+boundary word at the bottom of the entries for that group. Furthermore,
+|save_value(p-1)| contains the source line number at which the current level of
+grouping was entered, this field has itself a type: |save_type(p-1)==saved_line|.
+
+Besides this `official' use, various subroutines push temporary variables on the
+save stack when it is handy to do so. These all have an explicit |save_type|, and
+they are:
|saved_adjust| signifies an adjustment is beging scanned,
|saved_insert| an insertion is being scanned,
@@ -154,32 +147,34 @@ an explicit |save_type|, and they are:
|saved_boxattr| the box \.{attr} specification,
|saved_boxpack| the box \.{pack} specification.
-@ The global variable |cur_group| keeps track of what sort of group we are
-currently in. Another global variable, |cur_boundary|, points to the
-topmost |level_boundary| word. And |cur_level| is the current depth of
-nesting. The routines are designed to preserve the condition that no entry
-in the |save_stack| or in |eqtb| ever has a level greater than |cur_level|.
+The global variable |cur_group| keeps track of what sort of group we are
+currently in. Another global variable, |cur_boundary|, points to the topmost
+|level_boundary| word. And |cur_level| is the current depth of nesting. The
+routines are designed to preserve the condition that no entry in the |save_stack|
+or in |eqtb| ever has a level greater than |cur_level|.
+
+*/
-@c
save_record *save_stack;
-int save_ptr; /* first unused entry on |save_stack| */
+int save_ptr; /* first unused entry on the save stack */
int max_save_stack; /* maximum usage of save stack */
quarterword cur_level = level_one; /* current nesting level for groups */
group_code cur_group = bottom_level; /* current group type */
int cur_boundary; /* where the current level begins */
-@ At this time it might be a good idea for the reader to review the introduction
-to |eqtb| that was given above just before the long lists of parameter names.
-Recall that the ``outer level'' of the program is |level_one|, since
-undefined control sequences are assumed to be ``defined'' at |level_zero|.
+/*tex
+At this time it might be a good idea for the reader to review the introduction to
+|eqtb| that was given above just before the long lists of parameter names. Recall
+that the ``outer level'' of the program is |level_one|, since undefined control
+sequences are assumed to be ``defined'' at |level_zero|.
+The following macro is used to test if there is room for up to eight more entries
+on |save_stack|. By making a conservative test like this, we can get by with
+testing for overflow in only a few places.
-@ The following macro is used to test if there is room for up to eight more
-entries on |save_stack|. By making a conservative test like this, we can
-get by with testing for overflow in only a few places.
+*/
-@c
#define check_full_save_stack() do { \
if (save_ptr>max_save_stack) { \
max_save_stack=save_ptr; \
@@ -188,30 +183,32 @@ get by with testing for overflow in only a few places.
} \
} while (0)
-@ Procedure |new_save_level| is called when a group begins. The
-argument is a group identification code like `|hbox_group|'. After
-calling this routine, it is safe to put six more entries on |save_stack|.
+/*tex
+
+Procedure |new_save_level| is called when a group begins. The argument is a group
+identification code like `|hbox_group|'. After calling this routine, it is safe
+to put six more entries on |save_stack|.
-In some cases integer-valued items are placed onto the
-|save_stack| just below a |level_boundary| word, because this is a
-convenient place to keep information that is supposed to ``pop up'' just
-when the group has finished.
-For example, when `\.{\\hbox to 100pt}' is being treated, the 100pt
-dimension is stored on |save_stack| just before |new_save_level| is
-called.
+In some cases integer-valued items are placed onto the |save_stack| just below a
+|level_boundary| word, because this is a convenient place to keep information
+that is supposed to ``pop up'' just when the group has finished. For example,
+when `\.{\\hbox to 100pt}' is being treated, the 100pt dimension is stored on
+|save_stack| just before |new_save_level| is called.
+
+*/
-@c
void new_save_level(group_code c)
-{ /* begin a new level of grouping */
+{ /*tex We begin a new level of grouping. */
check_full_save_stack();
set_saved_record(0, saved_line, 0, line);
incr(save_ptr);
save_type(save_ptr) = level_boundary;
save_level(save_ptr) = cur_group;
save_value(save_ptr) = cur_boundary;
- if (cur_level == max_quarterword)
+ if (cur_level == max_quarterword) {
overflow("grouping levels", max_quarterword - min_quarterword);
- /* quit if |(cur_level+1)| is too big to be stored in |eqtb| */
+ }
+ /*tex We quit if |(cur_level+1)| is too big to be stored in |eqtb|. */
cur_boundary = save_ptr;
cur_group = c;
if (tracing_groups_par > 0)
@@ -220,7 +217,6 @@ void new_save_level(group_code c)
incr(save_ptr);
}
-@ @c
static const char *save_stack_type(int v)
{
const char *s = "";
@@ -243,13 +239,13 @@ static const char *save_stack_type(int v)
case saved_boxdir: s = "saved_boxdir"; break;
case saved_boxattr: s = "saved_boxattr"; break;
case saved_boxpack: s = "saved_boxpack"; break;
+ case saved_attrlist: s = "saved_attrlist"; break;
case saved_eqtb: s = "saved_eqtb"; break;
default: break;
}
return s;
}
-@ @c
void print_save_stack(void)
{
int i;
@@ -274,7 +270,7 @@ void print_save_stack(void)
print_int(save_word(i - 1).cint);
} else {
print_int(eq_type_field(save_word(i - 1)));
- print_char(','); /* |print_int(eq_level_field(save_word(i-1)));| */
+ print_char(',');
print_int(equiv_field(save_word(i - 1)));
}
i--;
@@ -303,17 +299,21 @@ void print_save_stack(void)
break;
case saved_adjust:
tprint(", ");
- print_int(save_level(i)); /* vadjust vs vadjust pre */
+ /*tex vadjust vs vadjust pre */
+ print_int(save_level(i));
break;
case saved_insert:
tprint(", ");
- print_int(save_value(i)); /* insert number */
+ /*tex insert number */
+ print_int(save_value(i));
break;
- case saved_boxtype: /* \.{\\localleftbox} vs \.{\\localrightbox} */
+ case saved_boxtype:
+ /*tex \.{\\localleftbox} vs \.{\\localrightbox} */
tprint(", ");
print_int(save_value(i));
break;
- case saved_eqno: /* \.{\\eqno} vs \.{\\leqno} */
+ case saved_eqno:
+ /*tex \.{\\eqno} vs \.{\\leqno} */
tprint(", ");
print_int(save_value(i));
break;
@@ -339,10 +339,11 @@ void print_save_stack(void)
case saved_textdir:
case saved_boxdir:
tprint(", ");
- print_dir(dir_dir(save_value(i)));
+ print_dir_text(save_value(i));
break;
case saved_boxattr:
case saved_boxpack:
+ case saved_attrlist:
tprint(", ");
print_int(save_value(i));
break;
@@ -357,27 +358,28 @@ void print_save_stack(void)
end_diagnostic(true);
}
-@ The \.{\\showgroups} command displays all currently active grouping
- levels.
+/*tex
+
+The \.{\\showgroups} command displays all currently active grouping levels.
+
+The modifications of \TeX\ required for the display produced by the
+|show_save_groups| procedure were first discussed by Donald~E. Knuth in {\sl
+TUGboat\/} {\bf 11}, 165--170 and 499--511, 1990. @^Knuth, Donald Ervin@>
-@ The modifications of \TeX\ required for the display produced by the
- |show_save_groups| procedure were first discussed by Donald~E. Knuth in
- {\sl TUGboat\/} {\bf 11}, 165--170 and 499--511, 1990.
- @^Knuth, Donald Ervin@>
+In order to understand a group type we also have to know its mode. Since
+unrestricted horizontal modes are not associated with grouping, they are skipped
+when traversing the semantic nest.
- In order to understand a group type we also have to know its mode.
- Since unrestricted horizontal modes are not associated with grouping,
- they are skipped when traversing the semantic nest.
+*/
-@c
void show_save_groups(void)
{
- int p = nest_ptr; /* index into |nest| */
- int m; /* mode */
- save_pointer v = save_ptr; /* saved value of |save_ptr| */
- quarterword l = cur_level; /* saved value of |cur_level| */
- group_code c = cur_group; /* saved value of |cur_group| */
- int a = 1; /* to keep track of alignments */
+ int p = nest_ptr;
+ int m;
+ save_pointer v = save_ptr;
+ quarterword l = cur_level;
+ group_code c = cur_group;
+ int a = 1; /* to keep track of alignments */
int i;
quarterword j;
const char *s = NULL;
@@ -447,16 +449,21 @@ void show_save_groups(void)
break;
case disc_group:
tprint_esc("discretionary");
- for (i = 1; i < 3; i++)
- if (i <= saved_value(-2))
+ for (i = 1; i < 3; i++) {
+ if (i <= saved_value(-2)) {
tprint("{}");
+ }
+ }
goto FOUND2;
break;
case math_choice_group:
tprint_esc("mathchoice");
- for (i = 1; i < 4; i++)
- if (i <= saved_value(-3)) /* different offset because |-2==saved_textdir| */
+ for (i = 1; i < 4; i++) {
+ /*tex A different offset because |-2==saved_textdir|: */
+ if (i <= saved_value(-3)) {
tprint("{}");
+ }
+ }
goto FOUND2;
break;
case insert_group:
@@ -500,7 +507,7 @@ void show_save_groups(void)
confusion("showgroups");
break;
}
- /* Show the box context */
+ /*tex Show the box context */
i = saved_value(-5);
if (i != 0) {
if (i < box_flag) {
@@ -528,9 +535,8 @@ void show_save_groups(void)
}
FOUND1:
tprint_esc(s);
- /* Show the box packaging info */
+ /*tex Show the box packaging info. The offsets may vary. */
{
- /* offsets may vary */
int ii = -1;
while (saved_type(ii) != saved_boxspec)
ii--;
@@ -558,18 +564,20 @@ void show_save_groups(void)
cur_group = c;
}
-@ Just before an entry of |eqtb| is changed, the following procedure should
-be called to update the other data structures properly. It is important
-to keep in mind that reference counts in |mem| include references from
-within |save_stack|, so these counts must be handled carefully.
-@^reference counts@>
+/*tex
+
+Just before an entry of |eqtb| is changed, the following procedure should be
+called to update the other data structures properly. It is important to keep in
+mind that reference counts in |mem| include references from within |save_stack|,
+so these counts must be handled carefully. @^reference counts@>
-@c
-/* we don't need to destroy when an assignment has the same node */
+We don't need to destroy when an assignment has the same node:
+
+*/
void eq_destroy(memory_word w)
-{ /* gets ready to forget |w| */
- halfword q; /* |equiv| field of |w| */
+{
+ halfword q;
switch (eq_type_field(w)) {
case call_cmd:
case long_call_cmd:
@@ -581,10 +589,16 @@ void eq_destroy(memory_word w)
flush_node(equiv_field(w));
break;
case shape_ref_cmd:
- q = equiv_field(w); /* we need to free a \.{\\parshape} block */
- if (q != null)
+ q = equiv_field(w);
+ if (q != null) {
+ /*tex
+ We need to free a \.{\\parshape} block. Such a block is
+ |2n+1| words long, where |n=vinfo(q)|. It happens in the
+ flush function.
+ */
flush_node(q);
- break; /* such a block is |2n+1| words long, where |n=vinfo(q)| */
+ }
+ break;
case box_ref_cmd:
flush_node_list(equiv_field(w));
break;
@@ -593,12 +607,14 @@ void eq_destroy(memory_word w)
}
}
-@ To save a value of |eqtb[p]| that was established at level |l|, we
-can use the following subroutine.
+/*tex
-@c
+To save a value of |eqtb[p]| that was established at level |l|, we can use the
+following subroutine.
+
+*/
void eq_save(halfword p, quarterword l)
-{ /* saves |eqtb[p]| */
+{
check_full_save_stack();
if (l == level_zero) {
save_type(save_ptr) = restore_zero;
@@ -613,16 +629,17 @@ void eq_save(halfword p, quarterword l)
incr(save_ptr);
}
-@ The procedure |eq_define| defines an |eqtb| entry having specified
-|eq_type| and |equiv| fields, and saves the former value if appropriate.
-This procedure is used only for entries in the first four regions of |eqtb|,
-i.e., only for entries that have |eq_type| and |equiv| fields.
-After calling this routine, it is safe to put four more entries on
-|save_stack|, provided that there was room for four more entries before
-the call, since |eq_save| makes the necessary test.
+/*tex
+
+The procedure |eq_define| defines an |eqtb| entry having specified |eq_type| and
+|equiv| fields, and saves the former value if appropriate. This procedure is used
+only for entries in the first four regions of |eqtb|, i.e., only for entries that
+have |eq_type| and |equiv| fields. After calling this routine, it is safe to put
+four more entries on |save_stack|, provided that there was room for four more
+entries before the call, since |eq_save| makes the necessary test.
+
+*/
-@ new data for |eqtb|
-@c
void eq_define(halfword p, quarterword t, halfword e)
{
boolean trace = tracing_assigns_par > 0;
@@ -645,11 +662,14 @@ void eq_define(halfword p, quarterword t, halfword e)
diagnostic_trace(p, "into");
}
-@ The counterpart of |eq_define| for the remaining (fullword) positions in
-|eqtb| is called |eq_word_define|. Since |xeq_level[p]>=level_one| for all
-|p|, a `|restore_zero|' will never be used in this case.
+/*tex
+
+The counterpart of |eq_define| for the remaining (fullword) positions in |eqtb|
+is called |eq_word_define|. Since |xeq_level[p]>=level_one| for all |p|, a
+`|restore_zero|' will never be used in this case.
+
+*/
-@c
void eq_word_define(halfword p, int w)
{
boolean trace = tracing_assigns_par > 0;
@@ -669,15 +689,17 @@ void eq_word_define(halfword p, int w)
diagnostic_trace(p, "into");
}
+/*tex
-@ The |eq_define| and |eq_word_define| routines take care of local definitions.
-@^global definitions@>
-Global definitions are done in almost the same way, but there is no need
-to save old values, and the new value is associated with |level_one|.
+The |eq_define| and |eq_word_define| routines take care of local definitions.
+@^global definitions@> Global definitions are done in almost the same way, but
+there is no need to save old values, and the new value is associated with
+|level_one|.
+
+*/
-@c
void geq_define(halfword p, quarterword t, halfword e)
-{ /* global |eq_define| */
+{
boolean trace = tracing_assigns_par > 0;
if (trace)
diagnostic_trace(p, "globally changing");
@@ -690,7 +712,7 @@ void geq_define(halfword p, quarterword t, halfword e)
}
void geq_word_define(halfword p, int w)
-{ /* global |eq_word_define| */
+{
boolean trace = tracing_assigns_par > 0;
if (trace)
diagnostic_trace(p, "globally changing");
@@ -700,9 +722,12 @@ void geq_word_define(halfword p, int w)
diagnostic_trace(p, "into");
}
-@ Subroutine |save_for_after| puts a token on the stack for save-keeping.
+/*tex
+
+Subroutine |save_for_after| puts a token on the stack for save-keeping.
+
+*/
-@c
void save_for_after(halfword t)
{
if (cur_level > level_one) {
@@ -714,16 +739,20 @@ void save_for_after(halfword t)
}
}
-@ The |unsave| routine goes the other way, taking items off of |save_stack|.
-This routine takes care of restoration when a level ends; everything
-belonging to the topmost group is cleared off of the save stack.
+/*tex
+
+The |unsave| routine goes the other way, taking items off of |save_stack|. This
+routine takes care of restoration when a level ends; everything belonging to the
+topmost group is cleared off of the save stack.
+
+*/
-@c
void unsave(void)
-{ /* pops the top level off the save stack */
- halfword p; /* position to be restored */
- quarterword l = level_one; /* saved level, if in fullword regions of |eqtb| */
- boolean a = false; /* have we already processed an \.{\\aftergroup} ? */
+{
+ halfword p;
+ quarterword l = level_one;
+ /*tex Variable |a| registers if we already have processed an \.{\\aftergroup}. */
+ boolean a = false;
unsave_math_codes(cur_level);
unsave_cat_codes(cat_code_table_par, cur_level);
unsave_text_codes(cur_level);
@@ -731,7 +760,7 @@ void unsave(void)
if (cur_level > level_one) {
boolean trace = tracing_restores_par > 0;
decr(cur_level);
- /* Clear off top level from |save_stack| */
+ /*tex Clear off top level from |save_stack|. */
while (true) {
decr(save_ptr);
if (save_type(save_ptr) == level_boundary)
@@ -739,7 +768,8 @@ void unsave(void)
p = save_value(save_ptr);
if (save_type(save_ptr) == insert_token) {
reinsert_token(a, p);
- a = true; /* always ... always etex now */
+ /*tex always |true| as we are always in \ETEX\ now. */
+ a = true;
} else {
if (save_type(save_ptr) == restore_old_value) {
l = save_level(save_ptr);
@@ -747,21 +777,25 @@ void unsave(void)
} else {
save_word(save_ptr) = eqtb[undefined_control_sequence];
}
- /* Store |save_stack[save_ptr]| in |eqtb[p]|, unless
- |eqtb[p]| holds a global value */
- /* A global definition, which sets the level to |level_one|,
- will not be undone by |unsave|. If at least one global definition of
- |eqtb[p]| has been carried out within the group that just ended, the
- last such definition will therefore survive.
- */
+ /*tex
+ Store |save_stack[save_ptr]| in |eqtb[p]|, unless |eqtb[p]|
+ holds a global value A global definition, which sets the
+ level to |level_one|, will not be undone by |unsave|. If at
+ least one global definition of |eqtb[p]| has been carried out
+ within the group that just ended, the last such definition
+ will therefore survive.
+ */
if (p < int_base || p > eqtb_size) {
if (eq_level(p) == level_one) {
- eq_destroy(save_word(save_ptr)); /* destroy the saved value */
+ /*tex Destroy the saved value: */
+ eq_destroy(save_word(save_ptr));
if (trace)
diagnostic_trace(p, "retaining");
} else {
- eq_destroy(eqtb[p]); /* destroy the current value */
- eqtb[p] = save_word(save_ptr); /* restore the saved value */
+ /*tex Destroy the current value: */
+ eq_destroy(eqtb[p]);
+ /*tex Restore the saved value: */
+ eqtb[p] = save_word(save_ptr);
if (trace)
diagnostic_trace(p, "restoring");
}
@@ -776,32 +810,40 @@ void unsave(void)
}
}
}
- if (tracing_groups_par > 0)
+
+ if (tracing_groups_par > 0) {
group_trace(true);
- if (grp_stack[in_open] == cur_boundary)
- group_warning(); /* groups possibly not properly nested with files */
+ }
+ if (grp_stack[in_open] == cur_boundary) {
+ /*tex Groups are possibly not properly nested with files. */
+ group_warning();
+ }
cur_group = save_level(save_ptr);
cur_boundary = save_value(save_ptr);
decr(save_ptr);
} else {
- confusion("curlevel"); /* |unsave| is not used when |cur_group=bottom_level| */
+ /*tex |unsave| is not used when |cur_group=bottom_level| */
+ confusion("curlevel");
}
attr_list_cache = cache_disabled;
}
-@ Most of the parameters kept in |eqtb| can be changed freely, but there's
-an exception: The magnification should not be used with two different
-values during any \TeX\ job, since a single magnification is applied to an
-entire run. The global variable |mag_set| is set to the current magnification
-whenever it becomes necessary to ``freeze'' it at a particular value.
+/*tex
+
+Most of the parameters kept in |eqtb| can be changed freely, but there's an
+exception: The magnification should not be used with two different values during
+any \TeX\ job, since a single magnification is applied to an entire run. The
+global variable |mag_set| is set to the current magnification whenever it becomes
+necessary to ``freeze'' it at a particular value.
-@c
-int mag_set = 0; /* if nonzero, this magnification should be used henceforth */
+The |prepare_mag| subroutine is called whenever \TeX\ wants to use |mag| for
+magnification. If nonzero, this magnification should be used henceforth. We might
+drop magnifaction at some point.
-@ The |prepare_mag| subroutine is called whenever \TeX\ wants to use |mag|
-for magnification.
+*/
+
+int mag_set = 0;
-@c
void prepare_mag(void)
{
if ((mag_set > 0) && (mag_par != mag_set)) {
@@ -809,14 +851,18 @@ void prepare_mag(void)
print_int(mag_par);
tprint(");");
tprint_nl(" the previous value will be retained");
- help2("I can handle only one magnification ratio per job. So I've",
- "reverted to the magnification you used earlier on this run.");
+ help2(
+ "I can handle only one magnification ratio per job. So I've",
+ "reverted to the magnification you used earlier on this run."
+ );
int_error(mag_set);
geq_word_define(int_base + mag_code, mag_set); /* |mag:=mag_set| */
}
if ((mag_par <= 0) || (mag_par > 32768)) {
print_err("Illegal magnification has been changed to 1000");
- help1("The magnification ratio must be between 1 and 32768.");
+ help1(
+ "The magnification ratio must be between 1 and 32768."
+ );
int_error(mag_par);
geq_word_define(int_base + mag_code, 1000);
}
@@ -829,65 +875,74 @@ void prepare_mag(void)
mag_set = mag_par;
}
-@ Let's pause a moment now and try to look at the Big Picture.
-The \TeX\ program consists of three main parts: syntactic routines,
-semantic routines, and output routines. The chief purpose of the
-syntactic routines is to deliver the user's input to the semantic routines,
-one token at a time. The semantic routines act as an interpreter
-responding to these tokens, which may be regarded as commands. And the
-output routines are periodically called on to convert box-and-glue
-lists into a compact set of instructions that will be sent
-to a typesetter. We have discussed the basic data structures and utility
-routines of \TeX, so we are good and ready to plunge into the real activity by
-considering the syntactic routines.
-
-Our current goal is to come to grips with the |get_next| procedure,
-which is the keystone of \TeX's input mechanism. Each call of |get_next|
-sets the value of three variables |cur_cmd|, |cur_chr|, and |cur_cs|,
-representing the next input token.
-$$\vbox{\halign{#\hfil\cr
- \hbox{|cur_cmd| denotes a command code from the long list of codes
- given above;}\cr
- \hbox{|cur_chr| denotes a character code or other modifier of the command
- code;}\cr
- \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr
- \hbox{\qquad if the current token was a control sequence,
- otherwise it's zero.}\cr}}$$
-Underlying this external behavior of |get_next| is all the machinery
-necessary to convert from character files to tokens. At a given time we
-may be only partially finished with the reading of several files (for
-which \.{\\input} was specified), and partially finished with the expansion
-of some user-defined macros and/or some macro parameters, and partially
-finished with the generation of some text in a template for \.{\\halign},
-and so on. When reading a character file, special characters must be
-classified as math delimiters, etc.; comments and extra blank spaces must
-be removed, paragraphs must be recognized, and control sequences must be
-found in the hash table. Furthermore there are occasions in which the
-scanning routines have looked ahead for a word like `\.{plus}' but only
-part of that word was found, hence a few characters must be put back
-into the input and scanned again.
-
-To handle these situations, which might all be present simultaneously,
-\TeX\ uses various stacks that hold information about the incomplete
-activities, and there is a finite state control for each level of the
-input mechanism. These stacks record the current state of an implicitly
-recursive process, but the |get_next| procedure is not recursive.
-Therefore it will not be difficult to translate these algorithms into
-low-level languages that do not support recursion.
-
-@c
-int cur_cmd; /* current command set by |get_next| */
-halfword cur_chr; /* operand of current command */
-halfword cur_cs; /* control sequence found here, zero if none found */
-halfword cur_tok; /* packed representative of |cur_cmd| and |cur_chr| */
-
-@ Here is a procedure that displays the current command.
-
-@c
+/*tex
+
+Let's pause a moment now and try to look at the Big Picture. The \TeX\ program
+consists of three main parts: syntactic routines, semantic routines, and output
+routines. The chief purpose of the syntactic routines is to deliver the user's
+input to the semantic routines, one token at a time. The semantic routines act as
+an interpreter responding to these tokens, which may be regarded as commands. And
+the output routines are periodically called on to convert box-and-glue lists into
+a compact set of instructions that will be sent to a typesetter. We have
+discussed the basic data structures and utility routines of \TeX, so we are good
+and ready to plunge into the real activity by considering the syntactic routines.
+
+Our current goal is to come to grips with the |get_next| procedure, which is the
+keystone of \TeX's input mechanism. Each call of |get_next| sets the value of
+three variables |cur_cmd|, |cur_chr|, and |cur_cs|, representing the next input
+token.
+
+$$
+ \vbox{\halign{#\hfil\cr
+ \hbox{|cur_cmd| denotes a command code from the long list of codes given above;}\cr
+ \hbox{|cur_chr| denotes a character code or other modifier of the command code;}\cr
+ \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr
+ \hbox{\qquad if the current token was a control sequence, otherwise it's zero.}\cr}}
+$$
+
+Underlying this external behavior of |get_next| is all the machinery necessary to
+convert from character files to tokens. At a given time we may be only partially
+finished with the reading of several files (for which \.{\\input} was specified),
+and partially finished with the expansion of some user-defined macros and/or some
+macro parameters, and partially finished with the generation of some text in a
+template for \.{\\halign}, and so on. When reading a character file, special
+characters must be classified as math delimiters, etc.; comments and extra blank
+spaces must be removed, paragraphs must be recognized, and control sequences must
+be found in the hash table. Furthermore there are occasions in which the scanning
+routines have looked ahead for a word like `\.{plus}' but only part of that word
+was found, hence a few characters must be put back into the input and scanned
+again.
+
+To handle these situations, which might all be present simultaneously, \TeX\ uses
+various stacks that hold information about the incomplete activities, and there
+is a finite state control for each level of the input mechanism. These stacks
+record the current state of an implicitly recursive process, but the |get_next|
+procedure is not recursive. Therefore it will not be difficult to translate these
+algorithms into low-level languages that do not support recursion.
+
+In general, |cur_cmd| is the current command as set by |get_next|, while
+|cur_chr| is the operand of the current command. The control sequence found here
+is registsred in |cur_cs| and is zero if none found. The |cur_tok| variable
+contains the packed representative of |cur_cmd| and |cur_chr| and like the other
+ones is global.
+
+*/
+
+int cur_cmd;
+halfword cur_chr;
+halfword cur_cs;
+halfword cur_tok;
+
+/*tex
+
+Here is a procedure that displays the current command. The variable |n| holds the
+level of \.{\\if...\\fi} nesting and |l| the line where \.{\\if} started.
+
+*/
+
void show_cur_cmd_chr(void)
{
- int n; /* level of \.{\\if...\\fi} nesting */
- int l; /* line where \.{\\if} started */
+ int n, l;
halfword p;
begin_diagnostic();
tprint_nl("{");
@@ -926,23 +981,26 @@ void show_cur_cmd_chr(void)
end_diagnostic(false);
}
-@ Here is a procedure that displays the contents of |eqtb[n]| symbolically.
+/*tex
+
+Here is a procedure that displays the contents of |eqtb[n]| symbolically.
+
+*/
-@c
void show_eqtb(halfword n)
{
if (n < null_cs) {
- /* this can't happen */
- print_char('?');
+ /*tex
+ This can't happen in a pure \TEX\ run, but careless usage of tokens
+ at the \LUA\ end can make you end up here.
+ */
+ tprint("? bad token, case 1: ");
+ print_int(n);
} else if ((n < glue_base) || ((n > eqtb_size) && (n <= eqtb_top))) {
- /*
- Show equivalent |n|, in region 1 or 2
-
- Here is a routine that displays the current meaning of an |eqtb| entry
- in region 1 or~2. (Similar routines for the other regions will appear
- below.)
+ /*tex
+ This routine show the current meaning of |eqtb| entry |n| in region 1 or 2.
+ Similar routines for the other regions will appear below.
*/
-
sprint_cs(n);
print_char('=');
print_cmd_chr(eq_type(n), equiv(n));
@@ -951,10 +1009,9 @@ void show_eqtb(halfword n)
show_token_list(token_link(equiv(n)), null, 32);
}
} else if (n < local_base) {
- /*
- Show equivalent |n|, in region 3
-
- All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'.
+ /*tex
+ Here we show equivalent |n| in region 3. All glue parameters and registers
+ are initially `\.{0pt plus0pt minus0pt}'.
*/
if (n < skip_base) {
if (n < glue_base + thin_mu_skip_code)
@@ -979,18 +1036,17 @@ void show_eqtb(halfword n)
}
} else if (n < int_base) {
- /*
- Show equivalent |n|, in region 4
-
- We initialize most things to null or undefined values. An undefined font
- is represented by the internal code |font_base|.
-
- However, the character code tables are given initial values based on the
- conventional interpretation of ASCII code. These initial values should
- not be changed when \TeX\ is adapted for use with non-English languages;
- all changes to the initialization conventions should be made in format
- packages, not in \TeX\ itself, so that global interchange of formats is
- possible.
+ /*tex
+ We're now at equivalent |n| in region 4. First we initialize most
+ things to null or undefined values. An undefined font is represented
+ by the internal code |font_base|.
+
+ However, the character code tables are given initial values based on
+ the conventional interpretation of ASCII code. These initial values
+ should not be changed when \TeX\ is adapted for use with non-English
+ languages; all changes to the initialization conventions should be
+ made in format packages, not in \TeX\ itself, so that global
+ interchange of formats is possible.
*/
if ((n == par_shape_loc) || ((n >= etex_pen_base) && (n < etex_pens))) {
if (n == par_shape_loc)
@@ -1032,13 +1088,16 @@ void show_eqtb(halfword n)
show_node_list(equiv(n));
}
} else if (n == cur_font_loc) {
- /* Show the font identifier in |eqtb[n]| */
+ /*tex
+ Let's show the font identifier in |eqtb[n]|, that's
+ |font_id_text(equiv(n))|
+ */
tprint("current font");
print_char('=');
- print_esc(hash[font_id_base + equiv(n)].rh); /* that's |font_id_text(equiv(n))| */
+ print_esc(hash[font_id_base + equiv(n)].rh);
}
} else if (n < dimen_base) {
- /* Show equivalent |n|, in region 5 */
+ /*tex Show equivalent |n| in region 5: */
if (n < dir_base) {
print_cmd_chr(assign_int_cmd, n);
print_char('=');
@@ -1046,7 +1105,7 @@ void show_eqtb(halfword n)
} else if (n < count_base) {
print_cmd_chr(assign_dir_cmd, n);
print_char(' ');
- print_dir(eqtb[n].cint);
+ print_dir_par(eqtb[n].cint);
} else if (n < attribute_base) {
tprint_esc("count");
print_int(n - count_base);
@@ -1059,7 +1118,7 @@ void show_eqtb(halfword n)
print_int(eqtb[n].cint);
}
} else if (n <= eqtb_size) {
- /* Show equivalent |n|, in region 6 */
+ /*tex Show equivalent |n| in region 6: */
if (n < scaled_base) {
print_cmd_chr(assign_dimen_cmd, n);
} else {
@@ -1070,31 +1129,28 @@ void show_eqtb(halfword n)
print_scaled(eqtb[n].cint);
tprint("pt");
} else {
- /* this can't happen either */
- print_char('?');
+ /*tex This can't happen unless you messed up at the \LUA\ end. */
+ tprint("? bad token, case 2: ");
+ print_int(n);
}
}
-@ @c
void show_eqtb_meaning(halfword n)
{
if (n < null_cs) {
- /* this can't happen */
+ /*tex This can't happen. */
print_char('?');
} else if ((n < glue_base) || ((n > eqtb_size) && (n <= eqtb_top))) {
- /*
- Show equivalent |n|, in region 1 or 2
-
- Here is a routine that displays the current meaning of an |eqtb| entry
- in region 1 or~2. (Similar routines for the other regions will appear
- below.)
+ /*tex
+ Here is a routine that displays the current meaning of an |eqtb|
+ entry in region 1 or~2. Similar routines for the other regions will
+ appear below.
*/
sprint_cs(n);
} else if (n < local_base) {
/*
- Show equivalent |n|, in region 3
-
- All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'.
+ Show equivalent |n| in region 3. All glue parameters and registers
+ are initially `\.{0pt plus0pt minus0pt}'.
*/
if (n < skip_base) {
if (n < glue_base + thin_mu_skip_code)
@@ -1108,20 +1164,16 @@ void show_eqtb_meaning(halfword n)
tprint_esc("muskip");
print_int(n - mu_skip_base);
}
-
} else if (n < int_base) {
- /*
- Show equivalent |n|, in region 4
-
- We initialize most things to null or undefined values. An undefined font
- is represented by the internal code |font_base|.
-
- However, the character code tables are given initial values based on the
- conventional interpretation of ASCII code. These initial values should
- not be changed when \TeX\ is adapted for use with non-English languages;
- all changes to the initialization conventions should be made in format
- packages, not in \TeX\ itself, so that global interchange of formats is
- possible.
+ /*tex
+ Show equivalent |n| in region 4. We initialize most things to null or
+ undefined values. An undefined font is represented by the internal
+ code |font_base|. However, the character code tables are given
+ initial values based on the conventional interpretation of ASCII
+ code. These initial values should not be changed when \TeX\ is
+ adapted for use with non-English languages; all changes to the
+ initialization conventions should be made in format packages, not in
+ \TeX\ itself, so that global interchange of formats is possible.
*/
if ((n == par_shape_loc) || ((n >= etex_pen_base) && (n < etex_pens))) {
if (n == par_shape_loc)
@@ -1137,11 +1189,11 @@ void show_eqtb_meaning(halfword n)
tprint_esc("box");
print_int(n - box_base);
} else if (n == cur_font_loc) {
- /* Show the font identifier in |eqtb[n]| */
+ /*tex Show the font identifier in |eqtb[n]|. */
tprint("current font");
}
} else if (n < dimen_base) {
- /* Show equivalent |n|, in region 5 */
+ /*tex Show equivalent |n| in region 5. */
if (n < dir_base) {
print_cmd_chr(assign_int_cmd, n);
} else if (n < count_base) {
@@ -1154,7 +1206,7 @@ void show_eqtb_meaning(halfword n)
print_int(n - attribute_base);
}
} else if (n <= eqtb_size) {
- /* Show equivalent |n|, in region 6 */
+ /*tex Show equivalent |n| in region 6. */
if (n < scaled_base) {
print_cmd_chr(assign_dimen_cmd, n);
} else {
@@ -1162,7 +1214,7 @@ void show_eqtb_meaning(halfword n)
print_int(n - scaled_base);
}
} else {
- /* this can't happen either */
+ /*tex This can't happen either. */
print_char('?');
}
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/errors.c b/Build/source/texk/web2c/luatexdir/tex/errors.c
new file mode 100644
index 00000000000..b630422ee98
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/errors.c
@@ -0,0 +1,1032 @@
+/*
+
+errors.w
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+#define edit_var "TEXEDIT"
+
+/*tex
+
+When something anomalous is detected, \TeX\ typically does something like this:
+$$\vbox{\halign{#\hfil\cr |print_err("Something anomalous has been
+detected");|\cr |help3("This is the first line of my offer to help.")|\cr |("This
+is the second line. I'm trying to")|\cr |("explain the best way for you to
+proceed.");|\cr |error;|\cr}}$$ A two-line help message would be given using
+|help2|, etc.; these informal helps should use simple vocabulary that complements
+the words used in the official error message that was printed. (Outside the
+U.S.A., the help messages should preferably be translated into the local
+vernacular. Each line of help is at most 60 characters long, in the present
+implementation, so that |max_print_line| will not be exceeded.)
+
+The |print_err| procedure supplies a `\.!' before the official message, and makes
+sure that the terminal is awake if a stop is going to occur. The |error|
+procedure supplies a `\..' after the official message, then it shows the location
+of the error; and if |interaction=error_stop_mode|, it also enters into a dialog
+with the user, during which time the help message may be printed. @^system
+dependencies@>
+
+*/
+
+/*tex The current level of interaction: */
+
+int interaction;
+
+/*tex Set from the command line: */
+
+int interactionoption;
+
+char *last_error = NULL;
+char *last_lua_error = NULL;
+char *last_warning_tag = NULL;
+char *last_warning_str = NULL;
+char *last_error_context = NULL;
+
+int err_old_setting = 0 ;
+int in_error = 0 ;
+
+void set_last_error_context(void)
+{
+ str_number str;
+ int sel = selector;
+ int saved_new_line_char;
+ int saved_new_string_line;
+ selector = new_string;
+ saved_new_line_char = new_line_char_par;
+ saved_new_string_line = new_string_line;
+ new_line_char_par = 10;
+ new_string_line = 10;
+ show_context();
+ xfree(last_error_context);
+ str = make_string();
+ last_error_context = makecstring(str);
+ flush_str(str);
+ selector = sel;
+ new_line_char_par = saved_new_line_char;
+ new_string_line = saved_new_string_line;
+ return;
+}
+
+void flush_err(void)
+{
+ str_number s_error;
+ char *s = NULL;
+ int callback_id ;
+ if (in_error) {
+ selector = err_old_setting;
+ str_room(1);
+ s_error = make_string();
+ s = makecstring(s_error);
+ flush_str(s_error);
+ if (interaction == error_stop_mode) {
+ wake_up_terminal();
+ }
+ xfree(last_error);
+ last_error = (string) xmalloc((unsigned) (strlen(s) + 1));
+ strcpy(last_error,s);
+ callback_id = callback_defined(show_error_message_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ } else {
+ tprint(s);
+ }
+ in_error = 0 ;
+ }
+}
+
+void print_err(const char *s)
+{
+ int callback_id = callback_defined(show_error_message_callback);
+ if (interaction == error_stop_mode) {
+ wake_up_terminal();
+ }
+ if (callback_id > 0) {
+ err_old_setting = selector;
+ selector = new_string;
+ in_error = 1 ;
+ }
+ if (filelineerrorstylep) {
+ print_file_line();
+ } else {
+ tprint_nl("! ");
+ }
+ tprint(s);
+ if (callback_id <= 0) {
+ xfree(last_error);
+ last_error = (string) xmalloc((unsigned) (strlen(s) + 1));
+ strcpy(last_error,s);
+ }
+}
+
+/*tex
+
+\TeX\ is careful not to call |error| when the print |selector| setting might be
+unusual. The only possible values of |selector| at the time of error messages are
+
+|no_print| (when |interaction=batch_mode| and |log_file| not yet open);
+
+|term_only| (when |interaction>batch_mode| and |log_file| not yet open);
+
+|log_only| (when |interaction=batch_mode| and |log_file| is open);
+
+|term_and_log| (when |interaction>batch_mode| and |log_file| is open).
+
+*/
+
+void fixup_selector(boolean logopened)
+{
+ if (interaction == batch_mode)
+ selector = no_print;
+ else
+ selector = term_only;
+ if (logopened)
+ selector = selector + 2;
+}
+
+/*tex
+
+A global variable |deletions_allowed| is set |false| if the |get_next| routine is
+active when |error| is called; this ensures that |get_next| and related routines
+like |get_token| will never be called recursively. A similar interlock is
+provided by |set_box_allowed|. @^recursion@>
+
+The global variable |history| records the worst level of error that has been
+detected. It has four possible values: |spotless|, |warning_issued|,
+|error_message_issued|, and |fatal_error_stop|.
+
+Another global variable, |error_count|, is increased by one when an |error|
+occurs without an interactive dialog, and it is reset to zero at the end of every
+paragraph. If |error_count| reaches 100, \TeX\ decides that there is no point in
+continuing further.
+
+*/
+
+/*tex Is it safe for |error| to call |get_token|? */
+
+boolean deletions_allowed;
+
+/*tex Is it safe to do a \.{\\setbox} assignment? */
+
+boolean set_box_allowed;
+/*tex Has the source input been clean so far? */
+
+int history;
+
+/*tex The number of scrolled errors since the last paragraph ended. */
+
+int error_count;
+
+/*tex Should \TeX\ pause for instructions? */
+
+int interrupt;
+
+/*tex Should interrupts be observed? */
+
+boolean OK_to_interrupt;
+
+/*tex
+
+The value of |history| is initially |fatal_error_stop|, but it will be changed to
+|spotless| if \TeX\ survives the initialization process.
+
+*/
+
+void initialize_errors(void)
+{
+ if (interactionoption == unspecified_mode)
+ interaction = error_stop_mode;
+ else
+ interaction = interactionoption;
+ deletions_allowed = true;
+ set_box_allowed = true;
+ OK_to_interrupt = true;
+}
+
+/*tex
+
+It is possible for |error| to be called recursively if some error arises when
+|get_token| is being used to delete a token, and/or if some fatal error occurs
+while \TeX\ is trying to fix a non-fatal one. But such recursion @^recursion@> is
+never more than two levels deep.
+
+Individual lines of help are recorded in the array |help_line|.
+
+*/
+
+const char *help_line[7];
+
+/*tex
+ Should the |err_help| list be shown?
+*/
+
+boolean use_err_help;
+
+/*tex
+
+The |jump_out| procedure just cuts across all active procedure levels and exits
+the program. It is used when there is no recovery from a particular error. The
+exit code can be overloaded.
+
+*/
+
+int defaultexitcode = 0;
+
+__attribute__ ((noreturn))
+void do_final_end(void)
+{
+ update_terminal();
+ ready_already = 0;
+ lua_close(Luas);
+ if ((history != spotless) && (history != warning_issued))
+ uexit(1);
+ else
+ uexit(defaultexitcode);
+}
+
+__attribute__ ((noreturn))
+void jump_out(void)
+{
+ close_files_and_terminate();
+ do_final_end();
+}
+
+/*tex
+
+Here is the function that calls the editor, if one is defined. This is loosely
+based on a similar function in kpathsea, but the calling convention is quite
+different.
+
+*/
+
+static const_string edit_value = EDITOR;
+
+#if defined(WIN32)
+
+static int Isspace (char c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+#endif /* WIN32 */
+
+__attribute__ ((noreturn))
+static void luatex_calledit (int baseptr, int linenumber)
+{
+ char *temp, *command, *fullcmd;
+ char c;
+ int sdone, ddone, i;
+ char *filename = makecstring(input_stack[base_ptr].name_field);
+ int fnlength = strlen(filename);
+#ifdef WIN32
+ char *fp, *ffp, *env, editorname[256], buffer[256];
+ int cnt = 0;
+ int dontchange = 0;
+#endif
+ sdone = ddone = 0;
+ /*tex
+ Close any open input files, since we're going to kill the job.
+ */
+ close_files_and_terminate();
+ /*tex
+ Replace the default with the value of the appropriate environment
+ variable or config file value, if it's set.
+ */
+ temp = kpse_var_value (edit_var);
+ if (temp != NULL)
+ edit_value = temp;
+ /*tex
+ Construct the command string. The `11' is the maximum length an
+ integer might be.
+ */
+ command = xmalloc (strlen (edit_value) + fnlength + 11);
+ /*tex
+ So we can construct it as we go.
+ */
+ temp = command;
+#ifdef WIN32
+ fp = editorname;
+ if ((isalpha(*edit_value) && *(edit_value + 1) == ':' && IS_DIR_SEP (*(edit_value + 2)))
+ || (*edit_value == '"' && isalpha(*(edit_value + 1))
+ && *(edit_value + 2) == ':' && IS_DIR_SEP (*(edit_value + 3)))) {
+ dontchange = 1;
+ }
+#endif
+ while ((c = *edit_value++) != 0) {
+ if (c == '%') {
+ switch (c = *edit_value++) {
+ case 'd':
+ if (ddone)
+ FATAL1 ("call_edit: `%%d' appears twice in editor command: `%s'", edit_value);
+ sprintf (temp, "%ld", (long int)linenumber);
+ while (*temp != '\0')
+ temp++;
+ ddone = 1;
+ break;
+ case 's':
+ if (sdone)
+ FATAL1 ("call_edit: `%%s' appears twice in editor command: `%s'", edit_value);
+ for (i =0; i < fnlength; i++)
+ *temp++ = filename[i];
+ sdone = 1;
+ break;
+ case '\0':
+ *temp++ = '%';
+ /*tex
+ Back up to the null to force termination.
+ */
+ edit_value--;
+ break;
+ default:
+ *temp++ = '%';
+ *temp++ = c;
+ break;
+ }
+ } else {
+#ifdef WIN32
+ if (dontchange) {
+ *temp++ = c;
+ } else if(Isspace(c) && cnt == 0) {
+ cnt++;
+ temp = command;
+ *temp++ = c;
+ *fp = '\0';
+ } else if(!Isspace(c) && cnt == 0) {
+ *fp++ = c;
+ } else {
+ *temp++ = c;
+ }
+#else
+ *temp++ = c;
+#endif
+ }
+ }
+ *temp = 0;
+#ifdef WIN32
+ if (dontchange == 0) {
+ if(editorname[0] == '.' || editorname[0] == '/' || editorname[0] == '\\') {
+ fprintf(stderr, "%s is not allowed to execute.\n", editorname);
+ do_final_end();
+ }
+ env = (char *)getenv("PATH");
+ if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
+ if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
+ fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
+ do_final_end();
+ }
+ }
+ fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
+ strcpy(fullcmd, "\"");
+ strcat(fullcmd, buffer);
+ strcat(fullcmd, "\"");
+ strcat(fullcmd, command);
+ }
+#endif
+ fullcmd = command;
+ /*tex Execute the command. */
+ if (system (fullcmd) != 0) {
+ fprintf (stderr, "! Trouble executing `%s'.\n", command);
+ }
+ /*tex Quit, since we found an error. */
+ do_final_end ();
+}
+
+/*tex
+
+ This completes the job of error reporting.
+
+*/
+
+void error(void)
+{
+ /*tex What the user types :*/
+ ASCII_code c;
+ int callback_id;
+ /*tex Used to save global variables when deleting tokens: */
+ int s1, s2, s3, s4;
+ int i;
+ flush_err();
+ if (history < error_message_issued)
+ history = error_message_issued;
+ callback_id = callback_defined(show_error_hook_callback);
+ if (callback_id > 0) {
+ set_last_error_context();
+ run_callback(callback_id, "->");
+ } else {
+ print_char('.');
+ show_context();
+ }
+ if (haltonerrorp) {
+ history = fatal_error_stop;
+ jump_out();
+ }
+ if (interaction == error_stop_mode) {
+ /*tex Get user's advice and |return|. */
+ while (1) {
+ CONTINUE:
+ clear_for_error_prompt();
+ prompt_input("? ");
+ if (last == first)
+ return;
+ c = buffer[first];
+ if (c >= 'a')
+ c = c + 'A' - 'a';
+ /*tex
+ Interpret code |c| and |return| if done. It is desirable to
+ provide an `\.E' option here that gives the user an easy way
+ to return from \TeX\ to the system editor, with the offending
+ line ready to be edited. But such an extension requires some
+ system wizardry, so the present implementation simply types
+ out the name of the file that should be edited and the
+ relevant line number.
+ */
+ switch (c) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (deletions_allowed) {
+ /*tex
+ Delete |c-"0"| tokens and |goto continue|. We allow
+ deletion of up to 99 tokens at a time.
+ */
+ s1 = cur_tok;
+ s2 = cur_cmd;
+ s3 = cur_chr;
+ s4 = align_state;
+ align_state = 1000000;
+ OK_to_interrupt = false;
+ if ((last > first + 1) && (buffer[first + 1] >= '0')
+ && (buffer[first + 1] <= '9'))
+ c = c * 10 + buffer[first + 1] - '0' * 11;
+ else
+ c = c - '0';
+ while (c > 0) {
+ /*tex One-level recursive call of |error| is possible. */
+ get_token();
+ decr(c);
+ }
+ cur_tok = s1;
+ cur_cmd = s2;
+ cur_chr = s3;
+ align_state = s4;
+ OK_to_interrupt = true;
+ help2(
+ "I have just deleted some text, as you asked.",
+ "You can now delete more, or insert, or whatever."
+ );
+ show_context();
+ goto CONTINUE;
+ }
+ break;
+ case 'E':
+ if (base_ptr > 0) {
+ int callback_id = callback_defined(call_edit_callback);
+ if (callback_id>0) {
+ (void)run_callback(callback_id, "Sd->", makecstring(input_stack[base_ptr].name_field), line);
+ /*tex This should not be reached. */
+ jump_out();
+ } else {
+ tprint_nl("You want to edit file ");
+ print(input_stack[base_ptr].name_field);
+ tprint(" at line ");
+ print_int(line);
+ interaction = scroll_mode;
+ if (kpse_init) {
+ luatex_calledit(base_ptr, line);
+ } else {
+ /*tex This should not be reached. */
+ tprint_nl("There is no valid callback defined.");
+ jump_out();
+ }
+ }
+ }
+ break;
+ case 'H':
+ /*tex Print the help information and |goto continue| */
+ if (use_err_help) {
+ give_err_help();
+ } else {
+ if (help_line[0] == NULL) {
+ help2(
+ "Sorry, I don't know how to help in this situation.",
+ "Maybe you should try asking a human?"
+ );
+ }
+ i = 0;
+ while (help_line[i] != NULL)
+ tprint_nl(help_line[i++]);
+ help4(
+ "Sorry, I already gave what help I could...",
+ "Maybe you should try asking a human?",
+ "An error might have occurred before I noticed any problems.",
+ "``If all else fails, read the instructions.''"
+ );
+ goto CONTINUE;
+ }
+ break;
+ case 'I':
+ /*tex
+
+ Introduce new material from the terminal and |return|. When
+ the following code is executed, |buffer[(first+1)..(last-1)]|
+ may contain the material inserted by the user; otherwise
+ another prompt will be given. In order to understand this
+ part of the program fully, you need to be familiar with
+ \TeX's input stacks.
+
+ We enter a new syntactic level for terminal input:
+
+ */
+ begin_file_reading();
+ /*tex
+ Now |state=mid_line|, so an initial blank space will count as
+ a blank.
+ */
+ if (last > first + 1) {
+ iloc = first + 1;
+ buffer[first] = ' ';
+ } else {
+ prompt_input("insert>");
+ iloc = first;
+ }
+ first = last;
+ /*tex No |end_line_char| ends this line. */
+ ilimit = last - 1;
+ return;
+ break;
+ case 'Q':
+ case 'R':
+ case 'S':
+ /*tex
+
+ Change the interaction level and |return|. Here the author of
+ \TeX\ apologizes for making use of the numerical relation
+ between |"Q"|, |"R"|, |"S"|, and the desired interaction
+ settings |batch_mode|, |nonstop_mode|, |scroll_mode|.
+
+ */
+ error_count = 0;
+ interaction = batch_mode + c - 'Q';
+ tprint("OK, entering ");
+ switch (c) {
+ case 'Q':
+ tprint_esc("batchmode");
+ decr(selector);
+ break;
+ case 'R':
+ tprint_esc("nonstopmode");
+ break;
+ case 'S':
+ tprint_esc("scrollmode");
+ break;
+ }
+ tprint("...");
+ print_ln();
+ update_terminal();
+ return;
+ break;
+ case 'X':
+ interaction = scroll_mode;
+ jump_out();
+ break;
+ default:
+ break;
+ }
+ if (!use_err_help) {
+ /* Print the menu of available options */
+ tprint("Type <return> to proceed, S to scroll future error messages,");
+ tprint_nl("R to run without stopping, Q to run quietly,");
+ tprint_nl("I to insert something, ");
+ if (base_ptr > 0)
+ tprint("E to edit your file,");
+ if (deletions_allowed)
+ tprint_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
+ tprint_nl("H for help, X to quit.");
+ }
+ use_err_help = false;
+ }
+
+ }
+ incr(error_count);
+ if (error_count == 100) {
+ tprint_nl("(That makes 100 errors; please try again.)");
+ history = fatal_error_stop;
+ jump_out();
+ }
+ /*tex Put help message on the transcript file. */
+ if (interaction > batch_mode) {
+ /*tex Avoid terminal output: */
+ decr(selector);
+ }
+ if (use_err_help) {
+ print_ln();
+ give_err_help();
+ } else {
+ int i1 = 0;
+ while (help_line[i1] != NULL)
+ tprint_nl(help_line[i1++]);
+ }
+ print_ln();
+ if (interaction > batch_mode) {
+ /*tex Re-enable terminal output: */
+ incr(selector);
+ }
+ print_ln();
+}
+
+/*tex
+
+A dozen or so error messages end with a parenthesized integer, so we save a teeny
+bit of program space by declaring the following procedure:
+
+*/
+
+void int_error(int n)
+{
+ tprint(" (");
+ print_int(n);
+ print_char(')');
+ error();
+}
+
+/*tex
+
+In anomalous cases, the print selector might be in an unknown state; the
+following subroutine is called to fix things just enough to keep running a bit
+longer.
+
+*/
+
+void normalize_selector(void)
+{
+ if (log_opened_global)
+ selector = term_and_log;
+ else
+ selector = term_only;
+ if (job_name == 0)
+ open_log_file();
+ if (interaction == batch_mode)
+ decr(selector);
+}
+
+/*tex
+
+The following procedure prints \TeX's last words before dying.
+
+*/
+
+void succumb(void)
+{
+ if (interaction == error_stop_mode) {
+ /*tex No more interaction: */
+ interaction = scroll_mode;
+ }
+ if (log_opened_global) {
+ error();
+ }
+ history = fatal_error_stop;
+ /*tex Irrecoverable error: */
+ jump_out();
+}
+
+/*tex
+
+This prints |s|, and that's it.
+
+*/
+
+void fatal_error(const char *s)
+{
+ normalize_selector();
+ print_err("Emergency stop");
+ help1(s);
+ succumb();
+}
+
+/*tex
+
+Here is the most dreaded error message. We stop due to finiteness.
+
+*/
+
+void overflow(const char *s, unsigned int n)
+{
+ normalize_selector();
+ print_err("TeX capacity exceeded, sorry [");
+ tprint(s);
+ print_char('=');
+ print_int((int) n);
+ print_char(']');
+ if (varmem == NULL) {
+ print_err("Sorry, I ran out of memory.");
+ print_ln();
+ exit(EXIT_FAILURE);
+ }
+ help2(
+ "If you really absolutely need more capacity,",
+ "you can ask a wizard to enlarge me."
+ );
+ succumb();
+}
+
+/*tex
+
+The program might sometime run completely amok, at which point there is no choice
+but to stop. If no previous error has been detected, that's bad news; a message
+is printed that is really intended for the \TeX\ maintenance person instead of
+the user (unless the user has been particularly diabolical). The index entries
+for `this can't happen' may help to pinpoint the problem. @^dry rot@>
+
+*/
+
+void confusion(const char *s)
+{ /* consistency check violated; |s| tells where */
+ normalize_selector();
+ if (history < error_message_issued) {
+ print_err("This can't happen (");
+ tprint(s);
+ print_char(')');
+ help1(
+ "I'm broken. Please show this to someone who can fix"
+ );
+ } else {
+ print_err("I can't go on meeting you like this");
+ help2(
+ "One of your faux pas seems to have wounded me deeply...",
+ "in fact, I'm barely conscious. Please fix it and try again."
+ );
+ }
+ succumb();
+}
+
+/*tex
+
+Users occasionally want to interrupt \TeX\ while it's running. If the runtime
+system allows this, one can implement a routine that sets the global variable
+|interrupt| to some nonzero value when such an interrupt is signalled. Otherwise
+there is probably at least a way to make |interrupt| nonzero using the debugger.
+@^system dependencies@> @^debugging@>
+
+*/
+
+void check_interrupt(void)
+{
+ if (interrupt != 0)
+ pause_for_instructions();
+}
+
+/*tex
+
+When an interrupt has been detected, the program goes into its highest
+interaction level and lets the user have nearly the full flexibility of the
+|error| routine. \TeX\ checks for interrupts only at times when it is safe to do
+this.
+
+*/
+
+void pause_for_instructions(void)
+{
+ if (OK_to_interrupt) {
+ interaction = error_stop_mode;
+ if ((selector == log_only) || (selector == no_print))
+ incr(selector);
+ print_err("Interruption");
+ help3(
+ "You rang?",
+ "Try to insert some instructions for me (e.g.,`I\\showlists'),",
+ "unless you just want to quit by typing `X'."
+ );
+ deletions_allowed = false;
+ error();
+ deletions_allowed = true;
+ interrupt = 0;
+ }
+}
+
+void tex_error(const char *msg, const char **hlp)
+{
+ print_err(msg);
+ if (hlp != NULL) {
+ int i;
+ for (i = 0; (hlp[i] != NULL && i <= 5); i++) {
+ help_line[i] = hlp[i];
+ }
+ help_line[i] = NULL;
+ } else {
+ help_line[0] = NULL;
+ }
+ error();
+}
+
+/*tex
+
+The |back_error| routine is used when we want to replace an offending token just
+before issuing an error message. This routine, like |back_input|, requires that
+|cur_tok| has been set. We disable interrupts during the call of |back_input| so
+that the help message won't be lost.
+
+*/
+
+void back_error(void)
+{
+ OK_to_interrupt = false;
+ back_input();
+ OK_to_interrupt = true;
+ error();
+}
+
+/*tex
+
+ Back up one inserted token and call |error|.
+*/
+
+void ins_error(void)
+{
+ OK_to_interrupt = false;
+ back_input();
+ token_type = inserted;
+ OK_to_interrupt = true;
+ error();
+}
+
+/*tex
+
+When \TeX\ wants to typeset a character that doesn't exist, the character node is
+not created; thus the output routine can assume that characters exist when it
+sees them. The following procedure prints a warning message unless the user has
+suppressed it.
+
+*/
+
+void char_warning(internal_font_number f, int c)
+{
+ /*tex saved value of |tracing_online| */
+ int old_setting;
+ /* index to current digit; we assume that $0\L n<16^{22}$ */
+ int k;
+ if (tracing_lost_chars_par > 0) {
+ old_setting = tracing_online_par;
+ if (tracing_lost_chars_par > 1)
+ tracing_online_par = 1;
+ begin_diagnostic();
+ tprint_nl("Missing character: There is no ");
+ print(c);
+ tprint(" (U+");
+ k = 0;
+ if (c < 16)
+ print_char('0');
+ if (c < 256)
+ print_char('0');
+ if (c < 4096)
+ print_char('0');
+ do {
+ dig[k] = c % 16;
+ c = c / 16;
+ incr(k);
+ } while (c != 0);
+ print_the_digs((eight_bits) k);
+ tprint(") in font ");
+ print_font_name(f);
+ print_char('!');
+ end_diagnostic(false);
+ tracing_online_par = old_setting;
+ }
+}
+
+void wrapup_backend(void) {
+ ensure_output_state(static_pdf, ST_OMODE_FIX);
+ if (output_mode_used == OMODE_NONE) {
+ print_err(" ==> Fatal error occurred, no FMT file produced!");
+ } else {
+ backend_out_control[backend_control_finish_file](static_pdf,history == fatal_error_stop);
+ }
+}
+
+void normal_error(const char *t, const char *p)
+{
+ normalize_selector();
+ if (interaction == error_stop_mode) {
+ wake_up_terminal();
+ }
+ if (filelineerrorstylep) {
+ print_file_line();
+ } else {
+ tprint_nl("! ");
+ }
+ tprint("error: ");
+ if (cur_file_name) {
+ tprint(" (file ");
+ tprint(cur_file_name);
+ tprint(")");
+ }
+ if (t != NULL) {
+ tprint(" (");
+ tprint(t);
+ tprint(")");
+ }
+ tprint(": ");
+ if (p != NULL)
+ tprint(p);
+ history = fatal_error_stop;
+ wrapup_backend();
+ exit(EXIT_FAILURE);
+}
+
+void normal_warning(const char *t, const char *p)
+{
+ int report_id ;
+ if (strcmp(t,"lua") == 0) {
+ int saved_new_line_char;
+ saved_new_line_char = new_line_char_par;
+ new_line_char_par = 10;
+ report_id = callback_defined(show_lua_error_hook_callback);
+ if (report_id == 0) {
+ tprint(p);
+ help2(
+ "The lua interpreter ran into a problem, so the",
+ "remainder of this lua chunk will be ignored."
+ );
+ } else {
+ (void) run_callback(report_id, "->");
+ }
+ error();
+ new_line_char_par = saved_new_line_char;
+ } else {
+ report_id = callback_defined(show_warning_message_callback);
+ if (report_id > 0) {
+ /*tex Free the last ones, */
+ xfree(last_warning_str);
+ xfree(last_warning_tag);
+ last_warning_str = (string) xmalloc(strlen(p) + 1);
+ last_warning_tag = (string) xmalloc(strlen(t) + 1);
+ strcpy(last_warning_str,p);
+ strcpy(last_warning_tag,t);
+ run_callback(report_id, "->");
+ } else {
+ print_ln();
+ tprint("warning ");
+ if (cur_file_name) {
+ tprint(" (file ");
+ tprint(cur_file_name);
+ tprint(")");
+ }
+ if (t != NULL) {
+ tprint(" (");
+ tprint(t);
+ tprint(")");
+ }
+ tprint(": ");
+ if (p != NULL)
+ tprint(p);
+ print_ln();
+ }
+ if (history == spotless)
+ history = warning_issued;
+ }
+}
+
+static char print_buf[PRINTF_BUF_SIZE];
+
+__attribute__ ((format(printf, 2,3)))
+void formatted_error(const char *t, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
+ normal_error(t,print_buf);
+ va_end(args);
+}
+
+__attribute__ ((format(printf, 2,3)))
+void formatted_warning(const char *t, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
+ normal_warning(t,print_buf);
+ va_end(args);
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/errors.w b/Build/source/texk/web2c/luatexdir/tex/errors.w
deleted file mode 100644
index 93dbe141b91..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/errors.w
+++ /dev/null
@@ -1,972 +0,0 @@
-% errors.w
-%
-% Copyright 2009-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/>.
-
-@ TODO: we need to use a formatted normal_error in:
-
-hyphen.w
-luafflib.c
-
-@ @c
-#include "ptexlib.h"
-#define edit_var "TEXEDIT"
-
-@ When something anomalous is detected, \TeX\ typically does something like this:
-$$\vbox{\halign{#\hfil\cr
-|print_err("Something anomalous has been detected");|\cr
-|help3("This is the first line of my offer to help.")|\cr
-|("This is the second line. I'm trying to")|\cr
-|("explain the best way for you to proceed.");|\cr
-|error;|\cr}}$$
-A two-line help message would be given using |help2|, etc.; these informal
-helps should use simple vocabulary that complements the words used in the
-official error message that was printed. (Outside the U.S.A., the help
-messages should preferably be translated into the local vernacular. Each
-line of help is at most 60 characters long, in the present implementation,
-so that |max_print_line| will not be exceeded.)
-
-The |print_err| procedure supplies a `\.!' before the official message,
-and makes sure that the terminal is awake if a stop is going to occur.
-The |error| procedure supplies a `\..' after the official message, then it
-shows the location of the error; and if |interaction=error_stop_mode|,
-it also enters into a dialog with the user, during which time the help
-message may be printed.
-@^system dependencies@>
-
-@c
-int interaction; /* current level of interaction */
-int interactionoption; /* set from command line */
-
-/* ls-hh: so, new code only kicks in when we have a callback defined */
-
-char *last_error = NULL;
-char *last_lua_error = NULL;
-char *last_warning_tag = NULL;
-char *last_warning_str = NULL;
-char *last_error_context = NULL;
-
-int err_old_setting = 0 ;
-int in_error = 0 ;
-
-void set_last_error_context(void)
-{
- str_number str;
- int sel = selector;
- int saved_new_line_char;
- int saved_new_string_line;
- selector = new_string;
- saved_new_line_char = new_line_char_par;
- saved_new_string_line = new_string_line;
- new_line_char_par = 10;
- new_string_line = 10;
- show_context();
- xfree(last_error_context);
- str = make_string();
- last_error_context = makecstring(str);
- flush_str(str);
- selector = sel;
- new_line_char_par = saved_new_line_char;
- new_string_line = saved_new_string_line;
- return;
-}
-
-void flush_err(void)
-{
- str_number s_error;
- char *s = NULL;
- int callback_id ;
- if (in_error) {
- selector = err_old_setting;
- str_room(1);
- s_error = make_string();
- s = makecstring(s_error);
- flush_str(s_error);
- if (interaction == error_stop_mode) {
- wake_up_terminal();
- }
- xfree(last_error);
- last_error = (string) xmalloc((unsigned) (strlen(s) + 1));
- strcpy(last_error,s);
- callback_id = callback_defined(show_error_message_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "->");
- } else {
- tprint(s);
- }
- in_error = 0 ;
- }
-}
-
-void print_err(const char *s)
-{
- int callback_id = callback_defined(show_error_message_callback);
- if (interaction == error_stop_mode) {
- wake_up_terminal();
- }
- if (callback_id > 0) {
- err_old_setting = selector;
- selector = new_string;
- in_error = 1 ;
- }
- if (filelineerrorstylep) {
- print_file_line();
- } else {
- tprint_nl("! ");
- }
- tprint(s);
- if (callback_id <= 0) {
- xfree(last_error);
- last_error = (string) xmalloc((unsigned) (strlen(s) + 1));
- strcpy(last_error,s);
- }
-}
-
-@ \TeX\ is careful not to call |error| when the print |selector| setting
-might be unusual. The only possible values of |selector| at the time of
-error messages are
-
-\yskip
-\hang|no_print| (when |interaction=batch_mode| and |log_file| not yet open);
-
-\hang|term_only| (when |interaction>batch_mode| and |log_file| not yet open);
-
-\hang|log_only| (when |interaction=batch_mode| and |log_file| is open);
-
-\hang|term_and_log| (when |interaction>batch_mode| and |log_file| is open).
-
-@c
-void fixup_selector(boolean logopened)
-{
- if (interaction == batch_mode)
- selector = no_print;
- else
- selector = term_only;
- if (logopened)
- selector = selector + 2;
-}
-
-@ A global variable |deletions_allowed| is set |false| if the |get_next|
-routine is active when |error| is called; this ensures that |get_next|
-and related routines like |get_token| will never be called recursively.
-A similar interlock is provided by |set_box_allowed|.
-@^recursion@>
-
-The global variable |history| records the worst level of error that
-has been detected. It has four possible values: |spotless|, |warning_issued|,
-|error_message_issued|, and |fatal_error_stop|.
-
-Another global variable, |error_count|, is increased by one when an
-|error| occurs without an interactive dialog, and it is reset to zero at
-the end of every paragraph. If |error_count| reaches 100, \TeX\ decides
-that there is no point in continuing further.
-
-@c
-boolean deletions_allowed; /* is it safe for |error| to call |get_token|? */
-boolean set_box_allowed; /* is it safe to do a \.{\\setbox} assignment? */
-int history; /* has the source input been clean so far? */
-int error_count; /* the number of scrolled errors since the last paragraph ended */
-int interrupt; /* should \TeX\ pause for instructions? */
-boolean OK_to_interrupt; /* should interrupts be observed? */
-
-@ The value of |history| is initially |fatal_error_stop|, but it will
-be changed to |spotless| if \TeX\ survives the initialization process.
-
-@c
-void initialize_errors(void)
-{
- if (interactionoption == unspecified_mode)
- interaction = error_stop_mode;
- else
- interaction = interactionoption;
- deletions_allowed = true;
- set_box_allowed = true;
- OK_to_interrupt = true;
- /* |history| is initialized elsewhere */
-}
-
-@ It is possible for |error| to be called recursively if some error arises
-when |get_token| is being used to delete a token, and/or if some fatal error
-occurs while \TeX\ is trying to fix a non-fatal one. But such recursion
-@^recursion@>
-is never more than two levels deep.
-
-@ Individual lines of help are recorded in the array |help_line|.
-
-@c
-const char *help_line[7]; /* helps for the next |error| */
-boolean use_err_help; /* should the |err_help| list be shown? */
-
-@ The |jump_out| procedure just cuts across all active procedure levels and
-exits the program. It is used when there is no recovery from a particular error.
-
-@c
-int defaultexitcode = 0; /* the exit code can be overloaded */
-
-__attribute__ ((noreturn))
-void do_final_end(void)
-{
- update_terminal();
- ready_already = 0;
- lua_close(Luas); /* new per 0.99 */
- if ((history != spotless) && (history != warning_issued))
- uexit(1);
- else
- uexit(defaultexitcode);
-}
-
-__attribute__ ((noreturn))
-void jump_out(void)
-{
- close_files_and_terminate();
- do_final_end();
-}
-@ Here is the function that calls the editor, if one is defined. This
-is loosely based on a similar function in kpathsea, but the calling
-convention is quite different.
-
-@c
-static const_string edit_value = EDITOR;
-
-#if defined(WIN32)
-static int
-Isspace (char c)
-{
- return (c == ' ' || c == '\t');
-}
-#endif /* WIN32 */
-
-__attribute__ ((noreturn))
-static void luatex_calledit (int baseptr, int linenumber)
-{
- char *temp, *command, *fullcmd;
- char c;
- int sdone, ddone, i;
- char *filename = makecstring(input_stack[base_ptr].name_field);
- int fnlength = strlen(filename);
-
-#ifdef WIN32
- char *fp, *ffp, *env, editorname[256], buffer[256];
- int cnt = 0;
- int dontchange = 0;
-#endif
-
- sdone = ddone = 0;
-
- /* Close any open input files, since we're going to kill the job. */
- close_files_and_terminate();
-
- /* Replace the default with the value of the appropriate environment
- variable or config file value, if it's set. */
- temp = kpse_var_value (edit_var);
- if (temp != NULL)
- edit_value = temp;
-
- /* Construct the command string. The `11' is the maximum length an
- integer might be. */
- command = xmalloc (strlen (edit_value) + fnlength + 11);
-
- /* So we can construct it as we go. */
- temp = command;
-
-#ifdef WIN32
- fp = editorname;
- if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
- && IS_DIR_SEP (*(edit_value + 2)))
- || (*edit_value == '"' && isalpha(*(edit_value + 1))
- && *(edit_value + 2) == ':'
- && IS_DIR_SEP (*(edit_value + 3)))
- )
- dontchange = 1;
-#endif
-
- while ((c = *edit_value++) != 0)
- {
- if (c == '%')
- {
- switch (c = *edit_value++)
- {
- case 'd':
- if (ddone)
- FATAL1 ("call_edit: `%%d' appears twice in editor command: `%s'", edit_value);
- sprintf (temp, "%ld", (long int)linenumber);
- while (*temp != '\0')
- temp++;
- ddone = 1;
- break;
-
- case 's':
- if (sdone)
- FATAL1 ("call_edit: `%%s' appears twice in editor command: `%s'", edit_value);
- for (i =0; i < fnlength; i++)
- *temp++ = filename[i];
- sdone = 1;
- break;
-
- case '\0':
- *temp++ = '%';
- /* Back up to the null to force termination. */
- edit_value--;
- break;
-
- default:
- *temp++ = '%';
- *temp++ = c;
- break;
- }
- }
- else {
-#ifdef WIN32
- if (dontchange)
- *temp++ = c;
- else { if(Isspace(c) && cnt == 0) {
- cnt++;
- temp = command;
- *temp++ = c;
- *fp = '\0';
- } else if(!Isspace(c) && cnt == 0) {
- *fp++ = c;
- } else {
- *temp++ = c;
- }
- }
-#else
- *temp++ = c;
-#endif
- }
- }
-
- *temp = 0;
-
-#ifdef WIN32
- if (dontchange == 0) {
- if(editorname[0] == '.' ||
- editorname[0] == '/' ||
- editorname[0] == '\\') {
- fprintf(stderr, "%s is not allowed to execute.\n", editorname);
- do_final_end();
- }
- env = (char *)getenv("PATH");
- if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
- if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
- fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
- do_final_end();
- }
- }
- fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
- strcpy(fullcmd, "\"");
- strcat(fullcmd, buffer);
- strcat(fullcmd, "\"");
- strcat(fullcmd, command);
- } else
-#endif
- fullcmd = command;
-
- /* Execute the command. */
- if (system (fullcmd) != 0)
- fprintf (stderr, "! Trouble executing `%s'.\n", command);
-
- /* Quit, since we found an error. */
- do_final_end ();
-}
-
-
-@ @c
-void error(void)
-{ /* completes the job of error reporting */
- ASCII_code c; /* what the user types */
- int callback_id;
- int s1, s2, s3, s4; /* used to save global variables when deleting tokens */
- int i;
- flush_err(); /* hh-ls */
- if (history < error_message_issued)
- history = error_message_issued;
- callback_id = callback_defined(show_error_hook_callback);
- if (callback_id > 0) {
- set_last_error_context();
- run_callback(callback_id, "->");
- } else {
- print_char('.');
- show_context();
- }
- if (haltonerrorp) {
- history = fatal_error_stop;
- jump_out();
- }
- if (interaction == error_stop_mode) {
- /* Get user's advice and |return| */
- while (1) {
- CONTINUE:
- clear_for_error_prompt();
- prompt_input("? ");
- if (last == first)
- return;
- c = buffer[first];
- if (c >= 'a')
- c = c + 'A' - 'a'; /* convert to uppercase */
- /* Interpret code |c| and |return| if done */
-
- /* It is desirable to provide an `\.E' option here that gives the user
- an easy way to return from \TeX\ to the system editor, with the offending
- line ready to be edited. But such an extension requires some system
- wizardry, so the present implementation simply types out the name of the
- file that should be edited and the relevant line number.
-
- There is a secret `\.D' option available when the debugging routines haven't
- been commented~out. */
-
- switch (c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (deletions_allowed) {
- /* Delete |c-"0"| tokens and |goto continue| */
- /* We allow deletion of up to 99 tokens at a time */
- s1 = cur_tok;
- s2 = cur_cmd;
- s3 = cur_chr;
- s4 = align_state;
- align_state = 1000000;
- OK_to_interrupt = false;
- if ((last > first + 1) && (buffer[first + 1] >= '0')
- && (buffer[first + 1] <= '9'))
- c = c * 10 + buffer[first + 1] - '0' * 11;
- else
- c = c - '0';
- while (c > 0) {
- get_token(); /* one-level recursive call of |error| is possible */
- decr(c);
- }
- cur_tok = s1;
- cur_cmd = s2;
- cur_chr = s3;
- align_state = s4;
- OK_to_interrupt = true;
- help2("I have just deleted some text, as you asked.",
- "You can now delete more, or insert, or whatever.");
- show_context();
- goto CONTINUE;
- }
- break;
-#ifdef DEBUG
- case 'D':
- debug_help();
- goto CONTINUE;
- break;
-#endif
- case 'E':
- if (base_ptr > 0) {
- int callback_id = callback_defined(call_edit_callback);
- if (callback_id>0) {
- (void)run_callback(callback_id, "Sd->", makecstring(input_stack[base_ptr].name_field), line);
- jump_out(); /* should not be reached */
- } else {
- tprint_nl("You want to edit file ");
- print(input_stack[base_ptr].name_field);
- tprint(" at line ");
- print_int(line);
- interaction = scroll_mode;
- if (kpse_init) {
- luatex_calledit(base_ptr, line);
- } else {
- tprint_nl("There is no valid callback defined.");
- jump_out(); /* should not be reached */
- }
- }
- }
- break;
- case 'H':
- /* Print the help information and |goto continue| */
- if (use_err_help) {
- give_err_help();
- } else {
- if (help_line[0] == NULL) {
- help2
- ("Sorry, I don't know how to help in this situation.",
- "Maybe you should try asking a human?");
- }
- i = 0;
- while (help_line[i] != NULL)
- tprint_nl(help_line[i++]);
- help4("Sorry, I already gave what help I could...",
- "Maybe you should try asking a human?",
- "An error might have occurred before I noticed any problems.",
- "``If all else fails, read the instructions.''");
- goto CONTINUE;
- }
- break;
- case 'I':
- /* Introduce new material from the terminal and |return| */
- /* When the following code is executed, |buffer[(first+1)..(last-1)]| may
- contain the material inserted by the user; otherwise another prompt will
- be given. In order to understand this part of the program fully, you need
- to be familiar with \TeX's input stacks. */
-
- begin_file_reading(); /* enter a new syntactic level for terminal input */
- /* now |state=mid_line|, so an initial blank space will count as a blank */
- if (last > first + 1) {
- iloc = first + 1;
- buffer[first] = ' ';
- } else {
- prompt_input("insert>");
- iloc = first;
- }
- first = last;
- ilimit = last - 1; /* no |end_line_char| ends this line */
- return;
- break;
- case 'Q':
- case 'R':
- case 'S':
- /* Change the interaction level and |return| */
- /* Here the author of \TeX\ apologizes for making use of the numerical
- relation between |"Q"|, |"R"|, |"S"|, and the desired interaction settings
- |batch_mode|, |nonstop_mode|, |scroll_mode|. */
- error_count = 0;
- interaction = batch_mode + c - 'Q';
- tprint("OK, entering ");
- switch (c) {
- case 'Q':
- tprint_esc("batchmode");
- decr(selector);
- break;
- case 'R':
- tprint_esc("nonstopmode");
- break;
- case 'S':
- tprint_esc("scrollmode");
- break;
- }
- tprint("...");
- print_ln();
- update_terminal();
- return;
- break;
- case 'X':
- interaction = scroll_mode;
- jump_out();
- break;
- default:
- break;
- }
- if (!use_err_help) {
- /* Print the menu of available options */
- tprint("Type <return> to proceed, S to scroll future error messages,");
- tprint_nl("R to run without stopping, Q to run quietly,");
- tprint_nl("I to insert something, ");
- if (base_ptr > 0)
- tprint("E to edit your file,");
- if (deletions_allowed)
- tprint_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,");
- tprint_nl("H for help, X to quit.");
- }
- use_err_help = false;
- }
-
- }
- incr(error_count);
- if (error_count == 100) {
- tprint_nl("(That makes 100 errors; please try again.)");
- history = fatal_error_stop;
- jump_out();
- }
- /* Put help message on the transcript file */
- if (interaction > batch_mode)
- decr(selector); /* avoid terminal output */
- if (use_err_help) {
- print_ln();
- give_err_help();
- } else {
- int i1 = 0;
- while (help_line[i1] != NULL)
- tprint_nl(help_line[i1++]);
- }
- print_ln();
- if (interaction > batch_mode)
- incr(selector); /* re-enable terminal output */
- print_ln();
-}
-
-@ A dozen or so error messages end with a parenthesized integer, so we
-save a teeny bit of program space by declaring the following procedure:
-
-@c
-void int_error(int n)
-{
- tprint(" (");
- print_int(n);
- print_char(')');
- error();
-}
-
-@ In anomalous cases, the print selector might be in an unknown state;
-the following subroutine is called to fix things just enough to keep
-running a bit longer.
-
-@c
-void normalize_selector(void)
-{
- if (log_opened_global)
- selector = term_and_log;
- else
- selector = term_only;
- if (job_name == 0)
- open_log_file();
- if (interaction == batch_mode)
- decr(selector);
-}
-
-@ The following procedure prints \TeX's last words before dying
-@c
-void succumb(void)
-{
- if (interaction == error_stop_mode)
- interaction = scroll_mode; /* no more interaction */
- if (log_opened_global)
- error();
-#ifdef DEBUG
- if (interaction > batch_mode)
- debug_help();
-#endif
- history = fatal_error_stop;
- jump_out(); /* irrecoverable error */
-}
-
-@ @c
-void fatal_error(const char *s)
-{ /* prints |s|, and that's it */
- normalize_selector();
- print_err("Emergency stop");
- help1(s);
- succumb();
-}
-
-@ Here is the most dreaded error message
-@c
-void overflow(const char *s, unsigned int n)
-{ /* stop due to finiteness */
- normalize_selector();
- print_err("TeX capacity exceeded, sorry [");
- tprint(s);
- print_char('=');
- print_int((int) n);
- print_char(']');
- if (varmem == NULL) {
- print_err("Sorry, I ran out of memory.");
- print_ln();
- exit(EXIT_FAILURE);
- }
- help2("If you really absolutely need more capacity,",
- "you can ask a wizard to enlarge me.");
- succumb();
-}
-
-@ The program might sometime run completely amok, at which point there is
-no choice but to stop. If no previous error has been detected, that's bad
-news; a message is printed that is really intended for the \TeX\
-maintenance person instead of the user (unless the user has been
-particularly diabolical). The index entries for `this can't happen' may
-help to pinpoint the problem.
-@^dry rot@>
-
-@c
-void confusion(const char *s)
-{ /* consistency check violated; |s| tells where */
- normalize_selector();
- if (history < error_message_issued) {
- print_err("This can't happen (");
- tprint(s);
- print_char(')');
- help1("I'm broken. Please show this to someone who can fix can fix");
- } else {
- print_err("I can't go on meeting you like this");
- help2("One of your faux pas seems to have wounded me deeply...",
- "in fact, I'm barely conscious. Please fix it and try again.");
- }
- succumb();
-}
-
-@ Users occasionally want to interrupt \TeX\ while it's running.
-If the runtime system allows this, one can implement
-a routine that sets the global variable |interrupt| to some nonzero value
-when such an interrupt is signalled. Otherwise there is probably at least
-a way to make |interrupt| nonzero using the debugger.
-@^system dependencies@>
-@^debugging@>
-
-@c
-void check_interrupt(void)
-{
- if (interrupt != 0)
- pause_for_instructions();
-}
-
-@ When an interrupt has been detected, the program goes into its
-highest interaction level and lets the user have nearly the full flexibility of
-the |error| routine. \TeX\ checks for interrupts only at times when it is
-safe to do this.
-
-@c
-void pause_for_instructions(void)
-{
- if (OK_to_interrupt) {
- interaction = error_stop_mode;
- if ((selector == log_only) || (selector == no_print))
- incr(selector);
- print_err("Interruption");
- help3("You rang?",
- "Try to insert some instructions for me (e.g.,`I\\showlists'),",
- "unless you just want to quit by typing `X'.");
- deletions_allowed = false;
- error();
- deletions_allowed = true;
- interrupt = 0;
- }
-}
-
-@ @c
-void tex_error(const char *msg, const char **hlp)
-{
- print_err(msg);
- if (hlp != NULL) {
- int i;
- for (i = 0; (hlp[i] != NULL && i <= 5); i++) {
- help_line[i] = hlp[i];
- }
- help_line[i] = NULL;
- } else {
- help_line[0] = NULL;
- }
- error();
-}
-
-@ The |back_error| routine is used when we want to replace an offending token
-just before issuing an error message. This routine, like |back_input|,
-requires that |cur_tok| has been set. We disable interrupts during the
-call of |back_input| so that the help message won't be lost.
-
-@c
-void back_error(void)
-{ /* back up one token and call |error| */
- OK_to_interrupt = false;
- back_input();
- OK_to_interrupt = true;
- error();
-}
-
-@ @c
-void ins_error(void)
-{ /* back up one inserted token and call |error| */
- OK_to_interrupt = false;
- back_input();
- token_type = inserted;
- OK_to_interrupt = true;
- error();
-}
-
-@ When \TeX\ wants to typeset a character that doesn't exist, the
-character node is not created; thus the output routine can assume
-that characters exist when it sees them. The following procedure
-prints a warning message unless the user has suppressed it.
-
-@c
-void char_warning(internal_font_number f, int c)
-{
- int old_setting; /* saved value of |tracing_online| */
- int k; /* index to current digit; we assume that $0\L n<16^{22}$ */
- if (tracing_lost_chars_par > 0) {
- old_setting = tracing_online_par;
- if (tracing_lost_chars_par > 1)
- tracing_online_par = 1;
- begin_diagnostic();
- tprint_nl("Missing character: There is no ");
- print(c);
- tprint(" (U+");
- k = 0;
- if (c < 16)
- print_char('0');
- if (c < 256)
- print_char('0');
- if (c < 4096)
- print_char('0');
- do {
- dig[k] = c % 16;
- c = c / 16;
- incr(k);
- } while (c != 0);
- print_the_digs((eight_bits) k);
- tprint(") in font ");
- print_font_name(f);
- print_char('!');
- end_diagnostic(false);
- tracing_online_par = old_setting;
- }
-}
-
-@ @c
-
-void wrapup_backend(void) {
- ensure_output_state(static_pdf, ST_OMODE_FIX);
- switch (output_mode_used) {
- case OMODE_NONE:
- print_err(" ==> Fatal error occurred, no FMT file produced!");
- break;
- case OMODE_PDF:
- if (history == fatal_error_stop) {
- remove_pdffile(static_pdf); /* will become remove_output_file */
- print_err(" ==> Fatal error occurred, no output PDF file produced!");
- } else {
- finish_pdf_file(static_pdf, luatex_version, get_luatexrevision());
- }
- break;
- case OMODE_DVI:
- if (history == fatal_error_stop) {
- print_err(" ==> Fatal error occurred, bad output DVI file produced!");
- finish_dvi_file(static_pdf, luatex_version, get_luatexrevision());
- } else {
- finish_dvi_file(static_pdf, luatex_version, get_luatexrevision());
- }
- break;
- }
-}
-
-void normal_error(const char *t, const char *p)
-{
- normalize_selector();
- if (interaction == error_stop_mode) {
- wake_up_terminal();
- }
- if (filelineerrorstylep) {
- print_file_line();
- } else {
- tprint_nl("! ");
- }
- tprint("error: ");
- if (cur_file_name) {
- tprint(" (file ");
- tprint(cur_file_name);
- tprint(")");
- }
- if (t != NULL) {
- tprint(" (");
- tprint(t);
- tprint(")");
- }
- tprint(": ");
- if (p != NULL)
- tprint(p);
- history = fatal_error_stop;
- wrapup_backend();
- exit(EXIT_FAILURE);
-}
-
-/*
-void normal_error(const char *t, const char *p)
-{
- normalize_selector();
- if (interaction == error_stop_mode) {
- wake_up_terminal();
- }
- tprint("error : ");
- if (p != NULL)
- tprint(p);
- history = fatal_error_stop;
- wrapup_backend();
- exit(EXIT_FAILURE);
-}
-*/
-
-@ @c
-void normal_warning(const char *t, const char *p)
-{
- int report_id ;
- if (strcmp(t,"lua") == 0) {
- int saved_new_line_char;
- saved_new_line_char = new_line_char_par;
- new_line_char_par = 10;
- report_id = callback_defined(show_lua_error_hook_callback);
- if (report_id == 0) {
- tprint(p);
- help2("The lua interpreter ran into a problem, so the",
- "remainder of this lua chunk will be ignored.");
- } else {
- (void) run_callback(report_id, "->");
- }
- error();
- new_line_char_par = saved_new_line_char;
- } else {
- report_id = callback_defined(show_warning_message_callback);
- if (report_id > 0) {
- /* free last ones */
- xfree(last_warning_str);
- xfree(last_warning_tag);
- last_warning_str = (string) xmalloc(strlen(p) + 1);
- last_warning_tag = (string) xmalloc(strlen(t) + 1);
- strcpy(last_warning_str,p);
- strcpy(last_warning_tag,t);
- run_callback(report_id, "->");
- } else {
- print_ln();
- tprint("warning ");
- if (cur_file_name) {
- tprint(" (file ");
- tprint(cur_file_name);
- tprint(")");
- }
- if (t != NULL) {
- tprint(" (");
- tprint(t);
- tprint(")");
- }
- tprint(": ");
- if (p != NULL)
- tprint(p);
- print_ln();
- }
- if (history == spotless)
- history = warning_issued;
- }
-}
-
-@ @c
-static char print_buf[PRINTF_BUF_SIZE];
-__attribute__ ((format(printf, 2,3)))
-void formatted_error(const char *t, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
- normal_error(t,print_buf);
- va_end(args);
-}
-
-__attribute__ ((format(printf, 2,3)))
-void formatted_warning(const char *t, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
- normal_warning(t,print_buf);
- va_end(args);
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/expand.c b/Build/source/texk/web2c/luatexdir/tex/expand.c
new file mode 100644
index 00000000000..a0a317db238
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/expand.c
@@ -0,0 +1,967 @@
+/*
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+ Only a dozen or so command codes |>max_command| can possibly be returned by
+ |get_next|; in increasing order, they are |undefined_cs|, |expand_after|,
+ |no_expand|, |input|, |if_test|, |fi_or_else|, |cs_name|, |convert|, |the|,
+ |top_bot_mark|, |call|, |long_call|, |outer_call|, |long_outer_call|, and
+ |end_template|.
+
+ Sometimes, recursive calls to the following |expand| routine may cause
+ exhaustion of the run-time calling stack, resulting in forced execution stops
+ by the operating system. To diminish the chance of this happening, a counter
+ is used to keep track of the recursion depth, in conjunction with a constant
+ called |expand_depth|.
+
+ Note that this does not catch all possible infinite recursion loops, just the
+ ones that exhaust the application calling stack. The actual maximum value of
+ |expand_depth| is outside of our control, but the initial setting of |100|
+ should be enough to prevent problems.
+
+*/
+
+static int expand_depth_count = 0;
+
+/*tex
+
+ The |expand| subroutine is used when |cur_cmd>max_command|. It removes a
+ ``call'' or a conditional or one of the other special operations just listed.
+ It follows that |expand| might invoke itself recursively. In all cases,
+ |expand| destroys the current token, but it sets things up so that the next
+ |get_next| will deliver the appropriate next token. The value of |cur_tok|
+ need not be known when |expand| is called.
+
+ Since several of the basic scanning routines communicate via global
+ variables, their values are saved as local variables of |expand| so that
+ recursive calls don't invalidate them.
+
+*/
+
+int is_in_csname = 0;
+
+void expand(void)
+{
+ /*tex token that is being ``expanded after'' */
+ halfword t;
+ /*tex for list manipulation */
+ halfword p;
+ /*tex for a local token list pointer */
+ halfword cur_ptr;
+ /*tex to save the global quantity |cur_val| */
+ int cv_backup;
+ /*tex to save |cur_val_level|, etc. */
+ int cvl_backup, radix_backup, co_backup;
+ /*tex to save |link(backup_head)| */
+ halfword backup_backup;
+ /*tex temporary storage of |scanner_status| */
+ int save_scanner_status;
+ incr(expand_depth_count);
+ if (expand_depth_count >= expand_depth)
+ overflow("expansion depth", (unsigned) expand_depth);
+ cv_backup = cur_val;
+ cvl_backup = cur_val_level;
+ radix_backup = radix;
+ co_backup = cur_order;
+ backup_backup = token_link(backup_head);
+ RESWITCH:
+ if (cur_cmd < call_cmd) {
+ /*tex Expand a nonmacro. */
+ if (tracing_commands_par > 1)
+ show_cur_cmd_chr();
+ switch (cur_cmd) {
+ case top_bot_mark_cmd:
+ /*tex Insert the appropriate mark text into the scanner. */
+ t = cur_chr % marks_code;
+ if (cur_chr >= marks_code)
+ scan_mark_num();
+ else
+ cur_val = 0;
+ switch (t) {
+ case first_mark_code:
+ cur_ptr = first_mark(cur_val);
+ break;
+ case bot_mark_code:
+ cur_ptr = bot_mark(cur_val);
+ break;
+ case split_first_mark_code:
+ cur_ptr = split_first_mark(cur_val);
+ break;
+ case split_bot_mark_code:
+ cur_ptr = split_bot_mark(cur_val);
+ break;
+ default:
+ cur_ptr = top_mark(cur_val);
+ break;
+ }
+ if (cur_ptr != null)
+ begin_token_list(cur_ptr, mark_text);
+ break;
+ case expand_after_cmd:
+ if (cur_chr == 0) {
+ /*tex
+
+ Expand the token after the next token. It takes only a
+ little shuffling to do what \TeX\ calls
+ \.{\\expandafter}.
+
+ */
+ get_token();
+ t = cur_tok;
+ get_token();
+ if (cur_cmd > max_command_cmd)
+ expand();
+ else
+ back_input();
+ cur_tok = t;
+ back_input();
+ } else {
+ /*tex
+
+ Negate a boolean conditional and |goto reswitch|. The
+ result of a boolean condition is reversed when the
+ conditional is preceded by \.{\\unless}.
+
+ */
+ get_token();
+ if ((cur_cmd == if_test_cmd) && (cur_chr != if_case_code)) {
+ cur_chr = cur_chr + unless_code;
+ goto RESWITCH;
+ }
+ print_err("You can't use `\\unless' before `");
+ print_cmd_chr((quarterword) cur_cmd, cur_chr);
+ print_char('\'');
+ help1("Continue, and I'll forget that it ever happened.");
+ back_error();
+ }
+ break;
+ case no_expand_cmd:
+ if (cur_chr == 0) {
+ /*tex
+
+ Suppress expansion of the next token. The implementation
+ of \.{\\noexpand} is a bit trickier, because it is
+ necessary to insert a special `|dont_expand|' marker into
+ \TeX's reading mechanism. This special marker is
+ processed by |get_next|, but it does not slow down the
+ inner loop.
+
+ Since \.{\\outer} macros might arise here, we must also
+ clear the |scanner_status| temporarily.
+
+ */
+ save_scanner_status = scanner_status;
+ scanner_status = normal;
+ get_token();
+ scanner_status = save_scanner_status;
+ t = cur_tok;
+ back_input();
+ /*tex Now |start| and |loc| point to the backed-up token |t|. */
+ if (t >= cs_token_flag) {
+ p = get_avail();
+ set_token_info(p, cs_token_flag + frozen_dont_expand);
+ set_token_link(p, iloc);
+ istart = p;
+ iloc = p;
+ }
+
+ } else {
+ /*tex
+
+ The \.{\\primitive} handling. If the primitive meaning of
+ the next token is an expandable command, it suffices to
+ replace the current token with the primitive one and
+ restart |expand|.
+
+ Otherwise, the token we just read has to be pushed back,
+ as well as a token matching the internal form of
+ \.{\\primitive}, that is sneaked in as an alternate form
+ of |ignore_spaces|.
+
+ An implementation problem surfaces: There really is no
+ |cur_cs| attached to the inserted primitive command, so
+ it is safer to set |cur_cs| to zero. |cur_tok| has a
+ similar problem. And for the non-expanded branch, simply
+ pushing back a token that matches the correct internal
+ command does not work, because that approach would not
+ survive roundtripping to a temporary file or even a token
+ list.
+
+ It would be smart to create |frozen_| versions of all the
+ primitives. Then, this problem would not happen, at the
+ expense of a few hundred extra control sequences.
+
+ */
+ save_scanner_status = scanner_status;
+ scanner_status = normal;
+ get_token();
+ scanner_status = save_scanner_status;
+ cur_cs = prim_lookup(cs_text(cur_cs));
+ if (cur_cs != undefined_primitive) {
+ t = get_prim_eq_type(cur_cs);
+ if (t > max_command_cmd) {
+ cur_cmd = t;
+ cur_chr = get_prim_equiv(cur_cs);
+ cur_tok = token_val(cur_cmd, cur_chr);
+ cur_cs = 0;
+ goto RESWITCH;
+ } else {
+ back_input();
+ /*tex Now |loc| and |start| point to a one-item list. */
+ p = get_avail();
+ set_token_info(p, cs_token_flag + frozen_primitive);
+ set_token_link(p, iloc);
+ iloc = p;
+ istart = p;
+ }
+ } else if (suppress_primitive_error_par == 0) {
+ print_err("Missing primitive name");
+ help2(
+ "The control sequence marked <to be read again> does not",
+ "represent any known primitive."
+ );
+ back_error();
+ }
+ }
+ break;
+ case cs_name_cmd:
+ /*tex Manufacture a control sequence name. */
+ if (cur_chr == 0) {
+ manufacture_csname(0);
+ } else if (cur_chr == 1) {
+ inject_last_tested_cs();
+ } else {
+ manufacture_csname(1);
+ }
+ break;
+ case convert_cmd:
+ conv_toks();
+ break;
+ case the_cmd:
+ ins_the_toks();
+ break;
+ case combine_toks_cmd:
+ combine_the_toks(cur_chr);
+ break;
+ case if_test_cmd:
+ /*tex An experiment. */
+ if (cur_chr == if_condition_code) {
+ break;
+ }
+ /*tex End of experiment. */
+ conditional();
+ break;
+ case fi_or_else_cmd:
+ /*tex
+
+ Terminate the current conditional and skip to \.{\\fi} The
+ processing of conditionals is complete except for the
+ following code, which is actually part of |expand|. It comes
+ into play when \.{\\or}, \.{\\else}, or \.{\\fi} is scanned.
+
+ */
+ if (tracing_ifs_par > 0)
+ if (tracing_commands_par <= 1)
+ show_cur_cmd_chr();
+ if (cur_chr > if_limit) {
+ if (if_limit == if_code) {
+ /*tex Condition is not yet evaluated. */
+ insert_relax();
+ } else {
+ print_err("Extra ");
+ print_cmd_chr(fi_or_else_cmd, cur_chr);
+ help1("I'm ignoring this; it doesn't match any \\if.");
+ error();
+ }
+ } else {
+ while (cur_chr != fi_code) {
+ /*tex Skip to \.{\\fi}. */
+ pass_text();
+ }
+ pop_condition_stack();
+ }
+ break;
+ case input_cmd:
+ /*tex Initiate or terminate input from a file */
+ if (cur_chr == 1)
+ force_eof = true;
+ else if (cur_chr == 2)
+ pseudo_start();
+ else if (cur_chr == 3) {
+ pseudo_start();
+ iname = 19;
+ } else if (name_in_progress)
+ insert_relax();
+ else
+ start_input();
+ break;
+ case lua_expandable_call_cmd:
+ if (cur_chr <= 0) {
+ normal_error("luacall", "invalid number");
+ } else {
+ str_number u = save_cur_string();
+ luacstrings = 0;
+ luafunctioncall(cur_chr);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
+ break;
+ case lua_local_call_cmd:
+ if (cur_chr <= 0) {
+ normal_error("luacall", "invalid number");
+ } else {
+ str_number u = save_cur_string();
+ luacstrings = 0;
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, cur_chr);
+ lua_call(Luas,0,0);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
+ break;
+ case variable_cmd:
+ do_variable();
+ break;
+ case feedback_cmd:
+ do_feedback();
+ break;
+ default:
+ /*tex Complain about an undefined macro */
+ print_err("Undefined control sequence");
+ help5(
+ "The control sequence at the end of the top line",
+ "of your error message was never \\def'ed. If you have",
+ "misspelled it (e.g., `\\hobx'), type `I' and the correct",
+ "spelling (e.g., `I\\hbox'). Otherwise just continue,",
+ "and I'll forget about whatever was undefined."
+ );
+ error();
+ break;
+ }
+ } else if (cur_cmd < end_template_cmd) {
+ macro_call();
+ } else {
+ /*tex
+
+ Insert a token containing |frozen_endv|. An |end_template| command is
+ effectively changed to an |endv| command by the following code. (The
+ reason for this is discussed below; the |frozen_end_template| at the
+ end of the template has passed the |check_outer_validity| test, so
+ its mission of error detection has been accomplished.)
+
+ */
+ cur_tok = cs_token_flag + frozen_endv;
+ back_input();
+ }
+ cur_val = cv_backup;
+ cur_val_level = cvl_backup;
+ radix = radix_backup;
+ cur_order = co_backup;
+ set_token_link(backup_head, backup_backup);
+ decr(expand_depth_count);
+}
+
+void complain_missing_csname(void)
+{
+ print_err("Missing \\endcsname inserted");
+ help2(
+ "The control sequence marked <to be read again> should",
+ "not appear between \\csname and \\endcsname."
+ );
+ back_error();
+}
+
+void manufacture_csname(boolean use)
+{
+ halfword p, q, r;
+ lstring *ss;
+ r = get_avail();
+ p = r;
+ is_in_csname += 1;
+ do {
+ get_x_token();
+ if (cur_cs == 0)
+ store_new_token(cur_tok);
+ } while (cur_cs == 0);
+ if (cur_cmd != end_cs_name_cmd) {
+ /*tex Complain about missing \.{\\endcsname}. */
+ complain_missing_csname();
+ }
+ /*tex Look up the characters of list |r| in the hash table, and set |cur_cs|. */
+ ss = tokenlist_to_lstring(r, true);
+ is_in_csname -= 1;
+ if (use) {
+ if (ss->l > 0) {
+ cur_cs = string_lookup((char *) ss->s, ss->l);
+ } else {
+ cur_cs = null_cs;
+ }
+ last_cs_name = cur_cs ;
+ free_lstring(ss);
+ flush_list(r);
+ if (cur_cs == null_cs) {
+ /*tex skip */
+ } else if (eq_type(cur_cs) == undefined_cs_cmd) {
+ /*tex skip */
+ } else {
+ cur_tok = cur_cs + cs_token_flag;
+ back_input();
+ }
+ } else {
+ if (ss->l > 0) {
+ no_new_control_sequence = false;
+ cur_cs = string_lookup((char *) ss->s, ss->l);
+ no_new_control_sequence = true;
+ } else {
+ /*tex the list is empty */
+ cur_cs = null_cs;
+ }
+ last_cs_name = cur_cs ;
+ free_lstring(ss);
+ flush_list(r);
+ if (eq_type(cur_cs) == undefined_cs_cmd) {
+ /*tex The |save_stack| might change! */
+ eq_define(cur_cs, relax_cmd, too_big_char);
+ };
+ /*tex The control sequence will now match \.{\\relax} */
+ cur_tok = cur_cs + cs_token_flag;
+ back_input();
+ }
+}
+
+void inject_last_tested_cs(void)
+{
+ if (last_cs_name != null_cs) {
+ cur_cs = last_cs_name;
+ cur_tok = last_cs_name + cs_token_flag;
+ back_input();
+ }
+}
+
+/*tex
+
+ Sometimes the expansion looks too far ahead, so we want to insert a harmless
+ \.{\\relax} into the user's input.
+
+*/
+
+void insert_relax(void)
+{
+ cur_tok = cs_token_flag + cur_cs;
+ back_input();
+ cur_tok = cs_token_flag + frozen_relax;
+ back_input();
+ token_type = inserted;
+}
+
+
+/*tex
+
+ Here is a recursive procedure that is \TeX's usual way to get the next token
+ of input. It has been slightly optimized to take account of common cases.
+
+*/
+
+void get_x_token(void)
+{
+ /*tex This code sets |cur_cmd|, |cur_chr|, |cur_tok|, and expands macros. */
+ RESTART:
+ get_next();
+ if (cur_cmd <= max_command_cmd)
+ goto DONE;
+ if (cur_cmd >= call_cmd) {
+ if (cur_cmd < end_template_cmd) {
+ macro_call();
+ } else {
+ cur_cs = frozen_endv;
+ cur_cmd = endv_cmd;
+ /*tex Now |cur_chr=null_list|. */
+ goto DONE;
+ }
+ } else {
+ expand();
+ }
+ goto RESTART;
+ DONE:
+ if (cur_cs == 0)
+ cur_tok = token_val(cur_cmd, cur_chr);
+ else
+ cur_tok = cs_token_flag + cur_cs;
+}
+
+/*tex
+
+ The |get_x_token| procedure is equivalent to two consecutive procedure calls:
+ |get_next; x_token|. It's |get_x_token| without the initial |get_next|.
+
+*/
+
+void x_token(void)
+{
+ while (cur_cmd > max_command_cmd) {
+ expand();
+ get_next();
+ }
+ if (cur_cs == 0)
+ cur_tok = token_val(cur_cmd, cur_chr);
+ else
+ cur_tok = cs_token_flag + cur_cs;
+}
+
+/*tex
+
+ A control sequence that has been \.{\\def}'ed by the user is expanded by
+ \TeX's |macro_call| procedure.
+
+ Before we get into the details of |macro_call|, however, let's consider the
+ treatment of primitives like \.{\\topmark}, since they are essentially macros
+ without parameters. The token lists for such marks are kept in five global
+ arrays of pointers; we refer to the individual entries of these arrays by
+ symbolic macros |top_mark|, etc. The value of |top_mark(x)|, etc. is either
+ |null| or a pointer to the reference count of a token list.
+
+ The variable |biggest_used_mark| is an aid to try and keep the code somehwat
+ efficient without too much extra work: it registers the highest mark class
+ ever instantiated by the user, so the loops in |fire_up| and |vsplit| do not
+ have to traverse the full range |0..biggest_mark|.
+
+*/
+
+halfword top_marks_array[(biggest_mark + 1)];
+halfword first_marks_array[(biggest_mark + 1)];
+halfword bot_marks_array[(biggest_mark + 1)];
+halfword split_first_marks_array[(biggest_mark + 1)];
+halfword split_bot_marks_array[(biggest_mark + 1)];
+halfword biggest_used_mark;
+
+void initialize_marks(void)
+{
+ int i;
+ biggest_used_mark = 0;
+ for (i = 0; i <= biggest_mark; i++) {
+ top_mark(i) = null;
+ first_mark(i) = null;
+ bot_mark(i) = null;
+ split_first_mark(i) = null;
+ split_bot_mark(i) = null;
+ }
+}
+
+/*tex
+
+ Now let's consider |macro_call| itself, which is invoked when \TeX\ is
+ scanning a control sequence whose |cur_cmd| is either |call|, |long_call|,
+ |outer_call|, or |long_outer_call|. The control sequence definition appears
+ in the token list whose reference count is in location |cur_chr| of |mem|.
+
+ The global variable |long_state| will be set to |call| or to |long_call|,
+ depending on whether or not the control sequence disallows \.{\\par} in its
+ parameters. The |get_next| routine will set |long_state| to |outer_call| and
+ emit \.{\\par}, if a file ends or if an \.{\\outer} control sequence occurs
+ in the midst of an argument.
+
+*/
+
+/*tex Governs the acceptance of \.{\\par}: */
+
+int long_state;
+
+/*tex
+
+ The parameters, if any, must be scanned before the macro is expanded.
+ Parameters are token lists without reference counts. They are placed on an
+ auxiliary stack called |pstack| while they are being scanned, since the
+ |param_stack| may be losing entries during the matching process. (Note that
+ |param_stack| can't be gaining entries, since |macro_call| is the only
+ routine that puts anything onto |param_stack|, and it is not recursive.)
+
+*/
+
+/*tex The arguments supplied to a macro: */
+
+halfword pstack[9];
+
+/*tex
+
+ After parameter scanning is complete, the parameters are moved to the
+ |param_stack|. Then the macro body is fed to the scanner; in other words,
+ |macro_call| places the defined text of the control sequence at the top of\/
+ \TeX's input stack, so that |get_next| will proceed to read it next.
+
+ The global variable |cur_cs| contains the |eqtb| address of the control
+ sequence being expanded, when |macro_call| begins. If this control sequence
+ has not been declared \.{\\long}, i.e., if its command code in the |eq_type|
+ field is not |long_call| or |long_outer_call|, its parameters are not allowed
+ to contain the control sequence \.{\\par}. If an illegal \.{\\par} appears,
+ the macro call is aborted, and the \.{\\par} will be rescanned.
+
+*/
+
+/*tex This invokes a user-defined control sequence. */
+
+void macro_call(void)
+{
+ /*tex current node in the macro's token list */
+ halfword r;
+ /*tex current node in parameter token list being built */
+ halfword p = null;
+ /*tex new node being put into the token list */
+ halfword q;
+ /*tex backup pointer for parameter matching */
+ halfword s;
+ /*tex cycle pointer for backup recovery */
+ halfword t;
+ /*tex auxiliary pointers for backup recovery */
+ halfword u, v;
+ /*tex one step before the last |right_brace| token */
+ halfword rbrace_ptr = null;
+ /*tex the number of parameters scanned */
+ int n = 0;
+ /*tex unmatched left braces in current parameter */
+ halfword unbalance;
+ /*tex the number of tokens or groups (usually) */
+ halfword m = 0;
+ /*tex start of the token list */
+ halfword ref_count;
+ /*tex |scanner_status| upon entry */
+ int save_scanner_status = scanner_status;
+ /*tex |warning_index| upon entry */
+ halfword save_warning_index = warning_index;
+ /*tex character used in parameter */
+ int match_chr = 0;
+ warning_index = cur_cs;
+ ref_count = cur_chr;
+ r = token_link(ref_count);
+ if (tracing_macros_par > 0) {
+ /*tex Show the text of the macro being expanded. */
+ begin_diagnostic();
+ print_ln();
+ print_cs(warning_index);
+ token_show(ref_count);
+ end_diagnostic(false);
+ }
+ if (token_info(r) == protected_token)
+ r = token_link(r);
+ if (token_info(r) != end_match_token) {
+ /*tex
+
+ Scan the parameters and make |link(r)| point to the macro body; but
+ |return| if an illegal \.{\\par} is detected.
+
+ At this point, the reader will find it advisable to review the
+ explanation of token list format that was presented earlier, since
+ many aspects of that format are of importance chiefly in the
+ |macro_call| routine.
+
+ The token list might begin with a string of compulsory tokens before
+ the first |match| or |end_match|. In that case the macro name is
+ supposed to be followed by those tokens; the following program will
+ set |s=null| to represent this restriction. Otherwise |s| will be set
+ to the first token of a string that will delimit the next parameter.
+
+ */
+ scanner_status = matching;
+ unbalance = 0;
+ long_state = eq_type(cur_cs);
+ if (long_state >= outer_call_cmd)
+ long_state = long_state - 2;
+ do {
+ set_token_link(temp_token_head, null);
+ if ((token_info(r) >= end_match_token)
+ || (token_info(r) < match_token)) {
+ s = null;
+ } else {
+ match_chr = token_info(r) - match_token;
+ s = token_link(r);
+ r = s;
+ p = temp_token_head;
+ m = 0;
+ }
+ /*tex
+
+ Scan a parameter until its delimiter string has been found; or,
+ if |s=null|, simply scan the delimiter string.
+
+ If |info(r)| is a |match| or |end_match| command, it cannot be
+ equal to any token found by |get_token|. Therefore an undelimited
+ parameter---i.e., a |match| that is immediately followed by
+ |match| or |end_match|---will always fail the test
+ `|cur_tok=info(r)|' in the following algorithm.
+
+ */
+ CONTINUE:
+ /*tex Set |cur_tok| to the next token of input: */
+ get_token();
+ if (cur_tok == token_info(r)) {
+ /*tex
+
+ Advance |r|; |goto found| if the parameter delimiter has been
+ fully matched, otherwise |goto continue|.
+
+ A slightly subtle point arises here: When the parameter
+ delimiter ends with `\.{\#\{}', the token list will have a
+ left brace both before and after the |end_match|\kern-.4pt.
+ Only one of these should affect the |align_state|, but both
+ will be scanned, so we must make a correction.
+
+ */
+ r = token_link(r);
+ if ((token_info(r) >= match_token)
+ && (token_info(r) <= end_match_token)) {
+ if (cur_tok < left_brace_limit)
+ decr(align_state);
+ goto FOUND;
+ } else {
+ goto CONTINUE;
+ }
+
+ }
+ /*tex
+
+ Contribute the recently matched tokens to the current parameter,
+ and |goto continue| if a partial match is still in effect; but
+ abort if |s=null|.
+
+ When the following code becomes active, we have matched tokens
+ from |s| to the predecessor of |r|, and we have found that
+ |cur_tok<>info(r)|. An interesting situation now presents itself:
+ If the parameter is to be delimited by a string such as `\.{ab}',
+ and if we have scanned `\.{aa}', we want to contribute one `\.a'
+ to the current parameter and resume looking for a `\.b'. The
+ program must account for such partial matches and for others that
+ can be quite complex. But most of the time we have |s=r| and
+ nothing needs to be done.
+
+ Incidentally, it is possible for \.{\\par} tokens to sneak in to
+ certain parameters of non-\.{\\long} macros. For example,
+ consider a case like `\.{\\def\\a\#1\\par!\{...\}}' where the
+ first \.{\\par} is not followed by an exclamation point. In such
+ situations it does not seem appropriate to prohibit the
+ \.{\\par}, so \TeX\ keeps quiet about this bending of the rules.
+
+ */
+ if (s != r) {
+ if (s == null) {
+ /*tex Report an improper use of the macro and abort. */
+ print_err("Use of ");
+ sprint_cs(warning_index);
+ tprint(" doesn't match its definition");
+ help4(
+ "If you say, e.g., `\\def\\a1{...}', then you must always",
+ "put `1' after `\\a', since control sequence names are",
+ "made up of letters only. The macro here has not been",
+ "followed by the required stuff, so I'm ignoring it."
+ );
+ error();
+ goto EXIT;
+
+ } else {
+ t = s;
+ do {
+ store_new_token(token_info(t));
+ incr(m);
+ u = token_link(t);
+ v = s;
+ while (1) {
+ if (u == r) {
+ if (cur_tok != token_info(v)) {
+ goto DONE;
+ } else {
+ r = token_link(v);
+ goto CONTINUE;
+ }
+ }
+ if (token_info(u) != token_info(v))
+ goto DONE;
+ u = token_link(u);
+ v = token_link(v);
+ }
+ DONE:
+ t = token_link(t);
+ } while (t != r);
+ r = s;
+ /*tex At this point, no tokens are recently matched. */
+ }
+ }
+ if (cur_tok == par_token)
+ if (long_state != long_call_cmd)
+ if (!suppress_long_error_par) {
+ goto RUNAWAY;
+ }
+ if (cur_tok < right_brace_limit) {
+ if (cur_tok < left_brace_limit) {
+ /*tex Contribute an entire group to the current parameter. */
+ unbalance = 1;
+ while (1) {
+ fast_store_new_token(cur_tok);
+ get_token();
+ if (cur_tok == par_token) {
+ if (long_state != long_call_cmd) {
+ if (!suppress_long_error_par) {
+ goto RUNAWAY;
+
+ }
+ }
+ }
+ if (cur_tok < right_brace_limit) {
+ if (cur_tok < left_brace_limit) {
+ incr(unbalance);
+ } else {
+ decr(unbalance);
+ if (unbalance == 0)
+ break;
+ }
+ }
+ }
+ rbrace_ptr = p;
+ store_new_token(cur_tok);
+ } else {
+ /*tex Report an extra right brace and |goto continue|. */
+ back_input();
+ print_err("Argument of ");
+ sprint_cs(warning_index);
+ tprint(" has an extra }");
+ help6(
+ "I've run across a `}' that doesn't seem to match anything.",
+ "For example, `\\def\\a#1{...}' and `\\a}' would produce",
+ "this error. If you simply proceed now, the `\\par' that",
+ "I've just inserted will cause me to report a runaway",
+ "argument that might be the root of the problem. But if",
+ "your `}' was spurious, just type `2' and it will go away."
+ );
+ incr(align_state);
+ long_state = call_cmd;
+ cur_tok = par_token;
+ ins_error();
+ goto CONTINUE;
+ /*tex A white lie; the \.{\\par} won't always trigger a runaway. */
+ }
+ } else {
+ /*tex
+
+ Store the current token, but |goto continue| if it is a blank
+ space that would become an undelimited parameter.
+
+ */
+ if (cur_tok == space_token && token_info(r) <= end_match_token && token_info(r) >= match_token)
+ goto CONTINUE;
+ store_new_token(cur_tok);
+ }
+ incr(m);
+ if (token_info(r) > end_match_token)
+ goto CONTINUE;
+ if (token_info(r) < match_token)
+ goto CONTINUE;
+ FOUND:
+ if (s != null) {
+ /*
+
+ Tidy up the parameter just scanned, and tuck it away. If the
+ parameter consists of a single group enclosed in braces, we
+ must strip off the enclosing braces. That's why |rbrace_ptr|
+ was introduced.
+
+ */
+ if ((m == 1) && (token_info(p) < right_brace_limit)
+ && (p != temp_token_head)) {
+ set_token_link(rbrace_ptr, null);
+ free_avail(p);
+ p = token_link(temp_token_head);
+ pstack[n] = token_link(p);
+ free_avail(p);
+ } else {
+ pstack[n] = token_link(temp_token_head);
+ }
+ incr(n);
+ if (tracing_macros_par > 0) {
+ begin_diagnostic();
+ print_nl(match_chr);
+ print_int(n);
+ tprint("<-");
+ show_token_list(pstack[n - 1], null, 1000);
+ end_diagnostic(false);
+ }
+ }
+ /*tex
+
+ Now |info(r)| is a token whose command code is either |match| or
+ |end_match|.
+
+ */
+ } while (token_info(r) != end_match_token);
+ }
+ /*tex
+
+ Feed the macro body and its parameters to the scanner Before we put a new
+ token list on the input stack, it is wise to clean off all token lists
+ that have recently been depleted. Then a user macro that ends with a call
+ to itself will not require unbounded stack space.
+
+ */
+ while ((istate == token_list) && (iloc == null) && (token_type != v_template)) {
+ /*tex Conserve stack space. */
+ end_token_list();
+ }
+ begin_token_list(ref_count, macro);
+ iname = warning_index;
+ iloc = token_link(r);
+ if (n > 0) {
+ if (param_ptr + n > max_param_stack) {
+ max_param_stack = param_ptr + n;
+ if (max_param_stack > param_size)
+ overflow("parameter stack size", (unsigned) param_size);
+ }
+ for (m = 0; m <= n - 1; m++)
+ param_stack[param_ptr + m] = pstack[m];
+ param_ptr = param_ptr + n;
+ }
+ goto EXIT;
+ RUNAWAY:
+ /*tex
+
+ Report a runaway argument and abort. If |long_state=outer_call|, a
+ runaway argument has already been reported.
+
+ */
+ if (long_state == call_cmd) {
+ runaway();
+ print_err("Paragraph ended before ");
+ sprint_cs(warning_index);
+ tprint(" was complete");
+ help3(
+ "I suspect you've forgotten a `}', causing me to apply this",
+ "control sequence to too much text. How can we recover?",
+ "My plan is to forget the whole thing and hope for the best."
+ );
+ back_error();
+ }
+ pstack[n] = token_link(temp_token_head);
+ align_state = align_state - unbalance;
+ for (m = 0; m <= n; m++)
+ flush_list(pstack[m]);
+ EXIT:
+ scanner_status = save_scanner_status;
+ warning_index = save_warning_index;
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/expand.w b/Build/source/texk/web2c/luatexdir/tex/expand.w
deleted file mode 100644
index c912863b2a1..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/expand.w
+++ /dev/null
@@ -1,829 +0,0 @@
-% expand.w
-%
-% Copyright 2009-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"
-
-@ Only a dozen or so command codes |>max_command| can possibly be returned by
-|get_next|; in increasing order, they are |undefined_cs|, |expand_after|,
-|no_expand|, |input|, |if_test|, |fi_or_else|, |cs_name|, |convert|, |the|,
-|top_bot_mark|, |call|, |long_call|, |outer_call|, |long_outer_call|, and
-|end_template|.{\emergencystretch=40pt\par}
-
-Sometimes, recursive calls to the following |expand| routine may
-cause exhaustion of the run-time calling stack, resulting in
-forced execution stops by the operating system. To diminish the chance
-of this happening, a counter is used to keep track of the recursion
-depth, in conjunction with a constant called |expand_depth|.
-
-Note that this does not catch all possible infinite recursion loops,
-just the ones that exhaust the application calling stack. The
-actual maximum value of |expand_depth| is outside of our control, but
-the initial setting of |100| should be enough to prevent problems.
-@^system dependencies@>
-
-@c
-static int expand_depth_count = 0;
-
-
-@ The |expand| subroutine is used when |cur_cmd>max_command|. It removes a
-``call'' or a conditional or one of the other special operations just
-listed. It follows that |expand| might invoke itself recursively. In all
-cases, |expand| destroys the current token, but it sets things up so that
-the next |get_next| will deliver the appropriate next token. The value of
-|cur_tok| need not be known when |expand| is called.
-
-Since several of the basic scanning routines communicate via global variables,
-their values are saved as local variables of |expand| so that
-recursive calls don't invalidate them.
-@^recursion@>
-
-@c
-int is_in_csname = 0;
-
-@ @c
-void expand(void)
-{
- halfword t; /* token that is being ``expanded after'' */
- halfword p; /* for list manipulation */
- halfword cur_ptr; /* for a local token list pointer */
- int cv_backup; /* to save the global quantity |cur_val| */
- int cvl_backup, radix_backup, co_backup; /* to save |cur_val_level|, etc. */
- halfword backup_backup; /* to save |link(backup_head)| */
- int save_scanner_status; /* temporary storage of |scanner_status| */
- incr(expand_depth_count);
- if (expand_depth_count >= expand_depth)
- overflow("expansion depth", (unsigned) expand_depth);
- cv_backup = cur_val;
- cvl_backup = cur_val_level;
- radix_backup = radix;
- co_backup = cur_order;
- backup_backup = token_link(backup_head);
- RESWITCH:
- if (cur_cmd < call_cmd) {
- /* Expand a nonmacro */
- if (tracing_commands_par > 1)
- show_cur_cmd_chr();
- switch (cur_cmd) {
- case top_bot_mark_cmd:
- /* Insert the appropriate mark text into the scanner */
- t = cur_chr % marks_code;
- if (cur_chr >= marks_code)
- scan_mark_num();
- else
- cur_val = 0;
- switch (t) {
- case first_mark_code:
- cur_ptr = first_mark(cur_val);
- break;
- case bot_mark_code:
- cur_ptr = bot_mark(cur_val);
- break;
- case split_first_mark_code:
- cur_ptr = split_first_mark(cur_val);
- break;
- case split_bot_mark_code:
- cur_ptr = split_bot_mark(cur_val);
- break;
- default:
- cur_ptr = top_mark(cur_val);
- break;
- }
- if (cur_ptr != null)
- begin_token_list(cur_ptr, mark_text);
- break;
- case expand_after_cmd:
- if (cur_chr == 0) {
- /* Expand the token after the next token */
- /* It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}. */
- get_token();
- t = cur_tok;
- get_token();
- if (cur_cmd > max_command_cmd)
- expand();
- else
- back_input();
- cur_tok = t;
- back_input();
-
- } else { /* \\unless */
- /* Negate a boolean conditional and |goto reswitch| */
- /* The result of a boolean condition is reversed when the conditional is
- preceded by \.{\\unless}. */
- get_token();
- if ((cur_cmd == if_test_cmd) && (cur_chr != if_case_code)) {
- cur_chr = cur_chr + unless_code;
- goto RESWITCH;
- }
- print_err("You can't use `\\unless' before `");
- print_cmd_chr((quarterword) cur_cmd, cur_chr);
- print_char('\'');
- help1("Continue, and I'll forget that it ever happened.");
- back_error();
- }
- break;
- case no_expand_cmd:
- if (cur_chr == 0) {
- /* Suppress expansion of the next token */
- /* The implementation of \.{\\noexpand} is a bit trickier, because it is
- necessary to insert a special `|dont_expand|' marker into \TeX's reading
- mechanism. This special marker is processed by |get_next|, but it does
- not slow down the inner loop.
-
- Since \.{\\outer} macros might arise here, we must also
- clear the |scanner_status| temporarily.
- */
-
- save_scanner_status = scanner_status;
- scanner_status = normal;
- get_token();
- scanner_status = save_scanner_status;
- t = cur_tok;
- back_input(); /* now |start| and |loc| point to the backed-up token |t| */
- if (t >= cs_token_flag) {
- p = get_avail();
- set_token_info(p, cs_token_flag + frozen_dont_expand);
- set_token_link(p, iloc);
- istart = p;
- iloc = p;
- }
-
- } else {
- /* Implement \.{\\primitive} */
- /*
- The \.{\\primitive} handling. If the primitive meaning of the next
- token is an expandable command, it suffices to replace the current
- token with the primitive one and restart |expand|.
-
- Otherwise, the token we just read has to be pushed back, as well
- as a token matching the internal form of \.{\\primitive}, that is
- sneaked in as an alternate form of |ignore_spaces|.
-
- An implementation problem surfaces: There really is no |cur_cs|
- attached to the inserted primitive command, so it is safer to set
- |cur_cs| to zero. |cur_tok| has a similar problem. And for the
- non-expanded branch, simply pushing back a token that matches the
- correct internal command does not work, because that approach would
- not survive roundtripping to a temporary file or even a token list.
-
- In a next version, it would be smart to create |frozen_| versions of
- all the primitives. Then, this problem would not happen, at the
- expense of a few hundred extra control sequences.
- */
- save_scanner_status = scanner_status;
- scanner_status = normal;
- get_token();
- scanner_status = save_scanner_status;
- cur_cs = prim_lookup(cs_text(cur_cs));
- if (cur_cs != undefined_primitive) {
- t = get_prim_eq_type(cur_cs);
- if (t > max_command_cmd) {
- cur_cmd = t;
- cur_chr = get_prim_equiv(cur_cs);
- cur_tok = token_val(cur_cmd, cur_chr);
- cur_cs = 0;
- goto RESWITCH;
- } else {
- back_input(); /* now |loc| and |start| point to a one-item list */
- p = get_avail();
- set_token_info(p, cs_token_flag + frozen_primitive);
- set_token_link(p, iloc);
- iloc = p;
- istart = p;
- }
- } else if (suppress_primitive_error_par == 0) {
- print_err("Missing primitive name");
- help2
- ("The control sequence marked <to be read again> does not",
- "represent any known primitive.");
- back_error();
- }
-
- }
- break;
- case cs_name_cmd:
- /* Manufacture a control sequence name; */
- if (cur_chr == 0) {
- manufacture_csname(0);
- } else if (cur_chr == 1) {
- inject_last_tested_cs();
- } else {
- manufacture_csname(1);
- }
- break;
- case convert_cmd:
- conv_toks(); /* this procedure is discussed in Part 27 below */
- break;
- case the_cmd:
- ins_the_toks(); /* this procedure is discussed in Part 27 below */
- break;
- case combine_toks_cmd:
- combine_the_toks(cur_chr);
- break;
- case if_test_cmd:
- conditional(); /* this procedure is discussed in Part 28 below */
- break;
- case fi_or_else_cmd:
- /* Terminate the current conditional and skip to \.{\\fi} */
- /* The processing of conditionals is complete except for the following
- code, which is actually part of |expand|. It comes into play when
- \.{\\or}, \.{\\else}, or \.{\\fi} is scanned. */
-
- if (tracing_ifs_par > 0)
- if (tracing_commands_par <= 1)
- show_cur_cmd_chr();
- if (cur_chr > if_limit) {
- if (if_limit == if_code) {
- insert_relax(); /* condition not yet evaluated */
- } else {
- print_err("Extra ");
- print_cmd_chr(fi_or_else_cmd, cur_chr);
- help1("I'm ignoring this; it doesn't match any \\if.");
- error();
- }
- } else {
- while (cur_chr != fi_code)
- pass_text(); /* skip to \.{\\fi} */
- pop_condition_stack();
- }
-
- break;
- case input_cmd:
- /* Initiate or terminate input from a file */
- if (cur_chr == 1)
- force_eof = true;
- else if (cur_chr == 2)
- pseudo_start();
- else if (cur_chr == 3) {
- pseudo_start();
- iname = 19;
- } else if (name_in_progress)
- insert_relax();
- else
- start_input();
- break;
- case variable_cmd:
- do_variable();
- break;
- case feedback_cmd:
- do_feedback();
- break;
- default:
- /* Complain about an undefined macro */
- print_err("Undefined control sequence");
- help5("The control sequence at the end of the top line",
- "of your error message was never \\def'ed. If you have",
- "misspelled it (e.g., `\\hobx'), type `I' and the correct",
- "spelling (e.g., `I\\hbox'). Otherwise just continue,",
- "and I'll forget about whatever was undefined.");
- error();
- break;
- }
- } else if (cur_cmd < end_template_cmd) {
- macro_call();
- } else {
- /* Insert a token containing |frozen_endv| */
- /* An |end_template| command is effectively changed to an |endv| command
- by the following code. (The reason for this is discussed below; the
- |frozen_end_template| at the end of the template has passed the
- |check_outer_validity| test, so its mission of error detection has been
- accomplished.)
- */
- cur_tok = cs_token_flag + frozen_endv;
- back_input();
-
- }
- cur_val = cv_backup;
- cur_val_level = cvl_backup;
- radix = radix_backup;
- cur_order = co_backup;
- set_token_link(backup_head, backup_backup);
- decr(expand_depth_count);
-}
-
-@ @c
-void complain_missing_csname(void)
-{
- print_err("Missing \\endcsname inserted");
- help2("The control sequence marked <to be read again> should",
- "not appear between \\csname and \\endcsname.");
- back_error();
-}
-
-@ @c
-void manufacture_csname(boolean use)
-{
- halfword p, q, r;
- lstring *ss;
- r = get_avail();
- p = r; /* head of the list of characters */
- is_in_csname += 1;
- do {
- get_x_token();
- if (cur_cs == 0)
- store_new_token(cur_tok);
- } while (cur_cs == 0);
- if (cur_cmd != end_cs_name_cmd) {
- /* Complain about missing \.{\\endcsname} */
- complain_missing_csname();
- }
- /* Look up the characters of list |r| in the hash table, and set |cur_cs| */
- ss = tokenlist_to_lstring(r, true);
- is_in_csname -= 1;
- if (use) {
- if (ss->l > 0) {
- cur_cs = string_lookup((char *) ss->s, ss->l);
- } else {
- cur_cs = null_cs;
- }
- last_cs_name = cur_cs ;
- free_lstring(ss);
- flush_list(r);
- if (cur_cs == null_cs) {
- /* skip */
- } else if (eq_type(cur_cs) == undefined_cs_cmd) {
- /* skip */
- } else {
- cur_tok = cur_cs + cs_token_flag;
- back_input();
- }
- } else {
- if (ss->l > 0) {
- no_new_control_sequence = false;
- cur_cs = string_lookup((char *) ss->s, ss->l);
- no_new_control_sequence = true;
- } else {
- cur_cs = null_cs; /* the list is empty */
- }
- last_cs_name = cur_cs ;
- free_lstring(ss);
- flush_list(r);
- if (eq_type(cur_cs) == undefined_cs_cmd) {
- eq_define(cur_cs, relax_cmd, too_big_char); /* N.B.: The |save_stack| might change */
- }; /* the control sequence will now match `\.{\\relax}' */
- cur_tok = cur_cs + cs_token_flag;
- back_input();
- }
-}
-
-void inject_last_tested_cs(void)
-{
- if (last_cs_name != null_cs) {
- cur_cs = last_cs_name;
- cur_tok = last_cs_name + cs_token_flag;
- back_input();
- }
-}
-
-@ Sometimes the expansion looks too far ahead, so we want to insert
-a harmless \.{\\relax} into the user's input.
-
-@c
-void insert_relax(void)
-{
- cur_tok = cs_token_flag + cur_cs;
- back_input();
- cur_tok = cs_token_flag + frozen_relax;
- back_input();
- token_type = inserted;
-}
-
-
-@ Here is a recursive procedure that is \TeX's usual way to get the
-next token of input. It has been slightly optimized to take account of
-common cases.
-
-@c
-void get_x_token(void)
-{ /* sets |cur_cmd|, |cur_chr|, |cur_tok|, and expands macros */
- RESTART:
- get_next();
- if (cur_cmd <= max_command_cmd)
- goto DONE;
- if (cur_cmd >= call_cmd) {
- if (cur_cmd < end_template_cmd) {
- macro_call();
- } else {
- cur_cs = frozen_endv;
- cur_cmd = endv_cmd;
- goto DONE; /* |cur_chr=null_list| */
- }
- } else {
- expand();
- }
- goto RESTART;
- DONE:
- if (cur_cs == 0)
- cur_tok = token_val(cur_cmd, cur_chr);
- else
- cur_tok = cs_token_flag + cur_cs;
-}
-
-
-@ The |get_x_token| procedure is equivalent to two consecutive
-procedure calls: |get_next; x_token|.
-
-@c
-void x_token(void)
-{ /* |get_x_token| without the initial |get_next| */
- while (cur_cmd > max_command_cmd) {
- expand();
- get_next();
- }
- if (cur_cs == 0)
- cur_tok = token_val(cur_cmd, cur_chr);
- else
- cur_tok = cs_token_flag + cur_cs;
-}
-
-
-@ A control sequence that has been \.{\\def}'ed by the user is expanded by
-\TeX's |macro_call| procedure.
-
-Before we get into the details of |macro_call|, however, let's consider the
-treatment of primitives like \.{\\topmark}, since they are essentially
-macros without parameters. The token lists for such marks are kept in five
-global arrays of pointers; we refer to the individual entries of these
-arrays by symbolic macros |top_mark|, etc. The value of |top_mark(x)|, etc.
-is either |null| or a pointer to the reference count of a token list.
-
-The variable |biggest_used_mark| is an aid to try and keep the code
-somehwat efficient without too much extra work: it registers the
-highest mark class ever instantiated by the user, so the loops
-in |fire_up| and |vsplit| do not have to traverse the full range
-|0..biggest_mark|.
-
-@c
-halfword top_marks_array[(biggest_mark + 1)];
-halfword first_marks_array[(biggest_mark + 1)];
-halfword bot_marks_array[(biggest_mark + 1)];
-halfword split_first_marks_array[(biggest_mark + 1)];
-halfword split_bot_marks_array[(biggest_mark + 1)];
-halfword biggest_used_mark;
-
-@ @c
-void initialize_marks(void)
-{
- int i;
- biggest_used_mark = 0;
- for (i = 0; i <= biggest_mark; i++) {
- top_mark(i) = null;
- first_mark(i) = null;
- bot_mark(i) = null;
- split_first_mark(i) = null;
- split_bot_mark(i) = null;
- }
-}
-
-
-@ Now let's consider |macro_call| itself, which is invoked when \TeX\ is
-scanning a control sequence whose |cur_cmd| is either |call|, |long_call|,
-|outer_call|, or |long_outer_call|. The control sequence definition
-appears in the token list whose reference count is in location |cur_chr|
-of |mem|.
-
-The global variable |long_state| will be set to |call| or to |long_call|,
-depending on whether or not the control sequence disallows \.{\\par}
-in its parameters. The |get_next| routine will set |long_state| to
-|outer_call| and emit \.{\\par}, if a file ends or if an \.{\\outer}
-control sequence occurs in the midst of an argument.
-
-@c
-int long_state; /* governs the acceptance of \.{\\par} */
-
-@ The parameters, if any, must be scanned before the macro is expanded.
-Parameters are token lists without reference counts. They are placed on
-an auxiliary stack called |pstack| while they are being scanned, since
-the |param_stack| may be losing entries during the matching process.
-(Note that |param_stack| can't be gaining entries, since |macro_call| is
-the only routine that puts anything onto |param_stack|, and it
-is not recursive.)
-
-@c
-halfword pstack[9]; /* arguments supplied to a macro */
-
-
-@ After parameter scanning is complete, the parameters are moved to the
-|param_stack|. Then the macro body is fed to the scanner; in other words,
-|macro_call| places the defined text of the control sequence at the
-top of\/ \TeX's input stack, so that |get_next| will proceed to read it
-next.
-
-The global variable |cur_cs| contains the |eqtb| address of the control sequence
-being expanded, when |macro_call| begins. If this control sequence has not been
-declared \.{\\long}, i.e., if its command code in the |eq_type| field is
-not |long_call| or |long_outer_call|, its parameters are not allowed to contain
-the control sequence \.{\\par}. If an illegal \.{\\par} appears, the macro
-call is aborted, and the \.{\\par} will be rescanned.
-
-@c
-void macro_call(void)
-{ /* invokes a user-defined control sequence */
- halfword r; /* current node in the macro's token list */
- halfword p = null; /* current node in parameter token list being built */
- halfword q; /* new node being put into the token list */
- halfword s; /* backup pointer for parameter matching */
- halfword t; /* cycle pointer for backup recovery */
- halfword u, v; /* auxiliary pointers for backup recovery */
- halfword rbrace_ptr = null; /* one step before the last |right_brace| token */
- int n = 0; /* the number of parameters scanned */
- halfword unbalance; /* unmatched left braces in current parameter */
- halfword m = 0; /* the number of tokens or groups (usually) */
- halfword ref_count; /* start of the token list */
- int save_scanner_status = scanner_status; /* |scanner_status| upon entry */
- halfword save_warning_index = warning_index; /* |warning_index| upon entry */
- int match_chr = 0; /* character used in parameter */
- warning_index = cur_cs;
- ref_count = cur_chr;
- r = token_link(ref_count);
- if (tracing_macros_par > 0) {
- /* Show the text of the macro being expanded */
- begin_diagnostic();
- print_ln();
- print_cs(warning_index);
- token_show(ref_count);
- end_diagnostic(false);
- }
- if (token_info(r) == protected_token)
- r = token_link(r);
- if (token_info(r) != end_match_token) {
- /* Scan the parameters and make |link(r)| point to the macro body; but
- |return| if an illegal \.{\\par} is detected */
- /* At this point, the reader will find it advisable to review the explanation
- of token list format that was presented earlier, since many aspects of that
- format are of importance chiefly in the |macro_call| routine.
-
- The token list might begin with a string of compulsory tokens before the
- first |match| or |end_match|. In that case the macro name is supposed to be
- followed by those tokens; the following program will set |s=null| to
- represent this restriction. Otherwise |s| will be set to the first token of
- a string that will delimit the next parameter.
- */
-
- scanner_status = matching;
- unbalance = 0;
- long_state = eq_type(cur_cs);
- if (long_state >= outer_call_cmd)
- long_state = long_state - 2;
- do {
- set_token_link(temp_token_head, null);
- if ((token_info(r) >= end_match_token)
- || (token_info(r) < match_token)) {
- s = null;
- } else {
- match_chr = token_info(r) - match_token;
- s = token_link(r);
- r = s;
- p = temp_token_head;
- m = 0;
- }
- /* Scan a parameter until its delimiter string has been found; or, if |s=null|,
- simply scan the delimiter string; */
-
- /* If |info(r)| is a |match| or |end_match| command, it cannot be equal to
- any token found by |get_token|. Therefore an undelimited parameter---i.e.,
- a |match| that is immediately followed by |match| or |end_match|---will
- always fail the test `|cur_tok=info(r)|' in the following algorithm. */
- CONTINUE:
- get_token(); /* set |cur_tok| to the next token of input */
- if (cur_tok == token_info(r)) {
- /* Advance |r|; |goto found| if the parameter delimiter has been
- fully matched, otherwise |goto continue| */
- /* A slightly subtle point arises here: When the parameter delimiter ends
- with `\.{\#\{}', the token list will have a left brace both before and
- after the |end_match|\kern-.4pt. Only one of these should affect the
- |align_state|, but both will be scanned, so we must make a correction.
- */
- r = token_link(r);
- if ((token_info(r) >= match_token)
- && (token_info(r) <= end_match_token)) {
- if (cur_tok < left_brace_limit)
- decr(align_state);
- goto FOUND;
- } else {
- goto CONTINUE;
- }
-
- }
- /* Contribute the recently matched tokens to the current parameter, and
- |goto continue| if a partial match is still in effect; but abort if |s=null| */
-
- /* When the following code becomes active, we have matched tokens from |s| to
- the predecessor of |r|, and we have found that |cur_tok<>info(r)|. An
- interesting situation now presents itself: If the parameter is to be
- delimited by a string such as `\.{ab}', and if we have scanned `\.{aa}',
- we want to contribute one `\.a' to the current parameter and resume
- looking for a `\.b'. The program must account for such partial matches and
- for others that can be quite complex. But most of the time we have |s=r|
- and nothing needs to be done.
-
- Incidentally, it is possible for \.{\\par} tokens to sneak in to certain
- parameters of non-\.{\\long} macros. For example, consider a case like
- `\.{\\def\\a\#1\\par!\{...\}}' where the first \.{\\par} is not followed
- by an exclamation point. In such situations it does not seem appropriate
- to prohibit the \.{\\par}, so \TeX\ keeps quiet about this bending of
- the rules. */
-
- if (s != r) {
- if (s == null) {
- /* Report an improper use of the macro and abort */
- print_err("Use of ");
- sprint_cs(warning_index);
- tprint(" doesn't match its definition");
- help4
- ("If you say, e.g., `\\def\\a1{...}', then you must always",
- "put `1' after `\\a', since control sequence names are",
- "made up of letters only. The macro here has not been",
- "followed by the required stuff, so I'm ignoring it.");
- error();
- goto EXIT;
-
- } else {
- t = s;
- do {
- store_new_token(token_info(t));
- incr(m);
- u = token_link(t);
- v = s;
- while (1) {
- if (u == r) {
- if (cur_tok != token_info(v)) {
- goto DONE;
- } else {
- r = token_link(v);
- goto CONTINUE;
- }
- }
- if (token_info(u) != token_info(v))
- goto DONE;
- u = token_link(u);
- v = token_link(v);
- }
- DONE:
- t = token_link(t);
- } while (t != r);
- r = s; /* at this point, no tokens are recently matched */
- }
- }
-
- if (cur_tok == par_token)
- if (long_state != long_call_cmd)
- if (!suppress_long_error_par) {
- goto RUNAWAY;
- }
- if (cur_tok < right_brace_limit) {
- if (cur_tok < left_brace_limit) {
- /* Contribute an entire group to the current parameter */
- unbalance = 1;
- while (1) {
- fast_store_new_token(cur_tok);
- get_token();
- if (cur_tok == par_token) {
- if (long_state != long_call_cmd) {
- if (!suppress_long_error_par) {
- goto RUNAWAY;
-
- }
- }
- }
- if (cur_tok < right_brace_limit) {
- if (cur_tok < left_brace_limit) {
- incr(unbalance);
- } else {
- decr(unbalance);
- if (unbalance == 0)
- break;
- }
- }
- }
- rbrace_ptr = p;
- store_new_token(cur_tok);
-
- } else {
- /* Report an extra right brace and |goto continue| */
- back_input();
- print_err("Argument of ");
- sprint_cs(warning_index);
- tprint(" has an extra }");
- help6
- ("I've run across a `}' that doesn't seem to match anything.",
- "For example, `\\def\\a#1{...}' and `\\a}' would produce",
- "this error. If you simply proceed now, the `\\par' that",
- "I've just inserted will cause me to report a runaway",
- "argument that might be the root of the problem. But if",
- "your `}' was spurious, just type `2' and it will go away.");
- incr(align_state);
- long_state = call_cmd;
- cur_tok = par_token;
- ins_error();
- goto CONTINUE;
- /* a white lie; the \.{\\par} won't always trigger a runaway */
- }
- } else {
- /* Store the current token, but |goto continue| if it is
- a blank space that would become an undelimited parameter */
- if (cur_tok == space_token)
- if (token_info(r) <= end_match_token)
- if (token_info(r) >= match_token)
- goto CONTINUE;
- store_new_token(cur_tok);
-
- }
- incr(m);
- if (token_info(r) > end_match_token)
- goto CONTINUE;
- if (token_info(r) < match_token)
- goto CONTINUE;
- FOUND:
- if (s != null) {
- /* Tidy up the parameter just scanned, and tuck it away */
- /* If the parameter consists of a single group enclosed in braces, we must
- strip off the enclosing braces. That's why |rbrace_ptr| was introduced. */
- if ((m == 1) && (token_info(p) < right_brace_limit)
- && (p != temp_token_head)) {
- set_token_link(rbrace_ptr, null);
- free_avail(p);
- p = token_link(temp_token_head);
- pstack[n] = token_link(p);
- free_avail(p);
- } else {
- pstack[n] = token_link(temp_token_head);
- }
- incr(n);
- if (tracing_macros_par > 0) {
- begin_diagnostic();
- print_nl(match_chr);
- print_int(n);
- tprint("<-");
- show_token_list(pstack[n - 1], null, 1000);
- end_diagnostic(false);
- }
-
- }
-
- /* now |info(r)| is a token whose command code is either |match| or |end_match| */
- } while (token_info(r) != end_match_token);
-
- }
- /* Feed the macro body and its parameters to the scanner */
- /* Before we put a new token list on the input stack, it is wise to clean off
- all token lists that have recently been depleted. Then a user macro that ends
- with a call to itself will not require unbounded stack space. */
- while ((istate == token_list) && (iloc == null) && (token_type != v_template)) {
- /* conserve stack space */
- end_token_list();
- }
- begin_token_list(ref_count, macro);
- iname = warning_index;
- iloc = token_link(r);
- if (n > 0) {
- if (param_ptr + n > max_param_stack) {
- max_param_stack = param_ptr + n;
- if (max_param_stack > param_size)
- overflow("parameter stack size", (unsigned) param_size);
- }
- for (m = 0; m <= n - 1; m++)
- param_stack[param_ptr + m] = pstack[m];
- param_ptr = param_ptr + n;
- }
- goto EXIT;
- RUNAWAY:
- /* Report a runaway argument and abort */
- /* If |long_state=outer_call|, a runaway argument has already been reported. */
- if (long_state == call_cmd) {
- runaway();
- print_err("Paragraph ended before ");
- sprint_cs(warning_index);
- tprint(" was complete");
- help3("I suspect you've forgotten a `}', causing me to apply this",
- "control sequence to too much text. How can we recover?",
- "My plan is to forget the whole thing and hope for the best.");
- back_error();
- }
- pstack[n] = token_link(temp_token_head);
- align_state = align_state - unbalance;
- for (m = 0; m <= n; m++)
- flush_list(pstack[m]);
-
- EXIT:
- scanner_status = save_scanner_status;
- warning_index = save_warning_index;
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/extensions.c b/Build/source/texk/web2c/luatexdir/tex/extensions.c
new file mode 100644
index 00000000000..d5914db8a67
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/extensions.c
@@ -0,0 +1,1329 @@
+/*
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+#define mode mode_par
+#define tail tail_par
+#define head head_par
+#define dir_save dirs_par
+
+/*tex
+
+ The program above includes a bunch of ``hooks'' that allow further
+ capabilities to be added without upsetting \TeX's basic structure. Most of
+ these hooks are concerned with ``whatsit'' nodes, which are intended to be
+ used for special purposes; whenever a new extension to \TeX\ involves a new
+ kind of whatsit node, a corresponding change needs to be made to the routines
+ below that deal with such nodes, but it will usually be unnecessary to make
+ many changes to the other parts of this program.
+
+ In order to demonstrate how extensions can be made, we shall treat
+ `\.{\\write}', `\.{\\openout}', `\.{\\closeout}', `\.{\\immediate}', and
+ `\.{\\special}' as if they were extensions. These commands are actually
+ primitives of \TeX, and they should appear in all implementations of the
+ system; but let's try to imagine that they aren't. Then the program below
+ illustrates how a person could add them.
+
+ Sometimes, of course, an extension will require changes to \TeX\ itself; no
+ system of hooks could be complete enough for all conceivable extensions. The
+ features associated with `\.{\\write}' are almost all confined to the
+ following paragraphs, but there are small parts of the |print_ln| and
+ |print_char| procedures that were introduced specifically to \.{\\write}
+ characters. Furthermore one of the token lists recognized by the scanner is a
+ |write_text|; and there are a few other miscellaneous places where we have
+ already provided for some aspect of \.{\\write}. The goal of a \TeX\ extender
+ should be to minimize alterations to the standard parts of the program, and
+ to avoid them completely if possible. He or she should also be quite sure
+ that there's no easy way to accomplish the desired goals with the standard
+ features that \TeX\ already has. ``Think thrice before extending,'' because
+ that may save a lot of work, and it will also keep incompatible extensions of
+ \TeX\ from proliferating.
+
+ First let's consider the format of whatsit nodes that are used to represent
+ the data associated with \.{\\write} and its relatives. Recall that a whatsit
+ has |type=whatsit_node|, and the |subtype| is supposed to distinguish
+ different kinds of whatsits. Each node occupies two or more words; the exact
+ number is immaterial, as long as it is readily determined from the |subtype|
+ or other data.
+
+ We shall introduce five |subtype| values here, corresponding to the control
+ sequences \.{\\openout}, \.{\\write}, \.{\\closeout}, and \.{\\special}. The
+ second word of I/O whatsits has a |write_stream| field that identifies the
+ write-stream number (0 to 15, or 16 for out-of-range and positive, or 17 for
+ out-of-range and negative). In the case of \.{\\write} and \.{\\special},
+ there is also a field that points to the reference count of a token list that
+ should be sent. In the case of \.{\\openout}, we need three words and three
+ auxiliary subfields to hold the string numbers for name, area, and extension.
+
+ Extensions might introduce new command codes; but it's best to use
+ |extension| with a modifier, whenever possible, so that |main_control| stays
+ the same.
+
+ The sixteen possible \.{\\write} streams are represented by the |write_file|
+ array. The |j|th file is open if and only if |write_open[j]=true|. The last
+ two streams are special; |write_open[16]| represents a stream number greater
+ than 15, while |write_open[17]| represents a negative stream number, and both
+ of these variables are always |false|.
+
+*/
+
+alpha_file write_file[last_file_selector+1];
+halfword write_file_mode[last_file_selector+1];
+halfword write_file_translation[last_file_selector+1];
+boolean write_open[last_file_selector+1];
+
+scaled neg_wd;
+scaled pos_wd;
+scaled neg_ht;
+
+/*tex
+
+ The variable |write_loc| just introduced is used to provide an appropriate
+ error message in case of ``runaway'' write texts.
+
+*/
+
+/*tex The |eqtb| address of \.{\\write}: */
+
+halfword write_loc;
+
+/*tex
+
+ When an |extension| command occurs in |main_control|, in any mode, the
+ |do_extension| routine is called.
+
+*/
+
+int last_saved_image_index ;
+int last_saved_image_pages ;
+int last_saved_box_index ;
+scaledpos last_position = { 0, 0 };
+
+static void do_extension_dvi(int immediate)
+{
+ if (scan_keyword("literal")) {
+ new_whatsit(special_node);
+ write_stream(tail) = null;
+ scan_toks(false, true);
+ write_tokens(tail) = def_ref;
+ } else {
+ tex_error("unexpected use of \\dviextension",null);
+ }
+}
+
+static void do_extension_pdf(int immediate)
+{
+ int i;
+ if (scan_keyword("literal")) {
+ new_whatsit(pdf_literal_node);
+ if (scan_keyword("direct"))
+ set_pdf_literal_mode(tail, direct_always);
+ else if (scan_keyword("page"))
+ set_pdf_literal_mode(tail, direct_page);
+ else if (scan_keyword("text"))
+ set_pdf_literal_mode(tail, direct_text);
+ else if (scan_keyword("raw"))
+ set_pdf_literal_mode(tail, direct_raw);
+ else if (scan_keyword("origin"))
+ set_pdf_literal_mode(tail, set_origin);
+ else
+ set_pdf_literal_mode(tail, set_origin);
+ scan_toks(false, true);
+ set_pdf_literal_type(tail, normal);
+ set_pdf_literal_data(tail, def_ref);
+ } else if (scan_keyword("dest")) {
+ scan_pdfdest(static_pdf);
+ } else if (scan_keyword("annot")) {
+ scan_annot(static_pdf);
+ } else if (scan_keyword("save")) {
+ new_whatsit(pdf_save_node);
+ } else if (scan_keyword("restore")) {
+ new_whatsit(pdf_restore_node);
+ } else if (scan_keyword("setmatrix")) {
+ new_whatsit(pdf_setmatrix_node);
+ scan_toks(false, true);
+ set_pdf_setmatrix_data(tail, def_ref);
+ } else if (scan_keyword("obj")) {
+ scan_obj(static_pdf);
+ if (immediate) {
+ if (obj_data_ptr(static_pdf, pdf_last_obj) == 0) {
+ /*tex This object has not been initialized yet. */
+ normal_error("pdf backend","\\pdfextension obj 'reserveobjnum' cannot be used with \\immediate");
+ }
+ pdf_write_obj(static_pdf, pdf_last_obj);
+ }
+ } else if (scan_keyword("refobj")) {
+ scan_refobj(static_pdf);
+ } else if (scan_keyword("colorstack")) {
+ scan_int();
+ if (cur_val >= colorstackused()) {
+ print_err("Unknown color stack number ");
+ print_int(cur_val);
+ help3(
+ "Allocate and initialize a color stack with \\pdfextension colorstackinit.",
+ "I'll use default color stack 0 here.",
+ "Proceed, with fingers crossed."
+ );
+ error();
+ cur_val = 0;
+ }
+ if (cur_val < 0) {
+ print_err("Invalid negative color stack number");
+ help2(
+ "I'll use default color stack 0 here.",
+ "Proceed, with fingers crossed."
+ );
+ error();
+ cur_val = 0;
+ }
+ if (scan_keyword("set"))
+ i = colorstack_set;
+ else if (scan_keyword("push"))
+ i = colorstack_push;
+ else if (scan_keyword("pop"))
+ i = colorstack_pop;
+ else if (scan_keyword("current"))
+ i = colorstack_current;
+ else
+ i = -1;
+ if (i >= 0) {
+ new_whatsit(pdf_colorstack_node);
+ set_pdf_colorstack_stack(tail, cur_val);
+ set_pdf_colorstack_cmd(tail, i);
+ set_pdf_colorstack_data(tail, null);
+ if (i <= colorstack_data) {
+ scan_toks(false, true);
+ set_pdf_colorstack_data(tail, def_ref);
+ }
+ } else {
+ print_err("Color stack action is missing");
+ help3(
+ "The expected actions for \\pdfextension colorstack:",
+ " set, push, pop, current",
+ "I'll ignore the color stack command."
+ );
+ error();
+ }
+ } else if (scan_keyword("startlink")) {
+ scan_startlink(static_pdf);
+ } else if (scan_keyword("endlink")) {
+ if (abs(mode) == vmode)
+ normal_error("pdf backend", "\\pdfextension endlink cannot be used in vertical mode");
+ new_whatsit(pdf_end_link_node);
+ } else if (scan_keyword("startthread")) {
+ new_annot_whatsit(pdf_start_thread_node);
+ scan_thread_id();
+ } else if (scan_keyword("endthread")) {
+ new_whatsit(pdf_end_thread_node);
+ } else if (scan_keyword("thread")) {
+ new_annot_whatsit(pdf_thread_node);
+ scan_thread_id();
+ } else if (scan_keyword("outline")) {
+ scan_pdfoutline(static_pdf);
+ } else if (scan_keyword("glyphtounicode")) {
+ glyph_to_unicode();
+ } else if (scan_keyword("catalog")) {
+ scan_pdfcatalog(static_pdf);
+ } else if (scan_keyword("fontattr")) {
+ /*tex
+
+ The font attributes are simply initialized to zero now, this is
+ easier to deal with from C than an empty \TeX{} string, and surely
+ nobody will want to set font attr to a string containing a single
+ zero, as that would be nonsensical in the PDF output.
+
+ */
+ scan_font_ident();
+ i = cur_val;
+ if (i == null_font)
+ normal_error("pdf backend", "invalid font identifier");
+ scan_toks(false, true);
+ set_pdf_font_attr(i, tokens_to_string(def_ref));
+ if (str_length(pdf_font_attr(i)) == 0) {
+ /*tex From |tokens_to_string|. */
+ flush_str((str_ptr - 1));
+ set_pdf_font_attr(i, 0);
+ }
+ } else if (scan_keyword("mapfile")) {
+ scan_toks(false, true);
+ pdfmapfile(def_ref);
+ delete_token_ref(def_ref);
+ } else if (scan_keyword("mapline")) {
+ scan_toks(false, true);
+ pdfmapline(def_ref);
+ delete_token_ref(def_ref);
+ } else if (scan_keyword("includechars")) {
+ pdf_include_chars(static_pdf);
+ } else if (scan_keyword("info")) {
+ scan_toks(false, true);
+ pdf_info_toks = concat_tokens(pdf_info_toks, def_ref);
+ } else if (scan_keyword("names")) {
+ scan_toks(false, true);
+ pdf_names_toks = concat_tokens(pdf_names_toks, def_ref);
+ } else if (scan_keyword("trailer")) {
+ scan_toks(false, true);
+ pdf_trailer_toks = concat_tokens(pdf_trailer_toks, def_ref);
+ } else {
+ tex_error("unexpected use of \\pdfextension",null);
+ }
+}
+
+static void do_resource_dvi(int immediate, int code)
+{
+ /*tex Nothing is done here. */
+}
+
+static void do_resource_pdf(int immediate, int code)
+{
+ switch (code) {
+ case use_box_resource_code:
+ scan_pdfrefxform(static_pdf);
+ break;
+ case use_image_resource_code:
+ scan_pdfrefximage(static_pdf);
+ break;
+ case save_box_resource_code:
+ scan_pdfxform(static_pdf);
+ if (immediate) {
+ pdf_cur_form = last_saved_box_index;
+ ship_out(static_pdf, obj_xform_box(static_pdf, last_saved_box_index), SHIPPING_FORM);
+ }
+ break;
+ case save_image_resource_code:
+ scan_pdfximage(static_pdf);
+ if (immediate) {
+ pdf_write_image(static_pdf, last_saved_image_index);
+ }
+ break;
+ }
+}
+
+/*tex
+
+ Ad immediate:
+
+ To write a token list, we must run it through \TeX's scanner, expanding
+ macros and \.{\\the} and \.{\\number}, etc. This might cause runaways, if a
+ delimited macro parameter isn't matched, and runaways would be extremely
+ confusing since we are calling on \TeX's scanner in the middle of a
+ \.{\\shipout} command. Therefore we will put a dummy control sequence as a
+ ``stopper,'' right after the token list. This control sequence is
+ artificially defined to be \.{\\outer}.
+
+ The presence of `\.{\\immediate}' causes the |do_extension| procedure to
+ descend to one level of recursion. Nothing happens unless \.{\\immediate} is
+ followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'.
+
+*/
+
+/*tex
+
+ The extensions are backend related. The next subroutine uses |cur_chr| to
+ decide what sort of whatsit is involved, and also inserts a |write_stream|
+ number.
+
+*/
+
+static void new_write_whatsit(int w, int check)
+{
+ new_whatsit(cur_chr);
+ if (check) {
+ /*tex So we check with open and close. */
+ scan_limited_int(last_file_selector,NULL);
+ } else {
+ /*tex But we're tolerant with the rest. */
+ scan_int();
+ if (cur_val < 0)
+ cur_val = term_only;
+ else if (cur_val > last_file_selector) {
+ cur_val = term_and_log;
+ }
+ }
+ write_stream(tail) = cur_val;
+}
+
+void do_extension(int immediate)
+{
+ /*tex An all-purpose pointer. */
+ halfword p;
+ if (cur_cmd == extension_cmd) {
+ /*tex These have their own range starting at 0. */
+ switch (cur_chr) {
+ case open_code:
+ p = tail;
+ new_write_whatsit(open_node_size,1);
+ scan_optional_equals();
+ scan_file_name();
+ open_name(tail) = cur_name;
+ open_area(tail) = cur_area;
+ open_ext(tail) = cur_ext;
+ if (immediate) {
+ wrapup_leader(tail);
+ flush_node_list(tail);
+ tail = p;
+ vlink(p) = null;
+ }
+ break;
+ case write_code:
+ /*tex
+
+ When `\.{\\write 12\{...\}}' appears, we scan the token list
+ `\.{\{...\}}' without expanding its macros; the macros will
+ be expanded later when this token list is rescanned.
+
+ */
+ p = tail;
+ new_write_whatsit(write_node_size,0);
+ cur_cs = write_stream(tail);
+ scan_toks(false, false);
+ write_tokens(tail) = def_ref;
+ if (immediate) {
+ wrapup_leader(tail);
+ flush_node_list(tail);
+ tail = p;
+ vlink(p) = null;
+ }
+ break;
+ case close_code:
+ p = tail;
+ new_write_whatsit(close_node_size,1);
+ write_tokens(tail) = null;
+ if (immediate) {
+ wrapup_leader(tail);
+ flush_node_list(tail);
+ tail = p;
+ vlink(p) = null;
+ }
+ break;
+ case special_code:
+ /*tex
+
+ When `\.{\\special\{...\}}' appears, we expand the macros in
+ the token list as in \.{\\xdef} and \.{\\mark}.
+
+ */
+ new_whatsit(special_node);
+ write_stream(tail) = null;
+ p = scan_toks(false, true);
+ write_tokens(tail) = def_ref;
+ break;
+ case immediate_code:
+ get_x_token();
+ do_extension(1);
+ break;
+ case end_local_code:
+ if (tracing_nesting_par > 2) {
+ local_control_message("leaving token scanner");
+ }
+ end_local_control();
+ break;
+ case use_box_resource_code:
+ case use_image_resource_code:
+ case save_box_resource_code:
+ case save_image_resource_code:
+ switch (get_o_mode()) {
+ case OMODE_DVI:
+ do_resource_dvi(immediate,cur_chr);
+ break;
+ case OMODE_PDF:
+ do_resource_pdf(immediate,cur_chr);
+ break;
+ default:
+ break;
+ }
+ break;
+ /*tex Backend extensions have their own range starting at 32. */
+ case dvi_extension_code:
+ if (get_o_mode() == OMODE_DVI)
+ do_extension_dvi(immediate);
+ break;
+ case pdf_extension_code:
+ if (get_o_mode() == OMODE_PDF)
+ do_extension_pdf(immediate);
+ break;
+ /*tex Done. */
+ default:
+ if (immediate) {
+ back_input();
+ } else {
+ confusion("invalid extension");
+ }
+ break;
+ }
+ } else {
+ /*tex No extension command, quite certainly following |\immediate|. */
+ back_input();
+ }
+}
+
+/*tex
+
+ Here is a subroutine that creates a whatsit node having a given |subtype| and
+ a given number of words. It initializes only the first word of the whatsit,
+ and appends it to the current list.
+
+*/
+
+void new_whatsit(int s)
+{
+ halfword p = new_node(whatsit_node, s);
+ couple_nodes(tail, p);
+ tail = p;
+}
+
+/*tex
+
+ The final line of this routine is slightly subtle; at least, the author
+ didn't think about it until getting burnt! There is a used-up token list on
+ the stack, namely the one that contained |end_write_token|. (We insert this
+ artificial `\.{\\endwrite}' to prevent runaways, as explained above.) If it
+ were not removed, and if there were numerous writes on a single page, the
+ stack would overflow.
+
+*/
+
+void expand_macros_in_tokenlist(halfword p)
+{
+ int old_mode;
+ pointer q = get_avail();
+ pointer r = get_avail();
+ token_info(q) = right_brace_token + '}';
+ token_link(q) = r;
+ token_info(r) = end_write_token;
+ begin_token_list(q, inserted);
+ begin_token_list(write_tokens(p), write_text);
+ q = get_avail();
+ token_info(q) = left_brace_token + '{';
+ begin_token_list(q, inserted);
+ /*tex
+
+ Now we're ready to scan `\.\{$\langle\,$token list$\,\rangle$\.{\}
+ \\endwrite}'.
+
+ */
+ old_mode = mode;
+ mode = 0;
+ /*tex
+
+ Disable \.{\\prevdepth}, \.{\\spacefactor}, \.{\\lastskip},
+ \.{\\prevgraf}.
+
+ */
+ cur_cs = write_loc;
+ /*tex Expand macros, etc. */
+ q = scan_toks(false, true);
+ get_token();
+ if (cur_tok != end_write_token) {
+ /*tex Recover from an unbalanced write command */
+ const char *hlp[] = {
+ "On this page there's a \\write with fewer real {'s than }'s.",
+ "I can't handle that very well; good luck.",
+ NULL
+ };
+ tex_error("Unbalanced write command", hlp);
+ do {
+ get_token();
+ } while (cur_tok != end_write_token);
+ }
+ mode = old_mode;
+ /*tex Conserve stack space. */
+ end_token_list();
+}
+
+void write_out(halfword p)
+{
+ /*tex holds print |selector| */
+ int old_setting;
+ /*tex write stream number */
+ int j;
+ /*tex line to be written, as a C string */
+ char *s, *ss;
+ int callback_id;
+ int lua_retval;
+ expand_macros_in_tokenlist(p);
+ old_setting = selector;
+ j = write_stream(p);
+ if (file_can_be_written(j)) {
+ selector = j;
+ } else if ((j == term_only) && (selector == term_and_log)) {
+ /*tex write to the terminal if file isn't open */
+ selector = log_only;
+ tprint_nl("");
+ } else {
+ tprint_nl("");
+ }
+ s = tokenlist_to_cstring(def_ref, false, NULL);
+ if (selector < no_print) {
+ /*tex selector is a file */
+ callback_id = callback_defined(process_output_buffer_callback);
+ if (callback_id > 0) {
+ /*tex fix up the output buffer using callbacks */
+ lua_retval = run_callback(callback_id, "S->S", s, &ss);
+ if ((lua_retval == true) && (ss != NULL)) {
+ xfree(s);
+ s = ss;
+ }
+ }
+ }
+ tprint(s);
+ xfree(s);
+ print_ln();
+ flush_list(def_ref);
+ selector = old_setting;
+}
+
+void finalize_write_files(void) {
+ int k;
+ for (k = 0; k <= last_file_selector; k++) {
+ if (write_open[k]) {
+ lua_a_close_out(write_file[k]);
+ }
+ }
+}
+
+void initialize_write_files(void) {
+ int k;
+ for (k = 0; k <= last_file_selector; k++) {
+ write_open[k] = false;
+ }
+}
+
+void close_write_file(int id) {
+ if (write_open[id]) {
+ lua_a_close_out(write_file[id]);
+ write_open[id] = false;
+ }
+}
+
+boolean open_write_file(int id, char *fn) {
+ if (lua_a_open_out(&(write_file[id]), fn, (id + 1))) {
+ write_open[id] = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/*tex
+
+ To implement primitives as \.{\\pdfextension info}, \.{\\pdfextension
+ catalog} or \.{\\pdfextension names} we need to concatenate tokens lists.
+
+*/
+
+halfword concat_tokens(halfword q, halfword r)
+{
+ /*tex concat |q| and |r| and returns the result tokens list */
+ halfword p;
+ if (q == null)
+ return r;
+ p = q;
+ while (token_link(p) != null)
+ p = token_link(p);
+ set_token_link(p, token_link(r));
+ free_avail(r);
+ return q;
+}
+
+/*tex
+
+ The \eTeX\ features available in extended mode are grouped into two
+ categories: (1)~Some of them are permanently enabled and have no semantic
+ effect as long as none of the additional primitives are executed. (2)~The
+ remaining \eTeX\ features are optional and can be individually enabled and
+ disabled. For each optional feature there is an \eTeX\ state variable named
+ \.{\\...state}; the feature is enabled, resp.\ disabled by assigning a
+ positive, resp.\ non-positive value to that integer.
+
+ In order to handle \.{\\everyeof} we need an array |eof_seen| of boolean
+ variables.
+
+*/
+
+boolean *eof_seen;
+
+/*tex
+
+ The |print_group| procedure prints the current level of grouping and the name
+ corresponding to |cur_group|.
+
+*/
+
+void print_group(boolean e)
+{
+ switch (cur_group) {
+ case bottom_level:
+ tprint("bottom level");
+ return;
+ break;
+ case simple_group:
+ case semi_simple_group:
+ if (cur_group == semi_simple_group)
+ tprint("semi ");
+ tprint("simple");
+ break;;
+ case hbox_group:
+ case adjusted_hbox_group:
+ if (cur_group == adjusted_hbox_group)
+ tprint("adjusted ");
+ tprint("hbox");
+ break;
+ case vbox_group:
+ tprint("vbox");
+ break;
+ case vtop_group:
+ tprint("vtop");
+ break;
+ case align_group:
+ case no_align_group:
+ if (cur_group == no_align_group)
+ tprint("no ");
+ tprint("align");
+ break;
+ case output_group:
+ tprint("output");
+ break;
+ case disc_group:
+ tprint("disc");
+ break;
+ case insert_group:
+ tprint("insert");
+ break;
+ case vcenter_group:
+ tprint("vcenter");
+ break;
+ case math_group:
+ case math_choice_group:
+ case math_shift_group:
+ case math_left_group:
+ tprint("math");
+ if (cur_group == math_choice_group)
+ tprint(" choice");
+ else if (cur_group == math_shift_group)
+ tprint(" shift");
+ else if (cur_group == math_left_group)
+ tprint(" left");
+ break;
+ }
+ tprint(" group (level ");
+ print_int(cur_level);
+ print_char(')');
+ if (saved_value(-1) != 0) {
+ /*tex |saved_line| */
+ if (e)
+ tprint(" entered at line ");
+ else
+ tprint(" at line ");
+ print_int(saved_value(-1));
+ }
+}
+
+/*tex
+
+ The |group_trace| procedure is called when a new level of grouping begins
+ (|e=false|) or ends (|e=true|) with |saved_value(-1)| containing the line
+ number.
+
+*/
+
+void group_trace(boolean e)
+{
+ begin_diagnostic();
+ print_char('{');
+ if (e)
+ tprint("leaving ");
+ else
+ tprint("entering ");
+ print_group(e);
+ print_char('}');
+ end_diagnostic(false);
+}
+
+/*tex
+
+ A group entered (or a conditional started) in one file may end in a different
+ file. Such slight anomalies, although perfectly legitimate, may cause errors
+ that are difficult to locate. In order to be able to give a warning message
+ when such anomalies occur, \eTeX\ uses the |grp_stack| and |if_stack| arrays
+ to record the initial |cur_boundary| and |cond_ptr| values for each input
+ file.
+
+*/
+
+/*tex initial |cur_boundary| */
+
+save_pointer *grp_stack;
+
+/*tex initial |cond_ptr| */
+
+halfword *if_stack;
+
+/*tex
+
+ When a group ends that was apparently entered in a different input file, the
+ |group_warning| procedure is invoked in order to update the |grp_stack|. If
+ moreover \.{\\tracingnesting} is positive we want to give a warning message.
+ The situation is, however, somewhat complicated by two facts: (1)~There may
+ be |grp_stack| elements without a corresponding \.{\\input} file or
+ \.{\\scantokens} pseudo file (e.g., error insertions from the terminal); and
+ (2)~the relevant information is recorded in the |name_field| of the
+ |input_stack| only loosely synchronized with the |in_open| variable indexing
+ |grp_stack|.
+
+*/
+
+void group_warning(void)
+{
+ /*tex do we need a warning? */
+ boolean w = false;
+ /*tex index into |grp_stack| */
+ int i = in_open;
+ base_ptr = input_ptr;
+ /*tex store current state */
+ input_stack[base_ptr] = cur_input;
+ while ((grp_stack[i] == cur_boundary) && (i > 0)) {
+ /*tex
+
+ Set variable |w| to indicate if this case should be reported. This
+ code scans the input stack in order to determine the type of the
+ current input file.
+
+ */
+ if (tracing_nesting_par > 0) {
+ while ((input_stack[base_ptr].state_field == token_list) || (input_stack[base_ptr].index_field > i))
+ decr(base_ptr);
+ if (input_stack[base_ptr].name_field > 17)
+ w = true;
+ }
+ grp_stack[i] = save_value(save_ptr);
+ decr(i);
+ }
+ if (w) {
+ tprint_nl("Warning: end of ");
+ print_group(true);
+ tprint(" of a different file");
+ print_ln();
+ if (tracing_nesting_par > 1)
+ show_context();
+ if (history == spotless)
+ history = warning_issued;
+ }
+}
+
+/*tex
+
+ When a conditional ends that was apparently started in a different input
+ file, the |if_warning| procedure is invoked in order to update the
+ |if_stack|. If moreover \.{\\tracingnesting} is positive we want to give a
+ warning message (with the same complications as above).
+
+*/
+
+void if_warning(void)
+{
+ /*tex Do we need a warning? */
+ boolean w = false;
+ int i = in_open;
+ base_ptr = input_ptr;
+ /*tex Store current state. */
+ input_stack[base_ptr] = cur_input;
+ while (if_stack[i] == cond_ptr) {
+ /*tex Set variable |w| to. */
+ if (tracing_nesting_par > 0) {
+ while ((input_stack[base_ptr].state_field == token_list) || (input_stack[base_ptr].index_field > i))
+ decr(base_ptr);
+ if (input_stack[base_ptr].name_field > 17)
+ w = true;
+ }
+ if_stack[i] = vlink(cond_ptr);
+ decr(i);
+ }
+ if (w) {
+ tprint_nl("Warning: end of ");
+ print_cmd_chr(if_test_cmd, cur_if);
+ print_if_line(if_line);
+ tprint(" of a different file");
+ print_ln();
+ if (tracing_nesting_par > 1)
+ show_context();
+ if (history == spotless)
+ history = warning_issued;
+ }
+}
+
+/*tex
+
+ Conversely, the |file_warning| procedure is invoked when a file ends and some
+ groups entered or conditionals started while reading from that file are still
+ incomplete.
+
+*/
+
+void file_warning(void)
+{
+ /*tex saved value of |save_ptr| or |cond_ptr| */
+ halfword p = save_ptr;
+ /*tex saved value of |cur_level| or |if_limit| */
+ int l = cur_level;
+ /*tex saved value of |cur_group| or |cur_if| */
+ int c = cur_group;
+ /*tex saved value of |if_line| */
+ int i;
+ save_ptr = cur_boundary;
+ while (grp_stack[in_open] != save_ptr) {
+ decr(cur_level);
+ tprint_nl("Warning: end of file when ");
+ print_group(true);
+ tprint(" is incomplete");
+ cur_group = save_level(save_ptr);
+ save_ptr = save_value(save_ptr);
+ }
+ save_ptr = p;
+ cur_level = (quarterword) l;
+ /*tex Restore old values. */
+ cur_group = (group_code) c;
+ p = cond_ptr;
+ l = if_limit;
+ c = cur_if;
+ i = if_line;
+ while (if_stack[in_open] != cond_ptr) {
+ tprint_nl("Warning: end of file when ");
+ print_cmd_chr(if_test_cmd, cur_if);
+ if (if_limit == fi_code)
+ tprint_esc("else");
+ print_if_line(if_line);
+ tprint(" is incomplete");
+ if_line = if_line_field(cond_ptr);
+ cur_if = if_limit_subtype(cond_ptr);
+ if_limit = if_limit_type(cond_ptr);
+ cond_ptr = vlink(cond_ptr);
+ }
+ /*tex restore old values */
+ cond_ptr = p;
+ if_limit = l;
+ cur_if = c;
+ if_line = i;
+ print_ln();
+ if (tracing_nesting_par > 1)
+ show_context();
+ if (history == spotless)
+ history = warning_issued;
+}
+
+/*tex The |par_fill_skip| glue node of the new paragraph. */
+
+halfword last_line_fill;
+
+/*tex
+
+ The lua interface needs some extra functions. The functions themselves are
+ quite boring, but they are handy because otherwise this internal stuff has to
+ be accessed from C directly, where lots of the defines are not available.
+
+*/
+
+#define get_tex_dimen_register(j) dimen(j)
+#define get_tex_skip_register(j) skip(j)
+#define get_tex_mu_skip_register(j) mu_skip(j)
+#define get_tex_count_register(j) count(j)
+#define get_tex_attribute_register(j) attribute(j)
+#define get_tex_box_register(j) box(j)
+
+/*tex These can now be macros (todo). */
+
+int get_tex_extension_count_register(int i)
+{
+ return (int) int_par(backend_int_base-int_base+i);
+}
+
+void set_tex_extension_count_register(int i, int d)
+{
+ int_par(backend_int_base-int_base+i) = d;
+}
+
+int get_tex_extension_dimen_register(int i)
+{
+ return (int) dimen_par(backend_dimen_base-dimen_base+i);
+}
+
+void set_tex_extension_dimen_register(int i, int d)
+{
+ dimen_par(backend_dimen_base-dimen_base+i) = d;
+}
+
+int get_tex_extension_toks_register(int i)
+{
+ return equiv(backend_toks_base+i);
+}
+
+int set_tex_dimen_register(int j, scaled v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ word_define(j + scaled_base, v);
+ return 0;
+}
+
+int set_tex_skip_register(int j, halfword v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ if (type(v) != glue_spec_node)
+ return 1;
+ word_define(j + skip_base, v);
+ return 0;
+}
+
+int set_tex_mu_skip_register(int j, halfword v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ if (type(v) != glue_spec_node)
+ return 1;
+ word_define(j + mu_skip_base, v);
+ return 0;
+}
+
+int set_tex_count_register(int j, scaled v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ word_define(j + count_base, v);
+ return 0;
+}
+
+int set_tex_box_register(int j, scaled v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ define(j + box_base, box_ref_cmd, v);
+ return 0;
+}
+
+int set_tex_attribute_register(int j, scaled v)
+{
+ int a;
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ if (j > max_used_attr)
+ max_used_attr = j;
+ attr_list_cache = cache_disabled;
+ word_define(j + attribute_base, v);
+ return 0;
+}
+
+int get_tex_toks_register(int j)
+{
+ str_number s = get_nullstr();
+ if (toks(j) != null) {
+ s = tokens_to_string(toks(j));
+ }
+ return s;
+}
+
+int set_tex_toks_register(int j, lstring s)
+{
+ int a;
+ halfword ref = get_avail();
+ (void) str_toks(s);
+ set_token_ref_count(ref, 0);
+ set_token_link(ref, token_link(temp_token_head));
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ define(j + toks_base, call_cmd, ref);
+ return 0;
+}
+
+int scan_tex_toks_register(int j, int c, lstring s)
+{
+ int a;
+ halfword ref = get_avail();
+ (void) str_scan_toks(c,s);
+ set_token_ref_count(ref, 0);
+ set_token_link(ref, token_link(temp_token_head));
+ if (global_defs_par > 0)
+ a = 4;
+ else
+ a = 0;
+ define(j + toks_base, call_cmd, ref);
+ return 0;
+}
+
+scaled get_tex_box_width(int j)
+{
+ halfword q = box(j);
+ if (q != null)
+ return width(q);
+ return 0;
+}
+
+int set_tex_box_width(int j, scaled v)
+{
+ halfword q = box(j);
+ if (q == null)
+ return 1;
+ width(q) = v;
+ return 0;
+}
+
+scaled get_tex_box_height(int j)
+{
+ halfword q = box(j);
+ if (q != null)
+ return height(q);
+ return 0;
+}
+
+int set_tex_box_height(int j, scaled v)
+{
+ halfword q = box(j);
+ if (q == null)
+ return 1;
+ height(q) = v;
+ return 0;
+}
+
+scaled get_tex_box_depth(int j)
+{
+ halfword q = box(j);
+ if (q != null)
+ return depth(q);
+ return 0;
+}
+
+int set_tex_box_depth(int j, scaled v)
+{
+ halfword q = box(j);
+ if (q == null)
+ return 1;
+ depth(q) = v;
+ return 0;
+}
+
+/*tex
+
+ This section is devoted to the {\sl Synchronize \TeX nology} - or simply {\sl
+ Sync\TeX} - used to synchronize between input and output. This section
+ explains how synchronization basics are implemented. Before we enter into
+ more technical details, let us recall in a few words what is synchronization.
+
+ \TeX\ typesetting system clearly separates the input and the output material,
+ and synchronization will provide a new link between both that can help text
+ editors and viewers to work together. More precisely, forwards
+ synchronization is the ability, given a location in the input source file, to
+ find what is the corresponding place in the output. Backwards synchronization
+ just performs the opposite: given a location in the output, retrieve the
+ corresponding material in the input source file.
+
+ For better code management and maintainance, we adopt a naming convention.
+ Throughout this program, code related to the {\sl Synchronize \TeX nology} is
+ tagged with the ``{\sl synctex}'' key word. Any code extract where {\sl
+ Sync\TeX} plays its part, either explicitly or implicitly, (should) contain
+ the string ``{\sl synctex}''. This naming convention also holds for external
+ files. Moreover, all the code related to {\sl Sync\TeX} is gathered in this
+ section, except the definitions.
+
+ Enabling synchronization should be performed from the command line,
+ |synctexoption| is used for that purpose. This global integer variable is
+ declared here but it is not used here. This is just a placeholder where the
+ command line controller will put the {\sl Sync\TeX} related options, and the
+ {\sl Sync\TeX} controller will read them.
+
+*/
+
+int synctexoption;
+
+/*tex
+
+ A convenient primitive is provided: \.{\\synctex=1} in the input source file
+ enables synchronization whereas \.{\\synctex=0} disables it. Its memory
+ address is |synctex_code|. It is initialized by the {\sl Sync\TeX} controller
+ to the command-line option if given. The controller may filter some reserved
+ bits.
+
+ In order to give the {\sl Sync\TeX} controller read and write access to the
+ contents of the \.{\\synctex} primitive, we declare |synctexoffset|, such
+ that |mem[synctexoffset]| and \.{\\synctex} correspond to the same memory
+ storage. |synctexoffset| is initialized to the correct value when quite
+ everything is initialized.
+
+*/
+
+/*tex Holds the true value of |synctex_code|: */
+
+int synctexoffset;
+
+/*tex
+
+ Synchronization is achieved with the help of an auxiliary file named `\.{{\sl
+ jobname}.synctex}' ({\sl jobname} is the contents of the \.{\\jobname}
+ macro), where a {\sl Sync\TeX} controller implemented in the external
+ |synctex.c| file will store geometrical information. This {\sl Sync\TeX}
+ controller will take care of every technical details concerning the {\sl
+ Sync\TeX} file, we will only focus on the messages the controller will
+ receive from the \TeX\ program.
+
+ The most accurate synchronization information should allow to map any
+ character of the input source file to the corresponding location in the
+ output, if relevant. Ideally, the synchronization information of the input
+ material consists of the file name, the line and column numbers of every
+ character. The synchronization information in the output is simply the page
+ number and either point coordinates, or box dimensions and position. The
+ problem is that the mapping between these informations is only known at ship
+ out time, which means that we must keep track of the input synchronization
+ information until the pages ship out.
+
+ As \TeX\ only knows about file names and line numbers, but forgets the column
+ numbers, we only consider a restricted input synchronization information
+ called {\sl Sync\TeX\ information}. It consists of a unique file name
+ identifier, the {\sl Sync\TeX\ file tag}, and the line number.
+
+ Keeping track of such information, should be different whether characters or
+ nodes are involved. Actually, only certain nodes are involved in {\sl
+ Sync\TeX}, we call them {\sl synchronized nodes}. Synchronized nodes store
+ the {\sl Sync\TeX} information in their last two words: the first one
+ contains a {\sl Sync\TeX\ file tag} uniquely identifying the input file, and
+ the second one contains the current line number, as returned by the
+ \.{\\inputlineno} primitive. The |synctex_field_size| macro contains the
+ necessary size to store the {\sl Sync\TeX} information in a node.
+
+ When declaring the size of a new node, it is recommanded to use the following
+ convention: if the node is synchronized, use a definition similar to
+ |my_synchronized_node_size|={\sl xxx}+|synctex_field_size|. Moreover, one
+ should expect that the {\sl Sync\TeX} information is always stored in the
+ last two words of a synchronized node.
+
+ By default, every node with a sufficiently big size is initialized at
+ creation time in the |get_node| routine with the current {\sl Sync\TeX}
+ information, whether or not the node is synchronized. One purpose is to set
+ this information very early in order to minimize code dependencies, including
+ forthcoming extensions. Another purpose is to avoid the assumption that every
+ node type has a dedicated getter, where initialization should take place.
+ Actually, it appears that some nodes are created using directly the
+ |get_node| routine and not the dedicated constructor. And finally,
+ initializing the node at only one place is less error prone.
+
+ Instead of storing the input file name, it is better to store just an
+ identifier. Each time \TeX\ opens a new file, it notifies the {\sl Sync\TeX}
+ controller with a |synctex_start_input| message. This controller will create
+ a new {\sl Sync\TeX} file tag and will update the current input state record
+ accordingly. If the input comes from the terminal or a pseudo file, the
+ |synctex_tag| is set to 0. It results in automatically disabling
+ synchronization for material input from the terminal or pseudo files.
+
+ Synchronized nodes are boxes, math, kern and glue nodes. Other nodes should
+ be synchronized too, in particular math noads. \TeX\ assumes that math, kern
+ and glue nodes have the same size, this is why both are synchronized. {\sl In
+ fine}, only horizontal lists are really used in {\sl Sync\TeX}, but all box
+ nodes are considered the same with respect to synchronization, because a box
+ node type is allowed to change at execution time.
+
+ {\em Nota Bene:} The {\sl Sync\TeX} code is very close to the memory model.
+ It is not connected to any other part of the code, except for memory
+ management. It is possible to neutralize the {\sl Sync\TeX} code rather
+ simply. The first step is to define a null |synctex_field_size|. The second
+ step is to comment out the code in ``Initialize bigger nodes...'' and every
+ ``Copy ... {\sl Sync\TeX} information''. The last step will be to comment out
+ the |synctex_tag_field| related code in the definition of |synctex_tag| and
+ the various ``Prepare ... {\sl Sync\TeX} information''. Then all the
+ remaining code should be just harmless. The resulting program would behave
+ exactly the same as if absolutely no {\sl Sync\TeX} related code was there,
+ including memory management. Of course, all this assumes that {\sl Sync\TeX}
+ is turned off from the command line.
+
+ Here are extra variables for Web2c. (This numbering of the system-dependent
+ section allows easy integration of Web2c and e-\TeX, etc.)
+
+*/
+
+/*tex where the filename to switch to starts */
+
+pool_pointer edit_name_start;
+
+/*tex what line to start editing at */
+
+int edit_name_length, edit_line;
+
+/*tex whether |more_name| returns false for space */
+
+boolean stop_at_space;
+
+/*tex
+
+ The |edit_name_start| will be set to point into |str_pool| somewhere after
+ its beginning if \TeX\ is supposed to switch to an editor on exit.
+
+*/
+
+int shellenabledp;
+int restrictedshell;
+char *output_comment;
+
+/*tex
+
+ Are we printing extra info as we read the format file?
+
+*/
+
+boolean debug_format_file;
+
+void wrapup_leader(halfword p)
+{
+ /*tex Do some work that has been queued up for \.{\\write}. */
+ if (!doing_leaders) {
+ int j = write_stream(p);
+ if (subtype(p) == write_node) {
+ write_out(p);
+ } else if (subtype(p) == close_node) {
+ close_write_file(j);
+ } else if (valid_write_file(j)) {
+ char *fn;
+ close_write_file(j);
+ cur_name = open_name(p);
+ cur_area = open_area(p);
+ cur_ext = open_ext(p);
+ if (cur_ext == get_nullstr())
+ cur_ext = maketexstring(".tex");
+ fn = pack_file_name(cur_name, cur_area, cur_ext);
+ while (! open_write_file(j,fn)) {
+ fn = prompt_file_name("output file name", ".tex");
+ }
+ }
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/extensions.w b/Build/source/texk/web2c/luatexdir/tex/extensions.w
deleted file mode 100644
index 73dc3ba4514..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/extensions.w
+++ /dev/null
@@ -1,1211 +0,0 @@
-% extensions.w
-%
-% Copyright 2009-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/>.
-
-\def\eTeX{e-\TeX}
-\def\pdfTeX{pdf\TeX}
-
-@ @c
-#include "ptexlib.h"
-
-@ @c
-#define mode mode_par
-#define tail tail_par
-#define head head_par
-#define dir_save dirs_par
-
-@ The program above includes a bunch of ``hooks'' that allow further
-capabilities to be added without upsetting \TeX's basic structure.
-Most of these hooks are concerned with ``whatsit'' nodes, which are
-intended to be used for special purposes; whenever a new extension to
-\TeX\ involves a new kind of whatsit node, a corresponding change needs
-to be made to the routines below that deal with such nodes,
-but it will usually be unnecessary to make many changes to the
-other parts of this program.
-
-In order to demonstrate how extensions can be made, we shall treat
-`\.{\\write}', `\.{\\openout}', `\.{\\closeout}', `\.{\\immediate}',
-and `\.{\\special}' as if they were extensions.
-These commands are actually primitives of \TeX, and they should
-appear in all implementations of the system; but let's try to imagine
-that they aren't. Then the program below illustrates how a person
-could add them.
-
-Sometimes, of course, an extension will require changes to \TeX\ itself;
-no system of hooks could be complete enough for all conceivable extensions.
-The features associated with `\.{\\write}' are almost all confined to the
-following paragraphs, but there are small parts of the |print_ln| and
-|print_char| procedures that were introduced specifically to \.{\\write}
-characters. Furthermore one of the token lists recognized by the scanner
-is a |write_text|; and there are a few other miscellaneous places where we
-have already provided for some aspect of \.{\\write}. The goal of a \TeX\
-extender should be to minimize alterations to the standard parts of the
-program, and to avoid them completely if possible. He or she should also
-be quite sure that there's no easy way to accomplish the desired goals
-with the standard features that \TeX\ already has. ``Think thrice before
-extending,'' because that may save a lot of work, and it will also keep
-incompatible extensions of \TeX\ from proliferating.
-@^system dependencies@>
-@^extensions to \TeX@>
-
-First let's consider the format of whatsit nodes that are used to represent
-the data associated with \.{\\write} and its relatives. Recall that a whatsit
-has |type=whatsit_node|, and the |subtype| is supposed to distinguish
-different kinds of whatsits. Each node occupies two or more words; the
-exact number is immaterial, as long as it is readily determined from the
-|subtype| or other data.
-
-We shall introduce five |subtype| values here, corresponding to the
-control sequences \.{\\openout}, \.{\\write}, \.{\\closeout}, and \.{\\special}.
-The second word of I/O whatsits has a |write_stream| field
-that identifies the write-stream number (0 to 15, or 16 for out-of-range and
-positive, or 17 for out-of-range and negative).
-In the case of \.{\\write} and \.{\\special}, there is also a field that
-points to the reference count of a token list that should be sent. In the
-case of \.{\\openout}, we need three words and three auxiliary subfields
-to hold the string numbers for name, area, and extension.
-
-@ Extensions might introduce new command codes; but it's best to use
-|extension| with a modifier, whenever possible, so that |main_control|
-stays the same.
-
-@ The sixteen possible \.{\\write} streams are represented by the |write_file|
-array. The |j|th file is open if and only if |write_open[j]=true|. The last
-two streams are special; |write_open[16]| represents a stream number
-greater than 15, while |write_open[17]| represents a negative stream number,
-and both of these variables are always |false|.
-
-@c
-alpha_file write_file[last_file_selector+1];
-halfword write_file_mode[last_file_selector+1];
-halfword write_file_translation[last_file_selector+1];
-boolean write_open[last_file_selector+1];
-
-scaled neg_wd;
-scaled pos_wd;
-scaled neg_ht;
-
-@ The variable |write_loc| just introduced is used to provide an
-appropriate error message in case of ``runaway'' write texts.
-
-@c
-halfword write_loc; /* |eqtb| address of \.{\\write} */
-
-/*
- hh: eventually i'll make \pdfextension a lua token parsed function;
- a complication is that sometimes token lists are delayed
-*/
-
-@ When an |extension| command occurs in |main_control|, in any mode,
-the |do_extension| routine is called.
-
-@c
-int last_saved_image_index ;
-int last_saved_image_pages ;
-int last_saved_box_index ;
-scaledpos last_position = { 0, 0 };
-
-static void do_extension_dvi(int immediate)
-{
- if (scan_keyword("literal")) {
- new_whatsit(special_node);
- write_stream(tail) = null;
- scan_toks(false, true);
- write_tokens(tail) = def_ref;
- } else {
- tex_error("unexpected use of \\dviextension",null);
- }
-}
-
-static void do_extension_pdf(int immediate)
-{
- int i;
-
- if (scan_keyword("literal")) {
- new_whatsit(pdf_literal_node);
- if (scan_keyword("direct"))
- set_pdf_literal_mode(tail, direct_always);
- else if (scan_keyword("page"))
- set_pdf_literal_mode(tail, direct_page);
- else if (scan_keyword("text"))
- set_pdf_literal_mode(tail, direct_text);
- else if (scan_keyword("raw"))
- set_pdf_literal_mode(tail, direct_raw);
- else if (scan_keyword("origin"))
- set_pdf_literal_mode(tail, set_origin);
- else
- set_pdf_literal_mode(tail, set_origin);
- scan_toks(false, true);
- set_pdf_literal_type(tail, normal);
- set_pdf_literal_data(tail, def_ref);
- } else if (scan_keyword("dest")) {
- scan_pdfdest(static_pdf);
- } else if (scan_keyword("annot")) {
- scan_annot(static_pdf);
- } else if (scan_keyword("save")) {
- new_whatsit(pdf_save_node);
- } else if (scan_keyword("restore")) {
- new_whatsit(pdf_restore_node);
- } else if (scan_keyword("setmatrix")) {
- new_whatsit(pdf_setmatrix_node);
- scan_toks(false, true);
- set_pdf_setmatrix_data(tail, def_ref);
- } else if (scan_keyword("obj")) {
- scan_obj(static_pdf);
- if (immediate) {
- if (obj_data_ptr(static_pdf, pdf_last_obj) == 0) /* this object has not been initialized yet */
- normal_error("pdf backend","\\pdfextension obj 'reserveobjnum' cannot be used with \\immediate");
- pdf_write_obj(static_pdf, pdf_last_obj);
- }
- } else if (scan_keyword("refobj")) {
- scan_refobj(static_pdf);
- } else if (scan_keyword("colorstack")) {
- scan_int();
- if (cur_val >= colorstackused()) {
- print_err("Unknown color stack number ");
- print_int(cur_val);
- help3
- ("Allocate and initialize a color stack with \\pdfextension colorstackinit.",
- "I'll use default color stack 0 here.",
- "Proceed, with fingers crossed.");
- error();
- cur_val = 0;
- }
- if (cur_val < 0) {
- print_err("Invalid negative color stack number");
- help2("I'll use default color stack 0 here.",
- "Proceed, with fingers crossed.");
- error();
- cur_val = 0;
- }
- if (scan_keyword("set"))
- i = colorstack_set;
- else if (scan_keyword("push"))
- i = colorstack_push;
- else if (scan_keyword("pop"))
- i = colorstack_pop;
- else if (scan_keyword("current"))
- i = colorstack_current;
- else
- i = -1; /* error */
- if (i >= 0) {
- new_whatsit(pdf_colorstack_node);
- set_pdf_colorstack_stack(tail, cur_val);
- set_pdf_colorstack_cmd(tail, i);
- set_pdf_colorstack_data(tail, null);
- if (i <= colorstack_data) {
- scan_toks(false, true);
- set_pdf_colorstack_data(tail, def_ref);
- }
- } else {
- print_err("Color stack action is missing");
- help3("The expected actions for \\pdfextension colorstack:",
- " set, push, pop, current",
- "I'll ignore the color stack command.");
- error();
- }
- } else if (scan_keyword("startlink")) {
- scan_startlink(static_pdf);
- } else if (scan_keyword("endlink")) {
- if (abs(mode) == vmode)
- normal_error("pdf backend", "\\pdfextension endlink cannot be used in vertical mode");
- new_whatsit(pdf_end_link_node);
- } else if (scan_keyword("startthread")) {
- new_annot_whatsit(pdf_start_thread_node);
- scan_thread_id();
- } else if (scan_keyword("endthread")) {
- new_whatsit(pdf_end_thread_node);
- } else if (scan_keyword("thread")) {
- new_annot_whatsit(pdf_thread_node);
- scan_thread_id();
- } else if (scan_keyword("outline")) {
- scan_pdfoutline(static_pdf);
- } else if (scan_keyword("glyphtounicode")) {
- glyph_to_unicode();
- } else if (scan_keyword("catalog")) {
- scan_pdfcatalog(static_pdf);
- } else if (scan_keyword("fontattr")) {
- /*
- The font attributes are simply initialized to zero now, this is easier to deal with from C than an
- empty \TeX{} string, and surely nobody will want to set font attr to a string containing a single zero,
- as that would be nonsensical in the PDF output.
- */
- scan_font_ident();
- i = cur_val;
- if (i == null_font)
- normal_error("pdf backend", "invalid font identifier");
- scan_toks(false, true);
- set_pdf_font_attr(i, tokens_to_string(def_ref));
- if (str_length(pdf_font_attr(i)) == 0) {
- flush_str((str_ptr - 1)); /* from |tokens_to_string| */
- set_pdf_font_attr(i, 0);
- }
- } else if (scan_keyword("mapfile")) {
- scan_toks(false, true);
- pdfmapfile(def_ref);
- delete_token_ref(def_ref);
- } else if (scan_keyword("mapline")) {
- scan_toks(false, true);
- pdfmapline(def_ref);
- delete_token_ref(def_ref);
- } else if (scan_keyword("includechars")) {
- pdf_include_chars(static_pdf);
- } else if (scan_keyword("info")) {
- scan_toks(false, true);
- pdf_info_toks = concat_tokens(pdf_info_toks, def_ref);
- } else if (scan_keyword("names")) {
- scan_toks(false, true);
- pdf_names_toks = concat_tokens(pdf_names_toks, def_ref);
- } else if (scan_keyword("trailer")) {
- scan_toks(false, true);
- pdf_trailer_toks = concat_tokens(pdf_trailer_toks, def_ref);
- } else {
- tex_error("unexpected use of \\pdfextension",null);
- }
-}
-
-static void do_resource_dvi(int immediate, int code)
-{
-}
-
-static void do_resource_pdf(int immediate, int code)
-{
- switch (code) {
- case use_box_resource_code:
- scan_pdfrefxform(static_pdf);
- break;
- case use_image_resource_code:
- scan_pdfrefximage(static_pdf);
- break;
- case save_box_resource_code:
- scan_pdfxform(static_pdf);
- if (immediate) {
- pdf_cur_form = last_saved_box_index;
- ship_out(static_pdf, obj_xform_box(static_pdf, last_saved_box_index), SHIPPING_FORM);
- }
- break;
- case save_image_resource_code:
- scan_pdfximage(static_pdf);
- if (immediate) {
- pdf_write_image(static_pdf, last_saved_image_index);
- }
- break;
- }
-}
-
-/*
-
- Ad immediate:
-
- To write a token list, we must run it through \TeX's scanner, expanding
- macros and \.{\\the} and \.{\\number}, etc. This might cause runaways,
- if a delimited macro parameter isn't matched, and runaways would be
- extremely confusing since we are calling on \TeX's scanner in the middle
- of a \.{\\shipout} command. Therefore we will put a dummy control sequence as
- a ``stopper,'' right after the token list. This control sequence is
- artificially defined to be \.{\\outer}.
-
- The presence of `\.{\\immediate}' causes the |do_extension| procedure
- to descend to one level of recursion. Nothing happens unless \.{\\immediate}
- is followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'.
-
-*/
-
-/* extensions are backend related */
-
-@ The next subroutine uses |cur_chr| to decide what sort of whatsit is
-involved, and also inserts a |write_stream| number.
-
-@c
-static void new_write_whatsit(int w, int check)
-{
- new_whatsit(cur_chr);
- if (check) {
- /* so we check with open and close */
- scan_limited_int(last_file_selector,NULL);
- } else {
- /* but we're tolerant with the rest */
- scan_int();
- if (cur_val < 0)
- cur_val = term_only;
- else if (cur_val > last_file_selector) {
- cur_val = term_and_log;
- }
- }
- write_stream(tail) = cur_val;
-}
-
-void do_extension(int immediate)
-{
- halfword p; /* all-purpose pointer */
- if (cur_cmd == extension_cmd) {
- /* these have their own range starting at 0 */
- switch (cur_chr) {
- case open_code:
- p = tail;
- new_write_whatsit(open_node_size,1);
- scan_optional_equals();
- scan_file_name();
- open_name(tail) = cur_name;
- open_area(tail) = cur_area;
- open_ext(tail) = cur_ext;
- if (immediate) {
- out_what(static_pdf, tail);
- flush_node_list(tail);
- tail = p;
- vlink(p) = null;
- }
- break;
- case write_code:
- /*
- When `\.{\\write 12\{...\}}' appears, we scan the token list `\.{\{...\}}'
- without expanding its macros; the macros will be expanded later when this
- token list is rescanned.
- */
- p = tail;
- new_write_whatsit(write_node_size,0);
- cur_cs = write_stream(tail);
- scan_toks(false, false);
- write_tokens(tail) = def_ref;
- if (immediate) {
- out_what(static_pdf, tail);
- flush_node_list(tail);
- tail = p;
- vlink(p) = null;
- }
- break;
- case close_code:
- p = tail;
- new_write_whatsit(close_node_size,1);
- write_tokens(tail) = null;
- if (immediate) {
- out_what(static_pdf, tail);
- flush_node_list(tail);
- tail = p;
- vlink(p) = null;
- }
- break;
- case special_code:
- /*
- When `\.{\\special\{...\}}' appears, we expand the macros in the token
- list as in \.{\\xdef} and \.{\\mark}.
- */
- new_whatsit(special_node);
- write_stream(tail) = null;
- p = scan_toks(false, true);
- write_tokens(tail) = def_ref;
- break;
- case immediate_code:
- get_x_token();
- do_extension(1);
- break;
- case use_box_resource_code:
- case use_image_resource_code:
- case save_box_resource_code:
- case save_image_resource_code:
- switch (get_o_mode()) {
- case OMODE_DVI:
- do_resource_dvi(immediate,cur_chr);
- break;
- case OMODE_PDF:
- do_resource_pdf(immediate,cur_chr);
- break;
- default:
- break;
- }
- break;
- /* backend extensions have their own range starting at 32 */
- case dvi_extension_code:
- if (get_o_mode() == OMODE_DVI)
- do_extension_dvi(immediate);
- break;
- case pdf_extension_code:
- if (get_o_mode() == OMODE_PDF)
- do_extension_pdf(immediate);
- break;
- /* done */
- default:
- if (immediate) {
- back_input();
- } else {
- confusion("invalid extension");
- }
- break;
- }
- } else {
- /* no extension command, quite certainly following \immediate */
- back_input();
- }
-}
-
-@ Here is a subroutine that creates a whatsit node having a given |subtype|
-and a given number of words. It initializes only the first word of the whatsit,
-and appends it to the current list.
-
-@c
-void new_whatsit(int s)
-{
- halfword p = new_node(whatsit_node, s);
- couple_nodes(tail, p);
- tail = p;
-}
-
-@ The final line of this routine is slightly subtle; at least, the author
-didn't think about it until getting burnt! There is a used-up token list
-@^Knuth, Donald Ervin@>
-on the stack, namely the one that contained |end_write_token|. (We
-insert this artificial `\.{\\endwrite}' to prevent runaways, as explained
-above.) If it were not removed, and if there were numerous writes on a
-single page, the stack would overflow.
-
-@c
-void expand_macros_in_tokenlist(halfword p)
-{
- int old_mode;
- pointer q = get_avail();
- pointer r = get_avail();
- token_info(q) = right_brace_token + '}';
- token_link(q) = r;
- token_info(r) = end_write_token;
- begin_token_list(q, inserted);
- begin_token_list(write_tokens(p), write_text);
- q = get_avail();
- token_info(q) = left_brace_token + '{';
- begin_token_list(q, inserted);
- /* now we're ready to scan
- `\.\{$\langle\,$token list$\,\rangle$\.{\} \\endwrite}' */
- old_mode = mode;
- mode = 0;
- /* disable \.{\\prevdepth}, \.{\\spacefactor}, \.{\\lastskip}, \.{\\prevgraf} */
- cur_cs = write_loc;
- q = scan_toks(false, true); /* expand macros, etc. */
- get_token();
- if (cur_tok != end_write_token) {
- /* Recover from an unbalanced write command */
- const char *hlp[] = {
- "On this page there's a \\write with fewer real {'s than }'s.",
- "I can't handle that very well; good luck.", NULL
- };
- tex_error("Unbalanced write command", hlp);
- do {
- get_token();
- } while (cur_tok != end_write_token);
- }
- mode = old_mode;
- end_token_list(); /* conserve stack space */
-}
-
-void write_out(halfword p)
-{
- int old_setting; /* holds print |selector| */
- int j; /* write stream number */
- char *s, *ss; /* line to be written, as a C string */
- int callback_id;
- int lua_retval;
- expand_macros_in_tokenlist(p);
- old_setting = selector;
- j = write_stream(p);
- if (file_can_be_written(j)) {
- selector = j;
- } else if ((j == term_only) && (selector == term_and_log)) {
- /* write to the terminal if file isn't open */
- selector = log_only;
- tprint_nl("");
- } else {
- tprint_nl("");
- }
- s = tokenlist_to_cstring(def_ref, false, NULL);
- if (selector < no_print) {
- /* selector is a file */
- callback_id = callback_defined(process_output_buffer_callback);
- if (callback_id > 0) {
- /* fix up the output buffer using callbacks */
- lua_retval = run_callback(callback_id, "S->S", s, &ss);
- if ((lua_retval == true) && (ss != NULL)) {
- xfree(s);
- s = ss;
- }
- }
- }
- tprint(s);
- xfree(s);
- print_ln();
- flush_list(def_ref);
- selector = old_setting;
-}
-
-void finalize_write_files(void) {
- int k;
- for (k = 0; k <= last_file_selector; k++) {
- if (write_open[k]) {
- lua_a_close_out(write_file[k]);
- }
- }
-}
-
-void initialize_write_files(void) {
- int k;
- for (k = 0; k <= last_file_selector; k++) {
- write_open[k] = false;
- }
-}
-
-void close_write_file(int id) {
- if (write_open[id]) {
- lua_a_close_out(write_file[id]);
- write_open[id] = false;
- }
-}
-
-boolean open_write_file(int id, char *fn) {
- if (lua_a_open_out(&(write_file[id]), fn, (id + 1))) {
- write_open[id] = true;
- return true;
- } else {
- return false;
- }
-}
-
-
-@ To implement primitives as \.{\\pdfextension info}, \.{\\pdfextension catalog} or
-\.{\\pdfextension names} we need to concatenate tokens lists.
-
-@c
-halfword concat_tokens(halfword q, halfword r)
-{ /* concat |q| and |r| and returns the result tokens list */
- halfword p;
- if (q == null)
- return r;
- p = q;
- while (token_link(p) != null)
- p = token_link(p);
- set_token_link(p, token_link(r));
- free_avail(r);
- return q;
-}
-
-@ The \eTeX\ features available in extended mode are grouped into two
-categories: (1)~Some of them are permanently enabled and have no
-semantic effect as long as none of the additional primitives are
-executed. (2)~The remaining \eTeX\ features are optional and can be
-individually enabled and disabled. For each optional feature there is
-an \eTeX\ state variable named \.{\\...state}; the feature is enabled,
-resp.\ disabled by assigning a positive, resp.\ non-positive value to
-that integer.
-
-@ In order to handle \.{\\everyeof} we need an array |eof_seen| of
-boolean variables.
-
-@c
-boolean *eof_seen; /* has eof been seen? */
-
-@ The |print_group| procedure prints the current level of grouping and
-the name corresponding to |cur_group|.
-
-@c
-void print_group(boolean e)
-{
- switch (cur_group) {
- case bottom_level:
- tprint("bottom level");
- return;
- break;
- case simple_group:
- case semi_simple_group:
- if (cur_group == semi_simple_group)
- tprint("semi ");
- tprint("simple");
- break;;
- case hbox_group:
- case adjusted_hbox_group:
- if (cur_group == adjusted_hbox_group)
- tprint("adjusted ");
- tprint("hbox");
- break;
- case vbox_group:
- tprint("vbox");
- break;
- case vtop_group:
- tprint("vtop");
- break;
- case align_group:
- case no_align_group:
- if (cur_group == no_align_group)
- tprint("no ");
- tprint("align");
- break;
- case output_group:
- tprint("output");
- break;
- case disc_group:
- tprint("disc");
- break;
- case insert_group:
- tprint("insert");
- break;
- case vcenter_group:
- tprint("vcenter");
- break;
- case math_group:
- case math_choice_group:
- case math_shift_group:
- case math_left_group:
- tprint("math");
- if (cur_group == math_choice_group)
- tprint(" choice");
- else if (cur_group == math_shift_group)
- tprint(" shift");
- else if (cur_group == math_left_group)
- tprint(" left");
- break;
- } /* there are no other cases */
- tprint(" group (level ");
- print_int(cur_level);
- print_char(')');
- if (saved_value(-1) != 0) { /* |saved_line| */
- if (e)
- tprint(" entered at line ");
- else
- tprint(" at line ");
- print_int(saved_value(-1)); /* |saved_line| */
- }
-}
-
-@ The |group_trace| procedure is called when a new level of grouping
-begins (|e=false|) or ends (|e=true|) with |saved_value(-1)| containing the
-line number.
-
-@c
-void group_trace(boolean e)
-{
- begin_diagnostic();
- print_char('{');
- if (e)
- tprint("leaving ");
- else
- tprint("entering ");
- print_group(e);
- print_char('}');
- end_diagnostic(false);
-}
-
-@ A group entered (or a conditional started) in one file may end in a
-different file. Such slight anomalies, although perfectly legitimate,
-may cause errors that are difficult to locate. In order to be able to
-give a warning message when such anomalies occur, \eTeX\ uses the
-|grp_stack| and |if_stack| arrays to record the initial |cur_boundary|
-and |cond_ptr| values for each input file.
-
-@c
-save_pointer *grp_stack; /* initial |cur_boundary| */
-halfword *if_stack; /* initial |cond_ptr| */
-
-@ When a group ends that was apparently entered in a different input
-file, the |group_warning| procedure is invoked in order to update the
-|grp_stack|. If moreover \.{\\tracingnesting} is positive we want to
-give a warning message. The situation is, however, somewhat complicated
-by two facts: (1)~There may be |grp_stack| elements without a
-corresponding \.{\\input} file or \.{\\scantokens} pseudo file (e.g.,
-error insertions from the terminal); and (2)~the relevant information is
-recorded in the |name_field| of the |input_stack| only loosely
-synchronized with the |in_open| variable indexing |grp_stack|.
-
-@c
-void group_warning(void)
-{
- boolean w = false; /* do we need a warning? */
- int i = in_open; /* index into |grp_stack| */
- base_ptr = input_ptr;
- input_stack[base_ptr] = cur_input; /* store current state */
- while ((grp_stack[i] == cur_boundary) && (i > 0)) {
- /* Set variable |w| to indicate if this case should be reported */
- /* This code scans the input stack in order to determine the type of the
- current input file. */
- if (tracing_nesting_par > 0) {
- while ((input_stack[base_ptr].state_field == token_list) ||
- (input_stack[base_ptr].index_field > i))
- decr(base_ptr);
- if (input_stack[base_ptr].name_field > 17)
- w = true;
- }
-
- grp_stack[i] = save_value(save_ptr);
- decr(i);
- }
- if (w) {
- tprint_nl("Warning: end of ");
- print_group(true);
- tprint(" of a different file");
- print_ln();
- if (tracing_nesting_par > 1)
- show_context();
- if (history == spotless)
- history = warning_issued;
- }
-}
-
-@ When a conditional ends that was apparently started in a different
-input file, the |if_warning| procedure is invoked in order to update the
-|if_stack|. If moreover \.{\\tracingnesting} is positive we want to
-give a warning message (with the same complications as above).
-
-@c
-void if_warning(void)
-{
- boolean w = false; /* do we need a warning? */
- int i = in_open;
- base_ptr = input_ptr;
- input_stack[base_ptr] = cur_input; /* store current state */
- while (if_stack[i] == cond_ptr) {
- /* Set variable |w| to... */
- if (tracing_nesting_par > 0) {
- while ((input_stack[base_ptr].state_field == token_list) ||
- (input_stack[base_ptr].index_field > i))
- decr(base_ptr);
- if (input_stack[base_ptr].name_field > 17)
- w = true;
- }
-
- if_stack[i] = vlink(cond_ptr);
- decr(i);
- }
- if (w) {
- tprint_nl("Warning: end of ");
- print_cmd_chr(if_test_cmd, cur_if);
- print_if_line(if_line);
- tprint(" of a different file");
- print_ln();
- if (tracing_nesting_par > 1)
- show_context();
- if (history == spotless)
- history = warning_issued;
- }
-}
-
-
-@ Conversely, the |file_warning| procedure is invoked when a file ends
-and some groups entered or conditionals started while reading from that
-file are still incomplete.
-
-@c
-void file_warning(void)
-{
- halfword p = save_ptr; /* saved value of |save_ptr| or |cond_ptr| */
- int l = cur_level; /* saved value of |cur_level| or |if_limit| */
- int c = cur_group; /* saved value of |cur_group| or |cur_if| */
- int i; /* saved value of |if_line| */
- save_ptr = cur_boundary;
- while (grp_stack[in_open] != save_ptr) {
- decr(cur_level);
- tprint_nl("Warning: end of file when ");
- print_group(true);
- tprint(" is incomplete");
- cur_group = save_level(save_ptr);
- save_ptr = save_value(save_ptr);
- }
- save_ptr = p;
- cur_level = (quarterword) l;
- cur_group = (group_code) c; /* restore old values */
- p = cond_ptr;
- l = if_limit;
- c = cur_if;
- i = if_line;
- while (if_stack[in_open] != cond_ptr) {
- tprint_nl("Warning: end of file when ");
- print_cmd_chr(if_test_cmd, cur_if);
- if (if_limit == fi_code)
- tprint_esc("else");
- print_if_line(if_line);
- tprint(" is incomplete");
- if_line = if_line_field(cond_ptr);
- cur_if = if_limit_subtype(cond_ptr);
- if_limit = if_limit_type(cond_ptr);
- cond_ptr = vlink(cond_ptr);
- }
- cond_ptr = p;
- if_limit = l;
- cur_if = c;
- if_line = i; /* restore old values */
- print_ln();
- if (tracing_nesting_par > 1)
- show_context();
- if (history == spotless)
- history = warning_issued;
-}
-
-@ @c
-halfword last_line_fill; /* the |par_fill_skip| glue node of the new paragraph */
-
-@ The lua interface needs some extra functions. The functions
-themselves are quite boring, but they are handy because otherwise this
-internal stuff has to be accessed from C directly, where lots of the
-defines are not available.
-
-@c
-#define get_tex_dimen_register(j) dimen(j)
-#define get_tex_skip_register(j) skip(j)
-#define get_tex_mu_skip_register(j) mu_skip(j)
-#define get_tex_count_register(j) count(j)
-#define get_tex_attribute_register(j) attribute(j)
-#define get_tex_box_register(j) box(j)
-
-/* these can now be macros (todo) */
-
-int get_tex_extension_count_register(int i)
-{
- return (int) int_par(backend_int_base-int_base+i);
-}
-
-void set_tex_extension_count_register(int i, int d)
-{
- int_par(backend_int_base-int_base+i) = d;
-}
-
-int get_tex_extension_dimen_register(int i)
-{
- return (int) dimen_par(backend_dimen_base-dimen_base+i);
-}
-
-void set_tex_extension_dimen_register(int i, int d)
-{
- dimen_par(backend_dimen_base-dimen_base+i) = d;
-}
-
-int get_tex_extension_toks_register(int i)
-{
- return equiv(backend_toks_base+i);
-}
-
-int set_tex_dimen_register(int j, scaled v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- word_define(j + scaled_base, v);
- return 0;
-}
-
-int set_tex_skip_register(int j, halfword v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- if (type(v) != glue_spec_node)
- return 1;
- word_define(j + skip_base, v);
- return 0;
-}
-
-int set_tex_mu_skip_register(int j, halfword v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- if (type(v) != glue_spec_node)
- return 1;
- word_define(j + mu_skip_base, v);
- return 0;
-}
-
-int set_tex_count_register(int j, scaled v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- word_define(j + count_base, v);
- return 0;
-}
-
-int set_tex_box_register(int j, scaled v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- define(j + box_base, box_ref_cmd, v);
- return 0;
-}
-
-int set_tex_attribute_register(int j, scaled v)
-{
- int a; /* return non-nil for error */
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- if (j > max_used_attr)
- max_used_attr = j;
- attr_list_cache = cache_disabled;
- word_define(j + attribute_base, v);
- return 0;
-}
-
-int get_tex_toks_register(int j)
-{
- str_number s = get_nullstr();
- if (toks(j) != null) {
- s = tokens_to_string(toks(j));
- }
- return s;
-}
-
-int set_tex_toks_register(int j, lstring s)
-{
- int a;
- halfword ref = get_avail();
- (void) str_toks(s);
- set_token_ref_count(ref, 0);
- set_token_link(ref, token_link(temp_token_head));
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- define(j + toks_base, call_cmd, ref);
- return 0;
-}
-
-int scan_tex_toks_register(int j, int c, lstring s)
-{
- int a;
- halfword ref = get_avail();
- (void) str_scan_toks(c,s);
- set_token_ref_count(ref, 0);
- set_token_link(ref, token_link(temp_token_head));
- if (global_defs_par > 0)
- a = 4;
- else
- a = 0;
- define(j + toks_base, call_cmd, ref);
- return 0;
-}
-
-scaled get_tex_box_width(int j)
-{
- halfword q = box(j);
- if (q != null)
- return width(q);
- return 0;
-}
-
-int set_tex_box_width(int j, scaled v)
-{
- halfword q = box(j);
- if (q == null)
- return 1;
- width(q) = v;
- return 0;
-}
-
-scaled get_tex_box_height(int j)
-{
- halfword q = box(j);
- if (q != null)
- return height(q);
- return 0;
-}
-
-int set_tex_box_height(int j, scaled v)
-{
- halfword q = box(j);
- if (q == null)
- return 1;
- height(q) = v;
- return 0;
-}
-
-scaled get_tex_box_depth(int j)
-{
- halfword q = box(j);
- if (q != null)
- return depth(q);
- return 0;
-}
-
-int set_tex_box_depth(int j, scaled v)
-{
- halfword q = box(j);
- if (q == null)
- return 1;
- depth(q) = v;
- return 0;
-}
-
-@ This section is devoted to the {\sl Synchronize \TeX nology}
-- or simply {\sl Sync\TeX} - used to synchronize between input and output.
-This section explains how synchronization basics are implemented.
-Before we enter into more technical details,
-let us recall in a few words what is synchronization.
-
-\TeX\ typesetting system clearly separates the input and the output material,
-and synchronization will provide a new link between both that can help
-text editors and viewers to work together.
-More precisely, forwards synchronization is the ability,
-given a location in the input source file,
-to find what is the corresponding place in the output.
-Backwards synchronization just performs the opposite:
-given a location in the output,
-retrieve the corresponding material in the input source file.
-
-For better code management and maintainance, we adopt a naming convention.
-Throughout this program, code related to the {\sl Synchronize \TeX nology} is tagged
-with the ``{\sl synctex}'' key word. Any code extract where {\sl Sync\TeX} plays
-its part, either explicitly or implicitly, (should) contain the string ``{\sl synctex}''.
-This naming convention also holds for external files.
-Moreover, all the code related to {\sl Sync\TeX} is gathered in this section,
-except the definitions.
-
-Enabling synchronization should be performed from the command line,
-|synctexoption| is used for that purpose.
-This global integer variable is declared here but it is not used here.
-This is just a placeholder where the command line controller will put
-the {\sl Sync\TeX} related options, and the {\sl Sync\TeX} controller will read them.
-
-@c
-int synctexoption;
-
-@ A convenient primitive is provided:
-\.{\\synctex=1} in the input source file enables synchronization whereas
-\.{\\synctex=0} disables it.
-Its memory address is |synctex_code|.
-It is initialized by the {\sl Sync\TeX} controller to the command-line option if given.
-The controller may filter some reserved bits.
-
-In order to give the {\sl Sync\TeX} controller read and write access to
-the contents of the \.{\\synctex} primitive, we declare |synctexoffset|,
-such that |mem[synctexoffset]| and \.{\\synctex} correspond to
-the same memory storage. |synctexoffset| is initialized to
-the correct value when quite everything is initialized.
-
-@c
-int synctexoffset; /* holds the true value of |synctex_code| */
-
-@ Synchronization is achieved with the help of an auxiliary file named
-`\.{{\sl jobname}.synctex}' ({\sl jobname} is the contents of the
-\.{\\jobname} macro), where a {\sl Sync\TeX} controller implemented
-in the external |synctex.c| file will store geometrical information.
-This {\sl Sync\TeX} controller will take care of every technical details
-concerning the {\sl Sync\TeX} file, we will only focus on the messages
-the controller will receive from the \TeX\ program.
-
-The most accurate synchronization information should allow to map
-any character of the input source file to the corresponding location
-in the output, if relevant.
-Ideally, the synchronization information of the input material consists of
-the file name, the line and column numbers of every character.
-The synchronization information in the output is simply the page number and
-either point coordinates, or box dimensions and position.
-The problem is that the mapping between these informations is only known at
-ship out time, which means that we must keep track of the input
-synchronization information until the pages ship out.
-
-As \TeX\ only knows about file names and line numbers,
-but forgets the column numbers, we only consider a
-restricted input synchronization information called {\sl Sync\TeX\ information}.
-It consists of a unique file name identifier, the {\sl Sync\TeX\ file tag},
-and the line number.
-
-Keeping track of such information,
-should be different whether characters or nodes are involved.
-Actually, only certain nodes are involved in {\sl Sync\TeX},
-we call them {\sl synchronized nodes}.
-Synchronized nodes store the {\sl Sync\TeX} information in their last two words:
-the first one contains a {\sl Sync\TeX\ file tag} uniquely identifying
-the input file, and the second one contains the current line number,
-as returned by the \.{\\inputlineno} primitive.
-The |synctex_field_size| macro contains the necessary size to store
-the {\sl Sync\TeX} information in a node.
-
-When declaring the size of a new node, it is recommanded to use the following
-convention: if the node is synchronized, use a definition similar to
-|my_synchronized_node_size|={\sl xxx}+|synctex_field_size|.
-Moreover, one should expect that the {\sl Sync\TeX} information is always stored
-in the last two words of a synchronized node.
-
-By default, every node with a sufficiently big size is initialized
-at creation time in the |get_node| routine with the current
-{\sl Sync\TeX} information, whether or not the node is synchronized.
-One purpose is to set this information very early in order to minimize code
-dependencies, including forthcoming extensions.
-Another purpose is to avoid the assumption that every node type has a dedicated getter,
-where initialization should take place. Actually, it appears that some nodes are created
-using directly the |get_node| routine and not the dedicated constructor.
-And finally, initializing the node at only one place is less error prone.
-
-Instead of storing the input file name, it is better to store just an identifier.
-Each time \TeX\ opens a new file, it notifies the {\sl Sync\TeX} controller with
-a |synctex_start_input| message.
-This controller will create a new {\sl Sync\TeX} file tag and
-will update the current input state record accordingly.
-If the input comes from the terminal or a pseudo file, the |synctex_tag| is set to 0.
-It results in automatically disabling synchronization for material
-input from the terminal or pseudo files.
-
-Synchronized nodes are boxes, math, kern and glue nodes.
-Other nodes should be synchronized too, in particular math noads.
-\TeX\ assumes that math, kern and glue nodes have the same size,
-this is why both are synchronized.
-{\sl In fine}, only horizontal lists are really used in {\sl Sync\TeX},
-but all box nodes are considered the same with respect to synchronization,
-because a box node type is allowed to change at execution time.
-
-{\sl Nota Bene:}
-The {\sl Sync\TeX} code is very close to the memory model.
-It is not connected to any other part of the code,
-except for memory management. It is possible to neutralize the {\sl Sync\TeX} code
-rather simply. The first step is to define a null |synctex_field_size|.
-The second step is to comment out the code in ``Initialize bigger nodes...'' and every
-``Copy ... {\sl Sync\TeX} information''.
-The last step will be to comment out the |synctex_tag_field| related code in the
-definition of |synctex_tag| and the various ``Prepare ... {\sl Sync\TeX} information''.
-Then all the remaining code should be just harmless.
-The resulting program would behave exactly the same as if absolutely no {\sl Sync\TeX}
-related code was there, including memory management.
-Of course, all this assumes that {\sl Sync\TeX} is turned off from the command line.
-@^synctex@>
-@^synchronization@>
-
-@ Here are extra variables for Web2c. (This numbering of the
-system-dependent section allows easy integration of Web2c and e-\TeX, etc.)
-@^<system dependencies@>
-
-@c
-pool_pointer edit_name_start; /* where the filename to switch to starts */
-int edit_name_length, edit_line; /* what line to start editing at */
-boolean stop_at_space; /* whether |more_name| returns false for space */
-
-@ The |edit_name_start| will be set to point into |str_pool| somewhere after
-its beginning if \TeX\ is supposed to switch to an editor on exit.
-
-@c
-int shellenabledp;
-int restrictedshell;
-char *output_comment;
-
-@ Are we printing extra info as we read the format file?
-
-@c
-boolean debug_format_file;
diff --git a/Build/source/texk/web2c/luatexdir/tex/filename.w b/Build/source/texk/web2c/luatexdir/tex/filename.c
index 9e5d9c5cc1c..fdc6641efca 100644
--- a/Build/source/texk/web2c/luatexdir/tex/filename.w
+++ b/Build/source/texk/web2c/luatexdir/tex/filename.c
@@ -1,59 +1,62 @@
-% filename.w
-%
-% Copyright 2009-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
+/*
+filename.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ In order to isolate the system-dependent aspects of file names, the
- @^system dependencies@>
- system-independent parts of \TeX\ are expressed in terms
- of three system-dependent
- procedures called |begin_name|, |more_name|, and |end_name|. In
- essence, if the user-specified characters of the file name are $c_1\ldots c_n$,
- the system-independent driver program does the operations
- $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
- \,|end_name|.$$
- These three procedures communicate with each other via global variables.
- Afterwards the file name will appear in the string pool as three strings
- called |cur_name|\penalty10000\hskip-.05em,
- |cur_area|, and |cur_ext|; the latter two are null (i.e.,
- |""|), unless they were explicitly specified by the user.
-
- Actually the situation is slightly more complicated, because \TeX\ needs
- to know when the file name ends. The |more_name| routine is a function
- (with side effects) that returns |true| on the calls |more_name|$(c_1)$,
- \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$
- returns |false|; or, it returns |true| and the token following $c_n$ is
- something like `\.{\\hbox}' (i.e., not a character). In other words,
- |more_name| is supposed to return |true| unless it is sure that the
- file name has been completely scanned; and |end_name| is supposed to be able
- to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of
- whether $|more_name|(c_n)$ returned |true| or |false|.
-
-
-@ Here now is the first of the system-dependent routines for file name scanning.
-@^system dependencies@>
-
-@c
+/*tex
+
+ In order to isolate the system-dependent aspects of file names, the @^system
+ dependencies@> system-independent parts of \TeX\ are expressed in terms of
+ three system-dependent procedures called |begin_name|, |more_name|, and
+ |end_name|. In essence, if the user-specified characters of the file name are
+ $c_1\ldots c_n$, the system-independent driver program does the operations
+ $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n);
+ \,|end_name|.$$
+
+ These three procedures communicate with each other via global variables.
+ Afterwards the file name will appear in the string pool as three strings
+ called |cur_name|\penalty10000\hskip-.05em, |cur_area|, and |cur_ext|; the
+ latter two are null (i.e., |""|), unless they were explicitly specified by
+ the user.
+
+ Actually the situation is slightly more complicated, because \TeX\ needs to
+ know when the file name ends. The |more_name| routine is a function (with
+ side effects) that returns |true| on the calls |more_name|$(c_1)$, \dots,
+ |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$ returns |false|;
+ or, it returns |true| and the token following $c_n$ is something like
+ `\.{\\hbox}' (i.e., not a character). In other words, |more_name| is supposed
+ to return |true| unless it is sure that the file name has been completely
+ scanned; and |end_name| is supposed to be able to finish the assembly of
+ |cur_name|, |cur_area|, and |cur_ext| regardless of whether
+ $|more_name|(c_n)$ returned |true| or |false|.
+
+
+ Here now is the first of the system-dependent routines for file name
+ scanning. @^system dependencies@>
+
+*/
+
static void begin_name(void)
{
area_delimiter = 0;
@@ -61,13 +64,16 @@ static void begin_name(void)
quoted_filename = false;
}
-@ And here's the second. The string pool might change as the file name is
- being scanned, since a new \.{\\csname} might be entered; therefore we keep
- |area_delimiter| and |ext_delimiter| relative to the beginning of the current
- string, instead of assigning an absolute address like |pool_ptr| to them.
- @^system dependencies@>
+/*tex
+
+ And here's the second. The string pool might change as the file name is being
+ scanned, since a new \.{\\csname} might be entered; therefore we keep
+ |area_delimiter| and |ext_delimiter| relative to the beginning of the current
+ string, instead of assigning an absolute address like |pool_ptr| to them.
+ @^system dependencies@>
+
+*/
-@c
static boolean more_name(ASCII_code c)
{
if (c == ' ' && stop_at_space && (!quoted_filename)) {
@@ -77,7 +83,7 @@ static boolean more_name(ASCII_code c)
return true;
} else {
str_room(1);
- append_char(c); /* contribute |c| to the current string */
+ append_char(c);
if (IS_DIR_SEP(c)) {
area_delimiter = (pool_pointer) cur_length;
ext_delimiter = 0;
@@ -87,17 +93,21 @@ static boolean more_name(ASCII_code c)
}
}
-@ The third.
-@^system dependencies@>
+/*tex
+
+ The third. @^system dependencies@>
+
+*/
-@c
static void end_name(void)
{
unsigned char *s;
if (str_ptr + 3 > (max_strings + STRING_OFFSET))
- overflow("number of strings",
- (unsigned) (max_strings - init_str_ptr + STRING_OFFSET));
- /* at this point, the full string lives in |cur_string| */
+ overflow(
+ "number of strings",
+ (unsigned) (max_strings - init_str_ptr + STRING_OFFSET)
+ );
+ /*tex At this point, the full string lives in |cur_string|. */
if (area_delimiter == 0) {
cur_area = get_nullstr();
} else {
@@ -105,7 +115,7 @@ static void end_name(void)
cur_string[area_delimiter] = '\0';
cur_length = (unsigned) strlen((char *) cur_string);
cur_area = make_string();
- xfree(cur_string);
+ xfree(cur_string);
cur_length = (unsigned) strlen((char *) s);
cur_string = s;
}
@@ -118,24 +128,27 @@ static void end_name(void)
cur_string[l] = '\0';
cur_length = (unsigned) strlen((char *) cur_string);
cur_name = make_string();
- xfree(cur_string);
+ xfree(cur_string);
cur_length = (unsigned) strlen((char *) s);
cur_string = s;
cur_ext = make_string();
}
}
-@ Now let's consider the ``driver'' routines by which \TeX\ deals with file names
- in a system-independent manner. First comes a procedure that looks for a
+/*tex
+
+ Now let's consider the ``driver'' routines by which \TeX\ deals with file
+ names in a system-independent manner. First comes a procedure that looks for a
file name in the input by calling |get_x_token| for the information.
-@c
+*/
+
void scan_file_name(void)
{
str_number u = 0;
name_in_progress = true;
begin_name();
- /* Get the next non-blank non-call token; */
+ /*tex Get the next non-blank non-call token: */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -145,9 +158,11 @@ void scan_file_name(void)
back_input();
break;
}
- /* If |cur_chr| is a space and we're not scanning a token list, check
- whether we're at the end of the buffer. Otherwise we end up adding
- spurious spaces to file names in some cases. */
+ /*tex
+ If |cur_chr| is a space and we're not scanning a token list, check
+ whether we're at the end of the buffer. Otherwise we end up adding
+ spurious spaces to file names in some cases.
+ */
if ((cur_chr == ' ') && (istate != token_list) && (iloc > ilimit)
&& !quoted_filename)
break;
@@ -174,8 +189,10 @@ void scan_file_name(void)
name_in_progress = false;
}
-@ This function constructs a the three file name strings from a token list
-@c
+/*
+ This function constructs a the three file name strings from a token list.
+*/
+
void scan_file_name_toks(void)
{
char *a, *n, *e, *s = NULL;
@@ -192,12 +209,14 @@ void scan_file_name_toks(void)
e = s + i;
}
}
- if (n != s) { /* explicit area */
+ if (n != s) {
+ /*tex explicit area */
cur_area = maketexlstring(a, (size_t) (n - a));
} else {
cur_area = get_nullstr();
}
- if (e != NULL) { /* explicit extension */
+ if (e != NULL) {
+ /*tex explicit extension */
cur_name = maketexlstring(n, (size_t) (e - n));
cur_ext = maketexstring(e);
} else {
@@ -205,33 +224,34 @@ void scan_file_name_toks(void)
cur_ext = get_nullstr();
}
xfree(s);
-
-}
-
+}
+/*tex
-@ Here is a routine that manufactures the output file names, assuming that
- |job_name<>0|. It ignores and changes the current settings of |cur_area|
- and |cur_ext|.
+ Here is a routine that manufactures the output file names, assuming that
+ |job_name<>0|. It ignores and changes the current settings of |cur_area| and
+ |cur_ext|; |s = ".log"|, |".dvi"|, or |format_extension|
+*/
-@c
char *pack_job_name(const char *s)
-{ /* |s = ".log"|, |".dvi"|, or |format_extension| */
+{
cur_area = get_nullstr();
cur_ext = maketexstring(s);
cur_name = job_name;
return pack_file_name(cur_name, cur_area, cur_ext);
}
-@ If some trouble arises when \TeX\ tries to open a file, the following
- routine calls upon the user to supply another file name. Parameter~|s|
- is used in the error message to identify the type of file; parameter~|e|
- is the default extension if none is given. Upon exit from the routine,
- variables |cur_name|, |cur_area|, and |cur_ext| are
- ready for another attempt at file opening.
+/*tex
+
+ If some trouble arises when \TeX\ tries to open a file, the following routine
+ calls upon the user to supply another file name. Parameter~|s| is used in the
+ error message to identify the type of file; parameter~|e| is the default
+ extension if none is given. Upon exit from the routine, variables |cur_name|,
+ |cur_area|, and |cur_ext| are ready for another attempt at file opening.
+
+*/
-@c
char *prompt_file_name(const char *s, const char *e)
{
int k; /* index into |buffer| */
@@ -290,12 +310,10 @@ char *prompt_file_name(const char *s, const char *e)
return pack_file_name(cur_name, cur_area, cur_ext);
}
-
-@ @c
void tprint_file_name(unsigned char *n, unsigned char *a, unsigned char *e)
{
- boolean must_quote; /* whether to quote the filename */
- unsigned char *j; /* index into string */
+ boolean must_quote; /* whether to quote the filename */
+ unsigned char *j; /* index into string */
must_quote = false;
if (a != NULL) {
j = a;
@@ -318,13 +336,11 @@ void tprint_file_name(unsigned char *n, unsigned char *a, unsigned char *e)
j++;
}
}
- /* FIXME: Alternative is to assume that any filename that has to be quoted has
- at least one quoted component...if we pick this, a number of insertions
- of |print_file_name| should go away.
- |must_quote|:=((|a|<>0)and(|str_pool|[|str_start|[|a|]]=""""))or
- ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or
- ((|e|<>0)and(|str_pool|[|str_start|[|e|]]="""")); */
-
+ /*tex
+ Alternative is to assume that any filename that has to be quoted has at
+ least one quoted component...if we pick this, a number of insertions of
+ |print_file_name| should go away.
+ */
if (must_quote)
print_char('"');
if (a != NULL) {
@@ -346,15 +362,17 @@ void tprint_file_name(unsigned char *n, unsigned char *a, unsigned char *e)
print_char('"');
}
-@ @c
void print_file_name(str_number n, str_number a, str_number e)
{
char *nam, *are, *ext;
nam = makecstring(n);
are = makecstring(a);
ext = makecstring(e);
- tprint_file_name((unsigned char *) nam, (unsigned char *) are,
- (unsigned char *) ext);
+ tprint_file_name(
+ (unsigned char *) nam,
+ (unsigned char *) are,
+ (unsigned char *) ext
+ );
free(nam);
free(are);
free(ext);
diff --git a/Build/source/texk/web2c/luatexdir/tex/inputstack.w b/Build/source/texk/web2c/luatexdir/tex/inputstack.c
index 68b22e1a334..c64111edc89 100644
--- a/Build/source/texk/web2c/luatexdir/tex/inputstack.w
+++ b/Build/source/texk/web2c/luatexdir/tex/inputstack.c
@@ -1,51 +1,85 @@
-% inputstack.w
-%
-% Copyright 2009-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
+/*
+
+inputstack.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ @c
in_state_record *input_stack = NULL;
-int input_ptr = 0; /* first unused location of |input_stack| */
-int max_in_stack = 0; /* largest value of |input_ptr| when pushing */
-in_state_record cur_input; /* the ``top'' input state */
-int in_open = 0; /* the number of lines in the buffer, less one */
-int open_parens = 0; /* the number of open text files */
+/*tex First unused location of |input_stack|: */
+
+int input_ptr = 0;
+
+/*tex Largest value of |input_ptr| when pushing: */
+
+int max_in_stack = 0;
+
+/*tex The `top' input state: */
+
+in_state_record cur_input;
+
+/*tex The number of lines in the buffer, less one: */
+
+int in_open = 0;
+
+/*tex The number of open text files: */
+
+int open_parens = 0;
+
alpha_file *input_file = NULL;
-int line = 0; /* current line number in the current source file */
+
+/*tex The current line number in the current source file: */
+
+int line = 0;
+
int *line_stack = NULL;
+
str_number *source_filename_stack = NULL;
+
char **full_source_filename_stack = NULL;
-int scanner_status = 0; /* can a subfile end now? */
-pointer warning_index = null; /* identifier relevant to non-|normal| scanner status */
-pointer def_ref = null; /* reference count of token list being defined */
+/*tex Can a subfile end now? */
-@ Here is a procedure that uses |scanner_status| to print a warning message
-when a subfile has ended, and at certain other crucial times:
+int scanner_status = 0;
+
+/*tex Identifier relevant to non-|normal| scanner status: */
+
+pointer warning_index = null;
+
+/*tex Reference count of token list being defined: */
+
+pointer def_ref = null;
+
+/*tex
+
+Here is a procedure that uses |scanner_status| to print a warning message when a
+subfile has ended, and at certain other crucial times:
+
+*/
-@c
void runaway(void)
{
- pointer p = null; /* head of runaway list */
+ /*tex The head of the runaway list: */
+ pointer p = null;
if (scanner_status > skipping) {
switch (scanner_status) {
case defining:
@@ -65,7 +99,7 @@ void runaway(void)
p = def_ref;
break;
default:
- /* there are no other cases */
+ /*tex There are no other cases. */
break;
}
print_char('?');
@@ -74,48 +108,69 @@ void runaway(void)
}
}
-@ The |param_stack| is an auxiliary array used to hold pointers to the token
-lists for parameters at the current level and subsidiary levels of input.
-This stack is maintained with convention (2), and it grows at a different
-rate from the others.
-
-@c
-pointer *param_stack = NULL; /* token list pointers for parameters */
-int param_ptr = 0; /* first unused entry in |param_stack| */
-int max_param_stack = 0; /* largest value of |param_ptr|, will be |<=param_size+9| */
-
-@ The input routines must also interact with the processing of
-\.{\\halign} and \.{\\valign}, since the appearance of tab marks and
-\.{\\cr} in certain places is supposed to trigger the beginning of special
-$v_j$ template text in the scanner. This magic is accomplished by an
-|align_state| variable that is increased by~1 when a `\.{\char'173}' is
-scanned and decreased by~1 when a `\.{\char'175}' is scanned. The |align_state|
-is nonzero during the $u_j$ template, after which it is set to zero; the
-$v_j$ template begins when a tab mark or \.{\\cr} occurs at a time that
-|align_state=0|.
-
-@c
-int align_state = 0; /* group level with respect to current alignment */
-
-@ Thus, the ``current input state'' can be very complicated indeed; there
-can be many levels and each level can arise in a variety of ways. The
-|show_context| procedure, which is used by \TeX's error-reporting routine to
-print out the current input state on all levels down to the most recent
-line of characters from an input file, illustrates most of these conventions.
-The global variable |base_ptr| contains the lowest level that was
-displayed by this procedure.
-
-@c
-int base_ptr = 0; /* shallowest level shown by |show_context| */
-
-@ The status at each level is indicated by printing two lines, where the first
-line indicates what was read so far and the second line shows what remains
-to be read. The context is cropped, if necessary, so that the first line
-contains at most |half_error_line| characters, and the second contains
-at most |error_line|. Non-current input levels whose |token_type| is
-`|backed_up|' are shown only if they have not been fully read.
-
-@c
+/*tex
+
+The |param_stack| is an auxiliary array used to hold pointers to the token lists
+for parameters at the current level and subsidiary levels of input. This stack is
+maintained with convention (2), and it grows at a different rate from the others.
+
+*/
+
+/*tex Token list pointers for parameters: */
+
+pointer *param_stack = NULL;
+
+/*tex First unused entry in |param_stack|: */
+
+int param_ptr = 0;
+
+/*tex Largest value of |param_ptr|, will be |<=param_size+9|: */
+
+int max_param_stack = 0;
+
+/*tex
+
+The input routines must also interact with the processing of \.{\\halign} and
+\.{\\valign}, since the appearance of tab marks and \.{\\cr} in certain places is
+supposed to trigger the beginning of special $v_j$ template text in the scanner.
+This magic is accomplished by an |align_state| variable that is increased by~1
+when a `\.{\char'173}' is scanned and decreased by~1 when a `\.{\char'175}' is
+scanned. The |align_state| is nonzero during the $u_j$ template, after which it
+is set to zero; the $v_j$ template begins when a tab mark or \.{\\cr} occurs at a
+time that |align_state=0|.
+
+*/
+
+/*tex The group level with respect to current alignment: */
+
+int align_state = 0;
+
+/*tex
+
+Thus, the ``current input state'' can be very complicated indeed; there can be
+many levels and each level can arise in a variety of ways. The |show_context|
+procedure, which is used by \TeX's error-reporting routine to print out the
+current input state on all levels down to the most recent line of characters from
+an input file, illustrates most of these conventions. The global variable
+|base_ptr| contains the lowest level that was displayed by this procedure.
+
+*/
+
+/*tex The shallowest level shown by |show_context|: */
+
+int base_ptr = 0;
+
+/*tex
+
+The status at each level is indicated by printing two lines, where the first line
+indicates what was read so far and the second line shows what remains to be read.
+The context is cropped, if necessary, so that the first line contains at most
+|half_error_line| characters, and the second contains at most |error_line|.
+Non-current input levels whose |token_type| is `|backed_up|' are shown only if
+they have not been fully read.
+
+*/
+
static void print_token_list_type(int t)
{
switch (t) {
@@ -172,47 +227,49 @@ static void print_token_list_type(int t)
case write_text:
tprint_nl("<write> ");
break;
+ case local_text:
+ tprint_nl("<local> ");
+ break;
default:
tprint_nl("?");
- /* this should never happen */
+ /*tex This should never happen. */
break;
}
}
-@ Here it is necessary to explain a little trick. We don't want to store a long
-string that corresponds to a token list, because that string might take up
-lots of memory; and we are printing during a time when an error message is
-being given, so we dare not do anything that might overflow one of \TeX's
-tables. So `pseudoprinting' is the answer: We enter a mode of printing
-that stores characters into a buffer of length |error_line|, where character
-$k+1$ is placed into \hbox{|trick_buf[k mod error_line]|} if
-|k<trick_count|, otherwise character |k| is dropped. Initially we set
-|tally:=0| and |trick_count:=1000000|; then when we reach the
-point where transition from line 1 to line 2 should occur, we
-set |first_count:=tally| and |trick_count:=@tmax@>(error_line,
-tally+1+error_line-half_error_line)|. At the end of the
-pseudoprinting, the values of |first_count|, |tally|, and
-|trick_count| give us all the information we need to print the two lines,
-and all of the necessary text is in |trick_buf|.
-
-Namely, let |l| be the length of the descriptive information that appears
-on the first line. The length of the context information gathered for that
-line is |k=first_count|, and the length of the context information
-gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|,
-where |h=half_error_line|, we print |trick_buf[0..k-1]| after the
-descriptive information on line~1, and set |n:=l+k|; here |n| is the
-length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h|
-and print `\.{...}' followed by
-$$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$
-where subscripts of |trick_buf| are circular modulo |error_line|. The
-second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|,
-unless |n+m>error_line|; in the latter case, further cropping is done.
-This is easier to program than to explain.
-
-@ The following code sets up the print routines so that they will gather
-the desired information.
-
-@c
+/*tex
+
+Here it is necessary to explain a little trick. We don't want to store a long
+string that corresponds to a token list, because that string might take up lots
+of memory; and we are printing during a time when an error message is being
+given, so we dare not do anything that might overflow one of \TeX's tables. So
+`pseudoprinting' is the answer: We enter a mode of printing that stores
+characters into a buffer of length |error_line|, where character $k+1$ is placed
+into \hbox{|trick_buf[k mod error_line]|} if |k<trick_count|, otherwise character
+|k| is dropped. Initially we set |tally:=0| and |trick_count:=1000000|; then when
+we reach the point where transition from line 1 to line 2 should occur, we set
+|first_count:=tally| and |trick_count:=@tmax@>(error_line,
+tally+1+error_line-half_error_line)|. At the end of the pseudoprinting, the
+values of |first_count|, |tally|, and |trick_count| give us all the information
+we need to print the two lines, and all of the necessary text is in |trick_buf|.
+
+Namely, let |l| be the length of the descriptive information that appears on the
+first line. The length of the context information gathered for that line is
+|k=first_count|, and the length of the context information gathered for line~2 is
+$m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|, where |h=half_error_line|, we
+print |trick_buf[0..k-1]| after the descriptive information on line~1, and set
+|n:=l+k|; here |n| is the length of line~1. If $l+k>h$, some cropping is
+necessary, so we set |n:=h| and print `\.{...}' followed by
+$$\hbox{|trick_buf[(l+k-h+3)..k-1]|,}$$ where subscripts of |trick_buf| are
+circular modulo |error_line|. The second line consists of |n|~spaces followed by
+|trick_buf[k..(k+m-1)]|, unless |n+m>error_line|; in the latter case, further
+cropping is done. This is easier to program than to explain.
+
+The following code sets up the print routines so that they will gather the
+desired information.
+
+*/
+
void set_trick_count(void)
{
first_count = tally;
@@ -230,10 +287,12 @@ void set_trick_count(void)
#define PSEUDO_PRINT_THE_LINE() do { \
begin_pseudoprint(); \
- if (buffer[ilimit]==end_line_char_par) \
+ if (buffer[ilimit]==end_line_char_par) { \
j=ilimit; \
- else \
- j=ilimit+1; /* determine the effective end of the line */ \
+ } else { \
+ /*tex Determine the effective end of the line. */ \
+ j=ilimit+1; \
+ } \
if (j>0) { \
for (i=istart;i<=j-1;i++) { \
if (i==iloc) \
@@ -243,10 +302,12 @@ void set_trick_count(void)
} \
} while (0)
-/*
- We don't care too much if we stay a bit too much below the max error_line
- even if we have more room on the line. If length is really an issue then
- any length is. After all one can set the length larger.
+/*tex
+
+We don't care too much if we stay a bit too much below the max error_line even if
+we have more room on the line. If length is really an issue then any length is.
+After all one can set the length larger.
+
*/
#define print_valid_utf8(q) do { \
@@ -268,46 +329,66 @@ void set_trick_count(void)
print_char(trick_buf[(q+2) % error_line]); \
print_char(trick_buf[(q+3) % error_line]); \
} else { \
- /* invalid */ \
+ /*tex Invalid character! */ \
} \
} while (0)
-@ @c
+/*tex
+
+This one prints where the scanner is.
+
+*/
+
void show_context(void)
-{ /* prints where the scanner is */
- int old_setting; /* saved |selector| setting */
- int nn = -1; /* number of contexts shown so far, less one */
- boolean bottom_line = false; /* have we reached the final context to be shown? */
- int i; /* index into |buffer| */
- int j; /* end of current line in |buffer| */
- int l; /* length of descriptive information on line 1 */
- int m; /* context information gathered for line 2 */
- int n; /* length of line 1 */
- int p; /* starting or ending place in |trick_buf| */
- int q; /* temporary index */
- int c; /* used in sanitizer */
+{
+ /*tex Saved |selector| setting: */
+ int old_setting;
+ /*tex Number of contexts shown so far, less one: */
+ int nn = -1;
+ /*tex Have we reached the final context to be shown? */
+ boolean bottom_line = false;
+ /*tex Index into |buffer|: */
+ int i;
+ /*tex End of current line in |buffer|: */
+ int j;
+ /*tex Length of descriptive information on line 1: */
+ int l;
+ /*tex Context information gathered for line 2: */
+ int m;
+ /*tex Length of line 1: */
+ int n;
+ /*tex Starting or ending place in |trick_buf|: */
+ int p;
+ /*tex Temporary index: */
+ int q;
+ /*tex Used in sanitizer: */
+ int c;
base_ptr = input_ptr;
input_stack[base_ptr] = cur_input;
- /* store current state */
+ /*tex Store the current state. */
while (true) {
- cur_input = input_stack[base_ptr]; /* enter into the context */
+ /*tex Enter into the context. */
+ cur_input = input_stack[base_ptr];
if (istate != token_list) {
if ((iname > 21) || (base_ptr == 0))
bottom_line = true;
}
if ((base_ptr == input_ptr) || bottom_line || (nn < error_context_lines_par)) {
- /* Display the current context */
+ /*tex Display the current context. */
if ((base_ptr == input_ptr) || (istate != token_list) || (token_type != backed_up) || (iloc != null)) {
- /* we omit backed-up token lists that have already been read */
- tally = 0; /* get ready to count characters */
+ /*tex
+ We omit backed-up token lists that have already been read.
+ Get ready to count characters.
+ */
+ tally = 0;
old_setting = selector;
if (istate != token_list) {
- /*
- Print location of current line
-
- This routine should be changed, if necessary, to give the best possible
- indication of where the current line resides in the input file. For example,
- on some systems it is best to print both a page and line number.
+ /*tex
+ Print the location of the current line. This routine
+ should be changed, if necessary, to give the best
+ possible indication of where the current line resides in
+ the input file. For example, on some systems it is best
+ to print both a page and line number.
*/
if (iname <= 17) {
if (terminal_input) {
@@ -327,7 +408,8 @@ void show_context(void)
tprint_nl("l.");
if (iindex == in_open) {
print_int(line);
- } else { /* input from a pseudo file */
+ } else {
+ /*tex Input from a pseudo file. */
print_int(line_stack[iindex + 1]);
}
}
@@ -337,21 +419,26 @@ void show_context(void)
print_token_list_type(token_type);
begin_pseudoprint();
- if (token_type < macro)
+ if (token_type < macro) {
show_token_list(istart, iloc, 100000);
- else
- show_token_list(token_link(istart), iloc, 100000); /* avoid reference count */
+ } else {
+ /*tex Avoid reference count. */
+ show_token_list(token_link(istart), iloc, 100000);
+ }
}
- /* stop pseudoprinting */
+ /*tex Stop pseudoprinting. */
selector = old_setting;
- /* Print two lines using the tricky pseudoprinted information */
- if (trick_count == 1000000)
+ /*tex Print two lines using the tricky pseudoprinted information. */
+ if (trick_count == 1000000) {
set_trick_count();
- /* |set_trick_count| must be performed */
- if (tally < trick_count)
+ }
+ /*tex The |set_trick_count| must be performed. */
+ if (tally < trick_count) {
m = tally - first_count;
- else
- m = trick_count - first_count; /* context on line 2 */
+ } else {
+ /* The context on line 2: */
+ m = trick_count - first_count;
+ }
if (l + first_count <= half_error_line) {
p = 0;
n = l + first_count;
@@ -360,12 +447,14 @@ void show_context(void)
p = l + first_count - half_error_line + 3;
n = half_error_line;
}
- for (q = p; q <= first_count - 1; q++)
+ for (q = p; q <= first_count - 1; q++) {
print_valid_utf8(q);
- print_ln();
- /* print |n| spaces to begin line~2 */
- for (q = 1; q <= n; q++)
+ }
+ print_ln();
+ /*tex Print |n| spaces to begin line 2. */
+ for (q = 1; q <= n; q++) {
print_char(' ');
+ }
if (m + n <= error_line)
p = first_count + m;
else
@@ -379,24 +468,26 @@ void show_context(void)
} else if (nn == error_context_lines_par) {
tprint_nl("...");
incr(nn);
- /* omitted if |error_context_lines_par<0| */
+ /*tex Omitted if |error_context_lines_par<0|. */
}
if (bottom_line)
break;
decr(base_ptr);
}
- /* restore original state */
+ /*tex Restore the original state. */
cur_input = input_stack[input_ptr];
}
-@ The following subroutines change the input status in commonly needed ways.
+/*tex
+
+The following subroutines change the input status in commonly needed ways.
First comes |push_input|, which stores the current state and creates a
new level (having, initially, the same properties as the old).
-@c
+Enter a new input level, save the old:
-/* enter a new input level, save the old */
+*/
# define pop_input() \
cur_input=input_stack[--input_ptr]
@@ -411,12 +502,14 @@ new level (having, initially, the same properties as the old).
nofilter = false; \
incr(input_ptr);
-@
-Here is a procedure that starts a new level of token-list input, given
-a token list |p| and its type |t|. If |t=macro|, the calling routine should
-set |name| and |loc|.
+/*tex
+
+Here is a procedure that starts a new level of token-list input, given a token
+list |p| and its type |t|. If |t=macro|, the calling routine should set |name|
+and |loc|.
+
+*/
-@c
void begin_token_list(halfword p, quarterword t)
{
push_input();
@@ -424,7 +517,7 @@ void begin_token_list(halfword p, quarterword t)
istart = p;
token_type = (unsigned char) t;
if (t >= macro) {
- /* the token list starts with a reference count */
+ /*tex The token list starts with a reference count. */
add_token_ref(p);
if (t == macro) {
param_start = param_ptr;
@@ -438,8 +531,7 @@ void begin_token_list(halfword p, quarterword t)
else if (t == write_text)
tprint_esc("write");
else
- print_cmd_chr(assign_toks_cmd,
- t - output_text + output_routine_loc);
+ print_cmd_chr(assign_toks_cmd, t - output_text + output_routine_loc);
tprint("->");
token_show(p);
end_diagnostic(false);
@@ -450,24 +542,26 @@ void begin_token_list(halfword p, quarterword t)
}
}
-@ When a token list has been fully scanned, the following computations
-should be done as we leave that level of input. The |token_type| tends
-to be equal to either |backed_up| or |inserted| about 2/3 of the time.
-@^inner loop@>
+/*tex
+
+When a token list has been fully scanned, the following computations should be
+done as we leave that level of input. The |token_type| tends to be equal to
+either |backed_up| or |inserted| about 2/3 of the time. @^inner loop@>
+
+*/
-@c
void end_token_list(void)
{
- /* leave a token-list input level */
+ /*tex Leave a token-list input level: */
if (token_type >= backed_up) {
- /* token list to be deleted */
+ /*tex The token list to be deleted: */
if (token_type <= inserted) {
flush_list(istart);
} else {
- /* update reference count */
+ /*tex Update the reference count: */
delete_token_ref(istart);
if (token_type == macro) {
- /* parameters must be flushed */
+ /*tex Parameters must be flushed: */
while (param_ptr > param_start) {
decr(param_ptr);
flush_list(param_stack[param_ptr]);
@@ -484,23 +578,24 @@ void end_token_list(void)
check_interrupt();
}
-@ Sometimes \TeX\ has read too far and wants to ``unscan'' what it has
-seen. The |back_input| procedure takes care of this by putting the token
-just scanned back into the input stream, ready to be read again. This
-procedure can be used only if |cur_tok| represents the token to be
-replaced. Some applications of \TeX\ use this procedure a lot,
-so it has been slightly optimized for speed.
-@^inner loop@>
+/*tex
+
+Sometimes \TeX\ has read too far and wants to ``unscan'' what it has seen. The
+|back_input| procedure takes care of this by putting the token just scanned back
+into the input stream, ready to be read again. This procedure can be used only if
+|cur_tok| represents the token to be replaced. Some applications of \TeX\ use
+this procedure a lot, so it has been slightly optimized for speed. @^inner loop@>
-@c
+*/
/* undoes one token of input */
void back_input(void)
{
- halfword p; /* a token list of length one */
+ /*tex A token list of length one: */
+ halfword p;
while ((istate == token_list) && (iloc == null) && (token_type != v_template)) {
- /* conserve stack space */
+ /*tex Conserve stack space. */
end_token_list();
}
p = get_avail();
@@ -512,14 +607,18 @@ void back_input(void)
incr(align_state);
}
push_input();
+ /*tex This is |back_list(p)|, without procedure overhead: */
istate = token_list;
istart = p;
token_type = backed_up;
- iloc = p; /* that was |back_list(p)|, without procedure overhead */
+ iloc = p;
}
-@ Insert token |p| into \TeX's input
-@c
+/*tex
+
+Insert token |p| into \TeX's input
+
+*/
void reinsert_token(boolean a, halfword pp)
{
@@ -545,13 +644,15 @@ void reinsert_token(boolean a, halfword pp)
cur_tok = t;
}
-@ The |begin_file_reading| procedure starts a new level of input for lines
-of characters to be read from a file, or as an insertion from the
-terminal. It does not take care of opening the file, nor does it set |loc|
-or |limit| or |line|.
+/*tex
+
+The |begin_file_reading| procedure starts a new level of input for lines of
+characters to be read from a file, or as an insertion from the terminal. It does
+not take care of opening the file, nor does it set |loc| or |limit| or |line|.
@^system dependencies@>
-@c
+*/
+
void begin_file_reading(void)
{
if (in_open == max_in_open)
@@ -569,48 +670,59 @@ void begin_file_reading(void)
line_stack[iindex] = line;
istart = first;
istate = mid_line;
- iname = 0; /* |terminal_input| is now |true| */
+ iname = 0;
+ /*tex Variable |terminal_input| is now |true|. */
line_catcode_table = DEFAULT_CAT_TABLE;
line_partial = false;
- /* Prepare terminal input {\sl Sync\TeX} information */
+ /*tex Prepare terminal input \SYNCTEX\ information. */
synctex_tag = 0;
}
-@ Conversely, the variables must be downdated when such a level of input
-is finished:
+/*tex
+
+Conversely, the variables must be downdated when such a level of input is
+finished:
+
+*/
-@c
void end_file_reading(void)
{
first = istart;
line = line_stack[iindex];
- if ((iname >= 18) && (iname <= 20))
+ if ((iname >= 18) && (iname <= 20)) {
pseudo_close();
- else if (iname == 21)
+ } else if (iname == 21) {
luacstring_close(iindex);
- else if (iname > 17)
- lua_a_close_in(cur_file, 0); /* forget it */
+ } else if (iname > 17) {
+ /*tex Forget it. */
+ lua_a_close_in(cur_file, 0);
+ }
pop_input();
decr(in_open);
}
-@ In order to keep the stack from overflowing during a long sequence of
+/*tex
+
+In order to keep the stack from overflowing during a long sequence of
inserted `\.{\\show}' commands, the following routine removes completed
error-inserted lines from memory.
-@c
+*/
void clear_for_error_prompt(void)
{
- while ((istate != token_list) && terminal_input
- && (input_ptr > 0) && (iloc > ilimit))
+ while ((istate != token_list) && terminal_input && (input_ptr > 0) && (iloc > ilimit)) {
end_file_reading();
+ }
print_ln();
clear_terminal();
}
-@ To get \TeX's whole input mechanism going, we perform the following actions.
+/*tex
+
+To get \TeX's whole input mechanism going, we perform the following actions.
+
+*/
-@c
void initialize_inputstack(void)
{
input_ptr = 0;
@@ -645,29 +757,29 @@ void initialize_inputstack(void)
line_catcode_table = DEFAULT_CAT_TABLE;
line_partial = false;
align_state = 1000000;
- if (!init_terminal())
- exit(EXIT_FAILURE); /* |goto final_end|; */
+ if (!init_terminal()) {
+ /*tex |goto final_end|; */
+ exit(EXIT_FAILURE);
+ }
+ /* |init_terminal| has set |loc| and |last| */
ilimit = last;
- first = last + 1; /* |init_terminal| has set |loc| and |last| */
+ first = last + 1;
}
-@ The global variable |pseudo_files| is used to maintain a stack of
-pseudo files. The |pseudo_lines| field of each pseudo file points to
-a linked list of variable size nodes representing lines not yet
-processed: the |subtype| field contains the size of this node,
-all the following words contain ASCII codes.
+/*tex
-/*
+The global variable |pseudo_files| is used to maintain a stack of pseudo files.
+The |pseudo_lines| field of each pseudo file points to a linked list of variable
+size nodes representing lines not yet processed: the |subtype| field contains the
+size of this node, all the following words contain ASCII codes.
- hh: todo: if this is really critical code (which it isn't) then we can
- consider a c stack and store a pointer to a line in the line node instead
- which saves splitting here and reconstructing later.
+If this is really critical code (which it isn't) then we can consider a c stack
+and store a pointer to a line in the line node instead which saves splitting here
+and reconstructing later.
*/
-
-@c
-halfword pseudo_files; /* stack of pseudo files */
+halfword pseudo_files;
static halfword string_to_pseudo(str_number str, int nl)
{
@@ -680,7 +792,8 @@ static halfword string_to_pseudo(str_number str, int nl)
len = (unsigned) str_length(str);
l = 0;
while (l < len) {
- unsigned m = l; /* start of current line */
+ /*tex start of current line */
+ unsigned m = l;
while ((l < len) && (s[l] != nl))
l++;
sz = (int) (l - m + 7) / 4;
@@ -703,7 +816,8 @@ static halfword string_to_pseudo(str_number str, int nl)
if (q == null) {
pseudo_lines(h) = r;
} else {
- vlink(q) = r ; /* no prev node here so no couple_nodes !*/
+ /*tex There is no |prev| node here so no need to couple_nodes! */
+ vlink(q) = r ;
}
q = r ;
if (s[l] == nl)
@@ -712,24 +826,33 @@ static halfword string_to_pseudo(str_number str, int nl)
return h;
}
-@ The |pseudo_start| procedure initiates reading from a pseudo file.
+/*tex
+
+The |pseudo_start| procedure initiates reading from a pseudo file.
+
+*/
-@c
void pseudo_from_string(void)
{
- str_number s; /* string to be converted into a pseudo file */
- halfword p; /* for list construction */
+ /*tex The string to be converted into a pseudo file: */
+ str_number s;
+ /*tex A helper for list construction: */
+ halfword p;
s = make_string();
- /* Convert string |s| into a new pseudo file */
+ /*tex Convert string |s| into a new pseudo file */
p = string_to_pseudo(s, new_line_char_par);
vlink(p) = pseudo_files;
pseudo_files = p;
flush_str(s);
- /* Initiate input from new pseudo file */
- begin_file_reading(); /* set up |cur_file| and new level of input */
+ /*tex
+ Initiate input from new pseudo file. It sets up |cur_file| and a new level
+ of input
+ */
+ begin_file_reading();
line = 0;
ilimit = istart;
- iloc = ilimit + 1; /* force line read */
+ /*tex force line read */
+ iloc = ilimit + 1;
if (tracing_scan_tokens_par > 0) {
if (term_offset > max_print_line - 3)
print_ln();
@@ -742,7 +865,7 @@ void pseudo_from_string(void)
} else {
iname = 18;
}
- /* Prepare pseudo file {\sl Sync\TeX} information */
+ /*tex Prepare pseudo file \SYNCTEX\ information. */
synctex_tag = 0;
}
@@ -759,29 +882,37 @@ void pseudo_start(void)
pseudo_from_string();
}
-@ @c
void lua_string_start(void)
{
- begin_file_reading(); /* set up |cur_file| and new level of input */
+ /*tex Set up |cur_file| and a new level of input: */
+ begin_file_reading();
line = 0;
ilimit = istart;
- iloc = ilimit + 1; /* force line read */
+ /*tex Force line read: */
+ iloc = ilimit + 1;
iname = 21;
luacstring_start(iindex);
}
-@ Here we read a line from the current pseudo file into |buffer|.
+/*tex
-@c
-/* inputs the next line or returns |false| */
+Here we read a line from the current pseudo file into |buffer|.
+It inputs the next line or returns |false|.
+
+*/
boolean pseudo_input(void)
{
- halfword p; /* current line from pseudo file */
- int sz; /* size of node |p| */
- four_quarters w; /* four ASCII codes */
- halfword r; /* loop index */
- last = first; /* cf.\ Matthew 19\thinspace:\thinspace30 */
+ /*tex The current line from pseudo file: */
+ halfword p;
+ /*tex The size of node |p|: */
+ int sz;
+ /*tex Four ASCII codes: */
+ four_quarters w;
+ /*tex The loop index: */
+ halfword r;
+ /*tex cf.\ Matthew 19\thinspace:\thinspace30 */
+ last = first;
p = pseudo_lines(pseudo_files);
if (p == null) {
return false;
@@ -808,10 +939,11 @@ boolean pseudo_input(void)
return true;
}
-@ When we are done with a pseudo file we `close' it.
+/*tex
+
+When we are done with a pseudo file we `close' it.
-@c
-/* close the top level pseudo file */
+*/
void pseudo_close(void)
{
diff --git a/Build/source/texk/web2c/luatexdir/tex/linebreak.c b/Build/source/texk/web2c/luatexdir/tex/linebreak.c
new file mode 100644
index 00000000000..df13931e14c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/linebreak.c
@@ -0,0 +1,2520 @@
+/*
+
+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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+ We come now to what is probably the most interesting algorithm of \TeX: the
+ mechanism for choosing the ``best possible'' breakpoints that yield the
+ individual lines of a paragraph. \TeX's line-breaking algorithm takes a given
+ horizontal list and converts it to a sequence of boxes that are appended to
+ the current vertical list. In the course of doing this, it creates a special
+ data structure containing three kinds of records that are not used elsewhere
+ in \TeX. Such nodes are created while a paragraph is being processed, and
+ they are destroyed afterwards; thus, the other parts of \TeX\ do not need to
+ know anything about how line-breaking is done.
+
+ The method used here is based on an approach devised by Michael F. Plass and
+ the author in 1977, subsequently generalized and improved by the same two
+ people in 1980. A detailed discussion appears in {\sl SOFTWARE---Practice
+ \AM\ Experience \bf11} (1981), 1119--1184, where it is shown that the
+ line-breaking problem can be regarded as a special case of the problem of
+ computing the shortest path in an acyclic network. The cited paper includes
+ numerous examples and describes the history of line breaking as it has been
+ practiced by printers through the ages. The present implementation adds two
+ new ideas to the algorithm of 1980: Memory space requirements are
+ considerably reduced by using smaller records for inactive nodes than for
+ active ones, and arithmetic overflow is avoided by using ``delta distances''
+ instead of keeping track of the total distance from the beginning of the
+ paragraph to the current point.
+
+ The |line_break| procedure should be invoked only in horizontal mode; it
+ leaves that mode and places its output into the current vlist of the
+ enclosing vertical mode (or internal vertical mode). There is one explicit
+ parameter: |d| is true for partial paragraphs preceding display math mode; in
+ this case the amount of additional penalty inserted before the final line is
+ |display_widow_penalty| instead of |widow_penalty|.
+
+ There are also a number of implicit parameters: The hlist to be broken starts
+ at |vlink(head)|, and it is nonempty. The value of |prev_graf| in the
+ enclosing semantic level tells where the paragraph should begin in the
+ sequence of line numbers, in case hanging indentation or \.{\\parshape} are
+ in use; |prev_graf| is zero unless this paragraph is being continued after a
+ displayed formula. Other implicit parameters, such as the |par_shape_ptr| and
+ various penalties to use for hyphenation, etc., appear in |eqtb|.
+
+ After |line_break| has acted, it will have updated the current vlist and the
+ value of |prev_graf|. Furthermore, the global variable |just_box| will point
+ to the final box created by |line_break|, so that the width of this line can
+ be ascertained when it is necessary to decide whether to use
+ |above_display_skip| or |above_display_short_skip| before a displayed
+ formula.
+
+*/
+
+/*tex The |hlist_node| for the last line of the new paragraph: */
+
+halfword just_box;
+
+/*tex
+
+ In it's complete form, |line_break| is a rather lengthy procedure---sort of a
+ small world unto itself---we must build it up little by little. Below you see
+ only the general outline.
+
+ The main task performed here is to move the list from |head| to |temp_head|
+ and go into the enclosing semantic level. We also append the
+ \.{\\parfillskip} glue to the end of the paragraph, removing a space (or
+ other glue node) if it was there, since spaces usually precede blank lines
+ and instances of `\.{\$\$}'. The |par_fill_skip| is preceded by an infinite
+ penalty, so it will never be considered as a potential breakpoint.
+
+ That code assumes that a |glue_node| and a |penalty_node| occupy the same
+ number of |mem|~words.
+
+ Most other processing is delegated to external functions.
+
+*/
+
+void line_break(boolean d, int line_break_context)
+{
+ /*tex Main direction of paragraph: */
+ int paragraph_dir = 0;
+ halfword final_par_glue;
+ halfword start_of_par;
+ int callback_id;
+ /*tex this is for over/underfull box messages */
+ pack_begin_line = cur_list.ml_field;
+ alink(temp_head) = null;
+ vlink(temp_head) = vlink(cur_list.head_field);
+ new_hyphenation(temp_head, cur_list.tail_field);
+ cur_list.tail_field = new_ligkern(temp_head, cur_list.tail_field);
+ if (is_char_node(cur_list.tail_field)) {
+ tail_append(new_penalty(inf_penalty,line_penalty));
+ } else if (type(cur_list.tail_field) != glue_node) {
+ tail_append(new_penalty(inf_penalty,line_penalty));
+ } else {
+ halfword t = alink(cur_list.tail_field);
+ flush_node(cur_list.tail_field);
+ cur_list.tail_field = t;
+ tail_append(new_penalty(inf_penalty,line_penalty));
+ }
+ final_par_glue = new_param_glue(par_fill_skip_code);
+ couple_nodes(cur_list.tail_field, final_par_glue);
+ cur_list.tail_field = vlink(cur_list.tail_field);
+ lua_node_filter(pre_linebreak_filter_callback, line_break_context, temp_head, addressof(cur_list.tail_field));
+ last_line_fill = cur_list.tail_field;
+ pop_nest();
+ start_of_par = cur_list.tail_field;
+ callback_id = callback_defined(linebreak_filter_callback);
+ if (callback_id > 0) {
+ callback_id = lua_linebreak_callback(d, temp_head, addressof(cur_list.tail_field));
+ if (callback_id > 0) {
+ /*tex find the correct value for the |just_box| */
+ halfword box_search = cur_list.tail_field;
+ just_box = null;
+ if (box_search != null) {
+ do {
+ if (type(box_search) == hlist_node) {
+ just_box = box_search;
+ }
+ box_search = vlink(box_search);
+ } while (box_search != null);
+ }
+ if (just_box == null) {
+ help3(
+ "A linebreaking routine should return a non-empty list of nodes",
+ "and at least one of those has to be a \\hbox.",
+ "Sorry, I cannot recover from this."
+ );
+ print_err("Invalid linebreak_filter");
+ succumb();
+ }
+ } else {
+ if (tracing_paragraphs_par > 0) {
+ begin_diagnostic();
+ print_int(line);
+ end_diagnostic(true);
+ }
+ }
+ }
+ if (callback_id == 0) {
+ if ((!is_char_node(vlink(temp_head))) && ((type(vlink(temp_head)) == local_par_node))) {
+ paragraph_dir = local_par_dir(vlink(temp_head));
+ } else {
+ confusion("weird par dir");
+ }
+ ext_do_line_break(
+ paragraph_dir,
+ pretolerance_par,
+ tracing_paragraphs_par,
+ tolerance_par,
+ emergency_stretch_par,
+ looseness_par,
+ adjust_spacing_par,
+ par_shape_par_ptr,
+ adj_demerits_par,
+ protrude_chars_par,
+ line_penalty_par,
+ last_line_fit_par,
+ double_hyphen_demerits_par,
+ final_hyphen_demerits_par,
+ hang_indent_par,
+ hsize_par,
+ hang_after_par,
+ left_skip_par,
+ right_skip_par,
+ inter_line_penalties_par_ptr,
+ inter_line_penalty_par,
+ club_penalty_par,
+ club_penalties_par_ptr,
+ (d ? display_widow_penalties_par_ptr : widow_penalties_par_ptr),
+ (d ? display_widow_penalty_par : widow_penalty_par),
+ broken_penalty_par,
+ final_par_glue
+ );
+ }
+ lua_node_filter(post_linebreak_filter_callback, line_break_context, start_of_par, addressof(cur_list.tail_field));
+ pack_begin_line = 0;
+}
+
+/*tex
+
+ Glue nodes in a horizontal list that is being paragraphed are not supposed to
+ include ``infinite'' shrinkability; that is why the algorithm maintains four
+ registers for stretching but only one for shrinking. If the user tries to
+ introduce infinite shrinkability, the shrinkability will be reset to finite
+ and an error message will be issued. A boolean variable |no_shrink_error_yet|
+ prevents this error message from appearing more than once per paragraph.
+
+*/
+
+#define check_shrinkage(a) \
+ if ((shrink_order((a))!=normal)&&(shrink((a))!=0)) \
+ a=finite_shrink((a))
+
+/*tex Have we complained about infinite shrinkage? */
+
+static boolean no_shrink_error_yet;
+
+/*tex Recovers from infinite shrinkage. */
+
+static halfword finite_shrink(halfword p)
+{
+ const char *hlp[] = {
+ "The paragraph just ended includes some glue that has",
+ "infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.",
+ "Such glue doesn't belong there---it allows a paragraph",
+ "of any length to fit on one line. But it's safe to proceed,",
+ "since the offensive shrinkability has been made finite.",
+ NULL
+ };
+ if (no_shrink_error_yet) {
+ no_shrink_error_yet = false;
+ tex_error("Infinite glue shrinkage found in a paragraph", hlp);
+ }
+ shrink_order(p) = normal;
+ return p;
+}
+
+/*tex
+
+ A pointer variable |cur_p| runs through the given horizontal list as we look
+ for breakpoints. This variable is global, since it is used both by
+ |line_break| and by its subprocedure |try_break|.
+
+ Another global variable called |threshold| is used to determine the
+ feasibility of individual lines: breakpoints are feasible if there is a way
+ to reach them without creating lines whose badness exceeds |threshold|. (The
+ badness is compared to |threshold| before penalties are added, so that
+ penalty values do not affect the feasibility of breakpoints, except that no
+ break is allowed when the penalty is 10000 or more.) If |threshold| is 10000
+ or more, all legal breaks are considered feasible, since the |badness|
+ function specified above never returns a value greater than~10000.
+
+ Up to three passes might be made through the paragraph in an attempt to find
+ at least one set of feasible breakpoints. On the first pass, we have
+ |threshold=pretolerance| and |second_pass=final_pass=false|. If this pass
+ fails to find a feasible solution, |threshold| is set to |tolerance|,
+ |second_pass| is set |true|, and an attempt is made to hyphenate as many
+ words as possible. If that fails too, we add |emergency_stretch| to the
+ background stretchability and set |final_pass=true|.
+
+*/
+
+/*tex is this our second attempt to break this paragraph? */
+
+static boolean second_pass;
+
+/*tex is this our final attempt to break this paragraph? */
+
+static boolean final_pass;
+
+/*tex maximum badness on feasible lines */
+
+static int threshold;
+
+/*tex
+
+ The maximum fill level for |hlist_stack|. Maybe good if larger than |2 *
+ max_quarterword|, so that box nesting level would overflow first.
+
+*/
+
+#define max_hlist_stack 512
+
+/*tex stack for |find_protchar_left()| and |find_protchar_right()| */
+
+static halfword hlist_stack[max_hlist_stack];
+
+/*tex fill level for |hlist_stack| */
+
+static short hlist_stack_level = 0;
+
+static void push_node(halfword p)
+{
+ if (hlist_stack_level >= max_hlist_stack)
+ normal_error("push_node","stack overflow");
+ hlist_stack[hlist_stack_level++] = p;
+}
+
+static halfword pop_node(void)
+{
+ if (hlist_stack_level <= 0) {
+ /*tex This can point to some bug. */
+ normal_error("pop_node","stack underflow (internal error)");
+ }
+ return hlist_stack[--hlist_stack_level];
+}
+
+/*tex maximal stretch ratio of expanded fonts */
+
+static int max_stretch_ratio = 0;
+
+/*tex maximal shrink ratio of expanded fonts */
+
+static int max_shrink_ratio = 0;
+
+/*tex the current step of expanded fonts */
+
+static int cur_font_step = 0;
+
+static boolean check_expand_pars(internal_font_number f)
+{
+ int m;
+ if ((font_step(f) == 0) || ((font_max_stretch(f) == 0) && (font_max_shrink(f) == 0)))
+ return false;
+ if (cur_font_step < 0)
+ cur_font_step = font_step(f);
+ else if (cur_font_step != font_step(f))
+ normal_error("font expansion","using fonts with different step of expansion in one paragraph is not allowed");
+ m = font_max_stretch(f);
+ if (m != 0) {
+ if (max_stretch_ratio < 0)
+ max_stretch_ratio = m;
+ else if (max_stretch_ratio != m)
+ normal_error("font expansion","using fonts with different limit of expansion in one paragraph is not allowed");
+ }
+ m = font_max_shrink(f);
+ if (m != 0) {
+ if (max_shrink_ratio < 0)
+ max_shrink_ratio = -m;
+ else if (max_shrink_ratio != -m)
+ normal_error("font expansion","using fonts with different limit of expansion in one paragraph is not allowed");
+ }
+ return true;
+}
+
+/*tex Search left to right from list head |l|, returns 1st non-skipable item */
+
+halfword find_protchar_left(halfword l, boolean d)
+{
+ halfword t;
+ boolean run;
+ boolean done = false ;
+ while ((vlink(l) != null) && (type(l) == hlist_node) && zero_dimensions(l) && (list_ptr(l) == null)) {
+ /*tex For paragraph start with \.{\\parindent} = 0pt or any empty hbox. */
+ l = vlink(l);
+ done = true ;
+ }
+ if ((!done) && (type(l) == local_par_node)) {
+ l = vlink(l);
+ done = true ;
+ }
+ if ((!done) && d) {
+ while ((vlink(l) != null) && (!(is_char_node(l) || non_discardable(l)))) {
+ /*tex standard discardables at line break, \TeX book, p 95 */
+ l = vlink(l);
+ }
+ }
+ if (type(l) != glyph_node) {
+ hlist_stack_level = 0;
+ run = true;
+ do {
+ t = l;
+ while (run && (type(l) == hlist_node) && (list_ptr(l) != null)) {
+ push_node(l);
+ l = list_ptr(l);
+ }
+ while (run && cp_skipable(l)) {
+ while ((vlink(l) == null) && (hlist_stack_level > 0)) {
+ /*tex Don't visit this node again. */
+ l = pop_node();
+ run = false;
+ }
+ if ((vlink(l) != null) && (type(l) == boundary_node) && (subtype(l) == protrusion_boundary) &&
+ ((boundary_value(l) == 1) || (boundary_value(l) == 3))) {
+ /*tex Skip next node. */
+ l = vlink(l);
+ }
+ if (vlink(l) != null) {
+ l = vlink(l);
+ } else if (hlist_stack_level == 0) {
+ run = false;
+ }
+ }
+ } while (t != l);
+ }
+ return l;
+}
+
+/*tex
+
+ Search right to left from list tail |r| to head |l|, returns 1st non-skipable
+ item.
+
+*/
+
+halfword find_protchar_right(halfword l, halfword r)
+{
+ halfword t;
+ boolean run = true;
+ if (r == null)
+ return null;
+ hlist_stack_level = 0;
+ do {
+ t = r;
+ while (run && (type(r) == hlist_node) && (list_ptr(r) != null)) {
+ push_node(l);
+ push_node(r);
+ l = list_ptr(r);
+ r = l;
+ while (vlink(r) != null) {
+ halfword s = r;
+ r = vlink(r);
+ alink(r) = s;
+ }
+ }
+ while (run && cp_skipable(r)) {
+ while ((r == l) && (hlist_stack_level > 0)) {
+ /*tex Don't visit this node again. */
+ r = pop_node();
+ l = pop_node();
+ }
+ if ((r != l) && (r != null)) {
+ if ((alink(r) != null) && (type(r) == boundary_node) && (subtype(r) == protrusion_boundary) &&
+ ((boundary_value(r) == 2) || (boundary_value(r) == 3))) {
+ /*tex Skip next node. */
+ r = alink(r);
+ }
+ if (alink(r) != null) {
+ r = alink(r);
+ } else {
+ /*tex This is the input: \.{\\leavevmode\\penalty-10000\\penalty-10000} (bug \#268). */
+ run = false;
+ }
+ } else if ((r == l) && (hlist_stack_level == 0))
+ run = false;
+ }
+ } while (t != r);
+ return r;
+}
+
+#define left_pw(a) char_pw((a), left_side)
+#define right_pw(a) char_pw((a), right_side)
+
+/*tex
+
+ When looking for optimal line breaks, \TeX\ creates a ``break node'' for each
+ break that is {\sl feasible}, in the sense that there is a way to end a line
+ at the given place without requiring any line to stretch more than a given
+ tolerance. A break node is characterized by three things: the position of the
+ break (which is a pointer to a |glue_node|, |math_node|, |penalty_node|, or
+ |disc_node|); the ordinal number of the line that will follow this
+ breakpoint; and the fitness classification of the line that has just ended,
+ i.e., |tight_fit|, |decent_fit|, |loose_fit|, or |very_loose_fit|.
+
+*/
+
+typedef enum {
+ /*tex fitness classification for lines stretching more than their stretchability */
+ very_loose_fit = 0,
+ /*tex fitness classification for lines stretching 0.5 to 1.0 of their stretchability */
+ loose_fit,
+ /*tex fitness classification for all other lines */
+ decent_fit,
+ /*tex fitness classification for lines shrinking 0.5 to 1.0 of their shrinkability */
+ tight_fit
+} fitness_value;
+
+/*tex
+
+ The algorithm essentially determines the best possible way to achieve each
+ feasible combination of position, line, and fitness. Thus, it answers
+ questions like, ``What is the best way to break the opening part of the
+ paragraph so that the fourth line is a tight line ending at such-and-such a
+ place?'' However, the fact that all lines are to be the same length after a
+ certain point makes it possible to regard all sufficiently large line numbers
+ as equivalent, when the looseness parameter is zero, and this makes it
+ possible for the algorithm to save space and time.
+
+ An ``active node'' and a ``passive node'' are created in |mem| for each
+ feasible breakpoint that needs to be considered. Active nodes are three words
+ long and passive nodes are two words long. We need active nodes only for
+ breakpoints near the place in the paragraph that is currently being examined,
+ so they are recycled within a comparatively short time after they are
+ created.
+
+ An active node for a given breakpoint contains six fields:
+
+ \startitemize[n]
+
+ \startitem
+ |vlink| points to the next node in the list of active nodes; the last
+ active node has |vlink=active|.
+ \stopitem
+
+ \startitem
+ |break_node| points to the passive node associated with this
+ breakpoint.
+ \stopitem
+
+ \startitem
+ |line_number| is the number of the line that follows this breakpoint.
+ \stopitem
+
+ \startitem
+ |fitness| is the fitness classification of the line ending at this
+ breakpoint.
+ \stopitem
+
+ \startitem
+ |type| is either |hyphenated_node| or |unhyphenated_node|, depending
+ on whether this breakpoint is a |disc_node|.
+ \stopitem
+
+ \startitem
+ |total_demerits| is the minimum possible sum of demerits over all
+ lines leading from the beginning of the paragraph to this breakpoint.
+ \stopitem
+
+ \stopitemize
+
+ The value of |vlink(active)| points to the first active node on a vlinked
+ list of all currently active nodes. This list is in order by |line_number|,
+ except that nodes with |line_number>easy_line| may be in any order relative
+ to each other.
+
+*/
+
+void initialize_active(void)
+{
+ type(active) = hyphenated_node;
+ line_number(active) = max_halfword;
+ /*tex The |subtype| is never examined. */
+ subtype(active) = 0;
+}
+
+/*tex
+
+ The passive node for a given breakpoint contains eight fields:
+
+ \startitemize
+
+ \startitem
+ |vlink| points to the passive node created just before this one, if
+ any, otherwise it is |null|.
+ \stopitem
+
+ \startitem
+ |cur_break| points to the position of this breakpoint in the
+ horizontal list for the paragraph being broken.
+ \stopitem
+
+ \startitem
+ |prev_break| points to the passive node that should precede this one
+ in an optimal path to this breakpoint.
+ \stopitem
+
+ \startitem
+ |serial| is equal to |n| if this passive node is the |n|th one
+ created during the current pass. (This field is used only when
+ printing out detailed statistics about the line-breaking
+ calculations.)
+ \stopitem
+
+ \startitem
+ |passive_pen_inter| holds the current \.{\\localinterlinepenalty}
+ \stopitem
+
+ \startitem
+ |passive_pen_broken| holds the current \.{\\localbrokenpenalty}
+ \stopitem
+
+ \stopitemize
+
+ There is a global variable called |passive| that points to the most recently
+ created passive node. Another global variable, |printed_node|, is used to
+ help print out the paragraph when detailed information about the
+ line-breaking computation is being displayed.
+
+*/
+
+/*tex most recent node on passive list */
+
+static halfword passive;
+
+/*tex most recent node that has been printed */
+
+static halfword printed_node;
+
+/*tex the number of passive nodes allocated on this pass */
+
+static halfword pass_number;
+
+/*tex
+
+ The active list also contains ``delta'' nodes that help the algorithm compute
+ the badness of individual lines. Such nodes appear only between two active
+ nodes, and they have |type=delta_node|. If |p| and |r| are active nodes and
+ if |q| is a delta node between them, so that |vlink(p)=q| and |vlink(q)=r|,
+ then |q| tells the space difference between lines in the horizontal list that
+ start after breakpoint |p| and lines that start after breakpoint |r|. In
+ other words, if we know the length of the line that starts after |p| and ends
+ at our current position, then the corresponding length of the line that
+ starts after |r| is obtained by adding the amounts in node~|q|. A delta node
+ contains seven scaled numbers, since it must record the net change in glue
+ stretchability with respect to all orders of infinity. The natural width
+ difference appears in |mem[q+1].sc|; the stretch differences in units of pt,
+ sfi, fil, fill, and filll appear in |mem[q+2..q+6].sc|; and the shrink
+ difference appears in |mem[q+7].sc|. The |subtype| field of a delta node is
+ not used.
+
+ Actually, we have two more fields that are used by |pdftex|.
+
+ As the algorithm runs, it maintains a set of seven delta-like registers for
+ the length of the line following the first active breakpoint to the current
+ position in the given hlist. When it makes a pass through the active list, it
+ also maintains a similar set of seven registers for the length following the
+ active breakpoint of current interest. A third set holds the length of an
+ empty line (namely, the sum of \.{\\leftskip} and \.{\\rightskip}); and a
+ fourth set is used to create new delta nodes.
+
+ When we pass a delta node we want to do operations like:
+
+ \starttyping
+ for k := 1 to 7 do
+ cur_active_width[k] := cur_active_width[k] + mem[q+k].sc|};
+ \stoptyping
+
+ and we want to do this without the overhead of |for| loops. The |do_all_six|
+ macro makes such six-tuples convenient.
+
+*/
+
+/*tex distance from first active node to~|cur_p| */
+
+static scaled active_width[10] = { 0 };
+
+/*tex length of an ``empty'' line */
+
+static scaled background[10] = { 0 };
+
+/*tex length being computed after current break */
+
+static scaled break_width[10] = { 0 };
+
+/*tex Make |auto_breaking| accessible out of |line_break|: */
+
+static boolean auto_breaking;
+
+/*tex
+
+ Let's state the principles of the delta nodes more precisely and concisely,
+ so that the following programs will be less obscure. For each legal
+ breakpoint~|p| in the paragraph, we define two quantities $\alpha(p)$ and
+ $\beta(p)$ such that the length of material in a line from breakpoint~|p| to
+ breakpoint~|q| is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$.
+ Intuitively, $\alpha(p)$ and $\beta(q)$ are the total length of material from
+ the beginning of the paragraph to a point ``after'' a break at |p| and to a
+ point ``before'' a break at |q|; and $\gamma$ is the width of an empty line,
+ namely the length contributed by \.{\\leftskip} and \.{\\rightskip}.
+
+ Suppose, for example, that the paragraph consists entirely of alternating
+ boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and let the
+ skips have widths $y_1\ldots y_n$, so that the paragraph can be represented
+ by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint at $y_i$; then
+ $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)= x_1+y_1+\cdots+x_i$.
+ To check this, note that the length of material from $p_2$ to $p_5$, say, is
+ $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5) -\alpha(p_2)$.
+
+ The quantities $\alpha$, $\beta$, $\gamma$ involve glue stretchability and
+ shrinkability as well as a natural width. If we were to compute $\alpha(p)$
+ and $\beta(p)$ for each |p|, we would need multiple precision arithmetic, and
+ the multiprecise numbers would have to be kept in the active nodes. \TeX\
+ avoids this problem by working entirely with relative differences or
+ ``deltas.'' Suppose, for example, that the active list contains
+ $a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the |a|'s are active breakpoints
+ and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$
+ and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is
+ currently positioned at some other breakpoint |p|, the |active_width| array
+ contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through
+ the list of active nodes and considering a tentative line that runs from
+ $a_2$ to~|p|, say, the |cur_active_width| array will contain the value
+ $\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$, we
+ want to add $\alpha(a_2)-\alpha(a_3)$ to |cur_active_width|; and this is just
+ $\delta_2$, which appears in the active list between $a_2$ and $a_3$. The
+ |background| array contains $\gamma$. The |break_width| array will be used to
+ calculate values of new delta nodes when the active list is being updated.
+
+ The heart of the line-breaking procedure is `|try_break|', a subroutine that
+ tests if the current breakpoint |cur_p| is feasible, by running through the
+ active list to see what lines of text can be made from active nodes
+ to~|cur_p|. If feasible breaks are possible, new break nodes are created. If
+ |cur_p| is too far from an active node, that node is deactivated.
+
+ The parameter |pi| to |try_break| is the penalty associated with a break at
+ |cur_p|; we have |pi=eject_penalty| if the break is forced, and
+ |pi=inf_penalty| if the break is illegal.
+
+ The other parameter, |break_type|, is set to |hyphenated_node| or
+ |unhyphenated_node|, depending on whether or not the current break is at a
+ |disc_node|. The end of a paragraph is also regarded as `|hyphenated_node|';
+ this case is distinguishable by the condition |cur_p=null|.
+
+*/
+
+/*tex running \.{\\localinterlinepenalty} */
+
+static int internal_pen_inter;
+
+/*tex running \.{\\localbrokenpenalty} */
+
+static int internal_pen_broken;
+
+/*tex running \.{\\localleftbox} */
+
+static halfword internal_left_box;
+
+/*tex running \.{\\localleftbox} width */
+
+static int internal_left_box_width;
+
+/*tex running \.{\\localleftbox} */
+
+static halfword init_internal_left_box;
+
+/*tex running \.{\\localleftbox} width */
+
+static int init_internal_left_box_width;
+
+/*tex running \.{\\localrightbox} */
+
+static halfword internal_right_box;
+
+/*tex running \.{\\localrightbox} width */
+
+static int internal_right_box_width;
+
+/*tex the length of discretionary material preceding a break */
+
+static scaled disc_width[10] = { 0 };
+
+/*tex
+
+ As we consider various ways to end a line at |cur_p|, in a given line number
+ class, we keep track of the best total demerits known, in an array with one
+ entry for each of the fitness classifications. For example,
+ |minimal_demerits[tight_fit]| contains the fewest total demerits of feasible
+ line breaks ending at |cur_p| with a |tight_fit| line;
+ |best_place[tight_fit]| points to the passive node for the break
+ before~|cur_p| that achieves such an optimum; and |best_pl_line[tight_fit]|
+ is the |line_number| field in the active node corresponding to
+ |best_place[tight_fit]|. When no feasible break sequence is known, the
+ |minimal_demerits| entries will be equal to |awful_bad|, which is $2^{30}-1$.
+ Another variable, |minimum_demerits|, keeps track of the smallest value in
+ the |minimal_demerits| array.
+
+*/
+
+/*tex best total demerits known for current line class and position, given the fitness */
+
+static int minimal_demerits[4];
+
+/*tex best total demerits known for current line class and position */
+
+static int minimum_demerits;
+
+/*tex how to achieve |minimal_demerits| */
+
+static halfword best_place[4];
+
+/*tex corresponding line number */
+
+static halfword best_pl_line[4];
+
+/*tex
+
+ The length of lines depends on whether the user has specified \.{\\parshape}
+ or \.{\\hangindent}. If |par_shape_ptr| is not null, it points to a
+ $(2n+1)$-word record in |mem|, where the |vinfo| in the first word contains
+ the value of |n|, and the other $2n$ words contain the left margins and line
+ lengths for the first |n| lines of the paragraph; the specifications for line
+ |n| apply to all subsequent lines. If |par_shape_ptr=null|, the shape of the
+ paragraph depends on the value of |n=hang_after|; if |n>=0|, hanging
+ indentation takes place on lines |n+1|, |n+2|, \dots, otherwise it takes
+ place on lines 1, \dots, $\vert n\vert$. When hanging indentation is active,
+ the left margin is |hang_indent|, if |hang_indent>=0|, else it is 0; the line
+ length is $|hsize|-\vert|hang_indent|\vert$. The normal setting is
+ |par_shape_ptr=null|, |hang_after=1|, and |hang_indent=0|. Note that if
+ |hang_indent=0|, the value of |hang_after| is irrelevant.
+
+*/
+
+/*tex line numbers |>easy_line| are equivalent in break nodes */
+
+static halfword easy_line;
+
+/*tex line numbers |>last_special_line| all have the same width */
+
+static halfword last_special_line;
+
+/*tex the width of all lines |<=last_special_line|, if no \.{\\parshape} has been specified */
+
+static scaled first_width;
+
+/*tex the width of all lines |>last_special_line| */
+
+static scaled second_width;
+
+/*tex left margin to go with |first_width| */
+
+static scaled first_indent;
+
+/*tex left margin to go with |second_width| */
+
+static scaled second_indent;
+
+/*tex use this passive node and its predecessors */
+
+static halfword best_bet;
+
+/*tex the demerits associated with |best_bet| */
+
+static int fewest_demerits;
+
+/*tex line number following the last line of the new paragraph */
+
+static halfword best_line;
+
+/*tex the difference between |line_number(best_bet)| and the optimum |best_line| */
+
+static int actual_looseness;
+
+/*tex the difference between the current line number and the optimum |best_line| */
+
+static int line_diff;
+
+/*tex
+
+ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|, |rule_node|,
+ |ins_node|, |mark_node|, |adjust_node|, |disc_node|, |whatsit_node|, and
+ |math_node| are at the low end of the type codes, by permitting a break at
+ glue in a list if and only if the |type| of the previous node is less than
+ |math_node|. Furthermore, a node is discarded after a break if its type is
+ |math_node| or~more.
+
+*/
+
+#define do_all_six(a) a(1);a(2);a(3);a(4);a(5);a(6);a(7)
+#define do_seven_eight(a) if (adjust_spacing > 1) { a(8);a(9); }
+#define do_all_eight(a) do_all_six(a); do_seven_eight(a)
+#define do_one_seven_eight(a) a(1); do_seven_eight(a)
+
+#define store_background(a) {active_width[a]=background[a];}
+
+#define kern_break() { \
+ if ((!is_char_node(vlink(cur_p))) && auto_breaking) \
+ if (type(vlink(cur_p))==glue_node) \
+ ext_try_break(\
+ 0, \
+ unhyphenated_node, \
+ line_break_dir, \
+ adjust_spacing, \
+ par_shape_ptr, \
+ adj_demerits, \
+ tracing_paragraphs, \
+ protrude_chars, \
+ line_penalty, \
+ last_line_fit, \
+ double_hyphen_demerits, \
+ final_hyphen_demerits, \
+ first_p, \
+ cur_p \
+ ); \
+ if (type(cur_p)!=math_node) \
+ active_width[1] += width(cur_p); \
+ else \
+ active_width[1] += surround(cur_p); \
+}
+
+#define clean_up_the_memory() { \
+ q=vlink(active); \
+ while (q!=active) { \
+ cur_p = vlink(q); \
+ if (type(q)==delta_node) \
+ flush_node(q); \
+ else \
+ flush_node(q); \
+ q = cur_p; \
+ } \
+ q = passive; \
+ while (q!=null) { \
+ cur_p = vlink(q); \
+ flush_node(q); \
+ q = cur_p; \
+ } \
+}
+
+/*tex special algorithm for last line of paragraph? */
+
+static boolean do_last_line_fit;
+
+/*tex infinite stretch components of |par_fill_skip| */
+
+static scaled fill_width[4];
+
+/*tex |shortfall| corresponding to |minimal_demerits| */
+
+static scaled best_pl_short[4];
+
+/*tex corresponding glue stretch or shrink */
+
+static scaled best_pl_glue[4];
+
+#define reset_disc_width(a) disc_width[(a)] = 0
+
+#define add_disc_width_to_break_width(a) break_width[(a)] += disc_width[(a)]
+#define sub_disc_width_from_active_width(a) active_width[(a)] -= disc_width[(a)]
+
+#define add_char_shrink(a,b) a += char_shrink((b))
+#define add_char_stretch(a,b) a += char_stretch((b))
+#define sub_char_shrink(a,b) a -= char_shrink((b))
+#define sub_char_stretch(a,b) a -= char_stretch((b))
+
+#define add_kern_shrink(a,b) a += kern_shrink((b))
+#define add_kern_stretch(a,b) a += kern_stretch((b))
+#define sub_kern_shrink(a,b) a -= kern_shrink((b))
+#define sub_kern_stretch(a,b) a -= kern_stretch((b))
+
+/*tex
+
+ This function is used to add the width of a list of nodes (from a
+ discretionary) to one of the width arrays.
+
+ Replacement texts and discretionary texts are supposed to contain only
+ character nodes, kern nodes, and box or rule nodes.
+
+*/
+
+#define bad_node_in_disc_error(p) { \
+ if (type(p) == whatsit_node) { \
+ formatted_error("linebreak","invalid node with type %s and subtype %i found in discretionary",node_data[type(p)].name,subtype(p)); \
+ } else { \
+ formatted_error("linebreak","invalid node with type %s found in discretionary",node_data[type(p)].name); \
+ } \
+}
+
+static void add_to_widths(halfword s, int line_break_dir, int adjust_spacing, scaled * widths)
+{
+ while (s != null) {
+ if (is_char_node(s)) {
+ widths[1] += pack_width(line_break_dir, dir_TRT, s, true);
+ if ((adjust_spacing > 1) && check_expand_pars(font(s))) {
+ set_prev_char_p(s);
+ add_char_stretch(widths[8], s);
+ add_char_shrink(widths[9], s);
+ };
+ } else {
+ switch (type(s)) {
+ case hlist_node:
+ case vlist_node:
+ widths[1] += pack_width(line_break_dir, box_dir(s), s, false);
+ break;
+ case kern_node:
+ if ((adjust_spacing == 2) && (subtype(s) == normal)) {
+ add_kern_stretch(widths[8], s);
+ add_kern_shrink(widths[9], s);
+ }
+ /*tex fall through */
+ case rule_node:
+ widths[1] += width(s);
+ break;
+ case disc_node:
+ break;
+ default:
+ bad_node_in_disc_error(s);
+ break;
+ }
+ }
+ s = vlink(s);
+ }
+}
+
+/*tex
+
+ This function is used to substract the width of a list of nodes (from a
+ discretionary) from one of the width arrays. It is used only once, but
+ deserves it own function because of orthogonality with the |add_to_widths|
+ function.
+
+*/
+
+static void sub_from_widths(halfword s, int line_break_dir, int adjust_spacing, scaled * widths)
+{
+ while (s != null) {
+ /*tex Subtract the width of node |s| from |break_width|; */
+ if (is_char_node(s)) {
+ widths[1] -= pack_width(line_break_dir, dir_TRT, s, true);
+ if ((adjust_spacing > 1) && check_expand_pars(font(s))) {
+ set_prev_char_p(s);
+ sub_char_stretch(widths[8], s);
+ sub_char_shrink(widths[9], s);
+ }
+ } else {
+ switch (type(s)) {
+ case hlist_node:
+ case vlist_node:
+ widths[1] -= pack_width(line_break_dir, box_dir(s), s, false);
+ break;
+ case kern_node:
+ if ((adjust_spacing == 2) && (subtype(s) == normal)) {
+ sub_kern_stretch(widths[8], s);
+ sub_kern_shrink(widths[9], s);
+ }
+ /*tex fall through */
+ case rule_node:
+ widths[1] -= width(s);
+ break;
+ case disc_node:
+ break;
+ default:
+ bad_node_in_disc_error(s);
+ break;
+ }
+ }
+ s = vlink(s);
+ }
+}
+
+/*tex
+
+ When we insert a new active node for a break at |cur_p|, suppose this new
+ node is to be placed just before active node |a|; then we essentially want to
+ insert `$\delta\,|cur_p|\,\delta^\prime$' before |a|, where
+ $\delta=\alpha(a)-\alpha(|cur_p|)$ and
+ $\delta^\prime=\alpha(|cur_p|)-\alpha(a)$ in the notation explained above.
+ The |cur_active_width| array now holds $\gamma+\beta(|cur_p|)-\alpha(a)$; so
+ $\delta$ can be obtained by subtracting |cur_active_width| from the quantity
+ $\gamma+\beta(|cur_p|)- \alpha(|cur_p|)$. The latter quantity can be regarded
+ as the length of a line ``from |cur_p| to |cur_p|''; we call it the
+ |break_width| at |cur_p|.
+
+ The |break_width| is usually negative, since it consists of the background
+ (which is normally zero) minus the width of nodes following~|cur_p| that are
+ eliminated after a break. If, for example, node |cur_p| is a glue node, the
+ width of this glue is subtracted from the background; and we also look ahead
+ to eliminate all subsequent glue and penalty and kern and math nodes,
+ subtracting their widths as well.
+
+ Kern nodes do not disappear at a line break unless they are |explicit|.
+
+*/
+
+static void compute_break_width(int break_type, int line_break_dir, int adjust_spacing, halfword p)
+{
+ /*tex
+
+ Glue and other 'whitespace' to be skipped after a break; used if
+ unhyphenated, or |post_break==empty|.
+
+ */
+ halfword s = p;
+ if (break_type > unhyphenated_node && p != null) {
+ /*tex
+
+ Compute the discretionary |break_width| values.
+
+ When |p| is a discretionary break, the length of a line ``from |p| to
+ |p|'' has to be defined properly so that the other calculations work
+ out. Suppose that the pre-break text at |p| has length $l_0$, the
+ post-break text has length $l_1$, and the replacement text has length
+ |l|. Suppose also that |q| is the node following the replacement
+ text. Then length of a line from |p| to |q| will be computed as
+ $\gamma+\beta(q)-\alpha(|p|)$, where $\beta(q)=\beta(|p|)-l_0+l$. The
+ actual length will be the background plus $l_1$, so the length from
+ |p| to |p| should be $\gamma+l_0+l_1-l$. If the post-break text of
+ the discretionary is empty, a break may also discard~|q|; in that
+ unusual case we subtract the length of~|q| and any other nodes that
+ will be discarded after the discretionary break.
+
+ The value of $l_0$ need not be computed, since |line_break| will put
+ it into the global variable |disc_width| before calling |try_break|.
+
+ In case of nested discretionaries, we always follow the no-break
+ path, as we are talking about the breaking on {\it this} position.
+
+ */
+ sub_from_widths(vlink_no_break(p), line_break_dir, adjust_spacing, break_width);
+ add_to_widths(vlink_post_break(p), line_break_dir, adjust_spacing, break_width);
+ do_one_seven_eight(add_disc_width_to_break_width);
+ if (vlink_post_break(p) == null) {
+ /*tex no |post_break|: 'skip' any 'whitespace' following */
+ s = vlink(p);
+ } else {
+ s = null;
+ }
+ }
+ while (s != null) {
+ switch (type(s)) {
+ case math_node:
+ /*tex begin mathskip code */
+ if (glue_is_zero(s)) {
+ break_width[1] -= surround(s);
+ break;
+ } else {
+ /*tex fall through */
+ }
+ /*tex end mathskip code */
+ case glue_node:
+ /*tex Subtract glue from |break_width|; */
+ break_width[1] -= width(s);
+ break_width[2 + stretch_order(s)] -= stretch(s);
+ break_width[7] -= shrink(s);
+ break;
+ case penalty_node:
+ break;
+ case kern_node:
+ if (subtype(s) != explicit_kern && subtype(s) != italic_kern)
+ return;
+ else
+ break_width[1] -= width(s);
+ break;
+ default:
+ return;
+ };
+ s = vlink(s);
+ }
+}
+
+static void print_break_node(halfword q, fitness_value fit_class, quarterword break_type, halfword cur_p)
+{
+ /*tex Print a symbolic description of the new break node. */
+ tprint_nl("@@");
+ print_int(serial(passive));
+ tprint(": line ");
+ print_int(line_number(q) - 1);
+ print_char('.');
+ print_int(fit_class);
+ if (break_type == hyphenated_node)
+ print_char('-');
+ tprint(" t=");
+ print_int(total_demerits(q));
+ if (do_last_line_fit) {
+ /*tex Print additional data in the new active node. */
+ tprint(" s=");
+ print_scaled(active_short(q));
+ if (cur_p == null)
+ tprint(" a=");
+ else
+ tprint(" g=");
+ print_scaled(active_glue(q));
+ }
+ tprint(" -> @");
+ if (prev_break(passive) == null)
+ print_char('0');
+ else
+ print_int(serial(prev_break(passive)));
+}
+
+static void print_feasible_break(halfword cur_p, pointer r, halfword b, int pi, int d, boolean artificial_demerits)
+{
+ /*tex
+
+ Print a symbolic description of this feasible break.
+
+ */
+ if (printed_node != cur_p) {
+ /*tex
+
+ Print the list between |printed_node| and |cur_p|, then set
+ |printed_node:=cur_p|.
+
+ */
+ tprint_nl("");
+ if (cur_p == null) {
+ short_display(vlink(printed_node));
+ } else {
+ halfword save_link = vlink(cur_p);
+ vlink(cur_p) = null;
+ tprint_nl("");
+ short_display(vlink(printed_node));
+ vlink(cur_p) = save_link;
+ }
+ printed_node = cur_p;
+ }
+ tprint_nl("@");
+ if (cur_p == null) {
+ tprint_esc("par");
+ } else if (type(cur_p) != glue_node) {
+ if (type(cur_p) == penalty_node)
+ tprint_esc("penalty");
+ else if (type(cur_p) == disc_node)
+ tprint_esc("discretionary");
+ else if (type(cur_p) == kern_node)
+ tprint_esc("kern");
+ else
+ tprint_esc("math");
+ }
+ tprint(" via @");
+ if (break_node(r) == null)
+ print_char('0');
+ else
+ print_int(serial(break_node(r)));
+ tprint(" b=");
+ if (b > inf_bad)
+ print_char('*');
+ else
+ print_int(b);
+ tprint(" p=");
+ print_int(pi);
+ tprint(" d=");
+ if (artificial_demerits)
+ print_char('*');
+ else
+ print_int(d);
+}
+
+#define add_disc_width_to_active_width(a) active_width[a] += disc_width[a]
+#define update_width(a) cur_active_width[a] += varmem[(r+(a))].cint
+
+#define set_break_width_to_background(a) break_width[a]=background[(a)]
+
+#define convert_to_break_width(a) \
+ varmem[(prev_r+(a))].cint = varmem[(prev_r+(a))].cint-cur_active_width[(a)]+break_width[(a)]
+
+#define store_break_width(a) active_width[(a)]=break_width[(a)]
+
+#define new_delta_to_break_width(a) \
+ varmem[(q+(a))].cint=break_width[(a)]-cur_active_width[(a)]
+
+#define new_delta_from_break_width(a) \
+ varmem[(q+(a))].cint=cur_active_width[(a)]-break_width[(a)]
+
+#define copy_to_cur_active(a) cur_active_width[(a)]=active_width[(a)]
+
+#define combine_two_deltas(a) varmem[(prev_r+(a))].cint += varmem[(r+(a))].cint
+#define downdate_width(a) cur_active_width[(a)] -= varmem[(prev_r+(a))].cint
+#define update_active(a) active_width[(a)]+=varmem[(r+(a))].cint
+
+#define total_font_stretch cur_active_width[8]
+#define total_font_shrink cur_active_width[9]
+
+#define cal_margin_kern_var(a) { \
+ character(cp) = character((a)); \
+ font(cp) = font((a)); \
+ do_subst_font(cp, 1000); \
+ if (font(cp) != font((a))) \
+ margin_kern_stretch += (left_pw((a)) - left_pw(cp)); \
+ font(cp) = font((a)); \
+ do_subst_font(cp, -1000); \
+ if (font(cp) != font((a))) \
+ margin_kern_shrink += (left_pw(cp) - left_pw((a))); \
+}
+
+static void ext_try_break(
+ int pi,
+ quarterword break_type,
+ int line_break_dir,
+ int adjust_spacing,
+ int par_shape_ptr,
+ int adj_demerits,
+ int tracing_paragraphs,
+ int protrude_chars,
+ int line_penalty,
+ int last_line_fit,
+ int double_hyphen_demerits,
+ int final_hyphen_demerits, halfword first_p, halfword cur_p
+)
+{
+ /*tex runs through the active list */
+ pointer r;
+ scaled margin_kern_stretch;
+ scaled margin_kern_shrink;
+ halfword lp, rp, cp;
+ /*tex stays a step behind |r| */
+ halfword prev_r = active;
+ /*tex a step behind |prev_r|, if |type(prev_r)=delta_node| */
+ halfword prev_prev_r = null;
+ /*tex maximum line number in current equivalence class of lines */
+ halfword old_l = 0;
+ /*tex have we found a feasible break at |cur_p|? */
+ boolean no_break_yet = true;
+ /*tex points to a new node being created */
+ halfword q;
+ /*tex line number of current active node */
+ halfword l;
+ /*tex should node |r| remain in the active list? */
+ boolean node_r_stays_active;
+ /*tex the current line will be justified to this width */
+ scaled line_width = 0;
+ /*tex possible fitness class of test line */
+ fitness_value fit_class;
+ /*tex badness of test line */
+ halfword b;
+ /*tex demerits of test line */
+ int d;
+ /*tex has |d| been forced to zero? */
+ boolean artificial_demerits;
+ /*tex used in badness calculations */
+ scaled shortfall;
+ /*tex glue stretch or shrink of test line, adjustment for last line */
+ scaled g = 0;
+ /*tex distance from current active node */
+ scaled cur_active_width[10] = { 0 };
+ /*tex Make sure that |pi| is in the proper range; */
+ if (pi >= inf_penalty) {
+ /*tex this breakpoint is inhibited by infinite penalty */
+ return;
+ } else if (pi <= -inf_penalty) {
+ /*tex this breakpoint will be forced */
+ pi = eject_penalty;
+ }
+
+ do_all_eight(copy_to_cur_active);
+
+ while (1) {
+ r = vlink(prev_r);
+ /*tex
+
+ If node |r| is of type |delta_node|, update |cur_active_width|, set
+ |prev_r| and |prev_prev_r|, then |goto continue|. The following code
+ uses the fact that |type(active)<>delta_node|.
+
+ */
+ if (type(r) == delta_node) {
+ /*tex implicit */
+ do_all_eight(update_width);
+ prev_prev_r = prev_r;
+ prev_r = r;
+ continue;
+ }
+ /*tex
+
+ If a line number class has ended, create new active nodes for the
+ best feasible breaks in that class; then |return| if |r=active|,
+ otherwise compute the new |line_width|.
+
+ The first part of the following code is part of \TeX's inner loop, so
+ we don't want to waste any time. The current active node, namely node
+ |r|, contains the line number that will be considered next. At the
+ end of the list we have arranged the data structure so that
+ |r=active| and |line_number(active)>old_l|.
+
+ */
+ l = line_number(r);
+ if (l > old_l) {
+ /*tex now we are no longer in the inner loop */
+ if ((minimum_demerits < awful_bad)
+ && ((old_l != easy_line) || (r == active))) {
+ /*tex
+
+ Create new active nodes for the best feasible breaks just
+ found. It is not necessary to create new active nodes having
+ |minimal_demerits| greater than
+ |minimum_demerits+abs(adj_demerits)|, since such active nodes
+ will never be chosen in the final paragraph breaks. This
+ observation allows us to omit a substantial number of
+ feasible breakpoints from further consideration.
+
+ */
+ if (no_break_yet) {
+ no_break_yet = false;
+ do_all_eight(set_break_width_to_background);
+ compute_break_width(break_type, line_break_dir, adjust_spacing, cur_p);
+ }
+ /*tex
+
+ Insert a delta node to prepare for breaks at |cur_p|. We use
+ the fact that |type(active)<>delta_node|.
+
+ */
+ if (type(prev_r) == delta_node) {
+ /*tex modify an existing delta node */
+ do_all_eight(convert_to_break_width);
+ } else if (prev_r == active) {
+ /*tex no delta node needed at the beginning */
+ do_all_eight(store_break_width);
+ } else {
+ q = new_node(delta_node, 0);
+ vlink(q) = r;
+ do_all_eight(new_delta_to_break_width);
+ vlink(prev_r) = q;
+ prev_prev_r = prev_r;
+ prev_r = q;
+ }
+ if (abs(adj_demerits) >= awful_bad - minimum_demerits)
+ minimum_demerits = awful_bad - 1;
+ else
+ minimum_demerits += abs(adj_demerits);
+ for (fit_class = very_loose_fit; fit_class <= tight_fit;
+ fit_class++) {
+ if (minimal_demerits[fit_class] <= minimum_demerits) {
+ /*tex
+
+ Insert a new active node from |best_place[fit_class]|
+ to |cur_p|. When we create an active node, we also
+ create the corresponding passive node.
+
+ */
+ q = new_node(passive_node, 0);
+ vlink(q) = passive;
+ passive = q;
+ cur_break(q) = cur_p;
+ incr(pass_number);
+ serial(q) = pass_number;
+ prev_break(q) = best_place[fit_class];
+ /*tex
+
+ Here we keep track of the subparagraph penalties in
+ the break nodes.
+
+ */
+ passive_pen_inter(q) = internal_pen_inter;
+ passive_pen_broken(q) = internal_pen_broken;
+ passive_last_left_box(q) = internal_left_box;
+ passive_last_left_box_width(q) =
+ internal_left_box_width;
+ if (prev_break(q) != null) {
+ passive_left_box(q) = passive_last_left_box(prev_break(q));
+ passive_left_box_width(q) = passive_last_left_box_width(prev_break(q));
+ } else {
+ passive_left_box(q) = init_internal_left_box;
+ passive_left_box_width(q) = init_internal_left_box_width;
+ }
+ passive_right_box(q) = internal_right_box;
+ passive_right_box_width(q) = internal_right_box_width;
+ q = new_node(break_type, fit_class);
+ break_node(q) = passive;
+ line_number(q) = best_pl_line[fit_class] + 1;
+ total_demerits(q) = minimal_demerits[fit_class];
+ if (do_last_line_fit) {
+ /*tex
+
+ Store additional data in the new active node.
+ Here we save these data in the active node
+ representing a potential line break.
+
+ */
+ active_short(q) = best_pl_short[fit_class];
+ active_glue(q) = best_pl_glue[fit_class];
+ }
+ vlink(q) = r;
+ vlink(prev_r) = q;
+ prev_r = q;
+ if (tracing_paragraphs > 0)
+ print_break_node(q, fit_class, break_type, cur_p);
+ }
+ minimal_demerits[fit_class] = awful_bad;
+ }
+ minimum_demerits = awful_bad;
+ /*tex
+
+ Insert a delta node to prepare for the next active node. When
+ the following code is performed, we will have just inserted
+ at least one active node before |r|, so
+ |type(prev_r)<>delta_node|.
+
+ */
+ if (r != active) {
+ q = new_node(delta_node, 0);
+ vlink(q) = r;
+ do_all_eight(new_delta_from_break_width);
+ vlink(prev_r) = q;
+ prev_prev_r = prev_r;
+ prev_r = q;
+ }
+ }
+ if (r == active)
+ return;
+ /*tex
+
+ Compute the new line width. When we come to the following code,
+ we have just encountered the first active node~|r| whose
+ |line_number| field contains |l|. Thus we want to compute the
+ length of the $l\mskip1mu$th line of the current paragraph.
+ Furthermore, we want to set |old_l| to the last number in the
+ class of line numbers equivalent to~|l|.
+
+ */
+ if (l > easy_line) {
+ old_l = max_halfword - 1;
+ line_width = second_width;
+ } else {
+ old_l = l;
+ if (l > last_special_line) {
+ line_width = second_width;
+ } else if (par_shape_ptr == null) {
+ line_width = first_width;
+ } else {
+ line_width = varmem[(par_shape_ptr + 2 * l + 1)].cint;
+ }
+ }
+ }
+ /*tex
+
+ If a line number class has ended, create new active nodes for the
+ best feasible breaks in that class; then |return| if |r=active|,
+ otherwise compute the new |line_width|.
+
+ Consider the demerits for a line from |r| to |cur_p|; deactivate node
+ |r| if it should no longer be active; then |goto continue| if a line
+ from |r| to |cur_p| is infeasible, otherwise record a new feasible
+ break.
+
+ */
+ artificial_demerits = false;
+ shortfall = line_width - cur_active_width[1];
+ if (break_node(r) == null)
+ shortfall -= init_internal_left_box_width;
+ else
+ shortfall -= passive_last_left_box_width(break_node(r));
+ shortfall -= internal_right_box_width;
+ if (protrude_chars > 1) {
+ halfword l1, o;
+ l1 = (break_node(r) == null) ? first_p : cur_break(break_node(r));
+ if (cur_p == null) {
+ o = null;
+ } else {
+ o = alink(cur_p);
+ assert(vlink(o) == cur_p);
+ }
+ /*tex
+
+ The disc could be a SELECT subtype, to we might need to get the
+ last character as |pre_break| from either the |pre_break| list
+ (if the previous INIT disc was taken), or the |no_break| (sic)
+ list (if the previous INIT disc was not taken).
+
+ The last characters (hyphenation character) if these two list
+ should always be the same anyway, so we just look at |pre_break|.
+
+ Let's look at the right margin first.
+
+ */
+ if ((cur_p != null) && (type(cur_p) == disc_node) && (vlink_pre_break(cur_p) != null)) {
+ /*tex a |disc_node| with non-empty |pre_break|, protrude the last char of |pre_break| */
+ o = tlink_pre_break(cur_p);
+ } else {
+ o = find_protchar_right(l1, o);
+ }
+ /*tex now the left margin */
+ if ((l1 != null) && (type(l1) == disc_node) && (vlink_post_break(l1) != null)) {
+ /*tex The first char could be a disc! Protrude the first char. */
+ l1 = vlink_post_break(l1);
+ } else {
+ l1 = find_protchar_left(l1, true);
+ }
+ shortfall += (left_pw(l1) + right_pw(o));
+ }
+ if (shortfall != 0) {
+ margin_kern_stretch = 0;
+ margin_kern_shrink = 0;
+ if (protrude_chars > 1) {
+ /*tex Calculate variations of marginal kerns. */
+ lp = last_leftmost_char;
+ rp = last_rightmost_char;
+ cp = raw_glyph_node();
+ if (lp != null) {
+ cal_margin_kern_var(lp);
+ }
+ if (rp != null) {
+ cal_margin_kern_var(rp);
+ }
+ flush_node(cp);
+ }
+ if ((shortfall > 0) && ((total_font_stretch + margin_kern_stretch) > 0)) {
+ if ((total_font_stretch + margin_kern_stretch) > shortfall)
+ shortfall = ((total_font_stretch + margin_kern_stretch) / (max_stretch_ratio / cur_font_step)) / 2;
+ else
+ shortfall -= (total_font_stretch + margin_kern_stretch);
+ } else if ((shortfall < 0) && ((total_font_shrink + margin_kern_shrink) > 0)) {
+ if ((total_font_shrink + margin_kern_shrink) > -shortfall)
+ shortfall -= ((total_font_shrink + margin_kern_shrink) / (max_shrink_ratio / cur_font_step)) / 2;
+ else
+ shortfall += (total_font_shrink + margin_kern_shrink);
+ }
+ }
+ if (shortfall > 0) {
+ /*tex
+
+ Set the value of |b| to the badness for stretching the line, and
+ compute the corresponding |fit_class|.
+
+ When a line must stretch, the available stretchability can be
+ found in the subarray |cur_active_width[2..6]|, in units of
+ points, sfi, fil, fill and filll.
+
+ The present section is part of \TeX's inner loop, and it is most
+ often performed when the badness is infinite; therefore it is
+ worth while to make a quick test for large width excess and small
+ stretchability, before calling the |badness| subroutine.
+
+ */
+ if ((cur_active_width[3] != 0) || (cur_active_width[4] != 0) ||
+ (cur_active_width[5] != 0) || (cur_active_width[6] != 0)) {
+ if (do_last_line_fit) {
+ if (cur_p == null) {
+ /*tex
+
+ The last line of a paragraph. Perform computations
+ for last line and |goto found|.
+
+ Here we compute the adjustment |g| and badness |b|
+ for a line from |r| to the end of the paragraph. When
+ any of the criteria for adjustment is violated we
+ fall through to the normal algorithm.
+
+ The last line must be too short, and have infinite
+ stretch entirely due to |par_fill_skip|.
+
+ */
+ if ((active_short(r) == 0) || (active_glue(r) <= 0))
+ /*tex
+
+ Previous line was neither stretched nor shrunk,
+ or was infinitely bad.
+
+ */
+ goto NOT_FOUND;
+ if ((cur_active_width[3] != fill_width[0]) || (cur_active_width[4] != fill_width[1]) ||
+ (cur_active_width[5] != fill_width[2]) || (cur_active_width[6] != fill_width[3]))
+ /*tex
+
+ Infinite stretch of this line not entirely due to |par_fill_skip|.
+
+ */
+ goto NOT_FOUND;
+ if (active_short(r) > 0)
+ g = cur_active_width[2];
+ else
+ g = cur_active_width[7];
+ if (g <= 0)
+ /*tex No finite stretch resp.\ no shrink. */
+ goto NOT_FOUND;
+ arith_error = false;
+ g = fract(g, active_short(r), active_glue(r),
+ max_dimen);
+ if (last_line_fit < 1000)
+ g = fract(g, last_line_fit, 1000, max_dimen);
+ if (arith_error) {
+ if (active_short(r) > 0)
+ g = max_dimen;
+ else
+ g = -max_dimen;
+ }
+ if (g > 0) {
+ /*tex
+
+ Set the value of |b| to the badness of the last
+ line for stretching, compute the corresponding
+ |fit_class, and |goto found|. These badness
+ computations are rather similar to those of the
+ standard algorithm, with the adjustment amount
+ |g| replacing the |shortfall|.
+
+ */
+ if (g > shortfall)
+ g = shortfall;
+ if (g > 7230584) {
+ if (cur_active_width[2] < 1663497) {
+ b = inf_bad;
+ fit_class = very_loose_fit;
+ goto FOUND;
+ }
+ }
+ b = badness(g, cur_active_width[2]);
+ if (b > 99) {
+ fit_class = very_loose_fit;
+ } else if (b > 12) {
+ fit_class = loose_fit;
+ } else {
+ fit_class = decent_fit;
+ }
+ goto FOUND;
+ } else if (g < 0) {
+ /*tex
+
+ Set the value of |b| to the badness of the last
+ line for shrinking, compute the corresponding
+ |fit_class, and |goto found||.
+
+ */
+ if (-g > cur_active_width[7])
+ g = -cur_active_width[7];
+ b = badness(-g, cur_active_width[7]);
+ if (b > 12)
+ fit_class = tight_fit;
+ else
+ fit_class = decent_fit;
+ goto FOUND;
+ }
+ }
+ NOT_FOUND:
+ shortfall = 0;
+ }
+ b = 0;
+ /*tex Infinite stretch. */
+ fit_class = decent_fit;
+ } else if (shortfall > 7230584 && cur_active_width[2] < 1663497) {
+ b = inf_bad;
+ fit_class = very_loose_fit;
+ } else {
+ b = badness(shortfall, cur_active_width[2]);
+ if (b > 99) {
+ fit_class = very_loose_fit;
+ } else if (b > 12) {
+ fit_class = loose_fit;
+ } else {
+ fit_class = decent_fit;
+ }
+ }
+ } else {
+ /*tex
+
+ Set the value of |b| to the badness for shrinking the line, and
+ compute the corresponding |fit_class|. Shrinkability is never
+ infinite in a paragraph; we can shrink the line from |r| to
+ |cur_p| by at most |cur_active_width[7]|.
+
+ */
+ if (-shortfall > cur_active_width[7])
+ b = inf_bad + 1;
+ else
+ b = badness(-shortfall, cur_active_width[7]);
+ if (b > 12)
+ fit_class = tight_fit;
+ else
+ fit_class = decent_fit;
+ }
+ if (do_last_line_fit) {
+ /*tex Adjust the additional data for last line; */
+ if (cur_p == null)
+ shortfall = 0;
+ if (shortfall > 0) {
+ g = cur_active_width[2];
+ } else if (shortfall < 0) {
+ g = cur_active_width[7];
+ } else {
+ g = 0;
+ }
+ }
+ FOUND:
+ if ((b > inf_bad) || (pi == eject_penalty)) {
+ /*tex
+
+ Prepare to deactivate node~|r|, and |goto deactivate| unless
+ there is a reason to consider lines of text from |r| to |cur_p|.
+ During the final pass, we dare not lose all active nodes, lest we
+ lose touch with the line breaks already found. The code shown
+ here makes sure that such a catastrophe does not happen, by
+ permitting overfull boxes as a last resort. This particular part
+ of \TeX\ was a source of several subtle bugs before the correct
+ program logic was finally discovered; readers who seek to
+ ``improve'' \TeX\ should therefore think thrice before daring to
+ make any changes here.
+
+ */
+ if (final_pass && (minimum_demerits == awful_bad) &&
+ (vlink(r) == active) && (prev_r == active)) {
+ /*tex Set demerits zero, this break is forced. */
+ artificial_demerits = true;
+ } else if (b > threshold) {
+ goto DEACTIVATE;
+ }
+ node_r_stays_active = false;
+ } else {
+ prev_r = r;
+ if (b > threshold)
+ continue;
+ node_r_stays_active = true;
+ }
+ /*tex
+
+ Record a new feasible break. When we get to this part of the code,
+ the line from |r| to |cur_p| is feasible, its badness is~|b|, and its
+ fitness classification is |fit_class|. We don't want to make an
+ active node for this break yet, but we will compute the total
+ demerits and record them in the |minimal_demerits| array, if such a
+ break is the current champion among all ways to get to |cur_p| in a
+ given line-number class and fitness class.
+
+ */
+ if (artificial_demerits) {
+ d = 0;
+ } else {
+ /*tex Compute the demerits, |d|, from |r| to |cur_p|. */
+ d = line_penalty + b;
+ if (abs(d) >= 10000)
+ d = 100000000;
+ else
+ d = d * d;
+ if (pi != 0) {
+ if (pi > 0) {
+ d += (pi * pi);
+ } else if (pi > eject_penalty) {
+ d -= (pi * pi);
+ }
+ }
+ if ((break_type == hyphenated_node) && (type(r) == hyphenated_node)) {
+ if (cur_p != null)
+ d += double_hyphen_demerits;
+ else
+ d += final_hyphen_demerits;
+ }
+ if (abs(fit_class - fitness(r)) > 1)
+ d = d + adj_demerits;
+ }
+ if (tracing_paragraphs > 0) {
+ print_feasible_break(cur_p, r, b, pi, d, artificial_demerits);
+ }
+ /*tex This is the minimum total demerits from the beginning to |cur_p| via |r|. */
+ d += total_demerits(r);
+ if (d <= minimal_demerits[fit_class]) {
+ minimal_demerits[fit_class] = d;
+ best_place[fit_class] = break_node(r);
+ best_pl_line[fit_class] = l;
+ if (do_last_line_fit) {
+ /*tex
+
+ Store additional data for this feasible break. For each
+ feasible break we record the shortfall and glue stretch or
+ shrink (or adjustment).
+
+ */
+ best_pl_short[fit_class] = shortfall;
+ best_pl_glue[fit_class] = g;
+ }
+ if (d < minimum_demerits)
+ minimum_demerits = d;
+ }
+ /*tex Record a new feasible break. */
+ if (node_r_stays_active) {
+ /*tex |prev_r| has been set to |r|. */
+ continue;
+ }
+ DEACTIVATE:
+ /*tex
+
+ Deactivate node |r|. When an active node disappears, we must delete
+ an adjacent delta node if the active node was at the beginning or the
+ end of the active list, or if it was surrounded by delta nodes. We
+ also must preserve the property that |cur_active_width| represents
+ the length of material from |vlink(prev_r)| to~|cur_p|.
+
+ */
+ vlink(prev_r) = vlink(r);
+ flush_node(r);
+ if (prev_r == active) {
+ /*tex
+
+ Update the active widths, since the first active node has been
+ deleted. The following code uses the fact that
+ |type(active)<>delta_node|. If the active list has just become
+ empty, we do not need to update the |active_width| array, since
+ it will be initialized when an active node is next inserted.
+
+ */
+ r = vlink(active);
+ if (type(r) == delta_node) {
+ do_all_eight(update_active);
+ do_all_eight(copy_to_cur_active);
+ vlink(active) = vlink(r);
+ flush_node(r);
+ }
+ } else if (type(prev_r) == delta_node) {
+ r = vlink(prev_r);
+ if (r == active) {
+ do_all_eight(downdate_width);
+ vlink(prev_prev_r) = active;
+ flush_node(prev_r);
+ prev_r = prev_prev_r;
+ } else if (type(r) == delta_node) {
+ do_all_eight(update_width);
+ do_all_eight(combine_two_deltas);
+ vlink(prev_r) = vlink(r);
+ flush_node(r);
+ }
+ }
+ }
+}
+
+void ext_do_line_break(
+ int paragraph_dir,
+ int pretolerance,
+ int tracing_paragraphs,
+ int tolerance,
+ scaled emergency_stretch,
+ int looseness,
+ int adjust_spacing,
+ halfword par_shape_ptr,
+ int adj_demerits,
+ int protrude_chars,
+ int line_penalty,
+ int last_line_fit,
+ int double_hyphen_demerits,
+ int final_hyphen_demerits,
+ int hang_indent,
+ int hsize,
+ int hang_after,
+ halfword left_skip,
+ halfword right_skip,
+ halfword inter_line_penalties_ptr,
+ int inter_line_penalty,
+ int club_penalty,
+ halfword club_penalties_ptr,
+ halfword widow_penalties_ptr,
+ int widow_penalty,
+ int broken_penalty,
+ halfword final_par_glue
+)
+{
+ /*tex Miscellaneous nodes of temporary interest. */
+ halfword cur_p, q, r, s;
+ int line_break_dir = paragraph_dir;
+ /*tex Get ready to start */
+ minimum_demerits = awful_bad;
+ minimal_demerits[tight_fit] = awful_bad;
+ minimal_demerits[decent_fit] = awful_bad;
+ minimal_demerits[loose_fit] = awful_bad;
+ minimal_demerits[very_loose_fit] = awful_bad;
+ fewest_demerits = 0;
+ actual_looseness = 0;
+ /*tex
+
+ We compute the values of |easy_line| and the other local variables
+ relating to line length when the |line_break| procedure is initializing
+ itself.
+
+ */
+ if (par_shape_ptr == null) {
+ if (hang_indent == 0) {
+ last_special_line = 0;
+ second_width = hsize;
+ second_indent = 0;
+ } else {
+ halfword used_hang_indent = swap_hang_indent(hang_indent);
+ /*tex
+
+ Set line length parameters in preparation for hanging
+ indentation. We compute the values of |easy_line| and the other
+ local variables relating to line length when the |line_break|
+ procedure is initializing itself.
+
+ */
+ last_special_line = abs(hang_after);
+ if (hang_after < 0) {
+ first_width = hsize - abs(used_hang_indent);
+ if (used_hang_indent >= 0)
+ first_indent = used_hang_indent;
+ else
+ first_indent = 0;
+ second_width = hsize;
+ second_indent = 0;
+ } else {
+ first_width = hsize;
+ first_indent = 0;
+ second_width = hsize - abs(used_hang_indent);
+ if (used_hang_indent >= 0)
+ second_indent = used_hang_indent;
+ else
+ second_indent = 0;
+ }
+ }
+ } else {
+ last_special_line = vinfo(par_shape_ptr + 1) - 1;
+ second_indent = varmem[(par_shape_ptr + 2 * (last_special_line + 1))].cint;
+ second_width = varmem[(par_shape_ptr + 2 * (last_special_line + 1) + 1)].cint;
+ second_indent = swap_parshape_indent(second_indent,second_width);
+ }
+ if (looseness == 0)
+ easy_line = last_special_line;
+ else
+ easy_line = max_halfword;
+ no_shrink_error_yet = true;
+ check_shrinkage(left_skip);
+ check_shrinkage(right_skip);
+ q = left_skip;
+ r = right_skip;
+ background[1] = width(q) + width(r);
+ background[2] = 0;
+ background[3] = 0;
+ background[4] = 0;
+ background[5] = 0;
+ background[6] = 0;
+ background[2 + stretch_order(q)] = stretch(q);
+ background[2 + stretch_order(r)] += stretch(r);
+ background[7] = shrink(q) + shrink(r);
+ if (adjust_spacing > 1) {
+ background[8] = 0;
+ background[9] = 0;
+ max_stretch_ratio = -1;
+ max_shrink_ratio = -1;
+ cur_font_step = -1;
+ set_prev_char_p(null);
+ }
+ /*tex
+
+ Check for special treatment of last line of paragraph. The new algorithm
+ for the last line requires that the stretchability |par_fill_skip| is
+ infinite and the stretchability of |left_skip| plus |right_skip| is
+ finite.
+
+ */
+ do_last_line_fit = false;
+ if (last_line_fit > 0) {
+ q = last_line_fill;
+ if ((stretch(q) > 0) && (stretch_order(q) > normal)) {
+ if ((background[3] == 0) && (background[4] == 0) && (background[5] == 0) && (background[6] == 0)) {
+ do_last_line_fit = true;
+ fill_width[0] = 0;
+ fill_width[1] = 0;
+ fill_width[2] = 0;
+ fill_width[3] = 0;
+ fill_width[stretch_order(q) - 1] = stretch(q);
+ }
+ }
+ }
+ /*tex Initialize |dir_ptr| for |line_break|. */
+ if (dir_ptr != null) {
+ flush_node_list(dir_ptr);
+ dir_ptr = null;
+ }
+ /*tex Find optimal breakpoints. */
+ threshold = pretolerance;
+ if (threshold >= 0) {
+ if (tracing_paragraphs > 0) {
+ begin_diagnostic();
+ tprint_nl("@firstpass");
+ }
+ second_pass = false;
+ final_pass = false;
+ } else {
+ threshold = tolerance;
+ second_pass = true;
+ final_pass = (emergency_stretch <= 0);
+ if (tracing_paragraphs > 0)
+ begin_diagnostic();
+ }
+ while (1) {
+ halfword first_p;
+ halfword nest_stack[10];
+ int nest_index = 0;
+ if (threshold > inf_bad)
+ threshold = inf_bad;
+ /*tex Create an active breakpoint representing the beginning of the paragraph. */
+ q = new_node(unhyphenated_node, decent_fit);
+ vlink(q) = active;
+ break_node(q) = null;
+ line_number(q) = cur_list.pg_field + 1;
+ total_demerits(q) = 0;
+ active_short(q) = 0;
+ active_glue(q) = 0;
+ vlink(active) = q;
+ do_all_eight(store_background);
+ passive = null;
+ printed_node = temp_head;
+ pass_number = 0;
+ font_in_short_display = null_font;
+ /*tex Create an active breakpoint representing the beginning of the paragraph. */
+ auto_breaking = true;
+ cur_p = vlink(temp_head);
+ /*tex Initialize with first |local_paragraph| node. */
+ if ((cur_p != null) && (type(cur_p) == local_par_node)) {
+ /*tex This used to be an assert, but may as well force it. */
+ alink(cur_p) = temp_head;
+ internal_pen_inter = local_pen_inter(cur_p);
+ internal_pen_broken = local_pen_broken(cur_p);
+ init_internal_left_box = local_box_left(cur_p);
+ init_internal_left_box_width = local_box_left_width(cur_p);
+ internal_left_box = init_internal_left_box;
+ internal_left_box_width = init_internal_left_box_width;
+ internal_right_box = local_box_right(cur_p);
+ internal_right_box_width = local_box_right_width(cur_p);
+ } else {
+ internal_pen_inter = 0;
+ internal_pen_broken = 0;
+ init_internal_left_box = null;
+ init_internal_left_box_width = 0;
+ internal_left_box = init_internal_left_box;
+ internal_left_box_width = init_internal_left_box_width;
+ internal_right_box = null;
+ internal_right_box_width = 0;
+ }
+ /*tex Initialize with first |local_paragraph| node. */
+ set_prev_char_p(null);
+ first_p = cur_p;
+ /*tex
+
+ To access the first node of paragraph as the first active node has
+ |break_node=null|.
+
+ */
+ while ((cur_p != null) && (vlink(active) != active)) {
+ /*tex
+
+ |try_break| if |cur_p| is a legal breakpoint; on the 2nd pass,
+ also look at |disc_node|s.
+
+ */
+ while (is_char_node(cur_p)) {
+ /*tex
+
+ Advance |cur_p| to the node following the present string of
+ characters. The code that passes over the characters of words
+ in a paragraph is part of \TeX's inner loop, so it has been
+ streamlined for speed. We use the fact that
+ `\.{\\parfillskip}' glue appears at the end of each
+ paragraph; it is therefore unnecessary to check if
+ |vlink(cur_p)=null| when |cur_p| is a character node.
+
+ */
+ active_width[1] += pack_width(line_break_dir, dir_TRT, cur_p, true);
+ if ((adjust_spacing > 1) && check_expand_pars(font(cur_p))) {
+ set_prev_char_p(cur_p);
+ add_char_stretch(active_width[8], cur_p);
+ add_char_shrink(active_width[9], cur_p);
+ }
+ cur_p = vlink(cur_p);
+ while (cur_p == null && nest_index > 0) {
+ cur_p = nest_stack[--nest_index];
+ }
+ }
+ if (cur_p == null) {
+ normal_error("linebreak","invalid list tail, probably missing glue");
+ }
+ /*tex
+
+ Determine legal breaks: As we move through the hlist, we need to
+ keep the |active_width| array up to date, so that the badness of
+ individual lines is readily calculated by |try_break|. It is
+ convenient to use the short name |active_width[1]| for the
+ component of active width that represents real width as opposed
+ to glue.
+
+ */
+ switch (type(cur_p)) {
+ case hlist_node:
+ case vlist_node:
+ active_width[1] += pack_width(line_break_dir, box_dir(cur_p), cur_p, false);
+ break;
+ case rule_node:
+ active_width[1] += width(cur_p);
+ break;
+ case dir_node:
+ /*tex Adjust the dir stack for the |line_break| routine. */
+ if (subtype(cur_p) == normal_dir) {
+ line_break_dir = dir_dir(cur_p);
+ /* Adds to |dir_ptr|. */
+ push_dir_node(dir_ptr,cur_p);
+ } else {
+ pop_dir_node(dir_ptr);
+ if (dir_ptr != null) {
+ line_break_dir = dir_dir(dir_ptr);
+ }
+ }
+ break;
+ case local_par_node:
+ /*tex Advance past a |local_paragraph| node. */
+ internal_pen_inter = local_pen_inter(cur_p);
+ internal_pen_broken = local_pen_broken(cur_p);
+ internal_left_box = local_box_left(cur_p);
+ internal_left_box_width = local_box_left_width(cur_p);
+ internal_right_box = local_box_right(cur_p);
+ internal_right_box_width = local_box_right_width(cur_p);
+ break;
+ case math_node:
+ auto_breaking = (subtype(cur_p) == after);
+ /*tex begin mathskip code */
+ if (glue_is_zero(cur_p) || ignore_math_skip(cur_p)) {
+ kern_break();
+ break;
+ } else {
+ /*tex fall through */
+ }
+ /*tex end mathskip code */
+ case glue_node:
+ /*tex
+
+ If node |cur_p| is a legal breakpoint, call |try_break|;
+ then update the active widths by including the glue in
+ |glue_ptr(cur_p)|.
+
+ When node |cur_p| is a glue node, we look at the previous
+ to see whether or not a breakpoint is legal at |cur_p|,
+ as explained above.
+
+ We only break after certain nodes (see texnodes.h), a
+ font related kern and a dir node when
+ |\breakafterdirmode=1|.
+
+ */
+ if (auto_breaking) {
+ halfword prev_p = alink(cur_p);
+ if (prev_p != temp_head && (is_char_node(prev_p)
+ || precedes_break(prev_p) || precedes_kern(prev_p) || precedes_dir(prev_p))) {
+ ext_try_break(
+ 0,
+ unhyphenated_node,
+ line_break_dir,
+ adjust_spacing,
+ par_shape_ptr,
+ adj_demerits,
+ tracing_paragraphs,
+ protrude_chars,
+ line_penalty,
+ last_line_fit,
+ double_hyphen_demerits,
+ final_hyphen_demerits,
+ first_p,
+ cur_p
+ );
+ }
+ }
+ check_shrinkage(cur_p);
+ active_width[1] += width(cur_p);
+ active_width[2 + stretch_order(cur_p)] += stretch(cur_p);
+ active_width[7] += shrink(cur_p);
+ break;
+ case kern_node:
+ if (subtype(cur_p) == explicit_kern || subtype(cur_p) == italic_kern) {
+ kern_break();
+ } else {
+ active_width[1] += width(cur_p);
+ if ((adjust_spacing == 2) && (subtype(cur_p) == normal)) {
+ add_kern_stretch(active_width[8], cur_p);
+ add_kern_shrink(active_width[9], cur_p);
+ }
+ }
+ break;
+ case disc_node:
+ /*tex
+
+ |select_disc|s are handled by the leading |init_disc|.
+
+ */
+ if (subtype(cur_p) == select_disc)
+ break;
+ /*tex
+
+ Try to break after a discretionary fragment, then |goto
+ done5|. The following code knows that discretionary texts
+ contain only character nodes, kern nodes, box nodes, and
+ rule nodes. This branch differs a bit from older engines
+ because in \LUATEX\ we already have hyphenated the list.
+ This means that we need to skip automatic disc nodes. Of
+ better, we need to treat discretionaries and explicit
+ hyphens always, even in the first pass.
+
+ */
+ if (second_pass || subtype(cur_p) <= automatic_disc) {
+ int actual_penalty = (int) disc_penalty(cur_p);
+ s = vlink_pre_break(cur_p);
+ do_one_seven_eight(reset_disc_width);
+ if (s == null) {
+ /*tex trivial pre-break */
+ ext_try_break(actual_penalty, hyphenated_node,
+ line_break_dir, adjust_spacing,
+ par_shape_ptr, adj_demerits,
+ tracing_paragraphs, protrude_chars,
+ line_penalty, last_line_fit,
+ double_hyphen_demerits,
+ final_hyphen_demerits, first_p, cur_p);
+ } else {
+ add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
+ do_one_seven_eight(add_disc_width_to_active_width);
+ ext_try_break(actual_penalty, hyphenated_node,
+ line_break_dir, adjust_spacing,
+ par_shape_ptr, adj_demerits,
+ tracing_paragraphs, protrude_chars,
+ line_penalty, last_line_fit,
+ double_hyphen_demerits,
+ final_hyphen_demerits, first_p, cur_p);
+ if (subtype(cur_p) == init_disc) {
+ /*tex
+
+ We should at two break points after the one
+ we added above:
+
+ \startitemize[n]
+ \startitem
+ which does a possible break in INIT's
+ |post_break|
+ \stopitem
+ \startitem
+ which means the |no_break| actually
+ was broken just a character later
+ \stopitem
+ \stopitemize
+
+ Do the select-0 case |f-f-i|:
+
+ */
+ s = vlink_pre_break(vlink(cur_p));
+ add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
+ ext_try_break(actual_penalty, hyphenated_node,
+ line_break_dir, adjust_spacing,
+ par_shape_ptr, adj_demerits,
+ tracing_paragraphs,
+ protrude_chars, line_penalty,
+ last_line_fit, double_hyphen_demerits,
+ final_hyphen_demerits, first_p,
+ vlink(cur_p));
+ /*tex This does not work. */
+#if 0
+ /*tex Go back to the starting situation. */
+ do_one_seven_eight(sub_disc_width_from_active_width);
+ do_one_seven_eight(reset_disc_width);
+ /*tex Add select |no_break| to |active_width|. */
+ s = vlink_no_break(vlink(cur_p));
+ add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
+ ext_try_break(actual_penalty, hyphenated_node,
+ line_break_dir, adjust_spacing,
+ par_shape_ptr, adj_demerits,
+ tracing_paragraphs,
+ protrude_chars, line_penalty,
+ last_line_fit, double_hyphen_demerits,
+ final_hyphen_demerits, first_p,
+ vlink(cur_p));
+#endif
+ }
+ do_one_seven_eight(sub_disc_width_from_active_width);
+ }
+ }
+ s = vlink_no_break(cur_p);
+ add_to_widths(s, line_break_dir, adjust_spacing, active_width);
+ break;
+ case penalty_node:
+ ext_try_break(penalty(cur_p), unhyphenated_node, line_break_dir,
+ adjust_spacing, par_shape_ptr, adj_demerits,
+ tracing_paragraphs, protrude_chars,
+ line_penalty, last_line_fit,
+ double_hyphen_demerits, final_hyphen_demerits,
+ first_p, cur_p);
+ break;
+ case boundary_node:
+ case whatsit_node:
+ /*tex Advance past a whatsit node in the |line_break| loop. */
+ case mark_node:
+ case ins_node:
+ case adjust_node:
+ break;
+ case glue_spec_node:
+ normal_warning("parbuilder","found a glue_spec in a paragraph");
+ break;
+ default:
+ formatted_error("parbuilder","weird node %d in paragraph",type(cur_p));
+ }
+ cur_p = vlink(cur_p);
+ while (cur_p == null && nest_index > 0) {
+ cur_p = nest_stack[--nest_index];
+ }
+ }
+ if (cur_p == null) {
+ /*tex
+
+ Try the final line break at the end of the paragraph, and |goto
+ done| if the desired breakpoints have been found.
+
+ The forced line break at the paragraph's end will reduce the list
+ of breakpoints so that all active nodes represent breaks at
+ |cur_p=null|. On the first pass, we insist on finding an active
+ node that has the correct ``looseness.'' On the final pass, there
+ will be at least one active node, and we will match the desired
+ looseness as well as we can.
+
+ The global variable |best_bet| will be set to the active node for
+ the best way to break the paragraph, and a few other variables
+ are used to help determine what is best.
+
+ */
+ ext_try_break(eject_penalty, hyphenated_node, line_break_dir,
+ adjust_spacing, par_shape_ptr, adj_demerits,
+ tracing_paragraphs, protrude_chars, line_penalty,
+ last_line_fit, double_hyphen_demerits,
+ final_hyphen_demerits, first_p, cur_p);
+ if (vlink(active) != active) {
+ /*tex Find an active node with fewest demerits; */
+ r = vlink(active);
+ fewest_demerits = awful_bad;
+ do {
+ if (type(r) != delta_node) {
+ if (total_demerits(r) < fewest_demerits) {
+ fewest_demerits = total_demerits(r);
+ best_bet = r;
+ }
+ }
+ r = vlink(r);
+ } while (r != active);
+ best_line = line_number(best_bet);
+ /*tex
+ Find an active node with fewest demerits;
+ */
+ if (looseness == 0)
+ goto DONE;
+ /*tex
+
+ Find the best active node for the desired looseness;
+
+ The adjustment for a desired looseness is a slightly more
+ complicated version of the loop just considered. Note that if
+ a paragraph is broken into segments by displayed equations,
+ each segment will be subject to the looseness calculation,
+ independently of the other segments.
+
+ */
+ r = vlink(active);
+ actual_looseness = 0;
+ do {
+ if (type(r) != delta_node) {
+ line_diff = line_number(r) - best_line;
+ if (((line_diff < actual_looseness)
+ && (looseness <= line_diff))
+ || ((line_diff > actual_looseness)
+ && (looseness >= line_diff))) {
+ best_bet = r;
+ actual_looseness = line_diff;
+ fewest_demerits = total_demerits(r);
+ } else if ((line_diff == actual_looseness) &&
+ (total_demerits(r) < fewest_demerits)) {
+ best_bet = r;
+ fewest_demerits = total_demerits(r);
+ }
+ }
+ r = vlink(r);
+ } while (r != active);
+ best_line = line_number(best_bet);
+ /*tex
+ Find the best active node for the desired looseness.
+ */
+ if ((actual_looseness == looseness) || final_pass)
+ goto DONE;
+ }
+ }
+ /*tex Clean up the memory by removing the break nodes. */
+ clean_up_the_memory();
+ /*tex Clean up the memory by removing the break nodes. */
+ if (!second_pass) {
+ if (tracing_paragraphs > 0)
+ tprint_nl("@secondpass");
+ threshold = tolerance;
+ second_pass = true;
+ final_pass = (emergency_stretch <= 0);
+ } else {
+ /*tex If at first you do not succeed, then: */
+ if (tracing_paragraphs > 0)
+ tprint_nl("@emergencypass");
+ background[2] += emergency_stretch;
+ final_pass = true;
+ }
+ }
+
+ DONE:
+ if (tracing_paragraphs > 0) {
+ end_diagnostic(true);
+ normalize_selector();
+ }
+ if (do_last_line_fit) {
+ /*tex
+ Adjust the final line of the paragraph; here we either reset
+ |do_last_line_fit| or adjust the |par_fill_skip| glue.
+ */
+ if (active_short(best_bet) == 0) {
+ do_last_line_fit = false;
+ } else {
+ width(last_line_fill) += (active_short(best_bet) - active_glue(best_bet));
+ stretch(last_line_fill) = 0;
+ }
+ }
+ /*tex
+ Break the paragraph at the chosen. Once the best sequence of
+ breakpoints has been found (hurray), we call on the procedure
+ |post_line_break| to finish the remainder of the work. By introducing
+ this subprocedure, we are able to keep |line_break| from getting
+ extremely long.
+
+ the first thing |ext_post_line_break| does is reset |dir_ptr|.
+
+ */
+ flush_node_list(dir_ptr);
+ dir_ptr = null;
+ ext_post_line_break(paragraph_dir,
+ right_skip,
+ left_skip,
+ protrude_chars,
+ par_shape_ptr,
+ adjust_spacing,
+ inter_line_penalties_par_ptr,
+ inter_line_penalty,
+ club_penalty,
+ club_penalties_ptr,
+ widow_penalties_ptr,
+ widow_penalty,
+ broken_penalty,
+ final_par_glue,
+ best_bet,
+ last_special_line,
+ second_width,
+ second_indent, first_width, first_indent, best_line);
+ /*tex
+
+ Clean up the memory by removing the break nodes.
+
+ */
+ clean_up_the_memory();
+}
+
+void get_linebreak_info (int *f, int *a)
+{
+ *f = fewest_demerits;
+ *a = actual_looseness;
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/linebreak.w b/Build/source/texk/web2c/luatexdir/tex/linebreak.w
deleted file mode 100644
index 345a1a42456..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/linebreak.w
+++ /dev/null
@@ -1,2164 +0,0 @@
-% linebreak.w
-%
-% 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"
-
-@ We come now to what is probably the most interesting algorithm of \TeX:
-the mechanism for choosing the ``best possible'' breakpoints that yield
-the individual lines of a paragraph. \TeX's line-breaking algorithm takes
-a given horizontal list and converts it to a sequence of boxes that are
-appended to the current vertical list. In the course of doing this, it
-creates a special data structure containing three kinds of records that are
-not used elsewhere in \TeX. Such nodes are created while a paragraph is
-being processed, and they are destroyed afterwards; thus, the other parts
-of \TeX\ do not need to know anything about how line-breaking is done.
-
-The method used here is based on an approach devised by Michael F. Plass and
-@^Plass, Michael Frederick@>
-@^Knuth, Donald Ervin@>
-the author in 1977, subsequently generalized and improved by the same two
-people in 1980. A detailed discussion appears in {\sl SOFTWARE---Practice
-\AM\ Experience \bf11} (1981), 1119--1184, where it is shown that the
-line-breaking problem can be regarded as a special case of the problem of
-computing the shortest path in an acyclic network. The cited paper includes
-numerous examples and describes the history of line breaking as it has been
-practiced by printers through the ages. The present implementation adds two
-new ideas to the algorithm of 1980: Memory space requirements are considerably
-reduced by using smaller records for inactive nodes than for active ones,
-and arithmetic overflow is avoided by using ``delta distances'' instead of
-keeping track of the total distance from the beginning of the paragraph to the
-current point.
-
-The |line_break| procedure should be invoked only in horizontal mode; it
-leaves that mode and places its output into the current vlist of the
-enclosing vertical mode (or internal vertical mode).
-There is one explicit parameter: |d| is true for partial paragraphs
-preceding display math mode; in this case the amount of additional
-penalty inserted before the final line is |display_widow_penalty|
-instead of |widow_penalty|.
-
-There are also a number of implicit parameters: The hlist to be broken
-starts at |vlink(head)|, and it is nonempty. The value of |prev_graf| in the
-enclosing semantic level tells where the paragraph should begin in the
-sequence of line numbers, in case hanging indentation or \.{\\parshape}
-are in use; |prev_graf| is zero unless this paragraph is being continued
-after a displayed formula. Other implicit parameters, such as the
-|par_shape_ptr| and various penalties to use for hyphenation, etc., appear
-in |eqtb|.
-
-After |line_break| has acted, it will have updated the current vlist and the
-value of |prev_graf|. Furthermore, the global variable |just_box| will
-point to the final box created by |line_break|, so that the width of this
-line can be ascertained when it is necessary to decide whether to use
-|above_display_skip| or |above_display_short_skip| before a displayed formula.
-
-@c
-halfword just_box; /* the |hlist_node| for the last line of the new paragraph */
-
-@ In it's complete form, |line_break| is a rather lengthy
-procedure---sort of a small world unto itself---we must build it up
-little by little. Below you see only the general outline.
-
-The main task performed here is to move the list from |head| to
-|temp_head| and go into the enclosing semantic level. We also append
-the \.{\\parfillskip} glue to the end of the paragraph, removing a
-space (or other glue node) if it was there, since spaces usually
-precede blank lines and instances of `\.{\$\$}'. The |par_fill_skip|
-is preceded by an infinite penalty, so it will never be considered as
-a potential breakpoint.
-
-That code assumes that a |glue_node| and a |penalty_node| occupy the
-same number of |mem|~words.
-@^data structure assumptions@>
-
-Most other processing is delegated to external functions.
-
-@c
-void line_break(boolean d, int line_break_context)
-{
- int paragraph_dir = 0; /* main direction of paragraph */
- halfword final_par_glue;
- halfword start_of_par;
- int callback_id;
- pack_begin_line = cur_list.ml_field; /* this is for over/underfull box messages */
- alink(temp_head) = null; /* hh-ls */
- vlink(temp_head) = vlink(cur_list.head_field);
- new_hyphenation(temp_head, cur_list.tail_field);
- cur_list.tail_field = new_ligkern(temp_head, cur_list.tail_field);
- if (is_char_node(cur_list.tail_field)) {
- tail_append(new_penalty(inf_penalty,line_penalty));
- } else if (type(cur_list.tail_field) != glue_node) {
- tail_append(new_penalty(inf_penalty,line_penalty));
- } else {
- halfword t = alink(cur_list.tail_field);
- flush_node(cur_list.tail_field);
- cur_list.tail_field = t;
- tail_append(new_penalty(inf_penalty,line_penalty));
- }
- final_par_glue = new_param_glue(par_fill_skip_code);
- couple_nodes(cur_list.tail_field, final_par_glue);
- cur_list.tail_field = vlink(cur_list.tail_field);
- lua_node_filter(pre_linebreak_filter_callback,
- line_break_context, temp_head,
- addressof(cur_list.tail_field));
- last_line_fill = cur_list.tail_field;
- pop_nest();
- start_of_par = cur_list.tail_field;
- callback_id = callback_defined(linebreak_filter_callback);
- if (callback_id > 0) {
- callback_id = lua_linebreak_callback(d, temp_head, addressof(cur_list.tail_field));
- if (callback_id > 0) {
- /* find the correct value for the |just_box| */
- halfword box_search = cur_list.tail_field;
- just_box = null;
- if (box_search != null) {
- do {
- if (type(box_search) == hlist_node) {
- just_box = box_search;
- }
- box_search = vlink(box_search);
- } while (box_search != null);
- }
- if (just_box == null) {
- help3
- ("A linebreaking routine should return a non-empty list of nodes",
- "and at least one of those has to be a \\hbox.",
- "Sorry, I cannot recover from this.");
- print_err("Invalid linebreak_filter");
- succumb();
- }
- } else {
- if (tracing_paragraphs_par > 0) {
- begin_diagnostic();
- print_int(line);
- end_diagnostic(true);
- }
- }
- }
- if (callback_id == 0) {
- if ((!is_char_node(vlink(temp_head))) && ((type(vlink(temp_head)) == local_par_node))) {
- paragraph_dir = local_par_dir(vlink(temp_head));
- } else {
- confusion("weird par dir"); /* assert(0); */ /* |paragraph_dir = 0|; */
- }
- ext_do_line_break(paragraph_dir,
- pretolerance_par,
- tracing_paragraphs_par,
- tolerance_par,
- emergency_stretch_par,
- looseness_par,
- adjust_spacing_par,
- par_shape_par_ptr,
- adj_demerits_par,
- protrude_chars_par,
- line_penalty_par,
- last_line_fit_par,
- double_hyphen_demerits_par,
- final_hyphen_demerits_par,
- hang_indent_par,
- hsize_par,
- hang_after_par,
- left_skip_par,
- right_skip_par,
- inter_line_penalties_par_ptr,
- inter_line_penalty_par,
- club_penalty_par,
- club_penalties_par_ptr,
- (d ? display_widow_penalties_par_ptr : widow_penalties_par_ptr),
- (d ? display_widow_penalty_par : widow_penalty_par),
- broken_penalty_par,
- final_par_glue);
- }
- lua_node_filter(post_linebreak_filter_callback,
- line_break_context, start_of_par,
- addressof(cur_list.tail_field));
- pack_begin_line = 0;
-}
-
-@ Glue nodes in a horizontal list that is being paragraphed are not supposed to
- include ``infinite'' shrinkability; that is why the algorithm maintains
- four registers for stretching but only one for shrinking. If the user tries to
- introduce infinite shrinkability, the shrinkability will be reset to finite
- and an error message will be issued. A boolean variable |no_shrink_error_yet|
- prevents this error message from appearing more than once per paragraph.
-
-@c
-#define check_shrinkage(a) \
- if ((shrink_order((a))!=normal)&&(shrink((a))!=0)) \
- a=finite_shrink((a))
-
-static boolean no_shrink_error_yet; /*have we complained about infinite shrinkage? */
-
-static halfword finite_shrink(halfword p)
-{ /* recovers from infinite shrinkage */
- const char *hlp[] = {
- "The paragraph just ended includes some glue that has",
- "infinite shrinkability, e.g., `\\hskip 0pt minus 1fil'.",
- "Such glue doesn't belong there---it allows a paragraph",
- "of any length to fit on one line. But it's safe to proceed,",
- "since the offensive shrinkability has been made finite.",
- NULL
- };
- if (no_shrink_error_yet) {
- no_shrink_error_yet = false;
- tex_error("Infinite glue shrinkage found in a paragraph", hlp);
- }
- shrink_order(p) = normal;
- return p;
-}
-
-@ A pointer variable |cur_p| runs through the given horizontal list as we look
- for breakpoints. This variable is global, since it is used both by |line_break|
- and by its subprocedure |try_break|.
-
- Another global variable called |threshold| is used to determine the feasibility
- of individual lines: breakpoints are feasible if there is a way to reach
- them without creating lines whose badness exceeds |threshold|. (The
- badness is compared to |threshold| before penalties are added, so that
- penalty values do not affect the feasibility of breakpoints, except that
- no break is allowed when the penalty is 10000 or more.) If |threshold|
- is 10000 or more, all legal breaks are considered feasible, since the
- |badness| function specified above never returns a value greater than~10000.
-
- Up to three passes might be made through the paragraph in an attempt to find at
- least one set of feasible breakpoints. On the first pass, we have
- |threshold=pretolerance| and |second_pass=final_pass=false|.
- If this pass fails to find a
- feasible solution, |threshold| is set to |tolerance|, |second_pass| is set
- |true|, and an attempt is made to hyphenate as many words as possible.
- If that fails too, we add |emergency_stretch| to the background
- stretchability and set |final_pass=true|.
-
-@c
-static boolean second_pass; /* is this our second attempt to break this paragraph? */
-static boolean final_pass; /*is this our final attempt to break this paragraph? */
-static int threshold; /* maximum badness on feasible lines */
-
-/* maximum fill level for |hlist_stack|*/
-#define max_hlist_stack 512 /* maybe good if larger than |2 *
- max_quarterword|, so that box nesting
- level would overflow first */
-
-/* stack for |find_protchar_left()| and |find_protchar_right()| */
-static halfword hlist_stack[max_hlist_stack];
-
-/* fill level for |hlist_stack| */
-static short hlist_stack_level = 0;
-
-@ @c
-static void push_node(halfword p)
-{
- if (hlist_stack_level >= max_hlist_stack)
- normal_error("push_node","stack overflow");
- hlist_stack[hlist_stack_level++] = p;
-}
-
-static halfword pop_node(void)
-{
- if (hlist_stack_level <= 0) /* would point to some bug */
- normal_error("pop_node","stack underflow (internal error)");
- return hlist_stack[--hlist_stack_level];
-}
-
-@ @c
-static int max_stretch_ratio = 0; /*maximal stretch ratio of expanded fonts */
-static int max_shrink_ratio = 0; /*maximal shrink ratio of expanded fonts */
-static int cur_font_step = 0; /*the current step of expanded fonts */
-
-static boolean check_expand_pars(internal_font_number f)
-{
- int m;
-
- if ((font_step(f) == 0)
- || ((font_max_stretch(f) == 0) && (font_max_shrink(f) == 0)))
- return false;
- if (cur_font_step < 0)
- cur_font_step = font_step(f);
- else if (cur_font_step != font_step(f))
- normal_error("font expansion","using fonts with different step of expansion in one paragraph is not allowed");
- m = font_max_stretch(f);
- if (m != 0) {
- if (max_stretch_ratio < 0)
- max_stretch_ratio = m;
- else if (max_stretch_ratio != m)
- normal_error("font expansion","using fonts with different limit of expansion in one paragraph is not allowed");
- }
- m = font_max_shrink(f);
- if (m != 0) {
- if (max_shrink_ratio < 0)
- max_shrink_ratio = -m;
- else if (max_shrink_ratio != -m)
- normal_error("font expansion","using fonts with different limit of expansion in one paragraph is not allowed");
- }
- return true;
-}
-
-@ searches left to right from list head |l|, returns 1st non-skipable item
-
-@c
-/*public*/ halfword find_protchar_left(halfword l, boolean d)
-{
- halfword t;
- boolean run;
- boolean done = false ;
- while ((vlink(l) != null) && (type(l) == hlist_node) && zero_dimensions(l) && (list_ptr(l) == null)) {
- /*for paragraph start with \.{\\parindent} = 0pt or any empty hbox */
- l = vlink(l);
- done = true ;
- }
- if ((!done) && (type(l) == local_par_node)) {
- l = vlink(l);
- done = true ;
- }
- if ((!done) && d) {
- while ((vlink(l) != null) && (!(is_char_node(l) || non_discardable(l)))) {
- /* std.\ discardables at line break, \TeX book, p 95 */
- l = vlink(l);
- }
- }
- if (type(l) != glyph_node) {
- hlist_stack_level = 0;
- run = true;
- do {
- t = l;
- while (run && (type(l) == hlist_node) && (list_ptr(l) != null)) {
- push_node(l);
- l = list_ptr(l);
- }
- while (run && cp_skipable(l)) {
- while ((vlink(l) == null) && (hlist_stack_level > 0)) {
- l = pop_node(); /* don't visit this node again */
- run = false;
- }
- if ((vlink(l) != null) && (type(l) == boundary_node) && (subtype(l) == protrusion_boundary) &&
- ((boundary_value(l) == 1) || (boundary_value(l) == 3))) {
- /* skip next node */
- l = vlink(l);
- }
- if (vlink(l) != null) {
- l = vlink(l);
- } else if (hlist_stack_level == 0) {
- run = false;
- }
- }
- } while (t != l);
- }
- return l;
-}
-
-@ searches right to left from list tail |r| to head |l|, returns 1st non-skipable item
-
-@c
-/*public*/ halfword find_protchar_right(halfword l, halfword r)
-{
- halfword t;
- boolean run = true;
- if (r == null)
- return null;
- hlist_stack_level = 0;
- do {
- t = r;
- while (run && (type(r) == hlist_node) && (list_ptr(r) != null)) {
- push_node(l);
- push_node(r);
- l = list_ptr(r);
- r = l;
- while (vlink(r) != null) {
- halfword s = r;
- r = vlink(r);
- alink(r) = s;
- }
- }
- while (run && cp_skipable(r)) {
- while ((r == l) && (hlist_stack_level > 0)) {
- r = pop_node(); /* don't visit this node again */
- l = pop_node();
- }
- if ((r != l) && (r != null)) {
- if ((alink(r) != null) && (type(r) == boundary_node) && (subtype(r) == protrusion_boundary) &&
- ((boundary_value(r) == 2) || (boundary_value(r) == 3))) {
- /* skip next node */
- r = alink(r);
- }
- if (alink(r) != null) {
- r = alink(r);
- } else { /* this is the input: \.{\\leavevmode\\penalty-10000\\penalty-10000} (bug \#268) */
- run = false;
- }
- } else if ((r == l) && (hlist_stack_level == 0))
- run = false;
- }
- } while (t != r);
- return r;
-}
-
-@ @c
-#define left_pw(a) char_pw((a), left_side)
-#define right_pw(a) char_pw((a), right_side)
-
-@ When looking for optimal line breaks, \TeX\ creates a ``break node'' for
- each break that is {\sl feasible}, in the sense that there is a way to end
- a line at the given place without requiring any line to stretch more than
- a given tolerance. A break node is characterized by three things: the position
- of the break (which is a pointer to a |glue_node|, |math_node|, |penalty_node|,
- or |disc_node|); the ordinal number of the line that will follow this
- breakpoint; and the fitness classification of the line that has just
- ended, i.e., |tight_fit|, |decent_fit|, |loose_fit|, or |very_loose_fit|.
-
-@c
-typedef enum {
- very_loose_fit = 0, /* fitness classification for lines stretching more than
- their stretchability */
- loose_fit, /* fitness classification for lines stretching 0.5 to 1.0 of their
- stretchability */
- decent_fit, /* fitness classification for all other lines */
- tight_fit /* fitness classification for lines shrinking 0.5 to 1.0 of their
- shrinkability */
-} fitness_value;
-
-
-@ The algorithm essentially determines the best possible way to achieve
- each feasible combination of position, line, and fitness. Thus, it answers
- questions like, ``What is the best way to break the opening part of the
- paragraph so that the fourth line is a tight line ending at such-and-such
- a place?'' However, the fact that all lines are to be the same length
- after a certain point makes it possible to regard all sufficiently large
- line numbers as equivalent, when the looseness parameter is zero, and this
- makes it possible for the algorithm to save space and time.
-
- An ``active node'' and a ``passive node'' are created in |mem| for each
- feasible breakpoint that needs to be considered. Active nodes are three
- words long and passive nodes are two words long. We need active nodes only
- for breakpoints near the place in the paragraph that is currently being
- examined, so they are recycled within a comparatively short time after
- they are created.
-
-@ An active node for a given breakpoint contains six fields:
-
-|vlink| points to the next node in the list of active nodes; the
-last active node has |vlink=active|.
-
-|break_node| points to the passive node associated with this
-breakpoint.
-
-|line_number| is the number of the line that follows this
-breakpoint.
-
-|fitness| is the fitness classification of the line ending at this
-breakpoint.
-
-|type| is either |hyphenated_node| or |unhyphenated_node|, depending on
-whether this breakpoint is a |disc_node|.
-
-|total_demerits| is the minimum possible sum of demerits over all
-lines leading from the beginning of the paragraph to this breakpoint.
-
-The value of |vlink(active)| points to the first active node on a vlinked list
-of all currently active nodes. This list is in order by |line_number|,
-except that nodes with |line_number>easy_line| may be in any order relative
-to each other.
-
-@c
-void initialize_active(void)
-{
- type(active) = hyphenated_node;
- line_number(active) = max_halfword;
- subtype(active) = 0; /* the |subtype| is never examined */
-}
-
-@ The passive node for a given breakpoint contains EIGHT fields:
-
-|vlink| points to the passive node created just before this one,
-if any, otherwise it is |null|.
-
-|cur_break| points to the position of this breakpoint in the
-horizontal list for the paragraph being broken.
-
-|prev_break| points to the passive node that should precede this
-one in an optimal path to this breakpoint.
-
-|serial| is equal to |n| if this passive node is the |n|th
-one created during the current pass. (This field is used only when
-printing out detailed statistics about the line-breaking calculations.)
-
-|passive_pen_inter| holds the current \.{\\localinterlinepenalty}
-
-|passive_pen_broken| holds the current \.{\\localbrokenpenalty}
-
-There is a global variable called |passive| that points to the most
-recently created passive node. Another global variable, |printed_node|,
-is used to help print out the paragraph when detailed information about
-the line-breaking computation is being displayed.
-
-@c
-static halfword passive; /* most recent node on passive list */
-static halfword printed_node; /*most recent node that has been printed */
-static halfword pass_number; /*the number of passive nodes allocated on this pass */
-
-@ The active list also contains ``delta'' nodes that help the algorithm
-compute the badness of individual lines. Such nodes appear only between two
-active nodes, and they have |type=delta_node|. If |p| and |r| are active nodes
-and if |q| is a delta node between them, so that |vlink(p)=q| and |vlink(q)=r|,
-then |q| tells the space difference between lines in the horizontal list that
-start after breakpoint |p| and lines that start after breakpoint |r|. In
-other words, if we know the length of the line that starts after |p| and
-ends at our current position, then the corresponding length of the line that
-starts after |r| is obtained by adding the amounts in node~|q|. A delta node
-contains seven scaled numbers, since it must record the net change in glue
-stretchability with respect to all orders of infinity. The natural width
-difference appears in |mem[q+1].sc|; the stretch differences in units of
-pt, sfi, fil, fill, and filll appear in |mem[q+2..q+6].sc|; and the shrink
-difference appears in |mem[q+7].sc|. The |subtype| field of a delta node
-is not used.
-
-Actually, we have two more fields that are used by |pdftex|.
-
-As the algorithm runs, it maintains a set of seven delta-like registers
-for the length of the line following the first active breakpoint to the
-current position in the given hlist. When it makes a pass through the
-active list, it also maintains a similar set of seven registers for the
-length following the active breakpoint of current interest. A third set
-holds the length of an empty line (namely, the sum of \.{\\leftskip} and
-\.{\\rightskip}); and a fourth set is used to create new delta nodes.
-
-When we pass a delta node we want to do operations like
-$$\hbox{\ignorespaces|for
-k:=1 to 7 do cur_active_width[k]:=cur_active_width[k]+mem[q+k].sc|};$$ and we
-want to do this without the overhead of |for| loops. The |do_all_six|
-macro makes such six-tuples convenient.
-
-@c
-static scaled active_width[10] = { 0 }; /*distance from first active node to~|cur_p| */
-static scaled background[10] = { 0 }; /*length of an ``empty'' line */
-static scaled break_width[10] = { 0 }; /*length being computed after current break */
-
-static boolean auto_breaking; /*make |auto_breaking| accessible out of |line_break| */
-
-@ Let's state the principles of the delta nodes more precisely and concisely,
- so that the following programs will be less obscure. For each legal
- breakpoint~|p| in the paragraph, we define two quantities $\alpha(p)$ and
- $\beta(p)$ such that the length of material in a line from breakpoint~|p|
- to breakpoint~|q| is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$.
- Intuitively, $\alpha(p)$ and $\beta(q)$ are the total length of material from
- the beginning of the paragraph to a point ``after'' a break at |p| and to a
- point ``before'' a break at |q|; and $\gamma$ is the width of an empty line,
- namely the length contributed by \.{\\leftskip} and \.{\\rightskip}.
-
- Suppose, for example, that the paragraph consists entirely of alternating
- boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and
- let the skips have widths $y_1\ldots y_n$, so that the paragraph can be
- represented by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint
- at $y_i$; then $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)=
- x_1+y_1+\cdots+x_i$. To check this, note that the length of material from
- $p_2$ to $p_5$, say, is $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5)
- -\alpha(p_2)$.
-
- The quantities $\alpha$, $\beta$, $\gamma$ involve glue stretchability and
- shrinkability as well as a natural width. If we were to compute $\alpha(p)$
- and $\beta(p)$ for each |p|, we would need multiple precision arithmetic, and
- the multiprecise numbers would have to be kept in the active nodes.
- \TeX\ avoids this problem by working entirely with relative differences
- or ``deltas.'' Suppose, for example, that the active list contains
- $a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the |a|'s are active breakpoints
- and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$
- and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is
- currently positioned at some other breakpoint |p|, the |active_width| array
- contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through
- the list of active nodes and considering a tentative line that runs from
- $a_2$ to~|p|, say, the |cur_active_width| array will contain the value
- $\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$,
- we want to add $\alpha(a_2)-\alpha(a_3)$ to |cur_active_width|; and this
- is just $\delta_2$, which appears in the active list between $a_2$ and
- $a_3$. The |background| array contains $\gamma$. The |break_width| array
- will be used to calculate values of new delta nodes when the active
- list is being updated.
-
-@ The heart of the line-breaking procedure is `|try_break|', a subroutine
- that tests if the current breakpoint |cur_p| is feasible, by running
- through the active list to see what lines of text can be made from active
- nodes to~|cur_p|. If feasible breaks are possible, new break nodes are
- created. If |cur_p| is too far from an active node, that node is
- deactivated.
-
- The parameter |pi| to |try_break| is the penalty associated
- with a break at |cur_p|; we have |pi=eject_penalty| if the break is forced,
- and |pi=inf_penalty| if the break is illegal.
-
- The other parameter, |break_type|, is set to |hyphenated_node| or |unhyphenated_node|,
- depending on whether or not the current break is at a |disc_node|. The
- end of a paragraph is also regarded as `|hyphenated_node|'; this case is
- distinguishable by the condition |cur_p=null|.
-
-@c
-static int internal_pen_inter; /* running \.{\\localinterlinepenalty} */
-static int internal_pen_broken; /* running \.{\\localbrokenpenalty} */
-static halfword internal_left_box; /* running \.{\\localleftbox} */
-static int internal_left_box_width; /* running \.{\\localleftbox} width */
-static halfword init_internal_left_box; /* running \.{\\localleftbox} */
-static int init_internal_left_box_width; /* running \.{\\localleftbox} width */
-static halfword internal_right_box; /* running \.{\\localrightbox} */
-static int internal_right_box_width; /* running \.{\\localrightbox} width */
-
-static scaled disc_width[10] = { 0 }; /* the length of discretionary material preceding a break */
-
-@ As we consider various ways to end a line at |cur_p|, in a given line number
- class, we keep track of the best total demerits known, in an array with
- one entry for each of the fitness classifications. For example,
- |minimal_demerits[tight_fit]| contains the fewest total demerits of feasible
- line breaks ending at |cur_p| with a |tight_fit| line; |best_place[tight_fit]|
- points to the passive node for the break before~|cur_p| that achieves such
- an optimum; and |best_pl_line[tight_fit]| is the |line_number| field in the
- active node corresponding to |best_place[tight_fit]|. When no feasible break
- sequence is known, the |minimal_demerits| entries will be equal to
- |awful_bad|, which is $2^{30}-1$. Another variable, |minimum_demerits|,
- keeps track of the smallest value in the |minimal_demerits| array.
-
-@c
-static int minimal_demerits[4]; /* best total demerits known for current
- line class and position, given the fitness */
-static int minimum_demerits; /* best total demerits known for current line class
- and position */
-static halfword best_place[4]; /* how to achieve |minimal_demerits| */
-static halfword best_pl_line[4]; /*corresponding line number */
-
-@ The length of lines depends on whether the user has specified
-\.{\\parshape} or \.{\\hangindent}. If |par_shape_ptr| is not null, it
-points to a $(2n+1)$-word record in |mem|, where the |vinfo| in the first
-word contains the value of |n|, and the other $2n$ words contain the left
-margins and line lengths for the first |n| lines of the paragraph; the
-specifications for line |n| apply to all subsequent lines. If
-|par_shape_ptr=null|, the shape of the paragraph depends on the value of
-|n=hang_after|; if |n>=0|, hanging indentation takes place on lines |n+1|,
-|n+2|, \dots, otherwise it takes place on lines 1, \dots, $\vert
-n\vert$. When hanging indentation is active, the left margin is
-|hang_indent|, if |hang_indent>=0|, else it is 0; the line length is
-$|hsize|-\vert|hang_indent|\vert$. The normal setting is
-|par_shape_ptr=null|, |hang_after=1|, and |hang_indent=0|.
-Note that if |hang_indent=0|, the value of |hang_after| is irrelevant.
-@^length of lines@> @^hanging indentation@>
-
-@c
-static halfword easy_line; /*line numbers |>easy_line| are equivalent in break nodes */
-static halfword last_special_line; /*line numbers |>last_special_line| all have the same width */
-static scaled first_width; /*the width of all lines |<=last_special_line|, if
- no \.{\\parshape} has been specified */
-static scaled second_width; /*the width of all lines |>last_special_line| */
-static scaled first_indent; /*left margin to go with |first_width| */
-static scaled second_indent; /*left margin to go with |second_width| */
-
-static halfword best_bet; /*use this passive node and its predecessors */
-static int fewest_demerits; /*the demerits associated with |best_bet| */
-static halfword best_line; /*line number following the last line of the new paragraph */
-static int actual_looseness; /*the difference between |line_number(best_bet)|
- and the optimum |best_line| */
-static int line_diff; /*the difference between the current line number and
- the optimum |best_line| */
-
-@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
- |rule_node|, |ins_node|, |mark_node|, |adjust_node|,
- |disc_node|, |whatsit_node|, and |math_node| are at the low end of the
- type codes, by permitting a break at glue in a list if and only if the
- |type| of the previous node is less than |math_node|. Furthermore, a
- node is discarded after a break if its type is |math_node| or~more.
-
-@c
-#define do_all_six(a) a(1);a(2);a(3);a(4);a(5);a(6);a(7)
-#define do_seven_eight(a) if (adjust_spacing > 1) { a(8);a(9); }
-#define do_all_eight(a) do_all_six(a); do_seven_eight(a)
-#define do_one_seven_eight(a) a(1); do_seven_eight(a)
-
-#define store_background(a) {active_width[a]=background[a];}
-
-#define kern_break() { \
- if ((!is_char_node(vlink(cur_p))) && auto_breaking) \
- if (type(vlink(cur_p))==glue_node) \
- ext_try_break(0, \
- unhyphenated_node, \
- line_break_dir, \
- adjust_spacing, \
- par_shape_ptr, \
- adj_demerits, \
- tracing_paragraphs, \
- protrude_chars, \
- line_penalty, \
- last_line_fit, \
- double_hyphen_demerits, \
- final_hyphen_demerits, \
- first_p, \
- cur_p); \
- if (type(cur_p)!=math_node) \
- active_width[1] += width(cur_p); \
- else \
- active_width[1] += surround(cur_p); \
-}
-
-#define clean_up_the_memory() { \
- q=vlink(active); \
- while (q!=active) { \
- cur_p = vlink(q); \
- if (type(q)==delta_node) \
- flush_node(q); \
- else \
- flush_node(q); \
- q = cur_p; \
- } \
- q = passive; \
- while (q!=null) { \
- cur_p = vlink(q); \
- flush_node(q); \
- q = cur_p; \
- } \
-}
-
-static boolean do_last_line_fit; /* special algorithm for last line of paragraph? */
-static scaled fill_width[4]; /* infinite stretch components of |par_fill_skip| */
-static scaled best_pl_short[4]; /* |shortfall| corresponding to |minimal_demerits| */
-static scaled best_pl_glue[4]; /*corresponding glue stretch or shrink */
-
-#define reset_disc_width(a) disc_width[(a)] = 0
-
-#define add_disc_width_to_break_width(a) break_width[(a)] += disc_width[(a)]
-#define sub_disc_width_from_active_width(a) active_width[(a)] -= disc_width[(a)]
-
-#define add_char_shrink(a,b) a += char_shrink((b))
-#define add_char_stretch(a,b) a += char_stretch((b))
-#define sub_char_shrink(a,b) a -= char_shrink((b))
-#define sub_char_stretch(a,b) a -= char_stretch((b))
-
-#define add_kern_shrink(a,b) a += kern_shrink((b))
-#define add_kern_stretch(a,b) a += kern_stretch((b))
-#define sub_kern_shrink(a,b) a -= kern_shrink((b))
-#define sub_kern_stretch(a,b) a -= kern_stretch((b))
-
-@ This function is used to add the width of a list of nodes
-(from a discretionary) to one of the width arrays.
-
-Replacement texts and discretionary texts are supposed to contain
-only character nodes, kern nodes, and box or rule nodes.
-
-@c
-#define bad_node_in_disc_error(p) { \
- if (type(p) == whatsit_node) { \
- formatted_error("linebreak","invalid node with type %s and subtype %i found in discretionary",node_data[type(p)].name,subtype(p)); \
- } else { \
- formatted_error("linebreak","invalid node with type %s found in discretionary",node_data[type(p)].name); \
- } \
-}
-
-static void add_to_widths(halfword s, int line_break_dir, int adjust_spacing, scaled * widths)
-{
- while (s != null) {
- if (is_char_node(s)) {
- widths[1] += pack_width(line_break_dir, dir_TRT, s, true);
- if ((adjust_spacing > 1) && check_expand_pars(font(s))) {
- set_prev_char_p(s);
- add_char_stretch(widths[8], s);
- add_char_shrink(widths[9], s);
- };
- } else {
- switch (type(s)) {
- case hlist_node:
- case vlist_node:
- widths[1] += pack_width(line_break_dir, box_dir(s), s, false);
- break;
- case kern_node:
- if ((adjust_spacing == 2) && (subtype(s) == normal)) {
- add_kern_stretch(widths[8], s);
- add_kern_shrink(widths[9], s);
- }
- /* fall through */
- case rule_node:
- widths[1] += width(s);
- break;
- case disc_node: /* TH temp */
- break;
- default:
- bad_node_in_disc_error(s);
- break;
- }
- }
- s = vlink(s);
- }
-}
-
-@ This function is used to substract the width of a list of nodes
-(from a discretionary) from one of the width arrays.
-It is used only once, but deserves it own function because of orthogonality
-with the |add_to_widths| function.
-
-@c
-static void sub_from_widths(halfword s, int line_break_dir, int adjust_spacing, scaled * widths)
-{
- while (s != null) {
- /* Subtract the width of node |s| from |break_width|; */
- if (is_char_node(s)) {
- widths[1] -= pack_width(line_break_dir, dir_TRT, s, true);
- if ((adjust_spacing > 1) && check_expand_pars(font(s))) {
- set_prev_char_p(s);
- sub_char_stretch(widths[8], s);
- sub_char_shrink(widths[9], s);
- }
- } else {
- switch (type(s)) {
- case hlist_node:
- case vlist_node:
- widths[1] -= pack_width(line_break_dir, box_dir(s), s, false);
- break;
- case kern_node:
- if ((adjust_spacing == 2) && (subtype(s) == normal)) {
- sub_kern_stretch(widths[8], s);
- sub_kern_shrink(widths[9], s);
- }
- /* fall through */
- case rule_node:
- widths[1] -= width(s);
- break;
- case disc_node: /* TH temp */
- break;
- default:
- bad_node_in_disc_error(s);
- break;
- }
- }
- s = vlink(s);
- }
-}
-
-@ When we insert a new active node for a break at |cur_p|, suppose this
- new node is to be placed just before active node |a|; then we essentially
- want to insert `$\delta\,|cur_p|\,\delta^\prime$' before |a|, where
- $\delta=\alpha(a)-\alpha(|cur_p|)$ and $\delta^\prime=\alpha(|cur_p|)-\alpha(a)$
- in the notation explained above. The |cur_active_width| array now holds
- $\gamma+\beta(|cur_p|)-\alpha(a)$; so $\delta$ can be obtained by
- subtracting |cur_active_width| from the quantity $\gamma+\beta(|cur_p|)-
- \alpha(|cur_p|)$. The latter quantity can be regarded as the length of a
- line ``from |cur_p| to |cur_p|''; we call it the |break_width| at |cur_p|.
-
- The |break_width| is usually negative, since it consists of the background
- (which is normally zero) minus the width of nodes following~|cur_p| that are
- eliminated after a break. If, for example, node |cur_p| is a glue node, the
- width of this glue is subtracted from the background; and we also look
- ahead to eliminate all subsequent glue and penalty and kern and math
- nodes, subtracting their widths as well.
-
- Kern nodes do not disappear at a line break unless they are |explicit|.
-
-@c
-static void compute_break_width(int break_type, int line_break_dir, int adjust_spacing, halfword p)
-{
- halfword s = p; /* glue and other 'whitespace' to be skipped after a break;
- used if unhyphenated, or |post_break==empty| */
- if (break_type > unhyphenated_node && p != null) {
- /*Compute the discretionary |break_width| values; */
- /* When |p| is a discretionary break, the length of a line
- ``from |p| to |p|'' has to be defined properly so
- that the other calculations work out. Suppose that the
- pre-break text at |p| has length $l_0$, the post-break
- text has length $l_1$, and the replacement text has length
- |l|. Suppose also that |q| is the node following the
- replacement text. Then length of a line from |p| to |q|
- will be computed as $\gamma+\beta(q)-\alpha(|p|)$, where
- $\beta(q)=\beta(|p|)-l_0+l$. The actual length will be
- the background plus $l_1$, so the length from |p| to
- |p| should be $\gamma+l_0+l_1-l$. If the post-break text
- of the discretionary is empty, a break may also discard~|q|;
- in that unusual case we subtract the length of~|q| and any
- other nodes that will be discarded after the discretionary
- break.
-
- TH: I don't quite understand the above remarks.
-
- The value of $l_0$ need not be computed, since |line_break|
- will put it into the global variable |disc_width| before
- calling |try_break|.
- */
- /* In case of nested discretionaries, we always follow the no-break
- path, as we are talking about the breaking on {\it this} position.
- */
-
- sub_from_widths(vlink_no_break(p), line_break_dir, adjust_spacing, break_width);
- add_to_widths(vlink_post_break(p), line_break_dir, adjust_spacing, break_width);
- do_one_seven_eight(add_disc_width_to_break_width);
- if (vlink_post_break(p) == null) {
- s = vlink(p); /* no |post_break|: 'skip' any 'whitespace' following */
- } else {
- s = null;
- }
- }
- while (s != null) {
- switch (type(s)) {
- case math_node:
- /* begin mathskip code */
- if (glue_is_zero(s)) {
- break_width[1] -= surround(s);
- break;
- } else {
- /* fall through */
- }
- /* end mathskip code */
- case glue_node:
- /*Subtract glue from |break_width|; */
- break_width[1] -= width(s);
- break_width[2 + stretch_order(s)] -= stretch(s);
- break_width[7] -= shrink(s);
- break;
- case penalty_node:
- break;
- case kern_node:
- if (subtype(s) != explicit_kern && subtype(s) != italic_kern)
- return;
- else
- break_width[1] -= width(s);
- break;
- default:
- return;
- };
- s = vlink(s);
- }
-}
-
-@ @c
-static void print_break_node(halfword q, fitness_value fit_class,
- quarterword break_type, halfword cur_p)
-{
- /* Print a symbolic description of the new break node */
- tprint_nl("@@@@");
- print_int(serial(passive));
- tprint(": line ");
- print_int(line_number(q) - 1);
- print_char('.');
- print_int(fit_class);
- if (break_type == hyphenated_node)
- print_char('-');
- tprint(" t=");
- print_int(total_demerits(q));
- if (do_last_line_fit) {
- /*Print additional data in the new active node; */
- tprint(" s=");
- print_scaled(active_short(q));
- if (cur_p == null)
- tprint(" a=");
- else
- tprint(" g=");
- print_scaled(active_glue(q));
- }
- tprint(" -> @@");
- if (prev_break(passive) == null)
- print_char('0');
- else
- print_int(serial(prev_break(passive)));
-}
-
-@ @c
-static void print_feasible_break(halfword cur_p, pointer r, halfword b, int pi,
- int d, boolean artificial_demerits)
-{
- /* Print a symbolic description of this feasible break; */
- if (printed_node != cur_p) {
- /* Print the list between |printed_node| and |cur_p|, then
- set |printed_node:=cur_p|; */
- tprint_nl("");
- if (cur_p == null) {
- short_display(vlink(printed_node));
- } else {
- halfword save_link = vlink(cur_p);
- vlink(cur_p) = null;
- tprint_nl("");
- short_display(vlink(printed_node));
- vlink(cur_p) = save_link;
- }
- printed_node = cur_p;
- }
- tprint_nl("@@");
- if (cur_p == null) {
- tprint_esc("par");
- } else if (type(cur_p) != glue_node) {
- if (type(cur_p) == penalty_node)
- tprint_esc("penalty");
- else if (type(cur_p) == disc_node)
- tprint_esc("discretionary");
- else if (type(cur_p) == kern_node)
- tprint_esc("kern");
- else
- tprint_esc("math");
- }
- tprint(" via @@");
- if (break_node(r) == null)
- print_char('0');
- else
- print_int(serial(break_node(r)));
- tprint(" b=");
- if (b > inf_bad)
- print_char('*');
- else
- print_int(b);
- tprint(" p=");
- print_int(pi);
- tprint(" d=");
- if (artificial_demerits)
- print_char('*');
- else
- print_int(d);
-}
-
-@ @c
-#define add_disc_width_to_active_width(a) active_width[a] += disc_width[a]
-#define update_width(a) cur_active_width[a] += varmem[(r+(a))].cint
-
-#define set_break_width_to_background(a) break_width[a]=background[(a)]
-
-#define convert_to_break_width(a) \
- varmem[(prev_r+(a))].cint = varmem[(prev_r+(a))].cint-cur_active_width[(a)]+break_width[(a)]
-
-#define store_break_width(a) active_width[(a)]=break_width[(a)]
-
-#define new_delta_to_break_width(a) \
- varmem[(q+(a))].cint=break_width[(a)]-cur_active_width[(a)]
-
-#define new_delta_from_break_width(a) \
- varmem[(q+(a))].cint=cur_active_width[(a)]-break_width[(a)]
-
-#define copy_to_cur_active(a) cur_active_width[(a)]=active_width[(a)]
-
-#define combine_two_deltas(a) varmem[(prev_r+(a))].cint += varmem[(r+(a))].cint
-#define downdate_width(a) cur_active_width[(a)] -= varmem[(prev_r+(a))].cint
-#define update_active(a) active_width[(a)]+=varmem[(r+(a))].cint
-
-#define total_font_stretch cur_active_width[8]
-#define total_font_shrink cur_active_width[9]
-
-#define cal_margin_kern_var(a) { \
- character(cp) = character((a)); \
- font(cp) = font((a)); \
- do_subst_font(cp, 1000); \
- if (font(cp) != font((a))) \
- margin_kern_stretch += (left_pw((a)) - left_pw(cp)); \
- font(cp) = font((a)); \
- do_subst_font(cp, -1000); \
- if (font(cp) != font((a))) \
- margin_kern_shrink += (left_pw(cp) - left_pw((a))); \
-}
-
-static void ext_try_break(int pi,
- quarterword break_type,
- int line_break_dir,
- int adjust_spacing,
- int par_shape_ptr,
- int adj_demerits,
- int tracing_paragraphs,
- int protrude_chars,
- int line_penalty,
- int last_line_fit,
- int double_hyphen_demerits,
- int final_hyphen_demerits, halfword first_p, halfword cur_p)
-{
- /* labels: |CONTINUE,DEACTIVATE,FOUND,NOT_FOUND|; */
- pointer r; /* runs through the active list */
- scaled margin_kern_stretch;
- scaled margin_kern_shrink;
- halfword lp, rp, cp;
- halfword prev_r = active; /* stays a step behind |r| */
- halfword prev_prev_r = null; /*a step behind |prev_r|, if |type(prev_r)=delta_node| */
- halfword old_l = 0; /* maximum line number in current equivalence class of lines */
- boolean no_break_yet = true; /* have we found a feasible break at |cur_p|? */
- halfword q; /*points to a new node being created */
- halfword l; /*line number of current active node */
- boolean node_r_stays_active; /*should node |r| remain in the active list? */
- scaled line_width = 0; /*the current line will be justified to this width */
- fitness_value fit_class; /*possible fitness class of test line */
- halfword b; /*badness of test line */
- int d; /*demerits of test line */
- boolean artificial_demerits; /*has |d| been forced to zero? */
-
- scaled shortfall; /*used in badness calculations */
- scaled g = 0; /*glue stretch or shrink of test line, adjustment for last line */
- scaled cur_active_width[10] = { 0 }; /*distance from current active node */
-
- /*Make sure that |pi| is in the proper range; */
- if (pi >= inf_penalty) {
- return; /* this breakpoint is inhibited by infinite penalty */
- } else if (pi <= -inf_penalty) {
- pi = eject_penalty; /*this breakpoint will be forced */
- }
-
- do_all_eight(copy_to_cur_active);
-
- while (1) {
- r = vlink(prev_r);
- /* If node |r| is of type |delta_node|, update |cur_active_width|,
- set |prev_r| and |prev_prev_r|, then |goto continue|; */
- /* The following code uses the fact that |type(active)<>delta_node| */
- if (type(r) == delta_node) {
- do_all_eight(update_width); /* IMPLICIT ,r */
- prev_prev_r = prev_r;
- prev_r = r;
- continue;
- }
- /* If a line number class has ended, create new active nodes for
- the best feasible breaks in that class; then |return|
- if |r=active|, otherwise compute the new |line_width|; */
- /* The first part of the following code is part of \TeX's inner loop, so
- we don't want to waste any time. The current active node, namely node |r|,
- contains the line number that will be considered next. At the end of the
- list we have arranged the data structure so that |r=active| and
- |line_number(active)>old_l|.
- */
- l = line_number(r);
- if (l > old_l) { /* now we are no longer in the inner loop */
- if ((minimum_demerits < awful_bad)
- && ((old_l != easy_line) || (r == active))) {
- /*Create new active nodes for the best feasible breaks just found */
- /* It is not necessary to create new active nodes having |minimal_demerits|
- greater than
- |minimum_demerits+abs(adj_demerits)|, since such active nodes will never
- be chosen in the final paragraph breaks. This observation allows us to
- omit a substantial number of feasible breakpoints from further consideration.
- */
- if (no_break_yet) {
- no_break_yet = false;
- do_all_eight(set_break_width_to_background);
- compute_break_width(break_type, line_break_dir, adjust_spacing, cur_p);
- }
- /* Insert a delta node to prepare for breaks at |cur_p|; */
- /* We use the fact that |type(active)<>delta_node|. */
- if (type(prev_r) == delta_node) { /* modify an existing delta node */
- do_all_eight(convert_to_break_width); /* IMPLICIT |prev_r| */
- } else if (prev_r == active) { /* no delta node needed at the beginning */
- do_all_eight(store_break_width);
- } else {
- q = new_node(delta_node, 0);
- vlink(q) = r;
- do_all_eight(new_delta_to_break_width); /* IMPLICIT q */
- vlink(prev_r) = q;
- prev_prev_r = prev_r;
- prev_r = q;
- }
-
- if (abs(adj_demerits) >= awful_bad - minimum_demerits)
- minimum_demerits = awful_bad - 1;
- else
- minimum_demerits += abs(adj_demerits);
- for (fit_class = very_loose_fit; fit_class <= tight_fit;
- fit_class++) {
- if (minimal_demerits[fit_class] <= minimum_demerits) {
- /* Insert a new active node from |best_place[fit_class]|
- to |cur_p|; */
- /* When we create an active node, we also create the corresponding
- passive node.
- */
- q = new_node(passive_node, 0);
- vlink(q) = passive;
- passive = q;
- cur_break(q) = cur_p;
- incr(pass_number);
- serial(q) = pass_number;
- prev_break(q) = best_place[fit_class];
- /*Here we keep track of the subparagraph penalties in the break nodes */
- passive_pen_inter(q) = internal_pen_inter;
- passive_pen_broken(q) = internal_pen_broken;
- passive_last_left_box(q) = internal_left_box;
- passive_last_left_box_width(q) =
- internal_left_box_width;
- if (prev_break(q) != null) {
- passive_left_box(q) =
- passive_last_left_box(prev_break(q));
- passive_left_box_width(q) =
- passive_last_left_box_width(prev_break(q));
- } else {
- passive_left_box(q) = init_internal_left_box;
- passive_left_box_width(q) =
- init_internal_left_box_width;
- }
- passive_right_box(q) = internal_right_box;
- passive_right_box_width(q) = internal_right_box_width;
- q = new_node(break_type, fit_class);
- break_node(q) = passive;
- line_number(q) = best_pl_line[fit_class] + 1;
- total_demerits(q) = minimal_demerits[fit_class];
- if (do_last_line_fit) {
- /*Store additional data in the new active node */
- /* Here we save these data in the active node
- representing a potential line break. */
- active_short(q) = best_pl_short[fit_class];
- active_glue(q) = best_pl_glue[fit_class];
- }
- vlink(q) = r;
- vlink(prev_r) = q;
- prev_r = q;
- if (tracing_paragraphs > 0)
- print_break_node(q, fit_class, break_type, cur_p);
- }
- minimal_demerits[fit_class] = awful_bad;
- }
- minimum_demerits = awful_bad;
- /* Insert a delta node to prepare for the next active node; */
- /* When the following code is performed, we will have just inserted at
- least one active node before |r|, so |type(prev_r)<>delta_node|.
- */
- if (r != active) {
- q = new_node(delta_node, 0);
- vlink(q) = r;
- do_all_eight(new_delta_from_break_width); /* IMPLICIT q */
- vlink(prev_r) = q;
- prev_prev_r = prev_r;
- prev_r = q;
- }
- }
- if (r == active)
- return;
- /*Compute the new line width; */
- /* When we come to the following code, we have just encountered
- the first active node~|r| whose |line_number| field contains
- |l|. Thus we want to compute the length of the $l\mskip1mu$th
- line of the current paragraph. Furthermore, we want to set
- |old_l| to the last number in the class of line numbers
- equivalent to~|l|.
- */
- if (l > easy_line) {
- old_l = max_halfword - 1;
- line_width = second_width;
- } else {
- old_l = l;
- if (l > last_special_line) {
- line_width = second_width;
- } else if (par_shape_ptr == null) {
- line_width = first_width;
- } else {
- line_width = varmem[(par_shape_ptr + 2 * l + 1)].cint;
- }
- }
- }
- /* /If a line number class has ended, create new active nodes for
- the best feasible breaks in that class; then |return|
- if |r=active|, otherwise compute the new |line_width|; */
-
- /* Consider the demerits for a line from |r| to |cur_p|;
- deactivate node |r| if it should no longer be active;
- then |goto continue| if a line from |r| to |cur_p| is infeasible,
- otherwise record a new feasible break; */
- artificial_demerits = false;
- shortfall = line_width - cur_active_width[1];
- if (break_node(r) == null)
- shortfall -= init_internal_left_box_width;
- else
- shortfall -= passive_last_left_box_width(break_node(r));
- shortfall -= internal_right_box_width;
- if (protrude_chars > 1) {
- halfword l1, o;
- l1 = (break_node(r) == null) ? first_p : cur_break(break_node(r));
- if (cur_p == null) {
- o = null;
- } else { /* TODO |if (is_character_node(alink(cur_p)))| */
- o = alink(cur_p);
- assert(vlink(o) == cur_p);
- }
- /* MAGIC: the disc could be a SELECT subtype, to we might need
- to get the last character as |pre_break| from either the
- |pre_break| list (if the previous INIT disc was taken), or the
- |no_break| (sic) list (if the previous INIT disc was not taken)
-
- BUT:
- the last characters (hyphenation character) if these two list
- should always be the same anyway, so we just look at |pre_break|.
- */
- /* let's look at the right margin first */
- if ((cur_p != null) && (type(cur_p) == disc_node)
- && (vlink_pre_break(cur_p) != null)) {
- /* a |disc_node| with non-empty |pre_break|, protrude the last char of |pre_break| */
- o = tlink_pre_break(cur_p);
- } else {
- o = find_protchar_right(l1, o);
- }
- /* now the left margin */
- if ((l1 != null) && (type(l1) == disc_node) && (vlink_post_break(l1) != null)) {
- /* FIXME: first 'char' could be a disc! */
- l1 = vlink_post_break(l1); /* protrude the first char */
- } else {
- l1 = find_protchar_left(l1, true);
- }
- shortfall += (left_pw(l1) + right_pw(o));
- }
- if (shortfall != 0) {
- margin_kern_stretch = 0;
- margin_kern_shrink = 0;
- if (protrude_chars > 1) {
- /* Calculate variations of marginal kerns; */
- lp = last_leftmost_char;
- rp = last_rightmost_char;
- cp = raw_glyph_node();
- if (lp != null) {
- cal_margin_kern_var(lp);
- }
- if (rp != null) {
- cal_margin_kern_var(rp);
- }
- flush_node(cp);
- }
- if ((shortfall > 0) && ((total_font_stretch + margin_kern_stretch) > 0)) {
- if ((total_font_stretch + margin_kern_stretch) > shortfall)
- shortfall = ((total_font_stretch + margin_kern_stretch) / (max_stretch_ratio / cur_font_step)) / 2;
- else
- shortfall -= (total_font_stretch + margin_kern_stretch);
- } else if ((shortfall < 0) && ((total_font_shrink + margin_kern_shrink) > 0)) {
- if ((total_font_shrink + margin_kern_shrink) > -shortfall)
- shortfall = -((total_font_shrink + margin_kern_shrink) / (max_shrink_ratio / cur_font_step)) / 2;
- else
- shortfall += (total_font_shrink + margin_kern_shrink);
- }
- }
- if (shortfall > 0) {
- /* Set the value of |b| to the badness for stretching the line,
- and compute the corresponding |fit_class| */
-
- /* When a line must stretch, the available stretchability can be
- found in the subarray |cur_active_width[2..6]|, in units of
- points, sfi, fil, fill and filll.
-
- The present section is part of \TeX's inner loop, and it is
- most often performed when the badness is infinite; therefore
- it is worth while to make a quick test for large width excess
- and small stretchability, before calling the |badness|
- subroutine. */
-
- if ((cur_active_width[3] != 0) || (cur_active_width[4] != 0) ||
- (cur_active_width[5] != 0) || (cur_active_width[6] != 0)) {
- if (do_last_line_fit) {
- if (cur_p == null) { /* the last line of a paragraph */
- /* Perform computations for last line and |goto found|; */
-
- /* Here we compute the adjustment |g| and badness |b| for
- a line from |r| to the end of the paragraph. When any
- of the criteria for adjustment is violated we fall
- through to the normal algorithm.
-
- The last line must be too short, and have infinite
- stretch entirely due to |par_fill_skip|. */
- if ((active_short(r) == 0) || (active_glue(r) <= 0))
- /* previous line was neither stretched nor shrunk, or
- was infinitely bad */
- goto NOT_FOUND;
- if ((cur_active_width[3] != fill_width[0]) ||
- (cur_active_width[4] != fill_width[1]) ||
- (cur_active_width[5] != fill_width[2]) ||
- (cur_active_width[6] != fill_width[3]))
- /* infinite stretch of this line not entirely due to
- |par_fill_skip| */
- goto NOT_FOUND;
- if (active_short(r) > 0)
- g = cur_active_width[2];
- else
- g = cur_active_width[7];
- if (g <= 0)
- /*no finite stretch resp.\ no shrink */
- goto NOT_FOUND;
- arith_error = false;
- g = fract(g, active_short(r), active_glue(r),
- max_dimen);
- if (last_line_fit < 1000)
- g = fract(g, last_line_fit, 1000, max_dimen);
- if (arith_error) {
- if (active_short(r) > 0)
- g = max_dimen;
- else
- g = -max_dimen;
- }
- if (g > 0) {
- /*Set the value of |b| to the badness of the last line
- for stretching, compute the corresponding |fit_class,
- and |goto found|| */
- /* These badness computations are rather similar to
- those of the standard algorithm, with the adjustment
- amount |g| replacing the |shortfall|. */
- if (g > shortfall)
- g = shortfall;
- if (g > 7230584) {
- if (cur_active_width[2] < 1663497) {
- b = inf_bad;
- fit_class = very_loose_fit;
- goto FOUND;
- }
- }
- b = badness(g, cur_active_width[2]);
- if (b > 99) {
- fit_class = very_loose_fit;
- } else if (b > 12) {
- fit_class = loose_fit;
- } else {
- fit_class = decent_fit;
- }
- goto FOUND;
- } else if (g < 0) {
- /*Set the value of |b| to the badness of the last line
- for shrinking, compute the corresponding |fit_class,
- and |goto found||; */
- if (-g > cur_active_width[7])
- g = -cur_active_width[7];
- b = badness(-g, cur_active_width[7]);
- if (b > 12)
- fit_class = tight_fit;
- else
- fit_class = decent_fit;
- goto FOUND;
- }
- }
- NOT_FOUND:
- shortfall = 0;
- }
- b = 0;
- fit_class = decent_fit; /* infinite stretch */
- } else {
- if (shortfall > 7230584 && cur_active_width[2] < 1663497) {
- b = inf_bad;
- fit_class = very_loose_fit;
- } else {
- b = badness(shortfall, cur_active_width[2]);
- if (b > 99) {
- fit_class = very_loose_fit;
- } else if (b > 12) {
- fit_class = loose_fit;
- } else {
- fit_class = decent_fit;
- }
- }
- }
- } else {
- /* Set the value of |b| to the badness for shrinking the line,
- and compute the corresponding |fit_class|; */
- /* Shrinkability is never infinite in a paragraph; we can shrink
- the line from |r| to |cur_p| by at most
- |cur_active_width[7]|. */
- if (-shortfall > cur_active_width[7])
- b = inf_bad + 1;
- else
- b = badness(-shortfall, cur_active_width[7]);
- if (b > 12)
- fit_class = tight_fit;
- else
- fit_class = decent_fit;
- }
- if (do_last_line_fit) {
- /* Adjust the additional data for last line; */
- if (cur_p == null)
- shortfall = 0;
- if (shortfall > 0) {
- g = cur_active_width[2];
- } else if (shortfall < 0) {
- g = cur_active_width[7];
- } else {
- g = 0;
- }
- }
- FOUND:
- if ((b > inf_bad) || (pi == eject_penalty)) {
- /* Prepare to deactivate node~|r|, and |goto deactivate| unless
- there is a reason to consider lines of text from |r| to |cur_p| */
- /* During the final pass, we dare not lose all active nodes, lest we lose
- touch with the line breaks already found. The code shown here makes
- sure that such a catastrophe does not happen, by permitting overfull
- boxes as a last resort. This particular part of \TeX\ was a source of
- several subtle bugs before the correct program logic was finally
- discovered; readers who seek to ``improve'' \TeX\ should therefore
- think thrice before daring to make any changes here.
- */
- if (final_pass && (minimum_demerits == awful_bad) &&
- (vlink(r) == active) && (prev_r == active)) {
- artificial_demerits = true; /* set demerits zero, this break is forced */
- } else if (b > threshold) {
- goto DEACTIVATE;
- }
- node_r_stays_active = false;
- } else {
- prev_r = r;
- if (b > threshold)
- continue;
- node_r_stays_active = true;
- }
- /* Record a new feasible break; */
- /* When we get to this part of the code, the line from |r| to |cur_p| is
- feasible, its badness is~|b|, and its fitness classification is
- |fit_class|. We don't want to make an active node for this break yet,
- but we will compute the total demerits and record them in the
- |minimal_demerits| array, if such a break is the current champion among
- all ways to get to |cur_p| in a given line-number class and fitness
- class.
- */
- if (artificial_demerits) {
- d = 0;
- } else {
- /* Compute the demerits, |d|, from |r| to |cur_p|; */
- d = line_penalty + b;
- if (abs(d) >= 10000)
- d = 100000000;
- else
- d = d * d;
- if (pi != 0) {
- if (pi > 0) {
- d += (pi * pi);
- } else if (pi > eject_penalty) {
- d -= (pi * pi);
- }
- }
- if ((break_type == hyphenated_node) && (type(r) == hyphenated_node)) {
- if (cur_p != null)
- d += double_hyphen_demerits;
- else
- d += final_hyphen_demerits;
- }
- if (abs(fit_class - fitness(r)) > 1)
- d = d + adj_demerits;
- }
- if (tracing_paragraphs > 0)
- print_feasible_break(cur_p, r, b, pi, d, artificial_demerits);
- d += total_demerits(r); /*this is the minimum total demerits
- from the beginning to |cur_p| via |r| */
- if (d <= minimal_demerits[fit_class]) {
- minimal_demerits[fit_class] = d;
- best_place[fit_class] = break_node(r);
- best_pl_line[fit_class] = l;
- if (do_last_line_fit) {
- /* Store additional data for this feasible break; */
- /* For each feasible break we record the shortfall and glue stretch or
- shrink (or adjustment). */
- best_pl_short[fit_class] = shortfall;
- best_pl_glue[fit_class] = g;
- }
- if (d < minimum_demerits)
- minimum_demerits = d;
- }
- /* /Record a new feasible break */
- if (node_r_stays_active)
- continue; /*|prev_r| has been set to |r| */
- DEACTIVATE:
- /* Deactivate node |r|; */
- /* When an active node disappears, we must delete an adjacent delta node if
- the active node was at the beginning or the end of the active list, or
- if it was surrounded by delta nodes. We also must preserve the property
- that |cur_active_width| represents the length of material from
- |vlink(prev_r)| to~|cur_p|. */
-
- vlink(prev_r) = vlink(r);
- flush_node(r);
- if (prev_r == active) {
- /*Update the active widths, since the first active node has been
- deleted */
- /* The following code uses the fact that |type(active)<>delta_node|.
- If the active list has just become empty, we do not need to update the
- |active_width| array, since it will be initialized when an active
- node is next inserted.
- */
- r = vlink(active);
- if (type(r) == delta_node) {
- do_all_eight(update_active); /* IMPLICIT r */
- do_all_eight(copy_to_cur_active);
- vlink(active) = vlink(r);
- flush_node(r);
- }
- } else if (type(prev_r) == delta_node) {
- r = vlink(prev_r);
- if (r == active) {
- do_all_eight(downdate_width); /* IMPLICIT |prev_r| */
- vlink(prev_prev_r) = active;
- flush_node(prev_r);
- prev_r = prev_prev_r;
- } else if (type(r) == delta_node) {
- do_all_eight(update_width); /* IMPLICIT ,r */
- do_all_eight(combine_two_deltas); /* IMPLICIT r |prev_r| */
- vlink(prev_r) = vlink(r);
- flush_node(r);
- }
- }
- }
-}
-
-@ @c
-void ext_do_line_break(int paragraph_dir,
- int pretolerance,
- int tracing_paragraphs,
- int tolerance,
- scaled emergency_stretch,
- int looseness,
- int adjust_spacing,
- halfword par_shape_ptr,
- int adj_demerits,
- int protrude_chars,
- int line_penalty,
- int last_line_fit,
- int double_hyphen_demerits,
- int final_hyphen_demerits,
- int hang_indent,
- int hsize,
- int hang_after,
- halfword left_skip,
- halfword right_skip,
- halfword inter_line_penalties_ptr,
- int inter_line_penalty,
- int club_penalty,
- halfword club_penalties_ptr,
- halfword widow_penalties_ptr,
- int widow_penalty,
- int broken_penalty,
- halfword final_par_glue)
-{
- /* DONE,DONE1,DONE2,DONE3,DONE4,DONE5,CONTINUE; */
- halfword cur_p, q, r, s; /* miscellaneous nodes of temporary interest */
- int line_break_dir = paragraph_dir;
-
- /* Get ready to start ... */
- minimum_demerits = awful_bad;
- minimal_demerits[tight_fit] = awful_bad;
- minimal_demerits[decent_fit] = awful_bad;
- minimal_demerits[loose_fit] = awful_bad;
- minimal_demerits[very_loose_fit] = awful_bad;
-
- fewest_demerits = 0;
- actual_looseness = 0;
-
- /* We compute the values of |easy_line| and the other local variables relating
- to line length when the |line_break| procedure is initializing itself. */
- if (par_shape_ptr == null) {
- if (hang_indent == 0) {
- last_special_line = 0;
- second_width = hsize;
- second_indent = 0;
- } else {
- halfword used_hang_indent = swap_hang_indent(hang_indent);
- /* Set line length parameters in preparation for hanging indentation */
- /* We compute the values of |easy_line| and the other local variables relating
- to line length when the |line_break| procedure is initializing itself. */
- last_special_line = abs(hang_after);
- if (hang_after < 0) {
- first_width = hsize - abs(used_hang_indent);
- if (used_hang_indent >= 0)
- first_indent = used_hang_indent;
- else
- first_indent = 0;
- second_width = hsize;
- second_indent = 0;
- } else {
- first_width = hsize;
- first_indent = 0;
- second_width = hsize - abs(used_hang_indent);
- if (used_hang_indent >= 0)
- second_indent = used_hang_indent;
- else
- second_indent = 0;
- }
- }
- } else {
- last_special_line = vinfo(par_shape_ptr + 1) - 1;
- second_indent = varmem[(par_shape_ptr + 2 * (last_special_line + 1))].cint;
- second_width = varmem[(par_shape_ptr + 2 * (last_special_line + 1) + 1)].cint;
- second_indent = swap_parshape_indent(second_indent,second_width);
- }
- if (looseness == 0)
- easy_line = last_special_line;
- else
- easy_line = max_halfword;
-
- no_shrink_error_yet = true;
- check_shrinkage(left_skip);
- check_shrinkage(right_skip);
- q = left_skip;
- r = right_skip;
- background[1] = width(q) + width(r);
- background[2] = 0;
- background[3] = 0;
- background[4] = 0;
- background[5] = 0;
- background[6] = 0;
- background[2 + stretch_order(q)] = stretch(q);
- background[2 + stretch_order(r)] += stretch(r);
- background[7] = shrink(q) + shrink(r);
- if (adjust_spacing > 1) {
- background[8] = 0;
- background[9] = 0;
- max_stretch_ratio = -1;
- max_shrink_ratio = -1;
- cur_font_step = -1;
- set_prev_char_p(null);
- }
- /* Check for special treatment of last line of paragraph; */
- /* The new algorithm for the last line requires that the stretchability
- |par_fill_skip| is infinite and the stretchability of |left_skip| plus
- |right_skip| is finite.
- */
- do_last_line_fit = false;
- if (last_line_fit > 0) {
- q = last_line_fill;
- if ((stretch(q) > 0) && (stretch_order(q) > normal)) {
- if ((background[3] == 0) && (background[4] == 0) &&
- (background[5] == 0) && (background[6] == 0)) {
- do_last_line_fit = true;
- fill_width[0] = 0;
- fill_width[1] = 0;
- fill_width[2] = 0;
- fill_width[3] = 0;
- fill_width[stretch_order(q) - 1] = stretch(q);
- }
- }
- }
- /* DIR: Initialize |dir_ptr| for |line_break| */
- if (dir_ptr != null) {
- flush_node_list(dir_ptr);
- dir_ptr = null;
- }
-#if 0
- push_dir(dir_ptr,paragraph_dir); /* TODO what was the point of this? */
-#endif
-
- /* Find optimal breakpoints; */
- threshold = pretolerance;
- if (threshold >= 0) {
- if (tracing_paragraphs > 0) {
- begin_diagnostic();
- tprint_nl("@@firstpass");
- }
- second_pass = false;
- final_pass = false;
- } else {
- threshold = tolerance;
- second_pass = true;
- final_pass = (emergency_stretch <= 0);
- if (tracing_paragraphs > 0)
- begin_diagnostic();
- }
- while (1) {
- halfword first_p;
- halfword nest_stack[10];
- int nest_index = 0;
- if (threshold > inf_bad)
- threshold = inf_bad;
- /* Create an active breakpoint representing the beginning of the paragraph */
- q = new_node(unhyphenated_node, decent_fit);
- vlink(q) = active;
- break_node(q) = null;
- line_number(q) = cur_list.pg_field + 1;
- total_demerits(q) = 0;
- active_short(q) = 0;
- active_glue(q) = 0;
- vlink(active) = q;
- do_all_eight(store_background);
- passive = null;
- printed_node = temp_head;
- pass_number = 0;
- font_in_short_display = null_font;
- /* /Create an active breakpoint representing the beginning of the paragraph */
- auto_breaking = true;
- cur_p = vlink(temp_head);
- /* LOCAL: Initialize with first |local_paragraph| node */
- if ((cur_p != null) && (type(cur_p) == local_par_node)) {
- alink(cur_p) = temp_head; /* this used to be an assert, but may as well force it */
- internal_pen_inter = local_pen_inter(cur_p);
- internal_pen_broken = local_pen_broken(cur_p);
- init_internal_left_box = local_box_left(cur_p);
- init_internal_left_box_width = local_box_left_width(cur_p);
- internal_left_box = init_internal_left_box;
- internal_left_box_width = init_internal_left_box_width;
- internal_right_box = local_box_right(cur_p);
- internal_right_box_width = local_box_right_width(cur_p);
- } else {
- internal_pen_inter = 0;
- internal_pen_broken = 0;
- init_internal_left_box = null;
- init_internal_left_box_width = 0;
- internal_left_box = init_internal_left_box;
- internal_left_box_width = init_internal_left_box_width;
- internal_right_box = null;
- internal_right_box_width = 0;
- }
- /* /LOCAL: Initialize with first |local_paragraph| node */
- set_prev_char_p(null);
- first_p = cur_p;
- /* to access the first node of paragraph as the first active node
- has |break_node=null| */
- while ((cur_p != null) && (vlink(active) != active)) {
- /* |try_break| if |cur_p| is a legal breakpoint; on the 2nd pass, also look at |disc_node|s. */
-
- while (is_char_node(cur_p)) {
- /* Advance |cur_p| to the node following the present string of characters ; */
- /* The code that passes over the characters of words in a paragraph is part of
- \TeX's inner loop, so it has been streamlined for speed. We use the fact that
- `\.{\\parfillskip}' glue appears at the end of each paragraph; it is therefore
- unnecessary to check if |vlink(cur_p)=null| when |cur_p| is a character node.
- */
- active_width[1] += pack_width(line_break_dir, dir_TRT, cur_p, true);
- if ((adjust_spacing > 1) && check_expand_pars(font(cur_p))) {
- set_prev_char_p(cur_p);
- add_char_stretch(active_width[8], cur_p);
- add_char_shrink(active_width[9], cur_p);
- }
- cur_p = vlink(cur_p);
- while (cur_p == null && nest_index > 0) {
- cur_p = nest_stack[--nest_index];
- }
- }
- if (cur_p == null) {
- normal_error("linebreak","invalid list tail, probably missing glue");
- }
- /* Determine legal breaks: As we move through the hlist, we need to keep
- the |active_width| array up to date, so that the badness of individual
- lines is readily calculated by |try_break|. It is convenient to use the
- short name |active_width[1]| for the component of active width that represents
- real width as opposed to glue. */
-
- switch (type(cur_p)) {
- case hlist_node:
- case vlist_node:
- active_width[1] += pack_width(line_break_dir, box_dir(cur_p), cur_p, false);
- break;
- case rule_node:
- active_width[1] += width(cur_p);
- break;
- case dir_node: /* DIR: Adjust the dir stack for the |line_break| routine; */
- if (dir_dir(cur_p) >= 0) {
- line_break_dir = dir_dir(cur_p);
- push_dir_node(dir_ptr,cur_p); /* adds to |dir_ptr| */
- } else {
- pop_dir_node(dir_ptr);
- if (dir_ptr != null) {
- line_break_dir = dir_dir(dir_ptr);
- }
- }
- break;
- case local_par_node: /* LOCAL: Advance past a |local_paragraph| node; */
- internal_pen_inter = local_pen_inter(cur_p);
- internal_pen_broken = local_pen_broken(cur_p);
- internal_left_box = local_box_left(cur_p);
- internal_left_box_width = local_box_left_width(cur_p);
- internal_right_box = local_box_right(cur_p);
- internal_right_box_width = local_box_right_width(cur_p);
- break;
- case math_node:
- auto_breaking = (subtype(cur_p) == after);
- /* begin mathskip code */
- if (glue_is_zero(cur_p) || ignore_math_skip(cur_p)) {
- kern_break();
- break;
- } else {
- /* fall through */
- }
- /* end mathskip code */
- case glue_node:
- /*
- If node |cur_p| is a legal breakpoint, call |try_break|;
- then update the active widths by including the glue in
- |glue_ptr(cur_p)|;
-
- When node |cur_p| is a glue node, we look at the previous
- to see whether or not a breakpoint is legal at |cur_p|,
- as explained above.
-
- We only break after certain nodes (see texnodes.h), a font related
- kern and a dir node when |\breakafterdirmode=1|.
- */
- if (auto_breaking) {
- halfword prev_p = alink(cur_p);
- if (prev_p != temp_head && (
- is_char_node(prev_p)
- || precedes_break(prev_p)
- || precedes_kern(prev_p)
- || precedes_dir(prev_p)
- )) {
- ext_try_break(0, unhyphenated_node, line_break_dir, adjust_spacing,
- par_shape_ptr, adj_demerits,
- tracing_paragraphs, protrude_chars,
- line_penalty, last_line_fit,
- double_hyphen_demerits,
- final_hyphen_demerits, first_p, cur_p);
- }
- }
- /* *INDENT-ON* */
- check_shrinkage(cur_p);
- active_width[1] += width(cur_p);
- active_width[2 + stretch_order(cur_p)] += stretch(cur_p);
- active_width[7] += shrink(cur_p);
- break;
- case kern_node:
- if (subtype(cur_p) == explicit_kern || subtype(cur_p) == italic_kern) {
- kern_break();
- } else {
- active_width[1] += width(cur_p);
- if ((adjust_spacing == 2) && (subtype(cur_p) == normal)) {
- add_kern_stretch(active_width[8], cur_p);
- add_kern_shrink(active_width[9], cur_p);
- }
- }
- break;
- case disc_node:
- /* |select_disc|s are handled by the leading |init_disc| */
- if (subtype(cur_p) == select_disc)
- break;
- /* Try to break after a discretionary fragment, then |goto done5|; */
- /* The following code knows that discretionary texts contain
- only character nodes, kern nodes, box nodes, and rule
- nodes. This branch differs a bit from older engines because in LuaTeX we
- already have hyphenated the list. This means that we need to skip
- automatic disc nodes. Of better, we need to treat discretionaries
- and explicit hyphens always, even in the first pass (HH). */
- if (second_pass || subtype(cur_p) <= automatic_disc) {
- /*
- int actual_penalty = hyphen_penalty;
- if (disc_penalty(cur_p) != 0) {
- actual_penalty = (int) disc_penalty(cur_p);
- } else if (subtype(cur_p) == automatic_disc) {
- actual_penalty = ex_hyphen_penalty;
- }
- */
- int actual_penalty = (int) disc_penalty(cur_p);
- s = vlink_pre_break(cur_p);
- do_one_seven_eight(reset_disc_width);
- if (s == null) { /* trivial pre-break */
- ext_try_break(actual_penalty, hyphenated_node,
- line_break_dir, adjust_spacing,
- par_shape_ptr, adj_demerits,
- tracing_paragraphs, protrude_chars,
- line_penalty, last_line_fit,
- double_hyphen_demerits,
- final_hyphen_demerits, first_p, cur_p);
- } else {
- add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
- do_one_seven_eight(add_disc_width_to_active_width);
- ext_try_break(actual_penalty, hyphenated_node,
- line_break_dir, adjust_spacing,
- par_shape_ptr, adj_demerits,
- tracing_paragraphs, protrude_chars,
- line_penalty, last_line_fit,
- double_hyphen_demerits,
- final_hyphen_demerits, first_p, cur_p);
- if (subtype(cur_p) == init_disc) {
- /* we should at two break points after the one we
- added above:
- \item1 which does a possible break in INIT's |post_break|
- \item2 which means the |no_break| actually was broken
- just a character later */
- /* do the select-0 case 'f-f-i' */
- s = vlink_pre_break(vlink(cur_p));
- add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
- ext_try_break(actual_penalty, hyphenated_node,
- line_break_dir, adjust_spacing,
- par_shape_ptr, adj_demerits,
- tracing_paragraphs,
- protrude_chars, line_penalty,
- last_line_fit, double_hyphen_demerits,
- final_hyphen_demerits, first_p,
- vlink(cur_p));
-#if 0
- /* TODO this does not work */
- /* go back to the starting situation */
- do_one_seven_eight(sub_disc_width_from_active_width);
- do_one_seven_eight(reset_disc_width);
- /* add select |no_break| to |active_width| */
- s = vlink_no_break(vlink(cur_p));
- add_to_widths(s, line_break_dir, adjust_spacing, disc_width);
- ext_try_break(actual_penalty, hyphenated_node,
- line_break_dir, adjust_spacing,
- par_shape_ptr, adj_demerits,
- tracing_paragraphs,
- protrude_chars, line_penalty,
- last_line_fit, double_hyphen_demerits,
- final_hyphen_demerits, first_p,
- vlink(cur_p));
-#endif
- }
- do_one_seven_eight(sub_disc_width_from_active_width);
- }
- }
- s = vlink_no_break(cur_p);
- add_to_widths(s, line_break_dir, adjust_spacing, active_width);
- break;
- case penalty_node:
- ext_try_break(penalty(cur_p), unhyphenated_node, line_break_dir,
- adjust_spacing, par_shape_ptr, adj_demerits,
- tracing_paragraphs, protrude_chars,
- line_penalty, last_line_fit,
- double_hyphen_demerits, final_hyphen_demerits,
- first_p, cur_p);
- break;
- case boundary_node:
- case whatsit_node:
- /* / Advance past a whatsit node in the |line_break| loop/; */
- case mark_node:
- case ins_node:
- case adjust_node:
- break;
- case glue_spec_node:
- normal_warning("parbuilder","found a glue_spec in a paragraph");
- break;
- default:
- formatted_error("parbuilder","weird node %d in paragraph",type(cur_p));
- }
- cur_p = vlink(cur_p);
- while (cur_p == null && nest_index > 0) {
- cur_p = nest_stack[--nest_index];
- }
- }
- if (cur_p == null) {
- /*
- Try the final line break at the end of the paragraph,
- and |goto done| if the desired breakpoints have been found
-
- The forced line break at the paragraph's end will reduce the list of
- breakpoints so that all active nodes represent breaks at |cur_p=null|.
- On the first pass, we insist on finding an active node that has the
- correct ``looseness.'' On the final pass, there will be at least one active
- node, and we will match the desired looseness as well as we can.
-
- The global variable |best_bet| will be set to the active node for the best
- way to break the paragraph, and a few other variables are used to
- help determine what is best.
- */
- ext_try_break(eject_penalty, hyphenated_node, line_break_dir,
- adjust_spacing, par_shape_ptr, adj_demerits,
- tracing_paragraphs, protrude_chars, line_penalty,
- last_line_fit, double_hyphen_demerits,
- final_hyphen_demerits, first_p, cur_p);
- if (vlink(active) != active) {
- /* Find an active node with fewest demerits; */
- r = vlink(active);
- fewest_demerits = awful_bad;
- do {
- if (type(r) != delta_node) {
- if (total_demerits(r) < fewest_demerits) {
- fewest_demerits = total_demerits(r);
- best_bet = r;
- }
- }
- r = vlink(r);
- } while (r != active);
- best_line = line_number(best_bet);
- /*
- Find an active node with fewest demerits;
- */
- if (looseness == 0)
- goto DONE;
- /*
- Find the best active node for the desired looseness;
-
- The adjustment for a desired looseness is a slightly more complicated
- version of the loop just considered. Note that if a paragraph is broken
- into segments by displayed equations, each segment will be subject to the
- looseness calculation, independently of the other segments.
- */
- r = vlink(active);
- actual_looseness = 0;
- do {
- if (type(r) != delta_node) {
- line_diff = line_number(r) - best_line;
- if (((line_diff < actual_looseness)
- && (looseness <= line_diff))
- || ((line_diff > actual_looseness)
- && (looseness >= line_diff))) {
- best_bet = r;
- actual_looseness = line_diff;
- fewest_demerits = total_demerits(r);
- } else if ((line_diff == actual_looseness) &&
- (total_demerits(r) < fewest_demerits)) {
- best_bet = r;
- fewest_demerits = total_demerits(r);
- }
- }
- r = vlink(r);
- } while (r != active);
- best_line = line_number(best_bet);
- /*
- Find the best active node for the desired looseness;
- */
- if ((actual_looseness == looseness) || final_pass)
- goto DONE;
- }
- }
- /* Clean up the memory by removing the break nodes; */
- clean_up_the_memory();
- /* /Clean up the memory by removing the break nodes; */
- if (!second_pass) {
- if (tracing_paragraphs > 0)
- tprint_nl("@@secondpass");
- threshold = tolerance;
- second_pass = true;
- final_pass = (emergency_stretch <= 0);
- } else {
- /* if at first you do not succeed, \dots */
- if (tracing_paragraphs > 0)
- tprint_nl("@@emergencypass");
- background[2] += emergency_stretch;
- final_pass = true;
- }
- }
-
- DONE:
- if (tracing_paragraphs > 0) {
- end_diagnostic(true);
- normalize_selector();
- }
- if (do_last_line_fit) {
- /*
- Adjust the final line of the paragraph; here we either reset
- |do_last_line_fit| or adjust the |par_fill_skip| glue.
- */
- if (active_short(best_bet) == 0) {
- do_last_line_fit = false;
- } else {
- width(last_line_fill) += (active_short(best_bet) - active_glue(best_bet));
- stretch(last_line_fill) = 0;
- }
- }
-
- /*
- Break the paragraph at the chosen...; Once the best sequence of breakpoints
- has been found (hurray), we call on the procedure |post_line_break| to finish
- the remainder of the work. By introducing this subprocedure, we are able to
- keep |line_break| from getting extremely long.
- */
-
- /* first thing |ext_post_line_break| does is reset |dir_ptr| */
- flush_node_list(dir_ptr);
- dir_ptr = null;
- ext_post_line_break(paragraph_dir,
- right_skip,
- left_skip,
- protrude_chars,
- par_shape_ptr,
- adjust_spacing,
- inter_line_penalties_par_ptr,
- inter_line_penalty,
- club_penalty,
- club_penalties_ptr,
- widow_penalties_ptr,
- widow_penalty,
- broken_penalty,
- final_par_glue,
- best_bet,
- last_special_line,
- second_width,
- second_indent, first_width, first_indent, best_line);
- /*
- Break the paragraph at the chosen ...Clean up the memory by removing
- the break nodes.
- */
- clean_up_the_memory();
-}
-
-@ @c
-void get_linebreak_info (int *f, int *a)
-{
- *f = fewest_demerits;
- *a = actual_looseness;
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/mainbody.c b/Build/source/texk/web2c/luatexdir/tex/mainbody.c
new file mode 100644
index 00000000000..ca9a79dbb02
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/mainbody.c
@@ -0,0 +1,769 @@
+/*
+
+mainbody.w
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+This is where the action starts. We're speaking of \LUATEX, a continuation of
+\PDFTEX\ (which included \ETEX) and \ALEPH. As \TEX, \LUATEX\ is a document
+compiler intended to simplify high quality typesetting for many of the world's
+languages. It is an extension of D. E. Knuth's \TEX, which was designed
+essentially for the typesetting of languages using the Latin alphabet. Although
+it is a direct decendant of \TEX, and therefore mostly compatible, there are
+some subtle differences that relate to \UNICODE\ support and \OPENTYPE\ math.
+
+The \ALEPH\ subsystem loosens many of the restrictions imposed by~\TeX: register
+numbers are no longer limited to 8~bits. Fonts may have more than 256~characters,
+more than 256~fonts may be used, etc. We use a similar model. We also borrowed
+the directional model but have upgraded it a bit as well as integrated it more
+tightly.
+
+This program is directly derived from Donald E. Knuth's \TEX; the change history
+which follows and the reward offered for finders of bugs refer specifically to
+\TEX; they should not be taken as referring to \LUATEX, \PDFTEX, nor \ETEX,
+although the change history is relevant in that it demonstrates the evolutionary
+path followed. This program is not \TEX; that name is reserved strictly for the
+program which is the creation and sole responsibility of Professor Knuth.
+
+\starttyping
+% Version 0 was released in September 1982 after it passed a variety of tests.
+% Version 1 was released in November 1983 after thorough testing.
+% Version 1.1 fixed ``disappearing font identifiers'' et alia (July 1984).
+% Version 1.2 allowed `0' in response to an error, et alia (October 1984).
+% Version 1.3 made memory allocation more flexible and local (November 1984).
+% Version 1.4 fixed accents right after line breaks, et alia (April 1985).
+% Version 1.5 fixed \the\toks after other expansion in \edefs (August 1985).
+% Version 2.0 (almost identical to 1.5) corresponds to "Volume B" (April 1986).
+% Version 2.1 corrected anomalies in discretionary breaks (January 1987).
+% Version 2.2 corrected "(Please type...)" with null \endlinechar (April 1987).
+% Version 2.3 avoided incomplete page in premature termination (August 1987).
+% Version 2.4 fixed \noaligned rules in indented displays (August 1987).
+% Version 2.5 saved cur_order when expanding tokens (September 1987).
+% Version 2.6 added 10sp slop when shipping leaders (November 1987).
+% Version 2.7 improved rounding of negative-width characters (November 1987).
+% Version 2.8 fixed weird bug if no \patterns are used (December 1987).
+% Version 2.9 made \csname\endcsname's "relax" local (December 1987).
+% Version 2.91 fixed \outer\def\a0{}\a\a bug (April 1988).
+% Version 2.92 fixed \patterns, also file names with complex macros (May 1988).
+% Version 2.93 fixed negative halving in allocator when mem_min<0 (June 1988).
+% Version 2.94 kept open_log_file from calling fatal_error (November 1988).
+% Version 2.95 solved that problem a better way (December 1988).
+% Version 2.96 corrected bug in "Infinite shrinkage" recovery (January 1989).
+% Version 2.97 corrected blunder in creating 2.95 (February 1989).
+% Version 2.98 omitted save_for_after at outer level (March 1989).
+% Version 2.99 caught $$\begingroup\halign..$$ (June 1989).
+% Version 2.991 caught .5\ifdim.6... (June 1989).
+% Version 2.992 introduced major changes for 8-bit extensions (September 1989).
+% Version 2.993 fixed a save_stack synchronization bug et alia (December 1989).
+% Version 3.0 fixed unusual displays; was more \output robust (March 1990).
+% Version 3.1 fixed nullfont, disabled \write{\the\prevgraf} (September 1990).
+% Version 3.14 fixed unprintable font names and corrected typos (March 1991).
+% Version 3.141 more of same; reconstituted ligatures better (March 1992).
+% Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993).
+% Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995).
+% Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002).
+% Version 3.1415926 was a general cleanup with minor fixes (February 2008).
+\stoptyping
+
+Although considerable effort has been expended to make the LuaTeX program correct
+and reliable, no warranty is implied; the authors disclaim any obligation or
+liability for damages, including but not limited to special, indirect, or
+consequential damages arising out of or in connection with the use or performance
+of this software. This work has been a ``labor of love'' and the authors hope
+that users enjoy it.
+
+{\em You will find a lot of comments that originate in original \TEX. We kept them
+as a side effect of the conversion from \WEB\ to \CWEB. Because there is not much
+webbing going on here eventually the files became regular \CCODE\ files with still
+potentially typeset comments. As we add our own comments, and also comments are
+there from \PDFTEX, \ALEPH\ and \ETEX, we get a curious mix. The best comments are
+of course from Don Knuth. All bad comments are ours. All errors are ours too!
+
+Not all comments make sense, because some things are implemented differently, for
+instance some memory management. But the principles of tokens and nodes stayed.
+It anyway means that you sometimes need to keep in mind that the explanation is
+more geared to traditional \TEX. But that's not a bad thing. Sorry Don for any
+confusion we introduced. The readers should have a copy of the \TEX\ books at hand
+anyway.}
+
+A large piece of software like \TeX\ has inherent complexity that cannot be
+reduced below a certain level of difficulty, although each individual part is
+fairly simple by itself. The \.{WEB} language is intended to make the algorithms
+as readable as possible, by reflecting the way the individual program pieces fit
+together and by providing the cross-references that connect different parts.
+Detailed comments about what is going on, and about why things were done in
+certain ways, have been liberally sprinkled throughout the program. These
+comments explain features of the implementation, but they rarely attempt to
+explain the \TeX\ language itself, since the reader is supposed to be familiar
+with {\sl The \TeX book}.
+
+The present implementation has a long ancestry, beginning in the summer of~1977,
+when Michael~F. Plass and Frank~M. Liang designed and coded a prototype @^Plass,
+Michael Frederick@> @^Liang, Franklin Mark@> @^Knuth, Donald Ervin@> based on
+some specifications that the author had made in May of that year. This original
+proto\TeX\ included macro definitions and elementary manipulations on boxes and
+glue, but it did not have line-breaking, page-breaking, mathematical formulas,
+alignment routines, error recovery, or the present semantic nest; furthermore, it
+used character lists instead of token lists, so that a control sequence like
+\.{\\halign} was represented by a list of seven characters. A complete version of
+\TeX\ was designed and coded by the author in late 1977 and early 1978; that
+program, like its prototype, was written in the {\mc SAIL} language, for which an
+excellent debugging system was available. Preliminary plans to convert the {\mc
+SAIL} code into a form somewhat like the present ``web'' were developed by Luis
+Trabb~Pardo and @^Trabb Pardo, Luis Isidoro@> the author at the beginning of
+1979, and a complete implementation was created by Ignacio~A. Zabala in 1979 and
+1980. The \TeX82 program, which @^Zabala Salelles, Ignacio Andr\'es@> was written
+by the author during the latter part of 1981 and the early part of 1982, also
+incorporates ideas from the 1979 implementation of @^Guibas, Leonidas Ioannis@>
+@^Sedgewick, Robert@> @^Wyatt, Douglas Kirk@> \TeX\ in {\mc MESA} that was
+written by Leonidas Guibas, Robert Sedgewick, and Douglas Wyatt at the Xerox Palo
+Alto Research Center. Several hundred refinements were introduced into \TeX82
+based on the experiences gained with the original implementations, so that
+essentially every part of the system has been substantially improved. After the
+appearance of ``Version 0'' in September 1982, this program benefited greatly
+from the comments of many other people, notably David~R. Fuchs and Howard~W.
+Trickey. A final revision in September 1989 extended the input character set to
+eight-bit codes and introduced the ability to hyphenate words from different
+languages, based on some ideas of Michael~J. Ferguson. @^Fuchs, David Raymond@>
+@^Trickey, Howard Wellington@> @^Ferguson, Michael John@>
+
+No doubt there still is plenty of room for improvement, but the author is firmly
+committed to keeping \TeX82 ``frozen'' from now on; stability and reliability are
+to be its main virtues.
+On the other hand, the \.{WEB} description can be extended without changing the
+core of \TeX82 itself, and the program has been designed so that such extensions
+are not extremely difficult to make. The |banner| string defined here should be
+changed whenever \TeX\ undergoes any modifications, so that it will be clear
+which version of \TeX\ might be the guilty party when a problem arises.
+@^extensions to \TeX@> @^system dependencies@>
+
+This program contains code for various features extending \TeX, therefore this
+program is called `\eTeX' and not `\TeX'; the official name `\TeX' by itself is
+reserved for software systems that are fully compatible with each other. A
+special test suite called the ``\.{TRIP} test'' is available for helping to
+determine whether a particular implementation deserves to be known as `\TeX'
+[cf.~Stanford Computer Science report CS1027, November 1984].
+
+A similar test suite called the ``\.{e-TRIP} test'' is available for helping to
+determine whether a particular implementation deserves to be known as `\eTeX'.
+
+This is the first of many sections of \TeX\ where global variables are defined.
+
+*/
+
+/*tex Are we using lua for initializations? */
+
+boolean luainit;
+
+/*tex Print file open and close info? */
+
+boolean tracefilenames;
+
+/*tex
+
+This program has two important variations: (1) There is a long and slow version
+called \.{INITEX}, which does the extra calculations needed to @.INITEX@>
+initialize \TeX's internal tables; and (2)~there is a shorter and faster
+production version, which cuts the initialization to a bare minimum.
+
+*/
+
+/*tex are we \.{INITEX}? */
+
+boolean ini_version;
+
+/*tex was the dump name option used? */
+
+boolean dump_option;
+
+/*tex was a \.{\%\AM format} line seen? */
+
+boolean dump_line;
+
+/*tex temporary for setup */
+
+int bound_default;
+
+/*tex temporary for setup */
+
+char *bound_name;
+
+/*tex width of context lines on terminal error messages */
+
+int error_line;
+
+/*tex
+ width of first lines of contexts in terminal error messages; should be
+ between 30 and |error_line-15|
+*/
+
+int half_error_line;
+
+/*tex width of longest text lines output; should be at least 60 */
+
+int max_print_line;
+
+/*tex maximum number of strings; must not exceed |max_halfword| */
+
+int max_strings;
+
+/*tex strings available after format loaded */
+
+int strings_free;
+
+/*tex loop variable for initialization */
+
+int font_k;
+
+/*tex
+ maximum number of characters simultaneously present in current lines of open
+ files and in control sequences between \.{\\csname} and \.{\\endcsname}; must
+ not exceed |max_halfword|
+*/
+
+int buf_size;
+
+/*tex maximum number of simultaneous input sources */
+
+int stack_size;
+
+/*tex
+ maximum number of input files and error insertions that can be going on
+ simultaneously
+*/
+
+int max_in_open;
+
+/*tex maximum number of simultaneous macro parameters */
+
+int param_size;
+
+/*tex maximum number of semantic levels simultaneously active */
+
+int nest_size;
+
+/*tex
+ space for saving values outside of current group; must be at most
+ |max_halfword|
+*/
+
+int save_size;
+
+/*tex limits recursive calls of the |expand| procedure */
+
+int expand_depth;
+
+/*tex parse the first line for options */
+
+int parsefirstlinep;
+
+/*tex format messages as file:line:error */
+
+int filelineerrorstylep;
+
+/*tex stop at first error */
+
+int haltonerrorp;
+
+/*tex current filename is quoted */
+
+boolean quoted_filename;
+
+int get_luatexversion(void)
+{
+ return luatex_version;
+}
+
+/*tex the number of pages that have been shipped out */
+
+int total_pages = 0;
+
+/*tex recent outputs that didn't ship anything out */
+
+int dead_cycles = 0;
+
+str_number get_luatexrevision(void)
+{
+ return luatex_revision;
+}
+
+/*tex
+
+This is it: the part of \TeX\ that executes all those procedures we have written.
+
+We have noted that there are two versions of \TeX82. One, called \.{INITEX},
+@.INITEX@> has to be run first; it initializes everything from scratch, without
+reading a format file, and it has the capability of dumping a format file. The
+other one is called `\.{VIRTEX}'; it is a ``virgin'' program that needs
+@.VIRTEX@> to input a format file in order to get started.
+
+For \LUATEX\ it is important to know that we still dump a format. But, in order
+to gain speed and a smaller footprint, we gzip the format (level 3). We also
+store some information that makes an abort possible in case of an incompatible
+engine version, which is important as \LUATEX\ develops. It is possible to store
+\LUA\ code in the format but not the current upvalues so you still need to
+initialize. Also, traditional fonts are stored, as are extended fonts but any
+additional information needed for instance to deal with \OPENTYPE\ fonts is to be
+handled by \LUA\ code and therefore not present in the format.
+
+*/
+
+#define const_chk(A) do { \
+ if (A < inf_##A) \
+ A = inf_##A; \
+ if (A > sup_##A) \
+ A = sup_##A; \
+} while (0)
+
+#define setup_bound_var(A,B,C) do { \
+ if (luainit>0) { \
+ get_lua_number("texconfig",B,&C); \
+ if (C==0) \
+ C=A; \
+ } else { \
+ integer x; \
+ setupboundvariable(&x, B, A); \
+ C = (int)x; \
+ } \
+} while (0)
+
+int ready_already = 0;
+
+int main_initialize(void)
+{
+ /*
+ In case somebody has inadvertently made bad settings of the
+ ``constants,'' \LUATEX\ checks them using a variable called |bad|.
+ */
+ int bad = 0;
+ /*tex
+ Bounds that may be set from the configuration file. We want the user to
+ be able to specify the names with underscores, but \.{TANGLE} removes
+ underscores, so we're stuck giving the names twice, once as a string,
+ once as the identifier. How ugly. (We can change that now.)
+ */
+ setup_bound_var(15000, "max_strings", max_strings);
+ setup_bound_var(100, "strings_free", strings_free);
+ setup_bound_var(3000, "buf_size", buf_size);
+ setup_bound_var(50, "nest_size", nest_size);
+ setup_bound_var(15, "max_in_open", max_in_open);
+ setup_bound_var(60, "param_size", param_size);
+ setup_bound_var(4000, "save_size", save_size);
+ setup_bound_var(300, "stack_size", stack_size);
+ setup_bound_var(16384, "dvi_buf_size", dvi_buf_size);
+ setup_bound_var(79, "error_line", error_line);
+ setup_bound_var(50, "half_error_line", half_error_line);
+ setup_bound_var(79, "max_print_line", max_print_line);
+ setup_bound_var(0, "hash_extra", hash_extra);
+ setup_bound_var(72, "pk_dpi", pk_dpi);
+ setup_bound_var(10000, "expand_depth", expand_depth);
+ /*tex
+ Check other constants against their sup and inf.
+ */
+ const_chk(buf_size);
+ const_chk(nest_size);
+ const_chk(max_in_open);
+ const_chk(param_size);
+ const_chk(save_size);
+ const_chk(stack_size);
+ const_chk(dvi_buf_size);
+ const_chk(max_strings);
+ const_chk(strings_free);
+ const_chk(hash_extra);
+ const_chk(pk_dpi);
+ if (error_line > ssup_error_line) {
+ error_line = ssup_error_line;
+ }
+ /*tex
+ Array memory allocation
+ */
+ buffer = xmallocarray(packed_ASCII_code, (unsigned) buf_size);
+ nest = xmallocarray(list_state_record, (unsigned) nest_size);
+ save_stack = xmallocarray(save_record, (unsigned) save_size);
+ input_stack = xmallocarray(in_state_record, (unsigned) stack_size);
+ input_file = xmallocarray(alpha_file, (unsigned) max_in_open);
+ input_file_callback_id = xmallocarray(int, (unsigned) max_in_open);
+ line_stack = xmallocarray(int, (unsigned) max_in_open);
+ eof_seen = xmallocarray(boolean, (unsigned) max_in_open);
+ grp_stack = xmallocarray(save_pointer, (unsigned) max_in_open);
+ if_stack = xmallocarray(pointer, (unsigned) max_in_open);
+ source_filename_stack = xmallocarray(str_number, (unsigned) max_in_open);
+ full_source_filename_stack = xmallocarray(char *, (unsigned) max_in_open);
+ param_stack = xmallocarray(halfword, (unsigned) param_size);
+ dvi_buf = xmallocarray(eight_bits, (unsigned) dvi_buf_size);
+ /*tex
+ Only in ini mode:
+ */
+ if (ini_version) {
+ fixmem = xmallocarray(smemory_word, fix_mem_init + 1);
+ memset(voidcast(fixmem), 0, (fix_mem_init + 1) * sizeof(smemory_word));
+ fix_mem_min = 0;
+ fix_mem_max = fix_mem_init;
+ eqtb_top = eqtb_size + hash_extra;
+ if (hash_extra == 0)
+ hash_top = undefined_control_sequence;
+ else
+ hash_top = eqtb_top;
+ hash = xmallocarray(two_halves, (unsigned) (hash_top + 1));
+ memset(hash, 0, sizeof(two_halves) * (unsigned) (hash_top + 1));
+ eqtb = xmallocarray(memory_word, (unsigned) (eqtb_top + 1));
+ memset(eqtb, 0, sizeof(memory_word) * (unsigned) (eqtb_top + 1));
+ init_string_pool_array((unsigned) max_strings);
+ reset_cur_string();
+ }
+ /*tex
+ Check the ``constant'' values...
+ */
+ if ((half_error_line < 30) || (half_error_line > error_line - 15))
+ bad = 1;
+ if (max_print_line < 60)
+ bad = 2;
+ if (dvi_buf_size % 8 != 0)
+ bad = 3;
+ if (hash_prime > hash_size)
+ bad = 5;
+ if (max_in_open >= (sup_max_in_open+1)) /* 128 */
+ bad = 6;
+ /*tex
+ Here are the inequalities that the quarterword and halfword values
+ must satisfy (or rather, the inequalities that they mustn't satisfy):
+ */
+ if ((min_quarterword > 0) || (max_quarterword < 0x7FFF))
+ bad = 11;
+ if ((min_halfword > 0) || (max_halfword < 0x3FFFFFFF))
+ bad = 12;
+ if ((min_quarterword < min_halfword) || (max_quarterword > max_halfword))
+ bad = 13;
+ if (font_base < min_quarterword)
+ bad = 15;
+ if ((save_size > max_halfword) || (max_strings > max_halfword))
+ bad = 17;
+ if (buf_size > max_halfword)
+ bad = 18;
+ if (max_quarterword - min_quarterword < 0xFFFF)
+ bad = 19;
+ if (cs_token_flag + eqtb_size + hash_extra > max_halfword)
+ bad = 21;
+ if (bad > 0) {
+ wterm_cr();
+ fprintf(term_out,
+ "Ouch---my internal constants have been clobbered! ---case %d",
+ (int) bad
+ );
+ } else {
+ /*tex Set global variables to their starting values. */
+ initialize();
+ if (ini_version) {
+ /*tex Initialize all the primitives. */
+ no_new_control_sequence = false;
+ first = 0;
+ initialize_commands();
+ initialize_etex_commands();
+ init_str_ptr = str_ptr;
+ no_new_control_sequence = true;
+ fix_date_and_time();
+ }
+ ready_already = 314159;
+ }
+ return bad;
+}
+
+
+void main_body(void)
+{
+ static char pdftex_map[] = "pdftex.map";
+ int bad = main_initialize();
+ /*tex in case we quit during initialization */
+ history = fatal_error_stop;
+ /*tex open the terminal for output */
+ t_open_out();
+ if (!luainit)
+ tracefilenames = true;
+ if (bad > 0) {
+ goto FINAL_END;
+ }
+ print_banner(luatex_version_string);
+ /*tex
+ Get the first line of input and prepare to start When we begin the
+ following code, \TeX's tables may still contain garbage; the strings
+ might not even be present. Thus we must proceed cautiously to get
+ bootstrapped in.
+
+ But when we finish this part of the program, \TeX\ is ready to call on
+ the |main_control| routine to do its work.
+ */
+ /*tex
+ This copies the command line,
+ */
+ initialize_inputstack();
+ if (buffer[iloc] == '*')
+ incr(iloc);
+ if ((format_ident == 0) || (buffer[iloc] == '&') || dump_line) {
+ char *fname = NULL;
+ if (format_ident != 0 && !ini_version) {
+ /*tex Erase preloaded format. */
+ initialize();
+ }
+ if ((fname = open_fmt_file()) == NULL)
+ goto FINAL_END;
+ if (!load_fmt_file(fname)) {
+ zwclose(fmt_file);
+ goto FINAL_END;
+ }
+ zwclose(fmt_file);
+ while ((iloc < ilimit) && (buffer[iloc] == ' '))
+ incr(iloc);
+ }
+ if (output_mode_option != 0)
+ output_mode_par = output_mode_value;
+ if (draft_mode_option != 0) {
+ draft_mode_par = draft_mode_value;
+ }
+ /*tex can this be moved? */
+ pdf_init_map_file((char *) pdftex_map);
+ /* */
+ if (end_line_char_inactive)
+ decr(ilimit);
+ else
+ buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
+ fix_date_and_time();
+ random_seed = (microseconds * 1000) + (epochseconds % 1000000);
+ init_randoms(random_seed);
+ initialize_math();
+ fixup_selector(log_opened_global);
+ check_texconfig_init();
+ if ((iloc < ilimit) && (get_cat_code(cat_code_table_par, buffer[iloc]) != escape_cmd)) {
+ /*tex \.{\\input} assumed */
+ start_input();
+ }
+ /*tex Initialize |text_dir_ptr| */
+ text_dir_ptr = new_dir(0);
+ /*tex Ready to go! */
+ history = spotless;
+ /*tex Initialize synctex primitive */
+ synctexinitcommand();
+ /*tex Come to life. */
+ main_control();
+ flush_node(text_dir_ptr);
+ /*tex Prepare for death. */
+ final_cleanup();
+ close_files_and_terminate();
+ FINAL_END:
+ do_final_end();
+}
+
+/*tex
+
+Here we do whatever is needed to complete \TeX's job gracefully on the local
+operating system. The code here might come into play after a fatal error; it must
+therefore consist entirely of ``safe'' operations that cannot produce error
+messages. For example, it would be a mistake to call |str_room| or |make_string|
+at this time, because a call on |overflow| might lead to an infinite loop.
+@^system dependencies@>
+
+Actually there's one way to get error messages, via |prepare_mag|; but that can't
+cause infinite recursion. @^recursion@>
+
+This program doesn't bother to close the input files that may still be open.
+
+*/
+
+void close_files_and_terminate(void)
+{
+ int callback_id;
+ callback_id = callback_defined(stop_run_callback);
+ finalize_write_files();
+ if (tracing_stats_par > 0) {
+ if (callback_id == 0) {
+ /*tex
+ Output statistics about this job. The present section goes
+ directly to the log file instead of using |print| commands,
+ because there's no need for these strings to take up
+ |string_pool| memory when a non-{\bf stat} version of \TeX\ is
+ being used.
+ */
+ if (log_opened_global) {
+ fprintf(log_file,
+ "\n\nHere is how much of LuaTeX's memory you used:\n"
+ );
+ fprintf(log_file, " %d string%s out of %d\n",
+ (int) (str_ptr - init_str_ptr),
+ (str_ptr == (init_str_ptr + 1) ? "" : "s"),
+ (int) (max_strings - init_str_ptr + STRING_OFFSET)
+ );
+ fprintf(log_file, " %d,%d words of node,token memory allocated",
+ (int) var_mem_max, (int) fix_mem_max
+ );
+ print_node_mem_stats();
+ fprintf(log_file,
+ " %d multiletter control sequences out of %ld+%d\n",
+ (int) cs_count, (long) hash_size, (int) hash_extra
+ );
+ fprintf(log_file, " %d font%s using %d bytes\n",
+ (int) max_font_id(), (max_font_id() == 1 ? "" : "s"),
+ (int) font_bytes
+ );
+ fprintf(log_file,
+ " %di,%dn,%dp,%db,%ds stack positions out of %di,%dn,%dp,%db,%ds\n",
+ (int) max_in_stack, (int) max_nest_stack,
+ (int) max_param_stack, (int) max_buf_stack,
+ (int) max_save_stack + 6, (int) stack_size,
+ (int) nest_size, (int) param_size, (int) buf_size,
+ (int) save_size
+ );
+ }
+ }
+ }
+ wake_up_terminal();
+ /*tex
+ Rubish, these \PDF arguments, passed, needs to be fixed, e.g. with a
+ dummy in \DVI.
+ */
+ wrapup_backend();
+ /*tex
+ Close {\sl Sync\TeX} file and write status.
+ */
+ synctexterminate(log_opened_global);
+ /*tex
+ The following is needed because synctex removes files and we want to keep
+ them which means renaming a temp file .. we can't bypass the terminate
+ because it might do mem cleanup.
+ */
+ if (synctex_get_mode() > 0) {
+ callback_id = callback_defined(finish_synctex_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ }
+ }
+ /* free_text_codes(); */
+ /* free_math_codes(); */
+ if (log_opened_global) {
+ wlog_cr();
+ selector = selector - 2;
+ if ((selector == term_only) && (callback_id == 0)) {
+ tprint_nl("Transcript written on ");
+ tprint_file_name(NULL, texmf_log_name, NULL);
+ print_char('.');
+ print_ln();
+ }
+ lua_a_close_out(log_file);
+ }
+ callback_id = callback_defined(wrapup_run_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "->");
+ }
+ free_text_codes();
+ free_math_codes();
+}
+
+/*tex
+
+We get to the |final_cleanup| routine when \.{\\end} or \.{\\dump} has been
+scanned and |its_all_over|.
+
+*/
+
+void final_cleanup(void)
+{
+ /*tex This one gets the value 0 for \.{\\end}, 1 for \.{\\dump}. */
+ int c;
+ /*tex Here's one for looping marks: */
+ halfword i;
+ /*tex This was a global temp_ptr: */
+ halfword t;
+ c = cur_chr;
+ if (job_name == 0)
+ open_log_file();
+ while (input_ptr > 0)
+ if (istate == token_list)
+ end_token_list();
+ else
+ end_file_reading();
+ while (open_parens > 0) {
+ report_stop_file(filetype_tex);
+ decr(open_parens);
+ }
+ if (cur_level > level_one) {
+ tprint_nl("(\\end occurred inside a group at level ");
+ print_int(cur_level - level_one);
+ print_char(')');
+ show_save_groups();
+ }
+ while (cond_ptr != null) {
+ tprint_nl("(\\end occurred when ");
+ print_cmd_chr(if_test_cmd, cur_if);
+ if (if_line != 0) {
+ tprint(" on line ");
+ print_int(if_line);
+ }
+ tprint(" was incomplete)");
+ if_line = if_line_field(cond_ptr);
+ cur_if = subtype(cond_ptr);
+ t = cond_ptr;
+ cond_ptr = vlink(cond_ptr);
+ flush_node(t);
+ }
+ if (callback_defined(stop_run_callback) == 0)
+ if (history != spotless)
+ if ((history == warning_issued) || (interaction < error_stop_mode))
+ if (selector == term_and_log) {
+ selector = term_only;
+ tprint_nl("(see the transcript file for additional information)");
+ selector = term_and_log;
+ }
+ if (c == 1) {
+ if (ini_version) {
+ for (i = 0; i <= biggest_used_mark; i++) {
+ delete_top_mark(i);
+ delete_first_mark(i);
+ delete_bot_mark(i);
+ delete_split_first_mark(i);
+ delete_split_bot_mark(i);
+ }
+ for (c = last_box_code; c <= vsplit_code; c++)
+ flush_node_list(disc_ptr[c]);
+ if (last_glue != max_halfword) {
+ flush_node(last_glue);
+ }
+ /*tex Flush the pseudo files. */
+ while (pseudo_files != null) {
+ pseudo_close();
+ }
+ store_fmt_file();
+ return;
+ }
+ tprint_nl("(\\dump is performed only by INITEX)");
+ return;
+ }
+}
+
+/*tex
+
+Once \TeX\ is working, you should be able to diagnose most errors with the
+\.{\\show} commands and other diagnostic features.
+
+Because we have made some internal changes the optional debug interface
+has been removed.
+
+*/
diff --git a/Build/source/texk/web2c/luatexdir/tex/mainbody.w b/Build/source/texk/web2c/luatexdir/tex/mainbody.w
deleted file mode 100644
index 4d38b9d4a47..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/mainbody.w
+++ /dev/null
@@ -1,708 +0,0 @@
-% mainbody.w
-%
-% Copyright 2009-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/>.
-
-\def\eTeX{e-\TeX}
-\def\Aleph{Aleph}
-\def\pdfTeX{pdf\TeX}
-
-@ @c
-
-
-#include "ptexlib.h"
-
-@
-pdfTeX is copyright (C) 1996-2006 Han The Thanh, <thanh@@pdftex.org>.
-
-e-TeX is copyright (C) 1994,98 by Peter Breitenlohner.
-
-This is LuaTeX, a continuation of $\pdfTeX$ and $\Aleph$. LuaTeX is a
-document compiler intended to simplify high-quality typesetting for
-many of the world's languages. It is an extension of D. E. Knuth's
-\TeX, which was designed essentially for the typesetting of languages
-using the Latin alphabet.
-
-The $\Aleph$ subsystem loosens many of the restrictions imposed by~\TeX:
-register numbers are no longer limited to 8~bits; fonts may have more
-than 256~characters; more than 256~fonts may be used; etc.
-
-% This program is directly derived from Donald E. Knuth's TeX;
-% the change history which follows and the reward offered for finders of
-% bugs refer specifically to TeX; they should not be taken as referring
-% to LuaTeX, pdfTeX, nor e-TeX, although the change history is relevant in that it
-% demonstrates the evolutionary path followed. This program is not TeX;
-% that name is reserved strictly for the program which is the creation
-% and sole responsibility of Professor Knuth.
-
-% Version 0 was released in September 1982 after it passed a variety of tests.
-% Version 1 was released in November 1983 after thorough testing.
-% Version 1.1 fixed ``disappearing font identifiers'' et alia (July 1984).
-% Version 1.2 allowed `0' in response to an error, et alia (October 1984).
-% Version 1.3 made memory allocation more flexible and local (November 1984).
-% Version 1.4 fixed accents right after line breaks, et alia (April 1985).
-% Version 1.5 fixed \the\toks after other expansion in \edefs (August 1985).
-% Version 2.0 (almost identical to 1.5) corresponds to "Volume B" (April 1986).
-% Version 2.1 corrected anomalies in discretionary breaks (January 1987).
-% Version 2.2 corrected "(Please type...)" with null \endlinechar (April 1987).
-% Version 2.3 avoided incomplete page in premature termination (August 1987).
-% Version 2.4 fixed \noaligned rules in indented displays (August 1987).
-% Version 2.5 saved cur_order when expanding tokens (September 1987).
-% Version 2.6 added 10sp slop when shipping leaders (November 1987).
-% Version 2.7 improved rounding of negative-width characters (November 1987).
-% Version 2.8 fixed weird bug if no \patterns are used (December 1987).
-% Version 2.9 made \csname\endcsname's "relax" local (December 1987).
-% Version 2.91 fixed \outer\def\a0{}\a\a bug (April 1988).
-% Version 2.92 fixed \patterns, also file names with complex macros (May 1988).
-% Version 2.93 fixed negative halving in allocator when mem_min<0 (June 1988).
-% Version 2.94 kept open_log_file from calling fatal_error (November 1988).
-% Version 2.95 solved that problem a better way (December 1988).
-% Version 2.96 corrected bug in "Infinite shrinkage" recovery (January 1989).
-% Version 2.97 corrected blunder in creating 2.95 (February 1989).
-% Version 2.98 omitted save_for_after at outer level (March 1989).
-% Version 2.99 caught $$\begingroup\halign..$$ (June 1989).
-% Version 2.991 caught .5\ifdim.6... (June 1989).
-% Version 2.992 introduced major changes for 8-bit extensions (September 1989).
-% Version 2.993 fixed a save_stack synchronization bug et alia (December 1989).
-% Version 3.0 fixed unusual displays; was more \output robust (March 1990).
-% Version 3.1 fixed nullfont, disabled \write{\the\prevgraf} (September 1990).
-% Version 3.14 fixed unprintable font names and corrected typos (March 1991).
-% Version 3.141 more of same; reconstituted ligatures better (March 1992).
-% Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993).
-% Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995).
-% Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002).
-% Version 3.1415926 was a general cleanup with minor fixes (February 2008).
-
-
-% Although considerable effort has been expended to make the LuaTeX program
-% correct and reliable, no warranty is implied; the authors disclaim any
-% obligation or liability for damages, including but not limited to
-% special, indirect, or consequential damages arising out of or in
-% connection with the use or performance of this software. This work has
-% been a ``labor of love'' and the authors hope that users enjoy it.
-
-A large piece of software like \TeX\ has inherent complexity that cannot
-be reduced below a certain level of difficulty, although each individual
-part is fairly simple by itself. The \.{WEB} language is intended to make
-the algorithms as readable as possible, by reflecting the way the
-individual program pieces fit together and by providing the
-cross-references that connect different parts. Detailed comments about
-what is going on, and about why things were done in certain ways, have
-been liberally sprinkled throughout the program. These comments explain
-features of the implementation, but they rarely attempt to explain the
-\TeX\ language itself, since the reader is supposed to be familiar with
-{\sl The \TeX book}.
-@.WEB@>
-@:TeXbook}{\sl The \TeX book@>
-
-The present implementation has a long ancestry, beginning in the summer
-of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded
-a prototype
-@^Plass, Michael Frederick@>
-@^Liang, Franklin Mark@>
-@^Knuth, Donald Ervin@>
-based on some specifications that the author had made in May of that year.
-This original proto\TeX\ included macro definitions and elementary
-manipulations on boxes and glue, but it did not have line-breaking,
-page-breaking, mathematical formulas, alignment routines, error recovery,
-or the present semantic nest; furthermore,
-it used character lists instead of token lists, so that a control sequence
-like \.{\\halign} was represented by a list of seven characters. A
-complete version of \TeX\ was designed and coded by the author in late
-1977 and early 1978; that program, like its prototype, was written in the
-{\mc SAIL} language, for which an excellent debugging system was
-available. Preliminary plans to convert the {\mc SAIL} code into a form
-somewhat like the present ``web'' were developed by Luis Trabb~Pardo and
-@^Trabb Pardo, Luis Isidoro@>
-the author at the beginning of 1979, and a complete implementation was
-created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which
-@^Zabala Salelles, Ignacio Andr\'es@>
-was written by the author during the latter part of 1981 and the early
-part of 1982, also incorporates ideas from the 1979 implementation of
-@^Guibas, Leonidas Ioannis@>
-@^Sedgewick, Robert@>
-@^Wyatt, Douglas Kirk@>
-\TeX\ in {\mc MESA} that was written by Leonidas Guibas, Robert Sedgewick,
-and Douglas Wyatt at the Xerox Palo Alto Research Center. Several hundred
-refinements were introduced into \TeX82 based on the experiences gained with
-the original implementations, so that essentially every part of the system
-has been substantially improved. After the appearance of ``Version 0'' in
-September 1982, this program benefited greatly from the comments of
-many other people, notably David~R. Fuchs and Howard~W. Trickey.
-A final revision in September 1989 extended the input character set to
-eight-bit codes and introduced the ability to hyphenate words from
-different languages, based on some ideas of Michael~J. Ferguson.
-@^Fuchs, David Raymond@>
-@^Trickey, Howard Wellington@>
-@^Ferguson, Michael John@>
-
-No doubt there still is plenty of room for improvement, but the author
-is firmly committed to keeping \TeX82 ``frozen'' from now on; stability
-and reliability are to be its main virtues.
-
-On the other hand, the \.{WEB} description can be extended without changing
-the core of \TeX82 itself, and the program has been designed so that such
-extensions are not extremely difficult to make.
-The |banner| string defined here should be changed whenever \TeX\
-undergoes any modifications, so that it will be clear which version of
-\TeX\ might be the guilty party when a problem arises.
-@^extensions to \TeX@>
-@^system dependencies@>
-
-This program contains code for various features extending \TeX,
-therefore this program is called `\eTeX' and not
-`\TeX'; the official name `\TeX' by itself is reserved
-for software systems that are fully compatible with each other.
-A special test suite called the ``\.{TRIP} test'' is available for
-helping to determine whether a particular implementation deserves to be
-known as `\TeX' [cf.~Stanford Computer Science report CS1027,
-November 1984].
-
-A similar test suite called the ``\.{e-TRIP} test'' is available for
-helping to determine whether a particular implementation deserves to be
-known as `\eTeX'.
-
-@ This is the first of many sections of \TeX\ where global variables are
-defined.
-
-@c
-boolean luainit; /* are we using lua for initializations */
-boolean tracefilenames; /* print file open-close info? */
-
-
-@ This program has two important variations: (1) There is a long and slow
-version called \.{INITEX}, which does the extra calculations needed to
-@.INITEX@>
-initialize \TeX's internal tables; and (2)~there is a shorter and faster
-production version, which cuts the initialization to a bare minimum.
-
-@c
-boolean ini_version; /* are we \.{INITEX}? */
-boolean dump_option; /* was the dump name option used? */
-boolean dump_line; /* was a \.{\%\AM format} line seen? */
-int bound_default; /* temporary for setup */
-char *bound_name; /* temporary for setup */
-int error_line; /* width of context lines on terminal error messages */
-int half_error_line; /* width of first lines of contexts in terminal
- error messages; should be between 30 and |error_line-15| */
-int max_print_line; /* width of longest text lines output; should be at least 60 */
-int max_strings; /* maximum number of strings; must not exceed |max_halfword| */
-int strings_free; /* strings available after format loaded */
-int font_k; /* loop variable for initialization */
-int buf_size; /* maximum number of characters simultaneously present in
- current lines of open files and in control sequences between
- \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword| */
-int stack_size; /* maximum number of simultaneous input sources */
-int max_in_open; /* maximum number of input files and error insertions that
- can be going on simultaneously */
-int param_size; /* maximum number of simultaneous macro parameters */
-int nest_size; /* maximum number of semantic levels simultaneously active */
-int save_size; /* space for saving values outside of current group; must be
- at most |max_halfword| */
-int expand_depth; /* limits recursive calls of the |expand| procedure */
-int parsefirstlinep; /* parse the first line for options */
-int filelineerrorstylep; /* format messages as file:line:error */
-int haltonerrorp; /* stop at first error */
-boolean quoted_filename; /* current filename is quoted */
-
-@ @c
-int get_luatexversion(void)
-{
- return luatex_version;
-}
-
-str_number get_luatexrevision(void)
-{
- return luatex_revision;
-}
-
-@ This is it: the part of \TeX\ that executes all those procedures we have
-written.
-
-We have noted that there are two versions of \TeX82. One, called \.{INITEX},
-@.INITEX@>
-has to be run first; it initializes everything from scratch, without
-reading a format file, and it has the capability of dumping a format file.
-The other one is called `\.{VIRTEX}'; it is a ``virgin'' program that needs
-@.VIRTEX@>
-to input a format file in order to get started.
-
-@c
-#define const_chk(A) do { \
- if (A < inf_##A) A = inf_##A; \
- if (A > sup_##A) A = sup_##A; \
- } while (0)
-
-#define setup_bound_var(A,B,C) do { \
- if (luainit>0) { \
- get_lua_number("texconfig",B,&C); \
- if (C==0) C=A; \
- } else { \
- integer x; \
- setupboundvariable(&x, B, A); \
- C = (int)x; \
- } \
- } while (0)
-
-
-int ready_already = 0;
-
-int main_initialize(void)
-{
- /* In case somebody has inadvertently made bad settings of the ``constants,''
- \LuaTeX\ checks them using a variable called |bad|. */
- int bad = 0;
- /* Bounds that may be set from the configuration file. We want the user to
- be able to specify the names with underscores, but \.{TANGLE} removes
- underscores, so we're stuck giving the names twice, once as a string,
- once as the identifier. How ugly. */
-
- setup_bound_var(15000, "max_strings", max_strings);
- setup_bound_var(100, "strings_free", strings_free);
- setup_bound_var(3000, "buf_size", buf_size);
- setup_bound_var(50, "nest_size", nest_size);
- setup_bound_var(15, "max_in_open", max_in_open);
- setup_bound_var(60, "param_size", param_size);
- setup_bound_var(4000, "save_size", save_size);
- setup_bound_var(300, "stack_size", stack_size);
- setup_bound_var(16384, "dvi_buf_size", dvi_buf_size);
- setup_bound_var(79, "error_line", error_line);
- setup_bound_var(50, "half_error_line", half_error_line);
- setup_bound_var(79, "max_print_line", max_print_line);
- setup_bound_var(0, "hash_extra", hash_extra);
- setup_bound_var(72, "pk_dpi", pk_dpi);
- setup_bound_var(10000, "expand_depth", expand_depth);
-
- /* Check other constants against their sup and inf. */
- const_chk(buf_size);
- const_chk(nest_size);
- const_chk(max_in_open);
- const_chk(param_size);
- const_chk(save_size);
- const_chk(stack_size);
- const_chk(dvi_buf_size);
- const_chk(max_strings);
- const_chk(strings_free);
- const_chk(hash_extra);
- const_chk(pk_dpi);
- if (error_line > ssup_error_line)
- error_line = ssup_error_line;
-
- /* array memory allocation */
- buffer = xmallocarray(packed_ASCII_code, (unsigned) buf_size);
- nest = xmallocarray(list_state_record, (unsigned) nest_size);
- save_stack = xmallocarray(save_record, (unsigned) save_size);
- input_stack = xmallocarray(in_state_record, (unsigned) stack_size);
- input_file = xmallocarray(alpha_file, (unsigned) max_in_open);
- input_file_callback_id = xmallocarray(int, (unsigned) max_in_open);
- line_stack = xmallocarray(int, (unsigned) max_in_open);
- eof_seen = xmallocarray(boolean, (unsigned) max_in_open);
- grp_stack = xmallocarray(save_pointer, (unsigned) max_in_open);
- if_stack = xmallocarray(pointer, (unsigned) max_in_open);
- source_filename_stack = xmallocarray(str_number, (unsigned) max_in_open);
- full_source_filename_stack = xmallocarray(char *, (unsigned) max_in_open);
- param_stack = xmallocarray(halfword, (unsigned) param_size);
- dvi_buf = xmallocarray(eight_bits, (unsigned) dvi_buf_size);
-
- if (ini_version) {
- fixmem = xmallocarray(smemory_word, fix_mem_init + 1);
- memset(voidcast(fixmem), 0, (fix_mem_init + 1) * sizeof(smemory_word));
- fix_mem_min = 0;
- fix_mem_max = fix_mem_init;
- eqtb_top = eqtb_size + hash_extra;
- if (hash_extra == 0)
- hash_top = undefined_control_sequence;
- else
- hash_top = eqtb_top;
- hash = xmallocarray(two_halves, (unsigned) (hash_top + 1));
- memset(hash, 0, sizeof(two_halves) * (unsigned) (hash_top + 1));
- eqtb = xmallocarray(memory_word, (unsigned) (eqtb_top + 1));
- memset(eqtb, 0, sizeof(memory_word) * (unsigned) (eqtb_top + 1));
- init_string_pool_array((unsigned) max_strings);
- reset_cur_string();
- }
- /* Check the ``constant'' values... */
- if ((half_error_line < 30) || (half_error_line > error_line - 15))
- bad = 1;
- if (max_print_line < 60)
- bad = 2;
- if (dvi_buf_size % 8 != 0)
- bad = 3;
- if (hash_prime > hash_size)
- bad = 5;
- if (max_in_open >= (sup_max_in_open+1)) /* 128 */
- bad = 6;
- /* Here are the inequalities that the quarterword and halfword values
- must satisfy (or rather, the inequalities that they mustn't satisfy): */
- if ((min_quarterword > 0) || (max_quarterword < 0x7FFF))
- bad = 11;
- if ((min_halfword > 0) || (max_halfword < 0x3FFFFFFF))
- bad = 12;
- if ((min_quarterword < min_halfword) || (max_quarterword > max_halfword))
- bad = 13;
- if (font_base < min_quarterword)
- bad = 15;
- if ((save_size > max_halfword) || (max_strings > max_halfword))
- bad = 17;
- if (buf_size > max_halfword)
- bad = 18;
- if (max_quarterword - min_quarterword < 0xFFFF)
- bad = 19;
- if (cs_token_flag + eqtb_size + hash_extra > max_halfword)
- bad = 21;
- if (bad > 0) {
- wterm_cr();
- fprintf(term_out,
- "Ouch---my internal constants have been clobbered! ---case %d",
- (int) bad);
- } else {
- initialize(); /* set global variables to their starting values */
- if (ini_version) {
- /* initialize all the primitives */
- no_new_control_sequence = false;
- first = 0;
- initialize_commands();
- initialize_etex_commands();
- init_str_ptr = str_ptr;
- no_new_control_sequence = true;
- fix_date_and_time();
- }
- ready_already = 314159;
- }
- return bad;
-}
-
-@ @c
-void main_body(void)
-{
- static char pdftex_map[] = "pdftex.map";
- int bad = main_initialize();
- history = fatal_error_stop; /* in case we quit during initialization */
- t_open_out(); /* open the terminal for output */
- if (!luainit)
- tracefilenames = true;
- if (bad > 0) {
- goto FINAL_END;
- }
- print_banner(luatex_version_string);
-
- /* Get the first line of input and prepare to start */
- /* When we begin the following code, \TeX's tables may still contain garbage;
- the strings might not even be present. Thus we must proceed cautiously to get
- bootstrapped in.
-
- But when we finish this part of the program, \TeX\ is ready to call on the
- |main_control| routine to do its work.
- */
- initialize_inputstack(); /* this copies the command-line */
- if (buffer[iloc] == '*')
- incr(iloc);
- if ((format_ident == 0) || (buffer[iloc] == '&') || dump_line) {
- char *fname = NULL;
- if (format_ident != 0 && !ini_version)
- initialize(); /* erase preloaded format */
- if ((fname = open_fmt_file()) == NULL)
- goto FINAL_END;
- if (!load_fmt_file(fname)) {
- zwclose(fmt_file);
- goto FINAL_END;
- }
- zwclose(fmt_file);
- while ((iloc < ilimit) && (buffer[iloc] == ' '))
- incr(iloc);
- }
- if (output_mode_option != 0)
- output_mode_par = output_mode_value;
- if (draft_mode_option != 0) {
- draft_mode_par = draft_mode_value;
- }
- /* can this be moved? */
- pdf_init_map_file((char *) pdftex_map);
- /* */
- if (end_line_char_inactive)
- decr(ilimit);
- else
- buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
- fix_date_and_time();
- random_seed = (microseconds * 1000) + (epochseconds % 1000000);
- init_randoms(random_seed);
- initialize_math();
- fixup_selector(log_opened_global);
- check_texconfig_init();
- if ((iloc < ilimit) && (get_cat_code(cat_code_table_par, buffer[iloc]) != escape_cmd))
- start_input(); /* \.{\\input} assumed */
- /* DIR: Initialize |text_dir_ptr| */
- text_dir_ptr = new_dir(0);
-
- history = spotless; /* ready to go! */
- /* Initialize synctex primitive */
- synctexinitcommand();
- main_control(); /* come to life */
- flush_node(text_dir_ptr);
- final_cleanup(); /* prepare for death */
- close_files_and_terminate();
- FINAL_END:
- do_final_end();
-}
-
-
-@ Here we do whatever is needed to complete \TeX's job gracefully on the
-local operating system. The code here might come into play after a fatal
-error; it must therefore consist entirely of ``safe'' operations that
-cannot produce error messages. For example, it would be a mistake to call
-|str_room| or |make_string| at this time, because a call on |overflow|
-might lead to an infinite loop.
-@^system dependencies@>
-
-Actually there's one way to get error messages, via |prepare_mag|;
-but that can't cause infinite recursion.
-@^recursion@>
-
-This program doesn't bother to close the input files that may still be open.
-
-@c
-void close_files_and_terminate(void)
-{
- int callback_id;
- callback_id = callback_defined(stop_run_callback);
- finalize_write_files();
- if (tracing_stats_par > 0) {
- if (callback_id == 0) {
- /* Output statistics about this job */
- /* The present section goes directly to the log file instead of using
- |print| commands, because there's no need for these strings to take
- up |string_pool| memory when a non-{\bf stat} version of \TeX\ is being used.
- */
-
- if (log_opened_global) {
- fprintf(log_file,
- "\n\nHere is how much of LuaTeX's memory you used:\n");
- fprintf(log_file, " %d string%s out of %d\n",
- (int) (str_ptr - init_str_ptr),
- (str_ptr == (init_str_ptr + 1) ? "" : "s"),
- (int) (max_strings - init_str_ptr + STRING_OFFSET));
- fprintf(log_file, " %d,%d words of node,token memory allocated",
- (int) var_mem_max, (int) fix_mem_max);
- print_node_mem_stats();
- fprintf(log_file,
- " %d multiletter control sequences out of %ld+%d\n",
- (int) cs_count, (long) hash_size, (int) hash_extra);
- fprintf(log_file, " %d font%s using %d bytes\n",
- (int) max_font_id(), (max_font_id() == 1 ? "" : "s"),
- (int) font_bytes);
- fprintf(log_file,
- " %di,%dn,%dp,%db,%ds stack positions out of %di,%dn,%dp,%db,%ds\n",
- (int) max_in_stack, (int) max_nest_stack,
- (int) max_param_stack, (int) max_buf_stack,
- (int) max_save_stack + 6, (int) stack_size,
- (int) nest_size, (int) param_size, (int) buf_size,
- (int) save_size);
- }
- }
- }
- wake_up_terminal();
- /* rubish, these pdf arguments, passed, needs to be fixed, e.g. with a dummy in dvi */
- wrapup_backend();
- /* Close {\sl Sync\TeX} file and write status */
- synctexterminate(log_opened_global);
- /*
- The following is needed because synctex removes files and we want to keep them which
- means renaming a temp file .. we can't bypass the terminate because it might do mem
- cleanup.
- */
- if (synctex_get_mode() > 0) {
- callback_id = callback_defined(finish_synctex_callback);
- if (callback_id > 0) {
- run_callback(callback_id, "->");
- }
- }
- free_text_codes();
- free_math_codes();
- if (log_opened_global) {
- wlog_cr();
- selector = selector - 2;
- if ((selector == term_only) && (callback_id == 0)) {
- tprint_nl("Transcript written on ");
- tprint_file_name(NULL, texmf_log_name, NULL);
- print_char('.');
- print_ln();
- }
- lua_a_close_out(log_file);
- }
-}
-
-
-@ We get to the |final_cleanup| routine when \.{\\end} or \.{\\dump} has
-been scanned and |its_all_over|\kern-2pt.
-
-@c
-void final_cleanup(void)
-{
- int c; /* 0 for \.{\\end}, 1 for \.{\\dump} */
- halfword i; /* for looping marks */
- halfword t; /* was a global temp_ptr */
- c = cur_chr;
- if (job_name == 0)
- open_log_file();
- while (input_ptr > 0)
- if (istate == token_list)
- end_token_list();
- else
- end_file_reading();
- while (open_parens > 0) {
- report_stop_file(filetype_tex);
- decr(open_parens);
- }
- if (cur_level > level_one) {
- tprint_nl("(\\end occurred inside a group at level ");
- print_int(cur_level - level_one);
- print_char(')');
- show_save_groups();
- }
- while (cond_ptr != null) {
- tprint_nl("(\\end occurred when ");
- print_cmd_chr(if_test_cmd, cur_if);
- if (if_line != 0) {
- tprint(" on line ");
- print_int(if_line);
- }
- tprint(" was incomplete)");
- if_line = if_line_field(cond_ptr);
- cur_if = subtype(cond_ptr);
- t = cond_ptr;
- cond_ptr = vlink(cond_ptr);
- flush_node(t);
- }
- if (callback_defined(stop_run_callback) == 0)
- if (history != spotless)
- if ((history == warning_issued) || (interaction < error_stop_mode))
- if (selector == term_and_log) {
- selector = term_only;
- tprint_nl("(see the transcript file for additional information)");
- selector = term_and_log;
- }
- if (c == 1) {
- if (ini_version) {
- for (i = 0; i <= biggest_used_mark; i++) {
- delete_top_mark(i);
- delete_first_mark(i);
- delete_bot_mark(i);
- delete_split_first_mark(i);
- delete_split_bot_mark(i);
- }
- for (c = last_box_code; c <= vsplit_code; c++)
- flush_node_list(disc_ptr[c]);
- if (last_glue != max_halfword) {
- flush_node(last_glue);
- }
- while (pseudo_files != null)
- pseudo_close(); /* flush pseudo files */
- store_fmt_file();
- return;
- }
- tprint_nl("(\\dump is performed only by INITEX)");
- return;
- }
-}
-
-@ Once \TeX\ is working, you should be able to diagnose most errors with
-the \.{\\show} commands and other diagnostic features.
-An additional routine called |debug_help|
-will come into play when you type `\.D' after an error message;
-|debug_help| also occurs just before a fatal error causes \TeX\ to succumb.
-@^debugging@>
-@^system dependencies@>
-
-The interface to |debug_help| is primitive, but it is good enough when used
-with a debugger that allows you to set breakpoints and to read
-variables and change their values. After getting the prompt `\.{debug \#}', you
-type either a negative number (this exits |debug_help|), or zero (this
-goes to a location where you can set a breakpoint, thereby entering into
-dialog with the debugger), or a positive number |m| followed by
-an argument |n|. The meaning of |m| and |n| will be clear from the
-program below. (If |m=13|, there is an additional argument, |l|.)
-@.debug \#@>
-
-@c
-#ifdef DEBUG
-void debug_help(void)
-{ /* routine to display various things */
- int k;
- int m = 0, n = 0, l = 0;
- while (1) {
- wake_up_terminal();
- tprint_nl("debug # (-1 to exit):");
- update_terminal();
- (void) fscanf(term_in, "%d", &m);
- if (m < 0)
- return;
- else if (m == 0)
- abort(); /* go to every label at least once */
- else {
- (void) fscanf(term_in, "%d", &n);
- switch (m) {
- case 1:
- print_word(varmem[n]); /* display |varmem[n]| in all forms */
- break;
- case 2:
- print_int(info(n));
- break;
- case 3:
- print_int(link(n));
- break;
- case 4:
- print_word(eqtb[n]);
- break;
- case 6:
- print_int(save_type(n));
- print_int(save_level(n));
- print_word(save_word(n));
- break;
- case 7:
- show_box(n); /* show a box, abbreviated by |show_box_depth| and |show_box_breadth| */
- break;
- case 8:
- breadth_max = 10000;
- depth_threshold = 0x7FFFFFFF;
- show_node_list(n); /* show a box in its entirety */
- break;
- case 9:
- show_token_list(n, null, 1000);
- break;
- case 10:
- print(n);
- break;
- case 13:
- (void) fscanf(term_in, "%d", &l);
- print_cmd_chr(n, l);
- break;
- case 14:
- for (k = 0; k <= n; k++)
- print(buffer[k]);
- break;
- case 15:
- font_in_short_display = null_font;
- short_display(n);
- break;
- default:
- tprint("?");
- break;
- }
- }
- }
-}
-#endif
diff --git a/Build/source/texk/web2c/luatexdir/tex/maincontrol.w b/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
index 7b4cf9065ca..295e2c6ccae 100644
--- a/Build/source/texk/web2c/luatexdir/tex/maincontrol.w
+++ b/Build/source/texk/web2c/luatexdir/tex/maincontrol.c
@@ -1,80 +1,79 @@
-% maincontrol.w
-%
-% Copyright 2009-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
+/*
+
+maincontrol.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
#include "lua/luatex-api.h"
-@ @c
#define mode mode_par
#define tail tail_par
#define head head_par
#define dir_save dirs_par
-@ We come now to the |main_control| routine, which contains the master
-switch that causes all the various pieces of \TeX\ to do their things,
-in the right order.
-
-In a sense, this is the grand climax of the program: It applies all the
-tools that we have worked so hard to construct. In another sense, this is
-the messiest part of the program: It necessarily refers to other pieces
-of code all over the place, so that a person can't fully understand what is
-going on without paging back and forth to be reminded of conventions that
-are defined elsewhere. We are now at the hub of the web, the central nervous
-system that touches most of the other parts and ties them together.
-@^brain@>
-
-The structure of |main_control| itself is quite simple. There's a label
-called |big_switch|, at which point the next token of input is fetched
-using |get_x_token|. Then the program branches at high speed into one of
-about 100 possible directions, based on the value of the current
-mode and the newly fetched command code; the sum |abs(mode)+cur_cmd|
-indicates what to do next. For example, the case `|vmode+letter|' arises
-when a letter occurs in vertical mode (or internal vertical mode); this
-case leads to instructions that initialize a new paragraph and enter
-horizontal mode.
+/*tex
+
+We come now to the |main_control| routine, which contains the master switch that
+causes all the various pieces of \TeX\ to do their things, in the right order.
+
+In a sense, this is the grand climax of the program: It applies all the tools
+that we have worked so hard to construct. In another sense, this is the messiest
+part of the program: It necessarily refers to other pieces of code all over the
+place, so that a person can't fully understand what is going on without paging
+back and forth to be reminded of conventions that are defined elsewhere. We are
+now at the hub of the web, the central nervous system that touches most of the
+other parts and ties them together. @^brain@>
+
+The structure of |main_control| itself is quite simple. There's a label called
+|big_switch|, at which point the next token of input is fetched using
+|get_x_token|. Then the program branches at high speed into one of about 100
+possible directions, based on the value of the current mode and the newly fetched
+command code; the sum |abs(mode)+cur_cmd| indicates what to do next. For example,
+the case `|vmode+letter|' arises when a letter occurs in vertical mode (or
+internal vertical mode); this case leads to instructions that initialize a new
+paragraph and enter horizontal mode.
The big |case| statement that contains this multiway switch has been labeled
-|reswitch|, so that the program can |goto reswitch| when the next token
-has already been fetched. Most of the cases are quite short; they call
-an ``action procedure'' that does the work for that case, and then they
-either |goto reswitch| or they ``fall through'' to the end of the |case|
-statement, which returns control back to |big_switch|. Thus, |main_control|
-is not an extremely large procedure, in spite of the multiplicity of things
-it must do; it is small enough to be handled by PASCAL compilers that put
-severe restrictions on procedure size.
-@!@^action procedure@>
-
-One case is singled out for special treatment, because it accounts for most
-of \TeX's activities in typical applications. The process of reading simple
-text and converting it into |char_node| records, while looking for ligatures
-and kerns, is part of \TeX's ``inner loop''; the whole program runs
-efficiently when its inner loop is fast, so this part has been written
-with particular care.
-
-We leave the |space_factor| unchanged if |sf_code(cur_chr)=0|; otherwise we
-set it equal to |sf_code(cur_chr)|, except that it should never change
-from a value less than 1000 to a value exceeding 1000. The most common
-case is |sf_code(cur_chr)=1000|, so we want that case to be fast.
-
-@c
+|reswitch|, so that the program can |goto reswitch| when the next token has
+already been fetched. Most of the cases are quite short; they call an ``action
+procedure'' that does the work for that case, and then they either |goto
+reswitch| or they ``fall through'' to the end of the |case| statement, which
+returns control back to |big_switch|. Thus, |main_control| is not an extremely
+large procedure, in spite of the multiplicity of things it must do; it is small
+enough to be handled by PASCAL compilers that put severe restrictions on
+procedure size. @!@^action procedure@>
+
+One case is singled out for special treatment, because it accounts for most of
+\TeX's activities in typical applications. The process of reading simple text and
+converting it into |char_node| records, while looking for ligatures and kerns, is
+part of \TeX's ``inner loop''; the whole program runs efficiently when its inner
+loop is fast, so this part has been written with particular care.
+
+We leave the |space_factor| unchanged if |sf_code(cur_chr)=0|; otherwise we set
+it equal to |sf_code(cur_chr)|, except that it should never change from a value
+less than 1000 to a value exceeding 1000. The most common case is
+|sf_code(cur_chr)=1000|, so we want that case to be fast.
+
+*/
+
void adjust_space_factor(void)
{
halfword s = get_sf_code(cur_chr);
@@ -90,21 +89,21 @@ void adjust_space_factor(void)
}
}
-@ From Knuth: ``Having |font_glue| allocated for each text font saves
-both time and memory.'' That may be true, but it also punches through
-the API wall for fonts, so I removed that -- Taco. But a bit of caching
-is very welcome, which is why I need to have the next two globals:
+/*tex
-@ To handle the execution state of |main_control|'s eternal loop,
-an extra global variable is used, along with a macro to define
-its values.
+To handle the execution state of |main_control|'s eternal loop, an extra global
+variable is used, along with a macro to define its values.
+
+*/
-@c
#define goto_next 0
#define goto_skip_token 1
#define goto_return 2
static int main_control_state;
+static int local_level = 0;
+
+/*tex
@* Main control helpers.
@@ -112,8 +111,8 @@ Here are all the functions that are called from |main_control| that
are not already defined elsewhere. For the moment, this list simply
in the order that the appear in |init_main_control|, below.
-@
-@c
+*/
+
static void run_char_num (void) {
scan_char_num();
cur_chr = cur_val;
@@ -126,23 +125,49 @@ static void run_char (void) {
tail_append(new_char(cur_font_par, cur_chr));
}
-@
-The occurrence of blank spaces is almost part of \TeX's inner loop,
-since we usually encounter about one space for every five non-blank characters.
-Therefore |main_control| gives second-highest priority to ordinary spaces.
+static void run_node (void) {
+ halfword n = cur_chr;
+ if (copy_lua_input_nodes_par) {
+ n = copy_node_list(n);
+ }
+ tail_append(n);
+ while (vlink(n) != null) {
+ n = vlink(n);
+ tail_append(n);
+ }
+}
-When a glue parameter like \.{\\spaceskip} is set to `\.{0pt}', we will
-see to it later that the corresponding glue specification is precisely
-|zero_glue|, not merely a pointer to some specification that happens
-to be full of zeroes. Therefore it is simple to test whether a glue parameter
-is zero or~not.
+static void run_lua_call(void) {
+ if (cur_chr <= 0) {
+ normal_error("luacall", "invalid number");
+ } else {
+ str_number u = save_cur_string();
+ luacstrings = 0;
+ luafunctioncall(cur_chr);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
+}
+
+/*tex
+
+The occurrence of blank spaces is almost part of \TeX's inner loop, since we
+usually encounter about one space for every five non-blank characters. Therefore
+|main_control| gives second-highest priority to ordinary spaces.
+
+When a glue parameter like \.{\\spaceskip} is set to `\.{0pt}', we will see to it
+later that the corresponding glue specification is precisely |zero_glue|, not
+merely a pointer to some specification that happens to be full of zeroes.
+Therefore it is simple to test whether a glue parameter is zero or~not.
+
+*/
-@c
static void run_app_space (void) {
halfword p; /* was a global temp_ptr */
int method = disable_space_par ;
if (method == 1) {
- /* don't inject anything, not even zero skip */
+ /*tex Don't inject anything, not even zero skip. */
} else if (method == 2) {
p = new_glue(zero_glue);
couple_nodes(tail,p);
@@ -150,9 +175,9 @@ static void run_app_space (void) {
} else if ((abs(mode) + cur_cmd == hmode + spacer_cmd) && (!(space_factor_par == 1000))) {
app_space();
} else {
- /* Append a normal inter-word space to the current list */
+ /*tex Append a normal inter-word space to the current list. */
if (glue_is_zero(space_skip_par)) {
- /* Find the glue specification for text spaces in the current font */
+ /*tex Find the glue specification for text spaces in the current font. */
p = new_glue(zero_glue);
width(p) = space(cur_font_par);
stretch(p) = space_stretch(cur_font_par);
@@ -161,20 +186,24 @@ static void run_app_space (void) {
} else {
p = new_param_glue(space_skip_code);
}
- /* so from now we have a subtype with spaces: */
+ /*tex So from now we have a subtype with spaces: */
subtype(p) = space_skip_code + 1 ;
couple_nodes(tail,p);
tail = p;
}
}
-@ Append a |boundary_node|
-@c
+/*tex
+
+Append a |boundary_node|
+
+*/
+
static void run_boundary (void) {
halfword n ;
n = new_node(boundary_node,cur_chr);
if ((cur_chr == 1) || (cur_chr == 2) ) {
- /* user boundary or protrusion boundary */
+ /*tex We expect a user boundary or protrusion boundary. */
scan_int();
boundary_value(n) = cur_val;
}
@@ -182,7 +211,6 @@ static void run_boundary (void) {
tail = n;
}
-@ @c
static void run_char_ghost (void) {
int t;
t = cur_chr;
@@ -199,19 +227,21 @@ static void run_char_ghost (void) {
}
}
-@ @c
static void run_relax (void) {
return;
}
-@ |ignore_spaces| is a special case: after it has acted, |get_x_token| has already
-fetched the next token from the input, so that operation in |main_control|
-should be skipped.
+/*tex
+
+|ignore_spaces| is a special case: after it has acted, |get_x_token| has already
+fetched the next token from the input, so that operation in |main_control| should
+be skipped.
+
+*/
-@c
static void run_ignore_spaces (void) {
if (cur_chr == 0) {
- /* Get the next non-blank non-call... */
+ /*tex Get the next non-blank non-call... */
do {
get_x_token();
} while (cur_cmd == spacer_cmd);
@@ -231,24 +261,33 @@ static void run_ignore_spaces (void) {
}
}
-@ |stop| is the second special case. We want |main_control| to return to its caller
+/*tex
+
+|stop| is the second special case. We want |main_control| to return to its caller
if there is nothing left to do.
-@c
+*/
+
static void run_stop (void) {
- if (its_all_over())
- main_control_state= goto_return; /* this is the only way out */
+ if (its_all_over()) {
+ /*tex this is the only way out */
+ main_control_state= goto_return;
+ }
}
-@ @c
static void run_non_math_math (void) {
back_input();
new_graf(true);
}
-@ @c
+/*tex
+
+ We build up an argument to |set_math_char|:
+
+*/
+
static void run_math_char_num (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
if (cur_chr == 0)
mval = scan_mathchar(tex_mathcode);
else if (cur_chr == 1)
@@ -258,35 +297,47 @@ static void run_math_char_num (void) {
math_char_in_text(mval);
}
-@ @c
+/*tex
+
+ We build up an argument to |set_math_char|:
+*/
+
static void run_math_given (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
mval = mathchar_from_integer(cur_chr, tex_mathcode);
math_char_in_text(mval);
}
+/*tex
+
+ We build up an argument to |set_math_char| the \LUATEX\ way:
+*/
+
static void run_xmath_given (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
mval = mathchar_from_integer(cur_chr, umath_mathcode);
math_char_in_text(mval);
}
-@ The most important parts of |main_control| are concerned with \TeX's
-chief mission of box-making. We need to control the activities that put
-entries on vlists and hlists, as well as the activities that convert
-those lists into boxes. All of the necessary machinery has already been
-developed; it remains for us to ``push the buttons'' at the right times.
+/*tex
-As an introduction to these routines, let's consider one of the simplest
-cases: What happens when `\.{\\hrule}' occurs in vertical mode, or
-`\.{\\vrule}' in horizontal mode or math mode? The code in |main_control|
-is short, since the |scan_rule_spec| routine already does most of what is
-required; thus, there is no need for a special action procedure.
+The most important parts of |main_control| are concerned with \TeX's chief
+mission of box-making. We need to control the activities that put entries on
+vlists and hlists, as well as the activities that convert those lists into boxes.
+All of the necessary machinery has already been developed; it remains for us to
+``push the buttons'' at the right times.
-Note that baselineskip calculations are disabled after a rule in vertical
-mode, by setting |prev_depth:=ignore_depth|.
+As an introduction to these routines, let's consider one of the simplest cases:
+What happens when `\.{\\hrule}' occurs in vertical mode, or `\.{\\vrule}' in
+horizontal mode or math mode? The code in |main_control| is short, since the
+|scan_rule_spec| routine already does most of what is required; thus, there is no
+need for a special action procedure.
+
+Note that baselineskip calculations are disabled after a rule in vertical mode,
+by setting |prev_depth:=ignore_depth|.
+
+*/
-@c
static void run_rule (void) {
tail_append(scan_rule_spec());
if (abs(mode) == vmode)
@@ -295,29 +346,30 @@ static void run_rule (void) {
space_factor_par = 1000;
}
-@
-Many of the actions related to box-making are triggered by the appearance
-of braces in the input. For example, when the user says `\.{\\hbox}
-\.{to} \.{100pt\{$\langle\,\hbox{hlist}\,\rangle$\}}' in vertical mode,
-the information about the box size (100pt, |exactly|) is put onto |save_stack|
-with a level boundary word just above it, and |cur_group:=adjusted_hbox_group|;
-\TeX\ enters restricted horizontal mode to process the hlist. The right
-brace eventually causes |save_stack| to be restored to its former state,
-at which time the information about the box size (100pt, |exactly|) is
-available once again; a box is packaged and we leave restricted horizontal
-mode, appending the new box to the current list of the enclosing mode
-(in this case to the current list of vertical mode), followed by any
-vertical adjustments that were removed from the box by |hpack|.
-
-The next few sections of the program are therefore concerned with the
-treatment of left and right curly braces.
-
-If a left brace occurs in the middle of a page or paragraph, it simply
-introduces a new level of grouping, and the matching right brace will not have
-such a drastic effect. Such grouping affects neither the mode nor the
-current list.
-
-@c
+/*tex
+
+Many of the actions related to box-making are triggered by the appearance of
+braces in the input. For example, when the user says `\.{\\hbox} \.{to}
+\.{100pt\{$\langle\,\hbox{hlist}\,\rangle$\}}' in vertical mode, the information
+about the box size (100pt, |exactly|) is put onto |save_stack| with a level
+boundary word just above it, and |cur_group:=adjusted_hbox_group|; \TeX\ enters
+restricted horizontal mode to process the hlist. The right brace eventually
+causes |save_stack| to be restored to its former state, at which time the
+information about the box size (100pt, |exactly|) is available once again; a box
+is packaged and we leave restricted horizontal mode, appending the new box to the
+current list of the enclosing mode (in this case to the current list of vertical
+mode), followed by any vertical adjustments that were removed from the box by
+|hpack|.
+
+The next few sections of the program are therefore concerned with the treatment
+of left and right curly braces.
+
+If a left brace occurs in the middle of a page or paragraph, it simply introduces
+a new level of grouping, and the matching right brace will not have such a
+drastic effect. Such grouping affects neither the mode nor the current list.
+
+*/
+
static void run_left_brace (void) {
new_save_level(simple_group);
eq_word_define(int_base + no_local_whatsits_code, 0);
@@ -338,11 +390,14 @@ static void run_end_group (void) {
}
}
-@ Constructions that require a box are started by calling |scan_box| with
-a specified context code. The |scan_box| routine verifies
-that a |make_box| command comes next and then it calls |begin_box|.
+/*tex
+
+Constructions that require a box are started by calling |scan_box| with a
+specified context code. The |scan_box| routine verifies that a |make_box| command
+comes next and then it calls |begin_box|.
+
+*/
-@c
static void run_move (void) {
int t = cur_chr;
scan_normal_dimen();
@@ -352,17 +407,14 @@ static void run_move (void) {
scan_box(-cur_val);
}
-@ @c
static void run_leader_ship (void) {
scan_box(leader_flag - a_leaders + cur_chr);
}
-@ @c
static void run_make_box (void) {
begin_box(0);
}
-@ @c
static void run_box_dir (void) {
scan_register_num();
cur_box = box(cur_val);
@@ -372,37 +424,51 @@ static void run_box_dir (void) {
box_dir(cur_box) = cur_val;
}
-@ There is a really small patch to add a new primitive called
-\.{\\quitvmode}. In vertical modes, it is identical to \.{\\indent},
-but in horizontal and math modes it is really a no-op (as opposed to
-\.{\\indent}, which executes the |indent_in_hmode| procedure).
+static void run_box_direction (void) {
+ scan_register_num();
+ cur_box = box(cur_val);
+ scan_optional_equals();
+ scan_int();
+ check_dir_value(cur_val);
+ if (cur_box != null)
+ box_dir(cur_box) = cur_val;
+}
+
+/*tex
+
+There is a really small patch to add a new primitive called \.{\\quitvmode}. In
+vertical modes, it is identical to \.{\\indent}, but in horizontal and math modes
+it is really a no-op (as opposed to \.{\\indent}, which executes the
+|indent_in_hmode| procedure).
-A paragraph begins when horizontal-mode material occurs in vertical mode,
-or when the paragraph is explicitly started by `\.{\\quitvmode}',
-`\.{\\indent}' or `\.{\\noindent}'.
+A paragraph begins when horizontal-mode material occurs in vertical mode, or when
+the paragraph is explicitly started by `\.{\\quitvmode}', `\.{\\indent}' or
+`\.{\\noindent}'.
+
+*/
-@c
static void run_start_par_vmode (void) {
new_graf((cur_chr > 0));
}
-@ @c
static void run_start_par (void) {
if (cur_chr != 2)
indent_in_hmode();
}
-@ @c
static void run_new_graf (void) {
back_input();
new_graf(true);
}
-@ A paragraph ends when a |par_end| command is sensed, or when we are in
-horizontal mode when reaching the right brace of vertical-mode routines
-like \.{\\vbox}, \.{\\insert}, or \.{\\output}.
+/*tex
+
+A paragraph ends when a |par_end| command is sensed, or when we are in horizontal
+mode when reaching the right brace of vertical-mode routines like \.{\\vbox},
+\.{\\insert}, or \.{\\output}.
+
+*/
-@c
static void run_par_end_vmode (void) {
normal_paragraph();
if (mode > 0) {
@@ -411,28 +477,27 @@ static void run_par_end_vmode (void) {
}
}
-@ @c
static void run_par_end_hmode (void) {
- if (align_state < 0)
- off_save(); /* this tries to recover from an alignment that didn't end properly */
- end_graf(bottom_level); /* this takes us to the enclosing mode, if |mode>0| */
+ if (align_state < 0) {
+ /*tex This tries to recover from an alignment that didn't end properly. */
+ off_save();
+ }
+ /* This takes us to the enclosing mode, if |mode>0|. */
+ end_graf(bottom_level);
if (mode == vmode) {
checked_page_filter(hmode_par);
build_page();
}
}
-@ @c
static void append_italic_correction_mmode (void) {
- tail_append(new_kern(0)); /* what subtype to use */
+ tail_append(new_kern(0));
}
-@ @c
static void run_local_box (void) {
append_local_box(cur_chr);
}
-@ @c
static void run_halign_mmode (void) {
if (privileged()) {
if (cur_group == math_shift_group)
@@ -442,7 +507,6 @@ static void run_halign_mmode (void) {
}
}
-@ @c
static void run_eq_no (void) {
if (privileged()) {
if (cur_group == math_shift_group)
@@ -452,21 +516,18 @@ static void run_eq_no (void) {
}
}
-@ @c
static void run_letter_mmode (void) {
set_math_char(get_math_code(cur_chr));
}
-@ @c
static void run_char_num_mmode (void) {
scan_char_num();
cur_chr = cur_val;
set_math_char(get_math_code(cur_chr));
}
-@ @c
static void run_math_char_num_mmode (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
if (cur_chr == 0)
mval = scan_mathchar(tex_mathcode);
else if (cur_chr == 1)
@@ -476,31 +537,27 @@ static void run_math_char_num_mmode (void) {
set_math_char(mval);
}
-@ @c
static void run_math_given_mmode (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
mval = mathchar_from_integer(cur_chr, tex_mathcode);
set_math_char(mval);
}
static void run_xmath_given_mmode (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
mval = mathchar_from_integer(cur_chr, umath_mathcode);
set_math_char(mval);
}
-@ @c
static void run_delim_num (void) {
- mathcodeval mval; /* to build up an argument to |set_math_char| */
+ mathcodeval mval;
if (cur_chr == 0)
mval = scan_delimiter_as_mathchar(tex_mathcode);
else
mval = scan_delimiter_as_mathchar(umath_mathcode);
set_math_char(mval);
-
}
-@ @c
static void run_vcenter (void) {
scan_spec(vcenter_group);
normal_paragraph();
@@ -511,18 +568,15 @@ static void run_vcenter (void) {
begin_token_list(every_vbox_par, every_vbox_text);
}
-@ @c
static void run_math_style (void) {
tail_append(new_style((small_number) cur_chr));
}
-@ @c
static void run_non_script (void) {
tail_append(new_glue(zero_glue));
subtype(tail) = cond_math_glue;
}
-@ @c
static void run_math_choice (void) {
if (cur_chr == 0)
append_choices();
@@ -530,7 +584,6 @@ static void run_math_choice (void) {
setup_math_style();
}
-@ @c
static void run_math_shift (void) {
if (cur_group == math_shift_group)
after_math();
@@ -538,19 +591,16 @@ static void run_math_shift (void) {
off_save();
}
-@ @c
static void run_after_assignment (void) {
get_token();
after_token = cur_tok;
}
-@ @c
static void run_after_group (void) {
get_token();
save_for_after(cur_tok);
}
-@ @c
static void run_extension (void) {
do_extension(0);
}
@@ -565,12 +615,16 @@ static void run_normal (void) {
scan_int();
if ((cur_val < 0) || (cur_val > 0x7FFF)) {
print_err("Invalid \\catcode table");
- help1("All \\catcode table ids must be between 0 and 0x7FFF");
+ help1(
+ "All \\catcode table ids must be between 0 and 0x7FFF"
+ );
error();
} else {
if (cur_val == cat_code_table_par) {
print_err("Invalid \\catcode table");
- help1("You cannot overwrite the current \\catcode table");
+ help1(
+ "You cannot overwrite the current \\catcode table"
+ );
error();
} else {
copy_cat_codes(cat_code_table_par, cur_val);
@@ -581,12 +635,16 @@ static void run_normal (void) {
scan_int();
if ((cur_val < 0) || (cur_val > 0x7FFF)) {
print_err("Invalid \\catcode table");
- help1("All \\catcode table ids must be between 0 and 0x7FFF");
+ help1(
+ "All \\catcode table ids must be between 0 and 0x7FFF"
+ );
error();
} else {
if (cur_val == cat_code_table_par) {
print_err("Invalid \\catcode table");
- help1("You cannot overwrite the current \\catcode table");
+ help1(
+ "You cannot overwrite the current \\catcode table"
+ );
error();
} else {
initex_cat_codes(cur_val);
@@ -607,6 +665,12 @@ static void run_normal (void) {
(void) scan_toks(false, false);
late_lua_data(tail) = def_ref;
break;
+ case late_lua_call_code:
+ new_whatsit(late_lua_node);
+ late_lua_type(tail) = lua_refid_call;
+ scan_int();
+ late_lua_data(tail) = cur_val;
+ break;
case expand_font_code:
read_expand_font();
break;
@@ -617,9 +681,10 @@ static void run_normal (void) {
}
}
-/*
- this is experimental and not used for production, only for testing and writing
- macros (some options stay)
+/*tex
+
+This is experimental and not used for production, only for testing and writing
+macros (some options stay).
*/
@@ -633,14 +698,10 @@ static void run_option(void) {
case math_option_code:
if (scan_keyword("old")) {
mathoption_set_int(c_mathoption_old_code);
- } else if (scan_keyword("noitaliccompensation")) {
- mathoption_set_int(c_mathoption_no_italic_compensation_code);
- } else if (scan_keyword("nocharitalic")) {
- mathoption_set_int(c_mathoption_no_char_italic_code);
- } else if (scan_keyword("useoldfractionscaling")) {
- mathoption_set_int(c_mathoption_use_old_fraction_scaling_code);
+ /*
} else if (scan_keyword("umathcodemeaning")) {
mathoption_set_int(c_mathoption_umathcode_meaning_code);
+ */
} else {
normal_warning("mathoption","unknown key");
}
@@ -651,20 +712,55 @@ static void run_option(void) {
}
}
-@ For mode-independent commands, the following macro is useful.
+static void lua_function_call(void) {
+ scan_int();
+ if (cur_val <= 0) {
+ normal_error("luafunctioncall", "invalid number");
+ } else {
+ str_number u = save_cur_string();
+ luacstrings = 0;
+ luafunctioncall(cur_val);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
+}
+
+static void lua_bytecode_call(void) {
+ scan_int();
+ if (cur_val < 0 || cur_val > 65535) {
+ normal_error("luabytecodecall", "invalid number");
+ } else {
+ str_number u = save_cur_string();
+ luacstrings = 0;
+ luabytecodecall(cur_val);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
+}
+
+/*tex
+
+For mode-independent commands, the following macro is useful.
-Also, there is a list of cases where the user has probably gotten into or out of math
-mode by mistake. \TeX\ will insert a dollar sign and rescan the current token, and
-it makes sense ot have a macro for that as well.
+Also, there is a list of cases where the user has probably gotten into or out of
+math mode by mistake. \TeX\ will insert a dollar sign and rescan the current
+token, and it makes sense ot have a macro for that as well.
+
+*/
-@c
#define any_mode(A,B) jump_table[vmode+(A)]=B; jump_table[hmode+(A)]=B; jump_table[mmode+(A)]=B
#define non_math(A,B) jump_table[vmode+(A)]=B; jump_table[hmode+(A)]=B;
+/*tex
+
+The |main_control| uses a jump table, and |init_main_control| sets that table up.
+
+*/
-@ The |main_control| uses a jump table, and |init_main_control| sets that table up.
-@c
typedef void (*main_control_function) (void);
+
main_control_function *jump_table;
static void init_main_control (void) {
@@ -749,6 +845,7 @@ static void init_main_control (void) {
any_mode(leader_ship_cmd, run_leader_ship);
any_mode(make_box_cmd, run_make_box);
any_mode(assign_box_dir_cmd, run_box_dir);
+ any_mode(assign_box_direction_cmd, run_box_direction);
jump_table[vmode + start_par_cmd] = run_start_par_vmode;
jump_table[hmode + start_par_cmd] = run_start_par;
jump_table[mmode + start_par_cmd] = run_start_par;
@@ -835,6 +932,7 @@ static void init_main_control (void) {
any_mode(assign_int_cmd, prefixed_command);
any_mode(assign_attr_cmd, prefixed_command);
any_mode(assign_dir_cmd, prefixed_command);
+ any_mode(assign_direction_cmd, prefixed_command);
any_mode(assign_dimen_cmd, prefixed_command);
any_mode(assign_glue_cmd, prefixed_command);
any_mode(assign_mu_glue_cmd, prefixed_command);
@@ -879,46 +977,181 @@ static void init_main_control (void) {
any_mode(normal_cmd, run_normal);
any_mode(extension_cmd, run_extension);
any_mode(option_cmd, run_option);
+
+ any_mode(lua_function_call_cmd, lua_function_call);
+ any_mode(lua_bytecode_call_cmd, lua_bytecode_call);
+ any_mode(def_lua_call_cmd, prefixed_command);
+ any_mode(lua_call_cmd, run_lua_call);
+ /* any_mode(lua_expandable_call_cmd, run_lua_call); */ /* no! outside jump table anyway, handled in expand() */
+ any_mode(node_cmd, run_node);
+
}
-@ And here is |main_control| itself. It is quite short nowadays.
+/*tex
+
+ And here is |main_control| itself. It is quite short nowadays.
+
+*/
-@c
void main_control(void)
{
main_control_state = goto_next;
- init_main_control () ;
-
- if (equiv(every_job_loc) != null)
+ init_main_control() ;
+ if (equiv(every_job_loc) != null) {
begin_token_list(equiv(every_job_loc), every_job_text);
-
+ }
while (1) {
- if (main_control_state == goto_skip_token)
- main_control_state = goto_next; /* reset */
- else
+ if (main_control_state == goto_skip_token) {
+ main_control_state = goto_next;
+ } else {
get_x_token();
-
- /* Give diagnostic information, if requested */
- /* When a new token has just been fetched at |big_switch|, we have an
- ideal place to monitor \TeX's activity. */
+ }
+ /*tex
+ Give diagnostic information, if requested When a new token has just
+ been fetched at |big_switch|, we have an ideal place to monitor
+ \TeX's activity.
+ */
if (interrupt != 0 && OK_to_interrupt) {
back_input();
check_interrupt();
continue;
}
- if (tracing_commands_par > 0)
+ if (tracing_commands_par > 0) {
show_cur_cmd_chr();
+ }
+ /*tex run the command */
+ (jump_table[(abs(mode) + cur_cmd)])();
+ if (main_control_state == goto_return) {
+ return;
+ }
+ }
+ /*tex not reached */
+ return;
+}
- (jump_table[(abs(mode) + cur_cmd)])(); /* run the command */
+/*tex
- if (main_control_state == goto_return) {
+We assume a trailing relax: |{...}\relax|, so we don't need a |back_input()| here.
+
+*/
+
+/*int local_level = 0; */
+
+extern void local_control_message(const char *s)
+{
+ tprint("local control level ");
+ print_int(local_level);
+ tprint(": ");
+ tprint(s);
+ tprint_nl("");
+}
+
+void local_control(void)
+{
+ int ll = local_level;
+ main_control_state = goto_next;
+ local_level += 1;
+ while (1) {
+ if (main_control_state == goto_skip_token) {
+ main_control_state = goto_next;
+ } else {
+ get_x_token();
+ }
+ if (interrupt != 0 && OK_to_interrupt) {
+ back_input();
+ check_interrupt();
+ continue;
+ }
+ if (tracing_commands_par > 0) {
+ show_cur_cmd_chr();
+ }
+ (jump_table[(abs(mode) + cur_cmd)])();
+ if (local_level <= ll) {
+ main_control_state = goto_next;
+ if (tracing_nesting_par > 2) {
+ local_control_message("leaving due to level change");
+ }
+ return ;
+ } else if (main_control_state == goto_return) {
+ if (tracing_nesting_par > 2) {
+ local_control_message("leaving due to triggering");
+ }
return;
}
}
- return; /* not reached */
+ return;
+}
+
+void end_local_control(void )
+{
+ local_level -= 1;
+}
+
+/*tex
+ We need to go back to the main loop. This is rather nasty and dirty
+ and counterintuive code and there might be a cleaner way. Basically
+ we trigger the main control state from here.
+
+ \starttyping
+ 0 0 \directlua{token.scan_list()}\hbox{!}
+ -1 0 \setbox0\hbox{x}\directlua{token.scan_list()}\box0
+ 1 1 \toks0={\directlua{token.scan_list()}\hbox{x}}\directlua{tex.runtoks(0)}
+ 0 0 1 1 \directlua{tex.box[0]=token.scan_list()}\hbox{x\directlua{node.write(token.scan_list())}\hbox{x}}
+ 0 0 0 1 \setbox0\hbox{x}\directlua{tex.box[0]=token.scan_list()}\hbox{x\directlua{node.write(token.scan_list())}\box0}
+ \stoptyping
+
+ It's rather fragile code so we added some tracing options.
+
+*/
+
+halfword local_scan_box(void)
+{
+ int old_mode = mode;
+ int ll = local_level;
+ mode = -hmode;
+ scan_box(lua_scan_flag);
+ if (local_level == ll) {
+ /*tex |\directlua{print(token.scan_list())}\hbox{!}| (n n) */
+ if (tracing_nesting_par > 2) {
+ local_control_message("entering at end of box scanning");
+ }
+ local_control();
+ } else {
+ /*tex |\directlua{print(token.scan_list())}\box0| (n-1 n) */
+ /*
+ if (tracing_nesting_par > 2) {
+ local_control_message("setting level after box scanning");
+ }
+ */
+ local_level = ll;
+ }
+ mode = old_mode;
+ return cur_box;
+}
+
+/*tex
+
+ We have an issue with modes when we quit here because we're coming
+ from and still staying at the \LUA\ end. So, unless we're already
+ nested, we trigger an end_local_level token (an extension code).
+
+*/
+
+static void wrapup_local_scan_box(void)
+{
+ /*
+ if (tracing_nesting_par > 2) {
+ local_control_message("leaving box scanner");
+ }
+ */
+ local_level -= 1;
+}
+
+int current_local_level(void)
+{
+ return local_level;
}
-@ @c
void app_space(void)
{ /* handle spaces when |space_factor<>1000| */
halfword q; /* glue node */
@@ -948,20 +1181,24 @@ void app_space(void)
tail = q;
}
-@ @c
void insert_dollar_sign(void)
{
back_input();
cur_tok = math_shift_token + '$';
print_err("Missing $ inserted");
- help2("I've inserted a begin-math/end-math symbol since I think",
- "you left one out. Proceed, with fingers crossed.");
+ help2(
+ "I've inserted a begin-math/end-math symbol since I think",
+ "you left one out. Proceed, with fingers crossed."
+ );
ins_error();
}
-@ We can silently ignore \.{\\par}s in a math formula.
+/*tex
+
+ We can silently ignore \.{\\par}s in a math formula.
+
+*/
-@c
void insert_dollar_sign_par_end(void)
{
if (!suppress_mathpar_error_par) {
@@ -969,10 +1206,13 @@ void insert_dollar_sign_par_end(void)
}
}
-@ The `|you_cant|' procedure prints a line saying that the current command
-is illegal in the current mode; it identifies these things symbolically.
+/*tex
+
+The `|you_cant|' procedure prints a line saying that the current command is
+illegal in the current mode; it identifies these things symbolically.
+
+*/
-@c
void you_cant(void)
{
print_err("You can't use `");
@@ -980,34 +1220,40 @@ void you_cant(void)
print_in_mode(mode);
}
-@
-When erroneous situations arise, \TeX\ usually issues an error message
-specific to the particular error. For example, `\.{\\noalign}' should
-not appear in any mode, since it is recognized by the |align_peek| routine
-in all of its legitimate appearances; a special error message is given
-when `\.{\\noalign}' occurs elsewhere. But sometimes the most appropriate
-error message is simply that the user is not allowed to do what he or she
-has attempted. For example, `\.{\\moveleft}' is allowed only in vertical mode,
-and `\.{\\lower}' only in non-vertical modes. Such cases are enumerated
-here and in the other sections referred to under `See also \dots.'
+/*tex
+
+When erroneous situations arise, \TeX\ usually issues an error message specific
+to the particular error. For example, `\.{\\noalign}' should not appear in any
+mode, since it is recognized by the |align_peek| routine in all of its legitimate
+appearances; a special error message is given when `\.{\\noalign}' occurs
+elsewhere. But sometimes the most appropriate error message is simply that the
+user is not allowed to do what he or she has attempted. For example,
+`\.{\\moveleft}' is allowed only in vertical mode, and `\.{\\lower}' only in
+non-vertical modes. Such cases are enumerated here and in the other sections
+referred to under `See also \dots.'
+
+*/
-@c
void report_illegal_case(void)
{
you_cant();
- help4("Sorry, but I'm not programmed to handle this case;",
- "I'll just pretend that you didn''t ask for it.",
- "If you're in the wrong mode, you might be able to",
- "return to the right one by typing `I}' or `I$' or `I\\par'.");
+ help4(
+ "Sorry, but I'm not programmed to handle this case;",
+ "I'll just pretend that you didn''t ask for it.",
+ "If you're in the wrong mode, you might be able to",
+ "return to the right one by typing `I}' or `I$' or `I\\par'."
+ );
error();
}
-@ Some operations are allowed only in privileged modes, i.e., in cases
-that |mode>0|. The |privileged| function is used to detect violations
-of this rule; it issues an error message and returns |false| if the
-current |mode| is negative.
+/*tex
+
+Some operations are allowed only in privileged modes, i.e., in cases that
+|mode>0|. The |privileged| function is used to detect violations of this rule; it
+issues an error message and returns |false| if the current |mode| is negative.
+
+*/
-@c
boolean privileged(void)
{
if (mode > 0) {
@@ -1018,15 +1264,18 @@ boolean privileged(void)
}
}
-@ We don't want to leave |main_control| immediately when a |stop| command
-is sensed, because it may be necessary to invoke an \.{\\output} routine
-several times before things really grind to a halt. (The output routine
-might even say `\.{\\gdef\\end\{...\}}', to prolong the life of the job.)
-Therefore |its_all_over| is |true| only when the current page
-and contribution list are empty, and when the last output was not a
-``dead cycle.''
+/*tex
+
+We don't want to leave |main_control| immediately when a |stop| command is
+sensed, because it may be necessary to invoke an \.{\\output} routine several
+times before things really grind to a halt. (The output routine might even say
+`\.{\\gdef\\end\{...\}}', to prolong the life of the job.) Therefore
+|its_all_over| is |true| only when the current page and contribution list are
+empty, and when the last output was not a ``dead cycle.''
+
+*/
+
-@c
boolean its_all_over(void)
{ /* do this when \.{\\end} or \.{\\dump} occurs */
if (privileged()) {
@@ -1044,16 +1293,18 @@ boolean its_all_over(void)
return false;
}
+/*tex
+
+The |hskip| and |vskip| command codes are used for control sequences like
+\.{\\hss} and \.{\\vfil} as well as for \.{\\hskip} and \.{\\vskip}. The
+difference is in the value of |cur_chr|.
-@ The |hskip| and |vskip| command codes are used for control sequences
-like \.{\\hss} and \.{\\vfil} as well as for \.{\\hskip} and \.{\\vskip}.
-The difference is in the value of |cur_chr|.
+All the work relating to glue creation has been relegated to the following
+subroutine. It does not call |build_page|, because it is used in at least one
+place where that would be a mistake.
-All the work relating to glue creation has been relegated to the
-following subroutine. It does not call |build_page|, because it is
-used in at least one place where that would be a mistake.
+*/
-@c
void append_glue(void)
{
int s = cur_chr;
@@ -1085,35 +1336,37 @@ void append_glue(void)
}
}
-@ @c
void append_kern(void)
{
- int s; /* |subtype| of the kern node */
- s = cur_chr;
+ int s = cur_chr; /* |subtype| of the kern node */
scan_dimen((s == mu_glue), false, false);
tail_append(new_kern(cur_val));
subtype(tail) = (quarterword) s;
}
-@ We have to deal with errors in which braces and such things are not
-properly nested. Sometimes the user makes an error of commission by
-inserting an extra symbol, but sometimes the user makes an error of omission.
-\TeX\ can't always tell one from the other, so it makes a guess and tries
-to avoid getting into a loop.
+/*tex
+
+We have to deal with errors in which braces and such things are not properly
+nested. Sometimes the user makes an error of commission by inserting an extra
+symbol, but sometimes the user makes an error of omission. \TeX\ can't always
+tell one from the other, so it makes a guess and tries to avoid getting into a
+loop.
The |off_save| routine is called when the current group code is wrong. It tries
-to insert something into the user's input that will help clean off
-the top level.
+to insert something into the user's input that will help clean off the top level.
+
+*/
-@c
void off_save(void)
{
- halfword p, q; /* inserted token */
+ halfword p, q;
if (cur_group == bottom_level) {
- /* Drop current token and complain that it was unmatched */
+ /*tex Drop current token and complain that it was unmatched */
print_err("Extra ");
print_cmd_chr((quarterword) cur_cmd, cur_chr);
- help1("Things are pretty mixed up, but I think the worst is over.");
+ help1(
+ "Things are pretty mixed up, but I think the worst is over."
+ );
error();
} else {
@@ -1121,8 +1374,11 @@ void off_save(void)
p = get_avail();
set_token_link(temp_token_head, p);
print_err("Missing ");
- /* Prepare to insert a token that matches |cur_group|, and print what it is */
- /* At this point, |link(temp_token_head)=p|, a pointer to an empty one-word node. */
+ /*tex
+ Prepare to insert a token that matches |cur_group|, and print what it
+ is. At this point, |link(temp_token_head)=p|, a pointer to an empty
+ one-word node.
+ */
switch (cur_group) {
case semi_simple_group:
set_token_info(p, cs_token_flag + frozen_end_group);
@@ -1147,23 +1403,27 @@ void off_save(void)
}
tprint(" inserted");
ins_list(token_link(temp_token_head));
- help5("I've inserted something that you may have forgotten.",
- "(See the <inserted text> above.)",
- "With luck, this will get me unwedged. But if you",
- "really didn't forget anything, try typing `2' now; then",
- "my insertion and my current dilemma will both disappear.");
+ help5(
+ "I've inserted something that you may have forgotten.",
+ "(See the <inserted text> above.)",
+ "With luck, this will get me unwedged. But if you",
+ "really didn't forget anything, try typing `2' now; then",
+ "my insertion and my current dilemma will both disappear."
+ );
error();
}
}
+/*tex
+
+The routine for a |right_brace| character branches into many subcases, since a
+variety of things may happen, depending on |cur_group|. Some types of groups are
+not supposed to be ended by a right brace; error messages are given in hopes of
+pinpointing the problem. Most branches of this routine will be filled in later,
+when we are ready to understand them; meanwhile, we must prepare ourselves to
+deal with such errors.
-@ The routine for a |right_brace| character branches into many subcases,
-since a variety of things may happen, depending on |cur_group|. Some
-types of groups are not supposed to be ended by a right brace; error
-messages are given in hopes of pinpointing the problem. Most branches
-of this routine will be filled in later, when we are ready to understand
-them; meanwhile, we must prepare ourselves to deal with such errors.
+*/
-@c
void handle_right_brace(void)
{
halfword p, q; /* for short-term use */
@@ -1176,8 +1436,10 @@ void handle_right_brace(void)
break;
case bottom_level:
print_err("Too many }'s");
- help2("You've closed more groups than you opened.",
- "Such booboos are generally harmless, so keep going.");
+ help2(
+ "You've closed more groups than you opened.",
+ "Such booboos are generally harmless, so keep going."
+ );
error();
break;
case semi_simple_group:
@@ -1185,10 +1447,20 @@ void handle_right_brace(void)
case math_left_group:
extra_right_brace();
break;
+ /*tex
+ When the right brace occurs at the end of an \.{\\hbox} or
+ \.{\\vbox} or \.{\\vtop} construction, the |package| routine
+ comes into action. We might also have to finish a paragraph that
+ hasn't ended.
+ */
case hbox_group:
- /* When the right brace occurs at the end of an \.{\\hbox} or \.{\\vbox} or
- \.{\\vtop} construction, the |package| routine comes into action. We might
- also have to finish a paragraph that hasn't ended. */
+ if (fixup_boxes_par) {
+ /*tex
+ This is unofficial! Fixing up (also elsewhere) might become default
+ some day but for a while I will test this in ConTeXt.
+ */
+ fixup_directions_only();
+ }
package(0);
break;
case adjusted_hbox_group:
@@ -1211,7 +1483,9 @@ void handle_right_brace(void)
f = floating_penalty_par;
unsave();
save_ptr--;
- /* now |saved_value(0)| is the insertion number, or the |vadjust| subtype */
+ /*tex
+ Now |saved_value(0)| is the insertion number, or the |vadjust| subtype.
+ */
p = vpack(vlink(head), 0, additional, -1);
pop_nest();
if (saved_type(0) == saved_insert) {
@@ -1236,9 +1510,11 @@ void handle_right_brace(void)
}
break;
case output_group:
- /* this is needed in case the \.{\\output} executes a \.{\\textdir} command. */
+ /*tex
+ this is needed in case the \.{\\output} executes a \.{\\textdir} command.
+ */
if (dir_level(text_dir_ptr) == cur_level) {
- /* DIR: Remove from |text_dir_ptr| */
+ /*tex Remove from |text_dir_ptr| */
halfword text_dir_tmp = vlink(text_dir_ptr);
flush_node(text_dir_ptr);
text_dir_ptr = text_dir_tmp;
@@ -1255,7 +1531,9 @@ void handle_right_brace(void)
back_input();
cur_tok = cs_token_flag + frozen_cr;
print_err("Missing \\cr inserted");
- help1("I'm guessing that you meant to end an alignment here.");
+ help1(
+ "I'm guessing that you meant to end an alignment here."
+ );
ins_error();
break;
case no_align_group:
@@ -1279,7 +1557,6 @@ void handle_right_brace(void)
}
}
-@ @c
void extra_right_brace(void)
{
print_err("Extra }, or forgotten ");
@@ -1294,19 +1571,24 @@ void extra_right_brace(void)
tprint_esc("right");
break;
}
- help5("I've deleted a group-closing symbol because it seems to be",
- "spurious, as in `$x}$'. But perhaps the } is legitimate and",
- "you forgot something else, as in `\\hbox{$x}'. In such cases",
- "the way to recover is to insert both the forgotten and the",
- "deleted material, e.g., by typing `I$}'.");
+ help5(
+ "I've deleted a group-closing symbol because it seems to be",
+ "spurious, as in `$x}$'. But perhaps the } is legitimate and",
+ "you forgot something else, as in `\\hbox{$x}'. In such cases",
+ "the way to recover is to insert both the forgotten and the",
+ "deleted material, e.g., by typing `I$}'."
+ );
error();
incr(align_state);
}
-@ Here is where we clear the parameters that are supposed to revert to their
+/*tex
+
+Here is where we clear the parameters that are supposed to revert to their
default values after every paragraph and when internal vertical mode is entered.
-@c
+*/
+
void normal_paragraph(void)
{
if (looseness_par != 0)
@@ -1323,27 +1605,35 @@ void normal_paragraph(void)
eq_word_define(dimen_base + shape_mode_code, 0);
}
-@ The global variable |cur_box| will point to a newly-made box. If the box
-is void, we will have |cur_box=null|. Otherwise we will have
-|type(cur_box)=hlist_node| or |vlist_node| or |rule_node|; the |rule_node|
-case can occur only with leaders.
+/*tex
+
+The global variable |cur_box| will point to a newly-made box. If the box is void,
+we will have |cur_box=null|. Otherwise we will have |type(cur_box)=hlist_node| or
+|vlist_node| or |rule_node|; the |rule_node| case can occur only with leaders.
+
+*/
-@c
halfword cur_box; /* box to be placed into its context */
-@ The |box_end| procedure does the right thing with |cur_box|, if
-|box_context| represents the context as explained above.
+/*tex
+
+The |box_end| procedure does the right thing with |cur_box|, if |box_context|
+represents the context as explained above.
+
+*/
-@c
void box_end(int box_context)
{
if (box_context < box_flag) {
- /* Append box |cur_box| to the current list, shifted by |box_context| */
- /*
- The global variable |adjust_tail| will be non-null if and only if the
- current box might include adjustments that should be appended to the
- current vertical list.
- */
+ /*tex
+
+ Append box |cur_box| to the current list, shifted by |box_context|.
+ The global variable |adjust_tail| will be non-null if and only if the
+ current box might include adjustments that should be appended to the
+ current vertical list.
+
+ */
+
if (cur_box != null) {
shift_amount(cur_box) = box_context;
if (abs(mode) == vmode) {
@@ -1372,15 +1662,28 @@ void box_end(int box_context)
}
}
} else if (box_context < ship_out_flag) {
- /* Store |cur_box| in a box register */
+ /*tex
+ Store |cur_box| in a box register
+ */
if (box_context < global_box_flag)
eq_define(box_base + box_context - box_flag, box_ref_cmd, cur_box);
else
geq_define(box_base + box_context - global_box_flag, box_ref_cmd, cur_box);
+ } else if (box_context == lua_scan_flag) {
+ /*tex
+ We are done with scanning so let's return to the caller.
+ */
+ wrapup_local_scan_box();
} else if (cur_box != null) {
- if (box_context > ship_out_flag) {
- /* Append a new leader node that uses |cur_box| */
- /* Get the next non-blank non-relax... */
+ /*tex
+ The leaders contexts come after shipout and luascan contexts.
+ */
+ /* if (box_context > lua_scan_flag) { */
+ if (box_context >= leader_flag) {
+ /*tex
+ Append a new leader node that uses |cur_box| and get the next
+ non-blank non-relax...
+ */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -1391,25 +1694,32 @@ void box_end(int box_context)
leader_ptr(tail) = cur_box;
} else {
print_err("Leaders not followed by proper glue");
- help3
- ("You should say `\\leaders <box or rule><hskip or vskip>'.",
- "I found the <box or rule>, but there's no suitable",
- "<hskip or vskip>, so I'm ignoring these leaders.");
+ help3(
+ "You should say `\\leaders <box or rule><hskip or vskip>'.",
+ "I found the <box or rule>, but there's no suitable",
+ "<hskip or vskip>, so I'm ignoring these leaders."
+ );
back_error();
flush_node_list(cur_box);
}
} else {
+ if (box_context != ship_out_flag) {
+ normal_error("scanner","shipout expected");
+ }
ship_out(static_pdf, cur_box, SHIPPING_PAGE);
}
}
}
-@ the next input should specify a box or perhaps a rule
+/*tex
+
+the next input should specify a box or perhaps a rule
+
+*/
-@c
void scan_box(int box_context)
{
- /* Get the next non-blank non-relax... */
+ /*tex Get the next non-blank non-relax... */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -1422,26 +1732,36 @@ void scan_box(int box_context)
box_end(box_context);
} else {
print_err("A <box> was supposed to be here");
- help3("I was expecting to see \\hbox or \\vbox or \\copy or \\box or",
- "something like that. So you might find something missing in",
- "your output. But keep trying; you can fix this later.");
+ help3(
+ "I was expecting to see \\hbox or \\vbox or \\copy or \\box or",
+ "something like that. So you might find something missing in",
+ "your output. But keep trying; you can fix this later."
+ );
back_error();
+ if (box_context == lua_scan_flag) {
+ cur_box = null;
+ box_end(box_context);
+ }
}
}
-@ @c
void new_graf(boolean indented)
{
halfword p, q, dir_graf_tmp;
halfword dir_rover;
- prev_graf_par = 0;
+ int callback_id;
if ((mode == vmode) || (head != tail)) {
tail_append(new_param_glue(par_skip_code));
}
+ callback_id = callback_defined(new_graf_callback);
+ if (callback_id > 0) {
+ run_callback(callback_id, "db->b", cur_list.mode_field,indented,&indented);
+ }
+ prev_graf_par = 0;
push_nest();
mode = hmode;
space_factor_par = 1000;
- /* LOCAL: Add local paragraph node */
+ /*tex Add local paragraph node */
tail_append(make_local_par_node(new_graf_par_code));
if (indented) {
p = new_null_box();
@@ -1470,15 +1790,16 @@ void new_graf(boolean indented)
begin_token_list(every_par_par, every_par_text);
if (nest_ptr == 1) {
checked_page_filter(new_graf);
- build_page(); /* put |par_skip| glue on current page */
+ /*tex put |par_skip| glue on current page */
+ build_page();
}
}
-@ @c
void indent_in_hmode(void)
{
halfword p;
- if (cur_chr > 0) { /* \.{\\indent} */
+ if (cur_chr > 0) {
+ /*tex \.{\\indent} */
p = new_null_box();
width(p) = par_indent_par;
if (abs(mode) == hmode)
@@ -1489,7 +1810,6 @@ void indent_in_hmode(void)
}
}
-@ @c
void head_for_vmode(void)
{
if (mode < 0) {
@@ -1497,8 +1817,10 @@ void head_for_vmode(void)
off_save();
} else {
print_err("You can't use `\\hrule' here except with leaders");
- help2("To put a horizontal rule in an hbox or an alignment,",
- "you should use \\leaders or \\hrulefill (see The TeXbook).");
+ help2(
+ "To put a horizontal rule in an hbox or an alignment,",
+ "you should use \\leaders or \\hrulefill (see The TeXbook)."
+ );
error();
}
} else {
@@ -1509,19 +1831,23 @@ void head_for_vmode(void)
}
}
-@ TODO (BUG?): |dir_save| would have been set by |line_break| by means
-of |post_line_break|, but this is not done right now, as it introduces
-pretty heavy memory leaks. This means the current code is probably
-wrong in some way that relates to in-paragraph displays.
+/*tex
+
+|dir_save| would have been set by |line_break| by means of |post_line_break|, but
+this is not done right now, as it introduces pretty heavy memory leaks. This
+means the current code might be wrong in some way that relates to in-paragraph
+displays.
+
+*/
-@c
void end_graf(int line_break_context)
{
if (mode == hmode) {
if ((head == tail) || (vlink(head) == tail)) {
if (vlink(head) == tail)
flush_node(vlink(head));
- pop_nest(); /* null paragraphs are ignored, all contain a |local_paragraph| node */
+ /*tex |null| paragraphs are ignored, all contain a |local_paragraph| node */
+ pop_nest();
} else {
line_break(false, line_break_context);
}
@@ -1534,7 +1860,6 @@ void end_graf(int line_break_context)
}
}
-@ @c
void begin_insert_or_adjust(void)
{
if (cur_cmd != vadjust_cmd) {
@@ -1542,7 +1867,9 @@ void begin_insert_or_adjust(void)
if (cur_val == output_box_par) {
print_err("You can't \\insert");
print_int(output_box_par);
- help1("I'm changing to \\insert0; box \\outputbox is special.");
+ help1(
+ "I'm changing to \\insert0; box \\outputbox is special."
+ );
error();
cur_val = 0;
}
@@ -1561,12 +1888,14 @@ void begin_insert_or_adjust(void)
prev_depth_par = ignore_depth;
}
-@ I (TH)'ve renamed the |make_mark| procedure to this, because if the
-current chr code is 1, then the actual command was \.{\\clearmarks},
-which does not generate a mark node but instead destroys the current
-mark tokenlists.
+/*tex
+
+I (TH)'ve renamed the |make_mark| procedure to this, because if the current chr
+code is 1, then the actual command was \.{\\clearmarks}, which does not generate
+a mark node but instead destroys the current mark tokenlists.
+
+*/
-@c
void handle_mark(void)
{
halfword p; /* new node */
@@ -1597,7 +1926,6 @@ void handle_mark(void)
}
}
-@ @c
void append_penalty(void)
{
scan_int();
@@ -1608,29 +1936,34 @@ void append_penalty(void)
}
}
-@ When |delete_last| is called, |cur_chr| is the |type| of node that
-will be deleted, if present.
+/*tex
+
+When |delete_last| is called, |cur_chr| is the |type| of node that will be
+deleted, if present.
-The |remove_item| command removes a penalty, kern, or glue node if it
-appears at the tail of the current list, using a brute-force linear scan.
-Like \.{\\lastbox}, this command is not allowed in vertical mode (except
-internal vertical mode), since the current list in vertical mode is sent
-to the page builder. But if we happen to be able to implement it in
-vertical mode, we do.
+The |remove_item| command removes a penalty, kern, or glue node if it appears at
+the tail of the current list, using a brute-force linear scan. Like
+\.{\\lastbox}, this command is not allowed in vertical mode (except internal
+vertical mode), since the current list in vertical mode is sent to the page
+builder. But if we happen to be able to implement it in vertical mode, we do.
+
+*/
-@c
void delete_last(void)
{
halfword p, q; /* run through the current list */
if ((mode == vmode) && (tail == head)) {
- /* Apologize for inability to do the operation now,
- unless \.{\\unskip} follows non-glue */
+ /*tex
+ Apologize for inability to do the operation now, unless \.{\\unskip}
+ follows non-glue
+ */
if ((cur_chr != glue_node) || (last_glue != max_halfword)) {
you_cant();
if (cur_chr == kern_node) {
- help2
- ("Sorry...I usually can't take things from the current page.",
- "Try `I\\kern-\\lastkern' instead.");
+ help2(
+ "Sorry...I usually can't take things from the current page.",
+ "Try `I\\kern-\\lastkern' instead."
+ );
} else if (cur_chr != glue_node) {
help2
("Sorry...I usually can't take things from the current page.",
@@ -1643,7 +1976,7 @@ void delete_last(void)
error();
}
} else {
- /* todo: clean this up */
+ /*tex Todo: clean this up! */
if (!is_char_node(tail)) {
if (type(tail) == cur_chr) {
q = head;
@@ -1665,7 +1998,6 @@ void delete_last(void)
}
}
-@ @c
void unpackage(void)
{
halfword p; /* the box */
@@ -1673,7 +2005,7 @@ void unpackage(void)
int c; /* should we copy? */
halfword s; /* for varmem assignment */
if (cur_chr > copy_code) {
- /* Handle saved items and |goto done| */
+ /*tex Handle saved items and |goto done| */
try_couple_nodes(tail, disc_ptr[cur_chr]);
disc_ptr[cur_chr] = null;
goto DONE;
@@ -1687,9 +2019,11 @@ void unpackage(void)
|| ((abs(mode) == vmode) && (type(p) != vlist_node))
|| ((abs(mode) == hmode) && (type(p) != hlist_node))) {
print_err("Incompatible list can't be unboxed");
- help3("Sorry, Pandora. (You sneaky devil.)",
- "I refuse to unbox an \\hbox in vertical mode or vice versa.",
- "And I can't open any boxes in math mode.");
+ help3(
+ "Sorry, Pandora. (You sneaky devil.)",
+ "I refuse to unbox an \\hbox in vertical mode or vice versa.",
+ "And I can't open any boxes in math mode."
+ );
error();
return;
}
@@ -1713,12 +2047,14 @@ void unpackage(void)
}
}
-@
+/*tex
+
Italic corrections are converted to kern nodes when the |ital_corr| command
-follows a character. In math mode the same effect is achieved by appending
-a kern of zero here, since italic corrections are supplied later.
+follows a character. In math mode the same effect is achieved by appending a kern
+of zero here, since italic corrections are supplied later.
+
+*/
-@c
void append_italic_correction(void)
{
halfword p; /* |char_node| at the tail of the current list */
@@ -1734,7 +2070,6 @@ void append_italic_correction(void)
}
}
-@ @c
void append_local_box(int kind)
{
incr(save_ptr);
@@ -1746,20 +2081,23 @@ void append_local_box(int kind)
space_factor_par = 1000;
}
-@ Discretionary nodes are easy in the common case `\.{\\-}', but in the
-general case we must process three braces full of items.
+/*tex
+
+Discretionary nodes are easy in the common case `\.{\\-}', but in the general
+case we must process three braces full of items.
+
+The space factor does not change when we append a discretionary node, but it
+starts out as 1000 in the subsidiary lists.
-The space factor does not change when we append a discretionary node,
-but it starts out as 1000 in the subsidiary lists.
+*/
-@c
void append_discretionary(void)
{
int c;
tail_append(new_disc());
subtype(tail) = (quarterword) cur_chr;
if (cur_chr == explicit_disc) {
- /* \- */
+ /* |\-| */
c = get_pre_hyphen_char(cur_lang_par);
if (c > 0) {
vlink(pre_break(tail)) = new_char(equiv(cur_font_loc), c);
@@ -1774,7 +2112,7 @@ void append_discretionary(void)
}
set_explicit_disc_penalty(tail);
} else if (cur_chr == automatic_disc) {
- /* - as done in hyphenator */
+ /*tex As done in hyphenator: */
c = get_pre_exhyphen_char(cur_lang_par);
if (c <= 0) {
c = ex_hyphen_char_par;
@@ -1798,7 +2136,7 @@ void append_discretionary(void)
}
set_automatic_disc_penalty(tail);
} else {
- /* \discretionary */
+ /*tex |\discretionary| */
if (scan_keyword("penalty")) {
scan_int();
disc_penalty(tail) = cur_val;
@@ -1810,14 +2148,17 @@ void append_discretionary(void)
push_nest();
mode = -hmode;
space_factor_par = 1000;
- /* already preset: disc_penalty(tail) = hyphen_penalty_par; */
+ /*tex Already preset: |disc_penalty(tail) = hyphen_penalty_par;| */
}
}
-@ The test for |p != null| ensures that empty \.{\\localleftbox} and
- \.{\\localrightbox} commands are not applied.
+/*tex
+
+The test for |p != null| ensures that empty \.{\\localleftbox} and
+\.{\\localrightbox} commands are not applied.
+
+*/
-@c
void build_local_box(void)
{
halfword p;
@@ -1828,41 +2169,51 @@ void build_local_box(void)
decr(save_ptr);
p = vlink(head);
pop_nest();
- if (p != null)
- p = hpack(p, 0, additional, -1);
+ if (p != null) {
+ /*tex Somehow |filtered_hpack| goes beyond the first node so we loose it. */
+ new_hyphenation(p, null);
+ (void) new_ligkern(p, null);
+ p = lua_hpack_filter(p, 0, additional, local_box_group, -1, null);
+ }
if (kind == 0)
eq_define(local_left_box_base, box_ref_cmd, p);
else
eq_define(local_right_box_base, box_ref_cmd, p);
if (abs(mode) == hmode) {
- /* LOCAL: Add local paragraph node */
+ /*tex Add local paragraph node */
tail_append(make_local_par_node(local_box_par_code));
}
eq_word_define(int_base + no_local_whatsits_code, no_local_whatsits_par + 1);
}
-@ The three discretionary lists are constructed somewhat as if they were
-hboxes. A~subroutine called |build_discretionary| handles the transitions.
-(This is sort of fun.)
+/*tex
+
+The three discretionary lists are constructed somewhat as if they were hboxes.
+A~subroutine called |build_discretionary| handles the transitions. (This is sort
+of fun.)
+
+*/
-@c
void build_discretionary(void)
{
halfword p, q; /* for link manipulation */
int n; /* length of discretionary list */
unsave();
- /* Prune the current list, if necessary, until it contains only
- |char_node|, |kern_node|, |hlist_node|, |vlist_node| and
- |rule_node| items; set |n| to the length of the list,
- and set |q| to the lists tail */
- /* During this loop, |p=vlink(q)| and there are |n| items preceding |p|. */
+ /*tex
+ Prune the current list, if necessary, until it contains only |char_node|,
+ |kern_node|, |hlist_node|, |vlist_node| and |rule_node| items; set |n| to
+ the length of the list, and set |q| to the lists tail. During this loop,
+ |p=vlink(q)| and there are |n| items preceding |p|.
+ */
q = head;
p = vlink(q);
n = 0;
while (p != null) {
if (!is_char_node(p) && type(p) > rule_node && type(p) != kern_node) {
print_err("Improper discretionary list");
- help1("Discretionary lists must contain only boxes and kerns.");
+ help1(
+ "Discretionary lists must contain only boxes and kerns."
+ );
error();
begin_diagnostic();
tprint_nl("The following discretionary sublist has been deleted:");
@@ -1897,12 +2248,16 @@ void build_discretionary(void)
}
break;
case 2:
- /* Attach list |p| to the current list, and record its length;
- then finish up and |return| */
+ /*tex
+ Attach list |p| to the current list, and record its length; then
+ finish up and |return|
+ */
if ((n > 0) && (abs(mode) == mmode)) {
print_err("Illegal math \\discretionary");
- help2("Sorry: The third part of a discretionary break must be",
- "empty, in math formulas. I had to delete your third part.");
+ help2(
+ "Sorry: The third part of a discretionary break must be",
+ "empty, in math formulas. I had to delete your third part."
+ );
flush_node_list(p);
error();
} else {
@@ -1913,9 +2268,10 @@ void build_discretionary(void)
}
}
decr(save_ptr);
+ /*tex There are no other cases. */
return;
break;
- } /* there are no other cases */
+ }
set_saved_record(-1, saved_disc, 0, (saved_value(-1) + 1));
new_save_level(disc_group);
scan_left_brace();
@@ -1924,15 +2280,18 @@ void build_discretionary(void)
space_factor_par = 1000;
}
-@ The positioning of accents is straightforward but tedious. Given an accent
-of width |a|, designed for characters of height |x| and slant |s|;
-and given a character of width |w|, height |h|, and slant |t|: We will shift
-the accent down by |x-h|, and we will insert kern nodes that have the effect of
-centering the accent over the character and shifting the accent to the
-right by $\delta={1\over2}(w-a)+h\cdot t-x\cdot s$. If either character is
-absent from the font, we will simply use the other, without shifting.
+/*tex
+
+The positioning of accents is straightforward but tedious. Given an accent of
+width |a|, designed for characters of height |x| and slant |s|; and given a
+character of width |w|, height |h|, and slant |t|: We will shift the accent down
+by |x-h|, and we will insert kern nodes that have the effect of centering the
+accent over the character and shifting the accent to the right by
+$\delta={1\over2}(w-a)+h\cdot t-x\cdot s$. If either character is absent from the
+font, we will simply use the other, without shifting.
+
+*/
-@c
void make_accent(void)
{
double s, t; /* amount of slant */
@@ -1944,11 +2303,14 @@ void make_accent(void)
p = new_glyph(f, cur_val);
if (p != null) {
x = x_height(f);
- s = float_cast(slant(f)) / float_constant(65536); /* real division */
+ /*tex real division */
+ s = float_cast(slant(f)) / float_constant(65536);
a = glyph_width(p);
do_assignments();
- /* Create a character node |q| for the next character,
- but set |q:=null| if problems arise */
+ /*tex
+ Create a character node |q| for the next character, but set |q:=null|
+ if problems arise
+ */
q = null;
f = equiv(cur_font_loc);
if ((cur_cmd == letter_cmd) ||
@@ -1962,22 +2324,26 @@ void make_accent(void)
}
if (q != null) {
- /* Append the accent with appropriate kerns, then set |p:=q| */
- /* The kern nodes appended here must be distinguished from other kerns, lest
- they be wiped away by the hyphenation algorithm or by a previous line break.
-
- The two kerns are computed with (machine-dependent) |real| arithmetic, but
- their sum is machine-independent; the net effect is machine-independent,
- because the user cannot remove these nodes nor access them via \.{\\lastkern}.
+ /*tex
+ Append the accent with appropriate kerns, then set |p:=q|. The
+ kern nodes appended here must be distinguished from other kerns,
+ lest they be wiped away by the hyphenation algorithm or by a
+ previous line break. The two kerns are computed with
+ (machine-dependent) |real| arithmetic, but their sum is
+ machine-independent; the net effect is machine-independent,
+ because the user cannot remove these nodes nor access them via
+ \.{\\lastkern}.
*/
t = float_cast(slant(f)) / float_constant(65536); /* real division */
w = glyph_width(q);
h = glyph_height(q);
- if (h != x) { /* the accent must be shifted up or down */
+ if (h != x) {
+ /*tex the accent must be shifted up or down */
p = hpack(p, 0, additional, -1);
shift_amount(p) = x - h;
}
- delta = round(float_cast(w - a) / float_constant(2) + h * t - x * s); /* real multiplication */
+ /*tex real multiplication */
+ delta = round(float_cast(w - a) / float_constant(2) + h * t - x * s);
r = new_kern(delta);
subtype(r) = accent_kern;
couple_nodes(tail, r);
@@ -1994,34 +2360,43 @@ void make_accent(void)
}
}
-@ When `\.{\\cr}' or `\.{\\span}' or a tab mark comes through the scanner
-into |main_control|, it might be that the user has foolishly inserted
-one of them into something that has nothing to do with alignment. But it is
-far more likely that a left brace or right brace has been omitted, since
-|get_next| takes actions appropriate to alignment only when `\.{\\cr}'
-or `\.{\\span}' or tab marks occur with |align_state=0|. The following
-program attempts to make an appropriate recovery.
+/*tex
+
+When `\.{\\cr}' or `\.{\\span}' or a tab mark comes through the scanner into
+|main_control|, it might be that the user has foolishly inserted one of them into
+something that has nothing to do with alignment. But it is far more likely that a
+left brace or right brace has been omitted, since |get_next| takes actions
+appropriate to alignment only when `\.{\\cr}' or `\.{\\span}' or tab marks occur
+with |align_state=0|. The following program attempts to make an appropriate
+recovery.
+
+*/
-@c
void align_error(void)
{
if (abs(align_state) > 2) {
- /* Express consternation over the fact that no alignment is in progress */
+ /*tex
+ Express consternation over the fact that no alignment is in progress.
+ */
print_err("Misplaced ");
print_cmd_chr((quarterword) cur_cmd, cur_chr);
if (cur_tok == tab_token + '&') {
- help6("I can't figure out why you would want to use a tab mark",
- "here. If you just want an ampersand, the remedy is",
- "simple: Just type `I\\&' now. But if some right brace",
- "up above has ended a previous alignment prematurely,",
- "you're probably due for more error messages, and you",
- "might try typing `S' now just to see what is salvageable.");
+ help6(
+ "I can't figure out why you would want to use a tab mark",
+ "here. If you just want an ampersand, the remedy is",
+ "simple: Just type `I\\&' now. But if some right brace",
+ "up above has ended a previous alignment prematurely,",
+ "you're probably due for more error messages, and you",
+ "might try typing `S' now just to see what is salvageable."
+ );
} else {
- help5("I can't figure out why you would want to use a tab mark",
- "or \\cr or \\span just now. If something like a right brace",
- "up above has ended a previous alignment prematurely,",
- "you're probably due for more error messages, and you",
- "might try typing `S' now just to see what is salvageable.");
+ help5(
+ "I can't figure out why you would want to use a tab mark",
+ "or \\cr or \\span just now. If something like a right brace",
+ "up above has ended a previous alignment prematurely,",
+ "you're probably due for more error messages, and you",
+ "might try typing `S' now just to see what is salvageable."
+ );
}
error();
@@ -2036,43 +2411,55 @@ void align_error(void)
decr(align_state);
cur_tok = right_brace_token + '}';
}
- help3("I've put in what seems to be necessary to fix",
- "the current column of the current alignment.",
- "Try to go on, since this might almost work.");
+ help3(
+ "I've put in what seems to be necessary to fix",
+ "the current column of the current alignment.",
+ "Try to go on, since this might almost work."
+ );
ins_error();
}
}
-@ The help messages here contain a little white lie, since \.{\\noalign}
-and \.{\\omit} are allowed also after `\.{\\noalign\{...\}}'.
+/*tex
+
+The help messages here contain a little white lie, since \.{\\noalign} and
+\.{\\omit} are allowed also after `\.{\\noalign\{...\}}'.
+
+*/
-@c
void no_align_error(void)
{
print_err("Misplaced \\noalign");
- help2("I expect to see \\noalign only after the \\cr of",
- "an alignment. Proceed, and I'll ignore this case.");
+ help2(
+ "I expect to see \\noalign only after the \\cr of",
+ "an alignment. Proceed, and I'll ignore this case."
+ );
error();
}
void omit_error(void)
{
print_err("Misplaced \\omit");
- help2("I expect to see \\omit only after tab marks or the \\cr of",
- "an alignment. Proceed, and I'll ignore this case.");
+ help2(
+ "I expect to see \\omit only after tab marks or the \\cr of",
+ "an alignment. Proceed, and I'll ignore this case."
+ );
error();
}
-@ We've now covered most of the abuses of \.{\\halign} and \.{\\valign}.
-Let's take a look at what happens when they are used correctly.
+/*tex
+
+We've now covered most of the abuses of \.{\\halign} and \.{\\valign}. Let's take
+a look at what happens when they are used correctly.
-An |align_group| code is supposed to remain on the |save_stack|
-during an entire alignment, until |fin_align| removes it.
+An |align_group| code is supposed to remain on the |save_stack| during an entire
+alignment, until |fin_align| removes it.
-A devious user might force an |endv| command to occur just about anywhere;
-we must defeat such hacks.
+A devious user might force an |endv| command to occur just about anywhere; we
+must defeat such hacks.
+
+*/
-@c
void do_endv(void)
{
base_ptr = input_ptr;
@@ -2085,7 +2472,7 @@ void do_endv(void)
(input_stack[base_ptr].loc_field != null) ||
(input_stack[base_ptr].state_field != token_list))
fatal_error("(interwoven alignment preambles are not allowed)");
- /*.interwoven alignment preambles... */
+ /*tex interwoven alignment preambles... */
if (cur_group == align_group) {
end_graf(align_group);
if (fin_col())
@@ -2095,55 +2482,62 @@ void do_endv(void)
}
}
-@ Finally, \.{\\endcsname} is not supposed to get through to |main_control|.
+/*tex
+
+Finally, \.{\\endcsname} is not supposed to get through to |main_control|.
+
+*/
-@c
void cs_error(void)
{
print_err("Extra \\endcsname");
- help1("I'm ignoring this, since I wasn't doing a \\csname.");
+ help1(
+ "I'm ignoring this, since I wasn't doing a \\csname."
+ );
error();
}
-@
- Assignments to values in |eqtb| can be global or local. Furthermore, a
- control sequence can be defined to be `\.{\\long}', `\.{\\protected}',
- or `\.{\\outer}', and it might or might not be expanded. The prefixes
- `\.{\\global}', `\.{\\long}', `\.{\\protected}',
- and `\.{\\outer}' can occur in any order. Therefore we assign binary numeric
- codes, making it possible to accumulate the union of all specified prefixes
- by adding the corresponding codes. (PASCAL's |set| operations could also
- have been used.)
+/*tex
+
+Assignments to values in |eqtb| can be global or local. Furthermore, a control
+sequence can be defined to be `\.{\\long}', `\.{\\protected}', or `\.{\\outer}',
+and it might or might not be expanded. The prefixes `\.{\\global}', `\.{\\long}',
+`\.{\\protected}', and `\.{\\outer}' can occur in any order. Therefore we assign
+binary numeric codes, making it possible to accumulate the union of all specified
+prefixes by adding the corresponding codes. (PASCAL's |set| operations could also
+have been used.)
- Every prefix, and every command code that might or might not be prefixed,
- calls the action procedure |prefixed_command|. This routine accumulates
- a sequence of prefixes until coming to a non-prefix, then it carries out
- the command.
+Every prefix, and every command code that might or might not be prefixed, calls
+the action procedure |prefixed_command|. This routine accumulates a sequence of
+prefixes until coming to a non-prefix, then it carries out the command.
-@ If the user says, e.g., `\.{\\global\\global}', the redundancy is
-silently accepted.
+*/
+/*tex
-@ The different types of code values have different legal ranges; the
+If the user says, e.g., `\.{\\global\\global}', the redundancy is silently
+accepted. The different types of code values have different legal ranges; the
following program is careful to check each case properly.
-@c
-#define check_def_code(A) do { \
- if (((cur_val<0)&&(p<(A)))||(cur_val>n)) { \
- print_err("Invalid code ("); \
- print_int(cur_val); \
- if (p<(A)) \
- tprint("), should be in the range 0.."); \
- else \
- tprint("), should be at most "); \
- print_int(n); \
- help1("I'm going to use 0 instead of that illegal code value."); \
- error(); \
- cur_val=0; \
- } \
+*/
+
+#define check_def_code(A) do { \
+ if (((cur_val<0)&&(p<(A)))||(cur_val>n)) { \
+ print_err("Invalid code ("); \
+ print_int(cur_val); \
+ if (p<(A)) \
+ tprint("), should be in the range 0.."); \
+ else \
+ tprint("), should be at most "); \
+ print_int(n); \
+ help1( \
+ "I'm going to use 0 instead of that illegal code value." \
+ ); \
+ error(); \
+ cur_val=0; \
+ } \
} while (0)
-@ @c
/*
halfword swap_hang_indent(halfword indentation, halfword shape_mode) {
if (shape_mode == 1 || shape_mode == 3 || shape_mode == -1 || shape_mode == -3) {
@@ -2176,40 +2570,51 @@ void prefixed_command(void)
while (cur_cmd == prefix_cmd) {
if (!odd(a / cur_chr))
a = a + cur_chr;
- /* Get the next non-blank non-relax... */
+ /*tex
+ Get the next non-blank non-relax...
+ */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
if (cur_cmd <= max_non_prefixed_command) {
- /* Discard erroneous prefixes and |return| */
+ /*tex
+ Discard erroneous prefixes and |return|
+ */
print_err("You can't use a prefix with `");
print_cmd_chr((quarterword) cur_cmd, cur_chr);
print_char('\'');
- help2
- ("I'll pretend you didn't say \\long or \\outer or \\global or",
- "\\protected.");
+ help2(
+ "I'll pretend you didn't say \\long or \\outer or \\global or",
+ "\\protected."
+ );
back_error();
return;
}
if (tracing_commands_par > 2)
show_cur_cmd_chr();
}
- /* Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant */
+ /*tex
+ Discard the prefixes \.{\\long} and \.{\\outer} if they are irrelevant
+ */
if (a >= 8) {
j = protected_token;
a = a - 8;
} else {
j = 0;
}
- if ((cur_cmd != def_cmd) && ((a % 4 != 0) || (j != 0))) {
+ if ((cur_cmd != def_cmd) && (cur_cmd != def_lua_call_cmd) && ((a % 4 != 0) || (j != 0))) {
print_err("You can't use `\\long' or `\\outer' or `\\protected' with `");
print_cmd_chr((quarterword) cur_cmd, cur_chr);
print_char('\'');
- help1("I'll pretend you didn't say \\long or \\outer or \\protected here.");
+ help1(
+ "I'll pretend you didn't say \\long or \\outer or \\protected here."
+ );
error();
}
- /* Adjust for the setting of \.{\\globaldefs} */
+ /*tex
+ Adjust for the setting of \.{\\globaldefs}
+ */
if (global_defs_par != 0) {
if (global_defs_par < 0) {
if (is_global(a))
@@ -2221,15 +2626,18 @@ void prefixed_command(void)
}
switch (cur_cmd) {
case set_font_cmd:
- /* Here's an example of the way many of the following routines operate.
- (Unfortunately, they aren't all as simple as this.) */
+ /*tex
+ Here's an example of the way many of the following routines operate.
+ (Unfortunately, they aren't all as simple as this.)
+ */
define(cur_font_loc, data_cmd, cur_chr);
break;
case def_cmd:
- /* When a |def| command has been scanned,
- |cur_chr| is odd if the definition is supposed to be global, and
- |cur_chr>=2| if the definition is supposed to be expanded. */
-
+ /*tex
+ When a |def| command has been scanned, |cur_chr| is odd if the
+ definition is supposed to be global, and |cur_chr>=2| if the
+ definition is supposed to be expanded.
+ */
if (odd(cur_chr) && !is_global(a) && (global_defs_par >= 0))
a = a + 4;
e = (cur_chr >= 2);
@@ -2246,35 +2654,15 @@ void prefixed_command(void)
break;
case let_cmd:
n = cur_chr;
- if (n == normal) {
- get_r_token();
- p = cur_cs;
- do {
- get_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok == other_token + '=') {
- get_token();
- if (cur_cmd == spacer_cmd)
- get_token();
- }
- } else if (n == normal + 1) {
- /* futurelet */
- get_r_token();
- p = cur_cs;
- get_token();
- q = cur_tok;
- get_token();
- back_input();
- cur_tok = q;
- /* look ahead, then back up */
- /* note that |back_input| doesn't affect |cur_cmd|, |cur_chr| */
- back_input();
- } else {
- /* letcharcode */
- scan_int();
- if (cur_val > 0) {
- cur_cs = active_to_cs(cur_val, true);
- set_token_info(cur_cs, cur_cs + cs_token_flag);
+ switch (n) {
+ case 0:
+ /*tex |glet| */
+ if (!is_global(a) && (global_defs_par >= 0)) {
+ a = a + 4;
+ }
+ case 1:
+ /*tex |let| */
+ get_r_token();
p = cur_cs;
do {
get_token();
@@ -2284,21 +2672,60 @@ void prefixed_command(void)
if (cur_cmd == spacer_cmd)
get_token();
}
- } else {
+ break;
+ case 2:
+ /*tex |futurelet| */
+ get_r_token();
+ p = cur_cs;
+ get_token();
+ q = cur_tok;
+ get_token();
+ back_input();
+ cur_tok = q;
+ /*tex
+ We look ahead and then back up. Note that |back_input| doesn't
+ affect |cur_cmd|, |cur_chr|
+ */
+ back_input();
+ break;
+ case 3:
+ /*tex |letcharcode| */
+ scan_int();
+ if (cur_val > 0) {
+ cur_cs = active_to_cs(cur_val, true);
+ set_token_info(cur_cs, cur_cs + cs_token_flag);
+ p = cur_cs;
+ do {
+ get_token();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_tok == other_token + '=') {
+ get_token();
+ if (cur_cmd == spacer_cmd)
+ get_token();
+ }
+ } else {
+ p = null;
+ tex_error("invalid number for \\letcharcode",NULL);
+ }
+ break;
+ default:
+ /*tex We please the compiler. */
p = null;
- tex_error("invalid number for \\letcharcode",NULL);
- }
+ confusion("let");
+ break;
}
if (cur_cmd >= call_cmd)
add_token_ref(cur_chr);
define(p, cur_cmd, cur_chr);
break;
case shorthand_def_cmd:
- /* We temporarily define |p| to be |relax|, so that an occurrence of |p|
- while scanning the definition will simply stop the scanning instead of
- producing an ``undefined control sequence'' error or expanding the
- previous meaning. This allows, for instance, `\.{\\chardef\\foo=123\\foo}'.
- */
+ /*tex
+ We temporarily define |p| to be |relax|, so that an occurrence of
+ |p| while scanning the definition will simply stop the scanning
+ instead of producing an ``undefined control sequence'' error or
+ expanding the previous meaning. This allows, for instance,
+ `\.{\\chardef\\foo=123\\foo}'.
+ */
n = cur_chr;
get_r_token();
p = cur_cs;
@@ -2311,13 +2738,13 @@ void prefixed_command(void)
break;
case math_char_def_code:
mval = scan_mathchar(tex_mathcode);
- if (math_umathcode_meaning_par == 1) {
- cur_val = (mval.class_value + (8 * mval.family_value)) * (65536 * 32) + mval.character_value;
- define(p, xmath_given_cmd, cur_val);
- } else {
+ /* if (math_umathcode_meaning_par == 1) { */
+ /* cur_val = (mval.class_value + (8 * mval.family_value)) * (65536 * 32) + mval.character_value; */
+ /* define(p, xmath_given_cmd, cur_val); */
+ /* } else { */
cur_val = (mval.class_value * 16 + mval.family_value) * 256 + mval.character_value;
define(p, math_given_cmd, cur_val);
- }
+ /* } */
break;
case xmath_char_def_code:
mval = scan_mathchar(umath_mathcode);
@@ -2363,8 +2790,10 @@ void prefixed_command(void)
n = cur_val;
if (!scan_keyword("to")) {
print_err("Missing `to' inserted");
- help2("You should have said `\\read<number> to \\cs'.",
- "I'm going to look for the \\cs now.");
+ help2(
+ "You should have said `\\read<number> to \\cs'.",
+ "I'm going to look for the \\cs now."
+ );
error();
}
get_r_token();
@@ -2374,25 +2803,30 @@ void prefixed_command(void)
break;
case toks_register_cmd:
case assign_toks_cmd:
- /* The token-list parameters, \.{\\output} and \.{\\everypar}, etc., receive
- their values in the following way. (For safety's sake, we place an
- enclosing pair of braces around an \.{\\output} list.) */
+ /*tex
+ The token-list parameters, \.{\\output} and \.{\\everypar}, etc.,
+ receive their values in the following way. (For safety's sake, we
+ place an enclosing pair of braces around an \.{\\output} list.)
+ */
q = cur_cs;
if (cur_cmd == toks_register_cmd) {
scan_register_num();
p = toks_base + cur_val;
} else {
- p = cur_chr; /* |p=every_par_loc| or |output_routine_loc| or \dots */
+ /*tex |p=every_par_loc| or |output_routine_loc| or \dots */
+ p = cur_chr;
}
scan_optional_equals();
- /* Get the next non-blank non-relax non-call token */
+ /*tex Get the next non-blank non-relax non-call token */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
if (cur_cmd != left_brace_cmd) {
- /* If the right-hand side is a token parameter
- or token register, finish the assignment and |goto done| */
+ /*tex
+ If the right-hand side is a token parameter or token
+ register, finish the assignment and |goto done|
+ */
if (cur_cmd == toks_register_cmd) {
scan_register_num();
cur_cmd = assign_toks_cmd;
@@ -2431,7 +2865,7 @@ void prefixed_command(void)
}
break;
case assign_int_cmd:
- /* Similar routines are used to assign values to the numeric parameters. */
+ /*tex Similar routines are used to assign values to the numeric parameters. */
p = cur_chr;
scan_optional_equals();
scan_int();
@@ -2446,9 +2880,18 @@ void prefixed_command(void)
attr_list_cache = cache_disabled;
word_define(p, cur_val);
break;
+ case assign_direction_cmd:
case assign_dir_cmd:
- /* DIR: Assign direction codes */
- scan_direction();
+ /*tex Assign direction codes. */
+ if (cur_cmd == assign_direction_cmd) {
+ p = cur_chr;
+ scan_optional_equals();
+ scan_int();
+ check_dir_value(cur_val);
+ cur_chr = p;
+ } else {
+ scan_direction();
+ }
switch (cur_chr) {
case int_base + page_direction_code:
eq_word_define(int_base + page_direction_code, cur_val);
@@ -2487,17 +2930,19 @@ void prefixed_command(void)
}
if (abs(mode) == hmode) {
if (no_local_dirs_par > 0) {
- /* tail is non zero but we test anyway */
+ /*tex |tail| is non zero but we test anyway. */
if (check_glue && (tail != null && type(tail) == glue_node)) {
halfword prev = alink(tail);
- halfword dirn = new_dir(text_direction_par - dir_swap);
+ halfword dirn = new_dir(text_direction_par);
+ subtype(dirn) = cancel_dir;
couple_nodes(prev,dirn);
couple_nodes(dirn,tail);
} else {
- tail_append(new_dir(text_direction_par - dir_swap));
+ tail_append(new_dir(text_direction_par));
+ subtype(tail) = cancel_dir;
}
} else {
- /* what is the use of nolocaldirs .. maybe we should get rid of it */
+ /*tex What is the use of nolocaldirs? Maybe we should get rid of it. */
}
update_text_dir_ptr(cur_val);
tail_append(new_dir(cur_val));
@@ -2505,19 +2950,6 @@ void prefixed_command(void)
} else {
update_text_dir_ptr(cur_val);
}
- /* original:
-
- // if ((no_local_dirs_par > 0) && (abs(mode) == hmode)) {
- // // tail_append(new_dir(text_direction_par) // kind of wrong
- // tail_append(new_dir(text_direction_par - dir_swap)); // better
- // }
-
- update_text_dir_ptr(cur_val);
- if (abs(mode) == hmode) {
- tail_append(new_dir(cur_val));
- dir_level(tail) = cur_level;
- }
- */
eq_word_define(int_base + text_direction_code, cur_val);
eq_word_define(int_base + no_local_dirs_code, no_local_dirs_par + 1);
break;
@@ -2542,14 +2974,13 @@ void prefixed_command(void)
break;
case def_char_code_cmd:
case def_del_code_cmd:
- /* Let |n| be the largest legal code value, based on |cur_chr| */
+ /*tex Let |n| be the largest legal code value, based on |cur_chr| */
if (cur_chr == cat_code_base)
n = max_char_code;
else if (cur_chr == sf_code_base)
n = 077777;
else
n = biggest_char;
-
p = cur_chr;
if (cur_chr == math_code_base) {
if (is_global(a))
@@ -2621,8 +3052,9 @@ void prefixed_command(void)
get_token();
if (cur_cmd != math_style_cmd) {
print_err("Missing math style, treated as \\displaystyle");
- help1
- ("A style should have been here; I inserted `\\displaystyle'.");
+ help1(
+ "A style should have been here; I inserted `\\displaystyle'."
+ );
cur_val1 = display_style;
back_error();
} else {
@@ -2652,9 +3084,11 @@ void prefixed_command(void)
do_register_command(a);
break;
case set_box_cmd:
- /* The processing of boxes is somewhat different, because we may need
- to scan and create an entire box before we actually change the value
- of the old one. */
+ /*tex
+ The processing of boxes is somewhat different, because we may
+ need to scan and create an entire box before we actually change
+ the value of the old one.
+ */
scan_register_num();
if (is_global(a))
n = global_box_flag + cur_val;
@@ -2665,16 +3099,22 @@ void prefixed_command(void)
scan_box(n);
} else {
print_err("Improper \\setbox");
- help2("Sorry, \\setbox is not allowed after \\halign in a display,",
- "or between \\accent and an accented character.");
+ help3(
+ "Sorry, \\setbox is not allowed after \\halign in a display,",
+ "between \\accent and an accented character, or in immediate",
+ "assignments."
+ );
error();
}
break;
case set_aux_cmd:
- /* The |space_factor| or |prev_depth| settings are changed when a |set_aux|
- command is sensed. Similarly, |prev_graf| is changed in the presence of
- |set_prev_graf|, and |dead_cycles| or |insert_penalties| in the presence of
- |set_page_int|. These definitions are always global. */
+ /*tex
+ The |space_factor| or |prev_depth| settings are changed when a
+ |set_aux| command is sensed. Similarly, |prev_graf| is changed in
+ the presence of |set_prev_graf|, and |dead_cycles| or
+ |insert_penalties| in the presence of |set_page_int|. These
+ definitions are always global.
+ */
alter_aux();
break;
case set_prev_graf_cmd:
@@ -2687,8 +3127,11 @@ void prefixed_command(void)
alter_integer();
break;
case set_box_dimen_cmd:
- /* When some dimension of a box register is changed, the change isn't exactly
- global; but \TeX\ does not look at the \.{\\global} switch. */
+ /*tex
+ When some dimension of a box register is changed, the change
+ isn't exactly global; but \TeX\ does not look at the \.{\\global}
+ switch.
+ */
alter_box_dimen();
break;
case set_tex_shape_cmd:
@@ -2722,7 +3165,7 @@ void prefixed_command(void)
p = new_node(shape_node, 2 * n + 1 + 1);
vinfo(p + 1) = n;
n = cur_val;
- varmem[p + 2].cint = n; /* number of penalties */
+ varmem[p + 2].cint = n; /* number of penalties */
for (j = p + 3; j <= p + n + 2; j++) {
scan_int();
varmem[j].cint = cur_val; /* penalty values */
@@ -2733,8 +3176,10 @@ void prefixed_command(void)
define(q, shape_ref_cmd, p);
break;
case hyph_data_cmd:
- /* All of \TeX's parameters are kept in |eqtb| except the font information,
- the interaction mode, and the hyphenation tables; these are strictly global.
+ /*tex
+ All of \TeX's parameters are kept in |eqtb| except the font
+ information, the interaction mode, and the hyphenation tables;
+ these are strictly global.
*/
switch (cur_chr) {
case 0:
@@ -2801,9 +3246,20 @@ void prefixed_command(void)
}
break;
case def_font_cmd:
- /* Here is where the information for a new font gets loaded. */
+ /*tex Here is where the information for a new font gets loaded. */
tex_def_font((small_number) a);
break;
+ case def_lua_call_cmd:
+ get_r_token();
+ p = cur_cs;
+ scan_optional_equals();
+ scan_int();
+ if (j != 0) {
+ define(p, lua_call_cmd, cur_val);
+ } else {
+ define(p, lua_expandable_call_cmd, cur_val);
+ }
+ break;
case letterspace_font_cmd:
new_letterspaced_font((small_number) a);
break;
@@ -2821,9 +3277,10 @@ void prefixed_command(void)
default:
confusion("prefix");
break;
- } /* end of Assignments cases */
+ }
+ /*tex End of assignments cases. */
DONE:
- /* Insert a token saved by \.{\\afterassignment}, if any */
+ /*tex Insert a token saved by \.{\\afterassignment}, if any. */
if (after_token != 0) {
cur_tok = after_token;
back_input();
@@ -2831,14 +3288,13 @@ void prefixed_command(void)
}
}
-@ @c
void fixup_directions(void)
{
int temp_no_whatsits = no_local_whatsits_par;
int temp_no_dirs = no_local_dirs_par;
int temporary_dir = text_direction_par;
if (dir_level(text_dir_ptr) == cur_level) {
- /* DIR: Remove from |text_dir_ptr| */
+ /* Remove from |text_dir_ptr|. */
halfword text_dir_tmp = vlink(text_dir_ptr);
flush_node(text_dir_ptr);
text_dir_ptr = text_dir_tmp;
@@ -2846,22 +3302,50 @@ void fixup_directions(void)
unsave();
if (abs(mode) == hmode) {
if (temp_no_dirs != 0) {
- /* DIR: Add local dir node */
+ /* Add local dir node. */
tail_append(new_dir(text_direction_par));
- dir_dir(tail) = temporary_dir - dir_swap;
+ dir_dir(tail) = temporary_dir;
+ subtype(tail) = cancel_dir;
}
if (temp_no_whatsits != 0) {
- /* LOCAL: Add local paragraph node */
+ /*tex Add local paragraph node. */
tail_append(make_local_par_node(hmode_par_par_code));
}
}
}
-@ When a control sequence is to be defined, by \.{\\def} or \.{\\let} or
-something similar, the |get_r_token| routine will substitute a special
-control sequence for a token that is not redefinable.
+/*tex
+
+ This is experimental and needs more checking!
+
+*/
+
+void fixup_directions_only(void)
+{
+ int temp_no_dirs = no_local_dirs_par;
+ int temporary_dir = text_direction_par;
+ if (dir_level(text_dir_ptr) == cur_level) {
+ /* Remove from |text_dir_ptr|. */
+ halfword text_dir_tmp = vlink(text_dir_ptr);
+ flush_node(text_dir_ptr);
+ text_dir_ptr = text_dir_tmp;
+ }
+ if (temp_no_dirs != 0) {
+ /* Add local dir node. */
+ tail_append(new_dir(text_direction_par));
+ dir_dir(tail) = temporary_dir;
+ subtype(tail) = cancel_dir;
+ }
+}
+
+/*tex
+
+When a control sequence is to be defined, by \.{\\def} or \.{\\let} or something
+similar, the |get_r_token| routine will substitute a special control sequence for
+a token that is not redefinable.
+
+*/
-@c
void get_r_token(void)
{
RESTART:
@@ -2871,11 +3355,13 @@ void get_r_token(void)
if ((cur_cs == 0) || (cur_cs > eqtb_top) ||
((cur_cs > frozen_control_sequence) && (cur_cs <= eqtb_size))) {
print_err("Missing control sequence inserted");
- help5("Please don't say `\\def cs{...}', say `\\def\\cs{...}'.",
- "I've inserted an inaccessible control sequence so that your",
- "definition will be completed without mixing me up too badly.",
- "You can recover graciously from this error, if you're",
- "careful; see exercise 27.2 in The TeXbook.");
+ help5(
+ "Please don't say `\\def cs{...}', say `\\def\\cs{...}'.",
+ "I've inserted an inaccessible control sequence so that your",
+ "definition will be completed without mixing me up too badly.",
+ "You can recover graciously from this error, if you're",
+ "careful; see exercise 27.2 in The TeXbook."
+ );
if (cur_cs == 0)
back_input();
cur_tok = cs_token_flag + frozen_protection;
@@ -2884,7 +3370,6 @@ void get_r_token(void)
}
}
-@ @c
void assign_internal_value(int a, halfword p, int val)
{
halfword n;
@@ -2896,17 +3381,19 @@ void assign_internal_value(int a, halfword p, int val)
word_define(p, val);
} else {
print_err("Invalid \\catcode table");
- help2
- ("You can only switch to a \\catcode table that is initialized",
- "using \\savecatcodetable or \\initcatcodetable, or to table 0");
+ help2(
+ "You can only switch to a \\catcode table that is initialized",
+ "using \\savecatcodetable or \\initcatcodetable, or to table 0"
+ );
error();
}
break;
case output_box_code:
if ((val > 65535) | (val < 0)) {
print_err("Invalid \\outputbox");
- help1
- ("The value for \\outputbox has to be between 0 and 65535.");
+ help1(
+ "The value for \\outputbox has to be between 0 and 65535."
+ );
error();
} else {
word_define(p, val);
@@ -2915,9 +3402,10 @@ void assign_internal_value(int a, halfword p, int val)
case new_line_char_code:
if (val > 127) {
print_err("Invalid \\newlinechar");
- help2
- ("The value for \\newlinechar has to be no higher than 127.",
- "Your invalid assignment will be ignored.");
+ help2(
+ "The value for \\newlinechar has to be no higher than 127.",
+ "Your invalid assignment will be ignored."
+ );
error();
} else {
word_define(p, val);
@@ -2926,9 +3414,10 @@ void assign_internal_value(int a, halfword p, int val)
case end_line_char_code:
if (val > 127) {
print_err("Invalid \\endlinechar");
- help2
- ("The value for \\endlinechar has to be no higher than 127.",
- "Your invalid assignment will be ignored.");
+ help2(
+ "The value for \\endlinechar has to be no higher than 127.",
+ "Your invalid assignment will be ignored."
+ );
error();
} else {
word_define(p, val);
@@ -2940,9 +3429,10 @@ void assign_internal_value(int a, halfword p, int val)
word_define(p, -1);
} else if (val > 16383) {
print_err("Invalid \\language");
- help2
- ("The absolute value for \\language has to be no higher than 16383.",
- "Your invalid assignment will be ignored.");
+ help2(
+ "The absolute value for \\language has to be no higher than 16383.",
+ "Your invalid assignment will be ignored."
+ );
error();
} else {
word_define(int_base + cur_lang_code, val);
@@ -2953,15 +3443,17 @@ void assign_internal_value(int a, halfword p, int val)
word_define(p, val);
break;
}
- /* If we are defining subparagraph penalty levels while we are
- in hmode, then we put out a whatsit immediately, otherwise
- we leave it alone. This mechanism might not be sufficiently
- powerful, and some other algorithm, searching down the stack,
- might be necessary. Good first step. */
+ /*tex
+ If we are defining subparagraph penalty levels while we are in hmode,
+ then we put out a whatsit immediately, otherwise we leave it alone.
+ This mechanism might not be sufficiently powerful, and some other
+ algorithm, searching down the stack, might be necessary. Good first
+ step.
+ */
if ((abs(mode) == hmode) &&
((p == (int_base + local_inter_line_penalty_code)) ||
(p == (int_base + local_broken_penalty_code)))) {
- /* LOCAL: Add local paragraph node */
+ /*tex Add local paragraph node */
tail_append(make_local_par_node(penalty_par_code));
eq_word_define(int_base + no_local_whatsits_code, no_local_whatsits_par + 1);
}
@@ -2980,20 +3472,23 @@ void assign_internal_value(int a, halfword p, int val)
word_define(dimen_base + page_top_offset_code, n);
}
word_define(p, val);
- } else if ((p >= local_base) && (p < toks_base)) { /* internal locals */
+ } else if ((p >= local_base) && (p < toks_base)) {
+ /*tex internal locals */
define(p, call_cmd, val);
} else {
confusion("assign internal value");
}
}
-@ We use the fact that |register<advance<multiply<divide|
+/*tex
-Compute the register location |l| and its type |p|; but |return| if invalid
-Here we use the fact that the consecutive codes |int_val..mu_val| and
+We use the fact that |register| $<$ |advance| $<$ |multiply| $<$ |divide|/ We
+compute the register location |l| and its type |p| but |return| if invalid. Here
+we use the fact that the consecutive codes |int_val..mu_val| and
|assign_int..assign_mu_glue| correspond to each other nicely.
-@c
+*/
+
void do_register_command(int a)
{
int p;
@@ -3011,7 +3506,9 @@ void do_register_command(int a)
print_cmd_chr((quarterword) cur_cmd, cur_chr);
tprint("' after ");
print_cmd_chr((quarterword) q, 0);
- help1("I'm forgetting what you said and not changing anything.");
+ help1(
+ "I'm forgetting what you said and not changing anything."
+ );
error();
return;
}
@@ -3032,11 +3529,11 @@ void do_register_command(int a)
if (q == register_cmd) {
scan_optional_equals();
} else if (scan_keyword("by")) {
- /* optional `\.{by}' */
+ /*tex optional `\.{by}' */
}
arith_error = false;
if (q < multiply_cmd) {
- /* Compute result of |register| or |advance|, put it in |cur_val| */
+ /*tex Compute result of |register| or |advance|, put it in |cur_val|. */
if (p < glue_val_level) {
if ((p == int_val_level) || (p == attr_val_level))
scan_int();
@@ -3045,7 +3542,6 @@ void do_register_command(int a)
if (q == advance_cmd)
cur_val = cur_val + eqtb[l].cint;
} else {
- /* we can probably save a copy */
scan_glue(p);
if (q == advance_cmd) {
/* Compute the sum of two glue specs */
@@ -3075,7 +3571,7 @@ void do_register_command(int a)
}
}
} else {
- /* Compute result of |multiply| or |divide|, put it in |cur_val| */
+ /*tex Compute result of |multiply| or |divide|, put it in |cur_val| */
scan_int();
if (p < glue_val_level) {
if (q == multiply_cmd) {
@@ -3104,8 +3600,10 @@ void do_register_command(int a)
}
if (arith_error) {
print_err("Arithmetic overflow");
- help2("I can't carry out that multiplication or division,",
- "since the result is out of range.");
+ help2(
+ "I can't carry out that multiplication or division,",
+ "since the result is out of range."
+ );
if (p >= glue_val_level)
flush_node(cur_val);
error();
@@ -3126,10 +3624,9 @@ void do_register_command(int a)
}
}
-@ @c
void alter_aux(void)
{
- halfword c; /* |hmode| or |vmode| */
+ halfword c; /* |hmode| or |vmode| */
if (cur_chr != abs(mode)) {
report_illegal_case();
} else {
@@ -3142,7 +3639,9 @@ void alter_aux(void)
scan_int();
if ((cur_val <= 0) || (cur_val > 32767)) {
print_err("Bad space factor");
- help1("I allow only values in the range 1..32767 here.");
+ help1(
+ "I allow only values in the range 1..32767 here."
+ );
int_error(cur_val);
} else {
space_factor_par = cur_val;
@@ -3151,39 +3650,39 @@ void alter_aux(void)
}
}
-@ @c
void alter_prev_graf(void)
{
- int p; /* index into |nest| */
- p = nest_ptr;
+ int p = nest_ptr; /* index into |nest| */
while (abs(nest[p].mode_field) != vmode)
decr(p);
scan_optional_equals();
scan_int();
if (cur_val < 0) {
print_err("Bad \\prevgraf");
- help1("I allow only nonnegative values here.");
+ help1(
+ "I allow only nonnegative values here."
+ );
int_error(cur_val);
} else {
nest[p].pg_field = cur_val;
}
}
-@ @c
void alter_page_so_far(void)
{
- int c; /* index into |page_so_far| */
- c = cur_chr;
+ int c = cur_chr; /* index into |page_so_far| */
scan_optional_equals();
scan_normal_dimen();
page_so_far[c] = cur_val;
}
-@ @c
+/*tex
+ The value of |c| is 0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}, etc.
+*/
+
void alter_integer(void)
{
- int c; /* 0 for \.{\\deadcycles}, 1 for \.{\\insertpenalties}, etc. */
- c = cur_chr;
+ int c = cur_chr;
scan_optional_equals();
scan_int();
if (c == 0) {
@@ -3191,8 +3690,10 @@ void alter_integer(void)
} else if (c == 2) {
if ((cur_val < batch_mode) || (cur_val > error_stop_mode)) {
print_err("Bad interaction mode");
- help2("Modes are 0=batch, 1=nonstop, 2=scroll, and",
- "3=errorstop. Proceed, and I'll ignore this case.");
+ help2(
+ "Modes are 0=batch, 1=nonstop, 2=scroll, and",
+ "3=errorstop. Proceed, and I'll ignore this case."
+ );
int_error(cur_val);
} else {
cur_chr = cur_val;
@@ -3203,11 +3704,10 @@ void alter_integer(void)
}
}
-@ @c
void alter_box_dimen(void)
{
- int c; /* |width_offset| or |height_offset| or |depth_offset| */
- int b; /* box number */
+ int c; /* |width_offset| or |height_offset| or |depth_offset| */
+ int b; /* box number */
c = cur_chr;
scan_register_num();
b = cur_val;
@@ -3217,7 +3717,6 @@ void alter_box_dimen(void)
varmem[box(b) + c].cint = cur_val;
}
-@ @c
void new_interaction(void)
{
print_ln();
@@ -3229,21 +3728,27 @@ void new_interaction(void)
fixup_selector(log_opened_global);
}
-@ The \.{\\afterassignment} command puts a token into the global
-variable |after_token|. This global variable is examined just after
-every assignment has been performed.
+/*tex
+
+The \.{\\afterassignment} command puts a token into the global variable
+|after_token|. This global variable is examined just after every assignment has
+been performed. It's value is zero, or a saved token.
+
+*/
+
+halfword after_token;
+
+/*tex
-@c
-halfword after_token; /* zero, or a saved token */
+ Here is a procedure that might be called `Get the next non-blank non-relax
+ non-call non-assignment token'.
-@ Here is a procedure that might be called `Get the next non-blank non-relax
-non-call non-assignment token'.
+*/
-@c
void do_assignments(void)
{
while (true) {
- /* Get the next non-blank non-relax... */
+ /*tex Get the next non-blank non-relax... */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -3255,13 +3760,13 @@ void do_assignments(void)
}
}
-@ @c
+/*tex |cur_chr| is 1 for \.{\\openin}, 0 for \.{\\closein}: */
+
void open_or_close_in(void)
{
- int c; /* 1 for \.{\\openin}, 0 for \.{\\closein} */
- int n; /* stream number */
+ int c = cur_chr;
+ int n;
char *fn;
- c = cur_chr;
scan_four_bit_int();
n = cur_val;
if (read_open[n] != closed) {
@@ -3275,7 +3780,8 @@ void open_or_close_in(void)
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
back_input();
if (cur_cmd != left_brace_cmd) {
- scan_file_name(); /* set |cur_name| to desired file name */
+ /*tex Set |cur_name| to desired file name. */
+ scan_file_name();
if (cur_ext == get_nullstr())
cur_ext = maketexstring(".tex");
} else {
@@ -3288,14 +3794,17 @@ void open_or_close_in(void)
}
}
-@ @c
-boolean long_help_seen; /* has the long \.{\\errmessage} help been used? */
+/*tex
+ Has the long \.{\\errmessage} help been used?
+*/
+
+boolean long_help_seen;
void issue_message(void)
{
- int old_setting; /* holds |selector| setting */
- int c; /* identifies \.{\\message} and \.{\\errmessage} */
- str_number s; /* the message */
+ int old_setting; /* holds |selector| setting */
+ int c; /* identifies \.{\\message} and \.{\\errmessage} */
+ str_number s; /* the message */
c = cur_chr;
(void) scan_toks(false, true);
old_setting = selector;
@@ -3306,7 +3815,7 @@ void issue_message(void)
str_room(1);
s = make_string();
if (c == 0) {
- /* Print string |s| on the terminal */
+ /*tex Print string |s| on the terminal */
if (term_offset + (int) str_length(s) > max_print_line - 2)
print_ln();
else if ((term_offset > 0) || (file_offset > 0))
@@ -3315,23 +3824,29 @@ void issue_message(void)
update_terminal();
} else {
- /* Print string |s| as an error message */
- /* If \.{\\errmessage} occurs often in |scroll_mode|, without user-defined
- \.{\\errhelp}, we don't want to give a long help message each time. So we
- give a verbose explanation only once. */
+ /*tex
+ Print string |s| as an error message. If \.{\\errmessage} occurs
+ often in |scroll_mode|, without user-defined \.{\\errhelp}, we don't
+ want to give a long help message each time. So we give a verbose
+ explanation only once.
+ */
print_err("");
print(s);
if (err_help_par != null) {
use_err_help = true;
} else if (long_help_seen) {
- help1("(That was another \\errmessage.)");
+ help1(
+ "(That was another \\errmessage.)"
+ );
} else {
if (interaction < error_stop_mode)
long_help_seen = true;
- help4("This error message was generated by an \\errmessage",
- "command, so I can't give any explicit help.",
- "Pretend that you're Hercule Poirot: Examine all clues,",
- "and deduce the truth by order and method.");
+ help4(
+ "This error message was generated by an \\errmessage",
+ "command, so I can't give any explicit help.",
+ "Pretend that you're Hercule Poirot: Examine all clues,",
+ "and deduce the truth by order and method."
+ );
}
error();
use_err_help = false;
@@ -3340,34 +3855,40 @@ void issue_message(void)
flush_str(s);
}
-@ The |error| routine calls on |give_err_help| if help is requested from
-the |err_help| parameter.
+/*tex
+
+The |error| routine calls on |give_err_help| if help is requested from the
+|err_help| parameter.
+
+*/
-@c
void give_err_help(void)
{
token_show(err_help_par);
}
-@ The \.{\\uppercase} and \.{\\lowercase} commands are implemented by
-building a token list and then changing the cases of the letters in it.
+/*tex
+
+The \.{\\uppercase} and \.{\\lowercase} commands are implemented by building a
+token list and then changing the cases of the letters in it.
+
+*/
-@c
void shift_case(void)
{
- halfword b; /* |lc_code_base| or |uc_code_base| */
- halfword p; /* runs through the token list */
- halfword t; /* token */
- halfword c; /* character code */
- halfword i; /* inbetween */
+ halfword b; /* |lc_code_base| or |uc_code_base| */
+ halfword p; /* runs through the token list */
+ halfword t; /* token */
+ halfword c; /* character code */
+ halfword i; /* inbetween */
b = cur_chr;
p = scan_toks(false, false);
p = token_link(def_ref);
while (p != null) {
- /* Change the case of the token in |p|, if a change is appropriate */
- /*
- When the case of a |chr_code| changes, we don't change the |cmd|.
- We also change active characters.
+ /*tex
+ Change the case of the token in |p|, if a change is appropriate. When
+ the case of a |chr_code| changes, we don't change the |cmd|. We also
+ change active characters.
*/
t = token_info(p);
if (t < cs_token_flag) {
@@ -3390,27 +3911,30 @@ void shift_case(void)
p = token_link(p);
}
back_list(token_link(def_ref));
- free_avail(def_ref); /* omit reference count */
+ free_avail(def_ref);
}
-@ We come finally to the last pieces missing from |main_control|, namely the
+/*tex
+
+We come finally to the last pieces missing from |main_control|, namely the
`\.{\\show}' commands that are useful when debugging.
-@c
+*/
+
void show_whatever(void)
{
- halfword p; /* tail of a token list to show */
- int t; /* type of conditional being shown */
- int m; /* upper bound on |fi_or_else| codes */
- int l; /* line where that conditional began */
- int n; /* level of \.{\\if...\\fi} nesting */
+ halfword p; /* tail of a token list to show */
+ int t; /* type of conditional being shown */
+ int m; /* upper bound on |fi_or_else| codes */
+ int l; /* line where that conditional began */
+ int n; /* level of \.{\\if...\\fi} nesting */
switch (cur_chr) {
case show_lists:
begin_diagnostic();
show_activities();
break;
case show_box_code:
- /* Show the current contents of a box */
+ /*tex Show the current contents of a box. */
scan_register_num();
begin_diagnostic();
tprint_nl("> \\box");
@@ -3422,7 +3946,7 @@ void show_whatever(void)
show_box(box(cur_val));
break;
case show_code:
- /* Show the current meaning of a token, then |goto common_ending| */
+ /*tex Show the current meaning of a token, then |goto common_ending|. */
get_token();
if (interaction == error_stop_mode)
wake_up_terminal();
@@ -3434,7 +3958,7 @@ void show_whatever(void)
print_meaning();
goto COMMON_ENDING;
break;
- /* Cases for |show_whatever| */
+ /*tex Cases for |show_whatever| */
case show_groups:
begin_diagnostic();
show_save_groups();
@@ -3474,8 +3998,10 @@ void show_whatever(void)
}
break;
default:
- /* Show the current value of some parameter or register,
- then |goto common_ending| */
+ /*tex
+ Show the current value of some parameter or register, then |goto
+ common_ending|.
+ */
p = the_toks();
if (interaction == error_stop_mode)
wake_up_terminal();
@@ -3485,7 +4011,7 @@ void show_whatever(void)
goto COMMON_ENDING;
break;
}
- /* Complete a potentially long \.{\\show} command */
+ /*tex Complete a potentially long \.{\\show} command: */
end_diagnostic(true);
print_err("OK");
if (selector == term_and_log) {
@@ -3500,32 +4026,40 @@ void show_whatever(void)
help0();
decr(error_count);
} else if (tracing_online_par > 0) {
- help3("This isn't an error message; I'm just \\showing something.",
- "Type `I\\show...' to show more (e.g., \\show\\cs,",
- "\\showthe\\count10, \\showbox255, \\showlists).");
+ help3(
+ "This isn't an error message; I'm just \\showing something.",
+ "Type `I\\show...' to show more (e.g., \\show\\cs,",
+ "\\showthe\\count10, \\showbox255, \\showlists)."
+ );
} else {
- help5("This isn't an error message; I'm just \\showing something.",
- "Type `I\\show...' to show more (e.g., \\show\\cs,",
- "\\showthe\\count10, \\showbox255, \\showlists).",
- "And type `I\\tracingonline=1\\show...' to show boxes and",
- "lists on your terminal as well as in the transcript file.");
+ help5(
+ "This isn't an error message; I'm just \\showing something.",
+ "Type `I\\show...' to show more (e.g., \\show\\cs,",
+ "\\showthe\\count10, \\showbox255, \\showlists).",
+ "And type `I\\tracingonline=1\\show...' to show boxes and",
+ "lists on your terminal as well as in the transcript file."
+ );
}
error();
}
-@ @c
+/*tex
+ This procedure gets things started properly:
+*/
+
void initialize(void)
-{ /* this procedure gets things started properly */
- int k; /* index into |mem|, |eqtb|, etc. */
- /* Initialize whatever \TeX\ might access */
- /* Set initial values of key variables */
+{
+ int k; /* index into |mem|, |eqtb|, etc. */
+ /*tex
+ Initialize whatever \TeX\ might access and set initial values of key
+ variables
+ */
initialize_errors();
initialize_arithmetic();
max_used_attr = -1;
attr_list_cache = cache_disabled;
initialize_nesting();
-
- /* Start a new current page */
+ /*tex Start a new current page: */
page_contents = empty;
page_tail = page_head;
#if 0
@@ -3539,7 +4073,7 @@ void initialize(void)
page_max_depth = 0;
initialize_equivalents();
- no_new_control_sequence = true; /* new identifiers are usually forbidden */
+ no_new_control_sequence = true; /* new identifiers are usually forbidden */
init_primitives();
mag_set = 0;
@@ -3559,11 +4093,10 @@ void initialize(void)
stop_at_space = true;
if (ini_version) {
- /* Initialize table entries (done by \.{INITEX} only) */
-
+ /*tex Initialize table entries (done by \.{INITEX} only). */
init_node_mem(500);
initialize_tokens();
- /* Initialize the special list heads and constant nodes */
+ /*tex Initialize the special list heads and constant nodes. */
initialize_alignments();
initialize_buildpage();
@@ -3629,7 +4162,9 @@ void initialize(void)
math_pre_display_gap_factor_par = 2000;
pre_bin_op_penalty_par = inf_penalty;
math_script_box_mode_par = 1;
+ math_script_char_mode_par = 1;
pre_rel_penalty_par = inf_penalty;
+ compound_hyphen_mode_par = 1;
escape_char_par = '\\';
end_line_char_par = carriage_return;
set_del_code('.', 0, 0, 0, 0, level_one); /* this null delimiter is used in error recovery */
@@ -3642,7 +4177,7 @@ void initialize(void)
page_right_offset_par = one_inch;
page_bottom_offset_par = one_inch;
ini_init_primitives();
- hash_used = frozen_control_sequence; /* nothing is used */
+ hash_used = frozen_control_sequence;
hash_high = 0;
cs_count = 0;
set_eq_type(frozen_dont_expand, dont_expand_cmd);
@@ -3655,16 +4190,16 @@ void initialize(void)
font_bytes = 0;
px_dimen_par = one_bp;
math_eqno_gap_step_par = 1000 ;
+ math_flatten_mode_par = 1; /* ord */
cs_text(frozen_protection) = maketexstring("inaccessible");
format_ident = maketexstring(" (INITEX)");
cs_text(end_write) = maketexstring("endwrite");
set_eq_level(end_write, level_one);
set_eq_type(end_write, outer_call_cmd);
set_equiv(end_write, null);
- /* bah */
+ /*tex Bah, this is a bad place do do this. */
set_pdf_major_version(1);
set_pdf_minor_version(0);
}
synctexoffset = int_base + synctex_code;
-
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/mathcodes.w b/Build/source/texk/web2c/luatexdir/tex/mathcodes.c
index a0a357e5319..42e8b0b15b9 100644
--- a/Build/source/texk/web2c/luatexdir/tex/mathcodes.w
+++ b/Build/source/texk/web2c/luatexdir/tex/mathcodes.c
@@ -1,81 +1,88 @@
-% mathnodes.w
-%
-% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
-% Copyright 2012 Khaled Hosny <khaledhosny@@eglug.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
+/*
+
+mathnodes.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/>.
+
+*/
#include "ptexlib.h"
-@ math codes
-@c
+/*tex
+
+We support tre traditional math codes as well as larger ones suitable for
+\UNICODE\ input and fonts.
+
+*/
+
static sa_tree mathcode_head = NULL;
-/* the 0xFFFFFFFF is a flag value */
+/*tex the |0xFFFFFFFF| is a flag value. */
#define MATHCODESTACK 8
#define MATHCODEDEFAULT 0xFFFFFFFF
#define MATHCODEACTIVE 0xFFFFFFFE
-@ delcodes
-@c
+/*tex
+
+Delcodes are also went larger.
+
+*/
+
static sa_tree delcode_head = NULL;
#define DELCODESTACK 4
#define DELCODEDEFAULT 0xFFFFFFFF
-@ some helpers for mathcode printing
+/*tex
+
+We now get lots of helpers for definitions and printing. The storage model
+that we use is different because we can hav emany more so we need to be
+sparse. Therefore we use trees.
+
+*/
+
-@c
-#define print_hex_digit(A) do { \
- if ((A)>=10) print_char('A'+(A)-10); \
- else print_char('0'+(A)); \
+#define print_hex_digit(A) do { \
+ if ((A)>=10) print_char('A'+(A)-10); \
+ else print_char('0'+(A)); \
} while (0)
-#define two_hex(A) do { \
- print_hex_digit((A)/16); \
- print_hex_digit((A)%16); \
+#define two_hex(A) do { \
+ print_hex_digit((A)/16); \
+ print_hex_digit((A)%16); \
} while (0)
-#define four_hex(A) do { \
- two_hex((A)/256); \
- two_hex((A)%256); \
+#define four_hex(A) do { \
+ two_hex((A)/256); \
+ two_hex((A)%256); \
} while (0)
-#define six_hex(A) do { \
- two_hex((A)/65536); \
+#define six_hex(A) do { \
+ two_hex((A)/65536); \
two_hex(((A)%65536)/256); \
- two_hex((A)%256); \
+ two_hex((A)%256); \
} while (0)
-/*
- At some point we will drop the mathchardef 8 bit storage (c_mathoption_umathcode_meaning_code => 1)
- and then some of the conversion can go away. Like mathchar_from_integer: only wide characters are
- possible then.
-*/
-
-
-@ @c
mathcodeval mathchar_from_integer(int value, int extcode)
{
mathcodeval mval;
if (extcode == tex_mathcode) {
- /* printf("can't happen: tex_mathcode\n"); */
mval.class_value = (value / 0x1000);
mval.family_value = ((value % 0x1000) / 0x100);
mval.character_value = (value % 0x100);
@@ -88,12 +95,12 @@ mathcodeval mathchar_from_integer(int value, int extcode)
return mval;
}
-@ @c
void show_mathcode_value_old(int value)
{
print_char('"');
four_hex(value);
}
+
void show_mathcode_value(mathcodeval c)
{
print_char('"');
@@ -104,7 +111,6 @@ void show_mathcode_value(mathcodeval c)
six_hex(c.character_value);
}
-@ @c
static void show_mathcode(int n)
{
mathcodeval c = get_math_code(n);
@@ -114,7 +120,6 @@ static void show_mathcode(int n)
show_mathcode_value(c);
}
-@ @c
static void unsavemathcode(quarterword gl)
{
sa_stack_item st;
@@ -138,7 +143,6 @@ static void unsavemathcode(quarterword gl)
}
}
-@ @c
void set_math_code(int n, int mathclass, int mathfamily, int mathcharacter, quarterword level)
{
sa_tree_item v;
@@ -161,9 +165,6 @@ void set_math_code(int n, int mathclass, int mathfamily, int mathcharacter, quar
}
}
-@ @c
-/* we could use two structs ... tex and umath */
-
mathcodeval get_math_code(int n)
{
mathcodeval d;
@@ -189,14 +190,12 @@ mathcodeval get_math_code(int n)
return d;
}
-@ @c
int get_math_code_num(int n)
{
mathcodeval d = get_math_code(n);
return (d.class_value + (d.family_value * 8)) * (65536 * 32) + d.character_value;
}
-@ @c
static void initializemathcode(void)
{
sa_tree_item sa_value = { 0 };
@@ -214,7 +213,6 @@ static void undumpmathcode(void)
mathcode_head = undump_sa_tree("mathcodes");
}
-@ @c
static void show_delcode(int n)
{
delcodeval c;
@@ -232,7 +230,6 @@ static void show_delcode(int n)
}
}
-@ @c
static void unsavedelcode(quarterword gl)
{
sa_stack_item st;
@@ -256,7 +253,6 @@ static void unsavedelcode(quarterword gl)
}
}
-@ @c
void set_del_code(int n, int smathfamily, int smathcharacter, int lmathfamily, int lmathcharacter, quarterword gl)
{
sa_tree_item v;
@@ -266,7 +262,8 @@ void set_del_code(int n, int smathfamily, int smathcharacter, int lmathfamily, i
v.del_code_value.dummy_value = 0;
v.del_code_value.large_family_value = lmathfamily;
v.del_code_value.large_character_value = lmathcharacter;
- set_sa_item(delcode_head, n, v, gl); /* always global */
+ /*tex Always global! */
+ set_sa_item(delcode_head, n, v, gl);
if (tracing_assigns_par > 1) {
begin_diagnostic();
print_char('{');
@@ -278,7 +275,6 @@ void set_del_code(int n, int smathfamily, int smathcharacter, int lmathfamily, i
}
}
-@ @c
delcodeval get_del_code(int n)
{
delcodeval d;
@@ -299,9 +295,12 @@ delcodeval get_del_code(int n)
return d;
}
-@ this really only works for old-style delcodes!
+/*tex
+
+This really only works for old-style delcodes!
+
+*/
-@c
int get_del_code_num(int n)
{
delcodeval d = get_del_code(n);
@@ -313,7 +312,6 @@ int get_del_code_num(int n)
}
}
-@ @c
static void initializedelcode(void)
{
sa_tree_item sa_value = { 0 };
@@ -321,7 +319,6 @@ static void initializedelcode(void)
delcode_head = new_sa_tree(DELCODESTACK, 2, sa_value);
}
-@ @c
static void dumpdelcode(void)
{
dump_sa_tree(delcode_head,"delcodes");
@@ -332,28 +329,24 @@ static void undumpdelcode(void)
delcode_head = undump_sa_tree("delcodes");
}
-@ @c
void unsave_math_codes(quarterword grouplevel)
{
unsavemathcode(grouplevel);
unsavedelcode(grouplevel);
}
-@ @c
void initialize_math_codes(void)
{
initializemathcode();
initializedelcode();
}
-@ @c
void free_math_codes(void)
{
destroy_sa_tree(mathcode_head);
destroy_sa_tree(delcode_head);
}
-@ @c
void dump_math_codes(void)
{
dumpmathcode();
diff --git a/Build/source/texk/web2c/luatexdir/tex/memoryword.c b/Build/source/texk/web2c/luatexdir/tex/memoryword.c
new file mode 100644
index 00000000000..7bf758dd0d4
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/memoryword.c
@@ -0,0 +1,29 @@
+/*
+memoryword.w
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+The debug code is no longer present!
+
+*/
diff --git a/Build/source/texk/web2c/luatexdir/tex/memoryword.w b/Build/source/texk/web2c/luatexdir/tex/memoryword.w
deleted file mode 100644
index b596abb37ec..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/memoryword.w
+++ /dev/null
@@ -1,55 +0,0 @@
-% memoryword.w
-%
-% Copyright 2009-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"
-
-@ When debugging, we may want to print a |memory_word| without knowing
-what type it is; so we print it in all modes.
-
-@c
-#ifdef DEBUG
-void print_word(memory_word w)
-{
- /* prints |w| in all ways */
- print_int(w.cint);
- print_char(' ');
- print_scaled(w.cint);
- print_char(' ');
- print_scaled(round(unity * float_cast(w.gr)));
- print_ln();
- print_int(w.hh.lhfield);
- print_char('=');
- print_int(w.hh.b0);
- print_char(':');
- print_int(w.hh.b1);
- print_char(';');
- print_int(w.hh.rh);
- print_char(' ');
- print_int(w.qqqq.b0);
- print_char(':');
- print_int(w.qqqq.b1);
- print_char(':');
- print_int(w.qqqq.b2);
- print_char(':');
- print_int(w.qqqq.b3);
-}
-#endif
diff --git a/Build/source/texk/web2c/luatexdir/tex/mlist.w b/Build/source/texk/web2c/luatexdir/tex/mlist.c
index 291ce8c4868..8f6d71eb294 100644
--- a/Build/source/texk/web2c/luatexdir/tex/mlist.w
+++ b/Build/source/texk/web2c/luatexdir/tex/mlist.c
@@ -1,71 +1,72 @@
-% mlist.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/>.
-
-% (HH / 0.82+):
-
-@ In traditional \TeX\ the italic correction is added to the width of the glyph. This
-is part of the engine design and related font design. In opentype math this is
-different. There the italic correction had more explicit usage. The 1.7 spec
-says:
-
-italic correction:
-
- When a run of slanted characters is followed by a straight character (such as
- an operator or a delimiter), the italics correction of the last glyph is added
- to its advance width.
-
- When positioning limits on an N-ary operator (e.g., integral sign), the horizontal
- position of the upper limit is moved to the right by ½ of the italics correction,
- while the position of the lower limit is moved to the left by the same distance.
-
- When positioning superscripts and subscripts, their default horizontal positions are
- also different by the amount of the italics correction of the preceding glyph.
-
-math kerning:
-
- Set the default horizontal position for the superscript as shifted relative to the
- position of the subscript by the italics correction of the base glyph.
-
-Before this was specified we had to gamble a bit and assume that cambria was the font
-benchmark and trust our eyes (and msword) for the logic. I must admit that I have been
-fighting these italics in fonts (and the heuristics that Lua\TeX\ provided) right from
-the start (e.g. using Lua based postprocessing) but by now we know more and have more
-fonts to test with. More fonts are handy because not all fonts are alike when it comes
-to italics. Axis are another area of concern, as it looks like opentype math fonts often
-already apply that shift.
-
-@ @c
+/*
+
+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/>.
+
+*/
+
+/*tex
+
+ In traditional \TeX\ the italic correction is added to the width of the
+ glyph. This is part of the engine design and related font design. In opentype
+ math this is different. There the italic correction had more explicit usage.
+ The 1.7 spec says:
+
+ \startitemize
+
+ \startitem
+ {\em italic correction:} When a run of slanted characters is followed by
+ a straight character (such as an operator or a delimiter), the italics
+ correction of the last glyph is added to its advance width.
+
+ When positioning limits on an N-ary operator (e.g., integral sign), the
+ horizontal position of the upper limit is moved to the right by ½ of the
+ italics correction, while the position of the lower limit is moved to the
+ left by the same distance.
+
+ When positioning superscripts and subscripts, their default horizontal
+ positions are also different by the amount of the italics correction of
+ the preceding glyph.
+ \stopitem
+
+ \startitem
+ {\em math kerning:} Set the default horizontal position for the
+ superscript as shifted relative to the position of the subscript by the
+ italics correction of the base glyph.
+ \stopitem
+
+ \stopitemize
+
+ Before this was specified we had to gamble a bit and assume that cambria was
+ the font benchmark and trust our eyes (and msword) for the logic. I must
+ admit that I have been fighting these italics in fonts (and the heuristics
+ that Lua\TeX\ provided) right from the start (e.g. using Lua based
+ postprocessing) but by now we know more and have more fonts to test with.
+ More fonts are handy because not all fonts are alike when it comes to
+ italics. Axis are another area of concern, as it looks like opentype math
+ fonts often already apply that shift.
+
+*/
+
#define is_new_mathfont(A) ((font_math_params(A) >0) && (math_old_par == 0))
#define is_old_mathfont(A,B) ((font_math_params(A)==0) && (font_params(A)>=(B)))
#define do_new_math(A) ((font_math_params(A) >0) && (font_oldmath(A) == 0) && (math_old_par == 0))
-@
-\def\LuaTeX{Lua\TeX}
-
-@ @c
-
#include "ptexlib.h"
#include "lua/luatex-api.h"
-@ @c
-#define nDEBUG
-
#define reset_attributes(p,newatt) do { \
delete_attribute_ref(node_attr(p)); \
node_attr(p) = newatt; \
@@ -97,83 +98,160 @@ already apply that shift.
#define font_MATH_par(a,b) \
(font_math_params(a)>=b ? font_math_param(a,b) : undefined_math_parameter)
-@ here are the math parameters that are font-dependant
+/*tex
+
+ Here are the math parameters that are font-dependant.
-@ Before an mlist is converted to an hlist, \TeX\ makes sure that
-the fonts in family~2 have enough parameters to be math-symbol
-fonts, and that the fonts in family~3 have enough parameters to be
-math-extension fonts. The math-symbol parameters are referred to by using the
-following macros, which take a size code as their parameter; for example,
-|num1(cur_size)| gives the value of the |num1| parameter for the current size.
-@^parameters for symbols@>
-@^font parameters@>
+ Before an mlist is converted to an hlist, \TeX\ makes sure that the fonts in
+ family~2 have enough parameters to be math-symbol fonts, and that the fonts
+ in family~3 have enough parameters to be math-extension fonts. The
+ math-symbol parameters are referred to by using the following macros, which
+ take a size code as their parameter; for example, |num1(cur_size)| gives the
+ value of the |num1| parameter for the current size.
+
+*/
-@c
#define total_mathsy_params 22
#define total_mathex_params 13
#define mathsy(A,B) font_param(fam_fnt(2,A),B)
-#define math_x_height(A) mathsy(A,5) /* height of `\.x' */
-#define math_quad(A) mathsy(A,6) /* \.{18mu} */
-#define num1(A) mathsy(A,8) /* numerator shift-up in display styles */
-#define num2(A) mathsy(A,9) /* numerator shift-up in non-display, non-\.{\\atop} */
-#define num3(A) mathsy(A,10) /* numerator shift-up in non-display \.{\\atop} */
-#define denom1(A) mathsy(A,11) /* denominator shift-down in display styles */
-#define denom2(A) mathsy(A,12) /* denominator shift-down in non-display styles */
-#define sup1(A) mathsy(A,13) /* superscript shift-up in uncramped display style */
-#define sup2(A) mathsy(A,14) /* superscript shift-up in uncramped non-display */
-#define sup3(A) mathsy(A,15) /* superscript shift-up in cramped styles */
-#define sub1(A) mathsy(A,16) /* subscript shift-down if superscript is absent */
-#define sub2(A) mathsy(A,17) /* subscript shift-down if superscript is present */
-#define sup_drop(A) mathsy(A,18) /* superscript baseline below top of large box */
-#define sub_drop(A) mathsy(A,19) /* subscript baseline below bottom of large box */
-#define delim1(A) mathsy(A,20) /* size of \.{\\atopwithdelims} delimiters in display styles */
-#define delim2(A) mathsy(A,21) /* size of \.{\\atopwithdelims} delimiters in non-displays */
-#define axis_height(A) mathsy(A,22) /* height of fraction lines above the baseline */
-
-@ The math-extension parameters have similar macros, but the size code is
-omitted (since it is always |cur_size| when we refer to such parameters).
-@^parameters for symbols@>
-@^font parameters@>
-
-@c
+/*tex height of `\.x' */
+
+#define math_x_height(A) mathsy(A,5)
+
+/*tex \.{18mu} */
+
+#define math_quad(A) mathsy(A,6)
+
+/*tex numerator shift-up in display styles */
+
+#define num1(A) mathsy(A,8)
+
+/*tex numerator shift-up in non-display, non-\.{\\atop} */
+
+#define num2(A) mathsy(A,9)
+
+/*tex numerator shift-up in non-display \.{\\atop} */
+
+#define num3(A) mathsy(A,10)
+
+/*tex denominator shift-down in display styles */
+
+#define denom1(A) mathsy(A,11)
+
+/*tex denominator shift-down in non-display styles */
+
+#define denom2(A) mathsy(A,12)
+
+/*tex superscript shift-up in uncramped display style */
+
+#define sup1(A) mathsy(A,13)
+
+/*tex superscript shift-up in uncramped non-display */
+
+#define sup2(A) mathsy(A,14)
+
+/*tex superscript shift-up in cramped styles */
+
+#define sup3(A) mathsy(A,15)
+
+/*tex subscript shift-down if superscript is absent */
+
+#define sub1(A) mathsy(A,16)
+
+/*tex subscript shift-down if superscript is present */
+
+#define sub2(A) mathsy(A,17)
+
+/*tex superscript baseline below top of large box */
+
+#define sup_drop(A) mathsy(A,18)
+
+/*tex subscript baseline below bottom of large box */
+
+#define sub_drop(A) mathsy(A,19)
+
+/*tex size of \.{\\atopwithdelims} delimiters in display styles */
+
+#define delim1(A) mathsy(A,20)
+
+/*tex size of \.{\\atopwithdelims} delimiters in non-displays */
+
+#define delim2(A) mathsy(A,21)
+
+/*tex height of fraction lines above the baseline */
+
+#define axis_height(A) mathsy(A,22)
+
+/*tex
+
+ The math-extension parameters have similar macros, but the size code is
+ omitted (since it is always |cur_size| when we refer to such parameters).
+
+*/
+
#define mathex(A,B) font_param(fam_fnt(3,A),B)
-#define default_rule_thickness(A) mathex(A,8) /* thickness of \.{\\over} bars */
-#define big_op_spacing1(A) mathex(A,9) /* minimum clearance above a displayed op */
-#define big_op_spacing2(A) mathex(A,10) /* minimum clearance below a displayed op */
-#define big_op_spacing3(A) mathex(A,11) /* minimum baselineskip above displayed op */
-#define big_op_spacing4(A) mathex(A,12) /* minimum baselineskip below displayed op */
-#define big_op_spacing5(A) mathex(A,13) /* padding above and below displayed limits */
-@ I (TH) made a bunch of extensions cf. the MATH table in OpenType, but some of
-the MathConstants values have no matching usage in \LuaTeX\ right now.
+/*tex thickness of \.{\\over} bars */
+
+#define default_rule_thickness(A) mathex(A,8)
+
+/*tex minimum clearance above a displayed op */
+
+#define big_op_spacing1(A) mathex(A,9)
+
+/*tex minimum clearance below a displayed op */
+
+#define big_op_spacing2(A) mathex(A,10)
+
+/*tex minimum baselineskip above displayed op */
+
+#define big_op_spacing3(A) mathex(A,11)
+
+/*tex minimum baselineskip below displayed op */
-ScriptPercentScaleDown,
-ScriptScriptPercentScaleDown:
- These should be handled by the macro package, on the engine
- side there are three separate fonts
+#define big_op_spacing4(A) mathex(A,12)
-DelimitedSubFormulaMinHeight:
- This is perhaps related to word's natural math input? I have
- no idea what to do about it
+/*tex padding above and below displayed limits */
-MathLeading:
- LuaTeX does not currently handle multi-line displays, and
- the parameter does not seem to make much sense elsewhere
+#define big_op_spacing5(A) mathex(A,13)
-FlattenedAccentBaseHeight:
- This is based on the 'flac' GSUB feature. It would not be hard
- to support that, but proper math accent placements cf. MATH
- needs support for MathTopAccentAttachment table to be
- implemented first
+/*tex
-Also still TODO for OpenType Math:
- * prescripts
+ \LUATEX makes a bunch of extensions cf. the |MATH| table in \OPENTYPE, but
+ some of the |MathConstants| values have no matching usage in \LUATEX\ right
+ now.
-@ this is not really a math parameter at all
+ \startitemize
+
+ \startitem
+ |ScriptPercentScaleDown| |ScriptScriptPercentScaleDown|: These should
+ be handled by the macro package, on the engine side there are three
+ separate fonts.
+ \stopitem
+
+ \startitem
+ |DelimitedSubFormulaMinHeight|: This is perhaps related to word's
+ natural math input? We have no idea what to do about it.
+ \stopitem
+
+ \startitem
+ |MathLeading|: \LUATEX does not currently handle multi-line displays,
+ and the parameter does not seem to make much sense elsewhere.
+ \stopitem
+
+ \startitem
+ |FlattenedAccentBaseHeight|: This is based on the |flac| |GSUB|
+ feature. It would not be hard to support that, but proper math accent
+ placements cf.\ |MATH| needs support for |MathTopAccentAttachment|
+ table to be implemented first.
+ \stopitem
+
+ \stopitemize
+
+*/
-@c
static void math_param_error(const char *param, int style)
{
char s[256];
@@ -184,16 +262,11 @@ static void math_param_error(const char *param, int style)
"the parameter mentioned earlier.",
NULL
};
- snprintf(s, 256, "Math error: parameter \\Umath%s\\%sstyle is not set",
- param, math_style_names[style]);
+ snprintf(s, 256, "Math error: parameter \\Umath%s\\%sstyle is not set", param, math_style_names[style]);
tex_error(s, hlp);
-#if 0
- flush_math();
-#endif
return;
}
-@ @c
static scaled accent_base_height(int f)
{
scaled a;
@@ -207,11 +280,14 @@ static scaled accent_base_height(int f)
return a;
}
-@ The non-staticness of this function is for the benefit of |texmath.w|. Watch out,
-this one uses the style! The style and size numbers don't match because we have
-cramped styles.
+/*tex
+
+ The non-staticness of this function is for the benefit of |texmath.w|.
+ Watch out, this one uses the style! The style and size numbers don't
+ match because we have cramped styles.
+
+*/
-@c
scaled get_math_quad_style(int var)
{
scaled a = get_math_param(math_param_quad, var);
@@ -223,10 +299,13 @@ scaled get_math_quad_style(int var)
}
}
-@ For this reason the next one is different because it is called with a size
-specifier instead of a style specifier.
+/*tex
+
+ For this reason the next one is different because it is called with a size
+ specifier instead of a style specifier.
+
+*/
-@c
static scaled math_axis_size(int b)
{
scaled a;
@@ -246,7 +325,6 @@ static scaled math_axis_size(int b)
}
}
-@ @c
scaled get_math_quad_size(int b)
{
int var;
@@ -259,26 +337,32 @@ scaled get_math_quad_size(int b)
return get_math_param(math_param_quad, var);
}
-@ @c
static scaled minimum_operator_size(int var)
{
scaled a = get_math_param(math_param_operator_size, var);
return a;
}
-@ Old-style fonts do not define the |radical_rule|. This allows |make_radical| to select
-the backward compatibility code, and it means that we can't raise an error here.
+/*tex
+
+ Old-style fonts do not define the |radical_rule|. This allows |make_radical|
+ to select the backward compatibility code, and it means that we can't raise
+ an error here.
+
+*/
-@c
static scaled radical_rule_par(int var)
{
scaled a = get_math_param(math_param_radical_rule, var);
return a;
}
-@ now follow all the trivial math parameters
+/*tex
+
+ Now follow all the trivial math parameters.
+
+*/
-@c
#define get_math_param_or_error(a,b) do_get_math_param_or_error(a, math_param_##b, #b)
#define get_math_param_or_zero(a,b) do_get_math_param_or_zero(a, math_param_##b, #b)
@@ -301,9 +385,12 @@ static scaled do_get_math_param_or_zero(int var, int param, const char *name)
return a;
}
-@ A variant on a suggestion on the list based on analysis by UV.
+/*tex
+
+ A variant on a suggestion on the list based on analysis by UV.
+
+*/
-@c
static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
scaled delta, delta1, delta2;
if (axis) {
@@ -313,7 +400,7 @@ static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
}
delta1 = max_h + max_d - delta2;
if (delta2 > delta1) {
- /* |delta1| is max distance from axis */
+ /*tex |delta1| is max distance from axis */
delta1 = delta2;
}
delta = (delta1 / 500) * delimiter_factor_par;
@@ -325,7 +412,6 @@ static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
}
}
-@ @c
#define radical_degree_before(a) get_math_param_or_error(a, radical_degree_before)
#define radical_degree_after(a) get_math_param_or_error(a, radical_degree_after)
#define radical_degree_raise(a) get_math_param_or_error(a, radical_degree_raise)
@@ -359,9 +445,7 @@ static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
#define fraction_num_up(a) get_math_param_or_error(a, fraction_num_up)
#define fraction_denom_down(a) get_math_param_or_error(a, fraction_denom_down)
#define fraction_del_size_new(a) get_math_param_or_error(a, fraction_del_size)
-/*
-#define fraction_del_size_old(a) get_math_param(a, math_param_fraction_del_size)
-*/
+/* fraction_del_size_old(a) get_math_param (a, math_param_fraction_del_size) */
#define fraction_del_size_old(a) get_math_param_or_error(a, fraction_del_size)
#define skewed_fraction_hgap(a) get_math_param_or_error(a, skewed_fraction_hgap)
@@ -390,11 +474,11 @@ static scaled get_delimiter_height(scaled max_d, scaled max_h, boolean axis) {
#define space_after_script(a) get_math_param_or_error(a, space_after_script)
-@ @c
void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
{
+ if (is_new_mathfont(f)) {
- if (is_new_mathfont(f)) { /* fix all known parameters */
+ /*tex Fix all known parameters. */
DEFINE_MATH_PARAMETERS(math_param_quad, size_id,
font_size(f), lvl);
@@ -632,7 +716,7 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
} else if (fam_id == 2 && is_old_mathfont(f, total_mathsy_params)) {
- /* fix old-style |sy| parameters */
+ /*tex Fix old-style |sy| parameters. */
DEFINE_MATH_PARAMETERS(math_param_quad, size_id,
math_quad(size_id), lvl);
@@ -746,9 +830,11 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
DEFINE_DMATH_PARAMETERS(math_param_sup_sub_bottom_max, size_id,
(abs(math_x_height(size_id) * 4) / 5), lvl);
- /*
- The display-size |radical_vgap| is done twice because it needs
- values from both the sy and the ex font.
+ /*tex
+
+ The display-size |radical_vgap| is done twice because it needs values
+ from both the sy and the ex font.
+
*/
DEFINE_DMATH_PARAMETERS(math_param_radical_vgap, size_id,
@@ -768,7 +854,7 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
} else if (fam_id == 3 && is_old_mathfont(f, total_mathex_params)) {
- /* fix old-style |ex| parameters */
+ /*tex Fix old-style |ex| parameters. */
DEFINE_MATH_PARAMETERS(math_param_overbar_kern, size_id,
default_rule_thickness(size_id), lvl);
@@ -853,9 +939,12 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
DEFINE_DMATH_PARAMETERS(math_param_subsup_vgap, size_id,
4 * default_rule_thickness(size_id), lvl);
- /*
- All of the |space_after_script|s are done in |finalize_math_parameters|
- because the \.{\\scriptspace} may have been altered by the user
+ /*tex
+
+ All of the |space_after_script|s are done in
+ |finalize_math_parameters| because the \.{\\scriptspace} may have
+ been altered by the user.
+
*/
DEFINE_MATH_PARAMETERS(math_param_connector_overlap_min, size_id,
@@ -880,9 +969,11 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
DEFINE_DMATH_PARAMETERS(math_param_over_delimiter_bgap, size_id,
big_op_spacing3(size_id), lvl);
- /*
- The display-size |radical_vgap| is done twice because it needs
- values from both the sy and the ex font.
+ /*tex
+
+ The display-size |radical_vgap| is done twice because it needs values
+ from both the sy and the ex font.
+
*/
DEFINE_DMATH_PARAMETERS(math_param_radical_vgap, size_id,
@@ -891,10 +982,13 @@ void fixup_math_parameters(int fam_id, int size_id, int f, int lvl)
}
}
-@ This needs to be called just at the start of |mlist_to_hlist|, for
-backward compatibility with \.{\\scriptspace}.
+/*tex
+
+ This needs to be called just at the start of |mlist_to_hlist|, for backward
+ compatibility with \.{\\scriptspace}.
+
+*/
-@c
static void finalize_math_parameters(void)
{
int saved_trace = tracing_assigns_par;
@@ -920,16 +1014,19 @@ static void finalize_math_parameters(void)
tracing_assigns_par = saved_trace;
}
-@ In order to convert mlists to hlists, i.e., noads to nodes, we need several
-subroutines that are conveniently dealt with now.
+/*tex
+
+ In order to convert mlists to hlists, i.e., noads to nodes, we need several
+ subroutines that are conveniently dealt with now.
+
+ Let us first introduce the macros that make it easy to get at the parameters
+ and other font information. A size code, which is a multiple of 256, is added
+ to a family number to get an index into the table of internal font numbers
+ for each combination of family and size. (Be alert: Size codes get larger as
+ the type gets smaller.)
-Let us first introduce the macros that make it easy to get at the parameters and
-other font information. A size code, which is a multiple of 256, is added to a
-family number to get an index into the table of internal font numbers
-for each combination of family and size. (Be alert: Size codes get
-larger as the type gets smaller.)
+*/
-@c
static const char *math_size_string(int s)
{
if (s == text_size)
@@ -940,10 +1037,13 @@ static const char *math_size_string(int s)
return "scriptscriptfont";
}
-@ When the style changes, the following piece of program computes associated
-information:
+/*tex
+
+ When the style changes, the following piece of program computes associated
+ information:
+
+*/
-@c
#define setup_cur_size(a) do { \
if (a==script_style || a==cramped_script_style) \
cur_size = script_size; \
@@ -954,8 +1054,12 @@ information:
} while (0)
-@ a simple routine that creates a flat copy of a nucleus
-@c
+/*tex
+
+ A simple routine that creates a flat copy of a nucleus.
+
+*/
+
static pointer math_clone(pointer q)
{
pointer x;
@@ -972,14 +1076,17 @@ static pointer math_clone(pointer q)
return x;
}
-@ Here is a function that returns a pointer to a rule node having a given
- thickness |t|. The rule will extend horizontally to the boundary of the vlist
- that eventually contains it.
+/*tex
+
+ Here is a function that returns a pointer to a rule node having a given
+ thickness |t|. The rule will extend horizontally to the boundary of the vlist
+ that eventually contains it.
+
+*/
-@c
static pointer do_fraction_rule(scaled t, pointer att, halfword some_rule, halfword cur_size, halfword cur_fam)
{
- pointer p; /* the new node */
+ pointer p;
if (math_rules_mode_par) {
p = new_rule(some_rule);
rule_math_size(p) = cur_size;
@@ -994,14 +1101,17 @@ static pointer do_fraction_rule(scaled t, pointer att, halfword some_rule, halfw
return p;
}
-@ The |overbar| function returns a pointer to a vlist box that consists of
- a given box |b|, above which has been placed a kern of height |k| under a
- fraction rule of thickness |t| under additional space of height |ht|.
+/*tex
+
+ The |overbar| function returns a pointer to a vlist box that consists of a
+ given box |b|, above which has been placed a kern of height |k| under a
+ fraction rule of thickness |t| under additional space of height |ht|.
+
+*/
-@c
static pointer overbar(pointer b, scaled k, scaled t, scaled ht, pointer att, halfword index, halfword cur_size, halfword cur_fam)
{
- pointer p, q; /* nodes being constructed */
+ pointer p, q;
p = new_kern(k);
reset_attributes(p, att);
couple_nodes(p,b);
@@ -1015,16 +1125,20 @@ static pointer overbar(pointer b, scaled k, scaled t, scaled ht, pointer att, ha
return q;
}
-@ Here is a subroutine that creates a new box, whose list contains a
-single character, and whose width includes the italic correction for
-that character. The height or depth of the box will be negative, if
-the height or depth of the character is negative; thus, this routine
-may deliver a slightly different result than |hpack| would produce.
+/*tex
+
+ Here is a subroutine that creates a new box, whose list contains a single
+ character, and whose width includes the italic correction for that character.
+ The height or depth of the box will be negative, if the height or depth of
+ the character is negative; thus, this routine may deliver a slightly
+ different result than |hpack| would produce.
+
+*/
-@c
static pointer char_box(internal_font_number f, int c, pointer bb)
{
- pointer b, p; /* the new box and its character node */
+ /*tex The new box and its character node. */
+ pointer b, p;
b = new_null_box();
if (do_new_math(f))
width(b) = char_width(f, c);
@@ -1039,24 +1153,31 @@ static pointer char_box(internal_font_number f, int c, pointer bb)
return b;
}
-@ Another handy subroutine computes the height plus depth of
- a given character:
+/*tex
+
+ Another handy subroutine computes the height plus depth of a given character:
+
+*/
-@c
static scaled height_plus_depth(internal_font_number f, int c)
{
return (char_height(f, c) + char_depth(f, c));
}
-@ When we build an extensible character, it's handy to have the
- following subroutine, which puts a given character on top
- of the characters already in box |b|:
+/*tex
+
+ When we build an extensible character, it's handy to have the following
+ subroutine, which puts a given character on top of the characters already in
+ box |b|:
+
+*/
-@c
static scaled stack_into_box(pointer b, internal_font_number f, int c)
{
- pointer p, q; /* new node placed into |b| */
- p = char_box(f, c, node_attr(b)); /* italic gets added to width */
+ /*tex New node placed into |b|: */
+ pointer p, q;
+ /*tex Italic gets added to width. */
+ p = char_box(f, c, node_attr(b));
if (type(b) == vlist_node) {
try_couple_nodes(p,list_ptr(b));
list_ptr(b) = p;
@@ -1085,7 +1206,9 @@ static void stack_glue_into_box(pointer b, scaled min, scaled max) {
halfword p = new_glue(zero_glue);
width(p) = min;
stretch(p) = max - min;
- reset_attributes(p, node_attr(b));
+ if (node_attr(b) != null) {
+ reset_attributes(p, node_attr(b));
+ }
if (type(b) == vlist_node) {
try_couple_nodes(p,list_ptr(b));
list_ptr(b) = p;
@@ -1094,59 +1217,96 @@ static void stack_glue_into_box(pointer b, scaled min, scaled max) {
if (q == null) {
list_ptr(b) = p;
} else {
- while (vlink(q) != null)
+ while (vlink(q) != null) {
q = vlink(q);
+ }
couple_nodes(q,p);
}
}
}
-@ \TeX's most important routine for dealing with formulas is called
- |mlist_to_hlist|. After a formula has been scanned and represented
- as an mlist, this routine converts it to an hlist that can be placed
- into a box or incorporated into the text of a paragraph. The
- explicit parameter |cur_mlist| points to the first node or noad in
- the given mlist (and it might be |null|); the parameter |penalties|
- is |true| if penalty nodes for potential line breaks are to be
- inserted into the resulting hlist, the parameter |cur_style| is a
- style code. After |mlist_to_hlist| has acted, |vlink(temp_head)|
- points to the translated hlist.
-
- Since mlists can be inside mlists, the procedure is recursive. And since this
- is not part of \TeX's inner loop, the program has been written in a manner
- that stresses compactness over efficiency.
-@^recursion@>
-
-@c
-int cur_size; /* size code corresponding to |cur_style| */
-
-@ @c
-static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, scaled v,
- pointer att, int cur_style, int boxtype)
+/*tex
+
+ \TeX's most important routine for dealing with formulas is called
+ |mlist_to_hlist|. After a formula has been scanned and represented as an
+ mlist, this routine converts it to an hlist that can be placed into a box or
+ incorporated into the text of a paragraph. The explicit parameter |cur_mlist|
+ points to the first node or noad in the given mlist (and it might be |null|);
+ the parameter |penalties| is |true| if penalty nodes for potential line
+ breaks are to be inserted into the resulting hlist, the parameter |cur_style|
+ is a style code. After |mlist_to_hlist| has acted, |vlink(temp_head)| points
+ to the translated hlist.
+
+ Since mlists can be inside mlists, the procedure is recursive. And since this
+ is not part of \TeX's inner loop, the program has been written in a manner
+ that stresses compactness over efficiency.
+
+*/
+
+/*tex Size code corresponding to |cur_style|: */
+
+int cur_size;
+
+static pointer get_delim_box(internal_font_number fnt, halfword chr, scaled v, scaled min_overlap, int horizontal, halfword att)
{
- pointer b; /* new box */
- scaled b_max; /* natural (maximum) size of the stack */
- scaled s_max; /* amount of possible shrink in the stack */
+ int callback_id = callback_defined(make_extensible_callback);
+ if (callback_id > 0) {
+ /*tex
+ This call is not optimized as it hardly makes sense to use it ... special
+ and a it of feature creep too.
+ */
+ halfword b = null;
+ run_callback(callback_id, "ddddbN->N",fnt,chr,v,min_overlap,horizontal,att,&b);
+ if (b == null) {
+ /*tex
+ We see this as a signal to do it the \TEX\ way.
+ */
+ } else if (type(b) == hlist_node || type(b) == vlist_node) {
+ return b;
+ } else {
+ formatted_error("fonts","invalid extensible character %i created for font %i, [h|v]list expected",chr,fnt);
+ }
+ }
+ return make_extensible(fnt, chr, v, min_overlap, horizontal, att);
+}
+
+pointer make_extensible(internal_font_number fnt, halfword chr, scaled v, scaled min_overlap, int horizontal, halfword att)
+{
+ /*tex new box */
+ pointer b;
+ /*tex natural (maximum) size of the stack */
+ scaled b_max;
+ /*tex amount of possible shrink in the stack */
+ scaled s_max;
extinfo *cur;
- scaled min_overlap, prev_overlap;
- int i; /* a temporary counter number of extensible pieces */
- int with_extenders; /* number of times to repeat each repeatable item in |ext| */
+ extinfo *ext;
+ scaled prev_overlap;
+ /*tex a temporary counter number of extensible pieces */
+ int i;
+ /*tex number of times to repeat each repeatable item in |ext| */
+ int with_extenders;
int num_extenders, num_normal;
scaled a, c, d;
-
- assert(ext != NULL);
b = new_null_box();
- type(b) = (quarterword) boxtype;
- reset_attributes(b, att);
- min_overlap = connector_overlap_min(cur_style);
- assert(min_overlap >= 0);
with_extenders = -1;
num_extenders = 0;
num_normal = 0;
-
+ if (min_overlap < 0) {
+ min_overlap = 0;
+ }
+ if (horizontal) {
+ type(b) = (quarterword) hlist_node;
+ ext = get_charinfo_hor_variants(char_info(fnt,chr));
+ } else {
+ type(b) = (quarterword) vlist_node;
+ ext = get_charinfo_vert_variants(char_info(fnt,chr));
+ }
+ if (att != null) {
+ reset_attributes(b,att);
+ }
cur = ext;
while (cur != NULL) {
- if (!char_exists(f, cur->glyph)) {
+ if (!char_exists(fnt, cur->glyph)) {
const char *hlp[] = {
"Each glyph part in an extensible item should exist in the font.",
"I will give up trying to find a suitable size for now. Fix your font!",
@@ -1160,7 +1320,7 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
num_extenders++;
else
num_normal++;
- /* no negative overlaps or advances are allowed */
+ /*tex No negative overlaps or advances are allowed. */
if (cur->start_overlap < 0 || cur->end_overlap < 0 || cur->advance < 0) {
const char *hlp[] = {
"All measurements in extensible items should be positive.",
@@ -1190,16 +1350,16 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
num_normal = 1;
num_extenders--;
}
- /*
+ /*tex
+
|ext| holds a linked list of numerous items that may or may not be
repeatable. For the total height, we have to figure out how many items
are needed to create a stack of at least |v|.
- The next |while| loop does that. It has two goals: it finds out
- the natural height |b_max| of the all the parts needed to reach
- at least |v|, and it sets |with_extenders| to the number of times
- each of the repeatable items in |ext| has to be repeated to reach
- that height.
+ The next |while| loop does that. It has two goals: it finds out the
+ natural height |b_max| of the all the parts needed to reach at least |v|,
+ and it sets |with_extenders| to the number of times each of the
+ repeatable items in |ext| has to be repeated to reach that height.
*/
cur = ext;
@@ -1217,12 +1377,15 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
c = prev_overlap;
a = cur->advance;
if (a == 0) {
- /* for tfm fonts */
- if (boxtype == vlist_node)
- a = height_plus_depth(f, cur->glyph);
- else
- a = char_width(f, cur->glyph);
- assert(a >= 0);
+ /*tex for tfm fonts */
+ if (horizontal) {
+ a = char_width(fnt, cur->glyph);
+ } else {
+ a = height_plus_depth(fnt, cur->glyph);
+ }
+ if (a < 0) {
+ formatted_error("fonts","bad extensible character %i in font %i",chr,fnt);
+ }
}
b_max += a - c;
prev_overlap = cur->end_overlap;
@@ -1236,12 +1399,15 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
c = prev_overlap;
a = cur->advance;
if (a == 0) {
- /* for tfm fonts */
- if (boxtype == vlist_node)
- a = height_plus_depth(f, cur->glyph);
- else
- a = char_width(f, cur->glyph);
- assert(a >= 0);
+ /*tex for tfm fonts */
+ if (horizontal) {
+ a = char_width(fnt, cur->glyph);
+ } else {
+ a = height_plus_depth(fnt, cur->glyph);
+ }
+ if (a < 0) {
+ formatted_error("fonts","bad extensible character %i in font %i",chr,fnt);
+ }
}
b_max += a - c;
prev_overlap = cur->end_overlap;
@@ -1250,10 +1416,11 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
}
}
}
+ /*tex
+
+ Assemble box using |with_extenders| copies of each extender, with
+ appropriate glue wherever an overlap occurs.
- /*
- assemble box using |with_extenders| copies of each extender, with
- appropriate glue wherever an overlap occurs
*/
prev_overlap = 0;
b_max = 0;
@@ -1271,7 +1438,7 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
s_max += (-c) - (-d);
b_max -= d;
}
- b_max += stack_into_box(b, f, cur->glyph);
+ b_max += stack_into_box(b, fnt, cur->glyph);
prev_overlap = cur->end_overlap;
i--;
} else {
@@ -1288,19 +1455,17 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
s_max += (-c) - (-d);
b_max -= d;
}
- b_max += stack_into_box(b, f, cur->glyph);
+ b_max += stack_into_box(b, fnt, cur->glyph);
prev_overlap = cur->end_overlap;
i--;
}
}
}
-
- /* set glue so as to stretch the connections if needed */
-
+ /*tex Set glue so as to stretch the connections if needed. */
d = 0;
if (v > b_max && s_max > 0) {
d = v-b_max;
- /* don't stretch more than |s_max| */
+ /*tex Don't stretch more than |s_max|. */
if (d > s_max)
d = s_max;
glue_order(b) = normal;
@@ -1308,32 +1473,33 @@ static pointer get_delim_box(pointer q, extinfo * ext, internal_font_number f, s
glue_set(b) = unfloat(d/(float) s_max);
b_max += d;
}
-
- if (boxtype == vlist_node) {
- height(b) = b_max;
- } else {
+ if (horizontal) {
width(b) = b_max;
+ } else {
+ height(b) = b_max;
}
-
return b;
}
-@ The |var_delimiter| function, which finds or constructs a sufficiently
- large delimiter, is the most interesting of the auxiliary functions that
- currently concern us. Given a pointer |d| to a delimiter field in some noad,
- together with a size code |s| and a vertical distance |v|, this function
- returns a pointer to a box that contains the smallest variant of |d| whose
- height plus depth is |v| or more. (And if no variant is large enough, it
- returns the largest available variant.) In particular, this routine will
- construct arbitrarily large delimiters from extensible components, if
- |d| leads to such characters.
-
- The value returned is a box whose |shift_amount| has been set so that
- the box is vertically centered with respect to the axis in the given size.
- If a built-up symbol is returned, the height of the box before shifting
- will be the height of its topmost component.
-
-@c
+/*tex
+
+ The |var_delimiter| function, which finds or constructs a sufficiently large
+ delimiter, is the most interesting of the auxiliary functions that currently
+ concern us. Given a pointer |d| to a delimiter field in some noad, together
+ with a size code |s| and a vertical distance |v|, this function returns a
+ pointer to a box that contains the smallest variant of |d| whose height plus
+ depth is |v| or more. (And if no variant is large enough, it returns the
+ largest available variant.) In particular, this routine will construct
+ arbitrarily large delimiters from extensible components, if |d| leads to such
+ characters.
+
+ The value returned is a box whose |shift_amount| has been set so that the box
+ is vertically centered with respect to the axis in the given size. If a
+ built-up symbol is returned, the height of the box before shifting will be
+ the height of its topmost component.
+
+*/
+
static void endless_loop_error(internal_font_number g, int y)
{
char s[256];
@@ -1343,23 +1509,31 @@ static void endless_loop_error(internal_font_number g, int y)
"I will jump out of the loop all by myself now. Fix your font!",
NULL
};
- snprintf(s, 256, "Math error: endless loop in charlist (U+%04x in %s)",
- (int) y, font_name(g));
+ snprintf(s, 256, "Math error: endless loop in charlist (U+%04x in %s)", (int) y, font_name(g));
tex_error(s, hlp);
}
static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat, int cur_style, boolean shift, boolean *stack, scaled *delta, int *same)
{
- pointer b; /* the box that will be constructed */
- internal_font_number f, g; /* best-so-far and tentative font codes */
- int c, i, x, y; /* best-so-far and tentative character codes */
- scaled u; /* height-plus-depth of a tentative character */
- scaled w = 0; /* largest height-plus-depth so far */
- int z; /* runs through font family members */
- boolean large_attempt = false; /* are we trying the ``large'' variant? */
- pointer att = null; /* to save the current attribute list */
+ /*tex the box that will be constructed */
+ pointer b;
+ /*tex best-so-far and tentative font codes */
+ internal_font_number f, g;
+ /*tex best-so-far and tentative character codes */
+ int c, i, x, y;
+ /*tex height-plus-depth of a tentative character */
+ scaled u;
+ /*tex largest height-plus-depth so far */
+ scaled w = 0;
+ /*tex runs through font family members */
+ int z;
+ /*tex are we trying the ``large'' variant? */
+ boolean large_attempt = false;
+ /*tex to save the current attribute list */
+ pointer att = null;
int emas = 0 ;
boolean do_parts = false;
+ boolean parts_done = false;
extinfo *ext;
f = null_font;
c = 0;
@@ -1373,10 +1547,12 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
same = 0;
}
while (true) {
- /*
- The search process is complicated slightly by the facts that some of the
- characters might not be present in some of the fonts, and they might not
- be probed in increasing order of height.
+ /*tex
+
+ The search process is complicated slightly by the facts that some of
+ the characters might not be present in some of the fonts, and they
+ might not be probed in increasing order of height.
+
*/
if ((z != 0) || (x != 0)) {
g = fam_fnt(z, s);
@@ -1403,7 +1579,6 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
goto FOUND;
}
if (i > 10000) {
- /* endless loop */
endless_loop_error(g, y);
goto FOUND;
}
@@ -1414,8 +1589,10 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
}
}
}
- if (large_attempt)
- goto FOUND; /* there were none large enough */
+ if (large_attempt) {
+ /*tex There were none large enough. */
+ goto FOUND;
+ }
large_attempt = true;
z = large_fam(d);
x = large_char(d);
@@ -1427,17 +1604,20 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
flush_node(d);
}
if (f != null_font) {
- /*
- When the following code is executed, |do_parts| will be true
- if a built-up symbol is supposed to be returned.
+ /*tex
+
+ When the following code is executed, |do_parts| will be true if a
+ built-up symbol is supposed to be returned.
+
*/
ext = NULL;
if ((do_parts) && ((!flat && (ext = get_charinfo_vert_variants(char_info(f,c))) != NULL)
|| ( flat && (ext = get_charinfo_hor_variants (char_info(f,c))) != NULL))) {
+ parts_done = true;
if (flat) {
- b = get_delim_box(d, ext, f, v, att, cur_style, hlist_node);
+ b = get_delim_box(f, c, v, connector_overlap_min(cur_style), 1, att);
} else {
- b = get_delim_box(d, ext, f, v, att, cur_style, vlist_node);
+ b = get_delim_box(f, c, v, connector_overlap_min(cur_style), 0, att);
}
if (delta != NULL) {
if (do_new_math(f)) {
@@ -1449,16 +1629,18 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
if (stack != NULL)
*stack = true ;
} else {
+ parts_done = false;
if (same != NULL && x == c) {
*same = emas;
}
b = char_box(f, c, att);
if (!do_new_math(f)) {
- /* italic gets added to width */
+ /*tex Italic gets added to width. */
width(b) += char_italic(f, c);
}
if (delta != NULL) {
- *delta = char_italic(f, c); /* was historically (f, x) */
+ /*tex This used to be (f, x). */
+ *delta = char_italic(f, c);
}
if (stack != NULL)
*stack = false ;
@@ -1469,7 +1651,7 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
if (flat) {
width(b) = 0;
} else {
- /* use this width if no delimiter was found */
+ /*tex Use this width if no delimiter was found. */
width(b) = null_delimiter_space_par;
}
if (delta != NULL) {
@@ -1479,38 +1661,54 @@ static pointer do_delimiter(pointer q, pointer d, int s, scaled v, boolean flat,
*stack = false ;
}
if (!flat) {
- if (emas == 0 || ! delimitermodenoshift) {
- /* vertical variant */
- shift_amount(b) = half(height(b) - depth(b));
- if (shift) {
- shift_amount(b) -= math_axis_size(s);
- }
+ /*tex when emas ~= 0 then we have a non scaled character */
+ if (emas != 0 && delimitermodesamenos) {
+ /*tex same character and no shift when same forced */
+ goto DONE;
+ }
+ if (! parts_done && delimitermodecharnos) {
+ /*tex same character and no shift when same forced */
+ goto DONE;
+ }
+ if (delimitermodenoshift) {
+ /*tex no shift forced */
+ goto DONE;
+ }
+ /*tex vertical variant */
+ shift_amount(b) = half(height(b) - depth(b));
+ if (shift) {
+ shift_amount(b) -= math_axis_size(s);
}
}
+ DONE:
delete_attribute_ref(att);
return b;
}
-@ The next subroutine is much simpler; it is used for numerators and
-denominators of fractions as well as for displayed operators and
-their limits above and below. It takes a given box~|b| and
-changes it so that the new box is centered in a box of width~|w|.
-The centering is done by putting \.{\\hss} glue at the left and right
-of the list inside |b|, then packaging the new box; thus, the
-actual box might not really be centered, if it already contains
-infinite glue.
+/*tex
+
+ The next subroutine is much simpler; it is used for numerators and
+ denominators of fractions as well as for displayed operators and their limits
+ above and below. It takes a given box~|b| and changes it so that the new box
+ is centered in a box of width~|w|. The centering is done by putting \.{\\hss}
+ glue at the left and right of the list inside |b|, then packaging the new
+ box; thus, the actual box might not really be centered, if it already
+ contains infinite glue.
+
+ The given box might contain a single character whose italic correction has
+ been added to the width of the box; in this case a compensating kern is
+ inserted.
-The given box might contain a single character whose italic correction
-has been added to the width of the box; in this case a compensating
-kern is inserted.
+*/
-@c
static pointer rebox(pointer b, scaled w)
{
- pointer p, q, r, att; /* temporary registers for list manipulation */
- internal_font_number f; /* font in a one-character box */
- scaled v; /* width of a character without italic correction */
-
+ /*tex temporary registers for list manipulation */
+ pointer p, q, r, att;
+ /*tex font in a one-character box */
+ internal_font_number f;
+ /*tex width of a character without italic correction */
+ scaled v;
if ((width(b) != w) && (list_ptr(b) != null)) {
if (type(b) == vlist_node) {
p = hpack(b, 0, additional, -1);
@@ -1549,23 +1747,30 @@ static pointer rebox(pointer b, scaled w)
}
}
-@ Here is a subroutine that creates a new glue specification from another
-one that is expressed in `\.{mu}', given the value of the math unit.
+/*tex
+
+ Here is a subroutine that creates a new glue specification from another one
+ that is expressed in `\.{mu}', given the value of the math unit.
+
+*/
-@c
#define mu_mult(A) mult_and_add(n,(A),xn_over_d((A),f,unity),max_dimen)
static pointer math_glue(pointer g, scaled m)
{
- int n = x_over_n(m, unity); /* integer part of |m| */
- scaled f = tex_remainder; /* fraction part of |m| */
- pointer p; /* the new glue specification */
+ /*tex integer part of |m| */
+ int n = x_over_n(m, unity);
+ /*tex fraction part of |m| */
+ scaled f = tex_remainder;
+ /*tex the new glue specification */
+ pointer p;
if (f < 0) {
decr(n);
f = f + unity;
}
p = new_node(glue_node, 0);
- width(p) = mu_mult(width(g)); /* convert \.{mu} to \.{pt} */
+ /* convert \.{mu} to \.{pt} */
+ width(p) = mu_mult(width(g));
stretch_order(p) = stretch_order(g);
if (stretch_order(p) == normal)
stretch(p) = mu_mult(stretch(g));
@@ -1581,13 +1786,16 @@ static pointer math_glue(pointer g, scaled m)
static void math_glue_to_glue(pointer p, scaled m)
{
- int n = x_over_n(m, unity); /* integer part of |m| */
- scaled f = tex_remainder; /* fraction part of |m| */
+ /*tex integer part of |m| */
+ int n = x_over_n(m, unity);
+ /*tex fraction part of |m| */
+ scaled f = tex_remainder;
if (f < 0) {
decr(n);
f = f + unity;
}
- width(p) = mu_mult(width(p)); /* convert \.{mu} to \.{pt} */
+ /* convert \.{mu} to \.{pt} */
+ width(p) = mu_mult(width(p));
if (stretch_order(p) == normal)
stretch(p) = mu_mult(stretch(p));
if (shrink_order(p) == normal)
@@ -1595,14 +1803,18 @@ static void math_glue_to_glue(pointer p, scaled m)
subtype(p) = normal;
}
-@ The |math_kern| subroutine removes |mu_glue| from a kern node, given
-the value of the math unit.
+/*tex
+
+ The |math_kern| subroutine removes |mu_glue| from a kern node, given the
+ value of the math unit.
-@c
+*/
static void math_kern(pointer p, scaled m)
{
- int n; /* integer part of |m| */
- scaled f; /* fraction part of |m| */
+ /*tex integer part of |m| */
+ int n;
+ /*tex fraction part of |m| */
+ scaled f;
if (subtype(p) == mu_glue) {
n = x_over_n(m, unity);
f = tex_remainder;
@@ -1611,15 +1823,15 @@ static void math_kern(pointer p, scaled m)
f = f + unity;
}
width(p) = mu_mult(width(p));
- subtype(p) = italic_kern; /* this is weird, it's not a italic but explicit_kern */
+ /* this is weird, it's not a italic but explicit_kern */
+ subtype(p) = italic_kern;
}
}
-@ @c
void run_mlist_to_hlist(halfword p, boolean penalties, int mstyle)
{
int callback_id;
- int a, sfix;
+ int a, sfix, i;
if (p == null) {
vlink(temp_head) = null;
return;
@@ -1636,18 +1848,16 @@ void run_mlist_to_hlist(halfword p, boolean penalties, int mstyle)
nodelist_to_lua(Luas, p);
lua_push_math_style_name(Luas, mstyle);
lua_pushboolean(Luas, penalties);
- if (lua_pcall(Luas, 3, 1, 0) != 0) { /* 3 args, 1 result */
- char errmsg[256]; /* temp hack ... we will have a formatted error */
- snprintf(errmsg, 255, "error: %s\n", lua_tostring(Luas, -1));
- errmsg[255]='\0';
+ if ((i=lua_pcall(Luas, 3, 1, 0)) != 0) {
+ formatted_warning("mlist to hlist","error: %s",lua_tostring(Luas, -1));
lua_settop(Luas, sfix);
- normal_error("mlist to hlist",errmsg); /* to be done */
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
return;
}
- a = nodelist_from_lua(Luas);
+ a = nodelist_from_lua(Luas,-1);
/* alink(vlink(a)) = null; */
- lua_settop(Luas, sfix);
vlink(temp_head) = a;
+ lua_settop(Luas, sfix);
} else if (callback_id == 0) {
mlist_to_hlist(p, penalties, mstyle);
} else {
@@ -1655,22 +1865,27 @@ void run_mlist_to_hlist(halfword p, boolean penalties, int mstyle)
}
}
-@ The recursion in |mlist_to_hlist| is due primarily to a subroutine
-called |clean_box| that puts a given noad field into a box using a given
-math style; |mlist_to_hlist| can call |clean_box|, which can call
-|mlist_to_hlist|.
-@^recursion@>
+/*tex
+
+ The recursion in |mlist_to_hlist| is due primarily to a subroutine called
+ |clean_box| that puts a given noad field into a box using a given math style;
+ |mlist_to_hlist| can call |clean_box|, which can call |mlist_to_hlist|.
-The box returned by |clean_box| is ``clean'' in the
-sense that its |shift_amount| is zero.
+ The box returned by |clean_box| is ``clean'' in the sense that its
+ |shift_amount| is zero.
+
+*/
-@c
static pointer clean_box(pointer p, int s, int cur_style)
{
- pointer q; /* beginning of a list to be boxed */
- pointer x; /* box to be returned */
- pointer r; /* temporary pointer */
- pointer mlist = null; /* beginning of mlist to be translated */
+ /*tex beginning of a list to be boxed */
+ pointer q;
+ /*tex box to be returned */
+ pointer x;
+ /*tex temporary pointer */
+ pointer r;
+ /*tex beginning of mlist to be translated */
+ pointer mlist = null;
switch (type(p)) {
case math_char_node:
mlist = new_noad();
@@ -1689,18 +1904,20 @@ static pointer clean_box(pointer p, int s, int cur_style)
goto FOUND;
}
mlist_to_hlist(mlist, false, s);
- q = vlink(temp_head); /* recursive call */
+ /*tex recursive call */
+ q = vlink(temp_head);
setup_cur_size(cur_style);
FOUND:
if (is_char_node(q) || (q == null))
x = hpack(q, 0, additional, -1);
else if ((vlink(q) == null) && (type(q) <= vlist_node) && (shift_amount(q) == 0))
- x = q; /* it's already clean */
+ /*tex It's already clean. */
+ x = q;
else
x = hpack(q, 0, additional, -1);
if (x != q && q != null)
reset_attributes(x, node_attr(q));
- /* Here we save memory space in a common case. */
+ /*tex Here we save memory space in a common case. */
q = list_ptr(x);
if (is_char_node(q)) {
r = vlink(q);
@@ -1708,7 +1925,7 @@ static pointer clean_box(pointer p, int s, int cur_style)
if (vlink(r) == null) {
if (!is_char_node(r)) {
if (type(r) == kern_node) {
- /* unneeded italic correction */
+ /*tex Unneeded italic correction. */
flush_node(r);
vlink(q) = null;
}
@@ -1719,22 +1936,30 @@ static pointer clean_box(pointer p, int s, int cur_style)
return x;
}
-@ It is convenient to have a procedure that converts a |math_char|
-field to an ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c|
-to the font code and character code of a given noad field.
-It also takes care of issuing error messages for
-nonexistent characters; in such cases, |char_exists(cur_f,cur_c)| will be |false|
-after |fetch| has acted, and the field will also have been reset to |null|.
+/*tex
-The outputs of |fetch| are placed in global variables.
+ It is convenient to have a procedure that converts a |math_char| field to an
+ ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c| to the font
+ code and character code of a given noad field. It also takes care of issuing
+ error messages for nonexistent characters; in such cases,
+ |char_exists(cur_f,cur_c)| will be |false| after |fetch| has acted, and the
+ field will also have been reset to |null|.
-@c
-internal_font_number cur_f; /* the |font| field of a |math_char| */
-int cur_c; /* the |character| field of a |math_char| */
+ The outputs of |fetch| are placed in global variables.
-@ Here we unpack the |math_char| field |a|.
+*/
+
+/*tex the |font| field of a |math_char| */
+
+internal_font_number cur_f;
+
+/*tex the |character| field of a |math_char| */
-@c static void fetch(pointer a)
+int cur_c;
+
+/*tex Here we unpack the |math_char| field |a|. */
+
+static void fetch(pointer a)
{
cur_c = math_character(a);
cur_f = fam_fnt(math_fam(a), cur_size);
@@ -1757,75 +1982,125 @@ int cur_c; /* the |character| field of a |math_char| */
}
}
-@ We need to do a lot of different things, so |mlist_to_hlist| makes two
-passes over the given mlist.
+/*tex
+
+ We need to do a lot of different things, so |mlist_to_hlist| makes two passes
+ over the given mlist.
-The first pass does most of the processing: It removes ``mu'' spacing from
-glue, it recursively evaluates all subsidiary mlists so that only the
-top-level mlist remains to be handled, it puts fractions and square roots
-and such things into boxes, it attaches subscripts and superscripts, and
-it computes the overall height and depth of the top-level mlist so that
-the size of delimiters for a |fence_noad| will be known.
-The hlist resulting from each noad is recorded in that noad's |new_hlist|
-field, an integer field that replaces the |nucleus| or |thickness|.
-@^recursion@>
+ The first pass does most of the processing: It removes ``mu'' spacing from
+ glue, it recursively evaluates all subsidiary mlists so that only the
+ top-level mlist remains to be handled, it puts fractions and square roots and
+ such things into boxes, it attaches subscripts and superscripts, and it
+ computes the overall height and depth of the top-level mlist so that the size
+ of delimiters for a |fence_noad| will be known. The hlist resulting from each
+ noad is recorded in that noad's |new_hlist| field, an integer field that
+ replaces the |nucleus| or |thickness|.
-The second pass eliminates all noads and inserts the correct glue and
-penalties between nodes.
+ The second pass eliminates all noads and inserts the correct glue and
+ penalties between nodes.
+
+*/
-@c
static void assign_new_hlist(pointer q, pointer r)
{
switch (type(q)) {
- case fraction_noad:
- math_list(numerator(q)) = null;
- flush_node(numerator(q));
- numerator(q) = null;
- math_list(denominator(q)) = null;
- flush_node(denominator(q));
- denominator(q) = null;
- break;
- case radical_noad:
- case simple_noad:
- case accent_noad:
- if (nucleus(q) != null) {
- math_list(nucleus(q)) = null;
- flush_node(nucleus(q));
- nucleus(q) = null;
- }
- break;
+ case fraction_noad:
+ math_list(numerator(q)) = null;
+ flush_node(numerator(q));
+ numerator(q) = null;
+ math_list(denominator(q)) = null;
+ flush_node(denominator(q));
+ denominator(q) = null;
+ break;
+ case radical_noad:
+ case simple_noad:
+ case accent_noad:
+ if (nucleus(q) != null) {
+ math_list(nucleus(q)) = null;
+ flush_node(nucleus(q));
+ nucleus(q) = null;
+ }
+ break;
}
new_hlist(q) = r;
}
-@ @c
#define choose_mlist(A) do { p=A(q); A(q)=null; } while (0)
-@ Most of the actual construction work of |mlist_to_hlist| is done
-by procedures with names like |make_fraction|, |make_radical|, etc. To
-illustrate the general setup of such procedures, let's begin with a
-couple of simple ones.
+/*tex
+
+ Most of the actual construction work of |mlist_to_hlist| is done by
+ procedures with names like |make_fraction|, |make_radical|, etc. To
+ illustrate the general setup of such procedures, let's begin with a couple of
+ simple ones.
+
+*/
-@c
static void make_over(pointer q, int cur_style, int cur_size, int cur_fam)
{
+ /*tex
+
+ No rule adaption yet, maybe never as overbars should be proper
+ extensibles.
+
+ */
pointer p;
+ scaled f, t;
+ scaled used_thickness = overbar_rule(cur_style);
+ scaled used_fam = cur_fam;
+ if (math_rule_thickness_mode_par > 0) {
+ f = noad_fam(q);
+ if (f >= 0) {
+ t = fam_fnt(f,cur_size);
+ if (do_new_math(t)) {
+ t = font_MATH_par(t, OverbarRuleThickness);
+ if (t != undefined_math_parameter) {
+ used_thickness = t;
+ used_fam = f;
+ }
+ }
+ }
+ }
p = overbar(clean_box(nucleus(q), cramped_style(cur_style), cur_style),
- overbar_vgap(cur_style), overbar_rule(cur_style),
- overbar_kern(cur_style), node_attr(nucleus(q)), math_over_rule, cur_size, cur_fam);
+ overbar_vgap(cur_style), used_thickness, overbar_kern(cur_style),
+ node_attr(nucleus(q)), math_over_rule, cur_size, used_fam);
math_list(nucleus(q)) = p;
type(nucleus(q)) = sub_box_node;
}
static void make_under(pointer q, int cur_style, int cur_size, int cur_fam)
{
- pointer p, x, y, r; /* temporary registers for box construction */
- scaled delta; /* overall height plus depth */
+ /*tex
+
+ No rule adaption yet, maybe never as underbars should be proper
+ extensibles.
+
+ */
+ /*tex temporary registers for box construction */
+ pointer p, x, y, r;
+ /*tex overall height plus depth */
+ scaled delta;
+ scaled f, t;
+ scaled used_thickness = underbar_rule(cur_style);
+ scaled used_fam = cur_fam;
x = clean_box(nucleus(q), cur_style, cur_style);
p = new_kern(underbar_vgap(cur_style));
reset_attributes(p, node_attr(q));
couple_nodes(x,p);
- r = do_fraction_rule(underbar_rule(cur_style), node_attr(q), math_under_rule, cur_size, cur_fam);
+ if (math_rule_thickness_mode_par > 0) {
+ f = noad_fam(q);
+ if (f >= 0) {
+ t = fam_fnt(f,cur_size);
+ if (do_new_math(t)) {
+ t = font_MATH_par(t, UnderbarRuleThickness);
+ if (t != undefined_math_parameter) {
+ used_thickness = t;
+ used_fam = f;
+ }
+ }
+ }
+ }
+ r = do_fraction_rule(used_thickness, node_attr(q), math_under_rule, cur_size, used_fam);
couple_nodes(p,r);
y = vpackage(x, 0, additional, max_dimen, math_direction_par);
reset_attributes(y, node_attr(q));
@@ -1838,8 +2113,10 @@ static void make_under(pointer q, int cur_style, int cur_size, int cur_fam)
static void make_vcenter(pointer q)
{
- pointer v; /* the box that should be centered vertically */
- scaled delta; /* its height plus depth */
+ /*tex the box that should be centered vertically */
+ pointer v;
+ /*tex its height plus depth */
+ scaled delta;
v = math_list(nucleus(q));
if (type(v) != vlist_node)
confusion("vcenter");
@@ -1848,16 +2125,19 @@ static void make_vcenter(pointer q)
depth(v) = delta - height(v);
}
-@ According to the rules in the \.{DVI} file specifications, we ensure alignment
-@^square roots@>
-between a square root sign and the rule above its nucleus by assuming that the
-baseline of the square-root symbol is the same as the bottom of the rule. The
-height of the square-root symbol will be the thickness of the rule, and the
-depth of the square-root symbol should exceed or equal the height-plus-depth
-of the nucleus plus a certain minimum clearance~|psi|. The symbol will be
-placed so that the actual clearance is |psi| plus half the excess.
+/*tex
+
+ According to the rules in the \.{DVI} file specifications, we ensure
+ alignment between a square root sign and the rule above its nucleus by
+ assuming that the baseline of the square-root symbol is the same as the
+ bottom of the rule. The height of the square-root symbol will be the
+ thickness of the rule, and the depth of the square-root symbol should exceed
+ or equal the height-plus-depth of the nucleus plus a certain minimum
+ clearance~|psi|. The symbol will be placed so that the actual clearance is
+ |psi| plus half the excess.
+
+*/
-@c
static void make_hextension(pointer q, int cur_style)
{
pointer e, p;
@@ -1885,25 +2165,50 @@ static void make_hextension(pointer q, int cur_style)
static void make_radical(pointer q, int cur_style)
{
- pointer x, y, p, l1, l2; /* temporary registers for box construction */
- scaled delta, clr, theta, h; /* dimensions involved in the calculation */
+ /*tex temporary registers for box construction */
+ pointer x, y, p, l1, l2;
+ /*tex dimensions involved in the calculation */
+ scaled delta, clr, theta, h, f;
+ scaled t, used_fam ;
x = clean_box(nucleus(q), cramped_style(cur_style), cur_style);
clr = radical_vgap(cur_style);
theta = radical_rule_par(cur_style);
+ used_fam = small_fam(left_delimiter(q));
+ /*tex
+
+ We can take the rule width from the fam/style of the delimiter or use the
+ most recent math parameters value.
+
+ */
+ if (math_rule_thickness_mode_par > 0) {
+ f = small_fam(left_delimiter(q));
+ if (f >= 0) {
+ t = fam_fnt(f,cur_size);
+ if (do_new_math(t)) {
+ t = font_MATH_par(t, RadicalRuleThickness);
+ if (t != undefined_math_parameter) {
+ theta = t;
+ used_fam = f;
+ }
+ }
+ }
+ }
if (theta == undefined_math_parameter) {
- /* a real radical */
+ /*tex a real radical */
theta = fraction_rule(cur_style);
y = do_delimiter(q, left_delimiter(q), cur_size, height(x) + depth(x) + clr + theta, false, cur_style, true, NULL, NULL, NULL);
- /*
+ /*tex
+
If |y| is a composite then set |theta| to the height of its top
character, else set it to the height of |y|.
+
*/
l1 = list_ptr(y);
if ((l1 != null) && (type(l1) == hlist_node)) {
- /* possible composite */
+ /*tex possible composite */
l2 = list_ptr(l1);
if ((l2 != null) && (type(l2) == glyph_node)) {
- /* top character */
+ /*tex top character */
theta = char_height(font(l2), character(l2));
} else {
theta = height(y);
@@ -1912,18 +2217,29 @@ static void make_radical(pointer q, int cur_style)
theta = height(y);
}
} else {
- /* not really a radical but we use its node, historical sharing (like in mathml) */
+ /*tex
+
+ Not really a radical but we use its node, historical sharing (like in
+ mathml).
+
+ */
y = do_delimiter(q, left_delimiter(q), cur_size, height(x) + depth(x) + clr + theta, false, cur_style, true, NULL, NULL, NULL);
}
+ /*tex
+
+ Weird hack, in overbar we use small_fam(left_delimiter(q)) so actually
+ small_fam(0).
+
+ */
left_delimiter(q) = null;
delta = (depth(y) + height(y) - theta) - (height(x) + depth(x) + clr);
if (delta > 0) {
- /* increase the actual clearance */
+ /*tex increase the actual clearance */
clr = clr + half(delta);
}
shift_amount(y) = (height(y) - theta) - (height(x) + clr);
h = depth(y) + height(y);
- p = overbar(x, clr, theta, radical_kern(cur_style), node_attr(y), math_radical_rule, cur_size, small_fam(left_delimiter(q)));
+ p = overbar(x, clr, theta, radical_kern(cur_style), node_attr(y), math_radical_rule, cur_size, used_fam);
couple_nodes(y,p);
if (degree(q) != null) {
scaled wr, br, ar;
@@ -1949,7 +2265,7 @@ static void make_radical(pointer q, int cur_style)
couple_nodes(x,r);
y = x;
}
- /* for \.{\\Uroot ..{<list>}{}} : */
+ /*tex for \.{\\Uroot ..{<list>}{}} : */
math_list(degree(q)) = null;
flush_node(degree(q));
}
@@ -1959,12 +2275,11 @@ static void make_radical(pointer q, int cur_style)
type(nucleus(q)) = sub_box_node;
}
-@ Construct a vlist box
+/*tex Construct a vlist box: */
-@c
static pointer wrapup_over_under_delimiter(pointer x, pointer y, pointer q, scaled shift_up, scaled shift_down)
{
- pointer p; /* temporary register for box construction */
+ pointer p;
pointer v = new_null_box();
type(v) = vlist_node;
height(v) = shift_up + height(x);
@@ -1978,9 +2293,7 @@ static pointer wrapup_over_under_delimiter(pointer x, pointer y, pointer q, scal
return v;
}
-/* when exact use radicalwidth (y is delimiter) */
-
-@ @c
+/*tex When |exact| use radicalwidth (|y| is delimiter). */
#define fixup_widths(q,x,y) do { \
if (width(y) >= width(x)) { \
@@ -2014,7 +2327,7 @@ static pointer wrapup_over_under_delimiter(pointer x, pointer y, pointer q, scal
width(r) = radicalwidth(q); \
reset_attributes(r, node_attr(q)); \
} else if (radicalright(q)) { \
- /* also kind of exact compared to vertical */ \
+ /*tex also kind of exact compared to vertical */ \
r = hpack(r, 0, additional, -1); \
width(r) = radicalwidth(q); \
reset_attributes(r, node_attr(q)); \
@@ -2030,12 +2343,15 @@ static pointer wrapup_over_under_delimiter(pointer x, pointer y, pointer q, scal
} \
} while (0)
-@ this has the |nucleus| box |x| as a limit above an extensible delimiter |y|
+/*tex
+
+ This has the |nucleus| box |x| as a limit above an extensible delimiter |y|.
+
+*/
-@c
static void make_over_delimiter(pointer q, int cur_style)
{
- pointer x, y, v; /* temporary registers for box construction */
+ pointer x, y, v;
scaled shift_up, shift_down, clr, delta, wd;
boolean stack;
x = clean_box(nucleus(q), sub_style(cur_style), cur_style);
@@ -2052,17 +2368,21 @@ static void make_over_delimiter(pointer q, int cur_style)
shift_up = shift_up + delta;
}
v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down);
- width(v) = width(x); /* this also equals |width(y)| */
+ /*tex This also equals |width(y)|: */
+ width(v) = width(x);
math_list(nucleus(q)) = v;
type(nucleus(q)) = sub_box_node;
}
-@ this has the extensible delimiter |x| as a limit below |nucleus| box |y|
+/*tex
+
+ This has the extensible delimiter |x| as a limit below |nucleus| box |y|.
+
+*/
-@c
static void make_under_delimiter(pointer q, int cur_style)
{
- pointer x, y, v; /* temporary registers for box construction */
+ pointer x, y, v;
scaled shift_up, shift_down, clr, delta, wd;
boolean stack;
y = clean_box(nucleus(q), sup_style(cur_style), cur_style);
@@ -2079,17 +2399,21 @@ static void make_under_delimiter(pointer q, int cur_style)
shift_down = shift_down + delta;
}
v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down);
- width(v) = width(y); /* this also equals |width(y)| */
+ /*tex This also equals |width(y)|: */
+ width(v) = width(y);
math_list(nucleus(q)) = v;
type(nucleus(q)) = sub_box_node;
}
-@ this has the extensible delimiter |x| as a limit above |nucleus| box |y|
+/*tex
+
+ This has the extensible delimiter |x| as a limit above |nucleus| box |y|.
+
+*/
-@c
static void make_delimiter_over(pointer q, int cur_style)
{
- pointer x, y, v; /* temporary registers for box construction */
+ pointer x, y, v;
scaled shift_up, shift_down, clr, actual, wd;
boolean stack;
y = clean_box(nucleus(q), cur_style, cur_style);
@@ -2106,17 +2430,21 @@ static void make_delimiter_over(pointer q, int cur_style)
shift_up = shift_up + (clr-actual);
}
v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down);
- width(v) = width(x); /* this also equals |width(y)| */
+ /*tex This also equals |width(y)|: */
+ width(v) = width(x);
math_list(nucleus(q)) = v;
type(nucleus(q)) = sub_box_node;
}
-@ this has the extensible delimiter |y| as a limit below a |nucleus| box |x|
+/*tex
+
+ This has the extensible delimiter |y| as a limit below a |nucleus| box |x|.
+
+*/
-@c
static void make_delimiter_under(pointer q, int cur_style)
{
- pointer x, y, v; /* temporary registers for box construction */
+ pointer x, y, v;
scaled shift_up, shift_down, clr, actual, wd;
boolean stack;
x = clean_box(nucleus(q), cur_style, cur_style);
@@ -2133,16 +2461,20 @@ static void make_delimiter_under(pointer q, int cur_style)
shift_down += (clr-actual);
}
v = wrapup_over_under_delimiter(x, y, q, shift_up, shift_down);
- width(v) = width(y); /* this also equals |width(y)| */
+ /*tex This also equals |width(y)|: */
+ width(v) = width(y);
math_list(nucleus(q)) = v;
type(nucleus(q)) = sub_box_node;
}
-@ Slants are not considered when placing accents in math mode. The accenter is
-centered over the accentee, and the accent width is treated as zero with
-respect to the size of the final box.
+/*tex
+
+ Slants are not considered when placing accents in math mode. The accenter is
+ centered over the accentee, and the accent width is treated as zero with
+ respect to the size of the final box.
+
+*/
-@c
#define TOP_CODE 1
#define BOT_CODE 2
#define OVERLAY_CODE 4
@@ -2150,14 +2482,17 @@ respect to the size of the final box.
static boolean compute_accent_skew(pointer q, int flags, scaled *s)
{
- pointer p; /* temporary register for box construction */
- boolean s_is_absolute = false; /* will be true if a top-accent is placed in |s| */
+ /*tex temporary register for box construction */
+ pointer p;
+ /*tex will be true if a top-accent is placed in |s| */
+ boolean s_is_absolute = false;
if (type(nucleus(q)) == math_char_node) {
fetch(nucleus(q));
if (do_new_math(cur_f)) {
- /*
- there is no bot_accent so let's assume similarity
+ /*tex
+ There is no bot_accent so let's assume similarity
+ \starttyping
if (flags & (TOP_CODE | OVERLAY_CODE)) {
*s = char_top_accent(cur_f, cur_c);
if (*s != INT_MIN) {
@@ -2169,6 +2504,7 @@ static boolean compute_accent_skew(pointer q, int flags, scaled *s)
s_is_absolute = true;
}
}
+ \stoptyping
*/
*s = char_top_accent(cur_f, cur_c);
if (*s != INT_MIN) {
@@ -2182,15 +2518,24 @@ static boolean compute_accent_skew(pointer q, int flags, scaled *s)
}
}
} else if (type(nucleus(q)) == sub_mlist_node) {
- /*
- if |nucleus(q)| is a |sub_mlist_node| composed of an |accent_noad| we
-
- * use the positioning of the nucleus of that noad, recursing until
- * the inner most |accent_noad|. This way multiple stacked accents are
- * aligned to the inner most one.
-
- the vlink test was added in version 1.06, so that we only consider a lone
- noad:
+ /*tex
+ If |nucleus(q)| is a |sub_mlist_node| composed of an |accent_noad| we:
+
+ \startitemize
+ \startitem
+ use the positioning of the nucleus of that noad, recursing until
+ \stopitem
+ \startitem
+ the inner most |accent_noad|. This way multiple stacked accents
+ are
+ \stopitem
+ \startitem
+ aligned to the inner most one.
+ \stopitem
+ \stoptitemize
+
+ The vlink test was added in version 1.06, so that we only consider a
+ lone noad:
$
\Umathaccent bottom 0 0 "023DF { \Umathaccent fixed 0 0 "00302 { m } r } \quad
@@ -2213,12 +2558,18 @@ static boolean compute_accent_skew(pointer q, int flags, scaled *s)
static void do_make_math_accent(pointer q, internal_font_number f, int c, int flags, int cur_style)
{
- pointer p, r, x, y; /* temporary registers for box construction */
- scaled s; /* amount to skew the accent to the right */
- scaled h; /* height of character being accented */
- scaled delta; /* space to remove between accent and accentee */
- scaled w; /* width of the accentee, not including sub/superscripts */
- boolean s_is_absolute; /* will be true if a top-accent is placed in |s| */
+ /*tex temporary registers for box construction */
+ pointer p, r, x, y;
+ /*tex amount to skew the accent to the right */
+ scaled s;
+ /*tex height of character being accented */
+ scaled h;
+ /*tex space to remove between accent and accentee */
+ scaled delta;
+ /*tex width of the accentee, not including sub/superscripts */
+ scaled w;
+ /*tex will be true if a top-accent is placed in |s| */
+ boolean s_is_absolute;
scaled fraction ;
scaled ic = 0;
scaled target ;
@@ -2232,7 +2583,7 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
if (fraction == 0) {
fraction = 1000;
}
- /* Compute the amount of skew, or set |s| to an alignment point */
+ /*tex Compute the amount of skew, or set |s| to an alignment point */
s_is_absolute = compute_accent_skew(q, flags, &s);
x = clean_box(nucleus(q), cramped_style(cur_style), cur_style);
w = width(x);
@@ -2241,7 +2592,7 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
s = half(w);
s_is_absolute = true;
}
- /* Switch to a larger accent if available and appropriate */
+ /*tex Switch to a larger accent if available and appropriate */
y = null;
ext = NULL;
if (flags & OVERLAY_CODE) {
@@ -2258,31 +2609,32 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
}
}
if ((flags & STRETCH_ACCENT_CODE) && (char_width(f, c) < w)) {
- while (1) {
- if ((char_tag(f, c) == ext_tag) && ((ext = get_charinfo_hor_variants(char_info(f, c))) != NULL)) {
- /* a bit weird for an overlay but anyway, here we don't need a factor as we don't step */
- y = get_delim_box(q, ext, f, w, node_attr(attr_p), cur_style, hlist_node);
- break;
- } else if (char_tag(f, c) != list_tag) {
- break;
- } else {
- int yy = char_remainder(f, c);
- if (!char_exists(f, yy)) {
+ while (1) {
+ if ((char_tag(f, c) == ext_tag) && ((ext = get_charinfo_hor_variants(char_info(f, c))) != NULL)) {
+ /*tex a bit weird for an overlay but anyway, here we don't need a factor as we don't step */
+ y = get_delim_box(f, c, w, connector_overlap_min(cur_style), 1, node_attr(attr_p));
+ break;
+ } else if (char_tag(f, c) != list_tag) {
break;
- } else if (flags & OVERLAY_CODE) {
- if (char_height(f, yy) > target) {
- break;
- }
} else {
- if (char_width(f, yy) > target)
- break;
+ int yy = char_remainder(f, c);
+ if (!char_exists(f, yy)) {
+ break;
+ } else if (flags & OVERLAY_CODE) {
+ if (char_height(f, yy) > target) {
+ break;
+ }
+ } else {
+ if (char_width(f, yy) > target)
+ break;
+ }
+ c = yy;
}
- c = yy;
}
- }
}
if (y == null) {
- y = char_box(f, c, node_attr(attr_p)); /* italic gets added to width */
+ /*tex italic gets added to width */
+ y = char_box(f, c, node_attr(attr_p));
}
if (flags & TOP_CODE) {
if (h < accent_base_height(f)) {
@@ -2291,13 +2643,14 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
delta = accent_base_height(f);
}
} else if (flags & OVERLAY_CODE) {
- delta = half(height(y) + depth(y) + height(x) + depth(x)); /* center the accent vertically around the accentee */
+ /*tex center the accent vertically around the accentee */
+ delta = half(height(y) + depth(y) + height(x) + depth(x));
} else {
delta = 0; /* hm */
}
if ((supscr(q) != null) || (subscr(q) != null)) {
if (type(nucleus(q)) == math_char_node) {
- /* swap the subscript and superscript into box |x| */
+ /*tex swap the subscript and superscript into box |x| */
flush_node_list(x);
x = new_noad();
r = math_clone(nucleus(q));
@@ -2313,32 +2666,34 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
h = height(x);
}
} else if ((vlink(q) != null) && (type(nucleus(q)) == math_char_node)) {
- /* only pure math char nodes */
+ /*tex only pure math char nodes */
internal_font_number f = fam_fnt(math_fam(nucleus(q)),cur_size);
if (do_new_math(f)) {
ic = char_italic(f,math_character(nucleus(q)));
}
}
- /* the top accents of both characters are aligned */
+ /*tex the top accents of both characters are aligned */
if (s_is_absolute) {
scaled sa;
if (ext != NULL) {
- /* if the accent is extensible just take the center */
+ /*tex if the accent is extensible just take the center */
sa = half(width(y));
} else {
- /*
- there is no bot_accent so let's assume similarity
+ /*tex
+ There is no bot_accent so let's assume similarity
+ \starttyping
if (flags & BOT_CODE) {
sa = char_bot_accent(f, c);
} else {
sa = char_top_accent(f, c);
}
+ \stoptyping
*/
sa = char_top_accent(f, c);
}
if (sa == INT_MIN) {
- /* just take the center */
+ /*tex just take the center */
sa = half(width(y));
}
if (math_direction_par == dir_TRT) {
@@ -2371,7 +2726,7 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
y = r;
if (flags & (TOP_CODE | OVERLAY_CODE)) {
if (height(y) < h) {
- /* make the height of box |y| equal to |h| */
+ /*tex make the height of box |y| equal to |h| */
p = new_kern(h - height(y));
reset_attributes(p, node_attr(q));
try_couple_nodes(p,list_ptr(y));
@@ -2382,7 +2737,7 @@ static void do_make_math_accent(pointer q, internal_font_number f, int c, int fl
shift_amount(y) = -(h - height(y));
}
if (ic != 0) {
- /* old font codepath has ic built in, new font code doesn't */
+ /*tex old font codepath has ic built in, new font code doesn't */
width(r) += ic ;
}
math_list(nucleus(q)) = y;
@@ -2420,26 +2775,48 @@ static void make_math_accent(pointer q, int cur_style)
}
}
-@ The |make_fraction| procedure is a bit different because it sets
-|new_hlist(q)| directly rather than making a sub-box.
+/*tex
+
+ The |make_fraction| procedure is a bit different because it sets
+ |new_hlist(q)| directly rather than making a sub-box.
+
+*/
-@c
static void make_fraction(pointer q, int cur_style)
{
- pointer p, p1, p2, v, x, y, z, l, r, m; /* temporary registers for box construction */
- scaled delta, delta1, delta2, shift_up, shift_down, clr1, clr2;
- /* dimensions for box calculations */
+ pointer p, p1, p2, v, x, y, z, l, r, m;
+ scaled delta, delta1, delta2, shift_up, shift_down, clr1, clr2, f, t;\
+ /*tex
+
+ We can take the rule width from an explicitly set fam, even if a fraction
+ itself has no character, otherwise we just use the math parameter.
+
+ */
+ scaled used_fam = math_rules_fam_par;
+ if (math_rule_thickness_mode_par > 0 && thickness(q) != 0) {
+ f = fraction_fam(q);
+ if (f >= 0) {
+ t = fam_fnt(f,cur_size);
+ if (do_new_math(t)) {
+ t = font_MATH_par(t, FractionRuleThickness);
+ if (t != undefined_math_parameter) {
+ thickness(q) = t;
+ used_fam = f;
+ }
+ }
+ }
+ }
if (thickness(q) == default_code)
thickness(q) = fraction_rule(cur_style);
- /*
+ /*tex
+
Create equal-width boxes |x| and |z| for the numerator and denominator,
and compute the default amounts |shift_up| and |shift_down| by which they
- are displaced from the baseline
- */
+ are displaced from the baseline.
+ */
x = clean_box(numerator(q), num_style(cur_style), cur_style);
z = clean_box(denominator(q), denom_style(cur_style), cur_style);
-
if (middle_delimiter(q) != null) {
delta = 0;
m = do_delimiter(q, middle_delimiter(q), cur_size, delta, false, cur_style, true, NULL, NULL, NULL);
@@ -2452,17 +2829,18 @@ static void make_fraction(pointer q, int cur_style)
z = rebox(z, width(x));
}
}
-
if (m != null) {
shift_up = 0;
shift_down = 0;
} else if (thickness(q) == 0) {
shift_up = stack_num_up(cur_style);
shift_down = stack_denom_down(cur_style);
- /*
- the numerator and denominator must be separated by a certain minimum
- clearance, called |clr| in the following program. The difference between
- |clr| and the actual clearance is |2delta|.
+ /*tex
+
+ The numerator and denominator must be separated by a certain minimum
+ clearance, called |clr| in the following program. The difference
+ between |clr| and the actual clearance is |2delta|.
+
*/
clr1 = stack_vgap(cur_style);
delta = half(clr1 - ((shift_up - depth(x)) - (height(z) - shift_down)));
@@ -2473,9 +2851,11 @@ static void make_fraction(pointer q, int cur_style)
} else {
shift_up = fraction_num_up(cur_style);
shift_down = fraction_denom_down(cur_style);
- /*
- in the case of a fraction line, the minimum clearance depends on the actual
- thickness of the line.
+ /*tex
+
+ In the case of a fraction line, the minimum clearance depends on the
+ actual thickness of the line.
+
*/
clr1 = fraction_num_vgap(cur_style);
clr2 = fraction_denom_vgap(cur_style);
@@ -2497,15 +2877,17 @@ static void make_fraction(pointer q, int cur_style)
}
}
if (m != null) {
- /*
- construct a hlist box for the fraction, according to |hgap| and |vgap|
+ /*tex
+
+ Construct a hlist box for the fraction, according to |hgap| and
+ |vgap|.
+
*/
shift_up = skewed_fraction_vgap(cur_style);
if (!fractionnoaxis(q)) {
shift_up += half(math_axis_size(cur_size));
}
-
shift_down = shift_up;
v = new_null_box();
reset_attributes(v, node_attr(q));
@@ -2516,7 +2898,6 @@ static void make_fraction(pointer q, int cur_style)
depth(v) = depth(x);
shift_amount(v) = - shift_up;
x = v;
-
v = new_null_box();
reset_attributes(v, node_attr(q));
type(v) = hlist_node;
@@ -2526,7 +2907,6 @@ static void make_fraction(pointer q, int cur_style)
depth(v) = depth(z) + shift_down;
shift_amount(v) = shift_down;
z = v;
-
v = new_null_box();
reset_attributes(v, node_attr(q));
type(v) = hlist_node;
@@ -2546,7 +2926,6 @@ static void make_fraction(pointer q, int cur_style)
if (depth(m) > depth(v)) {
depth(v) = depth(m);
}
-
if (fractionexact(q)) {
delta1 = -half(skewed_fraction_hgap(cur_style));
delta2 = delta1;
@@ -2557,33 +2936,34 @@ static void make_fraction(pointer q, int cur_style)
width(v) = width(x) + width(z) + skewed_fraction_hgap(cur_style);
width(m) = 0;
}
-
p1 = new_kern(delta1);
reset_attributes(p1, node_attr(q));
p2 = new_kern(delta2);
reset_attributes(p2, node_attr(q));
-
couple_nodes(x,p1);
couple_nodes(p1,m);
couple_nodes(m,p2);
couple_nodes(p2,z);
-
list_ptr(v) = x;
} else {
- /*
- construct a vlist box for the fraction, according to |shift_up| and |shift_down|
+ /*tex
+
+ Construct a vlist box for the fraction, according to |shift_up| and
+ |shift_down|.
+
*/
v = new_null_box();
type(v) = vlist_node;
height(v) = shift_up + height(x);
depth(v) = depth(z) + shift_down;
- width(v) = width(x); /* this also equals |width(z)| */
+ /*tex This also equals |width(z)|. */
+ width(v) = width(x);
reset_attributes(v, node_attr(q));
if (thickness(q) == 0) {
p = new_kern((shift_up - depth(x)) - (height(z) - shift_down));
couple_nodes(p,z);
} else {
- y = do_fraction_rule(thickness(q), node_attr(q), math_fraction_rule, cur_size, math_rules_fam_par);
+ y = do_fraction_rule(thickness(q), node_attr(q), math_fraction_rule, cur_size, used_fam);
p = new_kern((math_axis_size(cur_size) - delta) - (height(z) - shift_down));
reset_attributes(p, node_attr(q));
couple_nodes(y,p);
@@ -2595,16 +2975,14 @@ static void make_fraction(pointer q, int cur_style)
couple_nodes(x,p);
list_ptr(v) = x;
}
- /*
- put the fraction into a box with its delimiters, and make |new_hlist(q)|
- point to it
+ /*tex
+
+ Put the fraction into a box with its delimiters, and make |new_hlist(q)|
+ point to it.
+
*/
if (do_new_math(cur_f)) {
- if (math_use_old_fraction_scaling_par) {
- delta = fraction_del_size_old(cur_style);
- } else {
- delta = fraction_del_size_new(cur_style);
- }
+ delta = fraction_del_size_new(cur_style);
if (delta == undefined_math_parameter) {
delta = get_delimiter_height(depth(v), height(v), true);
}
@@ -2622,31 +3000,38 @@ static void make_fraction(pointer q, int cur_style)
assign_new_hlist(q, y);
}
-@ If the nucleus of an |op_noad| is a single character, it is to be
-centered vertically with respect to the axis, after first being enlarged
-(via a character list in the font) if we are in display style. The normal
-convention for placing displayed limits is to put them above and below the
-operator in display style.
+/*tex
+
+ If the nucleus of an |op_noad| is a single character, it is to be centered
+ vertically with respect to the axis, after first being enlarged (via a
+ character list in the font) if we are in display style. The normal convention
+ for placing displayed limits is to put them above and below the operator in
+ display style.
+
+ The italic correction is removed from the character if there is a subscript
+ and the limits are not being displayed. The |make_op| routine returns the
+ value that should be used as an offset between subscript and superscript.
-The italic correction is removed from the character if there is a subscript
-and the limits are not being displayed. The |make_op| routine returns the
-value that should be used as an offset between subscript and superscript.
+ After |make_op| has acted, |subtype(q)| will be |limits| if and only if the
+ limits have been set above and below the operator. In that case,
+ |new_hlist(q)| will already contain the desired final box.
-After |make_op| has acted, |subtype(q)| will be |limits| if and only if
-the limits have been set above and below the operator. In that case,
-|new_hlist(q)| will already contain the desired final box.
+*/
-@c
static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled supshift, scaled subshift);
static pointer check_nucleus_complexity(halfword q, scaled * delta, int cur_style, int *same);
static scaled make_op(pointer q, int cur_style)
{
- scaled delta = 0; /* offset between subscript and superscript */
+ /*tex offset between subscript and superscript */
+ scaled delta = 0;
scaled dummy = 0;
- pointer p, v, x, y, z, n; /* temporary registers for box construction */
- int c; /* register for character examination */
- scaled shift_up, shift_down; /* dimensions for box calculation */
+ /*tex temporary registers for box construction */
+ pointer p, v, x, y, z, n;
+ /*tex register for character examination */
+ int c;
+ /*tex dimensions for box calculation */
+ scaled shift_up, shift_down;
boolean axis_shift = false;
scaled ok_size;
if ((subtype(q) == op_noad_type_normal) && (cur_style < text_style)) {
@@ -2655,10 +3040,10 @@ static scaled make_op(pointer q, int cur_style)
if (type(nucleus(q)) == math_char_node) {
fetch(nucleus(q));
if (cur_style < text_style) {
- /* try to make it larger */
+ /*tex try to make it larger */
ok_size = minimum_operator_size(cur_style);
if (ok_size != undefined_math_parameter) {
- /* creating a temporary delimiter is the cleanest way */
+ /*tex creating a temporary delimiter is the cleanest way */
y = new_node(delim_node, 0);
reset_attributes(y, node_attr(q));
small_fam(y) = math_fam(nucleus(q));
@@ -2666,9 +3051,9 @@ static scaled make_op(pointer q, int cur_style)
x = do_delimiter(q, y, text_size, ok_size, false, cur_style, true, NULL, &delta, NULL);
if (delta != 0) {
if (do_new_math(cur_f)) {
- /* we never added italic correction */
+ /*tex we never added italic correction */
} else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
- /* remove italic correction */
+ /*tex remove italic correction */
width(x) -= delta;
}
}
@@ -2685,82 +3070,91 @@ static scaled make_op(pointer q, int cur_style)
x = clean_box(nucleus(q), cur_style, cur_style);
if (delta != 0) {
if (do_new_math(cur_f)) {
- /* we never added italic correction */
+ /*tex we never added italic correction */
} else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
- /* remove italic correction */
+ /*tex remove italic correction */
width(x) -= delta;
}
}
axis_shift = true;
}
} else {
- /* normal size */
+ /*tex normal size */
delta = char_italic(cur_f, cur_c);
x = clean_box(nucleus(q), cur_style, cur_style);
if (delta != 0) {
if (do_new_math(cur_f)) {
- /* we never added italic correction */
+ /*tex we never added italic correction */
} else if ((subscr(q) != null) && (subtype(q) != op_noad_type_limits)) {
- /* remove italic correction */
+ /*tex remove italic correction */
width(x) -= delta;
}
}
axis_shift = true;
}
if (axis_shift) {
- /* center vertically */
+ /*tex center vertically */
shift_amount(x) = half(height(x) - depth(x)) - math_axis_size(cur_size);
}
type(nucleus(q)) = sub_box_node;
math_list(nucleus(q)) = x;
}
-
- /* we now handle op_nod_type_no_limits here too */
-
+ /*tex we now handle op_nod_type_no_limits here too */
if (subtype(q) == op_noad_type_no_limits) {
if (do_new_math(cur_f)) {
- /*
+ /*tex
+ Not:
+
+ \starttyping
if (delta != 0) {
delta = half(delta) ;
}
+ \stoptyping
*/
p = check_nucleus_complexity(q, &dummy, cur_style, NULL);
if ((subscr(q) == null) && (supscr(q) == null)) {
assign_new_hlist(q, p);
} else {
- /*
+ /*tex
+ Not:
+
+ \starttyping
make_scripts(q, p, 0, cur_style, delta, -delta);
+ \stoptyping
*/
int mode = math_nolimits_mode_par; /* wins */
- /*
- for easy configuration ... fonts are somewhat inconsistent and the
- values for italic correction run from 30 to 60% of the width
+ /*tex
+
+ For easy configuration ... fonts are somewhat inconsistent
+ and the values for italic correction run from 30 to 60\% of.
+ the width.
+
*/
switch (mode) {
case 0 :
- /* full bottom correction */
+ /*tex full bottom correction */
make_scripts(q, p, 0, cur_style, 0, -delta);
break;
case 1 :
- /* MathConstants driven */
+ /*tex |MathConstants| driven */
make_scripts(q, p, 0, cur_style,
round_xn_over_d(delta, nolimit_sup_factor(cur_style), 1000),
-round_xn_over_d(delta, nolimit_sub_factor(cur_style), 1000));
case 2 :
- /* no correction */
+ /*tex no correction */
make_scripts(q, p, 0, cur_style, 0, 0);
break ;
case 3 :
- /* half bottom correction */
+ /*tex half bottom correction */
make_scripts(q, p, 0, cur_style, 0, -half(delta));
break;
case 4 :
- /* half bottom and top correction */
+ /*tex half bottom and top correction */
make_scripts(q, p, 0, cur_style, half(delta), -half(delta));
break;
default :
if (mode > 15) {
- /* for quickly testing values */
+ /*tex for quickly testing values */
make_scripts(q, p, 0, cur_style, 0, -round_xn_over_d(delta, mode, 1000));
} else {
make_scripts(q, p, 0, cur_style, 0, 0);
@@ -2770,7 +3164,7 @@ static scaled make_op(pointer q, int cur_style)
}
delta = 0;
} else {
- /* similar code then the caller (before CHECK_DIMENSIONS) */
+ /*tex similar code then the caller (before CHECK_DIMENSIONS) */
p = check_nucleus_complexity(q, &delta, cur_style, NULL);
if ((subscr(q) == null) && (supscr(q) == null)) {
assign_new_hlist(q, p);
@@ -2779,8 +3173,13 @@ static scaled make_op(pointer q, int cur_style)
}
}
} else if (subtype(q) == op_noad_type_limits) {
- /* The following program builds a vlist box |v| for displayed limits. The
- width of the box is not affected by the fact that the limits may be skewed. */
+ /*tex
+
+ The following program builds a vlist box |v| for displayed limits.
+ The width of the box is not affected by the fact that the limits may
+ be skewed.
+
+ */
x = clean_box(supscr(q), sup_style(cur_style), cur_style);
y = clean_box(nucleus(q), cur_style, cur_style);
z = clean_box(subscr(q), sub_style(cur_style), cur_style);
@@ -2788,38 +3187,36 @@ static scaled make_op(pointer q, int cur_style)
reset_attributes(v, node_attr(q));
type(v) = vlist_node;
if (do_new_math(cur_f)) {
- n = null;
- if (! math_no_italic_compensation_par) {
- n = nucleus(q);
- if (n != null) {
- if ((type(n) == sub_mlist_node) || (type(n) == sub_box_node)) {
- n = math_list(n);
- if (n != null) {
- if (type(n) == hlist_node) {
- n = list_ptr(n); /* just a not scaled char */
- while (n != null) {
- if (type(n) == glyph_node) {
- delta = char_italic(font(n),character(n));
- }
- n = vlink(n);
+ n = nucleus(q);
+ if (n != null) {
+ if ((type(n) == sub_mlist_node) || (type(n) == sub_box_node)) {
+ n = math_list(n);
+ if (n != null) {
+ if (type(n) == hlist_node) {
+ /*tex just a not scaled char */
+ n = list_ptr(n);
+ while (n != null) {
+ if (type(n) == glyph_node) {
+ delta = char_italic(font(n),character(n));
}
- } else {
- while (n != null) {
- if (type(n) == fence_noad) {
- if (delimiteritalic(n) > delta) {
- /* we can have dummies, the period ones */
- delta = delimiteritalic(n);
- }
+ n = vlink(n);
+ }
+ } else {
+ while (n != null) {
+ if (type(n) == fence_noad) {
+ if (delimiteritalic(n) > delta) {
+ /*tex we can have dummies, the period ones */
+ delta = delimiteritalic(n);
}
- n = vlink(n);
}
+ n = vlink(n);
}
}
- } else {
- n = nucleus(q);
- if (type(n) == math_char_node) {
- delta = char_italic(fam_fnt(math_fam(n),cur_size),math_character(n));
- }
+ }
+ } else {
+ n = nucleus(q);
+ if (type(n) == math_char_node) {
+ delta = char_italic(fam_fnt(math_fam(n),cur_size),math_character(n));
}
}
}
@@ -2834,23 +3231,23 @@ static scaled make_op(pointer q, int cur_style)
z = rebox(z, width(v));
shift_amount(x) = half(delta);
shift_amount(z) = -shift_amount(x);
- /* v is the still empty target */
+ /*tex v is the still empty target */
height(v) = height(y);
depth(v) = depth(y);
- /*
- attach the limits to |y| and adjust |height(v)|, |depth(v)| to
- account for their presence
+ /*tex
- we use |shift_up| and |shift_down| in the following program for the
- amount of glue between the displayed operator |y| and its limits |x| and
- |z|
+ Attach the limits to |y| and adjust |height(v)|, |depth(v)| to
+ account for their presence.
- the vlist inside box |v| will consist of |x| followed by |y| followed
- by |z|, with kern nodes for the spaces between and around them
+ We use |shift_up| and |shift_down| in the following program for the
+ amount of glue between the displayed operator |y| and its limits |x|
+ and |z|.
- b: baseline v: minumum gap
- */
+ The vlist inside box |v| will consist of |x| followed by |y| followed
+ by |z|, with kern nodes for the spaces between and around them;
+ |b| is baseline and |v| is the minumum gap.
+ */
if (supscr(q) == null) {
list_ptr(x) = null;
flush_node(x);
@@ -2905,17 +3302,20 @@ static scaled make_op(pointer q, int cur_style)
return delta;
}
-@ A ligature found in a math formula does not create a ligature, because
-there is no question of hyphenation afterwards; the ligature will simply be
-stored in an ordinary |glyph_node|, after residing in an |ord_noad|.
+/*tex
-The |type| is converted to |math_text_char| here if we would not want to
-apply an italic correction to the current character unless it belongs
-to a math font (i.e., a font with |space=0|).
+ A ligature found in a math formula does not create a ligature, because there
+ is no question of hyphenation afterwards; the ligature will simply be stored
+ in an ordinary |glyph_node|, after residing in an |ord_noad|.
-No boundary characters enter into these ligatures.
+ The |type| is converted to |math_text_char| here if we would not want to
+ apply an italic correction to the current character unless it belongs to a
+ math font (i.e., a font with |space=0|).
+
+ No boundary characters enter into these ligatures.
+
+*/
-@c
#define simple_char_noad(p) (\
(p != null) && \
(type(p) == simple_noad) && \
@@ -2928,10 +3328,14 @@ No boundary characters enter into these ligatures.
static void make_ord(pointer q)
{
- int a; /* the left-side character for lig/kern testing */
- pointer p, r, s; /* temporary registers for list manipulation */
- scaled k; /* a kern */
- liginfo lig; /* a ligature */
+ /*tex the left-side character for lig/kern testing */
+ int a;
+ /*tex temporary registers for list manipulation */
+ pointer p, r, s;
+ /*tex a kern */
+ scaled k;
+ /*tex a ligature */
+ liginfo lig;
RESTART:
if (subscr(q) == null && supscr(q) == null && type(nucleus(q)) == math_char_node) {
p = vlink(q);
@@ -2939,7 +3343,7 @@ static void make_ord(pointer q)
type(nucleus(q)) = math_text_char_node;
fetch(nucleus(q));
a = cur_c;
- /* add italic correction */
+ /*tex add italic correction */
if (do_new_math(cur_f) && (char_italic(cur_f,math_character(nucleus(q))) != 0)) {
p = new_kern(char_italic(cur_f,math_character(nucleus(q))));
subtype(p) = italic_kern;
@@ -2948,45 +3352,49 @@ static void make_ord(pointer q)
couple_nodes(q,p);
return;
}
- /* construct ligatures, quite unlikely in new math fonts */
+ /*tex construct ligatures, quite unlikely in new math fonts */
if ((has_kern(cur_f, a)) || (has_lig(cur_f, a))) {
cur_c = math_character(nucleus(p));
- /*
- if character |a| has a kern with |cur_c|, attach the kern after~|q|; or if
- it has a ligature with |cur_c|, combine noads |q| and~|p| appropriately;
- then |return| if the cursor has moved past a noad, or |goto restart|
+ /*tex
- note that a ligature between an |ord_noad| and another kind of noad
- is replaced by an |ord_noad|, when the two noads collapse into one
+ If character |a| has a kern with |cur_c|, attach the kern
+ after~|q|; or if it has a ligature with |cur_c|, combine
+ noads |q| and~|p| appropriately; then |return| if the cursor
+ has moved past a noad, or |goto restart|.
- we could make a parenthesis (say) change shape when it follows
- certain letters. Presumably a font designer will define such
- ligatures only when this convention makes sense
- */
+ Note that a ligature between an |ord_noad| and another kind
+ of noad is replaced by an |ord_noad|, when the two noads
+ collapse into one.
+ We could make a parenthesis (say) change shape when it
+ follows certain letters. Presumably a font designer will
+ define such ligatures only when this convention makes sense.
+
+ */
if (disable_lig_par == 0 && has_lig(cur_f, a)) {
lig = get_ligature(cur_f, a, cur_c);
if (is_valid_ligature(lig)) {
- check_interrupt(); /* allow a way out of infinite ligature loop */
+ /*tex allow a way out of infinite ligature loop */
+ check_interrupt();
switch (lig_type(lig)) {
case 1:
- /* \.{=:\char`\|} */
+ /*tex \.{=:\char`\|} */
case 5:
- /* \.{=:\char`\|>} */
+ /*tex \.{=:\char`\|>} */
math_character(nucleus(q)) = lig_replacement(lig);
break;
case 2:
- /* \.{\char`\|=:} */
+ /*tex \.{\char`\|=:} */
case 6:
- /* \.{\char`\|=:>} */
+ /*tex \.{\char`\|=:>} */
math_character(nucleus(p)) = lig_replacement(lig);
break;
case 3:
- /* \.{\char`\|=:\char`\|} */
+ /*tex \.{\char`\|=:\char`\|} */
case 7:
- /* \.{\char`\|=:\char`\|>} */
+ /*tex \.{\char`\|=:\char`\|>} */
case 11:
- /* \.{\char`\|=:\char`\|>>} */
+ /*tex \.{\char`\|=:\char`\|>>} */
r = new_noad();
reset_attributes(r, node_attr(q));
s = new_node(math_char_node, 0);
@@ -2996,21 +3404,20 @@ static void make_ord(pointer q)
math_fam(nucleus(r)) = math_fam(nucleus(q));
couple_nodes(q,r);
couple_nodes(r,p);
- if (lig_type(lig) < 11)
+ if (lig_type(lig) < 11) {
type(nucleus(r)) = math_char_node;
- else
- /* prevent combination */
+ } else {
+ /*tex prevent combination */
type(nucleus(r)) = math_text_char_node;
+ }
break;
default:
try_couple_nodes(q,vlink(p));
math_character(nucleus(q)) = lig_replacement(lig); /* \.{=:} */
- s = math_clone(subscr(p));
- subscr(q) = s;
- s = math_clone(supscr(p));
- supscr(q) = s;
- math_reset(subscr(p)); /* just in case */
- math_reset(supscr(p));
+ subscr(q) = subscr(p);
+ supscr(q) = supscr(p);
+ subscr(p) = null ;
+ supscr(p) = null ;
flush_node(p);
break;
}
@@ -3021,7 +3428,7 @@ static void make_ord(pointer q)
}
}
if (disable_kern_par == 0 && has_kern(cur_f, a)) {
- /* todo: should this use mathkerns? */
+ /*tex todo: should this use mathkerns? */
k = get_kern(cur_f, a, cur_c);
if (k != 0) {
p = new_kern(k);
@@ -3036,32 +3443,35 @@ static void make_ord(pointer q)
}
}
-@ If the fonts for the left and right bits of a mathkern are not
-both new-style fonts, then return a sentinel value meaning:
-please use old-style italic correction placement
+/*tex
+
+ If the fonts for the left and right bits of a mathkern are not both new-style
+ fonts, then return a sentinel value meaning: please use old-style italic
+ correction placement
+
+*/
-@c
#define MATH_KERN_NOT_FOUND 0x7FFFFFFF
-@ This function tries to find the kern needed for proper cut-ins.
-The left side doesn't move, but the right side does, so the first
-order of business is to create a staggered fence line on the
-left side of the right character.
+/*tex
-The microsoft spec says that there are four quadrants, but the
-actual images say
+ This function tries to find the kern needed for proper cut-ins. The left side
+ doesn't move, but the right side does, so the first order of business is to
+ create a staggered fence line on the left side of the right character.
+
+ The microsoft spec says that there are four quadrants, but the actual images
+ say.
+
+*/
-@c
static scaled math_kern_at(internal_font_number f, int c, int side, int v)
{
int h, k, numkerns;
scaled *kerns_heights;
scaled kern = 0;
- charinfo *co = char_info(f, c); /* known to exist */
+ /*tex Known to exist: */
+ charinfo *co = char_info(f, c);
numkerns = get_charinfo_math_kerns(co, side);
-#ifdef DEBUG
- fprintf(stderr, " entries = %d, height = %d\n", numkerns, v);
-#endif
if (numkerns == 0)
return kern;
if (side == top_left_kern) {
@@ -3073,21 +3483,15 @@ static scaled math_kern_at(internal_font_number f, int c, int side, int v)
} else if (side == bottom_right_kern) {
kerns_heights = co->bottom_right_math_kern_array;
} else {
+ /*tex Not reached: */
confusion("math_kern_at");
- kerns_heights = NULL; /* not reached */
+ kerns_heights = NULL;
}
-#ifdef DEBUG
- fprintf(stderr, " entry 0: %d,%d\n", kerns_heights[0], kerns_heights[1]);
-#endif
if (v < kerns_heights[0])
return kerns_heights[1];
for (k = 0; k < numkerns; k++) {
h = kerns_heights[(k * 2)];
kern = kerns_heights[(k * 2) + 1];
-#ifdef DEBUG
- if (k > 0)
- fprintf(stderr, " entry %d: %d,%d\n", k, h, kern);
-#endif
if (h > v) {
return kern;
}
@@ -3095,68 +3499,55 @@ static scaled math_kern_at(internal_font_number f, int c, int side, int v)
return kern;
}
-@ @c
-static scaled find_math_kern(internal_font_number l_f, int l_c,
- internal_font_number r_f, int r_c,
- int cmd, scaled shift)
+static scaled find_math_kern(internal_font_number l_f, int l_c, internal_font_number r_f, int r_c, int cmd, scaled shift)
{
scaled corr_height_top = 0, corr_height_bot = 0;
scaled krn_l = 0, krn_r = 0, krn = 0;
-// if ((!do_new_math(l_f)) || (!do_new_math(r_f)) || (!char_exists(l_f, l_c)) || (!char_exists(r_f, r_c)))
- if ((!(do_new_math(l_f) || do_new_math(r_f))) || (!char_exists(l_f, l_c)) || (!char_exists(r_f, r_c)))
+ if ((!do_new_math(l_f)) || (!do_new_math(r_f)) || (!char_exists(l_f,l_c)) || (!char_exists(r_f,r_c)))
return MATH_KERN_NOT_FOUND;
-
if (cmd == sup_mark_cmd) {
corr_height_top = char_height(l_f, l_c);
- corr_height_bot = -char_depth(r_f, r_c) + shift; /* bottom of superscript */
+ /*tex bottom of superscript */
+ corr_height_bot = -char_depth(r_f, r_c) + shift;
krn_l = math_kern_at(l_f, l_c, top_right_kern, corr_height_top);
krn_r = math_kern_at(r_f, r_c, bottom_left_kern, corr_height_top);
-#ifdef DEBUG
- fprintf(stderr, "SUPER Top LR = %d,%d (shift %d)\n", krn_l, krn_r, shift);
-#endif
krn = (krn_l + krn_r);
krn_l = math_kern_at(l_f, l_c, top_right_kern, corr_height_bot);
krn_r = math_kern_at(r_f, r_c, bottom_left_kern, corr_height_bot);
-#ifdef DEBUG
- fprintf(stderr, "SUPER Bot LR = %d,%d\n", krn_l, krn_r);
-#endif
if ((krn_l + krn_r) < krn)
krn = (krn_l + krn_r);
return (krn);
-
} else if (cmd == sub_mark_cmd) {
- corr_height_top = char_height(r_f, r_c) - shift; /* top of subscript */
+ /*tex top of subscript */
+ corr_height_top = char_height(r_f, r_c) - shift;
corr_height_bot = -char_depth(l_f, l_c);
krn_l = math_kern_at(l_f, l_c, bottom_right_kern, corr_height_top);
krn_r = math_kern_at(r_f, r_c, top_left_kern, corr_height_top);
-#ifdef DEBUG
- fprintf(stderr, "SUB Top LR = %d,%d\n", krn_l, krn_r);
-#endif
krn = (krn_l + krn_r);
krn_l = math_kern_at(l_f, l_c, bottom_right_kern, corr_height_bot);
krn_r = math_kern_at(r_f, r_c, top_left_kern, corr_height_bot);
-#ifdef DEBUG
- fprintf(stderr, "SUB Bot LR = %d,%d\n", krn_l, krn_r);
-#endif
if ((krn_l + krn_r) < krn)
krn = (krn_l + krn_r);
return (krn);
-
} else {
confusion("find_math_kern");
}
- return 0; /* not reached */
+ /*tex Not reached: */
+ return 0;
}
-@ just a small helper
-@c
-static pointer attach_hkern_to_new_hlist(pointer q, scaled delta2)
+/*tex Just a small helper: */
+
+static pointer attach_hkern_to_new_hlist(pointer q, scaled delta2, halfword subtyp)
{
pointer y;
pointer z = new_kern(delta2);
+ if (subtyp != 0) {
+ subtype(z) = subtyp;
+ }
reset_attributes(z, node_attr(q));
if (new_hlist(q) == null) {
- /* this is somewhat weird */
+ /*tex this is somewhat weird */
new_hlist(q) = z;
} else {
y = new_hlist(q);
@@ -3167,67 +3558,36 @@ static pointer attach_hkern_to_new_hlist(pointer q, scaled delta2)
return new_hlist(q);
}
-@
-@c
-#ifdef DEBUG
-void dump_simple_field(pointer q)
-{
- pointer p;
- printf(" [%d, type=%d, vlink=%d] ", q, type(q), vlink(q));
- switch (type(q)) {
- case math_char_node:
- printf("mathchar ");
- break;
- case math_text_char_node:
- printf("texchar ");
- break;
- case sub_box_node:
- printf("box ");
- break;
- case sub_mlist_node:
- printf("mlist ");
- p = math_list(q);
- while (p != null) {
- dump_simple_field(p);
- p = vlink(p);
- }
- break;
- }
-}
+/*tex
-void dump_simple_node(pointer q)
-{
- printf("node %d, type=%d, vlink=%d\n", q, type(q), vlink(q));
- printf("nucleus: ");
- dump_simple_field(nucleus(q));
- printf("\n");
- printf("sub: ");
- dump_simple_field(subscr(q));
- printf("\n");
- printf("sup: ");
- dump_simple_field(supscr(q));
- printf("\n\n");
-}
-#endif
+ The purpose of |make_scripts(q,it)| is to attach the subscript and/or
+ superscript of noad |q| to the list that starts at |new_hlist(q)|, given that
+ subscript and superscript aren't both empty. The superscript will be
+ horizontally shifted over |delta1|, the subscript over |delta2|.
-@ The purpose of |make_scripts(q,it)| is to attach the subscript and/or
-superscript of noad |q| to the list that starts at |new_hlist(q)|,
-given that subscript and superscript aren't both empty. The superscript
-will be horizontally shifted over |delta1|, the subscript over |delta2|.
+ We set |shift_down| and |shift_up| to the minimum amounts to shift the
+ baseline of subscripts and superscripts based on the given nucleus.
-We set |shift_down| and |shift_up| to the minimum amounts to shift the
-baseline of subscripts and superscripts based on the given nucleus.
+ Note: We need to look at a character but also at the first one in a sub list
+ and there we ignore leading kerns and glue. Elsewhere is code that removes
+ kerns assuming that is italic correction. The heuristics are unreliable for
+ the new fonts so eventualy there will be an option to ignore such
+ corrections.
-Note: We need to look at a character but also at the first one in a sub list
-and there we ignore leading kerns and glue. Elsewhere is code that removes
-kerns assuming that is italic correction. The heuristics are unreliable for
-the new fonts so eventualy there will be an option to ignore such corrections.
+*/
-@ @c
#define analyze_script(init,su_n,su_f,su_c) do { \
su_n = init; \
if (su_n != null) { \
- if (math_script_box_mode_par > 0 && type(su_n) == sub_mlist_node) { \
+ if (math_script_char_mode_par > 0 && type(su_n) == math_char_node) { \
+ fetch(su_n); \
+ if (char_exists(cur_f, cur_c)) { \
+ su_f = cur_f; \
+ su_c = cur_c; \
+ } else { \
+ su_n = null; \
+ } \
+ } else if (math_script_box_mode_par > 0 && type(su_n) == sub_mlist_node) { \
su_n = math_list(su_n); \
while (su_n != null) { \
if ((type(su_n) == kern_node) || (type(su_n) == glue_node)) { \
@@ -3312,10 +3672,10 @@ the new fonts so eventualy there will be an option to ignore such corrections.
static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled supshift, scaled subshift)
{
- pointer x, y, z; /* temporary registers for box construction */
- scaled shift_up, shift_down, clr; /* dimensions in the calculation */
+ pointer x, y, z;
+ scaled shift_up, shift_down, clr;
scaled delta1, delta2;
- halfword sub_n, sup_n;
+ halfword sub_n, sup_n, subtyp;
internal_font_number sub_f, sup_f;
int sub_c, sup_c;
sub_n = null;
@@ -3326,18 +3686,13 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
sup_c = 0;
delta1 = it;
delta2 = 0;
-
-#ifdef DEBUG
- printf("it: %d\n", it);
- dump_simple_node(q);
- printf("p: node %d, type=%d, subtype=%d\n", p, type(p), subtype(p));
-#endif
+ subtyp = 0;
switch (type(nucleus(q))) {
case math_char_node:
case math_text_char_node:
if ((subscr(q) == null) && (delta1 != 0)) {
- /* todo: selective */
- x = new_kern(delta1); /* italic correction */
+ /*tex todo: selective italic correction */
+ x = new_kern(delta1);
subtype(x) = italic_kern;
reset_attributes(x, node_attr(nucleus(q)));
couple_nodes(p,x);
@@ -3355,22 +3710,20 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
list_ptr(z) = null;
flush_node(z);
}
-
if (is_char_node(p)) {
- /* we look at the subscript character (_i) or first character in a list (_{ij}) */
+ /*tex We look at the subscript character (_i) or first character in a list (_{ij}). */
analyze_script(subscr(q),sub_n,sub_f,sub_c);
- /* we look at the superscript character (^i) or first character in a list (^{ij}) */
+ /*tex We look at the superscript character (^i) or first character in a list (^{ij}). */
analyze_script(supscr(q),sup_n,sup_f,sup_c);
}
-
if (supscr(q) == null) {
- /*
- construct a subscript box |x| when there is no superscript
+ /*tex
- when there is a subscript without a superscript, the top of the subscript
+ Construct a subscript box |x| when there is no superscript. When
+ there is a subscript without a superscript, the top of the subscript
should not exceed the baseline plus four-fifths of the x-height.
+
*/
- /* x = clean_box(subscr(q), sub_style(cur_style), cur_style); */
x = clean_box(subscr(q), (noadoptionnosubscript(q) ? cur_style : sub_style(cur_style)), cur_style);
width(x) = width(x) + space_after_script(cur_style);
switch (math_scripts_mode_par) {
@@ -3398,30 +3751,29 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
break;
}
shift_amount(x) = shift_down;
-
- /* now find and correct for horizontal shift */
+ /*tex Now find and correct for horizontal shift. */
+ subtyp = 0;
if (sub_n != null) {
delta2 = find_math_kern(font(p), character(p),sub_f,sub_c,sub_mark_cmd, shift_down);
if (delta2 == MATH_KERN_NOT_FOUND) {
delta2 = subshift ;
} else {
delta2 = delta2 + subshift ;
+ subtyp = font_kern;
}
} else {
delta2 = subshift ;
}
if (delta2 != 0) {
- p = attach_hkern_to_new_hlist(q, delta2);
+ p = attach_hkern_to_new_hlist(q, delta2, subtyp);
}
-
} else {
- /*
- construct a superscript box |x|
+ /*tex
+
+ Construct a superscript box |x|. The bottom of a superscript should
+ never descend below the baseline plus one-fourth of the x-height.
- the bottom of a superscript should never descend below the baseline plus
- one-fourth of the x-height.
*/
- /* x = clean_box(supscr(q), sup_style(cur_style), cur_style); */
x = clean_box(supscr(q), (noadoptionnosupscript(q) ? cur_style : sup_style(cur_style)), cur_style);
width(x) = width(x) + space_after_script(cur_style);
switch (math_scripts_mode_par) {
@@ -3451,33 +3803,35 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
}
if (subscr(q) == null) {
shift_amount(x) = -shift_up;
- /* now find and correct for horizontal shift */
+ /*tex Now find and correct for horizontal shift. */
+ subtyp = 0;
if (sup_n != null) {
clr = find_math_kern(font(p),character(p),sup_f,sup_c,sup_mark_cmd,shift_up);
if (clr == MATH_KERN_NOT_FOUND) {
clr = supshift ;
} else {
clr = clr + supshift ;
+ subtyp = font_kern;
}
} else {
clr = supshift;
}
if (clr != 0) {
- p = attach_hkern_to_new_hlist(q, clr);
+ p = attach_hkern_to_new_hlist(q, clr, subtyp);
}
} else {
- /*
- construct a sub/superscript combination box |x|, with the superscript offset
- by |delta|
+ /*tex
- when both subscript and superscript are present, the subscript must be
- separated from the superscript by at least four times |default_rule_thickness|
+ Construct a sub/superscript combination box |x|, with the
+ superscript offset by |delta|. When both subscript and
+ superscript are present, the subscript must be separated from the
+ superscript by at least four times |default_rule_thickness| If
+ this condition would be violated, the subscript moves down, after
+ which both subscript and superscript move up so that the bottom
+ of the superscript is at least as high as the baseline plus
+ four-fifths of the x-height.
- if this condition would be violated, the subscript moves down, after which
- both subscript and superscript move up so that the bottom of the superscript
- is at least as high as the baseline plus four-fifths of the x-height
*/
- /* y = clean_box(subscr(q) sub_style(cur_style), cur_style); */
y = clean_box(subscr(q), (noadoptionnosubscript(q) ? cur_style : sub_style(cur_style)), cur_style);
width(y) = width(y) + space_after_script(cur_style);
switch (math_scripts_mode_par) {
@@ -3510,30 +3864,37 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
}
break;
}
- /* now find and correct for horizontal shift */
+ /*tex Now find and correct for horizontal shift. */
+ subtyp = 0;
if (sub_n != null) {
delta2 = find_math_kern(font(p), character(p),sub_f,sub_c,sub_mark_cmd, shift_down);
if (delta2 == MATH_KERN_NOT_FOUND) {
delta2 = subshift ;
} else {
delta2 = delta2 + subshift ;
+ subtyp = font_kern;
}
} else {
delta2 = subshift ;
}
if (delta2 != 0) {
- p = attach_hkern_to_new_hlist(q, delta2);
+ p = attach_hkern_to_new_hlist(q, delta2, subtyp);
}
- /*
- now the horizontal shift for the superscript; the superscript is also to be shifted
- by |delta1| (the italic correction)
+ /*tex
+
+ Now the horizontal shift for the superscript; the superscript is
+ also to be shifted by |delta1| (the italic correction).
+
*/
clr = MATH_KERN_NOT_FOUND;
if (sup_n != null) {
clr = find_math_kern(font(p),character(p),sup_f,sup_c,sup_mark_cmd,shift_up);
}
+ /*tex
- /* delta can already have been applied and now be 0 */
+ The delta can already have been applied and now be 0.
+
+ */
if (delta2 == MATH_KERN_NOT_FOUND)
delta2 = - supshift ;
else
@@ -3543,18 +3904,17 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
} else {
shift_amount(x) = delta1 - delta2;
}
- /* todo: only if kern != 0 */
+ /*tex todo: only if kern != 0 */
p = new_kern((shift_up - depth(x)) - (height(y) - shift_down));
reset_attributes(p, node_attr(q));
couple_nodes(x,p);
couple_nodes(p,y);
- /* we end up with funny dimensions */
+ /*tex We end up with funny dimensions. */
x = vpackage(x, 0, additional, max_dimen, math_direction_par);
reset_attributes(x, node_attr(q));
shift_amount(x) = shift_down;
}
}
-
if (new_hlist(q) == null) {
new_hlist(q) = x;
} else {
@@ -3575,12 +3935,15 @@ static void make_scripts(pointer q, pointer p, scaled it, int cur_style, scaled
}
}
-@ The |make_left_right| function constructs a left or right delimiter of
-the required size and returns the value |open_noad| or |close_noad|. The
-|left_noad_side| and |right_noad_side| will both be based on the original |style|,
-so they will have consistent sizes.
+/*tex
+
+ The |make_left_right| function constructs a left or right delimiter of the
+ required size and returns the value |open_noad| or |close_noad|. The
+ |left_noad_side| and |right_noad_side| will both be based on the original
+ |style|, so they will have consistent sizes.
+
+*/
-@c
static small_number make_left_right(pointer q, int style, scaled max_d, scaled max_h)
{
scaled delta;
@@ -3589,21 +3952,21 @@ static small_number make_left_right(pointer q, int style, scaled max_d, scaled m
boolean stack = false;
boolean axis = false;
int same = subtype(q);
-
setup_cur_size(style);
-
if ((delimiterheight(q)!=0) || (delimiterdepth(q)!=0)) {
delta = delimiterheight(q) + delimiterdepth(q);
tmp = do_delimiter(q, delimiter(q), cur_size, delta, false, style, false, &stack, &ic, &same);
delimiteritalic(q) = ic;
+ /*tex
- /* beware, a stacked delimiter has a shift but no corrected height/depth (yet) */
+ Beware, a stacked delimiter has a shift but no corrected height/depth
+ (yet).
+ */
if (stack) {
shift_amount(tmp) = delimiterdepth(q);
}
-
if (delimiterexact(q)) {
delimiterheight(q) = height(tmp) - shift_amount(tmp);
delimiterdepth(q) = depth(tmp) + shift_amount(tmp);
@@ -3629,7 +3992,7 @@ static small_number make_left_right(pointer q, int style, scaled max_d, scaled m
}
delimiter(q) = null;
assign_new_hlist(q, tmp);
- delimitersamesize(q) = same; /* new */
+ delimitersamesize(q) = same;
if (delimiterclass(q) >= ord_noad_type) {
if (delimiterclass(q) <= inner_noad_type) {
return delimiterclass(q);
@@ -3643,35 +4006,32 @@ static small_number make_left_right(pointer q, int style, scaled max_d, scaled m
}
}
-@ @c
-#define TEXT_STYLES(A,B) do { \
- def_math_param(A,display_style,(B),level_one); \
- def_math_param(A,cramped_display_style,(B),level_one); \
- def_math_param(A,text_style,(B),level_one); \
- def_math_param(A,cramped_text_style,(B),level_one); \
+#define TEXT_STYLES(A,B) do { \
+ def_math_param(A,display_style,(B),level_one); \
+ def_math_param(A,cramped_display_style,(B),level_one); \
+ def_math_param(A,text_style,(B),level_one); \
+ def_math_param(A,cramped_text_style,(B),level_one); \
} while (0)
-#define SCRIPT_STYLES(A,B) do { \
- def_math_param(A,script_style,(B),level_one); \
- def_math_param(A,cramped_script_style,(B),level_one); \
- def_math_param(A,script_script_style,(B),level_one); \
- def_math_param(A,cramped_script_script_style,(B),level_one); \
+#define SCRIPT_STYLES(A,B) do { \
+ def_math_param(A,script_style,(B),level_one); \
+ def_math_param(A,cramped_script_style,(B),level_one); \
+ def_math_param(A,script_script_style,(B),level_one); \
+ def_math_param(A,cramped_script_script_style,(B),level_one); \
} while (0)
-#define ALL_STYLES(A,B) do { \
- TEXT_STYLES(A,(B)); \
- SCRIPT_STYLES(A,(B)); \
+#define ALL_STYLES(A,B) do { \
+ TEXT_STYLES(A,(B)); \
+ SCRIPT_STYLES(A,(B)); \
} while (0)
-#define SPLIT_STYLES(A,B,C) do { \
- TEXT_STYLES(A,(B)); \
- SCRIPT_STYLES(A,(C)); \
+#define SPLIT_STYLES(A,B,C) do { \
+ TEXT_STYLES(A,(B)); \
+ SCRIPT_STYLES(A,(C)); \
} while (0)
-
void initialize_math_spacing(void)
{
- /* *INDENT-OFF* */
ALL_STYLES (math_param_ord_ord_spacing, 0);
ALL_STYLES (math_param_ord_op_spacing, thin_mu_skip_code);
SPLIT_STYLES (math_param_ord_bin_spacing, med_mu_skip_code, 0);
@@ -3743,10 +4103,8 @@ void initialize_math_spacing(void)
ALL_STYLES (math_param_inner_close_spacing, 0);
SPLIT_STYLES (math_param_inner_punct_spacing, thin_mu_skip_code, 0);
SPLIT_STYLES (math_param_inner_inner_spacing, thin_mu_skip_code, 0);
- /* *INDENT-ON* */
}
-@ @c
#define both_types(A,B) ((A)*16+(B))
static pointer math_spacing_glue(int l_type, int r_type, int mstyle, scaled mmu)
@@ -3758,102 +4116,99 @@ static pointer math_spacing_glue(int l_type, int r_type, int mstyle, scaled mmu)
if (r_type == op_noad_type_limits || r_type == op_noad_type_no_limits)
r_type = op_noad_type_normal;
switch (both_types(l_type, r_type)) {
- /* *INDENT-OFF* */
- case both_types(ord_noad_type, ord_noad_type ): x = get_math_param(math_param_ord_ord_spacing,mstyle); break;
- case both_types(ord_noad_type, op_noad_type_normal): x = get_math_param(math_param_ord_op_spacing,mstyle); break;
- case both_types(ord_noad_type, bin_noad_type ): x = get_math_param(math_param_ord_bin_spacing,mstyle); break;
- case both_types(ord_noad_type, rel_noad_type ): x = get_math_param(math_param_ord_rel_spacing,mstyle); break;
- case both_types(ord_noad_type, open_noad_type ): x = get_math_param(math_param_ord_open_spacing,mstyle); break;
- case both_types(ord_noad_type, close_noad_type ): x = get_math_param(math_param_ord_close_spacing,mstyle); break;
- case both_types(ord_noad_type, punct_noad_type ): x = get_math_param(math_param_ord_punct_spacing,mstyle); break;
- case both_types(ord_noad_type, inner_noad_type ): x = get_math_param(math_param_ord_inner_spacing,mstyle); break;
- case both_types(op_noad_type_normal, ord_noad_type ): x = get_math_param(math_param_op_ord_spacing,mstyle); break;
- case both_types(op_noad_type_normal, op_noad_type_normal): x = get_math_param(math_param_op_op_spacing,mstyle); break;
-#if 0
- case both_types(op_noad_type_normal, bin_noad_type ): x = get_math_param(math_param_op_bin_spacing,mstyle); break;
-#endif
- case both_types(op_noad_type_normal, rel_noad_type ): x = get_math_param(math_param_op_rel_spacing,mstyle); break;
- case both_types(op_noad_type_normal, open_noad_type ): x = get_math_param(math_param_op_open_spacing,mstyle); break;
- case both_types(op_noad_type_normal, close_noad_type ): x = get_math_param(math_param_op_close_spacing,mstyle); break;
- case both_types(op_noad_type_normal, punct_noad_type ): x = get_math_param(math_param_op_punct_spacing,mstyle); break;
- case both_types(op_noad_type_normal, inner_noad_type ): x = get_math_param(math_param_op_inner_spacing,mstyle); break;
- case both_types(bin_noad_type, ord_noad_type ): x = get_math_param(math_param_bin_ord_spacing,mstyle); break;
- case both_types(bin_noad_type, op_noad_type_normal): x = get_math_param(math_param_bin_op_spacing,mstyle); break;
-#if 0
- case both_types(bin_noad_type, bin_noad_type ): x = get_math_param(math_param_bin_bin_spacing,mstyle); break;
- case both_types(bin_noad_type, rel_noad_type ): x = get_math_param(math_param_bin_rel_spacing,mstyle); break;
-#endif
- case both_types(bin_noad_type, open_noad_type ): x = get_math_param(math_param_bin_open_spacing,mstyle); break;
-#if 0
- case both_types(bin_noad_type, close_noad_type ): x = get_math_param(math_param_bin_close_spacing,mstyle); break;
- case both_types(bin_noad_type, punct_noad_type ): x = get_math_param(math_param_bin_punct_spacing,mstyle); break;
-#endif
- case both_types(bin_noad_type, inner_noad_type ): x = get_math_param(math_param_bin_inner_spacing,mstyle); break;
- case both_types(rel_noad_type, ord_noad_type ): x = get_math_param(math_param_rel_ord_spacing,mstyle); break;
- case both_types(rel_noad_type, op_noad_type_normal): x = get_math_param(math_param_rel_op_spacing,mstyle); break;
-#if 0
- case both_types(rel_noad_type, bin_noad_type ): x = get_math_param(math_param_rel_bin_spacing,mstyle); break;
-#endif
- case both_types(rel_noad_type, rel_noad_type ): x = get_math_param(math_param_rel_rel_spacing,mstyle); break;
- case both_types(rel_noad_type, open_noad_type ): x = get_math_param(math_param_rel_open_spacing,mstyle); break;
- case both_types(rel_noad_type, close_noad_type ): x = get_math_param(math_param_rel_close_spacing,mstyle); break;
- case both_types(rel_noad_type, punct_noad_type ): x = get_math_param(math_param_rel_punct_spacing,mstyle); break;
- case both_types(rel_noad_type, inner_noad_type ): x = get_math_param(math_param_rel_inner_spacing,mstyle); break;
- case both_types(open_noad_type, ord_noad_type ): x = get_math_param(math_param_open_ord_spacing,mstyle); break;
- case both_types(open_noad_type, op_noad_type_normal): x = get_math_param(math_param_open_op_spacing,mstyle); break;
-#if 0
- case both_types(open_noad_type, bin_noad_type ): x = get_math_param(math_param_open_bin_spacing,mstyle); break;
-#endif
- case both_types(open_noad_type, rel_noad_type ): x = get_math_param(math_param_open_rel_spacing,mstyle); break;
- case both_types(open_noad_type, open_noad_type ): x = get_math_param(math_param_open_open_spacing,mstyle); break;
- case both_types(open_noad_type, close_noad_type ): x = get_math_param(math_param_open_close_spacing,mstyle); break;
- case both_types(open_noad_type, punct_noad_type ): x = get_math_param(math_param_open_punct_spacing,mstyle); break;
- case both_types(open_noad_type, inner_noad_type ): x = get_math_param(math_param_open_inner_spacing,mstyle); break;
- case both_types(close_noad_type, ord_noad_type ): x = get_math_param(math_param_close_ord_spacing,mstyle); break;
- case both_types(close_noad_type, op_noad_type_normal): x = get_math_param(math_param_close_op_spacing,mstyle); break;
- case both_types(close_noad_type, bin_noad_type ): x = get_math_param(math_param_close_bin_spacing,mstyle); break;
- case both_types(close_noad_type, rel_noad_type ): x = get_math_param(math_param_close_rel_spacing,mstyle); break;
- case both_types(close_noad_type, open_noad_type ): x = get_math_param(math_param_close_open_spacing,mstyle); break;
- case both_types(close_noad_type, close_noad_type ): x = get_math_param(math_param_close_close_spacing,mstyle); break;
- case both_types(close_noad_type, punct_noad_type ): x = get_math_param(math_param_close_punct_spacing,mstyle); break;
- case both_types(close_noad_type, inner_noad_type ): x = get_math_param(math_param_close_inner_spacing,mstyle); break;
- case both_types(punct_noad_type, ord_noad_type ): x = get_math_param(math_param_punct_ord_spacing,mstyle); break;
- case both_types(punct_noad_type, op_noad_type_normal): x = get_math_param(math_param_punct_op_spacing,mstyle); break;
-#if 0
- case both_types(punct_noad_type, bin_noad_type ): x = get_math_param(math_param_punct_bin_spacing,mstyle); break;
-#endif
- case both_types(punct_noad_type, rel_noad_type ): x = get_math_param(math_param_punct_rel_spacing,mstyle); break;
- case both_types(punct_noad_type, open_noad_type ): x = get_math_param(math_param_punct_open_spacing,mstyle); break;
- case both_types(punct_noad_type, close_noad_type ): x = get_math_param(math_param_punct_close_spacing,mstyle); break;
- case both_types(punct_noad_type, punct_noad_type ): x = get_math_param(math_param_punct_punct_spacing,mstyle); break;
- case both_types(punct_noad_type, inner_noad_type ): x = get_math_param(math_param_punct_inner_spacing,mstyle); break;
- case both_types(inner_noad_type, ord_noad_type ): x = get_math_param(math_param_inner_ord_spacing,mstyle); break;
- case both_types(inner_noad_type, op_noad_type_normal): x = get_math_param(math_param_inner_op_spacing,mstyle); break;
- case both_types(inner_noad_type, bin_noad_type ): x = get_math_param(math_param_inner_bin_spacing,mstyle); break;
- case both_types(inner_noad_type, rel_noad_type ): x = get_math_param(math_param_inner_rel_spacing,mstyle); break;
- case both_types(inner_noad_type, open_noad_type ): x = get_math_param(math_param_inner_open_spacing,mstyle); break;
- case both_types(inner_noad_type, close_noad_type ): x = get_math_param(math_param_inner_close_spacing,mstyle); break;
- case both_types(inner_noad_type, punct_noad_type ): x = get_math_param(math_param_inner_punct_spacing,mstyle); break;
- case both_types(inner_noad_type, inner_noad_type ): x = get_math_param(math_param_inner_inner_spacing,mstyle); break;
- /* *INDENT-ON* */
+ case both_types(ord_noad_type, ord_noad_type ): x = get_math_param(math_param_ord_ord_spacing,mstyle); break;
+ case both_types(ord_noad_type, op_noad_type_normal): x = get_math_param(math_param_ord_op_spacing,mstyle); break;
+ case both_types(ord_noad_type, bin_noad_type ): x = get_math_param(math_param_ord_bin_spacing,mstyle); break;
+ case both_types(ord_noad_type, rel_noad_type ): x = get_math_param(math_param_ord_rel_spacing,mstyle); break;
+ case both_types(ord_noad_type, open_noad_type ): x = get_math_param(math_param_ord_open_spacing,mstyle); break;
+ case both_types(ord_noad_type, close_noad_type ): x = get_math_param(math_param_ord_close_spacing,mstyle); break;
+ case both_types(ord_noad_type, punct_noad_type ): x = get_math_param(math_param_ord_punct_spacing,mstyle); break;
+ case both_types(ord_noad_type, inner_noad_type ): x = get_math_param(math_param_ord_inner_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, ord_noad_type ): x = get_math_param(math_param_op_ord_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, op_noad_type_normal): x = get_math_param(math_param_op_op_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(op_noad_type_normal, bin_noad_type ): x = get_math_param(math_param_op_bin_spacing,mstyle); break;
+ /* */
+ case both_types(op_noad_type_normal, rel_noad_type ): x = get_math_param(math_param_op_rel_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, open_noad_type ): x = get_math_param(math_param_op_open_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, close_noad_type ): x = get_math_param(math_param_op_close_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, punct_noad_type ): x = get_math_param(math_param_op_punct_spacing,mstyle); break;
+ case both_types(op_noad_type_normal, inner_noad_type ): x = get_math_param(math_param_op_inner_spacing,mstyle); break;
+ case both_types(bin_noad_type, ord_noad_type ): x = get_math_param(math_param_bin_ord_spacing,mstyle); break;
+ case both_types(bin_noad_type, op_noad_type_normal): x = get_math_param(math_param_bin_op_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(bin_noad_type, bin_noad_type ): x = get_math_param(math_param_bin_bin_spacing,mstyle); break;
+ case both_types(bin_noad_type, rel_noad_type ): x = get_math_param(math_param_bin_rel_spacing,mstyle); break;
+ /* */
+ case both_types(bin_noad_type, open_noad_type ): x = get_math_param(math_param_bin_open_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(bin_noad_type, close_noad_type ): x = get_math_param(math_param_bin_close_spacing,mstyle); break;
+ case both_types(bin_noad_type, punct_noad_type ): x = get_math_param(math_param_bin_punct_spacing,mstyle); break;
+ /* */
+ case both_types(bin_noad_type, inner_noad_type ): x = get_math_param(math_param_bin_inner_spacing,mstyle); break;
+ case both_types(rel_noad_type, ord_noad_type ): x = get_math_param(math_param_rel_ord_spacing,mstyle); break;
+ case both_types(rel_noad_type, op_noad_type_normal): x = get_math_param(math_param_rel_op_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(rel_noad_type, bin_noad_type ): x = get_math_param(math_param_rel_bin_spacing,mstyle); break;
+ /* */
+ case both_types(rel_noad_type, rel_noad_type ): x = get_math_param(math_param_rel_rel_spacing,mstyle); break;
+ case both_types(rel_noad_type, open_noad_type ): x = get_math_param(math_param_rel_open_spacing,mstyle); break;
+ case both_types(rel_noad_type, close_noad_type ): x = get_math_param(math_param_rel_close_spacing,mstyle); break;
+ case both_types(rel_noad_type, punct_noad_type ): x = get_math_param(math_param_rel_punct_spacing,mstyle); break;
+ case both_types(rel_noad_type, inner_noad_type ): x = get_math_param(math_param_rel_inner_spacing,mstyle); break;
+ case both_types(open_noad_type, ord_noad_type ): x = get_math_param(math_param_open_ord_spacing,mstyle); break;
+ case both_types(open_noad_type, op_noad_type_normal): x = get_math_param(math_param_open_op_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(open_noad_type, bin_noad_type ): x = get_math_param(math_param_open_bin_spacing,mstyle); break;
+ /* */
+ case both_types(open_noad_type, rel_noad_type ): x = get_math_param(math_param_open_rel_spacing,mstyle); break;
+ case both_types(open_noad_type, open_noad_type ): x = get_math_param(math_param_open_open_spacing,mstyle); break;
+ case both_types(open_noad_type, close_noad_type ): x = get_math_param(math_param_open_close_spacing,mstyle); break;
+ case both_types(open_noad_type, punct_noad_type ): x = get_math_param(math_param_open_punct_spacing,mstyle); break;
+ case both_types(open_noad_type, inner_noad_type ): x = get_math_param(math_param_open_inner_spacing,mstyle); break;
+ case both_types(close_noad_type, ord_noad_type ): x = get_math_param(math_param_close_ord_spacing,mstyle); break;
+ case both_types(close_noad_type, op_noad_type_normal): x = get_math_param(math_param_close_op_spacing,mstyle); break;
+ case both_types(close_noad_type, bin_noad_type ): x = get_math_param(math_param_close_bin_spacing,mstyle); break;
+ case both_types(close_noad_type, rel_noad_type ): x = get_math_param(math_param_close_rel_spacing,mstyle); break;
+ case both_types(close_noad_type, open_noad_type ): x = get_math_param(math_param_close_open_spacing,mstyle); break;
+ case both_types(close_noad_type, close_noad_type ): x = get_math_param(math_param_close_close_spacing,mstyle); break;
+ case both_types(close_noad_type, punct_noad_type ): x = get_math_param(math_param_close_punct_spacing,mstyle); break;
+ case both_types(close_noad_type, inner_noad_type ): x = get_math_param(math_param_close_inner_spacing,mstyle); break;
+ case both_types(punct_noad_type, ord_noad_type ): x = get_math_param(math_param_punct_ord_spacing,mstyle); break;
+ case both_types(punct_noad_type, op_noad_type_normal): x = get_math_param(math_param_punct_op_spacing,mstyle); break;
+ /* shouldn't happen */
+ case both_types(punct_noad_type, bin_noad_type ): x = get_math_param(math_param_punct_bin_spacing,mstyle); break;
+ /* */
+ case both_types(punct_noad_type, rel_noad_type ): x = get_math_param(math_param_punct_rel_spacing,mstyle); break;
+ case both_types(punct_noad_type, open_noad_type ): x = get_math_param(math_param_punct_open_spacing,mstyle); break;
+ case both_types(punct_noad_type, close_noad_type ): x = get_math_param(math_param_punct_close_spacing,mstyle); break;
+ case both_types(punct_noad_type, punct_noad_type ): x = get_math_param(math_param_punct_punct_spacing,mstyle); break;
+ case both_types(punct_noad_type, inner_noad_type ): x = get_math_param(math_param_punct_inner_spacing,mstyle); break;
+ case both_types(inner_noad_type, ord_noad_type ): x = get_math_param(math_param_inner_ord_spacing,mstyle); break;
+ case both_types(inner_noad_type, op_noad_type_normal): x = get_math_param(math_param_inner_op_spacing,mstyle); break;
+ case both_types(inner_noad_type, bin_noad_type ): x = get_math_param(math_param_inner_bin_spacing,mstyle); break;
+ case both_types(inner_noad_type, rel_noad_type ): x = get_math_param(math_param_inner_rel_spacing,mstyle); break;
+ case both_types(inner_noad_type, open_noad_type ): x = get_math_param(math_param_inner_open_spacing,mstyle); break;
+ case both_types(inner_noad_type, close_noad_type ): x = get_math_param(math_param_inner_close_spacing,mstyle); break;
+ case both_types(inner_noad_type, punct_noad_type ): x = get_math_param(math_param_inner_punct_spacing,mstyle); break;
+ case both_types(inner_noad_type, inner_noad_type ): x = get_math_param(math_param_inner_inner_spacing,mstyle); break;
}
if (x < 0) {
confusion("mathspacing");
}
if (x != 0) {
if (x <= thick_mu_skip_code) {
- /* trap thin/med/thick settings cf. old TeX */
- z = math_glue(glue_par(x), mmu); /* allocates a glue */
- /* store a symbolic subtype */
+ /*tex trap thin/med/thick settings cf.\ old \TeX */
+ z = math_glue(glue_par(x), mmu);
+ /*tex store a symbolic subtype */
subtype(z) = (quarterword) (x + 1);
} else {
- z = math_glue(x, mmu); /* allocates a glue */
+ z = math_glue(x, mmu);
}
}
return z;
}
-@ @c
static pointer check_nucleus_complexity(halfword q, scaled * delta, int cur_style, int *same)
{
pointer p = null;
@@ -3866,37 +4221,36 @@ static pointer check_nucleus_complexity(halfword q, scaled * delta, int cur_styl
case math_text_char_node:
fetch(nucleus(q));
if (char_exists(cur_f, cur_c)) {
- /* we could look at neighbours */
+ /*tex we could look at neighbours */
if (do_new_math(cur_f)) {
- *delta = 0 ; /* cf spec only the last one */
+ /*tex cf spec only the last one */
+ *delta = 0 ;
} else {
*delta = char_italic(cur_f, cur_c);
}
p = new_glyph(cur_f, cur_c);
reset_attributes(p, node_attr(nucleus(q)));
if (do_new_math(cur_f)) {
- if (! math_no_char_italic_par) {
- /* keep italic, but bad with two successive letters */
- } else if (get_char_cat_code(cur_c) == 11) {
- /* no italic correction in mid-word of text font */
+ if (get_char_cat_code(cur_c) == 11) {
+ /*tex no italic correction in mid-word of text font */
*delta = 0;
}
} else {
- /* no italic correction in mid-word of text font */
+ /*tex no italic correction in mid-word of text font */
if (((type(nucleus(q))) == math_text_char_node) && (space(cur_f) != 0)) {
*delta = 0;
}
}
- /* so we only add italic correction when we have no scripts */
+ /*tex so we only add italic correction when we have no scripts */
if ((subscr(q) == null) && (supscr(q) == null) && (*delta != 0)) {
pointer x = new_kern(*delta);
subtype(x) = italic_kern;
reset_attributes(x, node_attr(nucleus(q)));
couple_nodes(p,x);
*delta = 0;
- } else /* needs checking but looks ok */
- if (do_new_math(cur_f)) {
- *delta = char_italic(cur_f, cur_c); /* must be more selective */
+ } else if (do_new_math(cur_f)) {
+ /*tex Needs checking but looks ok. It must be more selective. */
+ *delta = char_italic(cur_f, cur_c);
}
}
break;
@@ -3905,60 +4259,80 @@ static pointer check_nucleus_complexity(halfword q, scaled * delta, int cur_styl
break;
case sub_mlist_node:
t = math_list(nucleus(q));
- mlist_to_hlist(t, false, cur_style); /* recursive call */
-if (same != NULL && type(t) == fence_noad && delimitersamesize(t)) {
- *same = delimitersamesize(t) ;
-}
+ /*tex Recursive call: */
+ mlist_to_hlist(t, false, cur_style);
+ if (same != NULL && type(t) == fence_noad && delimitersamesize(t)) {
+ *same = delimitersamesize(t) ;
+ }
setup_cur_size(cur_style);
p = hpack(vlink(temp_head), 0, additional, -1);
reset_attributes(p, node_attr(nucleus(q)));
break;
default:
- confusion("mlist2"); /* this can't happen mlist2 */
+ confusion("mlist2");
}
return p;
}
-@ Here is the overall plan of |mlist_to_hlist|, and the list of its
- local variables.
+/*tex
+
+ Here is the overall plan of |mlist_to_hlist|, and the list of its local
+ variables.
+
+*/
-@c
void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
{
- pointer q = mlist; /* runs through the mlist */
- pointer r = null; /* the most recent noad preceding |q| */
- int style = cur_style; /* tuck global parameter away as local variable */
- int r_type = simple_noad; /* the |type| of noad |r|, or |op_noad| if |r=null| */
- int r_subtype = op_noad_type_normal; /* the |subtype| of noad |r| if |r_type| is |fence_noad| */
- int t; /* the effective |type| of noad |q| during the second pass */
- int t_subtype; /* the effective |subtype| of noad |q| during the second pass */
+ /*tex runs through the mlist */
+ pointer q = mlist;
+ /*tex the most recent noad preceding |q| */
+ pointer r = null;
+ /*tex tuck global parameter away as local variable */
+ int style = cur_style;
+ /*tex the |type| of noad |r|, or |op_noad| if |r=null| */
+ int r_type = simple_noad;
+ /*tex the |subtype| of noad |r| if |r_type| is |fence_noad| */
+ int r_subtype = op_noad_type_normal;
+ /*tex the effective |type| of noad |q| during the second pass */
+ int t;
+ /*tex the effective |subtype| of noad |q| during the second pass */
+ int t_subtype;
pointer p = null;
pointer pp = null;
pointer z = null;
halfword nxt ;
int same = 0;
- int pen; /* a penalty to be inserted */
- int prepen; /* a penalty to be inserted */
- scaled max_hl = 0; /* maximum height of the list translated so far */
- scaled max_d = 0; /* maximum depth of the list translated so far */
- scaled delta; /* italic correction offset for subscript and superscript */
- scaled cur_mu; /* the math unit width corresponding to |cur_size| */
+ /*tex a penalty to be inserted */
+ int pen;
+ /*tex a penalty to be inserted */
+ int prepen;
+ /*tex maximum height of the list translated so far */
+ scaled max_hl = 0;
+ /*tex maximum depth of the list translated so far */
+ scaled max_d = 0;
+ /*tex italic correction offset for subscript and superscript */
+ scaled delta;
+ /*tex the math unit width corresponding to |cur_size| */
+ scaled cur_mu;
r_subtype = op_noad_type_normal;
setup_cur_size(cur_style);
cur_mu = x_over_n(get_math_quad_size(cur_size), 18);
if (math_penalties_mode_par) {
- /* we could do this via the callback but it's nice to have it as primitive too */
+ /*tex
+ We could do this via the callback but it's nice to have it as
+ primitive too.
+ */
penalties = 1;
}
while (q != null) {
- /*
- we use the fact that no character nodes appear in an mlist, hence
- the field |type(q)| is always present.
+ /*tex
- one of the things we must do on the first pass is change a |bin_noad| to
- an |ord_noad| if the |bin_noad| is not in the context of a binary operator
+ We use the fact that no character nodes appear in an mlist, hence the
+ field |type(q)| is always present.One of the things we must do on the
+ first pass is change a |bin_noad| to an |ord_noad| if the |bin_noad|
+ is not in the context of a binary operator. The values of |r| and
+ |r_type| make this fairly easy.
- the values of |r| and |r_type| make this fairly easy
*/
RESWITCH:
delta = 0;
@@ -3966,66 +4340,69 @@ void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
switch (type(q)) {
case simple_noad:
switch (subtype(q)) {
- case bin_noad_type:
- switch (r_type) {
- case simple_noad:
- switch (r_subtype) {
- case bin_noad_type:
- case op_noad_type_normal:
- case op_noad_type_limits:
- case op_noad_type_no_limits:
- case rel_noad_type:
- case open_noad_type:
- case punct_noad_type:
- subtype(q) = ord_noad_type;
- goto RESWITCH;
- break;
+ case bin_noad_type:
+ switch (r_type) {
+ case simple_noad:
+ switch (r_subtype) {
+ case bin_noad_type:
+ case op_noad_type_normal:
+ case op_noad_type_limits:
+ case op_noad_type_no_limits:
+ case rel_noad_type:
+ case open_noad_type:
+ case punct_noad_type:
+ subtype(q) = ord_noad_type;
+ goto RESWITCH;
+ break;
+ }
+ break;
+ case fence_noad:
+ if (r_subtype == left_noad_side) {
+ /*tex So these can best be the same size. */
+ subtype(q) = ord_noad_type;
+ goto RESWITCH;
+ }
+ break;
}
break;
- case fence_noad:
- if (r_subtype == left_noad_side) {
- subtype(q) = ord_noad_type; /* so these can best be the same size */
- goto RESWITCH;
+ case over_noad_type:
+ make_over(q, cur_style, cur_size, math_rules_fam_par);
+ break;
+ case under_noad_type:
+ make_under(q, cur_style, cur_size, math_rules_fam_par);
+ break;
+ case vcenter_noad_type:
+ make_vcenter(q);
+ break;
+ case rel_noad_type:
+ case close_noad_type:
+ case punct_noad_type:
+ if (r_type == simple_noad && r_subtype == bin_noad_type) {
+ /*tex Assumes the same size; can't this go. */
+ type(r) = simple_noad;
+ subtype(r) = ord_noad_type;
}
break;
- }
- break;
- case over_noad_type:
- make_over(q, cur_style, cur_size, math_rules_fam_par);
- break;
- case under_noad_type:
- make_under(q, cur_style, cur_size, math_rules_fam_par);
- break;
- case vcenter_noad_type:
- make_vcenter(q);
- break;
- case rel_noad_type:
- case close_noad_type:
- case punct_noad_type:
- if (r_type == simple_noad && r_subtype == bin_noad_type) {
- type(r) = simple_noad; /* assumes the same size .. can't this go */
- subtype(r) = ord_noad_type;
- }
- break;
- case op_noad_type_normal:
- case op_noad_type_limits:
- case op_noad_type_no_limits:
- delta = make_op(q, cur_style);
- if ((subtype(q) == op_noad_type_limits) || (subtype(q) == op_noad_type_no_limits))
- goto CHECK_DIMENSIONS;
- break;
- case ord_noad_type:
- make_ord(q);
- break;
- case open_noad_type:
- case inner_noad_type:
- break;
+ case op_noad_type_normal:
+ case op_noad_type_limits:
+ case op_noad_type_no_limits:
+ delta = make_op(q, cur_style);
+ if ((subtype(q) == op_noad_type_limits) || (subtype(q) == op_noad_type_no_limits))
+ goto CHECK_DIMENSIONS;
+ break;
+ case ord_noad_type:
+ make_ord(q);
+ break;
+ case open_noad_type:
+ case inner_noad_type:
+ break;
}
break;
case fence_noad:
if (subtype(q) != left_noad_side) {
if (r_type == simple_noad && r_subtype == bin_noad_type) {
- type(r) = simple_noad; /* assumes the same size */
+ /*tex Assumes the same size. */
+ type(r) = simple_noad;
subtype(r) = ord_noad_type;
}
}
@@ -4060,16 +4437,20 @@ void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
break;
case choice_node:
switch (cur_style / 2) {
- case 0: /* |display_style=0| */
+ case 0:
+ /*tex |display_style=0| */
choose_mlist(display_mlist);
break;
- case 1: /* |text_style=2| */
+ case 1:
+ /*tex |text_style=2| */
choose_mlist(text_mlist);
break;
- case 2: /* |script_style=4| */
+ case 2:
+ /*tex |script_style=4| */
choose_mlist(script_mlist);
break;
- case 3: /* |script_script_style=6| */
+ case 3:
+ /*tex |script_script_style=6| */
choose_mlist(script_script_mlist);
break;
}
@@ -4105,14 +4486,16 @@ void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
goto DONE_WITH_NODE;
break;
case glue_node:
- /*
- conditional math glue (`\.{\\nonscript}') results in a |glue_node|
- pointing to |zero_glue|, with |subtype(q)=cond_math_glue|; in such a case
- the node following will be eliminated if it is a glue or kern node and if the
- current size is different from |text_size|
+ /*tex
+
+ Conditional math glue (`\.{\\nonscript}') results in a
+ |glue_node| pointing to |zero_glue|, with
+ |subtype(q)=cond_math_glue|; in such a case the node
+ following will be eliminated if it is a glue or kern node and
+ if the current size is different from |text_size|.
- unconditional math glue (`\.{\\muskip}') is converted to normal glue by
- multiplying the dimensions by |cur_mu|
+ Unconditional math glue (`\.{\\muskip}') is converted to
+ normal glue by multiplying the dimensions by |cur_mu|.
*/
if (subtype(q) == mu_glue) {
@@ -4139,29 +4522,31 @@ void mlist_to_hlist(pointer mlist, boolean penalties, int cur_style)
default:
confusion("mlist1");
}
- /*
- When we get to the following part of the program, we have ``fallen through''
- from cases that did not lead to |check_dimensions| or |done_with_noad| or
- |done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be
- converted to an hlist, and whose subscripts and superscripts need to be
- appended if they are present.
+ /*tex
- If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount
- by which a superscript should be moved right with respect to a subscript
- when both are present.
+ When we get to the following part of the program, we have ``fallen
+ through'' from cases that did not lead to |check_dimensions| or
+ |done_with_noad| or |done_with_node|. Thus, |q|~points to a noad
+ whose nucleus may need to be converted to an hlist, and whose
+ subscripts and superscripts need to be appended if they are present.
+
+ If |nucleus(q)| is not a |math_char|, the variable |delta| is the
+ amount by which a superscript should be moved right with respect to a
+ subscript when both are present.
*/
-same = 0 ;
+ same = 0 ;
p = check_nucleus_complexity(q, &delta, cur_style, &same);
-if (same) {
- noadextra4(q) = same ;
-}
+ if (same) {
+ noadextra4(q) = same ;
+ }
if ((subscr(q) == null) && (supscr(q) == null)) {
- /*
+ /*tex
+
Adding italic correction here is kind of fuzzy because some
- characters already have that built in. However, we also add
- it in the scripts so if it's optional here it also should
- be there.
+ characters already have that built in. However, we also add it in
+ the scripts so if it's optional here it also should be there.
+
*/
if (nxt && (math_italics_mode_par > 0) && (delta != 0)) {
if (type(nxt) == simple_noad) {
@@ -4199,7 +4584,7 @@ if (same) {
}
assign_new_hlist(q, p);
} else {
- /* top, bottom */
+ /*tex top, bottom */
make_scripts(q, p, delta, cur_style, 0, 0);
}
CHECK_DIMENSIONS:
@@ -4209,7 +4594,7 @@ if (same) {
if (depth(z) > max_d)
max_d = depth(z);
list_ptr(z) = null;
- /* only drop the \.{\\hbox} */
+ /*tex only drop the \.{\\hbox} */
flush_node(z);
DONE_WITH_NOAD:
r = q;
@@ -4219,7 +4604,8 @@ if (same) {
r_subtype = left_noad_side;
cur_style = style;
setup_cur_size(cur_style);
- cur_mu = x_over_n(get_math_quad_size(cur_size), 18); /* style */
+ /*tex style */
+ cur_mu = x_over_n(get_math_quad_size(cur_size), 18);
}
DONE_WITH_NODE:
q = vlink(q);
@@ -4228,15 +4614,18 @@ if (same) {
type(r) = simple_noad;
subtype(r) = ord_noad_type;
}
- /*
+ /*tex
+
Make a second pass over the mlist, removing all noads and inserting the
proper spacing and penalties.
- We have now tied up all the loose ends of the first pass of |mlist_to_hlist|.
- The second pass simply goes through and hooks everything together with the
- proper glue and penalties. It also handles the |fence_noad|s that
- might be present, since |max_hl| and |max_d| are now known. Variable |p| points
- to a node at the current end of the final hlist.
+ We have now tied up all the loose ends of the first pass of
+ |mlist_to_hlist|. The second pass simply goes through and hooks
+ everything together with the proper glue and penalties. It also handles
+ the |fence_noad|s that might be present, since |max_hl| and |max_d| are
+ now known. Variable |p| points to a node at the current end of the final
+ hlist.
+
*/
p = temp_head;
vlink(p) = null;
@@ -4248,15 +4637,18 @@ if (same) {
cur_mu = x_over_n(get_math_quad_size(cur_size), 18);
NEXT_NODE:
while (q != null) {
- /*
+ /*tex
+
If node |q| is a style node, change the style and |goto delete_q|;
- otherwise if it is not a noad, put it into the hlist,
- advance |q|, and |goto done|; otherwise set |s| to the size
- of noad |q|, set |t| to the associated type (|ord_noad..
- inner_noad|), and set |pen| to the associated penalty
+ otherwise if it is not a noad, put it into the hlist, advance |q|,
+ and |goto done|; otherwise set |s| to the size of noad |q|, set |t|
+ to the associated type (|ord_noad.. inner_noad|), and set |pen| to
+ the associated penalty.
+
+ Just before doing the big |case| switch in the second pass, the
+ program sets up default values so that most of the branches are
+ short.
- Just before doing the big |case| switch in the second pass, the program
- sets up default values so that most of the branches are short.
*/
t = simple_noad;
t_subtype = ord_noad_type;
@@ -4292,7 +4684,7 @@ if (same) {
t_subtype = make_left_right(q, style, max_d, max_hl);
break;
case style_node:
- /* Change the current style and |goto delete_q| */
+ /*tex Change the current style and |goto delete_q| */
cur_style = subtype(q);
setup_cur_size(cur_style);
cur_mu = x_over_n(get_math_quad_style(cur_style), 18);
@@ -4316,34 +4708,36 @@ if (same) {
default:
confusion("mlist3");
}
- /* Append inter-element spacing based on |r_type| and |t| */
+ /*tex Append inter-element spacing based on |r_type| and |t| */
if (r_type > 0) {
- /* not the first noad */
+ /*tex not the first noad */
pp = p;
-if (delimitermodeordinal && t_subtype == inner_noad_type && noadextra4(q) == 1) {
- z = math_spacing_glue(r_subtype, ord_noad_type, cur_style, cur_mu);
-} else {
- z = math_spacing_glue(r_subtype, t_subtype, cur_style, cur_mu);
-}
+ if (delimitermodeordinal && t_subtype == inner_noad_type && noadextra4(q) == 1) {
+ z = math_spacing_glue(r_subtype, ord_noad_type, cur_style, cur_mu);
+ } else {
+ z = math_spacing_glue(r_subtype, t_subtype, cur_style, cur_mu);
+ }
if (z != null) {
reset_attributes(z, node_attr(p));
couple_nodes(p,z);
p = z;
}
if (penalties && prepen < inf_penalty && type(pp) != penalty_node) {
- /* no checking of prev node type */
+ /*tex no checking of prev node type */
z = new_penalty(prepen,noad_penalty);
reset_attributes(z, node_attr(p));
couple_nodes(p,z);
p = z;
}
}
- /*
- Append any |new_hlist| entries for |q|, and any appropriate penalties
+ /*tex
+
+ Append any |new_hlist| entries for |q|, and any appropriate
+ penalties. We insert a penalty node after the hlist entries of noad
+ |q| if |pen| is not an ``infinite'' penalty, and if the node
+ immediately following |q| is not a penalty node or a |rel_noad| or
+ absent entirely.
- We insert a penalty node after the hlist entries of noad |q| if |pen|
- is not an ``infinite'' penalty, and if the node immediately following |q|
- is not a penalty node or a |rel_noad| or absent entirely.
*/
if (new_hlist(q) != null) {
couple_nodes(p,new_hlist(q));
@@ -4370,12 +4764,13 @@ if (delimitermodeordinal && t_subtype == inner_noad_type && noadextra4(q) == 1)
DELETE_Q:
r = q;
q = vlink(q);
- /*
- The m-to-hlist conversion takes place in-place, so the various dependant
- fields may not be freed (as would happen if |flush_node| was called).
+ /*tex
+
+ The m-to-hlist conversion takes place in-place, so the various
+ dependant fields may not be freed (as would happen if |flush_node|
+ was called). A low-level |free_node| is easier than attempting to
+ nullify such dependant fields for all possible node and noad types.
- A low-level |free_node| is easier than attempting to nullify such dependant
- fields for all possible node and noad types.
*/
if (nodetype_has_attributes(type(r))) {
delete_attribute_ref(node_attr(r));
diff --git a/Build/source/texk/web2c/luatexdir/tex/nesting.c b/Build/source/texk/web2c/luatexdir/tex/nesting.c
new file mode 100644
index 00000000000..0e50c1031dc
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/nesting.c
@@ -0,0 +1,429 @@
+/*
+
+nesting.w
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex These are for |show_activities|: */
+
+#define page_goal page_so_far[0]
+
+/*tex
+
+\TeX\ is typically in the midst of building many lists at once. For example, when
+a math formula is being processed, \TeX\ is in math mode and working on an mlist;
+this formula has temporarily interrupted \TeX\ from being in horizontal mode and
+building the hlist of a paragraph; and this paragraph has temporarily interrupted
+\TeX\ from being in vertical mode and building the vlist for the next page of a
+document. Similarly, when a \.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is
+temporarily interrupted from working in restricted horizontal mode, and it enters
+internal vertical mode. The ``semantic nest'' is a stack that keeps track of what
+lists and modes are currently suspended.
+
+At each level of processing we are in one of six modes:
+
+|vmode| stands for vertical mode (the page builder);
+
+|hmode| stands for horizontal mode (the paragraph builder);
+
+|mmode| stands for displayed formula mode;
+
+|-vmode| stands for internal vertical mode (e.g., in a \.{\\vbox});
+
+|-hmode| stands for restricted horizontal mode (e.g., in an \.{\\hbox});
+
+|-mmode| stands for math formula mode (not displayed).
+
+The mode is temporarily set to zero while processing \.{\\write} texts in the
+|ship_out| routine.
+
+Numeric values are assigned to |vmode|, |hmode|, and |mmode| so that \TeX's ``big
+semantic switch'' can select the appropriate thing to do by computing the value
+|abs(mode)+cur_cmd|, where |mode| is the current mode and |cur_cmd| is the
+current command code.
+
+*/
+
+static const char *string_mode(int m)
+{
+ if (m > 0) {
+ switch (m / (max_command_cmd + 1)) {
+ case 0:
+ return "vertical mode";
+ break;
+ case 1:
+ return "horizontal mode";
+ break;
+ case 2:
+ return "display math mode";
+ break;
+ default:
+ break;
+ }
+ } else if (m == 0) {
+ return "no mode";
+ } else {
+ switch ((-m) / (max_command_cmd + 1)) {
+ case 0:
+ return "internal vertical mode";
+ break;
+ case 1:
+ return "restricted horizontal mode";
+ break;
+ case 2:
+ return "math mode";
+ break;
+ default:
+ break;
+ }
+ }
+ return "unknown mode";
+}
+
+void print_mode(int m)
+{
+ tprint(string_mode(m));
+}
+
+void print_in_mode(int m)
+{
+ tprint("' in ");
+ tprint(string_mode(m));
+}
+
+int get_mode_id(void)
+{
+ int m = cur_list.mode_field;
+ if (m > 0) {
+ switch (m / (max_command_cmd + 1)) {
+ case 0:
+ return 'v';
+ break;
+ case 1:
+ return 'h';
+ break;
+ case 2:
+ return 'm';
+ break;
+ default:
+ return '\0';
+ break;
+ }
+ } else if (m == 0) {
+ return 'n';;
+ } else {
+ switch ((-m) / (max_command_cmd + 1)) {
+ case 0:
+ return 'V';
+ break;
+ case 1:
+ return 'H';
+ break;
+ case 2:
+ return 'M';
+ break;
+ default:
+ return '\0';
+ break;
+ }
+ }
+}
+
+/*tex
+
+The state of affairs at any semantic level can be represented by five values:
+
+|mode| is the number representing the semantic mode, as just explained.
+
+|head| is a |pointer| to a list head for the list being built; |link(head)|
+therefore points to the first element of the list, or to |null| if the list is
+empty.
+
+|tail| is a |pointer| to the final node of the list being built; thus,
+|tail=head| if and only if the list is empty.
+
+|prev_graf| is the number of lines of the current paragraph that have already
+been put into the present vertical list.
+
+|aux| is an auxiliary |memory_word| that gives further information that is needed
+to characterize the situation.
+
+In vertical mode, |aux| is also known as |prev_depth|; it is the scaled value
+representing the depth of the previous box, for use in baseline calculations, or
+it is |<=-1000|pt if the next box on the vertical list is to be exempt from
+baseline calculations. In horizontal mode, |aux| is also known as |space_factor|;
+it holds the current space factor used in spacing calculations. In math mode,
+|aux| is also known as |incompleat_noad|; if not |null|, it points to a record
+that represents the numerator of a generalized fraction for which the denominator
+is currently being formed in the current list.
+
+There is also a sixth quantity, |mode_line|, which correlates the semantic nest
+with the user's input; |mode_line| contains the source line number at which the
+current level of nesting was entered. The negative of this line number is the
+|mode_line| at the level of the user's output routine.
+
+A seventh quantity, |eTeX_aux|, is used by the extended features eTeX. In math
+mode it is known as |delim_ptr| and points to the most recent |fence_noad| of a
+|math_left_group|.
+
+In horizontal mode, the |prev_graf| field is used for initial language data.
+
+The semantic nest is an array called |nest| that holds the |mode|, |head|,
+|tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels below
+the currently active one. Information about the currently active level is kept in
+the global quantities |mode|, |head|, |tail|, |prev_graf|, |aux|, and
+|mode_line|, which live in a struct that is ready to be pushed onto |nest| if
+necessary.
+
+The math field is used by various bits and pieces in |texmath.w|
+
+This implementation of \TeX\ uses two different conventions for representing
+sequential stacks. @^stack conventions@>@^conventions for representing stacks@>
+
+1) If there is frequent access to the top entry, and if the stack is essentially
+never empty, then the top entry is kept in a global variable (even better would
+be a machine register), and the other entries appear in the array
+$\\{stack}[0\to(\\{ptr}-1)]$. The semantic stack is handled this way.
+
+2) If there is infrequent top access, the entire stack contents are in the array
+$\\{stack}[0\to(\\{ptr}-1)]$. For example, the |save_stack| is treated this way,
+as we have seen.
+
+In |nest_ptr| we have the first unused location of |nest|, and |max_nest_stack|
+has the maximum of |nest_ptr| when pushing. In |shown_mode| we store the most
+recent mode shown by \.{\\tracingcommands} and with |save_tail| we can examine
+whether we have an auto kern before a glue.
+
+*/
+
+list_state_record *nest;
+int nest_ptr, max_nest_stack, shown_mode;
+halfword save_tail;
+
+/*tex
+
+We will see later that the vertical list at the bottom semantic level is split
+into two parts; the ``current page'' runs from |page_head| to |page_tail|, and
+the ``contribution list'' runs from |contrib_head| to |tail| of semantic level
+zero. The idea is that contributions are first formed in vertical mode, then
+``contributed'' to the current page (during which time the page-breaking
+decisions are made). For now, we don't need to know any more details about the
+page-building process.
+
+*/
+
+void initialize_nesting(void)
+{
+ nest_ptr = 0;
+ max_nest_stack = 0;
+ shown_mode = 0;
+ cur_list.mode_field = vmode;
+ cur_list.head_field = contrib_head;
+ cur_list.tail_field = contrib_head;
+ cur_list.eTeX_aux_field = null;
+ cur_list.prev_depth_field = ignore_depth;
+ cur_list.space_factor_field = 1000;
+ cur_list.incompleat_noad_field = null;
+ cur_list.ml_field = 0;
+ cur_list.pg_field = 0;
+ cur_list.dirs_field = null;
+ init_math_fields();
+}
+
+/*tex
+
+Here is a common way to make the current list grow:
+
+*/
+
+void tail_append(halfword p)
+{
+ couple_nodes(cur_list.tail_field, p);
+ cur_list.tail_field = vlink(cur_list.tail_field);
+}
+
+halfword pop_tail(void)
+{
+ halfword n, r;
+ if (cur_list.tail_field != cur_list.head_field) {
+ r = cur_list.tail_field;
+ if (vlink(alink(cur_list.tail_field)) == cur_list.tail_field) {
+ n = alink(cur_list.tail_field);
+ } else {
+ n = cur_list.head_field;
+ while (vlink(n) != cur_list.tail_field)
+ n = vlink(n);
+ }
+ flush_node(cur_list.tail_field);
+ cur_list.tail_field = n;
+ vlink(n) = null;
+ return r;
+ } else {
+ return null;
+ }
+}
+
+/*tex
+
+When \TeX's work on one level is interrupted, the state is saved by calling
+|push_nest|. This routine changes |head| and |tail| so that a new (empty) list is
+begun; it does not change |mode| or |aux|.
+
+*/
+
+void push_nest(void)
+{
+ if (nest_ptr > max_nest_stack) {
+ max_nest_stack = nest_ptr;
+ if (nest_ptr == nest_size)
+ overflow("semantic nest size", (unsigned) nest_size);
+ }
+ incr(nest_ptr);
+ cur_list.mode_field = nest[nest_ptr - 1].mode_field;
+ cur_list.head_field = new_node(temp_node, 0);
+ cur_list.tail_field = cur_list.head_field;
+ cur_list.eTeX_aux_field = null;
+ cur_list.ml_field = line;
+ cur_list.pg_field = 0;
+ cur_list.dirs_field = null;
+ cur_list.prev_depth_field = nest[nest_ptr - 1].prev_depth_field;
+ cur_list.space_factor_field = nest[nest_ptr - 1].space_factor_field;
+ cur_list.incompleat_noad_field = nest[nest_ptr - 1].incompleat_noad_field;
+ init_math_fields();
+}
+
+/*tex
+
+Conversely, when \TeX\ is finished on the current level, the former state is
+restored by calling |pop_nest|. This routine will never be called at the lowest
+semantic level, nor will it be called unless |head| is a node that should be
+returned to free memory.
+
+*/
+
+void pop_nest(void)
+{
+ flush_node(cur_list.head_field);
+ decr(nest_ptr);
+}
+
+/*tex
+
+Here is a procedure that displays what \TeX\ is working on, at all levels.
+
+*/
+
+void show_activities(void)
+{
+ /*tex Index into |nest|: */
+ int p;
+ /*tex The mode: */
+ int m;
+ /*tex For showing the current page: */
+ halfword q, r;
+ /*tex Ditto: */
+ int t;
+ tprint_nl("");
+ print_ln();
+ for (p = nest_ptr; p >= 0; p--) {
+ m = nest[p].mode_field;
+ tprint_nl("### ");
+ print_mode(m);
+ tprint(" entered at line ");
+ print_int(abs(nest[p].ml_field));
+ if (nest[p].ml_field < 0)
+ tprint(" (\\output routine)");
+ if (p == 0) {
+ /*tex Show the status of the current page */
+ if (page_head != page_tail) {
+ tprint_nl("### current page:");
+ if (output_active)
+ tprint(" (held over for next output)");
+ show_box(vlink(page_head));
+ if (page_contents > empty) {
+ tprint_nl("total height ");
+ print_totals();
+ tprint_nl(" goal height ");
+ print_scaled(page_goal);
+ r = vlink(page_ins_head);
+ while (r != page_ins_head) {
+ print_ln();
+ tprint_esc("insert");
+ t = subtype(r);
+ print_int(t);
+ tprint(" adds ");
+ if (count(t) == 1000)
+ t = height(r);
+ else
+ t = x_over_n(height(r), 1000) * count(t);
+ print_scaled(t);
+ if (type(r) == split_up_node) {
+ q = page_head;
+ t = 0;
+ do {
+ q = vlink(q);
+ if ((type(q) == ins_node)
+ && (subtype(q) == subtype(r)))
+ incr(t);
+ } while (q != broken_ins(r));
+ tprint(", #");
+ print_int(t);
+ tprint(" might split");
+ }
+ r = vlink(r);
+ }
+ }
+ }
+ if (vlink(contrib_head) != null)
+ tprint_nl("### recent contributions:");
+ }
+ show_box(vlink(nest[p].head_field));
+ /*tex Show the auxiliary field, |a|. */
+ switch (abs(m) / (max_command_cmd + 1)) {
+ case 0:
+ tprint_nl("prevdepth ");
+ if (nest[p].prev_depth_field <= ignore_depth)
+ tprint("ignored");
+ else
+ print_scaled(nest[p].prev_depth_field);
+ if (nest[p].pg_field != 0) {
+ tprint(", prevgraf ");
+ print_int(nest[p].pg_field);
+ if (nest[p].pg_field != 1)
+ tprint(" lines");
+ else
+ tprint(" line");
+ }
+ break;
+ case 1:
+ tprint_nl("spacefactor ");
+ print_int(nest[p].space_factor_field);
+ break;
+ case 2:
+ if (nest[p].incompleat_noad_field != null) {
+ tprint("this will be denominator of:");
+ show_box(nest[p].incompleat_noad_field);
+ }
+ break;
+ }
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/nesting.w b/Build/source/texk/web2c/luatexdir/tex/nesting.w
deleted file mode 100644
index d9e7cf744ee..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/nesting.w
+++ /dev/null
@@ -1,436 +0,0 @@
-% nesting.w
-%
-% Copyright 2009-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"
-
-@ these are for |show_activities|
-@c
-#define page_goal page_so_far[0]
-
-@ \TeX\ is typically in the midst of building many lists at once. For example,
-when a math formula is being processed, \TeX\ is in math mode and
-working on an mlist; this formula has temporarily interrupted \TeX\ from
-being in horizontal mode and building the hlist of a paragraph; and this
-paragraph has temporarily interrupted \TeX\ from being in vertical mode
-and building the vlist for the next page of a document. Similarly, when a
-\.{\\vbox} occurs inside of an \.{\\hbox}, \TeX\ is temporarily
-interrupted from working in restricted horizontal mode, and it enters
-internal vertical mode. The ``semantic nest'' is a stack that
-keeps track of what lists and modes are currently suspended.
-
-At each level of processing we are in one of six modes:
-
-\yskip\hang|vmode| stands for vertical mode (the page builder);
-
-\hang|hmode| stands for horizontal mode (the paragraph builder);
-
-\hang|mmode| stands for displayed formula mode;
-
-\hang|-vmode| stands for internal vertical mode (e.g., in a \.{\\vbox});
-
-\hang|-hmode| stands for restricted horizontal mode (e.g., in an \.{\\hbox});
-
-\hang|-mmode| stands for math formula mode (not displayed).
-
-\yskip\noindent The mode is temporarily set to zero while processing \.{\\write}
-texts in the |ship_out| routine.
-
-Numeric values are assigned to |vmode|, |hmode|, and |mmode| so that
-\TeX's ``big semantic switch'' can select the appropriate thing to
-do by computing the value |abs(mode)+cur_cmd|, where |mode| is the current
-mode and |cur_cmd| is the current command code.
-
-@c
-static const char *string_mode(int m)
-{ /* prints the mode represented by |m| */
- if (m > 0) {
- switch (m / (max_command_cmd + 1)) {
- case 0:
- return "vertical mode";
- break;
- case 1:
- return "horizontal mode";
- break;
- case 2:
- return "display math mode";
- break;
- default:
- break;
- }
- } else if (m == 0) {
- return "no mode";
- } else {
- switch ((-m) / (max_command_cmd + 1)) {
- case 0:
- return "internal vertical mode";
- break;
- case 1:
- return "restricted horizontal mode";
- break;
- case 2:
- return "math mode";
- break;
- default:
- break;
- }
- }
- return "unknown mode";
-}
-
-@ @c
-void print_mode(int m)
-{ /* prints the mode represented by |m| */
- tprint(string_mode(m));
-}
-
-@ @c
-void print_in_mode(int m)
-{ /* prints the mode represented by |m| */
- tprint("' in ");
- tprint(string_mode(m));
-}
-
-@ @c
-int get_mode_id(void)
-{ /* returns the mode represented by |m| */
- int m = cur_list.mode_field;
- if (m > 0) {
- switch (m / (max_command_cmd + 1)) {
- case 0:
- return 'v';
- break;
- case 1:
- return 'h';
- break;
- case 2:
- return 'm';
- break;
- default:
- return '\0';
- break;
- }
- } else if (m == 0) {
- return 'n';;
- } else {
- switch ((-m) / (max_command_cmd + 1)) {
- case 0:
- return 'V';
- break;
- case 1:
- return 'H';
- break;
- case 2:
- return 'M';
- break;
- default:
- return '\0';
- break;
- }
- }
-}
-
-
-@ The state of affairs at any semantic level can be represented by
-five values:
-
-\yskip\hang|mode| is the number representing the semantic mode, as
-just explained.
-
-\yskip\hang|head| is a |pointer| to a list head for the list being built;
-|link(head)| therefore points to the first element of the list, or
-to |null| if the list is empty.
-
-\yskip\hang|tail| is a |pointer| to the final node of the list being
-built; thus, |tail=head| if and only if the list is empty.
-
-\yskip\hang|prev_graf| is the number of lines of the current paragraph that
-have already been put into the present vertical list.
-
-\yskip\hang|aux| is an auxiliary |memory_word| that gives further information
-that is needed to characterize the situation.
-
-\yskip\noindent
-In vertical mode, |aux| is also known as |prev_depth|; it is the scaled
-value representing the depth of the previous box, for use in baseline
-calculations, or it is |<=-1000|pt if the next box on the vertical list is to
-be exempt from baseline calculations. In horizontal mode, |aux| is also
-known as |space_factor|; it holds the current space factor used in
-spacing calculations. In math mode, |aux| is also known as |incompleat_noad|;
-if not |null|, it points to a record that represents the numerator of a
-generalized fraction for which the denominator is currently being formed
-in the current list.
-
-There is also a sixth quantity, |mode_line|, which correlates
-the semantic nest with the user's input; |mode_line| contains the source
-line number at which the current level of nesting was entered. The negative
-of this line number is the |mode_line| at the level of the
-user's output routine.
-
-A seventh quantity, |eTeX_aux|, is used by the extended features eTeX.
-In math mode it is known as |delim_ptr| and points to the most
-recent |fence_noad| of a |math_left_group|.
-
-In horizontal mode, the |prev_graf| field is used for initial language data.
-
-The semantic nest is an array called |nest| that holds the |mode|, |head|,
-|tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels
-below the currently active one. Information about the currently active
-level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|,
-|aux|, and |mode_line|, which live in a struct that is ready to
-be pushed onto |nest| if necessary.
-
-The math field is used by various bits and pieces in |texmath.w|
-
-@ This implementation of
-\TeX\ uses two different conventions for representing sequential stacks.
-@^stack conventions@>@^conventions for representing stacks@>
-
-\yskip\hang 1) If there is frequent access to the top entry, and if the
-stack is essentially never empty, then the top entry is kept in a global
-variable (even better would be a machine register), and the other entries
-appear in the array $\\{stack}[0\to(\\{ptr}-1)]$. The
-semantic stack is handled this way.
-
-\yskip\hang 2) If there is infrequent top access, the entire stack contents
-are in the array $\\{stack}[0\to(\\{ptr}-1)]$. For example, the |save_stack|
-is treated this way, as we have seen.
-
-@c
-list_state_record *nest;
-int nest_ptr; /* first unused location of |nest| */
-int max_nest_stack; /* maximum of |nest_ptr| when pushing */
-int shown_mode; /* most recent mode shown by \.{\\tracingcommands} */
-halfword save_tail; /* save |tail| so we can examine whether we have an auto
- kern before a glue */
-
-@ We will see later that the vertical list at the bottom semantic level is split
-into two parts; the ``current page'' runs from |page_head| to |page_tail|,
-and the ``contribution list'' runs from |contrib_head| to |tail| of
-semantic level zero. The idea is that contributions are first formed in
-vertical mode, then ``contributed'' to the current page (during which time
-the page-breaking decisions are made). For now, we don't need to know
-any more details about the page-building process.
-
-@c
-void initialize_nesting(void)
-{
- nest_ptr = 0;
- max_nest_stack = 0;
- shown_mode = 0;
- cur_list.mode_field = vmode;
- cur_list.head_field = contrib_head;
- cur_list.tail_field = contrib_head;
- cur_list.eTeX_aux_field = null;
- cur_list.prev_depth_field = ignore_depth;
- cur_list.space_factor_field = 1000;
- cur_list.incompleat_noad_field = null;
- cur_list.ml_field = 0;
- cur_list.pg_field = 0;
- cur_list.dirs_field = null;
- init_math_fields();
-}
-
-@ Here is a common way to make the current list grow:
-
-@c
-void tail_append(halfword p)
-{
- couple_nodes(cur_list.tail_field, p);
- cur_list.tail_field = vlink(cur_list.tail_field);
-}
-
-@ @c
-halfword pop_tail(void)
-{
- halfword n, r;
- if (cur_list.tail_field != cur_list.head_field) {
- r = cur_list.tail_field;
- if (vlink(alink(cur_list.tail_field)) == cur_list.tail_field) {
- n = alink(cur_list.tail_field);
- } else {
- n = cur_list.head_field;
- while (vlink(n) != cur_list.tail_field)
- n = vlink(n);
- }
- flush_node(cur_list.tail_field);
- cur_list.tail_field = n;
- vlink(n) = null;
- return r;
- } else {
- return null;
- }
-}
-
-@ When \TeX's work on one level is interrupted, the state is saved by
-calling |push_nest|. This routine changes |head| and |tail| so that
-a new (empty) list is begun; it does not change |mode| or |aux|.
-
-@c
-void push_nest(void)
-{ /* enter a new semantic level, save the old */
- if (nest_ptr > max_nest_stack) {
- max_nest_stack = nest_ptr;
- if (nest_ptr == nest_size)
- overflow("semantic nest size", (unsigned) nest_size);
- }
- incr(nest_ptr);
- cur_list.mode_field = nest[nest_ptr - 1].mode_field;
- cur_list.head_field = new_node(temp_node, 0);
- cur_list.tail_field = cur_list.head_field;
- cur_list.eTeX_aux_field = null;
- cur_list.ml_field = line;
- cur_list.pg_field = 0;
- cur_list.dirs_field = null;
- cur_list.prev_depth_field = nest[nest_ptr - 1].prev_depth_field;
- cur_list.space_factor_field = nest[nest_ptr - 1].space_factor_field;
- cur_list.incompleat_noad_field = nest[nest_ptr - 1].incompleat_noad_field;
- init_math_fields();
-}
-
-@ Conversely, when \TeX\ is finished on the current level, the former
-state is restored by calling |pop_nest|. This routine will never be
-called at the lowest semantic level, nor will it be called unless |head|
-is a node that should be returned to free memory.
-
-@c
-void pop_nest(void)
-{ /* leave a semantic level, re-enter the old */
- flush_node(cur_list.head_field);
- decr(nest_ptr);
-}
-
-@ Here is a procedure that displays what \TeX\ is working on, at all levels.
-
-@c
-void show_activities(void)
-{
- int p; /* index into |nest| */
- int m; /* mode */
- halfword q, r; /* for showing the current page */
- int t; /* ditto */
- tprint_nl("");
- print_ln();
- for (p = nest_ptr; p >= 0; p--) {
- m = nest[p].mode_field;
- tprint_nl("### ");
- print_mode(m);
- tprint(" entered at line ");
- print_int(abs(nest[p].ml_field));
- /* we dont do this any more */
-#if 0
-
- if (m == hmode)
- if (nest[p].pg_field != 040600000) {
- tprint(" (language");
- print_int(nest[p].pg_field % 0200000);
- tprint(":hyphenmin");
- print_int(nest[p].pg_field / 020000000);
- print_char(',');
- print_int((nest[p].pg_field / 0200000) % 0100);
- print_char(')');
- }
-#endif
- if (nest[p].ml_field < 0)
- tprint(" (\\output routine)");
- if (p == 0) {
- /* Show the status of the current page */
- if (page_head != page_tail) {
- tprint_nl("### current page:");
- if (output_active)
- tprint(" (held over for next output)");
- show_box(vlink(page_head));
- if (page_contents > empty) {
- tprint_nl("total height ");
- print_totals();
- tprint_nl(" goal height ");
- print_scaled(page_goal);
- r = vlink(page_ins_head);
- while (r != page_ins_head) {
- print_ln();
- tprint_esc("insert");
- t = subtype(r);
- print_int(t);
- tprint(" adds ");
- if (count(t) == 1000)
- t = height(r);
- else
- t = x_over_n(height(r), 1000) * count(t);
- print_scaled(t);
- if (type(r) == split_up_node) {
- q = page_head;
- t = 0;
- do {
- q = vlink(q);
- if ((type(q) == ins_node)
- && (subtype(q) == subtype(r)))
- incr(t);
- } while (q != broken_ins(r));
- tprint(", #");
- print_int(t);
- tprint(" might split");
- }
- r = vlink(r);
- }
- }
- }
- if (vlink(contrib_head) != null)
- tprint_nl("### recent contributions:");
- }
- show_box(vlink(nest[p].head_field));
- /* Show the auxiliary field, |a| */
- switch (abs(m) / (max_command_cmd + 1)) {
- case 0:
- tprint_nl("prevdepth ");
- if (nest[p].prev_depth_field <= ignore_depth)
- tprint("ignored");
- else
- print_scaled(nest[p].prev_depth_field);
- if (nest[p].pg_field != 0) {
- tprint(", prevgraf ");
- print_int(nest[p].pg_field);
- if (nest[p].pg_field != 1)
- tprint(" lines");
- else
- tprint(" line");
- }
- break;
- case 1:
- tprint_nl("spacefactor ");
- print_int(nest[p].space_factor_field);
- /* we dont do this any more, this was aux.rh originally */
-#if 0
- if (m > 0) {
- if (nest[p].current_language_field > 0) {
- tprint(", current language ");
- print_int(nest[p].current_language_field);
- }
- }
-#endif
- break;
- case 2:
- if (nest[p].incompleat_noad_field != null) {
- tprint("this will be denominator of:");
- show_box(nest[p].incompleat_noad_field);
- }
- } /* there are no other cases */
-
- }
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/packaging.w b/Build/source/texk/web2c/luatexdir/tex/packaging.c
index f094a0d9665..e2b007f11ef 100644
--- a/Build/source/texk/web2c/luatexdir/tex/packaging.w
+++ b/Build/source/texk/web2c/luatexdir/tex/packaging.c
@@ -1,84 +1,68 @@
-% packaging.w
-%
-% Copyright 2009-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
+/*
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ We're essentially done with the parts of \TeX\ that are concerned with the
-input (|get_next|) and the output (|ship_out|). So it's time to get heavily into
-the remaining part, which does the real work of typesetting.
-
-After lists are constructed, \TeX\ wraps them up and puts them into boxes. Two
-major subroutines are given the responsibility for this task: |hpack| applies to
-horizontal lists (hlists) and |vpack| applies to vertical lists (vlists). The
-main duty of |hpack| and |vpack| is to compute the dimensions of the resulting
-boxes, and to adjust the glue if one of those dimensions is pre-specified. The
-computed sizes normally enclose all of the material inside the new box; but some
-items may stick out if negative glue is used, if the box is overfull, or if a
-\.{\\vbox} includes other boxes that have been shifted left.
-
-The subroutine call |hpack(p,w,m)| returns a pointer to an |hlist_node| for a box
-containing the hlist that starts at |p|. Parameter |w| specifies a width; and
-parameter |m| is either `|exactly|' or `|additional|'. Thus, |hpack(p,w,exactly)|
-produces a box whose width is exactly |w|, while |hpack(p,w,additional)| yields a
-box whose width is the natural width plus |w|. It is convenient to define a macro
-called `|natural|' to cover the most common case, so that we can say
-|hpack(p,natural)| to get a box that has the natural width of list |p|.
-
-Similarly, |vpack(p,w,m)| returns a pointer to a |vlist_node| for a box
-containing the vlist that starts at |p|. In this case |w| represents a height
-instead of a width; the parameter |m| is interpreted as in |hpack|.
-
-@ The parameters to |hpack| and |vpack| correspond to \TeX's primitives like
-`\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note that
-`\.{\\hbox}' with no dimension following it is equivalent to `\.{\\hbox}
-\.{spread} \.{0pt}'. The |scan_spec| subroutine scans such constructions in the
-user's input, including the mandatory left brace that follows them, and it puts
-the specification onto |save_stack| so that the desired box can later be obtained
-by executing the following code: $$\vbox{\halign{#\hfil\cr
-|save_ptr:=save_ptr-1;|\cr |hpack(p,saved_value(0),saved_level(0)).|\cr}}$$
-
-@c
-/*
- void scan_spec(group_code c)
- {
- int spec_code;
- if (scan_keyword("to")) {
- spec_code = exactly;
- scan_normal_dimen();
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- scan_normal_dimen();
- } else {
- spec_code = additional;
- cur_val = 0;
- }
- set_saved_record(0, saved_boxspec, spec_code, cur_val);
- save_ptr++;
- new_save_level(c);
- scan_left_brace();
- }
+/*tex
+
+ We're essentially done with the parts of \TeX\ that are concerned with the
+ input (|get_next|) and the output (|ship_out|). So it's time to get heavily
+ into the remaining part, which does the real work of typesetting.
+
+ After lists are constructed, \TeX\ wraps them up and puts them into boxes.
+ Two major subroutines are given the responsibility for this task: |hpack|
+ applies to horizontal lists (hlists) and |vpack| applies to vertical lists
+ (vlists). The main duty of |hpack| and |vpack| is to compute the dimensions
+ of the resulting boxes, and to adjust the glue if one of those dimensions is
+ pre-specified. The computed sizes normally enclose all of the material inside
+ the new box; but some items may stick out if negative glue is used, if the
+ box is overfull, or if a \.{\\vbox} includes other boxes that have been
+ shifted left.
+
+ The subroutine call |hpack(p,w,m)| returns a pointer to an |hlist_node| for a
+ box containing the hlist that starts at |p|. Parameter |w| specifies a width;
+ and parameter |m| is either `|exactly|' or `|additional|'. Thus,
+ |hpack(p,w,exactly)| produces a box whose width is exactly |w|, while
+ |hpack(p,w,additional)| yields a box whose width is the natural width plus
+ |w|. It is convenient to define a macro called `|natural|' to cover the most
+ common case, so that we can say |hpack(p,natural)| to get a box that has the
+ natural width of list |p|.
+
+ Similarly, |vpack(p,w,m)| returns a pointer to a |vlist_node| for a box
+ containing the vlist that starts at |p|. In this case |w| represents a height
+ instead of a width; the parameter |m| is interpreted as in |hpack|.
+
+ The parameters to |hpack| and |vpack| correspond to \TeX's primitives like
+ `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note that
+ `\.{\\hbox}' with no dimension following it is equivalent to `\.{\\hbox}
+ \.{spread} \.{0pt}'. The |scan_spec| subroutine scans such constructions in
+ the user's input, including the mandatory left brace that follows them, and
+ it puts the specification onto |save_stack| so that the desired box can later
+ be obtained by executing the following code: $$\vbox{\halign{#\hfil\cr
+ |save_ptr:=save_ptr-1;|\cr |hpack(p,saved_value(0),saved_level(0)).|\cr}}$$
+
*/
+/*tex Scan a box specification and left brace: */
+
void scan_spec(group_code c)
-{ /* scans a box specification and left brace */
+{
int spec_code;
boolean done = false ;
do {
@@ -89,7 +73,7 @@ void scan_spec(group_code c)
cur_val = 0;
done = true;
} else {
- /* todo: attr */
+ /*tex todo: attr */
back_input();
if (scan_keyword("to")) {
spec_code = exactly;
@@ -110,84 +94,21 @@ void scan_spec(group_code c)
}
}
-@ When scanning, special care is necessary to ensure that the special
-|save_stack| codes are placed just below the new group code, because scanning can
-change |save_stack| when \.{\\csname} appears.
+/*tex
-This coincides with the text on |dir| and |attr| keywords, as these are exaclty
-the uses of \.{\\hbox}, \.{\\vbox}, and \.{\\vtop} in the input stream (the
-others are \.{\\vcenter}, \.{\\valign}, and \.{\\halign}).
+ When scanning, special care is necessary to ensure that the special
+ |save_stack| codes are placed just below the new group code, because scanning
+ can change |save_stack| when \.{\\csname} appears.
+
+ This coincides with the text on |dir| and |attr| keywords, as these are
+ exaclty the uses of \.{\\hbox}, \.{\\vbox}, and \.{\\vtop} in the input
+ stream (the others are \.{\\vcenter}, \.{\\valign}, and \.{\\halign}).
-@c
-/*
- void scan_full_spec(group_code c, int spec_direction)
- {
- int s;
- int i;
- int v;
- int spec_code;
- halfword attr_list;
- if (attr_list_cache == cache_disabled)
- update_attribute_cache();
- attr_list = attr_list_cache;
- s = saved_value(0);
- CONTINUE:
- while (cur_cmd == relax_cmd || cur_cmd == spacer_cmd) {
- get_x_token();
- if (cur_cmd != relax_cmd && cur_cmd != spacer_cmd)
- back_input();
- }
- if (scan_keyword("attr")) {
- scan_register_num();
- i = cur_val;
- scan_optional_equals();
- scan_int();
- v = cur_val;
- if ((attr_list != null) && (attr_list == attr_list_cache)) {
- attr_list = copy_attribute_list(attr_list_cache);
- add_node_attr_ref(attr_list);
- }
- attr_list = do_set_attribute(attr_list, i, v);
- goto CONTINUE;
- }
- if (scan_keyword("dir")) {
- scan_direction();
- spec_direction = cur_val;
- goto CONTINUE;
- }
- if (attr_list == attr_list_cache) {
- add_node_attr_ref(attr_list);
- }
- if (scan_keyword("to")) {
- spec_code = exactly;
- } else if (scan_keyword("spread")) {
- spec_code = additional;
- } else {
- spec_code = additional;
- cur_val = 0;
- goto FOUND;
- }
- scan_normal_dimen();
- FOUND:
- set_saved_record(0, saved_boxcontext, 0, s);
- set_saved_record(1, saved_boxspec, spec_code, cur_val);
- if (spec_direction != -1) {
- set_saved_record(2, saved_boxdir, spec_direction, text_dir_ptr);
- text_dir_ptr = new_dir(spec_direction);
- } else {
- set_saved_record(2, saved_boxdir, spec_direction, null);
- }
- set_saved_record(3, saved_boxattr, 0, attr_list);
- save_ptr += 4;
- new_save_level(c);
- scan_left_brace();
- eq_word_define(int_base + body_direction_code, spec_direction);
- eq_word_define(int_base + par_direction_code, spec_direction);
- eq_word_define(int_base + text_direction_code, spec_direction);
- }
*/
-/* scans a box specification and left brace */
+/*tex Scan a box specification and left brace: */
+
+#define first_char_is(a,A) (cur_cs == 0 && (cur_chr == a || cur_chr == A))
void scan_full_spec(group_code c, int spec_direction, int just_pack)
{
@@ -195,10 +116,12 @@ void scan_full_spec(group_code c, int spec_direction, int just_pack)
boolean done = false ;
halfword attr_list;
boolean attr_done = false ;
+ boolean dir_done = false ;
if (attr_list_cache == cache_disabled)
update_attribute_cache();
attr_list = attr_list_cache;
- s = saved_value(0); /* the box context */
+ /*tex The box context: */
+ s = saved_value(0);
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -219,6 +142,7 @@ void scan_full_spec(group_code c, int spec_direction, int just_pack)
}
}
KEYWORDS:
+ /*tex Multiple |attr| keys possible (before or after dir). */
if (scan_keyword("attr")) {
scan_register_num();
i = cur_val;
@@ -232,11 +156,23 @@ void scan_full_spec(group_code c, int spec_direction, int just_pack)
attr_list = do_set_attribute(attr_list, i, v);
goto CONTINUE;
}
- if (scan_keyword("dir")) {
- scan_direction();
- spec_direction = cur_val;
- goto CONTINUE;
+ /*tex We only permit one |(b)dir| directive. */
+ if (! dir_done) {
+ if (scan_keyword("bdir")) {
+ scan_int();
+ check_dir_value(cur_val);
+ spec_direction = cur_val;
+ dir_done = true;
+ goto CONTINUE;
+ }
+ if (scan_keyword("dir")) {
+ scan_direction();
+ spec_direction = cur_val;
+ dir_done = true;
+ goto CONTINUE;
+ }
}
+ /*tex Only one |to| or |spread| key possible and it comes last. */
if (scan_keyword("to")) {
spec_code = exactly;
} else if (scan_keyword("spread")) {
@@ -256,7 +192,7 @@ void scan_full_spec(group_code c, int spec_direction, int just_pack)
add_node_attr_ref(attr_list);
set_saved_record(0, saved_boxcontext, 0, s);
set_saved_record(1, saved_boxspec, spec_code, cur_val);
- /* DIR: Adjust |text_dir_ptr| for |scan_spec| */
+ /*tex Adjust |text_dir_ptr| for |scan_spec|. */
if (spec_direction != -1) {
set_saved_record(2, saved_boxdir, spec_direction, text_dir_ptr);
text_dir_ptr = new_dir(spec_direction);
@@ -270,73 +206,91 @@ void scan_full_spec(group_code c, int spec_direction, int just_pack)
if (! done) {
scan_left_brace();
}
- /* no gain: if (body_direction_par != spec_direction) etc */
+ /*tex No gain in |if (body_direction_par != spec_direction)| etc. */
eq_word_define(int_base + body_direction_code, spec_direction);
eq_word_define(int_base + par_direction_code, spec_direction);
eq_word_define(int_base + text_direction_code, spec_direction);
}
+/*tex
-@ To figure out the glue setting, |hpack| and |vpack| determine how much
-stretchability and shrinkability are present, considering all four orders of
-infinity. The highest order of infinity that has a nonzero coefficient is then
-used as if no other orders were present.
+ To figure out the glue setting, |hpack| and |vpack| determine how much
+ stretchability and shrinkability are present, considering all four orders of
+ infinity. The highest order of infinity that has a nonzero coefficient is
+ then used as if no other orders were present.
-For example, suppose that the given list contains six glue nodes with the
-respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill. Then the
-total is essentially 2fil; and if a total additional space of 6pt is to be
-achieved by stretching, the actual amounts of stretch will be 0pt, 0pt, 15pt,
-0pt, $-9$pt, and 0pt, since only `fil' glue will be considered. (The `fill' glue
-is therefore not really stretching infinitely with respect to `fil'; nobody would
-actually want that to happen.)
+ For example, suppose that the given list contains six glue nodes with the
+ respective stretchabilities 3pt, 8fill, 5fil, 6pt, $-3$fil, $-8$fill. Then
+ the total is essentially 2fil; and if a total additional space of 6pt is to
+ be achieved by stretching, the actual amounts of stretch will be 0pt, 0pt,
+ 15pt, 0pt, $-9$pt, and 0pt, since only `fil' glue will be considered. (The
+ `fill' glue is therefore not really stretching infinitely with respect to
+ `fil'; nobody would actually want that to happen.)
-The arrays |total_stretch| and |total_shrink| are used to determine how much glue
-of each kind is present. A global variable |last_badness| is used to implement
-\.{\\badness}.
+ The arrays |total_stretch| and |total_shrink| are used to determine how much
+ glue of each kind is present. A global variable |last_badness| is used to
+ implement \.{\\badness}.
+
+*/
+
+/*tex Glue found by |hpack| or |vpack|. */
-@c
scaled total_stretch[5];
-scaled total_shrink[5]; /* glue found by |hpack| or |vpack| */
-int last_badness; /* badness of the most recently packaged box */
+scaled total_shrink[5];
+
+/*tex Badness of the most recently packaged box. */
+
+int last_badness;
+
+/*tex
-@ If the global variable |adjust_tail| is non-null, the |hpack| routine also
-removes all occurrences of |ins_node|, |mark_node|, and |adjust_node| items and
-appends the resulting material onto the list that ends at location |adjust_tail|.
+ If the global variable |adjust_tail| is non-null, the |hpack| routine also
+ removes all occurrences of |ins_node|, |mark_node|, and |adjust_node| items
+ and appends the resulting material onto the list that ends at location
+ |adjust_tail|.
-@c
-halfword adjust_tail; /* tail of adjustment list */
+*/
+
+/*tex Tail of adjustment list. */
+
+halfword adjust_tail;
+/*tex
-@ Materials in \.{\\vadjust} used with \.{pre} keyword will be appended to
-|pre_adjust_tail| instead of |adjust_tail|.
+ Materials in \.{\\vadjust} used with \.{pre} keyword will be appended to
+ |pre_adjust_tail| instead of |adjust_tail|.
+
+*/
-@c
halfword pre_adjust_tail;
halfword last_leftmost_char;
halfword last_rightmost_char;
-halfword next_char_p; /* pointer to the next char of an implicit kern */
-halfword prev_char_p; /* pointer to the previous char of an implicit kern */
+/*tex Pointers to the prev and next char of an implicit kern. */
+
+halfword next_char_p;
+halfword prev_char_p;
+
+/*tex This procedure is called repeatedly from inside the line break algorithm. */
-@ This procedure is called repeatedly from inside the line break algorithm.
-@c
void set_prev_char_p(halfword p)
{
prev_char_p = p;
}
-/*
- the kern stretch / shrink code was (or had become) rather weird ... the width field
- is set, and then used in a second calculation, repeatedly, so why is that ... maybe some
- some weird left-over ... anyway, the values are so small that in practice they are not
- significant at all when the backend sees them because a few hundred sp positive or
- negative are just noise there (so adjustlevel 3 has hardly any consequence for the
- result but is more efficient)
-*/
+/*tex
+
+ The kern stretch / shrink code was (or had become) rather weird ... the width
+ field is set, and then used in a second calculation, repeatedly, so why is
+ that ... maybe some some weird left-over ... anyway, the values are so small
+ that in practice they are not significant at all when the backend sees them
+ because a few hundred sp positive or negative are just noise there (so
+ adjustlevel 3 has hardly any consequence for the result but is more
+ efficient).
+*/
-@ @c
scaled char_stretch(halfword p)
{
internal_font_number f = font(p);
@@ -345,7 +299,7 @@ scaled char_stretch(halfword p)
int c = character(p);
int ef = get_ef_code(f, c);
if (ef > 0) {
- scaled dw = calc_char_width(f, c, m) - char_width(f, c) - x_advance(p);
+ scaled dw = calc_char_width(f, c, m) - char_width(f, c);
if (dw > 0) {
return round_xn_over_d(dw, ef, 1000);
}
@@ -354,7 +308,6 @@ scaled char_stretch(halfword p)
return 0;
}
-@ @c
scaled char_shrink(halfword p)
{
internal_font_number f = font(p);
@@ -363,7 +316,7 @@ scaled char_shrink(halfword p)
int c = character(p);
int ef = get_ef_code(f, c);
if (ef > 0) {
- scaled dw = char_width(f, c) + x_advance(p) - calc_char_width(f, c, -m);
+ scaled dw = char_width(f, c) - calc_char_width(f, c, -m);
if (dw > 0) {
return round_xn_over_d(dw, ef, 1000);
}
@@ -372,33 +325,6 @@ scaled char_shrink(halfword p)
return 0;
}
-@ @c
-/*
-scaled kern_stretch(halfword p)
-{
- halfword l, r;
- scaled d;
- int m;
- if ((prev_char_p == null) || (vlink(prev_char_p) != p) || (vlink(p) == null))
- return 0;
- l = prev_char_p;
- // we need a left char
- if (!is_char_node(l))
- return 0;
- r = vlink(p);
- // and a right char
- if (!is_char_node(r))
- return 0;
- // and a reason to kern
- if ((font(l) != font(r)) || (font_max_stretch(font(l)) == 0))
- return 0;
- m = font_max_stretch(font(l));
- d = get_kern(font(l), character(l), character(r)); // real kern, so what is width(p) then; the messed up one
- d = round_xn_over_d(d, 1000 + m, 1000);
- return round_xn_over_d(d - width(p), get_ef_code(font(l), character(l)), 1000);
-}
-*/
-
scaled kern_stretch(halfword p)
{
int m;
@@ -407,69 +333,39 @@ scaled kern_stretch(halfword p)
halfword l;
halfword r;
if (w == 0) {
- /* why bother about zero kerns */
+ /*tex Why bother about zero kerns. */
return 0;
}
l = prev_char_p ;
if ((l == null) || (vlink(l) != p)) {
- /* we only care about kerns following a char*/
+ /*tex We only care about kerns following a char. */
return 0;
}
r = vlink(p);
if (r == null) {
- /* we only care about kerns between a char and something else */
+ /*tex We only care about kerns between a char and something else. */
}
if (!(is_char_node(l) && is_char_node(r))) {
- /* we want two chars (but but don't care about the fonts) */
+ /*tex We want two chars (but but don't care about the fonts). */
return 0;
}
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
+ /*tex We use the old logic, kind of, but average the ef as we might depend on proper overlap. */
m = (font_max_stretch(font(l)) + font_max_stretch(font(r)))/2;
if (m == 0) {
- /* nothing to kern */
+ /*tex nothing to kern */
return 0;
}
d = round_xn_over_d(w, 1000 + m, 1000);
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
+ /*tex We use the old logic, kind of, but average the ef as we might depend on proper overlap. */
e = (get_ef_code(font(l), character(l)) + get_ef_code(font(r), character(r)))/2 ;
if (e == 1000) {
x = d - w;
} else {
x = round_xn_over_d(d - w, e, 1000);
}
- /*
- printf("STRETCH w=%i s=%i x=%i\n",w,e+m,x);
- */
return x;
}
-@ @c
-/*
-scaled kern_shrink(halfword p)
-{
- halfword l, r;
- scaled d;
- int m;
- if ((prev_char_p == null) || (vlink(prev_char_p) != p) || (vlink(p) == null))
- return 0;
- l = prev_char_p;
- // we need a left char
- if (!is_char_node(l))
- return 0;
- r = vlink(p);
- // and a right char
- if (!is_char_node(r))
- return 0;
- // and a reason to kern
- if ((font(l) != font(r)) || (font_max_shrink(font(l)) == 0))
- return 0;
- m = font_max_shrink(font(l));
- d = get_kern(font(l), character(l), character(r)); // real kern, so what is width(p) then; the messed up one
- d = round_xn_over_d(d, 1000 - m, 1000);
- return round_xn_over_d(width(p) - d, get_ef_code(font(l), character(l)), 1000);
-}
-*/
-
scaled kern_shrink(halfword p)
{
int m;
@@ -478,26 +374,26 @@ scaled kern_shrink(halfword p)
halfword l;
halfword r;
if (w == 0) {
- /* why bother about zero kerns */
+ /*tex Why bother about zero kerns. */
return 0;
}
l = prev_char_p ;
if ((l == null) || (vlink(l) != p)) {
- /* we only care about kerns following a char*/
+ /*tex We only care about kerns following a char. */
return 0;
}
r = vlink(p);
if (r == null) {
- /* we only care about kerns between a char and something else */
+ /*tex We only care about kerns between a char and something else. */
}
if (!(is_char_node(l) && is_char_node(r))) {
- /* we want two chars (but but don't care about the fonts) */
+ /*tex We want two chars (but but don't care about the fonts). */
return 0;
}
- /* we use the old logic, kind of, but average the ef as we might depend on proper overlap */
+ /*tex We use the old logic, kind of, but average the ef as we might depend on proper overlap. */
m = (font_max_shrink(font(l)) + font_max_shrink(font(r)))/2;
if (m == 0) {
- /* nothing to kern */
+ /*tex Nothing to kern. */
return 0;
}
d = round_xn_over_d(w, 1000 - m, 1000);
@@ -507,13 +403,9 @@ scaled kern_shrink(halfword p)
} else {
x = round_xn_over_d(w - d, e, 1000);
}
- /*
- printf("SHRINK w=%i s=%i x=%i\n",w,e+m,x);
- */
return x;
}
-@ @c
void do_subst_font(halfword p, int ex_ratio)
{
if (type(p) == disc_node) {
@@ -555,7 +447,6 @@ void do_subst_font(halfword p, int ex_ratio)
}
}
-@ @c
scaled char_pw(halfword p, int side)
{
internal_font_number f;
@@ -582,7 +473,6 @@ scaled char_pw(halfword p, int side)
return round_xn_over_d(w, c, 1000);
}
-@ @c
halfword new_margin_kern(scaled w, halfword p, int side)
{
halfword k, q;
@@ -595,11 +485,16 @@ halfword new_margin_kern(scaled w, halfword p, int side)
return k;
}
-@ Here is |hpack|, which is place where we do font substituting when font
-expansion is being used.
+/*tex
+
+ Here we prepare for |hpack|, which is place where we do font substituting
+ when font expansion is being used.
+
+*/
+
+/*tex The current expansion ratio, needed for recursive call. */
-@c
-int font_expand_ratio = 0; /* current expansion ratio, needed for recursive call */
+int font_expand_ratio = 0;
int ignore_math_skip(halfword p)
{
@@ -632,47 +527,60 @@ int ignore_math_skip(halfword p)
halfword hpack(halfword p, scaled w, int m, int pack_direction)
{
- halfword r; /* the box node that will be returned */
- halfword q; /* trails behind |p| */
- scaled h = 0; /* height */
- scaled d = 0; /* depth */
- scaled x = 0; /* natural width */
+ /*tex the box node that will be returned */
+ halfword r;
+ /*tex trails behind |p| */
+ halfword q;
+ /*tex height */
+ scaled h = 0;
+ /*tex depth */
+ scaled d = 0;
+ /*tex natural width */
+ scaled x = 0;
scaled_whd whd;
- scaled s; /* shift amount */
- int o; /* order of infinity */
- halfword dir_ptr1 = null; /* for managing the direction stack */
- int hpack_dir; /* the current direction */
+ /*tex shift amount */
+ scaled s;
+ /*tex order of infinity */
+ int o;
+ /*tex for managing the direction stack */
+ halfword dir_ptr1 = null;
+ /*tex the current direction */
+ int hpack_dir;
int disc_level = 0;
halfword pack_interrupt[8];
scaled font_stretch = 0;
scaled font_shrink = 0;
int adjust_spacing = adjust_spacing_par;
-
-/*
- int font_expand_ratio = 0;
-*/
last_badness = 0;
- r = new_node(hlist_node, min_quarterword); /* the box node that will be returned */
+ /*tex the box node that will be returned */
+ r = new_node(hlist_node, min_quarterword);
if (pack_direction == -1) {
hpack_dir = text_direction_par;
} else {
hpack_dir = pack_direction;
}
box_dir(r) = hpack_dir;
- /*
- potential optimimization, save a little but neglectable in practice (not so
- many empty boxes are used)
+ /*tex
+ A potential optimimization, save a little but neglectable in practice
+ (not so many empty boxes are used):
+
+ \starttyping
if (p == null) {
width(r) = w;
return r;
}
+ \stoptyping
+
*/
- push_dir(dir_ptr1,hpack_dir); /* push null */
- q = r + list_offset; /* hm, adding something to a node address? */
+ /*tex push null */
+ push_dir(dir_ptr1,hpack_dir);
+ /*tex hm, adding something to a node address? */
+ q = r + list_offset;
vlink(q) = p;
if (m == cal_expand_ratio) {
- prev_char_p = null; /* why not always */
+ /*tex Why not always: */
+ prev_char_p = null;
}
if (adjust_spacing > 2) {
adjust_spacing = 0;
@@ -687,7 +595,6 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
total_shrink[fill] = 0;
total_stretch[filll] = 0;
total_shrink[filll] = 0;
-
RESWITCH:
while ((p != null) || (disc_level > 0)) {
if (p == null) {
@@ -695,20 +602,24 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
p = pack_interrupt[disc_level];
goto RESWITCH;
}
- /*
- Examine node |p| in the hlist, taking account of its effect
- on the dimensions of the new box, or moving it to the adjustment list;
- then advance |p| to the next node
+ /*tex
+
+ Examine node |p| in the hlist, taking account of its effect on the
+ dimensions of the new box, or moving it to the adjustment list; then
+ advance |p| to the next node.
+
*/
while (is_char_node(p)) {
- /*
+ /*tex
+
Incorporate character dimensions into the dimensions of the hbox
that will contain~it, then move to the next node.
The following code is part of \TeX's inner loop; i.e., adding
another character of text to the user's input will cause each of
these instructions to be exercised one more time.
- */
+
+ */
if (m >= cal_expand_ratio) {
prev_char_p = p;
if (m == cal_expand_ratio) {
@@ -730,13 +641,16 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
switch (type(p)) {
case hlist_node:
case vlist_node:
- /*
- Incorporate box dimensions into the dimensions of the hbox
- that will contain~it
+ /*tex
+
+ Incorporate box dimensions into the dimensions of the
+ hbox that will contain~it
+
+ The code here implicitly uses the fact that running
+ dimensions are indicated by |null_flag|, which will be
+ ignored in the calculations because it is a highly
+ negative number.
- The code here implicitly uses the fact that running dimensions are
- indicated by |null_flag|, which will be ignored in the calculations
- because it is a highly negative number.
*/
s = shift_amount(p);
whd = pack_width_height_depth(hpack_dir, box_dir(p), p, false);
@@ -746,20 +660,6 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
if (whd.dp + s > d)
d = whd.dp + s;
break;
- /*
- case rule_node:
- case unset_node:
- x += width(p);
- if (type(p) >= rule_node) // always
- s = 0;
- else
- s = shift_amount(p);
- if (height(p) - s > h)
- h = height(p) - s;
- if (depth(p) + s > d)
- d = depth(p) + s;
- break;
- */
case rule_node:
case unset_node:
x += width(p);
@@ -768,18 +668,17 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
if (depth(p) > d)
d = depth(p);
break;
- /* */
case math_node:
- /* begin mathskip code */
+ /*tex Begin mathskip code. */
if (glue_is_zero(p) || ignore_math_skip(p)) {
x += surround(p);
break;
} else {
- /* fall through */
+ /*tex Fall through. */
}
- /* end mathskip code */
+ /*tex End mathskip code. */
case glue_node:
- /* Incorporate glue into the horizontal totals */
+ /*tex Incorporate glue into the horizontal totals. */
x += width(p);
o = stretch_order(p);
total_stretch[o] = total_stretch[o] + stretch(p);
@@ -796,12 +695,12 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
case kern_node:
x += width(p);
if (subtype(p) == font_kern && adjust_spacing) {
- /* so only when 1 or 2 */
+ /*tex So only when 1 or 2. */
if (m == cal_expand_ratio) {
font_stretch = font_stretch + kern_stretch(p);
font_shrink = font_shrink + kern_shrink(p);
} else if (m == subst_ex_font) {
- /* this is the finalizer */
+ /*tex This is the finalizer. */
int k = 0;
if (font_expand_ratio > 0) {
k = kern_stretch(p);
@@ -810,9 +709,6 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
}
ex_kern(p) = k;
x += k;
- /*
- if (x!=0) printf("SET %i %i %i\n",font_expand_ratio,k,x);
- */
}
}
break;
@@ -826,8 +722,8 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
}
break;
case dir_node:
- /* Adjust the dir stack for the |hpack| routine */
- if (dir_dir(p) >= 0) {
+ /*tex Adjust the dir stack for the |hpack| routine. */
+ if (subtype(p) == normal_dir) {
hpack_dir = dir_dir(p);
push_dir_node(dir_ptr1,p);
} else {
@@ -856,15 +752,17 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
case ins_node:
case mark_node:
case adjust_node:
- /*
- Transfer node |p| to the adjustment list.
-
- Although node |q| is not necessarily the immediate predecessor of node |p|,
- it always points to some node in the list preceding |p|. Thus, we can delete
- nodes by moving |q| when necessary. The algorithm takes linear time, and the
- extra computation does not intrude on the inner loop unless it is necessary
- to make a deletion.
- */
+ /*tex
+
+ Transfer node |p| to the adjustment list.\Although node
+ |q| is not necessarily the immediate predecessor of node
+ |p|, it always points to some node in the list preceding
+ |p|. Thus, we can delete nodes by moving |q| when
+ necessary. The algorithm takes linear time, and the extra
+ computation does not intrude on the inner loop unless it
+ is necessary to make a deletion.
+
+ */
if (adjust_tail != null || pre_adjust_tail != null) {
while (vlink(q) != p)
q = vlink(q);
@@ -885,13 +783,11 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
p = q;
}
break;
- /* */
default:
break;
}
p = vlink(p);
}
-
}
if (adjust_tail != null)
@@ -900,31 +796,35 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
vlink(pre_adjust_tail) = null;
height(r) = h;
depth(r) = d;
- /*
+ /*tex
+
Determine the value of |width(r)| and the appropriate glue setting; then
|return| or |goto common_ending|.
When we get to the present part of the program, |x| is the natural width
of the box being packaged.
+
*/
if (m == additional)
w = x + w;
width(r) = w;
x = w - x;
- /* now |x| is the excess to be made up */
+ /*tex Now |x| is the excess to be made up. */
if (x == 0) {
glue_sign(r) = normal;
glue_order(r) = normal;
set_glue_ratio_zero(glue_set(r));
goto EXIT;
} else if (x > 0) {
- /*
- Determine horizontal glue stretch setting, then |return|
- or \hbox{|goto common_ending|}.
+ /*tex
+
+ Determine horizontal glue stretch setting, then |return| or
+ |goto common_ending|.
If |hpack| is called with |m=cal_expand_ratio| we calculate
|font_expand_ratio| and return without checking for overfull or
underfull box.
+
*/
if (total_stretch[filll] != 0)
o = filll;
@@ -936,7 +836,6 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
o = sfi;
else
o = normal;
-
if ((m == cal_expand_ratio) && (o == normal) && (font_stretch > 0)) {
font_expand_ratio = divide_scaled_n(x, font_stretch, 1000.0);
goto EXIT;
@@ -946,15 +845,17 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
if (total_stretch[o] != 0) {
glue_set(r) = unfloat((double) x / total_stretch[o]);
} else {
- /* there's nothing to stretch */
+ /*tex There's nothing to stretch. */
glue_sign(r) = normal;
set_glue_ratio_zero(glue_set(r));
}
if (o == normal) {
if (list_ptr(r) != null) {
- /*
- Report an underfull hbox and |goto common_ending|, if this box
- is sufficiently bad.
+ /*tex
+
+ Report an underfull hbox and |goto common_ending|, if this
+ box is sufficiently bad.
+
*/
last_badness = badness(x, total_stretch[normal]);
if (last_badness > hbadness_par) {
@@ -987,9 +888,11 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
}
goto EXIT;
} else {
- /*
- Determine horizontal glue shrink setting, then |return|
- or \hbox{|goto common_ending|},
+ /*tex
+
+ Determine horizontal glue shrink setting, then |return| or |goto
+ common_ending|,
+
*/
if (total_shrink[filll] != 0)
o = filll;
@@ -1001,7 +904,6 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
o = sfi;
else
o = normal;
-
if ((m == cal_expand_ratio) && (o == normal) && (font_shrink > 0)) {
font_expand_ratio = divide_scaled_n(x, font_shrink, 1000.0);
goto EXIT;
@@ -1011,18 +913,20 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
if (total_shrink[o] != 0) {
glue_set(r) = unfloat((double) (-x) / (double) total_shrink[o]);
} else {
- /* there's nothing to shrink */
+ /*tex There's nothing to shrink. */
glue_sign(r) = normal;
set_glue_ratio_zero(glue_set(r));
}
if ((total_shrink[o] < -x) && (o == normal) && (list_ptr(r) != null)) {
int overshoot = -x - total_shrink[normal] ;
last_badness = 1000000;
- /* use the maximum shrinkage */
+ /*tex Use the maximum shrinkage */
set_glue_ratio_one(glue_set(r));
- /*
- Report an overfull hbox and |goto common_ending|, if this box
- is sufficiently bad.
+ /*tex
+
+ Report an overfull hbox and |goto common_ending|, if this box is
+ sufficiently bad.
+
*/
if ((overshoot > hfuzz_par) || (hbadness_par < 100)) {
int callback_id = callback_defined(hpack_quality_callback);
@@ -1050,9 +954,11 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
}
} else if (o == normal) {
if (list_ptr(r) != null) {
- /*
+ /*tex
+
Report a tight hbox and |goto common_ending|, if this box is
sufficiently bad.
+
*/
last_badness = badness(-x, total_shrink[normal]);
if (last_badness > hbadness_par) {
@@ -1079,10 +985,7 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
}
COMMON_ENDING:
- /*
- Finish issuing a diagnostic message for an overfull or underfull
- hbox.
- */
+ /*tex Finish issuing a diagnostic message for an overfull or underfull hbox. */
if (output_active) {
tprint(") has occurred while \\output is active");
} else {
@@ -1113,17 +1016,16 @@ halfword hpack(halfword p, scaled w, int m, int pack_direction)
q = list_ptr(r);
list_ptr(r) = null;
flush_node(r);
- /* this nested call uses the more or less global font_expand_ratio */
+ /*tex This nested call uses the more or less global font_expand_ratio. */
r = hpack(q, w, subst_ex_font, hpack_dir);
}
while (dir_ptr1 != null)
pop_dir_node(dir_ptr1);
- /* here we reset the font_expan_ratio */
+ /*tex Here we reset the |font_expand_ratio|. */
font_expand_ratio = 0;
return r;
}
-@ @c
halfword filtered_hpack(halfword p, halfword qt, scaled w, int m, int grp, int pac, int just_pack, halfword attr)
{
halfword q;
@@ -1131,32 +1033,33 @@ halfword filtered_hpack(halfword p, halfword qt, scaled w, int m, int grp, int p
q = vlink(p);
} else if (type(p) == temp_node && vlink(p) == null) {
q = vlink(p);
- /*
- q = new_node(hlist_node, min_quarterword);
- box_dir(q) = (pac == -1) ? text_direction_par : pac;
- width(q) = w;
- return q;
- */
} else {
new_hyphenation(p, qt);
- (void) new_ligkern(p, qt); /* we don't care about the tail in this case */
+ /*tex We don't care about the tail in this case. */
+ (void) new_ligkern(p, qt);
q = vlink(p);
- /* maybe here: alink(p) = null */
- q = lua_hpack_filter(q, w, m, grp, pac, attr); /* ignores empty anyway */ /* maybe also pass tail */
+ /*tex Maybe here: |alink(p) = null|. */
+ /*tex ignores empty anyway. Maybe also pass tail? */
+ q = lua_hpack_filter(q, w, m, grp, pac, attr);
}
return hpack(q, w, m, pac);
}
-@ here is a function to calculate the natural whd of a (horizontal) node list
+/*tex
-@c
-scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult,
- int g_sign, int g_order, int pack_direction)
+ Here is a function to calculate the natural whd of a (horizontal) node list.
+
+*/
+
+scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult, int g_sign, int g_order, int pack_direction)
{
- scaled s; /* shift amount */
- halfword g; /* points to a glue specification */
+ /*tex shift amount */
+ scaled s;
+ /*tex points to a glue specification */
+ halfword g;
int hpack_dir;
- scaled_whd xx; /* for recursion */
+ /*tex For recursion */
+ scaled_whd xx;
scaled_whd whd, siz = { 0, 0, 0 };
scaled gp = 0;
scaled gm = 0;
@@ -1187,20 +1090,6 @@ scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult,
if (whd.dp + s > siz.dp)
siz.dp = whd.dp + s;
break;
- /*
- case rule_node:
- case unset_node:
- siz.wd += width(p);
- if (type(p) >= rule_node) // always true
- s = 0;
- else
- s = shift_amount(p);
- if (height(p) - s > siz.ht)
- siz.ht = height(p) - s;
- if (depth(p) + s > siz.dp)
- siz.dp = depth(p) + s;
- break;
- */
case rule_node:
case unset_node:
siz.wd += width(p);
@@ -1209,29 +1098,28 @@ scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult,
if (depth(p) > siz.dp)
siz.dp = depth(p);
break;
- /* */
case math_node:
- /* begin mathskip code */
+ /*tex Begin mathskip code. */
if (glue_is_zero(p) || ignore_math_skip(p)) {
siz.wd += surround(p);
break;
} else {
- /* fall through */
+ /*tex Fall through. */
}
- /* end mathskip code */
+ /*tex End mathskip code. */
case glue_node:
siz.wd += width(p);
if (g_sign != normal) {
if (g_sign == stretching) {
if (stretch_order(p) == g_order) {
- /*
- siz.wd += float_round(float_cast(g_mult) * float_cast(stretch(p)));
+ /*tex
+ |siz.wd += float_round(float_cast(g_mult) * float_cast(stretch(p)))|
*/
gp += stretch(p);
}
} else if (shrink_order(p) == g_order) {
- /*
- siz.wd -= float_round(float_cast(g_mult) * float_cast(shrink(p)));
+ /*tex
+ |siz.wd -= float_round(float_cast(g_mult) * float_cast(shrink(p)));|
*/
gm += shrink(p);
}
@@ -1275,34 +1163,46 @@ scaled_whd natural_sizes(halfword p, halfword pp, glue_ratio g_mult,
return siz;
}
-@ In order to provide a decent indication of where an overfull or underfull box
-originated, we use a global variable |pack_begin_line| that is set nonzero only
-when |hpack| is being called by the paragraph builder or the alignment finishing
-routine.
+/*tex
+
+ In order to provide a decent indication of where an overfull or underfull box
+ originated, we use a global variable |pack_begin_line| that is set nonzero
+ only when |hpack| is being called by the paragraph builder or the alignment
+ finishing routine.
-@ The source file line where the current paragraph or alignment began; a negative
-value denotes alignment:
+ The source file line where the current paragraph or alignment began; a
+ negative value denotes alignment:
+
+*/
-@c
int pack_begin_line;
-@ The |vpack| subroutine is actually a special case of a slightly more general
-routine called |vpackage|, which has four parameters. The fourth parameter, which
-is |max_dimen| in the case of |vpack|, specifies the maximum depth of the page
-box that is constructed. The depth is first computed by the normal rules; if it
-exceeds this limit, the reference point is simply moved down until the limiting
-depth is attained.
+/*tex
+
+ The |vpack| subroutine is actually a special case of a slightly more general
+ routine called |vpackage|, which has four parameters. The fourth parameter,
+ which is |max_dimen| in the case of |vpack|, specifies the maximum depth of
+ the page box that is constructed. The depth is first computed by the normal
+ rules; if it exceeds this limit, the reference point is simply moved down
+ until the limiting depth is attained.
+
+*/
-@c
halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
{
- halfword r; /* the box node that will be returned */
- scaled w = 0; /* width */
- scaled d = 0; /* depth */
- scaled x = 0; /* natural height */
+ /*tex the box node that will be returned */
+ halfword r;
+ /*tex width */
+ scaled w = 0;
+ /*tex depth */
+ scaled d = 0;
+ /*tex natural height */
+ scaled x = 0;
scaled_whd whd;
- scaled s; /* shift amount */
- int o; /* order of infinity */
+ /*tex shift amount */
+ scaled s;
+ /*tex order of infinity */
+ int o;
last_badness = 0;
r = new_node(vlist_node, 0);
if (pack_direction == -1) {
@@ -1323,12 +1223,12 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
total_shrink[fill] = 0;
total_stretch[filll] = 0;
total_shrink[filll] = 0;
-
while (p != null) {
- /*
- Examine node |p| in the vlist, taking account of its effect
- on the dimensions of the new box; then advance |p| to the next
- node.
+ /*tex
+
+ Examine node |p| in the vlist, taking account of its effect on the
+ dimensions of the new box; then advance |p| to the next node.
+
*/
if (is_char_node(p)) {
confusion("vpack");
@@ -1336,9 +1236,11 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
switch (type(p)) {
case hlist_node:
case vlist_node:
- /*
- Incorporate box dimensions into the dimensions of
- the vbox that will contain it.
+ /*tex
+
+ Incorporate box dimensions into the dimensions of the vbox
+ that will contain it.
+
*/
s = shift_amount(p);
whd = pack_width_height_depth(box_dir(r), box_dir(p), p, false);
@@ -1347,19 +1249,6 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
x += d + whd.ht;
d = whd.dp;
break;
- /*
- case rule_node:
- case unset_node:
- x += d + height(p);
- d = depth(p);
- if (type(p) >= rule_node) // always
- s = 0;
- else
- s = shift_amount(p);
- if (width(p) + s > w)
- w = width(p) + s;
- break;
- */
case rule_node:
case unset_node:
x += d + height(p);
@@ -1367,9 +1256,8 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
if (width(p) > w)
w = width(p);
break;
- /* */
case glue_node:
- /* Incorporate glue into the vertical totals */
+ /*tex Incorporate glue into the vertical totals. */
x += d;
d = 0;
x += width(p);
@@ -1400,27 +1288,30 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
} else {
depth(r) = d;
}
- /*
- Determine the value of |height(r)| and the appropriate glue setting;
- then |return| or |goto common_ending|.
+ /*tex
+
+ Determine the value of |height(r)| and the appropriate glue setting; then
+ |return| or |goto common_ending|.
- When we get to the present part of the program, |x| is the natural
- height of the box being packaged.
+ When we get to the present part of the program, |x| is the natural height
+ of the box being packaged.
*/
if (m == additional)
h = x + h;
height(r) = h;
x = h - x;
- /* now |x| is the excess to be made up */
+ /*tex Now |x| is the excess to be made up. */
if (x == 0) {
glue_sign(r) = normal;
glue_order(r) = normal;
set_glue_ratio_zero(glue_set(r));
return r;
} else if (x > 0) {
- /*
- Determine vertical glue stretch setting, then |return|
- or \hbox{|goto common_ending|}.
+ /*tex
+
+ Determine vertical glue stretch setting, then |return| or |goto
+ common_ending|.
+
*/
if (total_stretch[filll] != 0)
o = filll;
@@ -1432,20 +1323,22 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
o = sfi;
else
o = normal;
-
glue_order(r) = (quarterword) o;
glue_sign(r) = stretching;
if (total_stretch[o] != 0) {
glue_set(r) = unfloat((double) x / total_stretch[o]);
} else {
+ /*tex There's nothing to stretch. */
glue_sign(r) = normal;
- set_glue_ratio_zero(glue_set(r)); /* there's nothing to stretch */
+ set_glue_ratio_zero(glue_set(r));
}
if (o == normal) {
if (list_ptr(r) != null) {
- /*
- Report an underfull vbox and |goto common_ending|, if this box
- is sufficiently bad.
+ /*tex
+
+ Report an underfull vbox and |goto common_ending|, if this
+ box is sufficiently bad.
+
*/
last_badness = badness(x, total_stretch[normal]);
if (last_badness > vbadness_par) {
@@ -1471,11 +1364,12 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
}
}
return r;
-
} else {
- /*
- Determine vertical glue shrink setting, then |return|
- or \hbox{|goto common_ending|}.
+ /*tex
+
+ Determine vertical glue shrink setting, then |return| or |goto
+ common_ending|.
+
*/
if (total_shrink[filll] != 0)
o = filll;
@@ -1487,24 +1381,25 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
o = sfi;
else
o = normal;
-
glue_order(r) = (quarterword) o;
glue_sign(r) = shrinking;
if (total_shrink[o] != 0) {
glue_set(r) = unfloat((double) (-x) / total_shrink[o]);
} else {
- /* there's nothing to shrink */
+ /*tex There's nothing to shrink. */
glue_sign(r) = normal;
set_glue_ratio_zero(glue_set(r));
}
if ((total_shrink[o] < -x) && (o == normal) && (list_ptr(r) != null)) {
int overshoot = -x - total_shrink[normal];
last_badness = 1000000;
- /* use the maximum shrinkage */
+ /*tex Use the maximum shrinkage */
set_glue_ratio_one(glue_set(r));
- /*
- Report an overfull vbox and |goto common_ending|, if this box
- is sufficiently bad.
+ /*tex
+
+ Report an overfull vbox and |goto common_ending|, if this box is
+ sufficiently bad.
+
*/
if ((overshoot > vfuzz_par) || (vbadness_par < 100)) {
int callback_id = callback_defined(vpack_quality_callback);
@@ -1521,9 +1416,11 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
}
} else if (o == normal) {
if (list_ptr(r) != null) {
- /*
+ /*tex
+
Report a tight vbox and |goto common_ending|, if this box is
sufficiently bad.
+
*/
last_badness = badness(-x, total_shrink[normal]);
if (last_badness > vbadness_par) {
@@ -1544,12 +1441,12 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
}
COMMON_ENDING:
- /* Finish issuing a diagnostic message or an overfull or underfull vbox */
+ /*tex Finish issuing a diagnostic message or an overfull or underfull vbox. */
if (output_active) {
tprint(") has occurred while \\output is active");
} else {
if (pack_begin_line != 0) {
- /* it's actually negative */
+ /*tex It's actually negative. */
tprint(") in alignment at lines ");
print_int(abs(pack_begin_line));
tprint("--");
@@ -1566,17 +1463,14 @@ halfword vpackage(halfword p, scaled h, int m, scaled l, int pack_direction)
return r;
}
-@ @c
halfword filtered_vpackage(halfword p, scaled h, int m, scaled l, int grp, int pack_direction, int just_pack, halfword attr)
{
halfword q = p;
if (!just_pack)
- /* if (q != null) */
q = lua_vpack_filter(q, h, m, l, grp, pack_direction, attr);
return vpackage(q, h, m, l, pack_direction);
}
-@ @c
void finish_vcenter(void)
{
halfword p;
@@ -1588,12 +1482,11 @@ void finish_vcenter(void)
tail_append(p);
}
-@ @c
void package(int c)
{
halfword saved0, saved2, saved3, saved4;
int grp = cur_group;
- scaled d = box_max_depth_par; /* max depth */
+ scaled d = box_max_depth_par;
unsave();
save_ptr -= 5;
saved0 = saved_value(0);
@@ -1608,11 +1501,13 @@ void package(int c)
cur_box = filtered_vpackage(vlink(cur_list.head_field),
saved_value(1), saved_level(1), d, grp, saved_level(2), saved4, saved3);
if (c == vtop_code) {
- /*
+ /*tex
+
Read just the height and depth of |cur_box|, for \.{\\vtop}. The
height of a `\.{\\vtop}' box is inherited from the first item on
its list, if that item is an |hlist_node|, |vlist_node|, or
|rule_node|; otherwise the \.{\\vtop} height is zero.
+
*/
scaled h = 0;
halfword p = list_ptr(cur_box);
@@ -1625,7 +1520,7 @@ void package(int c)
}
}
if (saved2 != null) {
- /* DIR: Adjust back |text_dir_ptr| for |scan_spec| */
+ /*tex Adjust back |text_dir_ptr| for |scan_spec| */
flush_node_list(text_dir_ptr);
text_dir_ptr = saved2;
@@ -1635,14 +1530,19 @@ void package(int c)
box_end(saved0);
}
-@ When a box is being appended to the current vertical list, the baselineskip
-calculation is handled by the |append_to_vlist| routine.
+/*tex
+
+ When a box is being appended to the current vertical list, the baselineskip
+ calculation is handled by the |append_to_vlist| routine.
+
+*/
-@c
void append_to_vlist(halfword b, int location)
{
- scaled d; /* deficiency of space between baselines */
- halfword p; /* a new glue node */
+ /*tex The deficiency of space between baselines: */
+ scaled d;
+ /*tex A new glue node. */
+ halfword p;
boolean mirrored = (type(b) == hlist_node) && is_mirrored(box_dir(b)) ;
halfword result = null;
halfword next_depth = ignore_depth;
@@ -1682,188 +1582,235 @@ void append_to_vlist(halfword b, int location)
}
}
-@ When |saving_vdiscards| is positive then the glue, kern, and penalty nodes
-removed by the page builder or by \.{\\vsplit} from the top of a vertical list
-are saved in special lists instead of being discarded.
+/*tex
+
+ When |saving_vdiscards| is positive then the glue, kern, and penalty nodes
+ removed by the page builder or by \.{\\vsplit} from the top of a vertical
+ list are saved in special lists instead of being discarded.
+
+*/
+
+/*tex last item removed by page builder */
+
+#define tail_page_disc disc_ptr[copy_code]
+
+/*tex first item removed by page builder */
+
+#define page_disc disc_ptr[last_box_code]
+
+/*tex first item removed by \.{\\vsplit} */
-@c
-#define tail_page_disc disc_ptr[copy_code] /* last item removed by page builder */
-#define page_disc disc_ptr[last_box_code] /* first item removed by page builder */
-#define split_disc disc_ptr[vsplit_code] /* first item removed by \.{\\vsplit} */
+#define split_disc disc_ptr[vsplit_code]
-halfword disc_ptr[(vsplit_code + 1)]; /* list pointers */
+/*tex List pointers. */
-@ The |vsplit| procedure, which implements \TeX's \.{\\vsplit} operation, is
-considerably simpler than |line_break| because it doesn't have to worry about
-hyphenation, and because its mission is to discover a single break instead of an
-optimum sequence of breakpoints. But before we get into the details of |vsplit|,
-we need to consider a few more basic things.
+halfword disc_ptr[(vsplit_code + 1)];
-A subroutine called |prune_page_top| takes a pointer to a vlist and returns a
-pointer to a modified vlist in which all glue, kern, and penalty nodes have been
-deleted before the first box or rule node. However, the first box or rule is
-actually preceded by a newly created glue node designed so that the topmost
-baseline will be at distance |split_top_skip| from the top, whenever this is
-possible without backspacing.
+/*tex
-When the second argument |s| is |false| the deleted nodes are destroyed,
-otherwise they are collected in a list starting at |split_disc|.
+ The |vsplit| procedure, which implements \TeX's \.{\\vsplit} operation, is
+ considerably simpler than |line_break| because it doesn't have to worry about
+ hyphenation, and because its mission is to discover a single break instead of
+ an optimum sequence of breakpoints. But before we get into the details of
+ |vsplit|, we need to consider a few more basic things.
+
+ A subroutine called |prune_page_top| takes a pointer to a vlist and returns a
+ pointer to a modified vlist in which all glue, kern, and penalty nodes have
+ been deleted before the first box or rule node. However, the first box or
+ rule is actually preceded by a newly created glue node designed so that the
+ topmost baseline will be at distance |split_top_skip| from the top, whenever
+ this is possible without backspacing.
+
+ When the second argument |s| is |false| the deleted nodes are destroyed,
+ otherwise they are collected in a list starting at |split_disc|.
+
+*/
-@c
halfword prune_page_top(halfword p, boolean s)
{
halfword q;
- halfword prev_p = temp_head; /* lags one step behind |p| */
+ /*tex Lags one step behind |p|. */
+ halfword prev_p = temp_head;
halfword r = null;
vlink(temp_head) = p;
while (p != null) {
switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- /* Insert glue for |split_top_skip| and set~|p:=null| */
- q = new_skip_param(split_top_skip_code);
- vlink(prev_p) = q;
- vlink(q) = p;
- if (width(q) > height(p))
- width(q) = width(q) - height(p);
- else
- width(q) = 0;
- p = null;
- break;
- case boundary_node:
- case whatsit_node:
- case mark_node:
- case ins_node:
- prev_p = p;
- p = vlink(prev_p);
- break;
- case glue_node:
- case kern_node:
- case penalty_node:
- q = p;
- p = vlink(q);
- vlink(q) = null;
- vlink(prev_p) = p;
- if (s) {
- if (split_disc == null)
- split_disc = q;
+ case hlist_node:
+ case vlist_node:
+ case rule_node:
+ /*tex Insert glue for |split_top_skip| and set |p:=null|. */
+ q = new_skip_param(split_top_skip_code);
+ vlink(prev_p) = q;
+ vlink(q) = p;
+ if (width(q) > height(p))
+ width(q) = width(q) - height(p);
else
- vlink(r) = q;
- r = q;
- } else {
- flush_node_list(q);
- }
- break;
- default:
- confusion("pruning");
- break;
+ width(q) = 0;
+ p = null;
+ break;
+ case boundary_node:
+ case whatsit_node:
+ case mark_node:
+ case ins_node:
+ prev_p = p;
+ p = vlink(prev_p);
+ break;
+ case glue_node:
+ case kern_node:
+ case penalty_node:
+ q = p;
+ p = vlink(q);
+ vlink(q) = null;
+ vlink(prev_p) = p;
+ if (s) {
+ if (split_disc == null)
+ split_disc = q;
+ else
+ vlink(r) = q;
+ r = q;
+ } else {
+ flush_node_list(q);
+ }
+ break;
+ default:
+ confusion("pruning");
+ break;
}
}
return vlink(temp_head);
}
-@ The next subroutine finds the best place to break a given vertical list so as
-to obtain a box of height~|h|, with maximum depth~|d|. A pointer to the beginning
-of the vertical list is given, and a pointer to the optimum breakpoint is
-returned. The list is effectively followed by a forced break, i.e., a penalty
-node with the |eject_penalty|; if the best break occurs at this artificial node,
-the value |null| is returned.
+/*tex
+
+ The next subroutine finds the best place to break a given vertical list so as
+ to obtain a box of height~|h|, with maximum depth~|d|. A pointer to the
+ beginning of the vertical list is given, and a pointer to the optimum
+ breakpoint is returned. The list is effectively followed by a forced break,
+ i.e., a penalty node with the |eject_penalty|; if the best break occurs at
+ this artificial node, the value |null| is returned.
-@c
-scaled active_height[10]; /* distance from first active node to~|cur_p| */
+*/
+
+/*tex The distance from first active node to |cur_p|: */
+
+scaled active_height[10];
-@ An array of six |scaled| distances is used to keep track of the height from the
-beginning of the list to the current place, just as in |line_break|. In fact, we
-use one of the same arrays, only changing its name to reflect its new
-significance.
+/*tex
+
+ An array of six |scaled| distances is used to keep track of the height from
+ the beginning of the list to the current place, just as in |line_break|. In
+ fact, we use one of the same arrays, only changing its name to reflect its
+ new significance.
+
+*/
-@c
#define do_all_six(A) A(1);A(2);A(3);A(4);A(5);A(6);A(7)
#define set_height_zero(A) active_height[A]=0 /* initialize the height to zero */
-@ A global variable |best_height_plus_depth| will be set to the natural size of
-the box that corresponds to the optimum breakpoint found by |vert_break|. (This
-value is used by the insertion-splitting algorithm of the page builder.)
+/*tex
-@ height of the best box, without stretching or shrinking
+ A global variable |best_height_plus_depth| will be set to the natural size of
+ the box that corresponds to the optimum breakpoint found by |vert_break|.
+ (This value is used by the insertion-splitting algorithm of the page
+ builder.)
-@c
-scaled best_height_plus_depth;
+*/
-/* finds optimum page break */
+/*tex The height of the best box, without stretching or shrinking: */
+
+scaled best_height_plus_depth;
halfword vert_break(halfword p, scaled h, scaled d)
{
- halfword prev_p = p; /* if |p| is a glue node, |type(prev_p)| determines whether |p| is a
- legal breakpoint, an initial glue node is not a legal breakpoint */
- int pi = 0; /* penalty value */
- int b; /* badness at a trial breakpoint */
- int t; /* |type| of the node following a kern */
- int least_cost; /* the smallest badness plus penalties found so far */
- halfword best_place = null; /* the most recent break that leads to |least_cost| */
- scaled prev_dp = 0; /* depth of previous box in the list */
+ /*tex
+ If |p| is a glue node, |type(prev_p)| determines whether |p| is a legal
+ breakpoint, an initial glue node is not a legal breakpoint.
+ */
+ halfword prev_p = p;
+ /*tex penalty value */
+ int pi = 0;
+ /*tex badness at a trial breakpoint */
+ int b;
+ /*tex |type| of the node following a kern */
+ int t;
+ /*tex the smallest badness plus penalties found so far */
+ int least_cost;
+ /*tex the most recent break that leads to |least_cost| */
+ halfword best_place = null;
+ /*tex depth of previous box in the list */
+ scaled prev_dp = 0;
least_cost = awful_bad;
do_all_six(set_height_zero);
while (1) {
- /* If node |p| is a legal breakpoint, check if this break is
- the best known, and |goto done| if |p| is null or
- if the page-so-far is already too full to accept more stuff */
- /* A subtle point to be noted here is that the maximum depth~|d| might be
- negative, so |cur_height| and |prev_dp| might need to be corrected even
- after a glue or kern node. */
+ /*tex
+ If node |p| is a legal breakpoint, check if this break is the best
+ known, and |goto done| if |p| is null or if the page-so-far is
+ already too full to accept more stuff.
+
+ A subtle point to be noted here is that the maximum depth~|d| might
+ be negative, so |cur_height| and |prev_dp| might need to be corrected
+ even after a glue or kern node.
+ */
if (p == null) {
pi = eject_penalty;
} else {
- /* Use node |p| to update the current height and depth measurements;
- if this node is not a legal breakpoint, |goto not_found|
- or |update_heights|,
- otherwise set |pi| to the associated penalty at the break */
+ /*tex
+
+ Use node |p| to update the current height and depth measurements;
+ if this node is not a legal breakpoint, |goto not_found| or
+ |update_heights|, otherwise set |pi| to the associated penalty at
+ the break.
+
+ */
switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- cur_height = cur_height + prev_dp + height(p);
- prev_dp = depth(p);
- goto NOT_FOUND;
- break;
- case boundary_node:
- case whatsit_node:
- goto NOT_FOUND;
- break;
- case glue_node:
- if (precedes_break(prev_p))
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case kern_node:
- if (vlink(p) == null)
- t = penalty_node;
- else
- t = type(vlink(p));
- if (t == glue_node)
- pi = 0;
- else
- goto UPDATE_HEIGHTS;
- break;
- case penalty_node:
- pi = penalty(p);
- break;
- case mark_node:
- case ins_node:
- goto NOT_FOUND;
- break;
- default:
- confusion("vertbreak");
- break;
+ case hlist_node:
+ case vlist_node:
+ case rule_node:
+ cur_height = cur_height + prev_dp + height(p);
+ prev_dp = depth(p);
+ goto NOT_FOUND;
+ break;
+ case boundary_node:
+ case whatsit_node:
+ goto NOT_FOUND;
+ break;
+ case glue_node:
+ if (precedes_break(prev_p))
+ pi = 0;
+ else
+ goto UPDATE_HEIGHTS;
+ break;
+ case kern_node:
+ if (vlink(p) == null)
+ t = penalty_node;
+ else
+ t = type(vlink(p));
+ if (t == glue_node)
+ pi = 0;
+ else
+ goto UPDATE_HEIGHTS;
+ break;
+ case penalty_node:
+ pi = penalty(p);
+ break;
+ case mark_node:
+ case ins_node:
+ goto NOT_FOUND;
+ break;
+ default:
+ confusion("vertbreak");
+ break;
}
}
- /* Check if node |p| is a new champion breakpoint; then |goto done|
- if |p| is a forced break or if the page-so-far is already too full */
+ /*tex
+
+ Check if node |p| is a new champion breakpoint; then |goto done| if
+ |p| is a forced break or if the page-so-far is already too full.
+
+ */
if (pi < inf_penalty) {
- /* Compute the badness, |b|, using |awful_bad| if the box is too full */
+ /*tex Compute the badness, |b|, using |awful_bad| if the box is too full. */
if (cur_height < h) {
if ((active_height[3] != 0) || (active_height[4] != 0) ||
(active_height[5] != 0) || (active_height[6] != 0))
@@ -1875,7 +1822,6 @@ halfword vert_break(halfword p, scaled h, scaled d)
} else {
b = badness(cur_height - h, active_height[7]);
}
-
if (b < awful_bad) {
if (pi <= eject_penalty)
b = pi;
@@ -1892,25 +1838,29 @@ halfword vert_break(halfword p, scaled h, scaled d)
if ((b == awful_bad) || (pi <= eject_penalty))
goto DONE;
}
-
if ((type(p) < glue_node) || (type(p) > kern_node))
goto NOT_FOUND;
UPDATE_HEIGHTS:
- /* Update the current height and depth measurements with
- respect to a glue or kern node~|p| */
- /* Vertical lists that are subject to the |vert_break| procedure should not
- contain infinite shrinkability, since that would permit any amount of
- information to ``fit'' on one page. */
+ /*tex
+
+ Update the current height and depth measurements with respect to a
+ glue or kern node~|p|. Vertical lists that are subject to the
+ |vert_break| procedure should not contain infinite shrinkability,
+ since that would permit any amount of information to ``fit'' on one
+ page.
+ */
if (type(p) != kern_node) {
active_height[2 + stretch_order(p)] += stretch(p);
active_height[7] += shrink(p);
if ((shrink_order(p) != normal) && (shrink(p) != 0)) {
print_err("Infinite glue shrinkage found in box being split");
- help4("The box you are \\vsplitting contains some infinitely",
- "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
- "Such glue doesn't belong there; but you can safely proceed,",
- "since the offensive shrinkability has been made finite.");
+ help4(
+ "The box you are \\vsplitting contains some infinitely",
+ "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
+ "Such glue doesn't belong there; but you can safely proceed,",
+ "since the offensive shrinkability has been made finite."
+ );
error();
shrink_order(p) = normal;
}
@@ -1929,31 +1879,39 @@ halfword vert_break(halfword p, scaled h, scaled d)
return best_place;
}
-@ Now we are ready to consider |vsplit| itself. Most of its work is accomplished
-by the two subroutines that we have just considered.
+/*tex
+
+ Now we are ready to consider |vsplit| itself. Most of its work is
+ accomplished by the two subroutines that we have just considered.
-Given the number of a vlist box |n|, and given a desired page height |h|, the
-|vsplit| function finds the best initial segment of the vlist and returns a box
-for a page of height~|h|. The remainder of the vlist, if any, replaces the
-original box, after removing glue and penalties and adjusting for
-|split_top_skip|. Mark nodes in the split-off box are used to set the values of
-|split_first_mark| and |split_bot_mark|; we use the fact that
-|split_first_mark(x)=null| if and only if |split_bot_mark(x)=null|.
+ Given the number of a vlist box |n|, and given a desired page height |h|, the
+ |vsplit| function finds the best initial segment of the vlist and returns a
+ box for a page of height~|h|. The remainder of the vlist, if any, replaces
+ the original box, after removing glue and penalties and adjusting for
+ |split_top_skip|. Mark nodes in the split-off box are used to set the values
+ of |split_first_mark| and |split_bot_mark|; we use the fact that
+ |split_first_mark(x)=null| if and only if |split_bot_mark(x)=null|.
-The original box becomes ``void'' if and only if it has been entirely extracted.
-The extracted box is ``void'' if and only if the original box was void (or if it
-was, erroneously, an hlist box).
+ The original box becomes ``void'' if and only if it has been entirely
+ extracted. The extracted box is ``void'' if and only if the original box was
+ void (or if it was, erroneously, an hlist box).
-@c
-/* extracts a page of height |h| from box |n| */
+*/
+
+/*tex Extract a page of height |h| from box |n|: */
halfword vsplit(halfword n, scaled h, int m)
{
- halfword v; /* the box to be split */
- int vdir; /* the direction of the box to be split */
- halfword p; /* runs through the vlist */
- halfword q; /* points to where the break occurs */
- halfword i; /* for traversing marks lists */
+ /*tex the box to be split */
+ halfword v;
+ /*tex the direction of the box to be split */
+ int vdir;
+ /*tex runs through the vlist */
+ halfword p;
+ /*tex points to where the break occurs */
+ halfword q;
+ /*tex for traversing marks lists */
+ halfword i;
v = box(n);
vdir = box_dir(v);
flush_node_list(split_disc);
@@ -1962,23 +1920,27 @@ halfword vsplit(halfword n, scaled h, int m)
delete_split_first_mark(i);
delete_split_bot_mark(i);
}
- /* Dispense with trivial cases of void or bad boxes */
+ /*tex Dispense with trivial cases of void or bad boxes. */
if (v == null) {
return null;
}
if (type(v) != vlist_node) {
print_err("\\vsplit needs a \\vbox");
- help2("The box you are trying to split is an \\hbox.",
- "i can't split such a box, so I''ll leave it alone.");
+ help2(
+ "The box you are trying to split is an \\hbox.",
+ "i can't split such a box, so I''ll leave it alone."
+ );
error();
return null;
}
q = vert_break(list_ptr(v), h, split_max_depth_par);
- /*
- Look at all the marks in nodes before the break, and set the final
- link to |null| at the break. It's possible that the box begins with
- a penalty node that is the ``best'' break, so we must be careful to
- handle this special case correctly.
+ /*tex
+
+ Look at all the marks in nodes before the break, and set the final link
+ to |null| at the break. It's possible that the box begins with a penalty
+ node that is the ``best'' break, so we must be careful to handle this
+ special case correctly.
+
*/
p = list_ptr(v);
if (p == q) {
@@ -2009,7 +1971,7 @@ halfword vsplit(halfword n, scaled h, int m)
list_ptr(v) = null;
flush_node(v);
if (q == null) {
- /* the |eq_level| of the box stays the same */
+ /*tex The |eq_level| of the box stays the same. */
box(n) = null;
} else {
box(n) = filtered_vpackage(q, 0, additional, max_depth_par, split_keep_group, vdir, 0, 0);
@@ -2021,17 +1983,23 @@ halfword vsplit(halfword n, scaled h, int m)
}
}
-@ Now that we can see what eventually happens to boxes, we can consider the first
-steps in their creation. The |begin_box| routine is called when |box_context| is
-a context specification, |cur_chr| specifies the type of box desired, and
-|cur_cmd=make_box|.
+/*tex
+
+ Now that we can see what eventually happens to boxes, we can consider the
+ first steps in their creation. The |begin_box| routine is called when
+ |box_context| is a context specification, |cur_chr| specifies the type of box
+ desired, and |cur_cmd=make_box|.
+
+*/
-@c
void begin_box(int box_context)
{
- halfword q; /* run through the current list */
- halfword k; /* 0 or |vmode| or |hmode| */
- int n; /* a box number */
+ /*tex run through the current list */
+ halfword q;
+ /*tex 0 or |vmode| or |hmode| */
+ halfword k;
+ /*tex a box number */
+ int n;
int spec_direction = -1;
int just_pack = 0;
int split_mode = exactly ;
@@ -2039,7 +2007,7 @@ void begin_box(int box_context)
case box_code:
scan_register_num();
cur_box = box(cur_val);
- /* the box becomes void, at the same level */
+ /*tex The box becomes void, at the same level. */
box(cur_val) = null;
break;
case copy_code:
@@ -2047,10 +2015,11 @@ void begin_box(int box_context)
cur_box = copy_node_list(box(cur_val));
break;
case last_box_code:
- /*
- If the current list ends with a box node, delete it from
- the list and make |cur_box| point to it; otherwise set
- |cur_box:=null|.
+ /*tex
+
+ If the current list ends with a box node, delete it from the list
+ and make |cur_box| point to it; otherwise set |cur_box:=null|.
+
*/
cur_box = null;
if (abs(cur_list.mode_field) == mmode) {
@@ -2059,17 +2028,15 @@ void begin_box(int box_context)
error();
} else if ((cur_list.mode_field == vmode) && (cur_list.head_field == cur_list.tail_field)) {
you_cant();
- help2("Sorry...I usually can't take things from the current page.",
- "This \\lastbox will therefore be void.");
+ help2(
+ "Sorry...I usually can't take things from the current page.",
+ "This \\lastbox will therefore be void."
+ );
error();
} else {
if (cur_list.head_field != cur_list.tail_field) {
- /* todo: new code, needs testing */
-
- /* maybe: ((type(cur_list.tail_field) == hlist_node) < rule_node) */
-
if ((type(cur_list.tail_field) == hlist_node) || (type(cur_list.tail_field) == vlist_node)) {
- /* Remove the last box ... */
+ /*tex Remove the last box */
q = alink(cur_list.tail_field);
if (q == null || vlink(q) != cur_list.tail_field) {
q = cur_list.head_field;
@@ -2086,9 +2053,11 @@ void begin_box(int box_context)
}
break;
case vsplit_code:
- /*
- Split off part of a vertical box, make |cur_box| point to it. Here we
- deal with things like `\.{\\vsplit 13 to 100pt}'.
+ /*tex
+
+ Split off part of a vertical box, make |cur_box| point to it.
+ Here we deal with things like `\.{\\vsplit 13 to 100pt}'.
+
*/
scan_register_num();
n = cur_val;
@@ -2096,18 +2065,22 @@ void begin_box(int box_context)
split_mode = additional ;
} else if (!scan_keyword("to")) {
print_err("Missing `to' inserted");
- help2("I'm working on `\\vsplit<box number> to <dimen>';",
- "will look for the <dimen> next.");
+ help2(
+ "I'm working on `\\vsplit<box number> to <dimen>';",
+ "will look for the <dimen> next."
+ );
error();
}
scan_normal_dimen();
cur_box = vsplit(n, cur_val, split_mode);
break;
default:
- /*
- Initiate the construction of an hbox or vbox, then |return|. Here is
- where we enter restricted horizontal mode or internal vertical mode,
- in order to make a box.
+ /*tex
+
+ Initiate the construction of an hbox or vbox, then |return|. Here
+ is where we enter restricted horizontal mode or internal vertical
+ mode, in order to make a box.
+
*/
switch (cur_chr) {
case tpack_code:
@@ -2123,7 +2096,6 @@ void begin_box(int box_context)
just_pack = 1;
break;
}
- /* */
k = cur_chr - vtop_code;
set_saved_record(0, saved_boxcontext, 0, box_context);
switch (abs(cur_list.mode_field)) {
@@ -2165,6 +2137,6 @@ void begin_box(int box_context)
return;
break;
}
- /* in simple cases, we use the box immediately */
+ /*tex In simple cases, we use the box immediately. */
box_end(box_context);
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/postlinebreak.w b/Build/source/texk/web2c/luatexdir/tex/postlinebreak.c
index dd85cf01b3e..cbc77e556fa 100644
--- a/Build/source/texk/web2c/luatexdir/tex/postlinebreak.w
+++ b/Build/source/texk/web2c/luatexdir/tex/postlinebreak.c
@@ -1,60 +1,65 @@
-% postlinebreak.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
+postlinebreak.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/>.
+
+*/
#include "ptexlib.h"
-@ So far we have gotten a little way into the |line_break| routine, having
-covered its important |try_break| subroutine. Now let's consider the
-rest of the process.
+/*tex
+
+So far we have gotten a little way into the |line_break| routine, having covered
+its important |try_break| subroutine. Now let's consider the rest of the process.
-The main loop of |line_break| traverses the given hlist,
-starting at |vlink(temp_head)|, and calls |try_break| at each legal
-breakpoint. A variable called |auto_breaking| is set to true except
-within math formulas, since glue nodes are not legal breakpoints when
-they appear in formulas.
+The main loop of |line_break| traverses the given hlist, starting at
+|vlink(temp_head)|, and calls |try_break| at each legal breakpoint. A variable
+called |auto_breaking| is set to true except within math formulas, since glue
+nodes are not legal breakpoints when they appear in formulas.
The current node of interest in the hlist is pointed to by |cur_p|. Another
-variable, |prev_p|, is usually one step behind |cur_p|, but the real
-meaning of |prev_p| is this: If |type(cur_p)=glue_node| then |cur_p| is a legal
-breakpoint if and only if |auto_breaking| is true and |prev_p| does not
-point to a glue node, penalty node, explicit kern node, or math node.
+variable, |prev_p|, is usually one step behind |cur_p|, but the real meaning of
+|prev_p| is this: If |type(cur_p)=glue_node| then |cur_p| is a legal breakpoint
+if and only if |auto_breaking| is true and |prev_p| does not point to a glue
+node, penalty node, explicit kern node, or math node.
+
+The total number of lines that will be set by |post_line_break| is
+|best_line-prev_graf-1|. The last breakpoint is specified by
+|break_node(best_bet)|, and this passive node points to the other breakpoints via
+the |prev_break| links. The finishing-up phase starts by linking the relevant
+passive nodes in forward order, changing |prev_break| to |next_break|. (The
+|next_break| fields actually reside in the same memory space as the |prev_break|
+fields did, but we give them a new name because of their new significance.) Then
+the lines are justified, one by one.
-@ The total number of lines that will be set by |post_line_break|
-is |best_line-prev_graf-1|. The last breakpoint is specified by
-|break_node(best_bet)|, and this passive node points to the other breakpoints
-via the |prev_break| links. The finishing-up phase starts by linking the
-relevant passive nodes in forward order, changing |prev_break| to
-|next_break|. (The |next_break| fields actually reside in the same memory
-space as the |prev_break| fields did, but we give them a new name because
-of their new significance.) Then the lines are justified, one by one.
+The |post_line_break| must also keep an dir stack, so that it can output end
+direction instructions at the ends of lines and begin direction instructions at
+the beginnings of lines.
-The |post_line_break| must also keep an dir stack, so that it can
-output end direction instructions at the ends of lines
-and begin direction instructions at the beginnings of lines.
+*/
-@c
-#define next_break prev_break /*new name for |prev_break| after links are reversed */
+/*tex The new name for |prev_break| after links are reversed: */
+
+#define next_break prev_break
+
+/*tex The |int|s are actually halfwords. */
-/* the ints are actually halfwords */
void ext_post_line_break(int paragraph_dir,
int right_skip,
int left_skip,
@@ -78,32 +83,39 @@ void ext_post_line_break(int paragraph_dir,
{
boolean have_directional = true;
- halfword q, r; /* temporary registers for list manipulation */
+ /*tex temporary registers for list manipulation */
+ halfword q, r;
halfword k;
scaled w;
- boolean glue_break; /* was a break at glue? */
- boolean disc_break; /*was the current break at a discretionary node? */
- boolean post_disc_break; /*and did it have a nonempty post-break part? */
- scaled cur_width; /*width of line number |cur_line| */
- scaled cur_indent; /*left margin of line number |cur_line| */
- int pen; /*use when calculating penalties between lines */
- halfword cur_p; /* |cur_p|, but localized */
- halfword cur_line; /*the current line number being justified */
-
+ /*tex was a break at glue? */
+ boolean glue_break;
+ /*tex was the current break at a discretionary node? */
+ boolean disc_break;
+ /*tex and did it have a nonempty post-break part? */
+ boolean post_disc_break;
+ /*tex width of line number |cur_line| */
+ scaled cur_width;
+ /*tex left margin of line number |cur_line| */
+ scaled cur_indent;
+ /*tex use when calculating penalties between lines */
+ int pen;
+ /*tex |cur_p|, but localized */
+ halfword cur_p;
+ /*tex the current line number being justified */
+ halfword cur_line;
+ /*tex the current direction: */
dir_ptr = cur_list.dirs_field;
- /* Reverse the links of the relevant passive nodes, setting |cur_p| to
- the first breakpoint; */
- /* The job of reversing links in a list is conveniently regarded as the job
- of taking items off one stack and putting them on another. In this case we
- take them off a stack pointed to by |q| and having |prev_break| fields;
- we put them on a stack pointed to by |cur_p| and having |next_break| fields.
- Node |r| is the passive node being moved from stack to stack.
- */
+ /*tex
+ Reverse the links of the relevant passive nodes, setting |cur_p| to the
+ first breakpoint. The job of reversing links in a list is conveniently
+ regarded as the job of taking items off one stack and putting them on
+ another. In this case we take them off a stack pointed to by |q| and
+ having |prev_break| fields; we put them on a stack pointed to by |cur_p|
+ and having |next_break| fields. Node |r| is the passive node being moved
+ from stack to stack.
+ */
q = break_node(best_bet);
-#if 0
- used_discs = used_disc(best_bet);
-#endif
- /* |has_direction| */
+ /*tex |cur_p| will become the first breakpoint; */
cur_p = null;
do {
r = q;
@@ -111,73 +123,68 @@ void ext_post_line_break(int paragraph_dir,
next_break(r) = cur_p;
cur_p = r;
} while (q != null);
- /* |cur_p| is now the first breakpoint; */
-
- cur_line = cur_list.pg_field + 1; /* prevgraf+1 */
-
+ /*tex prevgraf + 1 */
+ cur_line = cur_list.pg_field + 1;
do {
- /* Justify the line ending at breakpoint |cur_p|, and append it to the
- current vertical list, together with associated penalties and other
- insertions; */
- /* The current line to be justified appears in a horizontal list starting
- at |vlink(temp_head)| and ending at |cur_break(cur_p)|. If |cur_break(cur_p)| is
- a glue node, we reset the glue to equal the |right_skip| glue; otherwise
- we append the |right_skip| glue at the right. If |cur_break(cur_p)| is a
- discretionary node, we modify the list so that the discretionary break
- is compulsory, and we set |disc_break| to |true|. We also append
- the |left_skip| glue at the left of the line, unless it is zero. */
-
-#if 0
- tprint("BEGIN OF LINE ");
- print_int(cur_break(cur_p));
- breadth_max = 100000;
- depth_threshold = 100000;
- show_node_list(temp_head);
-#endif
-
- /* DIR: Insert dir nodes at the beginning of the current line; */
- for (q = dir_ptr; q != null; q = vlink(q)) {
- halfword tmp = new_dir(dir_dir(q));
- halfword nxt = vlink(temp_head);
- delete_attribute_ref(node_attr(tmp));
- node_attr(tmp) = node_attr(temp_head);
- add_node_attr_ref(node_attr(tmp));
- couple_nodes(temp_head, tmp);
- try_couple_nodes(tmp, nxt); /* \.{\\break}\.{\\par} */
- }
+ /*tex
+ Justify the line ending at breakpoint |cur_p|, and append it to the
+ current vertical list, together with associated penalties and other
+ insertions.
+
+ The current line to be justified appears in a horizontal list
+ starting at |vlink(temp_head)| and ending at |cur_break(cur_p)|. If
+ |cur_break(cur_p)| is a glue node, we reset the glue to equal the
+ |right_skip| glue; otherwise we append the |right_skip| glue at the
+ right. If |cur_break(cur_p)| is a discretionary node, we modify the
+ list so that the discretionary break is compulsory, and we set
+ |disc_break| to |true|. We also append the |left_skip| glue at the
+ left of the line, unless it is zero.
+ */
if (dir_ptr != null) {
+ /*tex Insert dir nodes at the beginning of the current line. */
+ for (q = dir_ptr; q != null; q = vlink(q)) {
+ halfword tmp = new_dir(dir_dir(q));
+ halfword nxt = vlink(temp_head);
+ delete_attribute_ref(node_attr(tmp));
+ node_attr(tmp) = node_attr(temp_head);
+ add_node_attr_ref(node_attr(tmp));
+ couple_nodes(temp_head, tmp);
+ /*tex \.{\\break}\.{\\par} */
+ try_couple_nodes(tmp, nxt);
+ }
flush_node_list(dir_ptr);
dir_ptr = null;
}
+ /*tex
+ Modify the end of the line to reflect the nature of the break and to
+ include \.{\\rightskip}; also set the proper value of |disc_break|.
+ At the end of the following code, |q| will point to the final node on
+ the list about to be justified. In the meanwhile |r| will point to
+ the node we will use to insert end-of-line stuff after. |q==null|
+ means we use the final position of |r|.
+ */
- /* Modify the end of the line to reflect the nature of the break and to
- include \.{\\rightskip}; also set the proper value of |disc_break|; */
- /* At the end of the following code, |q| will point to the final node on the
- list about to be justified. In the meanwhile |r| will point to the
- node we will use to insert end-of-line stuff after. |q==null| means
- we use the final position of |r| */
-
- /* begin mathskip code */
if (temp_head != null) {
- q = temp_head;
- while(q != null) {
- if (type(q) == math_node) {
- surround(q) = 0 ;
- reset_glue_to_zero(q);
- break;
- } else if ((type(q) == hlist_node) && (subtype(q) == indent_list)) {
- /* go on */
- } else if (is_char_node(q)) {
- break;
- } else if (non_discardable(q)) {
- break;
- } else if (type(q) == kern_node && subtype(q) != explicit_kern && subtype(q) != italic_kern) {
- break;
- }
- q = vlink(q);
+ /*tex begin mathskip code */
+ q = temp_head;
+ while(q != null) {
+ if (type(q) == math_node) {
+ surround(q) = 0 ;
+ reset_glue_to_zero(q);
+ break;
+ } else if ((type(q) == hlist_node) && (subtype(q) == indent_list)) {
+ /* go on */
+ } else if (is_char_node(q)) {
+ break;
+ } else if (non_discardable(q)) {
+ break;
+ } else if (type(q) == kern_node && subtype(q) != explicit_kern && subtype(q) != italic_kern) {
+ break;
}
+ q = vlink(q);
}
- /* end mathskip code */
+ /*tex end mathskip code */
+ }
r = cur_break(cur_p);
q = null;
@@ -189,27 +196,26 @@ void ext_post_line_break(int paragraph_dir,
if (r == null) {
for (r = temp_head; vlink(r) != null; r = vlink(r));
if (r == final_par_glue) {
- /* This should almost always be true... */
- /* TODO assert ? */
+ /*tex This should almost always be true... */
q = r;
- /* |q| refers to the last node of the line (and paragraph) */
+ /*tex |q| refers to the last node of the line (and paragraph) */
r = alink(r);
}
- /* |r| refers to the node after which the dir nodes should be closed */
+ /*tex |r| refers to the node after which the dir nodes should be closed */
} else if (type(r) == math_node) {
surround(r) = 0;
- /* begin mathskip code */
+ /*tex begin mathskip code */
reset_glue_to_zero(r);
- /* end mathskip code */
+ /*tex end mathskip code */
} else if (type(r) == glue_node) {
copy_glue_values(r,right_skip);
subtype(r) = right_skip_code + 1;
glue_break = true;
- /* |q| refers to the last node of the line */
+ /*tex |q| refers to the last node of the line */
q = r;
r = alink(r);
assert(vlink(r) == q);
- /* |r| refers to the node after which the dir nodes should be closed */
+ /*tex |r| refers to the node after which the dir nodes should be closed */
} else if (type(r) == disc_node) {
halfword a = alink(r);
halfword v = vlink(r);
@@ -228,7 +234,6 @@ void ext_post_line_break(int paragraph_dir,
vlink_no_break(r) = null;
tlink_no_break(r) = null;
}
-
assert(type(a) == disc_node && subtype(a) == init_disc);
flush_node_list(vlink_no_break(a));
vlink_no_break(a) = null;
@@ -239,11 +244,10 @@ void ext_post_line_break(int paragraph_dir,
flush_node_list(vlink_post_break(a));
vlink_post_break(a) = null;
tlink_post_break(a) = null;
-
break;
case init_disc:
assert(type(v) == disc_node && subtype(v) == select_disc);
- subtype(v) = syllable_disc; /* not special any more */
+ subtype(v) = syllable_disc;
flush_node_list(vlink_no_break(v));
vlink_no_break(v) = vlink_post_break(r);
tlink_no_break(v) = tlink_post_break(r);
@@ -273,27 +277,24 @@ void ext_post_line_break(int paragraph_dir,
} else if (type(r) == kern_node) {
width(r) = 0;
}
-
- /* DIR: Adjust the dir stack based on dir nodes in this line; */
- /* TODO what about the previousparagraph ??? */
+ /*tex Adjust the dir stack based on dir nodes in this line. */
if (have_directional) {
- halfword e;
- halfword p;
+ halfword e, p;
for (e = vlink(temp_head); e != null && e != cur_break(cur_p); e = vlink(e)) {
if (type(e) == dir_node) {
- if (dir_dir(e) >= 0) {
+ if (subtype(e) == normal_dir) {
dir_ptr = do_push_dir_node(dir_ptr, e);
- } else if (dir_ptr != null && dir_dir(dir_ptr) == (dir_dir(e) + dir_swap)) {
+ } else if (dir_ptr != null && dir_dir(dir_ptr) == dir_dir(e)) {
dir_ptr = do_pop_dir_node(dir_ptr);
}
}
}
assert(e == cur_break(cur_p));
-
- /* DIR: Insert dir nodes at the end of the current line; */
+ /*tex Insert dir nodes at the end of the current line. */
e = vlink(r);
for (p = dir_ptr; p != null; p = vlink(p)) {
- halfword s = new_dir(dir_dir(p) - dir_swap);
+ halfword s = new_dir(dir_dir(p));
+ subtype(s) = cancel_dir;
delete_attribute_ref(node_attr(s));
node_attr(s) = node_attr(r);
add_node_attr_ref(node_attr(s));
@@ -303,7 +304,6 @@ void ext_post_line_break(int paragraph_dir,
}
}
if (passive_right_box(cur_p) != null) {
- /* TODO: CHECK has |s| below a |alink| ? */
halfword s = copy_node_list(passive_right_box(cur_p));
halfword e = vlink(r);
couple_nodes(r, s);
@@ -313,28 +313,30 @@ void ext_post_line_break(int paragraph_dir,
if (q == null) {
q = r;
}
- /* Now [q] refers to the last node on the line */
-
- /* FIXME from this point on we no longer keep alink() valid */
-
- /* at this point |q| is the rightmost breakpoint; the only exception is
- the case of a discretionary break with non-empty |pre_break|, then |q|
- has been changed to the last node of the |pre_break| list */
- /* If the par ends with a \break command, the last line is utterly empty.
- That is the case of |q==temp_head| */
+ /*tex
+ Now [q] refers to the last node on the line and therefore the
+ rightmost breakpoint. The only exception is the case of a
+ discretionary break with non-empty |pre_break|, then |q| has been
+ changed to the last node of the |pre_break| list. If the par ends
+ with a \break command, the last line is utterly empty. That is the
+ case of |q==temp_head|.
+ */
if (q != temp_head && protrude_chars > 0) {
halfword p, ptmp;
if (disc_break && (is_char_node(q) || (type(q) != disc_node))) {
- p = q; /* |q| has been reset to the last node of |pre_break| */
+ /*tex |q| is reset to the last node of |pre_break| */
+ p = q;
ptmp = p;
} else {
- p = alink(q); /* get |vlink(p) = q| */
+ /*tex get |vlink(p) = q| */
+ p = alink(q);
assert(vlink(p) == q);
ptmp = p;
}
p = find_protchar_right(vlink(temp_head), p);
w = char_pw(p, right_side);
- if (w != 0) { /* we have found a marginal kern, append it after |ptmp| */
+ if (w != 0) {
+ /*tex we have found a marginal kern, append it after |ptmp| */
k = new_margin_kern(-w, last_rightmost_char, right_side);
delete_attribute_ref(node_attr(k));
node_attr(k) = node_attr(p);
@@ -345,10 +347,12 @@ void ext_post_line_break(int paragraph_dir,
q = vlink(q);
}
}
- /* if |q| was not a breakpoint at glue and has been reset to |rightskip|
- then we append |rightskip| after |q| now */
+ /*tex
+ If |q| was not a breakpoint at glue and has been reset to |rightskip|
+ then we append |rightskip| after |q| now.
+ */
if (!glue_break) {
- /* Put the \.{\\rightskip} glue after node |q|; */
+ /*tex Put the \.{\\rightskip} glue after node |q|. */
halfword r1 = new_glue((right_skip == null ? zero_glue : right_skip));
subtype(r1) = right_skip_code+1;
try_couple_nodes(r1,vlink(q));
@@ -358,21 +362,22 @@ void ext_post_line_break(int paragraph_dir,
couple_nodes(q,r1);
q = r1;
}
-
- /* /Modify the end of the line to reflect the nature of the break and to
- include \.{\\rightskip}; also set the proper value of |disc_break|; */
-
- /* Put the \.{\\leftskip} glue at the left and detach this line; */
- /* The following code begins with |q| at the end of the list to be
- justified. It ends with |q| at the beginning of that list, and with
- |vlink(temp_head)| pointing to the remainder of the paragraph, if any. */
+ /*tex
+ Modify the end of the line to reflect the nature of the break and to
+ include \.{\\rightskip}; also set the proper value of |disc_break|;
+ Also put the \.{\\leftskip} glue at the left and detach this line.
+
+ The following code begins with |q| at the end of the list to be
+ justified. It ends with |q| at the beginning of that list, and with
+ |vlink(temp_head)| pointing to the remainder of the paragraph, if
+ any.
+ */
r = vlink(q);
vlink(q) = null;
q = vlink(temp_head);
try_couple_nodes(temp_head, r);
if (passive_left_box(cur_p) != null && passive_left_box(cur_p) != 0) {
- /* omega bits: */
halfword s;
r = copy_node_list(passive_left_box(cur_p));
s = vlink(q);
@@ -388,11 +393,14 @@ void ext_post_line_break(int paragraph_dir,
}
}
}
- /*at this point |q| is the leftmost node; all discardable nodes have been discarded */
+ /*tex
+ At this point |q| is the leftmost node; all discardable nodes have
+ been discarded
+ */
if (protrude_chars > 0) {
halfword p;
p = q;
- p = find_protchar_left(p, false); /* no more discardables */
+ p = find_protchar_left(p, false);
w = char_pw(p, left_side);
if (w != 0) {
k = new_margin_kern(-w, last_leftmost_char, left_side);
@@ -412,13 +420,14 @@ void ext_post_line_break(int paragraph_dir,
couple_nodes(r,q);
q = r;
}
- /* /Put the \.{\\leftskip} glue at the left and detach this line; */
-
- /* Call the packaging subroutine, setting |just_box| to the justified box; */
- /* Now |q| points to the hlist that represents the current line of the
- paragraph. We need to compute the appropriate line width, pack the
- line into a box of this size, and shift the box by the appropriate
- amount of indentation. */
+ /*tex
+ Put the \.{\\leftskip} glue at the left and detach this line. Call
+ the packaging subroutine, setting |just_box| to the justified box.
+ Now |q| points to the hlist that represents the current line of the
+ paragraph. We need to compute the appropriate line width, pack the
+ line into a box of this size, and shift the box by the appropriate
+ amount of indentation.
+ */
if (cur_line > last_special_line) {
cur_width = second_width;
cur_indent = second_indent;
@@ -438,8 +447,10 @@ void ext_post_line_break(int paragraph_dir,
}
shift_amount(just_box) = cur_indent;
subtype(just_box) = line_list;
- /* /Call the packaging subroutine, setting |just_box| to the justified box; */
-
+ /*tex
+ Call the packaging subroutine, setting |just_box| to the justified
+ box.
+ */
if ((vlink(contrib_head) != null))
checked_break_filter(pre_box);
if (pre_adjust_head != pre_adjust_tail) {
@@ -454,17 +465,17 @@ void ext_post_line_break(int paragraph_dir,
checked_break_filter(adjust);
}
adjust_tail = null;
-
- /* /Append the new box to the current vertical list, followed by the list of
- special nodes taken out of the box by the packager; */
-
- /* Append a penalty node, if a nonzero penalty is appropriate */
- /* Penalties between the lines of a paragraph come from club and widow lines,
- from the |inter_line_penalty| parameter, and from lines that end at
- discretionary breaks. Breaking between lines of a two-line paragraph gets
- both club-line and widow-line penalties. The local variable |pen| will
- be set to the sum of all relevant penalties for the current line, except
- that the final line is never penalized. */
+ /*tex
+ Append the new box to the current vertical list, followed by the list
+ of special nodes taken out of the box by the packager. Append a
+ penalty node, if a nonzero penalty is appropriate. Penalties between
+ the lines of a paragraph come from club and widow lines, from the
+ |inter_line_penalty| parameter, and from lines that end at
+ discretionary breaks. Breaking between lines of a two-line paragraph
+ gets both club-line and widow-line penalties. The local variable
+ |pen| will be set to the sum of all relevant penalties for the
+ current line, except that the final line is never penalized.
+ */
if (cur_line + 1 != best_line) {
q = inter_line_penalties_ptr;
if (q != null) {
@@ -481,11 +492,13 @@ void ext_post_line_break(int paragraph_dir,
}
q = club_penalties_ptr;
if (q != null) {
- r = cur_line - cur_list.pg_field; /* prevgraf */
+ /*tex prevgraf */
+ r = cur_line - cur_list.pg_field;
if (r > penalty(q))
r = penalty(q);
pen += penalty(q + r);
- } else if (cur_line == cur_list.pg_field + 1) { /* prevgraf */
+ } else if (cur_line == cur_list.pg_field + 1) {
+ /*tex prevgraf */
pen += club_penalty;
}
q = widow_penalties_ptr;
@@ -510,34 +523,37 @@ void ext_post_line_break(int paragraph_dir,
cur_list.tail_field = r;
}
}
- /* /Append a penalty node, if a nonzero penalty is appropriate */
-
- /* /Justify the line ending at breakpoint |cur_p|, and append it to the
- current vertical list, together with associated penalties and other
- insertions; */
+ /*tex
+ Append a penalty node, if a nonzero penalty is appropriate. Justify
+ the line ending at breakpoint |cur_p|, and append it to the current
+ vertical list, together with associated penalties and other
+ insertions.
+ */
incr(cur_line);
cur_p = next_break(cur_p);
if (cur_p != null && !post_disc_break) {
- /* Prune unwanted nodes at the beginning of the next line; */
- /* Glue and penalty and kern and math nodes are deleted at the
- beginning of a line, except in the anomalous case that the
- node to be deleted is actually one of the chosen
- breakpoints. Otherwise the pruning done here is designed to
- match the lookahead computation in |try_break|, where the
- |break_width| values are computed for non-discretionary
- breakpoints. */
+ /*tex
+ Prune unwanted nodes at the beginning of the next line. Glue and
+ penalty and kern and math nodes are deleted at the beginning of a
+ line, except in the anomalous case that the node to be deleted is
+ actually one of the chosen breakpoints. Otherwise the pruning
+ done here is designed to match the lookahead computation in
+ |try_break|, where the |break_width| values are computed for
+ non-discretionary breakpoints.
+ */
r = temp_head;
- /*
- Normally we have a matching math open and math close node but when we cross a line
- the open node is removed, including any glue or penalties following it. This is however
- not that nice for callbacks that rely on symmetry. Of course this only counts for one
- liners, as we can still have only a begin or end node on a line. The end_of_math lua
- helper is made robust against this although there you should be aware of the fact that
- one can end up in the middle of math in callbacks that don't work on whole paragraphs,
- but at least this branch makes sure that some proper analysis is possible. (todo: check
- if math glyphs have the subtype marked done).
-
- Todo: turn math nodes into glues when mathskip otherwise remove them.
+ /*tex
+ Normally we have a matching math open and math close node but
+ when we cross a line the open node is removed, including any glue
+ or penalties following it. This is however not that nice for
+ callbacks that rely on symmetry. Of course this only counts for
+ one liners, as we can still have only a begin or end node on a
+ line. The end_of_math lua helper is made robust against this
+ although there you should be aware of the fact that one can end
+ up in the middle of math in callbacks that don't work on whole
+ paragraphs, but at least this branch makes sure that some proper
+ analysis is possible. (todo: check if math glyphs have the
+ subtype marked done).
*/
while (1) {
q = vlink(r);
@@ -550,17 +566,17 @@ void ext_post_line_break(int paragraph_dir,
}
*/
if (type(q) == math_node) {
- /* begin mathskip code */
+ /*tex begin mathskip code */
surround(q) = 0 ;
reset_glue_to_zero(q);
- /* end mathskip code */
+ /*tex end mathskip code */
}
if (q == cur_break(cur_p)) {
break;
} else if (is_char_node(q)) {
break;
} else if (type(q) == local_par_node) {
- /* weird, in the middle somewhere */
+ /*tex weird, in the middle somewhere */
} else if (non_discardable(q)) {
break;
} else if (type(q) == kern_node && subtype(q) != explicit_kern && subtype(q) != italic_kern) {
@@ -577,7 +593,9 @@ void ext_post_line_break(int paragraph_dir,
} while (cur_p != null);
if ((cur_line != best_line) || (vlink(temp_head) != null))
confusion("line breaking");
- cur_list.pg_field = best_line - 1; /* prevgraf */
- cur_list.dirs_field = dir_ptr; /* |dir_save| */
+ /*tex prevgraf */
+ cur_list.pg_field = best_line - 1;
+ /*tex |dir_save| */
+ cur_list.dirs_field = dir_ptr;
dir_ptr = null;
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/primitive.c b/Build/source/texk/web2c/luatexdir/tex/primitive.c
new file mode 100644
index 00000000000..f16d69a333c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/primitive.c
@@ -0,0 +1,785 @@
+/*
+
+primitive.w
+
+Copyright 2008-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+/*tex
+
+Control sequences are stored and retrieved by means of a fairly standard hash
+table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C in
+{\sl The Art of Computer Programming\/}). Once a control sequence enters the
+table, it is never removed, because there are complicated situations involving
+\.{\\gdef} where the removal of a control sequence at the end of a group would be
+a mistake preventable only by the introduction of a complicated reference-count
+mechanism.
+
+The actual sequence of letters forming a control sequence identifier is stored in
+the |str_pool| array together with all the other strings. An auxiliary array
+|hash| consists of items with two halfword fields per word. The first of these,
+called |next(p)|, points to the next identifier belonging to the same coalesced
+list as the identifier corresponding to~|p|; and the other, called |text(p)|,
+points to the |str_start| entry for |p|'s identifier. If position~|p| of the hash
+table is empty, we have |text(p)=0|; if position |p| is either empty or the end
+of a coalesced hash list, we have |next(p)=0|. An auxiliary pointer variable
+called |hash_used| is maintained in such a way that all locations |p>=hash_used|
+are nonempty. The global variable |cs_count| tells how many multiletter control
+sequences have been defined, if statistics are being kept.
+
+A global boolean variable called |no_new_control_sequence| is set to |true|
+during the time that new hash table entries are forbidden.
+
+*/
+
+/*tex The hash table: */
+
+two_halves *hash;
+
+/*tex Allocation pointer for |hash|: */
+
+halfword hash_used;
+
+/*tex |hash_extra=hash| above |eqtb_size|: */
+
+int hash_extra;
+
+/*tex Maximum of the hash array: */
+
+halfword hash_top;
+
+/*tex Pointer to next high hash location: */
+
+halfword hash_high;
+
+/*tex Are new identifiers legal? */
+
+boolean no_new_control_sequence;
+
+/*tex Total number of known identifiers: */
+
+int cs_count;
+
+/*tex Test if all positions are occupied: */
+
+#define hash_is_full (hash_used==hash_base)
+
+/*tex
+
+ \.{\\primitive} support needs a few extra variables and definitions,
+ like:
+
+*/
+
+#define prim_base 1
+
+/*tex
+
+The arrays |prim| and |prim_eqtb| are used for name -> cmd,chr lookups. The are
+modelled after |hash| and |eqtb|, except that primitives do not have an
+|eq_level|, that field is replaced by |origin|.
+
+*/
+
+/*tex Link for coalesced lists: */
+
+#define prim_next(a) prim[(a)].lhfield
+
+/*tex String number for control sequence name: */
+
+#define prim_text(a) prim[(a)].rh
+
+/*tex Test if all positions are occupied: */
+
+#define prim_is_full (prim_used==prim_base)
+
+#define prim_origin_field(a) (a).hh.b1
+
+#define prim_eq_type_field(a) (a).hh.b0
+
+#define prim_equiv_field(a) (a).hh.rh
+
+/*tex Level of definition: */
+
+#define prim_origin(a) prim_origin_field(prim_eqtb[(a)])
+
+/*tex Command code for equivalent: */
+
+#define prim_eq_type(a) prim_eq_type_field(prim_eqtb[(a)])
+
+/*tex Equivalent value: */
+
+#define prim_equiv(a) prim_equiv_field(prim_eqtb[(a)])
+
+/*tex Allocation pointer for |prim|: */
+
+static pointer prim_used;
+
+/*tex The primitives table: */
+
+static two_halves prim[(prim_size + 1)];
+
+static memory_word prim_eqtb[(prim_size + 1)];
+
+/*tex
+
+The array |prim_data| works the other way around, it is used for cmd,chr -> name
+lookups.
+
+*/
+
+typedef struct prim_info {
+ /*tex Number of name entries: */
+ halfword subids;
+ /*tex Offset to be used for |chr_code|s: */
+ halfword offset;
+ /*tex Array of names: */
+ str_number *names;
+} prim_info;
+
+static prim_info prim_data[(last_cmd + 1)];
+
+/*tex
+
+Initialize the memory arrays:
+
+*/
+
+void init_primitives(void)
+{
+ int k;
+ memset(prim_data, 0, (sizeof(prim_info) * (last_cmd + 1)));
+ memset(prim, 0, (sizeof(two_halves) * (prim_size + 1)));
+ memset(prim_eqtb, 0, (sizeof(memory_word) * (prim_size + 1)));
+ for (k = 0; k <= prim_size; k++) {
+ prim_eq_type(k) = undefined_cs_cmd;
+ }
+}
+
+/*tex Nothing is used (yet). */
+
+void ini_init_primitives(void)
+{
+ prim_used = prim_size;
+}
+
+
+/*tex
+
+The value of |hash_prime| should be roughly 85\%! of |hash_size|, and it should
+be a prime number. The theory of hashing tells us to expect fewer than two table
+probes, on the average, when the search is successful. [See J.~S. Vitter, {\sl
+Journal of the ACM\/ \bf30} (1983), 231--258.] @^Vitter, Jeffrey Scott@>
+
+*/
+
+static halfword compute_hash(const char *j, unsigned int l, halfword prime_number)
+{
+ int k;
+ halfword h = (unsigned char) *j;
+ for (k = 1; k <= (int)(l - 1); k++) {
+ h = h + h + (unsigned char) *(j + k);
+ while (h >= prime_number) {
+ h = h - prime_number;
+ }
+ }
+ return h;
+}
+
+/*tex
+
+Here is the subroutine that searches the primitive table for an identifier.
+
+*/
+
+pointer prim_lookup(str_number s)
+{
+ /*tex The hash code: */
+ int h;
+ /*tex The index in the |hash| array: */
+ pointer p;
+ unsigned char *j;
+ unsigned l;
+ if (s < STRING_OFFSET) {
+ p = s;
+ if ((p < 0) || (get_prim_eq_type(p) == undefined_cs_cmd)) {
+ p = undefined_primitive;
+ }
+ } else {
+ j = str_string(s);
+ l = (unsigned) str_length(s);
+ h = compute_hash((char *) j, l, prim_prime);
+ /*tex We start searching here; note that |0<=h<hash_prime|. */
+ p = h + prim_base;
+ while (1) {
+ if (prim_text(p) > 0)
+ if (str_length(prim_text(p)) == l)
+ if (str_eq_str(prim_text(p), s))
+ goto FOUND;
+ if (prim_next(p) == 0) {
+ if (no_new_control_sequence) {
+ p = undefined_primitive;
+ } else {
+ /*tex Insert a new primitive after |p|, then make |p| point to it. */
+ if (prim_text(p) > 0) {
+ do {
+ /*tex Search for an empty location in |prim| */
+ if (prim_is_full) {
+ overflow("primitive size", prim_size);
+ }
+ decr(prim_used);
+ } while (prim_text(prim_used) != 0);
+ prim_next(p) = prim_used;
+ p = prim_used;
+ }
+ prim_text(p) = s;
+ }
+ goto FOUND;
+ }
+ p = prim_next(p);
+ }
+ }
+ FOUND:
+ return p;
+}
+
+/*tex
+
+How to test a csname for primitive-ness?
+
+*/
+
+boolean is_primitive(str_number csname)
+{
+ int n, m;
+ char *ss;
+ m = prim_lookup(csname);
+ ss = makecstring(csname);
+ n = string_lookup(ss, str_length(csname));
+ free(ss);
+ return ((n != undefined_cs_cmd) && (m != undefined_primitive) &&
+ (eq_type(n) == prim_eq_type(m)) && (equiv(n) == prim_equiv(m)));
+}
+
+
+/*tex
+
+A few simple accessors.
+
+*/
+
+quarterword get_prim_eq_type(int p)
+{
+ return prim_eq_type(p);
+}
+
+quarterword get_prim_origin(int p)
+{
+ return prim_origin(p);
+}
+
+halfword get_prim_equiv(int p)
+{
+ return prim_equiv(p);
+}
+
+str_number get_prim_text(int p)
+{
+ return prim_text(p);
+}
+
+
+/*tex
+
+Dumping and undumping.
+
+*/
+
+void dump_primitives(void)
+{
+ int p, q;
+ for (p = 0; p <= prim_size; p++) {
+ dump_hh(prim[p]);
+ }
+ for (p = 0; p <= prim_size; p++) {
+ dump_wd(prim_eqtb[p]);
+ }
+ for (p = 0; p <= last_cmd; p++) {
+ dump_int(prim_data[p].offset);
+ dump_int(prim_data[p].subids);
+ for (q = 0; q < prim_data[p].subids; q++) {
+ dump_int(prim_data[p].names[q]);
+ }
+ }
+}
+
+void undump_primitives(void)
+{
+ int p, q;
+ for (p = 0; p <= prim_size; p++) {
+ undump_hh(prim[p]);
+ }
+ for (p = 0; p <= prim_size; p++) {
+ undump_wd(prim_eqtb[p]);
+ }
+ for (p = 0; p <= last_cmd; p++) {
+ undump_int(prim_data[p].offset);
+ undump_int(prim_data[p].subids);
+ if (prim_data[p].subids > 0) {
+ prim_data[p].names = (str_number *) xmalloc((unsigned) ((unsigned) prim_data[p].subids * sizeof(str_number *)));
+ for (q = 0; q < prim_data[p].subids; q++) {
+ undump_int(prim_data[p].names[q]);
+ }
+ }
+ }
+}
+
+/*tex
+
+We need to put \TeX's ``primitive'' control sequences into the hash table,
+together with their command code (which will be the |eq_type|) and an operand
+(which will be the |equiv|). The |primitive| procedure does this, in a way that
+no \TeX\ user can. The global value |cur_val| contains the new |eqtb| pointer
+after |primitive| has acted.
+
+Because the definitions of the actual user-accessible name of a primitive can be
+postponed until runtime, the function |primitive_def| is needed that does nothing
+except creating the control sequence name.
+
+*/
+
+void primitive_def(const char *s, size_t l, quarterword c, halfword o)
+{
+ int nncs = no_new_control_sequence;
+ no_new_control_sequence = false;
+ /*tex This creates the |text()| string: */
+ cur_val = string_lookup(s, l);
+ no_new_control_sequence = nncs;
+ eq_level(cur_val) = level_one;
+ eq_type(cur_val) = c;
+ equiv(cur_val) = o;
+}
+
+/*tex
+
+The function |store_primitive_name| sets up the bookkeeping for the reverse
+lookup. It is quite paranoid, because it is easy to mess this up accidentally.
+
+The |offset| is needed because sometimes character codes (in |o|) are indices
+into |eqtb| or are offset by a magical value to make sure they do not conflict
+with something else. We don't want the |prim_data[c].names| to have too many
+entries as it will just be wasted room, so |offset| is substracted from |o|
+because creating or accessing the array. The |assert(idx<=0xFFFF)| is not
+strictly needed, but it helps catch errors of this kind.
+
+*/
+
+static void store_primitive_name(str_number s, quarterword c, halfword o, halfword offset)
+{
+ int idx;
+ /*
+ if (prim_data[c].offset != 0 && prim_data[c].offset != offset) {
+ assert(false);
+ }
+ */
+ prim_data[c].offset = offset;
+ idx = ((int) o - offset);
+ /*
+ assert(idx >= 0);
+ assert(idx <= 0xFFFF);
+ */
+ if (prim_data[c].subids < (idx + 1)) {
+ str_number *new = (str_number *) xcalloc((unsigned) (idx + 1), sizeof(str_number *));
+ if (prim_data[c].names != NULL) {
+ /*
+ assert(prim_data[c].subids);
+ */
+ memcpy(new, (prim_data[c].names), (unsigned) (prim_data[c].subids) * sizeof(str_number));
+ free(prim_data[c].names);
+ }
+ prim_data[c].names = new;
+ prim_data[c].subids = idx + 1;
+ }
+ prim_data[c].names[idx] = s;
+}
+
+/*tex
+
+Compared to tex82, |primitive| has two extra parameters. The |off| is an offset
+that will be passed on to |store_primitive_name|, the |cmd_origin| is the bit
+that is used to group primitives by originator.
+
+*/
+
+void primitive(const char *thes, quarterword c, halfword o, halfword off, int cmd_origin)
+{
+ /*tex Needed to fill |prim_eqtb|: */
+ int prim_val;
+ str_number ss;
+ ss = maketexstring(thes);
+ if (cmd_origin == tex_command || cmd_origin == core_command) {
+ primitive_def(thes, strlen(thes), c, o);
+ }
+ prim_val = prim_lookup(ss);
+ prim_origin(prim_val) = (quarterword) cmd_origin;
+ prim_eq_type(prim_val) = c;
+ prim_equiv(prim_val) = o;
+ store_primitive_name(ss, c, o, off);
+}
+
+/*tex
+
+Here is a helper that does the actual hash insertion. This code far from ideal:
+the existance of |hash_extra| changes all the potential (short) coalesced lists
+into a single (long) one. This will create a slowdown.
+
+*/
+
+static halfword insert_id(halfword p, const unsigned char *j, unsigned int l)
+{
+ unsigned saved_cur_length;
+ unsigned saved_cur_string_size;
+ unsigned char *saved_cur_string;
+ const unsigned char *k;
+ if (cs_text(p) > 0) {
+ if (hash_high < hash_extra) {
+ incr(hash_high);
+ /*tex
+ Can't we use |eqtb_top| here (perhaps because that is not
+ finalized yet when called from |primitive|?
+ */
+ cs_next(p) = hash_high + eqtb_size;
+ p = cs_next(p);
+ } else {
+ /*tex
+ Search for an empty location in |hash|.
+ */
+ do {
+ if (hash_is_full)
+ overflow("hash size", (unsigned) (hash_size + hash_extra));
+ decr(hash_used);
+ } while (cs_text(hash_used) != 0);
+ cs_next(p) = hash_used;
+ p = hash_used;
+ }
+ }
+ saved_cur_length = cur_length;
+ saved_cur_string = cur_string;
+ saved_cur_string_size = cur_string_size;
+ reset_cur_string();
+ for (k = j; k <= j + l - 1; k++) {
+ append_char(*k);
+ }
+ cs_text(p) = make_string();
+ cur_length = saved_cur_length;
+ xfree(cur_string);
+ cur_string = saved_cur_string;
+ cur_string_size = saved_cur_string_size;
+ incr(cs_count);
+ return p;
+}
+
+
+/*tex
+
+Here is the subroutine that searches the hash table for an identifier that
+matches a given string of length |l>1| appearing in |buffer[j.. (j+l-1)]|. If the
+identifier is found, the corresponding hash table address is returned. Otherwise,
+if the global variable |no_new_control_sequence| is |true|, the dummy address
+|undefined_control_sequence| is returned. Otherwise the identifier is inserted
+into the hash table and its location is returned.
+
+*/
+
+pointer id_lookup(int j, int l)
+{
+ /*tex The hash code: */
+ int h;
+ /*tex The index in |hash| array: */
+ pointer p;
+ h = compute_hash((char *) (buffer + j), (unsigned) l, hash_prime);
+ /*tex We start searching here. Note that |0<=h<hash_prime|: */
+ p = h + hash_base;
+ while (1) {
+ if (cs_text(p) > 0)
+ if (str_length(cs_text(p)) == (unsigned) l)
+ if (str_eq_buf(cs_text(p), j))
+ goto FOUND;
+ if (cs_next(p) == 0) {
+ if (no_new_control_sequence) {
+ p = undefined_control_sequence;
+ } else {
+ p = insert_id(p, (buffer + j), (unsigned) l);
+ }
+ goto FOUND;
+ }
+ p = cs_next(p);
+ }
+ FOUND:
+ return p;
+}
+
+/*tex
+
+Here is a similar subroutine for finding a primitive in the hash.
+This one is based on a C string.
+
+*/
+
+pointer string_lookup(const char *s, size_t l)
+{
+ /*tex The hash code: */
+ int h;
+ /*tex The index in |hash| array: */
+ pointer p;
+ h = compute_hash(s, (unsigned) l, hash_prime);
+ /*tex We start searching here. Note that |0<=h<hash_prime|: */
+ p = h + hash_base;
+ while (1) {
+ if (cs_text(p) > 0)
+ if (str_eq_cstr(cs_text(p), s, l))
+ goto FOUND;
+ if (cs_next(p) == 0) {
+ if (no_new_control_sequence) {
+ p = undefined_control_sequence;
+ } else {
+ p = insert_id(p, (const unsigned char *) s, (unsigned) l);
+ }
+ goto FOUND;
+ }
+ p = cs_next(p);
+ }
+ FOUND:
+ return p;
+}
+
+/*tex
+
+The |print_cmd_chr| routine prints a symbolic interpretation of a command code
+and its modifier. This is used in certain `\.{You can\'t}' error messages, and in
+the implementation of diagnostic routines like \.{\\show}.
+
+The body of |print_cmd_chr| use to be a rather tedious listing of print commands,
+and most of it was essentially an inverse to the |primitive| routine that enters
+a \TeX\ primitive into |eqtb|.
+
+Thanks to |prim_data|, there is no need for all that tediousness. What is left of
+|primt_cnd_chr| are just the exceptions to the general rule that the
+|cmd,chr_code| pair represents in a single primitive command.
+
+*/
+
+#define chr_cmd(A) do { tprint(A); print(chr_code); } while (0)
+
+static void prim_cmd_chr(quarterword cmd, halfword chr_code)
+{
+ int idx = chr_code - prim_data[cmd].offset;
+ if (cmd <= last_cmd &&
+ idx >= 0 && idx < prim_data[cmd].subids &&
+ prim_data[cmd].names != NULL && prim_data[cmd].names[idx] != 0) {
+ tprint_esc("");
+ print(prim_data[cmd].names[idx]);
+ } else {
+ /* \TEX82 didn't print the |cmd,idx| information, but it may be useful. */
+ tprint("[unknown command code! (");
+ print_int(cmd);
+ tprint(", ");
+ print_int(idx);
+ tprint(")]");
+ }
+}
+
+void print_cmd_chr(quarterword cmd, halfword chr_code)
+{
+ int n;
+ switch (cmd) {
+ case left_brace_cmd:
+ chr_cmd("begin-group character ");
+ break;
+ case right_brace_cmd:
+ chr_cmd("end-group character ");
+ break;
+ case math_shift_cmd:
+ chr_cmd("math shift character ");
+ break;
+ case mac_param_cmd:
+ if (chr_code == tab_mark_cmd_code)
+ tprint_esc("alignmark");
+ else
+ chr_cmd("macro parameter character ");
+ break;
+ case sup_mark_cmd:
+ chr_cmd("superscript character ");
+ break;
+ case sub_mark_cmd:
+ chr_cmd("subscript character ");
+ break;
+ case endv_cmd:
+ tprint("end of alignment template");
+ break;
+ case spacer_cmd:
+ chr_cmd("blank space ");
+ break;
+ case letter_cmd:
+ chr_cmd("the letter ");
+ break;
+ case other_char_cmd:
+ chr_cmd("the character ");
+ break;
+ case tab_mark_cmd:
+ if (chr_code == span_code)
+ tprint_esc("span");
+ else if (chr_code == tab_mark_cmd_code)
+ tprint_esc("aligntab");
+ else
+ chr_cmd("alignment tab character ");
+ break;
+ case if_test_cmd:
+ if (chr_code >= unless_code)
+ tprint_esc("unless");
+ prim_cmd_chr(cmd, (chr_code % unless_code));
+ break;
+ case char_given_cmd:
+ tprint_esc("char");
+ print_qhex(chr_code);
+ break;
+ case math_given_cmd:
+ /*tex
+ Okay, it's better for old macro packages that mess with meaning
+ to report a traditional value. A compromise.
+ */
+ tprint_esc("mathchar");
+ show_mathcode_value_old(chr_code);
+ break;
+ case xmath_given_cmd:
+ tprint_esc("Umathchar");
+ show_mathcode_value(mathchar_from_integer(chr_code, umath_mathcode));
+ break;
+ case lua_expandable_call_cmd:
+ tprint("expandable luacall ");
+ print_int(chr_code);
+ break;
+ case lua_local_call_cmd:
+ tprint("local luacall ");
+ print_int(chr_code);
+ break;
+ case lua_call_cmd:
+ tprint("luacall ");
+ print_int(chr_code);
+ break;
+ case set_font_cmd:
+ tprint("select font ");
+ tprint(font_name(chr_code));
+ if (font_size(chr_code) != font_dsize(chr_code)) {
+ tprint(" at ");
+ print_scaled(font_size(chr_code));
+ tprint("pt");
+ }
+ break;
+ case undefined_cs_cmd:
+ tprint("undefined");
+ break;
+ case call_cmd:
+ case long_call_cmd:
+ case outer_call_cmd:
+ case long_outer_call_cmd:
+ n = cmd - call_cmd;
+ if (token_info(token_link(chr_code)) == protected_token)
+ n = n + 4;
+ if (odd(n / 4))
+ tprint_esc("protected");
+ if (odd(n))
+ tprint_esc("long");
+ if (odd(n / 2))
+ tprint_esc("outer");
+ if (n > 0)
+ tprint(" ");
+ tprint("macro");
+ break;
+ case assign_glue_cmd:
+ case assign_mu_glue_cmd:
+ if (chr_code < skip_base) {
+ prim_cmd_chr(cmd, chr_code);
+ } else if (chr_code < mu_skip_base) {
+ tprint_esc("skip");
+ print_int(chr_code - skip_base);
+ } else {
+ tprint_esc("muskip");
+ print_int(chr_code - mu_skip_base);
+ }
+ break;
+ case assign_toks_cmd:
+ if (chr_code >= toks_base) {
+ tprint_esc("toks");
+ print_int(chr_code - toks_base);
+ } else {
+ prim_cmd_chr(cmd, chr_code);
+ }
+ break;
+ case assign_int_cmd:
+ if (chr_code < count_base) {
+ prim_cmd_chr(cmd, chr_code);
+ } else {
+ tprint_esc("count");
+ print_int(chr_code - count_base);
+ }
+ break;
+ case assign_attr_cmd:
+ tprint_esc("attribute");
+ print_int(chr_code - attribute_base);
+ break;
+ case assign_dimen_cmd:
+ if (chr_code < scaled_base) {
+ prim_cmd_chr(cmd, chr_code);
+ } else {
+ tprint_esc("dimen");
+ print_int(chr_code - scaled_base);
+ }
+ break;
+ case normal_cmd:
+ if (chr_code < prim_data[cmd].subids && prim_data[cmd].names[chr_code] != 0) {
+ prim_cmd_chr(cmd, chr_code);
+ } else {
+ tprint("[unknown command! (");
+ print_int(chr_code);
+ tprint(")]");
+ }
+ break;
+ case extension_cmd:
+ if (chr_code < prim_data[cmd].subids && prim_data[cmd].names[chr_code] != 0) {
+ prim_cmd_chr(cmd, chr_code);
+ } else {
+ tprint("[unknown extension! (");
+ print_int(chr_code);
+ tprint(")]");
+
+ }
+ break;
+ case node_cmd:
+ tprint("node ");
+ print_int(chr_code);
+ break;
+ default:
+ /*tex These are most commands, actually. */
+ prim_cmd_chr(cmd, chr_code);
+ break;
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/primitive.w b/Build/source/texk/web2c/luatexdir/tex/primitive.w
deleted file mode 100644
index 8c6592c9edf..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/primitive.w
+++ /dev/null
@@ -1,664 +0,0 @@
-% primitive.w
-%
-% Copyright 2008-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"
-
-@ Control sequences are stored and retrieved by means of a fairly standard hash
-table algorithm called the method of ``coalescing lists'' (cf.\ Algorithm 6.4C
-in {\sl The Art of Computer Programming\/}). Once a control sequence enters the
-table, it is never removed, because there are complicated situations
-involving \.{\\gdef} where the removal of a control sequence at the end of
-a group would be a mistake preventable only by the introduction of a
-complicated reference-count mechanism.
-
-The actual sequence of letters forming a control sequence identifier is
-stored in the |str_pool| array together with all the other strings. An
-auxiliary array |hash| consists of items with two halfword fields per
-word. The first of these, called |next(p)|, points to the next identifier
-belonging to the same coalesced list as the identifier corresponding to~|p|;
-and the other, called |text(p)|, points to the |str_start| entry for
-|p|'s identifier. If position~|p| of the hash table is empty, we have
-|text(p)=0|; if position |p| is either empty or the end of a coalesced
-hash list, we have |next(p)=0|. An auxiliary pointer variable called
-|hash_used| is maintained in such a way that all locations |p>=hash_used|
-are nonempty. The global variable |cs_count| tells how many multiletter
-control sequences have been defined, if statistics are being kept.
-
-A global boolean variable called |no_new_control_sequence| is set to
-|true| during the time that new hash table entries are forbidden.
-
-@c
-two_halves *hash; /* the hash table */
-halfword hash_used; /* allocation pointer for |hash| */
-int hash_extra; /* |hash_extra=hash| above |eqtb_size| */
-halfword hash_top; /* maximum of the hash array */
-halfword hash_high; /* pointer to next high hash location */
-boolean no_new_control_sequence; /* are new identifiers legal? */
-int cs_count; /* total number of known identifiers */
-
-#define hash_is_full (hash_used==hash_base) /* test if all positions are occupied */
-
-@ \.{\\primitive} support needs a few extra variables and definitions
-
-@c
-#define prim_base 1
-
-@ The arrays |prim| and |prim_eqtb| are used for name -> cmd,chr lookups.
-
- The are modelled after |hash| and |eqtb|, except that primitives do not
- have an |eq_level|, that field is replaced by |origin|.
-
-@c
-#define prim_next(a) prim[(a)].lhfield /* link for coalesced lists */
-#define prim_text(a) prim[(a)].rh /* string number for control sequence name */
-#define prim_is_full (prim_used==prim_base) /* test if all positions are occupied */
-
-#define prim_origin_field(a) (a).hh.b1
-#define prim_eq_type_field(a) (a).hh.b0
-#define prim_equiv_field(a) (a).hh.rh
-#define prim_origin(a) prim_origin_field(prim_eqtb[(a)]) /* level of definition */
-#define prim_eq_type(a) prim_eq_type_field(prim_eqtb[(a)]) /* command code for equivalent */
-#define prim_equiv(a) prim_equiv_field(prim_eqtb[(a)]) /* equivalent value */
-
-static pointer prim_used; /* allocation pointer for |prim| */
-static two_halves prim[(prim_size + 1)]; /* the primitives table */
-static memory_word prim_eqtb[(prim_size + 1)];
-
-@ The array |prim_data| works the other way around, it is used for
- cmd,chr -> name lookups.
-
-@c
-typedef struct prim_info {
- halfword subids; /* number of name entries */
- halfword offset; /* offset to be used for |chr_code|s */
- str_number *names; /* array of names */
-} prim_info;
-
-static prim_info prim_data[(last_cmd + 1)];
-
-@ initialize the memory arrays
-@c
-void init_primitives(void)
-{
- int k;
- memset(prim_data, 0, (sizeof(prim_info) * (last_cmd + 1)));
- memset(prim, 0, (sizeof(two_halves) * (prim_size + 1)));
- memset(prim_eqtb, 0, (sizeof(memory_word) * (prim_size + 1)));
- for (k = 0; k <= prim_size; k++)
- prim_eq_type(k) = undefined_cs_cmd;
-}
-
-void ini_init_primitives(void)
-{
- prim_used = prim_size; /* nothing is used */
-}
-
-
-@ The value of |hash_prime| should be roughly 85\%! of |hash_size|, and it
- should be a prime number. The theory of hashing tells us to expect fewer
- than two table probes, on the average, when the search is successful.
- [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
- @^Vitter, Jeffrey Scott@>
-
-@c
-static halfword compute_hash(const char *j, unsigned int l,
- halfword prime_number)
-{
- int k;
- halfword h = (unsigned char) *j;
- for (k = 1; k <= (int)(l - 1); k++) {
- h = h + h + (unsigned char) *(j + k);
- while (h >= prime_number)
- h = h - prime_number;
- }
- return h;
-}
-
-
-@ Here is the subroutine that searches the primitive table for an identifier
-@c
-pointer prim_lookup(str_number s)
-{
- int h; /* hash code */
- pointer p; /* index in |hash| array */
- unsigned char *j;
- unsigned l;
- if (s < STRING_OFFSET) {
- p = s;
- if ((p < 0) || (get_prim_eq_type(p) == undefined_cs_cmd)) {
- p = undefined_primitive;
- }
- } else {
- j = str_string(s);
- l = (unsigned) str_length(s);
- h = compute_hash((char *) j, l, prim_prime);
- p = h + prim_base; /* we start searching here; note that |0<=h<hash_prime| */
- while (1) {
- if (prim_text(p) > 0)
- if (str_length(prim_text(p)) == l)
- if (str_eq_str(prim_text(p), s))
- goto FOUND;
- if (prim_next(p) == 0) {
- if (no_new_control_sequence) {
- p = undefined_primitive;
- } else {
- /* Insert a new primitive after |p|, then make |p| point to it */
- if (prim_text(p) > 0) {
- do { /* search for an empty location in |prim| */
- if (prim_is_full)
- overflow("primitive size", prim_size);
- decr(prim_used);
- } while (prim_text(prim_used) != 0);
- prim_next(p) = prim_used;
- p = prim_used;
- }
- prim_text(p) = s;
- }
- goto FOUND;
- }
- p = prim_next(p);
- }
- }
- FOUND:
- return p;
-}
-
-@ how to test a csname for primitive-ness
-@c
-boolean is_primitive(str_number csname)
-{
- int n, m;
- char *ss;
- m = prim_lookup(csname);
- ss = makecstring(csname);
- n = string_lookup(ss, str_length(csname));
- free(ss);
- return ((n != undefined_cs_cmd) &&
- (m != undefined_primitive) &&
- (eq_type(n) == prim_eq_type(m)) && (equiv(n) == prim_equiv(m)));
-}
-
-
-@ a few simple accessors
-@c
-quarterword get_prim_eq_type(int p)
-{
- return prim_eq_type(p);
-}
-
-quarterword get_prim_origin(int p)
-{
- return prim_origin(p);
-}
-
-halfword get_prim_equiv(int p)
-{
- return prim_equiv(p);
-}
-
-str_number get_prim_text(int p)
-{
- return prim_text(p);
-}
-
-
-@ dumping and undumping
-@c
-void dump_primitives(void)
-{
- int p, q;
- for (p = 0; p <= prim_size; p++)
- dump_hh(prim[p]);
- for (p = 0; p <= prim_size; p++)
- dump_wd(prim_eqtb[p]);
- for (p = 0; p <= last_cmd; p++) {
- dump_int(prim_data[p].offset);
- dump_int(prim_data[p].subids);
- for (q = 0; q < prim_data[p].subids; q++) {
- dump_int(prim_data[p].names[q]);
- }
- }
-}
-
-void undump_primitives(void)
-{
- int p, q;
- for (p = 0; p <= prim_size; p++)
- undump_hh(prim[p]);
- for (p = 0; p <= prim_size; p++)
- undump_wd(prim_eqtb[p]);
-
- for (p = 0; p <= last_cmd; p++) {
- undump_int(prim_data[p].offset);
- undump_int(prim_data[p].subids);
- if (prim_data[p].subids > 0) {
- prim_data[p].names = (str_number *)
- xmalloc((unsigned)
- ((unsigned) prim_data[p].subids *
- sizeof(str_number *)));
- for (q = 0; q < prim_data[p].subids; q++)
- undump_int(prim_data[p].names[q]);
- }
- }
-}
-
-@ We need to put \TeX's ``primitive'' control sequences into the hash
- table, together with their command code (which will be the |eq_type|)
- and an operand (which will be the |equiv|). The |primitive| procedure
- does this, in a way that no \TeX\ user can. The global value |cur_val|
- contains the new |eqtb| pointer after |primitive| has acted.
-
-
-@ Because the definitions of the actual user-accessible name of a
- primitive can be postponed until runtime, the function |primitive_def|
- is needed that does nothing except creating the control sequence name.
-
-@c
-void primitive_def(const char *s, size_t l, quarterword c, halfword o)
-{
- int nncs = no_new_control_sequence;
- no_new_control_sequence = false;
- cur_val = string_lookup(s, l); /* this creates the |text()| string */
- no_new_control_sequence = nncs;
- eq_level(cur_val) = level_one;
- eq_type(cur_val) = c;
- equiv(cur_val) = o;
-}
-
-@ The function |store_primitive_name| sets up the bookkeeping for the
- reverse lookup. It is quite paranoid, because it is easy to mess this up
- accidentally.
-
- The |offset| is needed because sometimes character codes (in |o|)
- are indices into |eqtb| or are offset by a magical value to make
- sure they do not conflict with something else. We don't want the
- |prim_data[c].names| to have too many entries as it will just be
- wasted room, so |offset| is substracted from |o| because creating
- or accessing the array. The |assert(idx<=0xFFFF)| is not strictly
- needed, but it helps catch errors of this kind.
-
-@c
-static void
-store_primitive_name(str_number s, quarterword c, halfword o, halfword offset)
-{
- int idx;
- if (prim_data[c].offset != 0 && prim_data[c].offset != offset) {
- assert(false);
- }
- prim_data[c].offset = offset;
- idx = ((int) o - offset);
- assert(idx >= 0);
- assert(idx <= 0xFFFF);
- if (prim_data[c].subids < (idx + 1)) {
- str_number *new =
- (str_number *) xcalloc((unsigned) (idx + 1), sizeof(str_number *));
- if (prim_data[c].names != NULL) {
- assert(prim_data[c].subids);
- memcpy(new, (prim_data[c].names),
- (unsigned) (prim_data[c].subids) * sizeof(str_number));
- free(prim_data[c].names);
- }
- prim_data[c].names = new;
- prim_data[c].subids = idx + 1;
- }
- prim_data[c].names[idx] = s;
-}
-
-@ Compared to tex82, |primitive| has two extra parameters. The |off| is an offset
- that will be passed on to |store_primitive_name|, the |cmd_origin| is the bit
- that is used to group primitives by originator.
-
-@c
-void
-primitive(const char *thes, quarterword c, halfword o, halfword off,
- int cmd_origin)
-{
- int prim_val; /* needed to fill |prim_eqtb| */
- str_number ss;
- assert(o >= off);
- ss = maketexstring(thes);
- if (cmd_origin == tex_command || cmd_origin == core_command) {
- primitive_def(thes, strlen(thes), c, o);
- }
- prim_val = prim_lookup(ss);
- prim_origin(prim_val) = (quarterword) cmd_origin;
- prim_eq_type(prim_val) = c;
- prim_equiv(prim_val) = o;
- store_primitive_name(ss, c, o, off);
-}
-
-
-
-@ Here is a helper that does the actual hash insertion.
-
-@c
-static halfword insert_id(halfword p, const unsigned char *j, unsigned int l)
-{
- unsigned saved_cur_length;
- unsigned saved_cur_string_size;
- unsigned char *saved_cur_string;
- const unsigned char *k;
- /* This code far from ideal: the existance of |hash_extra| changes
- all the potential (short) coalesced lists into a single (long)
- one. This will create a slowdown. */
- if (cs_text(p) > 0) {
- if (hash_high < hash_extra) {
- incr(hash_high);
- /* can't use |eqtb_top| here (perhaps because that is not finalized
- yet when called from |primitive|?) */
- cs_next(p) = hash_high + eqtb_size;
- p = cs_next(p);
- } else {
- do {
- if (hash_is_full)
- overflow("hash size", (unsigned) (hash_size + hash_extra));
- decr(hash_used);
- } while (cs_text(hash_used) != 0); /* search for an empty location in |hash| */
- cs_next(p) = hash_used;
- p = hash_used;
- }
- }
- saved_cur_length = cur_length;
- saved_cur_string = cur_string;
- saved_cur_string_size = cur_string_size;
- reset_cur_string();
- for (k = j; k <= j + l - 1; k++)
- append_char(*k);
- cs_text(p) = make_string();
- cur_length = saved_cur_length;
- xfree(cur_string);
- cur_string = saved_cur_string;
- cur_string_size = saved_cur_string_size;
- incr(cs_count);
- return p;
-}
-
-
-@ Here is the subroutine that searches the hash table for an identifier
- that matches a given string of length |l>1| appearing in |buffer[j..
- (j+l-1)]|. If the identifier is found, the corresponding hash table address
- is returned. Otherwise, if the global variable |no_new_control_sequence|
- is |true|, the dummy address |undefined_control_sequence| is returned.
- Otherwise the identifier is inserted into the hash table and its location
- is returned.
-
-@c
-pointer id_lookup(int j, int l)
-{ /* search the hash table */
- int h; /* hash code */
- pointer p; /* index in |hash| array */
-
- h = compute_hash((char *) (buffer + j), (unsigned) l, hash_prime);
-#ifdef VERBOSE
- {
- unsigned char *todo = xmalloc(l + 2);
- strncpy(todo, (buffer + j), l);
- todo[l] = '\0';
- todo[l + 1] = '\0';
- fprintf(stdout, "id_lookup(%s)\n", todo);
- free(todo);
- }
-#endif
- p = h + hash_base; /* we start searching here; note that |0<=h<hash_prime| */
- while (1) {
- if (cs_text(p) > 0)
- if (str_length(cs_text(p)) == (unsigned) l)
- if (str_eq_buf(cs_text(p), j))
- goto FOUND;
- if (cs_next(p) == 0) {
- if (no_new_control_sequence) {
- p = undefined_control_sequence;
- } else {
- p = insert_id(p, (buffer + j), (unsigned) l);
- }
- goto FOUND;
- }
- p = cs_next(p);
- }
- FOUND:
- return p;
-}
-
-@ Here is a similar subroutine for finding a primitive in the hash.
-This one is based on a C string.
-
-@c
-pointer string_lookup(const char *s, size_t l)
-{ /* search the hash table */
- int h; /* hash code */
- pointer p; /* index in |hash| array */
- h = compute_hash(s, (unsigned) l, hash_prime);
- p = h + hash_base; /* we start searching here; note that |0<=h<hash_prime| */
- while (1) {
- if (cs_text(p) > 0)
- if (str_eq_cstr(cs_text(p), s, l))
- goto FOUND;
- if (cs_next(p) == 0) {
- if (no_new_control_sequence) {
- p = undefined_control_sequence;
- } else {
- p = insert_id(p, (const unsigned char *) s, (unsigned) l);
- }
- goto FOUND;
- }
- p = cs_next(p);
- }
- FOUND:
- return p;
-}
-
-@ The |print_cmd_chr| routine prints a symbolic interpretation of a
- command code and its modifier. This is used in certain `\.{You can\'t}'
- error messages, and in the implementation of diagnostic routines like
- \.{\\show}.
-
- The body of |print_cmd_chr| use to be a rather tedious listing of print
- commands, and most of it was essentially an inverse to the |primitive|
- routine that enters a \TeX\ primitive into |eqtb|.
-
- Thanks to |prim_data|, there is no need for all that tediousness. What
- is left of |primt_cnd_chr| are just the exceptions to the general rule
- that the |cmd,chr_code| pair represents in a single primitive command.
-
-@c
-#define chr_cmd(A) do { tprint(A); print(chr_code); } while (0)
-
-static void prim_cmd_chr(quarterword cmd, halfword chr_code)
-{
- int idx = chr_code - prim_data[cmd].offset;
- if (cmd <= last_cmd &&
- idx >= 0 && idx < prim_data[cmd].subids &&
- prim_data[cmd].names != NULL && prim_data[cmd].names[idx] != 0) {
- tprint_esc("");
- print(prim_data[cmd].names[idx]);
- } else {
- /* TEX82 didn't print the |cmd,idx| information, but it may be useful */
- tprint("[unknown command code! (");
- print_int(cmd);
- tprint(", ");
- print_int(idx);
- tprint(")]");
- }
-}
-
-void print_cmd_chr(quarterword cmd, halfword chr_code)
-{
- int n; /* temp variable */
- switch (cmd) {
- case left_brace_cmd:
- chr_cmd("begin-group character ");
- break;
- case right_brace_cmd:
- chr_cmd("end-group character ");
- break;
- case math_shift_cmd:
- chr_cmd("math shift character ");
- break;
- case mac_param_cmd:
- if (chr_code == tab_mark_cmd_code)
- tprint_esc("alignmark");
- else
- chr_cmd("macro parameter character ");
- break;
- case sup_mark_cmd:
- chr_cmd("superscript character ");
- break;
- case sub_mark_cmd:
- chr_cmd("subscript character ");
- break;
- case endv_cmd:
- tprint("end of alignment template");
- break;
- case spacer_cmd:
- chr_cmd("blank space ");
- break;
- case letter_cmd:
- chr_cmd("the letter ");
- break;
- case other_char_cmd:
- chr_cmd("the character ");
- break;
- case tab_mark_cmd:
- if (chr_code == span_code)
- tprint_esc("span");
- else if (chr_code == tab_mark_cmd_code)
- tprint_esc("aligntab");
- else
- chr_cmd("alignment tab character ");
- break;
- case if_test_cmd:
- if (chr_code >= unless_code)
- tprint_esc("unless");
- prim_cmd_chr(cmd, (chr_code % unless_code));
- break;
- case char_given_cmd:
- tprint_esc("char");
- print_hex(chr_code);
- break;
- case math_given_cmd:
- if (math_umathcode_meaning_par == 1) {
- tprint_esc("Umathchar");
- show_mathcode_value(mathchar_from_integer(chr_code, tex_mathcode));
- } else {
- /* better for old macro packages that mess with meaning */
- tprint_esc("mathchar");
- show_mathcode_value_old(chr_code);
- }
- break;
- case xmath_given_cmd:
- tprint_esc("Umathchar");
- show_mathcode_value(mathchar_from_integer(chr_code, umath_mathcode));
- break;
- case set_font_cmd:
- tprint("select font ");
- tprint(font_name(chr_code));
- if (font_size(chr_code) != font_dsize(chr_code)) {
- tprint(" at ");
- print_scaled(font_size(chr_code));
- tprint("pt");
- }
- break;
- case undefined_cs_cmd:
- tprint("undefined");
- break;
- case call_cmd:
- case long_call_cmd:
- case outer_call_cmd:
- case long_outer_call_cmd:
- n = cmd - call_cmd;
- if (token_info(token_link(chr_code)) == protected_token)
- n = n + 4;
- if (odd(n / 4))
- tprint_esc("protected");
- if (odd(n))
- tprint_esc("long");
- if (odd(n / 2))
- tprint_esc("outer");
- if (n > 0)
- tprint(" ");
- tprint("macro");
- break;
- case assign_glue_cmd:
- case assign_mu_glue_cmd:
- if (chr_code < skip_base) {
- prim_cmd_chr(cmd, chr_code);
- } else if (chr_code < mu_skip_base) {
- tprint_esc("skip");
- print_int(chr_code - skip_base);
- } else {
- tprint_esc("muskip");
- print_int(chr_code - mu_skip_base);
- }
- break;
- case assign_toks_cmd:
- if (chr_code >= toks_base) {
- tprint_esc("toks");
- print_int(chr_code - toks_base);
- } else {
- prim_cmd_chr(cmd, chr_code);
- }
- break;
- case assign_int_cmd:
- if (chr_code < count_base) {
- prim_cmd_chr(cmd, chr_code);
- } else {
- tprint_esc("count");
- print_int(chr_code - count_base);
- }
- break;
- case assign_attr_cmd:
- tprint_esc("attribute");
- print_int(chr_code - attribute_base);
- break;
- case assign_dimen_cmd:
- if (chr_code < scaled_base) {
- prim_cmd_chr(cmd, chr_code);
- } else {
- tprint_esc("dimen");
- print_int(chr_code - scaled_base);
- }
- break;
- case normal_cmd:
- if (chr_code < prim_data[cmd].subids && prim_data[cmd].names[chr_code] != 0) {
- prim_cmd_chr(cmd, chr_code);
- } else {
- tprint("[unknown command! (");
- print_int(chr_code);
- tprint(")]");
- }
- break;
- case extension_cmd:
- if (chr_code < prim_data[cmd].subids && prim_data[cmd].names[chr_code] != 0) {
- prim_cmd_chr(cmd, chr_code);
- } else {
- tprint("[unknown extension! (");
- print_int(chr_code);
- tprint(")]");
-
- }
- break;
- default:
- /* these are most commands, actually */
- prim_cmd_chr(cmd, chr_code);
- break;
- }
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/printing.w b/Build/source/texk/web2c/luatexdir/tex/printing.c
index 72444156480..0a961071b05 100644
--- a/Build/source/texk/web2c/luatexdir/tex/printing.w
+++ b/Build/source/texk/web2c/luatexdir/tex/printing.c
@@ -1,87 +1,137 @@
-% printing.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/>.
-
-@ @c
+/*
+
+printing.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/>.
+
+*/
+
#include "ptexlib.h"
-#include "lua/luatex-api.h" /* for luatex_banner */
+#include "lua/luatex-api.h"
-@ @c
#define wlog(A) fputc(A,log_file)
#define wterm(A) fputc(A,term_out)
int new_string_line = 0;
int escape_controls = 1;
-@ Messages that are sent to a user's terminal and to the transcript-log file
-are produced by several `|print|' procedures. These procedures will
-direct their output to a variety of places, based on the setting of
-the global variable |selector|, which has the following possible
-values:
+/*tex
+
+Messages that are sent to a user's terminal and to the transcript-log file are
+produced by several `|print|' procedures. These procedures will direct their
+output to a variety of places, based on the setting of the global variable
+|selector|, which has the following possible values:
+
+\startitemize
+
+\startitem
+ |term_and_log|, the normal setting, prints on the terminal and on the
+ transcript file.
+\stopitem
+
+\startitem
+ |log_only|, prints only on the transcript file.
+\stopitem
+
+\startitem
+ |term_only|, prints only on the terminal.
+\stopitem
+
+\startitem
+ |no_print|, doesn't print at all. This is used only in rare cases before the
+ transcript file is open.
+\stopitem
+
+\startitem
+ |pseudo|, puts output into a cyclic buffer that is used by the |show_context|
+ routine; when we get to that routine we shall discuss the reasoning behind
+ this curious mode.
+\stopitem
+
+\startitem
+ |new_string|, appends the output to the current string in the string pool.
+\stopitem
+
+\startitem
+ 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+\stopitem
-\yskip
-\hang |term_and_log|, the normal setting, prints on the terminal and on the
- transcript file.
+\stopitemize
-\hang |log_only|, prints only on the transcript file.
+The symbolic names `|term_and_log|', etc., have been assigned numeric codes that
+satisfy the convenient relations |no_print+1=term_only|, |no_print+2=log_only|,
+|term_only+2=log_only+1=term_and_log|.
-\hang |term_only|, prints only on the terminal.
+Three additional global variables, |tally| and |term_offset| and |file_offset|,
+record the number of characters that have been printed since they were most
+recently cleared to zero. We use |tally| to record the length of (possibly very
+long) stretches of printing; |term_offset| and |file_offset|, on the other hand,
+keep track of how many characters have appeared so far on the current line that
+has been output to the terminal or to the transcript file, respectively.
-\hang |no_print|, doesn't print at all. This is used only in rare cases
- before the transcript file is open.
+*/
+
+/*tex transcript of \TeX\ session */
+
+alpha_file log_file;
+
+/*tex where to print a message */
+
+int selector = term_only;
+
+/*tex digits in a number being output */
+
+int dig[23];
+
+/*tex the number of characters recently printed */
+
+int tally = 0;
+
+/*tex the number of characters on the current terminal line */
-\hang |pseudo|, puts output into a cyclic buffer that is used
- by the |show_context| routine; when we get to that routine we shall discuss
- the reasoning behind this curious mode.
+int term_offset = 0;
-\hang |new_string|, appends the output to the current string in the
- string pool.
+/*tex the number of characters on the current file line */
-\hang 0 to 15, prints on one of the sixteen files for \.{\\write} output.
+int file_offset = 0;
-\yskip
-\noindent The symbolic names `|term_and_log|', etc., have been assigned
-numeric codes that satisfy the convenient relations |no_print+1=term_only|,
-|no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|.
+/*tex circular buffer for pseudoprinting */
-Three additional global variables, |tally| and |term_offset| and
-|file_offset|, record the number of characters that have been printed
-since they were most recently cleared to zero. We use |tally| to record
-the length of (possibly very long) stretches of printing; |term_offset|
-and |file_offset|, on the other hand, keep track of how many characters
-have appeared so far on the current line that has been output to the
-terminal or to the transcript file, respectively.
+packed_ASCII_code trick_buf[(ssup_error_line + 1)];
-@c
-alpha_file log_file; /* transcript of \TeX\ session */
-int selector = term_only; /* where to print a message */
-int dig[23]; /* digits in a number being output */
-int tally = 0; /* the number of characters recently printed */
-int term_offset = 0; /* the number of characters on the current terminal line */
-int file_offset = 0; /* the number of characters on the current file line */
-packed_ASCII_code trick_buf[(ssup_error_line + 1)]; /* circular buffer for pseudoprinting */
-int trick_count; /* threshold for pseudoprinting, explained later */
-int first_count; /* another variable for pseudoprinting */
-boolean inhibit_par_tokens = false; /* for minor adjustments to |show_token_list| */
+/*tex threshold for pseudoprinting, explained later */
-@ To end a line of text output, we call |print_ln|
+int trick_count;
+
+/*tex another variable for pseudoprinting */
+
+int first_count;
+
+/*tex for minor adjustments to |show_token_list| */
+
+boolean inhibit_par_tokens = false;
+
+/*tex
+
+To end a line of text output, we call |print_ln|
+
+*/
-@c
void print_ln(void)
{
switch (selector) {
@@ -111,19 +161,21 @@ void print_ln(void)
fprintf(write_file[selector], "\n");
break;
}
- /* |tally| is not affected */
+ /*tex |tally| is not affected */
}
-@ The |print_char| procedure sends one byte to the desired destination.
-All printing comes through |print_ln| or |print_char|, except for the
-case of |tprint| (see below).
+/*tex
+
+The |print_char| procedure sends one byte to the desired destination. All
+printing comes through |print_ln| or |print_char|, except for the case of
+|tprint| (see below).
-The checking of the line length is an inheritance from previosu engines
-and we might drop it after release 1.0. We're not too picky about the exact
-match of that length because we have utf output so length is then a bit
-fuzzy anyway.
+The checking of the line length is an inheritance from previosu engines and we
+might drop it after release 1.0. We're not too picky about the exact match of
+that length because we have utf output so length is then a bit fuzzy anyway.
+
+*/
-@c
#define needs_escaping(A) \
((! escape_controls) || (A>=0x20) || (A==0x0A) || (A==0x0D) || (A==0x09))
@@ -144,17 +196,6 @@ fuzzy anyway.
term_offset += 2; \
}
-/*
-
-#define needs_wrapping(A,B) \
- (((A>=0xF0)&&(B+4>=max_print_line)) || \
- ((A>=0xE0)&&(B+3>=max_print_line)) || \
- ((A>=0xC0)&&(B+2>=max_print_line)))
-
-we have mostly ascii in logs, so ...
-
-*/
-
#define needs_wrapping(A,B) \
( (A>=0xC0) && \
(((A>=0xF0) && (B+4>=max_print_line)) || \
@@ -236,23 +277,25 @@ void print_char(int s)
incr(tally);
}
-@ An entire string is output by calling |print|. Note that if we are outputting
-the single standard ASCII character \.c, we could call |print("c")|, since
-|"c"=99| is the number of a single-character string, as explained above. But
-|print_char("c")| is quicker, so \TeX\ goes directly to the |print_char|
-routine when it knows that this is safe. (The present implementation
-assumes that it is always safe to print a visible ASCII character.)
+/*tex
+
+An entire string is output by calling |print|. Note that if we are outputting the
+single standard ASCII character \.c, we could call |print("c")|, since |"c"=99|
+is the number of a single-character string, as explained above. But
+|print_char("c")| is quicker, so \TeX\ goes directly to the |print_char| routine
+when it knows that this is safe. (The present implementation assumes that it is
+always safe to print a visible ASCII character.)
-@^system dependencies@>
+The first 256 entries above the 17th unicode plane are used for a special trick:
+when \TeX\ has to print items in that range, it will instead print the character
+that results from substracting 0x110000 from that value. This allows
+byte-oriented output to things like \.{\\specials} and \.{\\pdfextension
+literals}. Todo: Perhaps it would be useful to do the same substraction while
+typesetting.
-The first 256 entries above the 17th unicode plane are used for a
-special trick: when \TeX\ has to print items in that range, it will
-instead print the character that results from substracting 0x110000
-from that value. This allows byte-oriented output to things like
-\.{\\specials} and \.{\\pdfextension literals}. Todo: Perhaps it would be useful
-to do the same substraction while typesetting.
-@c
+*/
+
void print(int s)
{
if (s >= str_ptr) {
@@ -262,9 +305,9 @@ void print(int s)
if (s < 0) {
normal_warning("print","bad string offset");
} else {
- /* TH not sure about this, disabled for now! */
+ /*tex We're not sure about this so it's disabled for now! */
if ((false) && (selector > pseudo)) {
- /* internal strings are not expanded */
+ /*tex internal strings are not expanded */
print_char(s);
return;
}
@@ -307,12 +350,13 @@ void print(int s)
}
void lprint (lstring *ss) {
- unsigned char *j, *l; /* current character code position */
+ /*tex current character code position */
+ unsigned char *j, *l;
j = ss->s;
l = j + ss->l;
while (j < l) {
- /* 0x110000 in utf=8: 0xF4 0x90 0x80 0x80 */
- /* I don't bother checking the last two bytes explicitly */
+ /*tex I don't bother checking the last two bytes explicitly */
+ /* 0x110000 in utf=8: 0xF4 0x90 0x80 0x80 */
if ((j < l - 4) && (*j == 0xF4) && (*(j + 1) == 0x90)) {
int c = (*(j + 2) - 128) * 64 + (*(j + 3) - 128);
assert(c >= 0 && c < 256);
@@ -325,12 +369,17 @@ void lprint (lstring *ss) {
}
}
-@ The procedure |print_nl| is like |print|, but it makes sure that the
-string appears at the beginning of a new line.
+/*tex
+
+The procedure |print_nl| is like |print|, but it makes sure that the string
+appears at the beginning of a new line.
+
+*/
+
+/*tex Moev to the beginning of the next line. */
-@c
void print_nlp(void)
-{ /* move to beginning of a line */
+{
if (new_string_line > 0) {
print_char(new_string_line);
} else if (((term_offset > 0) && (odd(selector))) ||
@@ -339,17 +388,22 @@ void print_nlp(void)
}
}
+/*tex Prints string |s| at beginning of the next line. */
+
void print_nl(str_number s)
-{ /* prints string |s| at beginning of line */
+{
print_nlp();
print(s);
}
-@ |char *| versions of the same procedures. |tprint| is
-different because it uses buffering, which works well because
-most of the output actually comes through |tprint|.
+/*tex
+
+|char *| versions of the same procedures. |tprint| is different because it uses
+buffering, which works well because most of the output actually comes through
+|tprint|.
+
+*/
-@c
#define t_flush_buffer(target,offset) \
buffer[i++] = '\n'; \
buffer[i++] = '\0';\
@@ -361,7 +415,7 @@ most of the output actually comes through |tprint|.
void tprint(const char *sss)
{
char *buffer = NULL;
- int i = 0; /* buffer index */
+ int i = 0;
int newlinechar = new_line_char_par;
int dolog = 0;
int doterm = 0;
@@ -409,7 +463,7 @@ void tprint(const char *sss)
}
break;
}
- /* what is left is the 3 term/log settings */
+ /*tex What is left is the 3 term/log settings. */
if (dolog || doterm) {
buffer = xmalloc(strlen(sss)*3);
if (dolog) {
@@ -469,13 +523,16 @@ void tprint_nl(const char *s)
tprint(s);
}
-@ Here is the very first thing that \TeX\ prints: a headline that identifies
-the version number and format package. The |term_offset| variable is temporarily
-incorrect, but the discrepancy is not serious since we assume that the banner
-and format identifier together will occupy at most |max_print_line|
-character positions.
+/*tex
+
+Here is the very first thing that \TeX\ prints: a headline that identifies the
+version number and format package. The |term_offset| variable is temporarily
+incorrect, but the discrepancy is not serious since we assume that the banner and
+format identifier together will occupy at most |max_print_line| character
+positions.
+
+*/
-@c
void print_banner(const char *v)
{
int callback_id = callback_defined(start_run_callback);
@@ -484,15 +541,16 @@ void print_banner(const char *v)
if (format_ident > 0)
print(format_ident);
print_ln();
- if (show_luahashchars){
+ if (show_luahashchars) {
wterm(' ');
fprintf(term_out,"Number of bits used by the hash function (" my_name "): %d",LUAI_HASHLIMIT);
- print_ln();
+ print_ln();
}
if (shellenabledp) {
wterm(' ');
- if (restrictedshell)
+ if (restrictedshell) {
fprintf(term_out, "restricted ");
+ }
fprintf(term_out, "system commands enabled.\n");
}
} else if (callback_id > 0) {
@@ -500,7 +558,6 @@ void print_banner(const char *v)
}
}
-@ @c
void log_banner(const char *v)
{
const char *months[] = { " ",
@@ -536,41 +593,51 @@ void log_banner(const char *v)
}
}
-@ @c
void print_version_banner(void)
{
fprintf(term_out, "%s", luatex_banner);
}
-@ The procedure |print_esc| prints a string that is preceded by
-the user's escape character (which is usually a backslash).
+/*tex
+
+The procedure |print_esc| prints a string that is preceded by the user's escape
+character (which is usually a backslash).
+
+*/
-@c
void print_esc(str_number s)
{
- int c = escape_char_par; /* Set variable |c| to the current escape character */
- if (c >= 0 && c < STRING_OFFSET)
+ /*tex Set variable |c| to the current escape character: */
+ int c = escape_char_par;
+ if (c >= 0 && c < 0x110000)
print(c);
print(s);
}
-@ This prints escape character, then |s|.
+/*tex
+
+This prints escape character, then |s|.
+
+*/
-@c
void tprint_esc(const char *s)
{
- int c = escape_char_par; /* Set variable |c| to the current escape character */
- if (c >= 0 && c < STRING_OFFSET)
+ /*tex Set variable |c| to the current escape character: */
+ int c = escape_char_par;
+ if (c >= 0 && c < 0x110000)
print(c);
tprint(s);
}
-@ An array of digits in the range |0..15| is printed by |print_the_digs|.
+/*tex
+
+An array of digits in the range |0..15| is printed by |print_the_digs|.
+
+*/
-@c
void print_the_digs(eight_bits k)
{
- /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
+ /*tex prints |dig[k-1]|$\,\ldots\,$|dig[0]| */
while (k-- > 0) {
if (dig[k] < 10)
print_char('0' + dig[k]);
@@ -579,17 +646,22 @@ void print_the_digs(eight_bits k)
}
}
-@ The following procedure, which prints out the decimal representation of a
-given integer |n|, has been written carefully so that it works properly
-if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div|
-to negative arguments, since such operations are not implemented consistently
-by all PASCAL compilers.
+/*tex
+
+The following procedure, which prints out the decimal representation of a given
+integer |n|, has been written carefully so that it works properly if |n=0| or if
+|(-n)| would cause overflow. It does not apply |mod| or |div| to negative
+arguments, since such operations are not implemented consistently by all PASCAL
+compilers.
+
+*/
-@c
void print_int(longinteger n)
{
- int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */
- longinteger m; /* used to negate |n| in possibly dangerous cases */
+ /*tex index to current digit; we assume that $|n|<10^{23}$ */
+ int k = 0;
+ /*tex used to negate |n| in possibly dangerous cases */
+ longinteger m;
if (n < 0) {
print_char('-');
if (n > -100000000) {
@@ -615,11 +687,13 @@ void print_int(longinteger n)
print_the_digs((eight_bits) k);
}
+/*tex
-@ Here is a trivial procedure to print two digits; it is usually called with
-a parameter in the range |0<=n<=99|.
+Here is a trivial procedure to print two digits; it is usually called with a
+parameter in the range |0<=n<=99|.
+
+*/
-@c
void print_two(int n)
{
n = abs(n) % 100;
@@ -627,12 +701,16 @@ void print_two(int n)
print_char('0' + (n % 10));
}
-@ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
+/*tex
-@c
-void print_hex(int n)
+Hexadecimal printing of nonnegative integers is accomplished by |print_hex|.
+
+*/
+
+void print_qhex(int n)
{
- int k = 0 ; /* index to current digit; we assume that $0\L n<16^{22}$ */
+ /*tex index to current digit; we assume that $0\L n<16^{22}$ */
+ int k = 0 ;
print_char('"');
do {
dig[k] = n % 16;
@@ -642,16 +720,18 @@ void print_hex(int n)
print_the_digs((eight_bits) k);
}
-@ Roman numerals are produced by the |print_roman_int| routine. Readers
-who like puzzles might enjoy trying to figure out how this tricky code
-works; therefore no explanation will be given. Notice that 1990 yields
-\.{mcmxc}, not \.{mxm}.
+/*tex
+
+Roman numerals are produced by the |print_roman_int| routine. Readers who like
+puzzles might enjoy trying to figure out how this tricky code works; therefore no
+explanation will be given. Notice that 1990 yields \.{mcmxc}, not \.{mxm}.
+
+*/
-@c
void print_roman_int(int n)
{
- char *j, *k; /* mysterious indices */
- int u, v; /* mysterious numbers */
+ char *j, *k;
+ int u, v;
char mystery[] = "m2d5c2l5x2v5i";
j = (char *) mystery;
v = 1000;
@@ -661,7 +741,7 @@ void print_roman_int(int n)
n = n - v;
}
if (n <= 0) {
- /* nonpositive input produces no output */
+ /*tex nonpositive input produces no output */
return;
}
k = j + 2;
@@ -680,25 +760,31 @@ void print_roman_int(int n)
}
}
-@ The |print| subroutine will not print a string that is still being
-created. The following procedure will.
+/*tex
+
+The |print| subroutine will not print a string that is still being created. The
+following procedure will.
+
+*/
-@c
void print_current_string(void)
{
- unsigned j = 0; /* points to current character code */
+ /*tex points to current character code */
+ unsigned j = 0;
while (j < cur_length)
print_char(cur_string[j++]);
}
-@ The procedure |print_cs| prints the name of a control sequence, given
-a pointer to its address in |eqtb|. A space is printed after the name
-unless it is a single nonletter or an active character. This procedure
-might be invoked with invalid data, so it is ``extra robust.'' The
-individual characters must be printed one at a time using |print|, since
-they may be unprintable.
+/*tex
+
+The procedure |print_cs| prints the name of a control sequence, given a pointer
+to its address in |eqtb|. A space is printed after the name unless it is a single
+nonletter or an active character. This procedure might be invoked with invalid
+data, so it is ``extra robust.'' The individual characters must be printed one at
+a time using |print|, since they may be unprintable.
+
+*/
-@c
void print_cs(int p)
{
str_number t = cs_text(p);
@@ -731,10 +817,12 @@ void print_cs(int p)
}
}
-@ Here is a similar procedure; it avoids the error checks, and it never
-prints a space after the control sequence.
+/*tex
-@c
+Here is a similar procedure; it avoids the error checks, and it never prints a
+space after the control sequence.
+
+*/
void sprint_cs(pointer p)
{
str_number t;
@@ -762,9 +850,12 @@ void sprint_cs_name(pointer p)
}
}
-@ This procedure is never called when |interaction<scroll_mode|.
+/*tex
+
+This procedure is never called when |interaction<scroll_mode|.
+
+*/
-@c
void prompt_input(const char *s)
{
wake_up_terminal();
@@ -772,10 +863,13 @@ void prompt_input(const char *s)
term_input();
}
-@ Then there is a subroutine that prints glue stretch and shrink, possibly
-followed by the name of finite units:
+/*tex
+
+Then there is a subroutine that prints glue stretch and shrink, possibly followed
+by the name of finite units:
+
+*/
-@c
void print_glue(scaled d, int order, const char *s)
{
print_scaled(d);
@@ -792,9 +886,12 @@ void print_glue(scaled d, int order, const char *s)
}
}
-@ The next subroutine prints a whole glue specification
+/*tex
+
+The next subroutine prints a whole glue specification
+
+*/
-@c
void print_spec(int p, const char *s)
{
if (p < 0) {
@@ -814,42 +911,47 @@ void print_spec(int p, const char *s)
}
}
-@ We can reinforce our knowledge of the data structures just introduced
-by considering two procedures that display a list in symbolic form.
-The first of these, called |short_display|, is used in ``overfull box''
-messages to give the top-level description of a list. The other one,
-called |show_node_list|, prints a detailed description of exactly what
-is in the data structure.
+/*tex
-The philosophy of |short_display| is to ignore the fine points about exactly
-what is inside boxes, except that ligatures and discretionary breaks are
-expanded. As a result, |short_display| is a recursive procedure, but the
-recursion is never more than one level deep.
-@^recursion@>
+We can reinforce our knowledge of the data structures just introduced by
+considering two procedures that display a list in symbolic form. The first of
+these, called |short_display|, is used in ``overfull box'' messages to give the
+top-level description of a list. The other one, called |show_node_list|, prints a
+detailed description of exactly what is in the data structure.
-A global variable |font_in_short_display| keeps track of the font code that
-is assumed to be present when |short_display| begins; deviations from this
-font will be printed.
+The philosophy of |short_display| is to ignore the fine points about exactly what
+is inside boxes, except that ligatures and discretionary breaks are expanded. As
+a result, |short_display| is a recursive procedure, but the recursion is never
+more than one level deep. @^recursion@>
-@c
-int font_in_short_display; /* an internal font number */
+A global variable |font_in_short_display| keeps track of the font code that is
+assumed to be present when |short_display| begins; deviations from this font will
+be printed.
-@ Boxes, rules, inserts, whatsits, marks, and things in general that are
-sort of ``complicated'' are indicated only by printing `\.{[]}'.
+*/
-@c
+/*tex An internal font number: */
-/*
-So, 0, 1 as well as any large value will behave the same as before. The reason
-for this extension is that a \name not always makes sense.
+int font_in_short_display;
+
+/*tex
+
+Boxes, rules, inserts, whatsits, marks, and things in general that are sort of
+``complicated'' are indicated only by printing `\.{[]}'.
+We print a bit more than original \TEX. A value of 0 or 1 or any large value will
+behave the same as before. The reason for this extension is that a |name| not
+always makes sense.
+
+\starttyping
0 \foo xyz
1 \foo (bar)
2 <bar> xyz
-3 <bar @@ ..> xyz
+3 <bar @ ..> xyz
4 <id>
5 <id: bar>
-6 <id: bar @@ ..> xyz
+6 <id: bar @ ..> xyz
+\stoptyping
*/
@@ -858,12 +960,12 @@ void print_font_identifier(internal_font_number f)
str_number fonttext;
fonttext = font_id_text(f);
if (tracing_fonts_par >= 2 && tracing_fonts_par <= 6) {
- /* < > is less likely to clash with text parenthesis */
+ /*tex < > is less likely to clash with text parenthesis */
tprint("<");
if (tracing_fonts_par >= 2 && tracing_fonts_par <= 3) {
print_font_name(f);
if (tracing_fonts_par >= 3 || font_size(f) != font_dsize(f)) {
- tprint(" @@ ");
+ tprint(" @ ");
print_scaled(font_size(f));
tprint("pt");
}
@@ -873,7 +975,7 @@ void print_font_identifier(internal_font_number f)
tprint(": ");
print_font_name(f);
if (tracing_fonts_par >= 6 || font_size(f) != font_dsize(f)) {
- tprint(" @@ ");
+ tprint(" @ ");
print_scaled(font_size(f));
tprint("pt");
}
@@ -881,7 +983,7 @@ void print_font_identifier(internal_font_number f)
}
print_char('>');
} else {
- /* old method, inherited from pdftex */
+ /*tex old method, inherited from pdftex */
if (fonttext > 0) {
print_esc(fonttext);
} else {
@@ -892,7 +994,7 @@ void print_font_identifier(internal_font_number f)
tprint(" (");
print_font_name(f);
if (font_size(f) != font_dsize(f)) {
- tprint("@@");
+ tprint("@");
print_scaled(font_size(f));
tprint("pt");
}
@@ -901,9 +1003,12 @@ void print_font_identifier(internal_font_number f)
}
}
-@ This prints highlights of list |p|.
+/*tex
+
+This prints highlights of list |p|.
+
+*/
-@c
void short_display(int p)
{
while (p != null) {
@@ -922,20 +1027,27 @@ void short_display(int p)
print(character(p));
}
} else {
- /* Print a short indication of the contents of node |p| */
+ /*tex Print a short indication of the contents of node |p| */
print_short_node_contents(p);
}
p = vlink(p);
}
}
-@ The |show_node_list| routine requires some auxiliary subroutines: one to
-print a font-and-character combination, one to print a token list without
-its reference count, and one to print a rule dimension.
+/*tex
-@ This prints |char_node| data.
+The |show_node_list| routine requires some auxiliary subroutines: one to print a
+font-and-character combination, one to print a token list without its reference
+count, and one to print a rule dimension.
+
+*/
+
+/*tex
+
+This prints |char_node| data.
+
+*/
-@c
void print_font_and_char(int p)
{
if (!is_valid_font(font(p)))
@@ -946,9 +1058,12 @@ void print_font_and_char(int p)
print(character(p));
}
-@ This prints token list data in braces
+/*tex
+
+This prints token list data in braces
+
+*/
-@c
void print_mark(int p)
{
print_char('{');
@@ -959,9 +1074,12 @@ void print_mark(int p)
print_char('}');
}
-@ This prints dimensions of a rule node.
+/*tex
+
+This prints dimensions of a rule node.
+
+*/
-@c
void print_rule_dimen(scaled d)
{
if (is_running(d))
@@ -970,41 +1088,54 @@ void print_rule_dimen(scaled d)
print_scaled(d);
}
-@ Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
-@^recursion@>
-up to a given maximum number of levels. The history of nesting is indicated
-by the current string, which will be printed at the beginning of each line;
-the length of this string, namely |cur_length|, is the depth of nesting.
+/*tex
-A global variable called |depth_threshold| is used to record the maximum
-depth of nesting for which |show_node_list| will show information. If we
-have |depth_threshold=0|, for example, only the top level information will
-be given and no sublists will be traversed. Another global variable, called
-|breadth_max|, tells the maximum number of items to show at each level;
-|breadth_max| had better be positive, or you won't see anything.
+Since boxes can be inside of boxes, |show_node_list| is inherently recursive,
+@^recursion@> up to a given maximum number of levels. The history of nesting is
+indicated by the current string, which will be printed at the beginning of each
+line; the length of this string, namely |cur_length|, is the depth of nesting.
-@c
-int depth_threshold; /* maximum nesting depth in box displays */
-int breadth_max; /* maximum number of items shown at the same list level */
+A global variable called |depth_threshold| is used to record the maximum depth of
+nesting for which |show_node_list| will show information. If we have
+|depth_threshold=0|, for example, only the top level information will be given
+and no sublists will be traversed. Another global variable, called |breadth_max|,
+tells the maximum number of items to show at each level; |breadth_max| had better
+be positive, or you won't see anything.
-@ The recursive machinery is started by calling |show_box|. Assign the values
+*/
+
+/*tex The maximum nesting depth in box displays: */
+
+int depth_threshold;
+
+/*tex The maximum number of items shown at the same list level: */
+
+int breadth_max;
+
+/*tex
+
+The recursive machinery is started by calling |show_box|. Assign the values
|depth_threshold:=show_box_depth| and |breadth_max:=show_box_breadth|
-@c
+*/
+
void show_box(halfword p)
{
depth_threshold = show_box_depth_par;
breadth_max = show_box_breadth_par;
if (breadth_max <= 0)
breadth_max = 5;
- /* the show starts at |p| */
+ /*tex the show starts at |p| */
show_node_list(p);
print_ln();
}
-@ Helper for debugging purposes. It prints highlights of list |p|
+/*tex
+
+Helper for debugging purposes. It prints highlights of list |p|
+
+*/
-@c
void short_display_n(int p, int m)
{
int i = 0;
@@ -1041,7 +1172,7 @@ void short_display_n(int p, int m)
short_display(vlink(post_break(p)));
print_char('|');
} else {
- /* Print a short indication of the contents of node |p| */
+ /*tex Print a short indication of the contents of node |p| */
print_short_node_contents(p);
}
}
@@ -1052,13 +1183,16 @@ void short_display_n(int p, int m)
update_terminal();
}
-@ When debugging a macro package, it can be useful to see the exact
-control sequence names in the format file. For example, if ten new
-csnames appear, it's nice to know what they are, to help pinpoint where
-they came from. (This isn't a truly ``basic'' printing procedure, but
-that's a convenient module in which to put it.)
+/*tex
+
+When debugging a macro package, it can be useful to see the exact control
+sequence names in the format file. For example, if ten new csnames appear, it's
+nice to know what they are, to help pinpoint where they came from. (This isn't a
+truly ``basic'' printing procedure, but that's a convenient module in which to
+put it.)
+
+*/
-@c
void print_csnames(int hstart, int hfinish)
{
int h;
@@ -1066,11 +1200,11 @@ void print_csnames(int hstart, int hfinish)
fprintf(stderr, "fmtdebug:csnames from %d to %d:", (int) hstart, (int) hfinish);
for (h = hstart; h <= hfinish; h++) {
if (cs_text(h) > 0) {
- /* we have anything at this position */
+ /*tex We have anything at this position. */
c = str_string(cs_text(h));
l = c + str_length(cs_text(h));
while (c < l) {
- /* print the characters */
+ /*tex Print the characters. */
fputc(*c++, stderr);
}
fprintf(stderr, "|");
@@ -1078,11 +1212,14 @@ void print_csnames(int hstart, int hfinish)
}
}
-@ A helper for printing file:line:error style messages. Look for a
-filename in |full_source_filename_stack|, and if we fail to find
-one fall back on the non-file:line:error style.
+/*tex
+
+A helper for printing file:line:error style messages. Look for a filename in
+|full_source_filename_stack|, and if we fail to find one fall back on the
+non-file:line:error style.
+
+*/
-@c
void print_file_line(void)
{
int level = in_open;
@@ -1102,11 +1239,14 @@ void print_file_line(void)
}
}
-@ \TeX\ is occasionally supposed to print diagnostic information that
-goes only into the transcript file, unless |tracing_online| is positive.
-Here are two routines that adjust the destination of print commands:
+/*tex
+
+\TeX\ is occasionally supposed to print diagnostic information that goes only
+into the transcript file, unless |tracing_online| is positive. Here are two
+routines that adjust the destination of print commands:
+
+*/
-@c
void begin_diagnostic(void)
{
global_old_setting = selector;
@@ -1117,9 +1257,12 @@ void begin_diagnostic(void)
}
}
-@ Restore proper conditions after tracing.
+/*tex
+
+Restore proper conditions after tracing.
+
+*/
-@c
void end_diagnostic(boolean blank_line)
{
tprint_nl("");
@@ -1128,8 +1271,11 @@ void end_diagnostic(boolean blank_line)
selector = global_old_setting;
}
-@ Of course we had better declare another global variable, if the previous
-routines are going to work.
+/*tex
+
+Of course we had better declare another global variable, if the previous routines
+are going to work.
+
+*/
-@c
int global_old_setting;
diff --git a/Build/source/texk/web2c/luatexdir/tex/scanning.c b/Build/source/texk/web2c/luatexdir/tex/scanning.c
new file mode 100644
index 00000000000..8f7e1d59178
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/scanning.c
@@ -0,0 +1,2743 @@
+/*
+
+Copyright 2009-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"
+
+static void scan_expr(void);
+
+/*tex
+
+ Let's turn now to some procedures that \TeX\ calls upon frequently to digest
+ certain kinds of patterns in the input. Most of these are quite simple; some
+ are quite elaborate. Almost all of the routines call |get_x_token|, which can
+ cause them to be invoked recursively.
+
+ The |scan_left_brace| routine is called when a left brace is supposed to be
+ the next non-blank token. (The term ``left brace'' means, more precisely, a
+ character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to appear
+ before the |left_brace|.
+
+*/
+
+/* This reads a mandatory |left_brace|: */
+
+void scan_left_brace(void)
+{
+ /*tex Get the next non-blank non-relax non-call token */
+ do {
+ get_x_token();
+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
+ if (cur_cmd != left_brace_cmd) {
+ print_err("Missing { inserted");
+ help4(
+ "A left brace was mandatory here, so I've put one in.",
+ "You might want to delete and/or insert some corrections",
+ "so that I will find a matching right brace soon.",
+ "If you're confused by all this, try typing `I}' now."
+ );
+ back_error();
+ cur_tok = left_brace_token + '{';
+ cur_cmd = left_brace_cmd;
+ cur_chr = '{';
+ incr(align_state);
+ }
+}
+
+/*tex
+
+ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
+ by optional spaces; `\.{\\relax}' is not ignored here.
+
+*/
+
+void scan_optional_equals(void)
+{
+ /*tex Get the next non-blank non-call token */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_tok != other_token + '=')
+ back_input();
+}
+
+/*tex
+
+ Here is a procedure that sounds an alarm when mu and non-mu units are being
+ switched.
+
+*/
+
+static void mu_error(void)
+{
+ print_err("Incompatible glue units");
+ help1("I'm going to assume that 1mu=1pt when they're mixed.");
+ error();
+}
+
+/*tex
+
+ The next routine `|scan_something_internal|' is used to fetch internal
+ numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
+ when expanding constructions like `\.{\\the\\toks0}' and
+ `\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
+ procedure, which calls |scan_something_internal|; on the other hand,
+ |scan_something_internal| also calls |scan_int|, for constructions like
+ `\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we have to
+ declare |scan_int| as a |forward| procedure. A few other procedures are also
+ declared at this point.
+
+ \TeX\ doesn't know exactly what to expect when |scan_something_internal|
+ begins. For example, an integer or dimension or glue value could occur
+ immediately after `\.{\\hskip}'; and one can even say \.{\\the} with respect
+ to token lists in constructions like `\.{\\xdef\\o\{\\the\\output\}}'. On the
+ other hand, only integers are allowed after a construction like
+ `\.{\\count}'. To handle the various possibilities, |scan_something_internal|
+ has a |level| parameter, which tells the ``highest'' kind of quantity that
+ |scan_something_internal| is allowed to produce. Eight levels are
+ distinguished, namely |int_val|, |attr_val|, |dimen_val|, |glue_val|,
+ |mu_val|, |dir_val|, |ident_val|, and |tok_val|.
+
+ The output of |scan_something_internal| (and of the other routines
+ |scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
+ variable |cur_val|, and its level is put into |cur_val_level|. The highest
+ values of |cur_val_level| are special: |mu_val| is used only when |cur_val|
+ points to something in a ``muskip'' register, or to one of the three
+ parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip}; |ident_val|
+ is used only when |cur_val| points to a font identifier; |tok_val| is used
+ only when |cur_val| points to |null| or to the reference count of a token
+ list. The last two cases are allowed only when |scan_something_internal| is
+ called with |level=tok_val|.
+
+ If the output is glue, |cur_val| will point to a glue specification, and the
+ reference count of that glue will have been updated to reflect this
+ reference; if the output is a nonempty token list, |cur_val| will point to
+ its reference count, but in this case the count will not have been updated.
+ Otherwise |cur_val| will contain the integer or scaled value in question.
+
+*/
+
+/*tex The value returned by numeric scanners: */
+
+int cur_val;
+
+/*tex Delcodes are sometimes 51 digits: */
+
+int cur_val1;
+
+/*tex The level of this value: */
+
+int cur_val_level;
+
+#define scanned_result(A,B) do { \
+ cur_val=A; \
+ cur_val_level=B; \
+} while (0)
+
+/*tex
+
+ When a |glue_val| changes to a |dimen_val|, we use the width component of the
+ glue; there is no need to decrease the reference count, since it has not yet
+ been increased. When a |dimen_val| changes to an |int_val|, we use scaled
+ points so that the value doesn't actually change. And when a |mu_val| changes
+ to a |glue_val|, the value doesn't change either.
+
+*/
+
+static void downgrade_cur_val(boolean delete_glue)
+{
+ if (cur_val_level == glue_val_level) {
+ halfword m = cur_val;
+ cur_val = width(m);
+ if (delete_glue)
+ flush_node(m);
+ } else if (cur_val_level == mu_val_level) {
+ mu_error();
+ }
+ decr(cur_val_level);
+}
+
+void negate_cur_val(boolean modify_glue)
+{
+ if (cur_val_level >= glue_val_level) {
+ if (modify_glue) {
+ /*tex We modify in-place. */
+ } else {
+ cur_val = new_spec(cur_val);
+ }
+ negate(width(cur_val));
+ negate(stretch(cur_val));
+ negate(shrink(cur_val));
+ } else {
+ negate(cur_val);
+ }
+}
+
+/*tex
+
+ Some of the internal items can be fetched both routines, and these have been
+ split off into the next routine, that returns true if the command code was
+ understood.
+
+*/
+
+static boolean short_scan_something_internal(int cmd, int chr, int level, boolean negative)
+{
+ /*tex |chr_code| part of the operand token */
+ halfword m;
+ /*tex general purpose index */
+ halfword q;
+ /*tex index into |nest| */
+ int p;
+ int save_cur_chr;
+ boolean succeeded = true;
+ m = chr;
+ switch (cmd) {
+ case assign_toks_cmd:
+ scanned_result(equiv(m), tok_val_level);
+ break;
+ case assign_int_cmd:
+ scanned_result(eqtb[m].cint, int_val_level);
+ break;
+ case assign_attr_cmd:
+ scanned_result(eqtb[m].cint, int_val_level);
+ break;
+ case assign_dimen_cmd:
+ scanned_result(eqtb[m].cint, dimen_val_level);
+ break;
+ case assign_glue_cmd:
+ scanned_result(equiv(m), glue_val_level);
+ break;
+ case assign_mu_glue_cmd:
+ scanned_result(equiv(m), mu_val_level);
+ break;
+ case assign_direction_cmd:
+ if (m == (int_base + line_direction_code)) {
+ m = int_base + text_direction_code;
+ }
+ scanned_result(eqtb[m].cint, int_val_level);
+ break;
+ case assign_dir_cmd:
+ if (m == (int_base + line_direction_code)) {
+ m = int_base + text_direction_code;
+ }
+ scanned_result(eqtb[m].cint, dir_val_level);
+ break;
+ case math_style_cmd:
+ scanned_result(m, int_val_level);
+ break;
+ case set_aux_cmd:
+ /*tex Fetch the |space_factor| or the |prev_depth|. */
+ if (abs(cur_list.mode_field) != m) {
+ print_err("Improper ");
+ print_cmd_chr(set_aux_cmd, m);
+ help4(
+ "You can refer to \\spacefactor only in horizontal mode;",
+ "you can refer to \\prevdepth only in vertical mode; and",
+ "neither of these is meaningful inside \\write. So",
+ "I'm forgetting what you said and using zero instead."
+ );
+ error();
+ if (level != tok_val_level)
+ scanned_result(0, dimen_val_level);
+ else
+ scanned_result(0, int_val_level);
+ } else if (m == vmode) {
+ scanned_result(prev_depth_par, dimen_val_level);
+ } else {
+ scanned_result(space_factor_par, int_val_level);
+ }
+ break;
+ case set_prev_graf_cmd:
+ /*tex Fetch the |prev_graf| */
+ if (cur_list.mode_field == 0) {
+ /*tex |prev_graf=0| within \.{\\write} */
+ scanned_result(0, int_val_level);
+ } else {
+ p = nest_ptr;
+ while (abs(nest[p].mode_field) != vmode)
+ decr(p);
+ scanned_result(nest[p].pg_field, int_val_level);
+ }
+ break;
+ case set_page_int_cmd:
+ /*tex Fetch the |dead_cycles| or the |insert_penalties| */
+ if (m == 0)
+ cur_val = dead_cycles;
+ else if (m == 2)
+ cur_val = interaction;
+ else
+ cur_val = insert_penalties;
+ cur_val_level = int_val_level;
+ break;
+ case set_page_dimen_cmd:
+ /*tex Fetch something on the |page_so_far|. */
+ if ((page_contents == empty) && (!output_active)) {
+ if (m == 0)
+ cur_val = max_dimen;
+ else
+ cur_val = 0;
+ } else {
+ cur_val = page_so_far[m];
+ }
+ cur_val_level = dimen_val_level;
+ break;
+ case set_tex_shape_cmd:
+ /*tex Fetch the |par_shape| size. */
+ if (par_shape_par_ptr == null)
+ cur_val = 0;
+ else
+ cur_val = vinfo(par_shape_par_ptr + 1);
+ cur_val_level = int_val_level;
+ break;
+ case set_etex_shape_cmd:
+ /*tex Fetch a penalties array element. */
+ scan_int();
+ if ((equiv(m) == null) || (cur_val < 0)) {
+ cur_val = 0;
+ } else {
+ if (cur_val > penalty(equiv(m)))
+ cur_val = penalty(equiv(m));
+ cur_val = penalty(equiv(m) + cur_val);
+ }
+ cur_val_level = int_val_level;
+ break;
+ case char_given_cmd:
+ case math_given_cmd:
+ case xmath_given_cmd:
+ scanned_result(cur_chr, int_val_level);
+ break;
+ case last_item_cmd:
+ /*tex
+
+ Because the items in this case directly refer to |cur_chr|, it
+ needs to be saved and restored.
+
+ */
+ save_cur_chr = cur_chr;
+ cur_chr = chr;
+ /*tex
+
+ Fetch an item in the current node, if appropriate. Here is where
+ \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\ } are implemented.
+ The reference count for \.{\\lastskip} will be updated later.
+
+ We also handle \.{\\inputlineno} and \.{\\badness} here, because
+ they are legal in similar contexts.
+
+ */
+ if (m >= input_line_no_code) {
+ if (m >= eTeX_glue) {
+ /*tex Process an expression and |return|. */
+ if (m < eTeX_mu) {
+ if (m == mu_to_glue_code) {
+ scan_mu_glue();
+ };
+ cur_val_level = glue_val_level;
+ } else if (m < eTeX_expr) {
+ if (m == glue_to_mu_code) {
+ scan_normal_glue();
+ }
+ cur_val_level = mu_val_level;
+ } else {
+ cur_val_level = m - eTeX_expr + int_val_level;
+ scan_expr();
+ }
+ /*tex
+
+ This code for reducing |cur_val_level| and\slash or
+ negating the result is similar to the one for all the
+ other cases of |scan_something_internal|; we free a
+ glue_spec when needed.
+
+ */
+ while (cur_val_level > level) {
+ downgrade_cur_val(true);
+ }
+ if (negative) {
+ /*tex
+
+ We get a new glue spec node with negated values and
+ the old intermediate is deleted.
+
+ */
+ negate_cur_val(true);
+ }
+ return succeeded;
+ } else if (m >= eTeX_dim) {
+ switch (m) {
+ case font_char_wd_code:
+ case font_char_ht_code:
+ case font_char_dp_code:
+ case font_char_ic_code:
+ scan_font_ident();
+ q = cur_val;
+ scan_char_num();
+ if (char_exists(q, cur_val)) {
+ switch (m) {
+ case font_char_wd_code:
+ cur_val = char_width(q, cur_val);
+ break;
+ case font_char_ht_code:
+ cur_val = char_height(q, cur_val);
+ break;
+ case font_char_dp_code:
+ cur_val = char_depth(q, cur_val);
+ break;
+ case font_char_ic_code:
+ cur_val = char_italic(q, cur_val);
+ break;
+ }
+ } else {
+ cur_val = 0;
+ }
+ break;
+ case par_shape_length_code:
+ case par_shape_indent_code:
+ case par_shape_dimen_code:
+ q = cur_chr - par_shape_length_code;
+ scan_int();
+ if ((par_shape_par_ptr == null) || (cur_val <= 0)) {
+ cur_val = 0;
+ } else {
+ if (q == 2) {
+ q = cur_val % 2;
+ cur_val = (cur_val + q) / 2;
+ }
+ if (cur_val > vinfo(par_shape_par_ptr + 1))
+ cur_val = vinfo(par_shape_par_ptr + 1);
+ cur_val =
+ varmem[par_shape_par_ptr + 2 * cur_val - q + 1].cint;
+ }
+ cur_val_level = dimen_val_level;
+ break;
+ case glue_stretch_code:
+ case glue_shrink_code:
+ scan_normal_glue();
+ q = cur_val;
+ if (m == glue_stretch_code)
+ cur_val = stretch(q);
+ else
+ cur_val = shrink(q);
+ flush_node(q);
+ break;
+ }
+ cur_val_level = dimen_val_level;
+ } else {
+ switch (m) {
+ case input_line_no_code:
+ cur_val = line;
+ break;
+ case badness_code:
+ cur_val = last_badness;
+ break;
+ case luatex_version_code:
+ cur_val = get_luatexversion();
+ break;
+ case last_saved_box_resource_index_code:
+ cur_val = last_saved_box_index;
+ break;
+ case last_saved_image_resource_index_code:
+ cur_val = last_saved_image_index;
+ break;
+ case last_saved_image_resource_pages_code:
+ cur_val = last_saved_image_pages;
+ break;
+ case last_x_pos_code:
+ cur_val = last_position.h;
+ break;
+ case last_y_pos_code:
+ cur_val = last_position.v;
+ break;
+ case random_seed_code:
+ cur_val = random_seed;
+ break;
+ case eTeX_version_code:
+ cur_val = eTeX_version;
+ break;
+ case eTeX_minor_version_code:
+ cur_val = eTeX_minor_version;
+ break;
+ case current_group_level_code:
+ cur_val = cur_level - level_one;
+ break;
+ case current_group_type_code:
+ cur_val = cur_group;
+ break;
+ case current_if_level_code:
+ q = cond_ptr;
+ cur_val = 0;
+ while (q != null) {
+ incr(cur_val);
+ q = vlink(q);
+ }
+ break;
+ case current_if_type_code:
+ if (cond_ptr == null)
+ cur_val = 0;
+ else if (cur_if < unless_code)
+ cur_val = cur_if + 1;
+ else
+ cur_val = -(cur_if - unless_code + 1);
+ break;
+ case current_if_branch_code:
+ if ((if_limit == or_code) || (if_limit == else_code))
+ cur_val = 1;
+ else if (if_limit == fi_code)
+ cur_val = -1;
+ else
+ cur_val = 0;
+ break;
+ case glue_stretch_order_code:
+ case glue_shrink_order_code:
+ scan_normal_glue();
+ q = cur_val;
+ if (m == glue_stretch_order_code)
+ cur_val = stretch_order(q);
+ else
+ cur_val = shrink_order(q);
+ flush_node(q);
+ break;
+ }
+ cur_val_level = int_val_level;
+ }
+ } else {
+ if (cur_chr == glue_val_level)
+ cur_val = zero_glue;
+ else
+ cur_val = 0;
+ if (cur_chr == last_node_type_code) {
+ cur_val_level = int_val_level;
+ if ((cur_list.tail_field == cur_list.head_field)
+ || (cur_list.mode_field == 0))
+ cur_val = -1;
+ } else {
+ /*tex assumes identical values */
+ cur_val_level = cur_chr;
+ }
+ if ((cur_list.tail_field != contrib_head) &&
+ !is_char_node(cur_list.tail_field) &&
+ (cur_list.mode_field != 0)) {
+ switch (cur_chr) {
+ case lastpenalty_code:
+ if (type(cur_list.tail_field) == penalty_node)
+ cur_val = penalty(cur_list.tail_field);
+ break;
+ case lastkern_code:
+ if (type(cur_list.tail_field) == kern_node)
+ cur_val = width(cur_list.tail_field);
+ break;
+ case lastskip_code:
+ if (type(cur_list.tail_field) == glue_node)
+ cur_val = cur_list.tail_field;
+ if (subtype(cur_list.tail_field) == mu_glue)
+ cur_val_level = mu_val_level;
+ break;
+ case last_node_type_code:
+ cur_val = visible_last_node_type(cur_list.tail_field);
+ break;
+ }
+ } else if ((cur_list.mode_field == vmode) && (cur_list.tail_field == cur_list.head_field)) {
+ switch (cur_chr) {
+ case lastpenalty_code:
+ cur_val = last_penalty;
+ break;
+ case lastkern_code:
+ cur_val = last_kern;
+ break;
+ case lastskip_code:
+ if (last_glue != max_halfword)
+ cur_val = last_glue;
+ break;
+ case last_node_type_code:
+ cur_val = last_node_type;
+ break;
+ }
+ }
+ }
+ cur_chr = save_cur_chr;
+ break;
+ default:
+ succeeded = false;
+ }
+ if (succeeded) {
+ while (cur_val_level > level) {
+ /*tex Convert |cur_val| to a lower level. */
+ downgrade_cur_val(false);
+ }
+ /*tex
+
+ Fix the reference count, if any, and negate |cur_val| if |negative|.
+ If |cur_val| points to a glue specification at this point, the
+ reference count for the glue does not yet include the reference by
+ |cur_val|. If |negative| is |true|, |cur_val_level| is known to be
+ |<=mu_val|.
+
+ */
+ if (negative) {
+ /*tex We create a new (negated) glue spec and keep the old one. */
+ negate_cur_val(false);
+ } else if ((cur_val_level >= glue_val_level) && (cur_val_level <= mu_val_level)) {
+ cur_val = new_spec(cur_val);
+ }
+ }
+ return succeeded;
+}
+
+/*tex
+
+ First, here is a short routine that is called from lua code. All the real
+ work is delegated to |short_scan_something_internal| that is shared between
+ this routine and |scan_something_internal|.
+
+*/
+
+void scan_something_simple(halfword cmd, halfword subitem)
+{
+ /*tex Negative is never true. */
+ if (!short_scan_something_internal(cmd, subitem, tok_val_level, false)) {
+ /*tex Complain that |texlib| can not do this; give zero result. */
+ print_err("You can't use `");
+ print_cmd_chr((quarterword) cmd, subitem);
+ tprint("' as tex library index");
+ help1("I'm forgetting what you said and using zero instead.");
+ error();
+ scanned_result(0, int_val_level);
+ }
+}
+
+/*tex
+
+ OK, we're ready for |scan_something_internal| itself. A second parameter,
+ |negative|, is set |true| if the value that is found should be negated. It is
+ assumed that |cur_cmd| and |cur_chr| represent the first token of the
+ internal quantity to be scanned; an error will be signalled if
+ |cur_cmd<min_internal| or |cur_cmd>max_internal|.
+
+*/
+
+/*tex Fetch an internal parameter: */
+
+void scan_something_internal(int level, boolean negative)
+{
+ /*tex |chr_code| part of the operand token */
+ halfword m;
+ /*tex accumulators */
+ int n, k;
+ RESTART:
+ m = cur_chr;
+ if (!short_scan_something_internal(cur_cmd, cur_chr, level, negative)) {
+ switch (cur_cmd) {
+ case def_char_code_cmd:
+ /*tex Fetch a character code from some table */
+ scan_char_num();
+ if (m == math_code_base) {
+ cur_val1 = get_math_code_num(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ } else if (m == lc_code_base) {
+ cur_val1 = get_lc_code(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ } else if (m == uc_code_base) {
+ cur_val1 = get_uc_code(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ } else if (m == sf_code_base) {
+ cur_val1 = get_sf_code(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ } else if (m == cat_code_base) {
+ cur_val1 = get_cat_code(cat_code_table_par, cur_val);
+ scanned_result(cur_val1, int_val_level);
+ } else {
+ confusion("def_char");
+ }
+ break;
+ case def_del_code_cmd:
+ case extdef_del_code_cmd:
+ /*tex Fetch a character code from some table. */
+ scan_char_num();
+ cur_val1 = get_del_code_num(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ break;
+ case extdef_math_code_cmd:
+ /*tex Fetch an extended math code table value. */
+ scan_char_num();
+ cur_val1 = get_math_code_num(cur_val);
+ scanned_result(cur_val1, int_val_level);
+ break;
+ case toks_register_cmd:
+ case set_font_cmd:
+ case def_font_cmd:
+ case letterspace_font_cmd:
+ case copy_font_cmd:
+ /*tex Fetch a token list or font identifier, provided that |level=tok_val|. */
+ if (level != tok_val_level) {
+ print_err("Missing number, treated as zero");
+ help3(
+ "A number should have been here; I inserted `0'.",
+ "(If you can't figure out why I needed to see a number,",
+ "look up `weird error' in the index to The TeXbook.)"
+ );
+ back_error();
+ scanned_result(0, dimen_val_level);
+ } else if (cur_cmd == toks_register_cmd) {
+ scan_register_num();
+ m = toks_base + cur_val;
+ scanned_result(equiv(m), tok_val_level);
+ } else {
+ back_input();
+ scan_font_ident();
+ scanned_result(font_id_base + cur_val, ident_val_level);
+ }
+ break;
+ case set_font_id_cmd:
+ scan_int();
+ scanned_result(font_id_base + cur_val, ident_val_level);
+ break;
+ case def_family_cmd:
+ /*tex Fetch a math font identifier. */
+ scan_char_num();
+ cur_val1 = fam_fnt(cur_val, m);
+ scanned_result(font_id_base + cur_val1, ident_val_level);
+ break;
+ case set_math_param_cmd:
+ /*tex Fetch a math parameter. */
+ cur_val1 = cur_chr;
+ get_token();
+ if (cur_cmd != math_style_cmd) {
+ print_err("Missing math style, treated as \\displaystyle");
+ help1("A style should have been here; I inserted `\\displaystyle'.");
+ cur_val = display_style;
+ back_error();
+ } else {
+ cur_val = cur_chr;
+ }
+ if (cur_val1 < math_param_first_mu_glue) {
+ if (cur_val1 == math_param_radical_degree_raise) {
+ cur_val1 = get_math_param(cur_val1, cur_chr);
+ scanned_result(cur_val1, int_val_level);
+ } else {
+ cur_val1 = get_math_param(cur_val1, cur_chr);
+ scanned_result(cur_val1, dimen_val_level);
+ }
+ } else {
+ cur_val1 = get_math_param(cur_val1, cur_chr);
+ if (cur_val1 == thin_mu_skip_code)
+ cur_val1 = thin_mu_skip_par;
+ else if (cur_val1 == med_mu_skip_code)
+ cur_val1 = med_mu_skip_par;
+ else if (cur_val1 == thick_mu_skip_code)
+ cur_val1 = thick_mu_skip_par;
+ scanned_result(cur_val1, mu_val_level);
+ }
+ break;
+ case assign_box_dir_cmd:
+ scan_register_num();
+ m = cur_val;
+ if (box(m) != null)
+ cur_val = box_dir(box(m));
+ else
+ cur_val = 0;
+ cur_val_level = dir_val_level;
+ break;
+ case set_box_dimen_cmd:
+ /*tex Fetch a box dimension. */
+ scan_register_num();
+ if (box(cur_val) == null)
+ cur_val = 0;
+ else
+ cur_val = varmem[box(cur_val) + m].cint;
+ cur_val_level = dimen_val_level;
+ break;
+ case assign_font_dimen_cmd:
+ /*tex Fetch a font dimension. */
+ get_font_dimen();
+ break;
+ case assign_font_int_cmd:
+ /*tex Fetch a font integer. */
+ scan_font_ident();
+ if (m == 0) {
+ scanned_result(hyphen_char(cur_val), int_val_level);
+ } else if (m == 1) {
+ scanned_result(skew_char(cur_val), int_val_level);
+ } else if (m == no_lig_code) {
+ scanned_result(test_no_ligatures(cur_val), int_val_level);
+ } else {
+ n = cur_val;
+ scan_char_num();
+ k = cur_val;
+ switch (m) {
+ case lp_code_base:
+ scanned_result(get_lp_code(n, k), int_val_level);
+ break;
+ case rp_code_base:
+ scanned_result(get_rp_code(n, k), int_val_level);
+ break;
+ case ef_code_base:
+ scanned_result(get_ef_code(n, k), int_val_level);
+ break;
+ case tag_code:
+ scanned_result(get_tag_code(n, k), int_val_level);
+ break;
+ }
+ }
+ break;
+ case register_cmd:
+ /*tex Fetch a register */
+ scan_register_num();
+ switch (m) {
+ case int_val_level:
+ cur_val = count(cur_val);
+ break;
+ case attr_val_level:
+ cur_val = attribute(cur_val);
+ break;
+ case dimen_val_level:
+ cur_val = dimen(cur_val);
+ break;
+ case glue_val_level:
+ cur_val = skip(cur_val);
+ break;
+ case mu_val_level:
+ cur_val = mu_skip(cur_val);
+ break;
+ }
+ cur_val_level = m;
+ break;
+ case ignore_spaces_cmd:
+ /*tex Trap unexpandable primitives. */
+ if (cur_chr == 1) {
+ /*tex
+
+ Reset |cur_tok| for unexpandable primitives, goto
+ restart. This block deals with unexpandable
+ \.{\\primitive} appearing at a spot where an integer or
+ an internal values should have been found. It fetches the
+ next token then resets |cur_cmd|, |cur_cs|, and
+ |cur_tok|, based on the primitive value of that token. No
+ expansion takes place, because the next token may be all
+ sorts of things. This could trigger further expansion
+ creating new errors.
+
+ */
+ get_token();
+ cur_cs = prim_lookup(cs_text(cur_cs));
+ if (cur_cs != undefined_primitive) {
+ cur_cmd = get_prim_eq_type(cur_cs);
+ cur_chr = get_prim_equiv(cur_cs);
+ cur_tok = token_val(cur_cmd, cur_chr);
+ } else {
+ cur_cmd = relax_cmd;
+ cur_chr = 0;
+ cur_tok = cs_token_flag + frozen_relax;
+ cur_cs = frozen_relax;
+ }
+ goto RESTART;
+ }
+ break;
+ case hyph_data_cmd:
+ switch (cur_chr) {
+ case 0:
+ case 1:
+ goto DEFAULT;
+ break;
+ case 2:
+ cur_val = get_pre_hyphen_char(language_par);
+ cur_val_level = int_val_level;
+ break;
+ case 3:
+ cur_val = get_post_hyphen_char(language_par);
+ cur_val_level = int_val_level;
+ break;
+ case 4:
+ cur_val = get_pre_exhyphen_char(language_par);
+ cur_val_level = int_val_level;
+ break;
+ case 5:
+ cur_val = get_post_exhyphen_char(language_par);
+ cur_val_level = int_val_level;
+ break;
+ case 6:
+ cur_val = get_hyphenation_min(language_par);
+ cur_val_level = int_val_level;
+ break;
+ case 7:
+ scan_int();
+ cur_val = get_hj_code(language_par,cur_val);
+ cur_val_level = int_val_level;
+ break;
+ }
+ break;
+ default:
+ DEFAULT:
+ /*tex Complain that \.{\\the} can not do this; give zero result. */
+ print_err("You can't use `");
+ print_cmd_chr((quarterword) cur_cmd, cur_chr);
+ tprint("' after \\the");
+ help1("I'm forgetting what you said and using zero instead.");
+ error();
+ if (level != tok_val_level)
+ scanned_result(0, dimen_val_level);
+ else
+ scanned_result(0, int_val_level);
+ break;
+ }
+ while (cur_val_level > level) {
+ /*tex Convert |cur_val| to a lower level. */
+ downgrade_cur_val(false);
+ }
+ /*tex
+
+ Fix the reference count, if any, and negate |cur_val| if |negative|.
+ If |cur_val| points to a glue specification at this point, the
+ reference count for the glue does not yet include the reference by
+ |cur_val|. If |negative| is |true|, |cur_val_level| is known to be
+ |<=mu_val|.
+
+ */
+ if (negative) {
+ /*tex We create a new (negated) glue spec and keep the old one. */
+ negate_cur_val(false);
+ } else if ((cur_val_level >= glue_val_level) && (cur_val_level <= mu_val_level)) {
+ cur_val = new_spec(cur_val);
+ }
+ }
+}
+
+/*tex
+
+ It is nice to have routines that say what they do, so the original
+ |scan_eight_bit_int| is superceded by |scan_register_num| and
+ |scan_mark_num|. It may become split up even further in the future.
+
+ Many of the |restricted classes| routines are the essentially the same except
+ for the upper limit and the error message, so it makes sense to combine these
+ all into one function.
+
+*/
+
+void scan_limited_int(int max, const char *name)
+{
+ char hlp[80];
+ scan_int();
+ if ((cur_val < 0) || (cur_val > max)) {
+ if (name == NULL) {
+ snprintf(hlp, 80, "Since I expected to read a number between 0 and %d,", max);
+ print_err("Bad number");
+ } else {
+ char msg[80];
+ snprintf(hlp, 80, "A %s must be between 0 and %d.", name, max);
+ snprintf(msg, 80, "Bad %s", name);
+ print_err(msg);
+ }
+ help2(hlp, "I changed this one to zero.");
+ int_error(cur_val);
+ cur_val = 0;
+ }
+}
+
+void scan_fifteen_bit_int(void)
+{
+ scan_real_fifteen_bit_int();
+ cur_val = ((cur_val / 0x1000) * 0x1000000) + (((cur_val % 0x1000) / 0x100) * 0x10000) + (cur_val % 0x100);
+}
+
+void scan_fifty_one_bit_int(void)
+{
+ int iiii;
+ scan_int();
+ if ((cur_val < 0) || (cur_val > 0777777777)) {
+ print_err("Bad delimiter code");
+ help2(
+ "A numeric delimiter (first part) must be between 0 and 2^{27}-1.",
+ "I changed this one to zero."
+ );
+ int_error(cur_val);
+ cur_val = 0;
+ }
+ iiii = cur_val;
+ scan_int();
+ if ((cur_val < 0) || (cur_val > 0xFFFFFF)) {
+ print_err("Bad delimiter code");
+ help2(
+ "A numeric delimiter (second part) must be between 0 and 2^{24}-1.",
+ "I changed this one to zero."
+ );
+ int_error(cur_val);
+ cur_val = 0;
+ }
+ cur_val1 = cur_val;
+ cur_val = iiii;
+}
+
+/*tex
+
+ An integer number can be preceded by any number of spaces and `\.+' or `\.-'
+ signs. Then comes either a decimal constant (i.e., radix 10), an octal
+ constant (i.e., radix 8, preceded by~'), a hexadecimal constant (radix 16,
+ preceded by~"), an alphabetic constant (preceded by~`), or an internal
+ variable. After scanning is complete, |cur_val| will contain the answer,
+ which must be at most $2^{31}-1=2147483647$ in absolute value. The value of
+ |radix| is set to 10, 8, or 16 in the cases of decimal, octal, or hexadecimal
+ constants, otherwise |radix| is set to zero. An optional space follows a
+ constant.
+
+*/
+
+/*tex |scan_int| sets this to 8, 10, 16, or zero */
+
+int radix;
+
+/*tex
+
+ The |scan_int| routine is used also to scan the integer part of a fraction;
+ for example, the `\.3' in `\.{3.14159}' will be found by |scan_int|. The
+ |scan_dimen| routine assumes that |cur_tok=point_token| after the integer
+ part of such a fraction has been scanned by |scan_int|, and that the decimal
+ point has been backed up to be scanned again.
+
+*/
+
+/*tex Sets |cur_val| to an integer: */
+
+void scan_int(void)
+{
+ /*tex should the answer be negated? */
+ boolean negative;
+ /*tex |$2^{31}$ / radix|, the threshold of danger */
+ int m;
+ /*tex the digit just scanned */
+ int d;
+ /*tex have no digits appeared? */
+ boolean vacuous;
+ /*tex has an error message been issued? */
+ boolean OK_so_far;
+ radix = 0;
+ OK_so_far = true;
+ /*tex Get the next non-blank non-sign token; set |negative| appropriately. */
+ negative = false;
+ do {
+ /*tex Get the next non-blank non-call token. */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_tok == other_token + '-') {
+ negative = !negative;
+ cur_tok = other_token + '+';
+ }
+ } while (cur_tok == other_token + '+');
+
+ RESTART:
+ if (cur_tok == alpha_token) {
+ /*tex
+
+ Scan an alphabetic character code into |cur_val|. A space is ignored
+ after an alphabetic character constant, so that such constants behave
+ like numeric ones.
+
+ */
+ /*tex Suppress macro expansion: */
+ get_token();
+ if (cur_tok < cs_token_flag) {
+ cur_val = cur_chr;
+ if (cur_cmd <= right_brace_cmd) {
+ if (cur_cmd == right_brace_cmd)
+ incr(align_state);
+ else
+ decr(align_state);
+ }
+ } else {
+ /*tex The value of a csname in this context is its name. */
+ str_number txt = cs_text(cur_tok - cs_token_flag);
+ if (is_active_cs(txt))
+ cur_val = active_cs_value(txt);
+ else if (single_letter(txt))
+ cur_val = pool_to_unichar(str_string(txt));
+ else
+ cur_val = (biggest_char + 1);
+ }
+ if (cur_val > biggest_char) {
+ print_err("Improper alphabetic constant");
+ help2(
+ "A one-character control sequence belongs after a ` mark.",
+ "So I'm essentially inserting \\0 here."
+ );
+ cur_val = '0';
+ back_error();
+ } else {
+ /*tex Scan an optional space. */
+ get_x_token();
+ if (cur_cmd != spacer_cmd)
+ back_input();
+ }
+
+ } else if (cur_tok == cs_token_flag + frozen_primitive) {
+ /*tex
+
+ Reset |cur_tok| for unexpandable primitives, goto restart This block
+ deals with unexpandable \.{\\primitive} appearing at a spot where an
+ integer or an internal values should have been found. It fetches the
+ next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on
+ the primitive value of that token. No expansion takes place, because
+ the next token may be all sorts of things. This could trigger further
+ expansion creating new errors.
+
+ */
+ get_token();
+ cur_cs = prim_lookup(cs_text(cur_cs));
+ if (cur_cs != undefined_primitive) {
+ cur_cmd = get_prim_eq_type(cur_cs);
+ cur_chr = get_prim_equiv(cur_cs);
+ cur_tok = token_val(cur_cmd, cur_chr);
+ } else {
+ cur_cmd = relax_cmd;
+ cur_chr = 0;
+ cur_tok = cs_token_flag + frozen_relax;
+ cur_cs = frozen_relax;
+ }
+ goto RESTART;
+ } else if (cur_cmd == math_style_cmd) {
+ cur_val = cur_chr;
+ } else if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
+ scan_something_internal(int_val_level, false);
+ } else {
+ /*tex Scan a numeric constant. */
+ radix = 10;
+ m = 214748364;
+ if (cur_tok == octal_token) {
+ radix = 8;
+ m = 02000000000;
+ get_x_token();
+ } else if (cur_tok == hex_token) {
+ radix = 16;
+ m = 01000000000;
+ get_x_token();
+ }
+ vacuous = true;
+ cur_val = 0;
+ /*tex Accumulate the constant until |cur_tok| is not a suitable digit. */
+ while (1) {
+ if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token) && (cur_tok <= nine_token)) {
+ d = cur_tok - zero_token;
+ } else if (radix == 16) {
+ if ((cur_tok <= A_token + 5) && (cur_tok >= A_token)) {
+ d = cur_tok - A_token + 10;
+ } else if ((cur_tok <= other_A_token + 5) && (cur_tok >= other_A_token)) {
+ d = cur_tok - other_A_token + 10;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ vacuous = false;
+ if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10))) {
+ if (OK_so_far) {
+ print_err("Number too big");
+ help2(
+ "I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
+ "so I'm using that number instead of yours."
+ );
+ error();
+ cur_val = infinity;
+ OK_so_far = false;
+ }
+ } else {
+ cur_val = cur_val * radix + d;
+ }
+ get_x_token();
+ }
+ if (vacuous) {
+ /*tex Express astonishment that no number was here */
+ print_err("Missing number, treated as zero");
+ help3(
+ "A number should have been here; I inserted `0'.",
+ "(If you can't figure out why I needed to see a number,",
+ "look up `weird error' in the index to The TeXbook.)"
+ );
+ back_error();
+ } else if (cur_cmd != spacer_cmd) {
+ back_input();
+ }
+ }
+ if (negative)
+ negate(cur_val);
+}
+
+/*tex
+
+ The following code is executed when |scan_something_internal| was called
+ asking for |mu_val|, when we really wanted a ``mudimen'' instead of
+ ``muglue.''
+
+*/
+
+static void coerce_glue(void)
+{
+ int v;
+ if (cur_val_level >= glue_val_level) {
+ v = width(cur_val);
+ flush_node(cur_val);
+ cur_val = v;
+ }
+}
+
+/*tex
+
+ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to a
+ |scaled| value, i.e., an integral number of sp. One of its main tasks is
+ therefore to interpret the abbreviations for various kinds of units and to
+ convert measurements to scaled points.
+
+ There are three parameters: |mu| is |true| if the finite units must be
+ `\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed; |inf| is
+ |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}' are
+ permitted; and |shortcut| is |true| if |cur_val| already contains an integer
+ and only the units need to be considered.
+
+ The order of infinity that was found in the case of infinite glue is returned
+ in the global variable |cur_order|.
+
+*/
+
+/*tex The order of infinity found by |scan_dimen|: */
+
+int cur_order;
+
+/*tex
+
+ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen| may
+ begin with |scan_int|. This explains why it is convenient to use |scan_int|
+ also for the integer part of a decimal fraction.
+
+ Several branches of |scan_dimen| work with |cur_val| as an integer and with
+ an auxiliary fraction |f|, so that the actual quantity of interest is
+ $|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
+ representation is put into the single word |cur_val|, which suddenly switches
+ significance from |integer| to |scaled|.
+
+ The necessary conversion factors can all be specified exactly as fractions
+ whose numerator and denominator add to 32768 or less. According to the
+ definitions here, $\rm2660\,dd\approx1000.33297\,mm$; this agrees well with
+ the value $\rm1000.333\,mm$ cited by Bosshard \^{Bosshard, Hans Rudolf} in
+ {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). The Didot
+ point has been newly standardized in 1978; it's now exactly $\rm
+ 1\,nd=0.375\,mm$. Conversion uses the equation
+ $0.375=21681/20320/72.27\cdot25.4$. The new Cicero follows the new Didot
+ point; $\rm 1\,nc=12\,nd$. These would lead to the ratios $21681/20320$ and
+ $65043/5080$, respectively. The closest approximations supported by the
+ algorithm would be $11183/10481$ and $1370/107$. In order to maintain the
+ relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for $\rm nd$,
+ however.
+
+*/
+
+static void scan_dimen_mu_error(void) {
+ print_err("Illegal unit of measure (mu inserted)");
+ help4(
+ "The unit of measurement in math glue must be mu.",
+ "To recover gracefully from this error, it's best to",
+ "delete the erroneous units; e.g., type `2' to delete",
+ "two letters. (See Chapter 27 of The TeXbook.)"
+ );
+ error();
+}
+
+static void scan_dimen_unknown_unit_error(void) {
+ print_err("Illegal unit of measure (pt inserted)");
+ help6(
+ "Dimensions can be in units of em, ex, in, pt, pc,",
+ "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
+ "I'll assume that you meant to say pt, for printer's points.",
+ "To recover gracefully from this error, it's best to",
+ "delete the erroneous units; e.g., type `2' to delete",
+ "two letters. (See Chapter 27 of The TeXbook.)"
+ );
+ error();
+}
+
+static void scan_dimen_out_of_range_error(void) {
+ print_err("Dimension too large");
+ help2(
+ "I can't work with sizes bigger than about 19 feet.",
+ "Continue and I'll use the largest value I can."
+ );
+ error();
+}
+
+#define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
+
+/*tex
+
+ This function sets |cur_val| to a dimension. It could be optimized a bit more
+ (but not now, something for luatex > 1).
+
+*/
+
+void scan_dimen(boolean mu, boolean inf, boolean shortcut)
+{
+ /*tex should the answer be negated? */
+ boolean negative = false;
+ boolean is_true = false;
+ /*tex numerator of a fraction whose denominator is $2^{16}$ */
+ int f = 0;
+ /*tex conversion ratio for the scanned units */
+ int num = 0;
+ int denom = 0;
+ /*tex top of decimal digit stack */
+ halfword q;
+ /*tex an internal dimension */
+ scaled v;
+ /*tex temporary storage of |cur_val| */
+ int save_cur_val;
+ arith_error = false;
+ cur_order = normal;
+ if (!shortcut) {
+ /*tex Get the next non-blank non-sign. */
+ do {
+ /*tex Get the next non-blank non-call token. */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_tok == minus_token) {
+ negative = !negative;
+ cur_tok = plus_token;
+ }
+ } while (cur_tok == plus_token);
+ if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
+ /*tex Fetch an internal dimension and |goto attach_sign|, or fetch an internal integer. */
+ if (mu) {
+ scan_something_internal(mu_val_level, false);
+ coerce_glue();
+ if (cur_val_level == mu_val_level) {
+ goto ATTACH_SIGN;
+ } else if (cur_val_level != int_val_level) {
+ mu_error();
+ }
+ } else {
+ scan_something_internal(dimen_val_level, false);
+ if (cur_val_level == dimen_val_level) {
+ goto ATTACH_SIGN;
+ }
+ }
+ } else {
+ back_input();
+ if (cur_tok == continental_point_token) {
+ cur_tok = point_token;
+ }
+ if (cur_tok != point_token) {
+ scan_int();
+ } else {
+ radix = 10;
+ cur_val = 0;
+ }
+ if (cur_tok == continental_point_token) {
+ cur_tok = point_token;
+ }
+ if ((radix == 10) && (cur_tok == point_token)) {
+ /*tex
+
+ Scan decimal fraction. When the following code is executed,
+ we have |cur_tok=point_token|, but this token has been backed
+ up using |back_input|; we must first discard it. It turns out
+ that a decimal point all by itself is equivalent to
+ `\.{0.0}'. Let's hope people don't use that fact.
+
+ */
+ int k = 0;
+ halfword p = null;
+ int kk;
+ /*tex The |point_token| is being re-scanned. */
+ get_token();
+ while (1) {
+ get_x_token();
+ if ((cur_tok > nine_token) || (cur_tok < zero_token))
+ break;
+ if (k < 17) {
+ /*tex Digits for |k>=17| cannot affect the result. */
+ q = get_avail();
+ set_token_link(q, p);
+ set_token_info(q, cur_tok - zero_token);
+ p = q;
+ incr(k);
+ }
+ }
+ for (kk = k; kk >= 1; kk--) {
+ dig[kk - 1] = token_info(p);
+ q = p;
+ p = token_link(p);
+ free_avail(q);
+ }
+ f = round_decimals(k);
+ if (cur_cmd != spacer_cmd) {
+ back_input();
+ }
+ }
+ }
+ }
+ if (cur_val < 0) {
+ /*tex In this case |f=0|. */
+ negative = !negative;
+ negate(cur_val);
+ }
+ /*tex
+
+ Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
+ are |x| sp per unit; |goto attach_sign| if the units are internal. Now
+ comes the harder part: At this point in the program, |cur_val| is a
+ nonnegative integer and $f/2^{16}$ is a nonnegative fraction less than 1;
+ we want to multiply the sum of these two quantities by the appropriate
+ factor, based on the specified units, in order to produce a |scaled|
+ result, and we want to do the calculation with fixed point arithmetic
+ that does not overflow.
+
+ */
+ if (inf) {
+ if (scan_keyword("fi")) {
+ cur_order = sfi;
+ if (scan_keyword("l")) {
+ cur_order = fil;
+ if (scan_keyword("l")) {
+ cur_order = fill;
+ if (scan_keyword("l")) {
+ cur_order = filll;
+ }
+ }
+ }
+ goto ATTACH_FRACTION;
+ }
+ }
+ /*tex
+
+ Scan for (u)units that are internal dimensions; |goto attach_sign| with
+ |cur_val| set if found.
+
+ */
+ save_cur_val = cur_val;
+ /*tex
+
+ Get the next non-blank non-call; a pitty if just backed up the input.
+
+ */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+
+ if ((cur_cmd < min_internal_cmd) || (cur_cmd > max_internal_cmd)) {
+ back_input();
+ } else {
+ /*tex |math_given_cmd|, |xmath_given_cmd| and |last_item_cmd} */
+ if (mu) {
+ scan_something_internal(mu_val_level, false);
+ coerce_glue();
+ if (cur_val_level != mu_val_level) {
+ mu_error();
+ }
+ } else {
+ scan_something_internal(dimen_val_level, false);
+ }
+ v = cur_val;
+ goto FOUND;
+ }
+ /*tex Bah |true| forces to split the unit scanner. */
+ if (mu) {
+ /*tex Scan for (m)\.{mu} units and |goto attach_fraction|. */
+ if (! scan_keyword("mu")) {
+ scan_dimen_mu_error();
+ }
+ goto ATTACH_FRACTION;
+ } else if (scan_keyword("em")) {
+ v = quad(get_cur_font());
+ } else if (scan_keyword("ex")) {
+ v = x_height(get_cur_font());
+ } else if (scan_keyword("px")) {
+ v = px_dimen_par;
+ } else {
+ goto PICKUP_UNIT;
+ }
+ /*tex Scan an optional space (after em, ex or px) */
+ get_x_token();
+ if (cur_cmd != spacer_cmd) {
+ back_input();
+ }
+ FOUND:
+ cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
+ goto ATTACH_SIGN;
+ /*tex
+
+ Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
+ |goto done| in the case of scaled points.
+
+ */
+ PICKUP_UNIT:
+ if (scan_keyword("pt")) {
+ /*tex The easy case: */
+ goto SCALE_VALUE;
+ } else if (scan_keyword("mm")) {
+ set_conversion(7227, 2540);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("cm")) {
+ set_conversion(7227, 254);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("sp")) {
+ goto DONE;
+ } else if (scan_keyword("bp")) {
+ set_conversion(7227, 7200);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("in")) {
+ set_conversion(7227, 100);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("dd")) {
+ set_conversion(1238, 1157);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("cc")) {
+ set_conversion(14856, 1157);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("pc")) {
+ set_conversion(12, 1);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("nd")) {
+ set_conversion(685, 642);
+ goto SCALE_VALUE;
+ } else if (scan_keyword("nc")) {
+ set_conversion(1370, 107);
+ goto SCALE_VALUE;
+ } else if (!is_true && scan_keyword("true")) {
+ is_true = true;
+ goto PICKUP_UNIT;
+ }
+ /*tex Complain about unknown unit and |goto done2|. */
+ scan_dimen_unknown_unit_error();
+ goto BAD_NEWS;
+ SCALE_VALUE:
+ /*tex Adjust |f| for the magnification ratio. */
+ if (is_true) {
+ /*tex Maybe at some point we will drop mag completely, even in \DVI\ mode. */
+ if (output_mode_used <= OMODE_DVI) {
+ prepare_mag();
+ if (mag_par != 1000) {
+ cur_val = xn_over_d(cur_val, 1000, mag_par);
+ f = (1000 * f + 0200000 * tex_remainder) / mag_par;
+ cur_val = cur_val + (f / 0200000);
+ f = f % 0200000;
+ }
+ } else {
+ /*tex in \PDF\ mode we're always |true|. */
+ one_true_inch = one_inch;
+ }
+ }
+ if (num) {
+ cur_val = xn_over_d(cur_val, num, denom);
+ f = (num * f + 0200000 * tex_remainder) / denom;
+ cur_val = cur_val + (f / 0200000);
+ f = f % 0200000;
+ }
+ BAD_NEWS:
+ ATTACH_FRACTION:
+ if (cur_val >= 040000) {
+ arith_error = true;
+ } else {
+ cur_val = cur_val * unity + f;
+ }
+ DONE:
+ /*tex Scan an optional space; this happens too often. */
+ get_x_token();
+ if (cur_cmd != spacer_cmd) {
+ back_input();
+ }
+ ATTACH_SIGN:
+ if (arith_error || (abs(cur_val) >= 010000000000)) {
+ /*tex Report that this dimension is out of range. */
+ scan_dimen_out_of_range_error();
+ cur_val = max_dimen;
+ arith_error = false;
+ }
+ if (negative) {
+ negate(cur_val);
+ }
+}
+
+/*tex
+
+ The final member of \TeX's value-scanning trio is |scan_glue|, which makes
+ |cur_val| point to a glue specification. The reference count of that glue
+ spec will take account of the fact that |cur_val| is pointing to~it.
+
+ The |level| parameter should be either |glue_val| or |mu_val|.
+
+ Since |scan_dimen| was so much more complex than |scan_int|, we might expect
+ |scan_glue| to be even worse. But fortunately, it is very simple, since most
+ of the work has already been done.
+
+*/
+
+void scan_glue(int level)
+{
+ /*tex should the answer be negated? */
+ boolean negative = false;
+ /*tex new glue specification */
+ halfword q = null;
+ /*tex does |level=mu_val|? */
+ boolean mu = (level == mu_val_level);
+ /*tex Get the next non-blank non-sign. */
+ do {
+ /*tex Get the next non-blank non-call token. */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ if (cur_tok == minus_token) {
+ negative = !negative;
+ cur_tok = plus_token;
+ }
+ } while (cur_tok == plus_token);
+ if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
+ scan_something_internal(level, negative);
+ if (cur_val_level >= glue_val_level) {
+ if (cur_val_level != level)
+ mu_error();
+ return;
+ }
+ if (cur_val_level == int_val_level)
+ scan_dimen(mu, false, true);
+ else if (level == mu_val_level)
+ mu_error();
+ } else {
+ back_input();
+ scan_dimen(mu, false, false);
+ if (negative)
+ negate(cur_val);
+ }
+ /*tex
+
+ Create a new glue specification whose width is |cur_val|; scan for its
+ stretch and shrink components.
+
+ */
+ q = new_spec(zero_glue);
+ width(q) = cur_val;
+ if (scan_keyword("plus")) {
+ scan_dimen(mu, true, false);
+ stretch(q) = cur_val;
+ stretch_order(q) = (quarterword) cur_order;
+ }
+ if (scan_keyword("minus")) {
+ scan_dimen(mu, true, false);
+ shrink(q) = cur_val;
+ shrink_order(q) = (quarterword) cur_order;
+ }
+ cur_val = q;
+}
+
+/*tex
+
+ This procedure is supposed to scan something like `\.{\\skip\\count12}',
+ i.e., whatever can follow `\.{\\the}', and it constructs a token list
+ containing something like `\.{-3.0pt minus 0.5fill}'.
+
+*/
+
+halfword the_toks(void)
+{
+ /*tex holds |selector| setting */
+ int old_setting;
+ /*tex used for copying a token list */
+ halfword p, q, r;
+ /*tex value of |cur_chr| */
+ int c;
+ str_number s;
+ halfword retval;
+ /*tex Handle \.{\\unexpanded} or \.{\\detokenize} and |return|. */
+ if (odd(cur_chr)) {
+ c = cur_chr;
+ scan_general_text();
+ if (c == 1) {
+ return cur_val;
+ } else {
+ old_setting = selector;
+ selector = new_string;
+ p = get_avail();
+ set_token_link(p, token_link(temp_token_head));
+ token_show(p);
+ flush_list(p);
+ selector = old_setting;
+ s = make_string();
+ retval = str_toks(str_lstring(s));
+ flush_str(s);
+ return retval;
+ }
+ }
+ get_x_token();
+ scan_something_internal(tok_val_level, false);
+ if (cur_val_level >= ident_val_level) {
+ /*tex Copy the token list */
+ p = temp_token_head;
+ set_token_link(p, null);
+ if (cur_val_level == ident_val_level) {
+ store_new_token(cs_token_flag + cur_val);
+ } else if (cur_val != null) {
+ /*tex Do not copy the reference count! */
+ r = token_link(cur_val);
+ while (r != null) {
+ fast_store_new_token(token_info(r));
+ r = token_link(r);
+ }
+ }
+ return p;
+ } else {
+ old_setting = selector;
+ selector = new_string;
+ switch (cur_val_level) {
+ case int_val_level:
+ print_int(cur_val);
+ break;
+ case attr_val_level:
+ print_int(cur_val);
+ break;
+ case dir_val_level:
+ print_dir_par(cur_val);
+ break;
+ case dimen_val_level:
+ print_scaled(cur_val);
+ tprint("pt");
+ break;
+ case glue_val_level:
+ print_spec(cur_val, "pt");
+ flush_node(cur_val);
+ break;
+ case mu_val_level:
+ print_spec(cur_val, "mu");
+ flush_node(cur_val);
+ break;
+ }
+ selector = old_setting;
+ s = make_string();
+ retval = str_toks(str_lstring(s));
+ flush_str(s);
+ return retval;
+ }
+}
+
+str_number the_scanned_result(void)
+{
+ /*tex holds |selector| setting */
+ int old_setting;
+ /*tex return value */
+ str_number r;
+ old_setting = selector;
+ selector = new_string;
+ if (cur_val_level >= ident_val_level) {
+ if (cur_val != null) {
+ show_token_list(token_link(cur_val), null, -1);
+ r = make_string();
+ } else {
+ r = get_nullstr();
+ }
+ } else {
+ switch (cur_val_level) {
+ case int_val_level:
+ print_int(cur_val);
+ break;
+ case attr_val_level:
+ print_int(cur_val);
+ break;
+ case dir_val_level:
+ print_dir_par(cur_val);
+ break;
+ case dimen_val_level:
+ print_scaled(cur_val);
+ tprint("pt");
+ break;
+ case glue_val_level:
+ print_spec(cur_val, "pt");
+ flush_node(cur_val);
+ break;
+ case mu_val_level:
+ print_spec(cur_val, "mu");
+ flush_node(cur_val);
+ break;
+ }
+ r = make_string();
+ }
+ selector = old_setting;
+ return r;
+}
+
+/*tex
+
+ The following routine is used to implement `\.{\\fontdimen} |n| |f|'. The
+ boolean parameter |writing| is set |true| if the calling program intends to
+ change the parameter value.
+
+*/
+
+static void font_param_error(int f)
+{
+ print_err("Font ");
+ print_esc(font_id_text(f));
+ tprint(" has only ");
+ print_int(font_params(f));
+ tprint(" fontdimen parameters");
+ help2(
+ "To increase the number of font parameters, you must",
+ "use \\fontdimen immediately after the \\font is loaded."
+ );
+ error();
+}
+
+void set_font_dimen(void)
+{
+ internal_font_number f;
+ int n;
+ scan_int();
+ n = cur_val;
+ scan_font_ident();
+ f = cur_val;
+ if (n <= 0) {
+ font_param_error(f);
+ } else if (n > font_params(f)) {
+ if (font_used(f)) {
+ font_param_error(f);
+ } else {
+ /*tex Increase the number of parameters in the font. */
+ do {
+ set_font_param(f, (font_params(f) + 1), 0);
+ } while (n != font_params(f));
+ }
+ }
+ scan_optional_equals();
+ scan_normal_dimen();
+ set_font_param(f, n, cur_val);
+}
+
+void get_font_dimen(void)
+{
+ internal_font_number f;
+ /*tex The parameter number: */
+ int n;
+ scan_int();
+ n = cur_val;
+ scan_font_ident();
+ f = cur_val;
+ /*tex Initialize return value: */
+ cur_val = 0;
+ if (n <= 0) {
+ font_param_error(f);
+ goto EXIT;
+ } else if (n > font_params(f)) {
+ if (font_used(f)) {
+ font_param_error(f);
+ goto EXIT;
+ } else {
+ /*tex Increase the number of parameters in the font. */
+ do {
+ set_font_param(f, (font_params(f) + 1), 0);
+ } while (n != font_params(f));
+ }
+ }
+ cur_val = font_param(f, n);
+ EXIT:
+ scanned_result(cur_val, dimen_val_level);
+}
+
+/*tex
+
+ Here's a similar procedure that returns a pointer to a rule node. This
+ routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
+ therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
+ the default rule dimensions in the node, then to override them if
+ `\.{height}' or `\.{width}' or `\.{depth}' specifications are found (in any
+ order).
+
+*/
+
+halfword scan_rule_spec(void)
+{
+ /*tex |width|, |depth|, and |height| all equal |null_flag| now */
+ halfword q;
+ if (cur_cmd == no_vrule_cmd) {
+ q = new_rule(empty_rule);
+ cur_cmd = vrule_cmd;
+ } else if (cur_cmd == no_hrule_cmd) {
+ q = new_rule(empty_rule);
+ cur_cmd = hrule_cmd;
+ } else {
+ q = new_rule(normal_rule);
+ }
+ if (cur_cmd == vrule_cmd) {
+ width(q) = default_rule;
+ rule_dir(q) = body_direction_par;
+ } else {
+ height(q) = default_rule;
+ depth(q) = 0;
+ rule_dir(q) = text_direction_par;
+ }
+ RESWITCH:
+ if (scan_keyword("width")) {
+ scan_normal_dimen();
+ width(q) = cur_val;
+ goto RESWITCH;
+ }
+ if (scan_keyword("height")) {
+ scan_normal_dimen();
+ height(q) = cur_val;
+ goto RESWITCH;
+ }
+ if (scan_keyword("depth")) {
+ scan_normal_dimen();
+ depth(q) = cur_val;
+ goto RESWITCH;
+ }
+ return q;
+}
+
+/*tex Declare procedures that scan font-related stuff. */
+
+void scan_font_ident(void)
+{
+ internal_font_number f;
+ halfword m;
+ /*tex Get the next non-blank non-call. */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ if ((cur_cmd == def_font_cmd) || (cur_cmd == letterspace_font_cmd) || (cur_cmd == copy_font_cmd)) {
+ f = get_cur_font();
+ } else if (cur_cmd == set_font_cmd) {
+ f = cur_chr;
+ set_font_touched(f, 1);
+ } else if (cur_cmd == def_family_cmd) {
+ m = cur_chr;
+ scan_math_family_int();
+ f = fam_fnt(cur_val, m);
+ set_font_touched(f, 1);
+ } else {
+ print_err("Missing font identifier");
+ help2(
+ "I was looking for a control sequence whose",
+ "current meaning has been defined by \\font."
+ );
+ back_error();
+ f = null_font;
+ }
+ cur_val = f;
+}
+
+/*tex
+
+ The |scan_general_text| procedure is much like |scan_toks(false,false)|, but
+ will be invoked via |expand|, i.e., recursively.
+
+ The token list (balanced text) created by |scan_general_text| begins at
+ |link(temp_token_head)| and ends at |cur_val|. (If |cur_val=temp_token_head|,
+ the list is empty.)
+
+*/
+
+void scan_general_text(void)
+{
+ /*tex Here we save |scanner_status|: */
+ int s;
+ /*tex Here we save |warning_index|: */
+ halfword w;
+ /*tex Here we save |def_ref|: */
+ halfword d;
+ /*tex The tail of the token list being built: */
+ halfword p;
+ /*tex The new node being added to the token list via |store_new_token|: */
+ halfword q;
+ /*tex The number of unmatched left braces: */
+ halfword unbalance;
+ s = scanner_status;
+ w = warning_index;
+ d = def_ref;
+ scanner_status = absorbing;
+ warning_index = cur_cs;
+ p = get_avail();
+ def_ref = p;
+ set_token_ref_count(def_ref, 0);
+ p = def_ref;
+ /*tex Remove the compulsory left brace. */
+ scan_left_brace();
+ unbalance = 1;
+ while (1) {
+ get_token();
+ if (cur_tok < right_brace_limit) {
+ if (cur_cmd < right_brace_cmd) {
+ incr(unbalance);
+ } else {
+ decr(unbalance);
+ if (unbalance == 0)
+ break;
+ }
+ }
+ store_new_token(cur_tok);
+ }
+ q = token_link(def_ref);
+ /*tex Discard reference count. */
+ free_avail(def_ref);
+ if (q == null)
+ cur_val = temp_token_head;
+ else
+ cur_val = p;
+ set_token_link(temp_token_head, q);
+ scanner_status = s;
+ warning_index = w;
+ def_ref = d;
+}
+
+/*tex
+
+ The |get_x_or_protected| procedure is like |get_x_token| except that
+ protected macros are not expanded. It sets |cur_cmd|, |cur_chr|,
+ |cur_tok|,and expands non-protected macros.
+
+*/
+
+void get_x_or_protected(void)
+{
+
+ while (1) {
+ get_token();
+ if (cur_cmd <= max_command_cmd)
+ return;
+ if ((cur_cmd >= call_cmd) && (cur_cmd < end_template_cmd)) {
+ if (token_info(token_link(cur_chr)) == protected_token)
+ return;
+ }
+ expand();
+ }
+}
+
+/*tex
+
+ |scan_toks|. This function returns a pointer to the tail of a new token list,
+ and it also makes |def_ref| point to the reference count at the head of that
+ list.
+
+ There are two boolean parameters, |macro_def| and |xpand|. If |macro_def| is
+ true, the goal is to create the token list for a macro definition; otherwise
+ the goal is to create the token list for some other \TeX\ primitive:
+ \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase}, \.{\\uppercase},
+ \.{\\message}, \.{\\errmessage}, \.{\\write}, or \.{\\special}. In the latter
+ cases a left brace must be scanned next; this left brace will not be part of
+ the token list, nor will the matching right brace that comes at the end. If
+ |xpand| is false, the token list will simply be copied from the input using
+ |get_token|. Otherwise all expandable tokens will be expanded until
+ unexpandable tokens are left, except that the results of expanding
+ `\.{\\the}' are not expanded further. If both |macro_def| and |xpand| are
+ true, the expansion applies only to the macro body (i.e., to the material
+ following the first |left_brace| character).
+
+ The value of |cur_cs| when |scan_toks| begins should be the |eqtb| address of
+ the control sequence to display in ``runaway'' error messages.
+
+*/
+
+halfword scan_toks(boolean macro_def, boolean xpand)
+{
+ /*tex token representing the highest parameter number */
+ halfword t;
+ /*tex saved token */
+ halfword s;
+ /*tex tail of the token list being built */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex number of unmatched left braces */
+ halfword unbalance;
+ /*tex possible `\.{\#\{}' token */
+ halfword hash_brace;
+ if (macro_def)
+ scanner_status = defining;
+ else
+ scanner_status = absorbing;
+ warning_index = cur_cs;
+ p = get_avail();
+ def_ref = p;
+ set_token_ref_count(def_ref, 0);
+ p = def_ref;
+ hash_brace = 0;
+ t = zero_token;
+ if (macro_def) {
+ /*tex Scan and build the parameter part of the macro definition. */
+ while (1) {
+ /*tex Set |cur_cmd|, |cur_chr|, |cur_tok|: */
+ get_token();
+ if (cur_tok < right_brace_limit)
+ break;
+ if (cur_cmd == mac_param_cmd) {
+ /*tex
+
+ If the next character is a parameter number, make
+ |cur_tok| a |match| token; but if it is a left brace,
+ store `|left_brace|, |end_match|', set |hash_brace|, and
+ |goto done|.
+
+ */
+ s = match_token + cur_chr;
+ get_token();
+ if (cur_cmd == left_brace_cmd) {
+ hash_brace = cur_tok;
+ store_new_token(cur_tok);
+ store_new_token(end_match_token);
+ goto DONE;
+ }
+ if (t == nine_token) {
+ print_err("You already have nine parameters");
+ help1("I'm going to ignore the # sign you just used.");
+ error();
+ } else {
+ incr(t);
+ if (cur_tok != t) {
+ print_err("Parameters must be numbered consecutively");
+ help2(
+ "I've inserted the digit you should have used after the #.",
+ "Type `1' to delete what you did use."
+ );
+ back_error();
+ }
+ cur_tok = s;
+ }
+ }
+ store_new_token(cur_tok);
+ }
+ store_new_token(end_match_token);
+ if (cur_cmd == right_brace_cmd) {
+ /*tex Express shock at the missing left brace; |goto found|. */
+ print_err("Missing { inserted");
+ incr(align_state);
+ help2(
+ "Where was the left brace? You said something like `\\def\\a}',",
+ "which I'm going to interpret as `\\def\\a{}'."
+ );
+ error();
+ goto FOUND;
+ }
+
+ } else {
+ /*tex Remove the compulsory left brace. */
+ scan_left_brace();
+ }
+ DONE:
+ /*tex Scan and build the body of the token list; |goto found| when finished. */
+ unbalance = 1;
+ while (1) {
+ if (xpand) {
+ /*tex
+
+ Expand the next part of the input. Here we insert an entire token
+ list created by |the_toks| without expanding it further.
+
+ */
+ while (1) {
+ get_next();
+ if (cur_cmd >= call_cmd) {
+ if (token_info(token_link(cur_chr)) == protected_token) {
+ cur_cmd = relax_cmd;
+ cur_chr = no_expand_flag;
+ }
+ }
+ if (cur_cmd <= max_command_cmd)
+ break;
+ if (cur_cmd != the_cmd) {
+ expand();
+ } else {
+ q = the_toks();
+ if (token_link(temp_token_head) != null) {
+ set_token_link(p, token_link(temp_token_head));
+ p = q;
+ }
+ }
+ }
+ x_token();
+ } else {
+ get_token();
+ }
+ if (cur_tok < right_brace_limit) {
+ if (cur_cmd < right_brace_cmd) {
+ incr(unbalance);
+ } else {
+ decr(unbalance);
+ if (unbalance == 0)
+ goto FOUND;
+ }
+ } else if (cur_cmd == mac_param_cmd) {
+ if (macro_def) {
+ /*tex Look for parameter number or \.{\#\#}. */
+ s = cur_tok;
+ if (xpand)
+ get_x_token();
+ else
+ get_token();
+ if (cur_cmd != mac_param_cmd) {
+ if ((cur_tok <= zero_token) || (cur_tok > t)) {
+ print_err("Illegal parameter number in definition of ");
+ sprint_cs(warning_index);
+ help3(
+ "You meant to type ## instead of #, right?",
+ "Or maybe a } was forgotten somewhere earlier, and things",
+ "are all screwed up? I'm going to assume that you meant ##."
+ );
+ back_error();
+ cur_tok = s;
+ } else {
+ cur_tok = out_param_token - '0' + cur_chr;
+ }
+ }
+ }
+ }
+ store_new_token(cur_tok);
+ }
+ FOUND:
+ scanner_status = normal;
+ if (hash_brace != 0)
+ store_new_token(hash_brace);
+ return p;
+}
+
+/*tex
+
+ Here we declare two trivial procedures in order to avoid mutually recursive
+ procedures with parameters.
+
+*/
+
+void scan_normal_glue(void)
+{
+ scan_glue(glue_val_level);
+}
+
+void scan_mu_glue(void)
+{
+ scan_glue(mu_val_level);
+}
+
+/*tex
+
+ The |scan_expr| procedure scans and evaluates an expression. Evaluating an
+ expression is a recursive process: When the left parenthesis of a
+ subexpression is scanned we descend to the next level of recursion; the
+ previous level is resumed with the matching right parenthesis.
+
+*/
+
+typedef enum {
+ /*tex \.( seen, or \.( $\langle\it expr\rangle$ \.) seen */
+ expr_none = 0,
+ /*tex \.( $\langle\it expr\rangle$ \.+ seen */
+ expr_add = 1,
+ /*tex \.( $\langle\it expr\rangle$ \.- seen */
+ expr_sub = 2,
+ /*tex $\langle\it term\rangle$ \.* seen */
+ expr_mult = 3,
+ /*tex $\langle\it term\rangle$ \./ seen */
+ expr_div = 4,
+ /*tex $\langle\it term\rangle$ \.* $\langle\it factor\rangle$ \./ seen */
+ expr_scale = 5,
+} expression_states;
+
+/*tex
+
+ We want to make sure that each term and (intermediate) result is in the
+ proper range. Integer values must not exceed |infinity| ($2^{31}-1$) in
+ absolute value, dimensions must not exceed |max_dimen| ($2^{30}-1$). We avoid
+ the absolute value of an integer, because this might fail for the value
+ $-2^{31}$ using 32-bit arithmetic.
+
+*/
+
+/* Clear a number or dimension and set |arith_error|: */
+
+#define num_error(A) do { \
+ arith_error=true; \
+ A=0; \
+} while (0)
+
+/*tex Clear a glue spec and set |arith_error|: */
+
+#define glue_error(A) do { \
+ arith_error=true; \
+ reset_glue_to_zero(A); \
+} while (0)
+
+#define normalize_glue(A) do { \
+ if (stretch(A)==0) stretch_order(A)=normal; \
+ if (shrink(A)==0) shrink_order(A)=normal; \
+} while (0)
+
+/*tex
+
+ Parenthesized subexpressions can be inside expressions, and this nesting has
+ a stack. Seven local variables represent the top of the expression stack: |p|
+ points to pushed-down entries, if any; |l| specifies the type of expression
+ currently beeing evaluated; |e| is the expression so far and |r| is the state
+ of its evaluation; |t| is the term so far and |s| is the state of its
+ evaluation; finally |n| is the numerator for a combined multiplication and
+ division, if any.
+
+*/
+
+#define expr_add_sub(A,B,C) add_or_sub((A),(B),(C),(r==expr_sub))
+#define expr_a(A,B) expr_add_sub((A),(B),max_dimen)
+
+/*tex
+
+ The function |add_or_sub(x,y,max_answer,negative)| computes the sum (for
+ |negative=false|) or difference (for |negative=true|) of |x| and |y|,
+ provided the absolute value of the result does not exceed |max_answer|.
+
+*/
+
+inline static int add_or_sub(int x, int y, int max_answer, boolean negative)
+{
+ int a;
+ if (negative)
+ negate(y);
+ if (x >= 0) {
+ if (y <= max_answer - x)
+ a = x + y;
+ else
+ num_error(a);
+ } else if (y >= -max_answer - x) {
+ a = x + y;
+ } else {
+ num_error(a);
+ }
+ return a;
+}
+
+#define expr_m(A) A = nx_plus_y((A),f,0)
+#define expr_d(A) A=quotient((A),f)
+
+/*tex
+
+ The function |quotient(n,d)| computes the rounded quotient $q=\lfloor
+ n/d+{1\over2}\rfloor$, when $n$ and $d$ are positive.
+
+*/
+
+inline static int quotient(int n, int d)
+{
+ /*tex Should the answer be negated? */
+ boolean negative;
+ /*tex The answer: */
+ int a;
+ if (d == 0) {
+ num_error(a);
+ } else {
+ if (d > 0) {
+ negative = false;
+ } else {
+ negate(d);
+ negative = true;
+ }
+ if (n < 0) {
+ negate(n);
+ negative = !negative;
+ }
+ a = n / d;
+ n = n - a * d;
+ /*tex Avoid certain compiler optimizations! */
+ d = n - d;
+ if (d + n >= 0)
+ incr(a);
+ if (negative)
+ negate(a);
+ }
+ return a;
+}
+
+#define expr_s(A) A=fract((A),n,f,max_dimen)
+
+/*tex
+
+ Finally, the function |fract(x,n,d,max_answer)| computes the integer
+ $q=\lfloor xn/d+{1\over2}\rfloor$, when $x$, $n$, and $d$ are positive and
+ the result does not exceed |max_answer|. We can't use floating point
+ arithmetic since the routine must produce identical results in all cases; and
+ it would be too dangerous to multiply by~|n| and then divide by~|d|, in
+ separate operations, since overflow might well occur. Hence this subroutine
+ simulates double precision arithmetic, somewhat analogous to Metafont's
+ |make_fraction| and |take_fraction| routines.
+
+*/
+
+int fract(int x, int n, int d, int max_answer)
+{
+ /*tex should the answer be negated? */
+ boolean negative;
+ /*tex the answer */
+ int a;
+ /*tex a proper fraction */
+ int f;
+ /*tex smallest integer such that |2*h>=d| */
+ int h;
+ /*tex intermediate remainder */
+ int r;
+ /*tex temp variable */
+ int t;
+ if (d == 0)
+ goto TOO_BIG;
+ a = 0;
+ if (d > 0) {
+ negative = false;
+ } else {
+ negate(d);
+ negative = true;
+ }
+ if (x < 0) {
+ negate(x);
+ negative = !negative;
+ } else if (x == 0) {
+ goto DONE;
+ }
+ if (n < 0) {
+ negate(n);
+ negative = !negative;
+ }
+ t = n / d;
+ if (t > max_answer / x)
+ goto TOO_BIG;
+ a = t * x;
+ n = n - t * d;
+ if (n == 0)
+ goto FOUND;
+ t = x / d;
+ if (t > (max_answer - a) / n)
+ goto TOO_BIG;
+ a = a + t * n;
+ x = x - t * d;
+ if (x == 0)
+ goto FOUND;
+ if (x < n) {
+ t = x;
+ x = n;
+ n = t;
+ }
+ /*tex
+
+ Now |0<n<=x<d| and we compute $f=\lfloor xn/d+{1\over2}\rfloor$. The loop
+ here preserves the following invariant relations between |f|, |x|, |n|,
+ and~|r|: (i)~$f+\lfloor(xn+(r+d))/d\rfloor=\lfloor
+ x_0n_0/d+{1\over2}\rfloor$; (ii)~|-d<=r<0<n<=x<d|, where $x_0$, $n_0$ are
+ the original values of~$x$ and $n$.
+
+ Notice that the computation specifies |(x-d)+x| instead of |(x+x)-d|,
+ because the latter could overflow.
+
+ */
+ f = 0;
+ r = (d / 2) - d;
+ h = -r;
+ while (1) {
+ if (odd(n)) {
+ r = r + x;
+ if (r >= 0) {
+ r = r - d;
+ incr(f);
+ }
+ }
+ n = n / 2;
+ if (n == 0)
+ break;
+ if (x < h) {
+ x = x + x;
+ } else {
+ t = x - d;
+ x = t + x;
+ f = f + n;
+ if (x < n) {
+ if (x == 0)
+ break;
+ t = x;
+ x = n;
+ n = t;
+ }
+ }
+ }
+ if (f > (max_answer - a))
+ goto TOO_BIG;
+ a = a + f;
+ FOUND:
+ if (negative)
+ negate(a);
+ goto DONE;
+ TOO_BIG:
+ num_error(a);
+ DONE:
+ return a;
+}
+
+/*tex Scans and evaluates an expression: */
+
+static void scan_expr(void)
+{
+ /*tex saved values of |arith_error| */
+ boolean a, b;
+ /*tex type of expression */
+ int l;
+ /*tex state of expression so far */
+ int r;
+ /*tex state of term so far */
+ int s;
+ /*tex next operation or type of next factor */
+ int o;
+ /*tex expression so far */
+ int e;
+ /*tex term so far */
+ int t;
+ /*tex current factor */
+ int f;
+ /*tex numerator of combined multiplication and division */
+ int n;
+ /*tex top of expression stack */
+ halfword p;
+ /*tex for stack manipulations */
+ halfword q;
+ l = cur_val_level;
+ a = arith_error;
+ b = false;
+ p = null;
+ /*tex Scan and evaluate an expression |e| of type |l|. */
+ RESTART:
+ r = expr_none;
+ e = 0;
+ s = expr_none;
+ t = 0;
+ n = 0;
+ CONTINUE:
+ if (s == expr_none)
+ o = l;
+ else
+ o = int_val_level;
+ /*tex
+
+ Scan a factor |f| of type |o| or start a subexpression. Get the next
+ non-blank non-call token.
+
+ */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+
+ if (cur_tok == other_token + '(') {
+ /*tex Push the expression stack and |goto restart|. */
+ q = new_node(expr_node, 0);
+ vlink(q) = p;
+ expr_type(q) = (quarterword) l;
+ expr_state(q) = (quarterword) (4 * s + r);
+ expr_e_field(q) = e;
+ expr_t_field(q) = t;
+ expr_n_field(q) = n;
+ p = q;
+ l = o;
+ goto RESTART;
+ }
+ back_input();
+ if ((o == int_val_level) || (o == attr_val_level))
+ scan_int();
+ else if (o == dimen_val_level)
+ scan_normal_dimen();
+ else if (o == glue_val_level)
+ scan_normal_glue();
+ else
+ scan_mu_glue();
+ f = cur_val;
+
+ FOUND:
+ /*tex
+
+ Scan the next operator and set |o| and Get the next non-blank non-call
+ token.
+
+ */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+
+ if (cur_tok == other_token + '+') {
+ o = expr_add;
+ } else if (cur_tok == other_token + '-') {
+ o = expr_sub;
+ } else if (cur_tok == other_token + '*') {
+ o = expr_mult;
+ } else if (cur_tok == other_token + '/') {
+ o = expr_div;
+ } else {
+ o = expr_none;
+ if (p == null) {
+ if (cur_cmd != relax_cmd)
+ back_input();
+ } else if (cur_tok != other_token + ')') {
+ print_err("Missing ) inserted for expression");
+ help1("I was expecting to see `+', `-', `*', `/', or `)'. Didn't.");
+ back_error();
+ }
+ }
+ arith_error = b;
+ /*tex Make sure that |f| is in the proper range. */
+ if (((l == int_val_level) || (l == attr_val_level)) || (s > expr_sub)) {
+ if ((f > infinity) || (f < -infinity))
+ num_error(f);
+ } else if (l == dimen_val_level) {
+ if (abs(f) > max_dimen)
+ num_error(f);
+ } else {
+ if ((abs(width(f)) > max_dimen) || (abs(stretch(f)) > max_dimen) || (abs(shrink(f)) > max_dimen))
+ glue_error(f);
+ }
+ /*tex Cases for evaluation of the current term. */
+ switch (s) {
+ case expr_none:
+ /*tex
+
+ Applying the factor |f| to the partial term |t| (with the
+ operator |s|) is delayed until the next operator |o| has been
+ scanned. Here we handle the first factor of a partial term. A
+ glue spec has to be copied unless the next operator is a right
+ parenthesis; this allows us later on to simply modify the glue
+ components.
+
+ */
+ t = f;
+ if ((l >= glue_val_level) && (o != expr_none)) {
+ /*tex Do we really need to copy here? */
+ normalize_glue(t);
+ } else {
+ t = f;
+ }
+ break;
+ case expr_mult:
+ /*tex
+
+ If a multiplication is followed by a division, the two operations
+ are combined into a `scaling' operation. Otherwise the term |t|
+ is multiplied by the factor |f|.
+
+ */
+ if (o == expr_div) {
+ n = f;
+ o = expr_scale;
+ } else if ((l == int_val_level) || (l == attr_val_level)) {
+ t = mult_integers(t, f);
+ } else if (l == dimen_val_level) {
+ expr_m(t);
+ } else {
+ expr_m(width(t));
+ expr_m(stretch(t));
+ expr_m(shrink(t));
+ }
+ break;
+ case expr_div:
+ /*tex Here we divide the term |t| by the factor |f|. */
+ if (l < glue_val_level) {
+ expr_d(t);
+ } else {
+ expr_d(width(t));
+ expr_d(stretch(t));
+ expr_d(shrink(t));
+ }
+ break;
+ case expr_scale:
+ /*tex Here the term |t| is multiplied by the quotient $n/f$. */
+ if ((l == int_val_level) || (l == attr_val_level)) {
+ t = fract(t, n, f, infinity);
+ } else if (l == dimen_val_level) {
+ expr_s(t);
+ } else {
+ expr_s(width(t));
+ expr_s(stretch(t));
+ expr_s(shrink(t));
+ }
+ break;
+ }
+ if (o > expr_sub) {
+ s = o;
+ } else {
+ /*tex
+
+ Evaluate the current expression. When a term |t| has been completed
+ it is copied to, added to, or subtracted from the expression |e|.
+
+ */
+ s = expr_none;
+ if (r == expr_none) {
+ e = t;
+ } else if ((l == int_val_level) || (l == attr_val_level)) {
+ e = expr_add_sub(e, t, infinity);
+ } else if (l == dimen_val_level) {
+ e = expr_a(e, t);
+ } else {
+ /*tex
+
+ Compute the sum or difference of two glue specs. We know that
+ |stretch_order(e)>normal| implies |stretch(e)<>0| and
+ |shrink_order(e)>normal| implies |shrink(e)<>0|.
+
+ */
+ width(e) = expr_a(width(e), width(t));
+ if (stretch_order(e) == stretch_order(t)) {
+ stretch(e) = expr_a(stretch(e), stretch(t));
+ } else if ((stretch_order(e) < stretch_order(t)) && (stretch(t) != 0)) {
+ stretch(e) = stretch(t);
+ stretch_order(e) = stretch_order(t);
+ }
+ if (shrink_order(e) == shrink_order(t)) {
+ shrink(e) = expr_a(shrink(e), shrink(t));
+ } else if ((shrink_order(e) < shrink_order(t)) && (shrink(t) != 0)) {
+ shrink(e) = shrink(t);
+ shrink_order(e) = shrink_order(t);
+ }
+ flush_node(t);
+ normalize_glue(e);
+ }
+ r = o;
+ }
+ b = arith_error;
+ if (o != expr_none)
+ goto CONTINUE;
+ if (p != null) {
+ /*tex Pop the expression stack and |goto found|. */
+ f = e;
+ q = p;
+ e = expr_e_field(q);
+ t = expr_t_field(q);
+ n = expr_n_field(q);
+ s = expr_state(q) / 4;
+ r = expr_state(q) % 4;
+ l = expr_type(q);
+ p = vlink(q);
+ flush_node(q);
+ goto FOUND;
+ }
+
+ if (b) {
+ print_err("Arithmetic overflow");
+ help2(
+ "I can't evaluate this expression,",
+ "since the result is out of range."
+ );
+ error();
+ if (l >= glue_val_level) {
+ reset_glue_to_zero(e);
+ } else {
+ e = 0;
+ }
+ }
+ arith_error = a;
+ cur_val = e;
+ cur_val_level = l;
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/scanning.w b/Build/source/texk/web2c/luatexdir/tex/scanning.w
deleted file mode 100644
index 7bed4d29016..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/scanning.w
+++ /dev/null
@@ -1,2621 +0,0 @@
-% scanning.w
-%
-% Copyright 2009-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"
-
-@ @c
-static void scan_expr(void);
-
-@ Let's turn now to some procedures that \TeX\ calls upon frequently to digest
-certain kinds of patterns in the input. Most of these are quite simple;
-some are quite elaborate. Almost all of the routines call |get_x_token|,
-which can cause them to be invoked recursively.
-
-The |scan_left_brace| routine is called when a left brace is supposed to be
-the next non-blank token. (The term ``left brace'' means, more precisely,
-a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to
-appear before the |left_brace|.
-
-@c
-void scan_left_brace(void)
-{ /* reads a mandatory |left_brace| */
- /* Get the next non-blank non-relax non-call token */
- do {
- get_x_token();
- } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
-
- if (cur_cmd != left_brace_cmd) {
- print_err("Missing { inserted");
- help4("A left brace was mandatory here, so I've put one in.",
- "You might want to delete and/or insert some corrections",
- "so that I will find a matching right brace soon.",
- "If you're confused by all this, try typing `I}' now.");
- back_error();
- cur_tok = left_brace_token + '{';
- cur_cmd = left_brace_cmd;
- cur_chr = '{';
- incr(align_state);
- }
-}
-
-@ The |scan_optional_equals| routine looks for an optional `\.=' sign preceded
-by optional spaces; `\.{\\relax}' is not ignored here.
-
-@c
-void scan_optional_equals(void)
-{
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok != other_token + '=')
- back_input();
-}
-
-@ Here is a procedure that sounds an alarm when mu and non-mu units
-are being switched.
-
-@c
-static void mu_error(void)
-{
- print_err("Incompatible glue units");
- help1("I'm going to assume that 1mu=1pt when they're mixed.");
- error();
-}
-
-@ The next routine `|scan_something_internal|' is used to fetch internal
-numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}'
-when expanding constructions like `\.{\\the\\toks0}' and
-`\.{\\the\\baselineskip}'. Soon we will be considering the |scan_int|
-procedure, which calls |scan_something_internal|; on the other hand,
-|scan_something_internal| also calls |scan_int|, for constructions like
-`\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we
-have to declare |scan_int| as a |forward| procedure. A few other
-procedures are also declared at this point.
-
-\TeX\ doesn't know exactly what to expect when
-|scan_something_internal| begins. For example, an integer or
-dimension or glue value could occur immediately after `\.{\\hskip}';
-and one can even say \.{\\the} with respect to token lists in
-constructions like `\.{\\xdef\\o\{\\the\\output\}}'. On the other
-hand, only integers are allowed after a construction like
-`\.{\\count}'. To handle the various possibilities,
-|scan_something_internal| has a |level| parameter, which tells the
-``highest'' kind of quantity that |scan_something_internal| is allowed
-to produce. Eight levels are distinguished, namely |int_val|,
-|attr_val|, |dimen_val|, |glue_val|, |mu_val|, |dir_val|, |ident_val|,
-and |tok_val|.
-
-The output of |scan_something_internal| (and of the other routines
-|scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global
-variable |cur_val|, and its level is put into |cur_val_level|. The highest
-values of |cur_val_level| are special: |mu_val| is used only when
-|cur_val| points to something in a ``muskip'' register, or to one of the
-three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip};
-|ident_val| is used only when |cur_val| points to a font identifier;
-|tok_val| is used only when |cur_val| points to |null| or to the reference
-count of a token list. The last two cases are allowed only when
-|scan_something_internal| is called with |level=tok_val|.
-
-If the output is glue, |cur_val| will point to a glue specification, and
-the reference count of that glue will have been updated to reflect this
-reference; if the output is a nonempty token list, |cur_val| will point to
-its reference count, but in this case the count will not have been updated.
-Otherwise |cur_val| will contain the integer or scaled value in question.
-
-@c
-int cur_val; /* value returned by numeric scanners */
-int cur_val1; /* delcodes are sometimes 51 digits */
-int cur_val_level; /* the ``level'' of this value */
-
-#define scanned_result(A,B) do { \
- cur_val=A; \
- cur_val_level=B; \
-} while (0)
-
-@ When a |glue_val| changes to a |dimen_val|, we use the width component
-of the glue; there is no need to decrease the reference count, since it
-has not yet been increased. When a |dimen_val| changes to an |int_val|,
-we use scaled points so that the value doesn't actually change. And when a
-|mu_val| changes to a |glue_val|, the value doesn't change either.
-
-@c
-static void downgrade_cur_val(boolean delete_glue)
-{
- if (cur_val_level == glue_val_level) {
- halfword m = cur_val;
- cur_val = width(m);
- if (delete_glue)
- flush_node(m);
- } else if (cur_val_level == mu_val_level) {
- mu_error();
- }
- decr(cur_val_level);
-}
-
-/*
-void negate_cur_val(boolean delete_glue)
-{
- if (cur_val_level >= glue_val_level) {
- halfword m = cur_val;
- cur_val = new_spec(m);
- if (delete_glue)
- flush_node(m);
- negate(width(cur_val));
- negate(stretch(cur_val));
- negate(shrink(cur_val));
- } else {
- negate(cur_val);
- }
-}
-*/
-
-void negate_cur_val(boolean modify_glue)
-{
- if (cur_val_level >= glue_val_level) {
- if (modify_glue) {
- /* we modify in-place */
- } else {
- cur_val = new_spec(cur_val);
- }
- negate(width(cur_val));
- negate(stretch(cur_val));
- negate(shrink(cur_val));
- } else {
- negate(cur_val);
- }
-}
-
-@ Some of the internal items can be fetched both routines,
-and these have been split off into the next routine, that
-returns true if the command code was understood
-
-@c
-static boolean short_scan_something_internal(int cmd, int chr, int level,
- boolean negative)
-{
- halfword m; /* |chr_code| part of the operand token */
- halfword q; /* general purpose index */
- int p; /* index into |nest| */
- int save_cur_chr;
- boolean succeeded = true;
- m = chr;
- switch (cmd) {
- case assign_toks_cmd:
- scanned_result(equiv(m), tok_val_level);
- break;
- case assign_int_cmd:
- scanned_result(eqtb[m].cint, int_val_level);
- break;
- case assign_attr_cmd:
- scanned_result(eqtb[m].cint, int_val_level);
- break;
- case assign_dir_cmd:
- if (m == (int_base + line_direction_code)) {
- m = int_base + text_direction_code;
- }
- scanned_result(eqtb[m].cint, dir_val_level);
- break;
- case assign_dimen_cmd:
- scanned_result(eqtb[m].cint, dimen_val_level);
- break;
- case assign_glue_cmd:
- scanned_result(equiv(m), glue_val_level);
- break;
- case assign_mu_glue_cmd:
- scanned_result(equiv(m), mu_val_level);
- break;
- case math_style_cmd:
- scanned_result(m, int_val_level);
- break;
- case set_aux_cmd:
- /* Fetch the |space_factor| or the |prev_depth| */
- if (abs(cur_list.mode_field) != m) {
- print_err("Improper ");
- print_cmd_chr(set_aux_cmd, m);
- help4("You can refer to \\spacefactor only in horizontal mode;",
- "you can refer to \\prevdepth only in vertical mode; and",
- "neither of these is meaningful inside \\write. So",
- "I'm forgetting what you said and using zero instead.");
- error();
- if (level != tok_val_level)
- scanned_result(0, dimen_val_level);
- else
- scanned_result(0, int_val_level);
- } else if (m == vmode) {
- scanned_result(prev_depth_par, dimen_val_level);
- } else {
- scanned_result(space_factor_par, int_val_level);
- }
- break;
- case set_prev_graf_cmd:
- /* Fetch the |prev_graf| */
- if (cur_list.mode_field == 0) {
- scanned_result(0, int_val_level); /* |prev_graf=0| within \.{\\write} */
- } else {
- p = nest_ptr;
- while (abs(nest[p].mode_field) != vmode)
- decr(p);
- scanned_result(nest[p].pg_field, int_val_level);
- }
- break;
- case set_page_int_cmd:
- /* Fetch the |dead_cycles| or the |insert_penalties| */
- if (m == 0)
- cur_val = dead_cycles;
- else if (m == 2)
- cur_val = interaction; /* interactionmode */
- else
- cur_val = insert_penalties;
- cur_val_level = int_val_level;
- break;
- case set_page_dimen_cmd:
- /* Fetch something on the |page_so_far| */
- if ((page_contents == empty) && (!output_active)) {
- if (m == 0)
- cur_val = max_dimen;
- else
- cur_val = 0;
- } else {
- cur_val = page_so_far[m];
- }
- cur_val_level = dimen_val_level;
- break;
- case set_tex_shape_cmd:
- /* Fetch the |par_shape| size */
- if (par_shape_par_ptr == null)
- cur_val = 0;
- else
- cur_val = vinfo(par_shape_par_ptr + 1);
- cur_val_level = int_val_level;
- break;
- case set_etex_shape_cmd:
- /* Fetch a penalties array element */
- scan_int();
- if ((equiv(m) == null) || (cur_val < 0)) {
- cur_val = 0;
- } else {
- if (cur_val > penalty(equiv(m)))
- cur_val = penalty(equiv(m));
- cur_val = penalty(equiv(m) + cur_val);
- }
- cur_val_level = int_val_level;
- break;
- case char_given_cmd:
- case math_given_cmd:
- case xmath_given_cmd:
- scanned_result(cur_chr, int_val_level);
- break;
- case last_item_cmd:
- /* Because the items in this case directly refer to |cur_chr|,
- it needs to be saved and restored */
- save_cur_chr = cur_chr;
- cur_chr = chr;
- /* Fetch an item in the current node, if appropriate */
- /* Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\ } are
- implemented. The reference count for \.{\\lastskip} will be updated later.
-
- We also handle \.{\\inputlineno} and \.{\\badness} here, because they are
- legal in similar contexts. */
-
- if (m >= input_line_no_code) {
- if (m >= eTeX_glue) {
- /* Process an expression and |return| */
- if (m < eTeX_mu) {
- switch (m) {
- case mu_to_glue_code:
- scan_mu_glue();
- break;
- }; /* there are no other cases */
- cur_val_level = glue_val_level;
- } else if (m < eTeX_expr) {
- switch (m) {
- case glue_to_mu_code:
- scan_normal_glue();
- break;
- } /* there are no other cases */
- cur_val_level = mu_val_level;
- } else {
- cur_val_level = m - eTeX_expr + int_val_level;
- scan_expr();
- }
- /* This code for reducing |cur_val_level| and\slash or negating the
- result is similar to the one for all the other cases of
- |scan_something_internal|; we free a glue_spec when needed.
- */
- while (cur_val_level > level) {
- downgrade_cur_val(true);
- }
- if (negative) {
- /*
- we get a new glue spec node with negated values and the old
- intermediate is deleted
- */
- negate_cur_val(true);
- }
- return succeeded;
-
- } else if (m >= eTeX_dim) {
- switch (m) {
- case font_char_wd_code:
- case font_char_ht_code:
- case font_char_dp_code:
- case font_char_ic_code:
- scan_font_ident();
- q = cur_val;
- scan_char_num();
- if (char_exists(q, cur_val)) {
- switch (m) {
- case font_char_wd_code:
- cur_val = char_width(q, cur_val);
- break;
- case font_char_ht_code:
- cur_val = char_height(q, cur_val);
- break;
- case font_char_dp_code:
- cur_val = char_depth(q, cur_val);
- break;
- case font_char_ic_code:
- cur_val = char_italic(q, cur_val);
- break;
- } /* there are no other cases */
- } else {
- cur_val = 0;
- }
- break;
- case par_shape_length_code:
- case par_shape_indent_code:
- case par_shape_dimen_code:
- q = cur_chr - par_shape_length_code;
- scan_int();
- if ((par_shape_par_ptr == null) || (cur_val <= 0)) {
- cur_val = 0;
- } else {
- if (q == 2) {
- q = cur_val % 2;
- cur_val = (cur_val + q) / 2;
- }
- if (cur_val > vinfo(par_shape_par_ptr + 1))
- cur_val = vinfo(par_shape_par_ptr + 1);
- cur_val =
- varmem[par_shape_par_ptr + 2 * cur_val - q + 1].cint;
- }
- cur_val_level = dimen_val_level;
- break;
- case glue_stretch_code:
- case glue_shrink_code:
- scan_normal_glue();
- q = cur_val;
- if (m == glue_stretch_code)
- cur_val = stretch(q);
- else
- cur_val = shrink(q);
- flush_node(q);
- break;
- } /* there are no other cases */
- cur_val_level = dimen_val_level;
- } else {
- switch (m) {
- case input_line_no_code:
- cur_val = line;
- break;
- case badness_code:
- cur_val = last_badness;
- break;
- case luatex_version_code:
- cur_val = get_luatexversion();
- break;
- case last_saved_box_resource_index_code:
- cur_val = last_saved_box_index;
- break;
- case last_saved_image_resource_index_code:
- cur_val = last_saved_image_index;
- break;
- case last_saved_image_resource_pages_code:
- cur_val = last_saved_image_pages;
- break;
- case last_x_pos_code:
- cur_val = last_position.h;
- break;
- case last_y_pos_code:
- cur_val = last_position.v;
- break;
- case random_seed_code:
- cur_val = random_seed;
- break;
- case eTeX_version_code:
- cur_val = eTeX_version;
- break;
- case eTeX_minor_version_code:
- cur_val = eTeX_minor_version;
- break;
- case current_group_level_code:
- cur_val = cur_level - level_one;
- break;
- case current_group_type_code:
- cur_val = cur_group;
- break;
- case current_if_level_code:
- q = cond_ptr;
- cur_val = 0;
- while (q != null) {
- incr(cur_val);
- q = vlink(q);
- }
- break;
- case current_if_type_code:
- if (cond_ptr == null)
- cur_val = 0;
- else if (cur_if < unless_code)
- cur_val = cur_if + 1;
- else
- cur_val = -(cur_if - unless_code + 1);
- break;
- case current_if_branch_code:
- if ((if_limit == or_code) || (if_limit == else_code))
- cur_val = 1;
- else if (if_limit == fi_code)
- cur_val = -1;
- else
- cur_val = 0;
- break;
- case glue_stretch_order_code:
- case glue_shrink_order_code:
- scan_normal_glue();
- q = cur_val;
- if (m == glue_stretch_order_code)
- cur_val = stretch_order(q);
- else
- cur_val = shrink_order(q);
- flush_node(q);
- break;
- } /* there are no other cases */
- cur_val_level = int_val_level;
- }
- } else {
- if (cur_chr == glue_val_level)
- cur_val = zero_glue; /* a pointer */
- else
- cur_val = 0;
- if (cur_chr == last_node_type_code) {
- cur_val_level = int_val_level;
- if ((cur_list.tail_field == cur_list.head_field)
- || (cur_list.mode_field == 0))
- cur_val = -1;
- } else {
- cur_val_level = cur_chr; /* assumes identical values */
- }
- if ((cur_list.tail_field != contrib_head) &&
- !is_char_node(cur_list.tail_field) &&
- (cur_list.mode_field != 0)) {
- switch (cur_chr) {
- case lastpenalty_code:
- if (type(cur_list.tail_field) == penalty_node)
- cur_val = penalty(cur_list.tail_field);
- break;
- case lastkern_code:
- if (type(cur_list.tail_field) == kern_node)
- cur_val = width(cur_list.tail_field);
- break;
- case lastskip_code:
- if (type(cur_list.tail_field) == glue_node)
- // cur_val = new_spec(cur_list.tail_field);
- cur_val = cur_list.tail_field;
- if (subtype(cur_list.tail_field) == mu_glue)
- cur_val_level = mu_val_level;
- break;
- case last_node_type_code:
- cur_val = visible_last_node_type(cur_list.tail_field);
- break;
- } /* there are no other cases */
- } else if ((cur_list.mode_field == vmode)
- && (cur_list.tail_field == cur_list.head_field)) {
- switch (cur_chr) {
- case lastpenalty_code:
- cur_val = last_penalty;
- break;
- case lastkern_code:
- cur_val = last_kern;
- break;
- case lastskip_code:
- if (last_glue != max_halfword)
- cur_val = last_glue;
- break;
- case last_node_type_code:
- cur_val = last_node_type;
- break;
- } /* there are no other cases */
- }
- }
- cur_chr = save_cur_chr;
- break;
- default:
- succeeded = false;
- }
- if (succeeded) {
- while (cur_val_level > level) {
- /* Convert |cur_val| to a lower level */
- downgrade_cur_val(false);
- }
- /* Fix the reference count, if any, and negate |cur_val| if |negative| */
- /* If |cur_val| points to a glue specification at this point, the reference
- count for the glue does not yet include the reference by |cur_val|.
- If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
- */
- if (negative) {
- /* we create a new (negated) glue spec and keep the old one */
- negate_cur_val(false);
- } else if ((cur_val_level >= glue_val_level) && (cur_val_level <= mu_val_level)) {
- cur_val = new_spec(cur_val);
- }
- }
- return succeeded;
-}
-
-@ First, here is a short routine that is called from lua code. All
-the real work is delegated to |short_scan_something_internal| that
-is shared between this routine and |scan_something_internal|.
-
-@c
-void scan_something_simple(halfword cmd, halfword subitem)
-{
- /* negative is never true */
- if (!short_scan_something_internal(cmd, subitem, tok_val_level, false)) {
- /* Complain that |texlib| can not do this; give zero result */
- print_err("You can't use `");
- print_cmd_chr((quarterword) cmd, subitem);
- tprint("' as tex library index");
- help1("I'm forgetting what you said and using zero instead.");
- error();
- scanned_result(0, int_val_level);
- }
-}
-
-@ OK, we're ready for |scan_something_internal| itself. A second parameter,
-|negative|, is set |true| if the value that is found should be negated.
-It is assumed that |cur_cmd| and |cur_chr| represent the first token of
-the internal quantity to be scanned; an error will be signalled if
-|cur_cmd<min_internal| or |cur_cmd>max_internal|.
-
-@c
-void scan_something_internal(int level, boolean negative)
-{
- /* fetch an internal parameter */
- halfword m; /* |chr_code| part of the operand token */
- int n, k; /* accumulators */
- RESTART:
- m = cur_chr;
- if (!short_scan_something_internal(cur_cmd, cur_chr, level, negative)) {
- switch (cur_cmd) {
- case def_char_code_cmd:
- /* Fetch a character code from some table */
- scan_char_num();
- if (m == math_code_base) {
- cur_val1 = get_math_code_num(cur_val);
- scanned_result(cur_val1, int_val_level);
- } else if (m == lc_code_base) {
- cur_val1 = get_lc_code(cur_val);
- scanned_result(cur_val1, int_val_level);
- } else if (m == uc_code_base) {
- cur_val1 = get_uc_code(cur_val);
- scanned_result(cur_val1, int_val_level);
- } else if (m == sf_code_base) {
- cur_val1 = get_sf_code(cur_val);
- scanned_result(cur_val1, int_val_level);
- } else if (m == cat_code_base) {
- cur_val1 = get_cat_code(cat_code_table_par, cur_val);
- scanned_result(cur_val1, int_val_level);
- } else {
- confusion("def_char");
- }
- break;
- case def_del_code_cmd:
- case extdef_del_code_cmd: /* bonus */
- /* Fetch a character code from some table */
- scan_char_num();
- cur_val1 = get_del_code_num(cur_val);
- scanned_result(cur_val1, int_val_level);
- break;
- case extdef_math_code_cmd:
- /* Fetch an extended math code table value */
- scan_char_num();
- cur_val1 = get_math_code_num(cur_val);
- scanned_result(cur_val1, int_val_level);
- break;
- case toks_register_cmd:
- case set_font_cmd:
- case def_font_cmd:
- case letterspace_font_cmd:
- case copy_font_cmd:
- /* Fetch a token list or font identifier, provided that |level=tok_val| */
- if (level != tok_val_level) {
- print_err("Missing number, treated as zero");
- help3("A number should have been here; I inserted `0'.",
- "(If you can't figure out why I needed to see a number,",
- "look up `weird error' in the index to The TeXbook.)");
- back_error();
- scanned_result(0, dimen_val_level);
- } else if (cur_cmd == toks_register_cmd) {
- scan_register_num();
- m = toks_base + cur_val;
- scanned_result(equiv(m), tok_val_level);
- } else {
- back_input();
- scan_font_ident();
- scanned_result(font_id_base + cur_val, ident_val_level);
- }
- break;
- case set_font_id_cmd:
- scan_int();
- scanned_result(font_id_base + cur_val, ident_val_level);
- break;
- case def_family_cmd:
- /* Fetch a math font identifier */
- scan_char_num();
- cur_val1 = fam_fnt(cur_val, m);
- scanned_result(font_id_base + cur_val1, ident_val_level);
- break;
- case set_math_param_cmd:
- /* Fetch a math param */
- cur_val1 = cur_chr;
- get_token();
- if (cur_cmd != math_style_cmd) {
- print_err("Missing math style, treated as \\displaystyle");
- help1("A style should have been here; I inserted `\\displaystyle'.");
- cur_val = display_style;
- back_error();
- } else {
- cur_val = cur_chr;
- }
- if (cur_val1 < math_param_first_mu_glue) {
- if (cur_val1 == math_param_radical_degree_raise) {
- cur_val1 = get_math_param(cur_val1, cur_chr);
- scanned_result(cur_val1, int_val_level);
- } else {
- cur_val1 = get_math_param(cur_val1, cur_chr);
- scanned_result(cur_val1, dimen_val_level);
- }
- } else {
- cur_val1 = get_math_param(cur_val1, cur_chr);
- if (cur_val1 == thin_mu_skip_code)
- cur_val1 = thin_mu_skip_par;
- else if (cur_val1 == med_mu_skip_code)
- cur_val1 = med_mu_skip_par;
- else if (cur_val1 == thick_mu_skip_code)
- cur_val1 = thick_mu_skip_par;
- scanned_result(cur_val1, mu_val_level);
- }
- break;
- case assign_box_dir_cmd:
- scan_register_num();
- m = cur_val;
- if (box(m) != null)
- cur_val = box_dir(box(m));
- else
- cur_val = 0;
- cur_val_level = dir_val_level;
- break;
- case set_box_dimen_cmd:
- /* Fetch a box dimension */
- scan_register_num();
- if (box(cur_val) == null)
- cur_val = 0;
- else
- cur_val = varmem[box(cur_val) + m].cint;
- cur_val_level = dimen_val_level;
- break;
- case assign_font_dimen_cmd:
- /* Fetch a font dimension */
- get_font_dimen();
- break;
- case assign_font_int_cmd:
- /* Fetch a font integer */
- scan_font_ident();
- if (m == 0) {
- scanned_result(hyphen_char(cur_val), int_val_level);
- } else if (m == 1) {
- scanned_result(skew_char(cur_val), int_val_level);
- } else if (m == no_lig_code) {
- scanned_result(test_no_ligatures(cur_val), int_val_level);
- } else {
- n = cur_val;
- scan_char_num();
- k = cur_val;
- switch (m) {
- case lp_code_base:
- scanned_result(get_lp_code(n, k), int_val_level);
- break;
- case rp_code_base:
- scanned_result(get_rp_code(n, k), int_val_level);
- break;
- case ef_code_base:
- scanned_result(get_ef_code(n, k), int_val_level);
- break;
- case tag_code:
- scanned_result(get_tag_code(n, k), int_val_level);
- break;
- }
- }
- break;
- case register_cmd:
- /* Fetch a register */
- scan_register_num();
- switch (m) {
- case int_val_level:
- cur_val = count(cur_val);
- break;
- case attr_val_level:
- cur_val = attribute(cur_val);
- break;
- case dimen_val_level:
- cur_val = dimen(cur_val);
- break;
- case glue_val_level:
- cur_val = skip(cur_val);
- break;
- case mu_val_level:
- cur_val = mu_skip(cur_val);
- break;
- } /* there are no other cases */
- cur_val_level = m;
- break;
- case ignore_spaces_cmd: /* trap unexpandable primitives */
- if (cur_chr == 1) {
- /* Reset |cur_tok| for unexpandable primitives, goto restart */
- /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
- an integer or an internal values should have been found. It fetches the
- next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
- primitive value of that token. No expansion takes place, because the
- next token may be all sorts of things. This could trigger further
- expansion creating new errors.
- */
- get_token();
- cur_cs = prim_lookup(cs_text(cur_cs));
- if (cur_cs != undefined_primitive) {
- cur_cmd = get_prim_eq_type(cur_cs);
- cur_chr = get_prim_equiv(cur_cs);
- cur_tok = token_val(cur_cmd, cur_chr);
- } else {
- cur_cmd = relax_cmd;
- cur_chr = 0;
- cur_tok = cs_token_flag + frozen_relax;
- cur_cs = frozen_relax;
- }
- goto RESTART;
- }
- break;
- case hyph_data_cmd:
- switch (cur_chr) {
- case 0:
- case 1:
- goto DEFAULT;
- break;
- case 2:
- cur_val = get_pre_hyphen_char(language_par);
- cur_val_level = int_val_level;
- break;
- case 3:
- cur_val = get_post_hyphen_char(language_par);
- cur_val_level = int_val_level;
- break;
- case 4:
- cur_val = get_pre_exhyphen_char(language_par);
- cur_val_level = int_val_level;
- break;
- case 5:
- cur_val = get_post_exhyphen_char(language_par);
- cur_val_level = int_val_level;
- break;
- case 6:
- cur_val = get_hyphenation_min(language_par);
- cur_val_level = int_val_level;
- break;
- case 7:
- scan_int();
- cur_val = get_hj_code(language_par,cur_val);
- cur_val_level = int_val_level;
- break;
- }
- break;
- default:
- DEFAULT:
- /* Complain that \.{\\the} can not do this; give zero result */
- print_err("You can't use `");
- print_cmd_chr((quarterword) cur_cmd, cur_chr);
- tprint("' after \\the");
- help1("I'm forgetting what you said and using zero instead.");
- error();
- if (level != tok_val_level)
- scanned_result(0, dimen_val_level);
- else
- scanned_result(0, int_val_level);
- break;
- }
- while (cur_val_level > level) {
- /* Convert |cur_val| to a lower level */
- downgrade_cur_val(false);
- }
- /* Fix the reference count, if any, and negate |cur_val| if |negative| */
- /* If |cur_val| points to a glue specification at this point, the reference
- count for the glue does not yet include the reference by |cur_val|.
- If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|.
- */
- if (negative) {
- /* we create a new (negated) glue spec and keep the old one */
- negate_cur_val(false);
- } else if ((cur_val_level >= glue_val_level) && (cur_val_level <= mu_val_level)) {
- cur_val = new_spec(cur_val);
- }
- }
-}
-
-@ It is nice to have routines that say what they do, so the original
-|scan_eight_bit_int| is superceded by |scan_register_num| and
-|scan_mark_num|. It may become split up even further in the future.
-
-Many of the |restricted classes| routines are the essentially
-the same except for the upper limit and the error message, so it makes
-sense to combine these all into one function.
-
-@c
-void scan_limited_int(int max, const char *name)
-{
- char hlp[80];
- scan_int();
- if ((cur_val < 0) || (cur_val > max)) {
- if (name == NULL) {
- snprintf(hlp, 80,
- "Since I expected to read a number between 0 and %d,",
- max);
- print_err("Bad number");
- } else {
- char msg[80];
- snprintf(hlp, 80, "A %s must be between 0 and %d.", name, max);
- snprintf(msg, 80, "Bad %s", name);
- print_err(msg);
- }
- help2(hlp, "I changed this one to zero.");
- int_error(cur_val);
- cur_val = 0;
- }
-}
-
-@ @c
-void scan_fifteen_bit_int(void)
-{
- scan_real_fifteen_bit_int();
- cur_val = ((cur_val / 0x1000) * 0x1000000) +
- (((cur_val % 0x1000) / 0x100) * 0x10000) + (cur_val % 0x100);
-}
-
-@ @c
-void scan_fifty_one_bit_int(void)
-{
- int iiii;
- scan_int();
- if ((cur_val < 0) || (cur_val > 0777777777)) {
- print_err("Bad delimiter code");
- help2
- ("A numeric delimiter (first part) must be between 0 and 2^{27}-1.",
- "I changed this one to zero.");
- int_error(cur_val);
- cur_val = 0;
- }
- iiii = cur_val;
- scan_int();
- if ((cur_val < 0) || (cur_val > 0xFFFFFF)) {
- print_err("Bad delimiter code");
- help2
- ("A numeric delimiter (second part) must be between 0 and 2^{24}-1.",
- "I changed this one to zero.");
- int_error(cur_val);
- cur_val = 0;
- }
- cur_val1 = cur_val;
- cur_val = iiii;
-}
-
-@ An integer number can be preceded by any number of spaces and `\.+' or
-`\.-' signs. Then comes either a decimal constant (i.e., radix 10), an
-octal constant (i.e., radix 8, preceded by~'), a hexadecimal constant
-(radix 16, preceded by~"), an alphabetic constant (preceded by~`), or
-an internal variable. After scanning is complete,
-|cur_val| will contain the answer, which must be at most
-$2^{31}-1=2147483647$ in absolute value. The value of |radix| is set to
-10, 8, or 16 in the cases of decimal, octal, or hexadecimal constants,
-otherwise |radix| is set to zero. An optional space follows a constant.
-
-@c
-int radix; /* |scan_int| sets this to 8, 10, 16, or zero */
-
-@ The |scan_int| routine is used also to scan the integer part of a
- fraction; for example, the `\.3' in `\.{3.14159}' will be found by
- |scan_int|. The |scan_dimen| routine assumes that |cur_tok=point_token|
- after the integer part of such a fraction has been scanned by |scan_int|,
- and that the decimal point has been backed up to be scanned again.
-
-@c
-void scan_int(void)
-{ /* sets |cur_val| to an integer */
- boolean negative; /* should the answer be negated? */
- int m; /* |$2^{31}$ / radix|, the threshold of danger */
- int d; /* the digit just scanned */
- boolean vacuous; /* have no digits appeared? */
- boolean OK_so_far; /* has an error message been issued? */
- radix = 0;
- OK_so_far = true;
- /* Get the next non-blank non-sign token; set |negative| appropriately */
- negative = false;
- do {
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok == other_token + '-') {
- negative = !negative;
- cur_tok = other_token + '+';
- }
- } while (cur_tok == other_token + '+');
-
- RESTART:
- if (cur_tok == alpha_token) {
- /* Scan an alphabetic character code into |cur_val| */
- /* A space is ignored after an alphabetic character constant, so that
- such constants behave like numeric ones. */
- get_token(); /* suppress macro expansion */
- if (cur_tok < cs_token_flag) {
- cur_val = cur_chr;
- if (cur_cmd <= right_brace_cmd) {
- if (cur_cmd == right_brace_cmd)
- incr(align_state);
- else
- decr(align_state);
- }
- } else { /* the value of a csname in this context is its name */
- str_number txt = cs_text(cur_tok - cs_token_flag);
- if (is_active_cs(txt))
- cur_val = active_cs_value(txt);
- else if (single_letter(txt))
- cur_val = pool_to_unichar(str_string(txt));
- else
- cur_val = (biggest_char + 1);
- }
- if (cur_val > biggest_char) {
- print_err("Improper alphabetic constant");
- help2("A one-character control sequence belongs after a ` mark.",
- "So I'm essentially inserting \\0 here.");
- cur_val = '0';
- back_error();
- } else {
- /* Scan an optional space */
- get_x_token();
- if (cur_cmd != spacer_cmd)
- back_input();
- }
-
- } else if (cur_tok == cs_token_flag + frozen_primitive) {
- /* Reset |cur_tok| for unexpandable primitives, goto restart */
- /* This block deals with unexpandable \.{\\primitive} appearing at a spot where
- an integer or an internal values should have been found. It fetches the
- next token then resets |cur_cmd|, |cur_cs|, and |cur_tok|, based on the
- primitive value of that token. No expansion takes place, because the
- next token may be all sorts of things. This could trigger further
- expansion creating new errors.
- */
- get_token();
- cur_cs = prim_lookup(cs_text(cur_cs));
- if (cur_cs != undefined_primitive) {
- cur_cmd = get_prim_eq_type(cur_cs);
- cur_chr = get_prim_equiv(cur_cs);
- cur_tok = token_val(cur_cmd, cur_chr);
- } else {
- cur_cmd = relax_cmd;
- cur_chr = 0;
- cur_tok = cs_token_flag + frozen_relax;
- cur_cs = frozen_relax;
- }
- goto RESTART;
- } else if (cur_cmd == math_style_cmd) {
- cur_val = cur_chr;
- } else if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
- scan_something_internal(int_val_level, false);
- } else {
- /* Scan a numeric constant */
- radix = 10;
- m = 214748364;
- if (cur_tok == octal_token) {
- radix = 8;
- m = 02000000000;
- get_x_token();
- } else if (cur_tok == hex_token) {
- radix = 16;
- m = 01000000000;
- get_x_token();
- }
- vacuous = true;
- cur_val = 0;
- /* Accumulate the constant until |cur_tok| is not a suitable digit */
- while (1) {
- if ((cur_tok < zero_token + radix) && (cur_tok >= zero_token)
- && (cur_tok <= zero_token + 9)) {
- d = cur_tok - zero_token;
- } else if (radix == 16) {
- if ((cur_tok <= A_token + 5) && (cur_tok >= A_token)) {
- d = cur_tok - A_token + 10;
- } else if ((cur_tok <= other_A_token + 5)
- && (cur_tok >= other_A_token)) {
- d = cur_tok - other_A_token + 10;
- } else {
- break;
- }
- } else {
- break;
- }
- vacuous = false;
- if ((cur_val >= m) && ((cur_val > m) || (d > 7) || (radix != 10))) {
- if (OK_so_far) {
- print_err("Number too big");
- help2
- ("I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
- "so I'm using that number instead of yours.");
- error();
- cur_val = infinity;
- OK_so_far = false;
- }
- } else {
- cur_val = cur_val * radix + d;
- }
- get_x_token();
- }
- if (vacuous) {
- /* Express astonishment that no number was here */
- print_err("Missing number, treated as zero");
- help3("A number should have been here; I inserted `0'.",
- "(If you can't figure out why I needed to see a number,",
- "look up `weird error' in the index to The TeXbook.)");
- back_error();
- } else if (cur_cmd != spacer_cmd) {
- back_input();
- }
- }
- if (negative)
- negate(cur_val);
-}
-
-@ The following code is executed when |scan_something_internal| was
-called asking for |mu_val|, when we really wanted a ``mudimen'' instead
-of ``muglue.''
-
-@c
-static void coerce_glue(void)
-{
- int v;
- if (cur_val_level >= glue_val_level) {
- v = width(cur_val);
- flush_node(cur_val);
- cur_val = v;
- }
-}
-
-@ The |scan_dimen| routine is similar to |scan_int|, but it sets |cur_val| to
-a |scaled| value, i.e., an integral number of sp. One of its main tasks
-is therefore to interpret the abbreviations for various kinds of units and
-to convert measurements to scaled points.
-
-There are three parameters: |mu| is |true| if the finite units must be
-`\.{mu}', while |mu| is |false| if `\.{mu}' units are disallowed;
-|inf| is |true| if the infinite units `\.{fil}', `\.{fill}', `\.{filll}'
-are permitted; and |shortcut| is |true| if |cur_val| already contains
-an integer and only the units need to be considered.
-
-The order of infinity that was found in the case of infinite glue is returned
-in the global variable |cur_order|.
-
-@c
-int cur_order; /* order of infinity found by |scan_dimen| */
-
-
-@ Constructions like `\.{-\'77 pt}' are legal dimensions, so |scan_dimen|
-may begin with |scan_int|. This explains why it is convenient to use
-|scan_int| also for the integer part of a decimal fraction.
-
-Several branches of |scan_dimen| work with |cur_val| as an integer and
-with an auxiliary fraction |f|, so that the actual quantity of interest is
-$|cur_val|+|f|/2^{16}$. At the end of the routine, this ``unpacked''
-representation is put into the single word |cur_val|, which suddenly
-switches significance from |integer| to |scaled|.
-
-@
-The necessary conversion factors can all be specified exactly as
-fractions whose numerator and denominator add to 32768 or less.
-According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$;
-this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard
-\^{Bosshard, Hans Rudolf}
-in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980).
-The Didot point has been newly standardized in 1978;
-it's now exactly $\rm 1\,nd=0.375\,mm$.
-Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$.
-The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$.
-These would lead to the ratios $21681/20320$ and $65043/5080$,
-respectively.
-The closest approximations supported by the algorithm would be
-$11183/10481$ and $1370/107$. In order to maintain the
-relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for
-$\rm nd$, however.
-
-@c
-
-static void scan_dimen_mu_error(void) {
- print_err("Illegal unit of measure (mu inserted)");
- help4("The unit of measurement in math glue must be mu.",
- "To recover gracefully from this error, it's best to",
- "delete the erroneous units; e.g., type `2' to delete",
- "two letters. (See Chapter 27 of The TeXbook.)");
- error();
-}
-
-static void scan_dimen_unknown_unit_error(void) {
- print_err("Illegal unit of measure (pt inserted)");
- help6("Dimensions can be in units of em, ex, in, pt, pc,",
- "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
- "I'll assume that you meant to say pt, for printer's points.",
- "To recover gracefully from this error, it's best to",
- "delete the erroneous units; e.g., type `2' to delete",
- "two letters. (See Chapter 27 of The TeXbook.)");
- error();
-}
-
-static void scan_dimen_out_of_range_error(void) {
- print_err("Dimension too large");
- help2("I can't work with sizes bigger than about 19 feet.",
- "Continue and I'll use the largest value I can.");
- error();
-}
-
-#define set_conversion(A,B) do { num=(A); denom=(B); } while(0)
-
-/*
- This function sets |cur_val| to a dimension. It could be optimized a bit
- more (but not now, something for luatex > 1).
-*/
-
-void scan_dimen(boolean mu, boolean inf, boolean shortcut)
-{
- boolean negative = false; /* should the answer be negated? */
- boolean is_true = false;
- int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */
- int num = 0; /* conversion ratio for the scanned units */
- int denom = 0;
- halfword q; /* top of decimal digit stack */
- scaled v; /* an internal dimension */
- int save_cur_val; /* temporary storage of |cur_val| */
- arith_error = false;
- cur_order = normal;
- if (!shortcut) {
- /* Get the next non-blank non-sign... */
- do {
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok == other_token + '-') {
- negative = !negative;
- cur_tok = other_token + '+';
- }
- } while (cur_tok == other_token + '+');
- if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
- /* Fetch an internal dimension and |goto attach_sign|, or fetch an internal integer */
- if (mu) {
- scan_something_internal(mu_val_level, false);
- coerce_glue();
- if (cur_val_level == mu_val_level) {
- goto ATTACH_SIGN;
- } else if (cur_val_level != int_val_level) {
- mu_error();
- }
- } else {
- scan_something_internal(dimen_val_level, false);
- if (cur_val_level == dimen_val_level) {
- goto ATTACH_SIGN;
- }
- }
- } else {
- back_input();
- if (cur_tok == continental_point_token) {
- cur_tok = point_token;
- }
- if (cur_tok != point_token) {
- scan_int();
- } else {
- radix = 10;
- cur_val = 0;
- }
- if (cur_tok == continental_point_token) {
- cur_tok = point_token;
- }
- if ((radix == 10) && (cur_tok == point_token)) {
- /*
- Scan decimal fraction. When the following code is executed, we have
- |cur_tok=point_token|, but this token has been backed up using |back_input|;
- we must first discard it. It turns out that a decimal point all by itself
- is equivalent to `\.{0.0}'. Let's hope people don't use that fact.
- */
- int k = 0;
- halfword p = null;
- int kk;
- get_token(); /* |point_token| is being re-scanned */
- while (1) {
- get_x_token();
- if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
- break;
- if (k < 17) {
- /* digits for |k>=17| cannot affect the result */
- q = get_avail();
- set_token_link(q, p);
- set_token_info(q, cur_tok - zero_token);
- p = q;
- incr(k);
- }
- }
- for (kk = k; kk >= 1; kk--) {
- dig[kk - 1] = token_info(p);
- q = p;
- p = token_link(p);
- free_avail(q);
- }
- f = round_decimals(k);
- if (cur_cmd != spacer_cmd) {
- back_input();
- }
- }
- }
- }
- if (cur_val < 0) {
- /* in this case |f=0| */
- negative = !negative;
- negate(cur_val);
- }
- /*
- Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
- are |x| sp per unit; |goto attach_sign| if the units are internal. Now comes
- the harder part: At this point in the program, |cur_val| is a nonnegative
- integer and $f/2^{16}$ is a nonnegative fraction less than 1; we want to
- multiply the sum of these two quantities by the appropriate factor, based
- on the specified units, in order to produce a |scaled| result, and we want
- to do the calculation with fixed point arithmetic that does not overflow.
- */
- if (inf) {
- /*
- Scan for (f)\.{fil} units; |goto attach_fraction| if found. In traditional
- \TeX, a specification like `\.{filllll}' or `\.{fill L L L}' will lead to
- two error messages (one for each additional keyword \.{"l"}). Not so for
- \LuaTeX, it just parses the construct in reverse.
-
- if (scan_keyword("filll")) {
- cur_order = filll;
- goto ATTACH_FRACTION;
- } else if (scan_keyword("fill")) {
- cur_order = fill;
- goto ATTACH_FRACTION;
- } else if (scan_keyword("fil")) {
- cur_order = fil;
- goto ATTACH_FRACTION;
- } else if (scan_keyword("fi")) {
- cur_order = sfi;
- goto ATTACH_FRACTION;
- }
-
- But ... it failed in alignments so now we do this. And, as we support an extra
- l we don't issue an error message (we didn't do that anyway).
- */
- if (scan_keyword("fi")) {
- cur_order = sfi;
- if (scan_keyword("l")) {
- cur_order = fil;
- if (scan_keyword("l")) {
- cur_order = fill;
- if (scan_keyword("l")) {
- cur_order = filll;
- }
- }
- }
- goto ATTACH_FRACTION;
- }
- }
- /*
- Scan for (u)units that are internal dimensions; |goto attach_sign| with
- |cur_val| set if found
- */
- save_cur_val = cur_val;
- /* Get the next non-blank non-call... a pitty if just backed up the input */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
-
- if ((cur_cmd < min_internal_cmd) || (cur_cmd > max_internal_cmd)) {
- back_input();
- } else {
- /* math_given_cmd xmath_given_cmd last_item_cmd */
- if (mu) {
- scan_something_internal(mu_val_level, false);
- coerce_glue();
- if (cur_val_level != mu_val_level) {
- mu_error();
- }
- } else {
- scan_something_internal(dimen_val_level, false);
- }
- v = cur_val;
- goto FOUND;
- }
- /* bah ... true forces to split the unit scanner */
- if (mu) {
- /* Scan for (m)\.{mu} units and |goto attach_fraction| */
- if (! scan_keyword("mu")) {
- scan_dimen_mu_error();
- }
- goto ATTACH_FRACTION;
- } else if (scan_keyword("em")) {
- v = quad(get_cur_font());
- } else if (scan_keyword("ex")) {
- v = x_height(get_cur_font());
- } else if (scan_keyword("px")) {
- v = px_dimen_par;
- } else {
- goto PICKUP_UNIT;
- }
- /* Scan an optional space (after em, ex or px) */
- get_x_token();
- if (cur_cmd != spacer_cmd) {
- back_input();
- }
- FOUND:
- cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
- goto ATTACH_SIGN;
- /*
- Scan for (a)all other units and adjust |cur_val| and |f| accordingly;
- |goto done| in the case of scaled points
- */
- PICKUP_UNIT:
- if (scan_keyword("pt")) {
- goto SCALE_VALUE; /* the easy case */
- } else if (scan_keyword("mm")) {
- set_conversion(7227, 2540);
- goto SCALE_VALUE;
- } else if (scan_keyword("cm")) {
- set_conversion(7227, 254);
- goto SCALE_VALUE;
- } else if (scan_keyword("sp")) {
- goto DONE;
- } else if (scan_keyword("bp")) {
- set_conversion(7227, 7200);
- goto SCALE_VALUE;
- } else if (scan_keyword("in")) {
- set_conversion(7227, 100);
- goto SCALE_VALUE;
- } else if (scan_keyword("dd")) {
- set_conversion(1238, 1157);
- goto SCALE_VALUE;
- } else if (scan_keyword("cc")) {
- set_conversion(14856, 1157);
- goto SCALE_VALUE;
- } else if (scan_keyword("pc")) {
- set_conversion(12, 1);
- goto SCALE_VALUE;
- } else if (scan_keyword("nd")) {
- set_conversion(685, 642);
- goto SCALE_VALUE;
- } else if (scan_keyword("nc")) {
- set_conversion(1370, 107);
- goto SCALE_VALUE;
- } else if (!is_true && scan_keyword("true")) {
- is_true = true;
- goto PICKUP_UNIT;
- }
- /* Complain about unknown unit and |goto done2| */
- scan_dimen_unknown_unit_error();
- goto BAD_NEWS;
- SCALE_VALUE:
- /* Adjust (f) for the magnification ratio */
- if (is_true) {
- /* maybe at some point we will drop mag completely, even in dvi mode */
- if (output_mode_used <= OMODE_DVI) {
- prepare_mag();
- if (mag_par != 1000) {
- cur_val = xn_over_d(cur_val, 1000, mag_par);
- f = (1000 * f + 0200000 * tex_remainder) / mag_par;
- cur_val = cur_val + (f / 0200000);
- f = f % 0200000;
- }
- } else {
- /* in pdf mode we're always true */
- one_true_inch = one_inch; /* saveguard */
- }
- }
- /* */
- if (num) {
- cur_val = xn_over_d(cur_val, num, denom);
- f = (num * f + 0200000 * tex_remainder) / denom;
- cur_val = cur_val + (f / 0200000);
- f = f % 0200000;
- }
- BAD_NEWS:
- ATTACH_FRACTION:
- if (cur_val >= 040000) {
- arith_error = true;
- } else {
- cur_val = cur_val * unity + f;
- }
- DONE:
- /* Scan an optional space */ /* happens too often */
- get_x_token();
- if (cur_cmd != spacer_cmd) {
- back_input();
- }
- ATTACH_SIGN:
- if (arith_error || (abs(cur_val) >= 010000000000)) {
- /* Report that this dimension is out of range */
- scan_dimen_out_of_range_error();
- cur_val = max_dimen;
- arith_error = false;
- }
- if (negative) {
- negate(cur_val);
- }
-}
-
-@ The final member of \TeX's value-scanning trio is |scan_glue|, which
-makes |cur_val| point to a glue specification. The reference count of that
-glue spec will take account of the fact that |cur_val| is pointing to~it.
-
-The |level| parameter should be either |glue_val| or |mu_val|.
-
-Since |scan_dimen| was so much more complex than |scan_int|, we might expect
-|scan_glue| to be even worse. But fortunately, it is very simple, since
-most of the work has already been done.
-
-@c
-void scan_glue(int level)
-{
- boolean negative = false; /* should the answer be negated? */
- halfword q = null; /* new glue specification */
- boolean mu = (level == mu_val_level); /* does |level=mu_val|? */
- /* Get the next non-blank non-sign ... */
- do {
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok == other_token + '-') {
- negative = !negative;
- cur_tok = other_token + '+';
- }
- } while (cur_tok == other_token + '+');
- if ((cur_cmd >= min_internal_cmd) && (cur_cmd <= max_internal_cmd)) {
- scan_something_internal(level, negative);
- if (cur_val_level >= glue_val_level) {
- if (cur_val_level != level)
- mu_error();
- return;
- }
- if (cur_val_level == int_val_level)
- scan_dimen(mu, false, true);
- else if (level == mu_val_level)
- mu_error();
- } else {
- back_input();
- scan_dimen(mu, false, false);
- if (negative)
- negate(cur_val);
- }
- /*
- Create a new glue specification whose width is |cur_val|; scan for its
- stretch and shrink components.
- */
- q = new_spec(zero_glue);
- width(q) = cur_val;
- if (scan_keyword("plus")) {
- scan_dimen(mu, true, false);
- stretch(q) = cur_val;
- stretch_order(q) = (quarterword) cur_order;
- }
- if (scan_keyword("minus")) {
- scan_dimen(mu, true, false);
- shrink(q) = cur_val;
- shrink_order(q) = (quarterword) cur_order;
- }
- cur_val = q;
-}
-
-@ This is an omega routine
-@c
-void scan_scaled(void)
-{ /* sets |cur_val| to a scaled value */
- boolean negative; /* should the answer be negated? */
- int f; /* numerator of a fraction whose denominator is $2^{16}$ */
- int k, kk; /* number of digits in a decimal fraction */
- halfword p, q; /* top of decimal digit stack */
- f = 0;
- arith_error = false;
- negative = false;
- /* Get the next non-blank non-sign... */
- do {
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
- if (cur_tok == other_token + '-') {
- negative = !negative;
- cur_tok = other_token + '+';
- }
- } while (cur_tok == other_token + '+');
-
- back_input();
- if (cur_tok == continental_point_token)
- cur_tok = point_token;
- if (cur_tok != point_token) {
- scan_int();
- } else {
- radix = 10;
- cur_val = 0;
- }
- if (cur_tok == continental_point_token)
- cur_tok = point_token;
- if ((radix == 10) && (cur_tok == point_token)) {
- /* Scan decimal fraction */
- /* TODO: merge this with the same block in |scan_dimen| */
- /* When the following code is executed, we have |cur_tok=point_token|, but this
- token has been backed up using |back_input|; we must first discard it.
-
- It turns out that a decimal point all by itself is equivalent to `\.{0.0}'.
- Let's hope people don't use that fact. */
-
- k = 0;
- p = null;
- get_token(); /* |point_token| is being re-scanned */
- while (1) {
- get_x_token();
- if ((cur_tok > zero_token + 9) || (cur_tok < zero_token))
- break;
- if (k < 17) { /* digits for |k>=17| cannot affect the result */
- q = get_avail();
- set_token_link(q, p);
- set_token_info(q, cur_tok - zero_token);
- p = q;
- incr(k);
- }
- }
- for (kk = k; kk >= 1; kk--) {
- dig[kk - 1] = token_info(p);
- q = p;
- p = token_link(p);
- free_avail(q);
- }
- f = round_decimals(k);
- if (cur_cmd != spacer_cmd)
- back_input();
-
- }
- if (cur_val < 0) { /* in this case |f=0| */
- negative = !negative;
- negate(cur_val);
- }
- if (cur_val > 040000)
- arith_error = true;
- else
- cur_val = cur_val * unity + f;
- if (arith_error || (abs(cur_val) >= 010000000000)) {
- print_err("Stack number too large");
- error();
- }
- if (negative)
- negate(cur_val);
-}
-
-@ This procedure is supposed to scan something like `\.{\\skip\\count12}',
-i.e., whatever can follow `\.{\\the}', and it constructs a token list
-containing something like `\.{-3.0pt minus 0.5fill}'.
-
-@c
-halfword the_toks(void)
-{
- int old_setting; /* holds |selector| setting */
- halfword p, q, r; /* used for copying a token list */
- int c; /* value of |cur_chr| */
- str_number s;
- halfword retval;
- /* Handle \.{\\unexpanded} or \.{\\detokenize} and |return| */
- if (odd(cur_chr)) {
- c = cur_chr;
- scan_general_text();
- if (c == 1) {
- return cur_val;
- } else {
- old_setting = selector;
- selector = new_string;
- p = get_avail();
- set_token_link(p, token_link(temp_token_head));
- token_show(p);
- flush_list(p);
- selector = old_setting;
- s = make_string();
- retval = str_toks(str_lstring(s));
- flush_str(s);
- return retval;
- }
- }
- get_x_token();
- scan_something_internal(tok_val_level, false);
- if (cur_val_level >= ident_val_level) {
- /* Copy the token list */
- p = temp_token_head;
- set_token_link(p, null);
- if (cur_val_level == ident_val_level) {
- store_new_token(cs_token_flag + cur_val);
- } else if (cur_val != null) {
- r = token_link(cur_val); /* do not copy the reference count */
- while (r != null) {
- fast_store_new_token(token_info(r));
- r = token_link(r);
- }
- }
- return p;
- } else {
- old_setting = selector;
- selector = new_string;
- switch (cur_val_level) {
- case int_val_level:
- print_int(cur_val);
- break;
- case attr_val_level:
- print_int(cur_val);
- break;
- case dir_val_level:
- print_dir(cur_val);
- break;
- case dimen_val_level:
- print_scaled(cur_val);
- tprint("pt");
- break;
- case glue_val_level:
- print_spec(cur_val, "pt");
- flush_node(cur_val);
- break;
- case mu_val_level:
- print_spec(cur_val, "mu");
- flush_node(cur_val);
- break;
- } /* there are no other cases */
- selector = old_setting;
- s = make_string();
- retval = str_toks(str_lstring(s));
- flush_str(s);
- return retval;
- }
-}
-
-@ @c
-str_number the_scanned_result(void)
-{
- int old_setting; /* holds |selector| setting */
- str_number r; /* return value * */
- old_setting = selector;
- selector = new_string;
- if (cur_val_level >= ident_val_level) {
- if (cur_val != null) {
- show_token_list(token_link(cur_val), null, -1);
- r = make_string();
- } else {
- r = get_nullstr();
- }
- } else {
- switch (cur_val_level) {
- case int_val_level:
- print_int(cur_val);
- break;
- case attr_val_level:
- print_int(cur_val);
- break;
- case dir_val_level:
- print_dir(cur_val);
- break;
- case dimen_val_level:
- print_scaled(cur_val);
- tprint("pt");
- break;
- case glue_val_level:
- print_spec(cur_val, "pt");
- flush_node(cur_val);
- break;
- case mu_val_level:
- print_spec(cur_val, "mu");
- flush_node(cur_val);
- break;
- } /* there are no other cases */
- r = make_string();
- }
- selector = old_setting;
- return r;
-}
-
-@ The following routine is used to implement `\.{\\fontdimen} |n| |f|'.
-The boolean parameter |writing| is set |true| if the calling program
-intends to change the parameter value.
-
-@c
-static void font_param_error(int f)
-{
- print_err("Font ");
- print_esc(font_id_text(f));
- tprint(" has only ");
- print_int(font_params(f));
- tprint(" fontdimen parameters");
- help2("To increase the number of font parameters, you must",
- "use \\fontdimen immediately after the \\font is loaded.");
- error();
-}
-
-void set_font_dimen(void)
-{
- internal_font_number f;
- int n; /* the parameter number */
- scan_int();
- n = cur_val;
- scan_font_ident();
- f = cur_val;
- if (n <= 0) {
- font_param_error(f);
- } else {
- if (n > font_params(f)) {
- if (font_used(f)) {
- font_param_error(f);
- } else {
- /* Increase the number of parameters in the font */
- do {
- set_font_param(f, (font_params(f) + 1), 0);
- } while (n != font_params(f));
- }
- }
- }
- scan_optional_equals();
- scan_normal_dimen();
- set_font_param(f, n, cur_val);
-}
-
-void get_font_dimen(void)
-{
- internal_font_number f;
- int n; /* the parameter number */
- scan_int();
- n = cur_val;
- scan_font_ident();
- f = cur_val;
- cur_val = 0; /* initialize return value */
- if (n <= 0) {
- font_param_error(f);
- goto EXIT;
- } else {
- if (n > font_params(f)) {
- if (font_used(f)) {
- font_param_error(f);
- goto EXIT;
- } else {
- /* Increase the number of parameters in the font */
- do {
- set_font_param(f, (font_params(f) + 1), 0);
- } while (n != font_params(f));
-
- }
- }
- }
- cur_val = font_param(f, n);
- EXIT:
- scanned_result(cur_val, dimen_val_level);
-}
-
-@ Here's a similar procedure that returns a pointer to a rule node. This
-routine is called just after \TeX\ has seen \.{\\hrule} or \.{\\vrule};
-therefore |cur_cmd| will be either |hrule| or |vrule|. The idea is to store
-the default rule dimensions in the node, then to override them if
-`\.{height}' or `\.{width}' or `\.{depth}' specifications are
-found (in any order).
-
-@c
-halfword scan_rule_spec(void)
-{
- /* |width|, |depth|, and |height| all equal |null_flag| now */
- halfword q;
- if (cur_cmd == no_vrule_cmd) {
- q = new_rule(empty_rule);
- cur_cmd = vrule_cmd;
- } else if (cur_cmd == no_hrule_cmd) {
- q = new_rule(empty_rule);
- cur_cmd = hrule_cmd;
- } else {
- q = new_rule(normal_rule);
- }
- if (cur_cmd == vrule_cmd) {
- width(q) = default_rule;
- rule_dir(q) = body_direction_par;
- } else {
- height(q) = default_rule;
- depth(q) = 0;
- rule_dir(q) = text_direction_par;
- }
- RESWITCH:
- if (scan_keyword("width")) {
- scan_normal_dimen();
- width(q) = cur_val;
- goto RESWITCH;
- }
- if (scan_keyword("height")) {
- scan_normal_dimen();
- height(q) = cur_val;
- goto RESWITCH;
- }
- if (scan_keyword("depth")) {
- scan_normal_dimen();
- depth(q) = cur_val;
- goto RESWITCH;
- }
- return q;
-}
-
-
-@ Declare procedures that scan font-related stuff
-
-@c
-void scan_font_ident(void)
-{
- internal_font_number f;
- halfword m;
- /* Get the next non-blank non-call... */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
-
- if ((cur_cmd == def_font_cmd) || (cur_cmd == letterspace_font_cmd) || (cur_cmd == copy_font_cmd)) {
- f = get_cur_font();
- } else if (cur_cmd == set_font_cmd) {
- f = cur_chr;
- set_font_touched(f, 1);
- } else if (cur_cmd == def_family_cmd) {
- m = cur_chr;
- scan_math_family_int();
- f = fam_fnt(cur_val, m);
- set_font_touched(f, 1);
- } else {
- print_err("Missing font identifier");
- help2("I was looking for a control sequence whose",
- "current meaning has been defined by \\font.");
- back_error();
- f = null_font;
- }
- cur_val = f;
-}
-
-@ The |scan_general_text| procedure is much like |scan_toks(false,false)|,
-but will be invoked via |expand|, i.e., recursively.
-
-The token list (balanced text) created by |scan_general_text| begins
-at |link(temp_token_head)| and ends at |cur_val|. (If |cur_val=temp_token_head|,
-the list is empty.)
-
-@c
-void scan_general_text(void)
-{
- int s; /* to save |scanner_status| */
- halfword w; /* to save |warning_index| */
- halfword d; /* to save |def_ref| */
- halfword p; /* tail of the token list being built */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword unbalance; /* number of unmatched left braces */
- s = scanner_status;
- w = warning_index;
- d = def_ref;
- scanner_status = absorbing;
- warning_index = cur_cs;
- p = get_avail();
- def_ref = p;
- set_token_ref_count(def_ref, 0);
- p = def_ref;
- scan_left_brace(); /* remove the compulsory left brace */
- unbalance = 1;
- while (1) {
- get_token();
- if (cur_tok < right_brace_limit) {
- if (cur_cmd < right_brace_cmd) {
- incr(unbalance);
- } else {
- decr(unbalance);
- if (unbalance == 0)
- break;
- }
- }
- store_new_token(cur_tok);
- }
- q = token_link(def_ref);
- free_avail(def_ref); /* discard reference count */
- if (q == null)
- cur_val = temp_token_head;
- else
- cur_val = p;
- set_token_link(temp_token_head, q);
- scanner_status = s;
- warning_index = w;
- def_ref = d;
-}
-
-@ The |get_x_or_protected| procedure is like |get_x_token| except that
-protected macros are not expanded.
-
-@c
-void get_x_or_protected(void)
-{ /* sets |cur_cmd|, |cur_chr|, |cur_tok|,
- and expands non-protected macros */
- while (1) {
- get_token();
- if (cur_cmd <= max_command_cmd)
- return;
- if ((cur_cmd >= call_cmd) && (cur_cmd < end_template_cmd)) {
- if (token_info(token_link(cur_chr)) == protected_token)
- return;
- }
- expand();
- }
-}
-
-@ |scan_toks|. This function returns a pointer to the tail of a new token
-list, and it also makes |def_ref| point to the reference count at the
-head of that list.
-
-There are two boolean parameters, |macro_def| and |xpand|. If |macro_def|
-is true, the goal is to create the token list for a macro definition;
-otherwise the goal is to create the token list for some other \TeX\
-primitive: \.{\\mark}, \.{\\output}, \.{\\everypar}, \.{\\lowercase},
-\.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or
-\.{\\special}. In the latter cases a left brace must be scanned next; this
-left brace will not be part of the token list, nor will the matching right
-brace that comes at the end. If |xpand| is false, the token list will
-simply be copied from the input using |get_token|. Otherwise all expandable
-tokens will be expanded until unexpandable tokens are left, except that
-the results of expanding `\.{\\the}' are not expanded further.
-If both |macro_def| and |xpand| are true, the expansion applies
-only to the macro body (i.e., to the material following the first
-|left_brace| character).
-
-The value of |cur_cs| when |scan_toks| begins should be the |eqtb|
-address of the control sequence to display in ``runaway'' error
-messages.
-
-@c
-halfword scan_toks(boolean macro_def, boolean xpand)
-{
- halfword t; /* token representing the highest parameter number */
- halfword s; /* saved token */
- halfword p; /* tail of the token list being built */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword unbalance; /* number of unmatched left braces */
- halfword hash_brace; /* possible `\.{\#\{}' token */
- if (macro_def)
- scanner_status = defining;
- else
- scanner_status = absorbing;
- warning_index = cur_cs;
- p = get_avail();
- def_ref = p;
- set_token_ref_count(def_ref, 0);
- p = def_ref;
- hash_brace = 0;
- t = zero_token;
- if (macro_def) {
- /* Scan and build the parameter part of the macro definition */
- while (1) {
- get_token(); /* set |cur_cmd|, |cur_chr|, |cur_tok| */
- if (cur_tok < right_brace_limit)
- break;
- if (cur_cmd == mac_param_cmd) {
- /* If the next character is a parameter number, make |cur_tok|
- a |match| token; but if it is a left brace, store
- `|left_brace|, |end_match|', set |hash_brace|, and |goto done|;
- */
- s = match_token + cur_chr;
- get_token();
- if (cur_cmd == left_brace_cmd) {
- hash_brace = cur_tok;
- store_new_token(cur_tok);
- store_new_token(end_match_token);
- goto DONE;
- }
- if (t == zero_token + 9) {
- print_err("You already have nine parameters");
- help1("I'm going to ignore the # sign you just used.");
- error();
- } else {
- incr(t);
- if (cur_tok != t) {
- print_err("Parameters must be numbered consecutively");
- help2
- ("I've inserted the digit you should have used after the #.",
- "Type `1' to delete what you did use.");
- back_error();
- }
- cur_tok = s;
- }
- }
- store_new_token(cur_tok);
- }
- store_new_token(end_match_token);
- if (cur_cmd == right_brace_cmd) {
- /* Express shock at the missing left brace; |goto found| */
- print_err("Missing { inserted");
- incr(align_state);
- help2
- ("Where was the left brace? You said something like `\\def\\a}',",
- "which I'm going to interpret as `\\def\\a{}'.");
- error();
- goto FOUND;
- }
-
- } else {
- scan_left_brace(); /* remove the compulsory left brace */
- }
- DONE:
- /* Scan and build the body of the token list; |goto found| when finished */
- unbalance = 1;
- while (1) {
- if (xpand) {
- /* Expand the next part of the input */
- /* Here we insert an entire token list created by |the_toks| without
- expanding it further. */
- while (1) {
- get_next();
- if (cur_cmd >= call_cmd) {
- if (token_info(token_link(cur_chr)) == protected_token) {
- cur_cmd = relax_cmd;
- cur_chr = no_expand_flag;
- }
- }
- if (cur_cmd <= max_command_cmd)
- break;
- if (cur_cmd != the_cmd) {
- expand();
- } else {
- q = the_toks();
- if (token_link(temp_token_head) != null) {
- set_token_link(p, token_link(temp_token_head));
- p = q;
- }
- }
- }
- x_token();
-
- } else {
- get_token();
- }
- if (cur_tok < right_brace_limit) {
- if (cur_cmd < right_brace_cmd) {
- incr(unbalance);
- } else {
- decr(unbalance);
- if (unbalance == 0)
- goto FOUND;
- }
- } else if (cur_cmd == mac_param_cmd) {
- if (macro_def) {
- /* Look for parameter number or \.{\#\#} */
- s = cur_tok;
- if (xpand)
- get_x_token();
- else
- get_token();
- if (cur_cmd != mac_param_cmd) {
- if ((cur_tok <= zero_token) || (cur_tok > t)) {
- print_err("Illegal parameter number in definition of ");
- sprint_cs(warning_index);
- help3("You meant to type ## instead of #, right?",
- "Or maybe a } was forgotten somewhere earlier, and things",
- "are all screwed up? I'm going to assume that you meant ##.");
- back_error();
- cur_tok = s;
- } else {
- cur_tok = out_param_token - '0' + cur_chr;
- }
- }
- }
- }
- store_new_token(cur_tok);
- }
- FOUND:
- scanner_status = normal;
- if (hash_brace != 0)
- store_new_token(hash_brace);
- return p;
-}
-
-@ Here we declare two trivial procedures in order to avoid mutually
-recursive procedures with parameters.
-
-@c
-void scan_normal_glue(void)
-{
- scan_glue(glue_val_level);
-}
-
-void scan_mu_glue(void)
-{
- scan_glue(mu_val_level);
-}
-
-@ The |scan_expr| procedure scans and evaluates an expression.
-
-@ Evaluating an expression is a recursive process: When the left
-parenthesis of a subexpression is scanned we descend to the next level
-of recursion; the previous level is resumed with the matching right
-parenthesis.
-
-@c
-typedef enum {
- expr_none = 0, /* \.( seen, or \.( $\langle\it expr\rangle$ \.) seen */
- expr_add = 1, /* \.( $\langle\it expr\rangle$ \.+ seen */
- expr_sub = 2, /* \.( $\langle\it expr\rangle$ \.- seen */
- expr_mult = 3, /* $\langle\it term\rangle$ \.* seen */
- expr_div = 4, /* $\langle\it term\rangle$ \./ seen */
- expr_scale = 5, /* $\langle\it term\rangle$ \.* $\langle\it factor\rangle$ \./ seen */
-} expression_states;
-
-@ We want to make sure that each term and (intermediate) result is in
- the proper range. Integer values must not exceed |infinity|
- ($2^{31}-1$) in absolute value, dimensions must not exceed |max_dimen|
- ($2^{30}-1$). We avoid the absolute value of an integer, because this
- might fail for the value $-2^{31}$ using 32-bit arithmetic.
-
-@ clear a number or dimension and set |arith_error|
-
-@c
-#define num_error(A) do { \
- arith_error=true; \
- A=0; \
-} while (0)
-
-@ clear a glue spec and set |arith_error|
-
-@c
-#define glue_error(A) do { \
- arith_error=true; \
- reset_glue_to_zero(A); \
-} while (0)
-
-#define normalize_glue(A) do { \
- if (stretch(A)==0) stretch_order(A)=normal; \
- if (shrink(A)==0) shrink_order(A)=normal; \
-} while (0)
-
-@ Parenthesized subexpressions can be inside expressions, and this
-nesting has a stack. Seven local variables represent the top of the
-expression stack: |p| points to pushed-down entries, if any; |l|
-specifies the type of expression currently beeing evaluated; |e| is the
-expression so far and |r| is the state of its evaluation; |t| is the
-term so far and |s| is the state of its evaluation; finally |n| is the
-numerator for a combined multiplication and division, if any.
-
-@c
-#define expr_add_sub(A,B,C) add_or_sub((A),(B),(C),(r==expr_sub))
-#define expr_a(A,B) expr_add_sub((A),(B),max_dimen)
-
-@
- The function |add_or_sub(x,y,max_answer,negative)| computes the sum
- (for |negative=false|) or difference (for |negative=true|) of |x| and
- |y|, provided the absolute value of the result does not exceed
- |max_answer|.
-
-@c
-inline static int add_or_sub(int x, int y, int max_answer, boolean negative)
-{
- int a; /* the answer */
- if (negative)
- negate(y);
- if (x >= 0) {
- if (y <= max_answer - x)
- a = x + y;
- else
- num_error(a);
- } else if (y >= -max_answer - x) {
- a = x + y;
- } else {
- num_error(a);
- }
- return a;
-}
-
-#define expr_m(A) A = nx_plus_y((A),f,0)
-#define expr_d(A) A=quotient((A),f)
-
-@ The function |quotient(n,d)| computes the rounded quotient
-$q=\lfloor n/d+{1\over2}\rfloor$, when $n$ and $d$ are positive.
-
-@c
-inline static int quotient(int n, int d)
-{
- boolean negative; /* should the answer be negated? */
- int a; /* the answer */
- if (d == 0) {
- num_error(a);
- } else {
- if (d > 0) {
- negative = false;
- } else {
- negate(d);
- negative = true;
- }
- if (n < 0) {
- negate(n);
- negative = !negative;
- }
- a = n / d;
- n = n - a * d;
- d = n - d; /* avoid certain compiler optimizations! */
- if (d + n >= 0)
- incr(a);
- if (negative)
- negate(a);
- }
- return a;
-}
-
-#define expr_s(A) A=fract((A),n,f,max_dimen)
-
-@ Finally, the function |fract(x,n,d,max_answer)| computes the integer
-$q=\lfloor xn/d+{1\over2}\rfloor$, when $x$, $n$, and $d$ are positive
-and the result does not exceed |max_answer|. We can't use floating
-point arithmetic since the routine must produce identical results in all
-cases; and it would be too dangerous to multiply by~|n| and then divide
-by~|d|, in separate operations, since overflow might well occur. Hence
-this subroutine simulates double precision arithmetic, somewhat
-analogous to Metafont's |make_fraction| and |take_fraction| routines.
-
-@c
-int fract(int x, int n, int d, int max_answer)
-{
- boolean negative; /* should the answer be negated? */
- int a; /* the answer */
- int f; /* a proper fraction */
- int h; /* smallest integer such that |2*h>=d| */
- int r; /* intermediate remainder */
- int t; /* temp variable */
- if (d == 0)
- goto TOO_BIG;
- a = 0;
- if (d > 0) {
- negative = false;
- } else {
- negate(d);
- negative = true;
- }
- if (x < 0) {
- negate(x);
- negative = !negative;
- } else if (x == 0) {
- goto DONE;
- }
- if (n < 0) {
- negate(n);
- negative = !negative;
- }
- t = n / d;
- if (t > max_answer / x)
- goto TOO_BIG;
- a = t * x;
- n = n - t * d;
- if (n == 0)
- goto FOUND;
- t = x / d;
- if (t > (max_answer - a) / n)
- goto TOO_BIG;
- a = a + t * n;
- x = x - t * d;
- if (x == 0)
- goto FOUND;
- if (x < n) {
- t = x;
- x = n;
- n = t;
- }
- /* now |0<n<=x<d| */
- /* Compute $f=\lfloor xn/d+{1\over2}\rfloor$; */
- /* The loop here preserves the following invariant relations
- between |f|, |x|, |n|, and~|r|:
- (i)~$f+\lfloor(xn+(r+d))/d\rfloor=\lfloor x_0n_0/d+{1\over2}\rfloor$;
- (ii)~|-d<=r<0<n<=x<d|, where $x_0$, $n_0$ are the original values of~$x$
- and $n$. */
- /* Notice that the computation specifies |(x-d)+x| instead of |(x+x)-d|,
- because the latter could overflow. */
- f = 0;
- r = (d / 2) - d;
- h = -r;
- while (1) {
- if (odd(n)) {
- r = r + x;
- if (r >= 0) {
- r = r - d;
- incr(f);
- }
- }
- n = n / 2;
- if (n == 0)
- break;
- if (x < h) {
- x = x + x;
- } else {
- t = x - d;
- x = t + x;
- f = f + n;
- if (x < n) {
- if (x == 0)
- break;
- t = x;
- x = n;
- n = t;
- }
- }
- }
-
- if (f > (max_answer - a))
- goto TOO_BIG;
- a = a + f;
- FOUND:
- if (negative)
- negate(a);
- goto DONE;
- TOO_BIG:
- num_error(a);
- DONE:
- return a;
-}
-
-@ @c
-static void scan_expr(void)
-{ /* scans and evaluates an expression */
- boolean a, b; /* saved values of |arith_error| */
- int l; /* type of expression */
- int r; /* state of expression so far */
- int s; /* state of term so far */
- int o; /* next operation or type of next factor */
- int e; /* expression so far */
- int t; /* term so far */
- int f; /* current factor */
- int n; /* numerator of combined multiplication and division */
- halfword p; /* top of expression stack */
- halfword q; /* for stack manipulations */
- l = cur_val_level;
- a = arith_error;
- b = false;
- p = null;
- /* Scan and evaluate an expression |e| of type |l| */
- RESTART:
- r = expr_none;
- e = 0;
- s = expr_none;
- t = 0;
- n = 0;
- CONTINUE:
- if (s == expr_none)
- o = l;
- else
- o = int_val_level;
- /* Scan a factor |f| of type |o| or start a subexpression */
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
-
- if (cur_tok == other_token + '(') {
- /* Push the expression stack and |goto restart| */
- q = new_node(expr_node, 0);
- vlink(q) = p;
- expr_type(q) = (quarterword) l;
- expr_state(q) = (quarterword) (4 * s + r);
- expr_e_field(q) = e;
- expr_t_field(q) = t;
- expr_n_field(q) = n;
- p = q;
- l = o;
- goto RESTART;
- }
- back_input();
- if ((o == int_val_level) || (o == attr_val_level))
- scan_int();
- else if (o == dimen_val_level)
- scan_normal_dimen();
- else if (o == glue_val_level)
- scan_normal_glue();
- else
- scan_mu_glue();
- f = cur_val;
-
- FOUND:
- /* Scan the next operator and set |o| */
- /* Get the next non-blank non-call token */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
-
- if (cur_tok == other_token + '+') {
- o = expr_add;
- } else if (cur_tok == other_token + '-') {
- o = expr_sub;
- } else if (cur_tok == other_token + '*') {
- o = expr_mult;
- } else if (cur_tok == other_token + '/') {
- o = expr_div;
- } else {
- o = expr_none;
- if (p == null) {
- if (cur_cmd != relax_cmd)
- back_input();
- } else if (cur_tok != other_token + ')') {
- print_err("Missing ) inserted for expression");
- help1("I was expecting to see `+', `-', `*', `/', or `)'. Didn't.");
- back_error();
- }
- }
-
- arith_error = b;
- /* Make sure that |f| is in the proper range */
- if (((l == int_val_level) || (l == attr_val_level)) || (s > expr_sub)) {
- if ((f > infinity) || (f < -infinity))
- num_error(f);
- } else if (l == dimen_val_level) {
- if (abs(f) > max_dimen)
- num_error(f);
- } else {
- if ((abs(width(f)) > max_dimen) || (abs(stretch(f)) > max_dimen) || (abs(shrink(f)) > max_dimen))
- glue_error(f);
- }
-
- switch (s) {
- /* Cases for evaluation of the current term */
- case expr_none:
- /*
- Applying the factor |f| to the partial term |t| (with the operator
- |s|) is delayed until the next operator |o| has been scanned. Here we
- handle the first factor of a partial term. A glue spec has to be copied
- unless the next operator is a right parenthesis; this allows us later on
- to simply modify the glue components.
- */
- t = f;
- if ((l >= glue_val_level) && (o != expr_none)) {
- /* do we really need to copy here ? */
-// t = new_spec(f);
-// flush_node(f);
- normalize_glue(t);
- } else {
- t = f;
- }
- break;
- case expr_mult:
- /* If a multiplication is followed by a division, the two operations are
- combined into a `scaling' operation. Otherwise the term |t| is
- multiplied by the factor |f|. */
- if (o == expr_div) {
- n = f;
- o = expr_scale;
- } else if ((l == int_val_level) || (l == attr_val_level)) {
- t = mult_integers(t, f);
- } else if (l == dimen_val_level) {
- expr_m(t);
- } else {
- expr_m(width(t));
- expr_m(stretch(t));
- expr_m(shrink(t));
- }
- break;
- case expr_div:
- /* Here we divide the term |t| by the factor |f| */
- if (l < glue_val_level) {
- expr_d(t);
- } else {
- expr_d(width(t));
- expr_d(stretch(t));
- expr_d(shrink(t));
- }
- break;
- case expr_scale:
- /* Here the term |t| is multiplied by the quotient $n/f$. */
- if ((l == int_val_level) || (l == attr_val_level)) {
- t = fract(t, n, f, infinity);
- } else if (l == dimen_val_level) {
- expr_s(t);
- } else {
- expr_s(width(t));
- expr_s(stretch(t));
- expr_s(shrink(t));
- }
- break;
- } /* there are no other cases */
- if (o > expr_sub) {
- s = o;
- } else {
- /* Evaluate the current expression */
- /* When a term |t| has been completed it is copied to, added to, or
- subtracted from the expression |e|. */
- s = expr_none;
- if (r == expr_none) {
- e = t;
- } else if ((l == int_val_level) || (l == attr_val_level)) {
- e = expr_add_sub(e, t, infinity);
- } else if (l == dimen_val_level) {
- e = expr_a(e, t);
- } else {
- /* Compute the sum or difference of two glue specs */
- /* We know that |stretch_order(e)>normal| implies |stretch(e)<>0| and
- |shrink_order(e)>normal| implies |shrink(e)<>0|. */
- width(e) = expr_a(width(e), width(t));
- if (stretch_order(e) == stretch_order(t)) {
- stretch(e) = expr_a(stretch(e), stretch(t));
- } else if ((stretch_order(e) < stretch_order(t)) && (stretch(t) != 0)) {
- stretch(e) = stretch(t);
- stretch_order(e) = stretch_order(t);
- }
- if (shrink_order(e) == shrink_order(t)) {
- shrink(e) = expr_a(shrink(e), shrink(t));
- } else if ((shrink_order(e) < shrink_order(t)) && (shrink(t) != 0)) {
- shrink(e) = shrink(t);
- shrink_order(e) = shrink_order(t);
- }
- flush_node(t);
- normalize_glue(e);
- }
- r = o;
- }
- b = arith_error;
- if (o != expr_none)
- goto CONTINUE;
- if (p != null) {
- /* Pop the expression stack and |goto found| */
- f = e;
- q = p;
- e = expr_e_field(q);
- t = expr_t_field(q);
- n = expr_n_field(q);
- s = expr_state(q) / 4;
- r = expr_state(q) % 4;
- l = expr_type(q);
- p = vlink(q);
- flush_node(q);
- goto FOUND;
- }
-
- if (b) {
- print_err("Arithmetic overflow");
- help2("I can't evaluate this expression,",
- "since the result is out of range.");
- error();
- if (l >= glue_val_level) {
- reset_glue_to_zero(e);
- } else {
- e = 0;
- }
- }
- arith_error = a;
- cur_val = e;
- cur_val_level = l;
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/stringpool.w b/Build/source/texk/web2c/luatexdir/tex/stringpool.c
index 5972657f56e..bc09f814b00 100644
--- a/Build/source/texk/web2c/luatexdir/tex/stringpool.w
+++ b/Build/source/texk/web2c/luatexdir/tex/stringpool.c
@@ -1,69 +1,89 @@
-% stringpool.w
-%
-% Copyright 2009-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
+/*
+stringpool.w
+
+Copyright 2009-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/>.
+
+*/
#include "ptexlib.h"
-@ Control sequence names and diagnostic messages are variable-length strings
-of eight-bit characters. Since PASCAL did not have a well-developed string
+/*tex
+
+Control sequence names and diagnostic messages are variable-length strings of
+eight-bit characters. Since PASCAL did not have a well-developed string
mechanism, \TeX\ did all of its string processing by homegrown methods.
-Elaborate facilities for dynamic strings are not needed, so all of the
-necessary operations can be handled with a simple data structure.
-The array |str_pool| contains all of the (eight-bit) bytes off all
-of the strings, and the array |str_start| contains indices of the starting
-points of each string. Strings are referred to by integer numbers, so that
-string number |s| comprises the characters |str_pool[j]| for
-|str_start_macro(s)<=j<str_start_macro(s+1)|. Additional integer variables
-|pool_ptr| and |str_ptr| indicate the number of entries used so far
-in |str_pool| and |str_start|, respectively; locations
-|str_pool[pool_ptr]| and |str_start_macro(str_ptr)| are
-ready for the next string to be allocated.
-
-String numbers 0 to |biggest_char| are reserved for strings that correspond to
+Elaborate facilities for dynamic strings are not needed, so all of the necessary
+operations can be handled with a simple data structure. The array |str_pool|
+contains all of the (eight-bit) bytes off all of the strings, and the array
+|str_start| contains indices of the starting points of each string. Strings are
+referred to by integer numbers, so that string number |s| comprises the
+characters |str_pool[j]| for |str_start_macro(s)<=j<str_start_macro(s+1)|.
+Additional integer variables |pool_ptr| and |str_ptr| indicate the number of
+entries used so far in |str_pool| and |str_start|, respectively; locations
+|str_pool[pool_ptr]| and |str_start_macro(str_ptr)| are ready for the next string
+to be allocated.
+
+String numbers 0 to |biggest_char| are reserved for strings that correspond to
single UNICODE characters. This is in accordance with the conventions of \.{WEB}
-which converts single-character strings into the ASCII code number of the
-single character involved.
+which converts single-character strings into the ASCII code number of the single
+character involved.
+
+*/
+
+/*tex The array of strings: */
+
+lstring *string_pool;
+
+/*tex
+ This variable lives |STRING_OFFSET| below |string_pool| (handy for debugging:
+ |_string_pool[str_ptr] == str_string(str_ptr)|:
+*/
+
+lstring *_string_pool;
+
+/*tex The number of the current string being created: */
+
+str_number str_ptr = (STRING_OFFSET + 1);
+
+/*tex The starting value of |str_ptr|: */
-@c
-lstring *string_pool; /* the array of strings */
-lstring *_string_pool; /* this variable lives |STRING_OFFSET| below |string_pool|
- (handy for debugging:
- |_string_pool[str_ptr] == str_string(str_ptr)| */
+str_number init_str_ptr;
-str_number str_ptr = (STRING_OFFSET + 1); /* number of the current string being created */
-str_number init_str_ptr; /* the starting value of |str_ptr| */
+/*tex
+ The current string buffer, the current index in that buffer, the malloced
+ size of |cur_string| and the occupied byte count:
+*/
-unsigned char *cur_string; /* current string buffer */
-unsigned cur_length; /* current index in that buffer */
-unsigned cur_string_size; /* malloced size of |cur_string| */
-unsigned pool_size; /* occupied byte count */
+unsigned char *cur_string;
+unsigned cur_length;
+unsigned cur_string_size;
+unsigned pool_size;
+/*tex
-@ Once a sequence of characters has been appended to |cur_string|, it
-officially becomes a string when the function |make_string| is called.
-This function returns the identification number of the new string as its
-value.
+Once a sequence of characters has been appended to |cur_string|, it officially
+becomes a string when the function |make_string| is called. This function returns
+the identification number of the new string as its value.
+
+*/
-@c
void reset_cur_string(void)
{
cur_length = 0;
@@ -72,44 +92,41 @@ void reset_cur_string(void)
memset(cur_string, 0, 256);
}
-@ current string enters the pool
-@c
str_number make_string(void)
{
- if (str_ptr == (max_strings + STRING_OFFSET))
- overflow("number of strings",
- (unsigned) (max_strings - init_str_ptr + STRING_OFFSET));
+ if (str_ptr == (max_strings + STRING_OFFSET)) {
+ overflow(
+ "number of strings",
+ (unsigned) (max_strings - init_str_ptr + STRING_OFFSET)
+ );
+ }
str_room(1);
cur_string[cur_length] = '\0'; /* now |lstring.s| is always a valid C string */
str_string(str_ptr) = (unsigned char *) cur_string;
str_length(str_ptr) = cur_length;
pool_size += cur_length;
reset_cur_string();
-#if 0
- printf("Made a string: %s (s=%d)\n", (char *)str_string(str_ptr), (int)str_ptr);
-#endif
str_ptr++;
return (str_ptr - 1);
}
-@ @c
int pool_to_unichar(unsigned char *t)
{
return (int) str2uni(t);
}
+/*tex
+The following subroutine compares string |s| with another string of the same
+length that appears in |buffer| starting at position |k|; the result is |true| if
+and only if the strings are equal. Empirical tests indicate that |str_eq_buf| is
+used in such a way that it tends to return |true| about 80 percent of the time.
-@ The following subroutine compares string |s| with another string of the
-same length that appears in |buffer| starting at position |k|;
-the result is |true| if and only if the strings are equal.
-Empirical tests indicate that |str_eq_buf| is used in such a way that
-it tends to return |true| about 80 percent of the time.
+*/
-@c
boolean str_eq_buf(str_number s, int k)
-{ /* test equality of strings */
- int a; /* a unicode character */
+{
+ int a;
if (s < STRING_OFFSET) {
a = buffer_to_unichar(k);
if (a != s)
@@ -125,15 +142,17 @@ boolean str_eq_buf(str_number s, int k)
return true;
}
+/*tex
+
+Here is a similar routine, but it compares two strings in the string pool, and it
+does not assume that they have the same length.
-@ Here is a similar routine, but it compares two strings in the string pool,
-and it does not assume that they have the same length.
+*/
-@c
boolean str_eq_str(str_number s, str_number t)
-{ /* test equality of strings */
- int a = 0; /* a utf char */
- unsigned char *j, *k, *l; /* running indices */
+{
+ int a = 0;
+ unsigned char *j, *k, *l;
if (s < STRING_OFFSET) {
if (t >= STRING_OFFSET) {
k = str_string(t);
@@ -167,8 +186,8 @@ boolean str_eq_str(str_number s, str_number t)
return true;
}
-@ string compare
-@c
+/*tex A string compare helper: */
+
boolean str_eq_cstr(str_number r, const char *s, size_t l)
{
if (l != (size_t) str_length(r))
@@ -177,43 +196,47 @@ boolean str_eq_cstr(str_number r, const char *s, size_t l)
}
-@ The initial values of |str_pool|, |str_start|, |pool_ptr|,
-and |str_ptr| are computed by the \.{INITEX} program, based in part
-on the information that \.{WEB} has output while processing \TeX.
+/*tex
-The first |string_offset| strings are single-characters strings matching
-Unicode. There is no point in generating all of these. But |str_ptr| has
-initialized properly, otherwise |print_char| cannot see the difference
-between characters and strings.
+The initial values of |str_pool|, |str_start|, |pool_ptr|, and |str_ptr| are
+computed by the \.{INITEX} program, based in part on the information that \.{WEB}
+has output while processing \TeX.
+The first |string_offset| strings are single-characters strings matching Unicode.
+There is no point in generating all of these. But |str_ptr| has initialized
+properly, otherwise |print_char| cannot see the difference between characters and
+strings.
+
+*/
-@ initializes the string pool, but returns |false| if something goes wrong
-@c
boolean get_strings_started(void)
{
reset_cur_string();
return true;
}
-@ The string recycling routines.
- \TeX{} uses 2 upto 4 {\it new\/} strings when scanning a filename in an
- \.{\\input}, \.{\\openin}, or \.{\\openout} operation. These strings are
- normally lost because the reference to them are not saved after finishing
- the operation. |search_string| searches through the string pool for the
- given string and returns either 0 or the found string number.
+/*tex
+
+The string recycling routines. \TeX{} uses 2 upto 4 {\it new\/} strings when
+scanning a filename in an \.{\\input}, \.{\\openin}, or \.{\\openout} operation.
+These strings are normally lost because the reference to them are not saved after
+finishing the operation. |search_string| searches through the string pool for the
+given string and returns either 0 or the found string number.
+
+*/
-@c
str_number search_string(str_number search)
{
- str_number s; /* running index */
- size_t len; /* length of searched string */
+ str_number s;
+ size_t len;
len = str_length(search);
if (len == 0) {
return get_nullstr();
} else {
- s = search - 1; /* start search with newest string below |s|; |search>1|! */
+ /*tex We start the search with newest string below |s|; |search>1|! */
+ s = search - 1;
while (s >= STRING_OFFSET) {
- /* first |string_offset| strings depend on implementation!! */
+ /* The first |string_offset| of strings depend on the implementation! */
if (str_length(s) == len)
if (str_eq_str(s, search))
return s;
@@ -223,7 +246,6 @@ str_number search_string(str_number search)
return 0;
}
-@ @c
str_number maketexstring(const char *s)
{
if (s == NULL || *s == 0)
@@ -231,7 +253,6 @@ str_number maketexstring(const char *s)
return maketexlstring(s, strlen(s));
}
-@ @c
str_number maketexlstring(const char *s, size_t l)
{
if (s == NULL || l == 0)
@@ -243,8 +264,12 @@ str_number maketexlstring(const char *s, size_t l)
return (str_ptr - 1);
}
-@ append a C string to a TeX string
-@c
+/*tex
+
+ This appends a C string to a \TEX\ string:
+
+*/
+
void append_string(const unsigned char *s, unsigned l)
{
if (s == NULL || *s == 0)
@@ -256,14 +281,12 @@ void append_string(const unsigned char *s, unsigned l)
return;
}
-@ @c
char *makecstring(int s)
{
size_t l;
return makeclstring(s, &l);
}
-@ @c
char *makeclstring(int s, size_t * len)
{
if (s < STRING_OFFSET) {
@@ -279,7 +302,6 @@ char *makeclstring(int s, size_t * len)
}
}
-@ @c
int dump_string_pool(void)
{
int j;
@@ -297,7 +319,6 @@ int dump_string_pool(void)
return (k - STRING_OFFSET);
}
-@ @c
int undump_string_pool(void)
{
int j;
@@ -325,7 +346,6 @@ int undump_string_pool(void)
return str_ptr;
}
-@ @c
void init_string_pool_array(unsigned s)
{
string_pool = xmallocarray(lstring, s);
@@ -336,14 +356,16 @@ void init_string_pool_array(unsigned s)
string_pool[0].s[0] = '\0';
}
-@ To destroy an already made string, we say |flush_str|.
-@c
+/*tex
+
+ To destroy an already made string, we say |flush_str|.
+
+*/
+
void flush_str(str_number s)
{
-#if 0
- printf("Flushing a string: %s (s=%d,str_ptr=%d)\n", (char *)str_string(s), (int)s, (int)str_ptr);
-#endif
- if (s > STRING_OFFSET) { /* don't ever delete the null string */
+ if (s > STRING_OFFSET) {
+ /*tex Don't ever delete the null string! */
pool_size -= (unsigned) str_length(s);
str_length(s) = 0;
xfree(str_string(s));
diff --git a/Build/source/texk/web2c/luatexdir/tex/texdeffont.w b/Build/source/texk/web2c/luatexdir/tex/texdeffont.c
index 7fe5ae1e18c..f0b057d40b1 100644
--- a/Build/source/texk/web2c/luatexdir/tex/texdeffont.w
+++ b/Build/source/texk/web2c/luatexdir/tex/texdeffont.c
@@ -1,57 +1,73 @@
-% texdeffont.w
-%
-% Copyright 2008-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
+/*
+texdeffont.w
+
+Copyright 2008-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/>.
+
+*/
#include "ptexlib.h"
-@ When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number
-to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the
-|eqtb| location of a ``frozen'' control sequence that will always select
-the font.
+/*tex
+
+When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number to the
+user's font~\.{\\f}. Adding this number to |font_id_base| gives the |eqtb|
+location of a ``frozen'' control sequence that will always select the font.
+
+The variable |a| in the following code indicates the global nature of the value
+to be set. It's used in the |define| macro. Here we're never global.
+
+There's not much scanner code here because the other scanners are defined where
+they make most sense.
+
+*/
-@c
int font_bytes;
void set_cur_font(internal_font_number f)
{
- int a = 0; /* never global */
+ int a = 0;
define(cur_font_loc, data_cmd, f);
}
-@ @c
+/*tex
+
+ This prints a scaled real, rounded to five digits.
+
+*/
+
static char *scaled_to_string(scaled s)
-{ /* prints scaled real, rounded to five digits */
+{
static char result[16];
int n, k;
- scaled delta; /* amount of allowable inaccuracy */
+ /*tex The amount of allowable inaccuracy: */
+ scaled delta;
k = 0;
if (s < 0) {
+ /*tex Only print the sign, if negative */
result[k++] = '-';
- s = -s; /* print the sign, if negative */
+ s = -s;
}
{
int l = 0;
char digs[8] = { 0 };
n = s / unity;
- /* process the integer part */
+ /*tex Process the integer part: */
do {
digs[l++] = (char) (n % 10);
n = n / 10;;
@@ -64,29 +80,37 @@ static char *scaled_to_string(scaled s)
s = 10 * (s % unity) + 5;
delta = 10;
do {
- if (delta > unity)
- s = s + 0100000 - 050000; /* round the last digit */
+ if (delta > unity) {
+ /*tex Round the last digit: */
+ s = s + 0100000 - 050000;
+ }
result[k++] = (char) ('0' + (s / unity));
s = 10 * (s % unity);
delta = delta * 10;
} while (s > delta);
-
result[k] = 0;
return (char *) result;
}
-@ @c
void tex_def_font(small_number a)
{
- pointer u; /* user's font identifier */
- internal_font_number f; /* runs through existing fonts */
- str_number t; /* name for the frozen font identifier */
- int old_setting; /* holds |selector| setting */
- scaled s = -1000; /* stated ``at'' size, or negative of scaled magnification */
- int natural_dir = -1; /* the natural direction of the font */
+ /*tex The user's font identifier. */
+ pointer u;
+ /*tex This runs through existing fonts. */
+ internal_font_number f;
+ /*tex The name for the frozen font identifier. */
+ str_number t;
+ /*tex Thos holds the |selector| setting. */
+ int old_setting;
+ /*tex Stated `at' size, or negative of scaled magnification. */
+ scaled s = -1000;
+ /*tex The natural direction of the font. */
+ int natural_dir = -1;
char *fn;
- if (job_name == 0)
- open_log_file(); /* avoid confusing \.{texput} with the font name */
+ if (job_name == 0) {
+ /*tex Avoid confusing \.{texput} with the font name. */
+ open_log_file();
+ }
get_r_token();
u = cur_cs;
if (u >= null_cs)
@@ -99,7 +123,7 @@ void tex_def_font(small_number a)
eq_define(u, set_font_cmd, null_font);
}
scan_optional_equals();
- /* Get the next non-blank non-call token; */
+ /*tex Get the next non-blank non-call token. */
do {
get_x_token();
} while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
@@ -108,8 +132,10 @@ void tex_def_font(small_number a)
back_input();
scan_file_name();
if (cur_area != get_nullstr() || cur_ext != get_nullstr()) {
- /* Have to do some rescue-ing here, fonts only have a name,
- no area nor extension */
+ /*tex
+ Have to do some rescue-ing here, fonts only have a name, no area
+ nor extension.
+ */
old_setting = selector;
selector = new_string;
if (cur_area != get_nullstr()) {
@@ -134,26 +160,27 @@ void tex_def_font(small_number a)
token_show(def_ref);
selector = old_setting;
flush_list(def_ref);
- /* |str_room(1)|; *//* what did that do ? */
cur_name = make_string();
cur_ext = get_nullstr();
cur_area = get_nullstr();
}
- /* Scan the font size specification; */
- name_in_progress = true; /* this keeps |cur_name| from being changed */
+ /*tex
+ Scan the font size specification. The next variable keeps |cur_name| from
+ being changed
+ */
+ name_in_progress = true;
if (scan_keyword("at")) {
- /* Put the positive `at' size into |s| */
+ /*tex Put the positive `at' size into |s|. */
scan_normal_dimen();
s = cur_val;
if ((s <= 0) || (s >= 01000000000)) {
char err[256];
- const char *errhelp[] =
- { "I can only handle fonts at positive sizes that are",
+ const char *errhelp[] = {
+ "I can only handle fonts at positive sizes that are",
"less than 2048pt, so I've changed what you said to 10pt.",
NULL
};
- snprintf(err, 255, "Improper `at' size (%spt), replaced by 10pt",
- scaled_to_string(s));
+ snprintf(err, 255, "Improper `at' size (%spt), replaced by 10pt", scaled_to_string(s));
tex_error(err, errhelp);
s = 10 * unity;
}
@@ -162,27 +189,31 @@ void tex_def_font(small_number a)
s = -cur_val;
if ((cur_val <= 0) || (cur_val > 32768)) {
char err[256];
- const char *errhelp[] =
- { "The magnification ratio must be between 1 and 32768.",
+ const char *errhelp[] = {
+ "The magnification ratio must be between 1 and 32768.",
NULL
};
- snprintf(err, 255,
- "Illegal magnification has been changed to 1000 (%d)",
- (int) cur_val);
+ snprintf(err, 255, "Illegal magnification has been changed to 1000 (%d)", (int) cur_val);
tex_error(err, errhelp);
s = -1000;
}
}
+ /*tex
+ There is no real reason to support this obsolete key as there are no useful
+ fonts out there so let's get rid of this overhead. This also means that
+ |natural_dir| can go away.
+ */
+ /*
if (scan_keyword("naturaldir")) {
scan_direction();
natural_dir = cur_val;
}
+ */
name_in_progress = false;
fn = makecstring(cur_name);
f = read_font_info(u, fn, s, natural_dir);
xfree(fn);
equiv(u) = f;
-
eqtb[font_id_base + f] = eqtb[u];
cs_text(font_id_base + f) = t;
}
diff --git a/Build/source/texk/web2c/luatexdir/tex/texfileio.c b/Build/source/texk/web2c/luatexdir/tex/texfileio.c
new file mode 100644
index 00000000000..143e694e1ba
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/texfileio.c
@@ -0,0 +1,1509 @@
+/*
+
+Copyright 2009-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/>.
+
+*/
+
+#include "ptexlib.h"
+
+#include <string.h>
+#include <kpathsea/absolute.h>
+
+/*tex
+
+The bane of portability is the fact that different operating systems treat input
+and output quite differently, perhaps because computer scientists have not given
+sufficient attention to this problem. People have felt somehow that input and
+output are not part of ``real'' programming. Well, it is true that some kinds of
+programming are more fun than others. With existing input/output conventions
+being so diverse and so messy, the only sources of joy in such parts of the code
+are the rare occasions when one can find a way to make the program a little less
+bad than it might have been. We have two choices, either to attack I/O now and
+get it over with, or to postpone I/O until near the end. Neither prospect is very
+attractive, so let's get it over with.
+
+The basic operations we need to do are (1)~inputting and outputting of text, to
+or from a file or the user's terminal; (2)~inputting and outputting of eight-bit
+bytes, to or from a file; (3)~instructing the operating system to initiate
+(``open'') or to terminate (``close'') input or output from a specified file;
+(4)~testing whether the end of an input file has been reached.
+
+\TeX\ needs to deal with two kinds of files. We shall use the term |alpha_file|
+for a file that contains textual data, and the term |byte_file| for a file that
+contains eight-bit binary information. These two types turn out to be the same on
+many computers, but sometimes there is a significant distinction, so we shall be
+careful to distinguish between them. Standard protocols for transferring such
+files from computer to computer, via high-speed networks, are now becoming
+available to more and more communities of users.
+
+The program actually makes use also of a third kind of file, called a
+|word_file|, when dumping and reloading base information for its own
+initialization. We shall define a word file later; but it will be possible for us
+to specify simple operations on word files before they are defined.
+
+We finally did away with |nameoffile| and |namelength|, but the variables have to
+be kept otherwise there will be link errors from |openclose.c| in the web2c
+library
+
+*/
+
+char *nameoffile;
+int namelength;
+
+/*tex
+
+ When input files are opened via a callback, they will also be read using
+ callbacks. for that purpose, the |open_read_file_callback| returns an integer
+ to uniquely identify a callback table. This id replaces the file point |f| in
+ this case, because the input does not have to be a file in the traditional
+ sense.
+
+ Signalling this fact is achieved by having two arrays of integers.
+
+*/
+
+int *input_file_callback_id;
+int read_file_callback_id[17];
+
+/*tex
+
+ Here we handle |-output-directory|. We assume that it is OK to look here
+ first. Possibly it would be better to replace lookups in "." with lookups in
+ the |output_directory| followed by "." but to do this requires much more
+ invasive surgery in libkpathsea.
+
+*/
+
+static char *find_in_output_directory(const char *s)
+{
+ if (output_directory && !kpse_absolute_p(s, false)) {
+ FILE *f_ptr;
+ char *ftemp = concat3(output_directory, DIR_SEP_STRING, s);
+ /*tex This code is used for input files only. */
+ f_ptr = fopen(ftemp, "rb");
+ if (f_ptr) {
+ fclose(f_ptr);
+ return ftemp;
+ } else {
+ free(ftemp);
+
+ }
+ }
+ return NULL;
+}
+
+/*tex
+
+ Find an \.{\\input} or \.{\\read} file. |n| differentiates between those
+ case.
+
+*/
+
+int kpse_available(const char *m) {
+ if (!kpse_init) {
+ fprintf(stdout,"missing kpse replacement callback '%s', quitting\n",m);
+ exit(1);
+ }
+ return 1 ;
+}
+
+char *luatex_find_read_file(const char *s, int n, int callback_index)
+{
+ char *ftemp = NULL;
+ int callback_id = callback_defined(callback_index);
+ if (callback_id > 0) {
+ (void) run_callback(callback_id, "dS->R", n, s, &ftemp);
+ } else if (kpse_available("find_read_file")) {
+ /*tex Use kpathsea here. */
+ ftemp = find_in_output_directory(s);
+ if (!ftemp)
+ ftemp = kpse_find_file(s, kpse_tex_format, 1);
+ }
+ if (ftemp) {
+ if (fullnameoffile)
+ free(fullnameoffile);
+ fullnameoffile = xstrdup(ftemp);
+ }
+ return ftemp;
+}
+
+/*tex Find other files types. */
+
+char *luatex_find_file(const char *s, int callback_index)
+{
+ char *ftemp = NULL;
+ int callback_id = callback_defined(callback_index);
+ if (callback_id > 0) {
+ (void) run_callback(callback_id, "S->R", s, &ftemp);
+ } else if (kpse_available("find_read_file")) {
+ /*tex Use kpathsea here. */
+ switch (callback_index) {
+ case find_enc_file_callback:
+ ftemp = kpse_find_file(s, kpse_enc_format, 0);
+ break;
+ case find_map_file_callback:
+ ftemp = kpse_find_file(s, kpse_fontmap_format, 0);
+ break;
+ case find_type1_file_callback:
+ ftemp = kpse_find_file(s, kpse_type1_format, 0);
+ break;
+ case find_truetype_file_callback:
+ ftemp = kpse_find_file(s, kpse_truetype_format, 0);
+ break;
+ case find_opentype_file_callback:
+ ftemp = kpse_find_file(s, kpse_opentype_format, 0);
+ if (ftemp == NULL)
+ ftemp = kpse_find_file(s, kpse_truetype_format, 0);
+ break;
+ case find_data_file_callback:
+ ftemp = find_in_output_directory(s);
+ if (!ftemp)
+ ftemp = kpse_find_file(s, kpse_tex_format, 1);
+ break;
+ case find_font_file_callback:
+ ftemp = kpse_find_file(s, kpse_ofm_format, 1);
+ if (ftemp == NULL)
+ ftemp = kpse_find_file(s, kpse_tfm_format, 1);
+ break;
+ case find_vf_file_callback:
+ ftemp = kpse_find_file(s, kpse_ovf_format, 0);
+ if (ftemp == NULL)
+ ftemp = kpse_find_file(s, kpse_vf_format, 0);
+ break;
+ case find_cidmap_file_callback:
+ ftemp = kpse_find_file(s, kpse_cid_format, 0);
+ break;
+ default:
+ printf("luatex_find_file(): do not know how to handle file %s of type %d\n", s, callback_index);
+ break;
+ }
+ }
+ return ftemp;
+}
+
+/*tex
+
+ \LUATEX\ used to have private functions for these that did not use kpathsea,
+ but since the file paranoia tests have to come from kpathsea anyway, that is
+ no longer useful. The only downside to using luatex is that if one wants to
+ disable kpathsea via the Lua startup script, it is now an absolute
+ requirement that all file discovery callbacks are specified. Just using the
+ find_read_file, but not setting open_read_file, for example, does not work
+ any more if kpathsea is not to be used at all.
+
+*/
+
+#define openoutnameok(A) kpse_out_name_ok (A)
+#define openinnameok(A) kpse_in_name_ok (A)
+
+/*tex
+
+ Open an input file F, using the kpathsea format FILEFMT and passing
+ |FOPEN_MODE| to fopen. The filename is in `fn'. We return whether or not the
+ open succeeded.
+
+*/
+
+boolean luatex_open_input(FILE ** f_ptr, const char *fn, int filefmt, const_string fopen_mode, boolean must_exist)
+{
+ /*tex We haven't found anything yet. */
+ string fname = NULL;
+ *f_ptr = NULL;
+ if (fullnameoffile)
+ free(fullnameoffile);
+ fullnameoffile = NULL;
+ fname = kpse_find_file(fn, (kpse_file_format_type) filefmt, must_exist);
+ if (fname) {
+ fullnameoffile = xstrdup(fname);
+ /*tex
+
+ If we found the file in the current directory, don't leave the `./'
+ at the beginning of `fn', since it looks dumb when `tex foo' says
+ `(./foo.tex ... )'. On the other hand, if the user said `tex ./foo',
+ and that's what we opened, then keep it -- the user specified it, so
+ we shouldn't remove it.
+
+ */
+ if (fname[0] == '.' && IS_DIR_SEP(fname[1]) && (fn[0] != '.' || !IS_DIR_SEP(fn[1]))) {
+ unsigned i = 0;
+ while (fname[i + 2] != 0) {
+ fname[i] = fname[i + 2];
+ i++;
+ }
+ fname[i] = 0;
+ }
+ /*tex This fopen is not allowed to fail. */
+ *f_ptr = xfopen(fname, fopen_mode);
+ }
+ if (*f_ptr) {
+ recorder_record_input(fname);
+ }
+ return *f_ptr != NULL;
+}
+
+boolean luatex_open_output(FILE ** f_ptr, const char *fn, const_string fopen_mode)
+{
+ char *fname;
+ boolean absolute = kpse_absolute_p(fn, false);
+ /*tex If we have an explicit output directory, use it. */
+ if (output_directory && !absolute) {
+ fname = concat3(output_directory, DIR_SEP_STRING, fn);
+ } else {
+ fname = xstrdup(fn);
+ }
+ /*tex Is the filename openable as given? */
+ *f_ptr = fopen(fname, fopen_mode);
+ if (!*f_ptr) {
+ /*tex Can't open as given. Try the envvar. */
+ string texmfoutput = kpse_var_value("TEXMFOUTPUT");
+ if (texmfoutput && *texmfoutput && !absolute) {
+ fname = concat3(texmfoutput, DIR_SEP_STRING, fn);
+ *f_ptr = fopen(fname, fopen_mode);
+ }
+ }
+ if (*f_ptr) {
+ recorder_record_output(fname);
+ }
+ free(fname);
+ return *f_ptr != NULL;
+}
+
+boolean lua_a_open_in(alpha_file * f, char *fn, int n)
+{
+ int k;
+ char *fnam;
+ int callback_id;
+ boolean ret = true;
+ boolean file_ok = true;
+ if (n == 0) {
+ input_file_callback_id[iindex] = 0;
+ } else {
+ read_file_callback_id[n] = 0;
+ }
+ if (*fn == '|')
+ fnam = fn;
+ else
+ fnam = luatex_find_read_file(fn, n, find_read_file_callback);
+ if (!fnam)
+ return false;
+ callback_id = callback_defined(open_read_file_callback);
+ if (callback_id > 0) {
+ k = run_and_save_callback(callback_id, "S->", fnam);
+ if (k > 0) {
+ ret = true;
+ if (n == 0)
+ input_file_callback_id[iindex] = k;
+ else
+ read_file_callback_id[n] = k;
+ } else {
+ /*tex read failed */
+ file_ok = false;
+ }
+ } else {
+ /*tex no read callback */
+ if (openinnameok(fnam)) {
+ ret = open_in_or_pipe(f, fnam, kpse_tex_format, FOPEN_RBIN_MODE, (n == 0 ? true : false));
+ } else {
+ /*tex open failed */
+ file_ok = false;
+ }
+ }
+ if (!file_ok) {
+ ret = false;
+ }
+ return ret;
+}
+
+boolean lua_a_open_out(alpha_file * f, char *fn, int n)
+{
+ boolean test;
+ str_number fnam;
+ int callback_id;
+ boolean ret = false;
+ callback_id = callback_defined(find_write_file_callback);
+ if (callback_id > 0) {
+ fnam = 0;
+ test = run_callback(callback_id, "dS->s", n, fn, &fnam);
+ if ((test) && (fnam != 0) && (str_length(fnam) > 0)) {
+ /*tex
+
+ There is no message here because if that is needed the macro
+ package should do that in the callback code. As elsewhere,
+ messaging is left to \LUA\ then.
+
+ */
+ ret = open_outfile(f, fn, FOPEN_W_MODE);
+ }
+ } else {
+ if (openoutnameok(fn)) {
+ if (n > 0 && selector != term_only) {
+ /*tex
+
+ This message to the log is for downward compatibility with
+ other tex's as there are scripts out there that act on this
+ message. An alternative is to let a macro package write an
+ explicit message.
+
+ */
+ fprintf(log_file,"\n\\openout%i = %s\n",n-1,fn);
+ }
+ ret = open_out_or_pipe(f, fn, FOPEN_W_MODE);
+ }
+ }
+ return ret;
+}
+
+boolean lua_b_open_out(alpha_file * f, char *fn)
+{
+ boolean test;
+ str_number fnam;
+ int callback_id;
+ boolean ret = false;
+ callback_id = callback_defined(find_output_file_callback);
+ if (callback_id > 0) {
+ fnam = 0;
+ test = run_callback(callback_id, "S->s", fn, &fnam);
+ if ((test) && (fnam != 0) && (str_length(fnam) > 0)) {
+ ret = open_outfile(f, fn, FOPEN_WBIN_MODE);
+ }
+ } else {
+ if (openoutnameok(fn)) {
+ ret = luatex_open_output(f, fn, FOPEN_WBIN_MODE);
+ }
+ }
+ return ret;
+}
+
+void lua_a_close_in(alpha_file f, int n)
+{
+ int callback_id;
+ if (n == 0)
+ callback_id = input_file_callback_id[iindex];
+ else
+ callback_id = read_file_callback_id[n];
+ if (callback_id > 0) {
+ run_saved_callback(callback_id, "close", "->");
+ destroy_saved_callback(callback_id);
+ if (n == 0)
+ input_file_callback_id[iindex] = 0;
+ else
+ read_file_callback_id[n] = 0;
+ } else {
+ close_file_or_pipe(f);
+ }
+}
+
+void lua_a_close_out(alpha_file f)
+{
+ close_file_or_pipe(f);
+}
+
+/*tex
+
+ Binary input and output are done with C's ordinary procedures, so we don't
+ have to make any other special arrangements for binary~I/O. Text output is
+ also easy to do with standard routines. The treatment of text input is more
+ difficult, however, because of the necessary translation to |ASCII_code|
+ values. \TeX's conventions should be efficient, and they should blend nicely
+ with the user's operating environment.
+
+ Input from text files is read one line at a time, using a routine called
+ |lua_input_ln|. This function is defined in terms of global variables called
+ |buffer|, |first|, and |last| that will be described in detail later; for
+ now, it suffices for us to know that |buffer| is an array of |ASCII_code|
+ values, and that |first| and |last| are indices into this array representing
+ the beginning and ending of a line of text.
+
+*/
+
+/*tex lines of characters being read */
+
+packed_ASCII_code *buffer;
+
+/*tex the first unused position in |buffer| */
+
+int first;
+
+/*tex end of the line just input to |buffer| */
+
+int last;
+
+/*tex largest index used in |buffer| */
+
+int max_buf_stack;
+
+/*tex
+
+ The |lua_input_ln| function brings the next line of input from the specified
+ file into available positions of the buffer array and returns the value
+ |true|, unless the file has already been entirely read, in which case it
+ returns |false| and sets |last:=first|. In general, the |ASCII_code| numbers
+ that represent the next line of the file are input into |buffer[first]|,
+ |buffer[first+1]|, \dots, |buffer[last-1]|; and the global variable |last| is
+ set equal to |first| plus the length of the line. Trailing blanks are removed
+ from the line; thus, either |last=first| (in which case the line was entirely
+ blank) or |buffer[last-1]<>" "|.
+
+ An overflow error is given, however, if the normal actions of |lua_input_ln|
+ would make |last>=buf_size|; this is done so that other parts of \TeX\ can
+ safely look at the contents of |buffer[last+1]| without overstepping the
+ bounds of the |buffer| array. Upon entry to |lua_input_ln|, the condition
+ |first<buf_size| will always hold, so that there is always room for an
+ ``empty'' line.
+
+ The variable |max_buf_stack|, which is used to keep track of how large the
+ |buf_size| parameter must be to accommodate the present job, is also kept up
+ to date by |lua_input_ln|.
+
+ If the |bypass_eoln| parameter is |true|, |lua_input_ln| will do a |get|
+ before looking at the first character of the line; this skips over an |eoln|
+ that was in |f^|. The procedure does not do a |get| when it reaches the end
+ of the line; therefore it can be used to acquire input from the user's
+ terminal as well as from ordinary text files.
+
+ Since the inner loop of |lua_input_ln| is part of \TeX's ``inner
+ loop''---each character of input comes in at this place---it is wise to
+ reduce system overhead by making use of special routines that read in an
+ entire array of characters at once, if such routines are available.
+
+*/
+
+boolean lua_input_ln(alpha_file f, int n, boolean bypass_eoln)
+{
+ boolean lua_result;
+ int last_ptr;
+ int callback_id;
+ /*tex Todo: variable can be removed: */
+ (void) bypass_eoln;
+ if (n == 0)
+ callback_id = input_file_callback_id[iindex];
+ else
+ callback_id = read_file_callback_id[n];
+ if (callback_id > 0) {
+ last = first;
+ last_ptr = first;
+ lua_result =
+ run_saved_callback(callback_id, "reader", "->l", &last_ptr);
+ if ((lua_result == true) && (last_ptr != 0)) {
+ last = last_ptr;
+ if (last > max_buf_stack)
+ max_buf_stack = last;
+ } else {
+ lua_result = false;
+ }
+ } else {
+ lua_result = input_ln(f, bypass_eoln);
+ }
+ if (lua_result == true) {
+ /*tex Fix up the input buffer using callbacks */
+ if (last >= first) {
+ callback_id = callback_defined(process_input_buffer_callback);
+ if (callback_id > 0) {
+ last_ptr = first;
+ lua_result =
+ run_callback(callback_id, "l->l", (last - first),
+ &last_ptr);
+ if ((lua_result == true) && (last_ptr != 0)) {
+ last = last_ptr;
+ if (last > max_buf_stack)
+ max_buf_stack = last;
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+/*tex
+
+ We need a special routine to read the first line of \TeX\ input from the
+ user's terminal. This line is different because it is read before we have
+ opened the transcript file; there is sort of a ``chicken and egg'' problem
+ here. If the user types `\.{\\input paper}' on the first line, or if some
+ macro invoked by that line does such an \.{\\input}, the transcript file will
+ be named `\.{paper.log}'; but if no \.{\\input} commands are performed during
+ the first line of terminal input, the transcript file will acquire its
+ default name `\.{texput.log}'. (The transcript file will not contain error
+ messages generated by the first line before the first \.{\\input} command.)
+
+ The first line is special also because it may be read before \TeX\ has input
+ a format file. In such cases, normal error messages cannot yet be given. The
+ following code uses concepts that will be explained later.
+
+ Different systems have different ways to get started. But regardless of what
+ conventions are adopted, the routine that initializes the terminal should
+ satisfy the following specifications:
+
+ \startitemize[n]
+
+ \startitem
+ It should open file |term_in| for input from the terminal. (The file
+ |term_out| will already be open for output to the terminal.)
+ \stopitem
+
+ \startitem
+ If the user has given a command line, this line should be considered
+ the first line of terminal input. Otherwise the user should be
+ prompted with `\.{**}', and the first line of input should be
+ whatever is typed in response.
+ \stopitem
+
+ \startitem
+ The first line of input, which might or might not be a command line,
+ should appear in locations |first| to |last-1| of the |buffer| array.
+ \stopitem
+
+ \startitem
+ The global variable |loc| should be set so that the character to be
+ read next by \TeX\ is in |buffer[loc]|. This character should not be
+ blank, and we should have |loc<last|.
+ \stopitem
+
+ \stopitemize
+
+ It may be necessary to prompt the user several times before a non-blank line
+ comes in. The prompt is `\.{**}' instead of the later `\.*' because the
+ meaning is slightly different: `\.{\\input}' need not be typed immediately
+ after~`\.{**}'.)
+
+ The following program does the required initialization. Iff anything has been
+ specified on the command line, then |t_open_in| will return with |last >
+ first|.
+
+*/
+
+boolean init_terminal(void)
+{
+ /*tex This gets the terminal input started. */
+ t_open_in();
+ if (last > first) {
+ iloc = first;
+ while ((iloc < last) && (buffer[iloc] == ' '))
+ incr(iloc);
+ if (iloc < last) {
+ return true;
+ }
+ }
+ while (1) {
+ wake_up_terminal();
+ fputs("**", term_out);
+ update_terminal();
+ if (!input_ln(term_in, true)) {
+ /*tex This shouldn't happen. */
+ fputs("\n! End of file on the terminal... why?\n", term_out);
+ return false;
+ }
+ iloc = first;
+ while ((iloc < last) && (buffer[iloc] == ' ')) {
+ incr(iloc);
+ }
+ /*tex Return unless the line was all blank. */
+ if (iloc < last) {
+ return true;
+ }
+ fputs("Please type the name of your input file.\n", term_out);
+ }
+}
+
+
+/*tex
+
+ Here is a procedure that asks the user to type a line of input, assuming that
+ the |selector| setting is either |term_only| or |term_and_log|. The input is
+ placed into locations |first| through |last-1| of the |buffer| array, and
+ echoed on the transcript file if appropriate.
+
+*/
+
+void term_input(void)
+{
+ /*tex Index into |buffer|: */
+ int k;
+ /*tex Now the user sees the prompt for sure: */
+ update_terminal();
+ if (!input_ln(term_in, true))
+ fatal_error("End of file on the terminal!");
+ /*tex The user's line ended with \.{<return>}: */
+ term_offset = 0;
+ /*tex Prepare to echo the input. */
+ decr(selector);
+ if (last != first) {
+ for (k = first; k <= last - 1; k++)
+ print_char(buffer[k]);
+ }
+ print_ln();
+ /*tex Restore previous status. */
+ incr(selector);
+}
+
+/*tex
+
+ It's time now to fret about file names. Besides the fact that different
+ operating systems treat files in different ways, we must cope with the fact
+ that completely different naming conventions are used by different groups of
+ people. The following programs show what is required for one particular
+ operating system; similar routines for other systems are not difficult to
+ devise.
+
+ \TeX\ assumes that a file name has three parts: the name proper; its
+ ``extension''; and a ``file area'' where it is found in an external file
+ system. The extension of an input file or a write file is assumed to be
+ `\.{.tex}' unless otherwise specified; it is `\.{.log}' on the transcript
+ file that records each run of \TeX; it is `\.{.tfm}' on the font metric files
+ that describe characters in the fonts \TeX\ uses; it is `\.{.dvi}' on the
+ output files that specify typesetting information; and it is `\.{.fmt}' on
+ the format files written by \.{INITEX} to initialize \TeX. The file area can
+ be arbitrary on input files, but files are usually output to the user's
+ current area. If an input file cannot be found on the specified area, \TeX\
+ will look for it on a special system area; this special area is intended for
+ commonly used input files like \.{webmac.tex}.
+
+ Simple uses of \TeX\ refer only to file names that have no explicit extension
+ or area. For example, a person usually says `\.{\\input} \.{paper}' or
+ `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input} \.{paper.new}'
+ or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file names are best,
+ because they make the \TeX\ source files portable; whenever a file name
+ consists entirely of letters and digits, it should be treated in the same way
+ by all implementations of \TeX. However, users need the ability to refer to
+ other files in their environment, especially when responding to error
+ messages concerning unopenable files; therefore we want to let them use the
+ syntax that appears in their favorite operating system.
+
+ The following procedures don't allow spaces to be part of file names; but
+ some users seem to like names that are spaced-out. System-dependent changes
+ to allow such things should probably be made with reluctance, and only when
+ an entire file name that includes spaces is ``quoted'' somehow.
+
+ Here are the global values that file names will be scanned into.
+
+*/
+
+/*tex name of file just scanned */
+
+str_number cur_name;
+
+/*tex file area just scanned, or \.{""} */
+
+str_number cur_area;
+
+/*tex file extension just scanned, or \.{""} */
+
+str_number cur_ext;
+
+/*tex
+
+ The file names we shall deal with have the following structure: If the name
+ contains `\./' or `\.:' (for Amiga only), the file area consists of all
+ characters up to and including the final such character; otherwise the file
+ area is null. If the remaining file name contains `\..', the file extension
+ consists of all such characters from the last `\..' to the end, otherwise the
+ file extension is null.
+
+ We can scan such file names easily by using two global variables that keep
+ track of the occurrences of area and extension delimiters:
+
+*/
+
+/*tex the most recent `\./', if any */
+
+pool_pointer area_delimiter;
+
+/*tex the relevant `\..', if any */
+
+pool_pointer ext_delimiter;
+
+/*tex
+
+ Input files that can't be found in the user's area may appear in a standard
+ system area called |TEX_area|. Font metric files whose areas are not given
+ explicitly are assumed to appear in a standard system area called
+ |TEX_font_area|. $\Omega$'s compiled translation process files whose areas
+ are not given explicitly are assumed to appear in a standard system area.
+ These system area names will, of course, vary from place to place.
+
+*/
+
+#define append_to_fn(A) do { \
+ c=(A); \
+ if (c!='"') { \
+ if (k<file_name_size) fn[k++]=(unsigned char)(c); \
+ } \
+ } while (0)
+
+
+char *pack_file_name(str_number n, str_number a, str_number e)
+{
+ /*tex character being packed */
+ ASCII_code c;
+ /*tex index into |str_pool| */
+ unsigned char *j;
+ /*tex number of positions filled in |fn| */
+ int k = 0;
+ unsigned char *fn = xmallocarray(packed_ASCII_code, str_length(a) + str_length(n) + str_length(e) + 1);
+ for (j = str_string(a); j < str_string(a) + str_length(a); j++)
+ append_to_fn(*j);
+ for (j = str_string(n); j < str_string(n) + str_length(n); j++)
+ append_to_fn(*j);
+ for (j = str_string(e); j < str_string(e) + str_length(e); j++)
+ append_to_fn(*j);
+ fn[k] = 0;
+ return (char *) fn;
+}
+
+/*tex
+
+ A messier routine is also needed, since format file names must be scanned
+ before \TeX's string mechanism has been initialized. We shall use the global
+ variable |TEX_format_default| to supply the text for default system areas and
+ extensions related to format files.
+
+ Under \UNIX\ we don't give the area part, instead depending on the path
+ searching that will happen during file opening. Also, the length will be set
+ in the main program.
+
+*/
+
+char *TEX_format_default;
+
+
+/*tex
+
+ This part of the program becomes active when a ``virgin'' \TeX\ is trying to
+ get going, just after the preliminary initialization, or when the user is
+ substituting another format file by typing `\.\&' after the initial `\.{**}'
+ prompt. The buffer contains the first line of input in
+ |buffer[loc..(last-1)]|, where |loc<last| and |buffer[loc]<>" "|.
+
+*/
+
+char *open_fmt_file(void)
+{
+ /*tex The first space after the format file name: */
+ int j;
+ char *fmt = NULL;
+ int dist;
+ j = iloc;
+ if (buffer[iloc] == '&') {
+ incr(iloc);
+ j = iloc;
+ buffer[last] = ' ';
+ while (buffer[j] != ' ')
+ incr(j);
+ fmt = xmalloc((unsigned) (j - iloc + 1));
+ strncpy(fmt, (char *) (buffer + iloc), (size_t) (j - iloc));
+ fmt[j - iloc] = 0;
+ dist = (int) (strlen(fmt) - strlen(DUMP_EXT));
+ if (!(strstr(fmt, DUMP_EXT) == fmt + dist))
+ fmt = concat(fmt, DUMP_EXT);
+ if (zopen_w_input(&fmt_file, fmt, DUMP_FORMAT, FOPEN_RBIN_MODE))
+ goto FOUND;
+ wake_up_terminal();
+ fprintf(stdout, "Sorry, I can't find the format `%s'; will try `%s'.\n",
+ fmt, TEX_format_default);
+ update_terminal();
+ }
+ /*tex Now pull out all the stops: try for the system \.{plain} file. */
+ fmt = TEX_format_default;
+ if (!zopen_w_input(&fmt_file, fmt, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
+ wake_up_terminal();
+ fprintf(stdout, "I can't find the format file `%s'!\n",
+ TEX_format_default);
+ return NULL;
+ }
+ FOUND:
+ iloc = j;
+ return fmt;
+}
+
+/*tex
+
+ The global variable |name_in_progress| is used to prevent recursive use of
+ |scan_file_name|, since the |begin_name| and other procedures communicate via
+ global variables. Recursion would arise only by devious tricks like
+ `\.{\\input\\input f}'; such attempts at sabotage must be thwarted.
+ Furthermore, |name_in_progress| prevents \.{\\input} from being initiated
+ when a font size specification is being scanned.
+
+ Another global variable, |job_name|, contains the file name that was first
+ \.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
+ and `\.{.fmt}' in the names of \TeX's output files.
+
+*/
+
+/*tex is a file name being scanned? */
+
+boolean name_in_progress;
+
+/*tex principal file name */
+
+str_number job_name;
+
+/*tex has the transcript file been opened? */
+
+boolean log_opened_global;
+
+/*tex
+
+ Initially |job_name=0|; it becomes nonzero as soon as the true name is known.
+ We have |job_name=0| if and only if the `\.{log}' file has not been opened,
+ except of course for a short time just after |job_name| has become nonzero.
+
+*/
+
+/*tex full name of the log file */
+
+unsigned char *texmf_log_name;
+
+/*tex
+
+ The |open_log_file| routine is used to open the transcript file and to help
+ it catch up to what has previously been printed on the terminal.
+
+*/
+
+void open_log_file(void)
+{
+ /*tex previous |selector| setting */
+ int old_setting;
+ /*tex index into |buffer| */
+ int k;
+ /*tex end of first input line */
+ int l;
+ char *fn;
+ old_setting = selector;
+ if (job_name == 0)
+ job_name = getjobname(maketexstring("texput"));
+ fn = pack_job_name(".fls");
+ recorder_change_filename(fn);
+ fn = pack_job_name(".log");
+ while (!lua_a_open_out(&log_file, fn, 0)) {
+ /*tex
+
+ Try to get a different log file name. Sometimes |open_log_file| is
+ called at awkward moments when \TeX\ is unable to print error
+ messages or even to |show_context|. The |prompt_file_name| routine
+ can result in a |fatal_error|, but the |error| routine will not be
+ invoked because |log_opened| will be false.
+
+ The normal idea of |batch_mode| is that nothing at all should be
+ written on the terminal. However, in the unusual case that no log
+ file could be opened, we make an exception and allow an explanatory
+ message to be seen.
+
+ Incidentally, the program always refers to the log file as a
+ `\.{transcript file}', because some systems cannot use the extension
+ `\.{.log}' for this file.
+ */
+ selector = term_only;
+ fn = prompt_file_name("transcript file name", ".log");
+ }
+ texmf_log_name = (unsigned char *) xstrdup(fn);
+ selector = log_only;
+ log_opened_global = true;
+ if (callback_defined(start_run_callback) == 0) {
+ /*tex Print the banner line, including current date and time. */
+ log_banner(luatex_version_string);
+ /*tex Make sure bottom level is in memory. */
+ input_stack[input_ptr] = cur_input;
+ tprint_nl("**");
+ /*tex The last position of first line. */
+ l = input_stack[0].limit_field;
+ if (buffer[l] == end_line_char_par) {
+ /*tex maybe also handle multichar endlinechar */
+ decr(l);
+ }
+ for (k = 1; k <= l; k++) {
+ print_char(buffer[k]);
+ }
+ /*tex now the transcript file contains the first line of input */
+ print_ln();
+ }
+ /*tex should be done always */
+ flush_loggable_info();
+ /*tex should be done always */
+ selector = old_setting + 2;
+}
+
+/*tex
+
+ This function is needed by synctex to make its log appear in the right spot
+ when |output_directory| is set.
+
+*/
+
+char *get_full_log_name (void)
+{
+ if (output_directory) {
+ char *ret = xmalloc(strlen((char *)texmf_log_name)+2+strlen(output_directory));
+ ret = strcpy(ret, output_directory);
+ strcat(ret, "/");
+ strcat(ret, (char *)texmf_log_name);
+ return ret;
+ } else {
+ return xstrdup((const char*)texmf_log_name);
+ }
+}
+
+/*tex Synctex uses this to get the anchored path of an input file. */
+
+char *luatex_synctex_get_current_name (void)
+{
+ char *pwdbuf = NULL, *ret;
+ if (kpse_absolute_p(fullnameoffile, false)) {
+ return xstrdup(fullnameoffile);
+ }
+ pwdbuf = xgetcwd();
+ ret = concat3(pwdbuf, DIR_SEP_STRING, fullnameoffile);
+ free(pwdbuf) ;
+ return ret;
+}
+
+/*tex
+
+ Let's turn now to the procedure that is used to initiate file reading when an
+ `\.{\\input}' command is being processed.
+
+*/
+
+void start_input(void)
+{
+ str_number temp_str;
+ char *fn;
+ do {
+ get_x_token();
+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
+
+ back_input();
+ if (cur_cmd != left_brace_cmd) {
+ /*tex Set |cur_name| to desired file name. */
+ scan_file_name();
+ } else {
+ scan_file_name_toks();
+ }
+ fn = pack_file_name(cur_name, cur_area, cur_ext);
+ while (1) {
+ /*tex Set up |cur_file| and new level of input. */
+ begin_file_reading();
+ if (lua_a_open_in(&cur_file, fn, 0)) {
+ break;
+ }
+ /*tex Remove the level that didn't work. */
+ end_file_reading();
+ fn = prompt_file_name("input file name", "");
+ }
+ iname = maketexstring(fullnameoffile);
+ /*tex
+
+ Now that we have |fullnameoffile|, it is time to post-adjust |cur_name|
+ and |cur_ext| for trailing |.tex|.
+
+ */
+ {
+ char *n, *p;
+ n = p = fullnameoffile + strlen(fullnameoffile);
+ while (p>fullnameoffile) {
+ p--;
+ if (IS_DIR_SEP(*p)) {
+ break;
+ }
+ }
+ if (IS_DIR_SEP(*p)) {
+ p++;
+ }
+ while (n>fullnameoffile) {
+ n--;
+ if (*n == '.') {
+ break;
+ }
+ }
+ if (n>p) {
+ int q = *n;
+ cur_ext = maketexstring(n);
+ *n = 0;
+ cur_name = maketexstring(p);
+ *n = q;
+ }
+ }
+ source_filename_stack[in_open] = iname;
+ full_source_filename_stack[in_open] = xstrdup(fullnameoffile);
+ /*tex We can try to conserve string pool space now. */
+ temp_str = search_string(iname);
+ if (temp_str > 0) {
+ flush_str(iname);
+ iname = temp_str;
+ }
+ if (job_name == 0) {
+ job_name = getjobname(cur_name);
+ open_log_file();
+ }
+ /*tex
+
+ |open_log_file| doesn't |show_context|, so |limit| and |loc| needn't be
+ set to meaningful values yet.
+
+ */
+ report_start_file(filetype_tex,fullnameoffile);
+ incr(open_parens);
+ update_terminal();
+ istate = new_line;
+ /*tex Prepare new file {\sl Sync\TeX} information. */
+ if (! synctex_get_no_files()) {
+ /*tex Give control to the {\sl Sync\TeX} controller. */
+ synctexstartinput();
+ }
+ /*tex
+
+ Read the first line of the new file. Here we have to remember to tell the
+ |lua_input_ln| routine not to start with a |get|. If the file is empty,
+ it is considered to contain a single blank line.
+
+ */
+ line = 1;
+ if (lua_input_ln(cur_file, 0, false)) {
+ ;
+ }
+ firm_up_the_line();
+ if (end_line_char_inactive)
+ decr(ilimit);
+ else
+ buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
+ first = ilimit + 1;
+ iloc = istart;
+}
+
+/*tex
+
+ Because the format is zipped we read and write dump files through zlib.
+ Earlier versions recast |*f| from |FILE *| to |gzFile|, but there is no
+ guarantee that these have the same size, so a static variable is needed.
+
+*/
+
+static gzFile gz_fmtfile = NULL;
+
+/*tex
+
+ As distributed, the dump files are architecture dependent; specifically,
+ BigEndian and LittleEndian architectures produce different files. These
+ routines always output BigEndian files. This still does not guarantee them to
+ be architecture-independent, because it is possible to make a format that
+ dumps a glue ratio, i.e., a floating-point number. Fortunately, none of the
+ standard formats do that.
+
+*/
+
+#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
+
+/*tex
+
+ This macro is always invoked as a statement. It assumes a variable `temp'.
+
+*/
+
+# define SWAP(x, y) do { temp = x; x = y; y = temp; } while (0)
+
+/*tex
+
+ Make the NITEMS items pointed at by P, each of size SIZE, be the
+ opposite-endianness of whatever they are now.
+
+*/
+
+static void swap_items(char *pp, int nitems, int size)
+{
+ char temp;
+ unsigned total = (unsigned) (nitems * size);
+ char *q = xmalloc(total);
+ char *p = q;
+ memcpy(p,pp,total);
+ /*tex
+
+ Since `size' does not change, we can write a while loop for each case,
+ and avoid testing `size' for each time.
+
+ */
+ switch (size) {
+ case 16:
+ /*tex
+
+ 16-byte items happen on the DEC Alpha machine when we are not doing
+ sharable memory dumps.
+
+ */
+ while (nitems--) {
+ SWAP(p[0], p[15]);
+ SWAP(p[1], p[14]);
+ SWAP(p[2], p[13]);
+ SWAP(p[3], p[12]);
+ SWAP(p[4], p[11]);
+ SWAP(p[5], p[10]);
+ SWAP(p[6], p[9]);
+ SWAP(p[7], p[8]);
+ p += size;
+ }
+ break;
+
+ case 12:
+ while (nitems--) {
+ SWAP(p[0], p[11]);
+ SWAP(p[1], p[10]);
+ SWAP(p[2], p[9]);
+ SWAP(p[3], p[8]);
+ SWAP(p[4], p[7]);
+ SWAP(p[5], p[6]);
+ p += size;
+ }
+ break;
+
+ case 8:
+ while (nitems--) {
+ SWAP(p[0], p[7]);
+ SWAP(p[1], p[6]);
+ SWAP(p[2], p[5]);
+ SWAP(p[3], p[4]);
+ p += size;
+ }
+ break;
+
+ case 4:
+ while (nitems--) {
+ SWAP(p[0], p[3]);
+ SWAP(p[1], p[2]);
+ p += size;
+ }
+ break;
+
+ case 2:
+ while (nitems--) {
+ SWAP(p[0], p[1]);
+ p += size;
+ }
+ break;
+ case 1:
+ /*tex Nothing to do. */
+ break;
+ default:
+ FATAL1("Can't swap a %d-byte item for (un)dumping", size);
+ }
+ memcpy(pp,q,total);
+ xfree(q);
+}
+#endif
+
+/*tex
+
+ That second swap is to make sure following calls don't get confused in the
+ case of |dump_things|.
+
+*/
+
+void do_zdump(char *p, int item_size, int nitems, FILE * out_file)
+{
+ int err;
+ (void) out_file;
+ if (nitems == 0)
+ return;
+#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
+ swap_items(p, nitems, item_size);
+#endif
+ if (gzwrite(gz_fmtfile, (void *) p, (unsigned) (item_size * nitems)) !=
+ item_size * nitems) {
+ fprintf(stderr, "! Could not write %d %d-byte item(s): %s.\n", nitems, item_size, gzerror(gz_fmtfile, &err));
+ uexit(1);
+ }
+#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
+ swap_items(p, nitems, item_size);
+#endif
+}
+
+void do_zundump(char *p, int item_size, int nitems, FILE * in_file)
+{
+ int err;
+ (void) in_file;
+ if (nitems == 0)
+ return;
+ if (gzread(gz_fmtfile, (void *) p, (unsigned) (item_size * nitems)) <= 0) {
+ fprintf(stderr, "Could not undump %d %d-byte item(s): %s.\n", nitems, item_size, gzerror(gz_fmtfile, &err));
+ uexit(1);
+ }
+#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
+ swap_items(p, nitems, item_size);
+#endif
+}
+
+/*tex
+
+ Tests has shown that a level 3 compression is the most optimal tradeoff
+ between file size and load time.
+
+*/
+
+#define COMPRESSION "R3"
+
+boolean zopen_w_input(FILE ** f, const char *fname, int format, const_string fopen_mode)
+{
+ int callbackid;
+ int res;
+ char *fnam;
+ callbackid = callback_defined(find_format_file_callback);
+ if (callbackid > 0) {
+ res = run_callback(callbackid, "S->R", fname, &fnam);
+ if (res && fnam && strlen(fnam) > 0) {
+ *f = fopen(fnam, fopen_mode);
+ if (*f == NULL) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ res = luatex_open_input(f, fname, format, fopen_mode, true);
+ }
+ if (res) {
+ gz_fmtfile = gzdopen(fileno(*f), "rb" COMPRESSION);
+ }
+ return res;
+}
+
+boolean zopen_w_output(FILE ** f, const char *s, const_string fopen_mode)
+{
+ int res = 1;
+ if (luainit) {
+ *f = fopen(s, fopen_mode);
+ if (*f == NULL) {
+ return 0;
+ }
+ } else {
+ res = luatex_open_output(f, s, fopen_mode);
+ }
+ if (res) {
+ gz_fmtfile = gzdopen(fileno(*f), "wb" COMPRESSION);
+ }
+ return res;
+}
+
+void zwclose(FILE * f)
+{
+ (void) f;
+ gzclose(gz_fmtfile);
+}
+
+/*tex Create the \DVI\ or \PDF\ file. */
+
+int open_outfile(FILE ** f, const char *name, const char *mode)
+{
+ FILE *res;
+ res = fopen(name, mode);
+ if (res != NULL) {
+ *f = res;
+ return 1;
+ }
+ return 0;
+}
+
+/*tex The caller should set |tfm_buffer=NULL| and |tfm_size=0|. */
+
+int readbinfile(FILE * f, unsigned char **tfm_buffer, int *tfm_size)
+{
+ void *buf;
+ int size;
+ if (fseek(f, 0, SEEK_END) == 0) {
+ size = (int) ftell(f);
+ if (size > 0) {
+ buf = xmalloc((unsigned) size);
+ if (fseek(f, 0, SEEK_SET) == 0) {
+ if (fread((void *) buf, (size_t) size, 1, f) == 1) {
+ *tfm_buffer = (unsigned char *) buf;
+ *tfm_size = size;
+ return 1;
+ }
+ }
+ } else {
+ *tfm_buffer = NULL;
+ *tfm_size = 0;
+ return 1;
+ }
+ }
+ /*tex Either seek failed or we have a zero-sized file. */
+ return 0;
+}
+
+/*tex
+
+ Like |os.execute()|, the |runpopen()| function is called only when
+ |shellenabledp == 1|. Unlike |os.execute()| we write errors to stderr, since
+ we have nowhere better to use; and of course we return a file handle (or
+ NULL) instead of a status indicator.
+
+*/
+
+static FILE *runpopen(char *cmd, const char *mode)
+{
+ FILE *f = NULL;
+ char *safecmd = NULL;
+ char *cmdname = NULL;
+ int allow;
+#ifdef WIN32
+ char *pp;
+
+ for (pp = cmd; *pp; pp++) {
+ if (*pp == '\'') *pp = '"';
+ }
+#endif
+ /*tex If |restrictedshell| is zero, any command is allowed. */
+ if (restrictedshell == 0) {
+ allow = 1;
+ } else {
+ const char *thecmd = cmd;
+ allow = shell_cmd_is_allowed(thecmd, &safecmd, &cmdname);
+ }
+ if (allow == 1)
+ f = popen(cmd, mode);
+ else if (allow == 2)
+ f = popen(safecmd, mode);
+ else if (allow == -1)
+ fprintf(stderr, "\nrunpopen quotation error in command line: %s\n", cmd);
+ else
+ fprintf(stderr, "\nrunpopen command not allowed: %s\n", cmdname);
+ if (safecmd)
+ free(safecmd);
+ if (cmdname)
+ free(cmdname);
+ return f;
+}
+
+/*tex
+
+ The code that implements |popen()| needs an array for tracking possible pipe
+ file pointers, because these need to be closed using |pclose()|.
+
+*/
+
+#define NUM_PIPES 16
+static FILE *pipes[NUM_PIPES];
+
+#ifdef WIN32
+FILE *Poptr;
+#endif
+
+boolean open_in_or_pipe(FILE ** f_ptr, char *fn, int filefmt, const_string fopen_mode, boolean must_exist)
+{
+ string fname = NULL;
+ int i;
+ /*tex
+
+ Opening a read pipe is straightforward, only have to skip past the pipe
+ symbol in the file name. filename quoting is assumed to happen elsewhere
+ (it does :-))
+
+ */
+ if (shellenabledp && *fn == '|') {
+ /*tex The user requested a pipe. */
+ *f_ptr = NULL;
+ fname = (string) xmalloc((unsigned) (strlen(fn) + 1));
+ strcpy(fname, fn);
+ if (fullnameoffile)
+ free(fullnameoffile);
+ fullnameoffile = xstrdup(fname);
+ recorder_record_input(fname + 1);
+ *f_ptr = runpopen(fname + 1, "r");
+ free(fname);
+ for (i = 0; i < NUM_PIPES; i++) {
+ if (pipes[i] == NULL) {
+ pipes[i] = *f_ptr;
+ break;
+ }
+ }
+ if (*f_ptr)
+ setvbuf(*f_ptr, (char *) NULL, _IONBF, 0);
+#ifdef WIN32
+ Poptr = *f_ptr;
+#endif
+ return *f_ptr != NULL;
+ }
+ return luatex_open_input(f_ptr, fn, filefmt, fopen_mode, must_exist);
+}
+
+
+boolean open_out_or_pipe(FILE ** f_ptr, char *fn, const_string fopen_mode)
+{
+ string fname;
+ int i;
+ /*tex
+
+ Opening a write pipe takes a little bit more work, because TeX will
+ perhaps have appended ".tex". To avoid user confusion as much as
+ possible, this extension is stripped only when the command is a bare
+ word. Some small string trickery is needed to make sure the correct
+ number of bytes is free()-d afterwards.
+ */
+ if (shellenabledp && *fn == '|') {
+ /*tex The user requested a pipe. */
+ fname = (string) xmalloc((unsigned) (strlen(fn) + 1));
+ strcpy(fname, fn);
+ if (strchr(fname, ' ') == NULL && strchr(fname, '>') == NULL) {
+ /*tex
+
+ \METAPOST\ and \METAFIONT\ currently do not use this code, but it
+ is better to be prepared. Hm, what has this todo with \LUATEX ?
+
+ */
+ if (STREQ((fname + strlen(fname) - 3), "tex"))
+ *(fname + strlen(fname) - 4) = 0;
+ *f_ptr = runpopen(fname + 1, "w");
+ *(fname + strlen(fname)) = '.';
+ } else {
+ *f_ptr = runpopen(fname + 1, "w");
+ }
+ recorder_record_output(fname + 1);
+ free(fname);
+ for (i = 0; i < NUM_PIPES; i++) {
+ if (pipes[i] == NULL) {
+ pipes[i] = *f_ptr;
+ break;
+ }
+ }
+ if (*f_ptr)
+ setvbuf(*f_ptr, (char *) NULL, _IONBF, 0);
+ return *f_ptr != NULL;
+ }
+ return luatex_open_output(f_ptr, fn, fopen_mode);
+}
+
+
+void close_file_or_pipe(FILE * f)
+{
+ int i;
+ if (shellenabledp) {
+ for (i = 0; i <= 15; i++) {
+ /*tex If this file was a pipe, |pclose()| it and return. */
+ if (pipes[i] == f) {
+ if (f) {
+ pclose(f);
+#ifdef WIN32
+ Poptr = NULL;
+#endif
+ }
+ pipes[i] = NULL;
+ return;
+ }
+ }
+ }
+ close_file(f);
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/texfileio.w b/Build/source/texk/web2c/luatexdir/tex/texfileio.w
deleted file mode 100644
index a10e9ba63d0..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/texfileio.w
+++ /dev/null
@@ -1,1389 +0,0 @@
-% texfileio.w
-%
-% Copyright 2009-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 <string.h>
-#include <kpathsea/absolute.h>
-
-@ The bane of portability is the fact that different operating systems treat
-input and output quite differently, perhaps because computer scientists
-have not given sufficient attention to this problem. People have felt somehow
-that input and output are not part of ``real'' programming. Well, it is true
-that some kinds of programming are more fun than others. With existing
-input/output conventions being so diverse and so messy, the only sources of
-joy in such parts of the code are the rare occasions when one can find a
-way to make the program a little less bad than it might have been. We have
-two choices, either to attack I/O now and get it over with, or to postpone
-I/O until near the end. Neither prospect is very attractive, so let's
-get it over with.
-
-The basic operations we need to do are (1)~inputting and outputting of
-text, to or from a file or the user's terminal; (2)~inputting and
-outputting of eight-bit bytes, to or from a file; (3)~instructing the
-operating system to initiate (``open'') or to terminate (``close'') input or
-output from a specified file; (4)~testing whether the end of an input
-file has been reached.
-
-\TeX\ needs to deal with two kinds of files.
-We shall use the term |alpha_file| for a file that contains textual data,
-and the term |byte_file| for a file that contains eight-bit binary information.
-These two types turn out to be the same on many computers, but
-sometimes there is a significant distinction, so we shall be careful to
-distinguish between them. Standard protocols for transferring
-such files from computer to computer, via high-speed networks, are
-now becoming available to more and more communities of users.
-
-The program actually makes use also of a third kind of file, called a
-|word_file|, when dumping and reloading base information for its own
-initialization. We shall define a word file later; but it will be possible
-for us to specify simple operations on word files before they are defined.
-
-@ We finally did away with |nameoffile| and |namelength|, but the variables
-have to be kept otherwise there will be link errors from |openclose.c| in
-the web2c library
-
-@c
-char *nameoffile;
-int namelength;
-
-
-@ When input files are opened via a callback, they will also be read using
-callbacks. for that purpose, the |open_read_file_callback| returns an
-integer to uniquely identify a callback table. This id replaces the file
-point |f| in this case, because the input does not have to be a file
-in the traditional sense.
-
-Signalling this fact is achieved by having two arrays of integers.
-
-@c
-int *input_file_callback_id;
-int read_file_callback_id[17];
-
-@ Handle -output-directory.
-
-We assume that it is OK to look here first. Possibly it
-would be better to replace lookups in "." with lookups in the
-|output_directory| followed by "." but to do this requires much more
-invasive surgery in libkpathsea.
-
-@c
-static char *find_in_output_directory(const char *s)
-{
- if (output_directory && !kpse_absolute_p(s, false)) {
- FILE *f_ptr;
- char *ftemp = concat3(output_directory, DIR_SEP_STRING, s);
- f_ptr = fopen(ftemp, "rb"); /* this code is used for input files only */
- if (f_ptr) {
- fclose(f_ptr);
- return ftemp;
- } else {
- free(ftemp);
-
- }
- }
- return NULL;
-}
-
-@ find an \.{\\input} or \.{\\read} file. |n| differentiates between those case.
-
-@c
-int kpse_available(const char *m) {
- if (!kpse_init) {
- fprintf(stdout,"missing kpse replacement callback '%s', quitting\n",m);
- exit(1);
- }
- return 1 ;
-}
-
-char *luatex_find_read_file(const char *s, int n, int callback_index)
-{
- char *ftemp = NULL;
- int callback_id = callback_defined(callback_index);
- if (callback_id > 0) {
- (void) run_callback(callback_id, "dS->R", n, s, &ftemp);
- } else if (kpse_available("find_read_file")) {
- /* use kpathsea here */
- ftemp = find_in_output_directory(s);
- if (!ftemp)
- ftemp = kpse_find_file(s, kpse_tex_format, 1);
- }
- if (ftemp) {
- if (fullnameoffile)
- free(fullnameoffile);
- fullnameoffile = xstrdup(ftemp);
- }
- return ftemp;
-}
-
-@ find other files types
-@c
-char *luatex_find_file(const char *s, int callback_index)
-{
- char *ftemp = NULL;
- int callback_id = callback_defined(callback_index);
- if (callback_id > 0) {
- (void) run_callback(callback_id, "S->R", s, &ftemp);
-
- } else if (kpse_available("find_read_file")) {
- /* use kpathsea here */
- switch (callback_index) {
- case find_enc_file_callback:
- ftemp = kpse_find_file(s, kpse_enc_format, 0);
- break;
- case find_map_file_callback:
- ftemp = kpse_find_file(s, kpse_fontmap_format, 0);
- break;
- case find_type1_file_callback:
- ftemp = kpse_find_file(s, kpse_type1_format, 0);
- break;
- case find_truetype_file_callback:
- ftemp = kpse_find_file(s, kpse_truetype_format, 0);
- break;
- case find_opentype_file_callback:
- ftemp = kpse_find_file(s, kpse_opentype_format, 0);
- if (ftemp == NULL)
- ftemp = kpse_find_file(s, kpse_truetype_format, 0);
- break;
- case find_data_file_callback:
- ftemp = find_in_output_directory(s);
- if (!ftemp)
- ftemp = kpse_find_file(s, kpse_tex_format, 1);
- break;
- case find_font_file_callback:
- ftemp = kpse_find_file(s, kpse_ofm_format, 1);
- if (ftemp == NULL)
- ftemp = kpse_find_file(s, kpse_tfm_format, 1);
- break;
- case find_vf_file_callback:
- ftemp = kpse_find_file(s, kpse_ovf_format, 0);
- if (ftemp == NULL)
- ftemp = kpse_find_file(s, kpse_vf_format, 0);
- break;
- case find_cidmap_file_callback:
- ftemp = kpse_find_file(s, kpse_cid_format, 0);
- break;
- default:
- printf
- ("luatex_find_file(): do not know how to handle file %s of type %d\n",
- s, callback_index);
- break;
- }
- }
- return ftemp;
-}
-
-
-@ LuaTeX used to have private functions for these that did not use kpathsea,
-but since the file paranoia tests have to come from kpathsea anyway, that is no
-longer useful. The only downside to using luatex is that if one wants to disable
-kpathsea via the Lua startup script, it is now an absolute requirement that all
-file discovery callbacks are specified. Just using the find_read_file, but not
-setting open_read_file, for example, does not work any more if kpathsea is not
-to be used at all.
-
-@c
-#define openoutnameok(A) kpse_out_name_ok (A)
-#define openinnameok(A) kpse_in_name_ok (A)
-
-@ Open an input file F, using the kpathsea format FILEFMT and passing
- |FOPEN_MODE| to fopen. The filename is in `fn'. We return whether or
- not the open succeeded.
-
-@c
-boolean
-luatex_open_input(FILE ** f_ptr, const char *fn, int filefmt,
- const_string fopen_mode, boolean must_exist)
-{
- string fname = NULL;
- /* We havent found anything yet. */
- *f_ptr = NULL;
- if (fullnameoffile)
- free(fullnameoffile);
- fullnameoffile = NULL;
- fname = kpse_find_file(fn, (kpse_file_format_type) filefmt, must_exist);
- if (fname) {
- fullnameoffile = xstrdup(fname);
- /* If we found the file in the current directory, don't leave
- the `./' at the beginning of `fn', since it looks
- dumb when `tex foo' says `(./foo.tex ... )'. On the other
- hand, if the user said `tex ./foo', and that's what we
- opened, then keep it -- the user specified it, so we
- shouldn't remove it. */
- if (fname[0] == '.' && IS_DIR_SEP(fname[1])
- && (fn[0] != '.' || !IS_DIR_SEP(fn[1]))) {
- unsigned i = 0;
- while (fname[i + 2] != 0) {
- fname[i] = fname[i + 2];
- i++;
- }
- fname[i] = 0;
- }
- /* This fopen is not allowed to fail. */
- *f_ptr = xfopen(fname, fopen_mode);
- }
- if (*f_ptr) {
- recorder_record_input(fname);
- }
- return *f_ptr != NULL;
-}
-
-@ @c
-boolean luatex_open_output(FILE ** f_ptr, const char *fn,
- const_string fopen_mode)
-{
- char *fname;
- boolean absolute = kpse_absolute_p(fn, false);
-
- /* If we have an explicit output directory, use it. */
- if (output_directory && !absolute) {
- fname = concat3(output_directory, DIR_SEP_STRING, fn);
- } else {
- fname = xstrdup(fn);
- }
-
- /* Is the filename openable as given? */
- *f_ptr = fopen(fname, fopen_mode);
-
- if (!*f_ptr) {
- /* Can't open as given. Try the envvar. */
- string texmfoutput = kpse_var_value("TEXMFOUTPUT");
-
- if (texmfoutput && *texmfoutput && !absolute) {
- fname = concat3(texmfoutput, DIR_SEP_STRING, fn);
- *f_ptr = fopen(fname, fopen_mode);
- }
- }
- if (*f_ptr) {
- recorder_record_output(fname);
- }
- free(fname);
- return *f_ptr != NULL;
-}
-
-
-@ @c
-boolean lua_a_open_in(alpha_file * f, char *fn, int n)
-{
- int k;
- char *fnam; /* string returned by find callback */
- int callback_id;
- boolean ret = true; /* return value */
- boolean file_ok = true; /* the status so far */
- if (n == 0) {
- input_file_callback_id[iindex] = 0;
- } else {
- read_file_callback_id[n] = 0;
- }
- if (*fn == '|')
- fnam = fn;
- else
- fnam = luatex_find_read_file(fn, n, find_read_file_callback);
- if (!fnam)
- return false;
- callback_id = callback_defined(open_read_file_callback);
- if (callback_id > 0) {
- k = run_and_save_callback(callback_id, "S->", fnam);
- if (k > 0) {
- ret = true;
- if (n == 0)
- input_file_callback_id[iindex] = k;
- else
- read_file_callback_id[n] = k;
- } else {
- file_ok = false; /* read failed */
- }
- } else { /* no read callback */
- if (openinnameok(fnam)) {
- ret =
- open_in_or_pipe(f, fnam, kpse_tex_format, FOPEN_RBIN_MODE,
- (n == 0 ? true : false));
- } else {
- file_ok = false; /* open failed */
- }
- }
- if (!file_ok) {
- ret = false;
- }
- return ret;
-}
-
-
-@ @c
-boolean lua_a_open_out(alpha_file * f, char *fn, int n)
-{
- boolean test;
- str_number fnam;
- int callback_id;
- boolean ret = false;
- callback_id = callback_defined(find_write_file_callback);
- if (callback_id > 0) {
- fnam = 0;
- test = run_callback(callback_id, "dS->s", n, fn, &fnam);
- if ((test) && (fnam != 0) && (str_length(fnam) > 0)) {
- /* There is no message here because if that is needed the macro package */
- /* should do that in the callback code. As elsewhere, messaging is left */
- /* to lua then. */
- ret = open_outfile(f, fn, FOPEN_W_MODE);
- }
- } else {
- if (openoutnameok(fn)) {
- if (n > 0 && selector != term_only) {
- /* This message to the log is for downward compatibility with other tex's */
- /* as there are scripts out there that act on this message. An alternative */
- /* is to let a macro package write an explicit message. */
- fprintf(log_file,"\n\\openout%i = %s\n",n-1,fn);
- }
- ret = open_out_or_pipe(f, fn, FOPEN_W_MODE);
- }
- }
- return ret;
-}
-
-
-@ @c
-boolean lua_b_open_out(alpha_file * f, char *fn)
-{
- boolean test;
- str_number fnam;
- int callback_id;
- boolean ret = false;
- callback_id = callback_defined(find_output_file_callback);
- if (callback_id > 0) {
- fnam = 0;
- test = run_callback(callback_id, "S->s", fn, &fnam);
- if ((test) && (fnam != 0) && (str_length(fnam) > 0)) {
- ret = open_outfile(f, fn, FOPEN_WBIN_MODE);
- }
- } else {
- if (openoutnameok(fn)) {
- ret = luatex_open_output(f, fn, FOPEN_WBIN_MODE);
- }
- }
- return ret;
-}
-
-@ @c
-void lua_a_close_in(alpha_file f, int n)
-{ /* close a text file */
- int callback_id;
- if (n == 0)
- callback_id = input_file_callback_id[iindex];
- else
- callback_id = read_file_callback_id[n];
- if (callback_id > 0) {
- run_saved_callback(callback_id, "close", "->");
- destroy_saved_callback(callback_id);
- if (n == 0)
- input_file_callback_id[iindex] = 0;
- else
- read_file_callback_id[n] = 0;
- } else {
- close_file_or_pipe(f);
- }
-}
-
-@ @c
-void lua_a_close_out(alpha_file f)
-{ /* close a text file */
- close_file_or_pipe(f);
-}
-
-
-@ Binary input and output are done with C's ordinary
-procedures, so we don't have to make any other special arrangements for
-binary~I/O. Text output is also easy to do with standard routines.
-The treatment of text input is more difficult, however, because
-of the necessary translation to |ASCII_code| values.
-\TeX's conventions should be efficient, and they should
-blend nicely with the user's operating environment.
-
-Input from text files is read one line at a time, using a routine called
-|lua_input_ln|. This function is defined in terms of global variables called
-|buffer|, |first|, and |last| that will be described in detail later; for
-now, it suffices for us to know that |buffer| is an array of |ASCII_code|
-values, and that |first| and |last| are indices into this array
-representing the beginning and ending of a line of text.
-
-@c
-packed_ASCII_code *buffer; /* lines of characters being read */
-int first; /* the first unused position in |buffer| */
-int last; /* end of the line just input to |buffer| */
-int max_buf_stack; /* largest index used in |buffer| */
-
-
-@ The |lua_input_ln| function brings the next line of input from the specified
-file into available positions of the buffer array and returns the value
-|true|, unless the file has already been entirely read, in which case it
-returns |false| and sets |last:=first|. In general, the |ASCII_code|
-numbers that represent the next line of the file are input into
-|buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the
-global variable |last| is set equal to |first| plus the length of the
-line. Trailing blanks are removed from the line; thus, either |last=first|
-(in which case the line was entirely blank) or |buffer[last-1]<>" "|.
-
-An overflow error is given, however, if the normal actions of |lua_input_ln|
-would make |last>=buf_size|; this is done so that other parts of \TeX\
-can safely look at the contents of |buffer[last+1]| without overstepping
-the bounds of the |buffer| array. Upon entry to |lua_input_ln|, the condition
-|first<buf_size| will always hold, so that there is always room for an
-``empty'' line.
-
-The variable |max_buf_stack|, which is used to keep track of how large
-the |buf_size| parameter must be to accommodate the present job, is
-also kept up to date by |lua_input_ln|.
-
-If the |bypass_eoln| parameter is |true|, |lua_input_ln| will do a |get|
-before looking at the first character of the line; this skips over
-an |eoln| that was in |f^|. The procedure does not do a |get| when it
-reaches the end of the line; therefore it can be used to acquire input
-from the user's terminal as well as from ordinary text files.
-
-Since the inner loop of |lua_input_ln| is part of \TeX's ``inner loop''---each
-character of input comes in at this place---it is wise to reduce system
-overhead by making use of special routines that read in an entire array
-of characters at once, if such routines are available.
-@^inner loop@>
-
-@c
-boolean lua_input_ln(alpha_file f, int n, boolean bypass_eoln)
-{
- boolean lua_result;
- int last_ptr;
- int callback_id;
- (void) bypass_eoln; /* todo: variable can be removed */
- if (n == 0)
- callback_id = input_file_callback_id[iindex];
- else
- callback_id = read_file_callback_id[n];
- if (callback_id > 0) {
- last = first;
- last_ptr = first;
- lua_result =
- run_saved_callback(callback_id, "reader", "->l", &last_ptr);
- if ((lua_result == true) && (last_ptr != 0)) {
- last = last_ptr;
- if (last > max_buf_stack)
- max_buf_stack = last;
- } else {
- lua_result = false;
- }
- } else {
- lua_result = input_ln(f, bypass_eoln);
- }
- if (lua_result == true) {
- /* Fix up the input buffer using callbacks */
- if (last >= first) {
- callback_id = callback_defined(process_input_buffer_callback);
- if (callback_id > 0) {
- last_ptr = first;
- lua_result =
- run_callback(callback_id, "l->l", (last - first),
- &last_ptr);
- if ((lua_result == true) && (last_ptr != 0)) {
- last = last_ptr;
- if (last > max_buf_stack)
- max_buf_stack = last;
- }
- }
- }
- return true;
- }
- return false;
-}
-
-
-@ We need a special routine to read the first line of \TeX\ input from
-the user's terminal. This line is different because it is read before we
-have opened the transcript file; there is sort of a ``chicken and
-egg'' problem here. If the user types `\.{\\input paper}' on the first
-line, or if some macro invoked by that line does such an \.{\\input},
-the transcript file will be named `\.{paper.log}'; but if no \.{\\input}
-commands are performed during the first line of terminal input, the transcript
-file will acquire its default name `\.{texput.log}'. (The transcript file
-will not contain error messages generated by the first line before the
-first \.{\\input} command.)
-@.texput@>
-
-The first line is special also because it may be read before \TeX\ has
-input a format file. In such cases, normal error messages cannot yet
-be given. The following code uses concepts that will be explained later.
-
-@ Different systems have different ways to get started. But regardless of
-what conventions are adopted, the routine that initializes the terminal
-should satisfy the following specifications:
-
-\yskip\textindent{1)}It should open file |term_in| for input from the
- terminal. (The file |term_out| will already be open for output to the
- terminal.)
-
-\textindent{2)}If the user has given a command line, this line should be
- considered the first line of terminal input. Otherwise the
- user should be prompted with `\.{**}', and the first line of input
- should be whatever is typed in response.
-
-\textindent{3)}The first line of input, which might or might not be a
- command line, should appear in locations |first| to |last-1| of the
- |buffer| array.
-
-\textindent{4)}The global variable |loc| should be set so that the
- character to be read next by \TeX\ is in |buffer[loc]|. This
- character should not be blank, and we should have |loc<last|.
-
-\yskip\noindent(It may be necessary to prompt the user several times
-before a non-blank line comes in. The prompt is `\.{**}' instead of the
-later `\.*' because the meaning is slightly different: `\.{\\input}' need
-not be typed immediately after~`\.{**}'.)
-
-The following program does the required initialization.
-Iff anything has been specified on the command line, then |t_open_in|
-will return with |last > first|.
-@^system dependencies@>
-
-@c
-boolean init_terminal(void)
-{ /* gets the terminal input started */
- t_open_in();
- if (last > first) {
- iloc = first;
- while ((iloc < last) && (buffer[iloc] == ' '))
- incr(iloc);
- if (iloc < last) {
- return true;
- }
- }
- while (1) {
- wake_up_terminal();
- fputs("**", term_out);
- update_terminal();
- if (!input_ln(term_in, true)) {
- /* this shouldn't happen */
- fputs("\n! End of file on the terminal... why?\n", term_out);
- return false;
- }
- iloc = first;
- while ((iloc < last) && (buffer[iloc] == ' '))
- incr(iloc);
- if (iloc < last) {
- return true; /* return unless the line was all blank */
- }
- fputs("Please type the name of your input file.\n", term_out);
- }
-}
-
-
-@ Here is a procedure that asks the user to type a line of input,
-assuming that the |selector| setting is either |term_only| or |term_and_log|.
-The input is placed into locations |first| through |last-1| of the
-|buffer| array, and echoed on the transcript file if appropriate.
-
-@c
-void term_input(void)
-{ /* gets a line from the terminal */
- int k; /* index into |buffer| */
- update_terminal(); /* now the user sees the prompt for sure */
- if (!input_ln(term_in, true))
- fatal_error("End of file on the terminal!");
- term_offset = 0; /* the user's line ended with \.{<return>} */
- decr(selector); /* prepare to echo the input */
- if (last != first) {
- for (k = first; k <= last - 1; k++)
- print_char(buffer[k]);
- }
- print_ln();
- incr(selector); /* restore previous status */
-}
-
-
-@ It's time now to fret about file names. Besides the fact that different
-operating systems treat files in different ways, we must cope with the
-fact that completely different naming conventions are used by different
-groups of people. The following programs show what is required for one
-particular operating system; similar routines for other systems are not
-difficult to devise.
-@^fingers@>
-@^system dependencies@>
-
-\TeX\ assumes that a file name has three parts: the name proper; its
-``extension''; and a ``file area'' where it is found in an external file
-system. The extension of an input file or a write file is assumed to be
-`\.{.tex}' unless otherwise specified; it is `\.{.log}' on the
-transcript file that records each run of \TeX; it is `\.{.tfm}' on the font
-metric files that describe characters in the fonts \TeX\ uses; it is
-`\.{.dvi}' on the output files that specify typesetting information; and it
-is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX.
-The file area can be arbitrary on input files, but files are usually
-output to the user's current area. If an input file cannot be
-found on the specified area, \TeX\ will look for it on a special system
-area; this special area is intended for commonly used input files like
-\.{webmac.tex}.
-
-Simple uses of \TeX\ refer only to file names that have no explicit
-extension or area. For example, a person usually says `\.{\\input} \.{paper}'
-or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input}
-\.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file
-names are best, because they make the \TeX\ source files portable;
-whenever a file name consists entirely of letters and digits, it should be
-treated in the same way by all implementations of \TeX. However, users
-need the ability to refer to other files in their environment, especially
-when responding to error messages concerning unopenable files; therefore
-we want to let them use the syntax that appears in their favorite
-operating system.
-
-The following procedures don't allow spaces to be part of
-file names; but some users seem to like names that are spaced-out.
-System-dependent changes to allow such things should probably
-be made with reluctance, and only when an entire file name that
-includes spaces is ``quoted'' somehow.
-
-Here are the global values that file names will be scanned into.
-
-@c
-str_number cur_name; /* name of file just scanned */
-str_number cur_area; /* file area just scanned, or \.{""} */
-str_number cur_ext; /* file extension just scanned, or \.{""} */
-
-
-@ The file names we shall deal with have the
-following structure: If the name contains `\./' or `\.:'
-(for Amiga only), the file area
-consists of all characters up to and including the final such character;
-otherwise the file area is null. If the remaining file name contains
-`\..', the file extension consists of all such characters from the last
-`\..' to the end, otherwise the file extension is null.
-
-We can scan such file names easily by using two global variables that keep track
-of the occurrences of area and extension delimiters:
-
-@c
-pool_pointer area_delimiter; /* the most recent `\./', if any */
-pool_pointer ext_delimiter; /* the relevant `\..', if any */
-
-
-@ Input files that can't be found in the user's area may appear in a standard
-system area called |TEX_area|. Font metric files whose areas are not given
-explicitly are assumed to appear in a standard system area called
-|TEX_font_area|. $\Omega$'s compiled translation process files whose areas
-are not given explicitly are assumed to appear in a standard system area.
-These system area names will, of course, vary from place to place.
-
-@c
-#define append_to_fn(A) do { \
- c=(A); \
- if (c!='"') { \
- if (k<file_name_size) fn[k++]=(unsigned char)(c); \
- } \
- } while (0)
-
-
-char *pack_file_name(str_number n, str_number a, str_number e)
-{
- ASCII_code c; /* character being packed */
- unsigned char *j; /* index into |str_pool| */
- int k = 0; /* number of positions filled in |fn| */
- unsigned char *fn = xmallocarray(packed_ASCII_code,
- str_length(a) + str_length(n) +
- str_length(e) + 1);
- for (j = str_string(a); j < str_string(a) + str_length(a); j++)
- append_to_fn(*j);
- for (j = str_string(n); j < str_string(n) + str_length(n); j++)
- append_to_fn(*j);
- for (j = str_string(e); j < str_string(e) + str_length(e); j++)
- append_to_fn(*j);
- fn[k] = 0;
- return (char *) fn;
-}
-
-
-
-@ A messier routine is also needed, since format file names must be scanned
-before \TeX's string mechanism has been initialized. We shall use the
-global variable |TEX_format_default| to supply the text for default system areas
-and extensions related to format files.
-@^system dependencies@>
-
-Under {\mc UNIX} we don't give the area part, instead depending
-on the path searching that will happen during file opening. Also, the
-length will be set in the main program.
-
-@c
-char *TEX_format_default;
-
-
-@ This part of the program becomes active when a ``virgin'' \TeX\ is trying to get going,
-just after the preliminary initialization, or when the user is substituting another
-format file by typing `\.\&' after the initial `\.{**}' prompt. The buffer
-contains the first line of input in |buffer[loc..(last-1)]|, where
-|loc<last| and |buffer[loc]<>" "|.
-
-@c
-char *open_fmt_file(void)
-{
- int j; /* the first space after the format file name */
- char *fmt = NULL;
- int dist;
- j = iloc;
- if (buffer[iloc] == '&') {
- incr(iloc);
- j = iloc;
- buffer[last] = ' ';
- while (buffer[j] != ' ')
- incr(j);
- fmt = xmalloc((unsigned) (j - iloc + 1));
- strncpy(fmt, (char *) (buffer + iloc), (size_t) (j - iloc));
- fmt[j - iloc] = 0;
- dist = (int) (strlen(fmt) - strlen(DUMP_EXT));
- if (!(strstr(fmt, DUMP_EXT) == fmt + dist))
- fmt = concat(fmt, DUMP_EXT);
- if (zopen_w_input(&fmt_file, fmt, DUMP_FORMAT, FOPEN_RBIN_MODE))
- goto FOUND;
- wake_up_terminal();
- fprintf(stdout, "Sorry, I can't find the format `%s'; will try `%s'.\n",
- fmt, TEX_format_default);
- update_terminal();
- }
- /* now pull out all the stops: try for the system \.{plain} file */
- fmt = TEX_format_default;
- if (!zopen_w_input(&fmt_file, fmt, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
- wake_up_terminal();
- fprintf(stdout, "I can't find the format file `%s'!\n",
- TEX_format_default);
- return NULL;
- }
- FOUND:
- iloc = j;
- return fmt;
-}
-
-
-@ The global variable |name_in_progress| is used to prevent recursive
-use of |scan_file_name|, since the |begin_name| and other procedures
-communicate via global variables. Recursion would arise only by
-devious tricks like `\.{\\input\\input f}'; such attempts at sabotage
-must be thwarted. Furthermore, |name_in_progress| prevents \.{\\input}
-@^recursion@>
-from being initiated when a font size specification is being scanned.
-
-Another global variable, |job_name|, contains the file name that was first
-\.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}'
-and `\.{.fmt}' in the names of \TeX's output files.
-
-@c
-boolean name_in_progress; /* is a file name being scanned? */
-str_number job_name; /* principal file name */
-boolean log_opened_global; /* has the transcript file been opened? */
-
-
-@ Initially |job_name=0|; it becomes nonzero as soon as the true name is known.
-We have |job_name=0| if and only if the `\.{log}' file has not been opened,
-except of course for a short time just after |job_name| has become nonzero.
-
-@c
-unsigned char *texmf_log_name; /* full name of the log file */
-
-@ The |open_log_file| routine is used to open the transcript file and to help
-it catch up to what has previously been printed on the terminal.
-
-@c
-void open_log_file(void)
-{
- int old_setting; /* previous |selector| setting */
- int k; /* index into |buffer| */
- int l; /* end of first input line */
- char *fn;
- old_setting = selector;
- if (job_name == 0)
- job_name = getjobname(maketexstring("texput")); /* TODO */
- fn = pack_job_name(".fls");
- recorder_change_filename(fn);
- fn = pack_job_name(".log");
- while (!lua_a_open_out(&log_file, fn, 0)) {
- /* Try to get a different log file name */
- /* Sometimes |open_log_file| is called at awkward moments when \TeX\ is
- unable to print error messages or even to |show_context|.
- The |prompt_file_name| routine can result in a |fatal_error|, but the |error|
- routine will not be invoked because |log_opened| will be false.
-
- The normal idea of |batch_mode| is that nothing at all should be written
- on the terminal. However, in the unusual case that
- no log file could be opened, we make an exception and allow
- an explanatory message to be seen.
-
- Incidentally, the program always refers to the log file as a `\.{transcript
- file}', because some systems cannot use the extension `\.{.log}' for
- this file.
- */
- selector = term_only;
- fn = prompt_file_name("transcript file name", ".log");
- }
- texmf_log_name = (unsigned char *) xstrdup(fn);
- selector = log_only;
- log_opened_global = true;
- if (callback_defined(start_run_callback) == 0) {
- /* Print the banner line, including current date and time */
- log_banner(luatex_version_string);
-
- input_stack[input_ptr] = cur_input; /* make sure bottom level is in memory */
- tprint_nl("**");
- l = input_stack[0].limit_field; /* last position of first line */
- if (buffer[l] == end_line_char_par)
- decr(l); /* TODO: multichar endlinechar */
- for (k = 1; k <= l; k++)
- print_char(buffer[k]);
- print_ln(); /* now the transcript file contains the first line of input */
- }
- flush_loggable_info(); /* should be done always */
- selector = old_setting + 2; /* |log_only| or |term_and_log| */
-}
-
-@ This function is needed by synctex to make its log appear in the right
-spot when |output_directory| is set.
-
-@c
-char *get_full_log_name (void)
-{
- if (output_directory) {
- char *ret = xmalloc(strlen((char *)texmf_log_name)+2+strlen(output_directory));
- ret = strcpy(ret, output_directory);
- strcat(ret, "/");
- strcat(ret, (char *)texmf_log_name);
- return ret;
- } else {
- return xstrdup((const char*)texmf_log_name);
- }
-}
-
-@ Synctex uses this to get the anchored path of an input file.
-
-@c
-char *luatex_synctex_get_current_name (void)
-{
- char *pwdbuf = NULL, *ret;
- if (kpse_absolute_p(fullnameoffile, false)) {
- return xstrdup(fullnameoffile);
- }
- pwdbuf = xgetcwd();
- ret = concat3(pwdbuf, DIR_SEP_STRING, fullnameoffile);
- free(pwdbuf) ;
- return ret;
-}
-
-
-@ Let's turn now to the procedure that is used to initiate file reading
-when an `\.{\\input}' command is being processed.
-
-@c
-void start_input(void)
-{ /* \TeX\ will \.{\\input} something */
- str_number temp_str;
- char *fn;
- do {
- get_x_token();
- } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
-
- back_input();
- if (cur_cmd != left_brace_cmd) {
- scan_file_name(); /* set |cur_name| to desired file name */
- } else {
- scan_file_name_toks();
- }
- fn = pack_file_name(cur_name, cur_area, cur_ext);
- while (1) {
- begin_file_reading(); /* set up |cur_file| and new level of input */
- if (lua_a_open_in(&cur_file, fn, 0))
- break;
- end_file_reading(); /* remove the level that didn't work */
- fn = prompt_file_name("input file name", "");
- }
- iname = maketexstring(fullnameoffile);
- /* Now that we have |fullnameoffile|, it is time to post-adjust
- |cur_name| and |cur_ext| for trailing |.tex| */
- {
- char *n, *p;
- n = p = fullnameoffile + strlen(fullnameoffile);
- while (p>fullnameoffile) {
- p--;
- if (IS_DIR_SEP(*p)) {
- break;
- }
- }
- if (IS_DIR_SEP(*p)) {
- p++;
- }
- while (n>fullnameoffile) {
- n--;
- if (*n == '.') {
- break;
- }
- }
- if (n>p) {
- int q = *n;
- cur_ext = maketexstring(n);
- *n = 0;
- cur_name = maketexstring(p);
- *n = q;
- }
- }
-
-
- source_filename_stack[in_open] = iname;
- full_source_filename_stack[in_open] = xstrdup(fullnameoffile);
- /* we can try to conserve string pool space now */
- temp_str = search_string(iname);
- if (temp_str > 0) {
- flush_str(iname);
- iname = temp_str;
- }
- if (job_name == 0) {
- job_name = getjobname(cur_name);
- open_log_file();
- }
- /* |open_log_file| doesn't |show_context|, so |limit|
- and |loc| needn't be set to meaningful values yet */
- report_start_file(filetype_tex,fullnameoffile);
- incr(open_parens);
- update_terminal();
- istate = new_line;
- /* Prepare new file {\sl Sync\TeX} information */
- if (! synctex_get_no_files()) {
- synctexstartinput(); /* Give control to the {\sl Sync\TeX} controller */
- }
- /* Read the first line of the new file */
- /* Here we have to remember to tell the |lua_input_ln| routine not to
- start with a |get|. If the file is empty, it is considered to
- contain a single blank line. */
- line = 1;
- if (lua_input_ln(cur_file, 0, false)) {
- ;
- }
- firm_up_the_line();
- if (end_line_char_inactive)
- decr(ilimit);
- else
- buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
- first = ilimit + 1;
- iloc = istart;
-}
-
-@ Read and write dump files through zlib
-
-@ Earlier versions recast |*f| from |FILE *| to |gzFile|, but there is
-no guarantee that these have the same size, so a static variable
-is needed.
-
-@c
-static gzFile gz_fmtfile = NULL;
-
-@ As distributed, the dump files are
-architecture dependent; specifically, BigEndian and LittleEndian
-architectures produce different files. These routines always output
-BigEndian files. This still does not guarantee them to be
-architecture-independent, because it is possible to make a format
-that dumps a glue ratio, i.e., a floating-point number. Fortunately,
-none of the standard formats do that.
-
-@c
-#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
-
-/* This macro is always invoked as a statement. It assumes a variable
- `temp'. */
-# define SWAP(x, y) do { temp = x; x = y; y = temp; } while (0)
-
-/* Make the NITEMS items pointed at by P, each of size SIZE, be the
- opposite-endianness of whatever they are now. */
-static void
-swap_items(char *pp, int nitems, int size)
-{
- char temp;
- unsigned total = (unsigned) (nitems * size);
- char *q = xmalloc(total);
- char *p = q;
- memcpy(p,pp,total);
- /* Since `size' does not change, we can write a while loop for each
- case, and avoid testing `size' for each time. */
- switch (size) {
- /* 16-byte items happen on the DEC Alpha machine when we are not
- doing sharable memory dumps. */
- case 16:
- while (nitems--) {
- SWAP(p[0], p[15]);
- SWAP(p[1], p[14]);
- SWAP(p[2], p[13]);
- SWAP(p[3], p[12]);
- SWAP(p[4], p[11]);
- SWAP(p[5], p[10]);
- SWAP(p[6], p[9]);
- SWAP(p[7], p[8]);
- p += size;
- }
- break;
-
- case 12:
- while (nitems--) {
- SWAP(p[0], p[11]);
- SWAP(p[1], p[10]);
- SWAP(p[2], p[9]);
- SWAP(p[3], p[8]);
- SWAP(p[4], p[7]);
- SWAP(p[5], p[6]);
- p += size;
- }
- break;
-
- case 8:
- while (nitems--) {
- SWAP(p[0], p[7]);
- SWAP(p[1], p[6]);
- SWAP(p[2], p[5]);
- SWAP(p[3], p[4]);
- p += size;
- }
- break;
-
- case 4:
- while (nitems--) {
- SWAP(p[0], p[3]);
- SWAP(p[1], p[2]);
- p += size;
- }
- break;
-
- case 2:
- while (nitems--) {
- SWAP(p[0], p[1]);
- p += size;
- }
- break;
-
- case 1:
- /* Nothing to do. */
- break;
-
- default:
- FATAL1("Can't swap a %d-byte item for (un)dumping", size);
- }
- memcpy(pp,q,total);
- xfree(q);
-}
-#endif /* not WORDS_BIGENDIAN and not NO_DUMP_SHARE */
-
-@ That second swap is to make sure following calls don't get
-confused in the case of |dump_things|.
-
-@c
-void do_zdump(char *p, int item_size, int nitems, FILE * out_file)
-{
- int err;
- (void) out_file;
- if (nitems == 0)
- return;
-#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
- swap_items(p, nitems, item_size);
-#endif
- if (gzwrite(gz_fmtfile, (void *) p, (unsigned) (item_size * nitems)) !=
- item_size * nitems) {
- fprintf(stderr, "! Could not write %d %d-byte item(s): %s.\n", nitems,
- item_size, gzerror(gz_fmtfile, &err));
- uexit(1);
- }
-#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
- swap_items(p, nitems, item_size);
-#endif
-}
-
-@ @c
-void do_zundump(char *p, int item_size, int nitems, FILE * in_file)
-{
- int err;
- (void) in_file;
- if (nitems == 0)
- return;
- if (gzread(gz_fmtfile, (void *) p, (unsigned) (item_size * nitems)) <= 0) {
- fprintf(stderr, "Could not undump %d %d-byte item(s): %s.\n",
- nitems, item_size, gzerror(gz_fmtfile, &err));
- uexit(1);
- }
-#if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
- swap_items(p, nitems, item_size);
-#endif
-}
-
-@ @c
-#define COMPRESSION "R3"
-
-boolean zopen_w_input(FILE ** f, const char *fname, int format,
- const_string fopen_mode)
-{
- int callbackid;
- int res;
- char *fnam;
- callbackid = callback_defined(find_format_file_callback);
- if (callbackid > 0) {
- res = run_callback(callbackid, "S->R", fname, &fnam);
- if (res && fnam && strlen(fnam) > 0) {
- *f = fopen(fnam, fopen_mode);
- if (*f == NULL) {
- return 0;
- }
- } else {
- return 0;
- }
- } else {
- res = luatex_open_input(f, fname, format, fopen_mode, true);
- }
- if (res) {
- gz_fmtfile = gzdopen(fileno(*f), "rb" COMPRESSION);
- }
- return res;
-}
-
-@ @c
-boolean zopen_w_output(FILE ** f, const char *s, const_string fopen_mode)
-{
- int res = 1;
- if (luainit) {
- *f = fopen(s, fopen_mode);
- if (*f == NULL) {
- return 0;
- }
- } else {
- res = luatex_open_output(f, s, fopen_mode);
- }
- if (res) {
- gz_fmtfile = gzdopen(fileno(*f), "wb" COMPRESSION);
- }
- return res;
-}
-
-@ @c
-void zwclose(FILE * f)
-{
- (void) f;
- gzclose(gz_fmtfile);
-}
-
-@ create the dvi or pdf file
-@c
-int open_outfile(FILE ** f, const char *name, const char *mode)
-{
- FILE *res;
- res = fopen(name, mode);
- if (res != NULL) {
- *f = res;
- return 1;
- }
- return 0;
-}
-
-
-@ the caller should set |tfm_buffer=NULL| and |tfm_size=0|
-@c
-int readbinfile(FILE * f, unsigned char **tfm_buffer, int *tfm_size)
-{
- void *buf;
- int size;
- if (fseek(f, 0, SEEK_END) == 0) {
- size = (int) ftell(f);
- if (size > 0) {
- buf = xmalloc((unsigned) size);
- if (fseek(f, 0, SEEK_SET) == 0) {
- if (fread((void *) buf, (size_t) size, 1, f) == 1) {
- *tfm_buffer = (unsigned char *) buf;
- *tfm_size = size;
- return 1;
- }
- }
- } else {
- *tfm_buffer = NULL;
- *tfm_size = 0;
- return 1;
- }
- } /* seek failed, or zero-sized file */
- return 0;
-}
-
-@ Like |os.execute()|, the |runpopen()| function is called only when
-|shellenabledp == 1|. Unlike |os.execute()| we write errors to stderr, since we
-have nowhere better to use; and of course we return a file handle (or NULL)
-instead of a status indicator.
-
-@c
-static FILE *runpopen(char *cmd, const char *mode)
-{
- FILE *f = NULL;
- char *safecmd = NULL;
- char *cmdname = NULL;
- int allow;
-
-#ifdef WIN32
- char *pp;
-
- for (pp = cmd; *pp; pp++) {
- if (*pp == '\'') *pp = '"';
- }
-#endif
-
- /* If restrictedshell == 0, any command is allowed. */
- if (restrictedshell == 0) {
- allow = 1;
- } else {
- const char *thecmd = cmd;
- allow = shell_cmd_is_allowed(thecmd, &safecmd, &cmdname);
- }
- if (allow == 1)
- f = popen(cmd, mode);
- else if (allow == 2)
- f = popen(safecmd, mode);
- else if (allow == -1)
- fprintf(stderr, "\nrunpopen quotation error in command line: %s\n",
- cmd);
- else
- fprintf(stderr, "\nrunpopen command not allowed: %s\n", cmdname);
-
- if (safecmd)
- free(safecmd);
- if (cmdname)
- free(cmdname);
- return f;
-}
-
-@ piped I/O
-
-
-@ The code that implements |popen()| needs an array for tracking
- possible pipe file pointers, because these need to be
- closed using |pclose()|.
-
-@c
-#define NUM_PIPES 16
-static FILE *pipes[NUM_PIPES];
-
-#ifdef WIN32
-FILE *Poptr;
-#endif
-
-boolean open_in_or_pipe(FILE ** f_ptr, char *fn, int filefmt,
- const_string fopen_mode, boolean must_exist)
-{
- string fname = NULL;
- int i; /* iterator */
-
- /* opening a read pipe is straightforward, only have to
- skip past the pipe symbol in the file name. filename
- quoting is assumed to happen elsewhere (it does :-)) */
-
- if (shellenabledp && *fn == '|') {
- /* the user requested a pipe */
- *f_ptr = NULL;
- fname = (string) xmalloc((unsigned) (strlen(fn) + 1));
- strcpy(fname, fn);
- if (fullnameoffile)
- free(fullnameoffile);
- fullnameoffile = xstrdup(fname);
- recorder_record_input(fname + 1);
- *f_ptr = runpopen(fname + 1, "r");
- free(fname);
- for (i = 0; i < NUM_PIPES; i++) {
- if (pipes[i] == NULL) {
- pipes[i] = *f_ptr;
- break;
- }
- }
- if (*f_ptr)
- setvbuf(*f_ptr, (char *) NULL, _IONBF, 0);
-#ifdef WIN32
- Poptr = *f_ptr;
-#endif
-
- return *f_ptr != NULL;
- }
-
- return luatex_open_input(f_ptr, fn, filefmt, fopen_mode, must_exist);
-}
-
-
-boolean open_out_or_pipe(FILE ** f_ptr, char *fn, const_string fopen_mode)
-{
- string fname;
- int i; /* iterator */
-
- /* opening a write pipe takes a little bit more work, because TeX
- will perhaps have appended ".tex". To avoid user confusion as
- much as possible, this extension is stripped only when the command
- is a bare word. Some small string trickery is needed to make
- sure the correct number of bytes is free()-d afterwards */
-
- if (shellenabledp && *fn == '|') {
- /* the user requested a pipe */
- fname = (string) xmalloc((unsigned) (strlen(fn) + 1));
- strcpy(fname, fn);
- if (strchr(fname, ' ') == NULL && strchr(fname, '>') == NULL) {
- /* mp and mf currently do not use this code, but it
- is better to be prepared */
- if (STREQ((fname + strlen(fname) - 3), "tex"))
- *(fname + strlen(fname) - 4) = 0;
- *f_ptr = runpopen(fname + 1, "w");
- *(fname + strlen(fname)) = '.';
- } else {
- *f_ptr = runpopen(fname + 1, "w");
- }
- recorder_record_output(fname + 1);
- free(fname);
-
- for (i = 0; i < NUM_PIPES; i++) {
- if (pipes[i] == NULL) {
- pipes[i] = *f_ptr;
- break;
- }
- }
-
- if (*f_ptr)
- setvbuf(*f_ptr, (char *) NULL, _IONBF, 0);
-
- return *f_ptr != NULL;
- }
-
- return luatex_open_output(f_ptr, fn, fopen_mode);
-}
-
-
-void close_file_or_pipe(FILE * f)
-{
- int i; /* iterator */
-
- if (shellenabledp) {
- for (i = 0; i <= 15; i++) {
- /* if this file was a pipe, |pclose()| it and return */
- if (pipes[i] == f) {
- if (f) {
- pclose(f);
-#ifdef WIN32
- Poptr = NULL;
-#endif
- }
- pipes[i] = NULL;
- return;
- }
- }
- }
- close_file(f);
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/texmath.w b/Build/source/texk/web2c/luatexdir/tex/texmath.c
index 6d4b87a3864..69e58b0ea77 100644
--- a/Build/source/texk/web2c/luatexdir/tex/texmath.w
+++ b/Build/source/texk/web2c/luatexdir/tex/texmath.c
@@ -1,46 +1,43 @@
-% texmath.w
-%
-% Copyright 2008-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
+/*
+
+Copyright 2008-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/>.
+
+*/
+
#include "ptexlib.h"
-@ @c
#define mode mode_par
#define tail tail_par
#define head head_par
#define dir_save dirs_par
-/*
-
- \mathdisplayskipmode
+/*tex
- tex normally always inserts before and only after when larger than zero
+ Concerning display skips, \TEX\ normally always inserts before and only after
+ when larger than zero. THis can ow be controlled with |\mathdisplayskipmode|:
- 0 = normal tex
- 1 = always
- 2 = non-zero
- 3 = ignore
+ \starttabulate
+ \NC 0 \NC normal \TEX \NC \NR
+ \NC 1 \NC always \NC \NR
+ \NC 2 \NC non-zero \NC \NR
+ \NC 3 \NC ignore \NC \NR
+ \stoptabulate
*/
-@ TODO: not sure if this is the right order
-@c
#define back_error(A,B) do { \
OK_to_interrupt=false; \
back_input(); \
@@ -48,90 +45,107 @@
tex_error(A,B); \
} while (0)
-@ @c
int scan_math(pointer, int);
int scan_math_style(pointer, int);
pointer fin_mlist(pointer);
-@ When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
-{\sl mlist}, which is essentially a tree structure representing that
-formula. An mlist is a linear sequence of items, but we can regard it as
-a tree structure because mlists can appear within mlists. For example, many
-of the entries can be subscripted or superscripted, and such ``scripts''
-are mlists in their own right.
-
-An entire formula is parsed into such a tree before any of the actual
-typesetting is done, because the current style of type is usually not
-known until the formula has been fully scanned. For example, when the
-formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell
-that `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
-
-During the scanning process, each element of the mlist being built is
-classified as a relation, a binary operator, an open parenthesis, etc.,
-or as a construct like `\.{\\sqrt}' that must be built up. This classification
-appears in the mlist data structure.
-
-After a formula has been fully scanned, the mlist is converted to an hlist
-so that it can be incorporated into the surrounding text. This conversion is
-controlled by a recursive procedure that decides all of the appropriate
-styles by a ``top-down'' process starting at the outermost level and working
-in towards the subformulas. The formula is ultimately pasted together using
-combinations of horizontal and vertical boxes, with glue and penalty nodes
-inserted as necessary.
-
-An mlist is represented internally as a linked list consisting chiefly
-of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
-similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
-allowed to appear in mlists together with the noads; \TeX\ tells the difference
-by means of the |type| field, since a noad's |type| is always greater than
-that of a node. An mlist does not contain character nodes, hlist nodes, vlist
-nodes, math nodes or unset nodes; in particular, each mlist item appears in the
-variable-size part of |mem|, so the |type| field is always present.
-
-Each noad is five or more words long. The first word contains the
-|type| and |subtype| and |link| fields that are already so familiar to
-us; the second contains the attribute list pointer, and the third,
-fourth an fifth words are called the noad's |nucleus|, |subscr|, and
-|supscr| fields. (This use of a combined attribute list is temporary.
-Eventually, each of fields need their own list)
-
-Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
-parsed into an mlist containing a single element called an |ord_noad|.
-The |nucleus| of this noad is a representation of `\.x', the |subscr| is
-empty, and the |supscr| is a representation of `\.2'.
-
-The |nucleus|, |subscr|, and |supscr| fields are further broken into
-subfields. If |p| points to a noad, and if |q| is one of its principal
-fields (e.g., |q=subscr(p)|), |q=null| indicates a field with no value (the
-corresponding attribute of noad |p| is not present). Otherwise, there are
-several possibilities for the subfields, depending on the |type| of |q|.
-
-\yskip\hang|type(q)=math_char_node| means that |math_fam(q)| refers to one of
-the sixteen font families, and |character(q)| is the number of a character
-within a font of that family, as in a character node.
-
-\yskip\hang|type(q)=math_text_char_node| is similar, but the character is
-unsubscripted and unsuperscripted and it is followed immediately by another
-character from the same font. (This |type| setting appears only
-briefly during the processing; it is used to suppress unwanted italic
-corrections.)
-
-\yskip\hang|type(q)=sub_box_node| means that |math_list(q)| points to a box
-node (either an |hlist_node| or a |vlist_node|) that should be used as the
-value of the field. The |shift_amount| in the subsidiary box node is the
-amount by which that box will be shifted downward.
-
-\yskip\hang|type(q)=sub_mlist_node| means that |math_list(q)| points to
-an mlist; the mlist must be converted to an hlist in order to obtain
-the value of this field.
-
-\yskip\noindent In the latter case, we might have |math_list(q)=null|. This
-is not the same as |q=null|; for example, `\.{\$P\_\{\}\$}'
-and `\.{\$P\$}' produce different results (the former will not have the
-``italic correction'' added to the width of |P|, but the ``script skip''
-will be added).
-
-@c
+/*tex
+
+ When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an
+ {\sl mlist}, which is essentially a tree structure representing that formula.
+ An mlist is a linear sequence of items, but we can regard it as a tree
+ structure because mlists can appear within mlists. For example, many of the
+ entries can be subscripted or superscripted, and such ``scripts'' are mlists
+ in their own right.
+
+ An entire formula is parsed into such a tree before any of the actual
+ typesetting is done, because the current style of type is usually not known
+ until the formula has been fully scanned. For example, when the formula
+ `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell that
+ `\.{a+b}' will be in script size until `\.{\\over}' has appeared.
+
+ During the scanning process, each element of the mlist being built is
+ classified as a relation, a binary operator, an open parenthesis, etc., or as
+ a construct like `\.{\\sqrt}' that must be built up. This classification
+ appears in the mlist data structure.
+
+ After a formula has been fully scanned, the mlist is converted to an hlist so
+ that it can be incorporated into the surrounding text. This conversion is
+ controlled by a recursive procedure that decides all of the appropriate
+ styles by a ``top-down'' process starting at the outermost level and working
+ in towards the subformulas. The formula is ultimately pasted together using
+ combinations of horizontal and vertical boxes, with glue and penalty nodes
+ inserted as necessary.
+
+ An mlist is represented internally as a linked list consisting chiefly of
+ ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat
+ similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are
+ allowed to appear in mlists together with the noads; \TeX\ tells the
+ difference by means of the |type| field, since a noad's |type| is always
+ greater than that of a node. An mlist does not contain character nodes, hlist
+ nodes, vlist nodes, math nodes or unset nodes; in particular, each mlist item
+ appears in the variable-size part of |mem|, so the |type| field is always
+ present.
+
+ Each noad is five or more words long. The first word contains the |type| and
+ |subtype| and |link| fields that are already so familiar to us; the second
+ contains the attribute list pointer, and the third, fourth an fifth words are
+ called the noad's |nucleus|, |subscr|, and |supscr| fields. (This use of a
+ combined attribute list is temporary. Eventually, each of fields need their
+ own list)
+
+ Consider, for example, the simple formula `\.{\$x\^2\$}', which would be
+ parsed into an mlist containing a single element called an |ord_noad|. The
+ |nucleus| of this noad is a representation of `\.x', the |subscr| is empty,
+ and the |supscr| is a representation of `\.2'.
+
+ The |nucleus|, |subscr|, and |supscr| fields are further broken into
+ subfields. If |p| points to a noad, and if |q| is one of its principal fields
+ (e.g., |q=subscr(p)|), |q=null| indicates a field with no value (the
+ corresponding attribute of noad |p| is not present). Otherwise, there are
+ several possibilities for the subfields, depending on the |type| of |q|.
+
+ \startitemize
+
+ \startitem
+ |type(q)=math_char_node| means that |math_fam(q)| refers to one of
+ the sixteen font families, and |character(q)| is the number of a
+ character within a font of that family, as in a character node.
+ \stopitem
+
+ \startitem
+ |type(q)=math_text_char_node| is similar, but the character is
+ unsubscripted and unsuperscripted and it is followed immediately by
+ another character from the same font. (This |type| setting appears
+ only briefly during the processing; it is used to suppress unwanted
+ italic corrections.)
+ \stopitem
+
+ \startitem
+ |type(q)=sub_box_node| means that |math_list(q)| points to a box node
+ (either an |hlist_node| or a |vlist_node|) that should be used as the
+ value of the field. The |shift_amount| in the subsidiary box node is
+ the amount by which that box will be shifted downward.
+ \stopitem
+
+ \startitem
+ |type(q)=sub_mlist_node| means that |math_list(q)| points to an
+ mlist; the mlist must be converted to an hlist in order to obtain the
+ value of this field.
+ \stopitem
+
+ \startitem
+ In the latter case, we might have |math_list(q)=null|. This is not
+ the same as |q=null|; for example, `\.{\$P\_\{\}\$}' and `\.{\$P\$}'
+ produce different results (the former will not have the ``italic
+ correction'' added to the width of |P|, but the ``script skip'' will
+ be added).
+ \stopitem
+
+ \startitemize
+
+*/
+
static void unsave_math(void)
{
unsave();
@@ -141,10 +155,13 @@ static void unsave_math(void)
text_dir_ptr = saved_value(0);
}
-@ Sometimes it is necessary to destroy an mlist. The following
-subroutine empties the current list, assuming that |abs(mode)=mmode|.
+/*tex
+
+ Sometimes it is necessary to destroy an mlist. The following subroutine
+ empties the current list, assuming that |abs(mode)=mmode|.
+
+*/
-@c
void flush_math(void)
{
flush_node_list(vlink(head));
@@ -154,15 +171,13 @@ void flush_math(void)
incompleat_noad_par = null;
}
-@ Before we can do anything in math mode, we need fonts.
+/*tex Before we can do anything in math mode, we need fonts. */
-@c
#define MATHFONTSTACK 8
-#define MATHFONTDEFAULT 0 /* == nullfont */
+#define MATHFONTDEFAULT 0
static sa_tree math_fam_head = NULL;
-@ @c
int fam_fnt(int fam_id, int size_id)
{
int n = fam_id + (256 * size_id);
@@ -189,7 +204,6 @@ void def_fam_fnt(int fam_id, int size_id, int f, int lvl)
}
}
-@ @c
static void unsave_math_fam_data(int gl)
{
sa_stack_item st;
@@ -201,7 +215,7 @@ static void unsave_math_fam_data(int gl)
st = math_fam_head->stack[math_fam_head->stack_ptr];
if (st.level > 0) {
rawset_sa_item(math_fam_head, st.code, st.value);
- /* now do a trace message, if requested */
+ /*tex Now do a trace message, if requested. */
if (tracing_restores_par > 1) {
int size_id = st.code / 256;
int fam_id = st.code % 256;
@@ -220,15 +234,13 @@ static void unsave_math_fam_data(int gl)
}
}
-@ and parameters
+/*tex Parameters */
-@c
#define MATHPARAMSTACK 8
#define MATHPARAMDEFAULT undefined_math_parameter
static sa_tree math_param_head = NULL;
-@ @c
void def_math_param(int param_id, int style_id, scaled value, int lvl)
{
int n = param_id + (256 * style_id);
@@ -254,7 +266,6 @@ scaled get_math_param(int param_id, int style_id)
return (scaled) get_sa_item(math_param_head, n).int_value;
}
-@ @c
static void unsave_math_param_data(int gl)
{
sa_stack_item st;
@@ -266,7 +277,7 @@ static void unsave_math_param_data(int gl)
st = math_param_head->stack[math_param_head->stack_ptr];
if (st.level > 0) {
rawset_sa_item(math_param_head, st.code, st.value);
- /* now do a trace message, if requested */
+ /*tex Do a trace message, if requested. */
if (tracing_restores_par > 1) {
int param_id = st.code % 256;
int style_id = st.code / 256;
@@ -285,17 +296,16 @@ static void unsave_math_param_data(int gl)
}
}
-@ saving and unsaving of both
+/*tex Saving and unsaving of both: */
-@c
void unsave_math_data(int gl)
{
unsave_math_fam_data(gl);
unsave_math_param_data(gl);
}
-@ Dumping and undumping
-@c
+/*tex Dumping and undumping: */
+
void dump_math_data(void)
{
sa_tree_item sa_value = { 0 };
@@ -317,7 +327,6 @@ void undump_math_data(void)
math_param_head = undump_sa_tree("mathparameters");
}
-@ @c
void initialize_math(void)
{
sa_tree_item sa_value = { 0 };
@@ -333,62 +342,63 @@ void initialize_math(void)
return;
}
-@ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope,
-Clo, Pun, or Inn, for purposes of spacing and line breaking. An
-|ord_noad|, |op_noad|, |bin_noad|, |rel_noad|, |open_noad|, |close_noad|,
-|punct_noad|, or |inner_noad| is used to represent portions of the various
-types. For example, an `\.=' sign in a formula leads to the creation of a
-|rel_noad| whose |nucleus| field is a representation of an equals sign
-(usually |fam=0|, |character=075|). A formula preceded by \.{\\mathrel}
-also results in a |rel_noad|. When a |rel_noad| is followed by an
-|op_noad|, say, and possibly separated by one or more ordinary nodes (not
-noads), \TeX\ will insert a penalty node (with the current |rel_penalty|)
-just after the formula that corresponds to the |rel_noad|, unless there
-already was a penalty immediately following; and a ``thick space'' will be
-inserted just before the formula that corresponds to the |op_noad|.
-
-A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually
-has a |subtype=normal|. The only exception is that an |op_noad| might
-have |subtype=limits| or |no_limits|, if the normal positioning of
-limits has been overridden for this operator.
-
-A |radical_noad| also has a |left_delimiter| field, which usually
-represents a square root sign.
-
-A |fraction_noad| has a |right_delimiter| field as well as a |left_delimiter|.
-
-Delimiter fields have four subfields
-called |small_fam|, |small_char|, |large_fam|, |large_char|. These subfields
-represent variable-size delimiters by giving the ``small'' and ``large''
-starting characters, as explained in Chapter~17 of {\sl The \TeX book}.
-@:TeXbook}{\sl The \TeX book@>
-
-A |fraction_noad| is actually quite different from all other noads.
-It has |thickness|, |denominator|, and |numerator| fields instead of
-|nucleus|, |subscr|, and |supscr|. The |thickness| is a scaled value
-that tells how thick to make a fraction rule; however, the special
-value |default_code| is used to stand for the
-|default_rule_thickness| of the current size. The |numerator| and
-|denominator| point to mlists that define a fraction; we always have
-$$\hbox{|type(numerator)=type(denominator)=sub_mlist|}.$$ The
-|left_delimiter| and |right_delimiter| fields specify delimiters that will
-be placed at the left and right of the fraction. In this way, a
-|fraction_noad| is able to represent all of \TeX's operators \.{\\over},
-\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
- \.{\\abovewithdelims}.
-
-@ The |new_noad| function creates an |ord_noad| that is completely null
-
-@c
+/*tex
+
+ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope, Clo, Pun,
+ or Inn, for purposes of spacing and line breaking. An |ord_noad|, |op_noad|,
+ |bin_noad|, |rel_noad|, |open_noad|, |close_noad|, |punct_noad|, or
+ |inner_noad| is used to represent portions of the various types. For example,
+ an `\.=' sign in a formula leads to the creation of a |rel_noad| whose
+ |nucleus| field is a representation of an equals sign (usually |fam=0|,
+ |character=075|). A formula preceded by \.{\\mathrel} also results in a
+ |rel_noad|. When a |rel_noad| is followed by an |op_noad|, say, and possibly
+ separated by one or more ordinary nodes (not noads), \TeX\ will insert a
+ penalty node (with the current |rel_penalty|) just after the formula that
+ corresponds to the |rel_noad|, unless there already was a penalty immediately
+ following; and a ``thick space'' will be inserted just before the formula
+ that corresponds to the |op_noad|.
+
+ A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually has a
+ |subtype=normal|. The only exception is that an |op_noad| might have
+ |subtype=limits| or |no_limits|, if the normal positioning of limits has been
+ overridden for this operator.
+
+ A |radical_noad| also has a |left_delimiter| field, which usually represents
+ a square root sign.
+
+ A |fraction_noad| has a |right_delimiter| field as well as a
+ |left_delimiter|.
+
+ Delimiter fields have four subfields called |small_fam|, |small_char|,
+ |large_fam|, |large_char|. These subfields represent variable-size delimiters
+ by giving the ``small'' and ``large'' starting characters, as explained in
+ Chapter~17 of {\sl The \TeX book}.
+
+ A |fraction_noad| is actually quite different from all other noads. It has
+ |thickness|, |denominator|, and |numerator| fields instead of |nucleus|,
+ |subscr|, and |supscr|. The |thickness| is a scaled value that tells how
+ thick to make a fraction rule; however, the special value |default_code| is
+ used to stand for the |default_rule_thickness| of the current size. The
+ |numerator| and |denominator| point to mlists that define a fraction; we
+ always have $$\hbox{|type(numerator)=type(denominator)=sub_mlist|}.$$ The
+ |left_delimiter| and |right_delimiter| fields specify delimiters that will be
+ placed at the left and right of the fraction. In this way, a |fraction_noad|
+ is able to represent all of \TeX's operators \.{\\over}, \.{\\atop},
+ \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and
+ \.{\\abovewithdelims}.
+
+ The |new_noad| function creates an |ord_noad| that is completely null
+
+*/
+
pointer new_noad(void)
{
pointer p;
p = new_node(simple_noad, ord_noad_type);
- /* all noad fields are zero after this */
+ /*tex All noad fields are zero after this. */
return p;
}
-@ @c
pointer new_sub_box(pointer curbox)
{
pointer p, q;
@@ -399,40 +409,41 @@ pointer new_sub_box(pointer curbox)
return p;
}
-@ A few more kinds of noads will complete the set: An |under_noad| has its
-nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places
-an accent over its nucleus; the accent character appears as
-|math_fam(accent_chr(p))| and |math_character(accent_chr(p))|. A |vcenter_noad|
-centers its nucleus vertically with respect to the axis of the formula;
-in such noads we always have |type(nucleus(p))=sub_box|.
-
-And finally, we have the |fence_noad| type, to implement
-\TeX's \.{\\left} and \.{\\right} as well as eTeX's \.{\\middle}.
-The |nucleus| of such noads is
-replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces
-a |fence_noad| such that |delimiter(p)| holds the family and character
-codes for all left parentheses. A |fence_noad| of subtype |left_noad_side|
-never appears in an mlist except as the first element, and a |fence_noad|
-with subtype |right_noad_side| never appears in an mlist
-except as the last element; furthermore, we either have both a |left_noad_side|
-and a |right_noad_side|, or neither one is present.
-
-@ Math formulas can also contain instructions like \.{\\textstyle} that
-override \TeX's normal style rules. A |style_node| is inserted into the
-data structure to record such instructions; it is three words long, so it
-is considered a node instead of a noad. The |subtype| is either |display_style|
-or |text_style| or |script_style| or |script_script_style|. The
-second and third words of a |style_node| are not used, but they are
-present because a |choice_node| is converted to a |style_node|.
-
-\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
-|display_style|, \dots, |script_script_style|, and adds~1 to get the
-``cramped'' versions of these styles. This gives a numerical order that
-is backwards from the convention of Appendix~G in {\sl The \TeX book\/};
-i.e., a smaller style has a larger numerical value.
-@:TeXbook}{\sl The \TeX book@>
-
-@c
+/*tex
+
+ A few more kinds of noads will complete the set: An |under_noad| has its
+ nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places
+ an accent over its nucleus; the accent character appears as
+ |math_fam(accent_chr(p))| and |math_character(accent_chr(p))|. A
+ |vcenter_noad| centers its nucleus vertically with respect to the axis of the
+ formula; in such noads we always have |type(nucleus(p))=sub_box|.
+
+ And finally, we have the |fence_noad| type, to implement \TeX's \.{\\left}
+ and \.{\\right} as well as eTeX's \.{\\middle}. The |nucleus| of such noads
+ is replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces
+ a |fence_noad| such that |delimiter(p)| holds the family and character codes
+ for all left parentheses. A |fence_noad| of subtype |left_noad_side| never
+ appears in an mlist except as the first element, and a |fence_noad| with
+ subtype |right_noad_side| never appears in an mlist except as the last
+ element; furthermore, we either have both a |left_noad_side| and a
+ |right_noad_side|, or neither one is present.
+
+ Math formulas can also contain instructions like \.{\\textstyle} that
+ override \TeX's normal style rules. A |style_node| is inserted into the data
+ structure to record such instructions; it is three words long, so it is
+ considered a node instead of a noad. The |subtype| is either |display_style|
+ or |text_style| or |script_style| or |script_script_style|. The second and
+ third words of a |style_node| are not used, but they are present because a
+ |choice_node| is converted to a |style_node|.
+
+ \TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles
+ |display_style|, \dots, |script_script_style|, and adds~1 to get the
+ ``cramped'' versions of these styles. This gives a numerical order that is
+ backwards from the convention of Appendix~G in {\sl The \TeX book\/}; i.e., a
+ smaller style has a larger numerical value.
+
+*/
+
const char *math_style_names[] = {
"display", "crampeddisplay",
"text", "crampedtext",
@@ -482,93 +493,96 @@ const char *math_param_names[] = {
NULL
};
-@ @c
pointer new_style(small_number s)
-{ /* create a style node */
+{
m_style = s;
return new_node(style_node, s);
}
-@ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which
-has special subfields |display_mlist|, |text_mlist|, |script_mlist|,
-and |script_script_mlist| pointing to the mlists for each style.
+/*tex
+
+ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which has
+ special subfields |display_mlist|, |text_mlist|, |script_mlist|, and
+ |script_script_mlist| pointing to the mlists for each style.
+
+*/
-@c
static pointer new_choice(void)
-{ /* create a choice node */
- return new_node(choice_node, 0); /* the |subtype| is not used */
-}
-
-@ Let's consider now the previously unwritten part of |show_node_list|
-that displays the things that can only be present in mlists; this
-program illustrates how to access the data structures just defined.
-
-In the context of the following program, |p| points to a node or noad that
-should be displayed, and the current string contains the ``recursion history''
-that leads to this point. The recursion history consists of a dot for each
-outer level in which |p| is subsidiary to some node, or in which |p| is
-subsidiary to the |nucleus| field of some noad; the dot is replaced by
-`\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr|
-or |supscr| or |denominator| or |numerator| fields of noads. For example,
-the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for
-|x| in the (ridiculous) formula
-`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'.
-
-@c
-void display_normal_noad(pointer p); /* forward */
-void display_fence_noad(pointer p); /* forward */
-void display_fraction_noad(pointer p); /* forward */
+{
+ return new_node(choice_node, 0);
+}
+
+/*tex
+
+ Let's consider now the previously unwritten part of |show_node_list| that
+ displays the things that can only be present in mlists; this program
+ illustrates how to access the data structures just defined.
+
+ In the context of the following program, |p| points to a node or noad that
+ should be displayed, and the current string contains the ``recursion
+ history'' that leads to this point. The recursion history consists of a dot
+ for each outer level in which |p| is subsidiary to some node, or in which |p|
+ is subsidiary to the |nucleus| field of some noad; the dot is replaced by
+ `\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr| or
+ |supscr| or |denominator| or |numerator| fields of noads. For example, the
+ current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for |x|
+ in the (ridiculous) formula `\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over
+ x+y\}\}\}\}\$}'.
+
+*/
+
+void display_normal_noad(pointer p);
+void display_fence_noad(pointer p);
+void display_fraction_noad(pointer p);
void show_math_node(pointer p)
{
switch (type(p)) {
- case style_node:
- print_cmd_chr(math_style_cmd, subtype(p));
- break;
- case choice_node:
- tprint_esc("mathchoice");
- append_char('D');
- show_node_list(display_mlist(p));
- flush_char();
- append_char('T');
- show_node_list(text_mlist(p));
- flush_char();
- append_char('S');
- show_node_list(script_mlist(p));
- flush_char();
- append_char('s');
- show_node_list(script_script_mlist(p));
- flush_char();
- break;
- case simple_noad:
- case radical_noad:
- case accent_noad:
- display_normal_noad(p);
- break;
- case fence_noad:
- display_fence_noad(p);
- break;
- case fraction_noad:
- display_fraction_noad(p);
- break;
- default:
- tprint("Unknown node type!");
- break;
+ case style_node:
+ print_cmd_chr(math_style_cmd, subtype(p));
+ break;
+ case choice_node:
+ tprint_esc("mathchoice");
+ append_char('D');
+ show_node_list(display_mlist(p));
+ flush_char();
+ append_char('T');
+ show_node_list(text_mlist(p));
+ flush_char();
+ append_char('S');
+ show_node_list(script_mlist(p));
+ flush_char();
+ append_char('s');
+ show_node_list(script_script_mlist(p));
+ flush_char();
+ break;
+ case simple_noad:
+ case radical_noad:
+ case accent_noad:
+ display_normal_noad(p);
+ break;
+ case fence_noad:
+ display_fence_noad(p);
+ break;
+ case fraction_noad:
+ display_fraction_noad(p);
+ break;
+ default:
+ tprint("Unknown node type!");
+ break;
}
}
-@ Here are some simple routines used in the display of noads.
+/*tex Here are some simple routines used in the display of noads. */
-@c
static void print_fam_and_char(pointer p)
-{ /* prints family and character */
+{
tprint_esc("fam");
print_int(math_fam(p));
print_char(' ');
print(math_character(p));
}
-@ @c
static void print_delimiter(pointer p)
{
int a;
@@ -598,36 +612,38 @@ static void print_delimiter(pointer p)
tprint(" ");
}
if (small_fam(p) < 0) {
- print_int(-1); /* this should never happen */
- } else if (small_fam(p) < 16 && large_fam(p) < 16 &&
- small_char(p) < 256 && large_char(p) < 256) {
- /* traditional tex style */
+ /*tex This should never happen. */
+ print_int(-1);
+ } else if (small_fam(p) < 16 && large_fam(p) < 16 && small_char(p) < 256 && large_char(p) < 256) {
+ /*tex Traditional tex style. */
a = small_fam(p) * 256 + small_char(p);
a = a * 0x1000 + large_fam(p) * 256 + large_char(p);
- print_hex(a);
- } else if ((large_fam(p) == 0 && large_char(p) == 0) ||
- small_char(p) > 65535 || large_char(p) > 65535) {
- /* modern xetex/luatex style */
- print_hex(small_fam(p));
- print_hex(small_char(p));
+ print_qhex(a);
+ } else if ((large_fam(p) == 0 && large_char(p) == 0) || small_char(p) > 65535 || large_char(p) > 65535) {
+ /*tex \LUATEX\ style. */
+ print_qhex(small_fam(p));
+ print_qhex(small_char(p));
}
}
-@ The next subroutine will descend to another level of recursion when a
-subsidiary mlist needs to be displayed. The parameter |c| indicates what
-character is to become part of the recursion history. An empty mlist is
-distinguished from a missing field, because these are not equivalent
-(as explained above).
-@^recursion@>
+/*tex
+
+ The next subroutine will descend to another level of recursion when a
+ subsidiary mlist needs to be displayed. The parameter |c| indicates what
+ character is to become part of the recursion history. An empty mlist is
+ distinguished from a missing field, because these are not equivalent (as
+ explained above).
+
+*/
-@c
static void print_subsidiary_data(pointer p, ASCII_code c)
-{ /* display a noad field */
+{
if ((int) cur_length >= depth_threshold) {
if (p != null)
tprint(" []");
} else {
- append_char(c); /* include |c| in the recursion history */
+ /*tex Include |c| in the recursion history. */
+ append_char(c);
if (p != null) {
switch (type(p)) {
case math_char_node:
@@ -649,58 +665,58 @@ static void print_subsidiary_data(pointer p, ASCII_code c)
break;
}
}
- flush_char(); /* remove |c| from the recursion history */
+ /*tex Remove |c| from the recursion history. */
+ flush_char();
}
}
-@ @c
void display_normal_noad(pointer p)
{
switch (type(p)) {
case simple_noad:
switch (subtype(p)) {
- case ord_noad_type:
- tprint_esc("mathord");
- break;
- case op_noad_type_normal:
- case op_noad_type_limits:
- case op_noad_type_no_limits:
- tprint_esc("mathop");
- if (subtype(p) == op_noad_type_limits)
- tprint_esc("limits");
- else if (subtype(p) == op_noad_type_no_limits)
- tprint_esc("nolimits");
- break;
- case bin_noad_type:
- tprint_esc("mathbin");
- break;
- case rel_noad_type:
- tprint_esc("mathrel");
- break;
- case open_noad_type:
- tprint_esc("mathopen");
- break;
- case close_noad_type:
- tprint_esc("mathclose");
- break;
- case punct_noad_type:
- tprint_esc("mathpunct");
- break;
- case inner_noad_type:
- tprint_esc("mathinner");
- break;
- case over_noad_type:
- tprint_esc("overline");
- break;
- case under_noad_type:
- tprint_esc("underline");
- break;
- case vcenter_noad_type:
- tprint_esc("vcenter");
- break;
- default:
- tprint("<unknown noad type!>");
- break;
+ case ord_noad_type:
+ tprint_esc("mathord");
+ break;
+ case op_noad_type_normal:
+ case op_noad_type_limits:
+ case op_noad_type_no_limits:
+ tprint_esc("mathop");
+ if (subtype(p) == op_noad_type_limits)
+ tprint_esc("limits");
+ else if (subtype(p) == op_noad_type_no_limits)
+ tprint_esc("nolimits");
+ break;
+ case bin_noad_type:
+ tprint_esc("mathbin");
+ break;
+ case rel_noad_type:
+ tprint_esc("mathrel");
+ break;
+ case open_noad_type:
+ tprint_esc("mathopen");
+ break;
+ case close_noad_type:
+ tprint_esc("mathclose");
+ break;
+ case punct_noad_type:
+ tprint_esc("mathpunct");
+ break;
+ case inner_noad_type:
+ tprint_esc("mathinner");
+ break;
+ case over_noad_type:
+ tprint_esc("overline");
+ break;
+ case under_noad_type:
+ tprint_esc("underline");
+ break;
+ case vcenter_noad_type:
+ tprint_esc("vcenter");
+ break;
+ default:
+ tprint("<unknown noad type!>");
+ break;
}
break;
case radical_noad:
@@ -810,7 +826,6 @@ void display_normal_noad(pointer p)
print_subsidiary_data(subscr(p), '_');
}
-@ @c
void display_fence_noad(pointer p)
{
if (subtype(p) == right_noad_side)
@@ -822,7 +837,6 @@ void display_fence_noad(pointer p)
print_delimiter(delimiter(p));
}
-@ @c
void display_fraction_noad(pointer p)
{
tprint_esc("fraction, thickness ");
@@ -831,18 +845,14 @@ void display_fraction_noad(pointer p)
else
print_scaled(thickness(p));
if ((left_delimiter(p) != null) &&
- ((small_fam(left_delimiter(p)) != 0) ||
- (small_char(left_delimiter(p)) != 0) ||
- (large_fam(left_delimiter(p)) != 0) ||
- (large_char(left_delimiter(p)) != 0))) {
+ ((small_fam(left_delimiter(p)) != 0) || (small_char(left_delimiter(p)) != 0) ||
+ (large_fam(left_delimiter(p)) != 0) || (large_char(left_delimiter(p)) != 0))) {
tprint(", left-delimiter ");
print_delimiter(left_delimiter(p));
}
if ((right_delimiter(p) != null) &&
- ((small_fam(right_delimiter(p)) != 0) ||
- (small_char(right_delimiter(p)) != 0) ||
- (large_fam(right_delimiter(p)) != 0) ||
- (large_char(right_delimiter(p)) != 0))) {
+ ((small_fam(right_delimiter(p)) != 0) || (small_char(right_delimiter(p)) != 0) ||
+ (large_fam(right_delimiter(p)) != 0) || (large_char(right_delimiter(p)) != 0))) {
tprint(", right-delimiter ");
print_delimiter(right_delimiter(p));
}
@@ -850,16 +860,19 @@ void display_fraction_noad(pointer p)
print_subsidiary_data(denominator(p), '/');
}
-@ The routines that \TeX\ uses to create mlists are similar to those we have
-just seen for the generation of hlists and vlists. But it is necessary to
-make ``noads'' as well as nodes, so the reader should review the
-discussion of math mode data structures before trying to make sense out of
-the following program.
+/*tex
+
+ The routines that \TeX\ uses to create mlists are similar to those we have
+ just seen for the generation of hlists and vlists. But it is necessary to
+ make ``noads'' as well as nodes, so the reader should review the discussion
+ of math mode data structures before trying to make sense out of the following
+ program.
-Here is a little routine that needs to be done whenever a subformula
-is about to be processed. The parameter is a code like |math_group|.
+ Here is a little routine that needs to be done whenever a subformula is about
+ to be processed. The parameter is a code like |math_group|.
+
+*/
-@c
static void new_save_level_math(group_code c)
{
set_saved_record(0, saved_textdir, 0, text_dir_ptr);
@@ -871,7 +884,6 @@ static void new_save_level_math(group_code c)
eq_word_define(int_base + text_direction_code, math_direction_par);
}
-@ @c
static void push_math(group_code c, int mstyle)
{
if (math_direction_par != text_direction_par)
@@ -883,7 +895,6 @@ static void push_math(group_code c, int mstyle)
new_save_level_math(c);
}
-@ @c
static void enter_ordinary_math(void)
{
push_math(math_shift_group, text_style);
@@ -892,19 +903,21 @@ static void enter_ordinary_math(void)
begin_token_list(every_math_par, every_math_text);
}
-@ @c
void enter_display_math(void);
-@ We get into math mode from horizontal mode when a `\.\$' (i.e., a
-|math_shift| character) is scanned. We must check to see whether this
-`\.\$' is immediately followed by another, in case display math mode is
-called for.
+/*tex
+
+ We get into math mode from horizontal mode when a `\.\$' (i.e., a
+ |math_shift| character) is scanned. We must check to see whether this `\.\$'
+ is immediately followed by another, in case display math mode is called for.
+
+*/
-@c
void init_math(void)
{
if (cur_cmd == math_shift_cmd) {
- get_token(); /* |get_x_token| would fail on \.{\\ifmmode}\thinspace! */
+ /*tex |get_x_token| would fail on \.{\\ifmmode}\thinspace! */
+ get_token();
if ((cur_cmd == math_shift_cmd) && (mode > 0)) {
enter_display_math();
} else {
@@ -920,15 +933,17 @@ void init_math(void)
}
}
-@ We get into ordinary math mode from display math mode when `\.{\\eqno}' or
-`\.{\\leqno}' appears. In such cases |cur_chr| will be 0 or~1, respectively;
-the value of |cur_chr| is placed onto |save_stack| for safe keeping.
+/*tex
-@ When \TeX\ is in display math mode, |cur_group=math_shift_group|,
-so it is not necessary for the |start_eq_no| procedure to test for
-this condition.
+ We get into ordinary math mode from display math mode when `\.{\\eqno}' or
+ `\.{\\leqno}' appears. In such cases |cur_chr| will be 0 or~1, respectively;
+ the value of |cur_chr| is placed onto |save_stack| for safe keeping.
+
+ When \TeX\ is in display math mode, |cur_group=math_shift_group|, so it is
+ not necessary for the |start_eq_no| procedure to test for this condition.
+
+*/
-@c
void start_eq_no(void)
{
set_saved_record(0, saved_eqno, 0, cur_chr);
@@ -936,21 +951,24 @@ void start_eq_no(void)
enter_ordinary_math();
}
-@ Subformulas of math formulas cause a new level of math mode to be entered,
-on the semantic nest as well as the save stack. These subformulas arise in
-several ways: (1)~A left brace by itself indicates the beginning of a
-subformula that will be put into a box, thereby freezing its glue and
-preventing line breaks. (2)~A subscript or superscript is treated as a
-subformula if it is not a single character; the same applies to
-the nucleus of things like \.{\\underline}. (3)~The \.{\\left} primitive
-initiates a subformula that will be terminated by a matching \.{\\right}.
-The group codes placed on |save_stack| in these three cases are
-|math_group|, |math_group|, and |math_left_group|, respectively.
+/*tex
+
+ Subformulas of math formulas cause a new level of math mode to be entered, on
+ the semantic nest as well as the save stack. These subformulas arise in
+ several ways: (1)~A left brace by itself indicates the beginning of a
+ subformula that will be put into a box, thereby freezing its glue and
+ preventing line breaks. (2)~A subscript or superscript is treated as a
+ subformula if it is not a single character; the same applies to the nucleus
+ of things like \.{\\underline}. (3)~The \.{\\left} primitive initiates a
+ subformula that will be terminated by a matching \.{\\right}. The group codes
+ placed on |save_stack| in these three cases are |math_group|, |math_group|,
+ and |math_left_group|, respectively.
-Here is the code that handles case (1); the other cases are not quite as
-trivial, so we shall consider them later.
+ Here is the code that handles case (1); the other cases are not quite as
+ trivial, so we shall consider them later.
+
+*/
-@c
void math_left_brace(void)
{
pointer q;
@@ -961,18 +979,20 @@ void math_left_brace(void)
(void) scan_math(nucleus(tail), m_style);
}
-@ If the inline directions of \.{\\pardir} and \.{\\mathdir} are
-opposite, then this function will return true. Discovering that fact
-is somewhat odd because it needs traversal of the |save_stack|.
-The occurance of displayed equations is weird enough that this is
-probably still better than having yet another field in the |input_stack|
-structures.
+/*tex
+
+ If the inline directions of \.{\\pardir} and \.{\\mathdir} are opposite, then
+ this function will return true. Discovering that fact is somewhat odd because
+ it needs traversal of the |save_stack|. The occurance of displayed equations
+ is weird enough that this is probably still better than having yet another
+ field in the |input_stack| structures.
-None of this makes much sense if the inline direction of either one of
-\.{\\pardir} or \.{\\mathdir} is vertical, but in that case the current
-math machinery is ill suited anyway so I do not bother to test that.
+ None of this makes much sense if the inline direction of either one of
+ \.{\\pardir} or \.{\\mathdir} is vertical, but in that case the current math
+ machinery is ill suited anyway so I do not bother to test that.
+
+*/
-@c
static boolean math_and_text_reversed_p(void)
{
int i = save_ptr - 1;
@@ -989,26 +1009,43 @@ static boolean math_and_text_reversed_p(void)
return false;
}
-@ When we enter display math mode, we need to call |line_break| to
-process the partial paragraph that has just been interrupted by the
-display. Then we can set the proper values of |display_width| and
-|display_indent| and |pre_display_size|.
+/*tex
+
+ When we enter display math mode, we need to call |line_break| to process the
+ partial paragraph that has just been interrupted by the display. Then we can
+ set the proper values of |display_width| and |display_indent| and
+ |pre_display_size|.
+
+*/
-@c
void enter_display_math(void)
{
- scaled w; /* new or partial |pre_display_size| */
- scaled l; /* new |display_width| */
- scaled s; /* new |display_indent| */
+ /*tex new or partial |pre_display_size| */
+ scaled w;
+ /*tex new |display_width| */
+ scaled l;
+ /*tex new |display_indent| */
+ scaled s;
pointer p;
- int n; /* scope of paragraph shape specification */
- if (head == tail || /* `\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}' */
- (vlink(head) == tail && /* the 2nd of \.{\$\${ }\$\$} \.{\$\${ }\$\$} */
+ /*tex scope of paragraph shape specification */
+ int n;
+ /*tex
+
+ `\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}' or the 2nd of \.{\$\${ }\$\$}
+ \.{\$\${ }\$\$}
+
+ */
+ if (head == tail ||
+ (vlink(head) == tail &&
type(tail) == local_par_node && vlink(tail) == null)) {
if (vlink(head) == tail) {
- /* bug \#270: |resume_after_display| inserts a |local_par_node|, but if
- there is another display immediately following, we have to get rid
- of that node */
+ /*tex
+
+ |resume_after_display| inserts a |local_par_node|, but if there
+ is another display immediately following, we have to get rid of
+ that node.
+
+ */
flush_node(tail);
}
pop_nest();
@@ -1017,9 +1054,13 @@ void enter_display_math(void)
line_break(true, math_shift_group);
w = actual_box_width(just_box, x_over_n(quad(get_cur_font()),1000) * math_pre_display_gap_factor_par);
}
- /* now we are in vertical mode, working on the list that will contain the display */
- /* A displayed equation is considered to be three lines long, so we
- calculate the length and offset of line number |prev_graf+2|. */
+ /*tex
+
+ Now we are in vertical mode, working on the list that will contain the
+ display. A displayed equation is considered to be three lines long, so we
+ calculate the length and offset of line number |prev_graf+2|.
+
+ */
if (par_shape_par_ptr == null) {
if ((hang_indent_par != 0) && (((hang_after_par >= 0) && (prev_graf_par + 2 > hang_after_par)) || (prev_graf_par + 1 < -hang_after_par))) {
halfword used_hang_indent = swap_hang_indent(hang_indent_par);
@@ -1042,7 +1083,6 @@ void enter_display_math(void)
l = varmem[p].cint;
s = swap_parshape_indent(s,l);
}
-
push_math(math_shift_group, display_style);
mode = mmode;
eq_word_define(int_base + cur_fam_code, -1);
@@ -1058,12 +1098,15 @@ void enter_display_math(void)
}
}
-@ The next routine parses all variations of a delimiter code. The |extcode|
- tells what syntax form to use (\TeX, XeTeX, XeTeXnum, ...) , the
- |doclass| tells whether or not read a math class also (for \.{\\delimiter} c.s.).
- (the class is passed on for conversion to \.{\\mathchar}).
+/*tex
+
+ The next routine parses all variations of a delimiter code. The |extcode|
+ tells what syntax form to use (\TeX, XeTeX, XeTeXnum, ...) , the |doclass|
+ tells whether or not read a math class also (for \.{\\delimiter} c.s.). (the
+ class is passed on for conversion to \.{\\mathchar}).
+
+*/
-@c
static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
{
const char *hlp[] = {
@@ -1072,9 +1115,14 @@ static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
};
delcodeval d;
int mcls = 0, msfam = 0, mschr = 0, mlfam = 0, mlchr = 0;
- if (extcode == tex_mathcode) { /* \.{\\delcode}, this is the easiest */
+ if (extcode == tex_mathcode) {
+ /*tex
+
+ \.{\\delcode}, this is the easiest
+
+ */
scan_int();
- /* "MFCCFCC or "FCCFCC */
+ /*tex "MFCCFCC or "FCCFCC */
if (doclass) {
mcls = (cur_val / 0x1000000);
cur_val = (cur_val & 0xFFFFFF);
@@ -1087,8 +1135,12 @@ static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
mschr = (cur_val % 0x100000) / 0x1000;
mlfam = (cur_val & 0xFFF) / 0x100;
mlchr = (cur_val % 0x100);
- } else if (extcode == umath_mathcode) { /* \.{\\Udelcode} */
- /* <0-7>,<0-0xFF>,<0-0x10FFFF> or <0-0xFF>,<0-0x10FFFF> */
+ } else if (extcode == umath_mathcode) {
+ /*tex
+
+ \.{\\Udelcode}: <0-7>,<0-0xFF>,<0-0x10FFFF> or <0-0xFF>,<0-0x10FFFF>
+
+ */
if (doclass) {
scan_int();
mcls = cur_val;
@@ -1104,11 +1156,13 @@ static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
}
mlfam = 0;
mlchr = 0;
- } else if (extcode == umathnum_mathcode) { /* \.{\\Udelcodenum} */
- /* "FF<21bits> */
- /* the largest numeric value is $2^29-1$, but
- the top of bit 21 can't be used as it contains invalid USV's
- */
+ } else if (extcode == umathnum_mathcode) {
+ /*tex
+
+ \.{\\Udelcodenum}:"FF<21bits>; the largest numeric value is $2^29-1$,
+ but the top of bit 21 can't be used as it contains invalid USV's.
+
+ */
if (doclass) { /* such a primitive doesn't exist */
confusion("umathnum_mathcode");
}
@@ -1123,7 +1177,7 @@ static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
mlfam = 0;
mlchr = 0;
} else {
- /* something's gone wrong */
+ /*tex Something's gone wrong! */
confusion("unknown_extcode");
}
d.class_value = mcls;
@@ -1134,7 +1188,6 @@ static delcodeval do_scan_extdef_del_code(int extcode, boolean doclass)
return d;
}
-@ @c
void scan_extdef_del_code(int level, int extcode)
{
delcodeval d;
@@ -1144,11 +1197,9 @@ void scan_extdef_del_code(int level, int extcode)
scan_optional_equals();
d = do_scan_extdef_del_code(extcode, false);
set_del_code(p, d.small_family_value, d.small_character_value,
- d.large_family_value, d.large_character_value,
- (quarterword) (level));
+ d.large_family_value, d.large_character_value, (quarterword) (level));
}
-@ @c
mathcodeval scan_mathchar(int extcode)
{
char errstr[255] = { 0 };
@@ -1158,15 +1209,11 @@ mathcodeval scan_mathchar(int extcode)
};
mathcodeval d;
int mcls = 0, mfam = 0, mchr = 0;
- if (extcode == tex_mathcode) { /* \.{\\mathcode} */
- /* "TFCC */
+ if (extcode == tex_mathcode) {
+ /*tex \.{\\mathcode}: "TFCC */
scan_int();
if (cur_val > 0x8000) {
- /*
- tex_error("Invalid math code", hlp);
- cur_val = 0;
- */
- /* needed for latex: fallback to umathnum_mathcode */
+ /*tex Needed for latex: fallback to umathnum_mathcode. */
mfam = (cur_val / 0x200000) & 0x7FF;
mcls = mfam % 0x08;
mfam = mfam / 0x08;
@@ -1188,7 +1235,7 @@ mathcodeval scan_mathchar(int extcode)
mchr = (cur_val % 0x100);
}
} else if (extcode == umath_mathcode) {
- /* <0-0x7> <0-0xFF> <0-0x10FFFF> */
+ /*tex <0-0x7> <0-0xFF> <0-0x10FFFF> */
scan_int();
mcls = cur_val;
scan_int();
@@ -1202,11 +1249,14 @@ mathcodeval scan_mathchar(int extcode)
mcls = 0;
}
} else if (extcode == umathnum_mathcode) {
- /* "FFT<21bits> */
- /* the largest numeric value is $2^32-1$, but
- the top of bit 21 can't be used as it contains invalid USV's
- */
- /* Note: |scan_int| won't accept families 128-255 because these use bit 32 */
+ /*tex
+
+ "FFT<21bits>: the largest numeric value is $2^32-1$, but the top of
+ bit 21 can't be used as it contains invalid USV's
+
+ Note: |scan_int| won't accept families 128-255 because these use bit 32
+
+ */
scan_int();
mfam = (cur_val / 0x200000) & 0x7FF;
mcls = mfam % 0x08;
@@ -1219,7 +1269,7 @@ mathcodeval scan_mathchar(int extcode)
mchr = 0;
}
} else {
- /* something's gone wrong */
+ /*tex Something's gone wrong. */
confusion("unknown_extcode");
}
d.class_value = mcls;
@@ -1228,7 +1278,6 @@ mathcodeval scan_mathchar(int extcode)
return d;
}
-@ @c
void scan_extdef_math_code(int level, int extcode)
{
mathcodeval d;
@@ -1237,12 +1286,11 @@ void scan_extdef_math_code(int level, int extcode)
p = cur_val;
scan_optional_equals();
d = scan_mathchar(extcode);
- set_math_code(p, d.class_value,
- d.family_value, d.character_value, (quarterword) (level));
+ set_math_code(p, d.class_value, d.family_value, d.character_value, (quarterword) (level));
}
-@ this reads in a delcode when actually a mathcode is needed
-@c
+/*tex This reads in a delcode when actually a mathcode is needed. */
+
mathcodeval scan_delimiter_as_mathchar(int extcode)
{
delcodeval dval;
@@ -1254,14 +1302,17 @@ mathcodeval scan_delimiter_as_mathchar(int extcode)
return mval;
}
-@ Recall that the |nucleus|, |subscr|, and |supscr| fields in a noad
-are broken down into subfields called |type| and either |math_list| or
-|(math_fam,math_character)|. The job of |scan_math| is to figure out
-what to place in one of these principal fields; it looks at the
-subformula that comes next in the input, and places an encoding of
-that subformula into a given word of |mem|.
+/*tex
+
+ Recall that the |nucleus|, |subscr|, and |supscr| fields in a noad are broken
+ down into subfields called |type| and either |math_list| or
+ |(math_fam,math_character)|. The job of |scan_math| is to figure out what to
+ place in one of these principal fields; it looks at the subformula that comes
+ next in the input, and places an encoding of that subformula into a given
+ word of |mem|.
+
+*/
-@c
#define get_next_nb_nr() do { get_x_token(); } while (cur_cmd==spacer_cmd||cur_cmd==relax_cmd)
int scan_math_style(pointer p, int mstyle)
@@ -1277,7 +1328,6 @@ int scan_math_style(pointer p, int mstyle)
int scan_math(pointer p, int mstyle)
{
- /* label restart,reswitch,exit; */
mathcodeval mval = { 0, 0, 0 };
assert(p != null);
RESTART:
@@ -1289,7 +1339,7 @@ int scan_math(pointer p, int mstyle)
case char_given_cmd:
mval = get_math_code(cur_chr);
if (mval.class_value == 8) {
- /* An active character that is an |outer_call| is allowed here */
+ /*tex An active character that is an |outer_call| is allowed here. */
cur_cs = active_to_cs(cur_chr, true);
cur_cmd = eq_type(cur_cs);
cur_chr = equiv(cur_cs);
@@ -1329,8 +1379,12 @@ int scan_math(pointer p, int mstyle)
confusion("scan_math");
break;
default:
- /* The pointer |p| is placed on |save_stack| while a complex subformula
- is being scanned. */
+ /*tex
+
+ The pointer |p| is placed on |save_stack| while a complex subformula
+ is being scanned.
+
+ */
back_input();
scan_left_brace();
set_saved_record(0, saved_math, 0, p);
@@ -1347,12 +1401,15 @@ int scan_math(pointer p, int mstyle)
return 0;
}
-@ The |set_math_char| procedure creates a new noad appropriate to a given
-math code, and appends it to the current mlist. However, if the math code
-is sufficiently large, the |cur_chr| is treated as an active character and
-nothing is appended.
+/*tex
+
+ The |set_math_char| procedure creates a new noad appropriate to a given math
+ code, and appends it to the current mlist. However, if the math code is
+ sufficiently large, the |cur_chr| is treated as an active character and
+ nothing is appended.
+
+*/
-@c
#define math_class_to_type(target,source) \
switch (source) { \
case 0: target = ord_noad_type; break; \
@@ -1366,9 +1423,9 @@ nothing is appended.
void set_math_char(mathcodeval mval)
{
- pointer p; /* the new noad */
+ pointer p;
if (mval.class_value == 8) {
- /* An active character that is an |outer_call| is allowed here */
+ /*tex An active character that is an |outer_call| is allowed here */
cur_cs = active_to_cs(cur_chr, true);
cur_cmd = eq_type(cur_cs);
cur_chr = equiv(cur_cs);
@@ -1393,17 +1450,20 @@ void set_math_char(mathcodeval mval)
}
}
-@ The |math_char_in_text| procedure creates a new node representing a math char
-in text code, and appends it to the current list. However, if the math code
-is sufficiently large, the |cur_chr| is treated as an active character and
-nothing is appended.
+/*tex
+
+ The |math_char_in_text| procedure creates a new node representing a math char
+ in text code, and appends it to the current list. However, if the math code
+ is sufficiently large, the |cur_chr| is treated as an active character and
+ nothing is appended.
+
+*/
-@c
void math_char_in_text(mathcodeval mval)
{
- pointer p; /* the new node */
+ pointer p;
if (mval.class_value == 8) {
- /* An active character that is an |outer_call| is allowed here */
+ /*tex An active character that is an |outer_call| is allowed here */
cur_cs = active_to_cs(cur_chr, true);
cur_cmd = eq_type(cur_cs);
cur_chr = equiv(cur_cs);
@@ -1416,7 +1476,6 @@ void math_char_in_text(mathcodeval mval)
}
}
-@ @c
void math_math_comp(void)
{
pointer q;
@@ -1430,7 +1489,6 @@ void math_math_comp(void)
(void) scan_math(nucleus(tail), m_style);
}
-@ @c
void math_limit_switch(void)
{
const char *hlp[] = {
@@ -1449,18 +1507,23 @@ void math_limit_switch(void)
tex_error("Limit controls must follow a math operator", hlp);
}
-@ Delimiter fields of noads are filled in by the |scan_delimiter| routine.
-The first parameter of this procedure is the |mem| address where the
-delimiter is to be placed; the second tells if this delimiter follows
-\.{\\radical} or not.
+/*tex
+
+ Delimiter fields of noads are filled in by the |scan_delimiter| routine. The
+ first parameter of this procedure is the |mem| address where the delimiter
+ is to be placed; the second tells if this delimiter follows \.{\\radical} or
+ not.
+
+*/
-@c
static void scan_delimiter(pointer p, int r)
{
delcodeval dval = { 0, 0, 0, 0, 0 };
- if (r == tex_mathcode) { /* \.{\\radical} */
+ if (r == tex_mathcode) {
+ /*tex \.{\\radical} */
dval = do_scan_extdef_del_code(tex_mathcode, true);
- } else if (r == umath_mathcode) { /* \.{\\Uradical} */
+ } else if (r == umath_mathcode) {
+ /*tex \.{\\Uradical} */
dval = do_scan_extdef_del_code(umath_mathcode, false);
} else if (r == no_mathcode) {
get_next_nb_nr();
@@ -1470,12 +1533,15 @@ static void scan_delimiter(pointer p, int r)
dval = get_del_code(cur_chr);
break;
case delim_num_cmd:
- if (cur_chr == 0) /* \.{\\delimiter} */
+ if (cur_chr == 0) {
+ /*tex \.{\\delimiter} */
dval = do_scan_extdef_del_code(tex_mathcode, true);
- else if (cur_chr == 1) /* \.{\\Udelimiter} */
+ } else if (cur_chr == 1) {
+ /*tex \.{\\Udelimiter} */
dval = do_scan_extdef_del_code(umath_mathcode, true);
- else
+ } else {
confusion("scan_delimiter1");
+ }
break;
default:
dval.small_family_value = -1;
@@ -1510,7 +1576,6 @@ static void scan_delimiter(pointer p, int r)
return;
}
-@ @c
void math_radical(void)
{
halfword q;
@@ -1534,31 +1599,44 @@ void math_radical(void)
}
}
radicaloptions(tail) = options;
- if (chr_code == 0) /* \.{\\radical} */
+ if (chr_code == 0)
+ /*tex \.{\\radical} */
scan_delimiter(left_delimiter(tail), tex_mathcode);
- else if (chr_code == 1) /* \.{\\Uradical} */
+ else if (chr_code == 1)
+ /*tex \.{\\Uradical} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 2) /* \.{\\Uroot} */
+ else if (chr_code == 2)
+ /*tex \.{\\Uroot} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 3) /* \.{\\Uunderdelimiter} */
+ else if (chr_code == 3)
+ /*tex \.{\\Uunderdelimiter} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 4) /* \.{\\Uoverdelimiter} */
+ else if (chr_code == 4)
+ /*tex \.{\\Uoverdelimiter} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 5) /* \.{\\Udelimiterunder} */
+ else if (chr_code == 5)
+ /*tex \.{\\Udelimiterunder} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 6) /* \.{\\Udelimiterover} */
+ else if (chr_code == 6)
+ /*tex \.{\\Udelimiterover} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
- else if (chr_code == 7) /* \.{\\Uhextensible} */
+ else if (chr_code == 7)
+ /*tex \.{\\Uhextensible} */
scan_delimiter(left_delimiter(tail), umath_mathcode);
else
confusion("math_radical");
if (chr_code == 7) {
- q = new_node(sub_box_node, 0); /* type will change */
+ /*tex type will change */
+ q = new_node(sub_box_node, 0);
nucleus(tail) = q;
return;
} else if (chr_code == 2) {
- /* the trick with the |vlink(q)| is used by |scan_math|
- to decide whether it needs to go on */
+ /*tex
+
+ The trick with the |vlink(q)| is used by |scan_math| to decide
+ whether it needs to go on.
+
+ */
q = new_node(math_char_node, 0);
vlink(q) = tail;
degree(tail) = q;
@@ -1575,7 +1653,6 @@ void math_radical(void)
}
}
-@ @c
void math_ac(void)
{
halfword q;
@@ -1591,15 +1668,17 @@ void math_ac(void)
tex_error("Please use \\mathaccent for accents in math mode", hlp);
}
tail_append(new_node(accent_noad, 0));
- if (cur_chr == 0) { /* \.{\\mathaccent} */
+ if (cur_chr == 0) {
+ /*tex \.{\\mathaccent} */
t = scan_mathchar(tex_mathcode);
- } else if (cur_chr == 1) { /* \.{\\Umathaccent} */
+ } else if (cur_chr == 1) {
+ /*tex \.{\\Umathaccent} */
if (scan_keyword("fixed")) {
- /* top */
+ /*tex top */
subtype(tail) = 1;
t = scan_mathchar(umath_mathcode);
} else if (scan_keyword("both")) {
- /* top bottom */
+ /*tex top bottom */
if (scan_keyword("fixed")) {
subtype(tail) = 1;
}
@@ -1609,13 +1688,13 @@ void math_ac(void)
}
b = scan_mathchar(umath_mathcode);
} else if (scan_keyword("bottom")) {
- /* bottom */
+ /*tex bottom */
if (scan_keyword("fixed")) {
subtype(tail) = 2;
}
b = scan_mathchar(umath_mathcode);
} else if (scan_keyword("top")) {
- /* top */
+ /*tex top */
if (scan_keyword("fixed")) {
subtype(tail) = 1;
}
@@ -1627,7 +1706,7 @@ void math_ac(void)
}
o = scan_mathchar(umath_mathcode);
} else {
- /* top */
+ /*tex top */
t = scan_mathchar(umath_mathcode);
}
if (scan_keyword("fraction")) {
@@ -1669,7 +1748,6 @@ void math_ac(void)
(void) scan_math(nucleus(tail), cramped_style(m_style));
}
-@ @c
pointer math_vcenter_group(pointer p)
{
pointer q, r;
@@ -1681,10 +1759,13 @@ pointer math_vcenter_group(pointer p)
return q;
}
-@ The routine that scans the four mlists of a \.{\\mathchoice} is very
-much like the routine that builds discretionary nodes.
+/*tex
+
+ The routine that scans the four mlists of a \.{\\mathchoice} is very much
+ like the routine that builds discretionary nodes.
+
+*/
-@c
void append_choices(void)
{
tail_append(new_choice());
@@ -1694,10 +1775,9 @@ void append_choices(void)
scan_left_brace();
}
-@ @c
void build_choices(void)
{
- pointer p; /* the current mlist */
+ pointer p;
int prev_style;
prev_style = m_style;
unsave_math();
@@ -1718,16 +1798,19 @@ void build_choices(void)
decr(save_ptr);
return;
break;
- } /* there are no other cases */
+ }
set_saved_record(-1, saved_choices, 0, (saved_value(-1) + 1));
push_math(math_choice_group, (prev_style + 2));
scan_left_brace();
}
-@ Subscripts and superscripts are attached to the previous nucleus by the
-action procedure called |sub_sup|.
+/*tex
+
+ Subscripts and superscripts are attached to the previous nucleus by the
+ action procedure called |sub_sup|.
+
+*/
-@c
static void do_sub_sup(int no)
{
pointer q;
@@ -1736,7 +1819,8 @@ static void do_sub_sup(int no)
q = new_node(sub_mlist_node, 0);
nucleus(tail) = q;
}
- if (cur_cmd == sup_mark_cmd || cur_chr == sup_mark_cmd) { /* |super_sub_script| */
+ if (cur_cmd == sup_mark_cmd || cur_chr == sup_mark_cmd) {
+ /*tex |super_sub_script| */
if (supscr(tail) != null) {
const char *hlp[] = {
"I treat `x^1^2' essentially like `x^1{}^2'.", NULL
@@ -1781,19 +1865,21 @@ void no_sub_sup(void)
do_sub_sup(1);
}
+/*tex
-@ An operation like `\.{\\over}' causes the current mlist to go into a
-state of suspended animation: |incompleat_noad| points to a |fraction_noad|
-that contains the mlist-so-far as its numerator, while the denominator
-is yet to come. Finally when the mlist is finished, the denominator will
-go into the incompleat fraction noad, and that noad will become the
-whole formula, unless it is surrounded by `\.{\\left}' and `\.{\\right}'
-delimiters.
+ An operation like `\.{\\over}' causes the current mlist to go into a state of
+ suspended animation: |incompleat_noad| points to a |fraction_noad| that
+ contains the mlist-so-far as its numerator, while the denominator is yet to
+ come. Finally when the mlist is finished, the denominator will go into the
+ incompleat fraction noad, and that noad will become the whole formula, unless
+ it is surrounded by `\.{\\left}' and `\.{\\right}' delimiters.
+
+*/
-@c
void math_fraction(void)
{
- halfword c; /* the type of generalized fraction we are scanning */
+ /*tex The type of generalized fraction we are scanning: */
+ halfword c;
pointer q;
halfword options = 0;
halfword temp_value;
@@ -1870,16 +1956,19 @@ void math_fraction(void)
}
}
-@ At the end of a math formula or subformula, the |fin_mlist| routine is
-called upon to return a pointer to the newly completed mlist, and to
-pop the nest back to the enclosing semantic level. The parameter to
-|fin_mlist|, if not null, points to a |fence_noad| that ends the
-current mlist; this |fence_noad| has not yet been appended.
+/*tex
+
+ At the end of a math formula or subformula, the |fin_mlist| routine is called
+ upon to return a pointer to the newly completed mlist, and to pop the nest
+ back to the enclosing semantic level. The parameter to |fin_mlist|, if not
+ null, points to a |fence_noad| that ends the current mlist; this |fence_noad|
+ has not yet been appended.
+
+*/
-@c
pointer fin_mlist(pointer p)
{
- pointer q; /* the mlist to return */
+ pointer q;
if (incompleat_noad_par != null) {
if (denominator(incompleat_noad_par) != null) {
type(denominator(incompleat_noad_par)) = sub_mlist_node;
@@ -1892,9 +1981,8 @@ pointer fin_mlist(pointer p)
q = incompleat_noad_par;
} else {
q = math_list(numerator(incompleat_noad_par));
- if ((type(q) != fence_noad) || (subtype(q) != left_noad_side)
- || (delim_par == null))
- confusion("right"); /* this can't happen */
+ if ((type(q) != fence_noad) || (subtype(q) != left_noad_side) || (delim_par == null))
+ confusion("right");
math_list(numerator(incompleat_noad_par)) = vlink(delim_par);
vlink(delim_par) = incompleat_noad_par;
vlink(incompleat_noad_par) = p;
@@ -1907,26 +1995,50 @@ pointer fin_mlist(pointer p)
return q;
}
-@ Now at last we're ready to see what happens when a right brace occurs
-in a math formula. Two special cases are simplified here: Braces are effectively
-removed when they surround a single Ord without sub/superscripts, or when they
-surround an accent that is the nucleus of an Ord atom.
+/*tex
+
+ Now at last we're ready to see what happens when a right brace occurs in a
+ math formula. Two special cases are simplified here: Braces are effectively
+ removed when they surround a single Ord without sub/superscripts, or when
+ they surround an accent that is the nucleus of an Ord atom.
+
+*/
-@c
void close_math_group(pointer p)
{
int old_style = m_style;
unsave_math();
-
decr(save_ptr);
assert(saved_type(0) == saved_math);
type(saved_value(0)) = sub_mlist_node;
p = fin_mlist(null);
math_list(saved_value(0)) = p;
- if (p != null) {
- if (vlink(p) == null) {
- if (type(p) == simple_noad && subtype(p) == ord_noad_type) {
- if (subscr(p) == null && supscr(p) == null) {
+ if (p != null && vlink(p) == null) {
+ if (type(p) == simple_noad) {
+ if (subscr(p) == null && supscr(p) == null) {
+ /*tex (subtype(p) == ord_noad_type) */
+ int flatten = 0;
+ int modepar = math_flatten_mode_par;
+ switch (subtype(p)) {
+ case ord_noad_type :
+ flatten = (modepar & 1) == 1;
+ break;
+ case bin_noad_type :
+ flatten = (modepar & 2) == 2;
+ break;
+ case rel_noad_type :
+ flatten = (modepar & 4) == 4;
+ break;
+ case punct_noad_type :
+ flatten = (modepar & 8) == 8;
+ break;
+ case inner_noad_type :
+ flatten = (modepar & 16) == 16;
+ break;
+ default:
+ break;
+ }
+ if (flatten) {
type(saved_value(0)) = type(nucleus(p));
if (type(nucleus(p)) == math_char_node) {
math_fam(saved_value(0)) = math_fam(nucleus(p));
@@ -1941,24 +2053,21 @@ void close_math_group(pointer p)
node_attr(nucleus(p)) = null;
flush_node(p);
}
- } else if (type(p) == accent_noad) {
- if (saved_value(0) == nucleus(tail)) {
- if (type(tail) == simple_noad
- && subtype(tail) == ord_noad_type) {
- pointer q = head;
- while (vlink(q) != tail)
- q = vlink(q);
- vlink(q) = p;
- nucleus(tail) = null;
- subscr(tail) = null;
- supscr(tail) = null;
- delete_attribute_ref(node_attr(p));
- node_attr(p) = node_attr(tail);
- node_attr(tail) = null;
- flush_node(tail);
- tail = p;
- }
- }
+ }
+ } else if (type(p) == accent_noad) {
+ if (saved_value(0) == nucleus(tail) && type(tail) == simple_noad && subtype(tail) == ord_noad_type) {
+ pointer q = head;
+ while (vlink(q) != tail)
+ q = vlink(q);
+ vlink(q) = p;
+ nucleus(tail) = null;
+ subscr(tail) = null;
+ supscr(tail) = null;
+ delete_attribute_ref(node_attr(p));
+ node_attr(p) = node_attr(tail);
+ node_attr(tail) = null;
+ flush_node(tail);
+ tail = p;
}
}
}
@@ -1969,30 +2078,36 @@ void close_math_group(pointer p)
vlink(saved_value(0)) = null;
saved_value(0) = q;
(void) scan_math(saved_value(0), old_style);
- /* restart */
+ /*tex restart */
}
}
-@ We have dealt with all constructions of math mode except `\.{\\left}' and
-`\.{\\right}', so the picture is completed by the following sections of
-the program. The |middle| feature of eTeX allows one ore several \.{\\middle}
-delimiters to appear between \.{\\left} and \.{\\right}.
+/*tex
+
+ We have dealt with all constructions of math mode except `\.{\\left}' and
+ `\.{\\right}', so the picture is completed by the following sections of the
+ program. The |middle| feature of eTeX allows one ore several \.{\\middle}
+ delimiters to appear between \.{\\left} and \.{\\right}.
+
+*/
-@c
void math_left_right(void)
{
- halfword t; /* |left_noad_side| .. |right_noad_side| */
- pointer p; /* new noad */
- pointer q; /* resulting mlist */
- pointer r; /* temporary */
+ /*tex |left_noad_side| .. |right_noad_side| */
+ halfword t;
+ /*tex new noad */
+ pointer p;
+ /*tex resulting mlist */
+ pointer q;
+ /*tex temporary */
+ pointer r;
halfword ht = 0;
halfword dp = 0;
halfword options = 0;
halfword type = -1 ;
t = cur_chr;
-
if (t > 10) {
- /* we have \Uleft \Uright \Umiddle */
+ /*tex we have \Uleft \Uright \Umiddle */
t = t - 10;
while (1) {
if (scan_keyword("height")) {
@@ -2015,7 +2130,6 @@ void math_left_right(void)
}
}
}
-
if ((t != no_noad_side) && (t != left_noad_side) && (cur_group != math_left_group)) {
if (cur_group == math_shift_group) {
scan_delimiter(null, no_mathcode);
@@ -2041,14 +2155,12 @@ void math_left_right(void)
subtype(p) = (quarterword) t;
r = new_node(delim_node, 0);
delimiter(p) = r;
-
delimiterheight(p) = ht;
delimiterdepth(p) = dp;
delimiteroptions(p) = options;
delimiterclass(p) = type;
delimiteritalic(p) = 0;
delimitersamesize(p) = 0;
-
scan_delimiter(delimiter(p), no_mathcode);
if (t == no_noad_side) {
tail_append(new_noad());
@@ -2058,7 +2170,6 @@ void math_left_right(void)
math_list(nucleus(tail)) = p;
return ;
}
-
if (t == left_noad_side) {
q = p;
} else {
@@ -2080,10 +2191,13 @@ void math_left_right(void)
}
}
-@ \TeX\ gets to the following part of the program when
-the first `\.\$' ending a display has been scanned.
+/*tex
+
+ \TeX\ gets to the following part of the program when the first `\.\$' ending
+ a display has been scanned.
+
+*/
-@c
static void check_second_math_shift(void)
{
get_x_token();
@@ -2119,7 +2233,6 @@ static void check_inline_math_end(void)
}
}
-@ @c
static void resume_after_display(void)
{
if (cur_group != math_shift_group)
@@ -2129,7 +2242,7 @@ static void resume_after_display(void)
push_nest();
mode = hmode;
space_factor_par = 1000;
- /* this needs to be intercepted in the display math start ! */
+ /*tex This needs to be intercepted in the display math start! */
tail_append(make_local_par_node(penalty_par_code));
get_x_token();
if (cur_cmd != spacer_cmd)
@@ -2140,30 +2253,40 @@ static void resume_after_display(void)
}
}
-@ The fussiest part of math mode processing occurs when a displayed formula is
-being centered and placed with an optional equation number.
+/*tex
+
+ The fussiest part of math mode processing occurs when a displayed formula is
+ being centered and placed with an optional equation number.
-At this time we are in vertical mode (or internal vertical mode).
+ At this time we are in vertical mode (or internal vertical mode).
- |p| points to the mlist for the formula.
- |a| is either |null| or it points to a box containing the equation number.
- |l| is true if there was an \.{\\leqno}/ (so |a| is a horizontal box).
+ \starttabulate
+ \NC \type {p} \NC points to the mlist for the formula \NC \NR
+ \NC \type {a} \NC is either |null| or it points to a box containing the equation number \NC \NR
+ \NC \type {l} \NC is true if there was an \.{\\leqno}/ (so |a| is a horizontal box) \NC \NR
+ \stoptabulate
+
+*/
-@c
#define inject_display_skip_before(g) \
if (g > 0) { \
switch (display_skip_mode_par) { \
- case 0 : /* normal tex | always */ \
- case 1 : /* always */ \
+ case 0 : \
+ /*tex normal tex | always */ \
+ case 1 : \
+ /*tex always */ \
tail_append(new_param_glue(g)); \
break; \
- case 2 : /* non-zero */ \
+ case 2 : \
+ /*tex non-zero */ \
if (! glue_is_zero(glue_par(g))) \
tail_append(new_param_glue(g)); \
break; \
- case 3: /* ignore */ \
+ case 3: \
+ /*tex ignore */ \
break; \
- default: /* > 3 reserved for future use */ \
+ default: \
+ /*tex > 3 reserved for future use */ \
tail_append(new_param_glue(g)); \
break; \
} \
@@ -2172,17 +2295,22 @@ At this time we are in vertical mode (or internal vertical mode).
#define inject_display_skip_after(g) \
if (g > 0) { \
switch (display_skip_mode_par) { \
- case 0 : /* normal tex | always */ \
- case 1 : /* always */ \
+ case 0 : \
+ /*tex normal tex | always */ \
+ case 1 : \
+ /*tex always */ \
tail_append(new_param_glue(g)); \
break; \
- case 2 : /* non-zero */ \
+ case 2 : \
+ /*tex non-zero */ \
if (! glue_is_zero(glue_par(g))) \
tail_append(new_param_glue(g)); \
break; \
- case 3: /* ignore */ \
+ case 3: \
+ /*tex ignore */ \
break; \
- default: /* > 3 reserved for future use */ \
+ default: \
+ /*tex > 3 reserved for future use */ \
tail_append(new_param_glue(g)); \
break; \
} \
@@ -2190,18 +2318,30 @@ At this time we are in vertical mode (or internal vertical mode).
static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
{
- pointer eq_box; /* box containing the equation */
- scaled eq_w; /* width of the equation */
- scaled line_w; /* width of the line */
- scaled eqno_w; /* width of equation number */
- scaled eqno_w2; /* width of equation number plus space to separate from equation */
- scaled line_s; /* move the line right this much */
- scaled d; /* displacement of equation in the line */
- small_number g1, g2; /* glue parameter codes for before and after */
- pointer r,s; /* kern nodes used to position the display */
- pointer t; /* tail of adjustment list */
- pointer pre_t; /* tail of pre-adjustment list */
- boolean swap_dir; /* true if the math and surrounding text dirs are opposed */
+ /*tex box containing the equation */
+ pointer eq_box;
+ /*tex width of the equation */
+ scaled eq_w;
+ /*tex width of the line */
+ scaled line_w;
+ /*tex width of equation number */
+ scaled eqno_w;
+ /*tex width of equation number plus space to separate from equation */
+ scaled eqno_w2;
+ /*tex move the line right this much */
+ scaled line_s;
+ /*tex displacement of equation in the line */
+ scaled d;
+ /*tex glue parameter codes for before and after */
+ small_number g1, g2;
+ /*tex kern nodes used to position the display */
+ pointer r,s;
+ /*tex tail of adjustment list */
+ pointer t;
+ /*tex tail of pre-adjustment list */
+ pointer pre_t;
+ /*tex true if the math and surrounding text dirs are opposed */
+ boolean swap_dir;
scaled eqno_width;
swap_dir = (pre_display_direction_par < 0 ? true : false );
if (eqno_box != null && swap_dir)
@@ -2209,7 +2349,7 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
adjust_tail = adjust_head;
pre_adjust_tail = pre_adjust_head;
eq_box = hpack(p, 0, additional, -1);
- subtype(eq_box) = equation_list; /* new */
+ subtype(eq_box) = equation_list;
build_attribute_list(eq_box);
p = list_ptr(eq_box);
t = adjust_tail;
@@ -2227,21 +2367,23 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
eqno_w = width(eqno_box);
eqno_width = eqno_w;
eqno_w2 = eqno_w + round_xn_over_d(math_eqno_gap_step_par, get_math_quad_style(text_style), 1000);
- subtype(eqno_box) = equation_number_list; /* new */
- /* build_attribute_list(eqno_box); */ /* probably already set */
- }
+ subtype(eqno_box) = equation_number_list;
+ /*tex build_attribute_list(eqno_box); */
+ }
if (eq_w + eqno_w2 > line_w) {
- /* The user can force the equation number to go on a separate line
- by causing its width to be zero. */
+ /*tex
+
+ The user can force the equation number to go on a separate line by
+ causing its width to be zero.
+
+ */
if ((eqno_w != 0) && ((eq_w - total_shrink[normal] + eqno_w2 <= line_w)
- || (total_shrink[sfi] != 0)
- || (total_shrink[fil] != 0)
- || (total_shrink[fill] != 0)
- || (total_shrink[filll] != 0))) {
+ || (total_shrink[sfi] != 0) || (total_shrink[fil] != 0)
+ || (total_shrink[fill] != 0) || (total_shrink[filll] != 0))) {
list_ptr(eq_box) = null;
flush_node(eq_box);
eq_box = hpack(p, line_w - eqno_w2, exactly, -1);
- subtype(eq_box) = equation_list; /* new */
+ subtype(eq_box) = equation_list;
build_attribute_list(eq_box);
} else {
eqno_w = 0;
@@ -2249,47 +2391,52 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
list_ptr(eq_box) = null;
flush_node(eq_box);
eq_box = hpack(p, line_w, exactly, -1);
- subtype(eq_box) = equation_list; /* new */
+ subtype(eq_box) = equation_list;
build_attribute_list(eq_box);
}
}
eq_w = width(eq_box);
}
- /* We try first to center the display without regard to the existence of
- the equation number. If that would make it too close (where ``too close''
- means that the space between display and equation number is less than the
- width of the equation number), we either center it in the remaining space
- or move it as far from the equation number as possible. The latter alternative
- is taken only if the display begins with glue, since we assume that the
- user put glue there to control the spacing precisely.
- */
+ /*tex
+
+ We try first to center the display without regard to the existence of the
+ equation number. If that would make it too close (where ``too close''
+ means that the space between display and equation number is less than the
+ width of the equation number), we either center it in the remaining space
+ or move it as far from the equation number as possible. The latter
+ alternative is taken only if the display begins with glue, since we
+ assume that the user put glue there to control the spacing precisely.
+
+ */
d = half(line_w - eq_w);
- if ((eqno_w > 0) && (d < 2 * eqno_w)) { /* too close */
+ if ((eqno_w > 0) && (d < 2 * eqno_w)) {
+ /*tex too close */
d = half(line_w - eq_w - eqno_w);
if (p != null)
if (!is_char_node(p))
if (type(p) == glue_node)
d = 0;
}
-
tail_append(new_penalty(pre_display_penalty_par,after_display_penalty));
- if ((d + line_s <= pre_display_size_par) || l) { /* not enough clearance */
+ if ((d + line_s <= pre_display_size_par) || l) {
+ /*tex not enough clearance */
g1 = above_display_skip_code;
g2 = below_display_skip_code;
} else {
g1 = above_display_short_skip_code;
g2 = below_display_short_skip_code;
}
+ /*tex
+
+ If the equation number is set on a line by itself, either before or after
+ the formula, we append an infinite penalty so that no page break will
+ separate the display from its number; and we use the same size and
+ displacement for all three potential lines of the display, even though
+ `\.{\\parshape}' may specify them differently.
- /* If the equation number is set on a line by itself, either before or
- after the formula, we append an infinite penalty so that no page break will
- separate the display from its number; and we use the same size and
- displacement for all three potential lines of the display, even though
- `\.{\\parshape}' may specify them differently.
- */
- /* \.{\\leqno} on a forced single line due to |width=0| */
- /* it follows that |type(a)=hlist_node| */
+ \.{\\leqno} on a forced single line due to |width=0|; it follows that |type(a)=hlist_node|
+ */
if (eqno_box && l && (eqno_w == 0)) {
/* if (math_direction_par==dir_TLT) { */
shift_amount(eqno_box) = 0;
@@ -2300,40 +2447,27 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
} else {
inject_display_skip_before(g1);
}
-
if (eqno_w != 0) {
r = new_kern(line_w - eq_w - eqno_w - d);
if (l) {
if (swap_dir) {
if (math_direction_par==dir_TLT) {
- /* TRT + TLT + \eqno, (swap_dir=true, math_direction_par=TLT, l=true) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 1\n");
-#endif
+ /*tex TRT + TLT + \eqno: (swap_dir=true, math_direction_par=TLT, l=true) */
s = new_kern(width(r) + eqno_w);
try_couple_nodes(eqno_box,r);
try_couple_nodes(r,eq_box);
try_couple_nodes(eq_box,s);
} else {
- /* TLT + TRT + \eqno, (swap_dir=true, math_direction_par=TRT, l=true) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 2\n");
-#endif
+ /*tex TLT + TRT + \eqno: (swap_dir=true, math_direction_par=TRT, l=true) */
try_couple_nodes(eqno_box,r);
try_couple_nodes(r,eq_box);
}
} else {
if (math_direction_par==dir_TLT) {
- /* TLT + TLT + \leqno, (swap_dir=false, math_direction_par=TLT, l=true) */ /* OK */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 3\n");
-#endif
+ /*tex TLT + TLT + \leqno: (swap_dir=false, math_direction_par=TLT, l=true) */
s = new_kern(width(r) + eqno_w);
} else {
- /* TRT + TRT + \leqno, (swap_dir=false, math_direction_par=TRT, l=true) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 4\n");
-#endif
+ /*tex TRT + TRT + \leqno: (swap_dir=false, math_direction_par=TRT, l=true) */
s = new_kern(width(r));
}
try_couple_nodes(eqno_box,r);
@@ -2344,30 +2478,18 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
} else {
if (swap_dir) {
if (math_direction_par==dir_TLT) {
- /* TRT + TLT + \leqno, (swap_dir=true, math_direction_par=TLT, l=false) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 5\n");
-#endif
+ /*tex TRT + TLT + \leqno: (swap_dir=true, math_direction_par=TLT, l=false) */
} else {
- /* TLT + TRT + \leqno, (swap_dir=true, math_direction_par=TRT, l=false) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 6\n");
-#endif
+ /*tex TLT + TRT + \leqno: (swap_dir=true, math_direction_par=TRT, l=false) */
}
try_couple_nodes(eq_box,r);
try_couple_nodes(r,eqno_box);
} else {
if (math_direction_par==dir_TLT) {
- /* TLT + TLT + \eqno, (swap_dir=false, math_direction_par=TLT, l=false) */ /* OK */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 7\n");
-#endif
+ /*tex TLT + TLT + \eqno: (swap_dir=false, math_direction_par=TLT, l=false) */
s = new_kern(d);
} else {
- /* TRT + TRT + \eqno, (swap_dir=false, math_direction_par=TRT, l=false) */
-#ifdef DEBUG
- fprintf(stderr, "\nDEBUG: CASE 8\n");
-#endif
+ /*tex TRT + TRT + \eqno: (swap_dir=false, math_direction_par=TRT, l=false) */
s = new_kern(width(r) + eqno_w);
}
try_couple_nodes(s,eq_box);
@@ -2383,9 +2505,8 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
} else {
shift_amount(eq_box) = line_s + d;
}
-/* check for prev: */
+ /*tex check for prev: */
append_to_vlist(eq_box,lua_key_index(equation));
-
if ((eqno_box != null) && (eqno_w == 0) && !l) {
tail_append(new_penalty(inf_penalty,equation_number_penalty));
/* if (math_direction_par==dir_TLT) { */
@@ -2395,15 +2516,14 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
append_to_vlist(eqno_box,lua_key_index(equation_number));
g2 = 0;
}
- if (t != adjust_head) { /* migrating material comes after equation number */
+ if (t != adjust_head) {
+ /*tex migrating material comes after equation number */
vlink(tail) = vlink(adjust_head);
- /* needs testing */
alink(adjust_tail) = alink(tail);
tail = t;
}
if (pre_t != pre_adjust_head) {
vlink(tail) = vlink(pre_adjust_head);
- /* needs testing */
alink(pre_adjust_tail) = alink(tail);
tail = pre_t;
}
@@ -2412,20 +2532,25 @@ static void finish_displayed_math(boolean l, pointer eqno_box, pointer p)
resume_after_display();
}
-@ @c
void after_math(void)
{
- int m; /* |mmode| or |-mmode| */
- pointer p; /* the formula */
- pointer a = null; /* box containing equation number */
- boolean l = false; /* `\.{\\leqno}' instead of `\.{\\eqno}' */
+ /*tex |mmode| or |-mmode| */
+ int m;
+ /*tex the formula */
+ pointer p;
+ /*tex box containing equation number */
+ pointer a = null;
+ /*tex `\.{\\leqno}' instead of `\.{\\eqno}' */
+ boolean l = false;
m = mode;
- p = fin_mlist(null); /* this pops the nest */
+ /*tex this pops the nest */
+ p = fin_mlist(null);
if (cur_cmd == math_shift_cs_cmd &&
(cur_chr == text_style || cur_chr == display_style)) {
you_cant();
}
- if (mode == -m) { /* end of equation number */
+ if (mode == -m) {
+ /*tex end of equation number */
if (cur_cmd == math_shift_cmd) {
check_second_math_shift();
} else {
@@ -2435,7 +2560,8 @@ void after_math(void)
a = hpack(vlink(temp_head), 0, additional, -1);
build_attribute_list(a);
unsave_math();
- decr(save_ptr); /* now |cur_group=math_shift_group| */
+ /*tex now |cur_group=math_shift_group| */
+ decr(save_ptr);
assert(saved_type(0) == saved_eqno);
if (saved_value(0) == 1)
l = true;
@@ -2444,47 +2570,50 @@ void after_math(void)
}
if (m < 0) {
- /* The |unsave| is done after everything else here; hence an appearance of
- `\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing at these
- particular \.\$'s. This is consistent with the conventions of
- `\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display affects the
- space above that display.
- */
+ /*tex
+
+ The |unsave| is done after everything else here; hence an appearance
+ of `\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing
+ at these particular \.\$'s. This is consistent with the conventions
+ of `\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display
+ affects the space above that display.
+
+ */
if (cur_cmd == math_shift_cs_cmd) {
check_inline_math_end();
}
tail_append(new_math(math_surround_par, before));
- /* begin mathskip code */
+ /*tex begin mathskip code */
switch (math_skip_mode) {
case 0 :
- /* obey mathsurround when zero glue */
+ /*tex obey mathsurround when zero glue */
if (! glue_is_zero(math_skip_par)) {
copy_glue_values(tail,math_skip_par);
surround(tail) = 0;
}
break ;
case 1 :
- /* always left */
+ /*tex always left */
case 3 :
- /* always both */
+ /*tex always both */
case 6 :
- /* only when skip */
+ /*tex only when skip */
copy_glue_values(tail,math_skip_par);
surround(tail) = 0;
break ;
case 2 :
- /* only right */
+ /*tex only right */
surround(tail) = 0;
break ;
case 4 :
- /* ignore, obey marthsurround */
+ /*tex ignore, obey marthsurround */
break ;
case 5:
- /* all spacing disabled */
+ /*tex all spacing disabled */
surround(tail) = 0;
break ;
}
- /* end mathskip code */
+ /*tex end mathskip code */
if (dir_math_save) {
tail_append(new_dir(math_direction_par));
}
@@ -2494,41 +2623,42 @@ void after_math(void)
tail = vlink(tail);
}
if (dir_math_save) {
- tail_append(new_dir(math_direction_par - dir_swap));
+ tail_append(new_dir(math_direction_par));
+ subtype(tail) = cancel_dir;
}
dir_math_save = false;
tail_append(new_math(math_surround_par, after));
- /* begin mathskip code */
+ /*tex begin mathskip code */
switch (math_skip_mode) {
case 0 :
- /* obey mathsurround when zero glue */
+ /*tex obey mathsurround when zero glue */
if (! glue_is_zero(math_skip_par)) {
copy_glue_values(tail,math_skip_par);
surround(tail) = 0;
}
break ;
case 2 :
- /* always right */
+ /*tex always right */
case 3 :
- /* always both */
+ /*tex always both */
case 6 :
- /* only when skip */
+ /*tex only when skip */
copy_glue_values(tail,math_skip_par);
surround(tail) = 0;
break ;
case 1 :
- /* only left */
+ /*tex only left */
surround(tail) = 0;
break ;
case 4 :
- /* ignore, obey marthsurround */
+ /*tex ignore, obey marthsurround */
break ;
case 5:
- /* all spacing disabled */
+ /*tex all spacing disabled */
surround(tail) = 0;
break ;
}
- /* end mathskip code */
+ /*tex end mathskip code */
space_factor_par = 1000;
unsave_math();
} else {
@@ -2544,12 +2674,15 @@ void after_math(void)
}
}
-@ When \.{\\halign} appears in a display, the alignment routines operate
-essentially as they do in vertical mode. Then the following program is
-activated, with |p| and |q| pointing to the beginning and end of the
-resulting list, and with |aux_save| holding the |prev_depth| value.
+/*tex
+
+ When \.{\\halign} appears in a display, the alignment routines operate
+ essentially as they do in vertical mode. Then the following program is
+ activated, with |p| and |q| pointing to the beginning and end of the
+ resulting list, and with |aux_save| holding the |prev_depth| value.
+
+*/
-@c
void finish_display_alignment(pointer p, pointer q, halfword saved_prevdepth)
{
do_assignments();
@@ -2570,9 +2703,8 @@ void finish_display_alignment(pointer p, pointer q, halfword saved_prevdepth)
resume_after_display();
}
-@ Interface to \.{\\Umath} and \.{\\mathstyle}
+/*tex Interface to \.{\\Umath} and \.{\\mathstyle}: */
-@c
void setup_math_style(void)
{
pointer q;
@@ -2582,7 +2714,6 @@ void setup_math_style(void)
(void) scan_math_style(nucleus(tail), num_style(m_style));
}
-@ @c
void print_math_style(void)
{
if (abs(mode) == mmode)
diff --git a/Build/source/texk/web2c/luatexdir/tex/texnodes.c b/Build/source/texk/web2c/luatexdir/tex/texnodes.c
new file mode 100644
index 00000000000..1dd28cdf56d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/tex/texnodes.c
@@ -0,0 +1,4770 @@
+/*
+
+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/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/*tex
+
+ This module started out using NDEBUG to trigger checking invalid node usage,
+ something that is needed because users can mess up nodes in Lua. At some
+ point that code was always enabled so it is now always on but still can be
+ recognized as additional code. And as the performance hit is close to zero so
+ disabling makes no sense, not even to make it configureable. There is a
+ little more memory used but that is neglectable compared to other memory
+ usage.
+
+*/
+
+#define MAX_CHAIN_SIZE 13 /* why not a bit larger */
+#define CHECK_NODE_USAGE 1 /* this triggers checking */
+
+memory_word *volatile varmem = NULL;
+
+#ifdef CHECK_NODE_USAGE
+ char *varmem_sizes = NULL;
+#endif
+
+halfword var_mem_max = 0;
+halfword rover = 0;
+
+halfword free_chain[MAX_CHAIN_SIZE] = { null };
+
+static int my_prealloc = 0;
+
+/*tex Used in font and lang: */
+
+int fix_node_lists = 1;
+
+/*tex Defined below. */
+
+halfword slow_get_node(int s);
+
+#define fake_node 100
+#define fake_node_size 2
+#define fake_node_name "fake"
+
+#define variable_node_size 2
+
+/*tex
+
+ The following definitions are used for keys at the \LUA\ end and
+ provide an efficient way to share hashed strings.
+
+*/
+
+# define init_node_key(target,n,key) \
+ target[n].lua = luaS_##key##_index; \
+ target[n].name = luaS_##key##_ptr;
+
+# define init_field_key(target,n,key) \
+ target[n].lua = luaS_##key##_index; \
+ target[n].name = luaS_##key##_ptr;
+
+# define init_field_nop(target,n) \
+ target[n].lua = 0; \
+ target[n].name = NULL;
+
+/*tex The fields of nodes. */
+
+field_info node_fields_accent[10];
+field_info node_fields_adjust[3];
+field_info node_fields_attribute[3];
+field_info node_fields_attribute_list[1];
+field_info node_fields_boundary[3];
+field_info node_fields_choice[6];
+field_info node_fields_delim[6];
+field_info node_fields_dir[4];
+field_info node_fields_disc[6];
+field_info node_fields_fence[8];
+field_info node_fields_fraction[10];
+field_info node_fields_glue[8];
+field_info node_fields_glue_spec[6];
+field_info node_fields_glyph[16];
+field_info node_fields_insert[7];
+field_info node_fields_inserting[9];
+field_info node_fields_kern[4];
+field_info node_fields_list[11];
+field_info node_fields_local_par[9];
+field_info node_fields_margin_kern[4];
+field_info node_fields_mark[4];
+field_info node_fields_math[8];
+field_info node_fields_math_char[4];
+field_info node_fields_math_text_char[4];
+field_info node_fields_noad[5];
+field_info node_fields_penalty[3];
+field_info node_fields_radical[9];
+field_info node_fields_rule[9];
+field_info node_fields_splitup[6];
+field_info node_fields_style[3];
+field_info node_fields_sub_box[3];
+field_info node_fields_sub_mlist[3];
+field_info node_fields_unset[12];
+
+/*tex The fields of whatsit nodes. */
+
+field_info node_fields_whatsit_close[3];
+field_info node_fields_whatsit_late_lua[6];
+field_info node_fields_whatsit_open[6];
+field_info node_fields_whatsit_save_pos[2];
+field_info node_fields_whatsit_special[3];
+field_info node_fields_whatsit_user_defined[5];
+field_info node_fields_whatsit_write[4];
+
+field_info node_fields_whatsit_pdf_action[7];
+field_info node_fields_whatsit_pdf_annot[7];
+field_info node_fields_whatsit_pdf_colorstack[5];
+field_info node_fields_whatsit_pdf_dest[10];
+field_info node_fields_whatsit_pdf_end_link[2];
+field_info node_fields_whatsit_pdf_end_thread[2];
+field_info node_fields_whatsit_pdf_literal[4];
+field_info node_fields_whatsit_pdf_refobj[3];
+field_info node_fields_whatsit_pdf_restore[2];
+field_info node_fields_whatsit_pdf_save[2];
+field_info node_fields_whatsit_pdf_setmatrix[3];
+field_info node_fields_whatsit_pdf_start_link[8];
+field_info node_fields_whatsit_pdf_start_thread[8];
+field_info node_fields_whatsit_pdf_thread[8];
+
+/*tex The values of fields. */
+
+subtype_info node_values_dir[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { 3, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_pdf_destination[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { 3, NULL, 0 },
+ { 4, NULL, 0 },
+ { 5, NULL, 0 },
+ { 6, NULL, 0 },
+ { 7, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_pdf_action[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { 3, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_pdf_window[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_color_stack[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { 3, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_fill[] = {
+ { normal, NULL, 0 },
+ { sfi, NULL, 0 },
+ { fil, NULL, 0 },
+ { fill, NULL, 0 },
+ { filll, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_values_pdf_literal[] = {
+ { set_origin, NULL, 0 },
+ { direct_page, NULL, 0 },
+ { direct_always, NULL, 0 },
+ { direct_raw, NULL, 0 },
+ { direct_text, NULL, 0 },
+ { direct_font, NULL, 0 },
+ { scan_special, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info other_values_page_states[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { 2, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+/*tex The subtypes of nodes (most have one). */
+
+subtype_info node_subtypes_dir[] = {
+ { normal_dir, NULL, 0 },
+ { cancel_dir, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_glue[] = {
+ { user_skip_glue, NULL, 0 },
+ { line_skip_glue, NULL, 0 },
+ { baseline_skip_glue, NULL, 0 },
+ { par_skip_glue, NULL, 0 },
+ { above_display_skip_glue, NULL, 0 },
+ { below_display_skip_glue, NULL, 0 },
+ { above_display_short_skip_glue, NULL, 0 },
+ { below_display_short_skip_glue, NULL, 0 },
+ { left_skip_glue, NULL, 0 },
+ { right_skip_glue, NULL, 0 },
+ { top_skip_glue, NULL, 0 },
+ { split_top_skip_glue, NULL, 0 },
+ { tab_skip_glue, NULL, 0 },
+ { space_skip_glue, NULL, 0 },
+ { xspace_skip_glue, NULL, 0 },
+ { par_fill_skip_glue, NULL, 0 },
+ { math_skip_glue, NULL, 0 },
+ { thin_mu_skip_glue, NULL, 0 },
+ { med_mu_skip_glue, NULL, 0 },
+ { thick_mu_skip_glue, NULL, 0 },
+ /* math */
+ { cond_math_glue, NULL, 0 },
+ { mu_glue, NULL, 0 },
+ /* leaders */
+ { a_leaders, NULL, 0 },
+ { c_leaders, NULL, 0 },
+ { x_leaders, NULL, 0 },
+ { g_leaders, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+/*tex
+
+ Math glue and leaders have special numbers. At some point we might decide to
+ move them down so best don't use hard coded numbers!
+
+*/
+
+subtype_info node_subtypes_mathglue[] = { /* 98+ */
+ { cond_math_glue, NULL, 0 },
+ { mu_glue, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_leader[] = { /* 100+ */
+ { a_leaders, NULL, 0 },
+ { c_leaders, NULL, 0 },
+ { x_leaders, NULL, 0 },
+ { g_leaders, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_boundary[] = {
+ { cancel_boundary, NULL, 0 },
+ { user_boundary, NULL, 0 },
+ { protrusion_boundary, NULL, 0 },
+ { word_boundary, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_penalty[] = {
+ { user_penalty, NULL, 0 },
+ { linebreak_penalty, NULL, 0 },
+ { line_penalty, NULL, 0 },
+ { word_penalty, NULL, 0 },
+ { final_penalty, NULL, 0 },
+ { noad_penalty, NULL, 0 },
+ { before_display_penalty, NULL, 0 },
+ { after_display_penalty, NULL, 0 },
+ { equation_number_penalty, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_kern[] = {
+ { font_kern, NULL, 0 },
+ { explicit_kern, NULL, 0 },
+ { accent_kern, NULL, 0 },
+ { italic_kern, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_rule[] = {
+ { normal_rule, NULL, 0 },
+ { box_rule, NULL, 0 },
+ { image_rule, NULL, 0 },
+ { empty_rule, NULL, 0 },
+ { user_rule, NULL, 0 },
+ { math_over_rule, NULL, 0 },
+ { math_under_rule, NULL, 0 },
+ { math_fraction_rule, NULL, 0 },
+ { math_radical_rule, NULL, 0 },
+ { outline_rule, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_glyph[] = {
+ { glyph_unset, NULL, 0 },
+ { glyph_character, NULL, 0 },
+ { glyph_ligature, NULL, 0 },
+ { glyph_ghost, NULL, 0 },
+ { glyph_left, NULL, 0 },
+ { glyph_right, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_disc[] = {
+ { discretionary_disc, NULL, 0 },
+ { explicit_disc, NULL, 0 },
+ { automatic_disc, NULL, 0 },
+ { syllable_disc, NULL, 0 },
+ { init_disc, NULL, 0 },
+ { select_disc, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_marginkern[] = {
+ { left_side, NULL, 0 },
+ { right_side, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_list[] = {
+ { unknown_list, NULL, 0 },
+ { line_list, NULL, 0 },
+ { hbox_list, NULL, 0 },
+ { indent_list, NULL, 0 },
+ { align_row_list, NULL, 0 },
+ { align_cell_list, NULL, 0 },
+ { equation_list, NULL, 0 },
+ { equation_number_list, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_adjust[] = {
+ { 0, NULL, 0 },
+ { 1, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_math[] = {
+ { before, NULL, 0 },
+ { after, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_noad[] = {
+ { ord_noad_type, NULL, 0 },
+ { op_noad_type_normal, NULL, 0 },
+ { op_noad_type_limits, NULL, 0 },
+ { op_noad_type_no_limits, NULL, 0 },
+ { bin_noad_type, NULL, 0 },
+ { rel_noad_type, NULL, 0 },
+ { open_noad_type, NULL, 0 },
+ { close_noad_type, NULL, 0 },
+ { punct_noad_type, NULL, 0 },
+ { inner_noad_type, NULL, 0 },
+ { under_noad_type, NULL, 0 },
+ { over_noad_type, NULL, 0 },
+ { vcenter_noad_type, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_radical[] = {
+ { radical_noad_type, NULL, 0 },
+ { uradical_noad_type, NULL, 0 },
+ { uroot_noad_type, NULL, 0 },
+ { uunderdelimiter_noad_type, NULL, 0 },
+ { uoverdelimiter_noad_type, NULL, 0 },
+ { udelimiterunder_noad_type, NULL, 0 },
+ { udelimiterover_noad_type, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_accent[] = {
+ { bothflexible_accent, NULL, 0 },
+ { fixedtop_accent, NULL, 0 },
+ { fixedbottom_accent, NULL, 0 },
+ { fixedboth_accent, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+subtype_info node_subtypes_fence[] = {
+ { unset_noad_side, NULL, 0 },
+ { left_noad_side, NULL, 0 },
+ { middle_noad_side, NULL, 0 },
+ { right_noad_side, NULL, 0 },
+ { no_noad_side, NULL, 0 },
+ { -1, NULL, 0 },
+};
+
+/*tes This brings all together */
+
+node_info node_data[] = {
+ { hlist_node, box_node_size, node_subtypes_list, node_fields_list, NULL, 1, 0 },
+ { vlist_node, box_node_size, node_subtypes_list, node_fields_list, NULL, 2, 0 },
+ { rule_node, rule_node_size, node_subtypes_rule, node_fields_rule, NULL, 3, 0 },
+ { ins_node, ins_node_size, NULL, node_fields_insert, NULL, 4, 0 },
+ { mark_node, mark_node_size, NULL, node_fields_mark, NULL, 5, 0 },
+ { adjust_node, adjust_node_size, node_subtypes_adjust, node_fields_adjust, NULL, 6, 0 },
+ { boundary_node, boundary_node_size, node_subtypes_boundary, node_fields_boundary, NULL, -1, 0 },
+ { disc_node, disc_node_size, node_subtypes_disc, node_fields_disc, NULL, 8, 0 },
+ { whatsit_node, -1, NULL, NULL, NULL, 9, 0 },
+ { local_par_node, local_par_size, NULL, node_fields_local_par, NULL, -1, 0 },
+ { dir_node, dir_node_size, node_subtypes_dir, node_fields_dir, NULL, -1, 0 },
+ { math_node, math_node_size, node_subtypes_math, node_fields_math, NULL, 10, 0 },
+ { glue_node, glue_node_size, node_subtypes_glue, node_fields_glue, NULL, 11, 0 },
+ { kern_node, kern_node_size, node_subtypes_kern, node_fields_kern, NULL, 12, 0 },
+ { penalty_node, penalty_node_size, node_subtypes_penalty, node_fields_penalty, NULL, 13, 0 },
+ { unset_node, box_node_size, NULL, node_fields_unset, NULL, 14, 0 },
+ { style_node, style_node_size, NULL, node_fields_style, NULL, 15, 0 },
+ { choice_node, style_node_size, NULL, node_fields_choice, NULL, 15, 0 },
+ { simple_noad, noad_size, node_subtypes_noad, node_fields_noad, NULL, 15, 0 },
+ { radical_noad, radical_noad_size, node_subtypes_radical, node_fields_radical, NULL, 15, 0 },
+ { fraction_noad, fraction_noad_size, NULL, node_fields_fraction, NULL, 15, 0 },
+ { accent_noad, accent_noad_size, node_subtypes_accent, node_fields_accent, NULL, 15, 0 },
+ { fence_noad, fence_noad_size, node_subtypes_fence, node_fields_fence, NULL, 15, 0 },
+ { math_char_node, math_kernel_node_size, NULL, node_fields_math_char, NULL, 15, 0 },
+ { sub_box_node, math_kernel_node_size, NULL, node_fields_sub_box, NULL, 15, 0 },
+ { sub_mlist_node, math_kernel_node_size, NULL, node_fields_sub_mlist, NULL, 15, 0 },
+ { math_text_char_node, math_kernel_node_size, NULL, node_fields_math_text_char, NULL, 15, 0 },
+ { delim_node, math_shield_node_size, NULL, node_fields_delim, NULL, 15, 0 },
+ { margin_kern_node, margin_kern_node_size, node_subtypes_marginkern, node_fields_margin_kern, NULL, -1, 0 },
+ { glyph_node, glyph_node_size, node_subtypes_glyph, node_fields_glyph, NULL, 0, 0 },
+ { align_record_node, box_node_size, NULL, NULL, NULL, -1, 0 },
+ { pseudo_file_node, pseudo_file_node_size, NULL, NULL, NULL, -1, 0 },
+ { pseudo_line_node, variable_node_size, NULL, NULL, NULL, -1, 0 },
+ { inserting_node, page_ins_node_size, NULL, node_fields_inserting, NULL, -1, 0 },
+ { split_up_node, page_ins_node_size, NULL, node_fields_splitup, NULL, -1, 0 },
+ { expr_node, expr_node_size, NULL, NULL, NULL, -1, 0 },
+ { nesting_node, nesting_node_size, NULL, NULL, NULL, -1, 0 },
+ { span_node, span_node_size, NULL, NULL, NULL, -1, 0 },
+ { attribute_node, attribute_node_size, NULL, node_fields_attribute, NULL, -1, 0 },
+ { glue_spec_node, glue_spec_size, NULL, node_fields_glue_spec, NULL, -1, 0 },
+ { attribute_list_node, attribute_node_size, NULL, node_fields_attribute_list, NULL, -1, 0 },
+ { temp_node, temp_node_size, NULL, NULL, NULL, -1, 0 },
+ { align_stack_node, align_stack_node_size, NULL, NULL, NULL, -1, 0 },
+ { movement_node, movement_node_size, NULL, NULL, NULL, -1, 0 },
+ { if_node, if_node_size, NULL, NULL, NULL, -1, 0 },
+ { unhyphenated_node, active_node_size, NULL, NULL, NULL, -1, 0 },
+ { hyphenated_node, active_node_size, NULL, NULL, NULL, -1, 0 },
+ { delta_node, delta_node_size, NULL, NULL, NULL, -1, 0 },
+ { passive_node, passive_node_size, NULL, NULL, NULL, -1, 0 },
+ { shape_node, variable_node_size, NULL, NULL, NULL, -1, 0 },
+ { -1, -1, NULL, NULL, NULL, -1, 0 }
+};
+
+void l_set_node_data(void) {
+ init_node_key(node_data, hlist_node, hlist)
+ init_node_key(node_data, vlist_node, vlist)
+ init_node_key(node_data, rule_node, rule)
+ init_node_key(node_data, ins_node, ins)
+ init_node_key(node_data, mark_node, mark)
+ init_node_key(node_data, adjust_node, adjust)
+ init_node_key(node_data, boundary_node, boundary)
+ init_node_key(node_data, disc_node, disc)
+ init_node_key(node_data, whatsit_node, whatsit)
+ init_node_key(node_data, local_par_node, local_par)
+ init_node_key(node_data, dir_node, dir)
+ init_node_key(node_data, math_node, math)
+ init_node_key(node_data, glue_node, glue)
+ init_node_key(node_data, kern_node, kern)
+ init_node_key(node_data, penalty_node, penalty)
+ init_node_key(node_data, unset_node, unset)
+ init_node_key(node_data, style_node, style)
+ init_node_key(node_data, choice_node, choice)
+ init_node_key(node_data, simple_noad, noad)
+ init_node_key(node_data, radical_noad, radical)
+ init_node_key(node_data, fraction_noad, fraction)
+ init_node_key(node_data, accent_noad, accent)
+ init_node_key(node_data, fence_noad, fence)
+ init_node_key(node_data, math_char_node, math_char)
+ init_node_key(node_data, sub_box_node, sub_box)
+ init_node_key(node_data, sub_mlist_node, sub_mlist)
+ init_node_key(node_data, math_text_char_node, math_text_char)
+ init_node_key(node_data, delim_node, delim)
+ init_node_key(node_data, margin_kern_node, margin_kern)
+ init_node_key(node_data, glyph_node, glyph)
+ init_node_key(node_data, align_record_node, align_record)
+ init_node_key(node_data, pseudo_file_node, pseudo_file)
+ init_node_key(node_data, pseudo_line_node, pseudo_line)
+ init_node_key(node_data, inserting_node, page_insert)
+ init_node_key(node_data, split_up_node, split_insert)
+ init_node_key(node_data, expr_node, expr_stack)
+ init_node_key(node_data, nesting_node, nested_list)
+ init_node_key(node_data, span_node, span)
+ init_node_key(node_data, attribute_node, attribute)
+ init_node_key(node_data, glue_spec_node, glue_spec)
+ init_node_key(node_data, attribute_list_node, attribute_list)
+ init_node_key(node_data, temp_node, temp)
+ init_node_key(node_data, align_stack_node, align_stack)
+ init_node_key(node_data, movement_node, movement_stack)
+ init_node_key(node_data, if_node, if_stack)
+ init_node_key(node_data, unhyphenated_node, unhyphenated)
+ init_node_key(node_data, hyphenated_node, hyphenated)
+ init_node_key(node_data, delta_node, delta)
+ init_node_key(node_data, passive_node, passive)
+ init_node_key(node_data, shape_node, shape)
+
+ init_node_key(node_subtypes_dir, normal_dir, normal)
+ init_node_key(node_subtypes_dir, cancel_dir, cancel)
+
+ init_node_key(node_subtypes_glue, user_skip_glue, userskip)
+ init_node_key(node_subtypes_glue, line_skip_glue, lineskip)
+ init_node_key(node_subtypes_glue, baseline_skip_glue, baselineskip)
+ init_node_key(node_subtypes_glue, par_skip_glue, parskip)
+ init_node_key(node_subtypes_glue, above_display_skip_glue, abovedisplayskip)
+ init_node_key(node_subtypes_glue, below_display_skip_glue, belowdisplayskip)
+ init_node_key(node_subtypes_glue, above_display_short_skip_glue, abovedisplayshortskip)
+ init_node_key(node_subtypes_glue, below_display_short_skip_glue, belowdisplayshortskip)
+ init_node_key(node_subtypes_glue, left_skip_glue, leftskip)
+ init_node_key(node_subtypes_glue, right_skip_glue, rightskip)
+ init_node_key(node_subtypes_glue, top_skip_glue, topskip)
+ init_node_key(node_subtypes_glue, split_top_skip_glue, splittopskip)
+ init_node_key(node_subtypes_glue, tab_skip_glue, tabskip)
+ init_node_key(node_subtypes_glue, space_skip_glue, spaceskip)
+ init_node_key(node_subtypes_glue, xspace_skip_glue, xspaceskip)
+ init_node_key(node_subtypes_glue, par_fill_skip_glue, parfillskip)
+ init_node_key(node_subtypes_glue, math_skip_glue, mathskip)
+ init_node_key(node_subtypes_glue, thin_mu_skip_glue, thinmuskip)
+ init_node_key(node_subtypes_glue, med_mu_skip_glue, medmuskip)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue, thickmuskip)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 1, conditionalmathskip)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 2, muglue)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 3, leaders)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 4, cleaders)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 5, xleaders)
+ init_node_key(node_subtypes_glue, thick_mu_skip_glue + 6, gleaders)
+
+ init_node_key(node_subtypes_mathglue, 0, conditionalmathskip)
+ init_node_key(node_subtypes_mathglue, 1, muglue)
+
+ init_node_key(node_subtypes_leader, 0, leaders)
+ init_node_key(node_subtypes_leader, 1, cleaders)
+ init_node_key(node_subtypes_leader, 2, xleaders)
+ init_node_key(node_subtypes_leader, 3, gleaders)
+
+ init_node_key(node_subtypes_boundary, cancel_boundary, cancel)
+ init_node_key(node_subtypes_boundary, user_boundary, user)
+ init_node_key(node_subtypes_boundary, protrusion_boundary, protrusion)
+ init_node_key(node_subtypes_boundary, word_boundary, word)
+
+ init_node_key(node_subtypes_penalty, user_penalty, userpenalty)
+ init_node_key(node_subtypes_penalty, linebreak_penalty, linebreakpenalty)
+ init_node_key(node_subtypes_penalty, line_penalty, linepenalty)
+ init_node_key(node_subtypes_penalty, word_penalty, wordpenalty)
+ init_node_key(node_subtypes_penalty, final_penalty, finalpenalty)
+ init_node_key(node_subtypes_penalty, noad_penalty, noadpenalty)
+ init_node_key(node_subtypes_penalty, before_display_penalty, beforedisplaypenalty)
+ init_node_key(node_subtypes_penalty, after_display_penalty, afterdisplaypenalty)
+ init_node_key(node_subtypes_penalty, equation_number_penalty, equationnumberpenalty)
+
+ init_node_key(node_subtypes_kern, font_kern, fontkern)
+ init_node_key(node_subtypes_kern, explicit_kern, userkern)
+ init_node_key(node_subtypes_kern, accent_kern, accentkern)
+ init_node_key(node_subtypes_kern, italic_kern, italiccorrection)
+
+ init_node_key(node_subtypes_rule, normal_rule, normal)
+ init_node_key(node_subtypes_rule, box_rule, box)
+ init_node_key(node_subtypes_rule, image_rule, image)
+ init_node_key(node_subtypes_rule, empty_rule, empty)
+ init_node_key(node_subtypes_rule, user_rule, user)
+ init_node_key(node_subtypes_rule, math_over_rule, over)
+ init_node_key(node_subtypes_rule, math_under_rule, under)
+ init_node_key(node_subtypes_rule, math_fraction_rule, fraction)
+ init_node_key(node_subtypes_rule, math_radical_rule, radical)
+ init_node_key(node_subtypes_rule, outline_rule, outline)
+
+ init_node_key(node_subtypes_glyph, 0, unset)
+ init_node_key(node_subtypes_glyph, 1, character)
+ init_node_key(node_subtypes_glyph, 2, ligature)
+ init_node_key(node_subtypes_glyph, 3, ghost)
+ init_node_key(node_subtypes_glyph, 4, left)
+ init_node_key(node_subtypes_glyph, 5, right)
+
+ init_node_key(node_subtypes_disc, discretionary_disc, discretionary)
+ init_node_key(node_subtypes_disc, explicit_disc, explicit)
+ init_node_key(node_subtypes_disc, automatic_disc, automatic)
+ init_node_key(node_subtypes_disc, syllable_disc, regular)
+ init_node_key(node_subtypes_disc, init_disc, first)
+ init_node_key(node_subtypes_disc, select_disc, second)
+
+ init_node_key(node_subtypes_fence, unset_noad_side, unset)
+ init_node_key(node_subtypes_fence, left_noad_side, left)
+ init_node_key(node_subtypes_fence, middle_noad_side, middle)
+ init_node_key(node_subtypes_fence, right_noad_side, right)
+ init_node_key(node_subtypes_fence, no_noad_side, no)
+
+ init_node_key(node_subtypes_list, unknown_list, unknown)
+ init_node_key(node_subtypes_list, line_list, line)
+ init_node_key(node_subtypes_list, hbox_list, box)
+ init_node_key(node_subtypes_list, indent_list, indent)
+ init_node_key(node_subtypes_list, align_row_list, alignment)
+ init_node_key(node_subtypes_list, align_cell_list, cell)
+ init_node_key(node_subtypes_list, equation_list, equation)
+ init_node_key(node_subtypes_list, equation_number_list, equationnumber)
+
+ init_node_key(node_subtypes_math, before, beginmath)
+ init_node_key(node_subtypes_math, after, endmath)
+
+ init_node_key(node_subtypes_marginkern, left_side, left)
+ init_node_key(node_subtypes_marginkern, right_side, right)
+
+ init_node_key(node_subtypes_adjust, 0, normal)
+ init_node_key(node_subtypes_adjust, 1, pre)
+
+ init_node_key(node_subtypes_noad, ord_noad_type, ord)
+ init_node_key(node_subtypes_noad, op_noad_type_normal, opdisplaylimits)
+ init_node_key(node_subtypes_noad, op_noad_type_limits, oplimits)
+ init_node_key(node_subtypes_noad, op_noad_type_no_limits, opnolimits)
+ init_node_key(node_subtypes_noad, bin_noad_type, bin)
+ init_node_key(node_subtypes_noad, rel_noad_type, rel)
+ init_node_key(node_subtypes_noad, open_noad_type, open)
+ init_node_key(node_subtypes_noad, close_noad_type, close)
+ init_node_key(node_subtypes_noad, punct_noad_type, punct)
+ init_node_key(node_subtypes_noad, inner_noad_type, inner)
+ init_node_key(node_subtypes_noad, under_noad_type, under)
+ init_node_key(node_subtypes_noad, over_noad_type, over)
+ init_node_key(node_subtypes_noad, vcenter_noad_type, vcenter)
+
+ init_node_key(node_subtypes_radical, radical_noad_type, radical)
+ init_node_key(node_subtypes_radical, uradical_noad_type, uradical)
+ init_node_key(node_subtypes_radical, uroot_noad_type, uroot)
+ init_node_key(node_subtypes_radical, uunderdelimiter_noad_type, uunderdelimiter)
+ init_node_key(node_subtypes_radical, uoverdelimiter_noad_type, uoverdelimiter)
+ init_node_key(node_subtypes_radical, udelimiterunder_noad_type, udelimiterunder)
+ init_node_key(node_subtypes_radical, udelimiterover_noad_type, udelimiterover)
+
+ init_node_key(node_subtypes_accent, bothflexible_accent, bothflexible)
+ init_node_key(node_subtypes_accent, fixedtop_accent, fixedtop)
+ init_node_key(node_subtypes_accent, fixedbottom_accent, fixedbottom)
+ init_node_key(node_subtypes_accent, fixedboth_accent, fixedboth)
+
+ init_node_key(node_values_fill, normal, normal)
+ init_node_key(node_values_fill, sfi, fi)
+ init_node_key(node_values_fill, fil, fil)
+ init_node_key(node_values_fill, fill, fill)
+ init_node_key(node_values_fill, filll, filll)
+
+ init_node_key(node_values_dir, 0, TLT)
+ init_node_key(node_values_dir, 1, TRT)
+ init_node_key(node_values_dir, 2, LTL)
+ init_node_key(node_values_dir, 3, RTT)
+
+ init_node_key(other_values_page_states, 0, empty)
+ init_node_key(other_values_page_states, 1, box_there)
+ init_node_key(other_values_page_states, 2, inserts_only)
+
+ init_field_key(node_fields_accent, 0, attr);
+ init_field_key(node_fields_accent, 1, nucleus);
+ init_field_key(node_fields_accent, 2, sub);
+ init_field_key(node_fields_accent, 3, sup);
+ init_field_key(node_fields_accent, 4, accent);
+ init_field_key(node_fields_accent, 5, bot_accent);
+ init_field_key(node_fields_accent, 6, top_accent);
+ init_field_key(node_fields_accent, 7, overlay_accent);
+ init_field_key(node_fields_accent, 8, fraction);
+ init_field_nop(node_fields_accent, 9);
+
+ init_field_key(node_fields_adjust, 0, attr);
+ init_field_key(node_fields_adjust, 1, head);
+ init_field_nop(node_fields_adjust, 2);
+
+ init_field_key(node_fields_attribute, 0, number);
+ init_field_key(node_fields_attribute, 1, value);
+ init_field_nop(node_fields_attribute, 2);
+
+ init_field_nop(node_fields_attribute_list,0);
+
+ init_field_key(node_fields_boundary, 0, attr);
+ init_field_key(node_fields_boundary, 1, value);
+ init_field_nop(node_fields_boundary, 2);
+
+ init_field_key(node_fields_choice, 0, attr);
+ init_field_key(node_fields_choice, 1, display);
+ init_field_key(node_fields_choice, 2, text);
+ init_field_key(node_fields_choice, 3, script);
+ init_field_key(node_fields_choice, 4, scriptscript);
+ init_field_nop(node_fields_choice, 5);
+
+ init_field_key(node_fields_delim, 0, attr);
+ init_field_key(node_fields_delim, 1, small_fam);
+ init_field_key(node_fields_delim, 2, small_char);
+ init_field_key(node_fields_delim, 3, large_fam);
+ init_field_key(node_fields_delim, 4, large_char);
+ init_field_nop(node_fields_delim, 5);
+
+ init_field_key(node_fields_dir, 0, attr);
+ init_field_key(node_fields_dir, 1, dir);
+ init_field_key(node_fields_dir, 2, level);
+ init_field_nop(node_fields_dir, 3);
+
+ init_field_key(node_fields_disc, 0, attr);
+ init_field_key(node_fields_disc, 1, pre);
+ init_field_key(node_fields_disc, 2, post);
+ init_field_key(node_fields_disc, 3, replace);
+ init_field_key(node_fields_disc, 4, penalty);
+ init_field_nop(node_fields_disc, 5);
+
+ init_field_key(node_fields_fence, 0, attr);
+ init_field_key(node_fields_fence, 1, delim);
+ init_field_key(node_fields_fence, 2, italic);
+ init_field_key(node_fields_fence, 3, height);
+ init_field_key(node_fields_fence, 4, depth);
+ init_field_key(node_fields_fence, 5, options);
+ init_field_key(node_fields_fence, 6, class);
+ init_field_nop(node_fields_fence, 7);
+
+ init_field_key(node_fields_fraction, 0, attr);
+ init_field_key(node_fields_fraction, 1, width);
+ init_field_key(node_fields_fraction, 2, num);
+ init_field_key(node_fields_fraction, 3, denom);
+ init_field_key(node_fields_fraction, 4, left);
+ init_field_key(node_fields_fraction, 5, right);
+ init_field_key(node_fields_fraction, 6, middle);
+ init_field_key(node_fields_fraction, 7, fam);
+ init_field_key(node_fields_fraction, 8, options);
+ init_field_nop(node_fields_fraction, 9);
+
+ init_field_key(node_fields_glue, 0, attr);
+ init_field_key(node_fields_glue, 1, leader);
+ init_field_key(node_fields_glue, 2, width);
+ init_field_key(node_fields_glue, 3, stretch);
+ init_field_key(node_fields_glue, 4, shrink);
+ init_field_key(node_fields_glue, 5, stretch_order);
+ init_field_key(node_fields_glue, 6, shrink_order);
+ init_field_nop(node_fields_glue, 7);
+
+ init_field_key(node_fields_glue_spec, 0, width);
+ init_field_key(node_fields_glue_spec, 1, stretch);
+ init_field_key(node_fields_glue_spec, 2, shrink);
+ init_field_key(node_fields_glue_spec, 3, stretch_order);
+ init_field_key(node_fields_glue_spec, 4, shrink_order);
+ init_field_nop(node_fields_glue_spec, 5);
+
+ init_field_key(node_fields_glyph, 0, attr);
+ init_field_key(node_fields_glyph, 1, char);
+ init_field_key(node_fields_glyph, 2, font);
+ init_field_key(node_fields_glyph, 3, lang);
+ init_field_key(node_fields_glyph, 4, left);
+ init_field_key(node_fields_glyph, 5, right);
+ init_field_key(node_fields_glyph, 6, uchyph);
+ init_field_key(node_fields_glyph, 7, components);
+ init_field_key(node_fields_glyph, 8, xoffset);
+ init_field_key(node_fields_glyph, 9, yoffset);
+ init_field_key(node_fields_glyph, 10, width);
+ init_field_key(node_fields_glyph, 11, height);
+ init_field_key(node_fields_glyph, 12, depth);
+ init_field_key(node_fields_glyph, 13, expansion_factor);
+ init_field_key(node_fields_glyph, 14, data);
+ init_field_nop(node_fields_glyph, 15);
+
+ init_field_key(node_fields_insert, 0, attr);
+ init_field_key(node_fields_insert, 1, cost);
+ init_field_key(node_fields_insert, 2, depth);
+ init_field_key(node_fields_insert, 3, height);
+ init_field_key(node_fields_insert, 4, spec);
+ init_field_key(node_fields_insert, 5, head);
+ init_field_nop(node_fields_insert, 6);
+
+ init_field_key(node_fields_inserting, 0, height);
+ init_field_key(node_fields_inserting, 1, last_ins_ptr);
+ init_field_key(node_fields_inserting, 2, best_ins_ptr);
+ init_field_key(node_fields_inserting, 3, width);
+ init_field_key(node_fields_inserting, 4, stretch);
+ init_field_key(node_fields_inserting, 5, shrink);
+ init_field_key(node_fields_inserting, 6, stretch_order);
+ init_field_key(node_fields_inserting, 7, shrink_order);
+ init_field_nop(node_fields_inserting, 8);
+
+ init_field_key(node_fields_kern, 0, attr);
+ init_field_key(node_fields_kern, 1, kern);
+ init_field_key(node_fields_kern, 2, expansion_factor);
+ init_field_nop(node_fields_kern, 3);
+
+ init_field_key(node_fields_list, 0, attr);
+ init_field_key(node_fields_list, 1, width);
+ init_field_key(node_fields_list, 2, depth);
+ init_field_key(node_fields_list, 3, height);
+ init_field_key(node_fields_list, 4, dir);
+ init_field_key(node_fields_list, 5, shift);
+ init_field_key(node_fields_list, 6, glue_order);
+ init_field_key(node_fields_list, 7, glue_sign);
+ init_field_key(node_fields_list, 8, glue_set);
+ init_field_key(node_fields_list, 9, head);
+ init_field_nop(node_fields_list, 10);
+
+ init_field_key(node_fields_local_par, 0, attr);
+ init_field_key(node_fields_local_par, 1, pen_inter);
+ init_field_key(node_fields_local_par, 2, pen_broken);
+ init_field_key(node_fields_local_par, 3, dir);
+ init_field_key(node_fields_local_par, 4, box_left);
+ init_field_key(node_fields_local_par, 5, box_left_width);
+ init_field_key(node_fields_local_par, 6, box_right);
+ init_field_key(node_fields_local_par, 7, box_right_width);
+ init_field_nop(node_fields_local_par, 8);
+
+ init_field_key(node_fields_margin_kern, 0, attr);
+ init_field_key(node_fields_margin_kern, 1, width);
+ init_field_key(node_fields_margin_kern, 2, glyph);
+ init_field_nop(node_fields_margin_kern, 3);
+
+ init_field_key(node_fields_mark, 0, attr);
+ init_field_key(node_fields_mark, 1, class);
+ init_field_key(node_fields_mark, 2, mark);
+ init_field_nop(node_fields_mark, 3);
+
+ init_field_key(node_fields_math, 0, attr);
+ init_field_key(node_fields_math, 1, surround);
+ init_field_key(node_fields_math, 2, width);
+ init_field_key(node_fields_math, 3, stretch);
+ init_field_key(node_fields_math, 4, shrink);
+ init_field_key(node_fields_math, 5, stretch_order);
+ init_field_key(node_fields_math, 6, shrink_order);
+ init_field_nop(node_fields_math, 7);
+
+ init_field_key(node_fields_math_char, 0, attr);
+ init_field_key(node_fields_math_char, 1, fam);
+ init_field_key(node_fields_math_char, 2, char);
+ init_field_nop(node_fields_math_char, 3);
+
+ init_field_key(node_fields_math_text_char, 0, attr);
+ init_field_key(node_fields_math_text_char, 1, fam);
+ init_field_key(node_fields_math_text_char, 2, char);
+ init_field_nop(node_fields_math_text_char, 3);
+
+ init_field_key(node_fields_noad, 0, attr);
+ init_field_key(node_fields_noad, 1, nucleus);
+ init_field_key(node_fields_noad, 2, sub);
+ init_field_key(node_fields_noad, 3, sup);
+ init_field_nop(node_fields_noad, 4);
+
+ init_field_key(node_fields_penalty, 0, attr);
+ init_field_key(node_fields_penalty, 1, penalty);
+ init_field_nop(node_fields_penalty, 2);
+
+ init_field_key(node_fields_radical, 0, attr);
+ init_field_key(node_fields_radical, 1, nucleus);
+ init_field_key(node_fields_radical, 2, sub);
+ init_field_key(node_fields_radical, 3, sup);
+ init_field_key(node_fields_radical, 4, left);
+ init_field_key(node_fields_radical, 5, degree);
+ init_field_key(node_fields_radical, 6, width);
+ init_field_key(node_fields_radical, 7, options);
+ init_field_nop(node_fields_radical, 8);
+
+ init_field_key(node_fields_rule, 0, attr);
+ init_field_key(node_fields_rule, 1, width);
+ init_field_key(node_fields_rule, 2, depth);
+ init_field_key(node_fields_rule, 3, height);
+ init_field_key(node_fields_rule, 4, dir);
+ init_field_key(node_fields_rule, 5, index);
+ init_field_key(node_fields_rule, 6, left);
+ init_field_key(node_fields_rule, 7, right);
+ init_field_nop(node_fields_rule, 8);
+
+ init_field_key(node_fields_splitup, 0, height);
+ init_field_key(node_fields_splitup, 1, last_ins_ptr);
+ init_field_key(node_fields_splitup, 2, best_ins_ptr);
+ init_field_key(node_fields_splitup, 3, broken_ptr);
+ init_field_key(node_fields_splitup, 4, broken_ins);
+ init_field_nop(node_fields_splitup, 5);
+
+ init_field_key(node_fields_style, 0, attr);
+ init_field_key(node_fields_style, 1, style);
+ init_field_nop(node_fields_style, 2);
+
+ init_field_key(node_fields_sub_box, 0, attr);
+ init_field_key(node_fields_sub_box, 1, head);
+ init_field_nop(node_fields_sub_box, 2);
+
+ init_field_key(node_fields_sub_mlist, 0, attr);
+ init_field_key(node_fields_sub_mlist, 1, head);
+ init_field_nop(node_fields_sub_mlist, 2);
+
+ init_field_key(node_fields_unset, 0, attr);
+ init_field_key(node_fields_unset, 1, width);
+ init_field_key(node_fields_unset, 2, depth);
+ init_field_key(node_fields_unset, 3, height);
+ init_field_key(node_fields_unset, 4, dir);
+ init_field_key(node_fields_unset, 5, shrink);
+ init_field_key(node_fields_unset, 6, glue_order);
+ init_field_key(node_fields_unset, 7, glue_sign);
+ init_field_key(node_fields_unset, 8, stretch);
+ init_field_key(node_fields_unset, 9, span);
+ init_field_key(node_fields_unset, 10, head);
+ init_field_nop(node_fields_unset, 11);
+
+}
+
+node_info whatsit_node_data[] = {
+
+ /*tex These are always there. The fake nodes are historical. */
+
+ { open_node, open_node_size, NULL, node_fields_whatsit_open, NULL, -1, 0 },
+ { write_node, write_node_size, NULL, node_fields_whatsit_write, NULL, -1, 0 },
+ { close_node, close_node_size, NULL, node_fields_whatsit_close, NULL, -1, 0 },
+ { special_node, special_node_size, NULL, node_fields_whatsit_special, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { save_pos_node, save_pos_node_size, NULL, node_fields_whatsit_save_pos, NULL, -1, 0 },
+ { late_lua_node, late_lua_node_size, NULL, node_fields_whatsit_late_lua, NULL, -1, 0 },
+ { user_defined_node, user_defined_node_size, NULL, node_fields_whatsit_user_defined, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+ { fake_node, fake_node_size, NULL, NULL, NULL, -1, 0 },
+
+ /*tex Here starts the \DVI\ backend section, todo: a separate list. */
+
+ /*tex {\em There is nothing here.} */
+
+ /*tex Here starts the \PDF\ backend section, todo: a separate list. */
+
+ { pdf_literal_node, write_node_size, NULL, node_fields_whatsit_pdf_literal, NULL, -1, 0 },
+ { pdf_refobj_node, pdf_refobj_node_size, NULL, node_fields_whatsit_pdf_refobj, NULL, -1, 0 },
+ { pdf_annot_node, pdf_annot_node_size, NULL, node_fields_whatsit_pdf_annot, NULL, -1, 0 },
+ { pdf_start_link_node, pdf_annot_node_size, NULL, node_fields_whatsit_pdf_start_link, NULL, -1, 0 },
+ { pdf_end_link_node, pdf_end_link_node_size, NULL, node_fields_whatsit_pdf_end_link, NULL, -1, 0 },
+ { pdf_dest_node, pdf_dest_node_size, NULL, node_fields_whatsit_pdf_dest, NULL, -1, 0 },
+ { pdf_action_node, pdf_action_size, NULL, node_fields_whatsit_pdf_action, NULL, -1, 0 },
+ { pdf_thread_node, pdf_thread_node_size, NULL, node_fields_whatsit_pdf_thread, NULL, -1, 0 },
+ { pdf_start_thread_node, pdf_thread_node_size, NULL, node_fields_whatsit_pdf_start_thread, NULL, -1, 0 },
+ { pdf_end_thread_node, pdf_end_thread_node_size, NULL, node_fields_whatsit_pdf_end_thread, NULL, -1, 0 },
+ { pdf_thread_data_node, pdf_thread_node_size, NULL, NULL, NULL, -1, 0 },
+ { pdf_link_data_node, pdf_annot_node_size, NULL, NULL, NULL, -1, 0 },
+ { pdf_colorstack_node, pdf_colorstack_node_size, NULL, node_fields_whatsit_pdf_colorstack, NULL, -1, 0 },
+ { pdf_setmatrix_node, pdf_setmatrix_node_size, NULL, node_fields_whatsit_pdf_setmatrix, NULL, -1, 0 },
+ { pdf_save_node, pdf_save_node_size, NULL, node_fields_whatsit_pdf_save, NULL, -1, 0 },
+ { pdf_restore_node, pdf_restore_node_size, NULL, node_fields_whatsit_pdf_restore, NULL, -1, 0 },
+
+ /*tex That's it. */
+
+ { -1, -1, NULL, NULL, NULL, -1, 0 },
+
+};
+
+void l_set_whatsit_data(void) {
+ init_node_key(whatsit_node_data, open_node, open)
+ init_node_key(whatsit_node_data, write_node, write)
+ init_node_key(whatsit_node_data, close_node, close)
+ init_node_key(whatsit_node_data, special_node, special)
+ init_node_key(whatsit_node_data, save_pos_node, save_pos)
+ init_node_key(whatsit_node_data, late_lua_node, late_lua)
+ init_node_key(whatsit_node_data, user_defined_node, user_defined)
+
+ init_field_key(node_fields_whatsit_close, 0, attr);
+ init_field_key(node_fields_whatsit_close, 1, stream);
+ init_field_nop(node_fields_whatsit_close, 2);
+
+ init_field_key(node_fields_whatsit_late_lua, 0, attr);
+ init_field_key(node_fields_whatsit_late_lua, 1, reg);
+ init_field_key(node_fields_whatsit_late_lua, 2, data);
+ init_field_key(node_fields_whatsit_late_lua, 3, name);
+ init_field_key(node_fields_whatsit_late_lua, 4, string);
+ init_field_nop(node_fields_whatsit_late_lua, 5);
+
+ init_field_key(node_fields_whatsit_open, 0, attr);
+ init_field_key(node_fields_whatsit_open, 1, stream);
+ init_field_key(node_fields_whatsit_open, 2, name);
+ init_field_key(node_fields_whatsit_open, 3, area);
+ init_field_key(node_fields_whatsit_open, 4, ext);
+ init_field_nop(node_fields_whatsit_open, 5);
+
+ init_field_key(node_fields_whatsit_save_pos, 0, attr);
+ init_field_nop(node_fields_whatsit_save_pos, 1);
+
+ init_field_key(node_fields_whatsit_special, 0, attr);
+ init_field_key(node_fields_whatsit_special, 1, data);
+ init_field_nop(node_fields_whatsit_special, 2);
+
+ init_field_key(node_fields_whatsit_user_defined, 0, attr);
+ init_field_key(node_fields_whatsit_user_defined, 1, user_id);
+ init_field_key(node_fields_whatsit_user_defined, 2, type);
+ init_field_key(node_fields_whatsit_user_defined, 3, value);
+ init_field_nop(node_fields_whatsit_user_defined, 4);
+
+ init_field_key(node_fields_whatsit_write, 0, attr);
+ init_field_key(node_fields_whatsit_write, 1, stream);
+ init_field_key(node_fields_whatsit_write, 2, data);
+ init_field_nop(node_fields_whatsit_write, 3);
+
+ init_node_key(whatsit_node_data, pdf_literal_node, pdf_literal)
+ init_node_key(whatsit_node_data, pdf_refobj_node, pdf_refobj)
+ init_node_key(whatsit_node_data, pdf_annot_node, pdf_annot)
+ init_node_key(whatsit_node_data, pdf_start_link_node, pdf_start_link)
+ init_node_key(whatsit_node_data, pdf_end_link_node, pdf_end_link)
+ init_node_key(whatsit_node_data, pdf_dest_node, pdf_dest)
+ init_node_key(whatsit_node_data, pdf_action_node, pdf_action)
+ init_node_key(whatsit_node_data, pdf_thread_node, pdf_thread)
+ init_node_key(whatsit_node_data, pdf_start_thread_node,pdf_start_thread)
+ init_node_key(whatsit_node_data, pdf_end_thread_node, pdf_end_thread)
+ init_node_key(whatsit_node_data, pdf_thread_data_node, pdf_thread_data)
+ init_node_key(whatsit_node_data, pdf_link_data_node, pdf_link_data)
+ init_node_key(whatsit_node_data, pdf_colorstack_node, pdf_colorstack)
+ init_node_key(whatsit_node_data, pdf_setmatrix_node, pdf_setmatrix)
+ init_node_key(whatsit_node_data, pdf_save_node, pdf_save)
+ init_node_key(whatsit_node_data, pdf_restore_node, pdf_restore)
+
+ init_node_key(node_values_pdf_destination, 0, xyz)
+ init_node_key(node_values_pdf_destination, 1, fit)
+ init_node_key(node_values_pdf_destination, 2, fith)
+ init_node_key(node_values_pdf_destination, 3, fitv)
+ init_node_key(node_values_pdf_destination, 4, fitb)
+ init_node_key(node_values_pdf_destination, 5, fitbh)
+ init_node_key(node_values_pdf_destination, 6, fitbv)
+ init_node_key(node_values_pdf_destination, 7, fitr)
+
+ init_node_key(node_values_pdf_literal, set_origin, origin)
+ init_node_key(node_values_pdf_literal, direct_page, page)
+ init_node_key(node_values_pdf_literal, direct_always, always)
+ init_node_key(node_values_pdf_literal, direct_raw, raw)
+ init_node_key(node_values_pdf_literal, direct_text, text)
+ init_node_key(node_values_pdf_literal, direct_font, font)
+ init_node_key(node_values_pdf_literal, scan_special, special)
+
+ init_node_key(node_values_pdf_action, 0, page)
+ init_node_key(node_values_pdf_action, 1, goto)
+ init_node_key(node_values_pdf_action, 2, thread)
+ init_node_key(node_values_pdf_action, 3, user)
+
+ init_node_key(node_values_pdf_window, 0, unset)
+ init_node_key(node_values_pdf_window, 1, new)
+ init_node_key(node_values_pdf_window, 2, nonew)
+
+ init_node_key(node_values_color_stack, 0, set)
+ init_node_key(node_values_color_stack, 1, push)
+ init_node_key(node_values_color_stack, 2, pop)
+ init_node_key(node_values_color_stack, 3, current)
+
+ init_field_key(node_fields_whatsit_pdf_action, 0, action_type);
+ init_field_key(node_fields_whatsit_pdf_action, 1, named_id);
+ init_field_key(node_fields_whatsit_pdf_action, 2, action_id);
+ init_field_key(node_fields_whatsit_pdf_action, 3, file);
+ init_field_key(node_fields_whatsit_pdf_action, 4, new_window);
+ init_field_key(node_fields_whatsit_pdf_action, 5, data);
+ init_field_nop(node_fields_whatsit_pdf_action, 6);
+
+ init_field_key(node_fields_whatsit_pdf_annot, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_annot, 1, width);
+ init_field_key(node_fields_whatsit_pdf_annot, 2, depth);
+ init_field_key(node_fields_whatsit_pdf_annot, 3, height);
+ init_field_key(node_fields_whatsit_pdf_annot, 4, objnum);
+ init_field_key(node_fields_whatsit_pdf_annot, 5, data);
+ init_field_nop(node_fields_whatsit_pdf_annot, 6);
+
+ init_field_key(node_fields_whatsit_pdf_colorstack, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_colorstack, 1, stack);
+ init_field_key(node_fields_whatsit_pdf_colorstack, 2, cmd);
+ init_field_key(node_fields_whatsit_pdf_colorstack, 3, data);
+ init_field_nop(node_fields_whatsit_pdf_colorstack, 4);
+
+ init_field_key(node_fields_whatsit_pdf_dest, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_dest, 1, width);
+ init_field_key(node_fields_whatsit_pdf_dest, 2, depth);
+ init_field_key(node_fields_whatsit_pdf_dest, 3, height);
+ init_field_key(node_fields_whatsit_pdf_dest, 4, named_id);
+ init_field_key(node_fields_whatsit_pdf_dest, 5, dest_id);
+ init_field_key(node_fields_whatsit_pdf_dest, 6, dest_type);
+ init_field_key(node_fields_whatsit_pdf_dest, 7, xyz_zoom);
+ init_field_key(node_fields_whatsit_pdf_dest, 8, objnum);
+ init_field_nop(node_fields_whatsit_pdf_dest, 9);
+
+ init_field_key(node_fields_whatsit_pdf_end_link, 0, attr);
+ init_field_nop(node_fields_whatsit_pdf_end_link, 1);
+
+ init_field_key(node_fields_whatsit_pdf_end_thread, 0, attr);
+ init_field_nop(node_fields_whatsit_pdf_end_thread, 1);
+
+ init_field_key(node_fields_whatsit_pdf_literal, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_literal, 1, mode);
+ init_field_key(node_fields_whatsit_pdf_literal, 2, data);
+ init_field_nop(node_fields_whatsit_pdf_literal, 3);
+
+ init_field_key(node_fields_whatsit_pdf_refobj, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_refobj, 1, objnum);
+ init_field_nop(node_fields_whatsit_pdf_refobj, 2);
+
+ init_field_key(node_fields_whatsit_pdf_restore, 0, attr);
+ init_field_nop(node_fields_whatsit_pdf_restore, 1);
+
+ init_field_key(node_fields_whatsit_pdf_save, 0, attr);
+ init_field_nop(node_fields_whatsit_pdf_save, 1);
+
+ init_field_key(node_fields_whatsit_pdf_setmatrix, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_setmatrix, 1, data);
+ init_field_nop(node_fields_whatsit_pdf_setmatrix, 2);
+
+ init_field_key(node_fields_whatsit_pdf_start_link, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_start_link, 1, width);
+ init_field_key(node_fields_whatsit_pdf_start_link, 2, depth);
+ init_field_key(node_fields_whatsit_pdf_start_link, 3, height);
+ init_field_key(node_fields_whatsit_pdf_start_link, 4, objnum);
+ init_field_key(node_fields_whatsit_pdf_start_link, 5, link_attr);
+ init_field_key(node_fields_whatsit_pdf_start_link, 6, action);
+ init_field_nop(node_fields_whatsit_pdf_start_link, 7);
+
+ init_field_key(node_fields_whatsit_pdf_start_thread, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 1, width);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 2, depth);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 3, height);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 4, named_id);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 5, thread_id);
+ init_field_key(node_fields_whatsit_pdf_start_thread, 6, thread_attr);
+ init_field_nop(node_fields_whatsit_pdf_start_thread, 7);
+
+ init_field_key(node_fields_whatsit_pdf_thread, 0, attr);
+ init_field_key(node_fields_whatsit_pdf_thread, 1, width);
+ init_field_key(node_fields_whatsit_pdf_thread, 2, depth);
+ init_field_key(node_fields_whatsit_pdf_thread, 3, height);
+ init_field_key(node_fields_whatsit_pdf_thread, 4, named_id);
+ init_field_key(node_fields_whatsit_pdf_thread, 5, thread_id);
+ init_field_key(node_fields_whatsit_pdf_thread, 6, thread_attr);
+ init_field_nop(node_fields_whatsit_pdf_thread, 7);
+
+}
+
+#define last_whatsit_node pdf_restore_node
+
+/*tex
+
+ When we copy a node list, there are several possibilities: we do the same as
+ a new node, we copy the entry to the table in properties (a reference), we do
+ a deep copy of a table in the properties, we create a new table and give it
+ the original one as a metatable. After some experiments (that also included
+ timing) with these scenarios I decided that a deep copy made no sense, nor
+ did nilling. In the end both the shallow copy and the metatable variant were
+ both ok, although the second ons is slower. The most important aspect to keep
+ in mind is that references to other nodes in properties no longer can be
+ valid for that copy. We could use two tables (one unique and one shared) or
+ metatables but that only complicates matters.
+
+ When defining a new node, we could already allocate a table but it is rather
+ easy to do that at the lua end e.g. using a metatable __index method. That
+ way it is under macro package control.
+
+ When deleting a node, we could keep the slot (e.g. setting it to false) but
+ it could make memory consumption raise unneeded when we have temporary large
+ node lists and after that only small lists.
+
+ So, in the end this is what we ended up with. For the record, I also
+ experimented with the following:
+
+ \startitemize
+
+ \startitem
+ Copy attributes to the properties so that we have fast access at the
+ lua end: in the end the overhead is not compensated by speed and
+ convenience, in fact, attributes are not that slow when it comes to
+ accessing them.
+ \stopitem
+
+ \startitem
+ A bitset in the node but again the gain compared to attributes is
+ neglectable and it also demands a pretty string agreement over what
+ bit represents what, and this is unlikely to succeed in the tex
+ community (I could use it for font handling, which is cross package,
+ but decided that it doesn't pay off.
+ \stopitem
+
+ \stopitemize
+
+ In case one wonders why properties make sense then, well, it is not so much
+ speed that we gain, but more convenience: storing all kind of (temporary)
+ data in attributes is no fun and this mechanism makes sure that properties
+ are cleaned up when a node is freed. Also, the advantage of a more or less
+ global properties table is that we stay at the lua end. An alternative is to
+ store a reference in the node itself but that is complicated by the fact that
+ the register has some limitations (no numeric keys) and we also don't want to
+ mess with it too much.
+
+*/
+
+int lua_properties_level = 0 ;
+int lua_properties_enabled = 0 ;
+int lua_properties_use_metatable = 0 ;
+
+/*tex
+
+ We keep track of nesting so that we don't oveflow the stack, and, what is
+ more important, don't keep resolving the registry index.
+
+*/
+
+#define lua_properties_push do { \
+ if (lua_properties_enabled) { \
+ lua_properties_level = lua_properties_level + 1 ; \
+ if (lua_properties_level == 1) { \
+ lua_get_metatablelua_l(Luas,node_properties); \
+ } \
+ } \
+} while(0)
+
+#define lua_properties_pop do { \
+ if (lua_properties_enabled) { \
+ if (lua_properties_level == 1) \
+ lua_pop(Luas,1); \
+ lua_properties_level = lua_properties_level - 1 ; \
+ } \
+} while(0)
+
+/*tex No setting is needed: */
+
+#define lua_properties_set(target) do { \
+} while(0)
+
+/*tex Resetting boils down to nilling. */
+
+#define lua_properties_reset(target) do { \
+ if (lua_properties_enabled) { \
+ if (lua_properties_level == 0) { \
+ lua_get_metatablelua_l(Luas,node_properties); \
+ lua_pushnil(Luas); \
+ lua_rawseti(Luas,-2,target); \
+ lua_pop(Luas,1); \
+ } else { \
+ lua_pushnil(Luas); \
+ lua_rawseti(Luas,-2,target); \
+ } \
+ } \
+} while(0)
+
+/*tex
+
+ For a moment I considered supporting all kind of data types but in practice
+ that makes no sense. So we stick to a cheap shallow copy with as option a
+ metatable. BTW, a deep copy would look like this:
+
+ \starttyping
+ static void copy_lua_table(lua_State* L, int index) {
+ lua_newtable(L);
+ lua_pushnil(L);
+ while(lua_next(L, index-1) != 0) {
+ lua_pushvalue(L, -2);
+ lua_insert(L, -2);
+ if (lua_type(L,-1)==LUA_TTABLE)
+ copy_lua_table(L,-1);
+ lua_settable(L, -4);
+ }
+ lua_pop(L,1);
+ }
+
+ #define lua_properties_copy(target, source) do { \
+ if (lua_properties_enabled) { \
+ lua_pushinteger(Luas,source); \
+ lua_rawget(Luas,-2); \
+ if (lua_type(Luas,-1)==LUA_TTABLE) { \
+ copy_lua_table(Luas,-1); \
+ lua_pushinteger(Luas,target); \
+ lua_insert(Luas,-2); \
+ lua_rawset(Luas,-3); \
+ } else { \
+ lua_pop(Luas,1); \
+ } \
+ } \
+ } while(0)
+ \stoptyping
+
+*/
+
+/*tex Isn't there a faster way to metatable? */
+
+/*tex
+
+ \starttyping
+ #define lua_properties_copy(target,source) do { \
+ if (lua_properties_enabled) { \
+ if (lua_properties_level == 0) { \
+ lua_get_metatablelua_l(Luas,node_properties); \
+ lua_rawgeti(Luas,-1,source); \
+ if (lua_type(Luas,-1)==LUA_TTABLE) { \
+ if (lua_properties_use_metatable) { \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setfield(Luas,-2,"__index"); \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setmetatable(Luas,-2); \
+ } \
+ lua_rawseti(Luas,-2,target); \
+ } else { \
+ lua_pop(Luas,1); \
+ } \
+ lua_pop(Luas,1); \
+ } else { \
+ lua_rawgeti(Luas,-1,source); \
+ if (lua_type(Luas,-1)==LUA_TTABLE) { \
+ if (lua_properties_use_metatable) { \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setfield(Luas,-2,"__index"); \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setmetatable(Luas,-2); \
+ } \
+ lua_rawseti(Luas,-2,target); \
+ } else { \
+ lua_pop(Luas,1); \
+ } \
+ } \
+ } \
+ } while(0)
+ \stoptyping
+
+*/
+
+/*tex
+
+ A simple testrun on many pages of dumb text shows 1% gain (of course it
+ depends on how properties are used but some other tests confirm it).
+
+*/
+
+#define lua_properties_copy(target,source) do { \
+ if (lua_properties_enabled) { \
+ if (lua_properties_level == 0) { \
+ lua_get_metatablelua_l(Luas,node_properties); \
+ lua_rawgeti(Luas,-1,source); \
+ if (lua_type(Luas,-1)==LUA_TTABLE) { \
+ if (lua_properties_use_metatable) { \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_push_string_by_name(Luas,__index); \
+ lua_insert(Luas,-2); \
+ lua_rawset(Luas, -3); \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setmetatable(Luas,-2); \
+ } \
+ lua_rawseti(Luas,-2,target); \
+ } else { \
+ lua_pop(Luas,1); \
+ } \
+ lua_pop(Luas,1); \
+ } else { \
+ lua_rawgeti(Luas,-1,source); \
+ if (lua_type(Luas,-1)==LUA_TTABLE) { \
+ if (lua_properties_use_metatable) { \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_push_string_by_name(Luas,__index); \
+ lua_insert(Luas,-2); \
+ lua_rawset(Luas, -3); \
+ lua_newtable(Luas); \
+ lua_insert(Luas,-2); \
+ lua_setmetatable(Luas,-2); \
+ } \
+ lua_rawseti(Luas,-2,target); \
+ } else { \
+ lua_pop(Luas,1); \
+ } \
+ } \
+ } \
+} while(0)
+
+/*tex Here end the property handlers. */
+
+int valid_node(halfword p)
+{
+ if (p > my_prealloc && p < var_mem_max) {
+#ifdef CHECK_NODE_USAGE
+ if (varmem_sizes[p] > 0) {
+ return 1;
+ }
+#else
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+static int test_count = 1;
+
+#define dorangetest(a,b,c) do { \
+ if (!(b>=0 && b<c)) { \
+ fprintf(stdout,"For node p:=%d, 0<=%d<%d (l.%d,r.%d)\n", \
+ (int)a, (int)b, (int)c, __LINE__,test_count); \
+ confusion("node range test failed"); \
+ } } while (0)
+
+#define dotest(a,b,c) do { \
+ if (b!=c) { \
+ fprintf(stdout,"For node p:=%d, %d==%d (l.%d,r.%d)\n", \
+ (int)a, (int)b, (int)c, __LINE__,test_count); \
+ confusion("node test failed"); \
+ } } while (0)
+
+#define check_action_ref(a) { dorangetest(p,a,var_mem_max); }
+#define check_attribute_ref(a) { dorangetest(p,a,var_mem_max); }
+
+/*tex hm, we can just pass |p| then. */
+
+#define check_token_ref(p) { \
+ if (type(p) == whatsit_node) { \
+ formatted_error("nodes","fuzzy token cleanup in whatsit node with type %s and subtype %i",node_data[type(p)].name,subtype(p)); \
+ } else { \
+ formatted_error("nodes","fuzzy token cleanup in node with type %s",node_data[type(p)].name); \
+ } \
+}
+
+#ifdef CHECK_NODE_USAGE
+
+static void check_static_node_mem(void)
+{
+ dotest(zero_glue, width(zero_glue), 0);
+ dotest(zero_glue, type(zero_glue), glue_spec_node);
+ dotest(zero_glue, vlink(zero_glue), null);
+ dotest(zero_glue, stretch(zero_glue), 0);
+ dotest(zero_glue, stretch_order(zero_glue), normal);
+ dotest(zero_glue, shrink(zero_glue), 0);
+ dotest(zero_glue, shrink_order(zero_glue), normal);
+
+ dotest(sfi_glue, width(sfi_glue), 0);
+ dotest(sfi_glue, type(sfi_glue), glue_spec_node);
+ dotest(sfi_glue, vlink(sfi_glue), null);
+ dotest(sfi_glue, stretch(sfi_glue), 0);
+ dotest(sfi_glue, stretch_order(sfi_glue), sfi);
+ dotest(sfi_glue, shrink(sfi_glue), 0);
+ dotest(sfi_glue, shrink_order(sfi_glue), normal);
+
+ dotest(fil_glue, width(fil_glue), 0);
+ dotest(fil_glue, type(fil_glue), glue_spec_node);
+ dotest(fil_glue, vlink(fil_glue), null);
+ dotest(fil_glue, stretch(fil_glue), unity);
+ dotest(fil_glue, stretch_order(fil_glue), fil);
+ dotest(fil_glue, shrink(fil_glue), 0);
+ dotest(fil_glue, shrink_order(fil_glue), normal);
+
+ dotest(fill_glue, width(fill_glue), 0);
+ dotest(fill_glue, type(fill_glue), glue_spec_node);
+ dotest(fill_glue, vlink(fill_glue), null);
+ dotest(fill_glue, stretch(fill_glue), unity);
+ dotest(fill_glue, stretch_order(fill_glue), fill);
+ dotest(fill_glue, shrink(fill_glue), 0);
+ dotest(fill_glue, shrink_order(fill_glue), normal);
+
+ dotest(ss_glue, width(ss_glue), 0);
+ dotest(ss_glue, type(ss_glue), glue_spec_node);
+ dotest(ss_glue, vlink(ss_glue), null);
+ dotest(ss_glue, stretch(ss_glue), unity);
+ dotest(ss_glue, stretch_order(ss_glue), fil);
+ dotest(ss_glue, shrink(ss_glue), unity);
+ dotest(ss_glue, shrink_order(ss_glue), fil);
+
+ dotest(fil_neg_glue, width(fil_neg_glue), 0);
+ dotest(fil_neg_glue, type(fil_neg_glue), glue_spec_node);
+ dotest(fil_neg_glue, vlink(fil_neg_glue), null);
+ dotest(fil_neg_glue, stretch(fil_neg_glue), -unity);
+ dotest(fil_neg_glue, stretch_order(fil_neg_glue), fil);
+ dotest(fil_neg_glue, shrink(fil_neg_glue), 0);
+ dotest(fil_neg_glue, shrink_order(fil_neg_glue), normal);
+}
+
+static void node_mem_dump(halfword p)
+{
+ halfword r;
+ for (r = my_prealloc + 1; r < var_mem_max; r++) {
+ if (vlink(r) == p) {
+ halfword s = r;
+ while (s > my_prealloc && varmem_sizes[s] == 0) {
+ s--;
+ }
+ if (s != null
+ && s != my_prealloc
+ && s != var_mem_max
+ && (r - s) < get_node_size(type(s), subtype(s))
+ && alink(s) != p) {
+ if (type(s) == disc_node) {
+ fprintf(stdout," pointed to from %s node %d (vlink %d, alink %d): ",
+ get_node_name(type(s), subtype(s)), (int) s,
+ (int) vlink(s), (int) alink(s));
+ fprintf(stdout, "pre_break(%d,%d,%d), ",
+ (int) vlink_pre_break(s), (int) tlink(pre_break(s)),
+ (int) alink(pre_break(s)));
+ fprintf(stdout, "post_break(%d,%d,%d), ",
+ (int) vlink_post_break(s),
+ (int) tlink(post_break(s)),
+ (int) alink(post_break(s)));
+ fprintf(stdout, "no_break(%d,%d,%d)",
+ (int) vlink_no_break(s), (int) tlink(no_break(s)),
+ (int) alink(no_break(s)));
+ fprintf(stdout, "\n");
+ } else {
+ if (vlink(s) == p
+ || (type(s) == glyph_node && lig_ptr (s) == p)
+ || (type(s) == vlist_node && list_ptr(s) == p)
+ || (type(s) == hlist_node && list_ptr(s) == p)
+ || (type(s) == unset_node && list_ptr(s) == p)
+ || (type(s) == ins_node && ins_ptr (s) == p)
+ ) {
+ fprintf(stdout," pointed to from %s node %d (vlink %d, alink %d): ",
+ get_node_name(type(s), subtype(s)), (int) s,
+ (int) vlink(s), (int) alink(s));
+ if (type(s) == glyph_node) {
+ fprintf(stdout, "lig_ptr(%d)", (int) lig_ptr(s));
+ } else if (type(s) == vlist_node || type(s) == hlist_node) {
+ fprintf(stdout, "list_ptr(%d)", (int) list_ptr(s));
+ }
+ fprintf(stdout, "\n");
+ } else {
+ if ((type(s) != penalty_node) && (type(s) != math_node) && (type(s) != kern_node)) {
+ fprintf(stdout, " pointed to from %s node %d\n",
+ get_node_name(type(s), subtype(s)), (int) s);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif
+
+static int free_error(halfword p)
+{
+ if (p > my_prealloc && p < var_mem_max) {
+#ifdef CHECK_NODE_USAGE
+ int i;
+ if (varmem_sizes[p] == 0) {
+ check_static_node_mem();
+ for (i = (my_prealloc + 1); i < var_mem_max; i++) {
+ if (varmem_sizes[i] > 0) {
+ check_node(i);
+ }
+ }
+ test_count++;
+ if (type(p) == glyph_node) {
+ formatted_error("nodes", "attempt to double-free glyph (%c) node %d, ignored", (int) character(p), (int) p);
+ } else {
+ formatted_error("nodes", "attempt to double-free %s node %d, ignored", get_node_name(type(p), subtype(p)), (int) p);
+ }
+ node_mem_dump(p);
+ return 1;
+ }
+#endif
+ } else {
+ formatted_error("nodes", "attempt to free an impossible node %d", (int) p);
+ return 1;
+ }
+ return 0;
+}
+
+static int copy_error(halfword p)
+{
+ if (p >= 0 && p < var_mem_max) {
+#ifdef CHECK_NODE_USAGE
+ if (p > my_prealloc && varmem_sizes[p] == 0) {
+ if (type(p) == glyph_node) {
+ formatted_warning("nodes", "attempt to copy free glyph (%c) node %d, ignored", (int) character(p), (int) p);
+ } else {
+ formatted_warning("nodes", "attempt to copy free %s node %d, ignored", get_node_name(type(p), subtype(p)), (int) p);
+ }
+ return 1;
+ }
+#endif
+ } else {
+ formatted_error("nodes", "attempt to copy an impossible node %d", (int) p);
+ return 1;
+ }
+ return 0;
+}
+
+/*tex
+
+ Because of the 5-10\% overhead that \SYNTEX\ creates some options have been
+ implemented controlled by |synctex_anyway_mode|.
+
+ \startabulate
+ \NC \type {1} \NC all but glyphs \NC \NR
+ \NC \type {2} \NC also glyphs \NC \NR
+ \NC \type {3} \NC glyphs and glue \NC \NR
+ \NC \type {4} \NC only glyphs \NC \NR
+ \stoptabulate
+
+*/
+
+static halfword synctex_anyway_mode = 0;
+static halfword synctex_line_field = 0;
+static halfword synctex_no_files = 0;
+
+void synctex_set_mode(int m)
+{
+ synctex_anyway_mode = m;
+};
+
+int synctex_get_mode(void)
+{
+ return synctex_anyway_mode;
+};
+
+void synctex_set_no_files(int f)
+{
+ synctex_no_files = f;
+};
+
+int synctex_get_no_files(void)
+{
+ return (int) synctex_no_files ;
+};
+
+void synctex_set_tag(int t)
+{
+ cur_input.synctex_tag_field = t;
+};
+
+int synctex_get_tag(void)
+{
+ return (int) cur_input.synctex_tag_field;
+};
+
+int synctex_get_line(void)
+{
+ return (int) synctex_line_field;
+};
+
+static int forced_tag = 0;
+static int forced_line = 0;
+
+void synctex_force_tag(int t)
+{
+ forced_tag = t;
+};
+
+void synctex_force_line(int t)
+{
+ forced_line = t;
+};
+
+void synctex_set_line(int l)
+{
+ synctex_line_field = l;
+};
+
+/*tex |if_stack| is called a lot so maybe optimize that one. */
+
+halfword new_node(int i, int j)
+{
+ int s = get_node_size(i, j);
+ halfword n = get_node(s);
+ /*tex
+
+ It should be possible to do this memset at |free_node()|. Both type() and
+ subtype() will be set below, and vlink() is set to null by |get_node()|,
+ so we can do we clearing one word less than |s|.
+
+ */
+ (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * ((unsigned) s - 1)));
+ switch (i) {
+ case glyph_node:
+ init_lang_data(n);
+ break;
+ case hlist_node:
+ case vlist_node:
+ box_dir(n) = -1;
+ break;
+ case disc_node:
+ pre_break(n) = pre_break_head(n);
+ type(pre_break(n)) = nesting_node;
+ subtype(pre_break(n)) = pre_break_head(0);
+ post_break(n) = post_break_head(n);
+ type(post_break(n)) = nesting_node;
+ subtype(post_break(n)) = post_break_head(0);
+ no_break(n) = no_break_head(n);
+ type(no_break(n)) = nesting_node;
+ subtype(no_break(n)) = no_break_head(0);
+ break;
+ case rule_node:
+ depth(n) = null_flag;
+ height(n) = null_flag;
+ width(n) = null_flag;
+ rule_dir(n) = -1;
+ rule_index(n) = 0;
+ rule_transform(n) = 0;
+ break;
+ case whatsit_node:
+ if (j == open_node) {
+ open_name(n) = get_nullstr();
+ open_area(n) = open_name(n);
+ open_ext(n) = open_name(n);
+ }
+ break;
+ case unset_node:
+ width(n) = null_flag;
+ break;
+ case pseudo_line_node:
+ case shape_node:
+ /*tex
+
+ This is a trick that makes |pseudo_files| slightly slower, but
+ the overall allocation faster then an explicit test at the top of
+ |new_node()|.
+
+ */
+ if (j>0) {
+ free_node(n, variable_node_size);
+ n = slow_get_node(j);
+ (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * ((unsigned) j - 1)));
+ }
+ break;
+ case fraction_noad:
+ fraction_fam(n) = -1;
+ break;
+ case simple_noad:
+ noad_fam(n) = -1;
+ break;
+ default:
+ break;
+ }
+ if (synctex_anyway_mode) {
+ /*tex See table above. */
+ switch (i) {
+ case glyph_node:
+ if (synctex_anyway_mode > 1) {
+ synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ case glue_node:
+ if (synctex_anyway_mode < 4) {
+ synctex_tag_glue(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_glue(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ case kern_node:
+ if (synctex_anyway_mode < 3) {
+ synctex_tag_kern(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_kern(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ /*tex Rather useless: */
+ if (synctex_anyway_mode < 3) {
+ synctex_tag_box(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_box(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ case rule_node:
+ if (synctex_anyway_mode < 3) {
+ synctex_tag_rule(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_rule(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ case math_node:
+ /*tex Noads probably make more sense but let's not change that. */
+ if (synctex_anyway_mode < 3) {
+ synctex_tag_math(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_math(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ break;
+ }
+ } else if (synctex_par) {
+ /*tex Handle the \SYNTEX\ extension. */
+ switch (i) {
+ case glue_node:
+ synctex_tag_glue(n) = cur_input.synctex_tag_field;
+ synctex_line_glue(n) = line;
+ break;
+ case kern_node:
+ if (j != 0) {
+ synctex_tag_kern(n) = cur_input.synctex_tag_field;
+ synctex_line_kern(n) = line;
+ }
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ synctex_tag_box(n) = cur_input.synctex_tag_field;
+ synctex_line_box(n) = line;
+ break;
+ case rule_node:
+ synctex_tag_rule(n) = cur_input.synctex_tag_field;
+ synctex_line_rule(n) = line;
+ break;
+ case math_node:
+ synctex_tag_math(n) = cur_input.synctex_tag_field;
+ synctex_line_math(n) = line;
+ break;
+ }
+ }
+ /*tex Take care of attributes. */
+ if (nodetype_has_attributes(i)) {
+ build_attribute_list(n);
+ /*tex No need for |lua_properties_set|. */
+ }
+ type(n) = (quarterword) i;
+ subtype(n) = (quarterword) j;
+ return n;
+}
+
+halfword raw_glyph_node(void)
+{
+ register halfword n = get_node(glyph_node_size);
+ (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * (glyph_node_size - 1)));
+ if (synctex_anyway_mode > 1) {
+ synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ type(n) = glyph_node;
+ subtype(n) = 0;
+ return n;
+}
+
+halfword new_glyph_node(void)
+{
+ register halfword n = get_node(glyph_node_size);
+ (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * (glyph_node_size - 1)));
+ if (synctex_anyway_mode > 1) {
+ synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ type(n) = glyph_node;
+ subtype(n) = 0;
+ build_attribute_list(n);
+ /*tex No need for |lua_properties_set|. */
+ return n;
+}
+
+/*tex
+
+ This makes a duplicate of the node list that starts at |p| and returns a
+ pointer to the new list.
+
+*/
+
+halfword do_copy_node_list(halfword p, halfword end)
+{
+ /*tex previous position in new list */
+ halfword q = null;
+ /*tex head of the list */
+ halfword h = null;
+ register halfword s ;
+ /*tex saves stack and time */
+ lua_properties_push;
+ while (p != end) {
+ s = copy_node(p);
+ if (h == null) {
+ h = s;
+ } else {
+ couple_nodes(q, s);
+ }
+ q = s;
+ p = vlink(p);
+ }
+ /*tex saves stack and time */
+ lua_properties_pop;
+ return h;
+}
+
+halfword copy_node_list(halfword p)
+{
+ return do_copy_node_list(p, null);
+}
+
+#define copy_sub_list(target,source) do { \
+ if (source != null) { \
+ s = do_copy_node_list(source, null); \
+ target = s; \
+ } else { \
+ target = null; \
+ } \
+ } while (0)
+
+#define copy_sub_node(target,source) do { \
+ if (source != null) { \
+ s = copy_node(source); \
+ target = s ; \
+ } else { \
+ target = null; \
+ } \
+} while (0)
+
+/*tex Make a dupe of a single node. */
+
+static void copy_node_wrapup_core(halfword p, halfword r)
+{
+ halfword s ;
+ switch (subtype(p)) {
+ case write_node:
+ case special_node:
+ add_token_ref(write_tokens(p));
+ break;
+ case late_lua_node:
+ copy_late_lua(r, p);
+ break;
+ case user_defined_node:
+ switch (user_node_type(p)) {
+ case 'a':
+ add_node_attr_ref(user_node_value(p));
+ break;
+ case 'l':
+ copy_user_lua(r, p);
+ break;
+ case 'n':
+ s = copy_node_list(user_node_value(p));
+ user_node_value(r) = s;
+ break;
+ case 's':
+ /* |add_string_ref(user_node_value(p));| */
+ break;
+ case 't':
+ add_token_ref(user_node_value(p));
+ break;
+ }
+ break;
+ default:
+ break ;
+ }
+}
+
+void copy_node_wrapup_dvi(halfword p, halfword r)
+{
+}
+
+void copy_node_wrapup_pdf(halfword p, halfword r)
+{
+ switch(subtype(p)) {
+ case pdf_literal_node:
+ copy_pdf_literal(r, p);
+ break;
+ case pdf_colorstack_node:
+ if (pdf_colorstack_cmd(p) <= colorstack_data)
+ add_token_ref(pdf_colorstack_data(p));
+ break;
+ case pdf_setmatrix_node:
+ add_token_ref(pdf_setmatrix_data(p));
+ break;
+ case pdf_annot_node:
+ add_token_ref(pdf_annot_data(p));
+ break;
+ case pdf_start_link_node:
+ if (pdf_link_attr(r) != null)
+ add_token_ref(pdf_link_attr(r));
+ add_action_ref(pdf_link_action(r));
+ break;
+ case pdf_dest_node:
+ if (pdf_dest_named_id(p) > 0)
+ add_token_ref(pdf_dest_id(p));
+ break;
+ case pdf_thread_node:
+ case pdf_start_thread_node:
+ if (pdf_thread_named_id(p) > 0)
+ add_token_ref(pdf_thread_id(p));
+ if (pdf_thread_attr(p) != null)
+ add_token_ref(pdf_thread_attr(p));
+ break;
+ default:
+ break;
+ }
+}
+
+halfword copy_node(const halfword p)
+{
+ /*tex current node being fabricated for new list */
+ halfword r;
+ /*tex whatsit subtype */
+ halfword w;
+ /*tex type of node */
+ halfword t;
+ /*tex a helper variable for copying into variable mem */
+ register halfword s;
+ register int i;
+ if (copy_error(p)) {
+ r = new_node(temp_node, 0);
+ return r;
+ }
+ t = type(p);
+ i = get_node_size(t,subtype(p));
+ r = get_node(i);
+ (void) memcpy((void *) (varmem + r), (void *) (varmem + p), (sizeof(memory_word) * (unsigned) i));
+ /*tex A possible speedup:
+
+ \starttyping
+ if t == glue_spec) {
+ return r;
+ }
+ \stoptyping
+
+ */
+ if (synctex_anyway_mode) {
+ /*tex Not:
+
+ \starttyping
+ if (t == glyph_node) {
+ if (synctex_anyway_mode > 1) {
+ synctex_tag_glyph(r) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
+ synctex_line_glyph(r) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
+ }
+ }
+ \stoptyping
+ */
+ } else if (synctex_par) {
+ /*tex Handle synctex extension. */
+ switch (t) {
+ case math_node:
+ synctex_tag_math(r) = cur_input.synctex_tag_field;
+ synctex_line_math(r) = line;
+ break;
+ case kern_node:
+ synctex_tag_kern(r) = cur_input.synctex_tag_field;
+ synctex_line_kern(r) = line;
+ break;
+ }
+ }
+ if (nodetype_has_attributes(t)) {
+ add_node_attr_ref(node_attr(p));
+ alink(r) = null;
+ lua_properties_copy(r,p);
+ }
+ vlink(r) = null;
+ switch (t) {
+ case glyph_node:
+ copy_sub_list(lig_ptr(r),lig_ptr(p)) ;
+ break;
+ case glue_node:
+ copy_sub_list(leader_ptr(r),leader_ptr(p)) ;
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ copy_sub_list(list_ptr(r),list_ptr(p)) ;
+ break;
+ case disc_node:
+ pre_break(r) = pre_break_head(r);
+ if (vlink_pre_break(p) != null) {
+ s = copy_node_list(vlink_pre_break(p));
+ alink(s) = pre_break(r);
+ tlink_pre_break(r) = tail_of_list(s);
+ vlink_pre_break(r) = s;
+ } else {
+ assert(tlink(pre_break(r)) == null);
+ }
+ post_break(r) = post_break_head(r);
+ if (vlink_post_break(p) != null) {
+ s = copy_node_list(vlink_post_break(p));
+ alink(s) = post_break(r);
+ tlink_post_break(r) = tail_of_list(s);
+ vlink_post_break(r) = s;
+ } else {
+ assert(tlink_post_break(r) == null);
+ }
+ no_break(r) = no_break_head(r);
+ if (vlink(no_break(p)) != null) {
+ s = copy_node_list(vlink_no_break(p));
+ alink(s) = no_break(r);
+ tlink_no_break(r) = tail_of_list(s);
+ vlink_no_break(r) = s;
+ } else {
+ assert(tlink_no_break(r) == null);
+ }
+ break;
+ case math_node:
+ break;
+ case ins_node:
+ copy_sub_list(ins_ptr(r),ins_ptr(p)) ;
+ break;
+ case margin_kern_node:
+ copy_sub_node(margin_char(r),margin_char(p));
+ break;
+ case mark_node:
+ add_token_ref(mark_ptr(p));
+ break;
+ case adjust_node:
+ copy_sub_list(adjust_ptr(r),adjust_ptr(p));
+ break;
+ case choice_node:
+ copy_sub_list(display_mlist(r),display_mlist(p)) ;
+ copy_sub_list(text_mlist(r),text_mlist(p)) ;
+ copy_sub_list(script_mlist(r),script_mlist(p)) ;
+ copy_sub_list(script_script_mlist(r),script_script_mlist(p)) ;
+ break;
+ case simple_noad:
+ copy_sub_list(nucleus(r),nucleus(p)) ;
+ copy_sub_list(subscr(r),subscr(p)) ;
+ copy_sub_list(supscr(r),supscr(p)) ;
+ break;
+ case radical_noad:
+ copy_sub_list(nucleus(r),nucleus(p)) ;
+ copy_sub_list(subscr(r),subscr(p)) ;
+ copy_sub_list(supscr(r),supscr(p)) ;
+ copy_sub_node(left_delimiter(r),left_delimiter(p)) ;
+ copy_sub_list(degree(r),degree(p)) ;
+ break;
+ case accent_noad:
+ copy_sub_list(nucleus(r),nucleus(p)) ;
+ copy_sub_list(subscr(r),subscr(p)) ;
+ copy_sub_list(supscr(r),supscr(p)) ;
+ copy_sub_list(top_accent_chr(r),top_accent_chr(p)) ;
+ copy_sub_list(bot_accent_chr(r),bot_accent_chr(p)) ;
+ copy_sub_list(overlay_accent_chr(r),overlay_accent_chr(p)) ;
+ break;
+ case fence_noad:
+ copy_sub_node(delimiter(r),delimiter(p)) ;
+ break;
+ case sub_box_node:
+ case sub_mlist_node:
+ copy_sub_list(math_list(r),math_list(p)) ;
+ break;
+ case fraction_noad:
+ copy_sub_list(numerator(r),numerator(p)) ;
+ copy_sub_list(denominator(r),denominator(p)) ;
+ copy_sub_node(left_delimiter(r),left_delimiter(p)) ;
+ copy_sub_node(right_delimiter(r),right_delimiter(p)) ;
+ break;
+ case glue_spec_node:
+ break;
+ case dir_node:
+ break;
+ case local_par_node:
+ copy_sub_list(local_box_left(r),local_box_left(p));
+ copy_sub_list(local_box_right(r),local_box_right(p));
+ case boundary_node:
+ break;
+ case whatsit_node:
+ w = subtype(p) ;
+ if (w >= backend_first_pdf_whatsit) {
+ copy_node_wrapup_pdf(p,r);
+ } else if (w >= backend_first_dvi_whatsit) {
+ copy_node_wrapup_dvi(p,r);
+ } else {
+ copy_node_wrapup_core(p,r);
+ }
+ break;
+ }
+ return r;
+}
+
+#define free_sub_list(source) if (source != null) flush_node_list(source);
+#define free_sub_node(source) if (source != null) flush_node(source);
+
+static void flush_node_wrapup_core(halfword p)
+{
+ switch (subtype(p)) {
+ case open_node:
+ case write_node:
+ case close_node:
+ case save_pos_node:
+ break;
+ case special_node:
+ delete_token_ref(write_tokens(p));
+ break;
+ case late_lua_node:
+ free_late_lua(p);
+ break;
+ case user_defined_node:
+ switch (user_node_type(p)) {
+ case 'a':
+ delete_attribute_ref(user_node_value(p));
+ break;
+ case 'd':
+ break;
+ case 'l':
+ free_user_lua(user_node_value(p));
+ break;
+ case 'n':
+ flush_node_list(user_node_value(p));
+ break;
+ case 's':
+ /*tex |delete_string_ref(user_node_value(p));| *//* if this was mpost .. */
+ break;
+ case 't':
+ delete_token_ref(user_node_value(p));
+ break;
+ default:
+ {
+ const char *hlp[] = {
+ "The type of the value in a user defined whatsit node should be one",
+ "of 'a' (attribute list), 'd' (number), 'n' (node list), 's' (string),",
+ "or 't' (tokenlist). Yours has an unknown type, and therefore I don't",
+ "know how to free the node's value. A memory leak may result.",
+ NULL
+ };
+ tex_error("Unidentified user defined whatsit", hlp);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+void flush_node_wrapup_dvi(halfword p)
+{
+}
+
+void flush_node_wrapup_pdf(halfword p)
+{
+ switch(subtype(p)) {
+ case pdf_save_node:
+ case pdf_restore_node:
+ case pdf_refobj_node:
+ case pdf_end_link_node:
+ case pdf_end_thread_node:
+ break;
+ case pdf_literal_node:
+ free_pdf_literal(p);
+ break;
+ case pdf_colorstack_node:
+ if (pdf_colorstack_cmd(p) <= colorstack_data)
+ delete_token_ref(pdf_colorstack_data(p));
+ break;
+ case pdf_setmatrix_node:
+ delete_token_ref(pdf_setmatrix_data(p));
+ break;
+ case pdf_annot_node:
+ delete_token_ref(pdf_annot_data(p));
+ break;
+ case pdf_link_data_node:
+ break;
+ case pdf_start_link_node:
+ if (pdf_link_attr(p) != null)
+ delete_token_ref(pdf_link_attr(p));
+ delete_action_ref(pdf_link_action(p));
+ break;
+ case pdf_dest_node:
+ if (pdf_dest_named_id(p) > 0)
+ delete_token_ref(pdf_dest_id(p));
+ break;
+ case pdf_action_node:
+ if (pdf_action_type(p) == pdf_action_user) {
+ delete_token_ref(pdf_action_tokens(p));
+ } else {
+ if (pdf_action_file(p) != null)
+ delete_token_ref(pdf_action_file(p));
+ if (pdf_action_type(p) == pdf_action_page)
+ delete_token_ref(pdf_action_tokens(p));
+ else if (pdf_action_named_id(p) > 0)
+ delete_token_ref(pdf_action_id(p));
+ }
+ break;
+ case pdf_thread_data_node:
+ break;
+ case pdf_thread_node:
+ case pdf_start_thread_node:
+ if (pdf_thread_named_id(p) > 0)
+ delete_token_ref(pdf_thread_id(p));
+ if (pdf_thread_attr(p) != null)
+ delete_token_ref(pdf_thread_attr(p));
+ break;
+ }
+}
+
+void flush_node(halfword p)
+{
+ halfword w;
+ if (p == null){
+ /*tex legal, but no-op. */
+ return;
+ }
+ if (free_error(p))
+ return;
+ switch (type(p)) {
+ case glyph_node:
+ free_sub_list(lig_ptr(p));
+ break;
+ case glue_node:
+ free_sub_list(leader_ptr(p));
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ free_sub_list(list_ptr(p));
+ break;
+ case disc_node:
+ /*tex Watch the start at temp node hack! */
+ free_sub_list(vlink(pre_break(p)));
+ free_sub_list(vlink(post_break(p)));
+ free_sub_list(vlink(no_break(p)));
+ break;
+ case rule_node:
+ case kern_node:
+ case penalty_node:
+ case math_node:
+ break;
+ case glue_spec_node:
+ /*tex This allows free-ing of lua-allocated glue specs. */
+ break ;
+ case dir_node:
+ break;
+ case local_par_node:
+ free_sub_list(local_box_left(p));
+ free_sub_list(local_box_right(p));
+ break;
+ case boundary_node:
+ break;
+ case whatsit_node:
+ w = subtype(p) ;
+ if (w >= backend_first_pdf_whatsit) {
+ flush_node_wrapup_pdf(p);
+ } else if (w >= backend_first_dvi_whatsit) {
+ flush_node_wrapup_dvi(p);
+ } else {
+ flush_node_wrapup_core(p);
+ }
+ break;
+ case ins_node:
+ flush_node_list(ins_ptr(p));
+ break;
+ case margin_kern_node:
+ flush_node(margin_char(p));
+ break;
+ case mark_node:
+ delete_token_ref(mark_ptr(p));
+ break;
+ case adjust_node:
+ flush_node_list(adjust_ptr(p));
+ break;
+ case style_node:
+ /*tex Nothing to do. */
+ break;
+ case choice_node:
+ free_sub_list(display_mlist(p));
+ free_sub_list(text_mlist(p));
+ free_sub_list(script_mlist(p));
+ free_sub_list(script_script_mlist(p));
+ break;
+ case simple_noad:
+ free_sub_list(nucleus(p));
+ free_sub_list(subscr(p));
+ free_sub_list(supscr(p));
+ break;
+ case radical_noad:
+ free_sub_list(nucleus(p));
+ free_sub_list(subscr(p));
+ free_sub_list(supscr(p));
+ free_sub_node(left_delimiter(p));
+ free_sub_list(degree(p));
+ break;
+ case accent_noad:
+ free_sub_list(nucleus(p));
+ free_sub_list(subscr(p));
+ free_sub_list(supscr(p));
+ free_sub_list(top_accent_chr(p));
+ free_sub_list(bot_accent_chr(p));
+ free_sub_list(overlay_accent_chr(p));
+ break;
+ case fence_noad:
+ free_sub_list(delimiter(p));
+ break;
+ case delim_node:
+ case math_char_node:
+ case math_text_char_node:
+ /*tex Nothing to do. */
+ break;
+ case sub_box_node:
+ case sub_mlist_node:
+ free_sub_list(math_list(p));
+ break;
+ case fraction_noad:
+ free_sub_list(numerator(p));
+ free_sub_list(denominator(p));
+ free_sub_node(left_delimiter(p));
+ free_sub_node(right_delimiter(p));
+ break;
+ case pseudo_file_node:
+ free_sub_list(pseudo_lines(p));
+ break;
+ case pseudo_line_node:
+ case shape_node:
+ free_node(p, subtype(p));
+ return;
+ break;
+ case align_stack_node:
+ case span_node:
+ case movement_node:
+ case if_node:
+ case nesting_node:
+ case unhyphenated_node:
+ case hyphenated_node:
+ case delta_node:
+ case passive_node:
+ case inserting_node:
+ case split_up_node:
+ case expr_node:
+ case attribute_node:
+ case attribute_list_node:
+ case temp_node:
+ break;
+ default:
+ formatted_error("nodes","flushing weird node type %d", type(p));
+ return;
+ }
+ if (nodetype_has_attributes(type(p))) {
+ delete_attribute_ref(node_attr(p));
+ lua_properties_reset(p);
+ }
+ free_node(p, get_node_size(type(p), subtype(p)));
+ return;
+}
+
+/*tex Erase the list of nodes starting at |pp|. */
+
+void flush_node_list(halfword pp)
+{
+ register halfword p = pp;
+ if (p == null) {
+ /*tex Legal, but no-op. */
+ return;
+ }
+ if (free_error(p))
+ return;
+ /*tex Saves stack and time. */
+ lua_properties_push;
+ while (p != null) {
+ register halfword q = vlink(p);
+ flush_node(p);
+ p = q;
+ }
+ /*tex Saves stack and time. */
+ lua_properties_pop;
+}
+
+static void check_node_wrapup_core(halfword p)
+{
+ switch (subtype(p)) {
+ /*tex Frontend code. */
+ case special_node:
+ check_token_ref(p);
+ break;
+ case user_defined_node:
+ switch (user_node_type(p)) {
+ case 'a':
+ check_attribute_ref(user_node_value(p));
+ break;
+ case 't':
+ check_token_ref(p);
+ break;
+ case 'n':
+ dorangetest(p, user_node_value(p), var_mem_max);
+ break;
+ case 's':
+ case 'd':
+ break;
+ default:
+ confusion("unknown user node type");
+ break;
+ }
+ break;
+ case open_node:
+ case write_node:
+ case close_node:
+ case save_pos_node:
+ break;
+ }
+}
+
+void check_node_wrapup_dvi(halfword p)
+{
+}
+
+void check_node_wrapup_pdf(halfword p)
+{
+ switch (subtype(p)) {
+ case pdf_literal_node:
+ if (pdf_literal_type(p) == normal)
+ check_token_ref(p);
+ break;
+ case pdf_colorstack_node:
+ if (pdf_colorstack_cmd(p) <= colorstack_data)
+ check_token_ref(p);
+ break;
+ case pdf_setmatrix_node:
+ check_token_ref(p);
+ break;
+ case late_lua_node:
+ if (late_lua_name(p) > 0)
+ check_token_ref(p);
+ if (late_lua_type(p) == normal)
+ check_token_ref(p);
+ break;
+ case pdf_annot_node:
+ check_token_ref(p);
+ break;
+ case pdf_start_link_node:
+ if (pdf_link_attr(p) != null)
+ check_token_ref(p);
+ check_action_ref(pdf_link_action(p));
+ break;
+ case pdf_dest_node:
+ if (pdf_dest_named_id(p) > 0)
+ check_token_ref(p);
+ break;
+ case pdf_thread_node:
+ case pdf_start_thread_node:
+ if (pdf_thread_named_id(p) > 0)
+ check_token_ref(p);
+ if (pdf_thread_attr(p) != null)
+ check_token_ref(p);
+ break;
+ case pdf_save_node:
+ case pdf_restore_node:
+ case pdf_refobj_node:
+ case pdf_end_link_node:
+ case pdf_end_thread_node:
+ break;
+ default:
+ confusion("wrapup pdf nodes");
+ break;
+ }
+}
+
+void check_node(halfword p)
+{
+ halfword w ;
+ switch (type(p)) {
+ case glyph_node:
+ dorangetest(p, lig_ptr(p), var_mem_max);
+ break;
+ case glue_node:
+ dorangetest(p, leader_ptr(p), var_mem_max);
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ case align_record_node:
+ dorangetest(p, list_ptr(p), var_mem_max);
+ break;
+ case ins_node:
+ dorangetest(p, ins_ptr(p), var_mem_max);
+ break;
+ case whatsit_node:
+ w = subtype(p) ;
+ if (w >= backend_first_pdf_whatsit) {
+ check_node_wrapup_pdf(p);
+ } else if (w >= backend_first_dvi_whatsit) {
+ check_node_wrapup_dvi(p);
+ } else {
+ check_node_wrapup_core(p);
+ }
+ break;
+ case margin_kern_node:
+ check_node(margin_char(p));
+ break;
+ case math_node:
+ break;
+ case disc_node:
+ dorangetest(p, vlink(pre_break(p)), var_mem_max);
+ dorangetest(p, vlink(post_break(p)), var_mem_max);
+ dorangetest(p, vlink(no_break(p)), var_mem_max);
+ break;
+ case adjust_node:
+ dorangetest(p, adjust_ptr(p), var_mem_max);
+ break;
+ case pseudo_file_node:
+ dorangetest(p, pseudo_lines(p), var_mem_max);
+ break;
+ case pseudo_line_node:
+ case shape_node:
+ break;
+ case choice_node:
+ dorangetest(p, display_mlist(p), var_mem_max);
+ dorangetest(p, text_mlist(p), var_mem_max);
+ dorangetest(p, script_mlist(p), var_mem_max);
+ dorangetest(p, script_script_mlist(p), var_mem_max);
+ break;
+ case fraction_noad:
+ dorangetest(p, numerator(p), var_mem_max);
+ dorangetest(p, denominator(p), var_mem_max);
+ dorangetest(p, left_delimiter(p), var_mem_max);
+ dorangetest(p, right_delimiter(p), var_mem_max);
+ break;
+ case simple_noad:
+ dorangetest(p, nucleus(p), var_mem_max);
+ dorangetest(p, subscr(p), var_mem_max);
+ dorangetest(p, supscr(p), var_mem_max);
+ break;
+ case radical_noad:
+ dorangetest(p, nucleus(p), var_mem_max);
+ dorangetest(p, subscr(p), var_mem_max);
+ dorangetest(p, supscr(p), var_mem_max);
+ dorangetest(p, degree(p), var_mem_max);
+ dorangetest(p, left_delimiter(p), var_mem_max);
+ break;
+ case accent_noad:
+ dorangetest(p, nucleus(p), var_mem_max);
+ dorangetest(p, subscr(p), var_mem_max);
+ dorangetest(p, supscr(p), var_mem_max);
+ dorangetest(p, top_accent_chr(p), var_mem_max);
+ dorangetest(p, bot_accent_chr(p), var_mem_max);
+ dorangetest(p, overlay_accent_chr(p), var_mem_max);
+ break;
+ case fence_noad:
+ dorangetest(p, delimiter(p), var_mem_max);
+ break;
+ case local_par_node:
+ dorangetest(p, local_box_left(p), var_mem_max);
+ dorangetest(p, local_box_right(p), var_mem_max);
+ break;
+ /*tex
+
+ There is no need for useless cases:
+
+ \starttyping
+ case rule_node:
+ case kern_node:
+ case penalty_node:
+ case mark_node:
+ case style_node:
+ case attribute_list_node:
+ case attribute_node:
+ case glue_spec_node:
+ case temp_node:
+ case align_stack_node:
+ case movement_node:
+ case if_node:
+ case nesting_node:
+ case span_node:
+ case unhyphenated_node:
+ case hyphenated_node:
+ case delta_node:
+ case passive_node:
+ case expr_node:
+ case dir_node:
+ case boundary_node:
+ break;
+ default:
+ fprintf(stdout, "check_node: type is %d\n", type(p));
+ \stoptyping
+
+ */
+ }
+}
+
+halfword fix_node_list(halfword head)
+{
+ halfword next, tail;
+ if (head == null)
+ return null;
+ tail = head;
+ next = vlink(head);
+ while (next != null) {
+ alink(next) = tail;
+ tail = next;
+ next = vlink(tail);
+ }
+ return tail;
+}
+
+halfword get_node(int s)
+{
+ register halfword r;
+
+ if (s < MAX_CHAIN_SIZE) {
+ r = free_chain[s];
+ if (r != null) {
+ free_chain[s] = vlink(r);
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes[r] = (char) s;
+#endif
+ vlink(r) = null;
+ /*tex Maintain usage statistics. */
+ var_used += s;
+ return r;
+ }
+ /*tex This is the end of the \quote {inner loop}. */
+ return slow_get_node(s);
+ } else {
+ normal_error("nodes","there is a problem in getting a node, case 1");
+ return null;
+ }
+}
+
+void free_node(halfword p, int s)
+{
+ if (p <= my_prealloc) {
+ formatted_error("nodes", "node number %d of type %d should not be freed", (int) p, type(p));
+ return;
+ }
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes[p] = 0;
+#endif
+ if (s < MAX_CHAIN_SIZE) {
+ vlink(p) = free_chain[s];
+ free_chain[s] = p;
+ } else {
+ /*tex Todo: it is perhaps possible to merge this node with an existing rover? */
+ node_size(p) = s;
+ vlink(p) = rover;
+ while (vlink(rover) != vlink(p)) {
+ rover = vlink(rover);
+ }
+ vlink(rover) = p;
+ }
+ /*tex Maintain statistics. */
+ var_used -= s;
+}
+
+static void free_node_chain(halfword q, int s)
+{
+ register halfword p = q;
+ while (vlink(p) != null) {
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes[p] = 0;
+#endif
+ var_used -= s;
+ p = vlink(p);
+ }
+ var_used -= s;
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes[p] = 0;
+#endif
+ vlink(p) = free_chain[s];
+ free_chain[s] = q;
+}
+
+/*tex
+
+ At the start of the node memory area we reserve some special nodes, for
+ instance frequently used glue specifications. We could as well just use
+ new_glue here but for the moment we stick to the traditional approach.
+
+*/
+
+#define initialize_glue(n,wi,st,sh,sto,sho) \
+ vlink(n) = null; \
+ type(n) = glue_spec_node; \
+ width(n) = wi; \
+ stretch(n) = st; \
+ shrink(n) = sh; \
+ stretch_order(n) = sto; \
+ shrink_order(n) = sho;
+
+#define initialize_whatever(n,t) \
+ vinfo(n) = 0; \
+ type(n) = t; \
+ vlink(n) = null; \
+ alink(n) = null;
+
+#define initialize_point(n) \
+ type(n) = glyph_node; \
+ subtype(n) = 0; \
+ vlink(n) = null; \
+ vinfo(n + 1) = null; \
+ alink(n) = null; \
+ font(n) = 0; \
+ character(n) = '.'; \
+ vinfo(n + 3) = 0; \
+ vlink(n + 3) = 0; \
+ vinfo(n + 4) = 0; \
+ vlink(n + 4) = 0;
+
+void init_node_mem(int t)
+{
+ my_prealloc = var_mem_stat_max;
+
+ varmem = (memory_word *) realloc((void *) varmem, sizeof(memory_word) * (unsigned) t);
+ if (varmem == NULL) {
+ overflow("node memory size", (unsigned) var_mem_max);
+ }
+ memset((void *) (varmem), 0, (unsigned) t * sizeof(memory_word));
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes = (char *) realloc(varmem_sizes, sizeof(char) * (unsigned) t);
+ if (varmem_sizes == NULL) {
+ overflow("node memory size", (unsigned) var_mem_max);
+ }
+ memset((void *) varmem_sizes, 0, sizeof(char) * (unsigned) t);
+#endif
+ var_mem_max = t;
+ rover = var_mem_stat_max + 1;
+ vlink(rover) = rover;
+ node_size(rover) = (t - rover);
+ var_used = 0;
+
+ /*tex Initialize static glue specs. */
+
+ initialize_glue(zero_glue,0,0,0,0,0);
+ initialize_glue(sfi_glue,0,0,0,sfi,0);
+ initialize_glue(fil_glue,0,unity,0,fil,0);
+ initialize_glue(fill_glue,0,unity,0,fill,0);
+ initialize_glue(ss_glue,0,unity,unity,fil,fil);
+ initialize_glue(fil_neg_glue,0,-unity,0,fil,0);
+
+ /*tex Initialize node list heads. */
+
+ initialize_whatever(page_ins_head,temp_node);
+ initialize_whatever(contrib_head,temp_node);
+ initialize_whatever(page_head,temp_node);
+ initialize_whatever(temp_head,temp_node);
+ initialize_whatever(hold_head,temp_node);
+ initialize_whatever(adjust_head,temp_node);
+ initialize_whatever(pre_adjust_head,temp_node);
+ initialize_whatever(align_head,temp_node);
+
+ initialize_whatever(active,unhyphenated_node);
+ initialize_whatever(end_span,span_node);
+
+ initialize_point(begin_point);
+ initialize_point(end_point);
+}
+
+void dump_node_mem(void)
+{
+ dump_int(var_mem_max);
+ dump_int(rover);
+ dump_things(varmem[0], var_mem_max);
+#ifdef CHECK_NODE_USAGE
+ dump_things(varmem_sizes[0], var_mem_max);
+#endif
+ dump_things(free_chain[0], MAX_CHAIN_SIZE);
+ dump_int(var_used);
+ dump_int(my_prealloc);
+}
+
+/*tex
+
+ It makes sense to enlarge the varmem array immediately.
+
+*/
+
+void undump_node_mem(void)
+{
+ int x;
+ undump_int(x);
+ undump_int(rover);
+ var_mem_max = (x < 100000 ? 100000 : x);
+ varmem = xmallocarray(memory_word, (unsigned) var_mem_max);
+ undump_things(varmem[0], x);
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
+ memset((void *) varmem_sizes, 0, (unsigned) var_mem_max * sizeof(char));
+ undump_things(varmem_sizes[0], x);
+#endif
+ undump_things(free_chain[0], MAX_CHAIN_SIZE);
+ undump_int(var_used);
+ undump_int(my_prealloc);
+ if (var_mem_max > x) {
+ /*tex Todo: is it perhaps possible to merge the new node with an existing rover? */
+ vlink(x) = rover;
+ node_size(x) = (var_mem_max - x);
+ while (vlink(rover) != vlink(x)) {
+ rover = vlink(rover);
+ }
+ vlink(rover) = x;
+ }
+}
+
+halfword slow_get_node(int s)
+{
+ register int t;
+
+ RETRY:
+ t = node_size(rover);
+ if (vlink(rover) < var_mem_max && vlink(rover) != 0) {
+ if (t > s) {
+ /*tex Allocating from the bottom helps decrease page faults. */
+ register halfword r = rover;
+ rover += s;
+ vlink(rover) = vlink(r);
+ node_size(rover) = node_size(r) - s;
+ if (vlink(rover) != r) {
+ /*tex The list is longer than one. */
+ halfword q = r;
+ while (vlink(q) != r) {
+ q = vlink(q);
+ }
+ vlink(q) += s;
+ } else {
+ vlink(rover) += s;
+ }
+ if (vlink(rover) < var_mem_max) {
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes[r] = (char) (s > 127 ? 127 : s);
+#endif
+ vlink(r) = null;
+ /*tex Maintain usage statistics. */
+ var_used += s;
+ /*tex This is the only exit. */
+ return r;
+ } else {
+ normal_error("nodes","there is a problem in getting a node, case 2");
+ return null;
+ }
+ } else {
+ /*tex Attempt to keep the free list small. */
+ int x;
+ if (vlink(rover) != rover) {
+ if (t < MAX_CHAIN_SIZE) {
+ halfword l = vlink(rover);
+ vlink(rover) = free_chain[t];
+ free_chain[t] = rover;
+ rover = l;
+ while (vlink(l) != free_chain[t]) {
+ l = vlink(l);
+ }
+ vlink(l) = rover;
+ goto RETRY;
+ } else {
+ halfword l = rover;
+ while (vlink(rover) != l) {
+ if (node_size(rover) > s) {
+ goto RETRY;
+ }
+ rover = vlink(rover);
+ }
+ }
+ }
+ /*tex If we are still here, it was apparently impossible to get a match. */
+ x = (var_mem_max >> 2) + s;
+ varmem = (memory_word *) realloc((void *) varmem, sizeof(memory_word) * (unsigned) (var_mem_max + x));
+ if (varmem == NULL) {
+ overflow("node memory size", (unsigned) var_mem_max);
+ }
+ memset((void *) (varmem + var_mem_max), 0, (unsigned) x * sizeof(memory_word));
+#ifdef CHECK_NODE_USAGE
+ varmem_sizes = (char *) realloc(varmem_sizes, sizeof(char) * (unsigned) (var_mem_max + x));
+ if (varmem_sizes == NULL) {
+ overflow("node memory size", (unsigned) var_mem_max);
+ }
+ memset((void *) (varmem_sizes + var_mem_max), 0, (unsigned) (x) * sizeof(char));
+#endif
+ /*tex Todo: is it perhaps possible to merge the new memory with an existing rover? */
+ vlink(var_mem_max) = rover;
+ node_size(var_mem_max) = x;
+ while (vlink(rover) != vlink(var_mem_max)) {
+ rover = vlink(rover);
+ }
+ vlink(rover) = var_mem_max;
+ rover = var_mem_max;
+ var_mem_max += x;
+ goto RETRY;
+ }
+ } else {
+ normal_error("nodes","there is a problem in getting a node, case 3");
+ return null;
+ }
+}
+
+char *sprint_node_mem_usage(void)
+{
+ char *s;
+#ifdef CHECK_NODE_USAGE
+ char *ss;
+ int i;
+ int b = 0;
+ char msg[256];
+ int node_counts[last_normal_node + last_whatsit_node + 2] = { 0 };
+ s = strdup("");
+ for (i = (var_mem_max - 1); i > my_prealloc; i--) {
+ if (varmem_sizes[i] > 0) {
+ if (type(i) > last_normal_node + last_whatsit_node) {
+ node_counts[last_normal_node + last_whatsit_node + 1]++;
+ } else if (type(i) == whatsit_node) {
+ node_counts[(subtype(i) + last_normal_node + 1)]++;
+ } else {
+ node_counts[type(i)]++;
+ }
+ }
+ }
+ for (i = 0; i < last_normal_node + last_whatsit_node + 2; i++) {
+ if (node_counts[i] > 0) {
+ int j =
+ (i > (last_normal_node + 1) ? (i - last_normal_node - 1) : 0);
+ snprintf(msg, 255, "%s%d %s", (b ? ", " : ""), (int) node_counts[i],
+ get_node_name((i > last_normal_node ? whatsit_node : i), j));
+ ss = xmalloc((unsigned) (strlen(s) + strlen(msg) + 1));
+ strcpy(ss, s);
+ strcat(ss, msg);
+ free(s);
+ s = ss;
+ b = 1;
+ }
+ }
+#else
+ s = strdup("");
+#endif
+ return s;
+}
+
+halfword list_node_mem_usage(void)
+{
+ halfword q = null;
+#ifdef CHECK_NODE_USAGE
+ halfword p = null;
+ halfword i, j;
+ char *saved_varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
+ memcpy(saved_varmem_sizes, varmem_sizes, (size_t) var_mem_max);
+ for (i = my_prealloc + 1; i < (var_mem_max - 1); i++) {
+ if (saved_varmem_sizes[i] > 0) {
+ j = copy_node(i);
+ if (p == null) {
+ q = j;
+ } else {
+ vlink(p) = j;
+ }
+ p = j;
+ }
+ }
+ free(saved_varmem_sizes);
+#endif
+ return q;
+}
+
+void print_node_mem_stats(void)
+{
+ int i, b;
+ halfword j;
+ char msg[256];
+ char *s;
+ int free_chain_counts[MAX_CHAIN_SIZE] = { 0 };
+ snprintf(msg, 255, " %d words of node memory still in use:", (int) (var_used + my_prealloc));
+ tprint_nl(msg);
+ s = sprint_node_mem_usage();
+ tprint_nl(" ");
+ tprint(s);
+ free(s);
+ tprint(" nodes");
+ tprint_nl(" avail lists: ");
+ b = 0;
+ for (i = 1; i < MAX_CHAIN_SIZE; i++) {
+ for (j = free_chain[i]; j != null; j = vlink(j))
+ free_chain_counts[i]++;
+ if (free_chain_counts[i] > 0) {
+ snprintf(msg, 255, "%s%d:%d", (b ? "," : ""), i, (int) free_chain_counts[i]);
+ tprint(msg);
+ b = 1;
+ }
+ }
+ /*tex A newline, if needed: */
+ print_nlp();
+}
+
+halfword new_span_node(halfword n, int s, scaled w)
+{
+ halfword p = new_node(span_node, 0);
+ span_link(p) = n;
+ span_span(p) = s;
+ width(p) = w;
+ return p;
+}
+
+/* Now comes some attribute stuff. */
+
+static halfword new_attribute_node(unsigned int i, int v)
+{
+ register halfword r = get_node(attribute_node_size);
+ type(r) = attribute_node;
+ attribute_id(r) = (halfword) i;
+ attribute_value(r) = v;
+ /* not used but nicer in print */
+ subtype(r) = 0;
+ return r;
+}
+
+halfword copy_attribute_list(halfword n)
+{
+ halfword q = get_node(attribute_node_size);
+ register halfword p = q;
+ type(p) = attribute_list_node;
+ attr_list_ref(p) = 0;
+ n = vlink(n);
+ while (n != null) {
+ register halfword r = get_node(attribute_node_size);
+ /*tex The link will be fixed automatically in the next loop. */
+ (void) memcpy((void *) (varmem + r), (void *) (varmem + n), (sizeof(memory_word) * attribute_node_size));
+ vlink(p) = r;
+ p = r;
+ n = vlink(n);
+ }
+ return q;
+}
+
+void update_attribute_cache(void)
+{
+ halfword p;
+ register int i;
+ attr_list_cache = get_node(attribute_node_size);
+ type(attr_list_cache) = attribute_list_node;
+ attr_list_ref(attr_list_cache) = 0;
+ p = attr_list_cache;
+ for (i = 0; i <= max_used_attr; i++) {
+ register int v = attribute(i);
+ if (v > UNUSED_ATTRIBUTE) {
+ register halfword r = new_attribute_node((unsigned) i, v);
+ vlink(p) = r;
+ p = r;
+ }
+ }
+ if (vlink(attr_list_cache) == null) {
+ free_node(attr_list_cache, attribute_node_size);
+ attr_list_cache = null;
+ }
+ return;
+}
+
+void build_attribute_list(halfword b)
+{
+ if (max_used_attr >= 0) {
+ if (attr_list_cache == cache_disabled|| attr_list_cache == null) {
+ update_attribute_cache();
+ if (attr_list_cache == null)
+ return;
+ }
+ attr_list_ref(attr_list_cache)++;
+ node_attr(b) = attr_list_cache;
+ }
+}
+
+halfword current_attribute_list(void)
+{
+ if (max_used_attr >= 0) {
+ if (attr_list_cache == cache_disabled) {
+ update_attribute_cache();
+ }
+ return attr_list_cache ;
+ }
+ return null ;
+}
+
+void reassign_attribute(halfword n, halfword new)
+{
+ halfword old;
+ old = node_attr(n);
+ if (new == null) {
+ /*tex There is nothing to assign but we need to check for an old value. */
+ if (old != null) {
+ /*tex This also nulls |attr| field of |n|. */
+ delete_attribute_ref(old);
+ }
+ } else if (old == null) {
+ /*tex Nothing is assigned so we just do that now. */
+ assign_attribute_ref(n,new);
+ } else if (old != new) {
+ /*tex Something is assigned so we need to clean up and assign then. */
+ delete_attribute_ref(old);
+ assign_attribute_ref(n,new);
+ }
+ /*tex The same value so there is no need to assign and change the refcount. */
+ node_attr(n) = new ;
+}
+
+void delete_attribute_ref(halfword b)
+{
+ if (b != null) {
+ if (type(b) == attribute_list_node){
+ attr_list_ref(b)--;
+ if (attr_list_ref(b) == 0) {
+ if (b == attr_list_cache)
+ attr_list_cache = cache_disabled;
+ free_node_chain(b, attribute_node_size);
+ }
+ /*tex Maintain sanity. */
+ if (attr_list_ref(b) < 0) {
+ attr_list_ref(b) = 0;
+ }
+ } else {
+ normal_error("nodes","trying to delete an attribute reference of a non attribute node");
+ }
+ }
+}
+
+void reset_node_properties(halfword b)
+{
+ if (b != null) {
+ lua_properties_reset(b);
+ }
+}
+
+/*tex Here |p| is an attr list head, or zero. */
+
+halfword do_set_attribute(halfword p, int i, int val)
+{
+ register halfword q;
+ register int j = 0;
+ if (p == null) {
+ /*tex Add a new head \& node. */
+ q = get_node(attribute_node_size);
+ type(q) = attribute_list_node;
+ attr_list_ref(q) = 1;
+ p = new_attribute_node((unsigned) i, val);
+ vlink(q) = p;
+ return q;
+ }
+ q = p;
+ if (vlink(p) != null) {
+ while (vlink(p) != null) {
+ int t = attribute_id(vlink(p));
+ if (t == i && attribute_value(vlink(p)) == val) {
+ /*tex There is no need to do anything. */
+ return q;
+ }
+ if (t >= i)
+ break;
+ j++;
+ p = vlink(p);
+ }
+ p = q;
+ while (j-- > 0)
+ p = vlink(p);
+ if (attribute_id(vlink(p)) == i) {
+ attribute_value(vlink(p)) = val;
+ } else {
+ /*tex Add a new node. */
+ halfword r = new_attribute_node((unsigned) i, val);
+ vlink(r) = vlink(p);
+ vlink(p) = r;
+ }
+ return q;
+ } else {
+ normal_error("nodes","trying to set an attribute fails, case 1");
+ return null ;
+ }
+}
+
+void set_attribute(halfword n, int i, int val)
+{
+ register halfword p;
+ register int j = 0;
+ /*tex Not all nodes can have an attribute list. */
+ if (!nodetype_has_attributes(type(n)))
+ return;
+ /*tex If we have no list, we create one and quit. */
+ p = node_attr(n);
+ if (p == null) { /* add a new head \& node */
+ p = get_node(attribute_node_size);
+ type(p) = attribute_list_node;
+ attr_list_ref(p) = 1;
+ node_attr(n) = p;
+ p = new_attribute_node((unsigned) i, val);
+ vlink(node_attr(n)) = p;
+ return;
+ }
+ /*tex We check if we have this attribute already and quit if the value stays the same. */
+ if (vlink(p) != null) {
+ while (vlink(p) != null) {
+ int t = attribute_id(vlink(p));
+ if (t == i && attribute_value(vlink(p)) == val)
+ return;
+ if (t >= i)
+ break;
+ j++;
+ p = vlink(p);
+ }
+ /*tex If found |j| has now the position and we assume a sorted list ! */
+ p = node_attr(n);
+ if (attr_list_ref(p) == 0 ) {
+ /*tex The list is invalid i.e. freed already. */
+ formatted_warning("nodes","node %d has an attribute list that is free already, case 1",(int) n);
+ /*tex The still dangling list gets ref count 1. */
+ attr_list_ref(p) = 1;
+ } else if (attr_list_ref(p) == 1) {
+ /*tex This can really happen! */
+ if (p == attr_list_cache) {
+ /*tex
+
+ We can invalidate the cache setting with |attr_list_cache =
+ cache_disabled| or or save the list, as done below.
+
+ */
+ p = copy_attribute_list(p);
+ node_attr(n) = p;
+ /*tex The copied list gets ref count 1. */
+ attr_list_ref(p) = 1;
+ }
+ } else {
+ /*tex The list is used multiple times so we make a copy. */
+ p = copy_attribute_list(p);
+ /*tex We decrement the ref count or the original. */
+ delete_attribute_ref(node_attr(n));
+ node_attr(n) = p;
+ /*tex The copied list gets ref count 1. */
+ attr_list_ref(p) = 1;
+ }
+ /*tex We go to position |j| in the list. */
+ while (j-- > 0)
+ p = vlink(p);
+ /*tex If we have a hit we just set the value otherwise we add a new node. */
+ if (attribute_id(vlink(p)) == i) {
+ attribute_value(vlink(p)) = val;
+ } else {
+ /*tex Add a new node. */
+ halfword r = new_attribute_node((unsigned) i, val);
+ vlink(r) = vlink(p);
+ vlink(p) = r;
+ }
+ } else {
+ normal_error("nodes","trying to set an attribute fails, case 2");
+ }
+}
+
+int unset_attribute(halfword n, int i, int val)
+{
+ register halfword p;
+ register int t;
+ register int j = 0;
+ if (!nodetype_has_attributes(type(n)))
+ return null;
+ p = node_attr(n);
+ if (p == null)
+ return UNUSED_ATTRIBUTE;
+ if (attr_list_ref(p) == 0) {
+ formatted_warning("nodes","node %d has an attribute list that is free already, case 2", (int) n);
+ return UNUSED_ATTRIBUTE;
+ }
+ if (vlink(p) != null) {
+ while (vlink(p) != null) {
+ t = attribute_id(vlink(p));
+ if (t > i)
+ return UNUSED_ATTRIBUTE;
+ if (t == i) {
+ p = vlink(p);
+ break;
+ }
+ j++;
+ p = vlink(p);
+ }
+ if (attribute_id(p) != i)
+ return UNUSED_ATTRIBUTE;
+ /*tex If we are still here, the attribute exists. */
+ p = node_attr(n);
+ if (attr_list_ref(p) > 1 || p == attr_list_cache) {
+ halfword q = copy_attribute_list(p);
+ if (attr_list_ref(p) > 1) {
+ delete_attribute_ref(node_attr(n));
+ }
+ attr_list_ref(q) = 1;
+ node_attr(n) = q;
+ }
+ p = vlink(node_attr(n));
+ while (j-- > 0)
+ p = vlink(p);
+ t = attribute_value(p);
+ if (val == UNUSED_ATTRIBUTE || t == val) {
+ attribute_value(p) = UNUSED_ATTRIBUTE;
+ }
+ return t;
+ } else {
+ normal_error("nodes","trying to unset an attribute fails");
+ return null;
+ }
+}
+
+int has_attribute(halfword n, int i, int val)
+{
+ register halfword p;
+ if (!nodetype_has_attributes(type(n)))
+ return UNUSED_ATTRIBUTE;
+ p = node_attr(n);
+ if (p == null || vlink(p) == null)
+ return UNUSED_ATTRIBUTE;
+ p = vlink(p);
+ while (p != null) {
+ if (attribute_id(p) == i) {
+ int ret = attribute_value(p);
+ if (val == UNUSED_ATTRIBUTE || val == ret)
+ return ret;
+ return UNUSED_ATTRIBUTE;
+ } else if (attribute_id(p) > i) {
+ return UNUSED_ATTRIBUTE;
+ }
+ p = vlink(p);
+ }
+ return UNUSED_ATTRIBUTE;
+}
+
+void print_short_node_contents(halfword p)
+{
+ switch (type(p)) {
+ case hlist_node:
+ case vlist_node:
+ case ins_node:
+ case whatsit_node:
+ case mark_node:
+ case adjust_node:
+ case unset_node:
+ print_char('[');
+ print_char(']');
+ break;
+ case rule_node:
+ print_char('|');
+ break;
+ case glue_node:
+ if (! glue_is_zero(p))
+ print_char(' ');
+ break;
+ case math_node:
+ print_char('$');
+ break;
+ case disc_node:
+ short_display(vlink(pre_break(p)));
+ short_display(vlink(post_break(p)));
+ break;
+ }
+}
+
+static void show_pdftex_whatsit_rule_spec(int p)
+{
+ tprint("(");
+ print_rule_dimen(height(p));
+ print_char('+');
+ print_rule_dimen(depth(p));
+ tprint(")x");
+ print_rule_dimen(width(p));
+}
+
+/*tex
+
+ Each new type of node that appears in our data structure must be capable of
+ being displayed, copied, destroyed, and so on. The routines that we need for
+ write-oriented whatsits are somewhat like those for mark nodes; other
+ extensions might, of course, involve more subtlety here.
+
+*/
+
+static void print_write_whatsit(const char *s, pointer p)
+{
+ tprint_esc(s);
+ if (write_stream(p) < 16)
+ print_int(write_stream(p));
+ else if (write_stream(p) == 16)
+ print_char('*');
+ else
+ print_char('-');
+}
+
+static void show_node_wrapup_core(int p)
+{
+ switch (subtype(p)) {
+ case open_node:
+ print_write_whatsit("openout", p);
+ print_char('=');
+ print_file_name(open_name(p), open_area(p), open_ext(p));
+ break;
+ case write_node:
+ print_write_whatsit("write", p);
+ print_mark(write_tokens(p));
+ break;
+ case close_node:
+ print_write_whatsit("closeout", p);
+ break;
+ case special_node:
+ tprint_esc("special");
+ print_mark(write_tokens(p));
+ break;
+ case late_lua_node:
+ show_late_lua(p);
+ break;
+ case save_pos_node:
+ tprint_esc("savepos");
+ break;
+ case user_defined_node:
+ tprint_esc("whatsit");
+ print_int(user_node_id(p));
+ print_char('=');
+ switch (user_node_type(p)) {
+ case 'a':
+ tprint("<>");
+ break;
+ case 'n':
+ tprint("[");
+ show_node_list(user_node_value(p));
+ tprint("]");
+ break;
+ case 's':
+ print_char('"');
+ print(user_node_value(p));
+ print_char('"');
+ break;
+ case 't':
+ print_mark(user_node_value(p));
+ break;
+ default: /* only 'd' */
+ print_int(user_node_value(p));
+ break;
+ }
+ break;
+ }
+}
+
+void show_node_wrapup_dvi(int p)
+{
+}
+
+void show_node_wrapup_pdf(int p)
+{
+ switch (subtype(p)) {
+ case pdf_literal_node:
+ show_pdf_literal(p);
+ break;
+ case pdf_colorstack_node:
+ tprint_esc("pdfcolorstack ");
+ print_int(pdf_colorstack_stack(p));
+ switch (pdf_colorstack_cmd(p)) {
+ case colorstack_set:
+ tprint(" set ");
+ break;
+ case colorstack_push:
+ tprint(" push ");
+ break;
+ case colorstack_pop:
+ tprint(" pop");
+ break;
+ case colorstack_current:
+ tprint(" current");
+ break;
+ default:
+ confusion("colorstack");
+ break;
+ }
+ if (pdf_colorstack_cmd(p) <= colorstack_data)
+ print_mark(pdf_colorstack_data(p));
+ break;
+ case pdf_setmatrix_node:
+ tprint_esc("pdfsetmatrix");
+ print_mark(pdf_setmatrix_data(p));
+ break;
+ case pdf_save_node:
+ tprint_esc("pdfsave");
+ break;
+ case pdf_restore_node:
+ tprint_esc("pdfrestore");
+ break;
+ case pdf_refobj_node:
+ tprint_esc("pdfrefobj");
+ if (obj_obj_is_stream(static_pdf, pdf_obj_objnum(p))) {
+ if (obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
+ tprint(" attr");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)));
+ print_char(' ');
+ tprint((const char *) lua_tostring(Luas, -1));
+ lua_pop(Luas, 1);
+ }
+ tprint(" stream");
+ }
+ if (obj_obj_is_file(static_pdf, pdf_obj_objnum(p)))
+ tprint(" file");
+ if (obj_obj_data(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, obj_obj_data(static_pdf, pdf_obj_objnum(p)));
+ print_char(' ');
+ tprint((const char *) lua_tostring(Luas, -1));
+ lua_pop(Luas, 1);
+ }
+ break;
+ case pdf_annot_node:
+ tprint_esc("pdfannot");
+ show_pdftex_whatsit_rule_spec(p);
+ print_mark(pdf_annot_data(p));
+ break;
+ case pdf_start_link_node:
+ tprint_esc("pdfstartlink");
+ show_pdftex_whatsit_rule_spec(p);
+ if (pdf_link_attr(p) != null) {
+ tprint(" attr");
+ print_mark(pdf_link_attr(p));
+ }
+ tprint(" action");
+ if (pdf_action_type(pdf_link_action(p)) == pdf_action_user) {
+ tprint(" user");
+ print_mark(pdf_action_tokens(pdf_link_action(p)));
+ return;
+ }
+ if (pdf_action_file(pdf_link_action(p)) != null) {
+ tprint(" file");
+ print_mark(pdf_action_file(pdf_link_action(p)));
+ }
+ switch (pdf_action_type(pdf_link_action(p))) {
+ case pdf_action_goto:
+ if (pdf_action_named_id(pdf_link_action(p)) > 0) {
+ tprint(" goto name");
+ print_mark(pdf_action_id(pdf_link_action(p)));
+ } else {
+ tprint(" goto num");
+ print_int(pdf_action_id(pdf_link_action(p)));
+ }
+ break;
+ case pdf_action_page:
+ tprint(" page");
+ print_int(pdf_action_id(pdf_link_action(p)));
+ print_mark(pdf_action_tokens(pdf_link_action(p)));
+ break;
+ case pdf_action_thread:
+ if (pdf_action_named_id(pdf_link_action(p)) > 0) {
+ tprint(" thread name");
+ print_mark(pdf_action_id(pdf_link_action(p)));
+ } else {
+ tprint(" thread num");
+ print_int(pdf_action_id(pdf_link_action(p)));
+ }
+ break;
+ default:
+ normal_error("pdf backend", "unknown action type for link");
+ break;
+ }
+ break;
+ case pdf_end_link_node:
+ tprint_esc("pdfendlink");
+ break;
+ case pdf_dest_node:
+ tprint_esc("pdfdest");
+ if (pdf_dest_named_id(p) > 0) {
+ tprint(" name");
+ print_mark(pdf_dest_id(p));
+ } else {
+ tprint(" num");
+ print_int(pdf_dest_id(p));
+ }
+ print_char(' ');
+ switch (pdf_dest_type(p)) {
+ case pdf_dest_xyz:
+ tprint("xyz");
+ if (pdf_dest_xyz_zoom(p) != null) {
+ tprint(" zoom");
+ print_int(pdf_dest_xyz_zoom(p));
+ }
+ break;
+ case pdf_dest_fitbh:
+ tprint("fitbh");
+ break;
+ case pdf_dest_fitbv:
+ tprint("fitbv");
+ break;
+ case pdf_dest_fitb:
+ tprint("fitb");
+ break;
+ case pdf_dest_fith:
+ tprint("fith");
+ break;
+ case pdf_dest_fitv:
+ tprint("fitv");
+ break;
+ case pdf_dest_fitr:
+ tprint("fitr");
+ show_pdftex_whatsit_rule_spec(p);
+ break;
+ case pdf_dest_fit:
+ tprint("fit");
+ break;
+ default:
+ tprint("unknown!");
+ break;
+ }
+ break;
+ case pdf_thread_node:
+ case pdf_start_thread_node:
+ if (subtype(p) == pdf_thread_node)
+ tprint_esc("pdfthread");
+ else
+ tprint_esc("pdfstartthread");
+ tprint("(");
+ print_rule_dimen(height(p));
+ print_char('+');
+ print_rule_dimen(depth(p));
+ tprint(")x");
+ print_rule_dimen(width(p));
+ if (pdf_thread_attr(p) != null) {
+ tprint(" attr");
+ print_mark(pdf_thread_attr(p));
+ }
+ if (pdf_thread_named_id(p) > 0) {
+ tprint(" name");
+ print_mark(pdf_thread_id(p));
+ } else {
+ tprint(" num");
+ print_int(pdf_thread_id(p));
+ }
+ break;
+ case pdf_end_thread_node:
+ tprint_esc("pdfendthread");
+ break;
+ default:
+ break;
+ }
+}
+
+/*tex
+
+ Now we are ready for |show_node_list| itself. This procedure has been written
+ to be ``extra robust'' in the sense that it should not crash or get into a
+ loop even if the data structures have been messed up by bugs in the rest of
+ the program. You can safely call its parent routine |show_box(p)| for
+ arbitrary values of |p| when you are debugging \TeX. However, in the presence
+ of bad data, the procedure may fetch a |memory_word| whose variant is
+ different from the way it was stored; for example, it might try to read
+ |mem[p].hh| when |mem[p]| contains a scaled integer, if |p| is a pointer that
+ has been clobbered or chosen at random.
+
+*/
+
+#define node_list_display(A) do { \
+ append_char('.'); \
+ show_node_list(A); \
+ flush_char(); \
+} while (0)
+
+#define node_list_display_x(A,B) do { \
+ if ((B) != null) { \
+ append_char('.'); \
+ append_char(A); \
+ append_char(' '); \
+ show_node_list(B); \
+ flush_char(); \
+ flush_char(); \
+ flush_char(); \
+ } \
+} while (0)
+
+/*tex Print a node list symbolically: */
+
+void show_node_list(int p)
+{
+ /*tex The number of items already printed at this level: */
+ int n = 0;
+ halfword w;
+ /*tex A glue ratio, as a floating point number: */
+ real g;
+ if ((int) cur_length > depth_threshold) {
+ if (p > null) {
+ /*tex Indicate that there's been some truncation. */
+ tprint(" []");
+ }
+ return;
+ }
+ while (p != null) {
+ print_ln();
+ print_current_string();
+ /*tex Display the nesting history. */
+ if (tracing_online_par < -2)
+ print_int(p);
+ incr(n);
+ if (n > breadth_max) {
+ /*tex Time to stop. */
+ tprint("etc.");
+ return;
+ }
+ /*tex Display node |p|. */
+ if (is_char_node(p)) {
+ print_font_and_char(p);
+ if (is_ligature(p)) {
+ /*tex Display ligature |p|. */
+ tprint(" (ligature ");
+ if (is_leftboundary(p))
+ print_char('|');
+ font_in_short_display = font(p);
+ short_display(lig_ptr(p));
+ if (is_rightboundary(p))
+ print_char('|');
+ print_char(')');
+ }
+ } else {
+ switch (type(p)) {
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ /*tex Display box |p|. */
+ if (type(p) == hlist_node)
+ tprint_esc("h");
+ else if (type(p) == vlist_node)
+ tprint_esc("v");
+ else
+ tprint_esc("unset");
+ tprint("box(");
+ print_scaled(height(p));
+ print_char('+');
+ print_scaled(depth(p));
+ tprint(")x");
+ print_scaled(width(p));
+ if (type(p) == unset_node) {
+ /*tex Display special fields of the unset node |p|. */
+ if (span_count(p) != min_quarterword) {
+ tprint(" (");
+ print_int(span_count(p) + 1);
+ tprint(" columns)");
+ }
+ if (glue_stretch(p) != 0) {
+ tprint(", stretch ");
+ print_glue(glue_stretch(p), glue_order(p), NULL);
+ }
+ if (glue_shrink(p) != 0) {
+ tprint(", shrink ");
+ print_glue(glue_shrink(p), glue_sign(p), NULL);
+ }
+ } else {
+ /*tex
+
+ Display the value of |glue_set(p)|. The code will
+ have to change in this place if |glue_ratio| is a
+ structured type instead of an ordinary |real|. Note
+ that this routine should avoid arithmetic errors even
+ if the |glue_set| field holds an arbitrary random
+ value. The following code assumes that a properly
+ formed nonzero |real| number has absolute value
+ $2^{20}$ or more when it is regarded as an integer;
+ this precaution was adequate to prevent floating
+ point underflow on the author's computer.
+
+ */
+ g = (real) (glue_set(p));
+ if ((g != 0.0) && (glue_sign(p) != normal)) {
+ tprint(", glue set ");
+ if (glue_sign(p) == shrinking)
+ tprint("- ");
+ if (g > 20000.0 || g < -20000.0) {
+ if (g > 0.0)
+ print_char('>');
+ else
+ tprint("< -");
+ print_glue(20000 * unity, glue_order(p), NULL);
+ } else {
+ print_glue(round(unity * g), glue_order(p), NULL);
+ }
+ }
+ if (shift_amount(p) != 0) {
+ tprint(", shifted ");
+ print_scaled(shift_amount(p));
+ }
+ tprint(", direction ");
+ print_dir_par(box_dir(p));
+ }
+ /*tex Recursive call: */
+ node_list_display(list_ptr(p));
+ break;
+ case rule_node:
+ /*tex Display rule |p|. */
+ if (subtype(p) == normal_rule) {
+ tprint_esc("rule(");
+ } else if (subtype(p) == empty_rule) {
+ tprint_esc("norule(");
+ } else if (subtype(p) == user_rule) {
+ tprint_esc("userrule(");
+ } else if (subtype(p) == box_rule) {
+ tprint_esc("box(");
+ } else if (subtype(p) == image_rule) {
+ tprint_esc("image(");
+ }
+ print_rule_dimen(height(p));
+ print_char('+');
+ print_rule_dimen(depth(p));
+ tprint(")x");
+ print_rule_dimen(width(p));
+ break;
+ case ins_node:
+ /*tex Display insertion |p|. */
+ tprint_esc("insert");
+ print_int(subtype(p));
+ tprint(", natural size ");
+ print_scaled(height(p));
+ tprint("; split(");
+ print_spec(split_top_ptr(p), NULL);
+ print_char(',');
+ print_scaled(depth(p));
+ tprint("); float cost ");
+ print_int(float_cost(p));
+ /*tex Recursive call. */
+ node_list_display(ins_ptr(p));
+ break;
+ case dir_node:
+ if (subtype(p) == cancel_dir) {
+ tprint_esc("enddir");
+ } else {
+ tprint_esc("begindir");
+ }
+ print_char(' ');
+ print_dir_par(dir_dir(p));
+ break;
+ case local_par_node:
+ tprint_esc("localpar");
+ append_char('.');
+ print_ln();
+ print_current_string();
+ tprint_esc("localinterlinepenalty");
+ print_char('=');
+ print_int(local_pen_inter(p));
+ print_ln();
+ print_current_string();
+ tprint_esc("localbrokenpenalty");
+ print_char('=');
+ print_int(local_pen_broken(p));
+ print_ln();
+ print_current_string();
+ tprint_esc("localleftbox");
+ if (local_box_left(p) == null) {
+ tprint("=null");
+ } else {
+ append_char('.');
+ show_node_list(local_box_left(p));
+ decr(cur_length);
+ }
+ print_ln();
+ print_current_string();
+ tprint_esc("localrightbox");
+ if (local_box_right(p) == null) {
+ tprint("=null");
+ } else {
+ append_char('.');
+ show_node_list(local_box_right(p));
+ decr(cur_length);
+ }
+ decr(cur_length);
+ break;
+ case boundary_node:
+ if (subtype(p)==0) {
+ tprint_esc("noboundary");
+ } else {
+ switch (subtype(p)) {
+ case 1:
+ tprint_esc("boundary");
+ break;
+ case 2:
+ tprint_esc("protrusionboundary");
+ break;
+ case 3:
+ tprint_esc("wordboundary");
+ break;
+ default:
+ tprint_esc("boundary");
+ print_char(':');
+ print_int(subtype(p));
+ break;
+ }
+ print_char('=');
+ print_int(boundary_value(p));
+ }
+ break;
+ case whatsit_node:
+ w = subtype(p) ;
+ if (w >= backend_first_pdf_whatsit) {
+ show_node_wrapup_pdf(p);
+ } else if (w >= backend_first_dvi_whatsit) {
+ show_node_wrapup_dvi(p);
+ } else {
+ show_node_wrapup_core(p);
+ }
+ break;
+ case glue_node:
+ /*tex Display glue |p|. */
+ if (subtype(p) >= a_leaders) {
+ /*tex Display leaders |p|. */
+ tprint_esc("");
+ switch (subtype(p)) {
+ case a_leaders:
+ break;
+ case c_leaders:
+ print_char('c');
+ break;
+ case x_leaders:
+ print_char('x');
+ break;
+ case g_leaders:
+ print_char('g');
+ break;
+ default:
+ normal_warning("nodes","weird glue leader subtype ignored");
+ }
+ tprint("leaders ");
+ print_spec(p, NULL);
+ /*tex Recursive call: */
+ node_list_display(leader_ptr(p));
+ } else {
+ tprint_esc("glue");
+ if (subtype(p) != normal) {
+ print_char('(');
+ if ((subtype(p) - 1) < thin_mu_skip_code) {
+ print_cmd_chr(assign_glue_cmd, glue_base + (subtype(p) - 1));
+ } else if (subtype(p) < cond_math_glue) {
+ print_cmd_chr(assign_mu_glue_cmd, glue_base + (subtype(p) - 1));
+ } else if (subtype(p) == cond_math_glue) {
+ tprint_esc("nonscript");
+ } else {
+ tprint_esc("mskip");
+ }
+ print_char(')');
+ }
+ if (subtype(p) != cond_math_glue) {
+ print_char(' ');
+ if (subtype(p) < cond_math_glue)
+ print_spec(p, NULL);
+ else
+ print_spec(p, "mu");
+ }
+ }
+ break;
+ case margin_kern_node:
+ tprint_esc("kern");
+ print_scaled(width(p));
+ if (subtype(p) == left_side)
+ tprint(" (left margin)");
+ else
+ tprint(" (right margin)");
+ break;
+ case kern_node:
+ /*tex Display kern |p| */
+ if (subtype(p) != mu_glue) {
+ tprint_esc("kern");
+ /*tex
+
+ \starttyping
+ if (subtype(p) != normal) {
+ print_char(' ');
+ }
+ \stoptyping
+
+ */
+ print_scaled(width(p));
+ if (subtype(p) == font_kern)
+ tprint(" (font)");
+ else if (subtype(p) == italic_kern)
+ tprint(" (italic)");
+ else if (subtype(p) == accent_kern)
+ tprint(" (accent)");
+ } else {
+ tprint_esc("mkern");
+ print_scaled(width(p));
+ tprint("mu");
+ }
+ break;
+ case math_node:
+ /*tex Display math node |p|. */
+ tprint_esc("math");
+ if (subtype(p) == before)
+ tprint("on");
+ else
+ tprint("off");
+ if (!glue_is_zero(p)) {
+ tprint(", glued ");
+ print_spec(p, NULL);
+ } else if (surround(p) != 0) {
+ tprint(", surrounded ");
+ print_scaled(surround(p));
+ }
+ break;
+ case penalty_node:
+ /*tex Display penalty |p|. */
+ tprint_esc("penalty ");
+ print_int(penalty(p));
+ break;
+ case disc_node:
+ /*tex
+
+ Display discretionary |p|. The |post_break| list of a
+ discretionary node is indicated by a prefixed
+ `\.{\char'174}' instead of the `\..' before the
+ |pre_break| list.
+
+ We're not compatible anyway so ...
+
+ \starttyping
+ tprint_esc("discretionary");
+ print_int(disc_penalty(p));
+ print_char('|');
+ if (vlink(no_break(p)) != null) {
+ tprint(" replacing ");
+ node_list_display(vlink(no_break(p)));
+ }
+ node_list_display(vlink(pre_break(p)));
+ append_char('|');
+ show_node_list(vlink(post_break(p)));
+ flush_char();
+ \stoptyping
+
+ has become:
+
+ */
+ tprint_esc("discretionary");
+ tprint(" (penalty ");
+ print_int(disc_penalty(p));
+ print_char(')');
+ node_list_display_x('<',vlink(pre_break(p)));
+ node_list_display_x('>',vlink(post_break(p)));
+ node_list_display_x('=',vlink(no_break(p)));
+ break;
+ case mark_node:
+ /*tex Display mark |p|. */
+ tprint_esc("mark");
+ if (mark_class(p) != 0) {
+ print_char('s');
+ print_int(mark_class(p));
+ }
+ print_mark(mark_ptr(p));
+ break;
+ case adjust_node:
+ /*tex Display adjustment |p|. */
+ tprint_esc("vadjust");
+ if (subtype(p) != 0)
+ tprint(" pre ");
+ /*tex Recursive call. */
+ node_list_display(adjust_ptr(p));
+ break;
+ case glue_spec_node:
+ tprint("<glue_spec ");
+ print_spec(p, NULL);
+ tprint(">");
+ break;
+ default:
+ show_math_node(p);
+ break;
+ }
+ }
+ p = vlink(p);
+ }
+}
+
+/*tex
+
+ This routine finds the 'base' width of a horizontal box, using the same logic
+ that \TeX82 used for \.{\\predisplaywidth}.
+
+*/
+
+static pointer get_actual_box_width(pointer r,pointer p, scaled initial_width)
+{
+ /*tex increment to |v| */
+ scaled d;
+ /*tex calculated |size| */
+ scaled w = -max_dimen;
+ /*tex |w| plus possible glue amount */
+ scaled v = initial_width;
+ while (p != null) {
+ if (is_char_node(p)) {
+ d = glyph_width(p);
+ goto FOUND;
+ }
+ switch (type(p)) {
+ case hlist_node:
+ case vlist_node:
+ case rule_node:
+ d = width(p);
+ goto FOUND;
+ break;
+ case margin_kern_node:
+ d = width(p);
+ break;
+ case kern_node:
+ d = width(p);
+ break;
+ case disc_node:
+ /*tex At the end of the line we should actually take the |pre|. */
+ if (no_break(p) != null) {
+ d = get_actual_box_width(r,vlink_no_break(p),0);
+ if (d <= -max_dimen || d >= max_dimen) {
+ d = 0;
+ }
+ } else {
+ d = 0;
+ }
+ goto FOUND;
+ break;
+ case math_node:
+ /*tex Begin mathskip code. */
+ if (glue_is_zero(p)) {
+ d = surround(p);
+ break;
+ } else {
+ /*tex Fall through. */
+ }
+ /*tex End mathskip code. */
+ case glue_node:
+ /*tex
+
+ We need to be careful that |w|, |v|, and |d| do not depend on
+ any |glue_set| values, since such values are subject to
+ system-dependent rounding. System-dependent numbers are not
+ allowed to infiltrate parameters like |pre_display_size|,
+ since \TeX82 is supposed to make the same decisions on all
+ machines.
+
+ */
+ d = width(p);
+ if (glue_sign(r) == stretching) {
+ if ((glue_order(r) == stretch_order(p)) && (stretch(p) != 0))
+ v = max_dimen;
+ } else if (glue_sign(r) == shrinking) {
+ if ((glue_order(r) == shrink_order(p)) && (shrink(p) != 0))
+ v = max_dimen;
+ }
+ if (subtype(p) >= a_leaders)
+ goto FOUND;
+ break;
+ default:
+ d = 0;
+ break;
+ }
+ if (v < max_dimen)
+ v = v + d;
+ goto NOT_FOUND;
+ FOUND:
+ if (v < max_dimen) {
+ v = v + d;
+ w = v;
+ } else {
+ w = max_dimen;
+ break;
+ }
+ NOT_FOUND:
+ p = vlink(p);
+ }
+ return w;
+}
+
+pointer actual_box_width(pointer r, scaled base_width)
+{
+ /*tex
+
+ Often this is the same as:
+
+ \starttyping
+ return + shift_amount(r) + base_width +
+ natural_sizes(list_ptr(r),null,(glue_ratio) glue_set(r),glue_sign(r),glue_order(r),box_dir(r));
+ \stoptyping
+ */
+ return get_actual_box_width(r,list_ptr(r),shift_amount(r) + base_width);
+}
+
+halfword tail_of_list(halfword p)
+{
+ halfword q = p;
+ while (vlink(q) != null)
+ q = vlink(q);
+ return q;
+}
+
+int var_used;
+
+/*tex
+
+ Attribute lists need two extra globals to increase processing efficiency.
+ |max_used_attr| limits the test loop that checks for set attributes, and
+ |attr_list_cache| contains a pointer to an already created attribute list. It
+ is set to the special value |cache_disabled| when the current value can no
+ longer be trusted: after an assignment to an attribute register, and after a
+ group has ended.
+
+*/
+
+/*tex The maximum assigned attribute id: */
+
+int max_used_attr;
+halfword attr_list_cache;
+
+/*tex
+
+ From the computer's standpoint, \TeX's chief mission is to create horizontal
+ and vertical lists. We shall now investigate how the elements of these lists
+ are represented internally as nodes in the dynamic memory.
+
+ A horizontal or vertical list is linked together by |link| fields in the
+ first word of each node. Individual nodes represent boxes, glue, penalties,
+ or special things like discretionary hyphens; because of this variety, some
+ nodes are longer than others, and we must distinguish different kinds of
+ nodes. We do this by putting a `|type|' field in the first word, together
+ with the link and an optional `|subtype|'.
+
+ Character nodes appear only in horizontal lists, never in vertical lists.
+
+ An |hlist_node| stands for a box that was made from a horizontal list. Each
+ |hlist_node| is seven words long, and contains the following fields (in
+ addition to the mandatory |type| and |link|, which we shall not mention
+ explicitly when discussing the other node types): The |height| and |width|
+ and |depth| are scaled integers denoting the dimensions of the box. There is
+ also a |shift_amount| field, a scaled integer indicating how much this box
+ should be lowered (if it appears in a horizontal list), or how much it should
+ be moved to the right (if it appears in a vertical list). There is a
+ |list_ptr| field, which points to the beginning of the list from which this
+ box was fabricated; if |list_ptr| is |null|, the box is empty. Finally, there
+ are three fields that represent the setting of the glue: |glue_set(p)| is a
+ word of type |glue_ratio| that represents the proportionality constant for
+ glue setting; |glue_sign(p)| is |stretching| or |shrinking| or |normal|
+ depending on whether or not the glue should stretch or shrink or remain
+ rigid; and |glue_order(p)| specifies the order of infinity to which glue
+ setting applies (|normal|, |sfi|, |fil|, |fill|, or |filll|). The |subtype|
+ field is not used.
+
+ The |new_null_box| function returns a pointer to an |hlist_node| in which all
+ subfields have the values corresponding to `\.{\\hbox\{\}}'. The |subtype|
+ field is set to |min_quarterword|, since that's the desired |span_count|
+ value if this |hlist_node| is changed to an |unset_node|.
+
+*/
+
+/*tex Create a new box node. */
+
+halfword new_null_box(void)
+{
+ halfword p = new_node(hlist_node, min_quarterword);
+ box_dir(p) = text_direction_par;
+ return p;
+}
+
+/*tex
+
+ A |vlist_node| is like an |hlist_node| in all respects except that it
+ contains a vertical list.
+
+ A |rule_node| stands for a solid black rectangle; it has |width|, |depth|,
+ and |height| fields just as in an |hlist_node|. However, if any of these
+ dimensions is $-2^{30}$, the actual value will be determined by running the
+ rule up to the boundary of the innermost enclosing box. This is called a
+ ``running dimension.'' The |width| is never running in an hlist; the |height|
+ and |depth| are never running in a~vlist.
+
+ A new rule node is delivered by the |new_rule| function. It makes all the
+ dimensions ``running,'' so you have to change the ones that are not allowed
+ to run.
+
+*/
+
+halfword new_rule(int s)
+{
+ halfword p = new_node(rule_node,s);
+ return p;
+}
+
+/*tex
+
+ Insertions are represented by |ins_node| records, where the |subtype|
+ indicates the corresponding box number. For example, `\.{\\insert 250}' leads
+ to an |ins_node| whose |subtype| is |250+min_quarterword|. The |height| field
+ of an |ins_node| is slightly misnamed; it actually holds the natural height
+ plus depth of the vertical list being inserted. The |depth| field holds the
+ |split_max_depth| to be used in case this insertion is split, and the
+ |split_top_ptr| points to the corresponding |split_top_skip|. The
+ |float_cost| field holds the |floating_penalty| that will be used if this
+ insertion floats to a subsequent page after a split insertion of the same
+ class. There is one more field, the |ins_ptr|, which points to the beginning
+ of the vlist for the insertion.
+
+ A |mark_node| has a |mark_ptr| field that points to the reference count of a
+ token list that contains the user's \.{\\mark} text. In addition there is a
+ |mark_class| field that contains the mark class.
+
+ An |adjust_node|, which occurs only in horizontal lists, specifies material
+ that will be moved out into the surrounding vertical list; i.e., it is used
+ to implement \TeX's `\.{\\vadjust}' operation. The |adjust_ptr| field points
+ to the vlist containing this material.
+
+ A |glyph_node|, which occurs only in horizontal lists, specifies a glyph in a
+ particular font, along with its attribute list. Older versions of \TeX\ could
+ use token memory for characters, because the font,char combination would fit
+ in a single word (both values were required to be strictly less than
+ $2^{16}$). In LuaTeX, room is needed for characters that are larger than
+ that, as well as a pointer to a potential attribute list, and the two
+ displacement values.
+
+ In turn, that made the node so large that it made sense to merge ligature
+ glyphs as well, as that requires only one extra pointer. A few extra classes
+ of glyph nodes will be introduced later. The unification of all those types
+ makes it easier to manipulate lists of glyphs. The subtype differentiates
+ various glyph kinds.
+
+ First, here is a function that returns a pointer to a glyph node for a given
+ glyph in a given font. If that glyph doesn't exist, |null| is returned
+ instead. Nodes of this subtype are directly created only for accents and
+ their base (through |make_accent|), and math nucleus items (in the conversion
+ from |mlist| to |hlist|).
+
+*/
+
+halfword new_glyph(int f, int c)
+{
+ halfword p = null;
+ if ((f == 0) || (char_exists(f, c))) {
+ p = new_glyph_node();
+ set_to_glyph(p);
+ font(p) = f;
+ character(p) = c;
+ }
+ return p;
+}
+
+/*tex
+
+ A subset of the glyphs nodes represent ligatures: characters fabricated from
+ the interaction of two or more actual characters. The characters that
+ generated the ligature have not been forgotten, since they are needed for
+ diagnostic messages; the |lig_ptr| field points to a linked list of character
+ nodes for all original characters that have been deleted. (This list might be
+ empty if the characters that generated the ligature were retained in other
+ nodes.)
+
+ The |subtype| field of these |glyph_node|s is 1, plus 2 and/or 1 if the
+ original source of the ligature included implicit left and/or right
+ boundaries. These nodes are created by the C function |new_ligkern|.
+
+ A third general type of glyphs could be called a character, as it only
+ appears in lists that are not yet processed by the ligaturing and kerning
+ steps of the program.
+
+ |main_control| inserts these, and they are later converted to
+ |subtype_normal| by |new_ligkern|.
+
+*/
+
+quarterword norm_min(int h)
+{
+ if (h <= 0)
+ return 1;
+ else if (h >= 255)
+ return 255;
+ else
+ return (quarterword) h;
+}
+
+halfword new_char(int f, int c)
+{
+ halfword p;
+ p = new_glyph_node();
+ set_to_character(p);
+ font(p) = f;
+ character(p) = c;
+ lang_data(p) = make_lang_data(uc_hyph_par, cur_lang_par, left_hyphen_min_par, right_hyphen_min_par);
+ return p;
+}
+
+/*tex
+
+ Left and right ghost glyph nodes are the result of \.{\\leftghost} and
+ \.{\\rightghost}, respectively. They are going to be removed by
+ |new_ligkern|, at the end of which they are no longer needed.
+
+ Here are a few handy helpers used by the list output routines.
+
+*/
+
+scaled glyph_width(halfword p)
+{
+ scaled w = char_width(font(p), character(p));
+ return w;
+}
+
+scaled glyph_height(halfword p)
+{
+ scaled w = char_height(font(p), character(p)) + y_displace(p);
+ if (w < 0)
+ w = 0;
+ return w;
+}
+
+scaled glyph_depth(halfword p)
+{
+ scaled w = char_depth(font(p), character(p));
+ if (y_displace(p) > 0)
+ w = w - y_displace(p);
+ if (w < 0)
+ w = 0;
+ return w;
+}
+
+/*tex
+
+ A |disc_node|, which occurs only in horizontal lists, specifies a
+ ``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the
+ text that starts at |pre_break(p)| will precede the break, the text that
+ starts at |post_break(p)| will follow the break, and text that appears in
+ |no_break(p)| nodes will be ignored. For example, an ordinary discretionary
+ hyphen, indicated by `\.{\\-}', yields a |disc_node| with |pre_break|
+ pointing to a |char_node| containing a hyphen, |post_break=null|, and
+ |no_break=null|.
+
+ If |subtype(p)=automatic_disc|, the |ex_hyphen_penalty| will be charged for
+ this break. Otherwise the |hyphen_penalty| will be charged. The texts will
+ actually be substituted into the list by the line-breaking algorithm if it
+ decides to make the break, and the discretionary node will disappear at that
+ time; thus, the output routine sees only discretionaries that were not
+ chosen.
+
+*/
+
+halfword new_disc(void)
+{
+ halfword p = new_node(disc_node, 0);
+ disc_penalty(p) = hyphen_penalty_par;
+ return p;
+}
+
+/*
+
+ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
+ |subtype| field in its first word says what `\\{whatsit}' it is, and
+ implicitly determines the node size (which must be 2 or more) and the format
+ of the remaining words. When a |whatsit_node| is encountered in a list,
+ special actions are invoked; knowledgeable people who are careful not to mess
+ up the rest of \TeX\ are able to make \TeX\ do new things by adding code at
+ the end of the program. For example, there might be a `\TeX nicolor'
+ extension to specify different colors of ink, and the whatsit node might
+ contain the desired parameters.
+
+ The present implementation of \TeX\ treats the features associated with
+ `\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
+ illustrate how such routines might be coded. We shall defer further
+ discussion of extensions until the end of this program.
+
+ A |math_node|, which occurs only in horizontal lists, appears before and
+ after mathematical formulas. The |subtype| field is |before| before the
+ formula and |after| after it. There is a |surround| field, which represents
+ the amount of surrounding space inserted by \.{\\mathsurround}.
+
+*/
+
+halfword new_math(scaled w, int s)
+{
+ halfword p = new_node(math_node, s);
+ surround(p) = w;
+ return p;
+}
+
+/*tex
+
+ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|, |rule_node|,
+ |ins_node|, |mark_node|, |adjust_node|, |disc_node|, |whatsit_node|, and
+ |math_node| are at the low end of the type codes, by permitting a break at
+ glue in a list if and only if the |type| of the previous node is less than
+ |math_node|. Furthermore, a node is discarded after a break if its type is
+ |math_node| or~more.
+
+ A |glue_node| represents glue in a list. However, it is really only a pointer
+ to a separate glue specification, since \TeX\ makes use of the fact that many
+ essentially identical nodes of glue are usually present. If |p| points to a
+ |glue_node|, |glue_ptr(p)| points to another packet of words that specify the
+ stretch and shrink components, etc.
+
+ Glue nodes also serve to represent leaders; the |subtype| is used to
+ distinguish between ordinary glue (which is called |normal|) and the three
+ kinds of leaders (which are called |a_leaders|, |c_leaders|, and
+ |x_leaders|). The |leader_ptr| field points to a rule node or to a box node
+ containing the leaders; it is set to |null| in ordinary glue nodes.
+
+ Many kinds of glue are computed from \TeX's ``skip'' parameters, and it is
+ helpful to know which parameter has led to a particular glue node. Therefore
+ the |subtype| is set to indicate the source of glue, whenever it originated
+ as a parameter. We will be defining symbolic names for the parameter numbers
+ later (e.g., |line_skip_code=0|, |baseline_skip_code=1|, etc.); it suffices
+ for now to say that the |subtype| of parametric glue will be the same as the
+ parameter number, plus~one.
+
+ In math formulas there are two more possibilities for the |subtype| in a glue
+ node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
+ instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
+ feature that cancels the glue node immediately following if it appears in a
+ subscript.
+
+ A glue specification has a halfword reference count in its first word,
+ representing |null| plus the number of glue nodes that point to it (less
+ one). Note that the reference count appears in the same position as the
+ |link| field in list nodes; this is the field that is initialized to |null|
+ when a node is allocated, and it is also the field that is flagged by
+ |empty_flag| in empty nodes.
+
+ Glue specifications also contain three |scaled| fields, for the |width|,
+ |stretch|, and |shrink| dimensions. Finally, there are two one-byte fields
+ called |stretch_order| and |shrink_order|; these contain the orders of
+ infinity (|normal|, |sfi|, |fil|, |fill|, or |filll|) corresponding to the
+ stretch and shrink values.
+
+ Here is a function that returns a pointer to a copy of a glue spec. The
+ reference count in the copy is |null|, because there is assumed to be exactly
+ one reference to the new specification.
+
+*/
+
+halfword new_spec(halfword q)
+{
+ if (q == null) {
+ return copy_node(zero_glue);
+ } else if (type(q) == glue_spec_node) {
+ return copy_node(q);
+ } else if (type(q) == glue_node) {
+ halfword p = copy_node(zero_glue);
+ width(p) = width(q);
+ stretch(p) = stretch(q);
+ shrink(p) = shrink(q);
+ stretch_order(p) = stretch_order(q);
+ shrink_order(p) = shrink_order(q);
+ return p;
+ } else {
+ /*tex Alternatively we can issue a warning. */
+ return copy_node(zero_glue);
+ }
+}
+
+/*tex
+
+ And here's a function that creates a glue node for a given parameter
+ identified by its code number; for example, |new_param_glue(line_skip_code)|
+ returns a pointer to a glue node for the current \.{\\lineskip}.
+
+*/
+
+halfword new_param_glue(int n)
+{
+ halfword p = new_node(glue_node, n + 1);
+ halfword q = glue_par(n);
+ width(p) = width(q);
+ stretch(p) = stretch(q);
+ shrink(p) = shrink(q);
+ stretch_order(p) = stretch_order(q);
+ shrink_order(p) = shrink_order(q);
+ return p;
+}
+
+/*tex
+
+ Glue nodes that are more or less anonymous are created by |new_glue|, whose
+ argument points to a glue specification.
+
+*/
+
+halfword new_glue(halfword q)
+{
+ halfword p = new_node(glue_node, normal);
+ width(p) = width(q);
+ stretch(p) = stretch(q);
+ shrink(p) = shrink(q);
+ stretch_order(p) = stretch_order(q);
+ shrink_order(p) = shrink_order(q);
+ return p;
+}
+
+/*tex
+
+ Still another subroutine is needed: This one is sort of a combination of
+ |new_param_glue| and |new_glue|. It creates a glue node for one of the
+ current glue parameters, but it makes a fresh copy of the glue specification,
+ since that specification will probably be subject to change, while the
+ parameter will stay put.
+
+ The global variable |temp_ptr| is set to the address of the new spec.
+
+*/
+
+halfword new_skip_param(int n)
+{
+ halfword p = new_node(glue_node, n + 1);
+ halfword q = glue_par(n);
+ width(p) = width(q);
+ stretch(p) = stretch(q);
+ shrink(p) = shrink(q);
+ stretch_order(p) = stretch_order(q);
+ shrink_order(p) = shrink_order(q);
+ return p;
+}
+
+/*tex
+
+ A |kern_node| has a |width| field to specify a (normally negative) amount of
+ spacing. This spacing correction appears in horizontal lists between letters
+ like A and V when the font designer said that it looks better to move them
+ closer together or further apart. A kern node can also appear in a vertical
+ list, when its `|width|' denotes additional spacing in the vertical
+ direction. The |subtype| is either |normal| (for kerns inserted from font
+ information or math mode calculations) or |explicit| (for kerns inserted from
+ \.{\\kern} and \.{\\/} commands) or |acc_kern| (for kerns inserted from
+ non-math accents) or |mu_glue| (for kerns inserted from \.{\\mkern}
+ specifications in math formulas).
+
+ The |new_kern| function creates a kern node having a given width.
+
+*/
+
+halfword new_kern(scaled w)
+{
+ halfword p = new_node(kern_node, normal);
+ width(p) = w;
+ return p;
+}
+
+/*tex
+
+ A |penalty_node| specifies the penalty associated with line or page breaking,
+ in its |penalty| field. This field is a fullword integer, but the full range
+ of integer values is not used: Any penalty |>=10000| is treated as infinity,
+ and no break will be allowed for such high values. Similarly, any penalty
+ |<=-10000| is treated as negative infinity, and a break will be forced.
+
+ Anyone who has been reading the last few sections of the program will be able
+ to guess what comes next.
+
+*/
+
+halfword new_penalty(int m, int s)
+{
+ halfword p = new_node(penalty_node, 0);
+ penalty(p) = m;
+ subtype(p) = s;
+ return p;
+}
+
+/*tex
+
+ You might think that we have introduced enough node types by now. Well,
+ almost, but there is one more: An |unset_node| has nearly the same format as
+ an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign} or
+ \.{\\valign} that are not yet in their final form, since the box dimensions
+ are their ``natural'' sizes before any glue adjustment has been made. The
+ |glue_set| word is not present; instead, we have a |glue_stretch| field,
+ which contains the total stretch of order |glue_order| that is present in the
+ hlist or vlist being boxed. Similarly, the |shift_amount| field is replaced
+ by a |glue_shrink| field, containing the total shrink of order |glue_sign|
+ that is present. The |subtype| field is called |span_count|; an unset box
+ typically contains the data for |qo(span_count)+1| columns. Unset nodes will
+ be changed to box nodes when alignment is completed.
+
+ In fact, there are still more types coming. When we get to math formula
+ processing we will see that a |style_node| has |type=14|; and a number of
+ larger type codes will also be defined, for use in math mode only.
+
+ Warning: If any changes are made to these data structure layouts, such as
+ changing any of the node sizes or even reordering the words of nodes, the
+ |copy_node_list| procedure and the memory initialization code below may have
+ to be changed. Such potentially dangerous parts of the program are listed in
+ the index under `data structure assumptions'. However, other references to
+ the nodes are made symbolically in terms of the \.{WEB} macro definitions
+ above, so that format changes will leave \TeX's other algorithms intact.
+
+*/
+
+halfword make_local_par_node(int mode)
+{
+ int callback_id;
+ halfword q;
+ halfword p = new_node(local_par_node,0);
+ local_pen_inter(p) = local_inter_line_penalty_par;
+ local_pen_broken(p) = local_broken_penalty_par;
+ if (local_left_box_par != null) {
+ q = copy_node_list(local_left_box_par);
+ local_box_left(p) = q;
+ local_box_left_width(p) = width(local_left_box_par);
+ }
+ if (local_right_box_par != null) {
+ q = copy_node_list(local_right_box_par);
+ local_box_right(p) = q;
+ local_box_right_width(p) = width(local_right_box_par);
+ }
+ local_par_dir(p) = par_direction_par;
+ /*tex Callback with node passed: */
+ callback_id = callback_defined(insert_local_par_callback);
+ if (callback_id > 0) {
+ /*tex Todo: use general mechanism/wrapper. */
+ int sfix = lua_gettop(Luas);
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, sfix);
+ } else {
+ int i;
+ nodelist_to_lua(Luas, p);
+ lua_push_local_par_mode(Luas,mode)
+ /*tex 2 arg, 0 result */
+ i = lua_pcall(Luas, 2, 0, 0);
+ if (i != 0) {
+ lua_gc(Luas, LUA_GCCOLLECT, 0);
+ Luas = luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ }
+ lua_settop(Luas, sfix);
+ }
+ }
+ return p;
+}
diff --git a/Build/source/texk/web2c/luatexdir/tex/texnodes.w b/Build/source/texk/web2c/luatexdir/tex/texnodes.w
deleted file mode 100644
index 0c8bdb83726..00000000000
--- a/Build/source/texk/web2c/luatexdir/tex/texnodes.w
+++ /dev/null
@@ -1,3910 +0,0 @@
-% texnodes.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"
-
-/* we can consider less mode sizes: 2 4 6 8 */
-
-@
-This module started out using NDEBUG to trigger checking invalid node usage,
-something that is needed because users can mess up nodes in Lua. At some point
-that code was always enabled so it is now always on but still can be recognized
-as additional code. And as the performance hit is close to zero so disabling
-makes no sense, not even to make it configureable. There is a little more memory
-used but that is neglectable compared to other memory usage.
-
-@c
-#define MAX_CHAIN_SIZE 13 /* why not a bit larger */
-#define CHECK_NODE_USAGE 1 /* this triggers checking */
-
-memory_word *volatile varmem = NULL;
-
-#ifdef CHECK_NODE_USAGE
- char *varmem_sizes = NULL;
-#endif
-
-halfword var_mem_max = 0;
-halfword rover = 0;
-
-halfword free_chain[MAX_CHAIN_SIZE] = { null };
-
-static int my_prealloc = 0;
-
-int fix_node_lists = 1; /* used in font and lang */
-
-halfword slow_get_node(int s); /* defined below */
-
-#define fake_node 100
-#define fake_node_size 2
-#define fake_node_name "fake"
-
-#define variable_node_size 2
-
-/* core nodes */
-
-const char *node_fields_list[] = {
- "attr", "width", "depth", "height", "dir", "shift", "glue_order", "glue_sign",
- "glue_set", "head", NULL
-};
-const char *node_fields_rule[] = {
- "attr", "width", "depth", "height", "dir", "index", NULL
-};
-const char *node_fields_insert[] = {
- "attr", "cost", "depth", "height", "spec", "head", NULL
-};
-const char *node_fields_mark[] = {
- "attr", "class", "mark", NULL
-};
-const char *node_fields_adjust[] = {
- "attr", "head", NULL
-};
-const char *node_fields_disc[] = {
- "attr", "pre", "post", "replace", "penalty", NULL
-};
-const char *node_fields_math[] = {
- "attr", "surround", "width", "stretch", "shrink", "stretch_order", "shrink_order", NULL
-};
-const char *node_fields_glue[] = {
- "attr", "leader", "width", "stretch", "shrink", "stretch_order", "shrink_order", NULL
-};
-const char *node_fields_kern[] = {
- "attr", "kern", "expansion_factor", NULL
-};
-const char *node_fields_penalty[] = {
- "attr", "penalty", NULL
-};
-const char *node_fields_unset[] = {
- "attr", "width", "depth", "height", "dir", "shrink", "glue_order",
- "glue_sign", "stretch", "span", "head", NULL
-};
-const char *node_fields_margin_kern[] = {
- "attr", "width", "glyph", NULL
-};
-const char *node_fields_glyph[] = {
- "attr", "char", "font", "lang", "left", "right", "uchyph", "components",
- "xoffset", "yoffset", "width", "height", "depth", "expansion_factor", NULL
-};
-const char *node_fields_inserting[] = {
- "height", "last_ins_ptr", "best_ins_ptr",
- "width", "stretch", "shrink", "stretch_order", "shrink_order", NULL
-};
-const char *node_fields_splitup[] = {
- "height", "last_ins_ptr", "best_ins_ptr", "broken_ptr", "broken_ins", NULL
-};
-const char *node_fields_attribute[] = {
- "number", "value", NULL
-};
-const char *node_fields_glue_spec[] = {
- "width", "stretch", "shrink", "stretch_order", "shrink_order", NULL
-};
-const char *node_fields_attribute_list[] = {
- NULL
-};
-const char *node_fields_local_par[] = {
- "attr", "pen_inter", "pen_broken", "dir", "box_left", "box_left_width",
- "box_right", "box_right_width", NULL
-};
-const char *node_fields_dir[] = {
- "attr", "dir", "level", NULL
-};
-const char *node_fields_boundary[] = {
- "attr", "value", NULL
-};
-
-/* math nodes */
-
-const char *node_fields_noad[] = {
- "attr", "nucleus", "sub", "sup", NULL
-};
-
-const char *node_fields_style[] = {
- "attr", "style", NULL
-};
-const char *node_fields_choice[] = {
- "attr", "display", "text", "script", "scriptscript", NULL
-};
-const char *node_fields_radical[] = {
- "attr", "nucleus", "sub", "sup", "left", "degree", "width", "options", NULL
-};
-const char *node_fields_fraction[] = {
- "attr", "width", "num", "denom", "left", "right", "middle", "options", NULL
-};
-const char *node_fields_accent[] = {
- "attr", "nucleus", "sub", "sup", "accent", "bot_accent", "top_accent",
- "overlay_accent", "fraction", NULL
-};
-const char *node_fields_fence[] = {
- "attr", "delim", "italic", "height", "depth", "options", "class", NULL
-};
-const char *node_fields_math_char[] = {
- "attr", "fam", "char", NULL
-};
-const char *node_fields_sub_box[] = {
- "attr", "head", NULL
-};
-const char *node_fields_sub_mlist[] = {
- "attr", "head", NULL
-};
-const char *node_fields_math_text_char[] = {
- "attr", "fam", "char", NULL
-};
-const char *node_fields_delim[] = {
- "attr", "small_fam", "small_char", "large_fam", "large_char", NULL
-};
-
-/* whatsit nodes */
-
-const char *node_fields_whatsit_open[] = {
- "attr", "stream", "name", "area", "ext", NULL
-};
-const char *node_fields_whatsit_write[] = {
- "attr", "stream", "data", NULL
-};
-const char *node_fields_whatsit_close[] = {
- "attr", "stream", NULL
-};
-const char *node_fields_whatsit_special[] = {
- "attr", "data", NULL
-};
-const char *node_fields_whatsit_save_pos[] = {
- "attr", NULL
-};
-const char *node_fields_whatsit_late_lua[] = {
- "attr", "reg", "data", "name", "string", NULL
-};
-const char *node_fields_whatsit_user_defined[] = {
- "attr", "user_id", "type", "value", NULL
-};
-
-/* pdf backend whatsit nodes */
-
-const char *node_fields_whatsit_pdf_literal[] = {
- "attr", "mode", "data", NULL
-};
-const char *node_fields_whatsit_pdf_refobj[] = {
- "attr", "objnum", NULL
-};
-const char *node_fields_whatsit_pdf_annot[] = {
- "attr", "width", "depth", "height", "objnum", "data", NULL
-};
-const char *node_fields_whatsit_pdf_start_link[] = {
- "attr", "width", "depth", "height", "objnum", "link_attr", "action", NULL
-};
-const char *node_fields_whatsit_pdf_end_link[] = {
- "attr", NULL
-};
-const char *node_fields_whatsit_pdf_dest[] = {
- "attr", "width", "depth", "height", "named_id", "dest_id", "dest_type",
- "xyz_zoom", "objnum", NULL
-};
-const char *node_fields_whatsit_pdf_action[] = {
- "action_type", "named_id", "action_id", "file", "new_window", "data", NULL
-};
-const char *node_fields_whatsit_pdf_thread[] = {
- "attr", "width", "depth", "height", "named_id", "thread_id", "thread_attr", NULL
-};
-const char *node_fields_whatsit_pdf_start_thread[] = {
- "attr", "width", "depth", "height", "named_id", "thread_id", "thread_attr", NULL
-};
-const char *node_fields_whatsit_pdf_end_thread[] = {
- "attr", NULL
-};
-const char *node_fields_whatsit_pdf_colorstack[] = {
- "attr", "stack", "cmd", "data", NULL
-};
-const char *node_fields_whatsit_pdf_setmatrix[] = {
- "attr", "data", NULL
-};
-const char *node_fields_whatsit_pdf_save[] = {
- "attr", NULL
-};
-const char *node_fields_whatsit_pdf_restore[] = {
- "attr", NULL
-};
-
-/* subtypes */
-
-const char *node_subtypes_glue[] = {
- "userskip", "lineskip", "baselineskip", "parskip", "abovedisplayskip", "belowdisplayskip",
- "abovedisplayshortskip", "belowdisplayshortskip", "leftskip", "rightskip", "topskip",
- "splittopskip", "tabskip", "spaceskip", "xspaceskip", "parfillskip",
- "mathskip", "thinmuskip", "medmuskip", "thickmuskip", NULL
-};
-const char *node_subtypes_mathglue[] = { /* 98+ */
- "conditionalmathskip", "muglue", NULL
-};
-const char *node_subtypes_leader[] = { /* 100+ */
- "leaders", "cleaders", "xleaders", "gleaders", NULL
-};
-const char *node_subtypes_fill[] = {
- "stretch", "fi", "fil", "fill", "filll", NULL
-};
-const char *node_subtypes_boundary[] = {
- "cancel", "user", "protrusion", "word", NULL
-};
-const char *node_subtypes_penalty[] = {
- "userpenalty", "linebreakpenalty", "linepenalty", "wordpenalty", "finalpenalty",
- "noadpenalty", "beforedisplaypenalty", "afterdisplaypenalty", "equationnumberpenalty", NULL
-};
-const char *node_subtypes_kern[] = {
- "fontkern", "userkern", "accentkern", "italiccorrection", NULL
-};
-const char *node_subtypes_rule[] = {
- "normal", "box", "image", "empty", "user", "over", "under", "fraction", "radical", NULL
-};
-const char *node_subtypes_glyph[] = {
- "character", "glyph", "ligature", "ghost", "left", "right", NULL
-};
-const char *node_subtypes_disc[] = {
- "discretionary", "explicit", "automatic", "regular", "first", "second", NULL
-};
-const char *node_subtypes_marginkern[] = {
- "left", "right", NULL
-};
-const char *node_subtypes_list[] = {
- "unknown", "line", "box", "indent", "alignment", "cell", "equation", "equationnumber", NULL
-};
-const char *node_subtypes_adjust[] = {
- "normal", "pre", NULL
-};
-const char *node_subtypes_math[] = {
- "beginmath", "endmath", NULL
-};
-const char *node_subtypes_noad[] = {
- "ord", "opdisplaylimits", "oplimits", "opnolimits", "bin", "rel", "open", "close",
- "punct", "inner", "under", "over", "vcenter", NULL
-};
-const char *node_subtypes_radical[] = {
- "radical", "uradical", "uroot", "uunderdelimiter", "uoverdelimiter", "udelimiterunder",
- "udelimiterover", NULL
-};
-const char *node_subtypes_accent[] = {
- "bothflexible", "fixedtop", "fixedbottom", "fixedboth", NULL,
-};
-const char *node_subtypes_fence[] = {
- "unset", "left", "middle", "right", NULL
-};
-
-node_info node_data[] = { /* the last entry in a row is the etex number */
- { hlist_node, box_node_size, node_fields_list, "hlist", 1 },
- { vlist_node, box_node_size, node_fields_list, "vlist", 2 },
- { rule_node, rule_node_size, node_fields_rule, "rule", 3 },
- { ins_node, ins_node_size, node_fields_insert, "ins", 4 },
- { mark_node, mark_node_size, node_fields_mark, "mark", 5 },
- { adjust_node, adjust_node_size, node_fields_adjust, "adjust", 6 },
- { boundary_node, boundary_node_size, node_fields_boundary, "boundary", -1 },
- { disc_node, disc_node_size, node_fields_disc, "disc", 8 },
- { whatsit_node, -1, NULL, "whatsit", 9 },
- { local_par_node, local_par_size, node_fields_local_par, "local_par", -1 },
- { dir_node, dir_node_size, node_fields_dir, "dir", -1 },
- { math_node, math_node_size, node_fields_math, "math", 10 },
- { glue_node, glue_node_size, node_fields_glue, "glue", 11 },
- { kern_node, kern_node_size, node_fields_kern, "kern", 12 },
- { penalty_node, penalty_node_size, node_fields_penalty, "penalty", 13 },
- { unset_node, box_node_size, node_fields_unset, "unset", 14 },
- { style_node, style_node_size, node_fields_style, "style", 15 },
- { choice_node, style_node_size, node_fields_choice, "choice", 15 },
- { simple_noad, noad_size, node_fields_noad, "noad", 15 },
- { radical_noad, radical_noad_size, node_fields_radical, "radical", 15 },
- { fraction_noad, fraction_noad_size, node_fields_fraction, "fraction", 15 },
- { accent_noad, accent_noad_size, node_fields_accent, "accent", 15 },
- { fence_noad, fence_noad_size, node_fields_fence, "fence", 15 },
- { math_char_node, math_kernel_node_size, node_fields_math_char, "math_char", 15 },
- { sub_box_node, math_kernel_node_size, node_fields_sub_box, "sub_box", 15 },
- { sub_mlist_node, math_kernel_node_size, node_fields_sub_mlist, "sub_mlist", 15 },
- { math_text_char_node, math_kernel_node_size, node_fields_math_text_char, "math_text_char", 15 },
- { delim_node, math_shield_node_size, node_fields_delim, "delim", 15 },
- { margin_kern_node, margin_kern_node_size, node_fields_margin_kern, "margin_kern", -1 },
- { glyph_node, glyph_node_size, node_fields_glyph, "glyph", 0 },
- { align_record_node, box_node_size, NULL, "align_record", -1 },
- { pseudo_file_node, pseudo_file_node_size, NULL, "pseudo_file", -1 },
- { pseudo_line_node, variable_node_size, NULL, "pseudo_line", -1 },
- { inserting_node, page_ins_node_size, node_fields_inserting, "page_insert", -1 },
- { split_up_node, page_ins_node_size, node_fields_splitup, "split_insert", -1 },
- { expr_node, expr_node_size, NULL, "expr_stack", -1 },
- { nesting_node, nesting_node_size, NULL, "nested_list", -1 },
- { span_node, span_node_size, NULL, "span", -1 },
- { attribute_node, attribute_node_size, node_fields_attribute, "attribute", -1 },
- { glue_spec_node, glue_spec_size, node_fields_glue_spec, "glue_spec", -1 },
- { attribute_list_node, attribute_node_size, node_fields_attribute_list, "attribute_list", -1 },
- { temp_node, temp_node_size, NULL, "temp", -1 },
- { align_stack_node, align_stack_node_size, NULL, "align_stack", -1 },
- { movement_node, movement_node_size, NULL, "movement_stack", -1 },
- { if_node, if_node_size, NULL, "if_stack", -1 },
- { unhyphenated_node, active_node_size, NULL, "unhyphenated", -1 },
- { hyphenated_node, active_node_size, NULL, "hyphenated", -1 },
- { delta_node, delta_node_size, NULL, "delta", -1 },
- { passive_node, passive_node_size, NULL, "passive", -1 },
- { shape_node, variable_node_size, NULL, "shape", -1 },
- { -1, -1, NULL, NULL, -1 },
-};
-
-const char *node_subtypes_pdf_destination[] = {
- "xyz", "fit", "fith", "fitv", "fitb", "fitbh", "fitbv", "fitr", NULL
-};
-const char *node_subtypes_pdf_literal[] = {
- "origin", "page", "direct", NULL
-};
-
-node_info whatsit_node_data[] = {
- { open_node, open_node_size, node_fields_whatsit_open, "open", -1 },
- { write_node, write_node_size, node_fields_whatsit_write, "write", -1 },
- { close_node, close_node_size, node_fields_whatsit_close, "close", -1 },
- { special_node, special_node_size, node_fields_whatsit_special, "special", -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { save_pos_node, save_pos_node_size, node_fields_whatsit_save_pos, "save_pos", -1 },
- { late_lua_node, late_lua_node_size, node_fields_whatsit_late_lua, "late_lua", -1 },
- { user_defined_node, user_defined_node_size, node_fields_whatsit_user_defined, "user_defined", -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- { fake_node, fake_node_size, NULL, fake_node_name, -1 },
- /* here starts the dvi backend section, todo: a separate list */
- /* nothing for dvi */
- /* here starts the pdf backend section, todo: a separate list */
- { pdf_literal_node, write_node_size, node_fields_whatsit_pdf_literal, "pdf_literal", -1 },
- { pdf_refobj_node, pdf_refobj_node_size, node_fields_whatsit_pdf_refobj, "pdf_refobj", -1 },
- { pdf_annot_node, pdf_annot_node_size, node_fields_whatsit_pdf_annot, "pdf_annot", -1 },
- { pdf_start_link_node, pdf_annot_node_size, node_fields_whatsit_pdf_start_link, "pdf_start_link", -1 },
- { pdf_end_link_node, pdf_end_link_node_size, node_fields_whatsit_pdf_end_link, "pdf_end_link", -1 },
- { pdf_dest_node, pdf_dest_node_size, node_fields_whatsit_pdf_dest, "pdf_dest", -1 },
- { pdf_action_node, pdf_action_size, node_fields_whatsit_pdf_action, "pdf_action", -1 },
- { pdf_thread_node, pdf_thread_node_size, node_fields_whatsit_pdf_thread, "pdf_thread", -1 },
- { pdf_start_thread_node, pdf_thread_node_size, node_fields_whatsit_pdf_start_thread, "pdf_start_thread", -1 },
- { pdf_end_thread_node, pdf_end_thread_node_size, node_fields_whatsit_pdf_end_thread, "pdf_end_thread", -1 },
- { pdf_thread_data_node, pdf_thread_node_size, NULL, "pdf_thread_data", -1 },
- { pdf_link_data_node, pdf_annot_node_size, NULL, "pdf_link_data", -1 },
- { pdf_colorstack_node, pdf_colorstack_node_size, node_fields_whatsit_pdf_colorstack, "pdf_colorstack", -1 },
- { pdf_setmatrix_node, pdf_setmatrix_node_size, node_fields_whatsit_pdf_setmatrix, "pdf_setmatrix", -1 },
- { pdf_save_node, pdf_save_node_size, node_fields_whatsit_pdf_save, "pdf_save", -1 },
- { pdf_restore_node, pdf_restore_node_size, node_fields_whatsit_pdf_restore, "pdf_restore", -1 },
- /* done */
- { -1, -1, NULL, NULL, -1 },
-};
-
-#define last_whatsit_node pdf_restore_node
-
-@
-When we copy a node list, there are several possibilities: we do the same as a new node,
-we copy the entry to the table in properties (a reference), we do a deep copy of a table
-in the properties, we create a new table and give it the original one as a metatable.
-After some experiments (that also included timing) with these scenarios I decided that a
-deep copy made no sense, nor did nilling. In the end both the shallow copy and the metatable
-variant were both ok, although the second ons is slower. The most important aspect to keep
-in mind is that references to other nodes in properties no longer can be valid for that
-copy. We could use two tables (one unique and one shared) or metatables but that only
-complicates matters.
-
-When defining a new node, we could already allocate a table but it is rather easy to do
-that at the lua end e.g. using a metatable __index method. That way it is under macro
-package control.
-
-When deleting a node, we could keep the slot (e.g. setting it to false) but it could make
-memory consumption raise unneeded when we have temporary large node lists and after that
-only small lists.
-
-So, in the end this is what we ended up with. For the record, I also experimented with the
-following:
-
-- copy attributes to the properties so that we have fast access at the lua end: in the end
- the overhead is not compensated by speed and convenience, in fact, attributes are not
- that slow when it comes to accessing them
-
-- a bitset in the node but again the gain compared to attributes is neglectable and it also
- demands a pretty string agreement over what bit represents what, and this is unlikely to
- succeed in the tex community (I could use it for font handling, which is cross package,
- but decided that it doesn't pay off
-
-In case one wonders why properties make sense then, well, it is not so much speed that we
-gain, but more convenience: storing all kind of (temporary) data in attributes is no fun and
-this mechanism makes sure that properties are cleaned up when a node is freed. Also, the
-advantage of a more or less global properties table is that we stay at the lua end. An
-alternative is to store a reference in the node itself but that is complicated by the fact
-that the register has some limitations (no numeric keys) and we also don't want to mess with
-it too much.
-
-@c
-int lua_properties_level = 0 ; /* can be private */
-int lua_properties_enabled = 0 ;
-int lua_properties_use_metatable = 0 ;
-
-@
-We keep track of nesting so that we don't oveflow the stack, and, what is more
-important, don't keep resolving the registry index.
-
-@c
-#define lua_properties_push do { \
- if (lua_properties_enabled) { \
- lua_properties_level = lua_properties_level + 1 ; \
- if (lua_properties_level == 1) { \
- lua_get_metatablelua_l(Luas,node_properties); \
- } \
- } \
-} while(0)
-
-#define lua_properties_pop do { \
- if (lua_properties_enabled) { \
- if (lua_properties_level == 1) \
- lua_pop(Luas,1); \
- lua_properties_level = lua_properties_level - 1 ; \
- } \
-} while(0)
-
-/* No setting is needed: */
-
-#define lua_properties_set(target) do { \
-} while(0)
-
-/* Resetting boils down to nilling. */
-
-#define lua_properties_reset(target) do { \
- if (lua_properties_enabled) { \
- if (lua_properties_level == 0) { \
- lua_get_metatablelua_l(Luas,node_properties); \
- lua_pushnil(Luas); \
- lua_rawseti(Luas,-2,target); \
- lua_pop(Luas,1); \
- } else { \
- lua_pushnil(Luas); \
- lua_rawseti(Luas,-2,target); \
- } \
- } \
-} while(0)
-
-/*
- For a moment I considered supporting all kind of data types but in practice
- that makes no sense. So we stick to a cheap shallow copy with as option a
- metatable. Btw, a deep copy would look like this:
-
- static void copy_lua_table(lua_State* L, int index) {
- lua_newtable(L);
- lua_pushnil(L);
- while(lua_next(L, index-1) != 0) {
- lua_pushvalue(L, -2);
- lua_insert(L, -2);
- if (lua_type(L,-1)==LUA_TTABLE)
- copy_lua_table(L,-1);
- lua_settable(L, -4);
- }
- lua_pop(L,1);
- }
-
- #define lua_properties_copy(target, source) do { \
- if (lua_properties_enabled) { \
- lua_pushinteger(Luas,source); \
- lua_rawget(Luas,-2); \
- if (lua_type(Luas,-1)==LUA_TTABLE) { \
- copy_lua_table(Luas,-1); \
- lua_pushinteger(Luas,target); \
- lua_insert(Luas,-2); \
- lua_rawset(Luas,-3); \
- } else { \
- lua_pop(Luas,1); \
- } \
- } \
- } while(0)
-
-*/
-
-/* isn't there a faster way to metatable? */
-
-/*
-
-#define lua_properties_copy(target,source) do { \
- if (lua_properties_enabled) { \
- if (lua_properties_level == 0) { \
- lua_get_metatablelua_l(Luas,node_properties); \
- lua_rawgeti(Luas,-1,source); \
- if (lua_type(Luas,-1)==LUA_TTABLE) { \
- if (lua_properties_use_metatable) { \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setfield(Luas,-2,"__index"); \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setmetatable(Luas,-2); \
- } \
- lua_rawseti(Luas,-2,target); \
- } else { \
- lua_pop(Luas,1); \
- } \
- lua_pop(Luas,1); \
- } else { \
- lua_rawgeti(Luas,-1,source); \
- if (lua_type(Luas,-1)==LUA_TTABLE) { \
- if (lua_properties_use_metatable) { \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setfield(Luas,-2,"__index"); \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setmetatable(Luas,-2); \
- } \
- lua_rawseti(Luas,-2,target); \
- } else { \
- lua_pop(Luas,1); \
- } \
- } \
- } \
-} while(0)
-
-*/
-
-/*
- A simple testrun on many pages of dumb text shows 1% gain (of course it depends
- on how properties are used but some other tests confirm it).
-*/
-
-#define lua_properties_copy(target,source) do { \
- if (lua_properties_enabled) { \
- if (lua_properties_level == 0) { \
- lua_get_metatablelua_l(Luas,node_properties); \
- lua_rawgeti(Luas,-1,source); \
- if (lua_type(Luas,-1)==LUA_TTABLE) { \
- if (lua_properties_use_metatable) { \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_push_string_by_name(Luas,__index); \
- lua_insert(Luas,-2); \
- lua_rawset(Luas, -3); \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setmetatable(Luas,-2); \
- } \
- lua_rawseti(Luas,-2,target); \
- } else { \
- lua_pop(Luas,1); \
- } \
- lua_pop(Luas,1); \
- } else { \
- lua_rawgeti(Luas,-1,source); \
- if (lua_type(Luas,-1)==LUA_TTABLE) { \
- if (lua_properties_use_metatable) { \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_push_string_by_name(Luas,__index); \
- lua_insert(Luas,-2); \
- lua_rawset(Luas, -3); \
- lua_newtable(Luas); \
- lua_insert(Luas,-2); \
- lua_setmetatable(Luas,-2); \
- } \
- lua_rawseti(Luas,-2,target); \
- } else { \
- lua_pop(Luas,1); \
- } \
- } \
- } \
-} while(0)
-
-/* Here end the property handlers. */
-
-@ @c
-int valid_node(halfword p)
-{
- if (p > my_prealloc && p < var_mem_max) {
-#ifdef CHECK_NODE_USAGE
- if (varmem_sizes[p] > 0) {
- return 1;
- }
-#else
- return 1;
-#endif
- }
- return 0;
-}
-
-@ @c
-static int test_count = 1;
-
-#define dorangetest(a,b,c) do { \
- if (!(b>=0 && b<c)) { \
- fprintf(stdout,"For node p:=%d, 0<=%d<%d (l.%d,r.%d)\n", \
- (int)a, (int)b, (int)c, __LINE__,test_count); \
- confusion("node range test failed"); \
- } } while (0)
-
-#define dotest(a,b,c) do { \
- if (b!=c) { \
- fprintf(stdout,"For node p:=%d, %d==%d (l.%d,r.%d)\n", \
- (int)a, (int)b, (int)c, __LINE__,test_count); \
- confusion("node test failed"); \
- } } while (0)
-
-#define check_action_ref(a) { dorangetest(p,a,var_mem_max); }
-#define check_attribute_ref(a) { dorangetest(p,a,var_mem_max); }
-
-/* hm, we can just pass p then */
-
-#define check_token_ref(p) { \
- if (type(p) == whatsit_node) { \
- formatted_error("nodes","fuzzy token cleanup in whatsit node with type %s and subtype %i",node_data[type(p)].name,subtype(p)); \
- } else { \
- formatted_error("nodes","fuzzy token cleanup in node with type %s",node_data[type(p)].name); \
- } \
-}
-
-#ifdef CHECK_NODE_USAGE
-
-static void check_static_node_mem(void)
-{
- dotest(zero_glue, width(zero_glue), 0);
- dotest(zero_glue, type(zero_glue), glue_spec_node);
- dotest(zero_glue, vlink(zero_glue), null);
- dotest(zero_glue, stretch(zero_glue), 0);
- dotest(zero_glue, stretch_order(zero_glue), normal);
- dotest(zero_glue, shrink(zero_glue), 0);
- dotest(zero_glue, shrink_order(zero_glue), normal);
-
- dotest(sfi_glue, width(sfi_glue), 0);
- dotest(sfi_glue, type(sfi_glue), glue_spec_node);
- dotest(sfi_glue, vlink(sfi_glue), null);
- dotest(sfi_glue, stretch(sfi_glue), 0);
- dotest(sfi_glue, stretch_order(sfi_glue), sfi);
- dotest(sfi_glue, shrink(sfi_glue), 0);
- dotest(sfi_glue, shrink_order(sfi_glue), normal);
-
- dotest(fil_glue, width(fil_glue), 0);
- dotest(fil_glue, type(fil_glue), glue_spec_node);
- dotest(fil_glue, vlink(fil_glue), null);
- dotest(fil_glue, stretch(fil_glue), unity);
- dotest(fil_glue, stretch_order(fil_glue), fil);
- dotest(fil_glue, shrink(fil_glue), 0);
- dotest(fil_glue, shrink_order(fil_glue), normal);
-
- dotest(fill_glue, width(fill_glue), 0);
- dotest(fill_glue, type(fill_glue), glue_spec_node);
- dotest(fill_glue, vlink(fill_glue), null);
- dotest(fill_glue, stretch(fill_glue), unity);
- dotest(fill_glue, stretch_order(fill_glue), fill);
- dotest(fill_glue, shrink(fill_glue), 0);
- dotest(fill_glue, shrink_order(fill_glue), normal);
-
- dotest(ss_glue, width(ss_glue), 0);
- dotest(ss_glue, type(ss_glue), glue_spec_node);
- dotest(ss_glue, vlink(ss_glue), null);
- dotest(ss_glue, stretch(ss_glue), unity);
- dotest(ss_glue, stretch_order(ss_glue), fil);
- dotest(ss_glue, shrink(ss_glue), unity);
- dotest(ss_glue, shrink_order(ss_glue), fil);
-
- dotest(fil_neg_glue, width(fil_neg_glue), 0);
- dotest(fil_neg_glue, type(fil_neg_glue), glue_spec_node);
- dotest(fil_neg_glue, vlink(fil_neg_glue), null);
- dotest(fil_neg_glue, stretch(fil_neg_glue), -unity);
- dotest(fil_neg_glue, stretch_order(fil_neg_glue), fil);
- dotest(fil_neg_glue, shrink(fil_neg_glue), 0);
- dotest(fil_neg_glue, shrink_order(fil_neg_glue), normal);
-}
-
-static void node_mem_dump(halfword p)
-{
- halfword r;
- for (r = my_prealloc + 1; r < var_mem_max; r++) {
- if (vlink(r) == p) {
- halfword s = r;
- while (s > my_prealloc && varmem_sizes[s] == 0) {
- s--;
- }
- if (s != null
- && s != my_prealloc
- && s != var_mem_max
- && (r - s) < get_node_size(type(s), subtype(s))
- && alink(s) != p) {
- if (type(s) == disc_node) {
- fprintf(stdout," pointed to from %s node %d (vlink %d, alink %d): ",
- get_node_name(type(s), subtype(s)), (int) s,
- (int) vlink(s), (int) alink(s));
- fprintf(stdout, "pre_break(%d,%d,%d), ",
- (int) vlink_pre_break(s), (int) tlink(pre_break(s)),
- (int) alink(pre_break(s)));
- fprintf(stdout, "post_break(%d,%d,%d), ",
- (int) vlink_post_break(s),
- (int) tlink(post_break(s)),
- (int) alink(post_break(s)));
- fprintf(stdout, "no_break(%d,%d,%d)",
- (int) vlink_no_break(s), (int) tlink(no_break(s)),
- (int) alink(no_break(s)));
- fprintf(stdout, "\n");
- } else {
- if (vlink(s) == p
- || (type(s) == glyph_node && lig_ptr (s) == p)
- || (type(s) == vlist_node && list_ptr(s) == p)
- || (type(s) == hlist_node && list_ptr(s) == p)
- || (type(s) == unset_node && list_ptr(s) == p)
- || (type(s) == ins_node && ins_ptr (s) == p)
- ) {
- fprintf(stdout," pointed to from %s node %d (vlink %d, alink %d): ",
- get_node_name(type(s), subtype(s)), (int) s,
- (int) vlink(s), (int) alink(s));
- if (type(s) == glyph_node) {
- fprintf(stdout, "lig_ptr(%d)", (int) lig_ptr(s));
- } else if (type(s) == vlist_node || type(s) == hlist_node) {
- fprintf(stdout, "list_ptr(%d)", (int) list_ptr(s));
- }
- fprintf(stdout, "\n");
- } else {
- if ((type(s) != penalty_node) && (type(s) != math_node) && (type(s) != kern_node)) {
- fprintf(stdout, " pointed to from %s node %d\n",
- get_node_name(type(s), subtype(s)), (int) s);
- }
- }
- }
- }
- }
- }
-}
-
-#endif
-
-static int free_error(halfword p)
-{
- if (p > my_prealloc && p < var_mem_max) {
-#ifdef CHECK_NODE_USAGE
- int i;
- if (varmem_sizes[p] == 0) {
- check_static_node_mem();
- for (i = (my_prealloc + 1); i < var_mem_max; i++) {
- if (varmem_sizes[i] > 0) {
- check_node(i);
- }
- }
- test_count++;
- if (type(p) == glyph_node) {
- formatted_error("nodes", "attempt to double-free glyph (%c) node %d, ignored", (int) character(p), (int) p);
- } else {
- formatted_error("nodes", "attempt to double-free %s node %d, ignored", get_node_name(type(p), subtype(p)), (int) p);
- }
- node_mem_dump(p);
- return 1;
- }
-#endif
- } else {
- formatted_error("nodes", "attempt to free an impossible node %d", (int) p);
- return 1;
- }
- return 0;
-}
-
-@ @c
-static int copy_error(halfword p)
-{
- if (p >= 0 && p < var_mem_max) {
-#ifdef CHECK_NODE_USAGE
- if (p > my_prealloc && varmem_sizes[p] == 0) {
- if (type(p) == glyph_node) {
- formatted_warning("nodes", "attempt to copy free glyph (%c) node %d, ignored", (int) character(p), (int) p);
- } else {
- formatted_warning("nodes", "attempt to copy free %s node %d, ignored", get_node_name(type(p), subtype(p)), (int) p);
- }
- return 1;
- }
-#endif
- } else {
- formatted_error("nodes", "attempt to copy an impossible node %d", (int) p);
- return 1;
- }
- return 0;
-}
-
-@ @c
-static halfword synctex_anyway_mode = 0; /* 2 also glyphs */
-static halfword synctex_line_field = 0;
-static halfword synctex_no_files = 0;
-
-void synctex_set_mode(int m)
-{
- synctex_anyway_mode = m;
-};
-
-int synctex_get_mode(void)
-{
- return synctex_anyway_mode;
-};
-
-void synctex_set_no_files(int f)
-{
- synctex_no_files = f;
-};
-
-int synctex_get_no_files(void)
-{
- return (int) synctex_no_files ;
-};
-
-void synctex_set_tag(int t)
-{
- cur_input.synctex_tag_field = t;
-};
-
-int synctex_get_tag(void)
-{
- return (int) cur_input.synctex_tag_field;
-};
-
-
-int synctex_get_line(void)
-{
- return (int) synctex_line_field;
-};
-
-static int forced_tag = 0;
-static int forced_line = 0;
-
-void synctex_force_tag(int t)
-{
- forced_tag = t;
-};
-
-void synctex_force_line(int t)
-{
- forced_line = t;
-};
-
-void synctex_set_line(int l)
-{
- synctex_line_field = l;
-};
-
-@ @c
-/* if_stack is called a lot so maybe optimize */
-
-halfword new_node(int i, int j)
-{
- int s = get_node_size(i, j);
- halfword n = get_node(s);
- /*
- It should be possible to do this memset at |free_node()|.
-
- Both type() and subtype() will be set below, and vlink() is
- set to null by |get_node()|, so we can do we clearing one
- word less than |s|
- */
- (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * ((unsigned) s - 1)));
- switch (i) {
- case glyph_node:
- init_lang_data(n);
- break;
- case hlist_node:
- case vlist_node:
- box_dir(n) = -1;
- break;
- case disc_node:
- pre_break(n) = pre_break_head(n);
- type(pre_break(n)) = nesting_node;
- subtype(pre_break(n)) = pre_break_head(0);
- post_break(n) = post_break_head(n);
- type(post_break(n)) = nesting_node;
- subtype(post_break(n)) = post_break_head(0);
- no_break(n) = no_break_head(n);
- type(no_break(n)) = nesting_node;
- subtype(no_break(n)) = no_break_head(0);
- break;
- case rule_node:
- depth(n) = null_flag;
- height(n) = null_flag;
- width(n) = null_flag;
- rule_dir(n) = -1;
- rule_index(n) = 0;
- rule_transform(n) = 0;
- break;
- case whatsit_node:
- if (j == open_node) {
- open_name(n) = get_nullstr();
- open_area(n) = open_name(n);
- open_ext(n) = open_name(n);
- }
- break;
- case unset_node:
- width(n) = null_flag;
- break;
- case pseudo_line_node:
- case shape_node:
- /* this is a trick that makes |pseudo_files| slightly slower,
- but the overall allocation faster then an explicit test
- at the top of |new_node()|.
- */
- if (j>0) {
- free_node(n, variable_node_size);
- n = slow_get_node(j);
- (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * ((unsigned) j - 1)));
- }
- break;
- default:
- break;
- }
- if (synctex_anyway_mode) {
- switch (i) {
- /* 1 = all but glyphs */
- /* 2 = also glyphs */
- /* 3 = glyphs and glue */
- /* 4 = only glyphs */
- case glyph_node:
- if (synctex_anyway_mode > 1) {
- synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- case glue_node:
- if (synctex_anyway_mode < 4) {
- synctex_tag_glue(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_glue(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- case kern_node:
- if (synctex_anyway_mode < 3) {
- synctex_tag_kern(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_kern(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- case hlist_node:
- case vlist_node:
- case unset_node: /* useless */
- if (synctex_anyway_mode < 3) {
- synctex_tag_box(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_box(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- case rule_node:
- if (synctex_anyway_mode < 3) {
- synctex_tag_rule(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_rule(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- case math_node: /* noads probably make more sense */
- if (synctex_anyway_mode < 3) {
- synctex_tag_math(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_math(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- break;
- }
- } else if (synctex_par) {
- /* handle synctex extension */
- switch (i) {
- case glue_node:
- synctex_tag_glue(n) = cur_input.synctex_tag_field;
- synctex_line_glue(n) = line;
- break;
- case kern_node:
- if (j != 0) {
- synctex_tag_kern(n) = cur_input.synctex_tag_field;
- synctex_line_kern(n) = line;
- }
- break;
- case hlist_node:
- case vlist_node:
- case unset_node:
- synctex_tag_box(n) = cur_input.synctex_tag_field;
- synctex_line_box(n) = line;
- break;
- case rule_node:
- synctex_tag_rule(n) = cur_input.synctex_tag_field;
- synctex_line_rule(n) = line;
- break;
- case math_node:
- synctex_tag_math(n) = cur_input.synctex_tag_field;
- synctex_line_math(n) = line;
- break;
- }
- }
- /* take care of attributes */
- if (nodetype_has_attributes(i)) {
- build_attribute_list(n);
- /* lua_properties_set */
- }
- type(n) = (quarterword) i;
- subtype(n) = (quarterword) j;
- return n;
-}
-
-halfword raw_glyph_node(void)
-{
- register halfword n = get_node(glyph_node_size);
- (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * (glyph_node_size - 1)));
- if (synctex_anyway_mode > 1) {
- synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- type(n) = glyph_node;
- subtype(n) = 0;
- return n;
-}
-
-halfword new_glyph_node(void)
-{
- register halfword n = get_node(glyph_node_size);
- (void) memset((void *) (varmem + n + 1), 0, (sizeof(memory_word) * (glyph_node_size - 1)));
- if (synctex_anyway_mode > 1) {
- synctex_tag_glyph(n) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_glyph(n) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- type(n) = glyph_node;
- subtype(n) = 0;
- build_attribute_list(n);
- /* lua_properties_set */
- return n;
-}
-
-@ makes a duplicate of the node list that starts at |p| and returns a
-pointer to the new list
-
-@c
-halfword do_copy_node_list(halfword p, halfword end)
-{
- halfword q = null; /* previous position in new list */
- halfword h = null; /* head of the list */
- register halfword s ;
- lua_properties_push; /* saves stack and time */
- while (p != end) {
- s = copy_node(p);
- if (h == null) {
- h = s;
- } else {
- couple_nodes(q, s);
- }
- q = s;
- p = vlink(p);
- }
- lua_properties_pop; /* saves stack and time */
- return h;
-}
-
-halfword copy_node_list(halfword p)
-{
- return do_copy_node_list(p, null);
-}
-
-#define copy_sub_list(target,source) do { \
- if (source != null) { \
- s = do_copy_node_list(source, null); \
- target = s; \
- } else { \
- target = null; \
- } \
- } while (0)
-
-#define copy_sub_node(target,source) do { \
- if (source != null) { \
- s = copy_node(source); \
- target = s ; \
- } else { \
- target = null; \
- } \
-} while (0)
-
-@ make a dupe of a single node
-
-@c
-static void copy_node_wrapup_core(halfword p, halfword r)
-{
- halfword s ;
- switch (subtype(p)) {
- case write_node:
- case special_node:
- add_token_ref(write_tokens(p));
- break;
- case late_lua_node:
- copy_late_lua(r, p);
- break;
- case user_defined_node:
- switch (user_node_type(p)) {
- case 'a':
- add_node_attr_ref(user_node_value(p));
- break;
- case 'l':
- copy_user_lua(r, p);
- break;
- case 'n':
- s = copy_node_list(user_node_value(p));
- user_node_value(r) = s;
- break;
- case 's':
- /* |add_string_ref(user_node_value(p));| */
- break;
- case 't':
- add_token_ref(user_node_value(p));
- break;
- }
- break;
- default:
- break ;
- }
-}
-
-void copy_node_wrapup_dvi(halfword p, halfword r)
-{
-}
-
-void copy_node_wrapup_pdf(halfword p, halfword r)
-{
- switch(subtype(p)) {
- case pdf_literal_node:
- copy_pdf_literal(r, p);
- break;
- case pdf_colorstack_node:
- if (pdf_colorstack_cmd(p) <= colorstack_data)
- add_token_ref(pdf_colorstack_data(p));
- break;
- case pdf_setmatrix_node:
- add_token_ref(pdf_setmatrix_data(p));
- break;
- case pdf_annot_node:
- add_token_ref(pdf_annot_data(p));
- break;
- case pdf_start_link_node:
- if (pdf_link_attr(r) != null)
- add_token_ref(pdf_link_attr(r));
- add_action_ref(pdf_link_action(r));
- break;
- case pdf_dest_node:
- if (pdf_dest_named_id(p) > 0)
- add_token_ref(pdf_dest_id(p));
- break;
- case pdf_thread_node:
- case pdf_start_thread_node:
- if (pdf_thread_named_id(p) > 0)
- add_token_ref(pdf_thread_id(p));
- if (pdf_thread_attr(p) != null)
- add_token_ref(pdf_thread_attr(p));
- break;
- default:
- break;
- }
-}
-
-halfword copy_node(const halfword p)
-{
- halfword r; /* current node being fabricated for new list */
- halfword w; /* whatsit subtype */
- halfword t; /* type of node */
- register halfword s; /* a helper variable for copying into variable mem */
- register int i;
- if (copy_error(p)) {
- r = new_node(temp_node, 0);
- return r;
- }
- t = type(p);
- i = get_node_size(t,subtype(p));
- r = get_node(i);
-
- (void) memcpy((void *) (varmem + r), (void *) (varmem + p), (sizeof(memory_word) * (unsigned) i));
-
- /* possible speedup: */
- /*
- if t == glue_spec) {
- return r;
- }
- */
-
- if (synctex_anyway_mode) {
- /*
- if (t == glyph_node) {
- if (synctex_anyway_mode > 1) {
- synctex_tag_glyph(r) = forced_tag ? forced_tag : cur_input.synctex_tag_field;
- synctex_line_glyph(r) = forced_line ? forced_line : synctex_line_field ? synctex_line_field : line;
- }
- }
- */
- } else if (synctex_par) {
- /* handle synctex extension */
- switch (t) {
- case math_node:
- synctex_tag_math(r) = cur_input.synctex_tag_field;
- synctex_line_math(r) = line;
- break;
- case kern_node:
- synctex_tag_kern(r) = cur_input.synctex_tag_field;
- synctex_line_kern(r) = line;
- break;
- }
- }
- if (nodetype_has_attributes(t)) {
- add_node_attr_ref(node_attr(p));
- alink(r) = null;
- lua_properties_copy(r,p);
- }
- vlink(r) = null;
-
- switch (t) {
- case glyph_node:
- copy_sub_list(lig_ptr(r),lig_ptr(p)) ;
- break;
- case glue_node:
- copy_sub_list(leader_ptr(r),leader_ptr(p)) ;
- break;
- case hlist_node:
- case vlist_node:
- case unset_node:
- copy_sub_list(list_ptr(r),list_ptr(p)) ;
- break;
- case disc_node:
- pre_break(r) = pre_break_head(r);
- if (vlink_pre_break(p) != null) {
- s = copy_node_list(vlink_pre_break(p));
- alink(s) = pre_break(r);
- tlink_pre_break(r) = tail_of_list(s);
- vlink_pre_break(r) = s;
- } else {
- assert(tlink(pre_break(r)) == null);
- }
- post_break(r) = post_break_head(r);
- if (vlink_post_break(p) != null) {
- s = copy_node_list(vlink_post_break(p));
- alink(s) = post_break(r);
- tlink_post_break(r) = tail_of_list(s);
- vlink_post_break(r) = s;
- } else {
- assert(tlink_post_break(r) == null);
- }
- no_break(r) = no_break_head(r);
- if (vlink(no_break(p)) != null) {
- s = copy_node_list(vlink_no_break(p));
- alink(s) = no_break(r);
- tlink_no_break(r) = tail_of_list(s);
- vlink_no_break(r) = s;
- } else {
- assert(tlink_no_break(r) == null);
- }
- break;
- case math_node:
- break;
- case ins_node:
- copy_sub_list(ins_ptr(r),ins_ptr(p)) ;
- break;
- case margin_kern_node:
- copy_sub_node(margin_char(r),margin_char(p));
- break;
- case mark_node:
- add_token_ref(mark_ptr(p));
- break;
- case adjust_node:
- copy_sub_list(adjust_ptr(r),adjust_ptr(p));
- break;
- case choice_node:
- copy_sub_list(display_mlist(r),display_mlist(p)) ;
- copy_sub_list(text_mlist(r),text_mlist(p)) ;
- copy_sub_list(script_mlist(r),script_mlist(p)) ;
- copy_sub_list(script_script_mlist(r),script_script_mlist(p)) ;
- break;
- case simple_noad:
- copy_sub_list(nucleus(r),nucleus(p)) ;
- copy_sub_list(subscr(r),subscr(p)) ;
- copy_sub_list(supscr(r),supscr(p)) ;
- break;
- case radical_noad:
- copy_sub_list(nucleus(r),nucleus(p)) ;
- copy_sub_list(subscr(r),subscr(p)) ;
- copy_sub_list(supscr(r),supscr(p)) ;
- copy_sub_node(left_delimiter(r),left_delimiter(p)) ;
- copy_sub_list(degree(r),degree(p)) ;
- break;
- case accent_noad:
- copy_sub_list(nucleus(r),nucleus(p)) ;
- copy_sub_list(subscr(r),subscr(p)) ;
- copy_sub_list(supscr(r),supscr(p)) ;
- copy_sub_list(top_accent_chr(r),top_accent_chr(p)) ;
- copy_sub_list(bot_accent_chr(r),bot_accent_chr(p)) ;
- copy_sub_list(overlay_accent_chr(r),overlay_accent_chr(p)) ;
- break;
- case fence_noad:
- copy_sub_node(delimiter(r),delimiter(p)) ;
- break;
- case sub_box_node:
- case sub_mlist_node:
- copy_sub_list(math_list(r),math_list(p)) ;
- break;
- case fraction_noad:
- copy_sub_list(numerator(r),numerator(p)) ;
- copy_sub_list(denominator(r),denominator(p)) ;
- copy_sub_node(left_delimiter(r),left_delimiter(p)) ;
- copy_sub_node(right_delimiter(r),right_delimiter(p)) ;
- break;
- case glue_spec_node:
- case dir_node:
- case local_par_node:
- case boundary_node:
- break;
- case whatsit_node:
- w = subtype(p) ;
- if (w >= backend_first_pdf_whatsit) {
- copy_node_wrapup_pdf(p,r);
- } else if (w >= backend_first_dvi_whatsit) {
- copy_node_wrapup_dvi(p,r);
- } else {
- copy_node_wrapup_core(p,r);
- }
- break;
- }
- return r;
-}
-
-/* x */
-
-#define free_sub_list(source) if (source != null) flush_node_list(source);
-#define free_sub_node(source) if (source != null) flush_node(source);
-
-@ @c
-
-static void flush_node_wrapup_core(halfword p)
-{
- switch (subtype(p)) {
- case open_node:
- case write_node:
- case close_node:
- case save_pos_node:
- break;
- case special_node:
- delete_token_ref(write_tokens(p));
- break;
- case late_lua_node:
- free_late_lua(p);
- break;
- case user_defined_node:
- switch (user_node_type(p)) {
- case 'a':
- delete_attribute_ref(user_node_value(p));
- break;
- case 'd':
- break;
- case 'l':
- free_user_lua(user_node_value(p));
- break;
- case 'n':
- flush_node_list(user_node_value(p));
- break;
- case 's':
- /* |delete_string_ref(user_node_value(p));| *//* if this was mpost .. */
- break;
- case 't':
- delete_token_ref(user_node_value(p));
- break;
- default:
- {
- const char *hlp[] = {
- "The type of the value in a user defined whatsit node should be one",
- "of 'a' (attribute list), 'd' (number), 'n' (node list), 's' (string),",
- "or 't' (tokenlist). Yours has an unknown type, and therefore I don't",
- "know how to free the node's value. A memory leak may result.",
- NULL
- };
- tex_error("Unidentified user defined whatsit", hlp);
- }
- break;
- }
- break;
- }
-}
-
-void flush_node_wrapup_dvi(halfword p)
-{
-}
-
-void flush_node_wrapup_pdf(halfword p)
-{
- switch(subtype(p)) {
- case pdf_save_node:
- case pdf_restore_node:
- case pdf_refobj_node:
- case pdf_end_link_node:
- case pdf_end_thread_node:
- break;
- case pdf_literal_node:
- free_pdf_literal(p);
- break;
- case pdf_colorstack_node:
- if (pdf_colorstack_cmd(p) <= colorstack_data)
- delete_token_ref(pdf_colorstack_data(p));
- break;
- case pdf_setmatrix_node:
- delete_token_ref(pdf_setmatrix_data(p));
- break;
- case pdf_annot_node:
- delete_token_ref(pdf_annot_data(p));
- break;
- case pdf_link_data_node:
- break;
- case pdf_start_link_node:
- if (pdf_link_attr(p) != null)
- delete_token_ref(pdf_link_attr(p));
- delete_action_ref(pdf_link_action(p));
- break;
- case pdf_dest_node:
- if (pdf_dest_named_id(p) > 0)
- delete_token_ref(pdf_dest_id(p));
- break;
- case pdf_action_node:
- if (pdf_action_type(p) == pdf_action_user) {
- delete_token_ref(pdf_action_tokens(p));
- } else {
- if (pdf_action_file(p) != null)
- delete_token_ref(pdf_action_file(p));
- if (pdf_action_type(p) == pdf_action_page)
- delete_token_ref(pdf_action_tokens(p));
- else if (pdf_action_named_id(p) > 0)
- delete_token_ref(pdf_action_id(p));
- }
- break;
- case pdf_thread_data_node:
- break;
- case pdf_thread_node:
- case pdf_start_thread_node:
- if (pdf_thread_named_id(p) > 0)
- delete_token_ref(pdf_thread_id(p));
- if (pdf_thread_attr(p) != null)
- delete_token_ref(pdf_thread_attr(p));
- break;
- }
-}
-
-void flush_node(halfword p)
-{
- halfword w;
- if (p == null) /* legal, but no-op */
- return;
- if (free_error(p))
- return;
- switch (type(p)) {
- case glyph_node:
- free_sub_list(lig_ptr(p));
- break;
- case glue_node:
- free_sub_list(leader_ptr(p));
- break;
- case hlist_node:
- case vlist_node:
- case unset_node:
- free_sub_list(list_ptr(p));
- break;
- case disc_node:
- /* watch the start at temp node hack */
- free_sub_list(vlink(pre_break(p)));
- free_sub_list(vlink(post_break(p)));
- free_sub_list(vlink(no_break(p)));
- break;
- case rule_node:
- case kern_node:
- case penalty_node:
- case math_node:
- break;
- case glue_spec_node:
- /* this allows free-ing of lua-allocated glue specs */
-//if (valid_node(p)) {
-// free_node(p, subtype(p));
-//}
-// return ;
- break ;
- case dir_node:
- case local_par_node:
- case boundary_node:
- break;
- case whatsit_node:
- w = subtype(p) ;
- if (w >= backend_first_pdf_whatsit) {
- flush_node_wrapup_pdf(p);
- } else if (w >= backend_first_dvi_whatsit) {
- flush_node_wrapup_dvi(p);
- } else {
- flush_node_wrapup_core(p);
- }
- break;
- case ins_node:
- flush_node_list(ins_ptr(p));
- break;
- case margin_kern_node:
- flush_node(margin_char(p));
- break;
- case mark_node:
- delete_token_ref(mark_ptr(p));
- break;
- case adjust_node:
- flush_node_list(adjust_ptr(p));
- break;
- case style_node: /* nothing to do */
- break;
- case choice_node:
- free_sub_list(display_mlist(p));
- free_sub_list(text_mlist(p));
- free_sub_list(script_mlist(p));
- free_sub_list(script_script_mlist(p));
- break;
- case simple_noad:
- free_sub_list(nucleus(p));
- free_sub_list(subscr(p));
- free_sub_list(supscr(p));
- break;
- case radical_noad:
- free_sub_list(nucleus(p));
- free_sub_list(subscr(p));
- free_sub_list(supscr(p));
- free_sub_node(left_delimiter(p));
- free_sub_list(degree(p));
- break;
- case accent_noad:
- free_sub_list(nucleus(p));
- free_sub_list(subscr(p));
- free_sub_list(supscr(p));
- free_sub_list(top_accent_chr(p));
- free_sub_list(bot_accent_chr(p));
- free_sub_list(overlay_accent_chr(p));
- break;
- case fence_noad:
- free_sub_list(delimiter(p));
- break;
- case delim_node: /* nothing to do */
- case math_char_node:
- case math_text_char_node:
- break;
- case sub_box_node:
- case sub_mlist_node:
- free_sub_list(math_list(p));
- break;
- case fraction_noad:
- free_sub_list(numerator(p));
- free_sub_list(denominator(p));
- free_sub_node(left_delimiter(p));
- free_sub_node(right_delimiter(p));
- break;
- case pseudo_file_node:
- free_sub_list(pseudo_lines(p));
- break;
- case pseudo_line_node:
- case shape_node:
- free_node(p, subtype(p));
- return;
- break;
- case align_stack_node:
- case span_node:
- case movement_node:
- case if_node:
- case nesting_node:
- case unhyphenated_node:
- case hyphenated_node:
- case delta_node:
- case passive_node:
- case inserting_node:
- case split_up_node:
- case expr_node:
- case attribute_node:
- case attribute_list_node:
- case temp_node:
- break;
- default:
- formatted_error("nodes","flushing weird node type %d", type(p));
- return;
- }
- if (nodetype_has_attributes(type(p))) {
- delete_attribute_ref(node_attr(p));
- lua_properties_reset(p);
- }
- free_node(p, get_node_size(type(p), subtype(p)));
- return;
-}
-
-@ @c
-void flush_node_list(halfword pp)
-{ /* erase list of nodes starting at |p| */
- register halfword p = pp;
- if (p == null) /* legal, but no-op */
- return;
- if (free_error(p))
- return;
- lua_properties_push; /* saves stack and time */
- while (p != null) {
- register halfword q = vlink(p);
- flush_node(p);
- p = q;
- }
- lua_properties_pop; /* saves stack and time */
-}
-
-@ @c
-static void check_node_wrapup_core(halfword p)
-{
- switch (subtype(p)) {
- /* frontend code */
- case special_node:
- check_token_ref(p);
- break;
- case user_defined_node:
- switch (user_node_type(p)) {
- case 'a':
- check_attribute_ref(user_node_value(p));
- break;
- case 't':
- check_token_ref(p);
- break;
- case 'n':
- dorangetest(p, user_node_value(p), var_mem_max);
- break;
- case 's':
- case 'd':
- break;
- default:
- confusion("unknown user node type");
- break;
- }
- break;
- case open_node:
- case write_node:
- case close_node:
- case save_pos_node:
- break;
- }
-}
-
-void check_node_wrapup_dvi(halfword p)
-{
-}
-
-void check_node_wrapup_pdf(halfword p)
-{
- switch (subtype(p)) {
- case pdf_literal_node:
- if (pdf_literal_type(p) == normal)
- check_token_ref(p);
- break;
- case pdf_colorstack_node:
- if (pdf_colorstack_cmd(p) <= colorstack_data)
- check_token_ref(p);
- break;
- case pdf_setmatrix_node:
- check_token_ref(p);
- break;
- case late_lua_node:
- if (late_lua_name(p) > 0)
- check_token_ref(p);
- if (late_lua_type(p) == normal)
- check_token_ref(p);
- break;
- case pdf_annot_node:
- check_token_ref(p);
- break;
- case pdf_start_link_node:
- if (pdf_link_attr(p) != null)
- check_token_ref(p);
- check_action_ref(pdf_link_action(p));
- break;
- case pdf_dest_node:
- if (pdf_dest_named_id(p) > 0)
- check_token_ref(p);
- break;
- case pdf_thread_node:
- case pdf_start_thread_node:
- if (pdf_thread_named_id(p) > 0)
- check_token_ref(p);
- if (pdf_thread_attr(p) != null)
- check_token_ref(p);
- break;
- case pdf_save_node:
- case pdf_restore_node:
- case pdf_refobj_node:
- case pdf_end_link_node:
- case pdf_end_thread_node:
- break;
- default:
- confusion("wrapup pdf nodes");
- break;
- }
-}
-
-void check_node(halfword p)
-{
- halfword w ;
- switch (type(p)) {
- case glyph_node:
- dorangetest(p, lig_ptr(p), var_mem_max);
- break;
- case glue_node:
- dorangetest(p, leader_ptr(p), var_mem_max);
- break;
- case hlist_node:
- case vlist_node:
- case unset_node:
- case align_record_node:
- dorangetest(p, list_ptr(p), var_mem_max);
- break;
- case ins_node:
- dorangetest(p, ins_ptr(p), var_mem_max);
- break;
- case whatsit_node:
- w = subtype(p) ;
- if (w >= backend_first_pdf_whatsit) {
- check_node_wrapup_pdf(p);
- } else if (w >= backend_first_dvi_whatsit) {
- check_node_wrapup_dvi(p);
- } else {
- check_node_wrapup_core(p);
- }
- break;
- case margin_kern_node:
- check_node(margin_char(p));
- break;
- case math_node:
- break;
- case disc_node:
- dorangetest(p, vlink(pre_break(p)), var_mem_max);
- dorangetest(p, vlink(post_break(p)), var_mem_max);
- dorangetest(p, vlink(no_break(p)), var_mem_max);
- break;
- case adjust_node:
- dorangetest(p, adjust_ptr(p), var_mem_max);
- break;
- case pseudo_file_node:
- dorangetest(p, pseudo_lines(p), var_mem_max);
- break;
- case pseudo_line_node:
- case shape_node:
- break;
- case choice_node:
- dorangetest(p, display_mlist(p), var_mem_max);
- dorangetest(p, text_mlist(p), var_mem_max);
- dorangetest(p, script_mlist(p), var_mem_max);
- dorangetest(p, script_script_mlist(p), var_mem_max);
- break;
- case fraction_noad:
- dorangetest(p, numerator(p), var_mem_max);
- dorangetest(p, denominator(p), var_mem_max);
- dorangetest(p, left_delimiter(p), var_mem_max);
- dorangetest(p, right_delimiter(p), var_mem_max);
- break;
- case simple_noad:
- dorangetest(p, nucleus(p), var_mem_max);
- dorangetest(p, subscr(p), var_mem_max);
- dorangetest(p, supscr(p), var_mem_max);
- break;
- case radical_noad:
- dorangetest(p, nucleus(p), var_mem_max);
- dorangetest(p, subscr(p), var_mem_max);
- dorangetest(p, supscr(p), var_mem_max);
- dorangetest(p, degree(p), var_mem_max);
- dorangetest(p, left_delimiter(p), var_mem_max);
- break;
- case accent_noad:
- dorangetest(p, nucleus(p), var_mem_max);
- dorangetest(p, subscr(p), var_mem_max);
- dorangetest(p, supscr(p), var_mem_max);
- dorangetest(p, top_accent_chr(p), var_mem_max);
- dorangetest(p, bot_accent_chr(p), var_mem_max);
- dorangetest(p, overlay_accent_chr(p), var_mem_max);
- break;
- case fence_noad:
- dorangetest(p, delimiter(p), var_mem_max);
- break;
- /*
- case rule_node:
- case kern_node:
- case penalty_node:
- case mark_node:
- case style_node:
- case attribute_list_node:
- case attribute_node:
- case glue_spec_node:
- case temp_node:
- case align_stack_node:
- case movement_node:
- case if_node:
- case nesting_node:
- case span_node:
- case unhyphenated_node:
- case hyphenated_node:
- case delta_node:
- case passive_node:
- case expr_node:
- case dir_node:
- case boundary_node:
- case local_par_node:
- break;
- default:
- fprintf(stdout, "check_node: type is %d\n", type(p));
- */
- }
-}
-
-@ @c
-halfword fix_node_list(halfword head)
-{
- halfword next, tail;
- if (head == null)
- return null;
- tail = head;
- next = vlink(head);
- while (next != null) {
- alink(next) = tail;
- tail = next;
- next = vlink(tail);
- }
- return tail;
-}
-
-@ @c
-halfword get_node(int s)
-{
- register halfword r;
-
- if (s < MAX_CHAIN_SIZE) {
- r = free_chain[s];
- if (r != null) {
- free_chain[s] = vlink(r);
-#ifdef CHECK_NODE_USAGE
- varmem_sizes[r] = (char) s;
-#endif
- vlink(r) = null;
- var_used += s; /* maintain usage statistics */
- return r;
- }
- /* this is the end of the 'inner loop' */
- return slow_get_node(s);
- } else {
- normal_error("nodes","there is a problem in getting a node, case 1");
- return null;
- }
-}
-
-@ @c
-void free_node(halfword p, int s)
-{
- if (p <= my_prealloc) {
- formatted_error("nodes", "node number %d of type %d should not be freed", (int) p, type(p));
- return;
- }
-#ifdef CHECK_NODE_USAGE
- varmem_sizes[p] = 0;
-#endif
- if (s < MAX_CHAIN_SIZE) {
- vlink(p) = free_chain[s];
- free_chain[s] = p;
- } else {
- /* todo ? it is perhaps possible to merge this node with an existing rover */
- node_size(p) = s;
- vlink(p) = rover;
- while (vlink(rover) != vlink(p)) {
- rover = vlink(rover);
- }
- vlink(rover) = p;
- }
- /* maintain statistics */
- var_used -= s;
-}
-
-@ @c
-static void free_node_chain(halfword q, int s)
-{
- register halfword p = q;
- while (vlink(p) != null) {
-#ifdef CHECK_NODE_USAGE
- varmem_sizes[p] = 0;
-#endif
- var_used -= s;
- p = vlink(p);
- }
- var_used -= s;
-#ifdef CHECK_NODE_USAGE
- varmem_sizes[p] = 0;
-#endif
- vlink(p) = free_chain[s];
- free_chain[s] = q;
-}
-
-@ At the start of the node memory area we reserve some special nodes,
-for instance frequently used glue specifications. We could as well just
-use new_glue here but for the moment we stick to the traditional approach.
-
-@c
-#define initialize_glue(n,wi,st,sh,sto,sho) \
- vlink(n) = null; \
- type(n) = glue_spec_node; \
- width(n) = wi; \
- stretch(n) = st; \
- shrink(n) = sh; \
- stretch_order(n) = sto; \
- shrink_order(n) = sho;
-
-#define initialize_whatever(n,t) \
- vinfo(n) = 0; \
- type(n) = t; \
- vlink(n) = null; \
- alink(n) = null;
-
-#define initialize_point(n) \
- type(n) = glyph_node; \
- subtype(n) = 0; \
- vlink(n) = null; \
- vinfo(n + 1) = null; \
- alink(n) = null; \
- font(n) = 0; \
- character(n) = '.'; \
- vinfo(n + 3) = 0; \
- vlink(n + 3) = 0; \
- vinfo(n + 4) = 0; \
- vlink(n + 4) = 0;
-
-void init_node_mem(int t)
-{
- my_prealloc = var_mem_stat_max;
-
- varmem = (memory_word *) realloc((void *) varmem, sizeof(memory_word) * (unsigned) t);
- if (varmem == NULL) {
- overflow("node memory size", (unsigned) var_mem_max);
- }
- memset((void *) (varmem), 0, (unsigned) t * sizeof(memory_word));
-#ifdef CHECK_NODE_USAGE
- varmem_sizes = (char *) realloc(varmem_sizes, sizeof(char) * (unsigned) t);
- if (varmem_sizes == NULL) {
- overflow("node memory size", (unsigned) var_mem_max);
- }
- memset((void *) varmem_sizes, 0, sizeof(char) * (unsigned) t);
-#endif
- var_mem_max = t;
- rover = var_mem_stat_max + 1;
- vlink(rover) = rover;
- node_size(rover) = (t - rover);
- var_used = 0;
-
- /* initialize static glue specs */
-
- initialize_glue(zero_glue,0,0,0,0,0);
- initialize_glue(sfi_glue,0,0,0,sfi,0);
- initialize_glue(fil_glue,0,unity,0,fil,0);
- initialize_glue(fill_glue,0,unity,0,fill,0);
- initialize_glue(ss_glue,0,unity,unity,fil,fil);
- initialize_glue(fil_neg_glue,0,-unity,0,fil,0);
-
- /* initialize node list heads */
-
- initialize_whatever(page_ins_head,temp_node);
- initialize_whatever(contrib_head,temp_node);
- initialize_whatever(page_head,temp_node);
- initialize_whatever(temp_head,temp_node);
- initialize_whatever(hold_head,temp_node);
- initialize_whatever(adjust_head,temp_node);
- initialize_whatever(pre_adjust_head,temp_node);
- initialize_whatever(align_head,temp_node);
-
- initialize_whatever(active,unhyphenated_node);
- initialize_whatever(end_span,span_node);
-
- initialize_point(begin_point);
- initialize_point(end_point);
-}
-
-@ @c
-void dump_node_mem(void)
-{
- dump_int(var_mem_max);
- dump_int(rover);
- dump_things(varmem[0], var_mem_max);
-#ifdef CHECK_NODE_USAGE
- dump_things(varmem_sizes[0], var_mem_max);
-#endif
- dump_things(free_chain[0], MAX_CHAIN_SIZE);
- dump_int(var_used);
- dump_int(my_prealloc);
-}
-
-@ it makes sense to enlarge the varmem array immediately
-@c
-
-void undump_node_mem(void)
-{
- int x;
- undump_int(x);
- undump_int(rover);
- var_mem_max = (x < 100000 ? 100000 : x);
- varmem = xmallocarray(memory_word, (unsigned) var_mem_max);
- undump_things(varmem[0], x);
-#ifdef CHECK_NODE_USAGE
- varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
- memset((void *) varmem_sizes, 0, (unsigned) var_mem_max * sizeof(char));
- undump_things(varmem_sizes[0], x);
-#endif
- undump_things(free_chain[0], MAX_CHAIN_SIZE);
- undump_int(var_used);
- undump_int(my_prealloc);
- if (var_mem_max > x) {
- /* todo ? it is perhaps possible to merge the new node with an existing rover */
- vlink(x) = rover;
- node_size(x) = (var_mem_max - x);
- while (vlink(rover) != vlink(x)) {
- rover = vlink(rover);
- }
- vlink(rover) = x;
- }
-}
-
-@ @c
-halfword slow_get_node(int s)
-{
- register int t;
-
- RETRY:
- t = node_size(rover);
- if (vlink(rover) < var_mem_max && vlink(rover) != 0) {
- if (t > s) {
- /* allocating from the bottom helps decrease page faults */
- register halfword r = rover;
- rover += s;
- vlink(rover) = vlink(r);
- node_size(rover) = node_size(r) - s;
- if (vlink(rover) != r) { /* list is longer than one */
- halfword q = r;
- while (vlink(q) != r) {
- q = vlink(q);
- }
- vlink(q) += s;
- } else {
- vlink(rover) += s;
- }
- if (vlink(rover) < var_mem_max) {
-#ifdef CHECK_NODE_USAGE
- varmem_sizes[r] = (char) (s > 127 ? 127 : s);
-#endif
- vlink(r) = null;
- var_used += s; /* maintain usage statistics */
- return r; /* this is the only exit */
- } else {
- normal_error("nodes","there is a problem in getting a node, case 2");
- return null;
- }
- } else {
- /* attempt to keep the free list small */
- int x;
- if (vlink(rover) != rover) {
- if (t < MAX_CHAIN_SIZE) {
- halfword l = vlink(rover);
- vlink(rover) = free_chain[t];
- free_chain[t] = rover;
- rover = l;
- while (vlink(l) != free_chain[t]) {
- l = vlink(l);
- }
- vlink(l) = rover;
- goto RETRY;
- } else {
- halfword l = rover;
- while (vlink(rover) != l) {
- if (node_size(rover) > s) {
- goto RETRY;
- }
- rover = vlink(rover);
- }
- }
- }
- /* if we are still here, it was apparently impossible to get a match */
- x = (var_mem_max >> 2) + s;
- varmem = (memory_word *) realloc((void *) varmem, sizeof(memory_word) * (unsigned) (var_mem_max + x));
- if (varmem == NULL) {
- overflow("node memory size", (unsigned) var_mem_max);
- }
- memset((void *) (varmem + var_mem_max), 0, (unsigned) x * sizeof(memory_word));
-#ifdef CHECK_NODE_USAGE
- varmem_sizes = (char *) realloc(varmem_sizes, sizeof(char) * (unsigned) (var_mem_max + x));
- if (varmem_sizes == NULL) {
- overflow("node memory size", (unsigned) var_mem_max);
- }
- memset((void *) (varmem_sizes + var_mem_max), 0, (unsigned) (x) * sizeof(char));
-#endif
- /* todo ? it is perhaps possible to merge the new memory with an existing rover */
- vlink(var_mem_max) = rover;
- node_size(var_mem_max) = x;
- while (vlink(rover) != vlink(var_mem_max)) {
- rover = vlink(rover);
- }
- vlink(rover) = var_mem_max;
- rover = var_mem_max;
- var_mem_max += x;
- goto RETRY;
- }
- } else {
- normal_error("nodes","there is a problem in getting a node, case 3");
- return null;
- }
-}
-
-@ @c
-char *sprint_node_mem_usage(void)
-{
- char *s;
-#ifdef CHECK_NODE_USAGE
- char *ss;
- int i;
- int b = 0;
- char msg[256];
- int node_counts[last_normal_node + last_whatsit_node + 2] = { 0 };
- s = strdup("");
- for (i = (var_mem_max - 1); i > my_prealloc; i--) {
- if (varmem_sizes[i] > 0) {
- if (type(i) > last_normal_node + last_whatsit_node) {
- node_counts[last_normal_node + last_whatsit_node + 1]++;
- } else if (type(i) == whatsit_node) {
- node_counts[(subtype(i) + last_normal_node + 1)]++;
- } else {
- node_counts[type(i)]++;
- }
- }
- }
- for (i = 0; i < last_normal_node + last_whatsit_node + 2; i++) {
- if (node_counts[i] > 0) {
- int j =
- (i > (last_normal_node + 1) ? (i - last_normal_node - 1) : 0);
- snprintf(msg, 255, "%s%d %s", (b ? ", " : ""), (int) node_counts[i],
- get_node_name((i > last_normal_node ? whatsit_node : i), j));
- ss = xmalloc((unsigned) (strlen(s) + strlen(msg) + 1));
- strcpy(ss, s);
- strcat(ss, msg);
- free(s);
- s = ss;
- b = 1;
- }
- }
-#else
- s = strdup("");
-#endif
- return s;
-}
-
-@ @c
-halfword list_node_mem_usage(void)
-{
- halfword q = null;
-#ifdef CHECK_NODE_USAGE
- halfword p = null;
- halfword i, j;
- char *saved_varmem_sizes = xmallocarray(char, (unsigned) var_mem_max);
- memcpy(saved_varmem_sizes, varmem_sizes, (size_t) var_mem_max);
- for (i = my_prealloc + 1; i < (var_mem_max - 1); i++) {
- if (saved_varmem_sizes[i] > 0) {
- j = copy_node(i);
- if (p == null) {
- q = j;
- } else {
- vlink(p) = j;
- }
- p = j;
- }
- }
- free(saved_varmem_sizes);
-#endif
- return q;
-}
-
-@ @c
-void print_node_mem_stats(void)
-{
- int i, b;
- halfword j;
- char msg[256];
- char *s;
- int free_chain_counts[MAX_CHAIN_SIZE] = { 0 };
- snprintf(msg, 255, " %d words of node memory still in use:", (int) (var_used + my_prealloc));
- tprint_nl(msg);
- s = sprint_node_mem_usage();
- tprint_nl(" ");
- tprint(s);
- free(s);
- tprint(" nodes");
- tprint_nl(" avail lists: ");
- b = 0;
- for (i = 1; i < MAX_CHAIN_SIZE; i++) {
- for (j = free_chain[i]; j != null; j = vlink(j))
- free_chain_counts[i]++;
- if (free_chain_counts[i] > 0) {
- snprintf(msg, 255, "%s%d:%d", (b ? "," : ""), i, (int) free_chain_counts[i]);
- tprint(msg);
- b = 1;
- }
- }
- /* newline, if needed */
- print_nlp();
-}
-
-/* this belongs in the web but i couldn't find the correct syntactic place */
-
-halfword new_span_node(halfword n, int s, scaled w)
-{
- halfword p = new_node(span_node, 0);
- span_link(p) = n;
- span_span(p) = s;
- width(p) = w;
- return p;
-}
-
-@* Attribute stuff.
-
-@c
-static halfword new_attribute_node(unsigned int i, int v)
-{
- register halfword r = get_node(attribute_node_size);
- type(r) = attribute_node;
- attribute_id(r) = (halfword) i;
- attribute_value(r) = v;
- /* not used but nicer in print */
- subtype(r) = 0;
- return r;
-}
-
-@ @c
-halfword copy_attribute_list(halfword n)
-{
- halfword q = get_node(attribute_node_size);
- register halfword p = q;
- type(p) = attribute_list_node;
- attr_list_ref(p) = 0;
- n = vlink(n);
- while (n != null) {
- register halfword r = get_node(attribute_node_size);
- /* the link will be fixed automatically in the next loop */
- (void) memcpy((void *) (varmem + r), (void *) (varmem + n),
- (sizeof(memory_word) * attribute_node_size));
- vlink(p) = r;
- p = r;
- n = vlink(n);
- }
- return q;
-}
-
-@ @c
-void update_attribute_cache(void)
-{
- halfword p;
- register int i;
- attr_list_cache = get_node(attribute_node_size);
- type(attr_list_cache) = attribute_list_node;
- attr_list_ref(attr_list_cache) = 0;
- p = attr_list_cache;
- for (i = 0; i <= max_used_attr; i++) {
- register int v = attribute(i);
- if (v > UNUSED_ATTRIBUTE) {
- register halfword r = new_attribute_node((unsigned) i, v);
- vlink(p) = r;
- p = r;
- }
- }
- if (vlink(attr_list_cache) == null) {
- free_node(attr_list_cache, attribute_node_size);
- attr_list_cache = null;
- }
- return;
-}
-
-@ @c
-void build_attribute_list(halfword b)
-{
- if (max_used_attr >= 0) {
- if (attr_list_cache == cache_disabled|| attr_list_cache == null) {
- update_attribute_cache();
- if (attr_list_cache == null)
- return;
- }
- attr_list_ref(attr_list_cache)++;
- node_attr(b) = attr_list_cache;
- }
-}
-
-@ @c
-halfword current_attribute_list(void)
-{
- if (max_used_attr >= 0) {
- if (attr_list_cache == cache_disabled) {
- update_attribute_cache();
- }
- return attr_list_cache ;
- }
- return null ;
-}
-
-
-@ @c
-void reassign_attribute(halfword n, halfword new)
-{
- halfword old;
- old = node_attr(n);
- if (new == null) {
- /* there is nothing to assign but we need to check for an old value */
- if (old != null)
- delete_attribute_ref(old); /* also nulls attr field of n */
- } else if (old == null) {
- /* nothing is assigned so we just do that now */
- assign_attribute_ref(n,new);
- } else if (old != new) {
- /* something is assigned so we need to clean up and assign then */
- delete_attribute_ref(old);
- assign_attribute_ref(n,new);
- }
- /* else: same value so there is no need to assign and change the refcount */
- node_attr(n) = new ;
-}
-
-@ @c
-void delete_attribute_ref(halfword b)
-{
- if (b != null) {
- if (type(b) == attribute_list_node){
- attr_list_ref(b)--;
- if (attr_list_ref(b) == 0) {
- if (b == attr_list_cache)
- attr_list_cache = cache_disabled;
- free_node_chain(b, attribute_node_size);
- }
- /* maintain sanity */
- if (attr_list_ref(b) < 0) {
- attr_list_ref(b) = 0;
- }
- } else {
- normal_error("nodes","trying to delete an attribute reference of a non attribute node");
- }
- }
-}
-
-void reset_node_properties(halfword b)
-{
- if (b != null) {
- lua_properties_reset(b);
- }
-}
-
-@ |p| is an attr list head, or zero
-@c
-halfword do_set_attribute(halfword p, int i, int val)
-{
- register halfword q;
- register int j = 0;
- if (p == null) { /* add a new head \& node */
- q = get_node(attribute_node_size);
- type(q) = attribute_list_node;
- attr_list_ref(q) = 1;
- p = new_attribute_node((unsigned) i, val);
- vlink(q) = p;
- return q;
- }
- q = p;
- if (vlink(p) != null) {
- while (vlink(p) != null) {
- int t = attribute_id(vlink(p));
- if (t == i && attribute_value(vlink(p)) == val)
- return q; /* no need to do anything */
- if (t >= i)
- break;
- j++;
- p = vlink(p);
- }
-
- p = q;
- while (j-- > 0)
- p = vlink(p);
- if (attribute_id(vlink(p)) == i) {
- attribute_value(vlink(p)) = val;
- } else { /* add a new node */
- halfword r = new_attribute_node((unsigned) i, val);
- vlink(r) = vlink(p);
- vlink(p) = r;
- }
- return q;
- } else {
- normal_error("nodes","trying to set an attribute fails, case 1");
- return null ;
- }
-}
-
-@ @c
-void set_attribute(halfword n, int i, int val)
-{
- register halfword p;
- register int j = 0;
- /* not all nodes can have an attribute list */
- if (!nodetype_has_attributes(type(n)))
- return;
- /* if we have no list, we create one and quit */
- p = node_attr(n);
- if (p == null) { /* add a new head \& node */
- p = get_node(attribute_node_size);
- type(p) = attribute_list_node;
- attr_list_ref(p) = 1;
- node_attr(n) = p;
- p = new_attribute_node((unsigned) i, val);
- vlink(node_attr(n)) = p;
- return;
- }
- /* we check if we have this attribute already and quit if the value stays the same */
- if (vlink(p) != null) {
- while (vlink(p) != null) {
- int t = attribute_id(vlink(p));
- if (t == i && attribute_value(vlink(p)) == val)
- return;
- if (t >= i)
- break;
- j++;
- p = vlink(p);
- }
- /* j has now the position (if found) .. we assume a sorted list ! */
- p = node_attr(n);
-
- if (attr_list_ref(p) == 0 ) {
- /* the list is invalid i.e. freed already */
- formatted_warning("nodes","node %d has an attribute list that is free already, case 1",(int) n);
- /* the still dangling list gets ref count 1 */
- attr_list_ref(p) = 1;
- } else if (attr_list_ref(p) == 1) {
- /* this can really happen HH-LS */
- if (p == attr_list_cache) {
- /* we can invalidate the cache setting */
- /* attr_list_cache = cache_disabled */
- /* or save the list, as done below */
- p = copy_attribute_list(p);
- node_attr(n) = p;
- /* the copied list gets ref count 1 */
- attr_list_ref(p) = 1;
- }
- } else {
- /* the list is used multiple times so we make a copy */
- p = copy_attribute_list(p);
- /* we decrement the ref count or the original */
- delete_attribute_ref(node_attr(n));
- node_attr(n) = p;
- /* the copied list gets ref count 1 */
- attr_list_ref(p) = 1;
- }
-
-
- /* we go to position j in the list */
- while (j-- > 0)
- p = vlink(p);
- /* if we have a hit we just set the value otherwise we add a new node */
- if (attribute_id(vlink(p)) == i) {
- attribute_value(vlink(p)) = val;
- } else { /* add a new node */
- halfword r = new_attribute_node((unsigned) i, val);
- vlink(r) = vlink(p);
- vlink(p) = r;
- }
- } else {
- normal_error("nodes","trying to set an attribute fails, case 2");
- }
-}
-
-@ @c
-int unset_attribute(halfword n, int i, int val)
-{
- register halfword p;
- register int t;
- register int j = 0;
-
- if (!nodetype_has_attributes(type(n)))
- return null;
- p = node_attr(n);
- if (p == null)
- return UNUSED_ATTRIBUTE;
- if (attr_list_ref(p) == 0) {
- formatted_warning("nodes","node %d has an attribute list that is free already, case 2", (int) n);
- return UNUSED_ATTRIBUTE;
- }
- if (vlink(p) != null) {
- while (vlink(p) != null) {
- t = attribute_id(vlink(p));
- if (t > i)
- return UNUSED_ATTRIBUTE;
- if (t == i) {
- p = vlink(p);
- break;
- }
- j++;
- p = vlink(p);
- }
- if (attribute_id(p) != i)
- return UNUSED_ATTRIBUTE;
- /* if we are still here, the attribute exists */
- p = node_attr(n);
- if (attr_list_ref(p) > 1 || p == attr_list_cache) {
- halfword q = copy_attribute_list(p);
- if (attr_list_ref(p) > 1) {
- delete_attribute_ref(node_attr(n));
- }
- attr_list_ref(q) = 1;
- node_attr(n) = q;
- }
- p = vlink(node_attr(n));
- while (j-- > 0)
- p = vlink(p);
- t = attribute_value(p);
- if (val == UNUSED_ATTRIBUTE || t == val) {
- attribute_value(p) = UNUSED_ATTRIBUTE;
- }
- return t;
- } else {
- normal_error("nodes","trying to unset an attribute fails");
- return null;
- }
-}
-
-@ @c
-int has_attribute(halfword n, int i, int val)
-{
- register halfword p;
- if (!nodetype_has_attributes(type(n)))
- return UNUSED_ATTRIBUTE;
- p = node_attr(n);
- if (p == null || vlink(p) == null)
- return UNUSED_ATTRIBUTE;
- p = vlink(p);
- while (p != null) {
- if (attribute_id(p) == i) {
- int ret = attribute_value(p);
- if (val == UNUSED_ATTRIBUTE || val == ret)
- return ret;
- return UNUSED_ATTRIBUTE;
- } else if (attribute_id(p) > i) {
- return UNUSED_ATTRIBUTE;
- }
- p = vlink(p);
- }
- return UNUSED_ATTRIBUTE;
-}
-
-@ @c
-void print_short_node_contents(halfword p)
-{
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case ins_node:
- case whatsit_node:
- case mark_node:
- case adjust_node:
- case unset_node:
- print_char('[');
- print_char(']');
- break;
- case rule_node:
- print_char('|');
- break;
- case glue_node:
- if (! glue_is_zero(p))
- print_char(' ');
- break;
- case math_node:
- print_char('$');
- break;
- case disc_node:
- short_display(vlink(pre_break(p)));
- short_display(vlink(post_break(p)));
- break;
- }
-}
-
-@ @c
-static void show_pdftex_whatsit_rule_spec(int p)
-{
- tprint("(");
- print_rule_dimen(height(p));
- print_char('+');
- print_rule_dimen(depth(p));
- tprint(")x");
- print_rule_dimen(width(p));
-}
-
-@ Each new type of node that appears in our data structure must be capable
-of being displayed, copied, destroyed, and so on. The routines that we
-need for write-oriented whatsits are somewhat like those for mark nodes;
-other extensions might, of course, involve more subtlety here.
-
-@c
-static void print_write_whatsit(const char *s, pointer p)
-{
- tprint_esc(s);
- if (write_stream(p) < 16)
- print_int(write_stream(p));
- else if (write_stream(p) == 16)
- print_char('*');
- else
- print_char('-');
-}
-
-@ @c
-static void show_node_wrapup_core(int p)
-{
- switch (subtype(p)) {
- case open_node:
- print_write_whatsit("openout", p);
- print_char('=');
- print_file_name(open_name(p), open_area(p), open_ext(p));
- break;
- case write_node:
- print_write_whatsit("write", p);
- print_mark(write_tokens(p));
- break;
- case close_node:
- print_write_whatsit("closeout", p);
- break;
- case special_node:
- tprint_esc("special");
- print_mark(write_tokens(p));
- break;
- case late_lua_node:
- show_late_lua(p);
- break;
- case save_pos_node:
- tprint_esc("savepos");
- break;
- case user_defined_node:
- tprint_esc("whatsit");
- print_int(user_node_id(p));
- print_char('=');
- switch (user_node_type(p)) {
- case 'a':
- tprint("<>");
- break;
- case 'n':
- tprint("[");
- show_node_list(user_node_value(p));
- tprint("]");
- break;
- case 's':
- print_char('"');
- print(user_node_value(p));
- print_char('"');
- break;
- case 't':
- print_mark(user_node_value(p));
- break;
- default: /* only 'd' */
- print_int(user_node_value(p));
- break;
- }
- break;
- }
-}
-
-void show_node_wrapup_dvi(int p)
-{
-}
-
-void show_node_wrapup_pdf(int p)
-{
- switch (subtype(p)) {
- case pdf_literal_node:
- show_pdf_literal(p);
- break;
- case pdf_colorstack_node:
- tprint_esc("pdfcolorstack ");
- print_int(pdf_colorstack_stack(p));
- switch (pdf_colorstack_cmd(p)) {
- case colorstack_set:
- tprint(" set ");
- break;
- case colorstack_push:
- tprint(" push ");
- break;
- case colorstack_pop:
- tprint(" pop");
- break;
- case colorstack_current:
- tprint(" current");
- break;
- default:
- confusion("colorstack");
- break;
- }
- if (pdf_colorstack_cmd(p) <= colorstack_data)
- print_mark(pdf_colorstack_data(p));
- break;
- case pdf_setmatrix_node:
- tprint_esc("pdfsetmatrix");
- print_mark(pdf_setmatrix_data(p));
- break;
- case pdf_save_node:
- tprint_esc("pdfsave");
- break;
- case pdf_restore_node:
- tprint_esc("pdfrestore");
- break;
- case pdf_refobj_node:
- tprint_esc("pdfrefobj");
- if (obj_obj_is_stream(static_pdf, pdf_obj_objnum(p))) {
- if (obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
- tprint(" attr");
- lua_rawgeti(Luas, LUA_REGISTRYINDEX,
- obj_obj_stream_attr(static_pdf, pdf_obj_objnum(p)));
- print_char(' ');
- tprint((const char *) lua_tostring(Luas, -1));
- lua_pop(Luas, 1);
- }
- tprint(" stream");
- }
- if (obj_obj_is_file(static_pdf, pdf_obj_objnum(p)))
- tprint(" file");
- if (obj_obj_data(static_pdf, pdf_obj_objnum(p)) != LUA_NOREF) {
- lua_rawgeti(Luas, LUA_REGISTRYINDEX,
- obj_obj_data(static_pdf, pdf_obj_objnum(p)));
- print_char(' ');
- tprint((const char *) lua_tostring(Luas, -1));
- lua_pop(Luas, 1);
- }
- break;
- case pdf_annot_node:
- tprint_esc("pdfannot");
- show_pdftex_whatsit_rule_spec(p);
- print_mark(pdf_annot_data(p));
- break;
- case pdf_start_link_node:
- tprint_esc("pdfstartlink");
- show_pdftex_whatsit_rule_spec(p);
- if (pdf_link_attr(p) != null) {
- tprint(" attr");
- print_mark(pdf_link_attr(p));
- }
- tprint(" action");
- if (pdf_action_type(pdf_link_action(p)) == pdf_action_user) {
- tprint(" user");
- print_mark(pdf_action_tokens(pdf_link_action(p)));
- return;
- }
- if (pdf_action_file(pdf_link_action(p)) != null) {
- tprint(" file");
- print_mark(pdf_action_file(pdf_link_action(p)));
- }
- switch (pdf_action_type(pdf_link_action(p))) {
- case pdf_action_goto:
- if (pdf_action_named_id(pdf_link_action(p)) > 0) {
- tprint(" goto name");
- print_mark(pdf_action_id(pdf_link_action(p)));
- } else {
- tprint(" goto num");
- print_int(pdf_action_id(pdf_link_action(p)));
- }
- break;
- case pdf_action_page:
- tprint(" page");
- print_int(pdf_action_id(pdf_link_action(p)));
- print_mark(pdf_action_tokens(pdf_link_action(p)));
- break;
- case pdf_action_thread:
- if (pdf_action_named_id(pdf_link_action(p)) > 0) {
- tprint(" thread name");
- print_mark(pdf_action_id(pdf_link_action(p)));
- } else {
- tprint(" thread num");
- print_int(pdf_action_id(pdf_link_action(p)));
- }
- break;
- default:
- normal_error("pdf backend", "unknown action type for link");
- break;
- }
- break;
- case pdf_end_link_node:
- tprint_esc("pdfendlink");
- break;
- case pdf_dest_node:
- tprint_esc("pdfdest");
- if (pdf_dest_named_id(p) > 0) {
- tprint(" name");
- print_mark(pdf_dest_id(p));
- } else {
- tprint(" num");
- print_int(pdf_dest_id(p));
- }
- print_char(' ');
- switch (pdf_dest_type(p)) {
- case pdf_dest_xyz:
- tprint("xyz");
- if (pdf_dest_xyz_zoom(p) != null) {
- tprint(" zoom");
- print_int(pdf_dest_xyz_zoom(p));
- }
- break;
- case pdf_dest_fitbh:
- tprint("fitbh");
- break;
- case pdf_dest_fitbv:
- tprint("fitbv");
- break;
- case pdf_dest_fitb:
- tprint("fitb");
- break;
- case pdf_dest_fith:
- tprint("fith");
- break;
- case pdf_dest_fitv:
- tprint("fitv");
- break;
- case pdf_dest_fitr:
- tprint("fitr");
- show_pdftex_whatsit_rule_spec(p);
- break;
- case pdf_dest_fit:
- tprint("fit");
- break;
- default:
- tprint("unknown!");
- break;
- }
- break;
- case pdf_thread_node:
- case pdf_start_thread_node:
- if (subtype(p) == pdf_thread_node)
- tprint_esc("pdfthread");
- else
- tprint_esc("pdfstartthread");
- tprint("(");
- print_rule_dimen(height(p));
- print_char('+');
- print_rule_dimen(depth(p));
- tprint(")x");
- print_rule_dimen(width(p));
- if (pdf_thread_attr(p) != null) {
- tprint(" attr");
- print_mark(pdf_thread_attr(p));
- }
- if (pdf_thread_named_id(p) > 0) {
- tprint(" name");
- print_mark(pdf_thread_id(p));
- } else {
- tprint(" num");
- print_int(pdf_thread_id(p));
- }
- break;
- case pdf_end_thread_node:
- tprint_esc("pdfendthread");
- break;
- default:
- break;
- }
-}
-
-@ Now we are ready for |show_node_list| itself. This procedure has been
- written to be ``extra robust'' in the sense that it should not crash or get
- into a loop even if the data structures have been messed up by bugs in
- the rest of the program. You can safely call its parent routine
- |show_box(p)| for arbitrary values of |p| when you are debugging \TeX.
- However, in the presence of bad data, the procedure may
- fetch a |memory_word| whose variant is different from the way it was stored;
- for example, it might try to read |mem[p].hh| when |mem[p]|
- contains a scaled integer, if |p| is a pointer that has been
- clobbered or chosen at random.
-
-
-@ |str_room| need not be checked; see |show_box|
-
-@ Recursive calls on |show_node_list| therefore use the following pattern:
-@c
-#define node_list_display(A) do { \
- append_char('.'); \
- show_node_list(A); \
- flush_char(); \
-} while (0)
-
-#define node_list_display_x(A,B) do { \
- if ((B) != null) { \
- append_char('.'); \
- append_char(A); \
- append_char(' '); \
- show_node_list(B); \
- flush_char(); \
- flush_char(); \
- flush_char(); \
- } \
-} while (0)
-
-/* prints a node list symbolically */
-
-void show_node_list(int p)
-{
- int n = 0; /* the number of items already printed at this level */
- halfword w;
- real g; /* a glue ratio, as a floating point number */
- if ((int) cur_length > depth_threshold) {
- if (p > null)
- tprint(" []"); /* indicate that there's been some truncation */
- return;
- }
- while (p != null) {
- print_ln();
- print_current_string(); /* display the nesting history */
- if (tracing_online_par < -2)
- print_int(p);
- incr(n);
- if (n > breadth_max) { /* time to stop */
- tprint("etc.");
- return;
- }
- /* Display node |p| */
- if (is_char_node(p)) {
- print_font_and_char(p);
- if (is_ligature(p)) {
- /* Display ligature |p|; */
- tprint(" (ligature ");
- if (is_leftboundary(p))
- print_char('|');
- font_in_short_display = font(p);
- short_display(lig_ptr(p));
- if (is_rightboundary(p))
- print_char('|');
- print_char(')');
- }
- } else {
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case unset_node:
- /* Display box |p|; */
- if (type(p) == hlist_node)
- tprint_esc("h");
- else if (type(p) == vlist_node)
- tprint_esc("v");
- else
- tprint_esc("unset");
- tprint("box(");
- print_scaled(height(p));
- print_char('+');
- print_scaled(depth(p));
- tprint(")x");
- print_scaled(width(p));
- if (type(p) == unset_node) {
- /* Display special fields of the unset node |p|; */
- if (span_count(p) != min_quarterword) {
- tprint(" (");
- print_int(span_count(p) + 1);
- tprint(" columns)");
- }
- if (glue_stretch(p) != 0) {
- tprint(", stretch ");
- print_glue(glue_stretch(p), glue_order(p), NULL);
- }
- if (glue_shrink(p) != 0) {
- tprint(", shrink ");
- print_glue(glue_shrink(p), glue_sign(p), NULL);
- }
- } else {
- /* Display the value of |glue_set(p)| */
- /* The code will have to change in this place if |glue_ratio| is
- a structured type instead of an ordinary |real|. Note that this routine
- should avoid arithmetic errors even if the |glue_set| field holds an
- arbitrary random value. The following code assumes that a properly
- formed nonzero |real| number has absolute value $2^{20}$ or more when
- it is regarded as an integer; this precaution was adequate to prevent
- floating point underflow on the author's computer.
- */
-
- g = (real) (glue_set(p));
- if ((g != 0.0) && (glue_sign(p) != normal)) {
- tprint(", glue set ");
- if (glue_sign(p) == shrinking)
- tprint("- ");
- if (g > 20000.0 || g < -20000.0) {
- if (g > 0.0)
- print_char('>');
- else
- tprint("< -");
- print_glue(20000 * unity, glue_order(p), NULL);
- } else {
- print_glue(round(unity * g), glue_order(p), NULL);
- }
- }
-
- if (shift_amount(p) != 0) {
- tprint(", shifted ");
- print_scaled(shift_amount(p));
- }
- tprint(", direction ");
- print_dir(box_dir(p));
- }
- node_list_display(list_ptr(p)); /* recursive call */
- break;
- case rule_node:
- /* Display rule |p|; */
- if (subtype(p) == normal_rule) {
- tprint_esc("rule(");
- } else if (subtype(p) == empty_rule) {
- tprint_esc("norule(");
- } else if (subtype(p) == user_rule) {
- tprint_esc("userrule(");
- } else if (subtype(p) == box_rule) {
- tprint_esc("box(");
- } else if (subtype(p) == image_rule) {
- tprint_esc("image(");
- }
- print_rule_dimen(height(p));
- print_char('+');
- print_rule_dimen(depth(p));
- tprint(")x");
- print_rule_dimen(width(p));
- break;
- case ins_node:
- /* Display insertion |p|; */
- tprint_esc("insert");
- print_int(subtype(p));
- tprint(", natural size ");
- print_scaled(height(p));
- tprint("; split(");
- print_spec(split_top_ptr(p), NULL);
- print_char(',');
- print_scaled(depth(p));
- tprint("); float cost ");
- print_int(float_cost(p));
- node_list_display(ins_ptr(p)); /* recursive call */
- break;
- case dir_node:
- if (dir_dir(p) < 0) {
- tprint_esc("enddir");
- print_char(' ');
- print_dir(dir_dir(p) + dir_swap);
- } else {
- tprint_esc("begindir");
- print_char(' ');
- print_dir(dir_dir(p));
- }
- break;
- case local_par_node:
- tprint_esc("localpar");
- append_char('.');
- print_ln();
- print_current_string();
- tprint_esc("localinterlinepenalty");
- print_char('=');
- print_int(local_pen_inter(p));
- print_ln();
- print_current_string();
- tprint_esc("localbrokenpenalty");
- print_char('=');
- print_int(local_pen_broken(p));
- print_ln();
- print_current_string();
- tprint_esc("localleftbox");
- if (local_box_left(p) == null) {
- tprint("=null");
- } else {
- append_char('.');
- show_node_list(local_box_left(p));
- decr(cur_length);
- }
- print_ln();
- print_current_string();
- tprint_esc("localrightbox");
- if (local_box_right(p) == null) {
- tprint("=null");
- } else {
- append_char('.');
- show_node_list(local_box_right(p));
- decr(cur_length);
- }
- decr(cur_length);
- break;
- case boundary_node:
- if (subtype(p)==0) {
- tprint_esc("noboundary");
- } else {
- switch (subtype(p)) {
- case 1:
- tprint_esc("boundary");
- break;
- case 2:
- tprint_esc("protrusionboundary");
- break;
- case 3:
- tprint_esc("wordboundary");
- break;
- default:
- tprint_esc("boundary");
- print_char(':');
- print_int(subtype(p));
- break;
- }
- print_char('=');
- print_int(boundary_value(p));
- }
- break;
- case whatsit_node:
- w = subtype(p) ;
- if (w >= backend_first_pdf_whatsit) {
- show_node_wrapup_pdf(p);
- } else if (w >= backend_first_dvi_whatsit) {
- show_node_wrapup_dvi(p);
- } else {
- show_node_wrapup_core(p);
- }
- break;
- case glue_node:
- /* Display glue |p|; */
- if (subtype(p) >= a_leaders) {
- /* Display leaders |p|; */
- tprint_esc("");
- switch (subtype(p)) {
- case a_leaders:
- break;
- case c_leaders:
- print_char('c');
- break;
- case x_leaders:
- print_char('x');
- break;
- case g_leaders:
- print_char('g');
- break;
- default:
- normal_warning("nodes","weird glue leader subtype ignored");
- }
- tprint("leaders ");
- print_spec(p, NULL);
- node_list_display(leader_ptr(p)); /* recursive call */
- } else {
- tprint_esc("glue");
- if (subtype(p) != normal) {
- print_char('(');
- if ((subtype(p) - 1) < thin_mu_skip_code) {
- print_cmd_chr(assign_glue_cmd, glue_base + (subtype(p) - 1));
- } else if (subtype(p) < cond_math_glue) {
- print_cmd_chr(assign_mu_glue_cmd, glue_base + (subtype(p) - 1));
- } else if (subtype(p) == cond_math_glue) {
- tprint_esc("nonscript");
- } else {
- tprint_esc("mskip");
- }
- print_char(')');
- }
- if (subtype(p) != cond_math_glue) {
- print_char(' ');
- if (subtype(p) < cond_math_glue)
- print_spec(p, NULL);
- else
- print_spec(p, "mu");
- }
- }
- break;
- case margin_kern_node:
- tprint_esc("kern");
- print_scaled(width(p));
- if (subtype(p) == left_side)
- tprint(" (left margin)");
- else
- tprint(" (right margin)");
- break;
- case kern_node:
- /* Display kern |p|; */
- /* An ``explicit'' kern value is indicated implicitly by an explicit space. */
- if (subtype(p) != mu_glue) {
- tprint_esc("kern");
- /*
- if (subtype(p) != normal)
- print_char(' ');
- */
- print_scaled(width(p));
- if (subtype(p) == font_kern)
- tprint(" (font)");
- else if (subtype(p) == italic_kern)
- tprint(" (italic)");
- else if (subtype(p) == accent_kern)
- tprint(" (accent)");
- } else {
- tprint_esc("mkern");
- print_scaled(width(p));
- tprint("mu");
- }
- break;
- case math_node:
- /* Display math node |p|; */
- tprint_esc("math");
- if (subtype(p) == before)
- tprint("on");
- else
- tprint("off");
- if (!glue_is_zero(p)) {
- tprint(", glued ");
- print_spec(p, NULL);
- } else if (surround(p) != 0) {
- tprint(", surrounded ");
- print_scaled(surround(p));
- }
- break;
- case penalty_node:
- /* Display penalty |p|; */
- tprint_esc("penalty ");
- print_int(penalty(p));
- break;
- case disc_node:
- /* Display discretionary |p|; */
- /* The |post_break| list of a discretionary node is indicated by a prefixed
- `\.{\char'174}' instead of the `\..' before the |pre_break| list. */
- /* We're not compatible anyway so ...
- tprint_esc("discretionary");
- print_int(disc_penalty(p));
- print_char('|');
- if (vlink(no_break(p)) != null) {
- tprint(" replacing ");
- node_list_display(vlink(no_break(p)));
- }
- node_list_display(vlink(pre_break(p)));
- append_char('|');
- show_node_list(vlink(post_break(p)));
- flush_char();
- */
- tprint_esc("discretionary");
- tprint(" (penalty ");
- print_int(disc_penalty(p));
- print_char(')');
- node_list_display_x('<',vlink(pre_break(p)));
- node_list_display_x('>',vlink(post_break(p)));
- node_list_display_x('=',vlink(no_break(p)));
- break;
- case mark_node:
- /* Display mark |p|; */
- tprint_esc("mark");
- if (mark_class(p) != 0) {
- print_char('s');
- print_int(mark_class(p));
- }
- print_mark(mark_ptr(p));
- break;
- case adjust_node:
- /* Display adjustment |p|; */
- tprint_esc("vadjust");
- if (subtype(p) != 0)
- tprint(" pre ");
- node_list_display(adjust_ptr(p)); /* recursive call */
- break;
- case glue_spec_node:
- tprint("<glue_spec ");
- print_spec(p, NULL);
- tprint(">");
- break;
- default:
- show_math_node(p);
- break;
- }
- }
- p = vlink(p);
- }
-}
-
-@ This routine finds the 'base' width of a horizontal box, using the same logic
- that \TeX82 used for \.{\\predisplaywidth} */
-
-@c
-static pointer get_actual_box_width(pointer r,pointer p, scaled initial_width)
-{
- scaled d; /* increment to |v| */
- scaled w = -max_dimen; /* calculated |size| */
- scaled v = initial_width; /* |w| plus possible glue amount */
- while (p != null) {
- if (is_char_node(p)) {
- d = glyph_width(p);
- goto FOUND;
- }
- switch (type(p)) {
- case hlist_node:
- case vlist_node:
- case rule_node:
- d = width(p);
- goto FOUND;
- break;
- case margin_kern_node:
- d = width(p);
- break;
- case kern_node:
- d = width(p);
- break;
- case disc_node:
- /* at the end of the line we should actually take the pre */
- if (no_break(p) != null) {
- d = get_actual_box_width(r,vlink_no_break(p),0);
- if (d <= -max_dimen || d >= max_dimen) {
- d = 0;
- }
- } else {
- d = 0;
- }
- goto FOUND;
- break;
- case math_node:
- /* begin mathskip code */
- if (glue_is_zero(p)) {
- d = surround(p);
- break;
- } else {
- /* fall through */
- }
- /* end mathskip code */
- case glue_node:
- /* We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set|
- values, since such values are subject to system-dependent rounding.
- System-dependent numbers are not allowed to infiltrate parameters like
- |pre_display_size|, since \TeX82 is supposed to make the same decisions on all
- machines.
- */
- d = width(p);
- if (glue_sign(r) == stretching) {
- if ((glue_order(r) == stretch_order(p)) && (stretch(p) != 0))
- v = max_dimen;
- } else if (glue_sign(r) == shrinking) {
- if ((glue_order(r) == shrink_order(p)) && (shrink(p) != 0))
- v = max_dimen;
- }
- if (subtype(p) >= a_leaders)
- goto FOUND;
- break;
- default:
- d = 0;
- break;
- }
- if (v < max_dimen)
- v = v + d;
- goto NOT_FOUND;
- FOUND:
- if (v < max_dimen) {
- v = v + d;
- w = v;
- } else {
- w = max_dimen;
- break;
- }
- NOT_FOUND:
- p = vlink(p);
- }
- return w;
-}
-
-pointer actual_box_width(pointer r, scaled base_width)
-{
- /* often this is the same as:
- return + shift_amount(r) + base_width +
- natural_sizes(list_ptr(r),null,(glue_ratio) glue_set(r),glue_sign(r),glue_order(r),box_dir(r));
- */
- return get_actual_box_width(r,list_ptr(r),shift_amount(r) + base_width);
-}
-
-@ @c
-halfword tail_of_list(halfword p)
-{
- halfword q = p;
- while (vlink(q) != null)
- q = vlink(q);
- return q;
-}
-
-
-
-@ @c
-int var_used;
-
-@ Attribute lists need two extra globals to increase processing efficiency.
-|max_used_attr| limits the test loop that checks for set attributes, and
-|attr_list_cache| contains a pointer to an already created attribute list. It is
-set to the special value |cache_disabled| when the current value can no longer be
-trusted: after an assignment to an attribute register, and after a group has
-ended.
-
-@c
-int max_used_attr; /* maximum assigned attribute id */
-halfword attr_list_cache;
-
-@ From the computer's standpoint, \TeX's chief mission is to create
-horizontal and vertical lists. We shall now investigate how the elements
-of these lists are represented internally as nodes in the dynamic memory.
-
-A horizontal or vertical list is linked together by |link| fields in
-the first word of each node. Individual nodes represent boxes, glue,
-penalties, or special things like discretionary hyphens; because of this
-variety, some nodes are longer than others, and we must distinguish different
-kinds of nodes. We do this by putting a `|type|' field in the first word,
-together with the link and an optional `|subtype|'.
-
-@ Character nodes appear only in horizontal lists, never in vertical lists.
-
-An |hlist_node| stands for a box that was made from a horizontal list.
-Each |hlist_node| is seven words long, and contains the following fields
-(in addition to the mandatory |type| and |link|, which we shall not
-mention explicitly when discussing the other node types): The |height| and
-|width| and |depth| are scaled integers denoting the dimensions of the
-box. There is also a |shift_amount| field, a scaled integer indicating
-how much this box should be lowered (if it appears in a horizontal list),
-or how much it should be moved to the right (if it appears in a vertical
-list). There is a |list_ptr| field, which points to the beginning of the
-list from which this box was fabricated; if |list_ptr| is |null|, the box
-is empty. Finally, there are three fields that represent the setting of
-the glue: |glue_set(p)| is a word of type |glue_ratio| that represents
-the proportionality constant for glue setting; |glue_sign(p)| is
-|stretching| or |shrinking| or |normal| depending on whether or not the
-glue should stretch or shrink or remain rigid; and |glue_order(p)|
-specifies the order of infinity to which glue setting applies (|normal|,
-|sfi|, |fil|, |fill|, or |filll|). The |subtype| field is not used.
-
-@ The |new_null_box| function returns a pointer to an |hlist_node| in
-which all subfields have the values corresponding to `\.{\\hbox\{\}}'.
-The |subtype| field is set to |min_quarterword|, since that's the desired
-|span_count| value if this |hlist_node| is changed to an |unset_node|.
-
-@c
-halfword new_null_box(void)
-{ /* creates a new box node */
- halfword p = new_node(hlist_node, min_quarterword);
- box_dir(p) = text_direction_par;
- return p;
-}
-
-@ A |vlist_node| is like an |hlist_node| in all respects except that it
-contains a vertical list.
-
-@ A |rule_node| stands for a solid black rectangle; it has |width|,
-|depth|, and |height| fields just as in an |hlist_node|. However, if
-any of these dimensions is $-2^{30}$, the actual value will be determined
-by running the rule up to the boundary of the innermost enclosing box.
-This is called a ``running dimension.'' The |width| is never running in
-an hlist; the |height| and |depth| are never running in a~vlist.
-
-@ A new rule node is delivered by the |new_rule| function. It
-makes all the dimensions ``running,'' so you have to change the
-ones that are not allowed to run.
-
-@c
-halfword new_rule(int s)
-{
- halfword p = new_node(rule_node,s);
- return p;
-}
-
-@ Insertions are represented by |ins_node| records, where the |subtype|
-indicates the corresponding box number. For example, `\.{\\insert 250}'
-leads to an |ins_node| whose |subtype| is |250+min_quarterword|.
-The |height| field of an |ins_node| is slightly misnamed; it actually holds
-the natural height plus depth of the vertical list being inserted.
-The |depth| field holds the |split_max_depth| to be used in case this
-insertion is split, and the |split_top_ptr| points to the corresponding
-|split_top_skip|. The |float_cost| field holds the |floating_penalty| that
-will be used if this insertion floats to a subsequent page after a
-split insertion of the same class. There is one more field, the
-|ins_ptr|, which points to the beginning of the vlist for the insertion.
-
-@ A |mark_node| has a |mark_ptr| field that points to the reference count
-of a token list that contains the user's \.{\\mark} text.
-In addition there is a |mark_class| field that contains the mark class.
-
-@ An |adjust_node|, which occurs only in horizontal lists,
-specifies material that will be moved out into the surrounding
-vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}'
-operation. The |adjust_ptr| field points to the vlist containing this
-material.
-
-@ A |glyph_node|, which occurs only in horizontal lists, specifies a
-glyph in a particular font, along with its attribute list. Older
-versions of \TeX\ could use token memory for characters, because the
-font,char combination would fit in a single word (both values were
-required to be strictly less than $2^{16}$). In LuaTeX, room is
-needed for characters that are larger than that, as well as a pointer
-to a potential attribute list, and the two displacement values.
-
-In turn, that made the node so large that it made sense to merge
-ligature glyphs as well, as that requires only one extra pointer. A
-few extra classes of glyph nodes will be introduced later. The
-unification of all those types makes it easier to manipulate lists of
-glyphs. The subtype differentiates various glyph kinds.
-
-First, here is a function that returns a pointer to a glyph node for a given
-glyph in a given font. If that glyph doesn't exist, |null| is returned
-instead. Nodes of this subtype are directly created only for accents
-and their base (through |make_accent|), and math nucleus items (in the
-conversion from |mlist| to |hlist|).
-
-@c
-halfword new_glyph(int f, int c)
-{
- halfword p = null; /* the new node */
- if ((f == 0) || (char_exists(f, c))) {
- p = new_glyph_node();
- set_to_glyph(p);
- font(p) = f;
- character(p) = c;
- }
- return p;
-}
-
-@ A subset of the glyphs nodes represent ligatures: characters
-fabricated from the interaction of two or more actual characters. The
-characters that generated the ligature have not been forgotten, since
-they are needed for diagnostic messages; the |lig_ptr| field points to
-a linked list of character nodes for all original characters that have
-been deleted. (This list might be empty if the characters that
-generated the ligature were retained in other nodes.)
-
-The |subtype| field of these |glyph_node|s is 1, plus 2 and/or 1 if
-the original source of the ligature included implicit left and/or
-right boundaries. These nodes are created by the C function |new_ligkern|.
-
-A third general type of glyphs could be called a character, as it
-only appears in lists that are not yet processed by the ligaturing and
-kerning steps of the program.
-
-|main_control| inserts these, and they are later converted to
-|subtype_normal| by |new_ligkern|.
-
-@c
-quarterword norm_min(int h)
-{
- if (h <= 0)
- return 1;
- else if (h >= 255)
- return 255;
- else
- return (quarterword) h;
-}
-
-halfword new_char(int f, int c)
-{
- halfword p; /* the new node */
- p = new_glyph_node();
- set_to_character(p);
- font(p) = f;
- character(p) = c;
- lang_data(p) = make_lang_data(uc_hyph_par, cur_lang_par, left_hyphen_min_par, right_hyphen_min_par);
- return p;
-}
-
-@ Left and right ghost glyph nodes are the result of \.{\\leftghost}
-and \.{\\rightghost}, respectively. They are going to be removed by
-|new_ligkern|, at the end of which they are no longer needed.
-
-@ Here are a few handy helpers used by the list output routines.
-
-@c
-scaled glyph_width(halfword p)
-{
- scaled w = char_width(font(p), character(p));
- return w;
-}
-
-scaled glyph_height(halfword p)
-{
- scaled w = char_height(font(p), character(p)) + y_displace(p);
- if (w < 0)
- w = 0;
- return w;
-}
-
-scaled glyph_depth(halfword p)
-{
- scaled w = char_depth(font(p), character(p));
- if (y_displace(p) > 0)
- w = w - y_displace(p);
- if (w < 0)
- w = 0;
- return w;
-}
-
-@ A |disc_node|, which occurs only in horizontal lists, specifies a
-``dis\-cretion\-ary'' line break. If such a break occurs at node |p|, the text
-that starts at |pre_break(p)| will precede the break, the text that starts at
-|post_break(p)| will follow the break, and text that appears in
-|no_break(p)| nodes will be ignored. For example, an ordinary
-discretionary hyphen, indicated by `\.{\\-}', yields a |disc_node| with
-|pre_break| pointing to a |char_node| containing a hyphen, |post_break=null|,
-and |no_break=null|.
-
-{TODO: Knuth said: All three of the discretionary texts must be lists
-that consist entirely of character, kern, box and rule nodes.}
-
-If |subtype(p)=automatic_disc|, the |ex_hyphen_penalty| will be charged for this
-break. Otherwise the |hyphen_penalty| will be charged. The texts will
-actually be substituted into the list by the line-breaking algorithm if it
-decides to make the break, and the discretionary node will disappear at
-that time; thus, the output routine sees only discretionaries that were
-not chosen.
-
-@c
-halfword new_disc(void)
-{ /* creates an empty |disc_node| */
- halfword p = new_node(disc_node, 0);
- disc_penalty(p) = hyphen_penalty_par;
- return p;
-}
-
-@ A |whatsit_node| is a wild card reserved for extensions to \TeX. The
-|subtype| field in its first word says what `\\{whatsit}' it is, and
-implicitly determines the node size (which must be 2 or more) and the
-format of the remaining words. When a |whatsit_node| is encountered
-in a list, special actions are invoked; knowledgeable people who are
-careful not to mess up the rest of \TeX\ are able to make \TeX\ do new
-things by adding code at the end of the program. For example, there
-might be a `\TeX nicolor' extension to specify different colors of ink,
-@^extensions to \TeX@>
-and the whatsit node might contain the desired parameters.
-
-The present implementation of \TeX\ treats the features associated with
-`\.{\\write}' and `\.{\\special}' as if they were extensions, in order to
-illustrate how such routines might be coded. We shall defer further
-discussion of extensions until the end of this program.
-
-@ A |math_node|, which occurs only in horizontal lists, appears before and
-after mathematical formulas. The |subtype| field is |before| before the
-formula and |after| after it. There is a |surround| field, which represents
-the amount of surrounding space inserted by \.{\\mathsurround}.
-
-@c
-halfword new_math(scaled w, int s)
-{
- halfword p = new_node(math_node, s);
- surround(p) = w;
- return p;
-}
-
-@ \TeX\ makes use of the fact that |hlist_node|, |vlist_node|,
-|rule_node|, |ins_node|, |mark_node|, |adjust_node|,
-|disc_node|, |whatsit_node|, and |math_node| are at the low end of the
-type codes, by permitting a break at glue in a list if and only if the
-|type| of the previous node is less than |math_node|. Furthermore, a
-node is discarded after a break if its type is |math_node| or~more.
-
-@ A |glue_node| represents glue in a list. However, it is really only
-a pointer to a separate glue specification, since \TeX\ makes use of the
-fact that many essentially identical nodes of glue are usually present.
-If |p| points to a |glue_node|, |glue_ptr(p)| points to
-another packet of words that specify the stretch and shrink components, etc.
-
-Glue nodes also serve to represent leaders; the |subtype| is used to
-distinguish between ordinary glue (which is called |normal|) and the three
-kinds of leaders (which are called |a_leaders|, |c_leaders|, and |x_leaders|).
-The |leader_ptr| field points to a rule node or to a box node containing the
-leaders; it is set to |null| in ordinary glue nodes.
-
-Many kinds of glue are computed from \TeX's ``skip'' parameters, and
-it is helpful to know which parameter has led to a particular glue node.
-Therefore the |subtype| is set to indicate the source of glue, whenever
-it originated as a parameter. We will be defining symbolic names for the
-parameter numbers later (e.g., |line_skip_code=0|, |baseline_skip_code=1|,
-etc.); it suffices for now to say that the |subtype| of parametric glue
-will be the same as the parameter number, plus~one.
-
-@ In math formulas there are two more possibilities for the |subtype| in a
-glue node: |mu_glue| denotes an \.{\\mskip} (where the units are scaled \.{mu}
-instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}'
-feature that cancels the glue node immediately following if it appears
-in a subscript.
-
-@ A glue specification has a halfword reference count in its first word,
-@^reference counts@>
-representing |null| plus the number of glue nodes that point to it (less one).
-Note that the reference count appears in the same position as
-the |link| field in list nodes; this is the field that is initialized
-to |null| when a node is allocated, and it is also the field that is flagged
-by |empty_flag| in empty nodes.
-
-Glue specifications also contain three |scaled| fields, for the |width|,
-|stretch|, and |shrink| dimensions. Finally, there are two one-byte
-fields called |stretch_order| and |shrink_order|; these contain the
-orders of infinity (|normal|, |sfi|, |fil|, |fill|, or |filll|)
-corresponding to the stretch and shrink values.
-
-@ Here is a function that returns a pointer to a copy of a glue spec.
-The reference count in the copy is |null|, because there is assumed
-to be exactly one reference to the new specification.
-
-@c
-halfword new_spec(halfword q) /* safeguard for copying a glue node */
-{
- if (q == null) {
- return copy_node(zero_glue);
- } else if (type(q) == glue_spec_node) {
- return copy_node(q);
- } else if (type(q) == glue_node) {
- halfword p = copy_node(zero_glue);
- width(p) = width(q);
- stretch(p) = stretch(q);
- shrink(p) = shrink(q);
- stretch_order(p) = stretch_order(q);
- shrink_order(p) = shrink_order(q);
- return p;
- } else {
- /* alternatively we can issue a warning */
- return copy_node(zero_glue);
- }
-}
-
-@ And here's a function that creates a glue node for a given parameter
-identified by its code number; for example,
-|new_param_glue(line_skip_code)| returns a pointer to a glue node for the
-current \.{\\lineskip}.
-
-@c
-halfword new_param_glue(int n)
-{
- halfword p = new_node(glue_node, n + 1);
- halfword q = glue_par(n);
- width(p) = width(q);
- stretch(p) = stretch(q);
- shrink(p) = shrink(q);
- stretch_order(p) = stretch_order(q);
- shrink_order(p) = shrink_order(q);
- return p;
-}
-
-@ Glue nodes that are more or less anonymous are created by |new_glue|,
-whose argument points to a glue specification.
-
-@c
-halfword new_glue(halfword q)
-{
- halfword p = new_node(glue_node, normal);
- width(p) = width(q);
- stretch(p) = stretch(q);
- shrink(p) = shrink(q);
- stretch_order(p) = stretch_order(q);
- shrink_order(p) = shrink_order(q);
- return p;
-}
-
-@ Still another subroutine is needed: This one is sort of a combination
-of |new_param_glue| and |new_glue|. It creates a glue node for one of
-the current glue parameters, but it makes a fresh copy of the glue
-specification, since that specification will probably be subject to change,
-while the parameter will stay put.
-
-/*
- The global variable |temp_ptr| is set to the address of the new spec.
-*/
-
-@c
-halfword new_skip_param(int n)
-{
- halfword p = new_node(glue_node, n + 1);
- halfword q = glue_par(n);
- width(p) = width(q);
- stretch(p) = stretch(q);
- shrink(p) = shrink(q);
- stretch_order(p) = stretch_order(q);
- shrink_order(p) = shrink_order(q);
- return p;
-}
-
-@ A |kern_node| has a |width| field to specify a (normally negative)
-amount of spacing. This spacing correction appears in horizontal lists
-between letters like A and V when the font designer said that it looks
-better to move them closer together or further apart. A kern node can
-also appear in a vertical list, when its `|width|' denotes additional
-spacing in the vertical direction. The |subtype| is either |normal| (for
-kerns inserted from font information or math mode calculations) or |explicit|
-(for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern|
-(for kerns inserted from non-math accents) or |mu_glue| (for kerns
-inserted from \.{\\mkern} specifications in math formulas).
-
-@ The |new_kern| function creates a kern node having a given width.
-
-@c
-halfword new_kern(scaled w)
-{
- halfword p = new_node(kern_node, normal);
- width(p) = w;
- return p;
-}
-
-@ A |penalty_node| specifies the penalty associated with line or page
-breaking, in its |penalty| field. This field is a fullword integer, but
-the full range of integer values is not used: Any penalty |>=10000| is
-treated as infinity, and no break will be allowed for such high values.
-Similarly, any penalty |<=-10000| is treated as negative infinity, and a
-break will be forced.
-
-@ Anyone who has been reading the last few sections of the program will
-be able to guess what comes next.
-
-@c
-halfword new_penalty(int m, int s)
-{
- halfword p = new_node(penalty_node, 0); /* the |subtype| is not used */
- penalty(p) = m;
- subtype(p) = s;
- return p;
-}
-
-@ You might think that we have introduced enough node types by now. Well,
-almost, but there is one more: An |unset_node| has nearly the same format
-as an |hlist_node| or |vlist_node|; it is used for entries in \.{\\halign}
-or \.{\\valign} that are not yet in their final form, since the box
-dimensions are their ``natural'' sizes before any glue adjustment has been
-made. The |glue_set| word is not present; instead, we have a |glue_stretch|
-field, which contains the total stretch of order |glue_order| that is
-present in the hlist or vlist being boxed.
-Similarly, the |shift_amount| field is replaced by a |glue_shrink| field,
-containing the total shrink of order |glue_sign| that is present.
-The |subtype| field is called |span_count|; an unset box typically
-contains the data for |qo(span_count)+1| columns.
-Unset nodes will be changed to box nodes when alignment is completed.
-
-In fact, there are still more types coming. When we get to math formula
-processing we will see that a |style_node| has |type=14|; and a number
-of larger type codes will also be defined, for use in math mode only.
-
-Warning: If any changes are made to these data structure layouts, such as
-changing any of the node sizes or even reordering the words of nodes,
-the |copy_node_list| procedure and the memory initialization code
-below may have to be changed. Such potentially dangerous parts of the
-program are listed in the index under `data structure assumptions'.
-@!@^data structure assumptions@>
-However, other references to the nodes are made symbolically in terms of
-the \.{WEB} macro definitions above, so that format changes will leave
-\TeX's other algorithms intact.
-@^system dependencies@>
-
-@ This function creates a |local_paragraph| node
-
-@c
-
-halfword make_local_par_node(int mode)
-{
- int callback_id;
- halfword q;
- halfword p = new_node(local_par_node,0);
- local_pen_inter(p) = local_inter_line_penalty_par;
- local_pen_broken(p) = local_broken_penalty_par;
- if (local_left_box_par != null) {
- q = copy_node_list(local_left_box_par);
- local_box_left(p) = q;
- local_box_left_width(p) = width(local_left_box_par);
- }
- if (local_right_box_par != null) {
- q = copy_node_list(local_right_box_par);
- local_box_right(p) = q;
- local_box_right_width(p) = width(local_right_box_par);
- }
- local_par_dir(p) = par_direction_par;
- /* callback with node passed */
- callback_id = callback_defined(insert_local_par_callback);
- if (callback_id > 0) {
- int sfix = lua_gettop(Luas);
- if (!get_callback(Luas, callback_id)) {
- lua_settop(Luas, sfix);
- return p;
- }
- nodelist_to_lua(Luas, p);
- lua_push_local_par_mode(Luas,mode)
- if (lua_pcall(Luas, 2, 0, 0) != 0) { /* 2 arg, 0 result */
- char errmsg[256]; /* temp hack ... we will have a formatted error */
- snprintf(errmsg, 255, "error: %s\n", lua_tostring(Luas, -1));
- errmsg[255]='\0';
- lua_settop(Luas, sfix);
- normal_error("insert_local_par",errmsg); /* to be done */
- return p;
- }
- lua_settop(Luas, sfix);
- }
- /* done */
- return p;
-}
diff --git a/Build/source/texk/web2c/luatexdir/tex/textcodes.w b/Build/source/texk/web2c/luatexdir/tex/textcodes.c
index 89e93684132..a6a0b3a55e3 100644
--- a/Build/source/texk/web2c/luatexdir/tex/textcodes.w
+++ b/Build/source/texk/web2c/luatexdir/tex/textcodes.c
@@ -1,27 +1,35 @@
-% textcodes.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
+/*
+
+textcodes.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/>.
+
+*/
#include "ptexlib.h"
-@ catcodes @c
+/*tex
+
+Contrary to traditional \TEX\ we have catcode tables so that we can switch
+catcode regimes very fast. We can have many such regimes and they're stored in
+trees.
+
+*/
#define CATCODESTACK 8
#define CATCODEDEFAULT 12
@@ -174,7 +182,11 @@ static void freecatcodes(void)
xfree(catcode_valid);
}
-@ lccodes @c
+/*tex
+
+The lowercase mapping codes are also stored in a tree.
+
+*/
#define LCCODESTACK 8
#define LCCODEDEFAULT 0
@@ -220,7 +232,11 @@ static void freelccodes(void)
destroy_sa_tree(lccode_head);
}
-@ uccodes @c
+/*tex
+
+And the uppercase mapping codes are again stored in a tree.
+
+*/
#define UCCODESTACK 8
#define UCCODEDEFAULT 0
@@ -266,7 +282,11 @@ static void freeuccodes(void)
destroy_sa_tree(uccode_head);
}
-@ sfcodes @c
+/*tex
+
+By now it will be no surprise that the space factors get stored in a tree.
+
+*/
#define SFCODESTACK 8
#define SFCODEDEFAULT 1000
@@ -312,19 +332,29 @@ static void freesfcodes(void)
destroy_sa_tree(sfcode_head);
}
-@ hjcodes @c
+/*tex
+
+The hyphenation codes are indeed stored in a tree and are used instead of
+lowercase codes when deciding what characters to take into acccount when
+hyphenating. They are bound to upto |HJCODE_MAX| languages.
+
+*/
#define HJCODESTACK 8
#define HJCODEDEFAULT 0
-#define HJCODE_MAX 16383 /* number of languages */
+#define HJCODE_MAX 16383
static sa_tree *hjcode_heads = NULL;
static int hjcode_max = 0;
static unsigned char *hjcode_valid = NULL;
-@ Here we set codes but we don't initialize from lccodes.
+/*tex
+
+Here we set codes but we don't initialize from lccodes.
+
+*/
-@c void set_hj_code(int h, int n, halfword v, quarterword gl)
+void set_hj_code(int h, int n, halfword v, quarterword gl)
{
sa_tree_item sa_value = { 0 };
sa_tree s = hjcode_heads[h];
@@ -339,9 +369,13 @@ static unsigned char *hjcode_valid = NULL;
set_sa_item(s, n, sa_value, gl);
}
-@ We just return the lccodes when nothing is set.
+/*tex
-@c halfword get_hj_code(int h, int n)
+We just return the lccodes when nothing is set.
+
+*/
+
+halfword get_hj_code(int h, int n)
{
sa_tree s = hjcode_heads[h];
if (s == NULL) {
@@ -350,12 +384,14 @@ static unsigned char *hjcode_valid = NULL;
return (halfword) get_sa_item(s, n).int_value;
}
-@ We don't restore as we can have more languages in a paragraph
-and hyphenation takes place at a later stage so we would get
-weird grouping side effects .. so, one can overload settings
-but management is then upto the used, so no:
+/*tex
+
+We don't restore as we can have more languages in a paragraph and hyphenation
+takes place at a later stage so we would get weird grouping side effects .. so,
+one can overload settings but management is then upto the used, so no:
+
+*/
-@c
/*
static void unsavehjcodes(quarterword gl) { }
*/
@@ -444,7 +480,11 @@ static void freehjcodes(void)
xfree(hjcode_valid);
}
-/* management */
+/*tex
+
+The public management functions.
+
+*/
void unsave_text_codes(quarterword grouplevel)
{
diff --git a/Build/source/texk/web2c/luatexdir/tex/textoken.w b/Build/source/texk/web2c/luatexdir/tex/textoken.c
index d58aa3dc49b..6056bba2517 100644
--- a/Build/source/texk/web2c/luatexdir/tex/textoken.w
+++ b/Build/source/texk/web2c/luatexdir/tex/textoken.c
@@ -1,40 +1,26 @@
-% textoken.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"
+Copyright 2006-2011 Taco Hoekwater <taco@luatex.org>
-@ @c
-#define detokenized_line() (line_catcode_table==NO_CAT_TABLE)
+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/>.
-/*
-#define do_get_cat_code(a,b) do { \
- if (line_catcode_table<=-0xFF) \
- a= - line_catcode_table - 0xFF ; \
- else if (line_catcode_table!=DEFAULT_CAT_TABLE) \
- a=get_cat_code(line_catcode_table,b); \
- else \
- a=get_cat_code(cat_code_table_par,b); \
- } while (0)
*/
+#include "ptexlib.h"
+
+#define detokenized_line() (line_catcode_table==NO_CAT_TABLE)
+
#define do_get_cat_code(a,b) do { \
if (line_catcode_table==DEFAULT_CAT_TABLE) \
a=get_cat_code(cat_code_table_par,b); \
@@ -45,47 +31,85 @@
} while (0)
-@ The \TeX\ system does nearly all of its own memory allocation, so that it can
-readily be transported into environments that do not have automatic facilities
-for strings, garbage collection, etc., and so that it can be in control of what
-error messages the user receives. The dynamic storage requirements of \TeX\ are
-handled by providing two large arrays called |fixmem| and |varmem| in which
-consecutive blocks of words are used as nodes by the \TeX\ routines.
+/*tex
+
+ The \TeX\ system does nearly all of its own memory allocation, so that it can
+ readily be transported into environments that do not have automatic
+ facilities for strings, garbage collection, etc., and so that it can be in
+ control of what error messages the user receives. The dynamic storage
+ requirements of \TeX\ are handled by providing two large arrays called
+ |fixmem| and |varmem| in which consecutive blocks of words are used as nodes
+ by the \TeX\ routines.
+
+ Pointer variables are indices into this array, or into another array called
+ |eqtb| that will be explained later. A pointer variable might also be a
+ special flag that lies outside the bounds of |mem|, so we allow pointers to
+ assume any |halfword| value. The minimum halfword value represents a null
+ pointer. \TeX\ does not assume that |mem[null]| exists.
+
+ Locations in |fixmem| are used for storing one-word records; a conventional
+ \.{AVAIL} stack is used for allocation in this array.
+
+*/
+
+/*tex the big dynamic storage area */
+
+smemory_word *fixmem;
+
+/*tex the smallest location of one-word memory in use */
-Pointer variables are indices into this array, or into another array called
-|eqtb| that will be explained later. A pointer variable might also be a special
-flag that lies outside the bounds of |mem|, so we allow pointers to assume any
-|halfword| value. The minimum halfword value represents a null pointer. \TeX\
-does not assume that |mem[null]| exists.
+unsigned fix_mem_min;
-@ Locations in |fixmem| are used for storing one-word records; a conventional
-\.{AVAIL} stack is used for allocation in this array.
+/*tex the largest location of one-word memory in use */
-@c
-smemory_word *fixmem; /* the big dynamic storage area */
-unsigned fix_mem_min; /* the smallest location of one-word memory in use */
-unsigned fix_mem_max; /* the largest location of one-word memory in use */
+unsigned fix_mem_max;
-@ In order to study the memory requirements of particular applications, it is
-possible to prepare a version of \TeX\ that keeps track of current and maximum
-memory usage. When code between the delimiters |@!stat| $\ldots$ |tats| is not
-commented out, \TeX\ will run a bit slower but it will report these statistics
-when |tracing_stats| is sufficiently large.
+/*tex
+
+ In order to study the memory requirements of particular applications, it is
+ possible to prepare a version of \TeX\ that keeps track of current and
+ maximum memory usage. When code between the delimiters |stat| $\ldots$
+ |tats| is not commented out, \TeX\ will run a bit slower but it will report
+ these statistics when |tracing_stats| is sufficiently large.
+
+*/
-@c
-int var_used, dyn_used; /* how much memory is in use */
+/*tex how much memory is in use */
-halfword avail; /* head of the list of available one-word nodes */
-unsigned fix_mem_end; /* the last one-word node used in |mem| */
+int var_used, dyn_used;
-halfword garbage; /* head of a junk list, write only */
-halfword temp_token_head; /* head of a temporary list of some kind */
-halfword hold_token_head; /* head of a temporary list of another kind */
-halfword omit_template; /* a constant token list */
-halfword null_list; /* permanently empty list */
-halfword backup_head; /* head of token list built by |scan_keyword| */
+/*tex head of the list of available one-word nodes */
+
+halfword avail;
+
+/*tex the last one-word node used in |mem| */
+
+unsigned fix_mem_end;
+
+/*tex head of a junk list, write only */
+
+halfword garbage;
+
+/*tex head of a temporary list of some kind */
+
+halfword temp_token_head;
+
+/*tex head of a temporary list of another kind */
+
+halfword hold_token_head;
+
+/*tex a constant token list */
+
+halfword omit_template;
+
+/*tex permanently empty list */
+
+halfword null_list;
+
+/*tex head of token list built by |scan_keyword| */
+
+halfword backup_head;
-@ @c
void initialize_tokens(void)
{
halfword p;
@@ -109,37 +133,44 @@ void initialize_tokens(void)
p = get_avail();
garbage = p;
set_token_info(garbage, 0);
- dyn_used = 0; /* initialize statistics */
+ dyn_used = 0;
}
-@ The function |get_avail| returns a pointer to a new one-word node whose |link|
-field is null. However, \TeX\ will halt if there is no more room left.
-@^inner loop@>
+/*tex
+
+ The function |get_avail| returns a pointer to a new one-word node whose
+ |link| field is null. However, \TeX\ will halt if there is no more room left.
-If the available-space list is empty, i.e., if |avail=null|, we try first to
-increase |fix_mem_end|. If that cannot be done, i.e., if
-|fix_mem_end=fix_mem_max|, we try to reallocate array |fixmem|. If, that doesn't
-work, we have to quit.
+ If the available-space list is empty, i.e., if |avail=null|, we try first to
+ increase |fix_mem_end|. If that cannot be done, i.e., if
+ |fix_mem_end=fix_mem_max|, we try to reallocate array |fixmem|. If, that
+ doesn't work, we have to quit.
+
+ Single-word node allocation:
+*/
-@c
halfword get_avail(void)
-{ /* single-word node allocation */
- unsigned p; /* the new node being got */
+{
+ /*tex The new node being got: */
+ unsigned p;
unsigned t;
- p = (unsigned) avail; /* get top location in the |avail| stack */
+ /*tex Get top location in the |avail| stack. */
+ p = (unsigned) avail;
if (p != null) {
- avail = token_link(avail); /* and pop it off */
- } else if (fix_mem_end < fix_mem_max) { /* or go into virgin territory */
+ /*tex Pop it off. */
+ avail = token_link(avail);
+ } else if (fix_mem_end < fix_mem_max) {
+ /*tex Go into virgin territory. */
incr(fix_mem_end);
p = fix_mem_end;
} else {
- smemory_word *new_fixmem; /* the big dynamic storage area */
+ /*tex The big dynamic storage area. */
+ smemory_word *new_fixmem;
t = (fix_mem_max / 5);
- new_fixmem =
- fixmemcast(realloc
- (fixmem, sizeof(smemory_word) * (fix_mem_max + t + 1)));
+ new_fixmem = fixmemcast(realloc(fixmem, sizeof(smemory_word) * (fix_mem_max + t + 1)));
if (new_fixmem == NULL) {
- runaway(); /* if memory is exhausted, display possible runaway text */
+ /*tex If memory is exhausted, display possible runaway text. */
+ runaway();
overflow("token memory size", fix_mem_max);
} else {
fixmem = new_fixmem;
@@ -148,111 +179,127 @@ halfword get_avail(void)
fix_mem_max += t;
p = ++fix_mem_end;
}
- token_link(p) = null; /* provide an oft-desired initialization of the new node */
- incr(dyn_used); /* maintain statistics */
+ /*tex Provide an oft-desired initialization of the new node. */
+ token_link(p) = null;
+ /*tex Maintain statistics. */
+ incr(dyn_used);
return (halfword) p;
}
-@ The procedure |flush_list(p)| frees an entire linked list of one-word nodes
-that starts at position |p|.
-@^inner loop@>
+/*tex
+
+ The procedure |flush_list(p)| frees an entire linked list of one-word nodes
+ that starts at position |p|.
+
+ This makes list of single-word nodes available:
+
+*/
-@c
void flush_list(halfword p)
-{ /* makes list of single-word nodes available */
- halfword q, r; /* list traversers */
+{
+ halfword q, r;
if (p != null) {
r = p;
do {
q = r;
r = token_link(r);
decr(dyn_used);
- } while (r != null); /* now |q| is the last node on the list */
+ } while (r != null);
+ /*tex Now |q| is the last node on the list. */
token_link(q) = avail;
avail = p;
}
}
-@ A \TeX\ token is either a character or a control sequence, and it is @^token@>
-represented internally in one of two ways: (1)~A character whose ASCII code
-number is |c| and whose command code is |m| is represented as the number
-$2^{21}m+c$; the command code is in the range |1<=m<=14|. (2)~A control sequence
-whose |eqtb| address is |p| is represented as the number |cs_token_flag+p|. Here
-|cs_token_flag=@t$2^{25}-1$@>| is larger than $2^{21}m+c$, yet it is small enough
-that |cs_token_flag+p< max_halfword|; thus, a token fits comfortably in a
-halfword.
-
-A token |t| represents a |left_brace| command if and only if
-|t<left_brace_limit|; it represents a |right_brace| command if and only if we
-have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
-|end_match| command if and only if |match_token<=t<=end_match_token|. The
-following definitions take care of these token-oriented constants and a few
-others.
-
-@ A token list is a singly linked list of one-word nodes in |mem|, where each
-word contains a token and a link. Macro definitions, output-routine definitions,
-marks, \.{\\write} texts, and a few other things are remembered by \TeX\ in the
-form of token lists, usually preceded by a node with a reference count in its
-|token_ref_count| field. The token stored in location |p| is called |info(p)|.
-
-Three special commands appear in the token lists of macro definitions. When
-|m=match|, it means that \TeX\ should scan a parameter for the current macro;
-when |m=end_match|, it means that parameter matching should end and \TeX\ should
-start reading the macro text; and when |m=out_param|, it means that \TeX\ should
-insert parameter number |c| into the text at this point.
-
-The enclosing \.{\char'173} and \.{\char'175} characters of a macro definition
-are omitted, but the final right brace of an output routine is included at the
-end of its token list.
-
-Here is an example macro definition that illustrates these conventions. After
-\TeX\ processes the text
-
-$$\.{\\def\\mac a\#1\#2 \\b \{\#1\\-a \#\#1\#2 \#2\}}$$
-
-the definition of \.{\\mac} is represented as a token list containing
-
-$$\def\,{\hskip2pt}
-\vbox{\halign{\hfil#\hfil\cr
-(reference count), |letter|\,\.a, |match|\,\#, |match|\,\#, |spacer|\,\.\ ,
-\.{\\b}, |end_match|,\cr
-|out_param|\,1, \.{\\-}, |letter|\,\.a, |spacer|\,\.\ , |mac_param|\,\#,
-|other_char|\,\.1,\cr
-|out_param|\,2, |spacer|\,\.\ , |out_param|\,2.\cr}}$$
-
-The procedure |scan_toks| builds such token lists, and |macro_call| does the
-parameter matching. @^reference counts@>
-
-Examples such as $$\.{\\def\\m\{\\def\\m\{a\}\ b\}}$$ explain why reference
-counts would be needed even if \TeX\ had no \.{\\let} operation: When the token
-list for \.{\\m} is being read, the redefinition of \.{\\m} changes the |eqtb|
-entry before the token list has been fully consumed, so we dare not simply
-destroy a token list when its control sequence is being redefined.
-
-If the parameter-matching part of a definition ends with `\.{\#\{}', the
-corresponding token list will have `\.\{' just before the `|end_match|' and also
-at the very end. The first `\.\{' is used to delimit the parameter; the second
-one keeps the first from disappearing.
-
-The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in symbolic form,
-including the expansion of a macro or mark.
-
-@c
+/*tex
+
+ A \TeX\ token is either a character or a control sequence, and it is
+ represented internally in one of two ways: (1)~A character whose ASCII code
+ number is |c| and whose command code is |m| is represented as the number
+ $2^{21}m+c$; the command code is in the range |1<=m<=14|. (2)~A control
+ sequence whose |eqtb| address is |p| is represented as the number
+ |cs_token_flag+p|. Here |cs_token_flag=t=| $2^{25}-1$ is larger than
+ $2^{21}m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
+ thus, a token fits comfortably in a halfword.
+
+ A token |t| represents a |left_brace| command if and only if
+ |t<left_brace_limit|; it represents a |right_brace| command if and only if we
+ have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
+ |end_match| command if and only if |match_token<=t<=end_match_token|. The
+ following definitions take care of these token-oriented constants and a few
+ others.
+
+ A token list is a singly linked list of one-word nodes in |mem|, where each
+ word contains a token and a link. Macro definitions, output-routine
+ definitions, marks, \.{\\write} texts, and a few other things are remembered
+ by \TeX\ in the form of token lists, usually preceded by a node with a
+ reference count in its |token_ref_count| field. The token stored in location
+ |p| is called |info(p)|.
+
+ Three special commands appear in the token lists of macro definitions. When
+ |m=match|, it means that \TeX\ should scan a parameter for the current macro;
+ when |m=end_match|, it means that parameter matching should end and \TeX\
+ should start reading the macro text; and when |m=out_param|, it means that
+ \TeX\ should insert parameter number |c| into the text at this point.
+
+ The enclosing \.{\char'173} and \.{\char'175} characters of a macro
+ definition are omitted, but the final right brace of an output routine is
+ included at the end of its token list.
+
+ Here is an example macro definition that illustrates these conventions. After
+ \TeX\ processes the text
+
+ \starttyping
+ \def\mac a#1#2 \b {#1\-a ##1#2 \#2\}
+ \stoptyping
+
+ the definition of \.{\\mac} is represented as a token list containing
+
+ \starttyping
+ (reference count) |letter|a |match|# |match|# |spacer| \b |end_match|
+ |out_param|1 \- |letter|a |spacer|, |mac_param|# |other_char|1
+ |out_param|2 |spacer| |out_param|2
+ \stoptyping
+
+ The procedure |scan_toks| builds such token lists, and |macro_call| does the
+ parameter matching.
+
+ Examples such as \type{\def\m{\def\m{a} b}} explain why reference
+ counts would be needed even if \TeX\ had no \.{\\let} operation: When the
+ token list for \.{\\m} is being read, the redefinition of \.{\\m} changes the
+ |eqtb| entry before the token list has been fully consumed, so we dare not
+ simply destroy a token list when its control sequence is being redefined.
+
+ If the parameter-matching part of a definition ends with `\.{\#\{}', the
+ corresponding token list will have `\.\{' just before the `|end_match|' and
+ also at the very end. The first `\.\{' is used to delimit the parameter; the
+ second one keeps the first from disappearing.
+
+ The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in symbolic
+ form, including the expansion of a macro or mark.
+
+*/
+
void print_meaning(void)
{
- /* remap \mathchar onto \Umathchar */
-/*
+ /*tex
+
+ This would make sense but some macro packages don't like it:
+
+ \starttyping
if (cur_cmd == math_given_cmd) {
cur_cmd = xmath_given_cmd ;
}
-*/
+ \stoptyping
+
+ */
print_cmd_chr((quarterword) cur_cmd, cur_chr);
if (cur_cmd >= call_cmd) {
print_char(':');
print_ln();
token_show(cur_chr);
} else {
- /* Show the meaning of a mark node */
+ /*tex Show the meaning of a mark node. */
if ((cur_cmd == top_bot_mark_cmd) && (cur_chr < marks_code)) {
print_char(':');
print_ln();
@@ -277,31 +324,35 @@ void print_meaning(void)
}
}
-@ The procedure |show_token_list|, which prints a symbolic form of the token list
-that starts at a given node |p|, illustrates these conventions. The token list
-being displayed should not begin with a reference count. However, the procedure
-is intended to be robust, so that if the memory links are awry or if |p| is not
-really a pointer to a token list, nothing catastrophic will happen.
-
-An additional parameter |q| is also given; this parameter is either null or it
-points to a node in the token list where a certain magic computation takes place
-that will be explained later. (Basically, |q| is non-null when we are printing
-the two-line context information at the time of an error message; |q| marks the
-place corresponding to where the second line should begin.)
-
-For example, if |p| points to the node containing the first \.a in the token list
-above, then |show_token_list| will print the string $$\hbox{`\.{a\#1\#2\ \\b\
-->\#1\\-a\ \#\#1\#2\ \#2}';}$$ and if |q| points to the node containing the
-second \.a, the magic computation will be performed just before the second \.a is
-printed.
-
-The generation will stop, and `\.{\\ETC.}' will be printed, if the length of
-printing exceeds a given limit~|l|. Anomalous entries are printed in the form of
-control sequences that are not followed by a blank space, e.g., `\.{\\BAD.}';
-this cannot be confused with actual control sequences because a real control
-sequence named \.{BAD} would come out `\.{\\BAD\ }'.
-
-@c
+/*tex
+
+ The procedure |show_token_list|, which prints a symbolic form of the token
+ list that starts at a given node |p|, illustrates these conventions. The
+ token list being displayed should not begin with a reference count. However,
+ the procedure is intended to be robust, so that if the memory links are awry
+ or if |p| is not really a pointer to a token list, nothing catastrophic will
+ happen.
+
+ An additional parameter |q| is also given; this parameter is either null or
+ it points to a node in the token list where a certain magic computation takes
+ place that will be explained later. (Basically, |q| is non-null when we are
+ printing the two-line context information at the time of an error message;
+ |q| marks the place corresponding to where the second line should begin.)
+
+ For example, if |p| points to the node containing the first \.a in the token
+ list above, then |show_token_list| will print the string $$\hbox{`\.{a\#1\#2\
+ \\b\ ->\#1\\-a\ \#\#1\#2\ \#2}';}$$ and if |q| points to the node containing
+ the second \.a, the magic computation will be performed just before the
+ second \.a is printed.
+
+ The generation will stop, and `\.{\\ETC.}' will be printed, if the length of
+ printing exceeds a given limit~|l|. Anomalous entries are printed in the form
+ of control sequences that are not followed by a blank space, e.g.,
+ `\.{\\BAD.}'; this cannot be confused with actual control sequences because a
+ real control sequence named \.{BAD} would come out `\.{\\BAD\ }'.
+
+*/
+
#define not_so_bad(p) \
switch (m) { \
case assign_int_cmd: \
@@ -316,6 +367,18 @@ sequence named \.{BAD} would come out `\.{\\BAD\ }'.
if (c >= (backend_toks_base) && c <= (backend_toks_last)) \
p("[internal backend tokenlist]"); \
break; \
+ case node_cmd: \
+ p("[internal node pointer]"); \
+ break; \
+ case lua_call_cmd: \
+ p("[internal lua function call]"); \
+ break; \
+ case lua_expandable_call_cmd: \
+ p("[internal expandable lua function call]"); \
+ break; \
+ case lua_local_call_cmd: \
+ p("[internal local lua function call]"); \
+ break; \
default: \
p("BAD"); \
break; \
@@ -323,18 +386,21 @@ sequence named \.{BAD} would come out `\.{\\BAD\ }'.
void show_token_list(int p, int q, int l)
{
- int m, c; /* pieces of a token */
- ASCII_code match_chr = '#'; /* character used in a `|match|' */
- ASCII_code n = '0'; /* the highest parameter number, as an ASCII digit */
+ /*tex pieces of a token */
+ int m, c;
+ /*tex character used in a `|match|' */
+ ASCII_code match_chr = '#';
+ /*tex the highest parameter number, as an ASCII digit */
+ ASCII_code n = '0';
tally = 0;
if (l < 0)
l = 0x3FFFFFFF;
while ((p != null) && (tally < l)) {
if (p == q) {
- /* Do magic computation */
+ /*tex Do magic computation. */
set_trick_count();
}
- /* Display token |p|, and |return| if there are problems */
+ /*tex Display token |p|, and |return| if there are problems. */
if ((p < (int) fix_mem_min) || (p > (int) fix_mem_end)) {
tprint_esc("CLOBBERED.");
return;
@@ -349,11 +415,11 @@ void show_token_list(int p, int q, int l)
tprint_esc("BAD");
} else {
/*
- Display the token $(|m|,|c|)$
-
- The procedure usually ``learns'' the character code used for macro
- parameters by seeing one in a |match| command before it runs into any
+ Display the token \type {(|m|,|c|)}. The procedure usually
+ ``learns'' the character code used for macro parameters by
+ seeing one in a |match| command before it runs into any
|out_param| commands.
+
*/
switch (m) {
case left_brace_cmd:
@@ -405,31 +471,36 @@ void show_token_list(int p, int q, int l)
tprint_esc("ETC.");
}
-@ @c
#define do_buffer_to_unichar(a,b) do { \
a = (halfword)str2uni(buffer+b); \
b += utf8_size(a); \
} while (0)
-@ Here's the way we sometimes want to display a token list, given a pointer to
-its reference count; the pointer may be null.
+/*tex
+
+ Here's the way we sometimes want to display a token list, given a pointer to
+ its reference count; the pointer may be null.
+
+*/
-@c
void token_show(halfword p)
{
if (p != null)
show_token_list(token_link(p), null, 10000000);
}
-@ |delete_token_ref|, is called when a pointer to a token list's reference count
-is being removed. This means that the token list should disappear if the
-reference count was |null|, otherwise the count should be decreased by one.
-@^reference counts@>
+/*tex
-@ |p| points to the reference count of a token list that is losing one
-reference.
+ |delete_token_ref|, is called when a pointer to a token list's reference
+ count is being removed. This means that the token list should disappear if
+ the reference count was |null|, otherwise the count should be decreased by
+ one.
+
+ |p| points to the reference count of a token list that is losing one
+ reference.
+
+*/
-@c
void delete_token_ref(halfword p)
{
if (token_ref_count(p) == 0)
@@ -438,7 +509,6 @@ void delete_token_ref(halfword p)
decr(token_ref_count(p));
}
-@ @c
int get_char_cat_code(int curchr)
{
int a;
@@ -446,7 +516,6 @@ int get_char_cat_code(int curchr)
return a;
}
-@ @c
static void invalid_character_error(void)
{
const char *hlp[] = {
@@ -459,10 +528,9 @@ static void invalid_character_error(void)
deletions_allowed = true;
}
-@ @c
-static boolean process_sup_mark(void); /* below */
+static boolean process_sup_mark(void);
-static int scan_control_sequence(void); /* below */
+static int scan_control_sequence(void);
typedef enum {
next_line_ok,
@@ -470,57 +538,83 @@ typedef enum {
next_line_restart
} next_line_retval;
-static next_line_retval next_line(void); /* below */
+static next_line_retval next_line(void);
-@ In case you are getting bored, here is a slightly less trivial routine: Given a
-string of lowercase letters, like `\.{pt}' or `\.{plus}' or `\.{width}', the
-|scan_keyword| routine checks to see whether the next tokens of input match this
-string. The match must be exact, except that uppercase letters will match their
-lowercase counterparts; uppercase equivalents are determined by subtracting
-|"a"-"A"|, rather than using the |uc_code| table, since \TeX\ uses this routine
-only for its own limited set of keywords.
+/*tex
-If a match is found, the characters are effectively removed from the input and
-|true| is returned. Otherwise |false| is returned, and the input is left
-essentially unchanged (except for the fact that some macros may have been
-expanded, etc.). @^inner loop@>
+ In case you are getting bored, here is a slightly less trivial routine: Given
+ a string of lowercase letters, like `\.{pt}' or `\.{plus}' or `\.{width}',
+ the |scan_keyword| routine checks to see whether the next tokens of input
+ match this string. The match must be exact, except that uppercase letters
+ will match their lowercase counterparts; uppercase equivalents are determined
+ by subtracting |"a"-"A"|, rather than using the |uc_code| table, since \TeX\
+ uses this routine only for its own limited set of keywords.
+
+ If a match is found, the characters are effectively removed from the input
+ and |true| is returned. Otherwise |false| is returned, and the input is left
+ essentially unchanged (except for the fact that some macros may have been
+ expanded, etc.).
+
+*/
-@c
boolean scan_keyword(const char *s)
-{ /* look for a given string */
- halfword p; /* tail of the backup list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- const char *k; /* index into |str_pool| */
+{
+ /*tex tail of the backup list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex index into |str_pool| */
+ const char *k;
halfword save_cur_cs = cur_cs;
- if (strlen(s) == 0) /* was assert (strlen(s) > 1); */
- return false ; /* but not with newtokenlib zero keyword simply doesn't match */
+ if (strlen(s) == 0) {
+ /*tex but not with newtokenlib zero keyword simply doesn't match */
+ return false ;
+ }
p = backup_head;
token_link(p) = null;
k = s;
while (*k) {
- get_x_token(); /* recursion is possible here */
+ /*tex Recursion is possible here! */
+ get_x_token();
if ((cur_cs == 0) && ((cur_chr == *k) || (cur_chr == *k - 'a' + 'A'))) {
store_new_token(cur_tok);
k++;
} else if ((cur_cmd != spacer_cmd) || (p != backup_head)) {
- /*
- crashes on some alignments:
+ back_input();
+ if (p != backup_head) {
+ begin_token_list(token_link(backup_head), backed_up);
+ }
+ cur_cs = save_cur_cs;
+ return false;
+ }
+ }
+ if (token_link(backup_head) != null)
+ flush_list(token_link(backup_head));
+ cur_cs = save_cur_cs;
+ return true;
+}
- if (p != backup_head) {
- q = get_avail();
- token_info(q) = cur_tok;
- token_link(q) = null;
- token_link(p) = q;
- begin_token_list(token_link(backup_head), backed_up);
- } else {
- back_input();
- }
- */
+boolean scan_keyword_case_sensitive(const char *s)
+{
+ halfword p;
+ halfword q;
+ const char *k;
+ halfword save_cur_cs = cur_cs;
+ if (strlen(s) == 0)
+ return false ;
+ p = backup_head;
+ token_link(p) = null;
+ k = s;
+ while (*k) {
+ get_x_token();
+ if ((cur_cs == 0) && (cur_chr == *k)) {
+ store_new_token(cur_tok);
+ k++;
+ } else if ((cur_cmd != spacer_cmd) || (p != backup_head)) {
back_input();
if (p != backup_head) {
begin_token_list(token_link(backup_head), backed_up);
}
- /* */
cur_cs = save_cur_cs;
return false;
}
@@ -531,36 +625,11 @@ boolean scan_keyword(const char *s)
return true;
}
-@ We can not return |undefined_control_sequence| under some conditions
- (inside |shift_case|, for example). This needs thinking.
+/*tex
-@c
+ We can not return |undefined_control_sequence| under some conditions (inside
+ |shift_case|, for example). This needs thinking.
-/*
- halfword active_to_cs(int curchr, int force)
- {
- halfword curcs;
- char *a, *b;
- char *utfbytes = xmalloc(8);
- int nncs = no_new_control_sequence;
- a = (char *) uni2str(0xFFFF);
- utfbytes = strcpy(utfbytes, a);
- if (force)
- no_new_control_sequence = false;
- if (curchr > 0) {
- b = (char *) uni2str((unsigned) curchr);
- utfbytes = strcat(utfbytes, b);
- free(b);
- curcs = string_lookup(utfbytes, strlen(utfbytes));
- } else {
- utfbytes[3] = '\0';
- curcs = string_lookup(utfbytes, 4);
- }
- no_new_control_sequence = nncs;
- free(a);
- free(utfbytes);
- return curcs;
- }
*/
/*static char * FFFF = "\xEF\xBF\xBF";*/ /* 0xFFFF */
@@ -581,7 +650,8 @@ halfword active_to_cs(int curchr, int force)
curcs = string_lookup(utfbytes, utf8_size(curchr)+3);
free(utfbytes);
} else {
- curcs = string_lookup("\xEF\xBF\xBF", 4); /* 0xFFFF ... why not 3 ? */
+ /*tex 0xFFFF ... why not 3 ? */
+ curcs = string_lookup("\xEF\xBF\xBF", 4);
}
no_new_control_sequence = nncs;
return curcs;
@@ -641,11 +711,12 @@ halfword active_to_cs(int curchr, int force)
*/
-@ TODO this function should listen to \.{\\escapechar}
+/*tex
-@ prints a control sequence
+ Maybe this function should listen to \.{\\escapechar} but we can do without.
+
+*/
-@c
static char *cs_to_string(halfword p)
{
const char *s;
@@ -687,9 +758,8 @@ static char *cs_to_string(halfword p)
return (char *) ret;
}
-@ TODO this is a quick hack, will be solved differently soon
+/*tex This is sort of a hack. */
-@c
static char *cmd_chr_to_string(int cmd, int chr)
{
char *s;
@@ -704,56 +774,76 @@ static char *cmd_chr_to_string(int cmd, int chr)
return s;
}
-@ The heart of \TeX's input mechanism is the |get_next| procedure, which we shall
-develop in the next few sections of the program. Perhaps we shouldn't actually
-call it the ``heart,'' however, because it really acts as \TeX's eyes and mouth,
-reading the source files and gobbling them up. And it also helps \TeX\ to
-regurgitate stored token lists that are to be processed again. @^eyes and mouth@>
-
-The main duty of |get_next| is to input one token and to set |cur_cmd| and
-|cur_chr| to that token's command code and modifier. Furthermore, if the input
-token is a control sequence, the |eqtb| location of that control sequence is
-stored in |cur_cs|; otherwise |cur_cs| is set to zero.
-
-Underlying this simple description is a certain amount of complexity because of
-all the cases that need to be handled. However, the inner loop of |get_next| is
-reasonably short and fast.
-
-When |get_next| is asked to get the next token of a \.{\\read} line,
-it sets |cur_cmd=cur_chr=cur_cs=0| in the case that no more tokens
-appear on that line. (There might not be any tokens at all, if the
-|end_line_char| has |ignore| as its catcode.)
-
-The value of |par_loc| is the |eqtb| address of `\.{\\par}'. This quantity is
-needed because a blank line of input is supposed to be exactly equivalent to the
-appearance of \.{\\par}; we must set |cur_cs:=par_loc| when detecting a blank
-line.
-
-@c
-halfword par_loc; /* location of `\.{\\par}' in |eqtb| */
-halfword par_token; /* token representing `\.{\\par}' */
-
-@ Parts |get_next| are executed more often than any other instructions of \TeX.
-@^mastication@>@^inner loop@>
-
-The global variable |force_eof| is normally |false|; it is set |true| by an
-\.{\\endinput} command. |luacstrings| is the number of lua print statements
-waiting to be input, it is changed by |luatokencall|.
-
-@c
-boolean force_eof; /* should the next \.{\\input} be aborted early? */
-int luacstrings; /* how many lua strings are waiting to be input? */
-
-@ If the user has set the |pausing| parameter to some positive value, and if
-nonstop mode has not been selected, each line of input is displayed on the
-terminal and the transcript file, followed by `\.{=>}'. \TeX\ waits for a
-response. If the response is simply |carriage_return|, the line is accepted as it
-stands, otherwise the line typed is used instead of the line in the file.
-
-@c
+/*tex
+
+ The heart of \TeX's input mechanism is the |get_next| procedure, which we
+ shall develop in the next few sections of the program. Perhaps we shouldn't
+ actually call it the ``heart,'' however, because it really acts as \TeX's
+ eyes and mouth, reading the source files and gobbling them up. And it also
+ helps \TeX\ to regurgitate stored token lists that are to be processed again.
+
+ The main duty of |get_next| is to input one token and to set |cur_cmd| and
+ |cur_chr| to that token's command code and modifier. Furthermore, if the
+ input token is a control sequence, the |eqtb| location of that control
+ sequence is stored in |cur_cs|; otherwise |cur_cs| is set to zero.
+
+ Underlying this simple description is a certain amount of complexity because
+ of all the cases that need to be handled. However, the inner loop of
+ |get_next| is reasonably short and fast.
+
+ When |get_next| is asked to get the next token of a \.{\\read} line, it sets
+ |cur_cmd=cur_chr=cur_cs=0| in the case that no more tokens appear on that
+ line. (There might not be any tokens at all, if the |end_line_char| has
+ |ignore| as its catcode.)
+
+ The value of |par_loc| is the |eqtb| address of `\.{\\par}'. This quantity is
+ needed because a blank line of input is supposed to be exactly equivalent to
+ the appearance of \.{\\par}; we must set |cur_cs:=par_loc| when detecting a
+ blank line.
+
+*/
+
+/*tex
+
+ The location of `\.{\\par}' in |eqtb| adn the token representing `\.{\\par}.
+
+*/
+
+halfword par_loc;
+halfword par_token;
+
+/*tex
+
+ Parts |get_next| are executed more often than any other instructions of \TeX.
+
+ The global variable |force_eof| is normally |false|; it is set |true| by an
+ \.{\\endinput} command. |luacstrings| is the number of lua print statements
+ waiting to be input, it is changed by |luatokencall|.
+
+
+*/
+
+/*tex Should the next \.{\\input} be aborted early? */
+boolean force_eof;
+
+/*tex How many lua strings are waiting to be input? */
+
+int luacstrings;
+
+/*tex
+
+ If the user has set the |pausing| parameter to some positive value, and if
+ nonstop mode has not been selected, each line of input is displayed on the
+ terminal and the transcript file, followed by `\.{=>}'. \TeX\ waits for a
+ response. If the response is simply |carriage_return|, the line is accepted
+ as it stands, otherwise the line typed is used instead of the line in the
+ file.
+
+*/
+
void firm_up_the_line(void)
{
- int k; /* an index into |buffer| */
+ int k;
ilimit = last;
if (pausing_par > 0) {
if (interaction > nonstop_mode) {
@@ -764,9 +854,10 @@ void firm_up_the_line(void)
print_char(buffer[k]);
}
first = ilimit;
- prompt_input("=>"); /* wait for user response */
+ prompt_input("=>");
if (last > first) {
- for (k = first; k < +last - 1; k++) /* move line down in buffer */
+ /*tex Move line down in buffer. */
+ for (k = first; k < +last - 1; k++)
buffer[k + istart - first] = buffer[k];
ilimit = istart + last - first;
}
@@ -774,31 +865,42 @@ void firm_up_the_line(void)
}
}
-@ Before getting into |get_next|, let's consider the subroutine that is called
-when an `\.{\\outer}' control sequence has been scanned or when the end of a file
-has been reached. These two cases are distinguished by |cur_cs|, which is zero at
-the end of a file.
+/*tex
+
+ Before getting into |get_next|, let's consider the subroutine that is called
+ when an `\.{\\outer}' control sequence has been scanned or when the end of a
+ file has been reached. These two cases are distinguished by |cur_cs|, which
+ is zero at the end of a file.
+
+*/
-@c
void check_outer_validity(void)
{
- halfword p; /* points to inserted token list */
- halfword q; /* auxiliary pointer */
+ /*tex points to inserted token list */
+ halfword p;
+ /*tex auxiliary pointer */
+ halfword q;
if (suppress_outer_error_par)
return;
if (scanner_status != normal) {
deletions_allowed = false;
- /* Back up an outer control sequence so that it can be reread; */
- /* An outer control sequence that occurs in a \.{\\read} will not be reread,
- since the error recovery for \.{\\read} is not very powerful. */
+ /*tex
+
+ Back up an outer control sequence so that it can be reread. An
+ outer control sequence that occurs in a \.{\\read} will not be
+ reread, since the error recovery for \.{\\read} is not very powerful.
+
+ */
if (cur_cs != 0) {
if ((istate == token_list) || (iname < 1) || (iname > 17)) {
p = get_avail();
token_info(p) = cs_token_flag + cur_cs;
- begin_token_list(p, backed_up); /* prepare to read the control sequence again */
+ /*tex prepare to read the control sequence again */
+ begin_token_list(p, backed_up);
}
+ /*tex replace it by a space */
cur_cmd = spacer_cmd;
- cur_chr = ' '; /* replace it by a space */
+ cur_chr = ' ';
}
if (scanner_status > skipping) {
const char *errhlp[] = {
@@ -808,56 +910,64 @@ void check_outer_validity(void)
"you'd better type `E' or `X' now and fix your file.",
NULL
};
- char errmsg[256];
+ char errmsg[318];
const char *startmsg;
const char *scannermsg;
- /* Tell the user what has run away and try to recover */
- runaway(); /* print a definition, argument, or preamble */
+ /*tex
+
+ Tell the user what has run away and try to recover Print a
+ definition, argument, or preamble.
+
+ */
+ runaway();
if (cur_cs == 0) {
startmsg = "File ended";
} else {
cur_cs = 0;
startmsg = "Forbidden control sequence found";
}
- /* Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}',
- and insert tokens that should lead to recovery; */
- /* The recovery procedure can't be fully understood without knowing more
- about the \TeX\ routines that should be aborted, but we can sketch the
- ideas here: For a runaway definition we will insert a right brace; for a
- runaway preamble, we will insert a special \.{\\cr} token and a right
- brace; and for a runaway argument, we will set |long_state| to
- |outer_call| and insert \.{\\par}. */
+ /*tex
+
+ Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or
+ `\.{text}', and insert tokens that should lead to recovery. The
+ recovery procedure can't be fully understood without knowing more
+ about the \TeX\ routines that should be aborted, but we can
+ sketch the ideas here: For a runaway definition we will insert a
+ right brace; for a runaway preamble, we will insert a special
+ \.{\\cr} token and a right brace; and for a runaway argument, we
+ will set |long_state| to |outer_call| and insert \.{\\par}.
+
+ */
p = get_avail();
switch (scanner_status) {
- case defining:
- scannermsg = "definition";
- token_info(p) = right_brace_token + '}';
- break;
- case matching:
- scannermsg = "use";
- token_info(p) = par_token;
- long_state = outer_call_cmd;
- break;
- case aligning:
- scannermsg = "preamble";
- token_info(p) = right_brace_token + '}';
- q = p;
- p = get_avail();
- token_link(p) = q;
- token_info(p) = cs_token_flag + frozen_cr;
- align_state = -1000000;
- break;
- case absorbing:
- scannermsg = "text";
- token_info(p) = right_brace_token + '}';
- break;
- default: /* can't happen */
- scannermsg = "unknown";
- break;
- } /*there are no other cases */
+ case defining:
+ scannermsg = "definition";
+ token_info(p) = right_brace_token + '}';
+ break;
+ case matching:
+ scannermsg = "use";
+ token_info(p) = par_token;
+ long_state = outer_call_cmd;
+ break;
+ case aligning:
+ scannermsg = "preamble";
+ token_info(p) = right_brace_token + '}';
+ q = p;
+ p = get_avail();
+ token_link(p) = q;
+ token_info(p) = cs_token_flag + frozen_cr;
+ align_state = -1000000;
+ break;
+ case absorbing:
+ scannermsg = "text";
+ token_info(p) = right_brace_token + '}';
+ break;
+ default:
+ scannermsg = "unknown";
+ break;
+ }
begin_token_list(p, inserted);
- snprintf(errmsg, 255, "%s while scanning %s of %s",
- startmsg, scannermsg, cs_to_string(warning_index));
+ snprintf(errmsg, 318, "%s while scanning %s of %s", startmsg, scannermsg, cs_to_string(warning_index));
tex_error(errmsg, errhlp);
} else {
char errmsg[256];
@@ -883,9 +993,9 @@ void check_outer_validity(void)
snprintf(errmsg, 255, "Incomplete %s; all text was ignored after line %d",
ss, (int) skip_line);
free(ss);
- /* Incomplete \\if... */
+ /*tex Incomplete |\if...| */
cur_tok = cs_token_flag + frozen_fi;
- /* back up one inserted token and call |error| */
+ /*tex back up one inserted token and call |error|. */
{
OK_to_interrupt = false;
back_input();
@@ -898,61 +1008,65 @@ void check_outer_validity(void)
}
}
-@ @c
-
#if 0
-/*
- The other variant gives less clutter in tracing cache usage when profiling and for
- some files (like the manual) also a bit of a speedup.
+/*tex
+
+ The other variant gives less clutter in tracing cache usage when profiling
+ and for some files (like the manual) also a bit of a speedup.
+
*/
static boolean get_next_file(void)
{
SWITCH:
if (iloc <= ilimit) {
- /* current line not yet finished */
+ /*tex current line not yet finished */
do_buffer_to_unichar(cur_chr, iloc);
-
RESWITCH:
if (detokenized_line()) {
cur_cmd = (cur_chr == ' ' ? 10 : 12);
} else {
do_get_cat_code(cur_cmd, cur_chr);
}
- /*
+ /*tex
+
Change state if necessary, and |goto switch| if the current
character should be ignored, or |goto reswitch| if the current
character changes to another;
- The following 48-way switch accomplishes the scanning quickly, assuming
- that a decent C compiler has translated the code. Note that the numeric
- values for |mid_line|, |skip_blanks|, and |new_line| are spaced
- apart from each other by |max_char_code+1|, so we can add a character's
- command code to the state to get a single number that characterizes both.
+ The following 48-way switch accomplishes the scanning quickly,
+ assuming that a decent C compiler has translated the code. Note that
+ the numeric values for |mid_line|, |skip_blanks|, and |new_line| are
+ spaced apart from each other by |max_char_code+1|, so we can add a
+ character's command code to the state to get a single number that
+ characterizes both.
- Remark [ls/hh]: checking performance indicated that this switch was the
- cause of many branch prediction errors but changing it to:
+ Remark [ls/hh]: checking performance indicated that this switch was
+ the cause of many branch prediction errors but changing it to:
- c = istate + cur_cmd;
- if (c == (mid_line + letter_cmd) || c == (mid_line + other_char_cmd)) {
- return true;
- } else if (c >= new_line) {
- switch (c) {
- }
- } else if (c >= skip_blanks) {
- switch (c) {
- }
- } else if (c >= mid_line) {
- switch (c) {
- }
- } else {
- istate = mid_line;
- return true;
+ \starttyping
+ c = istate + cur_cmd;
+ if (c == (mid_line + letter_cmd) || c == (mid_line + other_char_cmd)) {
+ return true;
+ } else if (c >= new_line) {
+ switch (c) {
+ }
+ } else if (c >= skip_blanks) {
+ switch (c) {
+ }
+ } else if (c >= mid_line) {
+ switch (c) {
}
+ } else {
+ istate = mid_line;
+ return true;
+ }
+ \stoptyping
+
+ gives as many prediction errors. So, we can indeed assume that the
+ compiler does the right job, or that there is simply no other way.
- gives as many prediction errors. So, we can indeed assume that the compiler
- does the right job, or that there is simply no other way.
*/
switch (istate + cur_cmd) {
@@ -961,13 +1075,13 @@ static boolean get_next_file(void)
case new_line + ignore_cmd:
case skip_blanks + spacer_cmd:
case new_line + spacer_cmd:
- /* Cases where character is ignored */
+ /*tex Cases where character is ignored. */
goto SWITCH;
break;
case mid_line + escape_cmd:
case new_line + escape_cmd:
case skip_blanks + escape_cmd:
- /* Scan a control sequence ...; */
+ /*tex Scan a control sequence. */
istate = (unsigned char) scan_control_sequence();
if (! suppress_outer_error_par && cur_cmd >= outer_call_cmd)
check_outer_validity();
@@ -975,7 +1089,7 @@ static boolean get_next_file(void)
case mid_line + active_char_cmd:
case new_line + active_char_cmd:
case skip_blanks + active_char_cmd:
- /* Process an active-character */
+ /*tex Process an active-character. */
cur_cs = active_to_cs(cur_chr, false);
cur_cmd = eq_type(cur_cs);
cur_chr = equiv(cur_cs);
@@ -986,7 +1100,7 @@ static boolean get_next_file(void)
case mid_line + sup_mark_cmd:
case new_line + sup_mark_cmd:
case skip_blanks + sup_mark_cmd:
- /* If this |sup_mark| starts */
+ /*tex If this |sup_mark| starts. */
if (process_sup_mark())
goto RESWITCH;
else
@@ -995,22 +1109,27 @@ static boolean get_next_file(void)
case mid_line + invalid_char_cmd:
case new_line + invalid_char_cmd:
case skip_blanks + invalid_char_cmd:
- /* Decry the invalid character and |goto restart|; */
+ /*tex Decry the invalid character and |goto restart|. */
invalid_character_error();
- return false; /* because state may be |token_list| now */
+ /*tex Because state may be |token_list| now: */
+ return false;
break;
case mid_line + spacer_cmd:
- /* Enter |skip_blanks| state, emit a space; */
+ /*tex Enter |skip_blanks| state, emit a space. */
istate = skip_blanks;
cur_chr = ' ';
break;
case mid_line + car_ret_cmd:
- /*
- Finish line, emit a space. When a character of type |spacer| gets through, its
- character code is changed to $\.{"\ "}=040$. This means that the ASCII codes
- for tab and space, and for the space inserted at the end of a line, will be
- treated alike when macro parameters are being matched. We do this since such
- characters are indistinguishable on most computer terminal displays.
+ /*tex
+
+ Finish line, emit a space. When a character of type |spacer|
+ gets through, its character code is changed to $\.{"\
+ "}=040$. This means that the ASCII codes for tab and space,
+ and for the space inserted at the end of a line, will be
+ treated alike when macro parameters are being matched. We do
+ this since such characters are indistinguishable on most
+ computer terminal displays.
+
*/
iloc = ilimit + 1;
cur_cmd = spacer_cmd;
@@ -1020,12 +1139,12 @@ static boolean get_next_file(void)
case mid_line + comment_cmd:
case new_line + comment_cmd:
case skip_blanks + comment_cmd:
- /* Finish line, |goto switch|; */
+ /*tex Finish line, |goto switch|; */
iloc = ilimit + 1;
goto SWITCH;
break;
case new_line + car_ret_cmd:
- /* Finish line, emit a \.{\\par}; */
+ /*tex Finish line, emit a \.{\\par}; */
iloc = ilimit + 1;
cur_cs = par_loc;
cur_cmd = eq_type(cur_cs);
@@ -1036,14 +1155,14 @@ static boolean get_next_file(void)
case skip_blanks + left_brace_cmd:
case new_line + left_brace_cmd:
istate = mid_line;
- /* fall through */
+ /*tex Fall through. */
case mid_line + left_brace_cmd:
align_state++;
break;
case skip_blanks + right_brace_cmd:
case new_line + right_brace_cmd:
istate = mid_line;
- /* fall through */
+ /*tex Fall through. */
case mid_line + right_brace_cmd:
align_state--;
break;
@@ -1075,11 +1194,12 @@ static boolean get_next_file(void)
} else {
if (iname != 21)
istate = new_line;
- /*
- Move to next line of file,
- or |goto restart| if there is no next line,
+ /*tex
+
+ Move to next line of file, or |goto restart| if there is no next line,
or |return| if a \.{\\read} line has finished;
- */
+
+ */
do {
next_line_retval r = next_line();
if (r == next_line_return) {
@@ -1096,13 +1216,10 @@ static boolean get_next_file(void)
#else
-/* 10 times less Bim in callgrind */
+/*tex
+
+ This variant gives 10 times less Bim in vallgrind!
-/*
- escape_cmd left_brace_cmd right_brace_cmd math_shift_cmd
- tab_mark_cmd car_ret_cmd mac_param_cmd sup_mark_cmd
- sub_mark_cmd ignore_cmd spacer_cmd letter_cmd
- other_char_cmd active_char_cmd comment_cmd invalid_char_cmd
*/
static boolean get_next_file(void)
@@ -1110,7 +1227,7 @@ static boolean get_next_file(void)
int c = 0;
SWITCH:
if (iloc <= ilimit) {
- /* current line not yet finished */
+ /*tex current line not yet finished */
do_buffer_to_unichar(cur_chr, iloc);
RESWITCH:
if (detokenized_line()) {
@@ -1118,10 +1235,12 @@ static boolean get_next_file(void)
} else {
do_get_cat_code(cur_cmd, cur_chr);
}
- /*
- Change state if necessary, and |goto switch| if the current
- character should be ignored, or |goto reswitch| if the current
- character changes to another;
+ /*tex
+
+ Change state if necessary, and |goto switch| if the current character
+ should be ignored, or |goto reswitch| if the current character changes
+ to another.
+
*/
c = istate + cur_cmd;
if (c == (mid_line + letter_cmd) || c == (mid_line + other_char_cmd)) {
@@ -1148,7 +1267,7 @@ static boolean get_next_file(void)
istate = mid_line;
return true;
case car_ret_cmd:
- /* Finish line, emit a \.{\\par}; */
+ /*tex Finish line, emit a \.{\\par}. */
iloc = ilimit + 1;
cur_cs = par_loc;
cur_cmd = eq_type(cur_cs);
@@ -1172,7 +1291,7 @@ static boolean get_next_file(void)
goto SWITCH;
return true;
case spacer_cmd:
- /* Cases where character is ignored */
+ /*tex Cases where character is ignored. */
goto SWITCH;
case letter_cmd:
istate = mid_line;
@@ -1192,8 +1311,9 @@ static boolean get_next_file(void)
iloc = ilimit + 1;
goto SWITCH;
case invalid_char_cmd:
+ /*tex Because state may be |token_list| now. */
invalid_character_error();
- return false; /* because state may be |token_list| now */
+ return false;
default:
istate = mid_line;
return true;
@@ -1201,7 +1321,7 @@ static boolean get_next_file(void)
} else if (c >= skip_blanks) {
switch (c-skip_blanks) {
case escape_cmd:
- /* Scan a control sequence ...; */
+ /*tex Scan a control sequence. */
istate = (unsigned char) scan_control_sequence();
if (! suppress_outer_error_par && cur_cmd >= outer_call_cmd)
check_outer_validity();
@@ -1227,7 +1347,6 @@ static boolean get_next_file(void)
istate = mid_line;
return true;
case sup_mark_cmd:
- /* If this |sup_mark| starts */
if (process_sup_mark())
goto RESWITCH;
else
@@ -1255,13 +1374,14 @@ static boolean get_next_file(void)
check_outer_validity();
return true;
case comment_cmd:
- /* Finish line, |goto switch|; */
+ /*tex Finish line, |goto switch|. */
iloc = ilimit + 1;
goto SWITCH;
case invalid_char_cmd:
- /* Decry the invalid character and |goto restart|; */
+ /*tex Decry the invalid character and |goto restart|. */
invalid_character_error();
- return false; /* because state may be |token_list| now */
+ /*tex Because state may be |token_list| now. */
+ return false;
default:
istate = mid_line;
return true;
@@ -1284,13 +1404,17 @@ static boolean get_next_file(void)
case tab_mark_cmd:
return true;
case car_ret_cmd:
- /*
- Finish line, emit a space. When a character of type |spacer| gets through, its
- character code is changed to $\.{"\ "}=040$. This means that the ASCII codes
- for tab and space, and for the space inserted at the end of a line, will be
- treated alike when macro parameters are being matched. We do this since such
- characters are indistinguishable on most computer terminal displays.
- */
+ /*tex
+
+ Finish line, emit a space. When a character of type
+ |spacer| gets through, its character code is changed to
+ $\.{"\ "}=040$. This means that the ASCII codes for tab
+ and space, and for the space inserted at the end of a
+ line, will be treated alike when macro parameters are
+ being matched. We do this since such characters are
+ indistinguishable on most computer terminal displays.
+
+ */
iloc = ilimit + 1;
cur_cmd = spacer_cmd;
cur_chr = ' ';
@@ -1308,7 +1432,7 @@ static boolean get_next_file(void)
case ignore_cmd:
goto SWITCH;
case spacer_cmd:
- /* Enter |skip_blanks| state, emit a space; */
+ /*tex Enter |skip_blanks| state, emit a space. */
istate = skip_blanks;
cur_chr = ' ';
return true;
@@ -1330,8 +1454,9 @@ static boolean get_next_file(void)
iloc = ilimit + 1;
goto SWITCH;
case invalid_char_cmd:
+ /*tex Because state may be |token_list| now. */
invalid_character_error();
- return false; /* because state may be |token_list| now */
+ return false;
default:
istate = mid_line;
return true;
@@ -1344,9 +1469,11 @@ static boolean get_next_file(void)
if (iname != 21) {
istate = new_line;
}
- /*
- Move to next line of file, or |goto restart| if there is no next line,
- or |return| if a \.{\\read} line has finished;
+ /*tex
+
+ Move to next line of file, or |goto restart| if there is no next
+ line, or |return| if a \.{\\read} line has finished;
+
*/
do {
next_line_retval r = next_line();
@@ -1364,14 +1491,18 @@ static boolean get_next_file(void)
#endif
-@ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit.
-We only support a limited set:
+/*tex
-^^^^^^XXXXXX
-^^^^XXXXXX
-^^XX ^^<char>
+ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit.
+ We only support a limited set:
-@c
+ \starttyping
+ ^^^^^^XXXXXX
+ ^^^^XXXXXX
+ ^^XX ^^<char>
+ \stoptyping
+
+*/
#define is_hex(a) ((a>='0'&&a<='9')||(a>='a'&&a<='f'))
@@ -1412,7 +1543,7 @@ static boolean process_sup_mark(void)
if (iloc < ilimit) {
if ((cur_chr == buffer[iloc + 1]) && (cur_chr == buffer[iloc + 2])) {
if ((cur_chr == buffer[iloc + 3]) && (cur_chr == buffer[iloc + 4])) {
- /* ^^^^^^XXXXXX */
+ /*tex |^^^^^^XXXXXX| */
if ((iloc + 10) <= ilimit) {
int c1 = buffer[iloc + 5];
int c2 = buffer[iloc + 6];
@@ -1432,7 +1563,7 @@ static boolean process_sup_mark(void)
tex_error("^^^^^^ needs six hex digits, end of input", NULL);
}
} else {
- /* ^^^^XXXX */
+ /*tex |^^^^XXXX| */
if ((iloc + 6) <= ilimit) {
int c1 = buffer[iloc + 3];
int c2 = buffer[iloc + 4];
@@ -1450,7 +1581,7 @@ static boolean process_sup_mark(void)
}
}
} else {
- /* ^^XX */
+ /*tex |^^XX| */
if ((iloc + 2) <= ilimit) {
int c1 = buffer[iloc + 1];
int c2 = buffer[iloc + 2];
@@ -1460,10 +1591,10 @@ static boolean process_sup_mark(void)
return true;
}
}
- /* go on, no error, good old tex */
+ /*tex Go on, no error, good old \TEX . */
}
}
- /* the rest */
+ /*tex The rest. */
{
int c1 = buffer[iloc + 1];
if (c1 < 0200) {
@@ -1484,37 +1615,43 @@ static boolean process_sup_mark(void)
return false;
}
-@ Control sequence names are scanned only when they appear in some line of a
-file; once they have been scanned the first time, their |eqtb| location serves as
-a unique identification, so \TeX\ doesn't need to refer to the original name any
-more except when it prints the equivalent in symbolic form.
+/*tex
+
+ Control sequence names are scanned only when they appear in some line of a
+ file; once they have been scanned the first time, their |eqtb| location
+ serves as a unique identification, so \TeX\ doesn't need to refer to the
+ original name any more except when it prints the equivalent in symbolic form.
-The program that scans a control sequence has been written carefully in order to
-avoid the blowups that might otherwise occur if a malicious user tried something
-like `\.{\\catcode\'15=0}'. The algorithm might look at |buffer[ilimit+1]|, but
-it never looks at |buffer[ilimit+2]|.
+ The program that scans a control sequence has been written carefully in order
+ to avoid the blowups that might otherwise occur if a malicious user tried
+ something like `\.{\\catcode\'15=0}'. The algorithm might look at
+ |buffer[ilimit+1]|, but it never looks at |buffer[ilimit+2]|.
-If expanded characters like `\.{\^\^A}' or `\.{\^\^df}' appear in or just
-following a control sequence name, they are converted to single characters in the
-buffer and the process is repeated, slowly but surely.
+ If expanded characters like `\.{\^\^A}' or `\.{\^\^df}' appear in or just
+ following a control sequence name, they are converted to single characters in
+ the buffer and the process is repeated, slowly but surely.
+
+*/
-@c
static boolean check_expanded_code(int *kk); /* below */
static int scan_control_sequence(void)
{
int retval = mid_line;
if (iloc > ilimit) {
- cur_cs = null_cs; /* |state| is irrelevant in this case */
+ /*tex |state| is irrelevant in this case. */
+ cur_cs = null_cs;
} else {
- register int cat; /* |cat_code(cur_chr)|, usually */
+ /*tex |cat_code(cur_chr)|, usually: */
+ register int cat;
while (1) {
int k = iloc;
do_buffer_to_unichar(cur_chr, k);
do_get_cat_code(cat, cur_chr);
if (cat != letter_cmd || k > ilimit) {
retval = (cat == spacer_cmd ? skip_blanks : mid_line);
- if (cat == sup_mark_cmd && check_expanded_code(&k)) /* If an expanded...; */
+ /*tex If an expanded \unknown */
+ if (cat == sup_mark_cmd && check_expanded_code(&k))
continue;
} else {
retval = skip_blanks;
@@ -1522,20 +1659,11 @@ static int scan_control_sequence(void)
do_buffer_to_unichar(cur_chr, k);
do_get_cat_code(cat, cur_chr);
} while (cat == letter_cmd && k <= ilimit);
-
- if (cat == sup_mark_cmd && check_expanded_code(&k)) /* If an expanded...; */
+ /*tex If an expanded \unknown */
+ if (cat == sup_mark_cmd && check_expanded_code(&k))
continue;
if (cat != letter_cmd) {
- /* backtrack one character which can be utf */
- /*
- decr(k);
- if (cur_chr > 0xFFFF)
- decr(k);
- if (cur_chr > 0x7FF)
- decr(k);
- if (cur_chr > 0x7F)
- decr(k);
- */
+ /*tex Backtrack one character which can be \UTF. */
if (cur_chr <= 0x7F) {
k -= 1; /* in most cases */
} else if (cur_chr > 0xFFFF) {
@@ -1545,7 +1673,7 @@ static int scan_control_sequence(void)
} else /* if (cur_chr > 0x7F) */ {
k -= 2;
}
- /* now |k| points to first nonletter */
+ /*tex Now |k| points to first nonletter. */
}
}
cur_cs = id_lookup(iloc, k - iloc);
@@ -1558,14 +1686,17 @@ static int scan_control_sequence(void)
return retval;
}
-@ Whenever we reach the following piece of code, we will have
-|cur_chr=buffer[k-1]| and |k<=ilimit+1| and
-|cat=get_cat_code(cat_code_table,cur_chr)|. If an expanded code like \.{\^\^A} or
-\.{\^\^df} appears in |buffer[(k-1)..(k+1)]| or |buffer[(k-1)..(k+2)]|, we will
-store the corresponding code in |buffer[k-1]| and shift the rest of the buffer
-left two or three places.
+/*tex
+
+ Whenever we reach the following piece of code, we will have
+ |cur_chr=buffer[k-1]| and |k<=ilimit+1| and
+ |cat=get_cat_code(cat_code_table,cur_chr)|. If an expanded code like
+ \.{\^\^A} or \.{\^\^df} appears in |buffer[(k-1)..(k+1)]| or
+ |buffer[(k-1)..(k+2)]|, we will store the corresponding code in |buffer[k-1]|
+ and shift the rest of the buffer left two or three places.
+
+*/
-@c
static boolean check_expanded_code(int *kk)
{
int l;
@@ -1666,26 +1797,38 @@ static boolean check_expanded_code(int *kk)
return false;
}
-@ All of the easy branches of |get_next| have now been taken care of. There is
-one more branch.
+/*tex
-@c static next_line_retval next_line(void)
+ All of the easy branches of |get_next| have now been taken care of. There is
+ one more branch.
+
+*/
+
+static next_line_retval next_line(void)
{
- boolean inhibit_eol = false; /* a way to end a pseudo file without trailing space */
+ /*tex A way to end a pseudo file without trailing space: */
+ boolean inhibit_eol = false;
if (iname > 17) {
- /* Read next line of file into |buffer|, or |goto restart| if the file has ended */
+ /*tex
+
+ Read next line of file into |buffer|, or |goto restart| if the file
+ has ended.
+
+ */
incr(line);
first = istart;
if (!force_eof) {
if (iname <= 20) {
- if (pseudo_input()) { /* not end of file */
- firm_up_the_line(); /* this sets |ilimit| */
+ if (pseudo_input()) {
+ /*tex Not end of file; set |ilimit|. */
+ firm_up_the_line();
line_catcode_table = DEFAULT_CAT_TABLE;
if ((iname == 19) && (pseudo_lines(pseudo_files) == null))
inhibit_eol = true;
} else if ((every_eof_par != null) && !eof_seen[iindex]) {
ilimit = first - 1;
- eof_seen[iindex] = true; /* fake one empty line */
+ /*tex Fake one empty line. */
+ eof_seen[iindex] = true;
if (iname != 19)
begin_token_list(every_eof_par, every_eof_text);
return next_line_restart;
@@ -1694,30 +1837,58 @@ one more branch.
}
} else {
if (iname == 21) {
- if (luacstring_input()) { /* not end of strings */
- firm_up_the_line();
- line_catcode_table = (short) luacstring_cattable();
- line_partial = (signed char) luacstring_partial();
- if (luacstring_final_line() || line_partial
- || line_catcode_table == NO_CAT_TABLE)
- inhibit_eol = true;
- if (!line_partial)
- istate = new_line;
- } else {
- force_eof = true;
+ halfword n = null;
+ int t = luacstring_input(&n);
+ switch (t) {
+ case 0:
+ force_eof = true;
+ break;
+ case 1:
+ /*tex string */
+ firm_up_the_line();
+ line_catcode_table = (short) luacstring_cattable();
+ line_partial = (signed char) luacstring_partial();
+ if (luacstring_final_line() || line_partial || line_catcode_table == NO_CAT_TABLE)
+ inhibit_eol = true;
+ if (!line_partial)
+ istate = new_line;
+ break;
+ case 2:
+ /*tex token */
+ cur_tok = n;
+ back_input();
+ /*tex Needs checking. */
+ return next_line_restart;
+ break;
+ case 3:
+ /*tex node */
+ if (n < biggest_char) {
+ /*tex |0x10FFFF == 1114111| */
+ cur_tok = token_val(node_cmd, n);
+ back_input();
+ /*tex Needs checking. */
+ return next_line_restart;
+ } else {
+ normal_warning("nodes","unable to store reference from lua in tex");
+ force_eof = true;
+ }
+ break;
+ default:
+ force_eof = true;
+ break;
}
+ } else if (lua_input_ln(cur_file, 0, true)) {
+ /*tex Not end of file, set |ilimit|. */
+ firm_up_the_line();
+ line_catcode_table = DEFAULT_CAT_TABLE;
+ } else if ((every_eof_par != null) && (!eof_seen[iindex])) {
+ ilimit = first - 1;
+ /* tex Fake one empty line. */
+ eof_seen[iindex] = true;
+ begin_token_list(every_eof_par, every_eof_text);
+ return next_line_restart;
} else {
- if (lua_input_ln(cur_file, 0, true)) { /* not end of file */
- firm_up_the_line(); /* this sets |ilimit| */
- line_catcode_table = DEFAULT_CAT_TABLE;
- } else if ((every_eof_par != null) && (!eof_seen[iindex])) {
- ilimit = first - 1;
- eof_seen[iindex] = true; /* fake one empty line */
- begin_token_list(every_eof_par, every_eof_text);
- return next_line_restart;
- } else {
- force_eof = true;
- }
+ force_eof = true;
}
}
}
@@ -1725,7 +1896,7 @@ one more branch.
if (tracing_nesting_par > 0)
if ((grp_stack[in_open] != cur_boundary) || (if_stack[in_open] != cond_ptr))
if (!((iname == 19) || (iname == 21))) {
- /* give warning for some unfinished groups and/or conditionals */
+ /*tex Give warning for some unfinished groups and/or conditionals. */
file_warning();
}
if ((iname > 21) || (iname == 20)) {
@@ -1733,7 +1904,7 @@ one more branch.
decr(open_parens);
}
force_eof = false;
- /* lua input or \.{\\scantextokens} */
+ /*tex \LUA\ input or \.{\\scantextokens} */
if (iname == 21 || iname == 19) {
end_file_reading();
} else {
@@ -1748,18 +1919,20 @@ one more branch.
else
buffer[ilimit] = (packed_ASCII_code) end_line_char_par;
first = ilimit + 1;
- iloc = istart; /* ready to read */
+ iloc = istart;
+ /*tex We're ready to read. */
} else {
if (!terminal_input) {
- /* \.{\\read} line has ended */
+ /*tex \.{\\read} line has ended */
cur_cmd = 0;
cur_chr = 0;
- return next_line_return; /* OUTER */
+ return next_line_return;
}
if (input_ptr > 0) {
- /* text was inserted during error recovery */
+ /*tex Text was inserted during error recovery. */
end_file_reading();
- return next_line_restart; /* resume previous level */
+ /*tex Resume previous level. */
+ return next_line_restart;
}
if (selector < log_only)
open_log_file();
@@ -1767,12 +1940,13 @@ one more branch.
if (end_line_char_inactive)
ilimit++;
if (ilimit == istart) {
- /* previous line was empty */
+ /*tex Previous line was empty. */
tprint_nl("(Please type a command or say `\\end')");
}
print_ln();
first = istart;
- prompt_input("*"); /* input on-line into |buffer| */
+ /*tex Input on-line into |buffer| */
+ prompt_input("*");
ilimit = last;
if (end_line_char_inactive)
ilimit--;
@@ -1781,9 +1955,11 @@ one more branch.
first = ilimit + 1;
iloc = istart;
} else {
- /*
+ /*tex
+
Nonstop mode, which is intended for overnight batch processing,
never waits for on-line input.
+
*/
fatal_error("*** (job aborted, no legal \\end found)");
}
@@ -1791,24 +1967,31 @@ one more branch.
return next_line_ok;
}
-@ Let's consider now what happens when |get_next| is looking at a token list.
+/*tex
+
+ Let's consider now what happens when |get_next| is looking at a token list.
+
+*/
-@c
static boolean get_next_tokenlist(void)
{
register halfword t = token_info(iloc);
- iloc = token_link(iloc); /* move to next */
+ /*tex Move to next. */
+ iloc = token_link(iloc);
if (t >= cs_token_flag) {
- /* a control sequence token */
+ /*tex A control sequence token */
cur_cs = t - cs_token_flag;
cur_cmd = eq_type(cur_cs);
if (cur_cmd >= outer_call_cmd) {
if (cur_cmd == dont_expand_cmd) {
- /*
- Get the next token, suppressing expansion. The present point in the program
- is reached only when the |expand| routine has inserted a special marker into
- the input. In this special case, |token_info(iloc)| is known to be a control
- sequence token, and |token_link(iloc)=null|.
+ /*tex
+
+ Get the next token, suppressing expansion. The present point
+ in the program is reached only when the |expand| routine has
+ inserted a special marker into the input. In this special
+ case, |token_info(iloc)| is known to be a control sequence
+ token, and |token_link(iloc)=null|.
+
*/
cur_cs = token_info(iloc) - cs_token_flag;
iloc = null;
@@ -1834,7 +2017,7 @@ static boolean get_next_tokenlist(void)
align_state--;
break;
case out_param_cmd:
- /* Insert macro parameter and |goto restart|; */
+ /*tex Insert macro parameter and |goto restart|. */
begin_token_list(param_stack[param_start + cur_chr - 1], parameter);
return false;
break;
@@ -1843,61 +2026,73 @@ static boolean get_next_tokenlist(void)
return true;
}
-@ Now we're ready to take the plunge into |get_next| itself. Parts of this
-routine are executed more often than any other instructions of \TeX.
-@^mastication@>@^inner loop@>
+/*tex
+
+ Now we're ready to take the plunge into |get_next| itself. Parts of this
+ routine are executed more often than any other instructions of \TeX.
-@ sets |cur_cmd|, |cur_chr|, |cur_cs| to next token
+ This sets |cur_cmd|, |cur_chr|, |cur_cs| to next token:
+
+*/
-@c
void get_next(void)
{
RESTART:
cur_cs = 0;
if (istate != token_list) {
- /* Input from external file, |goto restart| if no input found */
+ /*tex Input from external file, |goto restart| if no input found. */
if (!get_next_file())
goto RESTART;
} else {
if (iloc == null) {
end_token_list();
- goto RESTART; /* list exhausted, resume previous level */
+ /*tex List exhausted, resume previous level. */
+ goto RESTART;
} else if (!get_next_tokenlist()) {
- goto RESTART; /* parameter needs to be expanded */
+ /*tex Parameter needs to be expanded. */
+ goto RESTART;
}
}
- /* If an alignment entry has just ended, take appropriate action */
+ /*tex If an alignment entry has just ended, take appropriate action. */
if ((cur_cmd == tab_mark_cmd || cur_cmd == car_ret_cmd) && align_state == 0) {
insert_vj_template();
goto RESTART;
}
}
-@ Since |get_next| is used so frequently in \TeX, it is convenient to define
-three related procedures that do a little more:
-
-\yskip\hang|get_token| not only sets |cur_cmd| and |cur_chr|, it also sets
-|cur_tok|, a packed halfword version of the current token.
-
-\yskip\hang|get_x_token|, meaning ``get an expanded token,'' is like |get_token|,
-but if the current token turns out to be a user-defined control sequence (i.e., a
-macro call), or a conditional, or something like \.{\\topmark} or
-\.{\\expandafter} or \.{\\csname}, it is eliminated from the input by beginning
-the expansion of the macro or the evaluation of the conditional.
-
-\yskip\hang|x_token| is like |get_x_token| except that it assumes that |get_next|
-has already been called.
-
-\yskip\noindent In fact, these three procedures account for almost every use of
-|get_next|.
+/*tex
+
+ Since |get_next| is used so frequently in \TeX, it is convenient to define
+ three related procedures that do a little more:
+
+ \startitemize
+ \startitem
+ |get_token| not only sets |cur_cmd| and |cur_chr|, it also sets
+ |cur_tok|, a packed halfword version of the current token.
+ \stopitem
+ \startitem
+ |get_x_token|, meaning ``get an expanded token,'' is like
+ |get_token|, but if the current token turns out to be a user-defined
+ control sequence (i.e., a macro call), or a conditional, or something
+ like \.{\\topmark} or \.{\\expandafter} or \.{\\csname}, it is
+ eliminated from the input by beginning the expansion of the macro or
+ the evaluation of the conditional.
+ \stopitem
+ \startitem
+ |x_token| is like |get_x_token| except that it assumes that
+ |get_next| has already been called.
+ \stopitem
+ \stopitemize
+
+ In fact, these three procedures account for almost every use of |get_next|.
+ No new control sequences will be defined except during a call of |get_token|,
+ or when \.{\\csname} compresses a token list, because
+ |no_new_control_sequence| is always |true| at other times.
+
+ This sets |cur_cmd|, |cur_chr|, |cur_tok|:
-No new control sequences will be defined except during a call of |get_token|, or
-when \.{\\csname} compresses a token list, because |no_new_control_sequence| is
-always |true| at other times.
-
-@ sets |cur_cmd|, |cur_chr|, |cur_tok|
+*/
-@c
void get_token(void)
{
no_new_control_sequence = false;
@@ -1909,14 +2104,16 @@ void get_token(void)
cur_tok = cs_token_flag + cur_cs;
}
-@ changes the string |s| to a token list
+/*tex This changes the string |s| to a token list. */
-@c
halfword string_to_toks(const char *ss)
{
- halfword p; /* tail of the token list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword t; /* token being appended */
+ /*tex tail of the token list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex token being appended */
+ halfword t;
const char *s = ss;
const char *se = ss + strlen(s);
p = temp_token_head;
@@ -1933,29 +2130,37 @@ halfword string_to_toks(const char *ss)
return token_link(temp_token_head);
}
-@ The token lists for macros and for other things like \.{\\mark} and
-\.{\\output} and \.{\\write} are produced by a procedure called |scan_toks|.
+/*tex
-Before we get into the details of |scan_toks|, let's consider a much simpler
-task, that of converting the current string into a token list. The |str_toks|
-function does this; it classifies spaces as type |spacer| and everything else as
-type |other_char|.
+ The token lists for macros and for other things like \.{\\mark} and
+ \.{\\output} and \.{\\write} are produced by a procedure called |scan_toks|.
-The token list created by |str_toks| begins at |link(temp_token_head)| and ends
-at the value |p| that is returned. (If |p=temp_token_head|, the list is empty.)
+ Before we get into the details of |scan_toks|, let's consider a much simpler
+ task, that of converting the current string into a token list. The |str_toks|
+ function does this; it classifies spaces as type |spacer| and everything else
+ as type |other_char|.
-|lua_str_toks| is almost identical, but it also escapes the three symbols that
-|lua| considers special while scanning a literal string
+ The token list created by |str_toks| begins at |link(temp_token_head)| and
+ ends at the value |p| that is returned. (If |p=temp_token_head|, the list is
+ empty.)
-@ changes the string |str_pool[b..pool_ptr]| to a token list
+ |lua_str_toks| is almost identical, but it also escapes the three symbols
+ that |lua| considers special while scanning a literal string.
+
+ This changes the string |str_pool[b..pool_ptr]| to a token list:
+
+*/
-@c
halfword lua_str_toks(lstring b)
{
- halfword p; /* tail of the token list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword t; /* token being appended */
- unsigned char *k; /* index into string */
+ /*tex tail of the token list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex token being appended */
+ halfword t;
+ /*tex index into string */
+ unsigned char *k;
p = temp_token_head;
set_token_link(p, null);
k = (unsigned char *) b.s;
@@ -1978,18 +2183,25 @@ halfword lua_str_toks(lstring b)
return p;
}
-@ Incidentally, the main reason for wanting |str_toks| is the function
-|the_toks|, which has similar input/output characteristics.
+/*tex
+
+ Incidentally, the main reason for wanting |str_toks| is the function
+ |the_toks|, which has similar input/output characteristics.
-@ changes the string |str_pool[b..pool_ptr]| to a token list
+ This changes the string |str_pool[b..pool_ptr]| to a token list:
+
+*/
-@c
halfword str_toks(lstring s)
{
- halfword p; /* tail of the token list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword t; /* token being appended */
- unsigned char *k, *l; /* index into string */
+ /*tex tail of the token list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex token being appended */
+ halfword t;
+ /*tex index into string */
+ unsigned char *k, *l;
p = temp_token_head;
set_token_link(p, null);
k = s.s;
@@ -2006,18 +2218,25 @@ halfword str_toks(lstring s)
return p;
}
-/*
- hh: most of the converter is similar to the one i made for macro so at some point i
- can make a helper; also todo: there is no need to go through the pool
+/*tex
+
+ Most of the converter is similar to the one i made for macro so at some point
+ I can make a helper; also todo: there is no need to go through the pool.
*/
+/*tex Change the string |str_pool[b..pool_ptr]| to a token list. */
+
halfword str_scan_toks(int ct, lstring s)
-{ /* changes the string |str_pool[b..pool_ptr]| to a token list */
- halfword p; /* tail of the token list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- halfword t; /* token being appended */
- unsigned char *k, *l; /* index into string */
+{
+ /*tex tail of the token list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex token being appended */
+ halfword t;
+ /*tex index into string */
+ unsigned char *k, *l;
int cc;
p = temp_token_head;
set_token_link(p, null);
@@ -2028,7 +2247,7 @@ halfword str_scan_toks(int ct, lstring s)
k += utf8_size(t);
cc = get_cat_code(ct,t);
if (cc == 0) {
- /* we have a potential control sequence so we check for it */
+ /*tex We have a potential control sequence so we check for it. */
int _lname = 0 ;
int _s = 0 ;
int _c = 0 ;
@@ -2042,7 +2261,7 @@ halfword str_scan_toks(int ct, lstring s)
k += _s ;
_lname = _lname + _s ;
} else if (_c == 10) {
- /* we ignore a trailing space like normal scanning does */
+ /*tex We ignore a trailing space like normal scanning does. */
k += _s ;
break ;
} else {
@@ -2050,7 +2269,7 @@ halfword str_scan_toks(int ct, lstring s)
}
}
if (_s > 0) {
- /* we have a potential \cs */
+ /*tex We have a potential |\cs|. */
_cs = string_lookup((const char *) _name, _lname);
if (_cs == undefined_control_sequence) {
/* let's play safe and backtrack */
@@ -2060,15 +2279,24 @@ halfword str_scan_toks(int ct, lstring s)
t = cs_token_flag + _cs;
}
} else {
- /* just a character with some meaning, so \unknown becomes effectively */
- /* \\unknown assuming that \\ has some useful meaning of course */
+ /*tex
+
+ Just a character with some meaning, so |\unknown| becomes
+ effectively |\unknown| assuming that |\\| has some useful
+ meaning of course.
+
+ */
t = cc * (1<<21) + t ;
k = _name ;
}
} else {
- /* whatever token, so for instance $x^2$ just works given a tex */
- /* catcode regime */
+ /*tex
+
+ Whatever token, so for instance $x^2$ just works given a \TEX\
+ catcode regime.
+
+ */
t = cc * (1<<21) + t ;
}
fast_store_new_token(t);
@@ -2077,171 +2305,227 @@ halfword str_scan_toks(int ct, lstring s)
return p;
}
-@ Here's part of the |expand| subroutine that we are now ready to complete:
+/*tex
+
+ Here's part of the |expand| subroutine that we are now ready to complete:
+
+*/
-@c
void ins_the_toks(void)
{
(void) the_toks();
ins_list(token_link(temp_token_head));
}
-#define set_toks_register(n,t,g) { \
+#define set_toks_register(n,t,g) do { \
int a = (g>0) ? 4 : 0; \
halfword ref = get_avail(); \
set_token_ref_count(ref, 0); \
set_token_link(ref, token_link(t)); \
define(n + toks_base, call_cmd, ref); \
-}
+} while (0)
+
+#define append_copied_toks_list(s,t) do { \
+ halfword p; \
+ halfword q; \
+ p = temp_token_head; \
+ set_token_link(p, null); \
+ while (s != null) { \
+ fast_store_new_token(token_info(s)); \
+ s = token_link(s); \
+ } \
+ while (t != null) { \
+ fast_store_new_token(token_info(t)); \
+ t = token_link(t); \
+ } \
+ } while (0)
+
+
+/*tex
+
+ \starttabulate[|T||T||]
+ \NC 0 \NC \type {toksapp} \NC 1 \NC \type {etoksapp} \NC \NR
+ \NC 2 \NC \type {tokspre} \NC 3 \NC \type {etokspre} \NC \NR
+ \NC 4 \NC \type {gtoksapp} \NC 5 \NC \type {xtoksapp} \NC \NR
+ \NC 6 \NC \type {gtokspre} \NC 7 \NC \type {xtokspre} \NC \NR
+ \stoptabulate
+
+*/
void combine_the_toks(int how)
{
- halfword nt;
+ halfword source = null;
+ halfword target = null;
+ halfword append = (how == 0) || (how == 1) || (how == 4) || (how == 5);
+ halfword expand = odd(how);
+ halfword global = how > 3;
+ halfword nt, ns, s, t, p, q, h;
get_x_token();
- /* target */
+ /*tex The target. */
if (cur_cmd == assign_toks_cmd) {
+ /*tex Check range. */
nt = equiv(cur_cs) - toks_base;
- /* check range */
} else {
back_input();
- scan_int();
+ scan_register_num();
nt = cur_val;
}
- /* source */
+ /*tex The source. */
do {
get_x_token();
} while (cur_cmd == spacer_cmd);
if (cur_cmd == left_brace_cmd) {
- halfword x, source;
back_input();
- x = scan_toks(false,how > 1); /* expanded or not */
+ scan_toks(false,expand);
source = def_ref;
- /* action */
+ /*tex The action. */
if (source != null) {
- halfword target = toks(nt);
+ target = toks(nt);
if (target == null) {
- set_toks_register(nt,source,0);
+ set_toks_register(nt,source,global);
} else {
- halfword s = token_link(source);
+ s = token_link(source);
if (s != null) {
- halfword t = token_link(target);
+ t = token_link(target);
if (t == null) {
- /* can this happen ? */
+ /*tex Can this happen? */
set_token_link(target, s);
- } else if (odd(how)) {
- /* prepend */
- if (cur_level != eq_level_field(eqtb[toks_base+nt])) {
- halfword p = temp_token_head;
- halfword q;
- set_token_link(p, s); /* s = head, x = tail */
- p = x;
- while (t != null) {
- fast_store_new_token(token_info(t));
- t = token_link(t);
+ } else if (append) {
+ /*tex Append. */
+ if (token_ref_count(target) == 0) {
+ p = t;
+ while (token_link(p) != null) {
+ p = token_link(p);
+ }
+ while (s != null) {
+ fast_store_new_token(token_info(s));
+ s = token_link(s);
}
- set_toks_register(nt,temp_token_head,0);
} else {
- set_token_link(x,t);
- set_token_link(target,s);
+ token_ref_count(target)--;
+ append_copied_toks_list(t,s);
+ set_toks_register(nt,temp_token_head,global);
}
} else {
- /* append */
- if (cur_level != eq_level_field(eqtb[toks_base+nt])) {
- halfword p = temp_token_head;
- halfword q;
- set_token_link(p, null);
- while (t != null) {
- fast_store_new_token(token_info(t));
- t = token_link(t);
+ /* prepend */
+ if (token_ref_count(target) == 0) {
+ h = null;
+ p = null ;
+ while (s != null) {
+ fast_store_new_token(token_info(s));
+ if (h == null) {
+ h = p;
+ }
+ s = token_link(s);
}
- set_token_link(p,s);
- set_toks_register(nt,temp_token_head,0);
+ set_token_link(p,t);
+ set_token_link(target,h);
} else {
- while (token_link(t) != null) {
- t = token_link(t);
- }
- set_token_link(t,s);
+ token_ref_count(target)--;
+ append_copied_toks_list(s,t);
+ set_toks_register(nt,temp_token_head,global);
}
}
}
}
}
} else {
- halfword source, ns;
if (cur_cmd == assign_toks_cmd) {
ns = equiv(cur_cs) - toks_base;
- /* check range */
+ /*tex Check range. */
} else {
- back_input();
- scan_int();
+ scan_register_num();
ns = cur_val;
}
- /* action */
+ /*tex The action. */
source = toks(ns);
if (source != null) {
- halfword target = toks(nt);
+ target = toks(nt);
if (target == null) {
+ /*tex The assign. */
+ token_ref_count(source)++;
equiv(toks_base+nt) = source;
- equiv(toks_base+ns) = null;
+ return;
+ }
+ s = token_link(source);
+ t = token_link(target);
+ if (append) {
+ /*tex Append. */
+ if (token_ref_count(target) == 0) {
+ p = t;
+ while (token_link(p) != null) {
+ p = token_link(p);
+ }
+ while (s != null) {
+ fast_store_new_token(token_info(s));
+ s = token_link(s);
+ }
+ } else {
+ token_ref_count(target)--;
+ append_copied_toks_list(t,s);
+ set_toks_register(nt,temp_token_head,global);
+ }
} else {
- halfword s = token_link(source);
- if (s != null) {
- halfword t = token_link(target);
- if (t == null) {
- set_token_link(target, s);
- } else if (odd(how)) {
- /* prepend */
- halfword x = s;
- while (token_link(x) != null) {
- x = token_link(x);
- }
- set_token_link(x,t);
- set_token_link(target,s);
- } else {
- /* append */
- while (token_link(t) != null) {
- t = token_link(t);
+ /*tex Prepend. */
+ if (token_ref_count(target) == 0) {
+ h = null;
+ p = null;
+ while (s != null) {
+ fast_store_new_token(token_info(s));
+ if (h == null) {
+ h = p;
}
- set_token_link(t,s);
+ s = token_link(s);
}
- equiv(toks_base+ns) = null;
+ set_token_link(p,t);
+ set_token_link(target,h);
+ } else {
+ token_ref_count(target)--;
+ append_copied_toks_list(s,t);
+ set_toks_register(nt,temp_token_head,global);
}
}
}
}
}
-@ This routine, used in the next one, prints the job name, possibly modified by
-the |process_jobname| callback.
+/*tex
+
+ This routine, used in the next one, prints the job name, possibly modified by
+ the |process_jobname| callback.
+
+*/
-@c
static void print_job_name(void)
{
- if (job_name) {
- char *s, *ss; /* C strings for jobname before and after processing */
- int callback_id, lua_retval;
- s = (char*)str_string(job_name);
- callback_id = callback_defined(process_jobname_callback);
- if (callback_id > 0) {
- lua_retval = run_callback(callback_id, "S->S", s, &ss);
- if ((lua_retval == true) && (ss != NULL))
- s = ss;
- }
- tprint(s);
- } else {
- print(job_name);
- }
+ if (job_name) {
+ /*tex C strings for jobname before and after processing. */
+ char *s, *ss;
+ int callback_id, lua_retval;
+ s = (char*)str_string(job_name);
+ callback_id = callback_defined(process_jobname_callback);
+ if (callback_id > 0) {
+ lua_retval = run_callback(callback_id, "S->S", s, &ss);
+ if ((lua_retval == true) && (ss != NULL))
+ s = ss;
+ }
+ tprint(s);
+ } else {
+ print(job_name);
+ }
}
-@ Here is a routine that print the result of a convert command, using the
-argument |i|. It returns |false | if it does not know to print the code |c|. The
-function exists because lua code and tex code can both call it to convert
-something.
+/*tex
-@ Parse optional lua state integer, or an instance name to be stored in |sn| and
-get the next non-blank non-relax non-call token.
+ Here is a routine that print the result of a convert command, using the
+ argument |i|. It returns |false | if it does not know to print the code |c|.
+ The function exists because lua code and tex code can both call it to convert
+ something.
-@c
+ Parse optional \LUA\ state integer, or an instance name to be stored in |sn|
+ and get the next non-blank non-relax non-call token.
+
+*/
int scan_lua_state(void)
{
@@ -2263,15 +2547,18 @@ int scan_lua_state(void)
return sn;
}
-@ The procedure |conv_toks| uses |str_toks| to insert the token list for
-|convert| functions into the scanner; `\.{\\outer}' control sequences are allowed
-to follow `\.{\\string}' and `\.{\\meaning}'.
+/*tex
+
+ The procedure |conv_toks| uses |str_toks| to insert the token list for
+ |convert| functions into the scanner; `\.{\\outer}' control sequences are
+ allowed to follow `\.{\\string}' and `\.{\\meaning}'.
-The extra temp string |u| is needed because |pdf_scan_ext_toks| incorporates any
-pending string in its output. In order to save such a pending string, we have to
-create a temporary string that is destroyed immediately after.
+ The extra temp string |u| is needed because |pdf_scan_ext_toks| incorporates
+ any pending string in its output. In order to save such a pending string, we
+ have to create a temporary string that is destroyed immediately after.
+
+*/
-@c
#define push_selector { \
old_setting = selector; \
selector = new_string; \
@@ -2327,6 +2614,8 @@ static int do_variable_pdf(halfword c)
else if (scan_keyword("pkfixeddpi")) { do_variable_backend_int(c_pdf_pk_fixed_dpi); }
else if (scan_keyword("suppressoptionalinfo")) { do_variable_backend_int(c_pdf_suppress_optional_info); }
else if (scan_keyword("omitcidset")) { do_variable_backend_int(c_pdf_omit_cidset); }
+ else if (scan_keyword("omitcharset")) { do_variable_backend_int(c_pdf_omit_charset); }
+ else if (scan_keyword("recompress")) { do_variable_backend_int(c_pdf_recompress); }
else if (scan_keyword("horigin")) { do_variable_backend_dimen(d_pdf_h_origin); }
else if (scan_keyword("vorigin")) { do_variable_backend_dimen(d_pdf_v_origin); }
@@ -2353,23 +2642,30 @@ static int do_feedback_dvi(halfword c)
return 0;
}
-/* codes not really needed but cleaner when testing */
+/*tex Codes not really needed but cleaner when testing */
#define pdftex_version 140 /* these values will not change any more */
#define pdftex_revision "0" /* these values will not change any more */
static int do_feedback_pdf(halfword c)
{
- int old_setting; /* holds |selector| setting */
- int save_scanner_status; /* |scanner_status| upon entry */
- halfword save_def_ref; /* |def_ref| upon entry, important if inside `\.{\\message}' */
+ /*tex holds |selector| setting */
+ int old_setting;
+ /*tex |scanner_status| upon entry */
+ int save_scanner_status;
+ /*tex |def_ref| upon entry, important if inside `\.{\\message}' */
+ halfword save_def_ref;
halfword save_warning_index;
- boolean bool; /* temp boolean */
- str_number s; /* first temp string */
- int ff; /* for use with |set_ff| */
- str_number u = 0; /* third temp string, will become non-nil if a string is already being built */
- char *str; /* color stack init str */
-
+ /*tex temp boolean */
+ boolean bool;
+ /*tex first temp string */
+ str_number s;
+ /*tex for use with |set_ff| */
+ int ff;
+ /*tex third temp string, will become non-nil if a string is already being built */
+ str_number u = 0;
+ /*tex color stack init str */
+ char *str;
if (scan_keyword("lastlink")) {
push_selector;
print_int(pdf_last_link);
@@ -2394,7 +2690,7 @@ static int do_feedback_pdf(halfword c)
pop_selector;
} else if (scan_keyword("creationdate")) {
ins_list(string_to_toks(getcreationdate(static_pdf)));
- /* no further action */
+ /*tex No further action. */
return 2;
} else if (scan_keyword("fontname")) {
scan_font_ident();
@@ -2488,19 +2784,27 @@ static int do_feedback_pdf(halfword c)
void conv_toks(void)
{
- int old_setting; /* holds |selector| setting */
+ /*tex holds |selector| setting */
+ int old_setting;
halfword p, q;
- int save_scanner_status; /* |scanner_status| upon entry */
- halfword save_def_ref; /* |def_ref| upon entry, important if inside `\.{\\message}' */
+ /*tex |scanner_status| upon entry */
+ int save_scanner_status;
+ /*tex |def_ref| upon entry, important if inside `\.{\\message}' */
+ halfword save_def_ref;
halfword save_warning_index;
- boolean bool; /* temp boolean */
- str_number s; /* first temp string */
- int sn; /* lua chunk name */
- str_number u = 0; /* third temp string, will become non-nil if a string is already being built */
- int c = cur_chr; /* desired type of conversion */
+ /*tex temp boolean */
+ boolean bool;
+ /*tex first temp string */
+ str_number s;
+ /*tex lua chunk name */
+ int sn;
+ /*tex third temp string, will become non-nil if a string is already being built */
+ str_number u = 0;
+ /*tex desired type of conversion */
+ int c = cur_chr;
str_number str;
int i = 0;
- /* Scan the argument for command |c| */
+ /*tex Scan the argument for command |c|. */
switch (c) {
case number_code:
scan_int();
@@ -2520,7 +2824,20 @@ void conv_toks(void)
if (luacstrings > 0)
lua_string_start();
}
- /* no further action */
+ return;
+ break;
+ case lua_bytecode_code:
+ scan_int();
+ if (cur_val < 0 || cur_val > 65535) {
+ normal_error("luabytecode", "invalid number");
+ } else {
+ u = save_cur_string();
+ luacstrings = 0;
+ luabytecodecall(cur_val);
+ restore_cur_string(u);
+ if (luacstrings > 0)
+ lua_string_start();
+ }
return;
break;
case lua_code:
@@ -2537,10 +2854,10 @@ void conv_toks(void)
luacstrings = 0;
luatokencall(s, sn);
delete_token_ref(s);
- restore_cur_string(u); /* TODO: check this, was different */
+ restore_cur_string(u);
if (luacstrings > 0)
lua_string_start();
- /* no further action */
+ /*tex No further action. */
return;
break;
case expanded_code:
@@ -2554,7 +2871,56 @@ void conv_toks(void)
ins_list(token_link(def_ref));
def_ref = save_def_ref;
restore_cur_string(u);
- /* no further action */
+ /*tex No further action. */
+ return;
+ break;
+ case immediate_assignment_code:
+ case immediate_assigned_code:
+ /*tex
+
+ This is on-the-road-to-bachotex brain-wave but it needs a bit
+ more testing. A first variant did more in sequence till a relax
+ of spacer was seen (like do_assignments). It permits for instance
+ setting counters in full expansion.
+
+ */
+ save_scanner_status = scanner_status;
+ save_warning_index = warning_index;
+ save_def_ref = def_ref;
+ u = save_cur_string();
+ do {
+ get_x_token();
+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
+ if (c == immediate_assignment_code) {
+ /*tex one-step do_assignment */
+ if (cur_cmd > max_non_prefixed_command) {
+ set_box_allowed = false;
+ prefixed_command();
+ set_box_allowed = true;
+ }
+ /*tex done */
+ } else {
+ /*tex pseudo token list do_assignment */
+ if (cur_cmd == left_brace_cmd) {
+ while (1) {
+ do {
+ get_x_token();
+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
+ if (cur_cmd == right_brace_cmd) {
+ break;
+ } else {
+ set_box_allowed = false;
+ prefixed_command();
+ set_box_allowed = true;
+ }
+ }
+ }
+ /*tex done */
+ }
+ warning_index = save_warning_index;
+ scanner_status = save_scanner_status;
+ def_ref = save_def_ref;
+ restore_cur_string(u);
return;
break;
case math_style_code:
@@ -2629,7 +2995,7 @@ void conv_toks(void)
free(escstr.s);
return;
}
- /* no further action */
+ /*tex no further action */
break;
case font_id_code:
scan_font_ident();
@@ -2672,9 +3038,12 @@ void conv_toks(void)
p = list_ptr(box(cur_val));
if (p != null) {
p = tail_of_list(p);
- /*
- there can be a leftskip, rightskip, penalty and yes, also a disc node with a nesting
- node that points to glue spec ... and we don't want to analyze that messy lot
+ /*tex
+
+ There can be a leftskip, rightskip, penalty and yes, also a
+ disc node with a nesting node that points to glue spec ...
+ and we don't want to analyze that messy lot.
+
*/
while ((p != null) && (type(p) == glue_node)) {
p = alink(p);
@@ -2685,10 +3054,12 @@ void conv_toks(void)
if ((q != null) && ((type(q) == margin_kern_node) && (subtype(q) == right_side))) {
p = q;
} else {
- /*
- officially we should look in the replace but currently protrusion doesn't
- work anyway with "foo\discretionary{}{}{bar-} " (no following char) so we
- don't need it now
+ /*tex
+
+ Officially we should look in the replace but
+ currently protrusion doesn't work anyway with
+ "foo\discretionary{}{}{bar-} " (no following
+ char) so we don't need it now.
*/
}
}
@@ -2832,7 +3203,7 @@ void do_feedback(void)
return ;
}
if (done==0) {
- /* we recover */
+ /*tex We recover. */
normal_warning("pdf backend","unexpected use of \\pdffeedback");
return;
} else if (done==2) {
@@ -2857,7 +3228,7 @@ void do_variable(void)
case dvi_variable_code:
done = do_variable_dvi(c);
if (done==0) {
- /* we recover */
+ /*tex We recover. */
normal_warning("dvi backend","unexpected use of \\dvivariable");
}
return;
@@ -2865,7 +3236,7 @@ void do_variable(void)
case pdf_variable_code:
done = do_variable_pdf(c);
if (done==0) {
- /* we recover */
+ /*tex We recover. */
normal_warning("pdf backend","unexpected use of \\pdfvariable");
}
return;
@@ -2876,33 +3247,8 @@ void do_variable(void)
}
}
-/*
- The following code is not used as we can only set math options and not query them. If
- an option is really important we will provide a proper variable. Most options are not
- meant for users anyway but for development.
-*/
-
-/*
+/*tex This boolean is keeping track of the lua string escape state */
-#define do_mathoption_int(i) \
- cur_cmd = assign_int_cmd; \
- cur_val = mathoption_int_base + i; \
- cur_tok = token_val(cur_cmd, cur_val); \
- back_input();
-
-void do_mathoption(void)
-{
- if (scan_keyword("old")) { do_mathoption_int(c_mathoption_no_italic_compensation_code); }
- if (scan_keyword("noitaliccompensation")) { do_mathoption_int(c_mathoption_no_char_italic_code); }
- else if (scan_keyword("nocharitalic")) { do_mathoption_int(c_mathoption_use_old_fraction_scaling_code); }
- else if (scan_keyword("useoldfractionscaling")) { do_mathoption_int(c_mathoption_old_code); }
- else if (scan_keyword("umathcodemeaning")) { do_mathoption_int(c_mathoption_umathcode_meaning_code); }
-}
-
-*/
-
-@ This boolean is keeping track of the lua string escape state
-@c
boolean in_lua_escape;
static int the_convert_string_dvi(halfword c, int i)
@@ -2948,7 +3294,7 @@ static int the_convert_string_pdf(halfword c, int i)
str_number the_convert_string(halfword c, int i)
{
- int old_setting; /* saved |selector| setting */
+ int old_setting;
str_number ret = 0;
boolean done = true ;
old_setting = selector;
@@ -3017,14 +3363,14 @@ str_number the_convert_string(halfword c, int i)
case font_identifier_code:
print_font_identifier(i);
break;
- /* backend: this might become obsolete */
+ /*tex Backend: this might become obsolete! */
case dvi_feedback_code:
done = the_convert_string_dvi(c,i);
break;
case pdf_feedback_code:
done = the_convert_string_pdf(c,i);
break;
- /* done */
+ /*tex done */
default:
done = false;
break;
@@ -3036,16 +3382,24 @@ str_number the_convert_string(halfword c, int i)
return ret;
}
-@ Another way to create a token list is via the \.{\\read} command. The sixteen
-files potentially usable for reading appear in the following global variables.
-The value of |read_open[n]| will be |closed| if stream number |n| has not been
-opened or if it has been fully read; |just_open| if an \.{\\openin} but not a
-\.{\\read} has been done; and |normal| if it is open and ready to read the next
-line.
+/*tex
+
+ Another way to create a token list is via the \.{\\read} command. The sixteen
+ files potentially usable for reading appear in the following global
+ variables. The value of |read_open[n]| will be |closed| if stream number |n|
+ has not been opened or if it has been fully read; |just_open| if an
+ \.{\\openin} but not a \.{\\read} has been done; and |normal| if it is open
+ and ready to read the next line.
+
+*/
+
+/*tex used for \.{\\read} */
+
+FILE *read_file[16];
-@c
-FILE *read_file[16]; /* used for \.{\\read} */
-int read_open[17]; /* state of |read_file[n]| */
+/*tex state of |read_file[n]| */
+
+int read_open[17];
void initialize_read(void)
{
@@ -3054,41 +3408,51 @@ void initialize_read(void)
read_open[k] = closed;
}
-@ The |read_toks| procedure constructs a token list like that for any macro
-definition, and makes |cur_val| point to it. Parameter |r| points to the control
-sequence that will receive this token list.
+/*tex
+
+ The |read_toks| procedure constructs a token list like that for any macro
+ definition, and makes |cur_val| point to it. Parameter |r| points to the
+ control sequence that will receive this token list.
+
+*/
-@c
void read_toks(int n, halfword r, halfword j)
{
- halfword p; /* tail of the token list */
- halfword q; /* new node being added to the token list via |store_new_token| */
- int s; /* saved value of |align_state| */
- int m; /* stream number */
+ /*tex tail of the token list */
+ halfword p;
+ /*tex new node being added to the token list via |store_new_token| */
+ halfword q;
+ /*tex saved value of |align_state| */
+ int s;
+ /*tex stream number */
+ int m;
scanner_status = defining;
warning_index = r;
p = get_avail();
def_ref = p;
set_token_ref_count(def_ref, 0);
- p = def_ref; /* the reference count */
+ /*tex the reference count */
+ p = def_ref;
store_new_token(end_match_token);
if ((n < 0) || (n > 15))
m = 16;
else
m = n;
s = align_state;
- align_state = 1000000; /* disable tab marks, etc. */
+ /*tex disable tab marks, etc. */
+ align_state = 1000000;
do {
- /* Input and store tokens from the next line of the file */
+ /*tex Input and store tokens from the next line of the file. */
begin_file_reading();
iname = m + 1;
if (read_open[m] == closed) {
- /*
- Input for \.{\\read} from the terminal
+ /*tex
+
+ Input for \.{\\read} from the terminal. We input on-line into the
+ |buffer| array, prompting the user explicitly if |n>=0|. The
+ value of |n| is set negative so that additional prompts will not
+ be given in the case of multi-line input.
- Here we input on-line into the |buffer| array, prompting the user explicitly
- if |n>=0|. The value of |n| is set negative so that additional prompts
- will not be given in the case of multi-line input.
*/
if (interaction > nonstop_mode) {
if (n < 0) {
@@ -3106,11 +3470,12 @@ void read_toks(int n, halfword r, halfword j)
}
} else if (read_open[m] == just_open) {
- /*
- Input the first line of |read_file[m]|
+ /*tex
+
+ Input the first line of |read_file[m]|. The first line of a file
+ must be treated specially, since |lua_input_ln| must be told not
+ to start with |get|.
- The first line of a file must be treated specially, since |lua_input_ln|
- must be told not to start with |get|.
*/
if (lua_input_ln(read_file[m], (m + 1), false)) {
read_open[m] = normal;
@@ -3120,10 +3485,11 @@ void read_toks(int n, halfword r, halfword j)
}
} else {
- /*
- Input the next line of |read_file[m]|
+ /*tex
+
+ Input the next line of |read_file[m]|. An empty line is appended
+ at the end of a |read_file|.
- An empty line is appended at the end of a |read_file|.
*/
if (!lua_input_ln(read_file[m], (m + 1), true)) {
lua_a_close_in(read_file[m], (m + 1));
@@ -3146,10 +3512,10 @@ void read_toks(int n, halfword r, halfword j)
first = ilimit + 1;
iloc = istart;
istate = new_line;
- /* Handle \.{\\readline} and |goto done|; */
+ /*tex Handle \.{\\readline} and |goto done|. */
if (j == 1) {
while (iloc <= ilimit) {
- /* current line not yet finished */
+ /*tex Current line not yet finished. */
do_buffer_to_unichar(cur_chr, iloc);
if (cur_chr == ' ')
cur_tok = space_token;
@@ -3161,11 +3527,11 @@ void read_toks(int n, halfword r, halfword j)
while (1) {
get_token();
if (cur_tok == 0) {
- /* |cur_cmd=cur_chr=0| will occur at the end of the line */
+ /*tex |cur_cmd=cur_chr=0| will occur at the end of the line. */
break;
}
if (align_state < 1000000) {
- /* unmatched `\.\}' aborts the line */
+ /*tex Unmatched right brace aborts the line. */
do {
get_token();
} while (cur_tok != 0);
@@ -3183,9 +3549,8 @@ void read_toks(int n, halfword r, halfword j)
align_state = s;
}
-@ return a string from tokens list
+/*tex Return a string from tokens list: */
-@c
str_number tokens_to_string(halfword p)
{
int old_setting;
@@ -3198,11 +3563,20 @@ str_number tokens_to_string(halfword p)
return make_string();
}
-@ @c
+/*tex
+
+ Values like 512 and 128 also work ok. There is not much to gain in
+ optimization here.
+
+*/
+
+#define alloci_default 1024
+#define alloci_step 256
+
#define make_room(a) \
if ((unsigned)i+a+1>alloci) { \
- ret = xrealloc(ret,(alloci+64)); \
- alloci = alloci + 64; \
+ ret = xrealloc(ret,(alloci+alloci_step)); \
+ alloci = alloci + alloci_step; \
}
#define append_i_byte(a) ret[i++] = (char)(a)
@@ -3247,11 +3621,14 @@ str_number tokens_to_string(halfword p)
#define is_cat_letter(a) \
(get_char_cat_code(pool_to_unichar(str_string((a)))) == 11)
-@ the actual token conversion in this function is now functionally equivalent to
-|show_token_list|, except that it always prints the whole token list. TODO: check
-whether this causes problems in the lua library.
+/*tex
+
+ The actual token conversion in this function is now functionally equivalent
+ to |show_token_list|, except that it always prints the whole token list.
+ TODO: check whether this causes problems in the lua library.
+
+*/
-@c
char *tokenlist_to_cstring(int pp, int inhibit_par, int *siz)
{
register int p, c, m;
@@ -3262,7 +3639,7 @@ char *tokenlist_to_cstring(int pp, int inhibit_par, int *siz)
char *ret;
int match_chr = '#';
int n = '0';
- unsigned alloci = 1024;
+ unsigned alloci = alloci_default;
int i = 0;
p = pp;
if (p == null) {
@@ -3271,7 +3648,8 @@ char *tokenlist_to_cstring(int pp, int inhibit_par, int *siz)
return NULL;
}
ret = xmalloc(alloci);
- p = token_link(p); /* skip refcount */
+ /*tex Skip refcount. */
+ p = token_link(p);
if (p != null) {
e = escape_char_par;
}
@@ -3389,7 +3767,7 @@ char *tokenlist_to_xstring(int pp, int inhibit_par, int *siz)
char *ret;
int match_chr = '#';
int n = '0';
- unsigned alloci = 1024;
+ unsigned alloci = alloci_default;
int i = 0;
int skipping = 1;
p = pp;
@@ -3399,13 +3777,14 @@ char *tokenlist_to_xstring(int pp, int inhibit_par, int *siz)
return NULL;
}
ret = xmalloc(alloci);
- p = token_link(p); /* skip refcount */
+ /*tex Skip refcount. */
+ p = token_link(p);
if (p != null) {
e = escape_char_par;
}
while (p != null) {
if (p < (int) fix_mem_min || p > (int) fix_mem_end) {
- /* nothing */
+ /*tex Nothing done. */
break;
}
infop = token_info(p);
@@ -3413,13 +3792,12 @@ char *tokenlist_to_xstring(int pp, int inhibit_par, int *siz)
if (!(inhibit_par && infop == par_token)) {
q = infop - cs_token_flag;
if (q < hash_base) {
- /* nothing */
+ /*tex Nothing done. */
} else if ((q >= undefined_control_sequence) && ((q <= eqtb_size) || (q > eqtb_size + hash_extra))) {
- /* nothing */
+ /*tex Nothing done. */
} else if ((cs_text(q) < 0) || (cs_text(q) >= str_ptr)) {
- /* nothing */
- } else {
-if (!skipping) {
+ /*tex Nothing done. */
+ } else if (!skipping) {
str_number txt = cs_text(q);
sh = makecstring(txt);
s = sh;
@@ -3440,12 +3818,11 @@ if (!skipping) {
}
}
free(sh);
-}
}
}
} else {
if (infop < 0) {
- /* nothing */
+ /*tex Nothing done. */
} else {
m = token_cmd(infop);
c = token_chr(infop);
@@ -3459,54 +3836,54 @@ if (!skipping) {
case spacer_cmd:
case letter_cmd:
case other_char_cmd:
-if (!skipping) {
- Print_uchar(c);
-}
+ if (!skipping) {
+ Print_uchar(c);
+ }
break;
case mac_param_cmd:
-if (!skipping) {
- if (!in_lua_escape && (is_in_csname==0))
+ if (!skipping) {
+ if (!in_lua_escape && (is_in_csname==0))
+ Print_uchar(c);
Print_uchar(c);
- Print_uchar(c);
-}
+ }
break;
case out_param_cmd:
-if (!skipping) {
- Print_uchar(match_chr);
-}
+ if (!skipping) {
+ Print_uchar(match_chr);
+ }
if (c <= 9) {
-if (!skipping) {
- Print_char(c + '0');
-}
+ if (!skipping) {
+ Print_char(c + '0');
+ }
} else {
- /* nothing */
+ /*tex Nothing done. */
goto EXIT;
}
break;
case match_cmd:
match_chr = c;
-if (!skipping) {
- Print_uchar(c);
-}
+ if (!skipping) {
+ Print_uchar(c);
+ }
n++;
-if (!skipping) {
- Print_char(n);
-}
+ if (!skipping) {
+ Print_char(n);
+ }
if (n > '9')
goto EXIT;
break;
case end_match_cmd:
if (c == 0) {
-if (!skipping) {
- Print_char('-');
- Print_char('>');
-}
+ if (!skipping) {
+ Print_char('-');
+ Print_char('>');
+ }
i = 0;
-skipping = 0 ;
+ skipping = 0 ;
}
break;
default:
- /* nothing */
+ /*tex Nothing done. */
break;
}
}
@@ -3520,7 +3897,6 @@ skipping = 0 ;
return ret;
}
-@ @c
lstring *tokenlist_to_lstring(int pp, int inhibit_par)
{
int siz;
@@ -3530,7 +3906,6 @@ lstring *tokenlist_to_lstring(int pp, int inhibit_par)
return ret;
}
-@ @c
void free_lstring(lstring * ls)
{
if (ls == NULL)
diff --git a/Build/source/texk/web2c/luatexdir/utils/avlstuff.c b/Build/source/texk/web2c/luatexdir/utils/avlstuff.c
new file mode 100644
index 00000000000..887ba4f46e8
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/utils/avlstuff.c
@@ -0,0 +1,63 @@
+/*
+
+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/>.
+
+*/
+
+#include "ptexlib.h"
+#include "utils/avl.h"
+
+/*tex
+
+ Some memory management functions for AVL.
+
+*/
+
+static void *avl_xmalloc(struct libavl_allocator *allocator, size_t size)
+{
+ assert(allocator != NULL && size > 0);
+ return xmalloc((unsigned) size);
+}
+
+static void avl_xfree(struct libavl_allocator *allocator, void *block)
+{
+ assert(allocator != NULL && block != NULL);
+ xfree(block);
+}
+
+struct libavl_allocator avl_xallocator = {
+ avl_xmalloc,
+ avl_xfree
+};
+
+/*tex
+
+ The general AVL comparison functions.
+
+*/
+int comp_int_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ cmp_return(*(const int *) pa, *(const int *) pb);
+ return 0;
+}
+
+int comp_string_entry(const void *pa, const void *pb, void *p)
+{
+ (void) p;
+ return strcmp((const char *) pa, (const char *) pb);
+}
diff --git a/Build/source/texk/web2c/luatexdir/utils/avlstuff.w b/Build/source/texk/web2c/luatexdir/utils/avlstuff.w
deleted file mode 100644
index 1ea148b0917..00000000000
--- a/Build/source/texk/web2c/luatexdir/utils/avlstuff.w
+++ /dev/null
@@ -1,61 +0,0 @@
-% avlstuff.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/>.
-
-@* AVL helper functions.
-
-@ @c
-
-
-#include "ptexlib.h"
-#include "utils/avl.h"
-
-@ memory management functions for AVL
-@c
-static void *avl_xmalloc(struct libavl_allocator *allocator, size_t size)
-{
- assert(allocator != NULL && size > 0);
- return xmalloc((unsigned) size);
-}
-
-static void avl_xfree(struct libavl_allocator *allocator, void *block)
-{
- assert(allocator != NULL && block != NULL);
- xfree(block);
-}
-
-struct libavl_allocator avl_xallocator = {
- avl_xmalloc,
- avl_xfree
-};
-
-@ general AVL comparison functions
-@c
-int comp_int_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- cmp_return(*(const int *) pa, *(const int *) pb);
- return 0;
-}
-
-int comp_string_entry(const void *pa, const void *pb, void *p)
-{
- (void) p;
- return strcmp((const char *) pa, (const char *) pb);
-}
diff --git a/Build/source/texk/web2c/luatexdir/utils/managed-sa.w b/Build/source/texk/web2c/luatexdir/utils/managed-sa.c
index 6ac4a68ac08..6cf10e301ce 100644
--- a/Build/source/texk/web2c/luatexdir/utils/managed-sa.w
+++ b/Build/source/texk/web2c/luatexdir/utils/managed-sa.c
@@ -1,36 +1,36 @@
-% managed-sa.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/>.
+/*
-@* Sparse arrays with an embedded save stack.
+Copyright 2006-2010 Taco Hoekwater <taco@luatex.org>
-These functions are called very often but a few days of experimenting proved that
-there is not much to gain (if at all) from using macros or optimizations like
-preallocating and fast access to the first 128 entries. In practice the overhead
-is mostly in accessing memory and not in (probably inlined) calls. So, we should
-accept fate and wait for faster memory. It's the price we pay for being unicode
-on the one hand and sparse on the other.
+This file is part of LuaTeX.
-@ @c
+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 we implement sparse arrays with an embedded save stack. These functions
+ are called very often but a few days of experimenting proved that there is
+ not much to gain (if at all) from using macros or optimizations like
+ preallocating and fast access to the first 128 entries. In practice the
+ overhead is mostly in accessing memory and not in (probably inlined) calls.
+ So, we should accept fate and wait for faster memory. It's the price we pay
+ for being unicode on the one hand and sparse on the other.
+
+*/
#include "ptexlib.h"
-@ @c
static void store_sa_stack(sa_tree a, int n, sa_tree_item v, int gl)
{
sa_stack_item st;
@@ -47,7 +47,6 @@ static void store_sa_stack(sa_tree a, int n, sa_tree_item v, int gl)
a->stack[a->stack_ptr] = st;
}
-@ @c
static void skip_in_stack(sa_tree a, int n)
{
int p = a->stack_ptr;
@@ -61,7 +60,6 @@ static void skip_in_stack(sa_tree a, int n)
}
}
-@ @c
sa_tree_item get_sa_item(const sa_tree head, const int n)
{
if (head->tree != NULL) {
@@ -76,7 +74,6 @@ sa_tree_item get_sa_item(const sa_tree head, const int n)
return head->dflt;
}
-@ @c
void set_sa_item(sa_tree head, int n, sa_tree_item v, int gl)
{
int h = HIGHPART_PART(n);
@@ -103,13 +100,11 @@ void set_sa_item(sa_tree head, int n, sa_tree_item v, int gl)
head->tree[h][m][l] = v;
}
-@ @c
void rawset_sa_item(sa_tree head, int n, sa_tree_item v)
{
head->tree[HIGHPART_PART(n)][MIDPART_PART(n)][LOWPART_PART(n)] = v;
}
-@ @c
void clear_sa_stack(sa_tree a)
{
xfree(a->stack);
@@ -117,7 +112,6 @@ void clear_sa_stack(sa_tree a)
a->stack_size = a->stack_step;
}
-@ @c
void destroy_sa_tree(sa_tree a)
{
if (a == NULL)
@@ -138,7 +132,6 @@ void destroy_sa_tree(sa_tree a)
xfree(a);
}
-@ @c
sa_tree copy_sa_tree(sa_tree b)
{
sa_tree a = (sa_tree) Mxmalloc_array(sa_tree_head, 1);
@@ -168,15 +161,17 @@ sa_tree copy_sa_tree(sa_tree b)
return a;
}
-@ The main reason to fill in the lowest entry branches here immediately
-is that most of the sparse arrays have a bias toward ASCII values.
+/*tes
-Allocating those here immediately improves the chance of the structure
-|a->tree[0][0][x]| being close together in actual memory locations
+ The main reason to fill in the lowest entry branches here immediately is that
+ most of the sparse arrays have a bias toward \ASCII\ values.
-@c
+ Allocating those here immediately improves the chance of the structure
+ |a->tree[0][0][x]| being close together in actual memory locations
-/* we could save less for type 0 stacks */
+ We could save less for type 0 stacks.
+
+*/
sa_tree new_sa_tree(int size, int type, sa_tree_item dflt)
{
@@ -190,11 +185,9 @@ sa_tree new_sa_tree(int size, int type, sa_tree_item dflt)
a->stack_step = size;
a->stack_type = type;
a->stack_ptr = 0;
- /* printf("creating sa tree of type %d\n",type); */
return (sa_tree) a;
}
-@ @c
void restore_sa_stack(sa_tree head, int gl)
{
sa_stack_item st;
@@ -209,7 +202,6 @@ void restore_sa_stack(sa_tree head, int gl)
}
}
-@ @c
void dump_sa_tree(sa_tree a, const char * name)
{
boolean f;
@@ -219,10 +211,10 @@ void dump_sa_tree(sa_tree a, const char * name)
x = a->dflt.int_value;
dump_int(x);
if (a->tree != NULL) {
- dump_int(1); /* marker */
+ /*tex A marker: */
+ dump_int(1);
n = a->stack_type;
dump_int(n);
- /* printf("dumping sa tree %s with type %d\n",name,n); */
for (h = 0; h < HIGHPART; h++) {
if (a->tree[h] != NULL) {
f = 1;
@@ -253,11 +245,11 @@ void dump_sa_tree(sa_tree a, const char * name)
}
}
} else {
- dump_int(0); /* marker */
+ /*tex A marker: */
+ dump_int(0);
}
}
-@ @c
sa_tree undump_sa_tree(const char * name)
{
int x, n;
@@ -272,13 +264,13 @@ sa_tree undump_sa_tree(const char * name)
a->stack = Mxmalloc_array(sa_stack_item, a->stack_size);
a->stack_ptr = 0;
a->tree = NULL;
- undump_int(x); /* marker */
+ /*tex The marker: */
+ undump_int(x);
if (x == 0)
return a;
a->tree = (sa_tree_item ***) Mxcalloc_array(void *, HIGHPART);
undump_int(n);
a->stack_type = n;
- /* printf("undumping sa tree %s with type %d\n",name,n); */
for (h = 0; h < HIGHPART; h++) {
undump_qqqq(f);
if (f > 0) {
diff --git a/Build/source/texk/web2c/luatexdir/utils/unistring.w b/Build/source/texk/web2c/luatexdir/utils/unistring.c
index a5b365a5f2e..6c95ee31e67 100644
--- a/Build/source/texk/web2c/luatexdir/utils/unistring.w
+++ b/Build/source/texk/web2c/luatexdir/utils/unistring.c
@@ -1,34 +1,29 @@
-% unistring.w
-%
-% Copyright 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
-
-
-@ @c
+/*
+
+Copyright 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/>.
+
+*/
+
#include "ptexlib.h"
#include <string.h>
-@ @c
static void utf_error(void)
{
- const char *hlp[] =
- { "A funny symbol that I can't read has just been (re)read.",
+ const char *hlp[] = {
+ "A funny symbol that I can't read has just been (re)read.",
"Just continue, I'll change it to 0xFFFD.",
NULL
};
@@ -37,7 +32,6 @@ static void utf_error(void)
deletions_allowed = true;
}
-@ @c
unsigned str2uni(const unsigned char *k)
{
register int ch;
@@ -45,7 +39,8 @@ unsigned str2uni(const unsigned char *k)
const unsigned char *text = k;
if ((ch = *text++) < 0x80) {
val = (unsigned) ch;
- } else if (ch <= 0xbf) { /* error */
+ } else if (ch <= 0xbf) {
+ /*tex An error that we skip. */
} else if (ch <= 0xdf) {
if (*text >= 0x80 && *text < 0xc0)
val = (unsigned) (((ch & 0x1f) << 6) | (*text++ & 0x3f));
@@ -64,9 +59,11 @@ unsigned str2uni(const unsigned char *k)
*text >= 0xc0 || text[1] >= 0xc0 || text[2] >= 0xc0)
val = 0xFFFD;
} else {
- /* the 5- and 6-byte UTF-8 sequences generate integers
- that are outside of the valid UCS range, and therefore
- unsupported
+ /*tex
+
+ The 5- and 6-byte UTF-8 sequences generate integers that are outside
+ of the valid UCS range, and therefore unsupported.
+
*/
}
if (val == 0xFFFD)
@@ -74,8 +71,11 @@ unsigned str2uni(const unsigned char *k)
return (val);
}
-@ This is a very basic helper
-@c
+/*tex
+
+ A real basic helper.
+*/
+
unsigned char *uni2str(unsigned unic)
{
unsigned char *buf = xmalloc(5);
@@ -106,26 +106,30 @@ unsigned char *uni2str(unsigned unic)
return buf;
}
-@ |buffer_to_unichar| converts a sequence of bytes in the |buffer|
-into a unicode character value. It does not check for overflow
-of the |buffer|, but it is careful to check the validity of the
-UTF-8 encoding.
+/*tex
+
+ Function |buffer_to_unichar| converts a sequence of bytes in the |buffer|
+ into a unicode character value. It does not check for overflow of the
+ |buffer|, but it is careful to check the validity of the \UTF-8 encoding.
+
+*/
-@c
int buffer_to_unichar(int k)
{
return str2uni((const unsigned char *)(buffer+k));
}
+/*tex
+
+ These came from texlang.c:
+
+*/
-@ These came from texlang.w
-@c
char *uni2string(char *utf8_text, unsigned ch)
{
- /* Increment and deposit character */
+ /*tex Increment and deposit character: */
if (ch >= 17 * 65536)
return (utf8_text);
-
if (ch <= 127)
*utf8_text++ = (char) ch;
else if (ch <= 0x7ff) {
@@ -155,15 +159,12 @@ unsigned u_length(register unsigned int *str)
return (len);
}
-
void utf2uni_strcpy(unsigned int *ubuf, const char *utf8buf)
{
int len = (int) strlen(utf8buf) + 1;
unsigned int *upt = ubuf, *uend = ubuf + len - 1;
- const unsigned char *pt = (const unsigned char *) utf8buf, *end =
- pt + strlen(utf8buf);
+ const unsigned char *pt = (const unsigned char *) utf8buf, *end = pt + strlen(utf8buf);
int w, w2;
-
while (pt < end && *pt != '\0' && upt < uend) {
if (*pt <= 127)
*upt = *pt++;
@@ -171,9 +172,7 @@ void utf2uni_strcpy(unsigned int *ubuf, const char *utf8buf)
*upt = (unsigned int) (((*pt & 0x1f) << 6) | (pt[1] & 0x3f));
pt += 2;
} else if (*pt <= 0xef) {
- *upt =
- (unsigned int) (((*pt & 0xf) << 12) | ((pt[1] & 0x3f) << 6) |
- (pt[2] & 0x3f));
+ *upt = (unsigned int) (((*pt & 0xf) << 12) | ((pt[1] & 0x3f) << 6) | (pt[2] & 0x3f));
pt += 3;
} else {
w = (((*pt & 0x7) << 2) | ((pt[1] & 0x30) >> 4)) - 1;
@@ -187,15 +186,11 @@ void utf2uni_strcpy(unsigned int *ubuf, const char *utf8buf)
*upt = '\0';
}
-@ @c
char *utf16be_str(long code)
{
static char buf[SMALL_BUF_SIZE];
long v;
unsigned vh, vl;
-
- assert(code >= 0);
-
if (code <= 0xFFFF)
sprintf(buf, "%04lX", code);
else {
@@ -206,5 +201,3 @@ char *utf16be_str(long code)
}
return buf;
}
-
-
diff --git a/Build/source/texk/web2c/luatexdir/utils/utils.w b/Build/source/texk/web2c/luatexdir/utils/utils.c
index 420f5cfe4e4..55ff1cb3e29 100644
--- a/Build/source/texk/web2c/luatexdir/utils/utils.w
+++ b/Build/source/texk/web2c/luatexdir/utils/utils.c
@@ -1,51 +1,52 @@
-% utils.w
-%
-% Copyright 1996-2006 Han The Thanh <thanh@@pdftex.org>
-% 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
-
-
-@ @c
+/*
+
+Copyright 1996-2006 Han The Thanh <thanh@pdftex.org>
+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"
-#include <kpathsea/config.h> /* this is a trick to load mingw32's io.h early,
- using a macro redefinition of |eof()|. */
+/*tex
+
+ This is a trick to load mingw32's io.h early, using a macro redefinition of
+ |eof()|.
+
+*/
+
+#include <kpathsea/config.h>
#include "sys/types.h"
#include <kpathsea/c-stat.h>
#include <kpathsea/c-fopen.h>
#include <string.h>
#include <time.h>
-#include <float.h> /* for |DBL_EPSILON| */
+
+/*tex For |DBL_EPSILON|: */
+
+#include <float.h>
+
#include "zlib.h"
#include "md5.h"
-#include "lua/luatex-api.h" /* for luatex_banner */
+#include "lua/luatex-api.h"
#include "luatex_svnversion.h"
#include "png.h"
#include "mplib.h"
-/* POPPLER_VERSION is defined in poppler-config.h for poppler from
- * the TeX Live tree, or in the Makefile for an installed version. */
-#include "poppler-config.h"
-
-@ @c
#define check_nprintf(size_get, size_want) \
if ((unsigned)(size_get) >= (unsigned)(size_want)) \
formatted_error("internal","snprintf failed: file %s, line %d", __FILE__, __LINE__);
@@ -55,12 +56,11 @@ static char print_buf[PRINTF_BUF_SIZE];
int epochseconds;
int microseconds;
-/* define |char_ptr|, |char_array|, and |char_limit| */
typedef char char_entry;
define_array(char);
-@ @c
#define SUBSET_TAG_LENGTH 6
+
void make_subset_tag(fd_entry * fd)
{
int i, j = 0, a[SUBSET_TAG_LENGTH];
@@ -117,7 +117,6 @@ void make_subset_tag(fd_entry * fd)
formatted_warning("subsets","subset-tag collision, resolved in round %d",j);
}
-@ @c
__attribute__ ((format(printf, 1, 2)))
void tex_printf(const char *fmt, ...)
{
@@ -129,7 +128,6 @@ void tex_printf(const char *fmt, ...)
va_end(args);
}
-@ @c
size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE * stream)
{
if (fwrite(ptr, size, nmemb, stream) != nmemb)
@@ -137,7 +135,6 @@ size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE * stream)
return nmemb;
}
-@ @c
int xfflush(FILE * stream)
{
if (fflush(stream) != 0)
@@ -145,7 +142,6 @@ int xfflush(FILE * stream)
return 0;
}
-@ @c
int xgetc(FILE * stream)
{
int c = getc(stream);
@@ -154,7 +150,6 @@ int xgetc(FILE * stream)
return c;
}
-@ @c
int xputc(int c, FILE * stream)
{
int i = putc(c, stream);
@@ -163,7 +158,6 @@ int xputc(int c, FILE * stream)
return i;
}
-@ @c
scaled ext_xn_over_d(scaled x, scaled n, scaled d)
{
double r = (((double) x) * ((double) n)) / ((double) d);
@@ -176,9 +170,13 @@ scaled ext_xn_over_d(scaled x, scaled n, scaled d)
return (scaled) r;
}
-@ function strips trailing zeros in string with numbers;
-leading zeros are not stripped (as in real life)
-@c
+/*tex
+
+ This function strips trailing zeros in string with numbers; leading zeros are
+ not stripped (as in real life), It's not used.
+
+*/
+
#if 0
char *stripzeros(char *a)
{
@@ -248,9 +246,9 @@ char *stripzeros(char *a)
}
#endif
-@ @c
void initversionstring(char **versions)
{
+
#ifdef LuajitTeX
#define LUA_VER_STRING LUAJIT_VERSION
#else
@@ -258,35 +256,37 @@ void initversionstring(char **versions)
#endif
#define STR(tok) STR2(tok)
#define STR2(tok) #tok
+
const_string fmt =
- "Compiled with libpng %s; using %s\n"
- "Compiled with %s\n" /* Lua or LuaJIT */
- "Compiled with mplib version %s\n"
- "Compiled with poppler version %s\n"
- "Compiled with zlib %s; using %s\n"
- "\nDevelopment id: %s\n";
+ "Compiled with libpng %s; using %s\n"
+ "Compiled with %s\n" /* Lua or LuaJIT */
+ "Compiled with mplib version %s\n"
+ "Compiled with zlib %s; using %s\n"
+ "\nDevelopment id: %s\n";
size_t len = strlen(fmt)
- + strlen(PNG_LIBPNG_VER_STRING) + strlen(png_libpng_ver)
- + strlen(LUA_VER_STRING)
- + strlen(mp_metapost_version())
- + strlen(POPPLER_VERSION)
- + strlen(ZLIB_VERSION) + strlen(zlib_version)
- + strlen(STR(luatex_svn_revision))
- + 1;
-
- /* len will be more than enough, because of the placeholder chars in fmt
- that get replaced by the arguments. */
+ + strlen(PNG_LIBPNG_VER_STRING) + strlen(png_libpng_ver)
+ + strlen(LUA_VER_STRING)
+ + strlen(mp_metapost_version())
+ + strlen(ZLIB_VERSION) + strlen(zlib_version)
+ + strlen(STR(luatex_svn_revision))
+ + 1;
+
+ /*tex
+ The size of |len| will be more than enough, because of the placeholder
+ chars in fmt that get replaced by the arguments.
+ */
*versions = xmalloc(len);
sprintf(*versions, fmt,
PNG_LIBPNG_VER_STRING, png_libpng_ver, LUA_VER_STRING,
- mp_metapost_version(),POPPLER_VERSION,
+ mp_metapost_version(),
ZLIB_VERSION, zlib_version,STR(luatex_svn_revision));
+
#undef STR2
#undef STR
#undef LUA_VER_STRING
+
}
-@ @c
void check_buffer_overflow(int wsize)
{
if (wsize > buf_size) {
@@ -294,16 +294,18 @@ void check_buffer_overflow(int wsize)
if (nsize < wsize) {
nsize = wsize + 5;
}
- buffer =
- (unsigned char *) xreallocarray(buffer, char, (unsigned) nsize);
+ buffer = (unsigned char *) xreallocarray(buffer, char, (unsigned) nsize);
buf_size = nsize;
}
}
-@ the return value is a decimal number with the point |dd| places from the back,
- |scaled_out| is the number of scaled points corresponding to that.
+/*tex
+
+ The return value is a decimal number with the point |dd| places from the
+ back, |scaled_out| is the number of scaled points corresponding to that.
+
+*/
-@c
#define max_integer 0x7FFFFFFF
scaled divide_scaled(scaled s, scaled m, int dd)
@@ -331,7 +333,7 @@ scaled divide_scaled(scaled s, scaled m, int dd)
q = 10 * q + (10 * r) / m;
r = (10 * r) % m;
}
- /* rounding */
+ /*tex Rounding: */
if (2 * r >= m) {
q++;
}
@@ -343,8 +345,12 @@ scaled divide_scaled(scaled s, scaled m, int dd)
#define floor win32_floor
#endif
-@ Same function, but using doubles instead of integers (faster)
-@c
+/*tex
+
+ The same function, but using doubles instead of integers (faster).
+
+*/
+
scaled divide_scaled_n(double sd, double md, double n)
{
double dd, di = 0.0;
@@ -356,11 +362,9 @@ scaled divide_scaled_n(double sd, double md, double n)
return (scaled) di;
}
-@ @c
int do_zround(double r)
{
int i;
-
if (r > 2147483647.0)
i = 2147483647;
else if (r < -2147483647.0)
@@ -369,16 +373,20 @@ int do_zround(double r)
i = (int) (r + 0.5);
else
i = (int) (r - 0.5);
-
return i;
}
-@ Old MSVC doesn't have |rint|.
-@c
+/*tex
+
+ Old MSVC doesn't have |rint|.
+
+*/
+
#if defined(_MSC_VER) && _MSC_VER <= 1600
# include <math.h>
+
double rint(double x)
{
return floor(x+0.5);
@@ -386,57 +394,66 @@ double rint(double x)
#endif
-@ replace tmpfile() on Windows
-@c
+/*tex
+
+ We replace |tmpfile| on \MSWINDOWS:
+
+*/
+
#if defined(_WIN32)
-/* _cairo_win_tmpfile (void) - replace tmpfile() on Windows
- * extracted from cairo-misc.c in cairo - a vector graphics library
- * with display and print output
- * the functiion name is changed from
- * _cairo_win32_tmpfile (void) to
- * _cairo_win_tmpfile (void)
- *
- *
- * Copyright 2002 University of Southern California
- * Copyright 2005 Red Hat, Inc.
- * Copyright 2007 Adrian Johnson
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- * The Original Code is the cairo graphics library.
- *
- * The Initial Developer of the Original Code is University of Southern
- * California.
- *
- * Contributor(s):
- * Carl D. Worth <cworth@cworth.org>
- * Adrian Johnson <ajohnson@redneon.com>
- */
+
+/*
+
+ _cairo_win_tmpfile (void) - replace tmpfile() on Windows
+ extracted from cairo-misc.c in cairo - a vector graphics library
+ with display and print output
+
+ the functiion name is changed from _cairo_win32_tmpfile (void) to
+ _cairo_win_tmpfile (void)
+
+ Copyright 2002 University of Southern California
+ Copyright 2005 Red Hat, Inc.
+ Copyright 2007 Adrian Johnson
+
+ This library is free software; you can redistribute it and/or modify it
+ either under the terms of the GNU Lesser General Public License version 2.1
+ as published by the Free Software Foundation (the "LGPL") or, at your option,
+ under the terms of the Mozilla Public License Version 1.1 (the "MPL"). If you
+ do not alter this notice, a recipient may use your version of this file under
+ either the MPL or the LGPL.
+
+ You should have received a copy of the LGPL along with this library in the
+ file COPYING-LGPL-2.1; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA You should have
+ received a copy of the MPL along with this library in the file
+ COPYING-MPL-1.1
+
+ The contents of this file are subject to the Mozilla Public License Version
+ 1.1 (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
+
+ This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ KIND, either express or implied. See the LGPL or the MPL for the specific
+ language governing rights and limitations.
+
+ The Original Code is the cairo graphics library. The Initial Developer of the
+ Original Code is University of Southern California. Contributor(s):
+
+ Carl D. Worth <cworth@cworth.org>
+ Adrian Johnson <ajohnson@redneon.com>
+
+*/
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
+
+/*tex
+
+ We require \MSWINDOWS\ 2000 features such as |ETO_PDY|. We probably can now
+ assume that all \MSWINDOWS\ versions are recent.
+
+*/
+
#if !defined(WINVER) || (WINVER < 0x0500)
# define WINVER 0x0500
#endif
@@ -447,14 +464,15 @@ double rint(double x)
#include <windows.h>
#include <io.h>
-/* tmpfile() replacement for Windows.
- *
- * On Windows tmpfile() creates the file in the root directory. This
- * may fail due to unsufficient privileges. However, this isn't a
- * problem on Windows CE so we don't use it there.
- */
-FILE *
-_cairo_win_tmpfile (void)
+/*tex
+
+ On \MSWINDOWS\ |tmpfile| creates the file in the root directory. This may
+ fail due to unsufficient privileges. However, this isn't a problem on
+ \MSWINDOWS\ CE so we don't use it there. Who is actually using CE anyway?
+
+*/
+
+FILE * _cairo_win_tmpfile (void)
{
DWORD path_len;
WCHAR path_name[MAX_PATH + 1];
@@ -462,14 +480,11 @@ _cairo_win_tmpfile (void)
HANDLE handle;
int fd;
FILE *fp;
-
path_len = GetTempPathW (MAX_PATH, path_name);
if (path_len <= 0 || path_len >= MAX_PATH)
- return NULL;
-
+ return NULL;
if (GetTempFileNameW (path_name, L"ps_", 0, file_name) == 0)
- return NULL;
-
+ return NULL;
handle = CreateFileW (file_name,
GENERIC_READ | GENERIC_WRITE,
0,
@@ -478,22 +493,20 @@ _cairo_win_tmpfile (void)
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
- DeleteFileW (file_name);
- return NULL;
+ DeleteFileW (file_name);
+ return NULL;
}
-
fd = _open_osfhandle((intptr_t) handle, 0);
if (fd < 0) {
- CloseHandle (handle);
- return NULL;
+ CloseHandle (handle);
+ return NULL;
}
-
fp = _fdopen(fd, "w+b");
if (fp == NULL) {
- _close(fd);
- return NULL;
+ _close(fd);
+ return NULL;
}
-
return fp;
}
+
#endif