diff --git a/.gitignore b/.gitignore index 5c0ef1d..e50de72 100644 --- a/.gitignore +++ b/.gitignore @@ -603,6 +603,7 @@ SOURCES/tex.doc.tar.xz SOURCES/tex.tar.xz SOURCES/tex4ht.doc.tar.xz SOURCES/tex4ht.tar.xz +SOURCES/texlive-20180414-poppler-20.11.0-luatex.patch SOURCES/texlive-20180414-source.tar.xz SOURCES/texlive-common.doc.tar.xz SOURCES/texlive-docindex.doc.tar.xz diff --git a/.texlive.metadata b/.texlive.metadata index 39bb02c..0bde8e4 100644 --- a/.texlive.metadata +++ b/.texlive.metadata @@ -603,6 +603,7 @@ de2f54d2a459bae570d9f9fb0c0638bb531b0d9c SOURCES/tex-ini-files.tar.xz 5df5b9595fcc9948fca717aa5dd1757c5aad0ee6 SOURCES/tex.tar.xz 6161195cb1d8638a1d08773e66a607a2b2057dc4 SOURCES/tex4ht.doc.tar.xz afebcd84632de9c43c9461ba2ff593882a426a88 SOURCES/tex4ht.tar.xz +a03553f4e0d70a86d861628edc5969b92c533477 SOURCES/texlive-20180414-poppler-20.11.0-luatex.patch 81bdd9999b6ab860d1d3c388cf27062aba960255 SOURCES/texlive-20180414-source.tar.xz 626b3dc7527c30a380406d888a890a56cd59aa2a SOURCES/texlive-common.doc.tar.xz 91424e8fec75b4af84884f7dc0bafb32cd9a7170 SOURCES/texlive-docindex.doc.tar.xz diff --git a/SOURCES/texlive-2018-luatex-CVE-2023-32700.patch b/SOURCES/texlive-2018-luatex-CVE-2023-32700.patch new file mode 100644 index 0000000..780bb1e --- /dev/null +++ b/SOURCES/texlive-2018-luatex-CVE-2023-32700.patch @@ -0,0 +1,1266 @@ +diff --git a/source/texk/web2c/luatexdir/lua/loslibext.c b/source/texk/web2c/luatexdir/lua/loslibext.c +index 309d636..e6bcfb0 100644 +--- a/source/texk/web2c/luatexdir/lua/loslibext.c ++++ b/source/texk/web2c/luatexdir/lua/loslibext.c +@@ -1014,6 +1014,111 @@ static int os_execute(lua_State * L) + } + + ++/* ++** ====================================================== ++** l_kpse_popen spawns a new process connected to the current ++** one through the file streams with some checks by kpse. ++** Almost verbatim from Lua liolib.c . ++** ======================================================= ++*/ ++#if !defined(l_kpse_popen) /* { */ ++ ++#if defined(LUA_USE_POSIX) /* { */ ++ ++#define l_kpse_popen(L,c,m) (fflush(NULL), popen(c,m)) ++#define l_kpse_pclose(L,file) (pclose(file)) ++ ++#elif defined(LUA_USE_WINDOWS) /* }{ */ ++ ++#define l_kpse_popen(L,c,m) (_popen(c,m)) ++#define l_kpse_pclose(L,file) (_pclose(file)) ++ ++#else /* }{ */ ++ ++/* ISO C definitions */ ++#define l_kpse_popen(L,c,m) \ ++ ((void)((void)c, m), \ ++ luaL_error(L, "'popen' not supported"), \ ++ (FILE*)0) ++#define l_kpse_pclose(L,file) ((void)L, (void)file, -1) ++ ++#endif /* } */ ++ ++#endif /* } */ ++typedef luaL_Stream LStream; ++#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) ++static LStream *newprefile (lua_State *L) { ++ LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); ++ p->closef = NULL; /* mark file handle as 'closed' */ ++ luaL_setmetatable(L, LUA_FILEHANDLE); ++ return p; ++} ++static int io_kpse_pclose (lua_State *L) { ++ LStream *p = tolstream(L); ++ return luaL_execresult(L, l_kpse_pclose(L, p->f)); ++} ++static int io_kpse_check_permissions(lua_State *L) { ++ const char *filename = luaL_checkstring(L, 1); ++ if (filename == NULL) { ++ lua_pushboolean(L,0); ++ lua_pushliteral(L,"no command name given"); ++ } else if (shellenabledp <= 0) { ++ lua_pushboolean(L,0); ++ lua_pushliteral(L,"all command execution is disabled"); ++ } else if (restrictedshell == 0) { ++ lua_pushboolean(L,1); ++ lua_pushstring(L,filename); ++ } else { ++ char *safecmd = NULL; ++ char *cmdname = NULL; ++ switch (shell_cmd_is_allowed(filename, &safecmd, &cmdname)) { ++ case 0: ++ lua_pushboolean(L,0); ++ lua_pushliteral(L, "specific command execution disabled"); ++ break; ++ case 1: ++ /* doesn't happen */ ++ lua_pushboolean(L,1); ++ lua_pushstring(L,filename); ++ break; ++ case 2: ++ lua_pushboolean(L,1); ++ lua_pushstring(L,safecmd); ++ break; ++ default: ++ /* -1 */ ++ lua_pushboolean(L,0); ++ lua_pushliteral(L, "bad command line quoting"); ++ break; ++ } ++ } ++ return 2; ++} ++static int io_kpse_popen (lua_State *L) { ++ const char *filename = NULL; ++ const char *mode = NULL; ++ LStream *p = NULL; ++ int okay; ++ filename = luaL_checkstring(L, 1); ++ mode = luaL_optstring(L, 2, "r"); ++ lua_pushstring(L,filename); ++ io_kpse_check_permissions(L); ++ filename = luaL_checkstring(L, -1); ++ okay = lua_toboolean(L,-2); ++ if (okay && filename) { ++ p = newprefile(L); ++ luaL_argcheck(L, ((mode[0] == 'r' || mode[0] == 'w') && mode[1] == '\0'), ++ 2, "invalid mode"); ++ p->f = l_kpse_popen(L, filename, mode); ++ p->closef = &io_kpse_pclose; ++ return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; ++ } else { ++ lua_pushnil(L); ++ lua_pushvalue(L,-2); ++ return 2; ++ } ++} ++ + void open_oslibext(lua_State * L) + { + +@@ -1047,6 +1152,8 @@ void open_oslibext(lua_State * L) + lua_setfield(L, -2, "execute"); + lua_pushcfunction(L, os_tmpdir); + lua_setfield(L, -2, "tmpdir"); ++ lua_pushcfunction(L, io_kpse_popen); ++ lua_setfield(L, -2, "kpsepopen"); + + lua_pop(L, 1); /* pop the table */ + } +diff --git a/source/texk/web2c/luatexdir/lua/luatex-core.lua b/source/texk/web2c/luatexdir/lua/luatex-core.lua +index 35005d1..6ea8188 100644 +--- a/source/texk/web2c/luatexdir/lua/luatex-core.lua ++++ b/source/texk/web2c/luatexdir/lua/luatex-core.lua +@@ -17,7 +17,6 @@ local type, next, getmetatable, require = type, next, getmetatable, require + local find, gsub, format = string.find, string.gsub, string.format + + local io_open = io.open +-local io_popen = io.popen + local io_lines = io.lines + + local fio_readline = fio.readline +@@ -66,13 +65,6 @@ local function luatex_io_open_readonly(name,how) + return f + end + +-local function luatex_io_popen(name,...) +- local okay, found = fio_checkpermission(name) +- if okay and found then +- return io_popen(found,...) +- end +-end +- + -- local function luatex_io_lines(name,how) + -- if name then + -- local f = io_open(name,how or 'r') +@@ -126,7 +118,7 @@ mt.lines = luatex_io_readline + if kpseused == 1 then + + io.open = luatex_io_open +- io.popen = luatex_io_popen ++ io.popen = os.kpsepopen + + end + +@@ -156,6 +148,8 @@ if saferoption == 1 then + os.setenv = installdummy("os.setenv") + os.tempdir = installdummy("os.tempdir") + ++ os.kpsepopen = installdummy("os.kpsepopen") ++ + io.popen = installdummy("io.popen") + io.open = installdummy("io.open",luatex_io_open_readonly) + +diff -up a/source/texk/web2c/luatexdir/lua/luatex-core.c.than a/source/texk/web2c/luatexdir/lua/luatex-core.c +--- a/source/texk/web2c/luatexdir/lua/luatex-core.c.than 2023-05-25 21:18:12.108403829 +0200 ++++ a/source/texk/web2c/luatexdir/lua/luatex-core.c 2023-05-25 21:18:38.470955456 +0200 +@@ -66,570 +66,560 @@ int load_luatex_core_lua (lua_State * L) + 0x74, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, + 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, +- 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, +- 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, +- 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, +- 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, +- 0x6f, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, +- 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, +- 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, +- 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, +- 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, +- 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, +- 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, +- 0x20, 0x6d, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, +- 0x62, 0x6c, 0x65, 0x28, 0x69, 0x6f, 0x2e, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x6c, +- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x2e, 0x6c, 0x69, +- 0x6e, 0x65, 0x73, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, +- 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, +- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x74, +- 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, +- 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, +- 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f, 0x65, 0x73, 0x63, +- 0x61, 0x70, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x30, 0x20, 0x28, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, +- 0x65, 0x64, 0x29, 0x20, 0x31, 0x20, 0x28, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x29, +- 0x20, 0x32, 0x20, 0x28, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x29, 0x0a, +- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, +- 0x75, 0x73, 0x2e, 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, +- 0x2d, 0x2d, 0x20, 0x30, 0x20, 0x31, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x72, +- 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, +- 0x6e, 0x6c, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x73, 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, +- 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, +- 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, +- 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x6d, 0x74, 0x2e, 0x73, +- 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, +- 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, +- 0x6e, 0x6c, 0x79, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, +- 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, +- 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, +- 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, +- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, +- 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, +- 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x68, 0x6f, 0x77, 0x29, 0x20, 0x3d, 0x3d, +- 0x20, 0x27, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69, +- 0x6e, 0x64, 0x28, 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x77, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, +- 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, +- 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x77, 0x27, 0x29, 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, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, +- 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, ++ 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, ++ 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x61, ++ 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, ++ 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, ++ 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, ++ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, ++ 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, ++ 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, ++ 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x74, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x69, ++ 0x6f, 0x2e, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, ++ 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x6c, ++ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, ++ 0x73, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6c, ++ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, ++ 0x73, 0x2e, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x2d, ++ 0x2d, 0x20, 0x30, 0x20, 0x28, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x29, 0x20, 0x31, ++ 0x20, 0x28, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x32, 0x20, 0x28, 0x72, ++ 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, ++ 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x6b, 0x70, ++ 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x30, 0x20, ++ 0x31, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, ++ 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x74, ++ 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x0a, 0x0a, 0x69, ++ 0x6f, 0x2e, 0x73, 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, ++ 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, ++ 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x6d, 0x74, 0x2e, 0x73, 0x61, 0x76, 0x65, 0x64, 0x5f, ++ 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x61, ++ 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x0a, ++ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, ++ 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, ++ 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, ++ 0x6f, 0x74, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, ++ 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, ++ 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, ++ 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, ++ 0x79, 0x70, 0x65, 0x28, 0x68, 0x6f, 0x77, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x73, 0x74, 0x72, ++ 0x69, 0x6e, 0x67, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x28, 0x68, 0x6f, ++ 0x77, 0x2c, 0x27, 0x77, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, ++ 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, ++ 0x27, 0x77, 0x27, 0x29, 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, 0x66, 0x69, ++ 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, ++ 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x0a, 0x65, 0x6e, 0x64, 0x0a, ++ 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, ++ 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x72, ++ 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, ++ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, ++ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, ++ 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, 0x62, 0x28, ++ 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x5b, 0x5e, 0x72, 0x62, 0x5d, 0x27, 0x2c, 0x27, 0x27, 0x29, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, ++ 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, +- 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, +- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, +- 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x28, 0x6e, 0x61, 0x6d, +- 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, +- 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, +- 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, +- 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, +- 0x67, 0x73, 0x75, 0x62, 0x28, 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x5b, 0x5e, 0x72, 0x62, 0x5d, 0x27, +- 0x2c, 0x27, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +- 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, +- 0x20, 0x27, 0x72, 0x27, 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, 0x6c, 0x6f, 0x63, +- 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, +- 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +- 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, +- 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, +- 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, +- 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, +- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, +- 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x2c, 0x20, 0x66, +- 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, +- 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x20, 0x61, 0x6e, 0x64, +- 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x70, 0x6f, +- 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6c, +- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, +- 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x6e, 0x61, +- 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, +- 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, +- 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, +- 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, +- 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, +- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, +- 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, +- 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, +- 0x65, 0x73, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, +- 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x73, +- 0x6f, 0x6d, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, +- 0x63, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x6b, 0x69, 0x63, 0x6b, 0x20, 0x69, +- 0x6e, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, +- 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x74, 0x6c, 0x79, 0x0a, 0x2d, +- 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, +- 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, 0x2e, +- 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, +- 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, +- 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +- 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, +- 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x3d, 0x3d, +- 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, +- 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, +- 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, ++ 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, ++ 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, ++ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, ++ 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, ++ 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x0a, 0x65, 0x6e, 0x64, 0x0a, ++ 0x0a, 0x2d, 0x2d, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, ++ 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, ++ 0x65, 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x2d, 0x2d, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, ++ 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, ++ 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, ++ 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x2d, ++ 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, ++ 0x68, 0x65, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, ++ 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, +- 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, +- 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 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, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 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, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 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, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x6f, +- 0x73, 0x65, 0x20, 0x77, 0x68, 0x6f, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x20, 0x74, +- 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x70, 0x61, 0x74, 0x63, +- 0x68, 0x65, 0x64, 0x20, 0x27, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x27, 0x20, 0x63, +- 0x61, 0x6e, 0x27, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x27, 0x22, 0x20, 0x2e, 0x2e, 0x20, +- 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x27, 0x22, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, +- 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, +- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, +- 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, ++ 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x2d, ++ 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, ++ 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, ++ 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x2d, 0x2d, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, ++ 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, ++ 0x46, 0x6f, 0x72, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, ++ 0x74, 0x68, 0x65, 0x20, 0x67, 0x63, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x6b, ++ 0x69, 0x63, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, ++ 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, ++ 0x74, 0x6c, 0x79, 0x0a, 0x2d, 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, ++ 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6c, 0x75, ++ 0x73, 0x68, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, ++ 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, ++ 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, ++ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, ++ 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6e, 0x61, 0x6d, ++ 0x65, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, ++ 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, ++ 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, ++ 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, ++ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, ++ 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, ++ 0x6c, 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, 0x66, 0x3a, 0x63, 0x6c, 0x6f, ++ 0x73, 0x65, 0x28, 0x29, 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, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, ++ 0x6c, 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, 0x6c, 0x73, 0x65, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x6f, ++ 0x72, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, 0x77, 0x68, 0x6f, 0x20, 0x6c, 0x69, 0x6b, 0x65, ++ 0x20, 0x69, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x3a, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, ++ 0x22, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x20, 0x27, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, ++ 0x65, 0x73, 0x27, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x27, ++ 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x27, 0x22, ++ 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, 0x72, ++ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, ++ 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, ++ 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, ++ 0x66, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, ++ 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, ++ 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, ++ 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, ++ 0x6d, 0x74, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, ++ 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x0a, 0x2d, ++ 0x2d, 0x20, 0x57, 0x65, 0x20, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, ++ 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, ++ 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, ++ 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x70, 0x73, 0x65, ++ 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2d, 0x2d, ++ 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x54, 0x65, 0x58, 0x74, ++ 0x2e, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, ++ 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, ++ 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, ++ 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, ++ 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x6f, 0x73, 0x2e, 0x6b, 0x70, 0x73, 0x65, 0x70, 0x6f, ++ 0x70, 0x65, 0x6e, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, 0x66, ++ 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, ++ 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, ++ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, ++ 0x6d, 0x6d, 0x79, 0x28, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, ++ 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x72, 0x65, 0x74, 0x75, +- 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, +- 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, +- 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, +- 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x6d, 0x74, 0x2e, 0x6c, 0x69, +- 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, +- 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, +- 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, +- 0x74, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, +- 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, +- 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, +- 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x73, 0x65, +- 0x20, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x54, 0x65, 0x58, 0x74, 0x2e, 0x0a, 0x0a, 0x69, 0x66, +- 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, +- 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, +- 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, +- 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, +- 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x65, +- 0x6e, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, +- 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, +- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, +- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, +- 0x79, 0x28, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, +- 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, +- 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, +- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x28, 0x66, +- 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x73, 0x61, 0x66, 0x65, 0x72, 0x20, 0x6f, 0x70, 0x74, +- 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +- 0x6e, 0x20, 0x25, 0x71, 0x20, 0x69, 0x73, 0x20, 0x25, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, ++ 0x6e, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, ++ 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, ++ 0x28, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x73, 0x61, 0x66, 0x65, 0x72, 0x20, 0x6f, ++ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, ++ 0x69, 0x6f, 0x6e, 0x20, 0x25, 0x71, 0x20, 0x69, 0x73, 0x20, 0x25, 0x73, 0x22, 0x2c, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x6c, 0x69, 0x6d, 0x69, +- 0x74, 0x65, 0x64, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, +- 0x64, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, +- 0x74, 0x72, 0x75, 0x65, 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, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +- 0x6e, 0x20, 0x66, 0x28, 0x2e, 0x2e, 0x2e, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, +- 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x28, 0x73, 0x74, +- 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, +- 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, +- 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, +- 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, +- 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, +- 0x73, 0x70, 0x61, 0x77, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, +- 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0x6e, +- 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x6c, 0x69, ++ 0x6d, 0x69, 0x74, 0x65, 0x64, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x64, 0x69, 0x73, 0x61, 0x62, ++ 0x6c, 0x65, 0x64, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, ++ 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 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, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, ++ 0x75, 0x72, 0x6e, 0x20, 0x66, 0x28, 0x2e, 0x2e, 0x2e, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, ++ 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x28, ++ 0x73, 0x74, 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, ++ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, ++ 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x3d, 0x20, ++ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, ++ 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, ++ 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, ++ 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, ++ 0x77, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, ++ 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, ++ 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x22, 0x29, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x20, 0x20, 0x3d, 0x20, 0x69, ++ 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, ++ 0x73, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, ++ 0x74, 0x65, 0x6d, 0x70, 0x64, 0x69, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, ++ 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x64, ++ 0x69, 0x72, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x6b, 0x70, 0x73, ++ 0x65, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, ++ 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x6b, 0x70, 0x73, 0x65, 0x70, 0x6f, ++ 0x70, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, ++ 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, ++ 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, ++ 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, ++ 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, ++ 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, ++ 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, + 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, +- 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x6f, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, +- 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x65, +- 0x74, 0x65, 0x6e, 0x76, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x74, 0x65, +- 0x6d, 0x70, 0x64, 0x69, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, +- 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x64, 0x69, 0x72, +- 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, +- 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, +- 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, +- 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, +- 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, +- 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x29, 0x0a, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, +- 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, +- 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, +- 0x73, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, +- 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6d, +- 0x6f, 0x76, 0x65, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x74, 0x6d, +- 0x70, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, +- 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x74, 0x6d, 0x70, 0x66, 0x69, 0x6c, 0x65, +- 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, +- 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, +- 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, 0x0a, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, +- 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, +- 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, +- 0x73, 0x2e, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, +- 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6c, 0x6f, 0x63, +- 0x6b, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, +- 0x68, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, +- 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, 0x29, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, +- 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, +- 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, +- 0x73, 0x2e, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, +- 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6d, 0x6b, 0x64, +- 0x69, 0x72, 0x22, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, +- 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x6f, +- 0x72, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x7e, 0x3d, +- 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, +- 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x66, 0x66, 0x69, 0x27, +- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x20, 0x76, 0x20, 0x69, +- 0x6e, 0x20, 0x6e, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x66, 0x69, 0x20, 0x64, 0x6f, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x20, 0x7e, 0x3d, 0x20, 0x27, +- 0x67, 0x63, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, 0x5b, 0x6b, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x69, +- 0x6c, 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, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, +- 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x73, 0x2e, +- 0x5b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x7c, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, +- 0x6e, 0x7c, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x5d, 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, +- 0x64, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, +- 0x70, 0x65, 0x20, 0x61, 0x77, 0x61, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6d, +- 0x64, 0x35, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, +- 0x61, 0x6c, 0x20, 0x73, 0x75, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x64, 0x35, 0x2e, +- 0x73, 0x75, 0x6d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x73, +- 0x75, 0x62, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, +- 0x75, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x72, +- 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, +- 0x6d, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x79, +- 0x74, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x79, +- 0x74, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, +- 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, +- 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x28, 0x6b, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, +- 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x75, 0x6d, 0x28, 0x6b, 0x29, 0x2c, +- 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, +- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +- 0x22, 0x25, 0x30, 0x32, 0x78, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, 0x29, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, +- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, +- 0x74, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, 0x58, 0x41, 0x20, 0x74, 0x68, ++ 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x69, ++ 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, ++ 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, ++ 0x2e, 0x74, 0x6d, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, ++ 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x74, 0x6d, 0x70, 0x66, ++ 0x69, 0x6c, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, ++ 0x70, 0x75, 0x74, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, ++ 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, ++ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x20, ++ 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, ++ 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, ++ 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, ++ 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x74, ++ 0x6f, 0x75, 0x63, 0x68, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, ++ 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, ++ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, ++ 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, ++ 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, ++ 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, ++ 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, ++ 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, ++ 0x31, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, ++ 0x20, 0x7e, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x66, ++ 0x66, 0x69, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x20, ++ 0x76, 0x20, 0x69, 0x6e, 0x20, 0x6e, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x66, 0x69, 0x20, 0x64, ++ 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x20, 0x7e, ++ 0x3d, 0x20, 0x27, 0x67, 0x63, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, 0x5b, 0x6b, 0x5d, 0x20, 0x3d, ++ 0x20, 0x6e, 0x69, 0x6c, 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, 0x66, 0x66, 0x69, ++ 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, ++ 0x6f, 0x73, 0x2e, 0x5b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x7c, 0x6f, 0x73, 0x2e, 0x73, ++ 0x70, 0x61, 0x77, 0x6e, 0x7c, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x5d, 0x20, 0x61, 0x6c, ++ 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, ++ 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x61, 0x77, 0x61, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x0a, 0x69, ++ 0x66, 0x20, 0x6d, 0x64, 0x35, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, ++ 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, ++ 0x20, 0x67, 0x73, 0x75, 0x62, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, ++ 0x2e, 0x67, 0x73, 0x75, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, ++ 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, ++ 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, ++ 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, ++ 0x2e, 0x62, 0x79, 0x74, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, ++ 0x74, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x20, 0x74, 0x68, + 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, +- 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, 0x58, 0x41, 0x28, ++ 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x28, + 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, + 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x75, 0x6d, 0x28, + 0x6b, 0x29, 0x2c, 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d, +- 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x58, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, ++ 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x78, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, + 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, + 0x6e, 0x64, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, +- 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x3a, +- 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x67, 0x6f, 0x20, 0x61, +- 0x77, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, 0x6e, 0x70, 0x61, +- 0x63, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x6e, 0x70, 0x61, +- 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x75, 0x6e, 0x70, 0x61, 0x63, +- 0x6b, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x70, 0x61, +- 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, +- 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, +- 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, +- 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, +- 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x74, 0x72, 0x69, 0x6e, +- 0x67, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, +- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x65, 0x6e, 0x64, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, ++ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, 0x58, 0x41, ++ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, ++ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, ++ 0x58, 0x41, 0x28, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, ++ 0x75, 0x6d, 0x28, 0x6b, 0x29, 0x2c, 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, ++ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, ++ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x58, 0x22, 0x2c, 0x62, 0x79, 0x74, ++ 0x65, 0x28, 0x63, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, + 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, +- 0x74, 0x79, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, +- 0x74, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x74, 0x68, +- 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, +- 0x2e, 0x32, 0x3a, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x0a, 0x0a, +- 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x74, 0x68, 0x65, 0x6e, +- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, 0x2e, 0x33, +- 0x3a, 0x20, 0x20, 0x62, 0x69, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2e, 0x6c, 0x75, 0x61, 0x2c, 0x20, +- 0x76, 0x20, 0x31, 0x2e, 0x32, 0x34, 0x20, 0x32, 0x30, 0x31, 0x34, 0x2f, 0x31, 0x32, 0x2f, 0x32, +- 0x36, 0x20, 0x31, 0x37, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x20, 0x72, 0x6f, 0x62, 0x65, 0x72, +- 0x74, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, +- 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, +- 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, +- 0x2d, 0x2d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, 0x3a, 0x20, 0x61, +- 0x72, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x7d, 0x0a, 0x0a, 0x62, 0x69, +- 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x3d, +- 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x29, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7e, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, +- 0x20, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +- 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, +- 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, +- 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, +- 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, +- 0x78, 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, +- 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x73, +- 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, +- 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, +- 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, ++ 0x74, 0x79, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x67, ++ 0x6f, 0x20, 0x61, 0x77, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, ++ 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, ++ 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x75, 0x6e, ++ 0x70, 0x61, 0x63, 0x6b, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, ++ 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, ++ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, ++ 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, ++ 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e, ++ 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x74, ++ 0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, ++ 0x61, 0x64, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x0a, ++ 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, ++ 0x69, 0x6c, 0x69, 0x74, 0x79, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, ++ 0x74, 0x20, 0x73, 0x74, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, ++ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, ++ 0x61, 0x20, 0x35, 0x2e, 0x32, 0x3a, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x6f, 0x6b, 0x61, ++ 0x79, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x74, ++ 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, ++ 0x35, 0x2e, 0x33, 0x3a, 0x20, 0x20, 0x62, 0x69, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2e, 0x6c, 0x75, ++ 0x61, 0x2c, 0x20, 0x76, 0x20, 0x31, 0x2e, 0x32, 0x34, 0x20, 0x32, 0x30, 0x31, 0x34, 0x2f, 0x31, ++ 0x32, 0x2f, 0x32, 0x36, 0x20, 0x31, 0x37, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x20, 0x72, 0x6f, ++ 0x62, 0x65, 0x72, 0x74, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, ++ 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, ++ 0x61, 0x6c, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, ++ 0x63, 0x74, 0x20, 0x2d, 0x2d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, ++ 0x3a, 0x20, 0x61, 0x72, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x7d, 0x0a, ++ 0x0a, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x62, 0x6e, 0x6f, ++ 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7e, 0x61, 0x20, 0x26, ++ 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, ++ 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, + 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, + 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, +- 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7c, 0x20, 0x28, +- 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, +- 0x20, 0x78, 0x20, 0x7c, 0x20, 0x79, 0x20, 0x7c, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, +- 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x7c, 0x20, +- 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, +- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, +- 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, +- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, +- 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, +- 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, +- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7e, +- 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, ++ 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, ++ 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, +- 0x20, 0x3d, 0x20, 0x78, 0x20, 0x7e, 0x20, 0x79, 0x20, 0x7e, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x3d, 0x20, 0x78, 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, +- 0x7e, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, ++ 0x26, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, +- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, 0x74, 0x20, 0x3d, ++ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, ++ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, ++ 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, ++ 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, ++ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, ++ 0x7c, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, ++ 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, ++ 0x73, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x7c, 0x20, 0x79, 0x20, 0x7c, 0x20, 0x7a, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, ++ 0x63, 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, ++ 0x20, 0x7c, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, ++ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, + 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, +- 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, +- 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, +- 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, +- 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, +- 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, +- 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, +- 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, +- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, +- 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, +- 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +- 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x29, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, +- 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +- 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, +- 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, +- 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, ++ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, ++ 0x29, 0x20, 0x7e, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, ++ 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, ++ 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, ++ 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x7e, 0x20, 0x79, 0x20, 0x7e, 0x20, 0x7a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, ++ 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, ++ 0x65, 0x73, 0x20, 0x7e, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, ++ 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, ++ 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, ++ 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, ++ 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, ++ 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x28, 0x78, 0x20, ++ 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x2d, ++ 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, ++ 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, ++ 0x3d, 0x20, 0x78, 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, ++ 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, ++ 0x20, 0x26, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, ++ 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, ++ 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, ++ 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, ++ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, ++ 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, ++ 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x3c, 0x3d, 0x20, 0x30, +- 0x20, 0x6f, 0x72, 0x20, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x38, 0x30, 0x30, 0x30, 0x30, +- 0x30, 0x30, 0x30, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, +- 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x62, +- 0x29, 0x20, 0x7c, 0x20, 0x7e, 0x28, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, +- 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, +- 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, +- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x2c, 0x62, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, ++ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, ++ 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, ++ 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, ++ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, +- 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, +- 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, +- 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, +- 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, +- 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x2d, 0x62, +- 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, +- 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, +- 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, +- 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, +- 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, +- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, +- 0x20, 0x66, 0x29, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, +- 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, +- 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, +- 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x76, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, +- 0x3d, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, +- 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, +- 0x28, 0x61, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3c, 0x3c, 0x20, 0x66, +- 0x29, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x28, 0x76, 0x20, 0x26, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x29, +- 0x20, 0x3c, 0x3c, 0x20, 0x66, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, +- 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x3c, ++ 0x3d, 0x20, 0x30, 0x20, 0x6f, 0x72, 0x20, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x38, 0x30, ++ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, ++ 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, ++ 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x3e, ++ 0x3e, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x7e, 0x28, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, ++ 0x46, 0x46, 0x46, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, ++ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, ++ 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x2c, ++ 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x26, 0x20, 0x33, ++ 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, ++ 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, 0x3e, ++ 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, ++ 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, ++ 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, ++ 0x20, 0x2d, 0x62, 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, ++ 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, ++ 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, ++ 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, ++ 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, ++ 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, 0x20, ++ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x66, 0x2c, 0x20, ++ 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, ++ 0x20, 0x3e, 0x3e, 0x20, 0x66, 0x29, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, ++ 0x20, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, ++ 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, ++ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x76, 0x2c, 0x20, 0x66, 0x2c, ++ 0x20, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, ++ 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, 0x20, ++ 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, ++ 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3c, ++ 0x3c, 0x20, 0x66, 0x29, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x28, 0x76, 0x20, 0x26, 0x20, 0x6d, 0x61, ++ 0x73, 0x6b, 0x29, 0x20, 0x3c, 0x3c, 0x20, 0x66, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, ++ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x7d, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, ++ 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x6a, 0x69, 0x74, 0x20, 0x28, 0x66, ++ 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, ++ 0x33, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, ++ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x2c, ++ 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, ++ 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, ++ 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, ++ 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x0a, 0x0a, 0x62, 0x69, ++ 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, ++ 0x74, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, ++ 0x0a, 0x20, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x6e, ++ 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, ++ 0x6e, 0x6f, 0x74, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, ++ 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, ++ 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x78, 0x6f, 0x72, 0x2c, 0x0a, ++ 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, ++ 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, ++ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x7e, ++ 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, ++ 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, ++ 0x61, 0x2c, 0x66, 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, ++ 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x61, 0x2c, ++ 0x66, 0x29, 0x2c, 0x32, 0x5e, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x29, ++ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, ++ 0x65, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x6f, 0x6c, 0x2c, 0x0a, 0x20, 0x20, 0x6c, ++ 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, ++ 0x0a, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, ++ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x76, 0x2c, 0x66, 0x2c, 0x77, 0x29, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, ++ 0x32, 0x5e, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x62, ++ 0x6e, 0x6f, 0x74, 0x28, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x2c, ++ 0x66, 0x29, 0x29, 0x29, 0x2b, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x62, 0x61, 0x6e, 0x64, ++ 0x28, 0x76, 0x2c, 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, ++ 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x62, ++ 0x69, 0x74, 0x2e, 0x72, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, ++ 0x20, 0x20, 0x3d, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, +- 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x6a, 0x69, 0x74, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, +- 0x6e, 0x6f, 0x77, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, +- 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, +- 0x6c, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x72, 0x73, +- 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x62, +- 0x69, 0x74, 0x2e, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x6e, 0x6f, +- 0x74, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x62, +- 0x69, 0x74, 0x2e, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x0a, 0x0a, 0x62, 0x69, 0x74, 0x33, 0x32, +- 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, +- 0x20, 0x62, 0x69, 0x74, 0x2e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, +- 0x62, 0x61, 0x6e, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x0a, +- 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x6e, 0x6f, 0x74, +- 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x69, +- 0x74, 0x2e, 0x62, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x20, 0x20, +- 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x78, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, +- 0x74, 0x65, 0x73, 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +- 0x6e, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, +- 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, +- 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, +- 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x66, +- 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, +- 0x61, 0x6e, 0x64, 0x28, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x61, 0x2c, 0x66, 0x29, 0x2c, +- 0x32, 0x5e, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, +- 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, +- 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x6f, 0x6c, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, 0x68, 0x69, +- 0x66, 0x74, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, +- 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, +- 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x76, 0x2c, 0x66, 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x32, 0x5e, 0x28, +- 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, +- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x62, 0x6e, 0x6f, 0x74, +- 0x28, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x66, 0x29, 0x29, +- 0x29, 0x2b, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x76, 0x2c, +- 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, +- 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, +- 0x72, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x20, 0x3d, +- 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, +- 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x0a, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, +- 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x62, 0x69, 0x74, 0x33, 0x32, 0x22, 0x29, 0x0a, 0x0a, 0x65, +- 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, +- 0x65, 0x65, 0x64, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6e, +- 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, +- 0x74, 0x22, 0x29, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, +- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, +- 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, +- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, +- 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, +- 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d, 0x20, +- 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, +- 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, +- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, 0x69, 0x6d, 0x65, +- 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, +- 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, +- 0x6d, 0x69, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x20, 0x20, 0x65, 0x6e, +- 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, +- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, +- 0x74, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x61, 0x74, +- 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, +- 0x61, 0x6c, 0x20, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, +- 0x75, 0x74, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, 0x79, 0x6d, 0x6c, 0x69, +- 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x6e, +- 0x6f, 0x77, 0x20, 0x62, 0x65, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, +- 0x20, 0x6c, 0x66, 0x73, 0x20, 0x28, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x61, 0x64, 0x20, 0x73, +- 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x66, 0x69, +- 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x66, +- 0x69, 0x6c, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, +- 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, 0x61, +- 0x6d, 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x20, +- 0x3d, 0x3d, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x20, 0x3d, +- 0x3d, 0x20, 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x64, +- 0x69, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x64, +- 0x69, 0x72, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x6c, +- 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, 0x61, 0x6d, +- 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x20, 0x3d, +- 0x3d, 0x20, 0x22, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x0a, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, +- 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x6e, +- 0x61, 0x6d, 0x65, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x62, +- 0x65, 0x20, 0x73, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, +- 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, 0x68, 0x6f, 0x72, +- 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x66, 0x6f, ++ 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x61, ++ 0x69, 0x6c, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, ++ 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x62, 0x69, 0x74, 0x33, 0x32, 0x22, 0x29, ++ 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, ++ 0x73, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x65, 0x74, ++ 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, ++ 0x63, 0x6b, 0x65, 0x74, 0x22, 0x29, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x0a, 0x64, 0x6f, ++ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x61, 0x64, ++ 0x65, 0x64, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, ++ 0x64, 0x65, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, ++ 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x74, 0x68, ++ 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, ++ 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, ++ 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, ++ 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, ++ 0x64, 0x2e, 0x6d, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, ++ 0x64, 0x5b, 0x22, 0x6d, 0x69, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x20, ++ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, ++ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, ++ 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, ++ 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, ++ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, 0x79, ++ 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, 0x61, ++ 0x6e, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x62, 0x65, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, 0x75, 0x73, ++ 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x66, 0x73, 0x20, 0x28, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x61, ++ 0x64, 0x20, 0x73, 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x29, 0x0a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, ++ 0x73, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, +- 0x73, 0x68, 0x6f, 0x72, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, +- 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, +- 0x20, 0x2d, 0x2d, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, +- 0x20, 0x61, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x2c, +- 0x20, 0x73, 0x6f, 0x20, 0x2e, 0x2e, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, +- 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x6b, +- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, +- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, +- 0x69, 0x6e, 0x6b, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, +- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x79, 0x6d, +- 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, +- 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x29, 0x20, 0x6f, 0x72, +- 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, +- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, +- 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x0a, 0x00 ++ 0x69, 0x73, 0x66, 0x69, 0x6c, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, ++ 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, ++ 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, ++ 0x20, 0x6d, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x6f, 0x72, 0x20, ++ 0x6d, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, ++ 0x69, 0x73, 0x64, 0x69, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, ++ 0x69, 0x73, 0x64, 0x69, 0x72, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, ++ 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, ++ 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, ++ 0x6d, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, ++ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x68, 0x6f, ++ 0x72, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6c, 0x73, ++ 0x6f, 0x20, 0x62, 0x65, 0x20, 0x73, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x72, 0x6f, ++ 0x70, 0x70, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x0a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, ++ 0x68, 0x6f, 0x72, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, ++ 0x66, 0x73, 0x2e, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, ++ 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, ++ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, ++ 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, ++ 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x66, 0x69, 0x65, ++ 0x6c, 0x64, 0x2c, 0x20, 0x73, 0x6f, 0x20, 0x2e, 0x2e, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, ++ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, ++ 0x69, 0x6e, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, ++ 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, ++ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, ++ 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, ++ 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x29, ++ 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, ++ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, ++ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x0a, 0x00 + }; + return luaL_dostring(L, (const char*) luatex_core_lua); + } +\ No newline at end of file diff --git a/SOURCES/texlive-20180414-poppler-20.11.0-luatex.patch b/SOURCES/texlive-20180414-poppler-20.11.0-luatex.patch deleted file mode 100644 index cc6e76c..0000000 --- a/SOURCES/texlive-20180414-poppler-20.11.0-luatex.patch +++ /dev/null @@ -1,155471 +0,0 @@ -commit 69c061f2071d5826fee7940ce7f83ae4a1c8fc2e -Author: Akira Kakuto -Date: Sat Apr 28 07:36:22 2018 +0000 - - support poppler-0.64.0 - - git-svn-id: svn://tug.org/texlive/trunk/Build/source@47470 c570f23f-e606-0410-a88d-b1316a301751 - -diff --git a/texk/web2c/luatexdir/image/pdftoepdf.w b/texk/web2c/luatexdir/image/pdftoepdf.w -index 7ba29731c..d69795926 100644 ---- a/texk/web2c/luatexdir/image/pdftoepdf.w -+++ b/texk/web2c/luatexdir/image/pdftoepdf.w -@@ -472,10 +472,10 @@ static void copyObject(PDF pdf, PdfDocument * pdf_doc, Object * obj) - break; - */ - case objString: -- copyString(pdf, obj->getString()); -+ copyString(pdf, (GooString *)obj->getString()); - break; - case objName: -- copyName(pdf, obj->getName()); -+ copyName(pdf, (char *)obj->getName()); - break; - case objNull: - pdf_add_null(pdf); -diff --git a/texk/web2c/luatexdir/lua/lepdflib.cc b/texk/web2c/luatexdir/lua/lepdflib.cc -index a16bf3bd4..32bcdab01 100644 ---- a/texk/web2c/luatexdir/lua/lepdflib.cc -+++ b/texk/web2c/luatexdir/lua/lepdflib.cc -@@ -674,7 +674,7 @@ static int m_##in##_##function(lua_State * L) \ - uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ - if (uin->pd != NULL && uin->pd->pc != uin->pc) \ - pdfdoc_changed_error(L); \ -- gs = ((in *) uin->d)->function(); \ -+ gs = (GooString *)((in *) uin->d)->function(); \ - if (gs != NULL) \ - lua_pushlstring(L, gs->getCString(), gs->getLength()); \ - else \ -@@ -1813,7 +1813,7 @@ static int m_Object_getString(lua_State * L) - if (uin->pd != NULL && uin->pd->pc != uin->pc) - pdfdoc_changed_error(L); - if (((Object *) uin->d)->isString()) { -- gs = ((Object *) uin->d)->getString(); -+ gs = (GooString *)((Object *) uin->d)->getString(); - lua_pushlstring(L, gs->getCString(), gs->getLength()); - } else - lua_pushnil(L); -diff --git a/texk/web2c/pdftexdir/ChangeLog b/texk/web2c/pdftexdir/ChangeLog -index c022bc252..f4af0358e 100644 ---- a/texk/web2c/pdftexdir/ChangeLog -+++ b/texk/web2c/pdftexdir/ChangeLog -@@ -1,3 +1,8 @@ -+2018-04-28 Akira Kakuto -+ -+ * pdftoepdf-newpoppler.cc, pdftosrc-newpoppler.cc: -+ Support poppler 0.64.0. -+ - 2018-04-14 Karl Berry - - * TeX Live 2018 release, pdftex 1.40.19. -diff --git a/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc b/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc -index 10fea2999..750579d61 100644 ---- a/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc -+++ b/texk/web2c/pdftexdir/pdftoepdf-newpoppler.cc -@@ -290,7 +290,7 @@ static void copyName(char *s) - static void copyDictEntry(Object * obj, int i) - { - Object obj1; -- copyName(obj->dictGetKey(i)); -+ copyName((char *)obj->dictGetKey(i)); - pdf_puts(" "); - obj1 = obj->dictGetValNF(i); - copyObject(&obj1); -@@ -355,7 +355,7 @@ static void copyProcSet(Object * obj) - if (!procset.isName()) - pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>", - procset.getTypeName()); -- copyName(procset.getName()); -+ copyName((char *)procset.getName()); - pdf_puts(" "); - } - pdf_puts("]\n"); -@@ -418,7 +418,7 @@ static void copyFont(char *tag, Object * fontRef) - && fontdescRef.isRef() - && fontdesc.isDict() - && embeddableFont(&fontdesc) -- && (fontmap = lookup_fontmap(basefont.getName())) != NULL) { -+ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) { - // round /StemV value, since the PDF input is a float - // (see Font Descriptors in PDF reference), but we only store an - // integer, since we don't want to change the struct. -@@ -427,7 +427,7 @@ static void copyFont(char *tag, Object * fontRef) - charset = fontdesc.dictLookup("CharSet"); - if (!charset.isNull() && - charset.isString() && is_subsetable(fontmap)) -- epdf_mark_glyphs(fd, charset.getString()->getCString()); -+ epdf_mark_glyphs(fd, (char *)charset.getString()->getCString()); - else - embed_whole_font(fd); - addFontDesc(fontdescRef.getRef(), fd); -@@ -456,7 +456,7 @@ static void copyFontResources(Object * obj) - if (fontRef.isRef()) - copyFont(obj->dictGetKey(i), &fontRef); - else if (fontRef.isDict()) { // some programs generate pdf with embedded font object -- copyName(obj->dictGetKey(i)); -+ copyName((char *)obj->dictGetKey(i)); - pdf_puts(" "); - copyObject(&fontRef); - } -@@ -565,7 +565,7 @@ static void copyObject(Object * obj) - } else if (obj->isNum()) { - pdf_printf("%s", convertNumToPDF(obj->getNum())); - } else if (obj->isString()) { -- s = obj->getString(); -+ s = (GooString *)obj->getString(); - p = s->getCString(); - l = s->getLength(); - if (strlen(p) == (unsigned int) l) { -@@ -589,7 +589,7 @@ static void copyObject(Object * obj) - pdf_puts(">"); - } - } else if (obj->isName()) { -- copyName(obj->getName()); -+ copyName((char *)obj->getName()); - } else if (obj->isNull()) { - pdf_puts("null"); - } else if (obj->isArray()) { -diff --git a/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc b/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc -index 4e2bcadbd..0db154b4f 100644 ---- a/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc -+++ b/texk/web2c/pdftexdir/pdftosrc-newpoppler.cc -@@ -109,7 +109,7 @@ int main(int argc, char *argv[]) - fprintf(stderr, "No SourceName found\n"); - exit(1); - } -- outname = srcName.getString()->getCString(); -+ outname = (char *)srcName.getString()->getCString(); - // We cannot free srcName, as objname shares its string. - // srcName.free(); - } else if (objnum > 0) { -commit 5f7832c4bf868184f41ac0a5f80af10475ae1ff4 -Author: Karl Berry -Date: Tue Jul 31 20:52:36 2018 +0000 - - doc,sync - - git-svn-id: svn://tug.org/texlive/trunk/Build/source@48318 c570f23f-e606-0410-a88d-b1316a301751 - -diff --git a/doc/tlbuild.info b/doc/tlbuild.info -index 62391d8af..fb7848e3a 100644 ---- a/doc/tlbuild.info -+++ b/doc/tlbuild.info -@@ -356,7 +356,8 @@ finish for working on 'dvipdfm-x'. - make check - - Then you modify source files in 'mydir/texk/dvipdfm-x' and rerun --'make' in 'mydir/Work/texk/dvipdfm-x' to rebuild. -+'make' in 'mydir/Work/texk/dvipdfm-x' to rebuild (that build directory -+is where the binaries end up). - - The second line of the 'configure' invocation shows examples of extra - things you likely want to specify if you intend to hack the sources (and -@@ -375,8 +376,8 @@ do so. If you cut down the source tree, you must also give additional - 'configure' flags to individually disable using system versions of - libraries, or the intricacies of the dependencies (such as 'teckit' - requiring 'zlib') will have undesired side effects. For an example, see --the 'build-pdftex.sh' script in the 'pdftex' development source --(), which is indeed a cut-down TL source tree. -+the 'build-pdftex.sh' script in the 'pdftex' development source (details -+at ), which is indeed a cut-down TL source tree. - - Even with '--disable-all-pkgs', dependencies will be checked. For - instance, if a non-MacOSX system does not have 'fontconfig', XeTeX -@@ -517,7 +518,7 @@ This section discusses the results of 'make install' in the source tree. - - The main consideration is that 'make install' is not enough to make a - usable TeX installation. Beyond the compiled binaries, (thousands of) --support files are needed; just as a first example 'plain.tex' is not in -+support files are needed; just as a first example, 'plain.tex' is not in - the source tree. - - These support files are maintained completely independently and are -@@ -5045,7 +5046,7 @@ Index - * --enable-maintainer-mode: Build system tools. (line 28) - * --enable-maintainer-mode <1>: --enable-maintainer-mode. - (line 6) --* --enable-missing to ignore dependencies: Build one package. (line 67) -+* --enable-missing to ignore dependencies: Build one package. (line 68) - * --enable-mktextfm-default: kpathsea library. (line 20) - * --enable-multiplatform: --enable-multiplatform. - (line 6) -@@ -5161,7 +5162,7 @@ Index - * callexe.c: Macros for Windows. (line 32) - * CC: Variables for configure. - (line 10) --* CC=C-COMPILER: Build one package. (line 73) -+* CC=C-COMPILER: Build one package. (line 74) - * CC_BUILD: Cross problems. (line 13) - * chktex: Declarations and definitions. - (line 18) -@@ -5220,7 +5221,7 @@ Index - * ctangle: Cross problems. (line 26) - * CXX: Variables for configure. - (line 11) --* CXX=C++-COMPILER: Build one package. (line 73) -+* CXX=C++-COMPILER: Build one package. (line 74) - * Debian installation of build prerequisites: Prerequisites. (line 60) - * declarations and definitions, in source code: Declarations and definitions. - (line 6) -@@ -5408,7 +5409,7 @@ Index - * motif: Configure options for texk/xdvik. - (line 9) - * native cross compilation: Cross compilation. (line 10) --* OBJCXX=OBJC-COMPILER: Build one package. (line 73) -+* OBJCXX=OBJC-COMPILER: Build one package. (line 74) - * one package, building: Build one package. (line 6) - * OpenGL, required for Asymptote: asymptote. (line 6) - * operating system distribution, building for: Distro builds. (line 6) -@@ -5451,7 +5452,7 @@ Index - * setup macros, general: General setup macros. (line 6) - * shared libraries, using vs. avoiding: Distro builds. (line 11) - * size of PDF and PS files: --disable-largefile. (line 10) --* size of source tree: Build one package. (line 57) -+* size of source tree: Build one package. (line 58) - * source code declarations: Declarations and definitions. - (line 6) - * source directory building, not supported: Building. (line 17) -@@ -5547,360 +5548,360 @@ Node: Build problems10656 - Node: Build in parallel11059 - Node: Build distribution11651 - Node: Build one package12222 --Node: Cross compilation15600 --Node: Cross configuring16881 --Node: Cross problems18558 --Node: Installing20209 --Node: Installation directories21224 --Node: Linked scripts23040 --Node: Distro builds24521 --Node: Layout and infrastructure26911 --Node: Build system tools27739 --Node: Top-level directories29750 --Node: Autoconf macros32164 --Node: General setup macros32865 --Node: Macros for programs33732 --Node: Macros for compilers34544 --Node: Macros for libraries35978 --Node: Macros for library and header flags36404 --Node: Macros for Windows38284 --Node: Library modules39861 --Node: png library40350 --Node: zlib library42624 --Node: freetype library43139 --Node: kpathsea library43667 --Node: Program modules45066 --Node: t1utils package45494 --Node: xindy package46045 --Node: xdvik package47195 --Node: asymptote48268 --Node: Extending TeX Live48719 --Node: Adding a new program module49496 --Node: Adding a new generic library module52791 --Node: Adding a new TeX-specific library module55004 --Node: Configure options55691 --Node: Global configure options57074 --Node: --disable-native-texlive-build57616 --Node: --prefix --bindir ...58606 --Node: --disable-largefile59146 --Node: --disable-missing59831 --Node: --enable-compiler-warnings=LEVEL60232 --Node: --enable-cxx-runtime-hack60971 --Node: --enable-maintainer-mode61398 --Node: --enable-multiplatform61927 --Node: --enable-shared62465 --Node: --enable-silent-rules62836 --Node: --without-ln-s63292 --Node: --without-x63643 --Node: Program-specific configure options63831 --Node: --enable-PROG --disable-PROG64474 --Node: --disable-all-pkgs64751 --Node: Configure options for texk/web2c65737 --Node: Configure options for texk/bibtex-x68255 --Node: Configure options for texk/dvipdfm-x68798 --Node: Configure options for texk/dvisvgm69571 --Node: Configure options for texk/texlive70457 --Node: Configure options for texk/xdvik70878 --Node: Configure options for utils/xindy71482 --Node: Library-specific configure options72383 --Node: Configure options for kpathsea73394 --Node: Configure options for system poppler74103 --Node: Variables for configure74894 --Node: Coding conventions76322 --Node: Declarations and definitions77061 --Node: Const79243 --Node: Continuous integration81106 --Node: Transfer from Subversion to Github81760 --Node: Automatic update of the Git mirror83942 --Node: CI testing on Travis-CI84530 --Node: install-tl85210 --Node: install-tl NAME85579 --Node: install-tl SYNOPSIS85737 --Node: install-tl DESCRIPTION85995 --Node: install-tl REFERENCES87062 --Node: install-tl OPTIONS87588 --Ref: install-tl *-gui* [[=]_module_]87929 --Ref: install-tl text88139 --Ref: install-tl wizard88262 --Ref: install-tl perltk88416 --Ref: install-tl *-no-gui*88847 --Ref: install-tl *-lang* _llcode_88928 --Ref: install-tl *-repository* _url|path_89615 --Ref: install-tl *-select-repository*91495 --Ref: install-tl *-all-options*91931 --Ref: install-tl *-custom-bin* _path_92186 --Ref: install-tl *-debug-translation*93017 --Ref: install-tl *-force-platform* _platform_93236 --Ref: install-tl *-help*, *--help*, *-?*93480 --Ref: install-tl *-in-place*93887 --Ref: install-tl *-init-from-profile* _profile_file_94432 --Ref: install-tl *-logfile* _file_94652 --Ref: install-tl *-no-cls*95003 --Ref: install-tl *-non-admin*95137 --Ref: install-tl *-persistent-downloads*95242 --Ref: install-tl *-no-persistent-downloads*95270 --Ref: install-tl *-no-verify-downloads*95888 --Ref: install-tl *-portable*96249 --Ref: install-tl *-print-platform*96388 --Ref: install-tl *-profile* _profile_file_96586 --Ref: install-tl *-q*96766 --Ref: install-tl *-scheme* _scheme_96828 --Ref: install-tl *-v*97302 --Ref: install-tl *-version*, *--version*97457 --Node: install-tl PROFILES97588 --Ref: install-tl instopt_adjustpath (default 0 on Unix, 1 on Windows)100238 --Ref: install-tl instopt_adjustrepo (default 1)100314 --Ref: install-tl instopt_letter (default 0)100451 --Ref: install-tl instopt_portable (default 0)100542 --Ref: install-tl instopt_write18_restricted (default 1)100638 --Node: install-tl ENVIRONMENT VARIABLES101957 --Ref: install-tl TEXLIVE_INSTALL_ENV_NOCHECK102348 --Ref: install-tl TEXLIVE_INSTALL_NO_CONTEXT_CACHE102550 --Ref: install-tl TEXLIVE_INSTALL_NO_WELCOME102660 --Ref: install-tl TEXLIVE_INSTALL_PREFIX102781 --Ref: install-tl TEXLIVE_INSTALL_TEXDIR102807 --Ref: install-tl TEXLIVE_INSTALL_TEXMFCONFIG102838 --Ref: install-tl TEXLIVE_INSTALL_TEXMFVAR102866 --Ref: install-tl TEXLIVE_INSTALL_TEXMFHOME102895 --Ref: install-tl TEXLIVE_INSTALL_TEXMFLOCAL102925 --Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSCONFIG102959 --Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSVAR102990 --Ref: install-tl NOPERLDOC103361 --Node: install-tl AUTHORS AND COPYRIGHT103425 --Node: tlmgr103841 --Node: tlmgr NAME104294 --Node: tlmgr SYNOPSIS104426 --Node: tlmgr DESCRIPTION104616 --Node: tlmgr EXAMPLES105712 --Ref: tlmgr tlmgr option repository ctan105963 --Ref: tlmgr tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet106035 --Ref: tlmgr tlmgr update --list106487 --Ref: tlmgr tlmgr update --all106580 --Ref: tlmgr tlmgr info _what_106737 --Node: tlmgr OPTIONS106999 --Ref: tlmgr *--repository* _url|path_107519 --Ref: tlmgr *--gui* [_action_]108244 --Ref: tlmgr *--gui-lang* _llcode_108651 --Ref: tlmgr *--debug-translation*109334 --Ref: tlmgr *--machine-readable*109537 --Ref: tlmgr *--no-execute-actions*109805 --Ref: tlmgr *--package-logfile* _file_109998 --Ref: tlmgr *--pause*110252 --Ref: tlmgr *--persistent-downloads*110407 --Ref: tlmgr *--no-persistent-downloads*110435 --Ref: tlmgr *--pin-file*110929 --Ref: tlmgr *--usermode*111147 --Ref: tlmgr *--usertree* _dir_111267 --Ref: tlmgr *--verify-repo=[none|main|all]*111393 --Node: tlmgr ACTIONS112292 --Node: tlmgr help113144 --Node: tlmgr version113620 --Node: tlmgr backup113883 --Ref: tlmgr *backup [_option_...] --all*114054 --Ref: tlmgr *backup [_option_...] _pkg_...*114087 --Ref: tlmgr *--backupdir* _directory_114942 --Ref: tlmgr *--all*115159 --Ref: tlmgr *--clean*[=_N_]115411 --Ref: tlmgr *--dry-run*115738 --Node: tlmgr candidates _pkg_115868 --Node: tlmgr check [_option_...] [files|depends|executes|runfiles|all]116214 --Ref: tlmgr *files*116587 --Ref: tlmgr *depends*116722 --Ref: tlmgr *executes*117064 --Ref: tlmgr *runfiles*117182 --Ref: tlmgr *--use-svn*117303 --Node: tlmgr conf117420 --Ref: tlmgr *conf [texmf|tlmgr|updmap [--conffile _file_] [--delete] [_key_ [_value_]]]*117699 --Ref: tlmgr *conf auxtrees [--conffile _file_] [show|add|delete] [_value_]*117763 --Node: tlmgr dump-tlpdb [_option_...] [--json]120108 --Ref: tlmgr *--local*120541 --Ref: tlmgr *--remote*120580 --Ref: tlmgr *--json*120618 --Node: tlmgr generate121189 --Ref: tlmgr *generate [_option_...] language*121385 --Ref: tlmgr *generate [_option_...] language.dat*121424 --Ref: tlmgr *generate [_option_...] language.def*121463 --Ref: tlmgr *generate [_option_...] language.dat.lua*121506 --Ref: tlmgr *--dest* _output_file_123832 --Ref: tlmgr *--localcfg* _local_conf_file_124408 --Ref: tlmgr *--rebuild-sys*124531 --Node: tlmgr gui125346 --Node: tlmgr info125524 --Ref: tlmgr *info [_option_...] _pkg_...*125686 --Ref: tlmgr *info [_option_...] collections*125720 --Ref: tlmgr *info [_option_...] schemes*125750 --Ref: tlmgr *--list*127280 --Ref: tlmgr *--only-installed*127594 --Ref: tlmgr *--data item1,item2,...*127793 --Ref: tlmgr *--json* 1128374 --Node: tlmgr init-usertree128757 --Node: tlmgr install [_option_...] _pkg_...129138 --Ref: tlmgr *--dry-run* 1129648 --Ref: tlmgr *--file*129765 --Ref: tlmgr *--force*129987 --Ref: tlmgr *--no-depends*130207 --Ref: tlmgr *--no-depends-at-all*130366 --Ref: tlmgr *--reinstall*130766 --Ref: tlmgr *--with-doc*131144 --Ref: tlmgr *--with-src*131157 --Node: tlmgr key131679 --Ref: tlmgr *key list*131837 --Ref: tlmgr *key add _file_*131855 --Ref: tlmgr *key remove _keyid_*131877 --Node: tlmgr list132472 --Node: tlmgr option132634 --Ref: tlmgr *option [--json] [show]*132789 --Ref: tlmgr *option [--json] showall*132815 --Ref: tlmgr *option _key_ [_value_]*132841 --Node: tlmgr paper137238 --Ref: tlmgr *paper [a4|letter]*137387 --Ref: tlmgr *[xdvi|pdftex|dvips|dvipdfmx|context|psutils] paper [_papersize_|--list]*137461 --Ref: tlmgr *paper --json*137476 --Node: tlmgr path138691 --Ref: tlmgr *path [--w32mode=user|admin] add*138852 --Ref: tlmgr *path [--w32mode=user|admin] remove*138889 --Node: tlmgr pinning140229 --Ref: tlmgr pinning show140470 --Ref: tlmgr pinning add _repo_ _pkgglob_...140543 --Ref: tlmgr pinning remove _repo_ _pkgglob_...140662 --Ref: tlmgr pinning remove _repo_ --all140815 --Node: tlmgr platform140869 --Ref: tlmgr *platform list|add|remove _platform_...*141055 --Ref: tlmgr *platform set _platform_*141082 --Ref: tlmgr *platform set auto*141103 --Ref: tlmgr *--dry-run* 2141989 --Node: tlmgr postaction142108 --Ref: tlmgr *postaction [_option_...] install [shortcut|fileassoc|script] [_pkg_...]*142338 --Ref: tlmgr *postaction [_option_...] remove [shortcut|fileassoc|script] [_pkg_...]*142412 --Ref: tlmgr *--w32mode=[user|admin]*142727 --Ref: tlmgr *--fileassocmode=[1|2]*143143 --Ref: tlmgr *--all* 1143428 --Node: tlmgr print-platform143483 --Node: tlmgr print-platform-info143814 --Node: tlmgr remove [_option_...] _pkg_...144114 --Ref: tlmgr *--all* 2144598 --Ref: tlmgr *--backup*144708 --Ref: tlmgr *--backupdir* _directory_ 1144734 --Ref: tlmgr *--no-depends* 1145139 --Ref: tlmgr *--no-depends-at-all* 1145201 --Ref: tlmgr *--force* 1145304 --Ref: tlmgr *--dry-run* 3145777 --Node: tlmgr repository145884 --Ref: tlmgr *repository list*146072 --Ref: tlmgr *repository list _path|tag_*146102 --Ref: tlmgr *repository add _path_ [_tag_]*146135 --Ref: tlmgr *repository remove _path|tag_*146167 --Ref: tlmgr *repository set _path_[#_tag_] [_path_[#_tag_] ...]*146221 --Node: tlmgr restore147274 --Ref: tlmgr *restore [_option_...] _pkg_ [_rev_]*147453 --Ref: tlmgr *restore [_option_...] --all*147483 --Ref: tlmgr *--all* 3148183 --Ref: tlmgr *--backupdir* _directory_ 2148397 --Ref: tlmgr *--dry-run* 4148578 --Ref: tlmgr *--force* 2148710 --Ref: tlmgr *--json* 2148756 --Node: tlmgr search149083 --Ref: tlmgr *search [_option_...] _what_*149247 --Ref: tlmgr *search [_option_...] --file _what_*149284 --Ref: tlmgr *search [_option_...] --all _what_*149320 --Ref: tlmgr *--file* 1149540 --Ref: tlmgr *--all* 4149602 --Ref: tlmgr *--global*149691 --Ref: tlmgr *--word*149818 --Node: tlmgr shell150133 --Ref: tlmgr protocol150868 --Ref: tlmgr help 1150932 --Ref: tlmgr version 1150985 --Ref: tlmgr quit, end, bye, byebye, EOF151053 --Ref: tlmgr restart151074 --Ref: tlmgr load [local|remote]151197 --Ref: tlmgr save151267 --Ref: tlmgr get [_var_] =item set [_var_ [_val_]]151390 --Node: tlmgr show151991 --Node: tlmgr uninstall152158 --Node: tlmgr update [_option_...] [_pkg_...]152388 --Ref: tlmgr *--all* 5152759 --Ref: tlmgr *--self*154500 --Ref: tlmgr *--dry-run* 5155264 --Ref: tlmgr *--list* [_pkg_]155441 --Ref: tlmgr *--exclude* _pkg_156130 --Ref: tlmgr *--no-auto-remove* [_pkg_...]156930 --Ref: tlmgr *--no-auto-install* [_pkg_...]157381 --Ref: tlmgr *--reinstall-forcibly-removed*158037 --Ref: tlmgr *--backup* 1158572 --Ref: tlmgr *--backupdir* _directory_ 3158598 --Ref: tlmgr *--no-depends* 2159764 --Ref: tlmgr *--no-depends-at-all* 2159967 --Ref: tlmgr *--force* 3160070 --Node: tlmgr CONFIGURATION FILE FOR TLMGR160885 --Ref: tlmgr auto-remove, value 0 or 1 (default 1), same as command-line option.161898 --Ref: tlmgr gui-expertmode, value 0 or 1 (default 1). This switches between the full GUI and a simplified GUI with only the most common settings.162035 --Ref: tlmgr gui-lang _llcode_, with a language code value as with the command-line option.162117 --Ref: tlmgr no-checksums, value 0 or 1 (default 0, see below).162171 --Ref: tlmgr persistent-downloads, value 0 or 1 (default 1), same as command-line option.162251 --Ref: tlmgr require-verification, value 0 or 1 (default 0), same as command-line option.162331 --Ref: tlmgr update-exclude, value: comma-separated list of packages (no space allowed). Same as the command line option --exclude for the action update.162479 --Ref: tlmgr verify-downloads, value 0 or 1 (default 1), same as command-line option.162555 --Ref: tlmgr allowed-actions _action1_ [,_action_,...] The value is a comma-separated list of tlmgr actions which are allowed to be executed when tlmgr is invoked in system mode (that is, without --usermode).162824 --Node: tlmgr CRYPTOGRAPHIC VERIFICATION163910 --Node: tlmgr Configuration of GnuPG invocation166059 --Node: tlmgr USER MODE166697 --Node: tlmgr User mode install169543 --Node: tlmgr User mode backup, restore, remove, update170687 --Node: tlmgr User mode generate, option, paper171129 --Node: tlmgr MULTIPLE REPOSITORIES171505 --Node: tlmgr Pinning173234 --Node: tlmgr GUI FOR TLMGR175209 --Node: tlmgr Main display176549 --Node: tlmgr Display configuration area176801 --Ref: tlmgr Status177162 --Ref: tlmgr Category177326 --Ref: tlmgr Match177512 --Ref: tlmgr Selection177693 --Ref: tlmgr Display configuration buttons177897 --Node: tlmgr Package list area178080 --Ref: tlmgr a checkbox178664 --Ref: tlmgr package name178800 --Ref: tlmgr local revision (and version)178899 --Ref: tlmgr remote revision (and version)179274 --Ref: tlmgr short description179571 --Node: tlmgr Main display action buttons179616 --Ref: tlmgr Update all installed179882 --Ref: tlmgr Update180254 --Ref: tlmgr Install180304 --Ref: tlmgr Remove180490 --Ref: tlmgr Backup180668 --Node: tlmgr Menu bar180825 --Ref: tlmgr tlmgr menu181048 --Ref: tlmgr Options menu181356 --Ref: tlmgr Actions menu182439 --Ref: tlmgr Help menu182867 --Node: tlmgr GUI options183000 --Ref: tlmgr -background _color_183246 --Ref: tlmgr -font " _fontname_ _fontsize_ "183311 --Ref: tlmgr -foreground _color_183469 --Ref: tlmgr -geometry _geomspec_183521 --Ref: tlmgr -xrm _xresource_183713 --Node: tlmgr MACHINE-READABLE OUTPUT183981 --Node: tlmgr Machine-readable update and install output184791 --Ref: tlmgr location-url _location_186067 --Ref: tlmgr total-bytes _count_186283 --Ref: tlmgr _pkgname_186693 --Ref: tlmgr _status_186903 --Ref: tlmgr d186981 --Ref: tlmgr f187041 --Ref: tlmgr u187220 --Ref: tlmgr r187266 --Ref: tlmgr a187389 --Ref: tlmgr i187567 --Ref: tlmgr I187686 --Ref: tlmgr _localrev_187788 --Ref: tlmgr _serverrev_187895 --Ref: tlmgr _size_188007 --Ref: tlmgr _runtime_188176 --Ref: tlmgr _esttot_188246 --Node: tlmgr Machine-readable option output188279 --Node: tlmgr AUTHORS AND COPYRIGHT188791 --Node: Index189190 -+Node: Cross compilation15663 -+Node: Cross configuring16944 -+Node: Cross problems18621 -+Node: Installing20272 -+Node: Installation directories21288 -+Node: Linked scripts23104 -+Node: Distro builds24585 -+Node: Layout and infrastructure26975 -+Node: Build system tools27803 -+Node: Top-level directories29814 -+Node: Autoconf macros32228 -+Node: General setup macros32929 -+Node: Macros for programs33796 -+Node: Macros for compilers34608 -+Node: Macros for libraries36042 -+Node: Macros for library and header flags36468 -+Node: Macros for Windows38348 -+Node: Library modules39925 -+Node: png library40414 -+Node: zlib library42688 -+Node: freetype library43203 -+Node: kpathsea library43731 -+Node: Program modules45130 -+Node: t1utils package45558 -+Node: xindy package46109 -+Node: xdvik package47259 -+Node: asymptote48332 -+Node: Extending TeX Live48783 -+Node: Adding a new program module49560 -+Node: Adding a new generic library module52855 -+Node: Adding a new TeX-specific library module55068 -+Node: Configure options55755 -+Node: Global configure options57138 -+Node: --disable-native-texlive-build57680 -+Node: --prefix --bindir ...58670 -+Node: --disable-largefile59210 -+Node: --disable-missing59895 -+Node: --enable-compiler-warnings=LEVEL60296 -+Node: --enable-cxx-runtime-hack61035 -+Node: --enable-maintainer-mode61462 -+Node: --enable-multiplatform61991 -+Node: --enable-shared62529 -+Node: --enable-silent-rules62900 -+Node: --without-ln-s63356 -+Node: --without-x63707 -+Node: Program-specific configure options63895 -+Node: --enable-PROG --disable-PROG64538 -+Node: --disable-all-pkgs64815 -+Node: Configure options for texk/web2c65801 -+Node: Configure options for texk/bibtex-x68319 -+Node: Configure options for texk/dvipdfm-x68862 -+Node: Configure options for texk/dvisvgm69635 -+Node: Configure options for texk/texlive70521 -+Node: Configure options for texk/xdvik70942 -+Node: Configure options for utils/xindy71546 -+Node: Library-specific configure options72447 -+Node: Configure options for kpathsea73458 -+Node: Configure options for system poppler74167 -+Node: Variables for configure74958 -+Node: Coding conventions76386 -+Node: Declarations and definitions77125 -+Node: Const79307 -+Node: Continuous integration81170 -+Node: Transfer from Subversion to Github81824 -+Node: Automatic update of the Git mirror84006 -+Node: CI testing on Travis-CI84594 -+Node: install-tl85274 -+Node: install-tl NAME85643 -+Node: install-tl SYNOPSIS85801 -+Node: install-tl DESCRIPTION86059 -+Node: install-tl REFERENCES87126 -+Node: install-tl OPTIONS87652 -+Ref: install-tl *-gui* [[=]_module_]87993 -+Ref: install-tl text88203 -+Ref: install-tl wizard88326 -+Ref: install-tl perltk88480 -+Ref: install-tl *-no-gui*88911 -+Ref: install-tl *-lang* _llcode_88992 -+Ref: install-tl *-repository* _url|path_89679 -+Ref: install-tl *-select-repository*91559 -+Ref: install-tl *-all-options*91995 -+Ref: install-tl *-custom-bin* _path_92250 -+Ref: install-tl *-debug-translation*93081 -+Ref: install-tl *-force-platform* _platform_93300 -+Ref: install-tl *-help*, *--help*, *-?*93544 -+Ref: install-tl *-in-place*93951 -+Ref: install-tl *-init-from-profile* _profile_file_94496 -+Ref: install-tl *-logfile* _file_94716 -+Ref: install-tl *-no-cls*95067 -+Ref: install-tl *-non-admin*95201 -+Ref: install-tl *-persistent-downloads*95306 -+Ref: install-tl *-no-persistent-downloads*95334 -+Ref: install-tl *-no-verify-downloads*95952 -+Ref: install-tl *-portable*96313 -+Ref: install-tl *-print-platform*96452 -+Ref: install-tl *-profile* _profile_file_96650 -+Ref: install-tl *-q*96830 -+Ref: install-tl *-scheme* _scheme_96892 -+Ref: install-tl *-v*97366 -+Ref: install-tl *-version*, *--version*97521 -+Node: install-tl PROFILES97652 -+Ref: install-tl instopt_adjustpath (default 0 on Unix, 1 on Windows)100302 -+Ref: install-tl instopt_adjustrepo (default 1)100378 -+Ref: install-tl instopt_letter (default 0)100515 -+Ref: install-tl instopt_portable (default 0)100606 -+Ref: install-tl instopt_write18_restricted (default 1)100702 -+Node: install-tl ENVIRONMENT VARIABLES102021 -+Ref: install-tl TEXLIVE_INSTALL_ENV_NOCHECK102412 -+Ref: install-tl TEXLIVE_INSTALL_NO_CONTEXT_CACHE102614 -+Ref: install-tl TEXLIVE_INSTALL_NO_WELCOME102724 -+Ref: install-tl TEXLIVE_INSTALL_PREFIX102845 -+Ref: install-tl TEXLIVE_INSTALL_TEXDIR102871 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFCONFIG102902 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFVAR102930 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFHOME102959 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFLOCAL102989 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSCONFIG103023 -+Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSVAR103054 -+Ref: install-tl NOPERLDOC103425 -+Node: install-tl AUTHORS AND COPYRIGHT103489 -+Node: tlmgr103905 -+Node: tlmgr NAME104358 -+Node: tlmgr SYNOPSIS104490 -+Node: tlmgr DESCRIPTION104680 -+Node: tlmgr EXAMPLES105776 -+Ref: tlmgr tlmgr option repository ctan106027 -+Ref: tlmgr tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet106099 -+Ref: tlmgr tlmgr update --list106551 -+Ref: tlmgr tlmgr update --all106644 -+Ref: tlmgr tlmgr info _what_106801 -+Node: tlmgr OPTIONS107063 -+Ref: tlmgr *--repository* _url|path_107583 -+Ref: tlmgr *--gui* [_action_]108308 -+Ref: tlmgr *--gui-lang* _llcode_108715 -+Ref: tlmgr *--debug-translation*109398 -+Ref: tlmgr *--machine-readable*109601 -+Ref: tlmgr *--no-execute-actions*109869 -+Ref: tlmgr *--package-logfile* _file_110062 -+Ref: tlmgr *--pause*110316 -+Ref: tlmgr *--persistent-downloads*110471 -+Ref: tlmgr *--no-persistent-downloads*110499 -+Ref: tlmgr *--pin-file*110993 -+Ref: tlmgr *--usermode*111211 -+Ref: tlmgr *--usertree* _dir_111331 -+Ref: tlmgr *--verify-repo=[none|main|all]*111457 -+Node: tlmgr ACTIONS112356 -+Node: tlmgr help113208 -+Node: tlmgr version113684 -+Node: tlmgr backup113947 -+Ref: tlmgr *backup [_option_...] --all*114118 -+Ref: tlmgr *backup [_option_...] _pkg_...*114151 -+Ref: tlmgr *--backupdir* _directory_115006 -+Ref: tlmgr *--all*115223 -+Ref: tlmgr *--clean*[=_N_]115475 -+Ref: tlmgr *--dry-run*115802 -+Node: tlmgr candidates _pkg_115932 -+Node: tlmgr check [_option_...] [files|depends|executes|runfiles|all]116278 -+Ref: tlmgr *files*116651 -+Ref: tlmgr *depends*116786 -+Ref: tlmgr *executes*117128 -+Ref: tlmgr *runfiles*117246 -+Ref: tlmgr *--use-svn*117367 -+Node: tlmgr conf117484 -+Ref: tlmgr *conf [texmf|tlmgr|updmap [--conffile _file_] [--delete] [_key_ [_value_]]]*117763 -+Ref: tlmgr *conf auxtrees [--conffile _file_] [show|add|delete] [_value_]*117827 -+Node: tlmgr dump-tlpdb [_option_...] [--json]120172 -+Ref: tlmgr *--local*120605 -+Ref: tlmgr *--remote*120644 -+Ref: tlmgr *--json*120682 -+Node: tlmgr generate121253 -+Ref: tlmgr *generate [_option_...] language*121449 -+Ref: tlmgr *generate [_option_...] language.dat*121488 -+Ref: tlmgr *generate [_option_...] language.def*121527 -+Ref: tlmgr *generate [_option_...] language.dat.lua*121570 -+Ref: tlmgr *--dest* _output_file_123896 -+Ref: tlmgr *--localcfg* _local_conf_file_124472 -+Ref: tlmgr *--rebuild-sys*124595 -+Node: tlmgr gui125410 -+Node: tlmgr info125588 -+Ref: tlmgr *info [_option_...] _pkg_...*125750 -+Ref: tlmgr *info [_option_...] collections*125784 -+Ref: tlmgr *info [_option_...] schemes*125814 -+Ref: tlmgr *--list*127344 -+Ref: tlmgr *--only-installed*127658 -+Ref: tlmgr *--data item1,item2,...*127857 -+Ref: tlmgr *--json* 1128438 -+Node: tlmgr init-usertree128821 -+Node: tlmgr install [_option_...] _pkg_...129202 -+Ref: tlmgr *--dry-run* 1129712 -+Ref: tlmgr *--file*129829 -+Ref: tlmgr *--force*130051 -+Ref: tlmgr *--no-depends*130271 -+Ref: tlmgr *--no-depends-at-all*130430 -+Ref: tlmgr *--reinstall*130830 -+Ref: tlmgr *--with-doc*131208 -+Ref: tlmgr *--with-src*131221 -+Node: tlmgr key131743 -+Ref: tlmgr *key list*131901 -+Ref: tlmgr *key add _file_*131919 -+Ref: tlmgr *key remove _keyid_*131941 -+Node: tlmgr list132536 -+Node: tlmgr option132698 -+Ref: tlmgr *option [--json] [show]*132853 -+Ref: tlmgr *option [--json] showall*132879 -+Ref: tlmgr *option _key_ [_value_]*132905 -+Node: tlmgr paper137302 -+Ref: tlmgr *paper [a4|letter]*137451 -+Ref: tlmgr *[xdvi|pdftex|dvips|dvipdfmx|context|psutils] paper [_papersize_|--list]*137525 -+Ref: tlmgr *paper --json*137540 -+Node: tlmgr path138755 -+Ref: tlmgr *path [--w32mode=user|admin] add*138916 -+Ref: tlmgr *path [--w32mode=user|admin] remove*138953 -+Node: tlmgr pinning140293 -+Ref: tlmgr pinning show140534 -+Ref: tlmgr pinning add _repo_ _pkgglob_...140607 -+Ref: tlmgr pinning remove _repo_ _pkgglob_...140726 -+Ref: tlmgr pinning remove _repo_ --all140879 -+Node: tlmgr platform140933 -+Ref: tlmgr *platform list|add|remove _platform_...*141119 -+Ref: tlmgr *platform set _platform_*141146 -+Ref: tlmgr *platform set auto*141167 -+Ref: tlmgr *--dry-run* 2142053 -+Node: tlmgr postaction142172 -+Ref: tlmgr *postaction [_option_...] install [shortcut|fileassoc|script] [_pkg_...]*142402 -+Ref: tlmgr *postaction [_option_...] remove [shortcut|fileassoc|script] [_pkg_...]*142476 -+Ref: tlmgr *--w32mode=[user|admin]*142791 -+Ref: tlmgr *--fileassocmode=[1|2]*143207 -+Ref: tlmgr *--all* 1143492 -+Node: tlmgr print-platform143547 -+Node: tlmgr print-platform-info143878 -+Node: tlmgr remove [_option_...] _pkg_...144178 -+Ref: tlmgr *--all* 2144662 -+Ref: tlmgr *--backup*144772 -+Ref: tlmgr *--backupdir* _directory_ 1144798 -+Ref: tlmgr *--no-depends* 1145203 -+Ref: tlmgr *--no-depends-at-all* 1145265 -+Ref: tlmgr *--force* 1145368 -+Ref: tlmgr *--dry-run* 3145841 -+Node: tlmgr repository145948 -+Ref: tlmgr *repository list*146136 -+Ref: tlmgr *repository list _path|tag_*146166 -+Ref: tlmgr *repository add _path_ [_tag_]*146199 -+Ref: tlmgr *repository remove _path|tag_*146231 -+Ref: tlmgr *repository set _path_[#_tag_] [_path_[#_tag_] ...]*146285 -+Node: tlmgr restore147338 -+Ref: tlmgr *restore [_option_...] _pkg_ [_rev_]*147517 -+Ref: tlmgr *restore [_option_...] --all*147547 -+Ref: tlmgr *--all* 3148247 -+Ref: tlmgr *--backupdir* _directory_ 2148461 -+Ref: tlmgr *--dry-run* 4148642 -+Ref: tlmgr *--force* 2148774 -+Ref: tlmgr *--json* 2148820 -+Node: tlmgr search149147 -+Ref: tlmgr *search [_option_...] _what_*149311 -+Ref: tlmgr *search [_option_...] --file _what_*149348 -+Ref: tlmgr *search [_option_...] --all _what_*149384 -+Ref: tlmgr *--file* 1149604 -+Ref: tlmgr *--all* 4149666 -+Ref: tlmgr *--global*149755 -+Ref: tlmgr *--word*149882 -+Node: tlmgr shell150197 -+Ref: tlmgr protocol150932 -+Ref: tlmgr help 1150996 -+Ref: tlmgr version 1151049 -+Ref: tlmgr quit, end, bye, byebye, EOF151117 -+Ref: tlmgr restart151138 -+Ref: tlmgr load [local|remote]151261 -+Ref: tlmgr save151331 -+Ref: tlmgr get [_var_] =item set [_var_ [_val_]]151454 -+Node: tlmgr show152055 -+Node: tlmgr uninstall152222 -+Node: tlmgr update [_option_...] [_pkg_...]152452 -+Ref: tlmgr *--all* 5152823 -+Ref: tlmgr *--self*154564 -+Ref: tlmgr *--dry-run* 5155328 -+Ref: tlmgr *--list* [_pkg_]155505 -+Ref: tlmgr *--exclude* _pkg_156194 -+Ref: tlmgr *--no-auto-remove* [_pkg_...]156994 -+Ref: tlmgr *--no-auto-install* [_pkg_...]157445 -+Ref: tlmgr *--reinstall-forcibly-removed*158101 -+Ref: tlmgr *--backup* 1158636 -+Ref: tlmgr *--backupdir* _directory_ 3158662 -+Ref: tlmgr *--no-depends* 2159828 -+Ref: tlmgr *--no-depends-at-all* 2160031 -+Ref: tlmgr *--force* 3160134 -+Node: tlmgr CONFIGURATION FILE FOR TLMGR160949 -+Ref: tlmgr auto-remove, value 0 or 1 (default 1), same as command-line option.161962 -+Ref: tlmgr gui-expertmode, value 0 or 1 (default 1). This switches between the full GUI and a simplified GUI with only the most common settings.162099 -+Ref: tlmgr gui-lang _llcode_, with a language code value as with the command-line option.162181 -+Ref: tlmgr no-checksums, value 0 or 1 (default 0, see below).162235 -+Ref: tlmgr persistent-downloads, value 0 or 1 (default 1), same as command-line option.162315 -+Ref: tlmgr require-verification, value 0 or 1 (default 0), same as command-line option.162395 -+Ref: tlmgr update-exclude, value: comma-separated list of packages (no space allowed). Same as the command line option --exclude for the action update.162543 -+Ref: tlmgr verify-downloads, value 0 or 1 (default 1), same as command-line option.162619 -+Ref: tlmgr allowed-actions _action1_ [,_action_,...] The value is a comma-separated list of tlmgr actions which are allowed to be executed when tlmgr is invoked in system mode (that is, without --usermode).162888 -+Node: tlmgr CRYPTOGRAPHIC VERIFICATION163974 -+Node: tlmgr Configuration of GnuPG invocation166123 -+Node: tlmgr USER MODE166761 -+Node: tlmgr User mode install169607 -+Node: tlmgr User mode backup, restore, remove, update170751 -+Node: tlmgr User mode generate, option, paper171193 -+Node: tlmgr MULTIPLE REPOSITORIES171569 -+Node: tlmgr Pinning173298 -+Node: tlmgr GUI FOR TLMGR175273 -+Node: tlmgr Main display176613 -+Node: tlmgr Display configuration area176865 -+Ref: tlmgr Status177226 -+Ref: tlmgr Category177390 -+Ref: tlmgr Match177576 -+Ref: tlmgr Selection177757 -+Ref: tlmgr Display configuration buttons177961 -+Node: tlmgr Package list area178144 -+Ref: tlmgr a checkbox178728 -+Ref: tlmgr package name178864 -+Ref: tlmgr local revision (and version)178963 -+Ref: tlmgr remote revision (and version)179338 -+Ref: tlmgr short description179635 -+Node: tlmgr Main display action buttons179680 -+Ref: tlmgr Update all installed179946 -+Ref: tlmgr Update180318 -+Ref: tlmgr Install180368 -+Ref: tlmgr Remove180554 -+Ref: tlmgr Backup180732 -+Node: tlmgr Menu bar180889 -+Ref: tlmgr tlmgr menu181112 -+Ref: tlmgr Options menu181420 -+Ref: tlmgr Actions menu182503 -+Ref: tlmgr Help menu182931 -+Node: tlmgr GUI options183064 -+Ref: tlmgr -background _color_183310 -+Ref: tlmgr -font " _fontname_ _fontsize_ "183375 -+Ref: tlmgr -foreground _color_183533 -+Ref: tlmgr -geometry _geomspec_183585 -+Ref: tlmgr -xrm _xresource_183777 -+Node: tlmgr MACHINE-READABLE OUTPUT184045 -+Node: tlmgr Machine-readable update and install output184855 -+Ref: tlmgr location-url _location_186131 -+Ref: tlmgr total-bytes _count_186347 -+Ref: tlmgr _pkgname_186757 -+Ref: tlmgr _status_186967 -+Ref: tlmgr d187045 -+Ref: tlmgr f187105 -+Ref: tlmgr u187284 -+Ref: tlmgr r187330 -+Ref: tlmgr a187453 -+Ref: tlmgr i187631 -+Ref: tlmgr I187750 -+Ref: tlmgr _localrev_187852 -+Ref: tlmgr _serverrev_187959 -+Ref: tlmgr _size_188071 -+Ref: tlmgr _runtime_188240 -+Ref: tlmgr _esttot_188310 -+Node: tlmgr Machine-readable option output188343 -+Node: tlmgr AUTHORS AND COPYRIGHT188855 -+Node: Index189254 -  - End Tag Table -diff --git a/texk/texlive/linked_scripts/texlive/tlmgr.pl b/texk/texlive/linked_scripts/texlive/tlmgr.pl -index f0c125b5a..d2cfaaebb 100755 ---- a/texk/texlive/linked_scripts/texlive/tlmgr.pl -+++ b/texk/texlive/linked_scripts/texlive/tlmgr.pl -@@ -8178,7 +8178,7 @@ With the C argument, C lists all keys. - - The C argument requires another argument, either a filename or - C<-> for stdin, from which the key is added. The key is added to the --local keyring C, which is normally) -+local keyring C, which is normally - C. - - The C argument requires a key id and removes the requested id -diff --git a/texk/web2c/configure b/texk/web2c/configure -index 65955e941..681a176fc 100755 ---- a/texk/web2c/configure -+++ b/texk/web2c/configure -@@ -18592,6 +18592,7 @@ fi - - - -+# Include additional code for web2c. - - ## texk/web2c/ac/web2c.ac: configure.ac fragment for the TeX Live subdirectory texk/web2c/ - ## configure options for TeX and MF -@@ -19003,12 +19004,14 @@ fi - - - -+# LuaTeX and XeTeX now require C++11 because poppler does :(. -+# XeTeX also requires C+11 because of ICU. - if test "x$enable_xetex" = xyes \ - || test "x$enable_luatex" = xyes \ - || test "x$enable_luajittex" = xyes \ - || test "x$enable_luatex53" = xyes; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: LuaTeX enabled, requiring C++11 support" >&5 --$as_echo "$as_me: LuaTeX enabled, requiring C++11 support" >&6;} -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++11, since LuaTeX and/or XeTeX enabled" >&5 -+$as_echo "$as_me: checking for C++11, since LuaTeX and/or XeTeX enabled" >&6;} - ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=true - ac_ext=cpp - ac_cpp='$CXXCPP $CPPFLAGS' -diff --git a/texk/web2c/configure.ac b/texk/web2c/configure.ac -index 902902ca5..6c0839297 100644 ---- a/texk/web2c/configure.ac -+++ b/texk/web2c/configure.ac -@@ -42,16 +42,17 @@ AC_PROG_OBJCXX - KPSE_CXX_HACK - KPSE_LT_HACK - --dnl Include additional code for web2c. -+# Include additional code for web2c. - KPSE_WEB2C_PREPARE - m4_include([ac/web2c.ac]) - --dnl LuaTeX requires C++11 because poppler does :(. -+# LuaTeX and XeTeX now require C++11 because poppler does :(. -+# XeTeX also requires C+11 because of ICU. - if test "x$enable_xetex" = xyes \ - || test "x$enable_luatex" = xyes \ - || test "x$enable_luajittex" = xyes \ - || test "x$enable_luatex53" = xyes; then -- AC_MSG_NOTICE([LuaTeX enabled, requiring C++11 support]) -+ AC_MSG_NOTICE([checking for C++11, since LuaTeX and/or XeTeX enabled]) - AX_CXX_COMPILE_STDCXX([11]) - fi - -commit aa5363bd0dc180752c7d8eb9d847c2581e453b1a -Author: Luigi Scarso -Date: Wed Sep 5 21:30:41 2018 +0000 - - sync with luatex revision 6924. - - git-svn-id: svn://tug.org/texlive/trunk/Build/source@48591 c570f23f-e606-0410-a88d-b1316a301751 - -diff --git a/libs/lua53/ChangeLog b/libs/lua53/ChangeLog -index 8ef10ff28..d5c4b88bc 100644 ---- a/libs/lua53/ChangeLog -+++ b/libs/lua53/ChangeLog -@@ -1,3 +1,14 @@ -+2018-07-21 Luigi Scarso -+ -+ * Adapted for Lua 5.3.5 -+ -+ -+2018-06-18 Luigi Scarso -+ -+ * dropped poppler, new pplib from -+ http://eurydyka.kaliope.org.pl/~pawel/libpp/html/ppapi.html -+ -+ - 2017-10-24 Luigi Scarso - - * Adapted for Lua 5.3.4 -diff --git a/libs/lua53/Makefile.am b/libs/lua53/Makefile.am -index a7994ea5a..f736ce9a3 100644 ---- a/libs/lua53/Makefile.am -+++ b/libs/lua53/Makefile.am -@@ -65,6 +65,7 @@ nodist_libtexlua53_la_SOURCES = \ - @LUA53_TREE@/src/lvm.c \ - @LUA53_TREE@/src/lzio.c - -+ - lua53includedir = ${includedir}/texlua53 - - lua53include_HEADERS = \ -diff --git a/libs/lua53/TLpatches/ChangeLog b/libs/lua53/TLpatches/ChangeLog -index 882ddcdde..dd2bcb2f0 100644 ---- a/libs/lua53/TLpatches/ChangeLog -+++ b/libs/lua53/TLpatches/ChangeLog -@@ -1,3 +1,7 @@ -+2018-07-21 Luigi Scarso -+ Adapted for lua 5.3.5 -+ -+ - 2017-10-24 Luigi Scarso - Adapted for lua 5.3.4 - -diff --git a/libs/lua53/TLpatches/patch-01-utf-8 b/libs/lua53/TLpatches/patch-01-utf-8 -index f2ac40134..0f7cb8981 100644 ---- a/libs/lua53/TLpatches/patch-01-utf-8 -+++ b/libs/lua53/TLpatches/patch-01-utf-8 -@@ -1,7 +1,16 @@ --diff -ur lua-5.3.4.orig/src/lctype.h lua-5.3.4/src/lctype.h ----- lctype.h.orig 2017-10-24 15:14:50.724139638 +0200 --+++ lctype.h 2017-10-24 15:15:51.704137138 +0200 --@@ -53,9 +53,11 @@ -+diff -u lctype.h.orig lctype.h -+--- lctype.h.orig 2018-07-21 09:57:36.061692228 +0200 -++++ lctype.h 2018-07-21 10:03:29.625677730 +0200 -+@@ -7,6 +7,8 @@ -+ #ifndef lctype_h -+ #define lctype_h -+ -++#include -++ -+ #include "lua.h" -+ -+ -+@@ -53,9 +55,11 @@ - - /* - ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' -diff --git a/libs/lua53/TLpatches/patch-02-FreeBSD b/libs/lua53/TLpatches/patch-02-FreeBSD -index fc59f4842..ad85a5988 100644 ---- a/libs/lua53/TLpatches/patch-02-FreeBSD -+++ b/libs/lua53/TLpatches/patch-02-FreeBSD -@@ -1,6 +1,6 @@ --diff -ur liolib.c.orig liolib.c ----- liolib.c.orig 2017-10-24 15:16:06.036136550 +0200 --+++ liolib.c 2017-10-24 15:16:49.968134748 +0200 -+diff -u liolib.c.orig liolib.c -+--- liolib.c.orig 2017-04-19 19:29:57.000000000 +0200 -++++ liolib.c 2018-07-21 10:04:50.965674394 +0200 - @@ -16,6 +16,9 @@ - #include - #include -diff --git a/libs/lua53/TLpatches/patch-03-export b/libs/lua53/TLpatches/patch-03-export -index dda2b87b2..9bc2a4627 100644 ---- a/libs/lua53/TLpatches/patch-03-export -+++ b/libs/lua53/TLpatches/patch-03-export -@@ -1,6 +1,6 @@ --diff -ur lopcodes.h.orig lopcodes.h ----- lopcodes.h.orig 2017-10-24 15:22:51.012119943 +0200 --+++ lopcodes.h 2017-10-24 15:18:37.924130321 +0200 -+diff -u lopcodes.h.orig lopcodes.h -+--- lopcodes.h.orig 2018-07-21 09:59:37.349687255 +0200 -++++ lopcodes.h 2018-07-21 10:07:04.413668921 +0200 - @@ -278,7 +278,7 @@ - OpArgK /* argument is a constant or register/constant */ - }; -@@ -20,9 +20,10 @@ diff -ur lopcodes.h.orig lopcodes.h - - /* number of list items to accumulate before a SETLIST instruction */ - --diff -ur lundump.h.orig lundump.h ----- lundump.h.orig 2017-10-24 15:19:03.860129258 +0200 --+++ lundump.h 2017-10-24 15:19:47.088127485 +0200 -+ -+diff -u lundump.h.orig lundump.h -+--- lundump.h.orig 2018-07-21 10:00:01.545686262 +0200 -++++ lundump.h 2018-07-21 10:08:12.341666136 +0200 - @@ -26,7 +26,7 @@ - LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); - -@@ -32,4 +33,3 @@ diff -ur lundump.h.orig lundump.h - void* data, int strip); - - #endif -- -diff --git a/libs/lua53/lua53-src/README b/libs/lua53/lua53-src/README -index 0b31908a0..ed424defe 100644 ---- a/libs/lua53/lua53-src/README -+++ b/libs/lua53/lua53-src/README -@@ -1,5 +1,5 @@ - --This is Lua 5.3.4, released on 12 Jan 2017. -+This is Lua 5.3.5, released on 26 Jun 2018. - - For installation instructions, license details, and - further information about Lua, see doc/readme.html. -diff --git a/libs/lua53/lua53-src/doc/contents.html b/libs/lua53/lua53-src/doc/contents.html -index 445556f96..c4eb26779 100644 ---- a/libs/lua53/lua53-src/doc/contents.html -+++ b/libs/lua53/lua53-src/doc/contents.html -@@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book - -

- --Copyright © 2015–2017 Lua.org, PUC-Rio. -+Copyright © 2015–2018 Lua.org, PUC-Rio. - Freely available under the terms of the - Lua license. - -@@ -609,10 +609,10 @@ Freely available under the terms of the - -

- - - -diff --git a/libs/lua53/lua53-src/doc/lua.css b/libs/lua53/lua53-src/doc/lua.css -index 5bedf7eb8..cbd0799d1 100644 ---- a/libs/lua53/lua53-src/doc/lua.css -+++ b/libs/lua53/lua53-src/doc/lua.css -@@ -10,7 +10,7 @@ body { - line-height: 1.25 ; - margin: 16px auto ; - padding: 32px ; -- border: solid #a0a0a0 1px ; -+ border: solid #ccc 1px ; - border-radius: 20px ; - max-width: 70em ; - width: 90% ; -@@ -111,36 +111,29 @@ pre.session { - border-radius: 8px ; - } - --td.gutter { -- width: 4% ; --} -- --table.columns { -+table { - border: none ; - border-spacing: 0 ; - border-collapse: collapse ; - } - --table.columns td { -- vertical-align: top ; -+td { - padding: 0 ; -- padding-bottom: 1em ; -- text-align: justify ; -- line-height: 1.25 ; -+ margin: 0 ; - } - --p.logos a:link:hover, p.logos a:visited:hover { -- background-color: inherit ; -+td.gutter { -+ width: 4% ; - } - --table.book { -- border: none ; -- border-spacing: 0 ; -- border-collapse: collapse ; -+table.columns td { -+ vertical-align: top ; -+ padding-bottom: 1em ; -+ text-align: justify ; -+ line-height: 1.25 ; - } - - table.book td { -- padding: 0 ; - vertical-align: top ; - } - -@@ -159,6 +152,10 @@ table.book span { - margin-top: 0.25em ; - } - -+p.logos a:link:hover, p.logos a:visited:hover { -+ background-color: inherit ; -+} -+ - img { - background-color: white ; - } -diff --git a/libs/lua53/lua53-src/doc/manual.html b/libs/lua53/lua53-src/doc/manual.html -index 3126b5d6a..89a642a45 100644 ---- a/libs/lua53/lua53-src/doc/manual.html -+++ b/libs/lua53/lua53-src/doc/manual.html -@@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes - -

- --Copyright © 2015–2017 Lua.org, PUC-Rio. -+Copyright © 2015–2018 Lua.org, PUC-Rio. - Freely available under the terms of the - Lua license. - -@@ -35,7 +35,7 @@ Freely available under the terms of the - -

- -- -+ - - - -@@ -203,8 +203,8 @@ even those that do not support threads natively. - -

- The type table implements associative arrays, --that is, arrays that can be indexed not only with numbers, --but with any Lua value except nil and NaN. -+that is, arrays that can have as indices not only numbers, -+but any Lua value except nil and NaN. - (Not a Number is a special value used to represent - undefined or unrepresentable numerical results, such as 0/0.) - Tables can be heterogeneous; -@@ -400,6 +400,8 @@ with the event name prefixed by two underscores; - the corresponding values are called metamethods. - In the previous example, the key is "__add" - and the metamethod is the function that performs the addition. -+Unless stated otherwise, -+metamethods should be function values. - - -

-@@ -597,7 +599,7 @@ it is also slower than a real __le metamethod.) - - -

  • __index: --The indexing access table[key]. -+The indexing access operation table[key]. - This event happens when table is not a table or - when key is not present in table. - The metamethod is looked up in table. -@@ -1276,13 +1278,8 @@ Square brackets are used to index a table: -
    - 	var ::= prefixexp ‘[’ exp ‘]’
    - 

    --The meaning of accesses to table fields can be changed via metatables. --An access to an indexed variable t[i] is equivalent to --a call gettable_event(t,i). --(See §2.4 for a complete description of the --gettable_event function. --This function is not defined or callable in Lua. --We use it here only for explanatory purposes.) -+The meaning of accesses to table fields can be changed via metatables -+(see §2.4). - - -

    -@@ -1476,23 +1473,18 @@ and - cyclically permutes the values of x, y, and z. - - --

    --The meaning of assignments to global variables --and table fields can be changed via metatables. --An assignment to an indexed variable t[i] = val is equivalent to --settable_event(t,i,val). --(See §2.4 for a complete description of the --settable_event function. --This function is not defined or callable in Lua. --We use it here only for explanatory purposes.) -- -- -

    - An assignment to a global name x = val - is equivalent to the assignment - _ENV.x = val (see §2.2). - - -+

    -+The meaning of assignments to table fields and -+global variables (which are actually table fields, too) -+can be changed via metatables (see §2.4). -+ -+ - - - -@@ -1831,17 +1823,17 @@ Here are some examples: - g(f(), x) -- f() is adjusted to 1 result - g(x, f()) -- g gets x plus all results from f() - a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil) -- a,b = ... -- a gets the first vararg parameter, b gets -+ a,b = ... -- a gets the first vararg argument, b gets - -- the second (both a and b can get nil if there -- -- is no corresponding vararg parameter) -+ -- is no corresponding vararg argument) - - a,b,c = x, f() -- f() is adjusted to 2 results - a,b,c = f() -- f() is adjusted to 3 results - return f() -- returns all results from f() -- return ... -- returns all received vararg parameters -+ return ... -- returns all received vararg arguments - return x,y,f() -- returns x, y, and all results from f() - {f()} -- creates a list with all results from f() -- {...} -- creates a list with all vararg parameters -+ {...} -- creates a list with all vararg arguments - {f(), nil} -- f() is adjusted to 1 result - - -@@ -2039,9 +2031,12 @@ two objects are considered equal only if they are the same object. - Every time you create a new object - (a table, userdata, or thread), - this new object is different from any previously existing object. --Closures with the same reference are always equal. -+A closure is always equal to itself. - Closures with any detectable difference - (different behavior, different definition) are always different. -+Closures created at different times but with no detectable differences -+may be classified as equal or not -+(depending on internal caching details). - - -

    -@@ -2303,7 +2298,7 @@ If the value of prefixexp has type function, - then this function is called - with the given arguments. - Otherwise, the prefixexp "call" metamethod is called, --having as first parameter the value of prefixexp, -+having as first argument the value of prefixexp, - followed by the original call arguments - (see §2.4). - -@@ -2881,7 +2876,7 @@ it can do whatever it wants on that Lua state, - as it should be already protected. - However, - when C code operates on other Lua states --(e.g., a Lua parameter to the function, -+(e.g., a Lua argument to the function, - a Lua state stored in the registry, or - the result of lua_newthread), - it should use them only in API calls that cannot raise errors. -@@ -3370,7 +3365,7 @@ it is left unchanged. - Destroys all objects in the given Lua state - (calling the corresponding garbage-collection metamethods, if any) - and frees all dynamic memory used by this state. --On several platforms, you may not need to call this function, -+In several platforms, you may not need to call this function, - because all resources are naturally released when the host program ends. - On the other hand, long-running programs that create multiple states, - such as daemons or web servers, -@@ -5584,7 +5579,7 @@ given as argument to a hook (see lua_Hook). - - -

    --To get information about a function you push it onto the stack -+To get information about a function, you push it onto the stack - and start the what string with the character '>'. - (In that case, - lua_getinfo pops the function from the top of the stack.) -@@ -6462,7 +6457,7 @@ file-related functions in the standard library - -

    - Pushes onto the stack the field e from the metatable --of the object at index obj and returns the type of pushed value. -+of the object at index obj and returns the type of the pushed value. - If the object does not have a metatable, - or if the metatable does not have this field, - pushes nothing and returns LUA_TNIL. -@@ -6749,7 +6744,7 @@ In words, if the argument arg is nil or absent, - the macro results in the default dflt. - Otherwise, it results in the result of calling func - with the state L and the argument index arg as --parameters. -+arguments. - Note that it evaluates the expression dflt only if needed. - - -@@ -8680,7 +8675,7 @@ the lowercase letters plus the '-' character. -

    - You can put a closing square bracket in a set - by positioning it as the first character in the set. --You can put an hyphen in a set -+You can put a hyphen in a set - by positioning it as the first or the last character in the set. - (You can also use an escape for both cases.) - -@@ -9082,8 +9077,8 @@ Returns the destination table a2. - - -

    --Returns a new table with all parameters stored into keys 1, 2, etc. --and with a field "n" with the total number of parameters. -+Returns a new table with all arguments stored into keys 1, 2, etc. -+and with a field "n" with the total number of arguments. - Note that the resulting table may not be a sequence. - - -@@ -9215,7 +9210,7 @@ Returns the arc sine of x (in radians). -

    - - Returns the arc tangent of y/x (in radians), --but uses the signs of both parameters to find the -+but uses the signs of both arguments to find the - quadrant of the result. - (It also handles correctly the case of x being zero.) - -@@ -9516,7 +9511,7 @@ all I/O functions return nil on failure - (plus an error message as a second result and - a system-dependent error code as a third result) - and some value different from nil on success. --On non-POSIX systems, -+In non-POSIX systems, - the computation of the error message and error code - in case of errors - may be not thread safe, -@@ -9553,7 +9548,7 @@ When called with a file name, it opens the named file (in text mode), - and sets its handle as the default input file. - When called with a file handle, - it simply sets this file handle as the default input file. --When called without parameters, -+When called without arguments, - it returns the current default input file. - - -@@ -9580,7 +9575,7 @@ it returns no values (to finish the loop) and automatically closes the file. - The call io.lines() (with no file name) is equivalent - to io.input():lines("*l"); - that is, it iterates over the lines of the default input file. --In this case it does not close the file when the loop ends. -+In this case, the iterator does not close the file when the loop ends. - - -

    -@@ -9963,7 +9958,7 @@ the host system and on the current locale. - - -

    --On non-POSIX systems, -+In non-POSIX systems, - this function may be not thread safe - because of its reliance on C function gmtime and C function localtime. - -@@ -10163,7 +10158,7 @@ and explicitly removed when no longer needed. - - -

    --On POSIX systems, -+In POSIX systems, - this function also creates a file with that name, - to avoid security risks. - (Someone else might create the file with wrong permissions -@@ -10301,8 +10296,8 @@ The first parameter or local variable has index 1, and so on, - following the order that they are declared in the code, - counting only the variables that are active - in the current scope of the function. --Negative indices refer to vararg parameters; ---1 is the first vararg parameter. -+Negative indices refer to vararg arguments; -+-1 is the first vararg argument. - The function returns nil if there is no variable with the given index, - and raises an error when called with a level out of range. - (You can call debug.getinfo to check whether the level is valid.) -@@ -10400,7 +10395,7 @@ When called without arguments, - - -

    --When the hook is called, its first parameter is a string -+When the hook is called, its first argument is a string - describing the event that has triggered its call: - "call" (or "tail call"), - "return", -@@ -10551,7 +10546,8 @@ The options are: - -

      -
    • -e stat: executes string stat;
    • --
    • -l mod: "requires" mod;
    • -+
    • -l mod: "requires" mod and assigns the -+ result to global @mod;
    • -
    • -i: enters interactive mode after running script;
    • -
    • -v: prints version information;
    • -
    • -E: ignores environment variables;
    • -@@ -10629,7 +10625,7 @@ For instance, the call -

      - will print "-e". - If there is a script, --the script is called with parameters -+the script is called with arguments - arg[1], ···, arg[#arg]. - (Like all chunks in Lua, - the script is compiled as a vararg function.) -@@ -10815,7 +10811,7 @@ The following functions were deprecated in the mathematical library: - frexp, and ldexp. - You can replace math.pow(x,y) with x^y; - you can replace math.atan2 with math.atan, --which now accepts one or two parameters; -+which now accepts one or two arguments; - you can replace math.ldexp(x,exp) with x * 2.0^exp. - For the other operations, - you can either use an external library or -@@ -10850,7 +10846,7 @@ of the first result.) -

        - -
      • --Continuation functions now receive as parameters what they needed -+Continuation functions now receive as arguments what they needed - to get through lua_getctx, - so lua_getctx has been removed. - Adapt your code accordingly. -@@ -10973,12 +10969,13 @@ and LiteralString, see §3.1.) - - - -+ - - - - -diff --git a/libs/lua53/lua53-src/doc/readme.html b/libs/lua53/lua53-src/doc/readme.html -index 96a9386e2..b118f7b02 100644 ---- a/libs/lua53/lua53-src/doc/readme.html -+++ b/libs/lua53/lua53-src/doc/readme.html -@@ -107,7 +107,7 @@ Here are the details. -
          -
        1. - Open a terminal window and move to --the top-level directory, which is named lua-5.3.x. -+the top-level directory, which is named lua-5.3.5. - The Makefile there controls both the build process and the installation process. -

          -

        2. -@@ -355,10 +355,10 @@ THE SOFTWARE. - - - - - -diff --git a/libs/lua53/lua53-src/src/Makefile b/libs/lua53/lua53-src/src/Makefile -index d71c75c87..64c78f775 100644 ---- a/libs/lua53/lua53-src/src/Makefile -+++ b/libs/lua53/lua53-src/src/Makefile -@@ -102,7 +102,7 @@ c89: - - - freebsd: -- $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -lreadline" -+ $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX -DLUA_USE_READLINE -I/usr/include/edit" SYSLIBS="-Wl,-E -ledit" CC="cc" - - generic: $(ALL) - -@@ -110,7 +110,7 @@ linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" - - macosx: -- $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" CC=cc -+ $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" - - mingw: - $(MAKE) "LUA_A=lua53.dll" "LUA_T=lua.exe" \ -diff --git a/libs/lua53/lua53-src/src/lapi.c b/libs/lua53/lua53-src/src/lapi.c -index c9455a5d8..02b7fab7e 100644 ---- a/libs/lua53/lua53-src/src/lapi.c -+++ b/libs/lua53/lua53-src/src/lapi.c -@@ -1,5 +1,5 @@ - /* --** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $ -+** $Id: lapi.c,v 2.259.1.2 2017/12/06 18:35:12 roberto Exp $ - ** Lua API - ** See Copyright Notice in lua.h - */ -@@ -533,6 +533,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - lua_lock(L); - if (n == 0) { - setfvalue(L->top, fn); -+ api_incr_top(L); - } - else { - CClosure *cl; -@@ -546,9 +547,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { - /* does not need barrier because closure is white */ - } - setclCvalue(L, L->top, cl); -+ api_incr_top(L); -+ luaC_checkGC(L); - } -- api_incr_top(L); -- luaC_checkGC(L); - lua_unlock(L); - } - -diff --git a/libs/lua53/lua53-src/src/lapi.h b/libs/lua53/lua53-src/src/lapi.h -index 6d36dee3f..8e16ad53d 100644 ---- a/libs/lua53/lua53-src/src/lapi.h -+++ b/libs/lua53/lua53-src/src/lapi.h -@@ -1,5 +1,5 @@ - /* --** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ -+** $Id: lapi.h,v 2.9.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Auxiliary functions from Lua API - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lauxlib.c b/libs/lua53/lua53-src/src/lauxlib.c -index f7a383663..8bdada50a 100644 ---- a/libs/lua53/lua53-src/src/lauxlib.c -+++ b/libs/lua53/lua53-src/src/lauxlib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $ -+** $Id: lauxlib.c,v 1.289.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Auxiliary functions for building Lua libraries - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lauxlib.h b/libs/lua53/lua53-src/src/lauxlib.h -index 9a2e66aa0..9857d3a83 100644 ---- a/libs/lua53/lua53-src/src/lauxlib.h -+++ b/libs/lua53/lua53-src/src/lauxlib.h -@@ -1,5 +1,5 @@ - /* --** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $ -+** $Id: lauxlib.h,v 1.131.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Auxiliary functions for building Lua libraries - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lbaselib.c b/libs/lua53/lua53-src/src/lbaselib.c -index 08523e6e7..6460e4f8d 100644 ---- a/libs/lua53/lua53-src/src/lbaselib.c -+++ b/libs/lua53/lua53-src/src/lbaselib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $ -+** $Id: lbaselib.c,v 1.314.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Basic library - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lbitlib.c b/libs/lua53/lua53-src/src/lbitlib.c -index 1cb1d5b93..4786c0d48 100644 ---- a/libs/lua53/lua53-src/src/lbitlib.c -+++ b/libs/lua53/lua53-src/src/lbitlib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ -+** $Id: lbitlib.c,v 1.30.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Standard library for bitwise operations - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lcode.c b/libs/lua53/lua53-src/src/lcode.c -index 0bb414262..12619f54a 100644 ---- a/libs/lua53/lua53-src/src/lcode.c -+++ b/libs/lua53/lua53-src/src/lcode.c -@@ -1,5 +1,5 @@ - /* --** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Code generator for Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lcode.h b/libs/lua53/lua53-src/src/lcode.h -index cd306d573..882dc9c15 100644 ---- a/libs/lua53/lua53-src/src/lcode.h -+++ b/libs/lua53/lua53-src/src/lcode.h -@@ -1,5 +1,5 @@ - /* --** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $ -+** $Id: lcode.h,v 1.64.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Code generator for Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lcorolib.c b/libs/lua53/lua53-src/src/lcorolib.c -index 2303429e7..0b17af9e3 100644 ---- a/libs/lua53/lua53-src/src/lcorolib.c -+++ b/libs/lua53/lua53-src/src/lcorolib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $ -+** $Id: lcorolib.c,v 1.10.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Coroutine Library - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lctype.c b/libs/lua53/lua53-src/src/lctype.c -index ae9367e69..f8ad7a2ed 100644 ---- a/libs/lua53/lua53-src/src/lctype.c -+++ b/libs/lua53/lua53-src/src/lctype.c -@@ -1,5 +1,5 @@ - /* --** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ -+** $Id: lctype.c,v 1.12.1.1 2017/04/19 17:20:42 roberto Exp $ - ** 'ctype' functions for Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lctype.h b/libs/lua53/lua53-src/src/lctype.h -index b961175bc..a963eb901 100644 ---- a/libs/lua53/lua53-src/src/lctype.h -+++ b/libs/lua53/lua53-src/src/lctype.h -@@ -1,5 +1,5 @@ - /* --** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ -+** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ - ** 'ctype' functions for Lua - ** See Copyright Notice in lua.h - */ -@@ -76,6 +76,7 @@ LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; - - - #else /* }{ */ -+ - /* - ** use standard C ctypes - */ -diff --git a/libs/lua53/lua53-src/src/lctype.h.orig b/libs/lua53/lua53-src/src/lctype.h.orig -index 99c7d1223..b09b21a33 100644 ---- a/libs/lua53/lua53-src/src/lctype.h.orig -+++ b/libs/lua53/lua53-src/src/lctype.h.orig -@@ -1,5 +1,5 @@ - /* --** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ -+** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $ - ** 'ctype' functions for Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ldblib.c b/libs/lua53/lua53-src/src/ldblib.c -index 786f6cd95..9d29afb0a 100644 ---- a/libs/lua53/lua53-src/src/ldblib.c -+++ b/libs/lua53/lua53-src/src/ldblib.c -@@ -1,5 +1,5 @@ - /* --** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $ -+** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Interface from Lua to its debug API - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ldebug.c b/libs/lua53/lua53-src/src/ldebug.c -index 239affb76..e1389296e 100644 ---- a/libs/lua53/lua53-src/src/ldebug.c -+++ b/libs/lua53/lua53-src/src/ldebug.c -@@ -1,5 +1,5 @@ - /* --** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $ -+** $Id: ldebug.c,v 2.121.1.2 2017/07/10 17:21:50 roberto Exp $ - ** Debug Interface - ** See Copyright Notice in lua.h - */ -@@ -653,6 +653,7 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { - CallInfo *ci = L->ci; - const char *msg; - va_list argp; -+ luaC_checkGC(L); /* error message uses memory */ - va_start(argp, fmt); - msg = luaO_pushvfstring(L, fmt, argp); /* format message */ - va_end(argp); -diff --git a/libs/lua53/lua53-src/src/ldebug.h b/libs/lua53/lua53-src/src/ldebug.h -index 0e31546b1..8cea0ee0a 100644 ---- a/libs/lua53/lua53-src/src/ldebug.h -+++ b/libs/lua53/lua53-src/src/ldebug.h -@@ -1,5 +1,5 @@ - /* --** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $ -+** $Id: ldebug.h,v 2.14.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Auxiliary functions from Debug Interface module - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ldo.c b/libs/lua53/lua53-src/src/ldo.c -index 90b695fb0..316e45c8f 100644 ---- a/libs/lua53/lua53-src/src/ldo.c -+++ b/libs/lua53/lua53-src/src/ldo.c -@@ -1,5 +1,5 @@ - /* --** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $ -+** $Id: ldo.c,v 2.157.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Stack and Call structure of Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ldo.h b/libs/lua53/lua53-src/src/ldo.h -index 4f5d51c3c..3b2983a38 100644 ---- a/libs/lua53/lua53-src/src/ldo.h -+++ b/libs/lua53/lua53-src/src/ldo.h -@@ -1,5 +1,5 @@ - /* --** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $ -+** $Id: ldo.h,v 2.29.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Stack and Call structure of Lua - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ldump.c b/libs/lua53/lua53-src/src/ldump.c -index 016e30082..f025acac3 100644 ---- a/libs/lua53/lua53-src/src/ldump.c -+++ b/libs/lua53/lua53-src/src/ldump.c -@@ -1,5 +1,5 @@ - /* --** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $ -+** $Id: ldump.c,v 2.37.1.1 2017/04/19 17:20:42 roberto Exp $ - ** save precompiled Lua chunks - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lfunc.c b/libs/lua53/lua53-src/src/lfunc.c -index 67967dab3..ccafbb8ab 100644 ---- a/libs/lua53/lua53-src/src/lfunc.c -+++ b/libs/lua53/lua53-src/src/lfunc.c -@@ -1,5 +1,5 @@ - /* --** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ -+** $Id: lfunc.c,v 2.45.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Auxiliary functions to manipulate prototypes and closures - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lfunc.h b/libs/lua53/lua53-src/src/lfunc.h -index 2eeb0d5a4..c916e9878 100644 ---- a/libs/lua53/lua53-src/src/lfunc.h -+++ b/libs/lua53/lua53-src/src/lfunc.h -@@ -1,5 +1,5 @@ - /* --** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $ -+** $Id: lfunc.h,v 2.15.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Auxiliary functions to manipulate prototypes and closures - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lgc.c b/libs/lua53/lua53-src/src/lgc.c -index ba2c19e14..db4df8292 100644 ---- a/libs/lua53/lua53-src/src/lgc.c -+++ b/libs/lua53/lua53-src/src/lgc.c -@@ -1,5 +1,5 @@ - /* --** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lgc.c,v 2.215.1.2 2017/08/31 16:15:27 roberto Exp $ - ** Garbage Collector - ** See Copyright Notice in lua.h - */ -@@ -643,8 +643,9 @@ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { - for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { - setnilvalue(gval(n)); /* remove value ... */ -- removeentry(n); /* and remove entry from table */ - } -+ if (ttisnil(gval(n))) /* is entry empty? */ -+ removeentry(n); /* remove entry from table */ - } - } - } -diff --git a/libs/lua53/lua53-src/src/lgc.h b/libs/lua53/lua53-src/src/lgc.h -index aed3e18a5..425cd7cef 100644 ---- a/libs/lua53/lua53-src/src/lgc.h -+++ b/libs/lua53/lua53-src/src/lgc.h -@@ -1,5 +1,5 @@ - /* --** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $ -+** $Id: lgc.h,v 2.91.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Garbage Collector - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/linit.c b/libs/lua53/lua53-src/src/linit.c -index afcaf98b2..480da52c7 100644 ---- a/libs/lua53/lua53-src/src/linit.c -+++ b/libs/lua53/lua53-src/src/linit.c -@@ -1,5 +1,5 @@ - /* --** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $ -+** $Id: linit.c,v 1.39.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Initialization of libraries for lua.c and other clients - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/liolib.c b/libs/lua53/lua53-src/src/liolib.c -index d47be5a27..76f372acb 100644 ---- a/libs/lua53/lua53-src/src/liolib.c -+++ b/libs/lua53/lua53-src/src/liolib.c -@@ -1,5 +1,5 @@ - /* --** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $ -+** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Standard I/O (and system) library - ** See Copyright Notice in lua.h - */ -@@ -209,11 +209,16 @@ static int aux_close (lua_State *L) { - } - - -+static int f_close (lua_State *L) { -+ tofile(L); /* make sure argument is an open stream */ -+ return aux_close(L); -+} -+ -+ - static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ -- tofile(L); /* make sure argument is an open stream */ -- return aux_close(L); -+ return f_close(L); - } - - -@@ -715,7 +720,7 @@ static const luaL_Reg iolib[] = { - ** methods for file handles - */ - static const luaL_Reg flib[] = { -- {"close", io_close}, -+ {"close", f_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, -diff --git a/libs/lua53/lua53-src/src/liolib.c.orig b/libs/lua53/lua53-src/src/liolib.c.orig -index 156840358..8a9e75cd0 100644 ---- a/libs/lua53/lua53-src/src/liolib.c.orig -+++ b/libs/lua53/lua53-src/src/liolib.c.orig -@@ -1,5 +1,5 @@ - /* --** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $ -+** $Id: liolib.c,v 2.151.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Standard I/O (and system) library - ** See Copyright Notice in lua.h - */ -@@ -206,11 +206,16 @@ static int aux_close (lua_State *L) { - } - - -+static int f_close (lua_State *L) { -+ tofile(L); /* make sure argument is an open stream */ -+ return aux_close(L); -+} -+ -+ - static int io_close (lua_State *L) { - if (lua_isnone(L, 1)) /* no argument? */ - lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ -- tofile(L); /* make sure argument is an open stream */ -- return aux_close(L); -+ return f_close(L); - } - - -@@ -712,7 +717,7 @@ static const luaL_Reg iolib[] = { - ** methods for file handles - */ - static const luaL_Reg flib[] = { -- {"close", io_close}, -+ {"close", f_close}, - {"flush", f_flush}, - {"lines", f_lines}, - {"read", f_read}, -diff --git a/libs/lua53/lua53-src/src/llex.c b/libs/lua53/lua53-src/src/llex.c -index 70328273f..66fd411ba 100644 ---- a/libs/lua53/lua53-src/src/llex.c -+++ b/libs/lua53/lua53-src/src/llex.c -@@ -1,5 +1,5 @@ - /* --** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $ -+** $Id: llex.c,v 2.96.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Lexical Analyzer - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/llex.h b/libs/lua53/lua53-src/src/llex.h -index 2363d87e4..2ed0af66a 100644 ---- a/libs/lua53/lua53-src/src/llex.h -+++ b/libs/lua53/lua53-src/src/llex.h -@@ -1,5 +1,5 @@ - /* --** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $ -+** $Id: llex.h,v 1.79.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Lexical Analyzer - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/llimits.h b/libs/lua53/lua53-src/src/llimits.h -index f21377fef..d1036f6bc 100644 ---- a/libs/lua53/lua53-src/src/llimits.h -+++ b/libs/lua53/lua53-src/src/llimits.h -@@ -1,5 +1,5 @@ - /* --** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $ -+** $Id: llimits.h,v 1.141.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Limits, basic types, and some other 'installation-dependent' definitions - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lmathlib.c b/libs/lua53/lua53-src/src/lmathlib.c -index b7f8baee0..7ef7e593f 100644 ---- a/libs/lua53/lua53-src/src/lmathlib.c -+++ b/libs/lua53/lua53-src/src/lmathlib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lmathlib.c,v 1.119.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Standard mathematical library - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lmem.c b/libs/lua53/lua53-src/src/lmem.c -index 0a0476cc7..0241cc3ba 100644 ---- a/libs/lua53/lua53-src/src/lmem.c -+++ b/libs/lua53/lua53-src/src/lmem.c -@@ -1,5 +1,5 @@ - /* --** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $ -+** $Id: lmem.c,v 1.91.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Interface to Memory Manager - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lmem.h b/libs/lua53/lua53-src/src/lmem.h -index 30f484895..357b1e43e 100644 ---- a/libs/lua53/lua53-src/src/lmem.h -+++ b/libs/lua53/lua53-src/src/lmem.h -@@ -1,5 +1,5 @@ - /* --** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $ -+** $Id: lmem.h,v 1.43.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Interface to Memory Manager - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/loadlib.c b/libs/lua53/lua53-src/src/loadlib.c -index 4791e748b..45f44d322 100644 ---- a/libs/lua53/lua53-src/src/loadlib.c -+++ b/libs/lua53/lua53-src/src/loadlib.c -@@ -1,5 +1,5 @@ - /* --** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $ -+** $Id: loadlib.c,v 1.130.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Dynamic library loader for Lua - ** See Copyright Notice in lua.h - ** -diff --git a/libs/lua53/lua53-src/src/lobject.c b/libs/lua53/lua53-src/src/lobject.c -index 2da76899a..2218c8cdd 100644 ---- a/libs/lua53/lua53-src/src/lobject.c -+++ b/libs/lua53/lua53-src/src/lobject.c -@@ -1,5 +1,5 @@ - /* --** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lobject.c,v 2.113.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Some generic functions over Lua objects - ** See Copyright Notice in lua.h - */ -@@ -435,7 +435,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { - } - case 'p': { /* a pointer */ - char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ -- int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); -+ void *p = va_arg(argp, void *); -+ int l = lua_pointer2str(buff, sizeof(buff), p); - pushstr(L, buff, l); - break; - } -diff --git a/libs/lua53/lua53-src/src/lobject.h b/libs/lua53/lua53-src/src/lobject.h -index 3c0422894..240886140 100644 ---- a/libs/lua53/lua53-src/src/lobject.h -+++ b/libs/lua53/lua53-src/src/lobject.h -@@ -1,5 +1,5 @@ - /* --** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $ -+** $Id: lobject.h,v 2.117.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Type definitions for Lua objects - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lopcodes.c b/libs/lua53/lua53-src/src/lopcodes.c -index a1cbef857..5ca3eb261 100644 ---- a/libs/lua53/lua53-src/src/lopcodes.c -+++ b/libs/lua53/lua53-src/src/lopcodes.c -@@ -1,5 +1,5 @@ - /* --** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $ -+** $Id: lopcodes.c,v 1.55.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Opcodes for Lua virtual machine - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lopcodes.h b/libs/lua53/lua53-src/src/lopcodes.h -index f9b438e15..df6c2264b 100644 ---- a/libs/lua53/lua53-src/src/lopcodes.h -+++ b/libs/lua53/lua53-src/src/lopcodes.h -@@ -1,5 +1,5 @@ - /* --** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $ -+** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Opcodes for Lua virtual machine - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lopcodes.h.orig b/libs/lua53/lua53-src/src/lopcodes.h.orig -index bbc4b6196..6feaa1cd0 100644 ---- a/libs/lua53/lua53-src/src/lopcodes.h.orig -+++ b/libs/lua53/lua53-src/src/lopcodes.h.orig -@@ -1,5 +1,5 @@ - /* --** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $ -+** $Id: lopcodes.h,v 1.149.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Opcodes for Lua virtual machine - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/loslib.c b/libs/lua53/lua53-src/src/loslib.c -index 5a94eb906..de590c6b7 100644 ---- a/libs/lua53/lua53-src/src/loslib.c -+++ b/libs/lua53/lua53-src/src/loslib.c -@@ -1,5 +1,5 @@ - /* --** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $ -+** $Id: loslib.c,v 1.65.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Standard Operating System library - ** See Copyright Notice in lua.h - */ -@@ -293,7 +293,8 @@ static int os_date (lua_State *L) { - else - stm = l_localtime(&t, &tmr); - if (stm == NULL) /* invalid date? */ -- luaL_error(L, "time result cannot be represented in this installation"); -+ return luaL_error(L, -+ "time result cannot be represented in this installation"); - if (strcmp(s, "*t") == 0) { - lua_createtable(L, 0, 9); /* 9 = number of fields */ - setallfields(L, stm); -@@ -340,7 +341,8 @@ static int os_time (lua_State *L) { - setallfields(L, &ts); /* update fields with normalized values */ - } - if (t != (time_t)(l_timet)t || t == (time_t)(-1)) -- luaL_error(L, "time result cannot be represented in this installation"); -+ return luaL_error(L, -+ "time result cannot be represented in this installation"); - l_pushtime(L, t); - return 1; - } -diff --git a/libs/lua53/lua53-src/src/lparser.c b/libs/lua53/lua53-src/src/lparser.c -index cd4512d4d..cc54de43c 100644 ---- a/libs/lua53/lua53-src/src/lparser.c -+++ b/libs/lua53/lua53-src/src/lparser.c -@@ -1,5 +1,5 @@ - /* --** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $ -+** $Id: lparser.c,v 2.155.1.2 2017/04/29 18:11:40 roberto Exp $ - ** Lua Parser - ** See Copyright Notice in lua.h - */ -@@ -1392,7 +1392,7 @@ static void test_then_block (LexState *ls, int *escapelist) { - luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ - enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - gotostat(ls, v.t); /* handle goto/break */ -- skipnoopstat(ls); /* skip other no-op statements */ -+ while (testnext(ls, ';')) {} /* skip colons */ - if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ - leaveblock(fs); - return; /* and that is it */ -diff --git a/libs/lua53/lua53-src/src/lparser.h b/libs/lua53/lua53-src/src/lparser.h -index 02e9b03ae..f45b23cba 100644 ---- a/libs/lua53/lua53-src/src/lparser.h -+++ b/libs/lua53/lua53-src/src/lparser.h -@@ -1,5 +1,5 @@ - /* --** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $ -+** $Id: lparser.h,v 1.76.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Lua Parser - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lprefix.h b/libs/lua53/lua53-src/src/lprefix.h -index 02daa837f..9a749a3f3 100644 ---- a/libs/lua53/lua53-src/src/lprefix.h -+++ b/libs/lua53/lua53-src/src/lprefix.h -@@ -1,5 +1,5 @@ - /* --** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ -+** $Id: lprefix.h,v 1.2.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Definitions for Lua code that must come before any other header file - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lstate.c b/libs/lua53/lua53-src/src/lstate.c -index 9194ac341..c1a76643c 100644 ---- a/libs/lua53/lua53-src/src/lstate.c -+++ b/libs/lua53/lua53-src/src/lstate.c -@@ -1,5 +1,5 @@ - /* --** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $ -+** $Id: lstate.c,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Global State - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lstate.h b/libs/lua53/lua53-src/src/lstate.h -index a469466c4..56b374100 100644 ---- a/libs/lua53/lua53-src/src/lstate.h -+++ b/libs/lua53/lua53-src/src/lstate.h -@@ -1,5 +1,5 @@ - /* --** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lstate.h,v 2.133.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Global State - ** See Copyright Notice in lua.h - */ -@@ -26,6 +26,24 @@ - ** 'tobefnz': all objects ready to be finalized; - ** 'fixedgc': all objects that are not to be collected (currently - ** only small strings, such as reserved words). -+** -+** Moreover, there is another set of lists that control gray objects. -+** These lists are linked by fields 'gclist'. (All objects that -+** can become gray have such a field. The field is not the same -+** in all objects, but it always has this name.) Any gray object -+** must belong to one of these lists, and all objects in these lists -+** must be gray: -+** -+** 'gray': regular gray objects, still waiting to be visited. -+** 'grayagain': objects that must be revisited at the atomic phase. -+** That includes -+** - black objects got in a write barrier; -+** - all kinds of weak tables during propagation phase; -+** - all threads. -+** 'weak': tables with weak values to be cleared; -+** 'ephemeron': ephemeron tables with white->white entries; -+** 'allweak': tables with weak keys and/or weak values to be cleared. -+** The last three lists are used only during the atomic phase. - - */ - -diff --git a/libs/lua53/lua53-src/src/lstring.c b/libs/lua53/lua53-src/src/lstring.c -index 9351766fd..6257f211d 100644 ---- a/libs/lua53/lua53-src/src/lstring.c -+++ b/libs/lua53/lua53-src/src/lstring.c -@@ -1,5 +1,5 @@ - /* --** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $ -+** $Id: lstring.c,v 2.56.1.1 2017/04/19 17:20:42 roberto Exp $ - ** String table (keeps all strings handled by Lua) - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lstring.h b/libs/lua53/lua53-src/src/lstring.h -index 27efd2077..d612abd33 100644 ---- a/libs/lua53/lua53-src/src/lstring.h -+++ b/libs/lua53/lua53-src/src/lstring.h -@@ -1,5 +1,5 @@ - /* --** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $ -+** $Id: lstring.h,v 1.61.1.1 2017/04/19 17:20:42 roberto Exp $ - ** String table (keep all strings handled by Lua) - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lstrlib.c b/libs/lua53/lua53-src/src/lstrlib.c -index c7aa755fa..b4bed7e93 100644 ---- a/libs/lua53/lua53-src/src/lstrlib.c -+++ b/libs/lua53/lua53-src/src/lstrlib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lstrlib.c,v 1.254.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Standard library for string operations and pattern-matching - ** See Copyright Notice in lua.h - */ -@@ -879,7 +879,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, - buff[i] = toupper(uchar(buff[i])); - } - else if (fmt[SIZELENMOD] != 'a') -- luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); -+ return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); - return n; - } - -@@ -1199,8 +1199,8 @@ static int getnum (const char **fmt, int df) { - static int getnumlimit (Header *h, const char **fmt, int df) { - int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) -- luaL_error(h->L, "integral size (%d) out of limits [1,%d]", -- sz, MAXINTSIZE); -+ return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", -+ sz, MAXINTSIZE); - return sz; - } - -diff --git a/libs/lua53/lua53-src/src/ltable.c b/libs/lua53/lua53-src/src/ltable.c -index d080189f2..ea4fe7fcb 100644 ---- a/libs/lua53/lua53-src/src/ltable.c -+++ b/libs/lua53/lua53-src/src/ltable.c -@@ -1,5 +1,5 @@ - /* --** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $ -+** $Id: ltable.c,v 2.118.1.4 2018/06/08 16:22:51 roberto Exp $ - ** Lua tables (hash) - ** See Copyright Notice in lua.h - */ -@@ -223,7 +223,9 @@ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { - unsigned int na = 0; /* number of elements to go to array part */ - unsigned int optimal = 0; /* optimal size for array part */ - /* loop while keys can fill more than half of total size */ -- for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { -+ for (i = 0, twotoi = 1; -+ twotoi > 0 && *pna > twotoi / 2; -+ i++, twotoi *= 2) { - if (nums[i] > 0) { - a += nums[i]; - if (a > twotoi/2) { /* more than half elements present? */ -@@ -330,17 +332,34 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { - } - - -+typedef struct { -+ Table *t; -+ unsigned int nhsize; -+} AuxsetnodeT; -+ -+ -+static void auxsetnode (lua_State *L, void *ud) { -+ AuxsetnodeT *asn = cast(AuxsetnodeT *, ud); -+ setnodevector(L, asn->t, asn->nhsize); -+} -+ -+ - void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - unsigned int nhsize) { - unsigned int i; - int j; -+ AuxsetnodeT asn; - unsigned int oldasize = t->sizearray; - int oldhsize = allocsizenode(t); - Node *nold = t->node; /* save old hash ... */ - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ -- setnodevector(L, t, nhsize); -+ asn.t = t; asn.nhsize = nhsize; -+ if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) { /* mem. error? */ -+ setarrayvector(L, t, oldasize); /* array back to its original size */ -+ luaD_throw(L, LUA_ERRMEM); /* rethrow memory error */ -+ } - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ -@@ -610,13 +629,13 @@ void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { - } - - --static int unbound_search (Table *t, unsigned int j) { -- unsigned int i = j; /* i is zero or a present index */ -+static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) { -+ lua_Unsigned i = j; /* i is zero or a present index */ - j++; - /* find 'i' and 'j' such that i is present and j is not */ - while (!ttisnil(luaH_getint(t, j))) { - i = j; -- if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ -+ if (j > l_castS2U(LUA_MAXINTEGER) / 2) { /* overflow? */ - /* table was built with bad purposes: resort to linear search */ - i = 1; - while (!ttisnil(luaH_getint(t, i))) i++; -@@ -626,7 +645,7 @@ static int unbound_search (Table *t, unsigned int j) { - } - /* now do a binary search between them */ - while (j - i > 1) { -- unsigned int m = (i+j)/2; -+ lua_Unsigned m = (i+j)/2; - if (ttisnil(luaH_getint(t, m))) j = m; - else i = m; - } -@@ -638,7 +657,7 @@ static int unbound_search (Table *t, unsigned int j) { - ** Try to find a boundary in table 't'. A 'boundary' is an integer index - ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). - */ --int luaH_getn (Table *t) { -+lua_Unsigned luaH_getn (Table *t) { - unsigned int j = t->sizearray; - if (j > 0 && ttisnil(&t->array[j - 1])) { - /* there is a boundary in the array part: (binary) search for it */ -diff --git a/libs/lua53/lua53-src/src/ltable.h b/libs/lua53/lua53-src/src/ltable.h -index 6da9024fe..92db0ac7b 100644 ---- a/libs/lua53/lua53-src/src/ltable.h -+++ b/libs/lua53/lua53-src/src/ltable.h -@@ -1,5 +1,5 @@ - /* --** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $ -+** $Id: ltable.h,v 2.23.1.2 2018/05/24 19:39:05 roberto Exp $ - ** Lua tables (hash) - ** See Copyright Notice in lua.h - */ -@@ -54,7 +54,7 @@ LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, - LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); - LUAI_FUNC void luaH_free (lua_State *L, Table *t); - LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); --LUAI_FUNC int luaH_getn (Table *t); -+LUAI_FUNC lua_Unsigned luaH_getn (Table *t); - - - #if defined(LUA_DEBUG) -diff --git a/libs/lua53/lua53-src/src/ltablib.c b/libs/lua53/lua53-src/src/ltablib.c -index 98b2f8713..c5349578e 100644 ---- a/libs/lua53/lua53-src/src/ltablib.c -+++ b/libs/lua53/lua53-src/src/ltablib.c -@@ -1,5 +1,5 @@ - /* --** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $ -+** $Id: ltablib.c,v 1.93.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Library for Table Manipulation - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ltm.c b/libs/lua53/lua53-src/src/ltm.c -index 14e525788..0e7c71321 100644 ---- a/libs/lua53/lua53-src/src/ltm.c -+++ b/libs/lua53/lua53-src/src/ltm.c -@@ -1,5 +1,5 @@ - /* --** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $ -+** $Id: ltm.c,v 2.38.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Tag methods - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/ltm.h b/libs/lua53/lua53-src/src/ltm.h -index 63db7269b..8170688da 100644 ---- a/libs/lua53/lua53-src/src/ltm.h -+++ b/libs/lua53/lua53-src/src/ltm.h -@@ -1,5 +1,5 @@ - /* --** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $ -+** $Id: ltm.h,v 2.22.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Tag methods - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lua.c b/libs/lua53/lua53-src/src/lua.c -index 3f082da6b..ca5b29852 100644 ---- a/libs/lua53/lua53-src/src/lua.c -+++ b/libs/lua53/lua53-src/src/lua.c -@@ -1,5 +1,5 @@ - /* --** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $ -+** $Id: lua.c,v 1.230.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Lua stand-alone interpreter - ** See Copyright Notice in lua.h - */ -@@ -138,7 +138,7 @@ static void print_usage (const char *badoption) { - "Available options are:\n" - " -e stat execute string 'stat'\n" - " -i enter interactive mode after executing 'script'\n" -- " -l name require library 'name'\n" -+ " -l name require library 'name' into global 'name'\n" - " -v show version information\n" - " -E ignore environment variables\n" - " -- stop handling options\n" -diff --git a/libs/lua53/lua53-src/src/lua.h b/libs/lua53/lua53-src/src/lua.h -index 26c0e2d69..c236e3609 100644 ---- a/libs/lua53/lua53-src/src/lua.h -+++ b/libs/lua53/lua53-src/src/lua.h -@@ -1,5 +1,5 @@ - /* --** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $ -+** $Id: lua.h,v 1.332.1.2 2018/06/13 16:58:17 roberto Exp $ - ** Lua - A Scripting Language - ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) - ** See Copyright Notice at the end of this file -@@ -19,11 +19,11 @@ - #define LUA_VERSION_MAJOR "5" - #define LUA_VERSION_MINOR "3" - #define LUA_VERSION_NUM 503 --#define LUA_VERSION_RELEASE "4" -+#define LUA_VERSION_RELEASE "5" - - #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR - #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE --#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio" -+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2018 Lua.org, PUC-Rio" - #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" - - -@@ -460,7 +460,7 @@ struct lua_Debug { - - - /****************************************************************************** --* Copyright (C) 1994-2017 Lua.org, PUC-Rio. -+* Copyright (C) 1994-2018 Lua.org, PUC-Rio. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the -diff --git a/libs/lua53/lua53-src/src/luac.c b/libs/lua53/lua53-src/src/luac.c -index c0c91d017..549ad3950 100644 ---- a/libs/lua53/lua53-src/src/luac.c -+++ b/libs/lua53/lua53-src/src/luac.c -@@ -1,5 +1,5 @@ - /* --** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ -+** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $ - ** Lua compiler (saves bytecodes to files; also lists bytecodes) - ** See Copyright Notice in lua.h - */ -@@ -206,7 +206,7 @@ int main(int argc, char* argv[]) - } - - /* --** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $ -+** $Id: luac.c,v 1.76 2018/06/19 01:32:02 lhf Exp $ - ** print bytecodes - ** See Copyright Notice in lua.h - */ -@@ -348,6 +348,7 @@ static void PrintCode(const Proto* f) - case OP_ADD: - case OP_SUB: - case OP_MUL: -+ case OP_MOD: - case OP_POW: - case OP_DIV: - case OP_IDIV: -diff --git a/libs/lua53/lua53-src/src/luaconf.h b/libs/lua53/lua53-src/src/luaconf.h -index dbd399e3c..9eeeea69e 100644 ---- a/libs/lua53/lua53-src/src/luaconf.h -+++ b/libs/lua53/lua53-src/src/luaconf.h -@@ -1,5 +1,5 @@ - /* --** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $ -+** $Id: luaconf.h,v 1.259.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Configuration file for Lua - ** See Copyright Notice in lua.h - */ -@@ -604,8 +604,6 @@ - */ - #if !defined(LUA_USE_C89) - #define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) --/* Should we use this line ? */ --/*#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))*/ - #else - #define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) - #endif -@@ -622,6 +620,13 @@ - #endif - - -+/* -+@@ lua_pointer2str converts a pointer to a readable string in a -+** non-specified way. -+*/ -+#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) -+ -+ - /* - @@ lua_number2strx converts a float to an hexadecimal numeric string. - ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. -diff --git a/libs/lua53/lua53-src/src/lualib.h b/libs/lua53/lua53-src/src/lualib.h -index 6c0bc4cb0..f5304aa0d 100644 ---- a/libs/lua53/lua53-src/src/lualib.h -+++ b/libs/lua53/lua53-src/src/lualib.h -@@ -1,5 +1,5 @@ - /* --** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $ -+** $Id: lualib.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Lua standard libraries - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lundump.c b/libs/lua53/lua53-src/src/lundump.c -index 4080af9c0..7a67d75aa 100644 ---- a/libs/lua53/lua53-src/src/lundump.c -+++ b/libs/lua53/lua53-src/src/lundump.c -@@ -1,5 +1,5 @@ - /* --** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $ -+** $Id: lundump.c,v 2.44.1.1 2017/04/19 17:20:42 roberto Exp $ - ** load precompiled Lua chunks - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lundump.h b/libs/lua53/lua53-src/src/lundump.h -index fe4a97463..f3e2e9061 100644 ---- a/libs/lua53/lua53-src/src/lundump.h -+++ b/libs/lua53/lua53-src/src/lundump.h -@@ -1,5 +1,5 @@ - /* --** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ -+** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ - ** load precompiled Lua chunks - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lundump.h.orig b/libs/lua53/lua53-src/src/lundump.h.orig -index aa5cc82f1..ce492d689 100644 ---- a/libs/lua53/lua53-src/src/lundump.h.orig -+++ b/libs/lua53/lua53-src/src/lundump.h.orig -@@ -1,5 +1,5 @@ - /* --** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ -+** $Id: lundump.h,v 1.45.1.1 2017/04/19 17:20:42 roberto Exp $ - ** load precompiled Lua chunks - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lutf8lib.c b/libs/lua53/lua53-src/src/lutf8lib.c -index de9e3dcdd..10bd238a7 100644 ---- a/libs/lua53/lua53-src/src/lutf8lib.c -+++ b/libs/lua53/lua53-src/src/lutf8lib.c -@@ -1,5 +1,5 @@ - /* --** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lutf8lib.c,v 1.16.1.1 2017/04/19 17:29:57 roberto Exp $ - ** Standard library for UTF-8 manipulation - ** See Copyright Notice in lua.h - */ -@@ -171,7 +171,7 @@ static int byteoffset (lua_State *L) { - } - else { - if (iscont(s + posi)) -- luaL_error(L, "initial position is a continuation byte"); -+ return luaL_error(L, "initial position is a continuation byte"); - if (n < 0) { - while (n < 0 && posi > 0) { /* move back */ - do { /* find beginning of previous character */ -diff --git a/libs/lua53/lua53-src/src/lvm.c b/libs/lua53/lua53-src/src/lvm.c -index 84ade6b2f..cc43d8714 100644 ---- a/libs/lua53/lua53-src/src/lvm.c -+++ b/libs/lua53/lua53-src/src/lvm.c -@@ -1,5 +1,5 @@ - /* --** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $ -+** $Id: lvm.c,v 2.268.1.1 2017/04/19 17:39:34 roberto Exp $ - ** Lua virtual machine - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lvm.h b/libs/lua53/lua53-src/src/lvm.h -index 422f87194..a8f954f04 100644 ---- a/libs/lua53/lua53-src/src/lvm.h -+++ b/libs/lua53/lua53-src/src/lvm.h -@@ -1,5 +1,5 @@ - /* --** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $ -+** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Lua virtual machine - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lzio.c b/libs/lua53/lua53-src/src/lzio.c -index c9e1f491f..6f7909441 100644 ---- a/libs/lua53/lua53-src/src/lzio.c -+++ b/libs/lua53/lua53-src/src/lzio.c -@@ -1,5 +1,5 @@ - /* --** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $ -+** $Id: lzio.c,v 1.37.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Buffered streams - ** See Copyright Notice in lua.h - */ -diff --git a/libs/lua53/lua53-src/src/lzio.h b/libs/lua53/lua53-src/src/lzio.h -index e7b6f34b1..d89787081 100644 ---- a/libs/lua53/lua53-src/src/lzio.h -+++ b/libs/lua53/lua53-src/src/lzio.h -@@ -1,5 +1,5 @@ - /* --** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $ -+** $Id: lzio.h,v 1.31.1.1 2017/04/19 17:20:42 roberto Exp $ - ** Buffered streams - ** See Copyright Notice in lua.h - */ -diff --git a/libs/luajit/native/Makefile.am b/libs/luajit/native/Makefile.am -index f89c2fa76..c9ed9d7a1 100644 ---- a/libs/luajit/native/Makefile.am -+++ b/libs/luajit/native/Makefile.am -@@ -28,6 +28,7 @@ buildvm_arch.h: minilua$(EXEEXT) $(LUAJIT_TREE)/dynasm/dynasm.lua - `cat ../dynasm_flags` \ - -o $@ $(srcdir)/$(LUAJIT_TREE)/src/vm_$(DASM_ARCH).dasc - -+minilua_CPPFLAGS = $(AM_CPPFLAGS) $(LUAJIT_DEFINES) `cat ../native_flags` - nodist_minilua_SOURCES = \ - @LUAJIT_TREE@/src/host/minilua.c - minilua_LDADD = $(MATH_LIB) -diff --git a/libs/zziplib/zziplib-src/zzip/lib.h b/libs/zziplib/zziplib-src/zzip/lib.h -index 4a02f5473..b09a13028 100644 ---- a/libs/zziplib/zziplib-src/zzip/lib.h -+++ b/libs/zziplib/zziplib-src/zzip/lib.h -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - - #ifdef __cplusplus - extern "C" { -diff --git a/texk/web2c/Makefile.am b/texk/web2c/Makefile.am -index 38740776a..ec388fc2b 100644 ---- a/texk/web2c/Makefile.am -+++ b/texk/web2c/Makefile.am -@@ -237,6 +237,7 @@ include $(srcdir)/luatexdir/am/libunilib.am - include $(srcdir)/luatexdir/am/luafontforge.am - include $(srcdir)/luatexdir/am/libluatex.am - include $(srcdir)/luatexdir/am/luaffi.am -+include $(srcdir)/luatexdir/am/luapplib.am - include $(srcdir)/luatexdir/am/luatex.am - - ## XeTeX -diff --git a/texk/web2c/ac/web2c.ac b/texk/web2c/ac/web2c.ac -index 8cf40e03c..27bd6bb2c 100644 ---- a/texk/web2c/ac/web2c.ac -+++ b/texk/web2c/ac/web2c.ac -@@ -35,9 +35,9 @@ m4_define([kpse_tex_progs], [dnl - [[euptex], [yes], [yes], [e-upTeX], [ptexenc]], - [[aleph], [yes], [], [Aleph], []], - [[pdftex], [yes], [yes], [pdfTeX], [xpdf libpng]], --[[luatex], [yes], [], [LuaTeX], [poppler mpfr libpng zziplib lua52]], --[[luatex53], [yes], [], [LuaTeX53], [poppler mpfr libpng zziplib lua53]], --[[luajittex], [yes], [], [LuaJITTeX], [poppler mpfr libpng zziplib luajit]], -+[[luatex], [yes], [], [LuaTeX], [libpng zziplib lua52]], -+[[luatex53], [yes], [], [LuaTeX53], [libpng zziplib lua53]], -+[[luajittex], [yes], [], [LuaJITTeX], [libpng zziplib luajit]], - [[mp], [yes], [], [MetaPost], [mpfr cairo libpng]], - [[pmp], [yes], [], [pMetaPost], [mpfr cairo libpng ptexenc]], - [[upmp], [yes], [], [upMetaPost], [mpfr cairo libpng ptexenc]], -diff --git a/texk/web2c/configure.ac b/texk/web2c/configure.ac -index 6c0839297..5448f6203 100644 ---- a/texk/web2c/configure.ac -+++ b/texk/web2c/configure.ac -@@ -46,13 +46,10 @@ KPSE_LT_HACK - KPSE_WEB2C_PREPARE - m4_include([ac/web2c.ac]) - --# LuaTeX and XeTeX now require C++11 because poppler does :(. -+# XeTeX now requires C++11 because poppler does :(. - # XeTeX also requires C+11 because of ICU. --if test "x$enable_xetex" = xyes \ -- || test "x$enable_luatex" = xyes \ -- || test "x$enable_luajittex" = xyes \ -- || test "x$enable_luatex53" = xyes; then -- AC_MSG_NOTICE([checking for C++11, since LuaTeX and/or XeTeX enabled]) -+if test "x$enable_xetex" = xyes; then -+ AC_MSG_NOTICE([checking for C++11, since XeTeX enabled]) - AX_CXX_COMPILE_STDCXX([11]) - fi - -diff --git a/texk/web2c/luatexdir/ChangeLog b/texk/web2c/luatexdir/ChangeLog -index 94cbfc3e6..62d4ab049 100644 ---- a/texk/web2c/luatexdir/ChangeLog -+++ b/texk/web2c/luatexdir/ChangeLog -@@ -1,3 +1,7 @@ -+2018-08-27 Luigi Scarso -+ * dropped dependency from gmp and mpfr -+ -+ - 2017-11-02 Luigi Scarso - LuaFilesystem 1.7.0 - -diff --git a/texk/web2c/luatexdir/NEWS b/texk/web2c/luatexdir/NEWS -index 91a4ec7fe..5c044e77e 100644 ---- a/texk/web2c/luatexdir/NEWS -+++ b/texk/web2c/luatexdir/NEWS -@@ -1,3 +1,38 @@ -+============================================================== -+LuaTeX 1.08 2018-08-28 -+============================================================== -+ -+ -+(1) This release is a prelude to 1.10, the next stable iteration of LuaTeX -+after version 1.00. -+ -+(2) Lua 5.3 is now considered to be default and we might use 5.4 in version -+1.10. There are no real functional changed expected. You still need to rename -+the binary for 5.3! -+ -+(3) Binary mode is no longer available in MPlib but it is still available in -+stand alone MetaPost. This simplifies compilation and reduces dependencies. -+ -+(4) The dependency on Poppler for pdf image inclusion has been removed. We -+now use a small dedicated library written by Pawel Jakowski. We no longer -+need c++ compilers. We're in the process of making it behave well on all -+platforms. It has been tested on intel platforms. -+ -+(5) We know that there can be some (alignment) issues with the arm platform -+but these are looked into. Therefore, later this year we will release 1.09. -+Version 1.10 is planned for TeXlive. We hope that ffi works ok on intel and -+arm platforms at that point. -+ -+(6) There have been some extensions to the Lua libraries and some callbacks -+have been added. Also, a few new primitives have been introduced. The -+documentation mentions the stable extensions. -+ -+(7) There are the usual bug fixes and cleanups but there have been no real -+fundamental changes in the API. -+ -+ -+ -+ - ============================================================== - LuaTeX 1.07 2018-01-17 - ============================================================== -diff --git a/texk/web2c/luatexdir/am/libluatex.am b/texk/web2c/luatexdir/am/libluatex.am -index 3e90186ac..e3678b64b 100644 ---- a/texk/web2c/luatexdir/am/libluatex.am -+++ b/texk/web2c/luatexdir/am/libluatex.am -@@ -26,9 +26,10 @@ liblua53tex_a_DEPENDENCIES = libff.a liblua53misc.a - libluajittex_a_DEPENDENCIES = libff.a libluajitmisc.a - - libluatex_a_preflags = $(AM_CPPFLAGS) $(ZLIB_INCLUDES) $(LIBPNG_INCLUDES) --libluatex_a_preflags += $(POPPLER_INCLUDES) -I$(srcdir)/libmd5 -+libluatex_a_preflags += -I$(srcdir)/libmd5 - libluatex_a_preflags += -DpdfTeX -I$(srcdir)/luatexdir - libluatex_a_preflags += -I$(srcdir)/luatexdir/unilib -+libluatex_a_preflags += -I$(srcdir)/luatexdir/luapplib/util - libluatex_a_preflags += -I$(srcdir)/luatexdir/luafontloader/fontforge/inc - libluatex_a_preflags += -DLUA_FF_LIB=1 -I$(srcdir)/luatexdir/luafontloader/fontforge/fontforge - libluatex_a_preflags += -DSYNCTEX_ENGINE_H='' -I$(srcdir)/synctexdir -@@ -43,29 +44,31 @@ liblua53tex_a_CXXFLAGS = $(WARNING_CXXFLAGS) - libluajittex_a_CXXFLAGS = $(WARNING_CXXFLAGS) - - dist_libluatex_a_SOURCES = \ -- luatexdir/lua/lstrlibext.c -+ luatexdir/lua/lstrlibext.c \ -+ luatexdir/lua/helpers.c \ -+ luatexdir/lua/texluac.c - nodist_libluatex_a_SOURCES = \ -- helpers.c luastuff.c texluac.c \ - $(dist_libluatex_sources) \ - $(nodist_libluatex_sources) - dist_liblua53tex_a_SOURCES = \ -- luatexdir/lua/lstrlibext.c -+ luatexdir/lua/lstrlibext.c \ -+ luatexdir/lua/helpers.c \ -+ luatexdir/lua/texluac.c - nodist_liblua53tex_a_SOURCES = \ -- helpers.c luastuff.c texluac.c \ - $(dist_libluatex_sources) \ - $(nodist_libluatex_sources) - dist_libluajittex_a_SOURCES = \ - luatexdir/lua/lauxlib_bridge.h \ -- luatexdir/lua/lstrlibext.c -+ luatexdir/lua/lstrlibext.c \ -+ luatexdir/lua/texluajitc.c - nodist_libluajittex_a_SOURCES = \ -- luastuff.c texluajitc.c \ - $(dist_libluatex_sources) \ - $(nodist_libluatex_sources) - - ## mplib "stub" backends are in mplibstuff.c --$(libluatex_a_OBJECTS): libff.a libmplibcore.a libluamisc.a $(POPPLER_DEPEND) --$(liblua53tex_a_OBJECTS): libff.a libmplibcore.a liblua53misc.a $(POPPLER_DEPEND) --$(libluajittex_a_OBJECTS): libff.a libmplibcore.a libluajitmisc.a $(POPPLER_DEPEND) -+$(libluatex_a_OBJECTS): libff.a libmplibcore.a libluamisc.a -+$(liblua53tex_a_OBJECTS): libff.a libmplibcore.a liblua53misc.a -+$(libluajittex_a_OBJECTS): libff.a libmplibcore.a libluajitmisc.a - - - ## from luatexdir -@@ -91,76 +94,77 @@ dist_libluatex_sources += \ - ## - luatex_dvi_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/dvi $(ctangle) - --dvigen.c: ctangle$(EXEEXT) luatexdir/dvi/dvigen.w -- $(luatex_dvi_ctangle) dvigen.w -+#dvigen.c: ctangle$(EXEEXT) luatexdir/dvi/dvigen.w -+# $(luatex_dvi_ctangle) dvigen.w - --libluatex_web += luatexdir/dvi/dvigen.w -+#libluatex_web += luatexdir/dvi/dvigen.w - --nodist_libluatex_sources += dvigen.c -+#nodist_libluatex_sources += dvigen.c - - dist_libluatex_sources += \ -- luatexdir/dvi/dvigen.h -+ luatexdir/dvi/dvigen.h \ -+ luatexdir/dvi/dvigen.c - - ## from luatexdir/font - ## - luatex_font_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/font $(ctangle) - --dofont.c: ctangle$(EXEEXT) luatexdir/font/dofont.w -- $(luatex_font_ctangle) dofont.w --luafont.c: ctangle$(EXEEXT) luatexdir/font/luafont.w -- $(luatex_font_ctangle) luafont.w --mapfile.c: ctangle$(EXEEXT) luatexdir/font/mapfile.w -- $(luatex_font_ctangle) mapfile.w --pkin.c: ctangle$(EXEEXT) luatexdir/font/pkin.w -- $(luatex_font_ctangle) pkin.w --sfnt.c: ctangle$(EXEEXT) luatexdir/font/sfnt.w -- $(luatex_font_ctangle) sfnt.w --texfont.c: ctangle$(EXEEXT) luatexdir/font/texfont.w -- $(luatex_font_ctangle) texfont.w --tfmofm.c: ctangle$(EXEEXT) luatexdir/font/tfmofm.w -- $(luatex_font_ctangle) tfmofm.w --tounicode.c: ctangle$(EXEEXT) luatexdir/font/tounicode.w -- $(luatex_font_ctangle) tounicode.w --tt_glyf.c: ctangle$(EXEEXT) luatexdir/font/tt_glyf.w -- $(luatex_font_ctangle) tt_glyf.w --tt_table.c: ctangle$(EXEEXT) luatexdir/font/tt_table.w -- $(luatex_font_ctangle) tt_table.w --vfovf.c: ctangle$(EXEEXT) luatexdir/font/vfovf.w -- $(luatex_font_ctangle) vfovf.w --vfpacket.c: ctangle$(EXEEXT) luatexdir/font/vfpacket.w -- $(luatex_font_ctangle) vfpacket.w --writecff.c: ctangle$(EXEEXT) luatexdir/font/writecff.w -- $(luatex_font_ctangle) writecff.w --writeenc.c: ctangle$(EXEEXT) luatexdir/font/writeenc.w -- $(luatex_font_ctangle) writeenc.w --writefont.c: ctangle$(EXEEXT) luatexdir/font/writefont.w -- $(luatex_font_ctangle) writefont.w --writet1.c: ctangle$(EXEEXT) luatexdir/font/writet1.w -- $(luatex_font_ctangle) writet1.w --writet3.c: ctangle$(EXEEXT) luatexdir/font/writet3.w -- $(luatex_font_ctangle) writet3.w --writettf.c: ctangle$(EXEEXT) luatexdir/font/writettf.w -- $(luatex_font_ctangle) writettf.w --writetype0.c: ctangle$(EXEEXT) luatexdir/font/writetype0.w -- $(luatex_font_ctangle) writetype0.w --writetype2.c: ctangle$(EXEEXT) luatexdir/font/writetype2.w -- $(luatex_font_ctangle) writetype2.w -- --libluatex_web += luatexdir/font/dofont.w luatexdir/font/luafont.w luatexdir/font/mapfile.w --libluatex_web += luatexdir/font/pkin.w luatexdir/font/sfnt.w --libluatex_web += luatexdir/font/texfont.w luatexdir/font/tfmofm.w --libluatex_web += luatexdir/font/tounicode.w luatexdir/font/tt_glyf.w --libluatex_web += luatexdir/font/tt_table.w luatexdir/font/vfovf.w --libluatex_web += luatexdir/font/vfpacket.w luatexdir/font/writecff.w --libluatex_web += luatexdir/font/writeenc.w luatexdir/font/writefont.w --libluatex_web += luatexdir/font/writet1.w luatexdir/font/writet3.w --libluatex_web += luatexdir/font/writettf.w luatexdir/font/writetype0.w --libluatex_web += luatexdir/font/writetype2.w -- --nodist_libluatex_sources += dofont.c luafont.c mapfile.c pkin.c sfnt.c --nodist_libluatex_sources += texfont.c tfmofm.c tounicode.c tt_glyf.c tt_table.c vfovf.c vfpacket.c --nodist_libluatex_sources += writecff.c writeenc.c writefont.c writet1.c writet3.c writettf.c --nodist_libluatex_sources += writetype0.c writetype2.c -+# dofont.c: ctangle$(EXEEXT) luatexdir/font/dofont.w -+# $(luatex_font_ctangle) dofont.w -+# luafont.c: ctangle$(EXEEXT) luatexdir/font/luafont.w -+# $(luatex_font_ctangle) luafont.w -+# mapfile.c: ctangle$(EXEEXT) luatexdir/font/mapfile.w -+# $(luatex_font_ctangle) mapfile.w -+# pkin.c: ctangle$(EXEEXT) luatexdir/font/pkin.w -+# $(luatex_font_ctangle) pkin.w -+# sfnt.c: ctangle$(EXEEXT) luatexdir/font/sfnt.w -+# $(luatex_font_ctangle) sfnt.w -+# texfont.c: ctangle$(EXEEXT) luatexdir/font/texfont.w -+# $(luatex_font_ctangle) texfont.w -+# tfmofm.c: ctangle$(EXEEXT) luatexdir/font/tfmofm.w -+# $(luatex_font_ctangle) tfmofm.w -+# tounicode.c: ctangle$(EXEEXT) luatexdir/font/tounicode.w -+# $(luatex_font_ctangle) tounicode.w -+# tt_glyf.c: ctangle$(EXEEXT) luatexdir/font/tt_glyf.w -+# $(luatex_font_ctangle) tt_glyf.w -+# tt_table.c: ctangle$(EXEEXT) luatexdir/font/tt_table.w -+# $(luatex_font_ctangle) tt_table.w -+# vfovf.c: ctangle$(EXEEXT) luatexdir/font/vfovf.w -+# $(luatex_font_ctangle) vfovf.w -+# vfpacket.c: ctangle$(EXEEXT) luatexdir/font/vfpacket.w -+# $(luatex_font_ctangle) vfpacket.w -+# writecff.c: ctangle$(EXEEXT) luatexdir/font/writecff.w -+# $(luatex_font_ctangle) writecff.w -+# writeenc.c: ctangle$(EXEEXT) luatexdir/font/writeenc.w -+# $(luatex_font_ctangle) writeenc.w -+# writefont.c: ctangle$(EXEEXT) luatexdir/font/writefont.w -+# $(luatex_font_ctangle) writefont.w -+# writet1.c: ctangle$(EXEEXT) luatexdir/font/writet1.w -+# $(luatex_font_ctangle) writet1.w -+# writet3.c: ctangle$(EXEEXT) luatexdir/font/writet3.w -+# $(luatex_font_ctangle) writet3.w -+# writettf.c: ctangle$(EXEEXT) luatexdir/font/writettf.w -+# $(luatex_font_ctangle) writettf.w -+# writetype0.c: ctangle$(EXEEXT) luatexdir/font/writetype0.w -+# $(luatex_font_ctangle) writetype0.w -+# writetype2.c: ctangle$(EXEEXT) luatexdir/font/writetype2.w -+# $(luatex_font_ctangle) writetype2.w -+ -+# libluatex_web += luatexdir/font/dofont.w luatexdir/font/luafont.w luatexdir/font/mapfile.w -+# libluatex_web += luatexdir/font/pkin.w luatexdir/font/sfnt.w -+# libluatex_web += luatexdir/font/texfont.w luatexdir/font/tfmofm.w -+# libluatex_web += luatexdir/font/tounicode.w luatexdir/font/tt_glyf.w -+# libluatex_web += luatexdir/font/tt_table.w luatexdir/font/vfovf.w -+# libluatex_web += luatexdir/font/vfpacket.w luatexdir/font/writecff.w -+# libluatex_web += luatexdir/font/writeenc.w luatexdir/font/writefont.w -+# libluatex_web += luatexdir/font/writet1.w luatexdir/font/writet3.w -+# libluatex_web += luatexdir/font/writettf.w luatexdir/font/writetype0.w -+# libluatex_web += luatexdir/font/writetype2.w -+ -+# nodist_libluatex_sources += dofont.c luafont.c mapfile.c pkin.c sfnt.c -+# nodist_libluatex_sources += texfont.c tfmofm.c tounicode.c tt_glyf.c tt_table.c vfovf.c vfpacket.c -+# nodist_libluatex_sources += writecff.c writeenc.c writefont.c writet1.c writet3.c writettf.c -+# nodist_libluatex_sources += writetype0.c writetype2.c - - dist_libluatex_sources += \ - luatexdir/font/luatexfont.h \ -@@ -170,33 +174,54 @@ dist_libluatex_sources += \ - luatexdir/font/tt_glyf.h \ - luatexdir/font/tt_table.h \ - luatexdir/font/writecff.h \ -- luatexdir/font/writettf.h -+ luatexdir/font/writettf.h \ -+ luatexdir/font/dofont.c \ -+ luatexdir/font/luafont.c \ -+ luatexdir/font/mapfile.c \ -+ luatexdir/font/pkin.c \ -+ luatexdir/font/sfnt.c \ -+ luatexdir/font/texfont.c \ -+ luatexdir/font/tfmofm.c \ -+ luatexdir/font/tounicode.c \ -+ luatexdir/font/tt_glyf.c \ -+ luatexdir/font/tt_table.c \ -+ luatexdir/font/vfovf.c \ -+ luatexdir/font/vfpacket.c \ -+ luatexdir/font/writecff.c \ -+ luatexdir/font/writeenc.c \ -+ luatexdir/font/writefont.c \ -+ luatexdir/font/writet1.c \ -+ luatexdir/font/writet3.c \ -+ luatexdir/font/writettf.c \ -+ luatexdir/font/writetype0.c \ -+ luatexdir/font/writetype2.c -+ - - ## from luatexdir/image - ## - luatex_image_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/image $(ctangle) - --writeimg.c: ctangle$(EXEEXT) luatexdir/image/writeimg.w -- $(luatex_image_ctangle) writeimg.w --writejbig2.c: ctangle$(EXEEXT) luatexdir/image/writejbig2.w -- $(luatex_image_ctangle) writejbig2.w --writejpg.c: ctangle$(EXEEXT) luatexdir/image/writejpg.w -- $(luatex_image_ctangle) writejpg.w --writejp2.c: ctangle$(EXEEXT) luatexdir/image/writejp2.w -- $(luatex_image_ctangle) writejp2.w --writepng.c: ctangle$(EXEEXT) luatexdir/image/writepng.w -- $(luatex_image_ctangle) writepng.w --pdftoepdf.cc: ctangle$(EXEEXT) luatexdir/image/pdftoepdf.w -- $(luatex_image_ctangle) pdftoepdf.w - $@ -- --libluatex_web += luatexdir/image/writeimg.w --libluatex_web += luatexdir/image/writejbig2.w --libluatex_web += luatexdir/image/writejpg.w --libluatex_web += luatexdir/image/writejp2.w --libluatex_web += luatexdir/image/writepng.w --libluatex_web += luatexdir/image/pdftoepdf.w -- --nodist_libluatex_sources += writeimg.c writejbig2.c writejpg.c writejp2.c writepng.c pdftoepdf.cc -+#writeimg.c: ctangle$(EXEEXT) luatexdir/image/writeimg.w -+# $(luatex_image_ctangle) writeimg.w -+#writejbig2.c: ctangle$(EXEEXT) luatexdir/image/writejbig2.w -+# $(luatex_image_ctangle) writejbig2.w -+#writejpg.c: ctangle$(EXEEXT) luatexdir/image/writejpg.w -+# $(luatex_image_ctangle) writejpg.w -+#writejp2.c: ctangle$(EXEEXT) luatexdir/image/writejp2.w -+# $(luatex_image_ctangle) writejp2.w -+#writepng.c: ctangle$(EXEEXT) luatexdir/image/writepng.w -+# $(luatex_image_ctangle) writepng.w -+#pdftoepdf.cc: ctangle$(EXEEXT) luatexdir/image/pdftoepdf.w -+# $(luatex_image_ctangle) pdftoepdf.w - $@ -+ -+#libluatex_web += luatexdir/image/writeimg.w -+#libluatex_web += luatexdir/image/writejbig2.w -+#libluatex_web += luatexdir/image/writejpg.w -+#libluatex_web += luatexdir/image/writejp2.w -+#libluatex_web += luatexdir/image/writepng.w -+#libluatex_web += luatexdir/image/pdftoepdf.w -+ -+#nodist_libluatex_sources += writeimg.c writejbig2.c writejpg.c writejp2.c writepng.c - - dist_libluatex_sources += \ - luatexdir/image/epdf.h \ -@@ -206,72 +231,61 @@ dist_libluatex_sources += \ - luatexdir/image/writejbig2.h \ - luatexdir/image/writejpg.h \ - luatexdir/image/writejp2.h \ -- luatexdir/image/writepng.h -+ luatexdir/image/writepng.h \ -+ luatexdir/image/pdftoepdf.c \ -+ luatexdir/image/writeimg.c \ -+ luatexdir/image/writejbig2.c \ -+ luatexdir/image/writejp2.c \ -+ luatexdir/image/writejpg.c \ -+ luatexdir/image/writepng.c - - ## from luatexdir/lang - ## - luatex_lang_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/lang $(ctangle) - --hnjalloc.c: ctangle$(EXEEXT) luatexdir/lang/hnjalloc.w -- $(luatex_lang_ctangle) hnjalloc.w --hyphen.c: ctangle$(EXEEXT) luatexdir/lang/hyphen.w -- $(luatex_lang_ctangle) hyphen.w --texlang.c: ctangle$(EXEEXT) luatexdir/lang/texlang.w -- $(luatex_lang_ctangle) texlang.w -- --libluatex_web += luatexdir/lang/texlang.w luatexdir/lang/hyphen.w luatexdir/lang/hnjalloc.w -- --nodist_libluatex_sources += texlang.c hyphen.c hnjalloc.c -- - dist_libluatex_sources += \ - luatexdir/lang/hnjalloc.h \ - luatexdir/lang/hyphen.h \ -- luatexdir/lang/texlang.h -+ luatexdir/lang/texlang.h \ -+ luatexdir/lang/hnjalloc.c \ -+ luatexdir/lang/hyphen.c \ -+ luatexdir/lang/texlang.c - - ## from luatexdir/lua - ## - luatex_lua_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/lua $(ctangle) - --helpers.c: ctangle$(EXEEXT) luatexdir/lua/helpers.w -- $(luatex_lua_ctangle) helpers.w --luainit.c: ctangle$(EXEEXT) luatexdir/lua/luainit.w -- $(luatex_lua_ctangle) luainit.w -+#helpers.c: ctangle$(EXEEXT) luatexdir/lua/helpers.w -+# $(luatex_lua_ctangle) helpers.w -+#luainit.c: ctangle$(EXEEXT) luatexdir/lua/luainit.w -+# $(luatex_lua_ctangle) luainit.w - #luajitstuff.c: ctangle$(EXEEXT) luatexdir/lua/luajitstuff.w - # $(luatex_lua_ctangle) luajitstuff.w --luanode.c: ctangle$(EXEEXT) luatexdir/lua/luanode.w -- $(luatex_lua_ctangle) luanode.w --luastuff.c: ctangle$(EXEEXT) luatexdir/lua/luastuff.w -- $(luatex_lua_ctangle) luastuff.w --luatoken.c: ctangle$(EXEEXT) luatexdir/lua/luatoken.w -- $(luatex_lua_ctangle) luatoken.w --mplibstuff.c: ctangle$(EXEEXT) luatexdir/lua/mplibstuff.w -- $(luatex_lua_ctangle) mplibstuff.w --texluac.c: ctangle$(EXEEXT) luatexdir/lua/texluac.w -- $(luatex_lua_ctangle) texluac.w --texluajitc.c: ctangle$(EXEEXT) luatexdir/lua/texluajitc.w -- $(luatex_lua_ctangle) texluajitc.w -- --libluatex_web += luatexdir/lua/helpers.w --#libluatex_web += luatexdir/lua/luainit.w luatexdir/lua/luajitstuff.w --libluatex_web += luatexdir/lua/luainit.w --libluatex_web += luatexdir/lua/luanode.w luatexdir/lua/luastuff.w luatexdir/lua/luatoken.w --libluatex_web += luatexdir/lua/mplibstuff.w --libluatex_web += luatexdir/lua/texluac.w luatexdir/lua/texluajitc.w -+#luanode.c: ctangle$(EXEEXT) luatexdir/lua/luanode.w -+# $(luatex_lua_ctangle) luanode.w -+#luastuff.c: ctangle$(EXEEXT) luatexdir/lua/luastuff.w -+# $(luatex_lua_ctangle) luastuff.w -+#luatoken.c: ctangle$(EXEEXT) luatexdir/lua/luatoken.w -+# $(luatex_lua_ctangle) luatoken.w -+#mplibstuff.c: ctangle$(EXEEXT) luatexdir/lua/mplibstuff.w -+# $(luatex_lua_ctangle) mplibstuff.w -+#texluac.c: ctangle$(EXEEXT) luatexdir/lua/texluac.w -+# $(luatex_lua_ctangle) texluac.w -+#texluajitc.c: ctangle$(EXEEXT) luatexdir/lua/texluajitc.w -+# $(luatex_lua_ctangle) texluajitc.w - --nodist_libluatex_sources += luainit.c luanode.c luatoken.c --nodist_libluatex_sources += mplibstuff.c -+#libluatex_web += luatexdir/lua/luainit.w luatexdir/lua/luajitstuff.w - - - dist_libluatex_sources += \ - luatexdir/lua/lcallbacklib.c \ - luatexdir/lua/lfontlib.c \ - luatexdir/lua/limglib.c \ -- luatexdir/lua/lpdfscannerlib.cc \ -- luatexdir/lua/lepdflib.cc \ -+ luatexdir/lua/lpdfelib.c \ -+ luatexdir/lua/lpdfscannerlib.c \ - luatexdir/lua/lkpselib.c \ - luatexdir/lua/llanglib.c \ - luatexdir/lua/llualib.c \ -- luatexdir/lua/llfslibext.c \ - luatexdir/lua/lnodelib.c \ - luatexdir/lua/liolibext.c \ - luatexdir/lua/loslibext.c \ -@@ -281,71 +295,79 @@ dist_libluatex_sources += \ - luatexdir/lua/ltexlib.c \ - luatexdir/lua/lnewtokenlib.c \ - luatexdir/lua/luatex-api.h \ -- luatexdir/lua/luatex-core.c -+ luatexdir/lua/luatex-core.c \ -+ luatexdir/lua/helpers.c \ -+ luatexdir/lua/luainit.c \ -+ luatexdir/lua/luanode.c \ -+ luatexdir/lua/luastuff.c \ -+ luatexdir/lua/luatoken.c \ -+ luatexdir/lua/mplibstuff.c -+ -+ - - ## from luatexdir/pdf - ## - luatex_pdf_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/pdf $(ctangle) - --pdfpagetree.c: ctangle$(EXEEXT) luatexdir/pdf/pdfpagetree.w -- $(luatex_pdf_ctangle) pdfpagetree.w --pdfaction.c: ctangle$(EXEEXT) luatexdir/pdf/pdfaction.w -- $(luatex_pdf_ctangle) pdfaction.w --pdfannot.c: ctangle$(EXEEXT) luatexdir/pdf/pdfannot.w -- $(luatex_pdf_ctangle) pdfannot.w --pdfcolorstack.c: ctangle$(EXEEXT) luatexdir/pdf/pdfcolorstack.w -- $(luatex_pdf_ctangle) pdfcolorstack.w --pdfdest.c: ctangle$(EXEEXT) luatexdir/pdf/pdfdest.w -- $(luatex_pdf_ctangle) pdfdest.w --pdffont.c: ctangle$(EXEEXT) luatexdir/pdf/pdffont.w -- $(luatex_pdf_ctangle) pdffont.w --pdfgen.c: ctangle$(EXEEXT) luatexdir/pdf/pdfgen.w -- $(luatex_pdf_ctangle) pdfgen.w --pdfglyph.c: ctangle$(EXEEXT) luatexdir/pdf/pdfglyph.w -- $(luatex_pdf_ctangle) pdfglyph.w --pdfimage.c: ctangle$(EXEEXT) luatexdir/pdf/pdfimage.w -- $(luatex_pdf_ctangle) pdfimage.w --pdflink.c: ctangle$(EXEEXT) luatexdir/pdf/pdflink.w -- $(luatex_pdf_ctangle) pdflink.w --pdflistout.c: ctangle$(EXEEXT) luatexdir/pdf/pdflistout.w -- $(luatex_pdf_ctangle) pdflistout.w --pdfliteral.c: ctangle$(EXEEXT) luatexdir/pdf/pdfliteral.w -- $(luatex_pdf_ctangle) pdfliteral.w --pdfobj.c: ctangle$(EXEEXT) luatexdir/pdf/pdfobj.w -- $(luatex_pdf_ctangle) pdfobj.w --pdfoutline.c: ctangle$(EXEEXT) luatexdir/pdf/pdfoutline.w -- $(luatex_pdf_ctangle) pdfoutline.w --pdfpage.c: ctangle$(EXEEXT) luatexdir/pdf/pdfpage.w -- $(luatex_pdf_ctangle) pdfpage.w --pdfrule.c: ctangle$(EXEEXT) luatexdir/pdf/pdfrule.w -- $(luatex_pdf_ctangle) pdfrule.w --pdfsaverestore.c: ctangle$(EXEEXT) luatexdir/pdf/pdfsaverestore.w -- $(luatex_pdf_ctangle) pdfsaverestore.w --pdfsetmatrix.c: ctangle$(EXEEXT) luatexdir/pdf/pdfsetmatrix.w -- $(luatex_pdf_ctangle) pdfsetmatrix.w --pdfshipout.c: ctangle$(EXEEXT) luatexdir/pdf/pdfshipout.w -- $(luatex_pdf_ctangle) pdfshipout.w --pdftables.c: ctangle$(EXEEXT) luatexdir/pdf/pdftables.w -- $(luatex_pdf_ctangle) pdftables.w --pdfthread.c: ctangle$(EXEEXT) luatexdir/pdf/pdfthread.w -- $(luatex_pdf_ctangle) pdfthread.w --pdfxform.c: ctangle$(EXEEXT) luatexdir/pdf/pdfxform.w -- $(luatex_pdf_ctangle) pdfxform.w -- --libluatex_web += luatexdir/pdf/pdfpagetree.w luatexdir/pdf/pdfaction.w luatexdir/pdf/pdfannot.w --libluatex_web += luatexdir/pdf/pdfcolorstack.w luatexdir/pdf/pdfdest.w --libluatex_web += luatexdir/pdf/pdffont.w luatexdir/pdf/pdfgen.w luatexdir/pdf/pdfglyph.w --libluatex_web += luatexdir/pdf/pdfimage.w luatexdir/pdf/pdflink.w luatexdir/pdf/pdflistout.w --libluatex_web += luatexdir/pdf/pdfliteral.w luatexdir/pdf/pdfobj.w --libluatex_web += luatexdir/pdf/pdfoutline.w luatexdir/pdf/pdfpage.w luatexdir/pdf/pdfrule.w --libluatex_web += luatexdir/pdf/pdfsaverestore.w luatexdir/pdf/pdfsetmatrix.w --libluatex_web += luatexdir/pdf/pdfshipout.w luatexdir/pdf/pdftables.w --libluatex_web += luatexdir/pdf/pdfthread.w luatexdir/pdf/pdfxform.w -- --nodist_libluatex_sources += pdfpagetree.c pdfaction.c pdfannot.c pdfcolorstack.c pdfdest.c pdffont.c --nodist_libluatex_sources += pdfgen.c pdfglyph.c pdfimage.c pdflink.c pdflistout.c pdfliteral.c --nodist_libluatex_sources += pdfobj.c pdfoutline.c pdfpage.c pdfrule.c pdfsaverestore.c --nodist_libluatex_sources += pdfsetmatrix.c pdfshipout.c pdftables.c pdfthread.c pdfxform.c -+# pdfpagetree.c: ctangle$(EXEEXT) luatexdir/pdf/pdfpagetree.w -+# $(luatex_pdf_ctangle) pdfpagetree.w -+# pdfaction.c: ctangle$(EXEEXT) luatexdir/pdf/pdfaction.w -+# $(luatex_pdf_ctangle) pdfaction.w -+# pdfannot.c: ctangle$(EXEEXT) luatexdir/pdf/pdfannot.w -+# $(luatex_pdf_ctangle) pdfannot.w -+# pdfcolorstack.c: ctangle$(EXEEXT) luatexdir/pdf/pdfcolorstack.w -+# $(luatex_pdf_ctangle) pdfcolorstack.w -+# pdfdest.c: ctangle$(EXEEXT) luatexdir/pdf/pdfdest.w -+# $(luatex_pdf_ctangle) pdfdest.w -+# pdffont.c: ctangle$(EXEEXT) luatexdir/pdf/pdffont.w -+# $(luatex_pdf_ctangle) pdffont.w -+# pdfgen.c: ctangle$(EXEEXT) luatexdir/pdf/pdfgen.w -+# $(luatex_pdf_ctangle) pdfgen.w -+# pdfglyph.c: ctangle$(EXEEXT) luatexdir/pdf/pdfglyph.w -+# $(luatex_pdf_ctangle) pdfglyph.w -+# pdfimage.c: ctangle$(EXEEXT) luatexdir/pdf/pdfimage.w -+# $(luatex_pdf_ctangle) pdfimage.w -+# pdflink.c: ctangle$(EXEEXT) luatexdir/pdf/pdflink.w -+# $(luatex_pdf_ctangle) pdflink.w -+# pdflistout.c: ctangle$(EXEEXT) luatexdir/pdf/pdflistout.w -+# $(luatex_pdf_ctangle) pdflistout.w -+# pdfliteral.c: ctangle$(EXEEXT) luatexdir/pdf/pdfliteral.w -+# $(luatex_pdf_ctangle) pdfliteral.w -+# pdfobj.c: ctangle$(EXEEXT) luatexdir/pdf/pdfobj.w -+# $(luatex_pdf_ctangle) pdfobj.w -+# pdfoutline.c: ctangle$(EXEEXT) luatexdir/pdf/pdfoutline.w -+# $(luatex_pdf_ctangle) pdfoutline.w -+# pdfpage.c: ctangle$(EXEEXT) luatexdir/pdf/pdfpage.w -+# $(luatex_pdf_ctangle) pdfpage.w -+# pdfrule.c: ctangle$(EXEEXT) luatexdir/pdf/pdfrule.w -+# $(luatex_pdf_ctangle) pdfrule.w -+# pdfsaverestore.c: ctangle$(EXEEXT) luatexdir/pdf/pdfsaverestore.w -+# $(luatex_pdf_ctangle) pdfsaverestore.w -+# pdfsetmatrix.c: ctangle$(EXEEXT) luatexdir/pdf/pdfsetmatrix.w -+# $(luatex_pdf_ctangle) pdfsetmatrix.w -+# pdfshipout.c: ctangle$(EXEEXT) luatexdir/pdf/pdfshipout.w -+# $(luatex_pdf_ctangle) pdfshipout.w -+# pdftables.c: ctangle$(EXEEXT) luatexdir/pdf/pdftables.w -+# $(luatex_pdf_ctangle) pdftables.w -+# pdfthread.c: ctangle$(EXEEXT) luatexdir/pdf/pdfthread.w -+# $(luatex_pdf_ctangle) pdfthread.w -+# pdfxform.c: ctangle$(EXEEXT) luatexdir/pdf/pdfxform.w -+# $(luatex_pdf_ctangle) pdfxform.w -+ -+#libluatex_web += luatexdir/pdf/pdfpagetree.w luatexdir/pdf/pdfaction.w luatexdir/pdf/pdfannot.w -+#libluatex_web += luatexdir/pdf/pdfcolorstack.w luatexdir/pdf/pdfdest.w -+#libluatex_web += luatexdir/pdf/pdffont.w luatexdir/pdf/pdfgen.w luatexdir/pdf/pdfglyph.w -+#libluatex_web += luatexdir/pdf/pdfimage.w luatexdir/pdf/pdflink.w luatexdir/pdf/pdflistout.w -+#libluatex_web += luatexdir/pdf/pdfliteral.w luatexdir/pdf/pdfobj.w -+#libluatex_web += luatexdir/pdf/pdfoutline.w luatexdir/pdf/pdfpage.w luatexdir/pdf/pdfrule.w -+#libluatex_web += luatexdir/pdf/pdfsaverestore.w luatexdir/pdf/pdfsetmatrix.w -+#libluatex_web += luatexdir/pdf/pdfshipout.w luatexdir/pdf/pdftables.w -+#libluatex_web += luatexdir/pdf/pdfthread.w luatexdir/pdf/pdfxform.w -+ -+#nodist_libluatex_sources += pdfpagetree.c pdfaction.c pdfannot.c pdfcolorstack.c pdfdest.c pdffont.c -+#nodist_libluatex_sources += pdfgen.c pdfglyph.c pdfimage.c pdflink.c pdflistout.c pdfliteral.c -+#nodist_libluatex_sources += pdfobj.c pdfoutline.c pdfpage.c pdfrule.c pdfsaverestore.c -+#nodist_libluatex_sources += pdfsetmatrix.c pdfshipout.c pdftables.c pdfthread.c pdfxform.c - - dist_libluatex_sources += \ - luatexdir/pdf/pdfpagetree.h \ -@@ -370,7 +392,29 @@ dist_libluatex_sources += \ - luatexdir/pdf/pdftables.h \ - luatexdir/pdf/pdfthread.h \ - luatexdir/pdf/pdftypes.h \ -- luatexdir/pdf/pdfxform.h -+ luatexdir/pdf/pdfxform.h \ -+ luatexdir/pdf/pdfaction.c \ -+ luatexdir/pdf/pdfannot.c \ -+ luatexdir/pdf/pdfcolorstack.c \ -+ luatexdir/pdf/pdfdest.c \ -+ luatexdir/pdf/pdffont.c \ -+ luatexdir/pdf/pdfgen.c \ -+ luatexdir/pdf/pdfglyph.c \ -+ luatexdir/pdf/pdfimage.c \ -+ luatexdir/pdf/pdflink.c \ -+ luatexdir/pdf/pdflistout.c \ -+ luatexdir/pdf/pdfliteral.c \ -+ luatexdir/pdf/pdfobj.c \ -+ luatexdir/pdf/pdfoutline.c \ -+ luatexdir/pdf/pdfpage.c \ -+ luatexdir/pdf/pdfpagetree.c \ -+ luatexdir/pdf/pdfrule.c \ -+ luatexdir/pdf/pdfsaverestore.c \ -+ luatexdir/pdf/pdfsetmatrix.c \ -+ luatexdir/pdf/pdfshipout.c \ -+ luatexdir/pdf/pdftables.c \ -+ luatexdir/pdf/pdfthread.c \ -+ luatexdir/pdf/pdfxform.c - - ################################################################################ - ################################################################################ -@@ -415,93 +459,79 @@ dist_libluatex_sources += \ - ## - luatex_tex_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/tex $(ctangle) - --align.c: ctangle$(EXEEXT) luatexdir/tex/align.w -- $(luatex_tex_ctangle) align.w --arithmetic.c: ctangle$(EXEEXT) luatexdir/tex/arithmetic.w -- $(luatex_tex_ctangle) arithmetic.w --buildpage.c: ctangle$(EXEEXT) luatexdir/tex/buildpage.w -- $(luatex_tex_ctangle) buildpage.w --commands.c: ctangle$(EXEEXT) luatexdir/tex/commands.w -- $(luatex_tex_ctangle) commands.w --conditional.c: ctangle$(EXEEXT) luatexdir/tex/conditional.w -- $(luatex_tex_ctangle) conditional.w --directions.c: ctangle$(EXEEXT) luatexdir/tex/directions.w -- $(luatex_tex_ctangle) directions.w --dumpdata.c: ctangle$(EXEEXT) luatexdir/tex/dumpdata.w -- $(luatex_tex_ctangle) dumpdata.w --equivalents.c: ctangle$(EXEEXT) luatexdir/tex/equivalents.w -- $(luatex_tex_ctangle) equivalents.w --errors.c: ctangle$(EXEEXT) luatexdir/tex/errors.w -- $(luatex_tex_ctangle) errors.w --expand.c: ctangle$(EXEEXT) luatexdir/tex/expand.w -- $(luatex_tex_ctangle) expand.w --extensions.c: ctangle$(EXEEXT) luatexdir/tex/extensions.w -- $(luatex_tex_ctangle) extensions.w --filename.c: ctangle$(EXEEXT) luatexdir/tex/filename.w -- $(luatex_tex_ctangle) filename.w --inputstack.c: ctangle$(EXEEXT) luatexdir/tex/inputstack.w -- $(luatex_tex_ctangle) inputstack.w --linebreak.c: ctangle$(EXEEXT) luatexdir/tex/linebreak.w -- $(luatex_tex_ctangle) linebreak.w --mainbody.c: ctangle$(EXEEXT) luatexdir/tex/mainbody.w -- $(luatex_tex_ctangle) mainbody.w --maincontrol.c: ctangle$(EXEEXT) luatexdir/tex/maincontrol.w -- $(luatex_tex_ctangle) maincontrol.w --mathcodes.c: ctangle$(EXEEXT) luatexdir/tex/mathcodes.w -- $(luatex_tex_ctangle) mathcodes.w --memoryword.c: ctangle$(EXEEXT) luatexdir/tex/memoryword.w -- $(luatex_tex_ctangle) memoryword.w --mlist.c: ctangle$(EXEEXT) luatexdir/tex/mlist.w -- $(luatex_tex_ctangle) mlist.w --nesting.c: ctangle$(EXEEXT) luatexdir/tex/nesting.w -- $(luatex_tex_ctangle) nesting.w --packaging.c: ctangle$(EXEEXT) luatexdir/tex/packaging.w -- $(luatex_tex_ctangle) packaging.w --postlinebreak.c: ctangle$(EXEEXT) luatexdir/tex/postlinebreak.w -- $(luatex_tex_ctangle) postlinebreak.w --primitive.c: ctangle$(EXEEXT) luatexdir/tex/primitive.w -- $(luatex_tex_ctangle) primitive.w --printing.c: ctangle$(EXEEXT) luatexdir/tex/printing.w -- $(luatex_tex_ctangle) printing.w --scanning.c: ctangle$(EXEEXT) luatexdir/tex/scanning.w -- $(luatex_tex_ctangle) scanning.w --stringpool.c: ctangle$(EXEEXT) luatexdir/tex/stringpool.w -- $(luatex_tex_ctangle) stringpool.w --texdeffont.c: ctangle$(EXEEXT) luatexdir/tex/texdeffont.w -- $(luatex_tex_ctangle) texdeffont.w --texfileio.c: ctangle$(EXEEXT) luatexdir/tex/texfileio.w -- $(luatex_tex_ctangle) texfileio.w --texmath.c: ctangle$(EXEEXT) luatexdir/tex/texmath.w -- $(luatex_tex_ctangle) texmath.w --texnodes.c: ctangle$(EXEEXT) luatexdir/tex/texnodes.w -- $(luatex_tex_ctangle) texnodes.w --textcodes.c: ctangle$(EXEEXT) luatexdir/tex/textcodes.w -- $(luatex_tex_ctangle) textcodes.w --textoken.c: ctangle$(EXEEXT) luatexdir/tex/textoken.w -- $(luatex_tex_ctangle) textoken.w -- --libluatex_web += luatexdir/tex/align.w luatexdir/tex/arithmetic.w luatexdir/tex/buildpage.w --libluatex_web += luatexdir/tex/commands.w luatexdir/tex/conditional.w luatexdir/tex/directions.w --libluatex_web += luatexdir/tex/dumpdata.w luatexdir/tex/equivalents.w luatexdir/tex/errors.w --libluatex_web += luatexdir/tex/expand.w luatexdir/tex/extensions.w luatexdir/tex/filename.w --libluatex_web += luatexdir/tex/inputstack.w luatexdir/tex/linebreak.w luatexdir/tex/mainbody.w --libluatex_web += luatexdir/tex/maincontrol.w luatexdir/tex/mathcodes.w luatexdir/tex/memoryword.w --libluatex_web += luatexdir/tex/mlist.w luatexdir/tex/nesting.w luatexdir/tex/packaging.w --libluatex_web += luatexdir/tex/postlinebreak.w luatexdir/tex/primitive.w luatexdir/tex/printing.w --libluatex_web += luatexdir/tex/scanning.w luatexdir/tex/stringpool.w luatexdir/tex/texdeffont.w --libluatex_web += luatexdir/tex/texfileio.w luatexdir/tex/texmath.w luatexdir/tex/texnodes.w --libluatex_web += luatexdir/tex/textcodes.w luatexdir/tex/textoken.w -- --nodist_libluatex_sources += align.c arithmetic.c buildpage.c commands.c conditional.c directions.c --nodist_libluatex_sources += dumpdata.c equivalents.c errors.c expand.c extensions.c filename.c --nodist_libluatex_sources += inputstack.c linebreak.c mainbody.c maincontrol.c mathcodes.c --nodist_libluatex_sources += memoryword.c mlist.c nesting.c packaging.c postlinebreak.c --nodist_libluatex_sources += primitive.c printing.c scanning.c stringpool.c texdeffont.c --nodist_libluatex_sources += texfileio.c texmath.c texnodes.c textcodes.c textoken.c -+# align.c: ctangle$(EXEEXT) luatexdir/tex/align.w -+# $(luatex_tex_ctangle) align.w -+#arithmetic.c: ctangle$(EXEEXT) luatexdir/tex/arithmetic.w -+# $(luatex_tex_ctangle) arithmetic.w -+# buildpage.c: ctangle$(EXEEXT) luatexdir/tex/buildpage.w -+# $(luatex_tex_ctangle) buildpage.w -+#commands.c: ctangle$(EXEEXT) luatexdir/tex/commands.w -+# $(luatex_tex_ctangle) commands.w -+#conditional.c: ctangle$(EXEEXT) luatexdir/tex/conditional.w -+# $(luatex_tex_ctangle) conditional.w -+#directions.c: ctangle$(EXEEXT) luatexdir/tex/directions.w -+# $(luatex_tex_ctangle) directions.w -+#dumpdata.c: ctangle$(EXEEXT) luatexdir/tex/dumpdata.w -+# $(luatex_tex_ctangle) dumpdata.w -+#equivalents.c: ctangle$(EXEEXT) luatexdir/tex/equivalents.w -+# $(luatex_tex_ctangle) equivalents.w -+#errors.c: ctangle$(EXEEXT) luatexdir/tex/errors.w -+# $(luatex_tex_ctangle) errors.w -+# expand.c: ctangle$(EXEEXT) luatexdir/tex/expand.w -+# $(luatex_tex_ctangle) expand.w -+# extensions.c: ctangle$(EXEEXT) luatexdir/tex/extensions.w -+# $(luatex_tex_ctangle) extensions.w -+#filename.c: ctangle$(EXEEXT) luatexdir/tex/filename.w -+# $(luatex_tex_ctangle) filename.w -+#inputstack.c: ctangle$(EXEEXT) luatexdir/tex/inputstack.w -+# $(luatex_tex_ctangle) inputstack.w -+# linebreak.c: ctangle$(EXEEXT) luatexdir/tex/linebreak.w -+# $(luatex_tex_ctangle) linebreak.w -+#mainbody.c: ctangle$(EXEEXT) luatexdir/tex/mainbody.w -+# $(luatex_tex_ctangle) mainbody.w -+#maincontrol.c: ctangle$(EXEEXT) luatexdir/tex/maincontrol.w -+# $(luatex_tex_ctangle) maincontrol.w -+#mathcodes.c: ctangle$(EXEEXT) luatexdir/tex/mathcodes.w -+# $(luatex_tex_ctangle) mathcodes.w -+#memoryword.c: ctangle$(EXEEXT) luatexdir/tex/memoryword.w -+# $(luatex_tex_ctangle) memoryword.w -+# mlist.c: ctangle$(EXEEXT) luatexdir/tex/mlist.w -+# $(luatex_tex_ctangle) mlist.w -+#nesting.c: ctangle$(EXEEXT) luatexdir/tex/nesting.w -+# $(luatex_tex_ctangle) nesting.w -+# packaging.c: ctangle$(EXEEXT) luatexdir/tex/packaging.w -+# $(luatex_tex_ctangle) packaging.w -+#postlinebreak.c: ctangle$(EXEEXT) luatexdir/tex/postlinebreak.w -+# $(luatex_tex_ctangle) postlinebreak.w -+#primitive.c: ctangle$(EXEEXT) luatexdir/tex/primitive.w -+# $(luatex_tex_ctangle) primitive.w -+#printing.c: ctangle$(EXEEXT) luatexdir/tex/printing.w -+# $(luatex_tex_ctangle) printing.w -+# scanning.c: ctangle$(EXEEXT) luatexdir/tex/scanning.w -+# $(luatex_tex_ctangle) scanning.w -+#stringpool.c: ctangle$(EXEEXT) luatexdir/tex/stringpool.w -+# $(luatex_tex_ctangle) stringpool.w -+#texdeffont.c: ctangle$(EXEEXT) luatexdir/tex/texdeffont.w -+# $(luatex_tex_ctangle) texdeffont.w -+# texfileio.c: ctangle$(EXEEXT) luatexdir/tex/texfileio.w -+# $(luatex_tex_ctangle) texfileio.w -+# texmath.c: ctangle$(EXEEXT) luatexdir/tex/texmath.w -+# $(luatex_tex_ctangle) texmath.w -+# texnodes.c: ctangle$(EXEEXT) luatexdir/tex/texnodes.w -+# $(luatex_tex_ctangle) texnodes.w -+#textcodes.c: ctangle$(EXEEXT) luatexdir/tex/textcodes.w -+# $(luatex_tex_ctangle) textcodes.w -+# textoken.c: ctangle$(EXEEXT) luatexdir/tex/textoken.w -+# $(luatex_tex_ctangle) textoken.w -+ -+ -+ - - dist_libluatex_sources += \ - luatexdir/tex/align.h \ - luatexdir/tex/arithmetic.h \ -+ luatexdir/tex/backend.h \ -+ luatexdir/tex/backend.c \ - luatexdir/tex/buildpage.h \ - luatexdir/tex/commands.h \ - luatexdir/tex/conditional.h \ -@@ -530,25 +560,58 @@ dist_libluatex_sources += \ - luatexdir/tex/texfileio.h \ - luatexdir/tex/texmath.h \ - luatexdir/tex/texnodes.h \ -+ luatexdir/tex/textcodes.h \ - luatexdir/tex/textoken.h \ -- luatexdir/tex/textcodes.h -+ luatexdir/tex/align.c \ -+ luatexdir/tex/arithmetic.c \ -+ luatexdir/tex/buildpage.c \ -+ luatexdir/tex/commands.c \ -+ luatexdir/tex/conditional.c \ -+ luatexdir/tex/directions.c \ -+ luatexdir/tex/dumpdata.c \ -+ luatexdir/tex/equivalents.c \ -+ luatexdir/tex/errors.c \ -+ luatexdir/tex/expand.c \ -+ luatexdir/tex/extensions.c \ -+ luatexdir/tex/filename.c \ -+ luatexdir/tex/inputstack.c \ -+ luatexdir/tex/linebreak.c \ -+ luatexdir/tex/mainbody.c \ -+ luatexdir/tex/maincontrol.c \ -+ luatexdir/tex/mathcodes.c \ -+ luatexdir/tex/memoryword.c \ -+ luatexdir/tex/mlist.c \ -+ luatexdir/tex/nesting.c \ -+ luatexdir/tex/packaging.c \ -+ luatexdir/tex/postlinebreak.c \ -+ luatexdir/tex/primitive.c \ -+ luatexdir/tex/printing.c \ -+ luatexdir/tex/scanning.c \ -+ luatexdir/tex/stringpool.c \ -+ luatexdir/tex/texdeffont.c \ -+ luatexdir/tex/texfileio.c \ -+ luatexdir/tex/texmath.c \ -+ luatexdir/tex/texnodes.c \ -+ luatexdir/tex/textcodes.c \ -+ luatexdir/tex/textoken.c -+ - - ## from luatexdir/utils - ## - luatex_utils_ctangle = $(ctangle_silent)CWEBINPUTS=$(srcdir)/luatexdir/utils $(ctangle) - --avlstuff.c: ctangle$(EXEEXT) luatexdir/utils/avlstuff.w -- $(luatex_utils_ctangle) avlstuff.w --managed-sa.c: ctangle$(EXEEXT) luatexdir/utils/managed-sa.w -- $(luatex_utils_ctangle) managed-sa.w --utils.c: ctangle$(EXEEXT) luatexdir/utils/utils.w -- $(luatex_utils_ctangle) utils.w --unistring.c: ctangle$(EXEEXT) luatexdir/utils/unistring.w -- $(luatex_utils_ctangle) unistring.w -+#avlstuff.c: ctangle$(EXEEXT) luatexdir/utils/avlstuff.w -+# $(luatex_utils_ctangle) avlstuff.w -+#managed-sa.c: ctangle$(EXEEXT) luatexdir/utils/managed-sa.w -+# $(luatex_utils_ctangle) managed-sa.w -+#utils.c: ctangle$(EXEEXT) luatexdir/utils/utils.w -+# $(luatex_utils_ctangle) utils.w -+#unistring.c: ctangle$(EXEEXT) luatexdir/utils/unistring.w -+# $(luatex_utils_ctangle) unistring.w - --libluatex_web += luatexdir/utils/avlstuff.w luatexdir/utils/managed-sa.w luatexdir/utils/utils.w luatexdir/utils/unistring.w -+#libluatex_web += luatexdir/utils/avlstuff.w luatexdir/utils/managed-sa.w luatexdir/utils/utils.w luatexdir/utils/unistring.w - --nodist_libluatex_sources += avlstuff.c managed-sa.c utils.c unistring.c -+#nodist_libluatex_sources += avlstuff.c managed-sa.c utils.c unistring.c - - dist_libluatex_sources += \ - luatexdir/utils/avl.c \ -@@ -556,7 +619,11 @@ dist_libluatex_sources += \ - luatexdir/utils/avlstuff.h \ - luatexdir/utils/managed-sa.h \ - luatexdir/utils/utils.h \ -- luatexdir/utils/unistring.h -+ luatexdir/utils/unistring.h \ -+ luatexdir/utils/avlstuff.c \ -+ luatexdir/utils/managed-sa.c \ -+ luatexdir/utils/unistring.c \ -+ luatexdir/utils/utils.c - - ## from ../synctexdir - ## -diff --git a/texk/web2c/luatexdir/am/luamisc.am b/texk/web2c/luatexdir/am/luamisc.am -index 7e874ae09..014b6eb3f 100644 ---- a/texk/web2c/luatexdir/am/luamisc.am -+++ b/texk/web2c/luatexdir/am/luamisc.am -@@ -8,9 +8,9 @@ - ## and slnunicode) - EXTRA_LIBRARIES += libluamisc.a liblua53misc.a libluajitmisc.a - --libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a libluaffi.a --liblua53misc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) liblua53socket.a liblua53ffi.a --libluajitmisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluajitsocket.a -+libluamisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluasocket.a libluaffi.a libluapplib.a -+liblua53misc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) liblua53socket.a liblua53ffi.a liblua53pplib.a -+libluajitmisc_a_DEPENDENCIES = $(ZZIPLIB_DEPEND) libluajitsocket.a libluajitpplib.a - - $(libluamisc_a_OBJECTS): $(libluamisc_a_DEPENDENCIES) - $(liblua53misc_a_OBJECTS): $(liblua53misc_a_DEPENDENCIES) -diff --git a/texk/web2c/luatexdir/am/luatex.am b/texk/web2c/luatexdir/am/luatex.am -index 4482ffe60..2fb4d64f6 100644 ---- a/texk/web2c/luatexdir/am/luatex.am -+++ b/texk/web2c/luatexdir/am/luatex.am -@@ -42,11 +42,11 @@ endif LUAJITTEX - EXTRA_PROGRAMS += luatex luatex53 luajittex - - # Force Automake to use CXXLD for linking --nodist_EXTRA_luatex_SOURCES = dummy.cxx --nodist_EXTRA_luatex53_SOURCES = dummy.cxx --nodist_EXTRA_luajittex_SOURCES = dummy.cxx -+#nodist_EXTRA_luatex_SOURCES = dummy.cxx -+#nodist_EXTRA_luatex53_SOURCES = dummy.cxx -+#nodist_EXTRA_luajittex_SOURCES = dummy.cxx - --luatex_preflags = $(AM_CPPFLAGS) $(ZLIB_INCLUDES) $(LIBPNG_INCLUDES) $(POPPLER_INCLUDES) -+luatex_preflags = $(AM_CPPFLAGS) $(ZLIB_INCLUDES) $(LIBPNG_INCLUDES) - luatex_postflags = -I$(srcdir)/libmd5 -DpdfTeX -I$(srcdir)/luatexdir -I$(srcdir)/mplibdir - luatex_postflags += -Dextra_version_info=`date +-%Y%m%d%H` - luatex_postflags += -I$(srcdir)/synctexdir -DSYNCTEX_ENGINE_H='' -@@ -64,14 +64,15 @@ luatex_LDFLAGS = -export-dynamic - luatex53_LDFLAGS = -export-dynamic - luajittex_LDFLAGS = -export-dynamic $(LUAJIT_LDEXTRA) - --luatex_postldadd = libmplibcore.a $(MPFR_LIBS) $(GMP_LIBS) --luatex_postldadd += $(ZZIPLIB_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) $(POPPLER_LIBS) -+#luatex_postldadd = libmplibcore.a $(MPFR_LIBS) $(GMP_LIBS) -+luatex_postldadd = libmplibcore.a -+luatex_postldadd += $(ZZIPLIB_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) - luatex_postldadd += $(LDADD) libmputil.a libunilib.a libmd5.a $(lua_socketlibs) - - --luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a libluaffi.a $(LUA_LIBS) $(luatex_postldadd) --luatex53_LDADD = liblua53tex.a libff.a liblua53misc.a liblua53socket.a liblua53ffi.a $(LUA_LUA53_LIBS) $(luatex_postldadd) --luajittex_LDADD = libluajittex.a libff.a libluajitmisc.a libluajitsocket.a $(LUAJIT_LIBS) $(luatex_postldadd) -+luatex_LDADD = libluatex.a libff.a libluamisc.a libluasocket.a libluaffi.a libluapplib.a $(LUA_LIBS) $(luatex_postldadd) -+luatex53_LDADD = liblua53tex.a libff.a liblua53misc.a liblua53socket.a liblua53ffi.a liblua53pplib.a $(LUA_LUA53_LIBS) $(luatex_postldadd) -+luajittex_LDADD = libluajittex.a libff.a libluajitmisc.a libluajitsocket.a libluajitpplib.a $(LUAJIT_LIBS) $(luatex_postldadd) - - luatex_depend = $(proglib) $(KPATHSEA_DEPEND) $(LIBPNG_DEPEND) libmputil.a libmd5.a - luatex_DEPENDENCIES = $(luatex_depend) libluatex.a -diff --git a/texk/web2c/luatexdir/dvi/dvigen.h b/texk/web2c/luatexdir/dvi/dvigen.h -index 49552f1d9..cfbbc6245 100644 ---- a/texk/web2c/luatexdir/dvi/dvigen.h -+++ b/texk/web2c/luatexdir/dvi/dvigen.h -@@ -21,166 +21,34 @@ - #ifndef DVIGEN_H - # define DVIGEN_H - --extern int total_pages; --extern scaled max_v; --extern scaled max_h; --extern int max_push; --extern int last_bop; --extern int dead_cycles; --extern boolean doing_leaders; --extern int oval, ocmd; --extern int lq, lr; --extern int cur_s; -- --typedef int dvi_index; /* an index into the output buffer */ -+/* todo: move initialization from mainbody to ensure_open */ - - extern int dvi_buf_size; - extern eight_bits *dvi_buf; /* 0 is unused */ --extern dvi_index half_buf; --extern dvi_index dvi_limit; --extern dvi_index dvi_ptr; --extern int dvi_offset; --extern int dvi_gone; -- --/* --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) -- --extern void dvi_swap(void); --extern void dvi_four(int x); --extern void dvi_push(void); --extern void dvi_pop(int l); --extern void out_cmd(void); --extern void dvi_font_def(internal_font_number f); -- --# 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) -- --# define location(A) varmem[(A)+1].cint -- --extern halfword down_ptr, right_ptr; /* heads of the down and right stacks */ -- --/* --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| */ -- --extern 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. --*/ -- --# 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) -- --# define billion 1000000000.0 -- --# 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) -- --extern scaledpos dvi; - --extern void dvi_special(PDF pdf, halfword p); -+/*tex Housekeeping. */ - --extern void ensure_dvi_header_written(PDF pdf); --extern void finish_dvi_file(PDF pdf, int version, int revision); -+extern void dvi_open_file(PDF pdf); -+extern void dvi_write_header(PDF pdf); -+extern void dvi_finish_file(PDF pdf, int fatal_error); -+extern void dvi_begin_page(PDF pdf); -+extern void dvi_end_page(PDF pdf); -+ -+/*tex Specific injections. */ - - extern void dvi_place_glyph(PDF pdf, internal_font_number f, int c, int ex); - extern void dvi_place_rule(PDF pdf, halfword q, scaledpos size); -+extern void dvi_special(PDF pdf, halfword p); - --extern void dvi_begin_page(PDF pdf); --extern void dvi_end_page(PDF pdf); -+/*tex List handling (and nesting). */ -+ -+extern void dvi_push_list(PDF pdf, scaledpos *saved_pos, int *saved_loc); -+extern void dvi_pop_list(PDF pdf, scaledpos *saved_pos, int *saved_loc); -+extern void dvi_set_reference_point(PDF pdf, posstructure *refpoint); -+ -+/*tex Status information used in |lstatslib|. Not that useful. */ -+ -+extern int dvi_get_status_ptr(PDF pdf); -+extern int dvi_get_status_gone(PDF pdf); - - #endif -diff --git a/texk/web2c/luatexdir/font/luatexfont.h b/texk/web2c/luatexdir/font/luatexfont.h -index 459d2092b..7016b8872 100644 ---- a/texk/web2c/luatexdir/font/luatexfont.h -+++ b/texk/web2c/luatexdir/font/luatexfont.h -@@ -1,4 +1,4 @@ --/* luatexfont.h --- General font definitions -+/* - - Copyright 2008-2013 Taco Hoekwater - -@@ -15,45 +15,36 @@ - License for more details. - - You should have received a copy of the GNU General Public License along -- with LuaTeX; if not, see . */ -+ with LuaTeX; if not, see . - -+*/ - - #ifndef LUATEXFONT_H --# define LUATEXFONT_H -- --# include "ptexlib.h" --# ifndef pdfTeX --# define pdfTeX --# include "sfnt.h" /* which wants that pdfTeX is defined */ --# undef pdfTeX --# else --# include "sfnt.h" --# endif -- --/**********************************************************************/ -- --# define ASCENT_CODE 0 --# define CAPHEIGHT_CODE 1 --# define DESCENT_CODE 2 --# define ITALIC_ANGLE_CODE 3 --# define STEMV_CODE 4 --# define XHEIGHT_CODE 5 --# define FONTBBOX1_CODE 6 --# define FONTBBOX2_CODE 7 --# define FONTBBOX3_CODE 8 --# define FONTBBOX4_CODE 9 --# define FONTNAME_CODE 10 --# define GEN_KEY_NUM (XHEIGHT_CODE + 1) --# define MAX_KEY_CODE (FONTBBOX1_CODE + 1) --# define INT_KEYS_NUM (FONTBBOX4_CODE + 1) --# define FONT_KEYS_NUM (FONTNAME_CODE + 1) -- --# define FD_FLAGS_NOT_SET_IN_MAPLINE -1 --# define FD_FLAGS_DEFAULT_EMBED 4 /* a symbol font */ --# define FD_FLAGS_DEFAULT_NON_EMBED 0x22 -- /* a nonsymbolic serif font */ -- --/**********************************************************************/ -+ -+#define LUATEXFONT_H -+ -+#include "ptexlib.h" -+#include "sfnt.h" -+ -+#define ASCENT_CODE 0 -+#define CAPHEIGHT_CODE 1 -+#define DESCENT_CODE 2 -+#define ITALIC_ANGLE_CODE 3 -+#define STEMV_CODE 4 -+#define XHEIGHT_CODE 5 -+#define FONTBBOX1_CODE 6 -+#define FONTBBOX2_CODE 7 -+#define FONTBBOX3_CODE 8 -+#define FONTBBOX4_CODE 9 -+#define FONTNAME_CODE 10 -+#define GEN_KEY_NUM (XHEIGHT_CODE + 1) -+#define MAX_KEY_CODE (FONTBBOX1_CODE + 1) -+#define INT_KEYS_NUM (FONTBBOX4_CODE + 1) -+#define FONT_KEYS_NUM (FONTNAME_CODE + 1) -+ -+#define FD_FLAGS_NOT_SET_IN_MAPLINE -1 -+#define FD_FLAGS_DEFAULT_EMBED 4 /* a symbol font */ -+#define FD_FLAGS_DEFAULT_NON_EMBED 0x22 /* a nonsymbolic serif font */ - - typedef struct { - const char *pdfname; -@@ -63,60 +54,59 @@ typedef struct { - - extern const key_entry font_key[FONT_KEYS_NUM]; - --# include "mapfile.h" -+#include "mapfile.h" - - typedef struct { -- int val; /* value */ -- boolean set; /* true if parameter has been set */ -+ int val; /* value */ -+ boolean set; /* true if parameter has been set */ - } intparm; - - typedef struct { -- int fe_objnum; /* object number */ -- char *name; /* encoding file name */ -- char **glyph_names; /* array of glyph names */ -- struct avl_table *tx_tree; /* tree of encoding positions marked as used by TeX */ -+ int fe_objnum; /* object number */ -+ char *name; /* encoding file name */ -+ char **glyph_names; /* array of glyph names */ -+ struct avl_table *tx_tree; /* tree of encoding positions marked as used by TeX */ - } fe_entry; - - typedef struct fd_entry_ { -- int fd_objnum; /* object number of the font descriptor object */ -- char *fontname; /* /FontName (without subset tag) */ -- char *subset_tag; /* 6-character subset tag */ -+ int fd_objnum; /* object number of the font descriptor object */ -+ char *fontname; /* /FontName (without subset tag) */ -+ char *subset_tag; /* 6-character subset tag */ - boolean ff_found; -- int ff_objnum; /* object number of the font program stream */ -- boolean all_glyphs; /* embed all glyphs? */ -+ int ff_objnum; /* object number of the font program stream */ -+ boolean all_glyphs; /* embed all glyphs? */ - boolean write_ttf_glyph_names; - intparm font_dim[FONT_KEYS_NUM]; -- fe_entry *fe; /* pointer to encoding structure */ -- char **builtin_glyph_names; /* builtin encoding as read from the Type1 font file */ -- fm_entry *fm; /* pointer to font map structure */ -- struct avl_table *tx_tree; /* tree of non-reencoded TeX characters marked as used */ -- struct avl_table *gl_tree; /* tree of all marked glyphs */ -- internal_font_number tex_font; /* needed for variable */ -+ fe_entry *fe; /* pointer to encoding structure */ -+ char **builtin_glyph_names; /* builtin encoding as read from the Type1 font file */ -+ fm_entry *fm; /* pointer to font map structure */ -+ struct avl_table *tx_tree; /* tree of non-reencoded TeX characters marked as used */ -+ struct avl_table *gl_tree; /* tree of all marked glyphs */ -+ internal_font_number tex_font; /* needed for variable */ - } fd_entry; - - typedef struct fo_entry_ { -- int fo_objnum; /* object number of the font dictionary */ -- internal_font_number tex_font; /* needed only for \pdffontattr{} */ -- fm_entry *fm; /* pointer to font map structure for this font dictionary */ -- fd_entry *fd; /* pointer to /FontDescriptor object structure */ -- fe_entry *fe; /* pointer to encoding structure */ -- int cw_objnum; /* object number of the font program object */ -- int first_char; /* first character used in this font */ -- int last_char; /* last character used in this font */ -- struct avl_table *tx_tree; /* tree of non-reencoded TeX characters marked as used */ -- int tounicode_objnum; /* object number of ToUnicode */ -+ int fo_objnum; /* object number of the font dictionary */ -+ internal_font_number tex_font; /* needed only for \pdffontattr{} */ -+ fm_entry *fm; /* pointer to font map structure for this font dictionary */ -+ fd_entry *fd; /* pointer to /FontDescriptor object structure */ -+ fe_entry *fe; /* pointer to encoding structure */ -+ int cw_objnum; /* object number of the font program object */ -+ int first_char; /* first character used in this font */ -+ int last_char; /* last character used in this font */ -+ struct avl_table *tx_tree; /* tree of non-reencoded TeX characters marked as used */ -+ int tounicode_objnum; /* object number of ToUnicode */ - } fo_entry; - - typedef struct { -- char *name; /* glyph name */ -- long code; /* -1 = undefined; -2 = multiple codes, stored -- as string in unicode_seq; otherwise unicode value */ -- char *unicode_seq; /* multiple unicode sequence */ -+ char *name; /* glyph name */ -+ long code; /* -1 = undefined; -2 = multiple codes, stored as string in unicode_seq; otherwise unicode value */ -+ char *unicode_seq; /* multiple unicode sequence */ - } glyph_unicode_entry; - --typedef struct glw_entry_ { /* subset glyphs for inclusion in CID-based fonts */ -- unsigned int id; /* glyph CID */ -- signed int wd; /* glyph width in 1/1000 em parts */ -+typedef struct glw_entry_ { /* subset glyphs for inclusion in CID-based fonts */ -+ unsigned int id; /* glyph CID */ -+ signed int wd; /* glyph width in 1/1000 em parts */ - } glw_entry; - - typedef struct { -@@ -124,19 +114,18 @@ typedef struct { - halfword *raster; - } chardesc; - --/**********************************************************************/ -- --# include "texfont.h" -+#include "texfont.h" - - /* tounicode.c */ -+ - int write_cid_tounicode(PDF, fo_entry *, internal_font_number); - void glyph_unicode_free(void); - void def_tounicode(str_number, str_number); - int write_tounicode(PDF, char **, char *); - - /* vfpacket.c */ --void replace_packet_fonts(internal_font_number f, int *old_fontid, -- int *new_fontid, int count); -+ -+void replace_packet_fonts(internal_font_number f, int *old_fontid, int *new_fontid, int count); - int *packet_local_fonts(internal_font_number f, int *num); - - int packet_cur_s; /* current |do_vf_packet()| recursion level */ -@@ -144,12 +133,15 @@ int packet_stack_ptr; /* pointer into |packet_stack| */ - vf_struct *new_vfstruct(void); - - /* writecff.c */ -+ - void writetype1w(PDF pdf, fd_entry * fd); - - /* writetype0.c */ -+ - void writetype0(PDF pdf, fd_entry * fd); - - /* writefont.c */ -+ - void do_pdf_font(PDF, internal_font_number); - fd_entry *lookup_fd_entry(char *); - fd_entry *new_fd_entry(internal_font_number); -@@ -157,6 +149,7 @@ void write_fontstuff(PDF); - void register_fd_entry(fd_entry * fd); - - /* writet1.c */ -+ - boolean t1_subset(char *, char *, unsigned char *); - char **load_enc_file(char *); - void writet1(PDF, fd_entry *); -@@ -164,36 +157,40 @@ void t1_free(void); - extern int t1_length1, t1_length2, t1_length3; - - /* writetype2.c */ -+ - boolean writetype2(PDF, fd_entry *); - extern unsigned long cidtogid_obj; --pdf_obj *pdf_new_stream(void); --void pdf_add_stream(pdf_obj * stream, unsigned char *buf, long len); --void pdf_release_obj(pdf_obj * stream); - unsigned long ttc_read_offset(sfnt * sfont, int ttc_idx, fd_entry *fd); - - /* writeenc.c */ -+ - fe_entry *get_fe_entry(char *); - void enc_free(void); - void write_fontencodings(PDF pdf); - - /* writettf.c */ -+ - void writettf(PDF, fd_entry *); - void writeotf(PDF, fd_entry *); - void ttf_free(void); - extern int ttf_length; - - /* pkin.c */ -+ - int readchar(boolean, chardesc *); - - /* macnames.c */ -+ - extern char notdef[]; - - /* vfovf.c */ -+ - internal_font_number letter_space_font(internal_font_number f, int e, boolean nolig); - void pdf_check_vf(internal_font_number f); - internal_font_number copy_font_info(internal_font_number f); - - /* writet3.c */ -+ - extern FILE *t3_file; - void writet3(PDF, internal_font_number); - -@@ -201,12 +198,11 @@ extern unsigned char *t3_buffer; - extern int t3_size; - extern int t3_curbyte; - --# define t3_read_file() readbinfile(t3_file, &t3_buffer, &t3_size) --# define t3_close() xfclose(t3_file, cur_file_name) --# define t3_getchar() t3_buffer[t3_curbyte++] --# define t3_eof() (t3_curbyte>t3_size) -- --# define t3_prefix(s) (!strncmp(t3_line_array, s, strlen(s))) --# define t3_putchar(c) pdfout(c) -+#define t3_read_file() readbinfile(t3_file, &t3_buffer, &t3_size) -+#define t3_close() xfclose(t3_file, cur_file_name) -+#define t3_getchar() t3_buffer[t3_curbyte++] -+#define t3_eof() (t3_curbyte>t3_size) -+#define t3_prefix(s) (!strncmp(t3_line_array, s, strlen(s))) -+#define t3_putchar(c) pdfout(c) - --#endif /* LUATEXFONT_H */ -+#endif -diff --git a/texk/web2c/luatexdir/font/mapfile.h b/texk/web2c/luatexdir/font/mapfile.h -index ad752af74..e3e0e613a 100644 ---- a/texk/web2c/luatexdir/font/mapfile.h -+++ b/texk/web2c/luatexdir/font/mapfile.h -@@ -98,13 +98,6 @@ typedef struct { - - /**********************************************************************/ - --# define FONT_SLANT_MIN -2000 --# define FONT_SLANT_MAX 2000 --# define FONT_EXTEND_MIN -5000 --# define FONT_EXTEND_MAX 5000 -- --/**********************************************************************/ -- - fm_entry *getfontmap(char *tfm_name); - void fm_free(void); - ff_entry *check_ff_exist(char *, boolean); -diff --git a/texk/web2c/luatexdir/font/sfnt.h b/texk/web2c/luatexdir/font/sfnt.h -index dce4248e9..602a0805f 100644 ---- a/texk/web2c/luatexdir/font/sfnt.h -+++ b/texk/web2c/luatexdir/font/sfnt.h -@@ -28,11 +28,12 @@ - # endif /* HAVE_CONFIG_H_ */ - - /* Data Types as described in Apple's TTRefMan */ --typedef unsigned char BYTE; -+ -+/*typedef unsigned char BYTE;*/ /* defined in pdfgen.h */ - typedef signed char ICHAR; - typedef unsigned short USHORT; - typedef signed short SHORT; --typedef unsigned long ULONG; -+/*typedef unsigned long ULONG;*//* defined in pdfgen.h */ - typedef signed long LONG; - typedef unsigned long Fixed; /* 16.16-bit signed fixed-point number */ - typedef short FWord; -@@ -70,40 +71,16 @@ struct sfnt_table_directory { - typedef struct { - int type; - struct sfnt_table_directory *directory; --# ifdef XETEX -- FT_Face ft_face; -- long loc; --# elif defined(pdfTeX) - BYTE *buffer; - long buflen; - long loc; --# else -- FILE *stream; --# endif - } sfnt; - - /* Convert sfnt "fixed" type to double */ -+ - # define fixed(a) ((double)((a)%0x10000L)/(double)(0x10000L) + \ - (a)/0x10000L - (((a)/0x10000L > 0x7fffL) ? 0x10000L : 0)) - --# ifdef XETEX --UNSIGNED_BYTE ft_unsigned_byte(sfnt * f); --SIGNED_BYTE ft_signed_byte(sfnt * f); --UNSIGNED_PAIR ft_unsigned_pair(sfnt * f); --SIGNED_PAIR ft_signed_pair(sfnt * f); --UNSIGNED_QUAD ft_unsigned_quad(sfnt * f); --unsigned long ft_read(unsigned char *buf, unsigned long len, sfnt * f); -- --# define sfnt_get_byte(s) ((BYTE) ft_unsigned_byte(s)) --# define sfnt_get_char(s) ((ICHAR) ft_signed_byte (s)) --# define sfnt_get_ushort(s) ((USHORT) ft_unsigned_pair(s)) --# define sfnt_get_short(s) ((SHORT) ft_signed_pair (s)) --# define sfnt_get_ulong(s) ((ULONG) ft_unsigned_quad(s)) --# define sfnt_get_long(s) ((LONG) ft_signed_quad (s)) -- --# define sfnt_seek_set(s,o) (s)->loc = (o) --# define sfnt_read(b,l,s) ft_read((b), (l), (s)) --# elif defined(pdfTeX) - BYTE get_unsigned_byte(sfnt * f); - ICHAR get_signed_byte(sfnt * f); - USHORT get_unsigned_pair(sfnt * f); -@@ -111,45 +88,28 @@ SHORT get_signed_pair(sfnt * f); - ULONG get_unsigned_quad(sfnt * f); - int do_sfnt_read(unsigned char *dest, int len, sfnt * f); - --# define sfnt_get_byte(s) ((BYTE) get_unsigned_byte(s)) --# define sfnt_get_char(s) ((ICHAR) get_signed_byte (s)) --# define sfnt_get_ushort(s) ((USHORT) get_unsigned_pair(s)) --# define sfnt_get_short(s) ((SHORT) get_signed_pair (s)) --# define sfnt_get_ulong(s) ((ULONG) get_unsigned_quad(s)) --# define sfnt_get_long(s) ((LONG) get_signed_quad (s)) -- --# define sfnt_seek_set(s,o) (s)->loc = (o) --# define sfnt_read(b,l,s) do_sfnt_read((b), (l), (s)) --# else --/* get_***_*** from numbers.h */ --# define sfnt_get_byte(s) ((BYTE) get_unsigned_byte((s)->stream)) --# define sfnt_get_char(s) ((ICHAR) get_signed_byte ((s)->stream)) --# define sfnt_get_ushort(s) ((USHORT) get_unsigned_pair((s)->stream)) --# define sfnt_get_short(s) ((SHORT) get_signed_pair ((s)->stream)) --# define sfnt_get_ulong(s) ((ULONG) get_unsigned_quad((s)->stream)) --# define sfnt_get_long(s) ((LONG) get_signed_quad ((s)->stream)) -- --# define sfnt_seek_set(s,o) seek_absolute((s)->stream, (o)) --# define sfnt_read(b,l,s) fread((b), 1, (l), (s)->stream) --# endif -+#define sfnt_get_byte(s) ((BYTE) get_unsigned_byte(s)) -+#define sfnt_get_char(s) ((ICHAR) get_signed_byte (s)) -+#define sfnt_get_ushort(s) ((USHORT) get_unsigned_pair(s)) -+#define sfnt_get_short(s) ((SHORT) get_signed_pair (s)) -+#define sfnt_get_ulong(s) ((ULONG) get_unsigned_quad(s)) -+#define sfnt_get_long(s) ((LONG) get_signed_quad (s)) -+ -+#define sfnt_seek_set(s,o) (s)->loc = (o) -+#define sfnt_read(b,l,s) do_sfnt_read((b), (l), (s)) - - extern int put_big_endian(void *s, LONG q, int n); - --# define sfnt_put_ushort(s,v) put_big_endian((s), v, 2); --# define sfnt_put_short(s,v) put_big_endian((s), v, 2); --# define sfnt_put_ulong(s,v) put_big_endian((s), v, 4); --# define sfnt_put_long(s,v) put_big_endian((s), v, 4); -+#define sfnt_put_ushort(s,v) put_big_endian((s), v, 2); -+#define sfnt_put_short(s,v) put_big_endian((s), v, 2); -+#define sfnt_put_ulong(s,v) put_big_endian((s), v, 4); -+#define sfnt_put_long(s,v) put_big_endian((s), v, 4); - --# ifdef XETEX --extern sfnt *sfnt_open(FT_Face face, int accept_types); --# elif defined(pdfTeX) - extern sfnt *sfnt_open(unsigned char *buffer, int buflen); --# else --extern sfnt *sfnt_open(FILE * fp); --# endif - extern void sfnt_close(sfnt * sfont); - - /* table directory */ -+ - extern int sfnt_read_table_directory(sfnt * sfont, ULONG offset); - extern ULONG sfnt_find_table_len(sfnt * sfont, const char *tag); - extern ULONG sfnt_find_table_pos(sfnt * sfont, const char *tag); -@@ -159,18 +119,10 @@ extern void sfnt_set_table(sfnt * sfont, - const char *tag, void *data, ULONG length); - extern int sfnt_require_table(sfnt * sfont, const char *tag, int must_exist); - --# ifdef pdfTeX --typedef struct { -- ULONG length; -- BYTE *data; --} pdf_obj; -- --# define ASSERT(a) assert(a) --# define RELEASE(a) free(a) --# define NEW(a,b) xmalloc((unsigned)((unsigned)(a)*sizeof(b))) --# define RENEW(a,b,c) xrealloc(a, (unsigned)((unsigned)(b)*sizeof(c))) -- --# endif -+#define ASSERT(a) assert(a) -+#define RELEASE(a) free(a) -+#define NEW(a,b) xmalloc((unsigned)((unsigned)(a)*sizeof(b))) -+#define RENEW(a,b,c) xrealloc(a, (unsigned)((unsigned)(b)*sizeof(c))) - - extern pdf_obj *sfnt_create_FontFile_stream(sfnt * sfont); - -diff --git a/texk/web2c/luatexdir/font/texfont.h b/texk/web2c/luatexdir/font/texfont.h -index 75beafe66..2622b7a14 100644 ---- a/texk/web2c/luatexdir/font/texfont.h -+++ b/texk/web2c/luatexdir/font/texfont.h -@@ -32,6 +32,17 @@ - - # define pointer halfword - -+# define FONT_SLANT_MIN -2000 -+# define FONT_SLANT_MAX 2000 -+# define FONT_EXTEND_MIN -5000 -+# define FONT_EXTEND_MAX 5000 -+# define FONT_SQUEEZE_MIN -5000 -+# define FONT_SQUEEZE_MAX 5000 -+# define FONT_MODE_MIN 0 -+# define FONT_MODE_MAX 3 /* pdf values */ -+# define FONT_WIDTH_MIN 0 -+# define FONT_WIDTH_MAX 5000 -+ - /* these are dumped en block, so they need endianness tests */ - - typedef struct liginfo { -@@ -141,6 +152,9 @@ typedef struct texfont { - boolean _font_oldmath; /* default to false when MathConstants seen */ - int _font_slant; /* a slant in ppt */ - int _font_extend; /* an extension in ppt, or 1000 */ -+ int _font_squeeze; /* an extension in ppt, or 1000 */ -+ int _font_width; -+ int _font_mode; - int font_max_shrink; - int font_max_stretch; - int _font_step; /* amount of one step of expansion */ -@@ -329,6 +343,15 @@ boolean cmp_font_area(int, str_number); - # define font_extend(a) font_tables[a]->_font_extend - # define set_font_extend(a,b) font_extend(a) = b - -+# define font_squeeze(a) font_tables[a]->_font_squeeze -+# define set_font_squeeze(a,b) font_squeeze(a) = b -+ -+# define font_width(a) font_tables[a]->_font_width -+# define set_font_width(a,b) font_width(a) = b -+ -+# define font_mode(a) font_tables[a]->_font_mode -+# define set_font_mode(a,b) font_mode(a) = b -+ - # define font_shrink(a) font_tables[a]->_font_shrink - # define set_font_shrink(a,b) font_shrink(a) = b - -@@ -625,7 +648,7 @@ typedef enum { packet_char_code, - packet_scale_code, - packet_lua_code, - packet_pdf_code, -- packet_pdf_mode, -+ packet_pdf_mode - } packet_command_codes; - - extern scaled store_scaled_f(scaled sq, int fw); -diff --git a/texk/web2c/luatexdir/image/epdf.h b/texk/web2c/luatexdir/image/epdf.h -index 57bb2e39a..9c32c06b7 100644 ---- a/texk/web2c/luatexdir/image/epdf.h -+++ b/texk/web2c/luatexdir/image/epdf.h -@@ -18,15 +18,19 @@ - with LuaTeX; if not, see . */ - - --// this is the common header file for C++ sources pdftoepdf.cc and lepdflib.cc -+/* this is the common header file for C++ sources pdftoepdf.c and lepdflib.c */ - - #ifndef EPDF_H - # define EPDF_H --extern "C" { -+ -+/*extern "C" {*/ -+ - #ifdef HAVE_CONFIG_H - #include - #endif --} -+ -+/*}*/ -+ - # include - # include - # include -@@ -35,41 +39,22 @@ extern "C" { - # include - # include - # include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include -- --extern "C" { -+ -+/*extern "C" { */ - - # include - -- extern char *xstrdup(const char *); -+extern char *xstrdup(const char *); - -- typedef enum { FE_FAIL, FE_RETURN_NULL } file_error_mode; -+typedef enum { FE_FAIL, FE_RETURN_NULL } file_error_mode; - - /* the following code is extremly ugly but needed for including web2c/config.h */ - -- typedef const char *const_string; /* including kpathsea/types.h doesn't work on some systems */ -+typedef const char *const_string; /* including kpathsea/types.h doesn't work on some systems */ - - # define KPATHSEA_CONFIG_H /* avoid including other kpathsea header files */ -- /* from web2c/config.h */ -+ -+/* from web2c/config.h */ - - # ifdef CONFIG_H /* CONFIG_H has been defined by some xpdf */ - # undef CONFIG_H /* header file */ -@@ -84,117 +69,105 @@ extern "C" { - # include "lua.h" - # include "lauxlib.h" - -- /* pdfgen.w */ -- extern int ten_pow[10]; -- __attribute__ ((format(printf, 2, 3))) -- extern void pdf_printf(PDF, const char *fmt, ...); -- extern void pdf_begin_obj(PDF, int, int); -- extern void pdf_end_obj(PDF); -- extern void pdf_begin_dict(PDF); -- extern void pdf_end_dict(PDF); -- extern void pdf_begin_array(PDF); -- extern void pdf_end_array(PDF); -- extern void pdf_add_null(PDF); -- extern void pdf_add_bool(PDF, int i); -- extern void pdf_add_int(PDF, int i); -- extern void pdf_add_ref(PDF, int num); -- extern void pdf_add_name(PDF, const char *name); -- extern void pdf_dict_add_streaminfo(PDF); -- extern void pdf_begin_stream(PDF); -- extern void pdf_end_stream(PDF); -- extern void pdf_room(PDF, int); -- extern void pdf_out_block(PDF pdf, const char *s, size_t n); -- -- extern void pdf_dict_add_int(PDF, const char *key, int i); -- extern void pdf_dict_add_ref(PDF, const char *key, int num); -- extern void pdf_dict_add_name(PDF, const char *key, const char *val); -- extern void pdf_dict_add_streaminfo(PDF); -- --# define pdf_out(pdf, A) do { pdf_room(pdf, 1); *(pdf->buf->p++) = A; } while (0) --# define pdf_quick_out(pdf,A) *(pdf->buf->p++)=(unsigned char)(A) -+# include "luapplib/pplib.h" -+ -+/* pdfgen.w */ -+ -+extern int ten_pow[10]; -+__attribute__ ((format(printf, 2, 3))) -+extern void pdf_printf(PDF, const char *fmt, ...); -+extern void pdf_begin_obj(PDF, int, int); -+extern void pdf_end_obj(PDF); -+extern void pdf_begin_dict(PDF); -+extern void pdf_end_dict(PDF); -+extern void pdf_begin_array(PDF); -+extern void pdf_end_array(PDF); -+extern void pdf_add_null(PDF); -+extern void pdf_add_bool(PDF, int i); -+extern void pdf_add_int(PDF, int i); -+extern void pdf_add_real(PDF, double d); -+extern void pdf_add_ref(PDF, int num); -+extern void pdf_add_name(PDF, const char *name); -+extern void pdf_dict_add_streaminfo(PDF); -+extern void pdf_begin_stream(PDF); -+extern void pdf_end_stream(PDF); -+extern void pdf_room(PDF, int); -+extern void pdf_out_block(PDF pdf, const char *s, size_t n); -+ -+extern void pdf_dict_add_int(PDF, const char *key, int i); -+extern void pdf_dict_add_ref(PDF, const char *key, int num); -+extern void pdf_dict_add_name(PDF, const char *key, const char *val); -+extern void pdf_dict_add_streaminfo(PDF); -+ -+/* Conflict with pdfgen.h */ -+/*# define pdf_out(pdf, A) do { pdf_room(pdf, 1); *(pdf->buf->p++) = A; } while (0)*/ -+/*# define pdf_quick_out(pdf,A) *(pdf->buf->p++)=(unsigned char)(A) */ -+ - # define pdf_puts(pdf, s) pdf_out_block((pdf), (s), strlen(s)) - -- /* pdfpage.w */ -- extern void print_pdffloat(PDF pdf, pdffloat f); -+/* pdfpage.w */ - -- /* pdftables.w */ -- extern int pdf_create_obj(PDF pdf, int t, int i); -+extern void print_pdffloat(PDF pdf, pdffloat f); - -- /* pdftoepdf.cc */ -- extern void read_pdf_info(image_dict *); -- extern void flush_pdf_info(image_dict *); -- extern void write_epdf(PDF, image_dict *, int suppress_optional_info); -- extern void unrefPdfDocument(char *); -- extern void unrefMemStreamPdfDocument(char *); -- extern void epdf_free(void); -- extern void copyReal(PDF pdf, double d); -+/* pdftables.w */ - -- /* writeimg.w */ -- extern void pdf_dict_add_img_filename(PDF pdf, image_dict * idict); -+extern int pdf_create_obj(PDF pdf, int t, int i); - -- /* utils.w */ -- extern char *convertStringToPDFString(char *in, int len); -+/* pdftoepdf.c */ - -- /* lepdflib.w */ -- int luaopen_epdf(lua_State * L); -+extern void read_pdf_info(image_dict *); -+extern void flush_pdf_info(image_dict *); - --# include "luatex-common.h" -+extern void write_epdf(PDF, image_dict *, int suppress_optional_info); -+extern int write_epdf_object(PDF, image_dict *, int n); - --}; -+extern void unrefPdfDocument(char *); -+extern void unrefMemStreamPdfDocument(char *); - --/**********************************************************************/ -- --// PdfObject encapsulates the xpdf Object type, --// and properly frees its resources on destruction. --// Use obj-> to access members of the Object, --// and &obj to get a pointer to the object. --// It is no longer necessary to call Object::free explicitely. -- --# if 0 --// PdfObject is replaced by xpdf's Object type, with manual obj.free() -- --// *INDENT-OFF* --class PdfObject { -- public: -- PdfObject() { // nothing -- } -- ~PdfObject() { -- iObject.free(); -- } -- Object *operator->() { -- return &iObject; -- } -- Object *operator&() { -- return &iObject; -- } -- private: // no copying or assigning -- PdfObject(const PdfObject &); -- void operator=(const PdfObject &); -- public: -- Object iObject; --}; --// *INDENT-ON* --# endif -+extern void epdf_free(void); -+ -+/* writeimg.w */ - --/**********************************************************************/ -+extern void pdf_dict_add_img_filename(PDF pdf, image_dict * idict); -+ -+/* utils.w */ -+ -+/*extern char *convertStringToPDFString(const char *in, int len);*/ -+ -+/* lepdflib.w */ -+ -+int luaopen_epdf(lua_State * L); -+ -+# include "luatex-common.h" -+ -+/*}*/ -+ -+typedef struct InObj InObj; - - struct InObj { -- Ref ref; // ref in original PDF -- int num; // new object number in output PDF -- InObj *next; // next entry in list of indirect objects --}; -+ ppref *ref; /* ref in original PDF */ -+ int num; /* new object number in output PDF */ -+ InObj *next; /* next entry in list of indirect objects */ -+} ; -+ -+ -+typedef struct avl_table avl_table; - - struct PdfDocument { -- char *file_path; // full file name including path -- char *checksum; // for reopening -- PDFDoc *doc; -- InObj *inObjList; // temporary linked list -- avl_table *ObjMapTree; // permanent over luatex run -- unsigned int occurences; // number of references to the PdfDocument; it can be deleted when occurences == 0 -- unsigned int pc; // counter to track PDFDoc generation or deletion -+ char *file_path; /* full file name including path */ -+ char *checksum; /* for reopening */ -+ ppdoc *pdfe; -+ InObj *inObjList; /* temporary linked list */ -+ avl_table *ObjMapTree; /* permanent over luatex run */ -+ int is_mem; -+ char *memstream; -+ unsigned int occurences; /* number of references to the PdfDocument; it can be deleted when occurences == 0 */ -+ unsigned int pc; /* counter to track PDFDoc generation or deletion */ - }; - --PdfDocument *refPdfDocument(const char *file_path, file_error_mode fe); -+typedef struct PdfDocument PdfDocument; -+ -+PdfDocument *refPdfDocument(const char *file_path, file_error_mode fe, const char *userpassword, const char *ownerpassword); - - PdfDocument *refMemStreamPdfDocument(char *docstream, unsigned long long streamsize, const char *file_id); - -diff --git a/texk/web2c/luatexdir/image/image.h b/texk/web2c/luatexdir/image/image.h -index 7c79723f1..985f53d06 100644 ---- a/texk/web2c/luatexdir/image/image.h -+++ b/texk/web2c/luatexdir/image/image.h -@@ -39,6 +39,7 @@ extern scaled one_hundred_bp; /* from pdfgen.w */ - - typedef struct { - char *stream; -+ size_t size; - } pdf_stream_struct; - - typedef struct { -@@ -116,6 +117,8 @@ typedef struct { - char *filepath; /* full file path after kpathsea */ - char *attr; /* additional image dict entries */ - FILE *file; -+ char *userpassword; -+ char *ownerpassword; - imgtype_e image_type; - int procset; /* /ProcSet flags */ - int color_depth; /* color depth */ -@@ -125,6 +128,7 @@ typedef struct { - int flags; - int luaref ; - boolean keepopen; -+ boolean nolength; - int errorlevel; - int pdfmajorversion; - int pdfminorversion; -@@ -159,6 +163,8 @@ typedef struct { - # define img_pagename(N) ((N)->pagename) - # define img_filename(N) ((N)->filename) - # define img_visiblefilename(N) ((N)->visiblefilename) -+# define img_userpassword(N) ((N)->userpassword) -+# define img_ownerpassword(N) ((N)->ownerpassword) - # define img_filepath(N) ((N)->filepath) - # define img_attr(N) ((N)->attr) - # define img_file(N) ((N)->file) -@@ -171,12 +177,14 @@ typedef struct { - # define img_flags(N) ((N)->flags) - # define img_luaref(N) ((N)->luaref) - # define img_keepopen(N) ((N)->keepopen) -+# define img_nolength(N) ((N)->nolength) - # define img_errorlevel(N) ((N)->errorlevel) - # define img_pdfmajorversion(N) ((N)->pdfmajorversion) - # define img_pdfminorversion(N) ((N)->pdfminorversion) - - # define img_pdfstream_ptr(N) ((N)->img_struct.pdfstream) - # define img_pdfstream_stream(N) ((N)->img_struct.pdfstream->stream) -+# define img_pdfstream_size(N) ((N)->img_struct.pdfstream->size) - - # define img_png_ptr(N) ((N)->img_struct.png) - # define img_png_png_ptr(N) ((N)->img_struct.png->png_ptr) -diff --git a/texk/web2c/luatexdir/image/pdftoepdf.h b/texk/web2c/luatexdir/image/pdftoepdf.h -index 0a8ef942c..cc8f0e150 100644 ---- a/texk/web2c/luatexdir/image/pdftoepdf.h -+++ b/texk/web2c/luatexdir/image/pdftoepdf.h -@@ -30,12 +30,7 @@ void flush_pdf_info(image_dict *); - void unrefPdfDocument(char *); - void unrefMemStreamPdfDocument(char *); - void write_epdf(PDF, image_dict *, int suppress_optional_info); --void epdf_check_mem(void); --void copyReal(PDF pdf, double d); -- --int poppler_version_major(void); --int poppler_version_minor(void); --int poppler_version_micro(void); -+int write_epdf_object(PDF, image_dict *, int n); - - /* epdf.c --- this should go in an own header file */ - -diff --git a/texk/web2c/luatexdir/image/writeimg.h b/texk/web2c/luatexdir/image/writeimg.h -index 46c42d265..dc86648e2 100644 ---- a/texk/web2c/luatexdir/image/writeimg.h -+++ b/texk/web2c/luatexdir/image/writeimg.h -@@ -38,6 +38,7 @@ void scan_pdfrefximage(PDF pdf); - scaled_whd tex_scale(scaled_whd nat, scaled_whd tex); - scaled_whd scale_img(image_dict *, scaled_whd, int); - void write_img(PDF, image_dict *); -+int write_img_object(PDF, image_dict *, int n); - void pdf_write_image(PDF pdf, int n); - void check_pdfstream_dict(image_dict *); - void write_pdfstream(PDF, image_dict *); -diff --git a/texk/web2c/luatexdir/lua/lcallbacklib.c b/texk/web2c/luatexdir/lua/lcallbacklib.c -index f3ff58a75..32cf66302 100644 ---- a/texk/web2c/luatexdir/lua/lcallbacklib.c -+++ b/texk/web2c/luatexdir/lua/lcallbacklib.c -@@ -22,6 +22,9 @@ - - int callback_count = 0; - int saved_callback_count = 0; -+int direct_callback_count = 0; -+int late_callback_count = 0; -+int function_callback_count = 0; - - int callback_set[total_callbacks] = { 0 }; - -@@ -74,7 +77,12 @@ static const char *const callbacknames[] = { - "call_edit", - "build_page_insert", - "glyph_stream_provider", -- "finish_synctex_callback", -+ "font_descriptor_objnum_provider", -+ "finish_synctex", -+ "wrapup_run", -+ "new_graf", -+ "page_objnum_provider", -+ "make_extensible", - NULL - }; - -@@ -207,7 +215,6 @@ int run_saved_callback(int r, const char *name, const char *values, ...) - lua_rawget(Luas, -2); - if (lua_isfunction(Luas, -1)) { - saved_callback_count++; -- callback_count++; - ret = do_run_callback(2, values, args); - } - va_end(args); -diff --git a/texk/web2c/luatexdir/lua/lepdflib.cc b/texk/web2c/luatexdir/lua/lepdflib.cc -index 32bcdab01..ea8ed96b0 100644 ---- a/texk/web2c/luatexdir/lua/lepdflib.cc -+++ b/texk/web2c/luatexdir/lua/lepdflib.cc -@@ -17,3627 +17,3 @@ - - You should have received a copy of the GNU General Public License along - with LuaTeX; if not, see . */ -- -- --#include "image/epdf.h" -- --// 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. -- --// define DEBUG -- --//********************************************************************** --// TODO: add more poppler functions (many are still missing) -- --//********************************************************************** --// objects allocated by poppler may not be deleted in the lepdflib -- --typedef enum { ALLOC_POPPLER, ALLOC_LEPDF } alloctype; -- --typedef struct { -- void *d; -- alloctype atype; // was it allocated by poppler or the lepdflib.cc? -- PdfDocument *pd; // reference to PdfDocument, or NULL -- unsigned long pc; // counter to detect PDFDoc change --} udstruct; -- --static const char *ErrorCodeNames[] = { "None", "OpenFile", "BadCatalog", -- "Damaged", "Encrypted", "HighlightFile", "BadPrinter", "Printing", -- "Permission", "BadPageNum", "FileIO", NULL --}; -- --//********************************************************************** -- --#define M_Annot "epdf.Annot" /* ls-hh: epdf.* gives better protection in registry */ --#define M_Annots "epdf.Annots" --#define M_Array "epdf.Array" --#define M_Catalog "epdf.Catalog" --#define M_Dict "epdf.Dict" --#define M_EmbFile "epdf.EmbFile" --#define M_FileSpec "epdf.FileSpec" --#define M_GooString "epdf.GooString" --#define M_LinkDest "epdf.LinkDest" --#define M_Link "epdf.Link" --#define M_Links "epdf.Links" --#define M_Object "epdf.Object" --#define M_Page "epdf.Page" --#define M_PDFDoc "epdf.PDFDoc" --#define M_PDFRectangle "epdf.PDFRectangle" --#define M_Ref "epdf.Ref" --#define M_Stream "epdf.Stream" --#define M_StructElement "epdf.StructElement" --#define M_Attribute "epdf.Attribute" --#define M_TextSpan "epdf.TextSpan" --#define M_StructTreeRoot "epdf.StructTreeRoot" --#define M_XRefEntry "epdf.XRefEntry" --#define M_XRef "epdf.XRef" -- --//********************************************************************** -- --#define new_poppler_userdata(type) \ --static udstruct *new_##type##_userdata(lua_State * L) \ --{ \ -- udstruct *a; \ -- a = (udstruct *) lua_newuserdata(L, sizeof(udstruct)); /* udstruct ... */ \ -- a->atype = ALLOC_POPPLER; \ -- luaL_getmetatable(L, M_##type); /* m udstruct ... */ \ -- lua_setmetatable(L, -2); /* udstruct ... */ \ -- return a; \ --} -- --new_poppler_userdata(PDFDoc); -- --new_poppler_userdata(Annot); --new_poppler_userdata(Array); --new_poppler_userdata(Catalog); --new_poppler_userdata(Dict); --new_poppler_userdata(EmbFile); --new_poppler_userdata(FileSpec); --new_poppler_userdata(LinkDest); --new_poppler_userdata(Links); --new_poppler_userdata(Object); --new_poppler_userdata(Page); --new_poppler_userdata(PDFRectangle); --new_poppler_userdata(Ref); --new_poppler_userdata(Stream); --new_poppler_userdata(StructElement); --new_poppler_userdata(Attribute); --new_poppler_userdata(TextSpan); --new_poppler_userdata(StructTreeRoot); --new_poppler_userdata(XRef); -- --//********************************************************************** -- --static void pdfdoc_changed_error(lua_State * L) --{ -- luaL_error(L, "PDFDoc changed or gone"); --} -- --static void pdfdoc_differs_error(lua_State * L) --{ -- luaL_error(L, "PDFDoc differs between arguments"); --} -- --//********************************************************************** -- --static int l_open_PDFDoc(lua_State * L) --{ -- const char *file_path; -- udstruct *uout; -- PdfDocument *d; -- file_path = luaL_checkstring(L, 1); // path -- d = refPdfDocument(file_path, FE_RETURN_NULL); -- if (d == NULL) -- lua_pushnil(L); -- else { -- if (!(globalParams)) // globalParams could be already created -- globalParams = new GlobalParams(); -- uout = new_PDFDoc_userdata(L); -- uout->d = d; -- uout->atype = ALLOC_LEPDF; -- uout->pc = d->pc; -- uout->pd = d; -- } -- return 1; // doc path --} -- --static int l_open_MemStreamPDFDoc(lua_State * L) --{ -- const char *docstream = NULL; -- char *docstream_usr = NULL ; -- const char *file_id; -- unsigned long long stream_size; -- udstruct *uout; -- PdfDocument *d; -- switch (lua_type(L, 1)) { -- case LUA_TSTRING: -- docstream = luaL_checkstring(L, 1); // stream as Lua string -- break; -- case LUA_TLIGHTUSERDATA: -- docstream = (const char *) lua_touserdata(L, 1); // stream as sequence of bytes -- break; -- default: -- luaL_error(L, "bad argument: string or lightuserdata expected"); -- } -- if (docstream==NULL) -- luaL_error(L, "bad document"); -- stream_size = (unsigned long long) luaL_checkint(L, 2);// size of the stream -- file_id = luaL_checkstring(L, 3); // a symbolic name for this stream, mandatory -- if (file_id == NULL) -- luaL_error(L, "PDFDoc has an invalid id"); -- if (strlen(file_id) >STREAM_FILE_ID_LEN ) // a limit to the length of the string -- luaL_error(L, "PDFDoc has a too long id"); -- docstream_usr = (char *)gmalloc((unsigned) (stream_size + 1)); -- if (!docstream_usr) -- luaL_error(L, "no room for PDFDoc"); -- memcpy(docstream_usr, docstream, (stream_size + 1)); -- docstream_usr[stream_size]='\0'; -- d = refMemStreamPdfDocument(docstream_usr, stream_size, file_id); -- if (d == NULL) { -- lua_pushnil(L); -- lua_pushnil(L); -- lua_pushnil(L); -- } -- else if (d->file_path == NULL ) { -- lua_pushnil(L); -- lua_pushnil(L); -- lua_pushnil(L); -- } -- else { -- if (!(globalParams)) // globalParams could be already created -- globalParams = new GlobalParams(); -- uout = new_PDFDoc_userdata(L); -- uout->d = d; -- uout->atype = ALLOC_LEPDF; -- uout->pc = d->pc; -- uout->pd = d; -- lua_pushstring(L,d->file_path); -- lua_pushstring(L,STREAM_URI); -- } -- return 3; // stream, stream_id, stream_uri --} -- -- -- -- --static int l_new_Array(lua_State * L) --{ -- udstruct *uxref, *uout; -- uxref = (udstruct *) luaL_checkudata(L, 1, M_XRef); -- if (uxref->pd != NULL && uxref->pd->pc != uxref->pc) -- pdfdoc_changed_error(L); -- uout = new_Array_userdata(L); -- uout->d = new Array((XRef *) uxref->d); // automatic init to length 0 -- uout->atype = ALLOC_LEPDF; -- uout->pc = uxref->pc; -- uout->pd = uxref->pd; -- return 1; --} -- --static int l_new_Attribute(lua_State * L) --{ -- Attribute::Type t; -- const char *n; -- int nlen; -- udstruct *uobj, *uout; -- -- if (lua_type(L,1)==LUA_TNUMBER) { -- uobj = (udstruct *) luaL_checkudata(L, 2, M_Object); -- if (uobj->pd != NULL && uobj->pd->pc != uobj->pc) -- pdfdoc_changed_error(L); -- t = (Attribute::Type) luaL_checkint(L, 1); -- uout = new_Attribute_userdata(L); -- uout->d = new Attribute(t, (Object *)uobj->d); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uobj->pc; -- uout->pd = uobj->pd; -- -- } else if (lua_type(L,1)==LUA_TSTRING) { -- n = luaL_checkstring(L,1); -- nlen = luaL_checkint(L,2); -- uobj = (udstruct *) luaL_checkudata(L, 3, M_Object); -- if (uobj->pd != NULL && uobj->pd->pc != uobj->pc) -- pdfdoc_changed_error(L); -- uout = new_Attribute_userdata(L); -- uout->d = new Attribute(n, nlen, (Object *)uobj->d); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uobj->pc; -- uout->pd = uobj->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --#define ATTRIBUTE_TYPE_ENTRY(name) \ -- lua_pushstring(L, #name); \ -- lua_pushinteger(L, Attribute::name); \ -- lua_settable(L,-3) -- -- --#define OBJECT_TYPE(name) \ -- lua_pushstring(L, #name); \ -- lua_pushinteger(L, (int)name); \ -- lua_settable(L,-3) -- -- --#define STRUCTELEMENT_TYPE_ENTRY(name) \ -- lua_pushstring(L, #name); \ -- lua_pushinteger(L, StructElement::name); \ -- lua_settable(L,-3) -- -- --static int l_Attribute_Type(lua_State * L) { -- lua_createtable (L, 0, 42); -- ATTRIBUTE_TYPE_ENTRY(BBox); -- ATTRIBUTE_TYPE_ENTRY(BackgroundColor); -- ATTRIBUTE_TYPE_ENTRY(BorderColor); -- ATTRIBUTE_TYPE_ENTRY(BorderThickness); -- ATTRIBUTE_TYPE_ENTRY(Color); -- ATTRIBUTE_TYPE_ENTRY(ColumnGap); -- ATTRIBUTE_TYPE_ENTRY(ColumnWidths); -- ATTRIBUTE_TYPE_ENTRY(Desc); -- ATTRIBUTE_TYPE_ENTRY(Role); -- ATTRIBUTE_TYPE_ENTRY(TextDecorationColor); -- ATTRIBUTE_TYPE_ENTRY(TextDecorationThickness); -- ATTRIBUTE_TYPE_ENTRY(BaselineShift); -- ATTRIBUTE_TYPE_ENTRY(BlockAlign); -- ATTRIBUTE_TYPE_ENTRY(BorderStyle); -- ATTRIBUTE_TYPE_ENTRY(ColSpan); -- ATTRIBUTE_TYPE_ENTRY(ColumnCount); -- ATTRIBUTE_TYPE_ENTRY(EndIndent); -- ATTRIBUTE_TYPE_ENTRY(GlyphOrientationVertical); -- ATTRIBUTE_TYPE_ENTRY(Headers); -- ATTRIBUTE_TYPE_ENTRY(Height); -- ATTRIBUTE_TYPE_ENTRY(InlineAlign); -- ATTRIBUTE_TYPE_ENTRY(LineHeight); -- ATTRIBUTE_TYPE_ENTRY(ListNumbering); -- ATTRIBUTE_TYPE_ENTRY(Padding); -- ATTRIBUTE_TYPE_ENTRY(Placement); -- ATTRIBUTE_TYPE_ENTRY(RowSpan); -- ATTRIBUTE_TYPE_ENTRY(RubyAlign); -- ATTRIBUTE_TYPE_ENTRY(RubyPosition); -- ATTRIBUTE_TYPE_ENTRY(Scope); -- ATTRIBUTE_TYPE_ENTRY(SpaceAfter); -- ATTRIBUTE_TYPE_ENTRY(SpaceBefore); -- ATTRIBUTE_TYPE_ENTRY(StartIndent); -- ATTRIBUTE_TYPE_ENTRY(Summary); -- ATTRIBUTE_TYPE_ENTRY(TBorderStyle); -- ATTRIBUTE_TYPE_ENTRY(TPadding); -- ATTRIBUTE_TYPE_ENTRY(TextAlign); -- ATTRIBUTE_TYPE_ENTRY(TextDecorationType); -- ATTRIBUTE_TYPE_ENTRY(TextIndent); -- ATTRIBUTE_TYPE_ENTRY(Width); -- ATTRIBUTE_TYPE_ENTRY(WritingMode); -- ATTRIBUTE_TYPE_ENTRY(Unknown); -- ATTRIBUTE_TYPE_ENTRY(checked); -- return 1; --} -- --static int l_Object_Type(lua_State * L) { -- lua_createtable(L,0,16);/*nr of ObjType values*/ ; -- OBJECT_TYPE(objBool); -- OBJECT_TYPE(objInt); -- OBJECT_TYPE(objReal); -- OBJECT_TYPE(objString); -- OBJECT_TYPE(objName); -- OBJECT_TYPE(objNull); -- OBJECT_TYPE(objArray); -- OBJECT_TYPE(objDict); -- OBJECT_TYPE(objStream); -- OBJECT_TYPE(objRef); -- OBJECT_TYPE(objCmd); -- OBJECT_TYPE(objError); -- OBJECT_TYPE(objEOF); -- OBJECT_TYPE(objNone); -- OBJECT_TYPE(objInt64); -- OBJECT_TYPE(objDead); -- return 1; --} -- -- --static int l_StructElement_Type(lua_State * L) { -- lua_createtable (L, 0, 50); -- STRUCTELEMENT_TYPE_ENTRY(Document); -- STRUCTELEMENT_TYPE_ENTRY(Part); -- STRUCTELEMENT_TYPE_ENTRY(Art); -- STRUCTELEMENT_TYPE_ENTRY(Sect); -- STRUCTELEMENT_TYPE_ENTRY(Div); -- STRUCTELEMENT_TYPE_ENTRY(BlockQuote); -- STRUCTELEMENT_TYPE_ENTRY(Caption); -- STRUCTELEMENT_TYPE_ENTRY(NonStruct); -- STRUCTELEMENT_TYPE_ENTRY(Index); -- STRUCTELEMENT_TYPE_ENTRY(Private); -- STRUCTELEMENT_TYPE_ENTRY(Span); -- STRUCTELEMENT_TYPE_ENTRY(Quote); -- STRUCTELEMENT_TYPE_ENTRY(Note); -- STRUCTELEMENT_TYPE_ENTRY(Reference); -- STRUCTELEMENT_TYPE_ENTRY(BibEntry); -- STRUCTELEMENT_TYPE_ENTRY(Code); -- STRUCTELEMENT_TYPE_ENTRY(Link); -- STRUCTELEMENT_TYPE_ENTRY(Annot); -- STRUCTELEMENT_TYPE_ENTRY(Ruby); -- STRUCTELEMENT_TYPE_ENTRY(RB); -- STRUCTELEMENT_TYPE_ENTRY(RT); -- STRUCTELEMENT_TYPE_ENTRY(RP); -- STRUCTELEMENT_TYPE_ENTRY(Warichu); -- STRUCTELEMENT_TYPE_ENTRY(WT); -- STRUCTELEMENT_TYPE_ENTRY(WP); -- STRUCTELEMENT_TYPE_ENTRY(P); -- STRUCTELEMENT_TYPE_ENTRY(H); -- STRUCTELEMENT_TYPE_ENTRY(H1); -- STRUCTELEMENT_TYPE_ENTRY(H2); -- STRUCTELEMENT_TYPE_ENTRY(H3); -- STRUCTELEMENT_TYPE_ENTRY(H4); -- STRUCTELEMENT_TYPE_ENTRY(H5); -- STRUCTELEMENT_TYPE_ENTRY(H6); -- STRUCTELEMENT_TYPE_ENTRY(L); -- STRUCTELEMENT_TYPE_ENTRY(LI); -- STRUCTELEMENT_TYPE_ENTRY(Lbl); -- STRUCTELEMENT_TYPE_ENTRY(LBody); -- STRUCTELEMENT_TYPE_ENTRY(Table); -- STRUCTELEMENT_TYPE_ENTRY(TR); -- STRUCTELEMENT_TYPE_ENTRY(TH); -- STRUCTELEMENT_TYPE_ENTRY(TD); -- STRUCTELEMENT_TYPE_ENTRY(THead); -- STRUCTELEMENT_TYPE_ENTRY(TFoot); -- STRUCTELEMENT_TYPE_ENTRY(TBody); -- STRUCTELEMENT_TYPE_ENTRY(Figure); -- STRUCTELEMENT_TYPE_ENTRY(Formula); -- STRUCTELEMENT_TYPE_ENTRY(Form); -- STRUCTELEMENT_TYPE_ENTRY(TOC); -- STRUCTELEMENT_TYPE_ENTRY(TOCI); -- lua_pushstring(L, "Unknown"); -- lua_pushinteger(L, 0); -- lua_settable(L,-3); -- return 1; --} -- --static int l_AttributeOwner_Type(lua_State * L) { -- lua_createtable (L, 0, 12); -- lua_pushstring(L, "XML-1.00"); lua_pushinteger(L, Attribute::XML_1_00); lua_settable(L,-3); -- lua_pushstring(L, "HTML-3.20"); lua_pushinteger(L, Attribute::HTML_3_20); lua_settable(L,-3); -- lua_pushstring(L, "HTML-4.01"); lua_pushinteger(L, Attribute::HTML_4_01); lua_settable(L,-3); -- lua_pushstring(L, "OEB-1.00"); lua_pushinteger(L, Attribute::OEB_1_00); lua_settable(L,-3); -- lua_pushstring(L, "RTF-1.05"); lua_pushinteger(L, Attribute::RTF_1_05); lua_settable(L,-3); -- lua_pushstring(L, "CSS-1.00"); lua_pushinteger(L, Attribute::CSS_1_00); lua_settable(L,-3); -- lua_pushstring(L, "CSS-2.00"); lua_pushinteger(L, Attribute::CSS_2_00); lua_settable(L,-3); -- lua_pushstring(L, "Layout"); lua_pushinteger(L, Attribute::Layout); lua_settable(L,-3); -- lua_pushstring(L, "PrintField"); lua_pushinteger(L, Attribute::PrintField); lua_settable(L,-3); -- lua_pushstring(L, "Table"); lua_pushinteger(L, Attribute::Table); lua_settable(L,-3); -- lua_pushstring(L, "List"); lua_pushinteger(L, Attribute::List); lua_settable(L,-3); -- lua_pushstring(L, "UserProperties"); lua_pushinteger(L, Attribute::UserProperties);lua_settable(L,-3); -- return 1; --} -- -- --static int l_new_Dict(lua_State * L) --{ -- udstruct *uxref, *uout; -- uxref = (udstruct *) luaL_checkudata(L, 1, M_XRef); -- if (uxref->pd != NULL && uxref->pd->pc != uxref->pc) -- pdfdoc_changed_error(L); -- uout = new_Dict_userdata(L); -- uout->d = new Dict((XRef *) uxref->d); // automatic init to length 0 -- uout->atype = ALLOC_LEPDF; -- uout->pc = uxref->pc; -- uout->pd = uxref->pd; -- return 1; --} -- --static int l_new_Object(lua_State * L) --{ -- udstruct *uout; -- int n = lua_gettop(L); // number of arguments -- uout = new_Object_userdata(L); -- switch(n) { -- case 0: -- uout->d = new Object(); // automatic init to type "none" -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; // not connected to any PDFDoc -- break; -- case 1: -- if (lua_isboolean (L,1)) { -- uout->d = new Object(lua_toboolean(L, 1)? gTrue : gFalse); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } else if (lua_isnumber (L,1)) { -- double d = lua_tonumber(L,1); -- // Missed :Object(long long int64gA) -- if (d==((int)d)) { -- uout->d = new Object((int)d); -- } else { -- uout->d = new Object(d); -- } -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } else if (lua_isstring (L,1)){ -- GooString *gs; -- const char *s; -- size_t len; -- s = luaL_checklstring(L, 2, &len); -- gs = new GooString(s, len); -- uout->d = new Object(gs); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } else if (luaL_testudata(L,1,M_Array)){ -- udstruct *u; -- Array *a; -- u = (udstruct *) luaL_checkudata(L, 1, M_Array); -- a = (Array *)u->d; -- uout->d = new Object(a); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } else if (luaL_testudata(L,1,M_Dict)){ -- udstruct *u; -- Dict *d; -- u = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- d = (Dict *)u->d; -- uout->d = new Object(d); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } else if (luaL_testudata(L,1,M_Stream)){ -- udstruct *u; -- Stream *s; -- u = (udstruct *) luaL_checkudata(L, 1, M_Stream); -- s = (Stream *)u->d; -- *((Object *) uout->d) = Object(s); -- } else -- luaL_error(L, "Invalid/unsupported value for Object constructor"); -- break; -- case 2: -- if (lua_isnumber (L,1) && lua_isnumber (L,2)) { -- double numA = lua_tonumber(L,1); -- double genA = lua_tonumber(L,2); -- if ( ((numA)==(int)(numA)) && ((genA)==(int)(genA)) ){ -- uout->d = new Object((int)(numA), (int)(genA)); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- } -- } else if (lua_isnumber (L,1) && (lua_isstring(L,2)|| lua_isnoneornil(L,2))) { -- double d_typeA = lua_tonumber(L,1); -- int typeA = (int)(d_typeA); -- if (d_typeA==typeA){ -- switch((int)(typeA)) { -- case objBool: -- case objInt: -- case objReal: -- case objString: -- case objName: -- case objNull: -- case objArray: -- case objDict: -- case objStream: -- case objRef: -- case objCmd: -- case objError: -- case objEOF: -- case objNone: -- case objInt64: -- case objDead: -- if (lua_isstring(L,2)) -- uout->d = new Object((ObjType)(typeA), luaL_checkstring(L, 2)); -- else -- uout->d = new Object((ObjType)(typeA)); -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- -- break; -- default: -- luaL_error(L, "Invalid values for Object constructor"); -- break; -- }//switch((int)(d)) -- } else // (d_typeA)!=(typeA) -- luaL_error(L, "Invalid/unsupported values for Object constructor"); -- } // if (lua_isnumber (L,1) && (lua_isstring(L,2)|| lua_isnoneornil(L,2))) -- break; -- default: -- luaL_error(L, "Invalid specification for Object constructor"); -- } -- lua_settop(L,1); -- return 1; --} -- --// static int l_new_Object(lua_State * L) --// { --// udstruct *uout; --// uout = new_Object_userdata(L); --// uout->d = new Object(); // automatic init to type "none" --// uout->atype = ALLOC_LEPDF; --// uout->pc = 0; --// uout->pd = NULL; // not connected to any PDFDoc --// return 1; --// } -- -- --// PDFRectangle see Page.h -- --static int l_new_PDFRectangle(lua_State * L) --{ -- udstruct *uout; -- uout = new_PDFRectangle_userdata(L); -- uout->d = new PDFRectangle(); // automatic init to [0, 0, 0, 0] -- uout->atype = ALLOC_LEPDF; -- uout->pc = 0; -- uout->pd = NULL; -- return 1; --} -- --static const struct luaL_Reg epdflib_f[] = { -- {"open", l_open_PDFDoc}, -- {"openMemStream", l_open_MemStreamPDFDoc}, -- {"Array", l_new_Array}, -- {"Attribute", l_new_Attribute}, -- {"StructElement_Type", l_StructElement_Type}, -- {"Attribute_Type", l_Attribute_Type}, -- {"AttributeOwner_Type",l_AttributeOwner_Type}, -- {"Dict", l_new_Dict}, -- {"Object", l_new_Object}, -- {"Object_Type", l_Object_Type}, -- {"PDFRectangle", l_new_PDFRectangle}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** -- --#define m_poppler_get_poppler(in, out, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- out *o; \ -- udstruct *uin, *uout; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- o = ((in *) uin->d)->function(); \ -- if (o != NULL) { \ -- uout = new_##out##_userdata(L); \ -- uout->d = o; \ -- uout->pc = uin->pc; \ -- uout->pd = uin->pd; \ -- } else \ -- lua_pushnil(L); \ -- return 1; \ --} -- --#define m_poppler_get_BOOL(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- if (((in *) uin->d)->function()) \ -- lua_pushboolean(L, 1); \ -- else \ -- lua_pushboolean(L, 0); \ -- return 1; \ --} -- --#define m_poppler_get_INT(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- int i; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- i = (int) ((in *) uin->d)->function(); \ -- lua_pushinteger(L, i); \ -- return 1; \ --} -- -- --#define m_poppler_get_GUINT(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- unsigned int i; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- i = (unsigned int) ((in *) uin->d)->function(); \ -- lua_pushinteger(L, i); \ -- return 1; \ --} -- --#define m_poppler_get_UINT(in, function) \ --m_poppler_get_GUINT(in, function) -- -- -- --#define m_poppler_get_DOUBLE(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- double d; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- d = (double) ((in *) uin->d)->function(); \ -- lua_pushnumber(L, d); /* float */ \ -- return 1; \ --} -- --#define m_poppler_get_GOOSTRING(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- GooString *gs; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- gs = (GooString *)((in *) uin->d)->function(); \ -- if (gs != NULL) \ -- lua_pushlstring(L, gs->getCString(), gs->getLength()); \ -- else \ -- lua_pushnil(L); \ -- return 1; \ --} -- --#define m_poppler_get_OBJECT(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- udstruct *uin, *uout; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- uout = new_Object_userdata(L); \ -- uout->d = new Object(); \ -- *((Object *)uout->d) = ((in *) uin->d)->function(); \ -- uout->atype = ALLOC_LEPDF; \ -- uout->pc = uin->pc; \ -- uout->pd = uin->pd; \ -- return 1; \ --} -- --#define m_poppler_do(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- ((in *) uin->d)->function(); \ -- return 0; \ --} -- --#define m_poppler__tostring(type) \ --static int m_##type##__tostring(lua_State * L) \ --{ \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##type); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- lua_pushfstring(L, "%s: %p", #type, (type *) uin->d); \ -- return 1; \ --} -- --#define m_poppler_check_string(in, function) \ --static int m_##in##_##function(lua_State * L) \ --{ \ -- const char *s; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_##in); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- s = luaL_checkstring(L, 2); \ -- if (((in *) uin->d)->function(s)) \ -- lua_pushboolean(L, 1); \ -- else \ -- lua_pushboolean(L, 0); \ -- return 1; \ --} -- --//********************************************************************** --// Annot -- --m_poppler_get_BOOL(Annot, isOk); -- --static int m_Annot_match(lua_State * L) --{ -- udstruct *uin, *uref; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Annot); -- uref = (udstruct *) luaL_checkudata(L, 2, M_Ref); -- if (uin->pd != NULL && uref->pd != NULL && uin->pd != uref->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uref->pd != NULL && uref->pd->pc != uref->pc)) -- pdfdoc_changed_error(L); -- lua_pushboolean(L, ((Annot *) uin->d)->match((Ref *) uref->d)); -- return 1; --} -- --m_poppler__tostring(Annot); -- --static int m_Annot__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Annot); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== Annot GC ===== uin=<%p>\n", uin); --#endif -- if (uin->atype == ALLOC_LEPDF) --#if 1 /* def HAVE_ANNOTDECREFCNT */ -- ((Annot *) uin->d)->decRefCnt(); --#else -- delete(Annot *) uin->d; --#endif -- return 0; --} -- --static const struct luaL_Reg Annot_m[] = { -- {"isOk", m_Annot_isOk}, -- {"match", m_Annot_match}, -- {"__tostring", m_Annot__tostring}, -- {"__gc", m_Annot__gc}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Annots -- --m_poppler_get_INT(Annots, getNumAnnots); -- --static int m_Annots_getAnnot(lua_State * L) --{ -- int i, annots; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Annots); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- annots = ((Annots *) uin->d)->getNumAnnots(); -- if (i > 0 && i <= annots) { -- uout = new_Annot_userdata(L); -- uout->d = ((Annots *) uin->d)->getAnnot(i); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler__tostring(Annots); -- --static const struct luaL_Reg Annots_m[] = { -- {"getNumAnnots", m_Annots_getNumAnnots}, -- {"getAnnot", m_Annots_getAnnot}, -- {"__tostring", m_Annots__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Array --// Now private --// static int m_Array_incRef(lua_State * L) --// { --// udstruct *uin; --// uin = (udstruct *) luaL_checkudata(L, 1, M_Array); --// if (uin->pd != NULL && uin->pd->pc != uin->pc) --// pdfdoc_changed_error(L); --// lua_pushinteger(L, 1); --// return 1; --// } --// Now private --// static int m_Array_decRef(lua_State * L) --// { --// int i; --// udstruct *uin; --// uin = (udstruct *) luaL_checkudata(L, 1, M_Array); --// if (uin->pd != NULL && uin->pd->pc != uin->pc) --// pdfdoc_changed_error(L); --// lua_pushinteger(L, 1); --// return 1; --// } -- --m_poppler_get_INT(Array, getLength); -- --static int m_Array_add(lua_State * L) --{ -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Array); -- uobj = (udstruct *) luaL_checkudata(L, 2, M_Object); -- if (uin->pd != NULL && uobj->pd != NULL && uin->pd != uobj->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uobj->pd != NULL && uobj->pd->pc != uobj->pc)) -- pdfdoc_changed_error(L); -- ((Array *) uin->d)->add(std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Array_get(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Array); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Array *) uin->d)->getLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Array *) uin->d)->get(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Array_getNF(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Array); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Array *) uin->d)->getLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Array *) uin->d)->getNF(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Array_getString(lua_State * L) --{ -- GooString *gs; -- int i, len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Array); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Array *) uin->d)->getLength(); -- if (i > 0 && i <= len) { -- gs = new GooString(); -- if (((Array *) uin->d)->getString(i - 1, gs)) -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- else -- lua_pushnil(L); -- delete gs; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler__tostring(Array); -- --static const struct luaL_Reg Array_m[] = { -- // {"incRef", m_Array_incRef},// Now private -- // {"decRef", m_Array_decRef},// Now private -- {"getLength", m_Array_getLength}, -- {"add", m_Array_add}, -- {"get", m_Array_get}, -- {"getNF", m_Array_getNF}, -- {"getString", m_Array_getString}, -- {"__tostring", m_Array__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Catalog -- --m_poppler_get_BOOL(Catalog, isOk); --m_poppler_get_INT(Catalog, getNumPages); -- --static int m_Catalog_getPage(lua_State * L) --{ -- int i, pages; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- pages = ((Catalog *) uin->d)->getNumPages(); -- if (i > 0 && i <= pages) { -- uout = new_Page_userdata(L); -- uout->d = ((Catalog *) uin->d)->getPage(i); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Catalog_getPageRef(lua_State * L) --{ -- int i, pages; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- pages = ((Catalog *) uin->d)->getNumPages(); -- if (i > 0 && i <= pages) { -- uout = new_Ref_userdata(L); -- uout->d = (Ref *) gmalloc(sizeof(Ref)); -- ((Ref *) uout->d)->num = ((Catalog *) uin->d)->getPageRef(i)->num; -- ((Ref *) uout->d)->gen = ((Catalog *) uin->d)->getPageRef(i)->gen; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler_get_GOOSTRING(Catalog, getBaseURI); --m_poppler_get_GOOSTRING(Catalog, readMetadata); --m_poppler_get_poppler(Catalog, StructTreeRoot, getStructTreeRoot); -- --static int m_Catalog_findPage(lua_State * L) --{ -- int num, gen, i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- num = luaL_checkint(L, 2); -- gen = luaL_checkint(L, 3); -- i = ((Catalog *) uin->d)->findPage(num, gen); -- if (i > 0) -- lua_pushinteger(L, i); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Catalog_findDest(lua_State * L) --{ -- GooString *name; -- LinkDest *dest; -- const char *s; -- size_t len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checklstring(L, 2, &len); -- name = new GooString(s, len); -- dest = ((Catalog *) uin->d)->findDest(name); -- if (dest != NULL) { -- uout = new_LinkDest_userdata(L); -- uout->d = dest; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- delete name; -- return 1; --} -- --m_poppler_get_poppler(Catalog, Object, getDests); --m_poppler_get_INT(Catalog, numEmbeddedFiles); -- --static int m_Catalog_embeddedFile(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Catalog *) uin->d)->numEmbeddedFiles(); -- if (i > 0 && i <= len) { -- uout = new_FileSpec_userdata(L); -- uout->d = ((Catalog *) uin->d)->embeddedFile(i - 1); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler_get_INT(Catalog, numJS); -- --static int m_Catalog_getJS(lua_State * L) --{ -- GooString *gs; -- int i, len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Catalog); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Catalog *) uin->d)->numJS(); -- if (i > 0 && i <= len) { -- gs = ((Catalog *) uin->d)->getJS(i - 1); -- if (gs != NULL) -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- else -- lua_pushnil(L); -- delete gs; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler_get_poppler(Catalog, Object, getOutline); --m_poppler_get_poppler(Catalog, Object, getAcroForm); -- --m_poppler__tostring(Catalog); -- --static const struct luaL_Reg Catalog_m[] = { -- {"isOk", m_Catalog_isOk}, -- {"getNumPages", m_Catalog_getNumPages}, -- {"getPage", m_Catalog_getPage}, -- {"getPageRef", m_Catalog_getPageRef}, -- {"getBaseURI", m_Catalog_getBaseURI}, -- {"readMetadata", m_Catalog_readMetadata}, -- {"getStructTreeRoot", m_Catalog_getStructTreeRoot}, -- {"findPage", m_Catalog_findPage}, -- {"findDest", m_Catalog_findDest}, -- {"getDests", m_Catalog_getDests}, -- {"numEmbeddedFiles", m_Catalog_numEmbeddedFiles}, -- {"embeddedFile", m_Catalog_embeddedFile}, -- {"numJS", m_Catalog_numJS}, -- {"getJS", m_Catalog_getJS}, -- {"getOutline", m_Catalog_getOutline}, -- {"getAcroForm", m_Catalog_getAcroForm}, -- {"__tostring", m_Catalog__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Dict --// Now private --// static int m_Dict_incRef(lua_State * L) --// { --// udstruct *uin; --// uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); --// if (uin->pd != NULL && uin->pd->pc != uin->pc) --// pdfdoc_changed_error(L); --// lua_pushinteger(L, 1); --// return 1; --// } --// Now private --// static int m_Dict_decRef(lua_State * L) --// { --// udstruct *uin; --// uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); --// if (uin->pd != NULL && uin->pd->pc != uin->pc) --// pdfdoc_changed_error(L); --// lua_pushinteger(L, 1); --// return 1; --// } -- --m_poppler_get_INT(Dict, getLength); -- --static int m_Dict_add(lua_State * L) --{ -- char *s; -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = copyString(luaL_checkstring(L, 2)); -- uobj = (udstruct *) luaL_checkudata(L, 3, M_Object); -- ((Dict *) uin->d)->add(s, std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Dict_set(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- uobj = (udstruct *) luaL_checkudata(L, 3, M_Object); -- ((Dict *) uin->d)->set(s, std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Dict_remove(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- ((Dict *) uin->d)->remove(s); -- return 0; --} -- --m_poppler_check_string(Dict, is); -- --static int m_Dict_lookup(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Dict *) uin->d)->lookup(s); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --static int m_Dict_lookupNF(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Dict *) uin->d)->lookupNF(s); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --static int m_Dict_lookupInt(lua_State * L) --{ -- const char *s1, *s2; -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s1 = luaL_checkstring(L, 2); -- s2 = luaL_checkstring(L, 3); -- if (((Dict *) uin->d)->lookupInt(s1, s2, &i)) -- lua_pushinteger(L, i); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Dict_getKey(lua_State * L) --{ -- int i, len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Dict *) uin->d)->getLength(); -- if (i > 0 && i <= len) -- lua_pushstring(L, ((Dict *) uin->d)->getKey(i - 1)); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Dict_getVal(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Dict *) uin->d)->getLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Dict *) uin->d)->getVal(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Dict_getValNF(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Dict); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- len = ((Dict *) uin->d)->getLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Dict *) uin->d)->getValNF(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_poppler_check_string(Dict, hasKey); -- --m_poppler__tostring(Dict); -- --static const struct luaL_Reg Dict_m[] = { -- // {"incRef", m_Dict_incRef},// Now private -- // {"decRef", m_Dict_decRef},// Now private -- {"getLength", m_Dict_getLength}, -- {"add", m_Dict_add}, -- {"set", m_Dict_set}, -- {"remove", m_Dict_remove}, -- {"is", m_Dict_is}, -- {"lookup", m_Dict_lookup}, -- {"lookupNF", m_Dict_lookupNF}, -- {"lookupInt", m_Dict_lookupInt}, -- {"getKey", m_Dict_getKey}, -- {"getVal", m_Dict_getVal}, -- {"getValNF", m_Dict_getValNF}, -- {"hasKey", m_Dict_hasKey}, -- {"__tostring", m_Dict__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// EmbFile -- --m_poppler_get_INT(EmbFile, size); --m_poppler_get_GOOSTRING(EmbFile, modDate); --m_poppler_get_GOOSTRING(EmbFile, createDate); --m_poppler_get_GOOSTRING(EmbFile, checksum); --m_poppler_get_GOOSTRING(EmbFile, mimeType); -- --m_poppler_get_BOOL(EmbFile, isOk); -- --static int m_EmbFile_save(lua_State * L) --{ -- const char *s; -- size_t len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_EmbFile); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checklstring(L, 2, &len); -- if (((EmbFile *) uin->d)->save(s)) -- lua_pushboolean(L, 1); -- else -- lua_pushboolean(L, 0); -- return 1; --} -- --m_poppler__tostring(EmbFile); -- --static const struct luaL_Reg EmbFile_m[] = { -- {"size", m_EmbFile_size}, -- {"modDate", m_EmbFile_modDate}, -- {"createDate", m_EmbFile_createDate}, -- {"checksum", m_EmbFile_checksum}, -- {"mimeType", m_EmbFile_mimeType}, -- {"isOk", m_EmbFile_isOk}, -- {"save", m_EmbFile_save}, -- {"__tostring", m_EmbFile__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// FileSpec -- --m_poppler_get_BOOL(FileSpec, isOk); --m_poppler_get_GOOSTRING(FileSpec, getFileName); --m_poppler_get_GOOSTRING(FileSpec, getFileNameForPlatform); --m_poppler_get_GOOSTRING(FileSpec, getDescription); -- --static int m_FileSpec_getEmbeddedFile(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_FileSpec); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uout = new_EmbFile_userdata(L); -- uout->d = ((FileSpec *) uin->d)->getEmbeddedFile(); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --m_poppler__tostring(FileSpec); -- --static const struct luaL_Reg FileSpec_m[] = { -- {"isOk", m_FileSpec_isOk}, -- {"getFileName", m_FileSpec_getFileName}, -- {"getFileNameForPlatform", m_FileSpec_getFileNameForPlatform}, -- {"getDescription", m_FileSpec_getDescription}, -- {"getEmbeddedFile", m_FileSpec_getEmbeddedFile}, -- {"__tostring", m_FileSpec__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// GooString -- --static int m_GooString__tostring(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_GooString); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushlstring(L, ((GooString *) uin->d)->getCString(), -- ((GooString *) uin->d)->getLength()); -- return 1; --} -- --static const struct luaL_Reg GooString_m[] = { -- {"__tostring", m_GooString__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// LinkDest -- --static const char *LinkDestKindNames[] = -- { "XYZ", "Fit", "FitH", "FitV", "FitR", "FitB", "FitBH", "FitBV", NULL }; -- --m_poppler_get_BOOL(LinkDest, isOk); -- --static int m_LinkDest_getKind(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_LinkDest); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (int) ((LinkDest *) uin->d)->getKind(); -- lua_pushinteger(L, i); -- return 1; --} -- --static int m_LinkDest_getKindName(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_LinkDest); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (int) ((LinkDest *) uin->d)->getKind(); -- lua_pushstring(L, LinkDestKindNames[i]); -- return 1; --} -- --m_poppler_get_BOOL(LinkDest, isPageRef); --m_poppler_get_INT(LinkDest, getPageNum); -- --static int m_LinkDest_getPageRef(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_LinkDest); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uout = new_Ref_userdata(L); -- uout->d = (Ref *) gmalloc(sizeof(Ref)); -- ((Ref *) uout->d)->num = ((LinkDest *) uin->d)->getPageRef().num; -- ((Ref *) uout->d)->gen = ((LinkDest *) uin->d)->getPageRef().gen; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --m_poppler_get_DOUBLE(LinkDest, getLeft); --m_poppler_get_DOUBLE(LinkDest, getBottom); --m_poppler_get_DOUBLE(LinkDest, getRight); --m_poppler_get_DOUBLE(LinkDest, getTop); --m_poppler_get_DOUBLE(LinkDest, getZoom); --m_poppler_get_BOOL(LinkDest, getChangeLeft); --m_poppler_get_BOOL(LinkDest, getChangeTop); --m_poppler_get_BOOL(LinkDest, getChangeZoom); -- --m_poppler__tostring(LinkDest); -- --static const struct luaL_Reg LinkDest_m[] = { -- {"isOk", m_LinkDest_isOk}, -- {"getKind", m_LinkDest_getKind}, -- {"getKindName", m_LinkDest_getKindName}, // not poppler -- {"isPageRef", m_LinkDest_isPageRef}, -- {"getPageNum", m_LinkDest_getPageNum}, -- {"getPageRef", m_LinkDest_getPageRef}, -- {"getLeft", m_LinkDest_getLeft}, -- {"getBottom", m_LinkDest_getBottom}, -- {"getRight", m_LinkDest_getRight}, -- {"getTop", m_LinkDest_getTop}, -- {"getZoom", m_LinkDest_getZoom}, -- {"getChangeLeft", m_LinkDest_getChangeLeft}, -- {"getChangeTop", m_LinkDest_getChangeTop}, -- {"getChangeZoom", m_LinkDest_getChangeZoom}, -- {"__tostring", m_LinkDest__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Links -- --m_poppler_get_INT(Links, getNumLinks); -- --m_poppler__tostring(Links); -- --static const struct luaL_Reg Links_m[] = { -- {"getNumLinks", m_Links_getNumLinks}, -- //{"getLink", m_Links_getLink}, -- {"__tostring", m_Links__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Object -- --#ifdef HAVE_OBJECT_INITCMD_CONST_CHARP --#define CHARP_CAST --#else --// must cast arg of Object::initCmd, Object::isStream, and Object::streamIs --// from 'const char *' to 'char *', although they are not modified. --#define CHARP_CAST (char *) --#endif -- --// Special type checking. --#define m_Object_isType_(function, cast) \ --static int m_Object_##function(lua_State * L) \ --{ \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- if (lua_gettop(L) >= 2) { \ -- if (lua_isstring(L, 2) \ -- && ((Object *) uin->d)->function(cast lua_tostring(L, 2))) \ -- lua_pushboolean(L, 1); \ -- else \ -- lua_pushboolean(L, 0); \ -- } else { \ -- if (((Object *) uin->d)->function()) \ -- lua_pushboolean(L, 1); \ -- else \ -- lua_pushboolean(L, 0); \ -- } \ -- return 1; \ --} --#define m_Object_isType(function) m_Object_isType_(function, ) --#define m_Object_isType_nonconst(function) m_Object_isType_(function, CHARP_CAST) -- --static int m_Object_initBool(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- luaL_checktype(L, 2, LUA_TBOOLEAN); -- if (lua_toboolean(L, 2) != 0) -- *((Object *) uin->d) = Object(gTrue); -- else -- *((Object *) uin->d) = Object(gFalse); -- return 0; --} -- --static int m_Object_initInt(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- *((Object *) uin->d) = Object(i); -- return 0; --} -- --static int m_Object_initReal(lua_State * L) --{ -- double d; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- d = luaL_checknumber(L, 2); -- *((Object *) uin->d) = Object(d); -- return 0; --} -- --static int m_Object_initString(lua_State * L) --{ -- GooString *gs; -- const char *s; -- size_t len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checklstring(L, 2, &len); -- gs = new GooString(s, len); -- *((Object *) uin->d) = Object(gs); -- return 0; --} -- --static int m_Object_initName(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- *((Object *) uin->d) = Object(objName, s); -- return 0; --} -- --static int m_Object_initNull(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- *((Object *) uin->d) = Object(objNull); -- return 0; --} -- --static int m_Object_initArray(lua_State * L) --{ -- udstruct *uin, *uxref; -- Array *a; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- uxref = (udstruct *) luaL_checkudata(L, 2, M_XRef); -- if (uin->pd != NULL && uxref->pd != NULL && uin->pd != uxref->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uxref->pd != NULL && uxref->pd->pc != uxref->pc)) -- pdfdoc_changed_error(L); -- a = new Array((XRef *) uxref->d); -- *((Object *) uin->d) = Object(a); -- return 0; --} -- --// TODO: decide betweeen --// Object *initDict(XRef *xref); --// Object *initDict(Dict *dictA); -- --static int m_Object_initDict(lua_State * L) --{ -- udstruct *uin, *uxref; -- Dict *d; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- uxref = (udstruct *) luaL_checkudata(L, 2, M_XRef); -- if (uin->pd != NULL && uxref->pd != NULL && uin->pd != uxref->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uxref->pd != NULL && uxref->pd->pc != uxref->pc)) -- pdfdoc_changed_error(L); -- d = new Dict((XRef *) uxref->d); -- *((Object *) uin->d) = Object(d); -- return 0; --} -- --static int m_Object_initStream(lua_State * L) --{ -- udstruct *uin, *ustream; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- ustream = (udstruct *) luaL_checkudata(L, 2, M_Stream); -- if (uin->pd != NULL && ustream->pd != NULL && uin->pd != ustream->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (ustream->pd != NULL && ustream->pd->pc != ustream->pc)) -- pdfdoc_changed_error(L); -- *((Object *) uin->d) = Object((Stream *) ustream->d); -- return 0; --} -- --static int m_Object_initRef(lua_State * L) --{ -- int num, gen; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- num = luaL_checkint(L, 2); -- gen = luaL_checkint(L, 3); -- *((Object *) uin->d) = Object(num, gen); -- return 0; --} -- --static int m_Object_initCmd(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- *((Object *) uin->d) = Object(objCmd, s); -- return 0; --} -- --static int m_Object_initError(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- *((Object *) uin->d) = Object(objError); -- return 0; --} -- --static int m_Object_initEOF(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- *((Object *) uin->d) = Object(objEOF); -- return 0; --} -- --static int m_Object_fetch(lua_State * L) --{ -- udstruct *uin, *uxref, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- uxref = (udstruct *) luaL_checkudata(L, 2, M_XRef); -- if (uin->pd != NULL && uxref->pd != NULL && uin->pd != uxref->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uxref->pd != NULL && uxref->pd->pc != uxref->pc)) -- pdfdoc_changed_error(L); -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->fetch((XRef *) uxref->d); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --static int m_Object_getType(lua_State * L) --{ -- ObjType t; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- t = ((Object *) uin->d)->getType(); -- lua_pushinteger(L, (int) t); -- return 1; --} -- --static int m_Object_getTypeName(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushstring(L, ((Object *) uin->d)->getTypeName()); -- return 1; --} -- --m_poppler_get_BOOL(Object, isBool); --m_poppler_get_BOOL(Object, isInt); --m_poppler_get_BOOL(Object, isReal); --m_poppler_get_BOOL(Object, isNum); --m_poppler_get_BOOL(Object, isString); --m_Object_isType(isName); --m_poppler_get_BOOL(Object, isNull); --m_poppler_get_BOOL(Object, isArray); --m_Object_isType(isDict); --m_Object_isType_nonconst(isStream); --m_poppler_get_BOOL(Object, isRef); --m_Object_isType(isCmd); --m_poppler_get_BOOL(Object, isError); --m_poppler_get_BOOL(Object, isEOF); --m_poppler_get_BOOL(Object, isNone); -- --static int m_Object_getBool(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isBool()) { -- if (((Object *) uin->d)->getBool()) -- lua_pushboolean(L, 1); -- else -- lua_pushboolean(L, 0); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getInt(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isInt()) -- lua_pushinteger(L, ((Object *) uin->d)->getInt()); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getReal(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isReal()) -- lua_pushnumber(L, ((Object *) uin->d)->getReal()); /* float */ -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getNum(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isInt()) -- lua_pushinteger(L, ((Object *) uin->d)->getInt()); -- else if (((Object *) uin->d)->isReal()) -- lua_pushinteger(L, ((Object *) uin->d)->getReal()); -- else if (((Object *) uin->d)->isNum()) /* redundant */ -- lua_pushnumber(L, ((Object *) uin->d)->getNum()); /* integer or float */ -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getString(lua_State * L) --{ -- GooString *gs; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isString()) { -- gs = (GooString *)((Object *) uin->d)->getString(); -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getName(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isName()) -- lua_pushstring(L, ((Object *) uin->d)->getName()); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getArray(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isArray()) { -- uout = new_Array_userdata(L); -- uout->d = ((Object *) uin->d)->getArray(); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getDict(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isDict()) { -- uout = new_Dict_userdata(L); -- uout->d = ((Object *) uin->d)->getDict(); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getStream(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) { -- uout = new_Stream_userdata(L); -- uout->d = ((Object *) uin->d)->getStream(); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getRef(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isRef()) { -- uout = new_Ref_userdata(L); -- uout->d = (Ref *) gmalloc(sizeof(Ref)); -- ((Ref *) uout->d)->num = ((Object *) uin->d)->getRef().num; -- ((Ref *) uout->d)->gen = ((Object *) uin->d)->getRef().gen; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getRefNum(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isRef()) { -- i = ((Object *) uin->d)->getRef().num; -- lua_pushinteger(L, i); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getRefGen(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isRef()) { -- i = ((Object *) uin->d)->getRef().gen; -- lua_pushinteger(L, i); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_getCmd(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isCmd()) -- lua_pushstring(L, ((Object *) uin->d)->getCmd()); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_arrayGetLength(lua_State * L) --{ -- int len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isArray()) { -- len = ((Object *) uin->d)->arrayGetLength(); -- lua_pushinteger(L, len); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_arrayAdd(lua_State * L) --{ -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- uobj = (udstruct *) luaL_checkudata(L, 2, M_Object); -- if (uin->pd != NULL && uobj->pd != NULL && uin->pd != uobj->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uobj->pd != NULL && uobj->pd->pc != uobj->pd->pc)) -- pdfdoc_changed_error(L); -- if (!((Object *) uin->d)->isArray()) -- luaL_error(L, "Object is not an Array"); -- ((Object *) uin->d)->arrayAdd(std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Object_arrayGet(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isArray()) { -- len = ((Object *) uin->d)->arrayGetLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->arrayGet(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_arrayGetNF(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isArray()) { -- len = ((Object *) uin->d)->arrayGetLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->arrayGetNF(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictGetLength(lua_State * L) --{ -- int len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isDict()) { -- len = ((Object *) uin->d)->dictGetLength(); -- lua_pushinteger(L, len); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictAdd(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- s = luaL_checkstring(L, 2); -- uobj = (udstruct *) luaL_checkudata(L, 3, M_Object); -- if (uin->pd != NULL && uobj->pd != NULL && uin->pd != uobj->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uobj->pd != NULL && uobj->pd->pc != uobj->pd->pc)) -- pdfdoc_changed_error(L); -- if (!((Object *) uin->d)->isDict()) -- luaL_error(L, "Object is not a Dict"); -- ((Object *) uin->d)->dictAdd(copyString(s), std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Object_dictSet(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uobj; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- s = luaL_checkstring(L, 2); -- uobj = (udstruct *) luaL_checkudata(L, 3, M_Object); -- if (uin->pd != NULL && uobj->pd != NULL && uin->pd != uobj->pd) -- pdfdoc_differs_error(L); -- if ((uin->pd != NULL && uin->pd->pc != uin->pc) -- || (uobj->pd != NULL && uobj->pd->pc != uobj->pd->pc)) -- pdfdoc_changed_error(L); -- if (!((Object *) uin->d)->isDict()) -- luaL_error(L, "Object is not a Dict"); -- ((Object *) uin->d)->dictSet(s, std::move(*((Object *) uobj->d))); -- return 0; --} -- --static int m_Object_dictLookup(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- if (((Object *) uin->d)->isDict()) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->dictLookup(s); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictLookupNF(lua_State * L) --{ -- const char *s; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- if (((Object *) uin->d)->isDict()) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->dictLookupNF(s); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictGetKey(lua_State * L) --{ -- int i, len; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isDict()) { -- len = ((Object *) uin->d)->dictGetLength(); -- if (i > 0 && i <= len) -- lua_pushstring(L, ((Object *) uin->d)->dictGetKey(i - 1)); -- else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictGetVal(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isDict()) { -- len = ((Object *) uin->d)->dictGetLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->dictGetVal(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_dictGetValNF(lua_State * L) --{ -- int i, len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isDict()) { -- len = ((Object *) uin->d)->dictGetLength(); -- if (i > 0 && i <= len) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((Object *) uin->d)->dictGetValNF(i - 1); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_streamIs(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- if (((Object *) uin->d)->isStream()) { -- if (((Object *) uin->d)->streamIs(CHARP_CAST s)) -- lua_pushboolean(L, 1); -- else -- lua_pushboolean(L, 0); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_streamReset(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) -- ((Object *) uin->d)->streamReset(); -- return 0; --} -- --static int m_Object_streamGetChar(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) { -- i = ((Object *) uin->d)->streamGetChar(); -- lua_pushinteger(L, i); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_streamLookChar(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) { -- i = ((Object *) uin->d)->streamLookChar(); -- lua_pushinteger(L, i); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_streamGetPos(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) { -- i = (int) ((Object *) uin->d)->streamGetPos(); -- lua_pushinteger(L, i); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object_streamSetPos(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- if (((Object *) uin->d)->isStream()) -- ((Object *) uin->d)->streamSetPos(i); -- return 0; --} -- --static int m_Object_streamGetDict(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((Object *) uin->d)->isStream()) { -- uout = new_Dict_userdata(L); -- uout->d = ((Object *) uin->d)->streamGetDict(); -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_Object__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== Object GC ===== uin=<%p>\n", uin); --#endif -- if (uin->atype == ALLOC_LEPDF) { -- // free() seems to collide with the lua gc -- //((Object *) uin->d)->free(); -- delete(Object *) uin->d; -- } -- return 0; --} -- --m_poppler__tostring(Object); -- --static const struct luaL_Reg Object_m[] = { -- {"initBool", m_Object_initBool}, -- {"initInt", m_Object_initInt}, -- {"initReal", m_Object_initReal}, -- {"initString", m_Object_initString}, -- {"initName", m_Object_initName}, -- {"initNull", m_Object_initNull}, -- {"initArray", m_Object_initArray}, -- {"initDict", m_Object_initDict}, -- {"initStream", m_Object_initStream}, -- {"initRef", m_Object_initRef}, -- {"initCmd", m_Object_initCmd}, -- {"initError", m_Object_initError}, -- {"initEOF", m_Object_initEOF}, -- // {"copy", m_Object_copy}, -- {"fetch", m_Object_fetch}, -- {"getType", m_Object_getType}, -- {"getTypeName", m_Object_getTypeName}, -- {"isBool", m_Object_isBool}, -- {"isInt", m_Object_isInt}, -- {"isReal", m_Object_isReal}, -- {"isNum", m_Object_isNum}, -- {"isString", m_Object_isString}, -- {"isName", m_Object_isName}, -- {"isNull", m_Object_isNull}, -- {"isArray", m_Object_isArray}, -- {"isDict", m_Object_isDict}, -- {"isStream", m_Object_isStream}, -- {"isRef", m_Object_isRef}, -- {"isCmd", m_Object_isCmd}, -- {"isError", m_Object_isError}, -- {"isEOF", m_Object_isEOF}, -- {"isNone", m_Object_isNone}, -- {"getBool", m_Object_getBool}, -- {"getInt", m_Object_getInt}, -- {"getReal", m_Object_getReal}, -- {"getNum", m_Object_getNum}, -- {"getString", m_Object_getString}, -- {"getName", m_Object_getName}, -- {"getArray", m_Object_getArray}, -- {"getDict", m_Object_getDict}, -- {"getStream", m_Object_getStream}, -- {"getRef", m_Object_getRef}, -- {"getRefNum", m_Object_getRefNum}, -- {"getRefGen", m_Object_getRefGen}, -- {"getCmd", m_Object_getCmd}, -- {"arrayGetLength", m_Object_arrayGetLength}, -- {"arrayAdd", m_Object_arrayAdd}, -- {"arrayGet", m_Object_arrayGet}, -- {"arrayGetNF", m_Object_arrayGetNF}, -- {"dictGetLength", m_Object_dictGetLength}, -- {"dictAdd", m_Object_dictAdd}, -- {"dictSet", m_Object_dictSet}, -- {"dictLookup", m_Object_dictLookup}, -- {"dictLookupNF", m_Object_dictLookupNF}, -- {"dictGetKey", m_Object_dictGetKey}, -- {"dictGetVal", m_Object_dictGetVal}, -- {"dictGetValNF", m_Object_dictGetValNF}, -- {"streamIs", m_Object_streamIs}, -- {"streamReset", m_Object_streamReset}, -- // {"streamClose", m_Object_streamClose}, -- {"streamGetChar", m_Object_streamGetChar}, -- {"streamLookChar", m_Object_streamLookChar}, -- // {"streamGetLine", m_Object_streamGetLine}, -- {"streamGetPos", m_Object_streamGetPos}, -- {"streamSetPos", m_Object_streamSetPos}, -- {"streamGetDict", m_Object_streamGetDict}, -- {"__tostring", m_Object__tostring}, -- {"__gc", m_Object__gc}, // finalizer -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Page -- --m_poppler_get_BOOL(Page, isOk); --m_poppler_get_INT(Page, getNum); --m_poppler_get_poppler(Page, PDFRectangle, getMediaBox); --m_poppler_get_poppler(Page, PDFRectangle, getCropBox); --m_poppler_get_BOOL(Page, isCropped); --m_poppler_get_DOUBLE(Page, getMediaWidth); --m_poppler_get_DOUBLE(Page, getMediaHeight); --m_poppler_get_DOUBLE(Page, getCropWidth); --m_poppler_get_DOUBLE(Page, getCropHeight); --m_poppler_get_poppler(Page, PDFRectangle, getBleedBox); --m_poppler_get_poppler(Page, PDFRectangle, getTrimBox); --m_poppler_get_poppler(Page, PDFRectangle, getArtBox); --m_poppler_get_INT(Page, getRotate); --m_poppler_get_GOOSTRING(Page, getLastModified); --m_poppler_get_poppler(Page, Dict, getBoxColorInfo); --m_poppler_get_poppler(Page, Dict, getGroup); --m_poppler_get_poppler(Page, Stream, getMetadata); --m_poppler_get_poppler(Page, Dict, getPieceInfo); --m_poppler_get_poppler(Page, Dict, getSeparationInfo); --m_poppler_get_poppler(Page, Dict, getResourceDict); --m_poppler_get_OBJECT(Page, getAnnotsObject); -- --m_poppler_get_OBJECT(Page, getContents); -- --m_poppler__tostring(Page); -- --static const struct luaL_Reg Page_m[] = { -- {"isOk", m_Page_isOk}, -- {"getNum", m_Page_getNum}, -- {"getMediaBox", m_Page_getMediaBox}, -- {"getCropBox", m_Page_getCropBox}, -- {"isCropped", m_Page_isCropped}, -- {"getMediaWidth", m_Page_getMediaWidth}, -- {"getMediaHeight", m_Page_getMediaHeight}, -- {"getCropWidth", m_Page_getCropWidth}, -- {"getCropHeight", m_Page_getCropHeight}, -- {"getBleedBox", m_Page_getBleedBox}, -- {"getTrimBox", m_Page_getTrimBox}, -- {"getArtBox", m_Page_getArtBox}, -- {"getRotate", m_Page_getRotate}, -- {"getLastModified", m_Page_getLastModified}, -- {"getBoxColorInfo", m_Page_getBoxColorInfo}, -- {"getGroup", m_Page_getGroup}, -- {"getMetadata", m_Page_getMetadata}, -- {"getPieceInfo", m_Page_getPieceInfo}, -- {"getSeparationInfo", m_Page_getSeparationInfo}, -- {"getResourceDict", m_Page_getResourceDict}, -- {"getAnnotsObject", m_Page_getAnnotsObject}, -- {"getContents", m_Page_getContents}, -- {"__tostring", m_Page__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// PDFDoc -- --#define m_PDFDoc_BOOL(function) \ --static int m_PDFDoc_##function(lua_State * L) \ --{ \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- if (((PdfDocument *) uin->d)->doc->function()) \ -- lua_pushboolean(L, 1); \ -- else \ -- lua_pushboolean(L, 0); \ -- return 1; \ --} -- --#define m_PDFDoc_INT(function) \ --static int m_PDFDoc_##function(lua_State * L) \ --{ \ -- int i; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- i = ((PdfDocument *) uin->d)->doc->function(); \ -- lua_pushinteger(L, i); \ -- return 1; \ --} -- --m_PDFDoc_BOOL(isOk); --m_PDFDoc_INT(getErrorCode); -- --static int m_PDFDoc_getFileName(lua_State * L) --{ -- GooString *gs; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- gs = ((PdfDocument *) uin->d)->doc->getFileName(); -- if (gs != NULL) -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_getErrorCodeName(lua_State * L) --{ -- int i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = ((PdfDocument *) uin->d)->doc->getErrorCode(); -- lua_pushstring(L, ErrorCodeNames[i]); -- return 1; --} -- --static int m_PDFDoc_getXRef(lua_State * L) --{ -- XRef *xref; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- xref = ((PdfDocument *) uin->d)->doc->getXRef(); -- if (xref->isOk()) { -- uout = new_XRef_userdata(L); -- uout->d = xref; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_getCatalog(lua_State * L) --{ -- Catalog *cat; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- cat = ((PdfDocument *) uin->d)->doc->getCatalog(); -- if (cat->isOk()) { -- uout = new_Catalog_userdata(L); -- uout->d = cat; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --#define m_PDFDoc_PAGEDIMEN(function) \ --static int m_PDFDoc_##function(lua_State * L) \ --{ \ -- int i, pages; \ -- double d; \ -- udstruct *uin; \ -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); \ -- if (uin->pd != NULL && uin->pd->pc != uin->pc) \ -- pdfdoc_changed_error(L); \ -- i = luaL_checkint(L, 2); \ -- pages = ((PdfDocument *) uin->d)->doc->getNumPages(); \ -- if (i > 0 && i <= pages) { \ -- d = (double) ((PdfDocument *) uin->d)->doc->function(i); \ -- lua_pushnumber(L, d); /* float */ \ -- } else \ -- lua_pushnil(L); \ -- return 1; \ --} -- --m_PDFDoc_PAGEDIMEN(getPageMediaWidth); --m_PDFDoc_PAGEDIMEN(getPageMediaHeight); --m_PDFDoc_PAGEDIMEN(getPageCropWidth); --m_PDFDoc_PAGEDIMEN(getPageCropHeight); --m_PDFDoc_INT(getNumPages); -- --static int m_PDFDoc_readMetadata(lua_State * L) --{ -- GooString *gs; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((PdfDocument *) uin->d)->doc->getCatalog()->isOk()) { -- gs = ((PdfDocument *) uin->d)->doc->readMetadata(); -- if (gs != NULL) -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_getStructTreeRoot(lua_State * L) --{ -- StructTreeRoot *obj; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((PdfDocument *) uin->d)->doc->getCatalog()->isOk()) { -- obj = ((PdfDocument *) uin->d)->doc->getStructTreeRoot(); -- uout = new_StructTreeRoot_userdata(L); -- uout->d = obj; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_findPage(lua_State * L) --{ -- int num, gen, i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- num = luaL_checkint(L, 2); -- gen = luaL_checkint(L, 3); -- if (((PdfDocument *) uin->d)->doc->getCatalog()->isOk()) { -- i = ((PdfDocument *) uin->d)->doc->findPage(num, gen); -- if (i > 0) -- lua_pushinteger(L, i); -- else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_getLinks(lua_State * L) --{ -- int i, pages; -- Links *links; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = luaL_checkint(L, 2); -- pages = ((PdfDocument *) uin->d)->doc->getNumPages(); -- if (i > 0 && i <= pages) { -- links = ((PdfDocument *) uin->d)->doc->getLinks(i); -- if (links != NULL) { -- uout = new_Links_userdata(L); -- uout->d = links; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_findDest(lua_State * L) --{ -- GooString *name; -- LinkDest *dest; -- const char *s; -- size_t len; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checklstring(L, 2, &len); -- name = new GooString(s, len); -- if (((PdfDocument *) uin->d)->doc->getCatalog()->isOk()) { -- dest = ((PdfDocument *) uin->d)->doc->findDest(name); -- if (dest != NULL) { -- uout = new_LinkDest_userdata(L); -- uout->d = dest; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- delete name; -- return 1; --} -- --m_PDFDoc_BOOL(isEncrypted); --m_PDFDoc_BOOL(okToPrint); --m_PDFDoc_BOOL(okToChange); --m_PDFDoc_BOOL(okToCopy); --m_PDFDoc_BOOL(okToAddNotes); --m_PDFDoc_BOOL(isLinearized); -- --static int m_PDFDoc_getDocInfo(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((PdfDocument *) uin->d)->doc->getXRef()->isOk()) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((PdfDocument *) uin->d)->doc->getDocInfo(); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFDoc_getDocInfoNF(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- if (((PdfDocument *) uin->d)->doc->getXRef()->isOk()) { -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((PdfDocument *) uin->d)->doc->getDocInfoNF(); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --m_PDFDoc_INT(getPDFMajorVersion); --m_PDFDoc_INT(getPDFMinorVersion); -- --m_poppler__tostring(PDFDoc); -- --static int m_PDFDoc__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFDoc); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== PDFDoc GC ===== file_path=<%s>\n", -- ((PdfDocument *) uin->d)->file_path); --#endif -- assert(uin->atype == ALLOC_LEPDF); -- unrefPdfDocument(((PdfDocument *) uin->d)->file_path); -- return 0; --} -- --static const struct luaL_Reg PDFDoc_m[] = { -- {"isOk", m_PDFDoc_isOk}, -- {"getErrorCode", m_PDFDoc_getErrorCode}, -- {"getErrorCodeName", m_PDFDoc_getErrorCodeName}, // not poppler -- {"getFileName", m_PDFDoc_getFileName}, -- {"getXRef", m_PDFDoc_getXRef}, -- {"getCatalog", m_PDFDoc_getCatalog}, -- // {"getBaseStream", m_PDFDoc_getBaseStream}, -- {"getPageMediaWidth", m_PDFDoc_getPageMediaWidth}, -- {"getPageMediaHeight", m_PDFDoc_getPageMediaHeight}, -- {"getPageCropWidth", m_PDFDoc_getPageCropWidth}, -- {"getPageCropHeight", m_PDFDoc_getPageCropHeight}, -- {"getNumPages", m_PDFDoc_getNumPages}, -- {"readMetadata", m_PDFDoc_readMetadata}, -- {"getStructTreeRoot", m_PDFDoc_getStructTreeRoot}, -- {"findPage", m_PDFDoc_findPage}, -- {"getLinks", m_PDFDoc_getLinks}, -- {"findDest", m_PDFDoc_findDest}, -- {"isEncrypted", m_PDFDoc_isEncrypted}, -- {"okToPrint", m_PDFDoc_okToPrint}, -- {"okToChange", m_PDFDoc_okToChange}, -- {"okToCopy", m_PDFDoc_okToCopy}, -- {"okToAddNotes", m_PDFDoc_okToAddNotes}, -- {"isLinearized", m_PDFDoc_isLinearized}, -- {"getDocInfo", m_PDFDoc_getDocInfo}, -- {"getDocInfoNF", m_PDFDoc_getDocInfoNF}, -- {"getPDFMajorVersion", m_PDFDoc_getPDFMajorVersion}, -- {"getPDFMinorVersion", m_PDFDoc_getPDFMinorVersion}, -- {"__tostring", m_PDFDoc__tostring}, -- {"__gc", m_PDFDoc__gc}, // finalizer -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// PDFRectangle -- --m_poppler_get_BOOL(PDFRectangle, isValid); -- --m_poppler__tostring(PDFRectangle); -- --static int m_PDFRectangle__index(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFRectangle); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- if (strlen(s) == 2) { -- if (s[0] == 'x') { -- if (s[1] == '1') -- lua_pushnumber(L, ((PDFRectangle *) uin->d)->x1); /* float */ -- else if (s[1] == '2') -- lua_pushnumber(L, ((PDFRectangle *) uin->d)->x2); /* float */ -- else -- lua_pushnil(L); -- } else if (s[0] == 'y') { -- if (s[1] == '1') -- lua_pushnumber(L, ((PDFRectangle *) uin->d)->y1); /* float */ -- else if (s[1] == '2') -- lua_pushnumber(L, ((PDFRectangle *) uin->d)->y2); /* float */ -- else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_PDFRectangle__newindex(lua_State * L) --{ -- double d; -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFRectangle); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- d = luaL_checknumber(L, 3); -- if (strlen(s) == 2) { -- if (s[0] == 'x') { -- if (s[1] == '1') -- ((PDFRectangle *) uin->d)->x1 = d; -- else if (s[1] == '2') -- ((PDFRectangle *) uin->d)->x2 = d; -- else -- luaL_error(L, "wrong PDFRectangle coordinate (%s)", s); -- } else if (s[0] == 'y') { -- if (s[1] == '1') -- ((PDFRectangle *) uin->d)->y1 = d; -- else if (s[1] == '2') -- ((PDFRectangle *) uin->d)->y2 = d; -- } else -- luaL_error(L, "wrong PDFRectangle coordinate (%s)", s); -- } else -- luaL_error(L, "wrong PDFRectangle coordinate (%s)", s); -- return 0; --} -- --static int m_PDFRectangle__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_PDFRectangle); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== PDFRectangle GC ===== uin=<%p>\n", uin); --#endif -- if (uin->atype == ALLOC_LEPDF) -- delete(PDFRectangle *) uin->d; -- return 0; --} -- --static const struct luaL_Reg PDFRectangle_m[] = { -- {"isValid", m_PDFRectangle_isValid}, -- {"__index", m_PDFRectangle__index}, -- {"__newindex", m_PDFRectangle__newindex}, -- {"__tostring", m_PDFRectangle__tostring}, -- {"__gc", m_PDFRectangle__gc}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Ref -- --static int m_Ref__index(lua_State * L) --{ -- const char *s; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Ref); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- s = luaL_checkstring(L, 2); -- if (strcmp(s, "num") == 0) -- lua_pushinteger(L, ((Ref *) uin->d)->num); -- else if (strcmp(s, "gen") == 0) -- lua_pushinteger(L, ((Ref *) uin->d)->gen); -- else -- lua_pushnil(L); -- return 1; --} -- --m_poppler__tostring(Ref); -- --static int m_Ref__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Ref); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== Ref GC ===== uin=<%p>\n", uin); --#endif -- if (uin->atype == ALLOC_LEPDF && ((Ref *) uin->d) != NULL) -- gfree(((Ref *) uin->d)); -- return 0; --} -- --static const struct luaL_Reg Ref_m[] = { -- {"__index", m_Ref__index}, -- {"__tostring", m_Ref__tostring}, -- {"__gc", m_Ref__gc}, // finalizer -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// Stream -- --static const char *StreamKindNames[] = -- { "File", "ASCIIHex", "ASCII85", "LZW", "RunLength", "CCITTFax", "DCT", -- "Flate", "JBIG2", "JPX", "Weird", NULL --}; -- --m_poppler_get_INT(Stream, getKind); -- --static int m_Stream_getKindName(lua_State * L) --{ -- StreamKind t; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Stream); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- t = ((Stream *) uin->d)->getKind(); -- lua_pushstring(L, StreamKindNames[t]); -- return 1; --} -- --m_poppler_do(Stream, reset); --m_poppler_do(Stream, close); --m_poppler_get_INT(Stream, getChar); --m_poppler_get_INT(Stream, lookChar); --m_poppler_get_INT(Stream, getRawChar); --m_poppler_get_INT(Stream, getUnfilteredChar); --m_poppler_do(Stream, unfilteredReset); --m_poppler_get_INT(Stream, getPos); --m_poppler_get_BOOL(Stream, isBinary); --m_poppler_get_poppler(Stream, Stream, getUndecodedStream); --m_poppler_get_poppler(Stream, Dict, getDict); -- --m_poppler__tostring(Stream); -- --static const struct luaL_Reg Stream_m[] = { -- {"getKind", m_Stream_getKind}, -- {"getKindName", m_Stream_getKindName}, // not poppler -- {"reset", m_Stream_reset}, -- {"close", m_Stream_close}, -- {"getUndecodedStream", m_Stream_getUndecodedStream}, -- {"getChar", m_Stream_getChar}, -- {"lookChar", m_Stream_lookChar}, -- {"getRawChar", m_Stream_getRawChar}, -- {"getUnfilteredChar", m_Stream_getUnfilteredChar}, -- {"unfilteredReset", m_Stream_unfilteredReset}, -- // {"getLine", m_Stream_getLine}, -- {"getPos", m_Stream_getPos}, -- {"isBinary", m_Stream_isBinary}, -- {"getUndecodedStream", m_Stream_getUndecodedStream}, -- {"getDict", m_Stream_getDict}, -- {"__tostring", m_Stream__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// TextSpan -- --m_poppler_get_GOOSTRING(TextSpan, getText); --m_poppler__tostring(TextSpan); -- --static const struct luaL_Reg TextSpan_m[] = { -- {"getText", m_TextSpan_getText}, -- {"__tostring", m_TextSpan__tostring}, -- {NULL, NULL} // sentinel --}; -- -- -- -- --//********************************************************************** --// Attribute --m_poppler_get_BOOL(Attribute,isOk); --m_poppler_get_INT(Attribute,getType); --m_poppler_get_INT(Attribute,getOwner); --m_poppler_get_GOOSTRING(Attribute,getName); -- --static int m_Attribute_getTypeName(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushstring(L, ((Attribute *) uin->d)->getTypeName()); -- return 1; --} -- --static int m_Attribute_getOwnerName(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushstring(L, ((Attribute *) uin->d)->getOwnerName()); -- return 1; --} -- --static int m_Attribute_getValue(lua_State * L) --{ -- udstruct *uin, *uout; -- Object *origin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- origin = (Object *) (((Attribute *) uin->d)->getValue()); -- *((Object *) uout->d) = origin->copy(); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- -- --static int m_Attribute_getDefaultValue(lua_State * L) --{ -- Attribute::Type t; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- t = (Attribute::Type) luaL_checkint(L, 2); -- uout = new_Object_userdata(L); -- uout->d = ((Attribute *)uin->d)->getDefaultValue(t) ; -- //uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- -- --m_poppler_get_GUINT(Attribute,getRevision); -- --static int m_Attribute_setRevision(lua_State * L) --{ -- Guint i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (Guint) luaL_checkint(L, 2); -- ((Attribute *) uin->d)->setRevision(i); -- return 0; --} -- --m_poppler_get_BOOL(Attribute, isHidden); -- --static int m_Attribute_setHidden(lua_State * L) --{ -- GBool i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (GBool) lua_toboolean(L, 2); -- ((Attribute *) uin->d)->setHidden(i); -- return 0; --} -- --static int m_Attribute_getFormattedValue(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushstring(L, ((Attribute *) uin->d)->getFormattedValue()); -- return 1; --} -- -- --static int m_Attribute_setFormattedValue(lua_State * L) --{ -- const char *c; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- c = luaL_checkstring(L, 2); -- ((Attribute *) uin->d)->setFormattedValue(c); -- return 0; --} -- --static int m_Attribute__gc(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_Attribute); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); --#ifdef DEBUG -- printf("\n===== Attribute GC ===== uin=<%p>\n", uin); --#endif -- if (uin->atype == ALLOC_LEPDF) { -- delete(Attribute *) uin->d; -- } -- return 0; --} -- -- --m_poppler__tostring(Attribute); -- -- --static const struct luaL_Reg Attribute_m[] = { -- {"isOk",m_Attribute_isOk}, -- {"getType",m_Attribute_getType}, -- {"getOwner",m_Attribute_getOwner}, -- {"getTypeName",m_Attribute_getTypeName}, -- {"getOwnerName",m_Attribute_getOwnerName}, -- {"getValue",m_Attribute_getValue}, -- {"getDefaultValue",m_Attribute_getDefaultValue}, -- {"getName",m_Attribute_getName}, -- {"getRevision",m_Attribute_getRevision}, -- {"setRevision",m_Attribute_setRevision}, -- {"istHidden",m_Attribute_isHidden}, -- {"setHidden",m_Attribute_setHidden}, -- {"getFormattedValue",m_Attribute_getFormattedValue}, -- {"setFormattedValue",m_Attribute_setFormattedValue}, -- {"__gc", m_Attribute__gc}, -- {"__tostring", m_Attribute__tostring}, -- {NULL, NULL} // sentinel --}; -- -- -- -- --//********************************************************************** --// StructElement -- -- --m_poppler_get_INT(StructElement,getType); --m_poppler_get_BOOL(StructElement,isOk); --m_poppler_get_BOOL(StructElement,isBlock); --m_poppler_get_BOOL(StructElement,isInline); --m_poppler_get_BOOL(StructElement,isGrouping); --m_poppler_get_BOOL(StructElement,isContent); --m_poppler_get_BOOL(StructElement,isObjectRef); --m_poppler_get_BOOL(StructElement,hasPageRef); --m_poppler_get_INT(StructElement,getMCID); --m_poppler_get_INT(StructElement, getNumChildren); -- --m_poppler_get_GUINT(StructElement,getRevision); --m_poppler_get_UINT(StructElement,getNumAttributes); -- --m_poppler_get_GOOSTRING(StructElement, getID); --m_poppler_get_GOOSTRING(StructElement, getLanguage); --m_poppler_get_GOOSTRING(StructElement, getTitle); --m_poppler_get_GOOSTRING(StructElement, getExpandedAbbr); --m_poppler_get_GOOSTRING(StructElement, getAltText); --m_poppler_get_GOOSTRING(StructElement, getActualText); -- --m_poppler_get_poppler(StructElement, StructTreeRoot, getStructTreeRoot); --m_poppler__tostring(StructElement); -- -- --static int m_StructElement_getObjectRef(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uout = new_Ref_userdata(L); -- uout->d = (Ref *) gmalloc(sizeof(Ref)); -- ((Ref *) uout->d)->num = ((StructElement *) uin->d)->getObjectRef().num; -- ((Ref *) uout->d)->gen = ((StructElement *) uin->d)->getObjectRef().gen; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- -- --static int m_StructElement_getParentRef(lua_State * L) --{ -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uout = new_Ref_userdata(L); -- uout->d = (Ref *) gmalloc(sizeof(Ref)); -- ((Ref *) uout->d)->num = ((StructElement *) uin->d)->getParentRef().num; -- ((Ref *) uout->d)->gen = ((StructElement *) uin->d)->getParentRef().gen; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --// Not exactly as the header: --// Ref = StructElement:getPageRef() --// Ref is false if the C++ functione return false --static int m_StructElement_getPageRef(lua_State * L) --{ -- GBool b; -- Ref *r; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- r = (Ref *) gmalloc(sizeof(Ref)); -- b = ((StructElement *) uin->d)->getPageRef( *r ); -- if (b) { -- uout = new_Ref_userdata(L); -- uout->d = r ; -- //uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushboolean(L,0); -- return 1; --} -- -- -- --static int m_StructElement_getTypeName(lua_State * L) --{ -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- lua_pushstring(L, ((StructElement *) uin->d)->getTypeName()); -- return 1; --} -- -- --static int m_StructElement_setRevision(lua_State * L) --{ -- Guint i; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (Guint) luaL_checkint(L, 2); -- ((StructElement *) uin->d)->setRevision(i); -- return 0; --} -- --static int m_StructElement_getText(lua_State * L) --{ -- GBool i; -- GooString *gs; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (GBool) lua_toboolean(L, 2); -- gs = ((StructElement *) uin->d)->getText(i); -- if (gs != NULL) -- lua_pushlstring(L, gs->getCString(), gs->getLength()); -- else -- lua_pushnil(L); -- return 1; --} -- -- --static int m_StructElement_getChild(lua_State * L) --{ -- StructElement *c; -- int i; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (int) luaL_checkint(L, 2); -- c = ((StructElement *) uin->d)->getChild(i-1); -- if (c != NULL) { -- uout = new_StructElement_userdata(L); -- uout->d = c ; -- //uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } -- else -- lua_pushnil(L); -- return 1; --} -- -- --static int m_StructElement_appendChild(lua_State * L) --{ -- udstruct *uin, *uin1; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uin1 = (udstruct *) luaL_checkudata(L, 2, M_StructElement); -- if (uin1->pd != NULL && uin1->pd->pc != uin1->pc) -- pdfdoc_changed_error(L); -- ((StructElement *) uin->d)->appendChild( (StructElement *)uin1->d ); -- return 0; --} -- -- --static int m_StructElement_getAttribute(lua_State * L) --{ -- Attribute *a; -- int i; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (int) luaL_checkint(L, 2); -- a = ((StructElement *) uin->d)->getAttribute(i-1); -- if (a != NULL) { -- uout = new_Attribute_userdata(L); -- uout->d = a ; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } -- else -- lua_pushnil(L); -- return 1; --} -- -- -- --static int m_StructElement_appendAttribute(lua_State * L) --{ -- -- udstruct *uin, *uin1; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uin1 = (udstruct *) luaL_checkudata(L, 2, M_Attribute); -- if (uin1->pd != NULL && uin1->pd->pc != uin1->pc) -- pdfdoc_changed_error(L); -- ((StructElement *) uin->d)->appendAttribute( (Attribute *)uin1->d ); -- return 0; --} -- -- --static int m_StructElement_findAttribute(lua_State * L) --{ -- Attribute::Type t; -- Attribute::Owner o; -- GBool g; -- udstruct *uin, *uout; -- const Attribute *a; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- t = (Attribute::Type) luaL_checkint(L,1); -- o = (Attribute::Owner) luaL_checkint(L,2); -- g = (GBool) lua_toboolean(L, 3); -- a = ((StructElement *) uin->d)->findAttribute(t,g,o); -- -- if (a!=NULL){ -- uout = new_Attribute_userdata(L); -- uout->d = new Attribute(a->getType(),a->getValue()); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --// This returns a lua table --static int m_StructElement_getTextSpans(lua_State * L) --{ -- int i ; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructElement); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- -- if ((((StructElement *) uin->d)->getTextSpans()).size()>0) { -- lua_createtable (L, -- (int) (((StructElement *) uin->d)->getTextSpans()).size(), -- 0); -- for(i=0;i<(int) (((StructElement *) uin->d)->getTextSpans()).size(); i++){ -- uout = new_TextSpan_userdata(L); -- uout->d = new TextSpan( (((StructElement *) uin->d)->getTextSpans())[i] ); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- lua_rawseti(L,-2,i+1); -- } -- } else -- lua_pushnil(L); -- return 1; --} -- -- -- --static const struct luaL_Reg StructElement_m[] = { -- {"getTypeName", m_StructElement_getTypeName}, -- {"getType",m_StructElement_getType}, -- {"isOk",m_StructElement_isOk}, -- {"isBlock",m_StructElement_isBlock}, -- {"isInline",m_StructElement_isInline}, -- {"isGrouping",m_StructElement_isGrouping}, -- {"isContent",m_StructElement_isContent}, -- {"isObjectRef",m_StructElement_isObjectRef}, -- {"getMCID",m_StructElement_getMCID}, -- {"getObjectRef",m_StructElement_getObjectRef}, -- {"getParentRef",m_StructElement_getParentRef}, -- {"hasPageRef",m_StructElement_hasPageRef}, -- {"getPageRef",m_StructElement_getPageRef}, -- {"getStructTreeRoot",m_StructElement_getStructTreeRoot}, -- {"getID",m_StructElement_getID}, -- {"getLanguage",m_StructElement_getLanguage}, -- {"getRevision",m_StructElement_getRevision}, -- {"setRevision",m_StructElement_setRevision}, -- {"getTitle",m_StructElement_getTitle}, -- {"getExpandedAbbr",m_StructElement_getExpandedAbbr}, -- {"getNumChildren",m_StructElement_getNumChildren}, -- {"getChild",m_StructElement_getChild}, -- {"appendChild",m_StructElement_appendChild}, -- {"getNumAttributes",m_StructElement_getNumAttributes}, -- {"getAttribute",m_StructElement_getAttribute}, -- {"appendAttribute",m_StructElement_appendAttribute}, -- {"findAttribute",m_StructElement_findAttribute}, -- {"getAltText",m_StructElement_getAltText}, -- {"getActualText",m_StructElement_getActualText}, -- {"getText",m_StructElement_getText}, -- {"getTextSpans",m_StructElement_getTextSpans}, -- {"__tostring", m_StructElement__tostring}, -- {NULL, NULL} // sentinel --}; -- -- --//********************************************************************** --// StructTreeRoot -- --m_poppler_get_INT(StructTreeRoot, getNumChildren); --m_poppler_get_poppler(StructTreeRoot, PDFDoc, getDoc); --m_poppler_get_poppler(StructTreeRoot, Dict, getRoleMap); --m_poppler_get_poppler(StructTreeRoot, Dict, getClassMap); --m_poppler__tostring(StructTreeRoot); -- --static int m_StructTreeRoot_getChild(lua_State * L) --{ -- unsigned int i; -- udstruct *uin, *uout; -- StructElement *child ; -- StructTreeRoot *root ; -- -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructTreeRoot); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (unsigned) luaL_checkint(L, 2); -- root = (StructTreeRoot *) uin->d; -- if (i-1 < root->getNumChildren() ){ -- child = root->getChild(i-1); -- uout = new_StructElement_userdata(L); -- uout->d = child; -- //uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- --static int m_StructTreeRoot_appendChild(lua_State * L) --{ -- udstruct *uin, *uin_child; -- StructElement *child ; -- StructTreeRoot *root ; -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructTreeRoot); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- uin_child = (udstruct *) luaL_checkudata(L, 2, M_StructElement); -- if (uin_child->pd != NULL && uin_child->pd->pc != uin_child->pc) -- pdfdoc_changed_error(L); -- root = (StructTreeRoot *) uin->d; -- child = (StructElement *) uin_child->d; -- root->appendChild(child); -- return 0; --} -- -- --static int m_StructTreeRoot_findParentElement(lua_State * L) --{ -- unsigned int i; -- udstruct *uin, *uout; -- const StructElement *parent ; -- StructTreeRoot *root ; -- -- uin = (udstruct *) luaL_checkudata(L, 1, M_StructTreeRoot); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- i = (unsigned) luaL_checkint(L, 2); -- root = (StructTreeRoot *) uin->d; -- parent = root->findParentElement(i-1); -- if (parent != NULL) { -- uout = new_StructElement_userdata(L); -- // see https://isocpp.org/wiki/faq/const-correctness#aliasing-and-const -- uout->d = (StructElement *) parent; -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- } else -- lua_pushnil(L); -- return 1; --} -- -- --static const struct luaL_Reg StructTreeRoot_m[] = { -- {"getDoc",m_StructTreeRoot_getDoc}, -- {"getRoleMap",m_StructTreeRoot_getRoleMap}, -- {"getClassMap",m_StructTreeRoot_getClassMap}, -- {"getNumChildren",m_StructTreeRoot_getNumChildren}, -- {"getChild",m_StructTreeRoot_getChild}, -- {"appendChild",m_StructTreeRoot_appendChild}, -- {"findParentElement",m_StructTreeRoot_findParentElement}, -- {"__tostring", m_StructTreeRoot__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// XRef -- --m_poppler_get_BOOL(XRef, isOk); --m_poppler_get_INT(XRef, getErrorCode); --m_poppler_get_BOOL(XRef, isEncrypted); --m_poppler_get_BOOL(XRef, okToPrint); --m_poppler_get_BOOL(XRef, okToPrintHighRes); --m_poppler_get_BOOL(XRef, okToChange); --m_poppler_get_BOOL(XRef, okToCopy); --m_poppler_get_BOOL(XRef, okToAddNotes); --m_poppler_get_BOOL(XRef, okToFillForm); --m_poppler_get_BOOL(XRef, okToAccessibility); --m_poppler_get_BOOL(XRef, okToAssemble); --m_poppler_get_OBJECT(XRef, getCatalog); -- --static int m_XRef_fetch(lua_State * L) --{ -- int num, gen; -- udstruct *uin, *uout; -- uin = (udstruct *) luaL_checkudata(L, 1, M_XRef); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- num = luaL_checkint(L, 2); -- gen = luaL_checkint(L, 3); -- uout = new_Object_userdata(L); -- uout->d = new Object(); -- *((Object *) uout->d) = ((XRef *) uin->d)->fetch(num, gen); -- uout->atype = ALLOC_LEPDF; -- uout->pc = uin->pc; -- uout->pd = uin->pd; -- return 1; --} -- --m_poppler_get_OBJECT(XRef, getDocInfo); --m_poppler_get_OBJECT(XRef, getDocInfoNF); --m_poppler_get_INT(XRef, getNumObjects); --m_poppler_get_INT(XRef, getRootNum); --m_poppler_get_INT(XRef, getRootGen); --// getStreamEnd -- --static int m_XRef_getNumEntry(lua_State * L) --{ -- int i, offset; -- udstruct *uin; -- uin = (udstruct *) luaL_checkudata(L, 1, M_XRef); -- if (uin->pd != NULL && uin->pd->pc != uin->pc) -- pdfdoc_changed_error(L); -- offset = luaL_checkint(L, 2); -- i = ((XRef *) uin->d)->getNumEntry(offset); -- if (i >= 0) -- lua_pushinteger(L, i); -- else -- lua_pushnil(L); -- return 1; --} -- --m_poppler_get_poppler(XRef, Object, getTrailerDict); -- --m_poppler__tostring(XRef); -- --static const struct luaL_Reg XRef_m[] = { -- {"isOk", m_XRef_isOk}, -- {"getErrorCode", m_XRef_getErrorCode}, -- {"isEncrypted", m_XRef_isEncrypted}, -- {"okToPrint", m_XRef_okToPrint}, -- {"okToPrintHighRes", m_XRef_okToPrintHighRes}, -- {"okToChange", m_XRef_okToChange}, -- {"okToCopy", m_XRef_okToCopy}, -- {"okToAddNotes", m_XRef_okToAddNotes}, -- {"okToFillForm", m_XRef_okToFillForm}, -- {"okToAccessibility", m_XRef_okToAccessibility}, -- {"okToAssemble", m_XRef_okToAssemble}, -- {"getCatalog", m_XRef_getCatalog}, -- {"fetch", m_XRef_fetch}, -- {"getDocInfo", m_XRef_getDocInfo}, -- {"getDocInfoNF", m_XRef_getDocInfoNF}, -- {"getNumObjects", m_XRef_getNumObjects}, -- {"getRootNum", m_XRef_getRootNum}, -- {"getRootGen", m_XRef_getRootGen}, -- // {"getStreamEnd", m_XRef_getStreamEnd}, -- {"getNumEntry", m_XRef_getNumEntry}, -- {"getTrailerDict", m_XRef_getTrailerDict}, -- {"__tostring", m_XRef__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** --// XRefEntry -- --m_poppler__tostring(XRefEntry); -- --static const struct luaL_Reg XRefEntry_m[] = { -- {"__tostring", m_XRefEntry__tostring}, -- {NULL, NULL} // sentinel --}; -- --//********************************************************************** -- --#ifdef LuajitTeX --#define setfuncs_meta(type) \ -- luaL_newmetatable(L, M_##type); \ -- lua_pushvalue(L, -1); \ -- lua_setfield(L, -2, "__index"); \ -- lua_pushstring(L, "no user access"); \ -- lua_setfield(L, -2, "__metatable"); \ -- luaL_openlib(L, NULL, type##_m, 0) --#else --#define setfuncs_meta(type) \ -- luaL_newmetatable(L, M_##type); \ -- lua_pushvalue(L, -1); \ -- lua_setfield(L, -2, "__index"); \ -- lua_pushstring(L, "no user access"); \ -- lua_setfield(L, -2, "__metatable"); \ -- luaL_setfuncs(L, type##_m, 0) --#endif -- --int luaopen_epdf(lua_State * L) --{ -- setfuncs_meta(Annot); -- setfuncs_meta(Annots); -- setfuncs_meta(Array); -- setfuncs_meta(Catalog); -- setfuncs_meta(Dict); -- setfuncs_meta(EmbFile); -- setfuncs_meta(FileSpec); -- setfuncs_meta(GooString); -- setfuncs_meta(LinkDest); -- setfuncs_meta(Links); -- setfuncs_meta(Object); -- setfuncs_meta(Page); -- setfuncs_meta(PDFDoc); -- setfuncs_meta(PDFRectangle); -- setfuncs_meta(Ref); -- setfuncs_meta(Stream); -- setfuncs_meta(Attribute); -- setfuncs_meta(StructElement); -- setfuncs_meta(StructTreeRoot); -- setfuncs_meta(TextSpan); -- setfuncs_meta(XRef); -- setfuncs_meta(XRefEntry); -- luaL_openlib(L, "epdf", epdflib_f, 0); -- return 1; --} -diff --git a/texk/web2c/luatexdir/lua/lfontlib.c b/texk/web2c/luatexdir/lua/lfontlib.c -index a709e42c4..2592ffba6 100644 ---- a/texk/web2c/luatexdir/lua/lfontlib.c -+++ b/texk/web2c/luatexdir/lua/lfontlib.c -@@ -324,7 +324,9 @@ static int l_vf_char(lua_State * L) - } - mat_p = &(vsp->packet_stack[vsp->packet_stack_level]); - w = char_width(lf, k); -- mat_p->pos.h += round_xn_over_d(w, 1000 + ex_glyph, 1000); -+ if (ex_glyph != 0) -+ w = round_xn_over_d(w, 1000 + ex_glyph, 1000); -+ mat_p->pos.h += w; - synch_pos_with_cur(static_pdf->posstruct, vsp->refpos, mat_p->pos); - return 0; - } -@@ -416,11 +418,14 @@ static int l_vf_right(lua_State * L) - { - scaled i; - vf_struct *vsp = static_pdf->vfstruct; -+ int ex_glyph = vsp->ex_glyph/1000; - packet_stack_record *mat_p; - if (!vsp->vflua) - normal_error("vf", "vf.right() outside virtual font"); - mat_p = &(vsp->packet_stack[vsp->packet_stack_level]); - i = (scaled) luaL_checkinteger(L, 1); -+ if (ex_glyph != 0 && i != 0) /* new, experiment */ -+ i = round_xn_over_d(i, 1000 + ex_glyph, 1000); - i = store_scaled_f(i, vsp->fs_f); - mat_p->pos.h += i; - synch_pos_with_cur(static_pdf->posstruct, vsp->refpos, mat_p->pos); -@@ -431,11 +436,14 @@ static int l_vf_rule(lua_State * L) - { - scaledpos size; - vf_struct *vsp = static_pdf->vfstruct; -+ int ex_glyph = vsp->ex_glyph/1000; - packet_stack_record *mat_p; - if (!vsp->vflua) - normal_error("vf", "vf.rule() outside virtual font"); - size.h = (scaled) luaL_checkinteger(L, 1); - size.v = (scaled) luaL_checkinteger(L, 2); -+ if (ex_glyph != 0 && size.h > 0) /* new, experiment */ -+ size.h = round_xn_over_d(size.h, 1000 + ex_glyph, 1000); - size.h = store_scaled_f(size.h, vsp->fs_f); - size.v = store_scaled_f(size.v, vsp->fs_f); - if (size.h > 0 && size.v > 0) -@@ -460,6 +468,16 @@ static int l_vf_special(lua_State * L) - return 0; - } - -+static int l_vf_pdf(lua_State * L) -+{ -+ vf_struct *vsp = static_pdf->vfstruct; -+ if (!vsp->vflua) -+ normal_error("vf", "vf.special() outside virtual font"); -+ luapdfprint(L); -+ pdf_out(static_pdf, '\n'); -+ return 0; -+} -+ - static const struct luaL_Reg vflib[] = { - {"char", l_vf_char}, - {"down", l_vf_down}, -@@ -476,6 +494,7 @@ static const struct luaL_Reg vflib[] = { - /* {"scale", l_vf_scale}, */ - /* {"slot", l_vf_slot}, */ - {"special", l_vf_special}, -+ {"pdf", l_vf_pdf}, - {NULL, NULL} /* sentinel */ - }; - -diff --git a/texk/web2c/luatexdir/lua/limglib.c b/texk/web2c/luatexdir/lua/limglib.c -index f9d863eef..ce2b4b7b5 100644 ---- a/texk/web2c/luatexdir/lua/limglib.c -+++ b/texk/web2c/luatexdir/lua/limglib.c -@@ -24,7 +24,7 @@ - #include "lua.h" - #include "lauxlib.h" - --#define img_types_max 7 -+#define img_types_max 8 - - const char *img_types[] = { - "none", -@@ -243,6 +243,26 @@ static void write_image_or_node(lua_State * L, wrtype_e writetype) - img_state(ad) = DICT_REFERED; - } - -+static int write_image_object(lua_State * L, wrtype_e writetype) -+{ -+ image *a, **aa; -+ image_dict *ad; -+ int num; -+ if (lua_gettop(L) != 2) -+ luaL_error(L, "%s expects two argument", wrtype_s[writetype]); -+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); -+ a = *aa; -+ ad = img_dict(a); -+ -+ read_img(ad); -+ -+ /* setup_image(static_pdf, a, writetype); */ -+ num = (int) lua_tointeger(L, 2); -+ num = write_img_object(static_pdf, ad, num); -+ lua_pushinteger(L,num); -+ return 1; -+} -+ - static int l_write_image(lua_State * L) - { - write_image_or_node(L, WR_WRITE); -@@ -260,6 +280,17 @@ static int l_immediatewrite_image(lua_State * L) - return 1; - } - -+static int l_immediatewrite_image_object(lua_State * L) -+{ -+ check_o_mode(static_pdf, "img.immediatewriteobject", 1 << OMODE_PDF, true); -+ if (global_shipping_mode != NOT_SHIPPING) { -+ luaL_error(L, "img.immediatewriteobject can not be used with \\latelua"); -+ } else { -+ write_image_object(L, WR_IMMEDIATEWRITE); -+ } -+ return 1; -+} -+ - static int l_image_node(lua_State * L) - { - write_image_or_node(L, WR_NODE); -@@ -273,7 +304,7 @@ static int l_image_keys(lua_State * L) - - static int l_image_types(lua_State * L) - { -- return lua_show_valid_list(L, img_types, img_types_max); -+ return lua_show_valid_list(L, img_types, 0, img_types_max); - } - - static int l_image_boxes(lua_State * L) -@@ -287,10 +318,13 @@ static const struct luaL_Reg imglib_f[] = { - { "scan", l_scan_image }, - { "write", l_write_image }, - { "immediatewrite", l_immediatewrite_image }, -+ { "immediatewriteobject", l_immediatewrite_image_object }, - { "node", l_image_node }, -- { "keys", l_image_keys }, -+ { "fields", l_image_keys }, - { "types", l_image_types }, - { "boxes", l_image_boxes }, -+ /* for a while: */ -+ { "keys", l_image_keys }, - { NULL, NULL } - }; - -@@ -348,14 +382,10 @@ static int m_img_get(lua_State * L) - } else { - lua_pushstring(L, img_filename(d)); - } -- } else if (lua_key_eq(s,visiblefilename)) { -- if (img_visiblefilename(d) == NULL || strlen(img_visiblefilename(d)) == 0) { -- lua_pushnil(L); -- } else { -- lua_pushstring(L, img_visiblefilename(d)); -- } - } else if (lua_key_eq(s,keepopen)) { - lua_pushboolean(L, img_keepopen(d)); -+ } else if (lua_key_eq(s,nolength)) { -+ lua_pushboolean(L, img_nolength(d)); - } else if (lua_key_eq(s,filepath)) { - if (img_filepath(d) == NULL || strlen(img_filepath(d)) == 0) { - lua_pushnil(L); -@@ -461,10 +491,28 @@ static int m_img_get(lua_State * L) - if (img_type(d) != IMG_TYPE_PDFSTREAM - || img_pdfstream_ptr(d) == NULL - || img_pdfstream_stream(d) == NULL -- || strlen(img_pdfstream_stream(d)) == 0) { -+ || img_pdfstream_size(d) == 0) { -+ lua_pushnil(L); -+ } else { -+ lua_pushlstring(L, img_pdfstream_stream(d), img_pdfstream_size(d)); -+ } -+ } else if (lua_key_eq(s,visiblefilename)) { -+ if (img_visiblefilename(d) == NULL || strlen(img_visiblefilename(d)) == 0) { -+ lua_pushnil(L); -+ } else { -+ lua_pushstring(L, img_visiblefilename(d)); -+ } -+ } else if (lua_key_eq(s,userpassword)) { -+ if (img_userpassword(d) == NULL || strlen(img_userpassword(d)) == 0) { -+ lua_pushnil(L); -+ } else { -+ lua_pushstring(L, img_userpassword(d)); -+ } -+ } else if (lua_key_eq(s,ownerpassword)) { -+ if (img_ownerpassword(d) == NULL || strlen(img_ownerpassword(d)) == 0) { - lua_pushnil(L); - } else { -- lua_pushstring(L, img_pdfstream_stream(d)); -+ lua_pushstring(L, img_ownerpassword(d)); - } - } else if (lua_key_eq(s,ref_count)) { - lua_pushinteger(L, img_luaref(d)); -@@ -520,7 +568,7 @@ static void lua_to_image(lua_State * L, image * a, image_dict * d) - if (img_state(d) >= DICT_FILESCANNED) { - luaL_error(L, "image.filename is now read-only"); - } else if (img_type(d) == IMG_TYPE_PDFSTREAM) { -- luaL_error(L, "image.filename can't be used with image.stream"); -+ /* just ignore */ - } else if (t == LUA_TSTRING) { - xfree(img_filename(d)); - img_filename(d) = xstrdup(lua_tostring(L, -1)); -@@ -531,13 +579,35 @@ static void lua_to_image(lua_State * L, image * a, image_dict * d) - if (img_state(d) >= DICT_FILESCANNED) { - luaL_error(L, "image.visiblefilename is now read-only"); - } else if (img_type(d) == IMG_TYPE_PDFSTREAM) { -- luaL_error(L, "image.visiblefilename can't be used with image.stream"); -+ img_visiblefilename(d) = NULL; - } else if (t == LUA_TSTRING) { - xfree(img_visiblefilename(d)); - img_visiblefilename(d) = xstrdup(lua_tostring(L, -1)); - } else { - luaL_error(L, "image.visiblefilename needs string value"); - } -+ } else if (lua_key_eq(s,userpassword)) { -+ if (img_state(d) >= DICT_FILESCANNED) { -+ luaL_error(L, "image.userpassword is now read-only"); -+ } else if (img_type(d) == IMG_TYPE_PDFSTREAM) { -+ img_userpassword(d) = NULL; -+ } else if (t == LUA_TSTRING) { -+ xfree(img_userpassword(d)); -+ img_userpassword(d) = xstrdup(lua_tostring(L, -1)); -+ } else { -+ luaL_error(L, "image.userpassword needs string value"); -+ } -+ } else if (lua_key_eq(s,ownerpassword)) { -+ if (img_state(d) >= DICT_FILESCANNED) { -+ luaL_error(L, "image.ownerpassword is now read-only"); -+ } else if (img_type(d) == IMG_TYPE_PDFSTREAM) { -+ img_ownerpassword(d) = NULL; -+ } else if (t == LUA_TSTRING) { -+ xfree(img_ownerpassword(d)); -+ img_ownerpassword(d) = xstrdup(lua_tostring(L, -1)); -+ } else { -+ luaL_error(L, "image.ownerpassword needs string value"); -+ } - } else if (lua_key_eq(s,attr)) { - if (img_state(d) >= DICT_FILESCANNED) { - luaL_error(L, "image.attr is now read-only"); -@@ -607,6 +677,8 @@ static void lua_to_image(lua_State * L, image * a, image_dict * d) - } else { - img_keepopen(d) = lua_toboolean(L, -1); - } -+ } else if (lua_key_eq(s,nolength)) { -+ img_nolength(d) = lua_toboolean(L, -1); - } else if (lua_key_eq(s,bbox)) { - if (img_state(d) >= DICT_FILESCANNED) { - luaL_error(L, "image.bbox is now read-only"); -@@ -636,11 +708,15 @@ static void lua_to_image(lua_State * L, image * a, image_dict * d) - } else if (img_state(d) >= DICT_FILESCANNED) { - luaL_error(L, "image.stream is now read-only"); - } else { -+ size_t size = 0; -+ const char *stream = lua_tolstring(L, -1, &size); - if (img_pdfstream_ptr(d) == NULL) { - new_img_pdfstream_struct(d); - } - xfree(img_pdfstream_stream(d)); -- img_pdfstream_stream(d) = xstrdup(lua_tostring(L, -1)); -+ img_pdfstream_size(d) = size; -+ img_pdfstream_stream(d) = xmalloc(size); -+ memcpy(img_pdfstream_stream(d),stream,size); - img_type(d) = IMG_TYPE_PDFSTREAM; - } - } else { -diff --git a/texk/web2c/luatexdir/lua/liolibext.c b/texk/web2c/luatexdir/lua/liolibext.c -index 29ad8447a..71b9b41d1 100644 ---- a/texk/web2c/luatexdir/lua/liolibext.c -+++ b/texk/web2c/luatexdir/lua/liolibext.c -@@ -125,7 +125,7 @@ static int readcardinal1_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p >= l) { -+ if (p >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p]); -@@ -150,7 +150,7 @@ static int readcardinal2_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+1 >= l) { -+ if (p+1 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -177,7 +177,7 @@ static int readcardinal3_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+2 >= l) { -+ if (p+2 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -206,7 +206,7 @@ static int readcardinal4_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+3 >= l) { -+ if (p+3 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -218,6 +218,139 @@ static int readcardinal4_s(lua_State *L) { - return 1; - } - -+static int readcardinaltable(lua_State *L) { -+ FILE *f = tofile(L); -+ int n = lua_tointeger(L,2); -+ int b = lua_tointeger(L,3); -+ int i; -+ lua_createtable(L,n,0); -+ switch (b) { -+ case 1: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ if (a == EOF) { -+ break; -+ } else { -+ lua_pushinteger(L, a); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 2: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ if (b == EOF) { -+ break; -+ } else { -+ /* (a<<8) | b */ -+ lua_pushinteger(L, 0x100 * a + b); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 3: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ int c = getc(f); -+ if (c == EOF) { -+ break; -+ } else { -+ /* (a<<16) | (b<<8) | c */ -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 4: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ int c = getc(f); -+ int d = getc(f); -+ if (d == EOF) { -+ break; -+ } else { -+ /* (a<<24) | (b<<16) | (c<<8) | d */ -+ lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ return 1; -+} -+ -+static int readcardinaltable_s(lua_State *L) { -+ size_t l; -+ const char *s = luaL_checklstring(L, 1, &l); -+ size_t p = luaL_checkinteger(L, 2) - 1; -+ int n = lua_tointeger(L,3); -+ int b = lua_tointeger(L,4); -+ int i; -+ lua_createtable(L,n,0); -+ /*if (p >= 0) {*/ -+ switch (b) { -+ case 1: -+ for (i=1;i<=n;i++) { -+ if (p >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ lua_pushinteger(L, a); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 2: -+ for (i=1;i<=n;i++) { -+ if (p+1 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ lua_pushinteger(L, 0x100 * a + b); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 3: -+ for (i=1;i<=n;i++) { -+ if (p+2 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ int c = uchar(s[p++]); -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 4: -+ for (i=1;i<=n;i++) { -+ if (p+3 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ int c = uchar(s[p++]); -+ int d = uchar(s[p++]); -+ lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d); -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ /*}*/ -+ return 1; -+} -+ - static int readinteger1(lua_State *L) { - FILE *f = tofile(L); - int a = getc(f); -@@ -234,7 +367,7 @@ static int readinteger1_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p >= l) { -+ if (p >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p]); -@@ -263,7 +396,7 @@ static int readinteger2_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+1 >= l) { -+ if (p+1 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -294,7 +427,7 @@ static int readinteger3_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+2 >= l) { -+ if (p+2 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -327,7 +460,7 @@ static int readinteger4_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+3 >= l) { -+ if (p+3 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -342,6 +475,160 @@ static int readinteger4_s(lua_State *L) { - return 1; - } - -+static int readintegertable(lua_State *L) { -+ FILE *f = tofile(L); -+ int n = lua_tointeger(L,2); -+ int b = lua_tointeger(L,3); -+ int i; -+ lua_createtable(L,n,0); -+ switch (b) { -+ case 1: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ if (a == EOF) { -+ break; -+ } else if (a >= 0x80) { -+ lua_pushinteger(L, a - 0x100); -+ } else { -+ lua_pushinteger(L, a); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ break; -+ case 2: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ if (b == EOF) { -+ break; -+ } else if (a >= 0x80) { -+ lua_pushinteger(L, 0x100 * a + b - 0x10000); -+ } else { -+ lua_pushinteger(L, 0x100 * a + b); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ break; -+ case 3: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ int c = getc(f); -+ if (c == EOF) { -+ break; -+ } else if (a >= 0x80) { -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); -+ } else { -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ break; -+ case 4: -+ for (i=1;i<=n;i++) { -+ int a = getc(f); -+ int b = getc(f); -+ int c = getc(f); -+ int d = getc(f); -+ if (d == EOF) { -+ break; -+ } else if (a >= 0x80) { -+ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); -+ } else { -+ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ break; -+ default: -+ break; -+ } -+ return 1; -+} -+ -+static int readintegertable_s(lua_State *L) { -+ size_t l; -+ const char *s = luaL_checklstring(L, 1, &l); -+ size_t p = luaL_checkinteger(L, 2) - 1; -+ int n = lua_tointeger(L,3); -+ int b = lua_tointeger(L,4); -+ int i; -+ lua_createtable(L,n,0); -+ /*if (p >= 0) {*/ -+ switch (b) { -+ case 1: -+ for (i=1;i<=n;i++) { -+ if (p >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ if (a >= 0x80) { -+ lua_pushinteger(L, a - 0x100); -+ } else { -+ lua_pushinteger(L, a); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 2: -+ for (i=1;i<=n;i++) { -+ if (p+1 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ if (a >= 0x80) { -+ lua_pushinteger(L, 0x100 * a + b - 0x10000); -+ } else { -+ lua_pushinteger(L, 0x100 * a + b); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 3: -+ for (i=1;i<=n;i++) { -+ if (p+2 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ int c = uchar(s[p++]); -+ if (a >= 0x80) { -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000); -+ } else { -+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ case 4: -+ for (i=1;i<=n;i++) { -+ if (p+3 >= l) { -+ break; -+ } else { -+ int a = uchar(s[p++]); -+ int b = uchar(s[p++]); -+ int c = uchar(s[p++]); -+ int d = uchar(s[p++]); -+ if (a >= 0x80) { -+ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000); -+ } else { -+ lua_pushinteger(L, 0x1000000 * a + 0x10000 * b + 0x100 * c + d); -+ } -+ lua_rawseti(L, -2, i); -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ /*}*/ -+ return 1; -+} -+ - static int readfixed2(lua_State *L) { - FILE *f = tofile(L); - int a = getc(f); -@@ -359,7 +646,7 @@ static int readfixed2_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+3 >= l) { -+ if (p+3 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -394,7 +681,7 @@ static int readfixed4_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+3 >= l) { -+ if (p+3 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -427,7 +714,7 @@ static int read2dot14_s(lua_State *L) { - size_t l; - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; -- if (p < 0 || p+1 >= l) { -+ if (p+1 >= l) { - lua_pushnil(L); - } else { - int a = uchar(s[p++]); -@@ -497,7 +784,7 @@ static int readbytetable_s(lua_State *L) { - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; - int n = lua_tointeger(L,3); -- if (p < 0 || p >= l) { -+ if (p >= l) { - lua_pushnil(L); - } else { - int i ; -@@ -534,7 +821,7 @@ static int readbytes_s(lua_State *L) { - const char *s = luaL_checklstring(L, 1, &l); - size_t p = luaL_checkinteger(L, 2) - 1; - int n = lua_tointeger(L,3); -- if (p < 0 || p >= l) { -+ if (p >= l) { - return 0; - } else { - int i ; -@@ -644,44 +931,48 @@ static int readline(lua_State *L) - - static const luaL_Reg fiolib[] = { - /* helpers */ -- { "readcardinal1", readcardinal1 }, -- { "readcardinal2", readcardinal2 }, -- { "readcardinal3", readcardinal3 }, -- { "readcardinal4", readcardinal4 }, -- { "readinteger1", readinteger1 }, -- { "readinteger2", readinteger2 }, -- { "readinteger3", readinteger3 }, -- { "readinteger4", readinteger4 }, -- { "readfixed2", readfixed2 }, -- { "readfixed4", readfixed4 }, -- { "read2dot14", read2dot14 }, -- { "setposition", setposition }, -- { "getposition", getposition }, -- { "skipposition", skipposition }, -- { "readbytes", readbytes }, -- { "readbytetable", readbytetable }, -- { "readline", readline }, -+ { "readcardinal1", readcardinal1 }, -+ { "readcardinal2", readcardinal2 }, -+ { "readcardinal3", readcardinal3 }, -+ { "readcardinal4", readcardinal4 }, -+ { "readcardinaltable", readcardinaltable }, -+ { "readinteger1", readinteger1 }, -+ { "readinteger2", readinteger2 }, -+ { "readinteger3", readinteger3 }, -+ { "readinteger4", readinteger4 }, -+ { "readintegertable", readintegertable }, -+ { "readfixed2", readfixed2 }, -+ { "readfixed4", readfixed4 }, -+ { "read2dot14", read2dot14 }, -+ { "setposition", setposition }, -+ { "getposition", getposition }, -+ { "skipposition", skipposition }, -+ { "readbytes", readbytes }, -+ { "readbytetable", readbytetable }, -+ { "readline", readline }, - /* extras */ -- { "recordfilename", recordfilename }, -- { "checkpermission", checkpermission }, -+ { "recordfilename", recordfilename }, -+ { "checkpermission", checkpermission }, - /* done */ - {NULL, NULL} - }; - - static const luaL_Reg siolib[] = { -- { "readcardinal1", readcardinal1_s }, -- { "readcardinal2", readcardinal2_s }, -- { "readcardinal3", readcardinal3_s }, -- { "readcardinal4", readcardinal4_s }, -- { "readinteger1", readinteger1_s }, -- { "readinteger2", readinteger2_s }, -- { "readinteger3", readinteger3_s }, -- { "readinteger4", readinteger4_s }, -- { "readfixed2", readfixed2_s }, -- { "readfixed4", readfixed4_s }, -- { "read2dot14", read2dot14_s }, -- { "readbytes", readbytes_s }, -- { "readbytetable", readbytetable_s }, -+ { "readcardinal1", readcardinal1_s }, -+ { "readcardinal2", readcardinal2_s }, -+ { "readcardinal3", readcardinal3_s }, -+ { "readcardinal4", readcardinal4_s }, -+ { "readcardinaltable", readcardinaltable_s }, -+ { "readinteger1", readinteger1_s }, -+ { "readinteger2", readinteger2_s }, -+ { "readinteger3", readinteger3_s }, -+ { "readinteger4", readinteger4_s }, -+ { "readintegertable", readintegertable_s }, -+ { "readfixed2", readfixed2_s }, -+ { "readfixed4", readfixed4_s }, -+ { "read2dot14", read2dot14_s }, -+ { "readbytes", readbytes_s }, -+ { "readbytetable", readbytetable_s }, - /* done */ - {NULL, NULL} - }; -diff --git a/texk/web2c/luatexdir/lua/llanglib.c b/texk/web2c/luatexdir/lua/llanglib.c -index 382d40944..5855f33fc 100644 ---- a/texk/web2c/luatexdir/lua/llanglib.c -+++ b/texk/web2c/luatexdir/lua/llanglib.c -@@ -20,7 +20,6 @@ - #include "ptexlib.h" - #include "lua/luatex-api.h" - -- - #define LANG_METATABLE "luatex.lang" - - #define check_islang(L,b) (struct tex_language **)luaL_checkudata(L,b,LANG_METATABLE) -@@ -84,7 +83,6 @@ static int lang_clear_patterns(lua_State * L) - return 0; - } - -- - static int lang_hyphenation(lua_State * L) - { - struct tex_language **lang_ptr; -@@ -137,7 +135,6 @@ static int lang_post_hyphen_char(lua_State * L) - } - } - -- - static int lang_pre_exhyphen_char(lua_State * L) - { - struct tex_language **lang_ptr; -@@ -262,7 +259,6 @@ static int do_lang_hyphenate(lua_State * L) - } - - static const struct luaL_Reg langlib_d[] = { -- /* *INDENT-OFF* */ - {"clear_patterns", lang_clear_patterns}, - {"clear_hyphenation", lang_clear_hyphenation}, - {"patterns", lang_patterns}, -@@ -275,13 +271,11 @@ static const struct luaL_Reg langlib_d[] = { - {"sethjcode", lang_sethjcode}, - {"gethjcode", lang_gethjcode}, - {"id", lang_id}, -- /* *INDENT-ON* */ -- {NULL, NULL} /* sentinel */ -+ /*tex sentinel */ -+ {NULL, NULL} - }; - -- - static const struct luaL_Reg langlib[] = { -- /* *INDENT-OFF* */ - {"clear_patterns", lang_clear_patterns}, - {"clear_hyphenation", lang_clear_hyphenation}, - {"patterns", lang_patterns}, -@@ -297,17 +291,19 @@ static const struct luaL_Reg langlib[] = { - {"clean", do_lang_clean}, - {"hyphenate", do_lang_hyphenate}, - {"new", lang_new}, -- /* *INDENT-ON* */ -- {NULL, NULL} /* sentinel */ -+ /*tex sentinel */ -+ {NULL, NULL} - }; - -- - int luaopen_lang(lua_State * L) - { - luaL_newmetatable(L, LANG_METATABLE); -- lua_pushvalue(L, -1); /* push metatable */ -- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ -- luaL_openlib(L, NULL, langlib_d, 0); /* dict methods */ -+ /*tex push metatable */ -+ lua_pushvalue(L, -1); -+ /*tex metatable.__index = metatable */ -+ lua_setfield(L, -2, "__index"); -+ /*tex set dict methods */ -+ luaL_openlib(L, NULL, langlib_d, 0); - luaL_openlib(L, "lang", langlib, 0); - return 1; - } -diff --git a/texk/web2c/luatexdir/lua/llualib.c b/texk/web2c/luatexdir/lua/llualib.c -index a73e3abf2..ac9b03ffe 100644 ---- a/texk/web2c/luatexdir/lua/llualib.c -+++ b/texk/web2c/luatexdir/lua/llualib.c -@@ -20,14 +20,13 @@ - #include "ptexlib.h" - #include "lua/luatex-api.h" - -- --#define LOAD_BUF_SIZE 256 -+#define LOAD_BUF_SIZE 64*1024 - #define UINT_MAX32 0xFFFFFFFF - - typedef struct { - unsigned char *buf; - int size; -- int done; -+ /* int done; */ - int alloc; - } bytecode; - -@@ -95,7 +94,7 @@ void undump_luac_registers(void) - lua_bytecode_registers = xmalloc((unsigned) (i * sizeof(bytecode))); - luabytecode_bytes = (unsigned) (i * sizeof(bytecode)); - for (i = 0; i <= (unsigned) luabytecode_max; i++) { -- lua_bytecode_registers[i].done = 0; -+ /* lua_bytecode_registers[i].done = 0; */ - lua_bytecode_registers[i].size = 0; - lua_bytecode_registers[i].buf = NULL; - } -@@ -170,14 +169,18 @@ static int writer(lua_State * L, const void *b, size_t size, void *B) - static const char *reader(lua_State * L, void *ud, size_t * size) - { - bytecode *buf = (bytecode *) ud; -- (void) L; /* for -Wunused */ -+ (void) L; /* for -Wunused */ -+ /* - if (buf->done == buf->size) { - *size = 0; - buf->done = 0; - return NULL; - } -+ */ - *size = (size_t) buf->size; -+ /* - buf->done = buf->size; -+ */ - return (const char *) buf->buf; - } - -@@ -196,7 +199,7 @@ static int get_bytecode(lua_State * L) - #else - "bytecode", NULL)) { - #endif -- return luaL_error(L, "bad bytecode register"); -+ return luaL_error(L, "bad bytecode register"); - } else { - lua_pushvalue(L, -1); - bytecode_register_shadow_set(L, k); -@@ -208,6 +211,41 @@ static int get_bytecode(lua_State * L) - return 1; - } - -+void luabytecodecall(int slot) -+{ -+ int i; -+ int stacktop = lua_gettop(Luas); -+ lua_active++; -+ if (slot < 0 || slot > luabytecode_max) { -+ luaL_error(Luas, "bytecode register out of range"); -+ } else if (bytecode_register_shadow_get(Luas, slot) || lua_bytecode_registers[slot].buf == NULL) { -+ luaL_error(Luas, "undefined bytecode register"); -+ } else if (lua_load(Luas, reader, (void *) (lua_bytecode_registers + slot), -+#ifdef LuajitTeX -+ "bytecode")) -+#else -+ "bytecode", NULL)) -+#endif -+ { -+ luaL_error(Luas, "bytecode register doesn't load well"); -+ } else { -+ int base = lua_gettop(Luas); /* function index */ -+ lua_pushinteger(Luas, slot); -+ lua_pushcfunction(Luas, lua_traceback); /* push traceback function */ -+ lua_insert(Luas, base); /* put it under chunk */ -+++function_callback_count; /* this will be a dedicated counter */ -+ i = lua_pcall(Luas, 1, 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)); -+ } -+ } -+ -+ lua_settop(Luas,stacktop); -+ lua_active--; -+} -+ - static int set_bytecode(lua_State * L) - { - int k, ltype; -@@ -244,7 +282,7 @@ static int set_bytecode(lua_State * L) - for (i = (unsigned) (luabytecode_max + 1); i <= (unsigned) k; i++) { - lua_bytecode_registers[i].buf = NULL; - lua_bytecode_registers[i].size = 0; -- lua_bytecode_registers[i].done = 0; -+ /* lua_bytecode_registers[i].done = 0; */ - } - luabytecode_max = k; - } -@@ -252,7 +290,7 @@ static int set_bytecode(lua_State * L) - xfree(lua_bytecode_registers[k].buf); - luabytecode_bytes -= (unsigned) lua_bytecode_registers[k].size; - lua_bytecode_registers[k].size = 0; -- lua_bytecode_registers[k].done = 0; -+ /* lua_bytecode_registers[k].done = 0; */ - lua_pushnil(L); - bytecode_register_shadow_set(L, k); - } -@@ -268,7 +306,7 @@ static int set_bytecode(lua_State * L) - lua_dump(L, writer, (void *) (lua_bytecode_registers + k),strip); - #endif - #if LUA_VERSION_NUM == 502 -- lua_dump(L, writer, (void *) (lua_bytecode_registers + k)); -+ lua_dump(L, writer, (void *) (lua_bytecode_registers + k)); - #endif - #endif - } -@@ -329,6 +367,18 @@ static int new_table(lua_State * L) /* hh */ - return 1; - } - -+static int get_stack_top(lua_State * L) /* hh */ -+{ -+ lua_pushinteger(L, lua_gettop(L)); -+ return 1; -+} -+ -+static int get_call_level(lua_State * L) /* hh */ -+{ -+ lua_pushinteger(L, lua_active); -+ return 1; -+} -+ - static const struct luaL_Reg lualib[] = { - /* *INDENT-OFF* */ - {"getluaname", get_luaname}, -@@ -337,6 +387,8 @@ static const struct luaL_Reg lualib[] = { - {"setbytecode", set_bytecode}, - {"newtable", new_table}, - {"get_functions_table",lua_functions_get_table}, -+ {"getstacktop",get_stack_top}, -+ {"getcalllevel", get_call_level}, - /* *INDENT-ON* */ - {NULL, NULL} /* sentinel */ - }; -diff --git a/texk/web2c/luatexdir/lua/lnewtokenlib.c b/texk/web2c/luatexdir/lua/lnewtokenlib.c -index 085129d54..3e879b54a 100644 ---- a/texk/web2c/luatexdir/lua/lnewtokenlib.c -+++ b/texk/web2c/luatexdir/lua/lnewtokenlib.c -@@ -33,10 +33,12 @@ - #include "ptexlib.h" - #include "lua/luatex-api.h" - -+/* - typedef struct lua_token { - int token; - int origin; - } lua_token; -+*/ - - typedef struct saved_tex_scanner { - int token; -@@ -145,33 +147,51 @@ static void push_token(lua_State * L, int tok) - lua_setmetatable(L, -2); - } - --/* static int run_get_cs_offset(lua_State * L) */ --/* { */ --/* lua_pushinteger(L, cs_token_flag); */ --/* return 1; */ --/* } */ -- --/* static int run_get_command_id(lua_State * L) */ --/* { */ --/* int cs = -1; */ --/* if (lua_type(L, -1) == LUA_TSTRING) { */ --/* cs = get_command_id(lua_tostring(L, -1)); */ --/* } */ --/* lua_pushinteger(L, cs); */ --/* return 1; */ --/* } */ -- --/* static int run_get_csname_id(lua_State * L) */ --/* { */ --/* const char *s; */ --/* size_t k, cs = 0; */ --/* if (lua_type(L, -1) == LUA_TSTRING) { */ --/* s = lua_tolstring(L, -1, &k); */ --/* cs = (size_t) string_lookup(s, k); */ --/* } */ --/* lua_pushinteger(L, (lua_Number) cs); */ --/* return 1; */ --/* } */ -+static int run_get_biggest_char(lua_State * L) -+{ -+ lua_pushinteger(L, biggest_char); -+ return 1; -+} -+ -+/* not that useful: -+ -+static int run_get_cs_offset(lua_State * L) -+{ -+ lua_pushinteger(L, cs_token_flag); -+ return 1; -+} -+ -+*/ -+ -+static int run_get_command_id(lua_State * L) -+{ -+ int id = -1; -+ if (lua_type(L, -1) == LUA_TSTRING) { -+ id = get_command_id(lua_tostring(L, -1)); -+ } -+ if (id >= 0) { -+ lua_pushinteger(L, id); -+ } else { -+ lua_pushnil(L); -+ } -+ return 1; -+} -+ -+/* not that useful: -+ -+static int run_get_csname_id(lua_State * L) -+{ -+ const char *s; -+ size_t k, cs = 0; -+ if (lua_type(L, -1) == LUA_TSTRING) { -+ s = lua_tolstring(L, -1, &k); -+ cs = (size_t) string_lookup(s, k); -+ } -+ lua_pushinteger(L, (lua_Number) cs); -+ return 1; -+} -+ -+*/ - - static int run_get_next(lua_State * L) - { -@@ -296,6 +316,22 @@ static int run_scan_keyword(lua_State * L) - return 1; - } - -+static int run_scan_keyword_cs(lua_State * L) -+{ -+ saved_tex_scanner texstate; -+ const char *s = luaL_checkstring(L, -1); -+ int v = 0; -+ if (s) { -+ save_tex_scanner(texstate); -+ if (scan_keyword_case_sensitive(s)) { -+ v = 1; -+ } -+ unsave_tex_scanner(texstate); -+ } -+ lua_pushboolean(L,v); -+ return 1; -+} -+ - static int run_scan_csname(lua_State * L) - { - unsigned char *s; -@@ -328,6 +364,138 @@ static int run_scan_int(lua_State * L) - return 1; - } - -+/* -+ char * str ; -+*/ -+ -+# define declare_buffer \ -+ unsigned char word[5 + 1]; \ -+ char *uindex = (char *)word; \ -+ luaL_Buffer b ; \ -+ luaL_buffinit(L,&b) ; -+ -+/* -+ str = (char *) uni2str(cur_chr); -+ luaL_addstring(&b,(char *) str); -+ xfree(str); -+*/ -+ -+# define add_to_buffer(chr) \ -+ if (chr <= 255) { \ -+ luaL_addchar(&b,(unsigned) (char) chr); \ -+ } else { \ -+ uindex = uni2string((char *)word,(unsigned) chr); \ -+ *uindex = '\0'; \ -+ luaL_addstring(&b,(char *) word); \ -+ } -+ -+# define push_buffer \ -+ luaL_pushresult(&b); -+ -+static int run_scan_float_indeed(lua_State * L, boolean exponent) -+{ -+ saved_tex_scanner texstate; -+ int ok; -+ boolean negative = false; -+ double d; -+ declare_buffer; -+ save_tex_scanner(texstate); -+ /* we collapse as in scan_dimen */ -+ while(1) { -+ do { -+ get_x_token(); -+ } while (cur_cmd == spacer_cmd); -+ if (cur_tok == minus_token) { -+ negative = !negative; -+ } else if (cur_tok != plus_token) { -+ break; -+ } -+ } -+ if (negative) { -+ add_to_buffer('-'); -+ } -+ /* we accept [.,]digits */ -+ if (cur_tok == point_token || cur_tok == comma_token) { -+ add_to_buffer('.'); -+ while (1) { -+ get_x_token(); -+ if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) { -+ add_to_buffer(cur_chr); -+ } else if (exponent) { -+ goto EXPONENT; -+ } else { -+ back_input(); -+ goto DONE; -+ } -+ } -+ } else { -+ back_input(); -+ while (1) { -+ get_x_token(); -+ if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) { -+ add_to_buffer(cur_chr); -+ } else { -+ if (cur_tok == point_token || cur_tok == comma_token) { -+ add_to_buffer('.'); -+ while (1) { -+ get_x_token(); -+ if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) { -+ add_to_buffer(cur_chr); -+ } else { -+ back_input(); -+ break; -+ } -+ } -+ } else if (exponent) { -+ goto EXPONENT; -+ } else { -+ back_input(); -+ goto DONE; -+ } -+ } -+ } -+ } -+EXPONENT: -+ if ((cur_chr == 'E') || (cur_chr == 'e')) { -+ add_to_buffer(cur_chr); -+ get_x_token(); -+ if ((cur_tok == minus_token) || (cur_tok == plus_token)) { -+ add_to_buffer(cur_chr); -+ } else if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) { -+ add_to_buffer(cur_chr); -+ } -+ while (1) { -+ get_x_token(); -+ if ((cur_tok >= zero_token) && (cur_tok <= nine_token)) { -+ add_to_buffer(cur_chr); -+ } else { -+ break; -+ } -+ } -+ } -+ back_input(); -+DONE: -+ push_buffer; -+ d = lua_tonumberx(L,1,&ok); -+ if (ok) { -+ lua_pushnumber(L,d); -+ } else { -+ lua_pushnil(L); -+ } -+ unsave_tex_scanner(texstate); -+ return 1; -+} -+ -+static int run_scan_float(lua_State * L) -+{ -+ return run_scan_float_indeed(L,true); -+} -+ -+static int run_scan_real(lua_State * L) -+{ -+ return run_scan_float_indeed(L,false); -+} -+ - static int run_scan_dimen(lua_State * L) - { - saved_tex_scanner texstate; -@@ -339,7 +507,7 @@ static int run_scan_dimen(lua_State * L) - if (t>1) - mu = lua_toboolean(L,2); /* mu units required ?*/ - save_tex_scanner(texstate); -- scan_dimen( mu,inf, false); /* arg3 = shortcut */ -+ scan_dimen(mu,inf, false); /* arg3 = shortcut */ - v = cur_val; - o = cur_order; - unsave_tex_scanner(texstate); -@@ -415,25 +583,67 @@ static int run_scan_string(lua_State * L) /* HH */ - } else if (cur_cmd == call_cmd) { - t = token_link(cur_chr); - tokenlist_to_luastring(L,t); -+ } else if (cur_cmd == 11 || cur_cmd == 12 ) { -+ declare_buffer; -+ while (1) { -+ add_to_buffer(cur_chr); -+ get_x_token(); -+ if (cur_cmd != 11 && cur_cmd != 12 ) { -+ break ; -+ } -+ } -+ back_input(); -+ push_buffer; - } else { -- if (cur_cmd == 11 || cur_cmd == 12 ) { -- char * str ; -- luaL_Buffer b ; -- luaL_buffinit(L,&b) ; -- while (1) { -- str = (char *) uni2str(cur_chr); -- luaL_addstring(&b,(char *) str); -- get_x_token(); -- if (cur_cmd != 11 && cur_cmd != 12 ) { -- break ; -- } -+ back_input(); -+ lua_pushnil(L); -+ } -+ unsave_tex_scanner(texstate); -+ return 1; -+} -+ -+static int run_scan_argument(lua_State * L) /* HH */ -+{ /* can be simplified, no need for intermediate list */ -+ saved_tex_scanner texstate; -+ halfword t, saved_defref; -+ save_tex_scanner(texstate); -+ do { -+ get_token(); -+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd)); -+ if (cur_cmd == left_brace_cmd) { -+ back_input(); -+ saved_defref = def_ref; -+ (void) scan_toks(false, true); -+ t = def_ref; -+ def_ref = saved_defref; -+ tokenlist_to_luastring(L,t); -+ } else if (cur_cmd == call_cmd) { -+ halfword saved_cur_tok = cur_tok; -+ cur_tok = right_brace_token + '}'; -+ back_input(); -+ cur_tok = saved_cur_tok; -+ back_input(); -+ cur_tok = left_brace_token + '{'; -+ back_input(); -+ saved_defref = def_ref; -+ (void) scan_toks(false, true); -+ t = def_ref; -+ def_ref = saved_defref; -+ tokenlist_to_luastring(L,t); -+ } else if (cur_cmd == 11 || cur_cmd == 12 ) { -+ declare_buffer; -+ while (1) { -+ add_to_buffer(cur_chr); -+ get_x_token(); -+ if (cur_cmd != 11 && cur_cmd != 12 ) { -+ break ; - } -- back_input(); -- luaL_pushresult(&b); -- } else { -- back_input(); -- lua_pushnil(L); - } -+ back_input(); -+ push_buffer; -+ } else { -+ back_input(); -+ lua_pushnil(L); - } - unsave_tex_scanner(texstate); - return 1; -@@ -447,20 +657,16 @@ static int run_scan_word(lua_State * L) /* HH */ - get_x_token(); - } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd)); - if (cur_cmd == 11 || cur_cmd == 12 ) { -- char *str ; -- luaL_Buffer b ; -- luaL_buffinit(L,&b) ; -+ declare_buffer; - while (1) { -- str = (char *) uni2str(cur_chr); -- luaL_addstring(&b,str); -- xfree(str); -+ add_to_buffer(cur_chr); - get_x_token(); - if (cur_cmd != 11 && cur_cmd != 12 ) { - break ; - } - } - back_input(); -- luaL_pushresult(&b); -+ push_buffer; - } else { - back_input(); - lua_pushnil(L); -@@ -503,12 +709,12 @@ static int lua_tokenlib_is_token(lua_State * L) /* HH */ - return 1; - } - --/* static int run_expand(lua_State * L) */ --/* { */ --/* (void) L; */ --/* expand(); */ --/* return 0; */ --/* } */ -+static int run_expand(lua_State * L) -+{ -+ (void) L; -+ expand(); -+ return 0; -+} - - static int run_lookup(lua_State * L) - { -@@ -529,6 +735,21 @@ static int run_lookup(lua_State * L) - return 1; - } - -+static int lua_tokenlib_is_defined(lua_State * L) -+{ -+ const char *s; -+ size_t l; -+ if (lua_type(L, -1) == LUA_TSTRING) { -+ s = lua_tolstring(L, -1, &l); -+ if (l > 0) { -+ lua_pushboolean(L,string_lookup(s, l) != undefined_control_sequence); -+ return 1; -+ } -+ } -+ lua_pushnil(L); -+ return 1; -+} -+ - static int run_build(lua_State * L) - { - if (lua_type(L, 1) == LUA_TNUMBER) { -@@ -550,6 +771,15 @@ static int run_build(lua_State * L) - } - } - -+static int run_new(lua_State * L) -+{ -+ int cs = 0; -+ int chr = (int) lua_tointeger(L, 1); -+ int cmd = (int) lua_tointeger(L, 2); -+ make_new_token(L, cmd, chr, cs); -+ return 1; -+} -+ - /* token instance functions */ - - static int lua_tokenlib_free(lua_State * L) -@@ -602,7 +832,6 @@ inline static int lua_tokenlib_get_index(lua_State * L) - e -= toks_base; - break; - default: -- e = -1; - break; - } - if ((e >= 0) && (e <= 65535)) { -@@ -630,7 +859,7 @@ inline static int lua_tokenlib_get_cmdname(lua_State * L) - lua_token *n = check_istoken(L, 1); - halfword t = token_info(n->token); - int cmd = (t >= cs_token_flag ? eq_type(t - cs_token_flag) : token_cmd(t)); -- lua_pushstring(L, command_names[cmd].cmd_name); /* can be sped up */ -+ lua_push_string_by_index(L, command_names[cmd].lua); - return 1; - } - -@@ -750,7 +979,7 @@ static int lua_tokenlib_equal(lua_State * L) - n = check_istoken(L, 1); - m = check_istoken(L, 2); - if (token_info(n->token) == token_info(m->token)) { -- lua_pushboolean(L,1); -+ lua_pushboolean(L,1); - return 1; - } - lua_pushboolean(L,0); -@@ -789,6 +1018,19 @@ static int run_scan_token(lua_State * L) - return 1; - } - -+static int run_scan_list(lua_State * L) -+{ -+ saved_tex_scanner texstate; -+ save_tex_scanner(texstate); -+ /*tex -+ This is s tricky call as we are in \LUA\ and therefore -+ mess with the main loop. -+ */ -+ lua_nodelib_push_fast(L, local_scan_box()); -+ unsave_tex_scanner(texstate); -+ return 1; -+} -+ - /* experiment */ - - /* [catcodetable] csname content : \def\csname{content} */ -@@ -844,6 +1086,56 @@ static int get_macro(lua_State * L) - return 0; - } - -+static int set_lua(lua_State *L) -+{ -+ const char *name = null; -+ const char *s = null; -+ size_t lname = 0; -+ int cs; -+ int n = lua_gettop(L); -+ int a = 0; /* global state */ -+ int p = 0; /* protected state */ -+ int f = 0; /* function index */ -+ int nncs = no_new_control_sequence; -+ if (n < 2) { -+ return 0 ; -+ } -+ name = lua_tolstring(L, 1, &lname); -+ if (name == null) { -+ return 0 ; -+ } -+ f = lua_tointeger(L, 2); -+ if (n > 2) { -+ s = lua_tostring(L, 3); -+ if (s) { -+ if (lua_key_eq(s, global)) { -+ a = 4; -+ } else if (lua_key_eq(s, protected)) { -+ p = 1; -+ } -+ } -+ if (n > 3) { -+ s = lua_tostring(L, 4); -+ if (s) { -+ if (lua_key_eq(s, global)) { -+ a = 4; -+ } else if (lua_key_eq(s, protected)) { -+ p = 1; -+ } -+ } -+ } -+ } -+ no_new_control_sequence = false ; -+ cs = string_lookup(name, lname); -+ no_new_control_sequence = nncs; -+ if (p) { -+ define(cs, lua_call_cmd, f); -+ } else { -+ define(cs, lua_expandable_call_cmd, f); -+ } -+ return 0; -+} -+ - static int set_macro(lua_State * L) - { - const char *name = null; -@@ -963,27 +1255,75 @@ static int set_macro(lua_State * L) - return 0; - } - -+static int set_char(lua_State * L) -+{ -+ const char *name = null; -+ const char *s = null; -+ size_t lname = 0; -+ int cs, value; -+ int n = lua_gettop(L); -+ int a = 0 ; /* global state */ -+ int nncs = no_new_control_sequence; -+ if (n < 2) -+ return 0; -+ name = lua_tolstring(L, 1, &lname); -+ if (name == null) -+ return 0; -+ value = lua_tointeger(L, 2); -+ if (value < 0) -+ return 0; -+ if (n > 2) -+ s = lua_tostring(L, 3); -+ if (s && (lua_key_eq(s, global))) { -+ a = 4; -+ } -+ no_new_control_sequence = false ; -+ cs = string_lookup(name, lname); -+ no_new_control_sequence = nncs; -+ define(cs, char_given_cmd, value); -+ return 0; -+} -+ -+static int get_command_names(lua_State * L) -+{ -+ int i; -+ lua_createtable(L,data_cmd+1,0); -+ for (i = 0; command_names[i].lua != 0; i++) { -+ lua_rawgeti(L, LUA_REGISTRYINDEX, command_names[i].lua); -+ lua_rawseti(L, -2, i); -+ } -+ return 1; -+} -+ - static const struct luaL_Reg tokenlib[] = { - { "type", lua_tokenlib_type }, - { "create", run_build }, -+ { "new", run_new }, - { "is_token", lua_tokenlib_is_token }, -+ { "is_defined", lua_tokenlib_is_defined }, -+ { "commands", get_command_names }, -+ { "command_id", run_get_command_id }, -+ { "biggest_char", run_get_biggest_char }, - /* scanners */ - { "get_next", run_get_next }, -- { "put_next", run_put_next }, - { "scan_keyword", run_scan_keyword }, -+ { "scan_keyword_cs", run_scan_keyword_cs }, - { "scan_int", run_scan_int }, -+ { "scan_float", run_scan_float }, -+ { "scan_real", run_scan_real }, - { "scan_dimen", run_scan_dimen }, - { "scan_glue", run_scan_glue }, - { "scan_toks", run_scan_toks }, - { "scan_code", run_scan_code }, - { "scan_string", run_scan_string }, -+ { "scan_argument", run_scan_argument }, - { "scan_word", run_scan_word }, - { "scan_csname", run_scan_csname }, - { "scan_token", run_scan_token }, /* expands next token if needed */ -- /* push into input stream */ -- /* -- { "write",luatwrite }, -- */ -+ { "scan_list", run_scan_list }, -+ /* writers */ -+ { "put_next", run_put_next }, -+ { "expand", run_expand }, - /* getters */ - { "get_command", lua_tokenlib_get_command }, - { "get_index", lua_tokenlib_get_index }, -@@ -995,15 +1335,12 @@ static const struct luaL_Reg tokenlib[] = { - { "get_active", lua_tokenlib_get_active }, - { "get_expandable", lua_tokenlib_get_expandable }, - { "get_protected", lua_tokenlib_get_protected }, -- /* maybe more setters */ -- { "set_macro", set_macro }, - { "get_macro", get_macro }, - { "get_meaning", get_meaning }, -- /* probably never */ -- /* {"expand", run_expand}, */ /* does not work yet! */ -- /* {"csname_id", run_get_csname_id}, */ /* yes or no */ -- /* {"command_id", run_get_command_id}, */ /* yes or no */ -- /* {"cs_offset", run_get_cs_offset}, */ /* not that useful */ -+ /* setters */ -+ { "set_macro", set_macro }, -+ { "set_char", set_char }, -+ { "set_lua", set_lua }, - {NULL, NULL} - }; - -diff --git a/texk/web2c/luatexdir/lua/lnodelib.c b/texk/web2c/luatexdir/lua/lnodelib.c -index 7b4c614ea..d8732df76 100644 ---- a/texk/web2c/luatexdir/lua/lnodelib.c -+++ b/texk/web2c/luatexdir/lua/lnodelib.c -@@ -209,6 +209,80 @@ halfword *check_isnode(lua_State * L, int i) - return NULL; - } - -+static int nodelib_setdir_text(lua_State * L, int i, halfword n) -+{ -+ if (lua_type(L, i) == LUA_TSTRING) { -+ const char *s = lua_tostring(L, i); -+ if (s==lua_key_plus(TLT)) { -+ dir_dir(n) = 0 ; -+ subtype(n) = normal_dir; -+ } else if (s==lua_key_minus(TLT)) { -+ dir_dir(n) = 0 ; -+ subtype(n) = cancel_dir; -+ } else if (s==lua_key_plus(TRT)) { -+ dir_dir(n) = 1 ; -+ subtype(n) = normal_dir; -+ } else if (s==lua_key_minus(TRT)) { -+ dir_dir(n) = 1 ; -+ subtype(n) = cancel_dir; -+ } else if (s==lua_key_plus(LTL)) { -+ dir_dir(n) = 2 ; -+ subtype(n) = normal_dir; -+ } else if (s==lua_key_minus(LTL)) { -+ dir_dir(n) = 2 ; -+ subtype(n) = cancel_dir; -+ } else if (s==lua_key_plus(RTT)) { -+ dir_dir(n) = 3 ; -+ subtype(n) = normal_dir; -+ } else if (s==lua_key_minus(RTT)) { -+ dir_dir(n) = 3 ; -+ subtype(n) = cancel_dir; -+ } else { -+ luaL_error(L, "Bad direction specifier %s", s); -+ } -+ } else { -+ luaL_error(L, "Direction specifiers have to be strings"); -+ } -+ return 0; -+} -+ -+static int nodelib_getdir_par(lua_State * L, int n) -+{ -+ if (lua_type(L, n) == LUA_TSTRING) { -+ const char *s = lua_tostring(L, n); -+ if (s==lua_key(TLT)) -+ return 0 ; -+ else if (s==lua_key(TRT)) -+ return 1 ; -+ else if (s==lua_key(LTL)) -+ return 2 ; -+ else if (s==lua_key(RTT)) -+ return 3 ; -+ else -+ luaL_error(L, "Bad direction specifier %s", s); -+ } else { -+ luaL_error(L, "Direction specifiers have to be strings"); -+ } -+ return 0; -+} -+ -+static int nodelib_getdirection(lua_State * L, int n) -+{ -+ if (lua_type(L, n) == LUA_TNUMBER) { -+ int i = lua_tointeger(L, n); -+ check_dir_value(i); -+ return i; -+ } else { -+ luaL_error(L, "Direction specifiers have to be numbers"); -+ } -+ return 0; -+} -+ -+int nodelib_getdir(lua_State * L, int n) /* the api public one */ -+{ -+ return nodelib_getdir_par(L,n); -+} -+ - /* - - This routine finds the numerical value of a string (or number) at -@@ -216,13 +290,32 @@ halfword *check_isnode(lua_State * L, int i) - - */ - -+/* s = lua_tostring(L, 2); */ -+/* if (lua_key_eq(s, id)) { */ -+ - static int get_node_type_id_from_name(lua_State * L, int n, node_info * data) - { -- int j; -- const char *s = lua_tostring(L, n); -- for (j = 0; data[j].id != -1; j++) { -- if (strcmp(s, data[j].name) == 0) { -- return j; -+ if (data != NULL) { -+ int j; -+ const char *s = lua_tostring(L, n); -+ for (j = 0; data[j].id != -1; j++) { -+ if (s == data[j].name) { -+ return j; -+ } -+ } -+ } -+ return -1; -+} -+ -+static int get_node_subtype_id_from_name(lua_State * L, int n, subtype_info * data) -+{ -+ if (data != NULL) { -+ int j; -+ const char *s = lua_tostring(L, n); -+ for (j = 0; data[j].id != -1; j++) { -+ if (s == data[j].name) { -+ return j; -+ } - } - } - return -1; -@@ -234,7 +327,7 @@ static int get_valid_node_type_id(lua_State * L, int n) - int t = lua_type(L, n); - if (t == LUA_TSTRING) { - i = get_node_type_id_from_name(L,n,node_data); -- if (i<0) { -+ if (i < 0) { - luaL_error(L, "invalid node type id: %s", lua_tostring(L, n)); - } - } else if (t == LUA_TNUMBER) { -@@ -347,6 +440,31 @@ void lua_nodelib_push_fast(lua_State * L, halfword n) - return; - } - -+/* getting and setting fields (helpers) */ -+ -+int nodelib_getlist(lua_State * L, int n) -+{ -+ if (lua_isuserdata(L, n)) { -+ halfword m = *check_isnode(L, n); -+ return m; -+ } else { -+ return null; -+ } -+} -+ -+static str_number nodelib_getstring(lua_State * L, int a) -+{ -+ size_t k; -+ const char *s = lua_tolstring(L, a, &k); -+ return maketexlstring(s, k); -+} -+ -+static int nodelib_cantset(lua_State * L, int n, const char *s) -+{ -+ luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name); -+ return 0; -+} -+ - /* converts type strings to type ids */ - - static int lua_nodelib_id(lua_State * L) -@@ -439,6 +557,44 @@ static int lua_nodelib_direct_setsubtype(lua_State * L) - return 1; - } - -+/* node.direct.getexpansion */ -+/* node.direct.setexpansion */ -+ -+static int lua_nodelib_direct_getexpansion(lua_State * L) -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n != null) { -+ halfword t = type(n); -+ if (t == glyph_node) { -+ lua_pushinteger(L, ex_glyph(n)); -+ return 1; -+ } else if (t == kern_node) { -+ lua_pushinteger(L, ex_kern(n)); -+ return 1; -+ } -+ } -+ lua_pushnil(L); -+ return 1; -+} -+ -+static int lua_nodelib_direct_setexpansion(lua_State * L) -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n) { -+ halfword t = type(n); -+ halfword e = 0; -+ if (lua_type(L, 2) == LUA_TNUMBER) { -+ e = (halfword) lua_tointeger(L, 2); -+ } -+ if (t == glyph_node) { -+ ex_glyph(n) = e; -+ } else if ( t == kern_node) { -+ ex_kern(n) = e; -+ } -+ } -+ return 0; -+} -+ - /* node.direct.getfont */ - /* node.direct.setfont */ - -@@ -530,6 +686,10 @@ static int lua_nodelib_direct_getfam(lua_State * L) - lua_pushinteger(L, math_fam(n)); - } else if (t == delim_node) { - lua_pushinteger(L, small_fam(n)); -+ } else if (t == fraction_noad) { -+ lua_pushinteger(L, fraction_fam(n)); -+ } else if (t == simple_noad) { -+ lua_pushinteger(L, noad_fam(n)); - } else { - lua_pushnil(L); - } -@@ -565,6 +725,10 @@ static int lua_nodelib_direct_setfam(lua_State * L) - math_fam(n) = (halfword) lua_tointeger(L, 2); - } else if (t == delim_node) { - small_fam(n) = (halfword) lua_tointeger(L, 2); -+ } else if (t == fraction_noad) { -+ fraction_fam(n) = (halfword) lua_tointeger(L, 2); -+ } else if (t == simple_noad) { -+ noad_fam(n) = (halfword) lua_tointeger(L, 2); - } - } - return 0; -@@ -572,7 +736,7 @@ static int lua_nodelib_direct_setfam(lua_State * L) - - /* node.getchar */ - -- static int lua_nodelib_getchar(lua_State * L) -+static int lua_nodelib_getchar(lua_State * L) - { - halfword *n = lua_touserdata(L, 1); - if ((n == NULL) || (! lua_getmetatable(L,1))) { -@@ -665,7 +829,8 @@ static int lua_nodelib_direct_setattributelist(lua_State * L) - { - halfword n = lua_tointeger(L, 1); - if ((n) && nodetype_has_attributes(type(n))) { -- if (lua_type(L, 2) == LUA_TNUMBER) { -+ int t = lua_type(L, 2); -+ if (t == LUA_TNUMBER) { - halfword a =lua_tointeger(L, 2); - if (type(a) == attribute_list_node) { - reassign_attribute(n,a); -@@ -674,6 +839,12 @@ static int lua_nodelib_direct_setattributelist(lua_State * L) - } else { - reassign_attribute(n,null); - } -+ } else if (t == LUA_TBOOLEAN) { -+ if (lua_toboolean(L,2)) { -+ reassign_attribute(n,current_attribute_list()); -+ } else { -+ reassign_attribute(n,null); -+ } - } else { - reassign_attribute(n,null); - } -@@ -681,7 +852,6 @@ static int lua_nodelib_direct_setattributelist(lua_State * L) - } - return 0; - } -- - /* node.direct.getpenalty */ - /* node.direct.setpenalty */ - -@@ -827,7 +997,15 @@ static int lua_nodelib_direct_getkern(lua_State * L) - halfword n = lua_tointeger(L, 1); - if (n) { - halfword t = type(n); -- if (t == kern_node || t == margin_kern_node) { -+ if (t == kern_node) { -+ if (lua_toboolean(L,2)) { -+ lua_pushnumber(L, (1+ex_kern(n)/1000) * width(n)); -+ lua_pushinteger(L, ex_kern(n)); -+ return 2; -+ } else { -+ lua_pushinteger(L, width(n)); -+ } -+ } else if (t == margin_kern_node) { - lua_pushinteger(L, width(n)); - } else if (t == math_node) { - lua_pushinteger(L, surround(n)); -@@ -874,7 +1052,7 @@ static int lua_nodelib_direct_getdir(lua_State * L) - if (n) { - halfword t = type(n); - if (t == dir_node) { -- lua_push_dir_text(L, dir_dir(n)); -+ lua_push_dir_text(L, dir_dir(n), subtype(n)); - } else if (t == hlist_node || t == vlist_node) { - lua_push_dir_par(L, box_dir(n)); - } else if (t == rule_node) { -@@ -890,19 +1068,68 @@ static int lua_nodelib_direct_getdir(lua_State * L) - return 1; - } - -+static int lua_nodelib_direct_getdirection(lua_State * L) -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n) { -+ halfword t = type(n); -+ if (t == dir_node) { -+ lua_push_direction(L, dir_dir(n)); -+ lua_pushboolean(L, subtype(n)); -+ return 2; -+ } else if (t == hlist_node || t == vlist_node) { -+ lua_push_direction(L, box_dir(n)); -+ } else if (t == rule_node) { -+ lua_push_direction(L, rule_dir(n)); -+ } else if (t == local_par_node) { -+ lua_push_direction(L, local_par_dir(n)); -+ } else { -+ lua_pushnil(L); -+ } -+ } else { -+ lua_pushnil(L); -+ } -+ return 1; -+} -+ - static int lua_nodelib_direct_setdir(lua_State * L) - { - halfword n = lua_tointeger(L, 1); - if (n) { - halfword t = type(n); - if (t == dir_node) { -- dir_dir(n) = nodelib_getdir(L, 2, 0); -+ nodelib_setdir_text(L, 2, n); - } else if (t == hlist_node || type(n) == vlist_node) { -- box_dir(n) = nodelib_getdir(L, 2, 1); -+ box_dir(n) = nodelib_getdir_par(L, 2); - } else if (t == rule_node) { -- rule_dir(n) = nodelib_getdir(L, 2, 1); -+ rule_dir(n) = nodelib_getdir_par(L, 2); - } else if (t == local_par_node) { -- local_par_dir(n) = nodelib_getdir(L, 3, 1); -+ local_par_dir(n) = nodelib_getdir_par(L, 2); -+ } -+ } -+ return 0; -+} -+ -+static int lua_nodelib_direct_setdirection(lua_State * L) -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n) { -+ halfword t = type(n); -+ if (t == dir_node) { -+ dir_dir(n) = nodelib_getdirection(L, 2); -+ if ((lua_type(L, 3) == LUA_TBOOLEAN)) { -+ if (lua_toboolean(L, 3)) { -+ subtype(n) = cancel_dir; -+ } else { -+ subtype(n) = normal_dir; -+ } -+ } -+ } else if (t == hlist_node || type(n) == vlist_node) { -+ box_dir(n) = nodelib_getdirection(L, 2); -+ } else if (t == rule_node) { -+ rule_dir(n) = nodelib_getdirection(L, 2); -+ } else if (t == local_par_node) { -+ local_par_dir(n) = nodelib_getdirection(L, 2); - } - } - return 0; -@@ -1017,15 +1244,24 @@ static int lua_nodelib_direct_setdisc(lua_State * L) - /* node.direct.getwhd */ - /* node.direct.setwhd */ - --#define push_list_whd(n) \ -- lua_pushinteger(L, width(n)); \ -+#define push_list_whd(n) do { \ -+ lua_pushinteger(L, width(n)); \ - lua_pushinteger(L, height(n)); \ -- lua_pushinteger(L, depth(n)); \ -+ lua_pushinteger(L, depth(n)); \ -+} while (0) -+ -+#define push_char_whd(n) do { \ -+ lua_pushinteger(L, char_width(font(n),character(n))); \ -+ lua_pushinteger(L, char_height(font(n),character(n))); \ -+ lua_pushinteger(L, char_depth(font(n),character(n))); \ -+} while (0) - --#define push_char_whd(n) \ -- lua_pushinteger(L, char_width(font(n),character(n))); \ -+#define push_char_ehd(n) do { \ -+ lua_pushnumber(L, (1+ex_glyph(n)/1000) * char_width(font(n),character(n))); \ - lua_pushinteger(L, char_height(font(n),character(n))); \ -- lua_pushinteger(L, char_depth(font(n),character(n))); \ -+ lua_pushinteger(L, char_depth(font(n),character(n))); \ -+ lua_pushinteger(L, ex_glyph(n)); \ -+} while (0) - - static int lua_nodelib_direct_getwhd(lua_State * L) - { -@@ -1036,8 +1272,13 @@ static int lua_nodelib_direct_getwhd(lua_State * L) - push_list_whd(n); - return 3; - } else if (t == glyph_node) { -- push_char_whd(n); -- return 3; -+ if (lua_toboolean(L,2)) { -+ push_char_ehd(n); -+ return 4; -+ } else { -+ push_char_whd(n); -+ return 3; -+ } - } else if (t == glue_node) { - halfword l = leader_ptr(n); - if (l != null) { -@@ -1104,8 +1345,13 @@ static int lua_nodelib_direct_setwhd(lua_State * L) - push_list_whd(*n); - return 3; - } else if (t == glyph_node) { -- push_char_whd(*n); -- return 3; -+ if (lua_toboolean(L,2)) { -+ push_char_ehd(*n); -+ return 4; -+ } else { -+ push_char_whd(*n); -+ return 3; -+ } - } else if (t == glue_node) { - halfword l = leader_ptr(*n); - if (l != null) { -@@ -1214,7 +1460,7 @@ static int lua_nodelib_direct_getleader(lua_State * L) - return 1; - } - -- static int lua_nodelib_direct_setleader(lua_State * L) -+static int lua_nodelib_direct_setleader(lua_State * L) - { - halfword n = lua_tointeger(L, 1); - if ((n) && (type(n) == glue_node)) { -@@ -1227,7 +1473,7 @@ static int lua_nodelib_direct_getleader(lua_State * L) - return 0; - } - -- /* node.getleader */ -+/* node.getleader */ - - static int lua_nodelib_getleader(lua_State * L) - { -@@ -1243,6 +1489,241 @@ static int lua_nodelib_direct_getleader(lua_State * L) - return 1; - } - -+/* node.direct.getdata */ -+/* node.direct.setdata */ -+ -+#define get_user_node_direct_value(L, n) do { \ -+ switch (user_node_type(n)) { \ -+ case 'a': \ -+ nodelib_pushdirect(user_node_value(n)); \ -+ break; \ -+ case 'd': \ -+ lua_pushinteger(L, user_node_value(n)); \ -+ break; \ -+ case 'l': \ -+ if (user_node_value(n) != 0) { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n)); \ -+ } else { \ -+ lua_pushnil(L); \ -+ } \ -+ break; \ -+ case 'n': \ -+ nodelib_pushdirect(user_node_value(n)); \ -+ break; \ -+ case 's': \ -+ nodelib_pushstring(L, user_node_value(n)); \ -+ break; \ -+ case 't': \ -+ tokenlist_to_lua(L, user_node_value(n)); \ -+ break; \ -+ default: \ -+ lua_pushinteger(L, user_node_value(n)); \ -+ break; \ -+ } \ -+} while (0) -+ -+#define set_user_node_direct_value(L,n,i) do { \ -+ switch (user_node_type(n)) { \ -+ case 'a': \ -+ user_node_value(n) = nodelib_getlist(L, i); \ -+ break; \ -+ case 'd': \ -+ user_node_value(n) = (halfword) lua_roundnumber(L, i); \ -+ break; \ -+ case 'l': \ -+ lua_pushvalue(L, i); \ -+ if (user_node_value(n) != 0) { \ -+ luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n)); \ -+ } \ -+ user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX); \ -+ break; \ -+ case 'n': \ -+ user_node_value(n) = nodelib_getlist(L, i); \ -+ break; \ -+ case 's': \ -+ user_node_value(n) = nodelib_getstring(L, i); \ -+ break; \ -+ case 't': \ -+ user_node_value(n) = nodelib_gettoks(L, i); \ -+ break; \ -+ default: \ -+ user_node_value(n) = (halfword) lua_roundnumber(L, i); \ -+ break; \ -+ } \ -+} while (0) -+ -+#define get_pdf_literal_direct_value(L,n) do { \ -+ if (pdf_literal_type(n) == lua_refid_literal) { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n)); \ -+ } else if (pdf_literal_type(n) == lua_refid_literal) { \ -+ tokenlist_to_luastring(L, pdf_literal_data(n)); \ -+ } \ -+} while (0) -+ -+#define set_pdf_literal_direct_normal(L,n,i) do { \ -+ if (ini_version) { \ -+ pdf_literal_data(n) = nodelib_gettoks(L, i); \ -+ pdf_literal_type(n) = normal; \ -+ } else { \ -+ lua_pushvalue(L, i); \ -+ pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); \ -+ pdf_literal_type(n) = lua_refid_literal; \ -+ } \ -+} while (0) -+ -+#define set_pdf_literal_direct_token(L,n,i) do { \ -+ pdf_literal_data(n) = nodelib_gettoks(L, i); \ -+} while (0) -+ -+#define cleanup_late_lua(n) do { \ -+ if (late_lua_data(n) != 0) { \ -+ if (late_lua_type(n) == normal) { \ -+ delete_token_ref(late_lua_data(n)); \ -+ } else if (late_lua_type(n) == lua_refid_literal) { \ -+ luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \ -+ } \ -+ } \ -+} while (0) -+ -+#define cleanup_late_lua_name(n) do { \ -+ if (late_lua_name(n) != 0) { \ -+ delete_token_ref(late_lua_name(n)); \ -+ } \ -+} while (0) -+ -+#define set_late_lua_direct_normal(L,n,i) do { \ -+ cleanup_late_lua(n) ; \ -+ if (ini_version) { \ -+ late_lua_data(n) = nodelib_gettoks(L, i); \ -+ late_lua_type(n) = normal; \ -+ } else if (lua_type(L, i) == LUA_TNUMBER) { \ -+ late_lua_data(n) = lua_tointeger(L,i); \ -+ late_lua_type(n) = lua_refid_call; \ -+ } else { \ -+ lua_pushvalue(L, i); \ -+ late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); \ -+ late_lua_type(n) = lua_refid_literal; \ -+ } \ -+} while (0) -+ -+#define set_late_lua_direct_token(L,n,i) do { \ -+ cleanup_late_lua(n) ; \ -+ late_lua_data(n) = nodelib_gettoks(L, i); \ -+ late_lua_type(n) = normal; \ -+} while (0) -+ -+#define get_late_lua_direct_value(L,n) do { \ -+ if (late_lua_type(n) == lua_refid_literal) { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n)); \ -+ } else if (late_lua_type(n) == lua_refid_call) { \ -+ lua_pushinteger(L, late_lua_data(n)); \ -+ } else if (late_lua_type(n) == normal) { \ -+ tokenlist_to_luastring(L, late_lua_data(n)); \ -+ } \ -+} while (0) -+ -+#define set_special_direct_value(L,n,i) do { \ -+ write_tokens(n) = nodelib_gettoks(L, i); \ -+} while (0) -+ -+#define get_special_direct_value(L,n) do { \ -+ tokenlist_to_luastring(L, write_tokens(n)); \ -+} while (0) -+ -+#define set_write_direct_value(L,n,i) do { \ -+ write_tokens(n) = nodelib_gettoks(L, i); \ -+} while (0) -+ -+#define get_write_direct_value(L,n) do { \ -+ tokenlist_to_lua(L, write_tokens(n)); \ -+} while (0) -+ -+#define set_pdf_setmatrix_direct_value(L,n,i) do { \ -+ pdf_setmatrix_data(n) = nodelib_gettoks(L, i); \ -+} while (0) -+ -+#define get_pdf_setmatrix_direct_value(L,n) do { \ -+ tokenlist_to_luastring(L, pdf_setmatrix_data(n)); \ -+} while (0) -+ -+/*tex -+ -+ These getter and setter get |data| as well as |value| fields. One can -+ make them equivalent to |getvalue| and |setvalue| if needed. -+ -+*/ -+ -+static int lua_nodelib_direct_getdata(lua_State * L) -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n == null) { -+ lua_pushnil(L); -+ } else { -+ halfword t = type(n) ; -+ if (t == glyph_node) { -+ lua_pushinteger(L,glyph_node_data(n)); -+ } else if (t == boundary_node) { -+ lua_pushinteger(L,boundary_value(n)); -+ } else if (t == whatsit_node) { -+ halfword s = subtype(n); -+ if (s == user_defined_node) { -+ get_user_node_direct_value(L, n); -+ } else if (s == pdf_literal_node) { -+ get_pdf_literal_direct_value(L, n); -+ /*tex A bonus. */ -+ lua_pushinteger(L,pdf_literal_mode(n)); -+ return 2; -+ } else if (s == late_lua_node) { -+ get_late_lua_direct_value(L, n); -+ } else if (s == pdf_setmatrix_node) { -+ get_pdf_setmatrix_direct_value(L, n); -+ } else if (s == special_node) { -+ get_special_direct_value(L, n); -+ } else if (s == write_node) { -+ get_write_direct_value(L, n); -+ } else { -+ lua_pushnil(L); -+ } -+ } else { -+ lua_pushnil(L); -+ } -+ } -+ return 1; -+} -+ -+static int lua_nodelib_direct_setdata(lua_State * L) /* data and value */ -+{ -+ halfword n = lua_tointeger(L, 1); -+ if (n != null) { -+ halfword t = type(n) ; -+ if (t == glyph_node) { -+ glyph_node_data(n) = lua_tointeger(L,2); -+ } else if (t == boundary_node) { -+ boundary_value(n) = lua_tointeger(L,2); -+ } else if (t == whatsit_node) { -+ halfword s = subtype(n); -+ if (s == user_defined_node) { -+ set_user_node_direct_value(L, n, 2); -+ } else if (s == pdf_literal_node) { -+ set_pdf_literal_direct_normal(L, n, 2); -+ if (lua_type(L,2) == LUA_TNUMBER) { -+ /*tex A bonus. */ -+ pdf_literal_mode(n) = lua_tointeger(L,2); -+ } -+ } else if (s == late_lua_node) { -+ set_late_lua_direct_normal(L, n, 2); -+ } else if (s == pdf_setmatrix_node) { -+ set_pdf_setmatrix_direct_value(L, n, 2); -+ } else if (s == special_node) { -+ set_special_direct_value(L, n, 2); -+ } else if (s == write_node) { -+ set_write_direct_value(L,n,2); -+ } -+ } -+ } -+ return 0; -+} -+ - /* node.direct.getnext */ - /* node.direct.setnext */ - -@@ -1488,11 +1969,13 @@ static int lua_nodelib_type(lua_State * L) - if (lua_type(L,1) == LUA_TNUMBER) { - int i = lua_tointeger(L, 1); - if (known_node_type(i)) { -- lua_pushstring(L, node_data[i].name); -+ /* lua_pushstring(L, node_data[i].name); */ -+ lua_push_string_by_index(L, node_data[i].lua); - return 1; - } - } else if (maybe_isnode(L, 1) != NULL) { -- lua_pushstring(L,"node"); -+ /* lua_pushstring(L,"node"); */ -+ lua_push_string_by_name(L,node); - return 1; - } - lua_pushnil(L); -@@ -1501,10 +1984,9 @@ static int lua_nodelib_type(lua_State * L) - - /* node.new (allocate a new node) */ - --static int lua_nodelib_new(lua_State * L) -+static halfword lua_nodelib_new_node(lua_State * L) - { - int i, j; -- halfword n = null; - int t = lua_type(L, 1); - if (t == LUA_TNUMBER) { - i = lua_tointeger(L,1); -@@ -1536,33 +2018,26 @@ static int lua_nodelib_new(lua_State * L) - } - } else if (t == LUA_TNUMBER) { - j = (int) lua_tointeger(L, 2); -+ } else if (t == LUA_TSTRING) { -+ j = get_node_subtype_id_from_name(L,2,node_data[i].subtypes); - } else { - j = 0; - } -- n = new_node(i, j); -+ return new_node(i, j); -+} -+ -+static int lua_nodelib_new(lua_State * L) -+{ -+ halfword n = lua_nodelib_new_node(L); - lua_nodelib_push_fast(L, n); - return 1; - } - --/* node.direct.new (still with checking) */ -+/* node.direct.new */ - - static int lua_nodelib_direct_new(lua_State * L) - { -- int j; -- halfword n ; -- int i = get_valid_node_type_id(L, 1); -- if (i == whatsit_node) { -- j = -1; -- if (lua_gettop(L) > 1) -- j = get_valid_node_subtype_id(L, 2); -- if (j < 0) -- luaL_error(L, "Creating a whatsit requires the subtype number as a second argument"); -- } else { -- j = 0; -- if (lua_gettop(L) > 1) -- j = (int) lua_tointeger(L, 2); -- } -- n = new_node(i, j); -+ halfword n = lua_nodelib_new_node(L); - lua_pushinteger(L,n); - return 1; - } -@@ -1704,9 +2179,6 @@ static int lua_nodelib_remove(lua_State * L) - alink(vlink(current)) = t; - current = vlink(current); - } --#if DEBUG -- show_node_links(head, "after"); --#endif - /* can be: lua_nodelib_push_fast(L, head); */ - lua_pushinteger(L, head); - lua_nodelib_push(L); -@@ -1843,8 +2315,9 @@ static int lua_nodelib_direct_insert_before(lua_State * L) - current = tail_of_list(head); - if (head != current) { - halfword t = alink(current); -- if (t == null || vlink(t) != current) -+ if (t == null || vlink(t) != current) { - set_t_to_prev(head, current); -+ } - couple_nodes(t, n); - } - couple_nodes(n, current); /* nice but incompatible: couple_nodes(tail_of_list(n),current) */ -@@ -2091,8 +2564,10 @@ static int lua_nodelib_hpack(lua_State * L) - luaL_error(L, "wrong mode in hpack"); - } - if (lua_gettop(L) > 3) { -- if (lua_type(L, 4) == LUA_TSTRING) { -- d = nodelib_getdir(L, 4, 1); -+ if (lua_type(L, 4) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, 4); -+ } else if (lua_type(L, 4) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, 4); - } else { - lua_pushstring(L, "incorrect 4th argument"); - } -@@ -2138,8 +2613,10 @@ static int lua_nodelib_direct_hpack(lua_State * L) - lua_pushstring(L, "incorrect 3rd argument"); - } - if (lua_gettop(L) > 3) { -- if (lua_type(L, 4) == LUA_TSTRING) { -- d = nodelib_getdir(L, 4, 1); -+ if (lua_type(L, 4) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, 4); -+ } else if (lua_type(L, 4) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, 4); - } else { - lua_pushstring(L, "incorrect 4th argument"); - } -@@ -2177,8 +2654,10 @@ static int lua_nodelib_vpack(lua_State * L) - } - - if (lua_gettop(L) > 3) { -- if (lua_type(L, 4) == LUA_TSTRING) { -- d = nodelib_getdir(L, 4, 1); -+ if (lua_type(L, 4) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, 4); -+ } else if (lua_type(L, 4) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, 4); - } else { - lua_pushstring(L, "incorrect 4th argument"); - } -@@ -2222,8 +2701,10 @@ static int lua_nodelib_direct_vpack(lua_State * L) - } - - if (lua_gettop(L) > 3) { -- if (lua_type(L, 4) == LUA_TSTRING) { -- d = nodelib_getdir(L, 4, 1); -+ if (lua_type(L, 4) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, 4); -+ } else if (lua_type(L, 4) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, 4); - } else { - lua_pushstring(L, "incorrect 4th argument"); - } -@@ -2269,13 +2750,17 @@ static int lua_nodelib_dimensions(lua_State * L) - n = *(check_isnode(L, i)); - if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) { - if (lua_type(L, (i + 1)) == LUA_TSTRING) { -- d = nodelib_getdir(L, (i + 1), 1); -+ d = nodelib_getdir_par(L, (i + 1)); - } else { - p = *(check_isnode(L, (i + 1))); - } - } -- if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING) { -- d = nodelib_getdir(L, (i + 2), 1); -+ if (lua_gettop(L) > (i + 1)) { -+ if (lua_type(L, (i + 2)) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, (i + 2)); -+ } else if (lua_type(L, (i + 2)) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, (i + 2)); -+ } - } - siz = natural_sizes(n, p, g_mult, g_sign, g_order, d); - lua_pushinteger(L, siz.wd); -@@ -2322,7 +2807,8 @@ static int lua_nodelib_direct_dimensions(lua_State * L) - int g_order = normal; - int i = 1; - int d = -1; -- halfword n = null, p = null; -+ halfword n = null; -+ halfword p = null; - if (top > 3) { - i += 3; - g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */ -@@ -2332,13 +2818,18 @@ static int lua_nodelib_direct_dimensions(lua_State * L) - n = (halfword) lua_tointeger(L,i); - if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) { - if (lua_type(L, (i + 1)) == LUA_TSTRING) { -- d = nodelib_getdir(L, (i + 1), 1); -+ d = nodelib_getdir_par(L, (i + 1)); - } else { - p = (halfword) lua_tointeger(L,i+1); - } - } -- if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING) -- d = nodelib_getdir(L, (i + 2), 1); -+ if (lua_gettop(L) > (i + 1)) { -+ if (lua_type(L, (i + 2)) == LUA_TNUMBER) { -+ d = nodelib_getdirection(L, (i + 2)); -+ } else if (lua_type(L, (i + 2)) == LUA_TSTRING) { -+ d = nodelib_getdir_par(L, (i + 2)); -+ } -+ } - siz = natural_sizes(n, p, g_mult, g_sign, g_order, d); - lua_pushinteger(L, siz.wd); - lua_pushinteger(L, siz.ht); -@@ -2383,7 +2874,7 @@ static int lua_nodelib_mlist_to_hlist(lua_State * L) - luaL_checkany(L, 3); - m = lua_toboolean(L, 3); - mlist_to_hlist(n, m, w); -- alink(vlink(temp_head)) = null; /*hh-ls */ -+ alink(vlink(temp_head)) = null; - lua_nodelib_push_fast(L, vlink(temp_head)); - return 1; - } -@@ -2407,8 +2898,8 @@ static int lua_nodelib_mfont(lua_State * L) - identifiers. It has to do some more work, because not all - identifiers are valid for all types of nodes. - -- If really needed we can optimize this one using a big if .. -- .. else like with the getter and setter. -+ We can make this faster if needed but when this needs to -+ be called often something is wrong with the code. - - */ - -@@ -2438,16 +2929,19 @@ static int get_node_field_id(lua_State * L, int n, int node) - } - } else { - int j; -- const char **fields = node_data[t].fields; -+ field_info *fields ; - if (t == whatsit_node) { - fields = whatsit_node_data[subtype(node)].fields; -+ } else { -+ fields = node_data[t].fields; - } - if (lua_key_eq(s, list)) { - s = lua_key(head); - } - if (fields != NULL) { -- for (j = 0; fields[j] != NULL; j++) { -- if (strcmp(s, fields[j]) == 0) { -+ for (j = 0; fields[j].lua != 0; j++) { -+ // if (strcmp(s, fields[j]) == 0) { -+ if (fields[j].name == s) { - return j + 3; - } - } -@@ -2549,7 +3043,7 @@ static int lua_nodelib_fields(lua_State * L) - { - int i = -1; - int offset = 2; -- const char **fields; -+ field_info *fields; - int t = get_valid_node_type_id(L, 1); - if (t == whatsit_node) { - t = get_valid_node_subtype_id(L, 2); -@@ -2573,26 +3067,63 @@ static int lua_nodelib_fields(lua_State * L) - lua_rawseti(L, -2, -1); - } - if (fields != NULL) { -- for (i = 0; fields[i] != NULL; i++) { -- lua_pushstring(L, fields[i]); /* todo */ -+ for (i = 0; fields[i].lua != 0; i++) { -+ // lua_pushstring(L, fields[i]); /* todo */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, fields[i].lua); - lua_rawseti(L, -2, (i + offset)); - } - } - return 1; - } - -+static int lua_nodelib_values(lua_State * L) -+{ -+ int i = -1; -+ subtype_info *values = NULL; -+ const char *s ; -+ int t = lua_type(L,1); -+ if (t == LUA_TSTRING) { -+ /* -+ delimiter options (bit set) -+ delimiter modes (bit set) -+ */ -+ s = lua_tostring(L,1); -+ if (lua_key_eq(s,dir)) values = node_values_dir; -+ else if (lua_key_eq(s,direction)) values = node_values_dir; -+ else if (lua_key_eq(s,glue)) values = node_values_fill; -+ /* backend */ -+ else if (lua_key_eq(s,pdf_literal)) values = node_values_pdf_literal; -+ else if (lua_key_eq(s,pdf_action)) values = node_values_pdf_action; -+ else if (lua_key_eq(s,pdf_window)) values = node_values_pdf_window; -+ else if (lua_key_eq(s,color_stack)) values = node_values_color_stack; -+ /* extras */ -+ else if (lua_key_eq(s,pagestate)) values = other_values_page_states; -+ } -+ if (values != NULL) { -+ lua_checkstack(L, 2); -+ lua_newtable(L); -+ for (i = 0; values[i].id >= 0 ; i++) { -+ lua_rawgeti(L, LUA_REGISTRYINDEX, values[i].lua); -+ lua_rawseti(L, -2, values[i].id); -+ } -+ } else { -+ lua_pushnil(L); -+ } -+ return 1; -+} -+ - static int lua_nodelib_subtypes(lua_State * L) - { - int i = -1; -- int l = 0; -- const char **subtypes = NULL; -+ subtype_info *subtypes = NULL; - const char *s ; - int t = lua_type(L,1); - if (t == LUA_TSTRING) { - /* official accessors */ - s = lua_tostring(L,1); - if (lua_key_eq(s,glyph)) subtypes = node_subtypes_glyph; -- else if (lua_key_eq(s,glue)) { subtypes = node_subtypes_glue; l = 1; } -+ else if (lua_key_eq(s,glue)) subtypes = node_subtypes_glue; -+ else if (lua_key_eq(s,dir)) subtypes = node_subtypes_dir; - else if (lua_key_eq(s,boundary)) subtypes = node_subtypes_boundary; - else if (lua_key_eq(s,penalty)) subtypes = node_subtypes_penalty; - else if (lua_key_eq(s,kern)) subtypes = node_subtypes_kern; -@@ -2602,8 +3133,8 @@ static int lua_nodelib_subtypes(lua_State * L) - || lua_key_eq(s,vlist)) subtypes = node_subtypes_list; /* too many but ok as reserved */ - else if (lua_key_eq(s,adjust)) subtypes = node_subtypes_adjust; - else if (lua_key_eq(s,disc)) subtypes = node_subtypes_disc; -- else if (lua_key_eq(s,fill)) subtypes = node_subtypes_fill; -- else if (lua_key_eq(s,leader)) { subtypes = node_subtypes_leader; l = 2; } -+ else if (lua_key_eq(s,fill)) subtypes = node_values_fill; -+ else if (lua_key_eq(s,leader)) subtypes = node_subtypes_leader; - else if (lua_key_eq(s,marginkern)) subtypes = node_subtypes_marginkern; - else if (lua_key_eq(s,math)) subtypes = node_subtypes_math; - else if (lua_key_eq(s,noad)) subtypes = node_subtypes_noad; -@@ -2611,13 +3142,14 @@ static int lua_nodelib_subtypes(lua_State * L) - else if (lua_key_eq(s,accent)) subtypes = node_subtypes_accent; - else if (lua_key_eq(s,fence)) subtypes = node_subtypes_fence; - /* backend */ -- else if (lua_key_eq(s,pdf_destination)) subtypes = node_subtypes_pdf_destination; -- else if (lua_key_eq(s,pdf_literal)) subtypes = node_subtypes_pdf_literal; -+ else if (lua_key_eq(s,pdf_destination)) subtypes = node_values_pdf_destination; -+ else if (lua_key_eq(s,pdf_literal)) subtypes = node_values_pdf_literal; - } else if (t == LUA_TNUMBER) { - /* maybe */ - t = lua_tointeger(L,1); - if (t == glyph_node) subtypes = node_subtypes_glyph; -- else if (t == glue_node) { subtypes = node_subtypes_glue; l = 1; } -+ else if (t == glue_node) subtypes = node_subtypes_glue; -+ else if (t == dir_node) subtypes = node_subtypes_dir; - else if (t == boundary_node) subtypes = node_subtypes_boundary; - else if (t == penalty_node) subtypes = node_subtypes_penalty; - else if (t == kern_node) subtypes = node_subtypes_kern; -@@ -2626,7 +3158,7 @@ static int lua_nodelib_subtypes(lua_State * L) - || (t == vlist_node)) subtypes = node_subtypes_list; - else if (t == adjust_node) subtypes = node_subtypes_adjust; - else if (t == disc_node) subtypes = node_subtypes_disc; -- else if (t == glue_spec_node) subtypes = node_subtypes_fill; -+ else if (t == glue_spec_node) subtypes = node_values_fill; - else if (t == margin_kern_node) subtypes = node_subtypes_marginkern; - else if (t == math_node) subtypes = node_subtypes_math; - else if (t == simple_noad) subtypes = node_subtypes_noad; -@@ -2634,29 +3166,15 @@ static int lua_nodelib_subtypes(lua_State * L) - else if (t == accent_noad) subtypes = node_subtypes_accent; - else if (t == fence_noad) subtypes = node_subtypes_fence; - /* backend */ -- else if (t == pdf_dest_node) subtypes = node_subtypes_pdf_destination; -- else if (t == pdf_literal_node) subtypes = node_subtypes_pdf_literal; -+ else if (t == pdf_dest_node) subtypes = node_values_pdf_destination; -+ else if (t == pdf_literal_node) subtypes = node_values_pdf_literal; - } - if (subtypes != NULL) { - lua_checkstack(L, 2); - lua_newtable(L); -- if (l < 2) { -- for (i = 0; subtypes[i] != NULL; i++) { -- lua_pushstring(L, subtypes[i]); /* todo */ -- lua_rawseti(L, -2, i); -- } -- } -- if (l > 0) { -- /* add math states */ -- for (i = 0; node_subtypes_mathglue[i] != NULL; i++) { -- lua_pushstring(L, node_subtypes_mathglue[i]); /* todo */ -- lua_rawseti(L, -2, 98 + i); -- } -- /* add leaders */ -- for (i = 0; node_subtypes_leader[i] != NULL; i++) { -- lua_pushstring(L, node_subtypes_leader[i]); /* todo */ -- lua_rawseti(L, -2, 100 + i); -- } -+ for (i = 0; subtypes[i].id >= 0 ; i++) { -+ lua_rawgeti(L, LUA_REGISTRYINDEX, subtypes[i].lua); -+ lua_rawseti(L, -2, subtypes[i].id); - } - } else { - lua_pushnil(L); -@@ -2823,7 +3341,10 @@ static int lua_nodelib_get_attribute(lua_State * L) - if (p != null) { - p = vlink(p); - if (p != null) { -- int i = lua_tointeger(L, 2); -+ int i = 0; -+ if (lua_gettop(L) > 1) { -+ i = lua_tointeger(L, 2); -+ } - while (p != null) { - if (attribute_id(p) == i) { - int ret = attribute_value(p); -@@ -2895,7 +3416,10 @@ static int lua_nodelib_direct_get_attribute(lua_State * L) - if (p != null) { - p = vlink(p); - if (p != null) { -- int i = lua_tointeger(L, 2); -+ int i = 0; -+ if (lua_gettop(L) > 1) { -+ i = lua_tointeger(L, 2); -+ } - while (p != null) { - if (attribute_id(p) == i) { - int ret = attribute_value(p); -@@ -3049,10 +3573,24 @@ static int lua_nodelib_direct_getwidth(lua_State * L) - if (t == hlist_node || t == vlist_node || t == rule_node) { - lua_pushinteger(L,width(n)); - } else if (t == glyph_node) { -- lua_pushinteger(L, char_width(font(n),character(n))); -+ if (lua_toboolean(L,2)) { -+ lua_pushnumber(L, (1+ex_glyph(n)/1000) * char_width(font(n),character(n))); -+ lua_pushinteger(L, ex_glyph(n)); -+ return 2; -+ } else { -+ lua_pushinteger(L, char_width(font(n),character(n))); -+ } - } else if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) { - lua_pushinteger(L,width(n)); -- } else if (t == kern_node || t == margin_kern_node) { -+ } else if (t == kern_node) { -+ if (lua_toboolean(L,2)) { -+ lua_pushnumber(L, (1+ex_kern(n)/1000) * width(n)); -+ lua_pushinteger(L, ex_kern(n)); -+ return 2; -+ } else { -+ lua_pushinteger(L, width(n)); -+ } -+ } else if (t == margin_kern_node) { - lua_pushinteger(L,width(n)); - } else if (t == unset_node) { - lua_pushinteger(L,width(n)); -@@ -3071,7 +3609,8 @@ static int lua_nodelib_direct_setwidth(lua_State * L) - if (n) { - halfword t = type(n); - if (t == hlist_node || t == vlist_node || t == rule_node || t == glue_node || t == glue_spec_node || t == math_node || -- t == kern_node || t == margin_kern_node || t == ins_node || t == unset_node) { -+ t == kern_node || t == margin_kern_node || t == ins_node || t == unset_node || -+ t == fraction_noad || t == radical_noad ) { - if (lua_type(L, 2) == LUA_TNUMBER) { - width(n) = lua_roundnumber(L,2); - } else { -@@ -3093,6 +3632,8 @@ static int lua_nodelib_direct_getheight(lua_State * L) - lua_pushinteger(L, char_height(font(n),character(n))); - } else if (t == unset_node || t == ins_node) { - lua_pushinteger(L,height(n)); -+ } else if (t == fence_noad) { -+ lua_pushinteger(L,delimiterheight(n)); - } else { - lua_pushnil(L); - } -@@ -3107,12 +3648,14 @@ static int lua_nodelib_direct_setheight(lua_State * L) - halfword n = lua_tointeger(L, 1); - if (n) { - halfword t = type(n); -+ halfword h = 0; -+ if (lua_type(L, 2) == LUA_TNUMBER) { -+ h = lua_roundnumber(L,2); -+ } - if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) { -- if (lua_type(L, 2) == LUA_TNUMBER) { -- height(n) = lua_roundnumber(L,2); -- } else { -- height(n) = 0; -- } -+ height(n) = h; -+ } else if (t == fence_noad) { -+ delimiterheight(n) = h; - } - } - return 0; -@@ -3129,6 +3672,8 @@ static int lua_nodelib_direct_getdepth(lua_State * L) - lua_pushinteger(L, char_depth(font(n),character(n))); - } else if (t == unset_node || t == ins_node) { - lua_pushinteger(L,depth(n)); -+ } else if (t == fence_noad) { -+ lua_pushinteger(L,delimiterdepth(n)); - } else { - lua_pushnil(L); - } -@@ -3143,12 +3688,14 @@ static int lua_nodelib_direct_setdepth(lua_State * L) - halfword n = lua_tointeger(L, 1); - if (n) { - halfword t = type(n); -+ halfword d = 0; -+ if (lua_type(L, 2) == LUA_TNUMBER) { -+ d = lua_roundnumber(L,2); -+ } - if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) { -- if (lua_type(L, 2) == LUA_TNUMBER) { -- depth(n) = lua_roundnumber(L,2); -- } else { -- depth(n) = 0; -- } -+ depth(n) = d; -+ } else if (t == fence_noad) { -+ delimiterdepth(n) = d; - } - } - return 0; -@@ -3324,9 +3871,51 @@ static int nodelib_aux_nil(lua_State * L) - return 1; - } - --/* node.direct.traverse_id */ - /* node.direct.traverse */ -+/* node.direct.traverse_id */ - /* node.direct.traverse_char */ -+/* node.direct.traverse_glyph */ -+/* node.direct.traverse_list */ -+ -+static int nodelib_direct_aux_next(lua_State * L) -+{ -+ halfword t; -+ if (lua_isnil(L, 2)) { -+ t = lua_tointeger(L,1) ; -+ lua_settop(L,1); -+ } else { -+ t = lua_tointeger(L,2) ; -+ t = vlink(t); -+ lua_settop(L,2); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ lua_pushinteger(L,t); -+ lua_pushinteger(L,type(t)); -+ lua_pushinteger(L,subtype(t)); -+ return 3; -+ } -+} -+ -+static int lua_nodelib_direct_traverse(lua_State * L) -+{ -+ halfword n; -+ if (lua_isnil(L, 1)) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ n = (halfword) lua_tointeger(L, 1); -+ if (n == null) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ lua_pushcclosure(L, nodelib_direct_aux_next, 0); -+ lua_pushinteger(L,n); -+ lua_pushnil(L); -+ return 3; -+} - - static int nodelib_direct_aux_next_filtered(lua_State * L) - { -@@ -3340,18 +3929,17 @@ static int nodelib_direct_aux_next_filtered(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -- while (1) { -- if (t == null) { -- break; -- } else if (type(t) == i) { -- lua_pushinteger(L,t); -- return 1; -- } else { -- t = vlink(t); -- } -+ while (t != null && type(t) != i) { -+ t = vlink(t); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ lua_pushinteger(L,t); -+ lua_pushinteger(L,subtype(t)); -+ return 2; - } -- lua_pushnil(L); -- return 1; - } - - static int lua_nodelib_direct_traverse_filtered(lua_State * L) -@@ -3371,7 +3959,7 @@ static int lua_nodelib_direct_traverse_filtered(lua_State * L) - return 3; - } - --static int nodelib_direct_aux_next(lua_State * L) -+static int nodelib_direct_aux_next_char(lua_State * L) - { - halfword t; /* traverser */ - if (lua_isnil(L, 2)) { /* first call */ -@@ -3382,15 +3970,21 @@ static int nodelib_direct_aux_next(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -+ while (! ((t == null) || (type(t) == glyph_node && subtype(t) < 256))) { -+ t = vlink(t); -+ } - if (t == null) { - lua_pushnil(L); -+ return 1; - } else { - lua_pushinteger(L,t); -+ lua_pushinteger(L,character(t)); -+ lua_pushinteger(L,font(t)); -+ return 3; - } -- return 1; - } - --static int lua_nodelib_direct_traverse(lua_State * L) -+static int lua_nodelib_direct_traverse_char(lua_State * L) - { - halfword n; - if (lua_isnil(L, 1)) { -@@ -3402,13 +3996,13 @@ static int lua_nodelib_direct_traverse(lua_State * L) - lua_pushcclosure(L, nodelib_aux_nil, 0); - return 1; - } -- lua_pushcclosure(L, nodelib_direct_aux_next, 0); -+ lua_pushcclosure(L, nodelib_direct_aux_next_char, 0); - lua_pushinteger(L,n); - lua_pushnil(L); - return 3; - } - --static int nodelib_direct_aux_next_char(lua_State * L) -+static int nodelib_direct_aux_next_glyph(lua_State * L) - { - halfword t; /* traverser */ - if (lua_isnil(L, 2)) { /* first call */ -@@ -3419,21 +4013,65 @@ static int nodelib_direct_aux_next_char(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -- while (1) { -- if (t == null) { -- break; -- } else if ((type(t) == glyph_node) && (subtype(t) < 256)){ -- lua_pushinteger(L,t); -- return 1; -- } else { -- t = vlink(t); -- } -+ while (t != null && type(t) != glyph_node) { -+ t = vlink(t); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ lua_pushinteger(L,t); -+ lua_pushinteger(L,character(t)); -+ lua_pushinteger(L,font(t)); -+ return 3; - } -+} -+ -+static int lua_nodelib_direct_traverse_glyph(lua_State * L) -+{ -+ halfword n; -+ if (lua_isnil(L, 1)) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ n = (halfword) lua_tointeger(L, 1); -+ if (n == null) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ lua_pushcclosure(L, nodelib_direct_aux_next_glyph, 0); -+ lua_pushinteger(L,n); - lua_pushnil(L); -- return 1; -+ return 3; - } - --static int lua_nodelib_direct_traverse_char(lua_State * L) -+static int nodelib_direct_aux_next_list(lua_State * L) -+{ -+ halfword t; /* traverser */ -+ if (lua_isnil(L, 2)) { /* first call */ -+ t = lua_tointeger(L,1) ; -+ lua_settop(L,1); -+ } else { -+ t = lua_tointeger(L,2) ; -+ t = vlink(t); -+ lua_settop(L,2); -+ } -+ while (t != null && type(t) != hlist_node && type(t) != vlist_node) { -+ t = vlink(t); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ lua_pushinteger(L,t); -+ lua_pushinteger(L,type(t)); -+ lua_pushinteger(L,subtype(t)); -+ nodelib_pushdirect_or_nil(list_ptr(t)); -+ return 4; -+ } -+} -+ -+static int lua_nodelib_direct_traverse_list(lua_State * L) - { - halfword n; - if (lua_isnil(L, 1)) { -@@ -3445,22 +4083,101 @@ static int lua_nodelib_direct_traverse_char(lua_State * L) - lua_pushcclosure(L, nodelib_aux_nil, 0); - return 1; - } -- lua_pushcclosure(L, nodelib_direct_aux_next_char, 0); -- lua_pushinteger(L,n); -+ lua_pushcclosure(L, nodelib_direct_aux_next_list, 1); -+ lua_pushinteger(L, n); -+ lua_pushnil(L); -+ return 3; -+} -+ -+/* node.traverse */ -+/* node.traverse_id */ -+/* node.traverse_char */ -+/* node.traverse_glyph */ -+/* node.traverse_list */ -+ -+static int nodelib_aux_next(lua_State * L) -+{ -+ halfword t; -+ halfword *a; -+ if (lua_isnil(L, 2)) { -+ t = *check_isnode(L, 1); -+ lua_settop(L,1); -+ } else { -+ t = *check_isnode(L, 2); -+ t = vlink(t); -+ lua_settop(L,2); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ fast_metatable_top(t); -+ lua_pushinteger(L,type(t)); -+ lua_pushinteger(L,subtype(t)); -+ return 3; -+ } -+} -+ -+static int lua_nodelib_traverse(lua_State * L) -+{ -+ halfword n; -+ if (lua_isnil(L, 1)) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ n = *check_isnode(L, 1); -+ lua_pushcclosure(L, nodelib_aux_next, 0); -+ lua_nodelib_push_fast(L, n); -+ lua_pushnil(L); -+ return 3; -+} -+ -+static int nodelib_aux_next_filtered(lua_State * L) -+{ -+ halfword t; /* traverser */ -+ halfword *a; -+ int i = (int) lua_tointeger(L, lua_upvalueindex(1)); -+ if (lua_isnil(L, 2)) { /* first call */ -+ t = *check_isnode(L, 1); -+ lua_settop(L,1); -+ } else { -+ t = *check_isnode(L, 2); -+ t = vlink(t); -+ lua_settop(L,2); -+ } -+ while (t != null && type(t) != i) { -+ t = vlink(t); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ fast_metatable_top(t); -+ lua_pushinteger(L,subtype(t)); -+ return 2; -+ } -+} -+ -+static int lua_nodelib_traverse_filtered(lua_State * L) -+{ -+ halfword n; -+ if (lua_isnil(L, 2)) { -+ lua_pushcclosure(L, nodelib_aux_nil, 0); -+ return 1; -+ } -+ n = *check_isnode(L, 2); -+ lua_pop(L, 1); /* the node, integer remains */ -+ lua_pushcclosure(L, nodelib_aux_next_filtered, 1); -+ lua_nodelib_push_fast(L, n); - lua_pushnil(L); - return 3; - } - --/* node.traverse_id */ --/* node.traverse */ --/* node.traverse_char */ -- --static int nodelib_aux_next_filtered(lua_State * L) -+static int nodelib_aux_next_char(lua_State * L) - { -- halfword t; /* traverser */ -+ halfword t; /* traverser */ - halfword *a; -- int i = (int) lua_tointeger(L, lua_upvalueindex(1)); -- if (lua_isnil(L, 2)) { /* first call */ -+ if (lua_isnil(L, 2)) { /* first call */ - t = *check_isnode(L, 1); - lua_settop(L,1); - } else { -@@ -3468,36 +4185,38 @@ static int nodelib_aux_next_filtered(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -- while (t != null && type(t) != i) { -+ while (! ((t == null) || (type(t) == glyph_node && subtype(t) < 256))) { - t = vlink(t); - } - if (t == null) { - lua_pushnil(L); -+ return 1; - } else { - fast_metatable_top(t); -+ lua_pushinteger(L,character(t)); -+ lua_pushinteger(L,font(t)); -+ return 3; - } -- return 1; - } - --static int lua_nodelib_traverse_filtered(lua_State * L) -+static int lua_nodelib_traverse_char(lua_State * L) - { - halfword n; -- if (lua_isnil(L, 2)) { -+ if (lua_isnil(L, 1)) { - lua_pushcclosure(L, nodelib_aux_nil, 0); - return 1; - } -- n = *check_isnode(L, 2); -- lua_pop(L, 1); /* the node, integer remains */ -- lua_pushcclosure(L, nodelib_aux_next_filtered, 1); -+ n = *check_isnode(L, 1); -+ lua_pushcclosure(L, nodelib_aux_next_char, 0); - lua_nodelib_push_fast(L, n); - lua_pushnil(L); - return 3; - } - --static int nodelib_aux_next(lua_State * L) -+static int nodelib_aux_next_glyph(lua_State * L) - { - halfword t; /* traverser */ -- halfword *a; /* a or *a */ -+ halfword *a; - if (lua_isnil(L, 2)) { /* first call */ - t = *check_isnode(L, 1); - lua_settop(L,1); -@@ -3506,15 +4225,21 @@ static int nodelib_aux_next(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -+ while (t != null && type(t) != glyph_node) { -+ t = vlink(t); -+ } - if (t == null) { - lua_pushnil(L); -+ return 1; - } else { - fast_metatable_top(t); -+ lua_pushinteger(L,character(t)); -+ lua_pushinteger(L,font(t)); -+ return 3; - } -- return 1; - } - --static int lua_nodelib_traverse(lua_State * L) -+static int lua_nodelib_traverse_glyph(lua_State * L) - { - halfword n; - if (lua_isnil(L, 1)) { -@@ -3522,17 +4247,17 @@ static int lua_nodelib_traverse(lua_State * L) - return 1; - } - n = *check_isnode(L, 1); -- lua_pushcclosure(L, nodelib_aux_next, 0); -+ lua_pushcclosure(L, nodelib_aux_next_glyph, 0); - lua_nodelib_push_fast(L, n); - lua_pushnil(L); - return 3; - } - --static int nodelib_aux_next_char(lua_State * L) -+static int nodelib_aux_next_list(lua_State * L) - { -- halfword t; /* traverser */ -+ halfword t; /* traverser */ - halfword *a; -- if (lua_isnil(L, 2)) { /* first call */ -+ if (lua_isnil(L, 2)) { /* first call */ - t = *check_isnode(L, 1); - lua_settop(L,1); - } else { -@@ -3540,20 +4265,22 @@ static int nodelib_aux_next_char(lua_State * L) - t = vlink(t); - lua_settop(L,2); - } -- while (1) { -- if (t == null) { -- break; -- } else if ((type(t) == glyph_node) && (subtype(t) < 256)){ -- fast_metatable_top(t); -- return 1; -- } else { -- t = vlink(t); -- } -+ while (t != null && type(t) != hlist_node && type(t) != vlist_node) { -+ t = vlink(t); -+ } -+ if (t == null) { -+ lua_pushnil(L); -+ return 1; -+ } else { -+ fast_metatable_top(t); -+ lua_pushinteger(L,type(t)); -+ lua_pushinteger(L,subtype(t)); -+ fast_metatable_or_nil(list_ptr(t)); -+ return 4; - } -- return 1; - } - --static int lua_nodelib_traverse_char(lua_State * L) -+static int lua_nodelib_traverse_list(lua_State * L) - { - halfword n; - if (lua_isnil(L, 1)) { -@@ -3561,7 +4288,7 @@ static int lua_nodelib_traverse_char(lua_State * L) - return 1; - } - n = *check_isnode(L, 1); -- lua_pushcclosure(L, nodelib_aux_next_char, 0); -+ lua_pushcclosure(L, nodelib_aux_next_list, 1); - lua_nodelib_push_fast(L, n); - lua_pushnil(L); - return 3; -@@ -3638,46 +4365,6 @@ static int lua_nodelib_count(lua_State * L) - return do_lua_nodelib_count(L, m, i, n); - } - --/* getting and setting fields (helpers) */ -- --int nodelib_getlist(lua_State * L, int n) --{ -- if (lua_isuserdata(L, n)) { -- halfword m = *check_isnode(L, n); -- return m; -- } else { -- return null; -- } --} -- --int nodelib_getdir(lua_State * L, int n, int absolute_only) --{ -- if (lua_type(L, n) == LUA_TSTRING) { -- const char *s = lua_tostring(L, n); -- RETURN_DIR_VALUES(TLT); -- RETURN_DIR_VALUES(TRT); -- RETURN_DIR_VALUES(LTL); -- RETURN_DIR_VALUES(RTT); -- luaL_error(L, "Bad direction specifier %s", s); -- } else { -- luaL_error(L, "Direction specifiers have to be strings"); -- } -- return 0; --} -- --static str_number nodelib_getstring(lua_State * L, int a) --{ -- size_t k; -- const char *s = lua_tolstring(L, a, &k); -- return maketexlstring(s, k); --} -- --static int nodelib_cantset(lua_State * L, int n, const char *s) --{ -- luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name); -- return 0; --} -- - /* node.direct.getfield */ - - static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s) -@@ -3690,54 +4377,48 @@ static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s) - lua_pushinteger(L, user_node_type(n)); - } else if (lua_key_eq(s, value)) { - switch (user_node_type(n)) { -- case 'a': -- nodelib_pushlist(L, user_node_value(n)); -- break; -- case 'd': -- lua_pushinteger(L, user_node_value(n)); -- break; -- case 'l': -- if (user_node_value(n) != 0) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n)); -- } else { -- lua_pushnil(L); -- } -- break; -- case 'n': -- nodelib_pushlist(L, user_node_value(n)); -- break; -- case 's': -- nodelib_pushstring(L, user_node_value(n)); -- break; -- case 't': -- tokenlist_to_lua(L, user_node_value(n)); -- break; -- default: -- lua_pushinteger(L, user_node_value(n)); -- break; -+ case 'a': -+ nodelib_pushlist(L, user_node_value(n)); -+ break; -+ case 'd': -+ lua_pushinteger(L, user_node_value(n)); -+ break; -+ case 'l': -+ if (user_node_value(n) != 0) { -+ lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n)); -+ } else { -+ lua_pushnil(L); -+ } -+ break; -+ case 'n': -+ nodelib_pushlist(L, user_node_value(n)); -+ break; -+ case 's': -+ nodelib_pushstring(L, user_node_value(n)); -+ break; -+ case 't': -+ tokenlist_to_lua(L, user_node_value(n)); -+ break; -+ default: -+ lua_pushinteger(L, user_node_value(n)); -+ break; - } - } else { - lua_pushnil(L); - } - } else if (t == pdf_literal_node) { -+ /*tex The |string| key is obsolete. */ - if (lua_key_eq(s, mode)) { - lua_pushinteger(L, pdf_literal_mode(n)); -- } else if (lua_key_eq(s, data)) { -- if (pdf_literal_type(n) == lua_refid_literal) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n)); -- } else { -- tokenlist_to_luastring(L, pdf_literal_data(n)); -- } -+ } else if (lua_key_eq(s, data) || lua_key_eq(s, token) || lua_key_eq(s, string)) { -+ get_pdf_literal_direct_value(L, n); - } else { - lua_pushnil(L); - } - } else if (t == late_lua_node) { -- if (lua_key_eq(s, string) || lua_key_eq(s, data)) { -- if (late_lua_type(n) == lua_refid_literal) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n)); -- } else { -- tokenlist_to_luastring(L, late_lua_data(n)); -- } -+ /*tex The |string| key is obsolete. */ -+ if (lua_key_eq(s, data) || lua_key_eq(s, token) || lua_key_eq(s, string)) { -+ get_late_lua_direct_value(L,n); - } else if (lua_key_eq(s, name)) { - tokenlist_to_luastring(L, late_lua_name(n)); - } else { -@@ -3782,7 +4463,7 @@ static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s) - } - } else if (t == pdf_setmatrix_node) { - if (lua_key_eq(s, data)) { -- tokenlist_to_luastring(L, pdf_setmatrix_data(n)); -+ get_pdf_setmatrix_direct_value(L,n); - } else { - lua_pushnil(L); - } -@@ -3806,13 +4487,13 @@ static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s) - if (lua_key_eq(s, stream)) { - lua_pushinteger(L, write_stream(n)); - } else if (lua_key_eq(s, data)) { -- tokenlist_to_lua(L, write_tokens(n)); -+ get_write_direct_value(L,n); - } else { - lua_pushnil(L); - } - } else if (t == special_node) { - if (lua_key_eq(s, data)) { -- tokenlist_to_luastring(L, write_tokens(n)); -+ get_special_direct_value(L,n); - } else { - lua_pushnil(L); - } -@@ -3978,8 +4659,8 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushinteger(L, x_displace(n)); - } else if (lua_key_eq(s, yoffset)) { - lua_pushinteger(L, y_displace(n)); -- } else if (lua_key_eq(s, xadvance)) { -- lua_pushinteger(L, x_advance(n)); -+ } else if (lua_key_eq(s, data)) { -+ lua_pushinteger(L, glyph_node_data(n)); - } else if (lua_key_eq(s, width)) { - lua_pushinteger(L, char_width(font(n),character(n))); - } else if (lua_key_eq(s, height)) { -@@ -4013,6 +4694,8 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, box_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, box_dir(n)); - } else if (lua_key_eq(s, shift)) { -@@ -4086,6 +4769,12 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, left)) { -+ lua_pushinteger(L,rule_left(n)); -+ } else if (lua_key_eq(s, right)) { -+ lua_pushinteger(L,rule_right(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, rule_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, rule_dir(n)); - } else if (lua_key_eq(s, index)) { -@@ -4096,8 +4785,10 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushnil(L); - } - } else if (t == dir_node) { -- if (lua_key_eq(s, dir)) { -- lua_push_dir_text(L, dir_dir(n)); -+ if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, dir_dir(n)); -+ } else if (lua_key_eq(s, dir)) { -+ lua_push_dir_text(L, dir_dir(n),subtype(n)); - } else if (lua_key_eq(s, level)) { - lua_pushinteger(L, dir_level(n)); - } else if (lua_key_eq(s, subtype)) { /* can be used for anything */ -@@ -4110,6 +4801,8 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushinteger(L, local_pen_inter(n)); - } else if (lua_key_eq(s, pen_broken)) { - lua_pushinteger(L, local_pen_broken(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, local_par_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, local_par_dir(n)); - } else if (lua_key_eq(s, box_left)) { -@@ -4241,6 +4934,8 @@ static int lua_nodelib_fast_getfield(lua_State * L) - fast_metatable_or_nil(right_delimiter(n)); - } else if (lua_key_eq(s, middle)) { - fast_metatable_or_nil(middle_delimiter(n)); -+ } else if (lua_key_eq(s, fam)) { -+ lua_pushinteger(L, fraction_fam(n)); - } else if (lua_key_eq(s, options)) { - lua_pushinteger(L, fractionoptions(n)); - } else { -@@ -4409,6 +5104,8 @@ static int lua_nodelib_fast_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, box_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, box_dir(n)); - } else if (lua_key_eq(s, shrink)) { -@@ -4477,55 +5174,23 @@ static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char - } else if (lua_key_eq(s, type)) { - lua_pushinteger(L, user_node_type(n)); - } else if (lua_key_eq(s, value)) { -- switch (user_node_type(n)) { -- case 'a': -- nodelib_pushdirect(user_node_value(n)); -- break; -- case 'd': -- lua_pushinteger(L, user_node_value(n)); -- break; -- case 'l': -- if (user_node_value(n) != 0) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n)); -- } else { -- lua_pushnil(L); -- } -- break; -- case 'n': -- nodelib_pushdirect(user_node_value(n)); -- break; -- case 's': -- nodelib_pushstring(L, user_node_value(n)); -- break; -- case 't': -- tokenlist_to_lua(L, user_node_value(n)); -- break; -- default: -- lua_pushinteger(L, user_node_value(n)); -- break; -- } -+ get_user_node_direct_value(L, n); - } else { - lua_pushnil(L); - } - } else if (t == pdf_literal_node) { -+ /*tex The |string| key is obsolete. */ - if (lua_key_eq(s, mode)) { - lua_pushinteger(L, pdf_literal_mode(n)); -- } else if (lua_key_eq(s, data)) { -- if (pdf_literal_type(n) == lua_refid_literal) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n)); -- } else { -- tokenlist_to_luastring(L, pdf_literal_data(n)); -- } -+ } else if (lua_key_eq(s, data) || lua_key_eq(s, token) || lua_key_eq(s, string)) { -+ get_pdf_literal_direct_value(L, n); - } else { - lua_pushnil(L); - } - } else if (t == late_lua_node) { -- if (lua_key_eq(s, string) || lua_key_eq(s, data)) { -- if (late_lua_type(n) == lua_refid_literal) { -- lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n)); -- } else { -- tokenlist_to_luastring(L, late_lua_data(n)); -- } -+ /*tex The |string| key is obsolete. */ -+ if (lua_key_eq(s, data) || lua_key_eq(s, token) || lua_key_eq(s, string)) { -+ get_late_lua_direct_value(L,n); - } else if (lua_key_eq(s, name)) { - tokenlist_to_luastring(L, late_lua_name(n)); - } else { -@@ -4570,7 +5235,7 @@ static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char - } - } else if (t == pdf_setmatrix_node) { - if (lua_key_eq(s, data)) { -- tokenlist_to_luastring(L, pdf_setmatrix_data(n)); -+ get_pdf_setmatrix_direct_value(L,n); - } else { - lua_pushnil(L); - } -@@ -4594,13 +5259,13 @@ static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char - if (lua_key_eq(s, stream)) { - lua_pushinteger(L, write_stream(n)); - } else if (lua_key_eq(s, data)) { -- tokenlist_to_lua(L, write_tokens(n)); -+ get_write_direct_value(L,n); - } else { - lua_pushnil(L); - } - } else if (t == special_node) { - if (lua_key_eq(s, data)) { -- tokenlist_to_luastring(L, write_tokens(n)); -+ get_special_direct_value(L,n); - } else { - lua_pushnil(L); - } -@@ -4751,8 +5416,8 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushinteger(L, x_displace(n)); - } else if (lua_key_eq(s, yoffset)) { - lua_pushinteger(L, y_displace(n)); -- } else if (lua_key_eq(s, xadvance)) { -- lua_pushinteger(L, x_advance(n)); -+ } else if (lua_key_eq(s, data)) { -+ lua_pushinteger(L, glyph_node_data(n)); - } else if (lua_key_eq(s, width)) { - lua_pushinteger(L, char_width(font(n),character(n))); - } else if (lua_key_eq(s, height)) { -@@ -4784,6 +5449,8 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, box_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, box_dir(n)); - } else if (lua_key_eq(s, shift)) { -@@ -4847,6 +5514,12 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, left)) { -+ lua_pushinteger(L,rule_left(n)); -+ } else if (lua_key_eq(s, right)) { -+ lua_pushinteger(L,rule_right(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, rule_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, rule_dir(n)); - } else if (lua_key_eq(s, index)) { -@@ -4857,8 +5530,10 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushnil(L); - } - } else if (t == dir_node) { -- if (lua_key_eq(s, dir)) { -- lua_push_dir_text(L, dir_dir(n)); -+ if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, dir_dir(n)); -+ } else if (lua_key_eq(s, dir)) { -+ lua_push_dir_text(L, dir_dir(n), subtype(n)); - } else if (lua_key_eq(s, level)) { - lua_pushinteger(L, dir_level(n)); - } else if (lua_key_eq(s, subtype)) { /* can be used for anything */ -@@ -4871,6 +5546,8 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushinteger(L, local_pen_inter(n)); - } else if (lua_key_eq(s, pen_broken)) { - lua_pushinteger(L, local_pen_broken(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, local_par_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, local_par_dir(n)); - } else if (lua_key_eq(s, box_left)) { -@@ -4969,6 +5646,8 @@ static int lua_nodelib_direct_getfield(lua_State * L) - nodelib_pushdirect_or_nil(right_delimiter(n)); - } else if (lua_key_eq(s, middle)) { - nodelib_pushdirect_or_nil(middle_delimiter(n)); -+ } else if (lua_key_eq(s, fam)) { -+ lua_pushinteger(L, fraction_fam(n)); - } else if (lua_key_eq(s, options)) { - lua_pushinteger(L, fractionoptions(n)); - } else { -@@ -5111,6 +5790,8 @@ static int lua_nodelib_direct_getfield(lua_State * L) - lua_pushinteger(L, height(n)); - } else if (lua_key_eq(s, depth)) { - lua_pushinteger(L, depth(n)); -+ } else if (lua_key_eq(s, direction)) { -+ lua_pushinteger(L, box_dir(n)); - } else if (lua_key_eq(s, dir)) { - lua_push_dir_par(L, box_dir(n)); - } else if (lua_key_eq(s, shrink)) { -@@ -5213,7 +5894,7 @@ static int lua_nodelib_equal(lua_State * L) - static int font_tex_ligaturing(lua_State * L) - { - /* on the stack are two nodes and a direction */ -- /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */ -+ /* we need to deal with prev nodes when a range starts with a ligature */ - halfword tmp_head; - halfword h; - halfword t = null; -@@ -5254,7 +5935,7 @@ static int font_tex_ligaturing(lua_State * L) - static int font_tex_direct_ligaturing(lua_State * L) - { - /* on the stack are two nodes and a direction */ -- /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */ -+ /* we need to deal with prev nodes when a range starts with a ligature */ - halfword tmp_head; - halfword h; - halfword t = null; -@@ -5805,57 +6486,29 @@ static int lua_nodelib_direct_tonode(lua_State * L) - - /* node.setfield */ - --#define cleanup_late_lua(n) do { \ -- if (late_lua_data(n) != 0) { \ -- if (late_lua_type(n) == normal) { \ -- delete_token_ref(late_lua_data(n)); \ -- } else if (late_lua_type(n) == lua_refid_literal) { \ -- luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \ -- } \ -- } \ --} while (0) -- --#define cleanup_late_lua_name(n) do { \ -- if (late_lua_name(n) != 0) { \ -- delete_token_ref(late_lua_name(n)); \ -- } \ --} while (0) -- - static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s) - { - int t = subtype(n); - - if (t == pdf_literal_node) { -+ /*tex The |string| key is obsolete. */ - if (lua_key_eq(s, mode)) { - pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3); -- } else if (lua_key_eq(s, data)) { -- if (ini_version) { -- pdf_literal_data(n) = nodelib_gettoks(L, 3); -- } else { -- lua_pushvalue(L, 3); -- pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- pdf_literal_type(n) = lua_refid_literal; -- } -+ } else if (lua_key_eq(s, data) || lua_key_eq(s, string)) { -+ set_pdf_literal_direct_normal(L, n, 3); -+ } else if (lua_key_eq(s, token)) { -+ set_pdf_literal_direct_token(L, n, 3); - } else { - return nodelib_cantset(L, n, s); - } - } else if (t == late_lua_node) { -- if (lua_key_eq(s, string)) { -- cleanup_late_lua(n) ; /* ls-hh */ -- if (ini_version) { -- late_lua_data(n) = nodelib_gettoks(L, 3); -- late_lua_type(n) = normal; -- } else { -- lua_pushvalue(L, 3); -- late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- late_lua_type(n) = lua_refid_literal; -- } -- } else if (lua_key_eq(s, data)) { -- cleanup_late_lua(n) ; /* ls-hh */ -- late_lua_data(n) = nodelib_gettoks(L, 3); -- late_lua_type(n) = normal; -+ /*tex The |string| key is obsolete. */ -+ if (lua_key_eq(s, data) || lua_key_eq(s, string)) { -+ set_late_lua_direct_normal(L, n, 3); -+ } else if (lua_key_eq(s, token)) { -+ set_late_lua_direct_token(L, n, 3); - } else if (lua_key_eq(s, name)) { -- cleanup_late_lua_name(n) ; /* ls-hh */ -+ cleanup_late_lua_name(n) ; - late_lua_name(n) = nodelib_gettoks(L, 3); - } else { - return nodelib_cantset(L, n, s); -@@ -5868,31 +6521,31 @@ static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s) - user_node_type(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, value)) { - switch (user_node_type(n)) { -- case 'a': -- user_node_value(n) = nodelib_getlist(L, 3); -- break; -- case 'd': -- user_node_value(n) = (halfword) lua_roundnumber(L, 3); -- break; -- case 'l': -- lua_pushvalue(L, 3); -- if (user_node_value(n) != 0) { -- luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n)); -- } -- user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- break; -- case 'n': -- user_node_value(n) = nodelib_getlist(L, 3); -- break; -- case 's': -- user_node_value(n) = nodelib_getstring(L, 3); -- break; -- case 't': -- user_node_value(n) = nodelib_gettoks(L, 3); -- break; -- default: -- user_node_value(n) = (halfword) lua_roundnumber(L, 3); -- break; -+ case 'a': -+ user_node_value(n) = nodelib_getlist(L, 3); -+ break; -+ case 'd': -+ user_node_value(n) = (halfword) lua_roundnumber(L, 3); -+ break; -+ case 'l': -+ lua_pushvalue(L, 3); -+ if (user_node_value(n) != 0) { -+ luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n)); -+ } -+ user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX); -+ break; -+ case 'n': -+ user_node_value(n) = nodelib_getlist(L, 3); -+ break; -+ case 's': -+ user_node_value(n) = nodelib_getstring(L, 3); -+ break; -+ case 't': -+ user_node_value(n) = nodelib_gettoks(L, 3); -+ break; -+ default: -+ user_node_value(n) = (halfword) lua_roundnumber(L, 3); -+ break; - } - } else { - return nodelib_cantset(L, n, s); -@@ -5937,7 +6590,7 @@ static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s) - } - } else if (t == pdf_setmatrix_node) { - if (lua_key_eq(s, data)) { -- pdf_setmatrix_data(n) = nodelib_gettoks(L, 3); -+ set_pdf_setmatrix_direct_value(L,n,3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -5967,7 +6620,7 @@ static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s) - if (lua_key_eq(s, stream)) { - write_stream(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, data)) { -- write_tokens(n) = nodelib_gettoks(L, 3); -+ set_write_direct_value(L,n,3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6023,7 +6676,7 @@ static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s) - } - } else if (t == special_node) { - if (lua_key_eq(s, data)) { -- write_tokens(n) = nodelib_gettoks(L, 3); -+ set_special_direct_value(L,n,3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6107,8 +6760,8 @@ static int lua_nodelib_fast_setfield(lua_State * L) - x_displace(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, yoffset)) { - y_displace(n) = (halfword) lua_roundnumber(L, 3); -- } else if (lua_key_eq(s, xadvance)) { -- x_advance(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, data)) { -+ glyph_node_data(n) = (halfword) lua_tointeger(L, 3);; - } else if (lua_key_eq(s, width)) { - /* not yet */ - } else if (lua_key_eq(s, height)) { -@@ -6141,8 +6794,10 @@ static int lua_nodelib_fast_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ box_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- box_dir(n) = nodelib_getdir(L, 3, 1); -+ box_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, shift)) { - shift_amount(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, glue_order)) { -@@ -6213,8 +6868,14 @@ static int lua_nodelib_fast_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, left)) { -+ rule_left(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, right)) { -+ rule_right(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ rule_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- rule_dir(n) = nodelib_getdir(L, 3, 1); -+ rule_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, index)) { - rule_index(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, transform)) { -@@ -6223,12 +6884,12 @@ static int lua_nodelib_fast_setfield(lua_State * L) - return nodelib_cantset(L, n, s); - } - } else if (t == dir_node) { -- if (lua_key_eq(s, dir)) { -- dir_dir(n) = nodelib_getdir(L, 3, 0); -+ if (lua_key_eq(s, direction)) { -+ dir_dir(n) = nodelib_getdirection(L, 3); -+ } else if (lua_key_eq(s, dir)) { -+ nodelib_setdir_text(L, 3, n); - } else if (lua_key_eq(s, level)) { - dir_level(n) = (halfword) lua_tointeger(L, 3); -- } else if (lua_key_eq(s, subtype)) { /* can be used for anything */ -- subtype(n) = (quarterword) lua_tointeger(L, 3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6237,8 +6898,10 @@ static int lua_nodelib_fast_setfield(lua_State * L) - local_pen_inter(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, pen_broken)) { - local_pen_broken(n) = (halfword) lua_tointeger(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ local_par_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- local_par_dir(n) = nodelib_getdir(L, 3, 1); -+ local_par_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, box_left)) { - local_box_left(n) = nodelib_getlist(L, 3); - } else if (lua_key_eq(s, box_left_width)) { -@@ -6349,6 +7012,8 @@ static int lua_nodelib_fast_setfield(lua_State * L) - right_delimiter(n) = nodelib_getlist(L, 3); - } else if (lua_key_eq(s, middle)) { - middle_delimiter(n) = nodelib_getlist(L, 3); -+ } else if (lua_key_eq(s, fam)) { -+ fraction_fam(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, options)) { - fractionoptions(n) = (halfword) lua_tointeger(L, 3); - } else { -@@ -6517,8 +7182,10 @@ static int lua_nodelib_fast_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ box_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- box_dir(n) = nodelib_getdir(L, 3, 1); -+ box_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, shrink)) { - glue_shrink(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, glue_order)) { -@@ -6592,36 +7259,24 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char - { - int t = subtype(n); - if (t == pdf_literal_node) { -+ /*tex The |string| key is obsolete. */ - if (lua_key_eq(s, mode)) { - pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3); -- } else if (lua_key_eq(s, data)) { -- if (ini_version) { -- pdf_literal_data(n) = nodelib_gettoks(L, 3); -- } else { -- lua_pushvalue(L, 3); -- pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- pdf_literal_type(n) = lua_refid_literal; -- } -+ } else if (lua_key_eq(s, data) || lua_key_eq(s, string)) { -+ set_pdf_literal_direct_normal(L, n, 3); -+ } else if (lua_key_eq(s, token)) { -+ set_pdf_literal_direct_token(L, n, 3); - } else { - return nodelib_cantset(L, n, s); - } - } else if (t == late_lua_node) { -- if (lua_key_eq(s, string)) { -- cleanup_late_lua(n) ; /* ls-hh */ -- if (ini_version) { -- late_lua_data(n) = nodelib_gettoks(L, 3); -- late_lua_type(n) = normal; -- } else { -- lua_pushvalue(L, 3); -- late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- late_lua_type(n) = lua_refid_literal; -- } -- } else if (lua_key_eq(s, data)) { -- cleanup_late_lua(n) ; /* ls-hh */ -- late_lua_data(n) = nodelib_gettoks(L, 3); -- late_lua_type(n) = normal; -+ /*tex The |string| key is obsolete. */ -+ if (lua_key_eq(s, data) || lua_key_eq(s, string)) { -+ set_late_lua_direct_normal(L, n, 3); -+ } else if (lua_key_eq(s, token)) { -+ set_late_lua_direct_token(L, n, 3); - } else if (lua_key_eq(s, name)) { -- cleanup_late_lua_name(n) ; /* ls-hh */ -+ cleanup_late_lua_name(n) ; - late_lua_name(n) = nodelib_gettoks(L, 3); - } else { - return nodelib_cantset(L, n, s); -@@ -6632,33 +7287,7 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char - } else if (lua_key_eq(s, type)) { - user_node_type(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, value)) { -- switch (user_node_type(n)) { -- case 'a': -- user_node_value(n) = nodelib_getlist(L, 3); -- break; -- case 'd': -- user_node_value(n) = (halfword) lua_roundnumber(L, 3); -- break; -- case 'l': -- lua_pushvalue(L, 3); -- if (user_node_value(n) != 0) { -- luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n)); -- } -- user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX); -- break; -- case 'n': -- user_node_value(n) = nodelib_getlist(L, 3); -- break; -- case 's': -- user_node_value(n) = nodelib_getstring(L, 3); -- break; -- case 't': -- user_node_value(n) = nodelib_gettoks(L, 3); -- break; -- default: -- user_node_value(n) = (halfword) lua_roundnumber(L, 3); -- break; -- } -+ set_user_node_direct_value(L, n, 3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6702,7 +7331,7 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char - } - } else if (t == pdf_setmatrix_node) { - if (lua_key_eq(s, data)) { -- pdf_setmatrix_data(n) = nodelib_gettoks(L, 3); -+ set_pdf_setmatrix_direct_value(L, n, 3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6730,9 +7359,9 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char - } - } else if (t == write_node) { - if (lua_key_eq(s, stream)) { -- write_stream(n) = (halfword) lua_tointeger(L, 3); -+ set_write_direct_value(L,n,3); - } else if (lua_key_eq(s, data)) { -- write_tokens(n) = nodelib_gettoks(L, 3); -+ set_write_direct_value(L,n,3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6788,7 +7417,7 @@ static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char - } - } else if (t == special_node) { - if (lua_key_eq(s, data)) { -- write_tokens(n) = nodelib_gettoks(L, 3); -+ set_special_direct_value(L, n, 3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -6963,8 +7592,8 @@ static int lua_nodelib_direct_setfield(lua_State * L) - x_displace(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, yoffset)) { - y_displace(n) = (halfword) lua_roundnumber(L, 3); -- } else if (lua_key_eq(s, xadvance)) { -- x_advance(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, data)) { -+ glyph_node_data(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, expansion_factor)) { - ex_glyph(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, components)) { -@@ -6997,8 +7626,10 @@ static int lua_nodelib_direct_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ box_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- box_dir(n) = nodelib_getdir(L, 3, 1); -+ box_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, shift)) { - shift_amount(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, glue_order)) { -@@ -7069,8 +7700,14 @@ static int lua_nodelib_direct_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, left)) { -+ rule_left(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, right)) { -+ rule_right(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ rule_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- rule_dir(n) = nodelib_getdir(L, 3, 1); -+ rule_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, index)) { - rule_index(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, transform)) { -@@ -7079,12 +7716,12 @@ static int lua_nodelib_direct_setfield(lua_State * L) - return nodelib_cantset(L, n, s); - } - } else if (t == dir_node) { -- if (lua_key_eq(s, dir)) { -- dir_dir(n) = nodelib_getdir(L, 3, 0); -+ if (lua_key_eq(s, direction)) { -+ dir_dir(n) = nodelib_getdirection(L, 3); -+ } else if (lua_key_eq(s, dir)) { -+ nodelib_setdir_text(L, 3, n); - } else if (lua_key_eq(s, level)) { - dir_level(n) = (halfword) lua_tointeger(L, 3); -- } else if (lua_key_eq(s, subtype)) { /* can be used for anything */ -- subtype(n) = (quarterword) lua_tointeger(L, 3); - } else { - return nodelib_cantset(L, n, s); - } -@@ -7099,8 +7736,10 @@ static int lua_nodelib_direct_setfield(lua_State * L) - local_pen_inter(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, pen_broken)) { - local_pen_broken(n) = (halfword) lua_tointeger(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ local_par_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- local_par_dir(n) = nodelib_getdir(L, 3, 1); -+ local_par_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, box_left)) { - local_box_left(n) = nodelib_getlist(L, 3); - } else if (lua_key_eq(s, box_left_width)) { -@@ -7205,6 +7844,8 @@ static int lua_nodelib_direct_setfield(lua_State * L) - right_delimiter(n) = nodelib_popdirect(3); - } else if (lua_key_eq(s, middle)) { - middle_delimiter(n) = nodelib_popdirect(3); -+ } else if (lua_key_eq(s, fam)) { -+ fraction_fam(n) = (halfword) lua_tointeger(L, 3); - } else if (lua_key_eq(s, options)) { - fractionoptions(n) = (halfword) lua_tointeger(L, 3); - } else { -@@ -7373,8 +8014,10 @@ static int lua_nodelib_direct_setfield(lua_State * L) - height(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, depth)) { - depth(n) = (halfword) lua_roundnumber(L, 3); -+ } else if (lua_key_eq(s, direction)) { -+ box_dir(n) = nodelib_getdirection(L, 3); - } else if (lua_key_eq(s, dir)) { -- box_dir(n) = nodelib_getdir(L, 3, 1); -+ box_dir(n) = nodelib_getdir_par(L, 3); - } else if (lua_key_eq(s, shrink)) { - glue_shrink(n) = (halfword) lua_roundnumber(L, 3); - } else if (lua_key_eq(s, glue_order)) { -@@ -7516,6 +8159,8 @@ static int lua_nodelib_direct_setbox(lua_State * L) - - /* node.is_node(n) */ - -+/* -+ - static int lua_nodelib_is_node(lua_State * L) - { - if (maybe_isnode(L,1) == NULL) -@@ -7525,6 +8170,18 @@ static int lua_nodelib_is_node(lua_State * L) - return 1; - } - -+*/ -+ -+static int lua_nodelib_is_node(lua_State * L) -+{ -+ halfword *p = maybe_isnode(L, 1); -+ if (p == NULL) -+ lua_pushboolean(L,0); -+ else -+ lua_pushinteger(L, *((halfword *)p)); -+ return 1; -+} -+ - /* node.direct.is_direct(n) (handy for mixed usage testing) */ - - static int lua_nodelib_direct_is_direct(lua_State * L) -@@ -7571,7 +8228,7 @@ static int lua_nodelib_direct_is_node(lua_State * L) - mechanism. And, one can always sweep the table empty. - */ - --static int lua_nodelib_properties_set_mode(lua_State * L) /* hh */ -+static int lua_nodelib_properties_set_mode(lua_State * L) - { /* */ - if (lua_isboolean(L,1)) { - lua_properties_enabled = lua_toboolean(L,1); -@@ -7584,7 +8241,7 @@ static int lua_nodelib_properties_set_mode(lua_State * L) /* hh */ - - /* We used to have variants in assigned defaults but they made no sense. */ - --static int lua_nodelib_properties_flush_table(lua_State * L) /* hh */ -+static int lua_nodelib_properties_flush_table(lua_State * L) - { /* */ - lua_get_metatablelua(node_properties); - lua_pushnil(L); /* initializes lua_next */ -@@ -7599,7 +8256,7 @@ static int lua_nodelib_properties_flush_table(lua_State * L) /* hh */ - - /* maybe we should allocate a proper index 0..var_mem_max but not now */ - --static int lua_nodelib_get_property(lua_State * L) /* hh */ -+static int lua_nodelib_get_property(lua_State * L) - { /* */ - halfword n = *((halfword *) lua_touserdata(L, 1)); - if (n == null) { -@@ -7611,7 +8268,7 @@ static int lua_nodelib_get_property(lua_State * L) /* hh */ - return 1; - } - --static int lua_nodelib_direct_get_property(lua_State * L) /* hh */ -+static int lua_nodelib_direct_get_property(lua_State * L) - { /* */ - halfword n = lua_tointeger(L, 1); - if (n == null) { -@@ -7623,7 +8280,7 @@ static int lua_nodelib_direct_get_property(lua_State * L) /* hh */ - return 1; - } - --static int lua_nodelib_set_property(lua_State * L) /* hh */ -+static int lua_nodelib_set_property(lua_State * L) - { - /* */ - halfword n = *((halfword *) lua_touserdata(L, 1)); -@@ -7638,7 +8295,7 @@ static int lua_nodelib_set_property(lua_State * L) /* hh */ - return 0; - } - --static int lua_nodelib_direct_set_property(lua_State * L) /* hh */ -+static int lua_nodelib_direct_set_property(lua_State * L) - { - /* */ - halfword n = lua_tointeger(L, 1); -@@ -7653,13 +8310,13 @@ static int lua_nodelib_direct_set_property(lua_State * L) /* hh */ - return 0; - } - --static int lua_nodelib_direct_properties_get_table(lua_State * L) /* hh */ -+static int lua_nodelib_direct_properties_get_table(lua_State * L) - { /* */ - lua_get_metatablelua(node_properties); - return 1; - } - --static int lua_nodelib_properties_get_table(lua_State * L) /* hh */ -+static int lua_nodelib_properties_get_table(lua_State * L) - { /* */ - lua_get_metatablelua(node_properties_indirect); - return 1; -@@ -7667,7 +8324,7 @@ static int lua_nodelib_properties_get_table(lua_State * L) /* hh */ - - /* bonus */ - --static int lua_nodelib_get_property_t(lua_State * L) /* hh */ -+static int lua_nodelib_get_property_t(lua_State * L) - { /* */ - halfword n = *((halfword *) lua_touserdata(L, 2)); - if (n == null) { -@@ -7678,7 +8335,7 @@ static int lua_nodelib_get_property_t(lua_State * L) /* hh */ - return 1; - } - --static int lua_nodelib_set_property_t(lua_State * L) /* hh */ -+static int lua_nodelib_set_property_t(lua_State * L) - { - /*
          */ - halfword n = *((halfword *) lua_touserdata(L, 2)); -@@ -7804,7 +8461,7 @@ static int lua_nodelib_direct_flatten_discretionaries(lua_State * L) - try_couple_nodes(alink(current),h); - } - vlink(n) = null ; -- //tlink(n) = null; -+ /*tlink(n) = null; */ - } else { - if (current == head) { - head = next; -@@ -7870,7 +8527,7 @@ static int lua_nodelib_flatten_discretionaries(lua_State * L) - try_couple_nodes(alink(current),h); - } - vlink(n) = null ; -- //tlink(n) = null; -+ /*tlink(n) = null; */ - } else { - if (current == head) { - head = next; -@@ -7967,6 +8624,115 @@ static int lua_nodelib_direct_get_synctex_fields(lua_State * L) - return 0; - } - -+/* helper, assumes one node, returns node and delta .. to be tested */ -+ -+static int lua_nodelib_prepend_prevdepth(lua_State * L) -+{ -+ halfword *a; -+ halfword p; -+ halfword prevdepth; -+ boolean mirrored; -+ halfword n = *check_isnode(L, 1); -+ if (!(type(n) == hlist_node || type(n) == vlist_node)) { -+ lua_pushnil(L); -+ return 1; -+ } -+ prevdepth = lua_tointeger(L,2); -+ mirrored = (type(n) == hlist_node) && is_mirrored(box_dir(n)) ; -+ if (prevdepth > ignore_depth) { -+ halfword d; -+ if (mirrored) { -+ d = width(baseline_skip_par) - prevdepth - depth(n); -+ } else { -+ d = width(baseline_skip_par) - prevdepth - height(n); -+ } -+ if (d < line_skip_limit_par) { -+ p = new_param_glue(line_skip_code); -+ } else { -+ p = new_skip_param(baseline_skip_code); -+ width(p) = d; -+ } -+ couple_nodes(p,n); -+ fast_metatable_or_nil(p); /* glue */ -+ } else { -+ fast_metatable_or_nil(n); /* node */ -+ } -+ if (mirrored) { -+ prevdepth = height(n); -+ } else { -+ prevdepth = depth(n); -+ } -+ lua_pushinteger(L,prevdepth); /* new prevdepth */ -+ return 2; -+} -+ -+static int lua_nodelib_direct_prepend_prevdepth(lua_State * L) -+{ -+ halfword p; -+ halfword prevdepth; -+ boolean mirrored; -+ halfword n = lua_tointeger(L, 1); -+ if (type(n) == hlist_node || type(n) == vlist_node) { -+ lua_pushnil(L); -+ return 1; -+ } -+ prevdepth = lua_tointeger(L,2); -+ mirrored = (type(n) == hlist_node) && is_mirrored(box_dir(n)) ; -+ if (prevdepth > ignore_depth) { -+ halfword d; -+ if (mirrored) { -+ d = width(baseline_skip_par) - prevdepth - depth(n); -+ } else { -+ d = width(baseline_skip_par) - prevdepth - height(n); -+ } -+ if (d < line_skip_limit_par) { -+ p = new_param_glue(line_skip_code); -+ } else { -+ p = new_skip_param(baseline_skip_code); -+ width(p) = d; -+ } -+ couple_nodes(p,n); -+ lua_pushinteger(L,p); /* glue */ -+ } else { -+ lua_pushinteger(L,n); /* node */ -+ } -+ if (mirrored) { -+ prevdepth = height(n); -+ } else { -+ prevdepth = depth(n); -+ } -+ lua_pushinteger(L,prevdepth); /* new prevdepth */ -+ return 2; -+} -+ -+static int lua_nodelib_make_extensible(lua_State * L) -+{ -+ int top = lua_gettop(L); -+ if (top >= 3) { -+ halfword fnt = lua_tointeger(L,1); -+ halfword chr = lua_tointeger(L,2); -+ halfword size = lua_tointeger(L,3); -+ halfword overlap = 65536 ; -+ halfword attlist = null; -+ halfword b = null; -+ int horizontal = 0; -+ if (top >= 4) { -+ overlap = lua_tointeger(L,4); -+ } -+ if (top >= 5) { -+ horizontal = lua_toboolean(L,5); -+ } -+ if (top >= 6) { -+ attlist = *check_isnode(L, 6); -+ } -+ b = make_extensible(fnt,chr,size,overlap,horizontal,attlist); -+ nodelib_pushlist(L,b); -+ } else { -+ lua_pushnil(L); -+ } -+ return 1; -+} -+ - /* done */ - - static const struct luaL_Reg nodelib_p[] = { -@@ -8022,6 +8788,7 @@ static const struct luaL_Reg direct_nodelib_f[] = { - {"getshift", lua_nodelib_direct_getshift}, - {"getfield", lua_nodelib_direct_getfield}, - {"getfont", lua_nodelib_direct_getfont}, -+ {"getexpansion", lua_nodelib_direct_getexpansion}, - {"getfam", lua_nodelib_direct_getfam}, - {"getid", lua_nodelib_direct_getid}, - {"getnext", lua_nodelib_direct_getnext}, -@@ -8029,11 +8796,13 @@ static const struct luaL_Reg direct_nodelib_f[] = { - {"getboth", lua_nodelib_direct_getboth}, - {"getlist", lua_nodelib_direct_getlist}, - {"getleader", lua_nodelib_direct_getleader}, -+ {"getdata", lua_nodelib_direct_getdata}, - {"getsubtype", lua_nodelib_direct_getsubtype}, - {"getattributelist", lua_nodelib_direct_getattributelist}, - {"getnucleus", lua_nodelib_direct_getnucleus}, - {"getsub", lua_nodelib_direct_getsub}, - {"getsup", lua_nodelib_direct_getsup}, -+ {"getdirection", lua_nodelib_direct_getdirection}, - {"has_glyph", lua_nodelib_direct_has_glyph}, - {"has_attribute", lua_nodelib_direct_has_attribute}, - {"get_attribute", lua_nodelib_direct_get_attribute}, -@@ -8064,12 +8833,14 @@ static const struct luaL_Reg direct_nodelib_f[] = { - {"setfield", lua_nodelib_direct_setfield}, - {"setchar", lua_nodelib_direct_setchar}, - {"setfont", lua_nodelib_direct_setfont}, -+ {"setexpansion", lua_nodelib_direct_setexpansion}, - {"setfam", lua_nodelib_direct_setfam}, - {"setcomponents", lua_nodelib_direct_setcomponents}, - {"setlang", lua_nodelib_direct_setlang}, - {"setkern", lua_nodelib_direct_setkern}, - {"setpenalty", lua_nodelib_direct_setpenalty}, - {"setdir", lua_nodelib_direct_setdir}, -+ {"setdirection", lua_nodelib_direct_setdirection}, - {"setoffsets", lua_nodelib_direct_setoffsets}, - {"setdisc", lua_nodelib_direct_setdisc}, - {"setwhd", lua_nodelib_direct_setwhd}, -@@ -8084,6 +8855,7 @@ static const struct luaL_Reg direct_nodelib_f[] = { - {"setsplit", lua_nodelib_direct_setsplit}, - {"setlist", lua_nodelib_direct_setlist}, - {"setleader", lua_nodelib_direct_setleader}, -+ {"setdata", lua_nodelib_direct_setdata}, - {"setsubtype", lua_nodelib_direct_setsubtype}, - {"setattributelist", lua_nodelib_direct_setattributelist}, - {"setnucleus", lua_nodelib_direct_setnucleus}, -@@ -8097,6 +8869,8 @@ static const struct luaL_Reg direct_nodelib_f[] = { - {"traverse", lua_nodelib_direct_traverse}, - {"traverse_id", lua_nodelib_direct_traverse_filtered}, - {"traverse_char", lua_nodelib_direct_traverse_char}, -+ {"traverse_glyph", lua_nodelib_direct_traverse_glyph}, -+ {"traverse_list", lua_nodelib_direct_traverse_list}, - /* {"type", lua_nodelib_type}, */ /* no node argument */ - /* {"types", lua_nodelib_types}, */ /* no node argument */ - {"unprotect_glyphs", lua_nodelib_direct_unprotect_glyphs}, -@@ -8110,14 +8884,15 @@ static const struct luaL_Reg direct_nodelib_f[] = { - /* {"whatsits", lua_nodelib_whatsits}, */ /* no node argument */ - {"write", lua_nodelib_direct_append}, - {"set_properties_mode",lua_nodelib_properties_set_mode}, -- {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */ -- {"get_properties_table",lua_nodelib_direct_properties_get_table}, /* hh experiment */ -+ {"flush_properties_table",lua_nodelib_properties_flush_table}, -+ {"get_properties_table",lua_nodelib_direct_properties_get_table}, - {"getproperty", lua_nodelib_direct_get_property}, - {"setproperty", lua_nodelib_direct_set_property}, - {"effective_glue", lua_nodelib_direct_effective_glue}, - {"check_discretionary", lua_nodelib_direct_check_discretionary}, - {"check_discretionaries", lua_nodelib_direct_check_discretionaries}, - {"flatten_discretionaries",lua_nodelib_direct_flatten_discretionaries}, -+ {"prepend_prevdepth",lua_nodelib_direct_prepend_prevdepth}, - /* done */ - {"set_synctex_fields", lua_nodelib_direct_set_synctex_fields}, - {"get_synctex_fields", lua_nodelib_direct_get_synctex_fields}, -@@ -8139,6 +8914,7 @@ static const struct luaL_Reg nodelib_f[] = { - {"family_font", lua_nodelib_mfont}, - {"fields", lua_nodelib_fields}, - {"subtypes", lua_nodelib_subtypes}, -+ {"values", lua_nodelib_values}, - {"first_glyph", lua_nodelib_first_glyph}, - {"flush_list", lua_nodelib_flush_list}, - {"flush_node", lua_nodelib_flush_node}, -@@ -8191,33 +8967,34 @@ static const struct luaL_Reg nodelib_f[] = { - {"traverse", lua_nodelib_traverse}, - {"traverse_id", lua_nodelib_traverse_filtered}, - {"traverse_char", lua_nodelib_traverse_char}, -+ {"traverse_glyph", lua_nodelib_traverse_glyph}, -+ {"traverse_list", lua_nodelib_traverse_list}, - {"type", lua_nodelib_type}, - {"types", lua_nodelib_types}, - {"unprotect_glyphs", lua_nodelib_unprotect_glyphs}, - {"unprotect_glyph", lua_nodelib_unprotect_glyph}, - {"unset_attribute", lua_nodelib_unset_attribute}, -- {"setglue",lua_nodelib_set_glue}, -- {"getglue",lua_nodelib_get_glue}, -- {"is_zero_glue",lua_nodelib_is_zero_glue}, -+ {"setglue", lua_nodelib_set_glue}, -+ {"getglue", lua_nodelib_get_glue}, -+ {"is_zero_glue", lua_nodelib_is_zero_glue}, - {"usedlist", lua_nodelib_usedlist}, - {"vpack", lua_nodelib_vpack}, - {"whatsits", lua_nodelib_whatsits}, - {"write", lua_nodelib_append}, - /* experiment */ -- /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ /* hh experiment */ -+ /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ - /* experiment */ -- {"set_properties_mode",lua_nodelib_properties_set_mode}, /* hh experiment */ -- {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */ -- {"get_properties_table",lua_nodelib_properties_get_table}, /* bonus */ /* hh experiment */ -- {"getproperty", lua_nodelib_get_property}, /* hh experiment */ -- {"setproperty", lua_nodelib_set_property}, /* hh experiment */ -+ {"set_properties_mode", lua_nodelib_properties_set_mode}, -+ {"flush_properties_table", lua_nodelib_properties_flush_table}, -+ {"get_properties_table", lua_nodelib_properties_get_table}, -+ {"getproperty", lua_nodelib_get_property}, -+ {"setproperty", lua_nodelib_set_property}, - {"effective_glue", lua_nodelib_effective_glue}, - {"check_discretionary", lua_nodelib_check_discretionary}, - {"check_discretionaries", lua_nodelib_check_discretionaries}, -- {"flatten_discretionaries",lua_nodelib_flatten_discretionaries}, -- /* done */ -- /* {"set_synctex_fields", lua_nodelib_set_synctex_fields}, */ -- /* {"get_synctex_fields", lua_nodelib_get_synctex_fields}, */ -+ {"flatten_discretionaries", lua_nodelib_flatten_discretionaries}, -+ {"prepend_prevdepth", lua_nodelib_prepend_prevdepth}, -+ {"make_extensible", lua_nodelib_make_extensible}, - /* done */ - {"fix_node_lists", lua_nodelib_fix_node_lists}, - {NULL, NULL} /* sentinel */ -@@ -8255,12 +9032,12 @@ void nodelist_to_lua(lua_State * L, int n) - lua_nodelib_push(L); - } - --int nodelist_from_lua(lua_State * L) -+int nodelist_from_lua(lua_State * L, int n) - { -- if (lua_isnil(L, -1)) { -+ if (lua_isnil(L, n)) { - return null; - } else { -- halfword n= *check_isnode(L, -1); -- return (n ? n : null); -+ halfword list = *check_isnode(L, n); -+ return (list ? list : null); - } - } -diff --git a/texk/web2c/luatexdir/lua/loslibext.c b/texk/web2c/luatexdir/lua/loslibext.c -index 309d636c4..979f72472 100644 ---- a/texk/web2c/luatexdir/lua/loslibext.c -+++ b/texk/web2c/luatexdir/lua/loslibext.c -@@ -703,28 +703,49 @@ static int uname(struct utsname *uts) - GetVersionEx(&osver); - GetSystemInfo(&sysinfo); - -+ -+ /* -+ Windows 10 10.0* -+ Windows Server 2016 10.0* -+ Windows 8.1 6.3* -+ Windows Server 2012 R2 6.3* -+ Windows 8 6.2 -+ Windows Server 2012 6.2 -+ Windows 7 6.1 -+ Windows Server 2008 R2 6.1 -+ Windows Server 2008 6.0 -+ Windows Vista 6.0 -+ Windows Server 2003 R2 5.2 -+ Windows Server 2003 5.2 -+ Windows XP 64-Bit Edition 5.2 -+ Windows XP 5.1 -+ Windows 2000 5.0 -+ */ -+ - switch (osver.dwPlatformId) { -- case VER_PLATFORM_WIN32_NT: /* NT, Windows 2000 or Windows XP */ -+ case VER_PLATFORM_WIN32_NT: - if (osver.dwMajorVersion == 4) -- strcpy(uts->sysname, "Windows NT4x"); /* NT4x */ -+ strcpy(uts->sysname, "Windows NT 4"); - else if (osver.dwMajorVersion <= 3) -- strcpy(uts->sysname, "Windows NT3x"); /* NT3x */ -+ strcpy(uts->sysname, "Windows NT 3"); - else if (osver.dwMajorVersion == 5) { - if (osver.dwMinorVersion == 0) -- strcpy(uts->sysname, "Windows 2000"); /* 2k */ -+ strcpy(uts->sysname, "Windows 2000"); - else if (osver.dwMinorVersion == 1) -- strcpy(uts->sysname, "Windows XP"); /* XP */ -+ strcpy(uts->sysname, "Windows XP"); - else if (osver.dwMinorVersion == 2) -- strcpy(uts->sysname, "Windows Server 2003"); /* Server 2003 */ -+ strcpy(uts->sysname, "Windows XP 64-Bit"); - } else if (osver.dwMajorVersion == 6) { -- /* -- if( osver.wProductType == VER_NT_WORKSTATION ) -- */ -- strcpy(uts->sysname, "Windows Vista"); /* Vista */ -- /* -- else -- strcpy (uts->sysname, "Windows Server 2008"); -- */ -+ if (osver.dwMinorVersion == 0) -+ strcpy(uts->sysname, "Windows Vista"); -+ else if (osver.dwMinorVersion == 1) -+ strcpy(uts->sysname, "Windows 7"); -+ else if (osver.dwMinorVersion == 2) -+ strcpy(uts->sysname, "Windows 8"); -+ else if (osver.dwMinorVersion == 3) -+ strcpy(uts->sysname, "Windows 8.1"); -+ } else if (osver.dwMajorVersion == 10) { -+ strcpy(uts->sysname, "Windows 10"); - } - os = WinNT; - break; -diff --git a/texk/web2c/luatexdir/lua/lpdflib.c b/texk/web2c/luatexdir/lua/lpdflib.c -index 096600de3..d8e051f3f 100644 ---- a/texk/web2c/luatexdir/lua/lpdflib.c -+++ b/texk/web2c/luatexdir/lua/lpdflib.c -@@ -22,7 +22,7 @@ - #include "lua/luatex-api.h" - #include "pdf/pdftables.h" - --static int luapdfprint(lua_State * L) -+int luapdfprint(lua_State * L) - { - int n; - const_lstring st; -@@ -82,6 +82,7 @@ static int luapdfprint(lua_State * L) - } - st.s = lua_tolstring(L, n, &st.l); - pdf_out_block(static_pdf, st.s, st.l); -+/* pdf_out(pdf, '\n'); */ - return 0; - } - -@@ -193,6 +194,7 @@ static int table_obj(lua_State * L) - const_lstring attr, st; - lstring buf; - int immediate = 0; /* default: not immediate */ -+ int nolength = 0; - attr.s = st.s = NULL; - attr.l = 0; - assert(lua_istable(L, 1)); /* t */ -@@ -213,6 +215,12 @@ static int table_obj(lua_State * L) - immediate = lua_toboolean(L, -1); /* 0 or 1 */ - } - lua_pop(L, 1); /* t */ -+ lua_key_rawgeti(nolength); -+ if (!lua_isnil(L, -1)) { /* b? t */ -+ if (lua_isboolean(L, -1)) /* !b t */ -+ nolength = lua_toboolean(L, -1); /* 0 or 1 */ -+ } -+ lua_pop(L, 1); /* t */ - - /* is a reserved object referenced by "objnum"? */ - -@@ -335,19 +343,29 @@ static int table_obj(lua_State * L) - } else { - if (immediate == 1) { - pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* 0 = not an object stream candidate! */ -- pdf_begin_dict(static_pdf); -- if (attr.s != NULL) { -+ if (nolength && attr.s != NULL) { -+ /* we have a direct copy possible with compressed data */ -+ pdf_begin_dict(static_pdf); - pdf_out_block(static_pdf, attr.s, attr.l); -- if (attr.s[attr.l - 1] != '\n') -- pdf_out(static_pdf, '\n'); -+ static_pdf->compress_level = 0; -+ static_pdf->stream_deflate = false; -+ pdf_end_dict(static_pdf); -+ } else { -+ pdf_begin_dict(static_pdf); -+ if (attr.s != NULL) { -+ pdf_check_space(static_pdf); -+ pdf_out_block(static_pdf, attr.s, attr.l); -+ pdf_set_space(static_pdf); -+ } -+ if (compress_level > -1) -+ static_pdf->compress_level = compress_level; -+ pdf_dict_add_streaminfo(static_pdf); -+ pdf_end_dict(static_pdf); - } -- if (compress_level > -1) -- static_pdf->compress_level = compress_level; -- pdf_dict_add_streaminfo(static_pdf); -- pdf_end_dict(static_pdf); - pdf_begin_stream(static_pdf); - } else { - set_obj_obj_is_stream(static_pdf, k); -+ set_obj_obj_no_length(static_pdf, k); - if (compress_level > -1) - obj_obj_pdfcompresslevel(static_pdf, k) = compress_level; - } -@@ -404,42 +422,42 @@ static int orig_obj(lua_State * L) - obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size); - init_obj_obj(static_pdf, k); - switch (n - first_arg + 1) { -- case 0: -- luaL_error(L, "pdf.obj() needs at least one argument"); -- break; -- case 1: -- if (!lua_isstring(L, first_arg)) /* or number */ -- luaL_error(L, "pdf.obj() 1st argument must be string"); -- break; -- case 2: -- case 3: -- if (lua_type(L, first_arg) != LUA_TSTRING) -- luaL_error(L, "pdf.obj() 1st argument must be string"); -- if (!lua_isstring(L, first_arg + 1)) /* or number */ -- luaL_error(L, "pdf.obj() 2nd argument must be string"); -- st_s = lua_tostring(L, first_arg); -- if (lua_key_eq(st_s, file)) { -- if (n == first_arg + 2) -- luaL_error(L, "pdf.obj() 3rd argument forbidden in file mode"); -- set_obj_obj_is_file(static_pdf, k); -- } else { -- if (n == first_arg + 2) { /* write attr text */ -- if (!lua_isstring(L, -1)) /* or number */ -- luaL_error(L, "pdf.obj() 3rd argument must be string"); -- obj_obj_stream_attr(static_pdf, k) = -- luaL_ref(Luas, LUA_REGISTRYINDEX); -- } -- if (lua_key_eq(st_s, stream)) { -- set_obj_obj_is_stream(static_pdf, k); -- } else if (lua_key_eq(st_s, streamfile)) { -- set_obj_obj_is_stream(static_pdf, k); -+ case 0: -+ luaL_error(L, "pdf.obj() needs at least one argument"); -+ break; -+ case 1: -+ if (!lua_isstring(L, first_arg)) /* or number */ -+ luaL_error(L, "pdf.obj() 1st argument must be string"); -+ break; -+ case 2: -+ case 3: -+ if (lua_type(L, first_arg) != LUA_TSTRING) -+ luaL_error(L, "pdf.obj() 1st argument must be string"); -+ if (!lua_isstring(L, first_arg + 1)) /* or number */ -+ luaL_error(L, "pdf.obj() 2nd argument must be string"); -+ st_s = lua_tostring(L, first_arg); -+ if (lua_key_eq(st_s, file)) { -+ if (n == first_arg + 2) -+ luaL_error(L, "pdf.obj() 3rd argument forbidden in file mode"); - set_obj_obj_is_file(static_pdf, k); -- } else -- luaL_error(L, "pdf.obj() invalid argument"); -- } -- break; -- default: -- luaL_error(L, "pdf.obj() allows max. 3 arguments"); -+ } else { -+ if (n == first_arg + 2) { /* write attr text */ -+ if (!lua_isstring(L, -1)) /* or number */ -+ luaL_error(L, "pdf.obj() 3rd argument must be string"); -+ obj_obj_stream_attr(static_pdf, k) = -+ luaL_ref(Luas, LUA_REGISTRYINDEX); -+ } -+ if (lua_key_eq(st_s, stream)) { -+ set_obj_obj_is_stream(static_pdf, k); -+ } else if (lua_key_eq(st_s, streamfile)) { -+ set_obj_obj_is_stream(static_pdf, k); -+ set_obj_obj_is_file(static_pdf, k); -+ } else -+ luaL_error(L, "pdf.obj() invalid argument"); -+ } -+ break; -+ default: -+ luaL_error(L, "pdf.obj() allows max. 3 arguments"); - } - obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); - return k; -@@ -478,23 +496,23 @@ static int l_reserveobj(lua_State * L) - const char *st_s = NULL; - n = lua_gettop(L); - switch (n) { -- case 0: -- static_pdf->obj_count++; -- pdf_last_obj = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1); -- break; -- case 1: -- if (lua_type(L, -1) != LUA_TSTRING) -- luaL_error(L, "pdf.reserveobj() optional argument must be string"); -- st_s = luaL_checkstring(L, 1); -- if (lua_key_eq(st_s, annot)) { -- pdf_last_annot = pdf_create_obj(static_pdf, obj_type_annot, 0); -- } else { -- luaL_error(L, "pdf.reserveobj() optional string must be \"annot\""); -- } -- lua_pop(L, 1); -- break; -- default: -- luaL_error(L, "pdf.reserveobj() allows max. 1 argument"); -+ case 0: -+ static_pdf->obj_count++; -+ pdf_last_obj = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1); -+ break; -+ case 1: -+ if (lua_type(L, -1) != LUA_TSTRING) -+ luaL_error(L, "pdf.reserveobj() optional argument must be string"); -+ st_s = luaL_checkstring(L, 1); -+ if (lua_key_eq(st_s, annot)) { -+ pdf_last_annot = pdf_create_obj(static_pdf, obj_type_annot, 0); -+ } else { -+ luaL_error(L, "pdf.reserveobj() optional string must be \"annot\""); -+ } -+ lua_pop(L, 1); -+ break; -+ default: -+ luaL_error(L, "pdf.reserveobj() allows max. 1 argument"); - } - lua_pushinteger(L, static_pdf->obj_ptr); - return 1; -@@ -505,16 +523,16 @@ static int l_registerannot(lua_State * L) - int n, i; - n = lua_gettop(L); - switch (n) { -- case 1: -- if (global_shipping_mode == NOT_SHIPPING) -- luaL_error(L, "pdf.registerannot() can only be used in late lua"); -- i = (int) luaL_checkinteger(L, 1); -- if (i <= 0) -- luaL_error(L, "pdf.registerannot() can only register positive object numbers"); -- addto_page_resources(static_pdf, obj_type_annot, i); -- break; -- default: -- luaL_error(L, "pdf.registerannot() needs exactly 1 argument"); -+ case 1: -+ if (global_shipping_mode == NOT_SHIPPING) -+ luaL_error(L, "pdf.registerannot() can only be used in late lua"); -+ i = (int) luaL_checkinteger(L, 1); -+ if (i <= 0) -+ luaL_error(L, "pdf.registerannot() can only register positive object numbers"); -+ addto_page_resources(static_pdf, obj_type_annot, i); -+ break; -+ default: -+ luaL_error(L, "pdf.registerannot() needs exactly 1 argument"); - } - return 0; - } -@@ -599,55 +617,30 @@ static int l_set_xformresources (lua_State * L) { l_set_pdf_value(xformresources - static int l_set_xformattributes(lua_State * L) { l_set_pdf_value(xformattributes); } - static int l_set_trailerid (lua_State * L) { l_set_pdf_value(trailerid); } - --/* -- --static int setpdf(lua_State * L) -+static int getpdfobjtype(lua_State * L) - { -- const char *s ; -- if (lua_gettop(L) != 3) { -- return 0; -- } -- if (lua_type(L, -2) == LUA_TSTRING) { -- s = lua_tostring(L, -1); -- if (valid_pdf_key) { -- lua_get_metatablelua(pdf_data); -- lua_replace(L, -4); -+ if (lua_type(L, 1) == LUA_TNUMBER) { -+ int n = (int) lua_tointeger(L, 1); -+ if (n > 0 && n <= static_pdf->obj_ptr) { -+ lua_pushstring(L, pdf_obj_typenames[obj_type(static_pdf, n)]); -+ return 1; - } - } -- lua_rawset(L, -3); -- return 0; --} -- --*/ -- --static int l_objtype(lua_State * L) --{ -- int n = lua_gettop(L); -- if (n != 1) -- luaL_error(L, "pdf.objtype() needs exactly 1 argument"); -- n = (int) luaL_checkinteger(L, 1); -- if (n < 0 || n > static_pdf->obj_ptr) -- lua_pushnil(L); -- else -- lua_pushstring(L, pdf_obj_typenames[obj_type(static_pdf, n)]); -+ lua_pushnil(L); - return 1; - } - --static int l_maxobjnum(lua_State * L) -+static int getpdfmaxobjnum(lua_State * L) - { -- int n = lua_gettop(L); -- if (n != 0) -- luaL_error(L, "pdf.maxobjnum() needs 0 arguments"); - lua_pushinteger(L, static_pdf->obj_ptr); - return 1; - } - - static int l_mapfile(lua_State * L) - { -- char *s; - const char *st; -- if ((lua_type(L,-1) == LUA_TSTRING) && (st = lua_tostring(L, -1)) != NULL) { -- s = xstrdup(st); -+ if ((lua_type(L, 1) == LUA_TSTRING) && (st = lua_tostring(L, 1)) != NULL) { -+ char *s = xstrdup(st); - process_map_item(s, MAPFILE); - free(s); - } -@@ -656,29 +649,15 @@ static int l_mapfile(lua_State * L) - - static int l_mapline(lua_State * L) - { -- char *s; - const char *st; -- if ((lua_type(L,-1) == LUA_TSTRING) && (st = lua_tostring(L, -1)) != NULL) { -- s = xstrdup(st); -+ if ((lua_type(L, 1) == LUA_TSTRING) && (st = lua_tostring(L, 1)) != NULL) { -+ char *s = xstrdup(st); - process_map_item(s, MAPLINE); - free(s); - } - return 0; - } - --static int l_pageref(lua_State * L) --{ -- int n = lua_gettop(L); -- if (n != 1) -- luaL_error(L, "pdf.pageref() needs exactly 1 argument"); -- n = (int) luaL_checkinteger(L, 1); -- if (n <= 0) -- luaL_error(L, "pdf.pageref() needs page number > 0"); -- n = pdf_get_obj(static_pdf, obj_type_page, n, false); -- lua_pushinteger(L, n); -- return 1; --} -- - static int l_getpos(lua_State * L) - { - lua_pushinteger(L, static_pdf->posstruct->pos.h); -@@ -770,6 +749,12 @@ static int l_get_obj_compress_level(lua_State * L) - return 1 ; - } - -+static int l_get_recompress(lua_State * L) -+{ -+ lua_pushinteger(L, (pdf_recompress)); -+ return 1 ; -+} -+ - static int l_set_compress_level(lua_State * L) - { - if (lua_type(L, 1) == LUA_TNUMBER) { -@@ -796,6 +781,19 @@ static int l_set_obj_compress_level(lua_State * L) - return 0 ; - } - -+ static int l_set_recompress(lua_State * L) -+{ -+ if (lua_type(L, 1) == LUA_TNUMBER) { -+ int c = (int) lua_tointeger(L, 1); -+ if (c<0) -+ c = 0 ; -+ else if (c>9) -+ c = 9 ; -+ set_pdf_recompress(c); -+ } -+ return 0 ; -+} -+ - /* fonts */ - - static int getpdfgentounicode(lua_State * L) -@@ -826,6 +824,18 @@ static int setpdfomitcidset(lua_State * L) - return 0 ; - } - -+/* for tracing purposes when no pages are flushed */ -+ -+static int setforcefile(lua_State * L) -+{ -+ if (lua_type(L, 1) == LUA_TBOOLEAN) { -+ static_pdf->force_file = lua_toboolean(L,1); -+ } else { -+ static_pdf->force_file = 0; -+ } -+ return 0 ; -+} -+ - /* accuracy */ - - static int l_get_decimal_digits(lua_State * L) -@@ -879,9 +889,10 @@ static int getpdffontname(lua_State * L) - int c, ff ; - if (lua_type(L, 1) == LUA_TNUMBER) { - c = (int) lua_tointeger(L, 1); -- pdf_check_vf(c); -- if (!font_used(c)) -+ /* pdf_check_vf(c); */ -+ if (!font_used(c)) { - pdf_init_font(static_pdf,c); -+ } - set_ff(c); - lua_pushinteger(L, (obj_info(static_pdf, pdf_font_num(ff)))); - } else { -@@ -895,9 +906,10 @@ static int getpdffontobjnum(lua_State * L) - if (lua_type(L, 1) == LUA_TNUMBER) { - int ff; - int c = (int) lua_tointeger(L, 1); -- pdf_check_vf(c); -- if (!font_used(c)) -+ /* pdf_check_vf(c); */ -+ if (!font_used(c)) { - pdf_init_font(static_pdf,c); -+ } - set_ff(c); - lua_pushinteger(L, (pdf_font_num(ff))); - } else { -@@ -917,21 +929,19 @@ static int getpdffontsize(lua_State * L) - return 1 ; - } - --/* -- - static int getpdfpageref(lua_State * L) - { - if (lua_type(L, 1) == LUA_TNUMBER) { - int c = (int) lua_tointeger(L, 1); -- lua_pushinteger(L, (pdf_get_obj(static_pdf, obj_type_page, c, false))); -- } else { -- lua_pushnil(L); -+ if (c > 0) { -+ lua_pushinteger(L, (pdf_get_obj(static_pdf, obj_type_page, c, false))); -+ return 1; -+ } - } -+ lua_pushnil(L); - return 1 ; - } - --*/ -- - static int getpdfxformname(lua_State * L) - { - if (lua_type(L, 1) == LUA_TNUMBER) { -@@ -944,12 +954,6 @@ static int getpdfxformname(lua_State * L) - return 1 ; - } - --static int getpdfversion(lua_State * L) --{ -- lua_pushinteger(L,1); -- return 1 ; --} -- - static int getpdfcreationdate(lua_State * L) - { - initialize_start_time(static_pdf); -@@ -1169,6 +1173,76 @@ static int l_set_font_attributes(lua_State * L) - return 0; - } - -+static int pdfincludechar(lua_State * L) -+{ -+ int f = lua_tointeger(L, 1); -+ if (lua_type(L,2) == LUA_TTABLE) { -+ int i, c; -+ int n = lua_rawlen(L, 2); -+ for (i=1; i<=n; i++) { -+ lua_rawgeti(L, 2, i); -+ c = lua_tointeger(L, 3); -+ pdf_mark_char(f,c); -+ lua_pop(L, 1); -+ } -+ } else { -+ int c = lua_tointeger(L, 2); -+ pdf_mark_char(f,c); -+ } -+ return 0; -+} -+ -+static int pdfincludefont(lua_State * L) -+{ -+ int f = lua_tointeger(L, 1); -+ pdf_init_font(static_pdf,f); -+ return 0; -+} -+ -+static int pdfincludeimage(lua_State * L) -+{ -+ /*tex How to check for a valid entry? */ -+ image_dict *idict = idict_array[lua_tointeger(L,1)]; -+ int objnum = img_objnum(idict); -+ if (img_state(idict) < DICT_OUTIMG) { -+ img_state(idict) = DICT_OUTIMG; -+ } -+ if (! is_obj_written(static_pdf, objnum)) { -+ pdf_write_image(static_pdf, objnum); -+ } -+ lua_pushinteger(L,img_type(idict)); -+ lua_pushinteger(L,img_xorig(idict)); -+ lua_pushinteger(L,img_yorig(idict)); -+ lua_pushinteger(L,img_xsize(idict)); -+ lua_pushinteger(L,img_ysize(idict)); -+ lua_pushinteger(L,img_rotation(idict)); -+ lua_pushinteger(L,objnum); -+ if (img_type(idict) == IMG_TYPE_PNG) { -+ lua_pushinteger(L,img_group_ref(idict)); -+ } else { -+ lua_pushnil(L); -+ } -+ return 8; -+} -+ -+static int getpdfnofobjects(lua_State * L) -+{ -+ int k; -+ int written = 0; -+ int dropped = 0; -+ for (k = 1; k <= static_pdf->obj_ptr; k++) { -+ if (is_obj_written(static_pdf, k)) { -+ written += 1; -+ } else { -+ dropped += 1; -+ } -+ } -+ lua_pushinteger(L,written); -+ lua_pushinteger(L,dropped); -+ return 2; -+} -+ -+/*tex For normal output see |pdflistout.c|: */ - - static const struct luaL_Reg pdflib[] = { - { "gethpos", l_gethpos }, -@@ -1179,11 +1253,10 @@ static const struct luaL_Reg pdflib[] = { - { "registerannot", l_registerannot }, - { "reserveobj", l_reserveobj }, - { "getpos", l_getpos }, -- /* { "pageref", getpdfpageref }, */ -- { "maxobjnum", l_maxobjnum }, -- { "pageref", l_pageref }, -+ { "getpageref", getpdfpageref }, -+ { "getmaxobjnum", getpdfmaxobjnum }, - { "print", luapdfprint }, -- { "objtype", l_objtype }, -+ { "getobjtype", getpdfobjtype }, - { "getmatrix", l_getmatrix }, - { "hasmatrix", l_hasmatrix }, - { "setfontattributes", l_set_font_attributes }, -@@ -1213,20 +1286,20 @@ static const struct luaL_Reg pdflib[] = { - { "getlastannot", l_get_lastannot }, - { "getcompresslevel", l_get_compress_level }, - { "getobjcompresslevel", l_get_obj_compress_level }, -+ { "getrecompress", l_get_recompress }, - { "setcompresslevel", l_set_compress_level }, - { "setobjcompresslevel", l_set_obj_compress_level }, -+ { "setrecompress", l_set_recompress }, - { "getdecimaldigits", l_get_decimal_digits }, - { "setdecimaldigits", l_set_decimal_digits }, - { "getpkresolution", l_get_pk_resolution }, - { "setpkresolution", l_set_pk_resolution }, - { "getsuppressoptionalinfo", l_get_suppress_optional_info }, - { "setsuppressoptionalinfo", l_set_suppress_optional_info }, -- /* moved from tex table */ -- { "fontname", getpdffontname }, -- { "fontobjnum", getpdffontobjnum }, -- { "fontsize", getpdffontsize }, -- { "xformname", getpdfxformname }, -- { "getversion", getpdfversion }, -+ { "getfontname", getpdffontname }, -+ { "getfontobjnum", getpdffontobjnum }, -+ { "getfontsize", getpdffontsize }, -+ { "getxformname", getpdfxformname }, - { "getcreationdate", getpdfcreationdate }, - { "getmajorversion", getpdfmajorversion }, - { "setmajorversion", setpdfmajorversion }, -@@ -1253,8 +1326,22 @@ static const struct luaL_Reg pdflib[] = { - { "setignoreunknownimages", setpdfignoreunknownimages }, - { "setgentounicode", setpdfgentounicode }, - { "setomitcidset", setpdfomitcidset }, -+ { "setforcefile", setforcefile }, - { "mapfile", l_mapfile }, - { "mapline", l_mapline }, -+ { "includechar", pdfincludechar }, -+ { "includefont", pdfincludefont }, -+ /* might go, used when sanitizing backend */ -+ { "includeimage", pdfincludeimage }, -+ { "getnofobjects", getpdfnofobjects }, -+ /* for a while */ -+ { "maxobjnum", getpdfmaxobjnum }, -+ { "pageref", getpdfpageref }, -+ { "objtype", getpdfobjtype }, -+ { "fontname", getpdffontname }, -+ { "fontobjnum", getpdffontobjnum }, -+ { "fontsize", getpdffontsize }, -+ { "xformname", getpdfxformname }, - /* sentinel */ - {NULL, NULL} - }; -diff --git a/texk/web2c/luatexdir/lua/lpdfscannerlib.cc b/texk/web2c/luatexdir/lua/lpdfscannerlib.cc -index 8bafd6122..56452b2ff 100644 ---- a/texk/web2c/luatexdir/lua/lpdfscannerlib.cc -+++ b/texk/web2c/luatexdir/lua/lpdfscannerlib.cc -@@ -17,6 +17,70 @@ - You should have received a copy of the GNU General Public License along - with LuaTeX; if not, see . */ - -+/* converted example in manual: -+ -+local operatortable = { } -+ -+operatortable.Do = function(scanner,info) -+ local resources = info.resources -+ if resources then -+ local val = scanner:pop() -+ local name = val[2] -+ local xobject = pdfe.dictionarytotable(resources.XObject[2]) -+ print(info.space .. "Uses XObject " .. name) -+ local kind, -+ entry = unpack(xobject[name]) -+ local dict -+ if kind == 10 then -- reference -+ kind, -+ entry, -+ dict = pdfe.getfromreference(entry) -+ end -+ if kind == 9 then -- stream -+ dict = pdfe.dictionarytotable(dict) -+ local resources = dict.Resources -+ if resources then -+ local newinfo = { -+ space = info.space .. " " , -+ resources = Resources[2], -+ } -+ pdfscanner.scan(entry, operatortable, newinfo) -+ end -+ end -+ end -+end -+ -+local function Analyze(filename) -+ local doc = pdfe.open(filename) -+ if doc then -+ local pagenum = 1 -+ local n = 1 -- pdfe.getnofpages(doc) -+ for i=1,n do -+ local page = pdfe.getpage(doc,i) -+ local kind, -+ data = pdfe.getfromdictionarybyname(page,"Resources") -+ if kind == 10 then -- reference -+ kind, data = pdfe.getfromreference(data) -+ end -+ data = pdfe.dictionarytotable(data) -+ local info = { -+ space = " " , -+ resources = data, -+ } -+ print("Page " .. i) -+ kind, data = pdfe.getfromdictionarybyname(page,"Contents") -+ if kind == 10 then -- reference -+ kind, data = pdfe.getfromreference(data) -+ end -+ pdfscanner.scan(data,operatortable,info) -+ end -+ end -+end -+ -+Analyze("e:/tmp/oeps.pdf") -+ -+*/ -+ - # include - # include - # include -@@ -28,26 +92,9 @@ extern "C" { - # include - # include - # include --} - --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include -+# include "luapplib/pplib.h" -+} - - # include - -@@ -57,48 +104,47 @@ extern "C" { - #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_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; -+ pdf_token_type type; -+ double value; -+ char *string; - } Token; - - typedef struct ObjectList { -- struct ObjectList *next; -- Object *stream; -+ struct ObjectList *next; -+ ppstream *stream; - } ObjectList; - - typedef struct scannerdata { -- int _ininlineimage; -- int _nextoperand; -- Token ** _operandstack; -- Object * _stream; -- ObjectList * _streams; -+ int _ininlineimage; -+ int _nextoperand; -+ Token ** _operandstack; -+ ppstream * _stream; -+ ObjectList * _streams; -+ const char *buffer; -+ size_t position; -+ size_t size; - } scannerdata; - --typedef enum { ALLOC_POPPLER, ALLOC_LEPDF } alloctype; -- --#define M_Object "Object" --#define M_Stream "Stream" -+#define PDFE_METATABLE_ARRAY "luatex.pdfe.array" -+#define PDFE_METATABLE_STREAM "luatex.pdfe.stream" - - typedef struct { - void *d; -- alloctype atype; // was it allocated by poppler or the lepdflib.cc? - void *pd; // reference to PdfDocument, or NULL -- unsigned long pc; // counter to detect PDFDoc change -+ unsigned long pc; // counter to detect PDFDoc change - } udstruct; - - static void clear_operand_stack (scannerdata *self, int from); -@@ -119,8 +165,8 @@ static void *priv_xrealloc (void *old_ptr, size_t size) - { - void *new_mem = (void *)realloc(old_ptr, size); - if (new_mem == NULL) { -- fprintf(stderr,"fatal: memory exhausted (realloc of %lu bytes).\n", (unsigned long)size); -- exit(EXIT_FAILURE); -+ fprintf(stderr,"fatal: memory exhausted (realloc of %lu bytes).\n", (unsigned long)size); -+ exit(EXIT_FAILURE); - } - return new_mem; - } -@@ -129,20 +175,20 @@ static void *priv_xrealloc (void *old_ptr, size_t size) - - #define INITBUFSIZE 64 - --#define define_buffer(a) \ -- char *a = (char *)priv_xmalloc (INITBUFSIZE); \ -- int a##_size = INITBUFSIZE; \ -- int a##index = 0; \ -+#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) -+#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) -@@ -155,769 +201,814 @@ static scannerdata * scanner_push(lua_State * L) - - 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; -+ 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); -+ 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; -+ int i = self->_nextoperand-1; -+ while (i>=from) { -+ if (self->_operandstack[i]) { -+ free_token(self->_operandstack[i]); -+ self->_operandstack[i] = NULL; -+ } -+ i--; - } -- i--; -- } -- self->_nextoperand = from; -+ 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; -+ 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; -+ Token *token = (Token *)priv_xmalloc(sizeof(Token)); -+ memset (token, 0, sizeof(Token)); -+ token->type = c; -+ return token; -+} -+ -+static void _nextStream (scannerdata *self) -+{ -+ if (self->buffer != NULL) { -+ ppstream_done(self->_stream); -+ } -+ ObjectList *rover = self->_streams; -+ self->_stream = rover->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 void _nextStream (scannerdata *self) { -- self->_stream->streamClose(); -- ObjectList *rover = self->_streams; -- self->_stream = rover->stream; -- self->_stream->streamReset(); -- self->_streams = rover->next; -- free(rover); -+static int streamLookChar (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 streamGetChar (scannerdata *self) { -- int i = self->_stream->streamGetChar(); -- if (i<0 && self->_streams) { -- _nextStream(self); -- i = streamGetChar(self); -- } -- return i; -+static void streamReset (scannerdata *self) -+{ -+ self->buffer = (const char*) ppstream_all(self->_stream,&self->size,1); -+ self->position = 0; - } - --static int streamLookChar (scannerdata *self) { -- int i= self->_stream->streamLookChar(); -- if (i<0 && self->_streams) { -- _nextStream(self); -- i = streamLookChar(self); -- } -- return i; -+static void streamClose (scannerdata *self) { -+ ppstream_done(self->_stream); -+ self->buffer = NULL; -+ self->_stream = NULL; - } - -+/* end of stream interface */ -+ - static Token * _parseSpace (scannerdata *self) - { -- return _parseToken (self,streamGetChar(self)); -+ return _parseToken (self,streamGetChar(self)); - } - - static Token * _parseString (scannerdata *self, int c) - { -- // local token = {type = pdf_string,value = ''} -- define_buffer(found); -- int level = 1; -- while (1) { -- c = streamGetChar(self); -- if (c == '(') { -- level = level + 1 ; -- } -- if (c == ')') { -- level = level - 1 ; -- if (level < 1) break; -- } -- 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') { -- next = next - '0'; -- int next2 = streamLookChar(self); -- if (next2 >= '0' && next2 <= '7') { -- next2 = streamGetChar(self); -- next2 = next2 - '0'; -- int 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 *token = new_operand(pdf_string); -- token->value = foundindex; -- token->string = found; -- return token; -+ define_buffer(found); -+ int 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') { -+ next = next - '0'; -+ int next2 = streamLookChar(self); -+ if (next2 >= '0' && next2 <= '7') { -+ next2 = streamGetChar(self); -+ next2 = next2 - '0'; -+ int 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 *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; -- 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 *token = new_operand(type); -- token->value = value; -- return token; -+ double value = 0; -+ pdf_token_type type = pdf_integer; -+ int isfraction = 0; -+ int isnegative = 0; -+ int i = 0; -+ 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 *token = new_operand(type); -+ token->value = value; -+ return token; - } - -- - static Token *_parseName (scannerdata *self, int c) - { -- 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 ; -+ define_buffer(found); - c = streamGetChar(self); -- } -- Token *token = new_operand(pdf_name); -- token->string = found; -- token->value = strlen(found); -- return token; -+ 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 *token = new_operand(pdf_name); -+ token->string = found; -+ token->value = strlen(found); -+ return token; - } - --#define hexdigit(c) \ -+#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; -- 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); -+ int isodd = 1; -+ int hexval = 0; -+ 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); - } -- c = streamGetChar(self); -- } -- Token *token = new_operand(pdf_string); -- token->value = foundindex; -- token->string = found; -- return token; -+ Token *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') - - // -- this is rather horrible -+ - static Token *_parseInlineImage (scannerdata *self, int c) - { -- define_buffer(found); -- if (c == ' ') { // 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)) { -- found[--foundindex] = '\0'; /* I */ -- found[--foundindex] = '\0'; /* E */ -- /* 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; -+ define_buffer(found); -+ if (c == ' ') { // first space can be ignored -+ c = streamGetChar(self); - } -- } -- Token *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); -- } -- // 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); -+ 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)) { -+ found[--foundindex] = '\0'; /* I */ -+ found[--foundindex] = '\0'; /* E */ -+ /* 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 *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); -+ } -+ // 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)); -+ 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); -- } -+ 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; -- } -+ 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; -+ fprintf(stderr, "stray %c [%d] in stream", c, c); -+ return NULL; - } - - static Token *_parseStartarray () - { -- return new_operand (pdf_startarray); -+ return new_operand (pdf_startarray); - } - - static Token *_parseStoparray () - { -- return new_operand (pdf_stoparray); -+ 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) { -- self->_ininlineimage = 0; -- Token *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); -- } -- } -+ if (self->_ininlineimage==1) { -+ self->_ininlineimage = 2; -+ return _parseInlineImage(self,c); -+ } else if (self->_ininlineimage==2) { -+ self->_ininlineimage = 0; -+ Token *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))); -- // 4 = self -- if (lua_type(L,1)== LUA_TTABLE) { -- udstruct *uin; -- int i = 1; -- while (1) { -- lua_rawgeti(L,1,i); -- if (lua_type(L,-1)== LUA_TUSERDATA) { -- uin = (udstruct *) luaL_checkudata(L, -1, M_Object); -- if (((Object *) uin->d)->isStream()) { -- ObjectList *rover = self->_streams; -- ObjectList *item = (ObjectList *)priv_xmalloc (sizeof(ObjectList)); -- item->stream = ((Object *) uin->d); -- item->next = NULL; -- if (!rover) { -- rover = item; -- self->_streams = rover; -- } else { -- while (rover->next) -- rover = rover->next; -- rover->next = item; -- } -- } -- } else { // done -- 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; -- luaL_checktype(L, 1, LUA_TUSERDATA); -- uin = (udstruct *) luaL_checkudata(L, 1, M_Object); -- if (((Object *) uin->d)->isStream()) { -- self->_stream = ((Object *) uin->d); -- } else if (((Object *) uin->d)->isArray()) { -- Array *arrayref = ((Object *) uin->d)->getArray(); -- int count = arrayref->getLength(); -- int i; -- for (i=0;iget(i); -- if (val->isStream()) { -- ObjectList *rover = self->_streams; -- ObjectList *item = (ObjectList *)priv_xmalloc (sizeof(ObjectList)); -- item->stream = val; -- item->next = NULL; -- if (!rover) { -- rover = item; -- self->_streams = rover; -- } else { -- while (rover->next) -- rover = rover->next; -- rover->next = item; -- } -- } -- } -- ObjectList *rover = self->_streams; -- self->_stream = rover->stream; -- self->_streams = rover->next; -- } -- -- } -- assert (lua_gettop(L) == 4); -- self->_stream->streamReset(); -- token = _parseToken(self,streamGetChar(self)); -- while (token) { -- if (token->type == pdf_operator) { -- lua_pushstring(L, token->string); -- free_token(token); -- lua_rawget(L,2); // operator table -- if (lua_isfunction(L,-1)) { -- lua_pushvalue(L,4); -- lua_pushvalue(L,3); -- (void)lua_call(L,2,0); -- } else { -- lua_pop(L,1); // nil -- } -- clear_operand_stack(self,0); -- } else { -- push_operand(self, token); -+ Token *token; -+ scannerdata *self; -+ if (lua_gettop(L) != 3) { -+ return 0; - } -- if (!self->_stream) { -- break; -+ 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))); -+ // 4 = self -+ 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) { -+ uin = (udstruct *) ud; -+ ObjectList *rover = self->_streams; -+ ObjectList *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) { -+ uin = (udstruct *) ud; -+ pparray * array = (pparray *) uin->d; -+ int count = array->size; -+ int i; -+ for (i=0;itype == 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; -+ } -+ } -+ } -+ ObjectList *rover = self->_streams; -+ self->_stream = rover->stream; -+ self->_streams = rover->next; -+ } -+ } - } -+ streamReset(self); - token = _parseToken(self,streamGetChar(self)); -- } -- /* wrap up */ -- if (self->_stream) { -- self->_stream->streamClose(); -- self->_stream = NULL; -- } -- clear_operand_stack(self,0); -- free(self->_operandstack); -- return 0; -+ while (token) { -+ if (token->type == pdf_operator) { -+ lua_pushstring(L, token->string); -+ free_token(token); -+ lua_rawget(L,2); // operator table -+ if (lua_isfunction(L,-1)) { -+ lua_pushvalue(L,4); -+ lua_pushvalue(L,3); -+ (void)lua_call(L,2,0); -+ } else { -+ lua_pop(L,1); // nil -+ } -+ clear_operand_stack(self,0); -+ } else { -+ push_operand(self, token); -+ } -+ if (!self->_stream) { -+ break; -+ } -+ token = _parseToken(self,streamGetChar(self)); -+ } -+ /* 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; -+ int c; -+ scannerdata *self = scanner_check(L,1); -+ while ((c=streamGetChar(self))>=0) ; -+ return 0; - } - - // 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; -+ 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) - { -- int balance = 1; // nesting tracking -- int index = 1; // lua array index -- 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++); -+ int balance = 1; // nesting tracking -+ int index = 1; // lua array index -+ 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++]; - } -- token = self->_operandstack[self->_nextoperand++]; -- } - } - - - static void push_dict (lua_State *L, scannerdata *self) - { -- int balance = 1; // nesting tracking -- int needskey = 1; // toggle between lua value and lua key -- 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); -- } -+ int balance = 1; // nesting tracking -+ int needskey = 1; // toggle between lua value and lua key -+ 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++]; - } -- token = self->_operandstack[self->_nextoperand++]; -- } - } - --const char *typenames[pdf_stopdict+1] = -- { "unknown", "integer", "real", "boolean", "name", "operator", -- "string", "array", "array", "dict", "dict" }; -+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) { -- lua_pushnumber(L, token->value); /* integer or float */ -- } 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); -+ 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) { -+ lua_pushnumber(L, token->value); /* integer or float */ -+ } 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) { -- int clear = 0; // how much of the operand stack needs deleting -- scannerdata *self = scanner_check(L,1); -- if (self->_nextoperand==0) { -- return 0; -- } -- clear = self->_nextoperand-1; -- Token *token = self->_operandstack[self->_nextoperand-1]; -- if (token ==NULL || (token->type != token_type )) { -- return 0; -- } -- // 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); -+ int clear = 0; // how much of the operand stack needs deleting -+ scannerdata *self = scanner_check(L,1); -+ if (self->_nextoperand==0) { -+ return 0; -+ } - clear = self->_nextoperand-1; -- push_token(L, self); -- lua_rawgeti(L,-1,2); -- } else if (token_type == pdf_real || token_type == pdf_integer) { -- lua_pushnumber(L, token->value); /* integer or float */ -- } 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; -+ Token *token = self->_operandstack[self->_nextoperand-1]; -+ if (token ==NULL || (token->type != token_type )) { -+ return 0; -+ } -+ // 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) { -+ lua_pushnumber(L, token->value); /* integer or float */ -+ } 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) { -- int clear = 0; // how much of the operand stack needs deleting -- scannerdata *self = scanner_check(L,1); -- if (self->_nextoperand==0) { -- return 0; -- } -- clear = self->_nextoperand-1; -- Token *token = self->_operandstack[self->_nextoperand-1]; -- if (token ==NULL) { -- return 0; -- } -- int token_type = token->type; -- // 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); -+ int clear = 0; // how much of the operand stack needs deleting -+ scannerdata *self = scanner_check(L,1); -+ if (self->_nextoperand==0) { -+ return 0; -+ } - clear = self->_nextoperand-1; -- push_token(L, self); -- } else { -- push_token(L, self); -- } -- clear_operand_stack(self,clear); -- return 1; -+ Token *token = self->_operandstack[self->_nextoperand-1]; -+ if (token ==NULL) { -+ return 0; -+ } -+ int token_type = token->type; -+ // 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); -+ 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)) -+ if(scanner_popsingular(L,pdf_boolean)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static int scanner_popstring(lua_State * L) - { -- if (scanner_popsingular(L,pdf_string)) -+ if (scanner_popsingular(L,pdf_string)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static int scanner_popname(lua_State * L) - { -- if (scanner_popsingular(L,pdf_name)) -+ if (scanner_popsingular(L,pdf_name)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static int scanner_poparray(lua_State * L) - { -- if (scanner_popsingular(L,pdf_stoparray)) -+ if (scanner_popsingular(L,pdf_stoparray)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static int scanner_popdictionary(lua_State * L) - { -- if (scanner_popsingular(L,pdf_stopdict)) -+ if (scanner_popsingular(L,pdf_stopdict)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static int scanner_popany(lua_State * L) - { -- if (scanner_popanything(L)) -+ if (scanner_popanything(L)) -+ return 1; -+ lua_pushnil(L); - return 1; -- lua_pushnil(L); -- return 1; - } - - static const luaL_Reg scannerlib_meta[] = { -- {0, 0} -+ {0, 0} - }; - - static const struct luaL_Reg scannerlib_m[] = { -@@ -929,10 +1020,9 @@ static const struct luaL_Reg scannerlib_m[] = { - {"popDict", scanner_popdictionary}, - {"popBool", scanner_popboolean}, - {"pop", scanner_popany}, -- {NULL, NULL} /* sentinel */ -+ {NULL, NULL} /* sentinel */ - }; - -- - static const luaL_Reg scannerlib[] = { - {"scan", scanner_scan}, - {NULL, NULL} -diff --git a/texk/web2c/luatexdir/lua/lstatslib.c b/texk/web2c/luatexdir/lua/lstatslib.c -index 43f33008d..5f3b72262 100644 ---- a/texk/web2c/luatexdir/lua/lstatslib.c -+++ b/texk/web2c/luatexdir/lua/lstatslib.c -@@ -147,13 +147,15 @@ static lua_Number get_luatexhashchars(void) - static const char *get_luatexhashtype(void) - { - #ifdef LuajitTeX -- return (const char *)jithash_hashname; -+ if (jithash_hashname) -+ return (const char *)jithash_hashname; -+ else -+ return "???"; - #else - return "lua"; - #endif - } - -- - static lua_Number get_pdf_gone(void) - { - if (static_pdf != NULL) -@@ -266,8 +268,22 @@ static lua_Number get_development_id(void) - return (lua_Number) luatex_svn_revision ; - } - -+static lua_Number get_dvi_gone(void) -+{ -+ if (static_pdf != NULL) -+ return (lua_Number) dvi_get_status_gone(static_pdf); -+ return (lua_Number) 0; -+} -+ -+static lua_Number get_dvi_ptr(void) -+{ -+ if (static_pdf != NULL) -+ return (lua_Number) dvi_get_status_ptr(static_pdf); -+ return (lua_Number) 0; -+} - - /* temp, for backward compat */ -+ - static int init_pool_ptr = 0; - - static struct statistic stats[] = { -@@ -291,8 +307,9 @@ static struct statistic stats[] = { - - {"pdf_gone", 'N', &get_pdf_gone}, - {"pdf_ptr", 'N', &get_pdf_ptr}, -- {"dvi_gone", 'g', &dvi_offset}, -- {"dvi_ptr", 'g', &dvi_ptr}, -+ {"dvi_gone", 'g', &get_dvi_gone}, -+ {"dvi_ptr", 'g', &get_dvi_ptr}, -+ - {"total_pages", 'g', &total_pages}, - {"output_file_name", 'S', (void *) &get_output_file_name}, - {"log_name", 'S', (void *) &getlogname}, -@@ -355,9 +372,14 @@ static struct statistic stats[] = { - {"luabytecodes", 'g', &luabytecode_max}, - {"luabytecode_bytes", 'g', &luabytecode_bytes}, - {"luastate_bytes", 'g', &luastate_bytes}, -+ - {"callbacks", 'g', &callback_count}, -+ {"indirect_callbacks", 'g', &saved_callback_count}, /* these are file io callbacks */ - -- {"indirect_callbacks", 'g', &saved_callback_count}, -+ {"saved_callbacks", 'g', &saved_callback_count}, -+ {"late_callbacks", 'g', &late_callback_count}, -+ {"direct_callbacks", 'g', &direct_callback_count}, -+ {"function_callbacks", 'g', &function_callback_count}, - - {"lc_ctype", 'S', (void *) &get_lc_ctype}, - {"lc_collate", 'S', (void *) &get_lc_collate}, -diff --git a/texk/web2c/luatexdir/lua/ltexiolib.c b/texk/web2c/luatexdir/lua/ltexiolib.c -index f0fa5d369..5f1786c65 100644 ---- a/texk/web2c/luatexdir/lua/ltexiolib.c -+++ b/texk/web2c/luatexdir/lua/ltexiolib.c -@@ -155,10 +155,26 @@ static int texio_setescape(lua_State * L) - return 0 ; - } - -+static int texio_closeinput(lua_State * L) -+{ -+ /* -+ printf("before, first %i, index %i, iname %i, inopen %i, pointer %i\n",istart,iindex,iname,in_open,input_ptr); -+ */ -+ if (iindex > 0) { -+ end_token_list(); -+ end_file_reading(); -+ /* -+ printf("after, first %i, index %i, iname %i, inopen %i, pointer %i\n",istart,iindex,iname,in_open,input_ptr); -+ */ -+ } -+ return 0 ; -+} -+ - static const struct luaL_Reg texiolib[] = { - {"write", texio_print}, - {"write_nl", texio_printnl}, - {"setescape", texio_setescape}, -+ {"closeinput",texio_closeinput}, - {NULL, NULL} - }; - -diff --git a/texk/web2c/luatexdir/lua/ltexlib.c b/texk/web2c/luatexdir/lua/ltexlib.c -index 65e55705e..c3e459b22 100644 ---- a/texk/web2c/luatexdir/lua/ltexlib.c -+++ b/texk/web2c/luatexdir/lua/ltexlib.c -@@ -35,7 +35,8 @@ typedef struct { - void *next; - boolean partial; - int cattable; -- /* halfword tok; */ -+ halfword tok; -+ halfword nod; - } rope; - - typedef struct { -@@ -54,33 +55,64 @@ static int spindle_size = 0; - static spindle *spindles = NULL; - static int spindle_index = 0; - --static void luac_store(lua_State * L, int i, int partial, int cattable) -+static int luac_store(lua_State * L, int i, int partial, int cattable) - { -- const char *sttemp; -- char *st; -- size_t tsize; -+ char *st = NULL; -+ size_t tsize = 0; - rope *rn = NULL; -- sttemp = lua_tolstring(L, i, &tsize); -- st = xmalloc((unsigned) (tsize + 1)); -- memcpy(st, sttemp, (tsize + 1)); -- if (st) { -- luacstrings++; -- rn = (rope *) xmalloc(sizeof(rope)); -- rn->text = st; -- rn->tsize = (unsigned) tsize; -- rn->partial = partial; -- rn->cattable = cattable; -- rn->next = NULL; -- /* rn->tok = 0; */ -- if (write_spindle.head == NULL) { -- assert(write_spindle.tail == NULL); -- write_spindle.head = rn; -+ halfword tok = null; -+ halfword nod = null; -+ int t = lua_type(L, i); -+ if (t == LUA_TNUMBER || t == LUA_TSTRING) { -+ const char *sttemp; -+ sttemp = lua_tolstring(L, i, &tsize); -+ st = xmalloc((unsigned) (tsize + 1)); -+ memcpy(st, sttemp, (tsize + 1)); -+ } else if (t == LUA_TUSERDATA) { -+ void *p ; -+ p = lua_touserdata(L, i); -+ if (p == NULL) { -+ return 0; -+ } else if (lua_getmetatable(L, i)) { -+ lua_get_metatablelua(luatex_token); -+ if (lua_rawequal(L, -1, -2)) { -+ tok = (halfword) token_info((*((lua_token *)p)).token); -+ lua_pop(L, 2); -+ } else { -+ lua_get_metatablelua(luatex_node); -+ if (lua_rawequal(L, -1, -3)) { -+ nod = *((halfword *)p); -+ lua_pop(L, 3); -+ } else { -+ lua_pop(L, 3); -+ return 0; -+ } -+ } - } else { -- write_spindle.tail->next = rn; -+ return 0; - } -- write_spindle.tail = rn; -- write_spindle.complete = 0; -+ } else { -+ return 0; -+ } -+ /* common */ -+ luacstrings++; -+ rn = (rope *) xmalloc(sizeof(rope)); -+ rn->text = st; -+ rn->tsize = (unsigned) tsize; -+ rn->tok = tok; -+ rn->nod = nod; -+ rn->next = NULL; -+ rn->partial = partial; -+ rn->cattable = cattable; -+ /* add */ -+ if (write_spindle.head == NULL) { -+ write_spindle.head = rn; -+ } else { -+ write_spindle.tail->next = rn; - } -+ write_spindle.tail = rn; -+ write_spindle.complete = 0; -+ return 1; - } - - static int do_luacprint(lua_State * L, int partial, int deftable) -@@ -93,47 +125,33 @@ static int do_luacprint(lua_State * L, int partial, int deftable) - cattable = lua_tointeger(L, 1); - startstrings = 2; - if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) { -- cattable = DEFAULT_CAT_TABLE; -- } -+ cattable = DEFAULT_CAT_TABLE; -+ } - } - } - if (lua_type(L, startstrings) == LUA_TTABLE) { - int i; - for (i = 1;; i++) { - lua_rawgeti(L, startstrings, i); -- if (lua_isstring(L,-1)) { /* or number */ -- luac_store(L, -1, partial, cattable); -+ if (luac_store(L, -1, partial, cattable)) { - lua_pop(L, 1); - } else { -+ lua_pop(L, 1); - break; - } - } - } else { - int i; - for (i = startstrings; i <= n; i++) { -- if (!lua_isstring(L,i)) { /* or number */ -- luaL_error(L, "no string to print"); -- } - luac_store(L, i, partial, cattable); - } -- /* hh: We could use this but it makes not much different, apart from allocating more ropes so less -- memory. To be looked into: lua 5.2 buffer mechanism as now we still hash the concatination. This -- test was part of the why-eis-luajit-so-slow on crited experiments. */ -- /* -- if (startstrings == n) { -- luac_store(L, n, partial, cattable); -- } else { -- lua_concat(L,n-startstrings+1); -- luac_store(L, startstrings, partial, cattable); -- } -- */ - } - return 0; - } - --/* -+/* the next one writes a raw token (number) */ - --// some first experiments .. somewhat tricky at the other end -+/* - - int luatwrite(lua_State * L) - { -@@ -148,6 +166,7 @@ int luatwrite(lua_State * L) - rn->cattable = DEFAULT_CAT_TABLE; - rn->next = NULL; - rn->tok = 0; -+ rn->nod = 0; - if (write_spindle.head == NULL) { - write_spindle.head = rn; - } else { -@@ -165,6 +184,7 @@ int luatwrite(lua_State * L) - r->cattable = DEFAULT_CAT_TABLE; - r->next = NULL; - r->tok = 0; -+ r->nod = 0; - rn->next = r; - rn = r; - write_spindle.tail = rn; -@@ -179,21 +199,79 @@ int luatwrite(lua_State * L) - - */ - -+/* the next one writes a raw node (number) */ -+ -+/* -+ -+int luanwrite(lua_State * L) -+{ -+ int top = lua_gettop(L); -+ if (top>0) { -+ rope *rn = xmalloc(sizeof(rope)); // overkill -+ int i = 1 ; -+ luacstrings++; // should be luactokens -+ rn->text = NULL; -+ rn->tsize = 0; -+ rn->partial = 0; -+ rn->cattable = DEFAULT_CAT_TABLE; -+ rn->next = NULL; -+ rn->tok = 0; -+ rn->nod = 0; -+ if (write_spindle.head == NULL) { -+ write_spindle.head = rn; -+ } else { -+ write_spindle.tail->next = rn; -+ } -+ write_spindle.tail = rn; -+ write_spindle.complete = 0; -+ while (1) { -+ rn->nod = lua_tointeger(L,i); -+ if (itext = NULL; -+ r->tsize = 0; -+ r->partial = 0; -+ r->cattable = DEFAULT_CAT_TABLE; -+ r->next = NULL; -+ r->tok = 0; -+ r->nod = 0; -+ rn->next = r; -+ rn = r; -+ write_spindle.tail = rn; -+ i++; -+ } else { -+ break; -+ } -+ } -+ } -+ return 0; -+} -+ -+*/ -+ -+/* lua.write */ -+ - static int luacwrite(lua_State * L) - { - return do_luacprint(L, FULL_LINE, NO_CAT_TABLE); - } - -+/* lua.print */ -+ - static int luacprint(lua_State * L) - { - return do_luacprint(L, FULL_LINE, DEFAULT_CAT_TABLE); - } - -+/* lua.sprint */ -+ - static int luacsprint(lua_State * L) - { - return do_luacprint(L, PARTIAL_LINE, DEFAULT_CAT_TABLE); - } - -+/* lua.cprint */ -+ - static int luaccprint(lua_State * L) - { - /* so a negative value is a specific catcode with offset 1 */ -@@ -207,10 +285,10 @@ static int luaccprint(lua_State * L) - int i; - for (i = 1;; i++) { - lua_rawgeti(L, 2, i); -- if (lua_isstring(L,-1)) { /* or number */ -- luac_store(L, -1, PARTIAL_LINE, cattable); -+ if (luac_store(L, -1, PARTIAL_LINE, cattable)) { - lua_pop(L, 1); - } else { -+ lua_pop(L, 1); - break; - } - } -@@ -218,15 +296,14 @@ static int luaccprint(lua_State * L) - int i; - int n = lua_gettop(L); - for (i = 2; i <= n; i++) { -- if (!lua_isstring(L,i)) { /* or number */ -- luaL_error(L, "no string to print"); -- } - luac_store(L, i, PARTIAL_LINE, cattable); - } - } - return 0; - } - -+/* lua.tprint */ -+ - static int luactprint(lua_State * L) - { - int i, j; -@@ -238,7 +315,7 @@ static int luactprint(lua_State * L) - if (lua_type(L, i) != LUA_TTABLE) { - luaL_error(L, "no string to print"); - } -- lua_pushvalue(L, i); /* push the table */ -+ lua_pushvalue(L, i); /* push the table */ - lua_pushinteger(L, 1); - lua_gettable(L, -2); - if (lua_type(L, -1) == LUA_TNUMBER) { -@@ -252,15 +329,14 @@ static int luactprint(lua_State * L) - for (j = startstrings;; j++) { - lua_pushinteger(L, j); - lua_gettable(L, -2); -- if (lua_isstring(L, -1)) { /* or number */ -- luac_store(L, -1, PARTIAL_LINE, cattable); -+ if (luac_store(L, -1, PARTIAL_LINE, cattable)) { - lua_pop(L, 1); - } else { - lua_pop(L, 1); - break; - } - } -- lua_pop(L, 1); /* pop the table */ -+ lua_pop(L, 1); /* pop the table */ - } - return 0; - } -@@ -280,7 +356,7 @@ int luacstring_final_line(void) - return (read_spindle.tail->next == NULL); - } - --int luacstring_input(void) -+int luacstring_input(halfword *n) - { - rope *t = read_spindle.head; - int ret = 1 ; -@@ -308,12 +384,15 @@ int luacstring_input(void) - } - free(t->text); - t->text = NULL; -- /* - } else if (t->tok > 0) { -- ret = - t->tok; -- */ -- } -- if (read_spindle.tail != NULL) { /* not a one-liner */ -+ *n = t->tok; -+ ret = 2; -+ } else if (t->nod > 0) { -+ *n = t->nod; -+ ret = 3; -+ } -+ if (read_spindle.tail != NULL) { -+ /* not a one-liner */ - free(read_spindle.tail); - } - read_spindle.tail = t; -@@ -322,11 +401,13 @@ int luacstring_input(void) - } - - /* open for reading, and make a new one for writing */ -+ - void luacstring_start(int n) - { -- (void) n; /* for -W */ -+ (void) n; /* for -W */ - spindle_index++; -- if (spindle_size == spindle_index) { /* add a new one */ -+ if (spindle_size == spindle_index) { -+ /* add a new one */ - spindles = xrealloc(spindles, (unsigned) (sizeof(spindle) * (unsigned) (spindle_size + 1))); - spindles[spindle_index].head = NULL; - spindles[spindle_index].tail = NULL; -@@ -340,7 +421,7 @@ void luacstring_start(int n) - void luacstring_close(int n) - { - rope *next, *t; -- (void) n; /* for -W */ -+ (void) n; /* for -W */ - next = read_spindle.head; - while (next != NULL) { - if (next->text != NULL) -@@ -378,15 +459,15 @@ void luacstring_close(int n) - - static const char *scan_integer_part(lua_State * L, const char *ss, int *ret, int *radix_ret) - { -- boolean negative = false; /* should the answer be negated? */ -- int m = 214748364; /* |$2^{31}$ / radix|, the threshold of danger */ -- int d; /* the digit just scanned */ -- boolean vacuous = true; /* have no digits appeared? */ -- boolean OK_so_far = true; /* has an error message been issued? */ -- int radix1 = 10; /* the radix of the integer */ -- int c = 0; /* the current character */ -- const char *s; /* where we stopped in the string |ss| */ -- integer val = 0; /* return value */ -+ boolean negative = false; /* should the answer be negated? */ -+ int m = 214748364; /* |$2^{31}$ / radix|, the threshold of danger */ -+ int d; /* the digit just scanned */ -+ boolean vacuous = true; /* have no digits appeared? */ -+ boolean OK_so_far = true; /* has an error message been issued? */ -+ int radix1 = 10; /* the radix of the integer */ -+ int c = 0; /* the current character */ -+ const char *s; /* where we stopped in the string |ss| */ -+ integer val = 0; /* return value */ - s = ss; - do { - do { -@@ -448,9 +529,9 @@ static const char *scan_integer_part(lua_State * L, const char *ss, int *ret, in - - #define set_conversion(A,B) do { num=(A); denom=(B); } while(0) - -+/* sets |cur_val| to a dimension */ - - static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) --/* sets |cur_val| to a dimension */ - { - boolean negative = false; /* should the answer be negated? */ - int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */ -@@ -460,7 +541,7 @@ static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) - int save_cur_val; /* temporary storage of |cur_val| */ - int c; /* the current character */ - const char *s = ss; /* where we are in the string */ -- int radix1 = 0; /* the current radix */ -+ int radix1 = 0; /* the current radix */ - int rdig[18]; /* to save the |dig[]| array */ - int saved_tex_remainder; /* to save |tex_remainder| */ - int saved_arith_error; /* to save |arith_error| */ -@@ -468,9 +549,9 @@ static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) - saved_tex_remainder = tex_remainder; - saved_arith_error = arith_error; - saved_cur_val = cur_val; -- /* Get the next non-blank non-sign... */ -+ /* get the next non-blank non-sign */ - do { -- /* Get the next non-blank non-call token */ -+ /* get the next non-blank non-call token */ - do { - c = *s++; - } while (c && c == ' '); -@@ -493,16 +574,18 @@ static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) - if (c == ',') - c = '.'; - if ((radix1 == 10) && (c == '.')) { -- /* Scan decimal fraction */ -+ /* scan decimal fraction */ - for (k = 0; k < 18; k++) - rdig[k] = dig[k]; - k = 0; -- s++; /* get rid of the '.' */ -+ s++; -+ /* get rid of the '.' */ - while (1) { - c = *s++; - if ((c > '0' + 9) || (c < '0')) - break; -- if (k < 17) { /* digits for |k>=17| cannot affect the result */ -+ if (k < 17) { -+ /* digits for |k>=17| cannot affect the result */ - dig[k++] = c - '0'; - } - } -@@ -516,8 +599,10 @@ static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) - negative = !negative; - cur_val = -cur_val; - } -- /* Scan for (u)units that are internal dimensions; -- |goto attach_sign| with |cur_val| set if found */ -+ /* -+ 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... */ - do { -@@ -570,8 +655,10 @@ static const char *scan_dimen_part(lua_State * L, const char *ss, int *ret) - s += 2; - goto ATTACH_FRACTION; /* the easy case */ - } -- /* Scan for (a)all other units and adjust |cur_val| and |f| accordingly; -- |goto done| in the case of scaled points */ -+ /* -+ Scan for (a)all other units and adjust |cur_val| and |f| accordingly; |goto done| -+ in the case of scaled points -+ */ - if (strncmp(s, "mm", 2) == 0) { - s += 2; - set_conversion(7227, 2540); -@@ -715,7 +802,7 @@ static int get_item_index(lua_State * L, int i, int base) - s = lua_tolstring(L, i, &kk); - cur_cs1 = string_lookup(s, kk); - if (cur_cs1 == undefined_control_sequence || cur_cs1 == undefined_cs_cmd) -- k = -1; /* guarandeed invalid */ -+ k = -1; /* guarandeed invalid */ - else - k = (equiv(cur_cs1) - base); - break; -@@ -724,7 +811,7 @@ static int get_item_index(lua_State * L, int i, int base) - break; - default: - luaL_error(L, "argument must be a string or a number"); -- k = -1; /* not a valid index */ -+ k = -1; /* not a valid index */ - } - return k; - } -@@ -1311,7 +1398,7 @@ static int vsetbox(lua_State * L, int is_global) - } else if (t == LUA_TNIL) { - j = null; - } else { -- j = nodelist_from_lua(L); -+ j = nodelist_from_lua(L,-1); - if (j != null && type(j) != hlist_node && type(j) != vlist_node) { - luaL_error(L, "setbox: incompatible node type (%s)\n", get_node_name(type(j), subtype(j))); - return 0; -@@ -2112,6 +2199,7 @@ static int gettex(lua_State * L) - case assign_int_cmd: - case assign_attr_cmd: - case assign_dir_cmd: -+ case assign_direction_cmd: - case assign_dimen_cmd: - case set_aux_cmd: - case set_prev_graf_cmd: -@@ -2141,8 +2229,9 @@ static int gettex(lua_State * L) - static int getlist(lua_State * L) - { - const char *str; -- if (lua_type(L,2) == LUA_TSTRING) { -- str = lua_tostring(L, 2); -+ int top = lua_gettop(L); -+ if (lua_type(L,top) == LUA_TSTRING) { -+ str = lua_tostring(L, top); - if (lua_key_eq(str,page_ins_head)) { - if (vlink(page_ins_head) == page_ins_head) - lua_pushinteger(L, null); -@@ -2203,17 +2292,18 @@ static int getlist(lua_State * L) - - static int setlist(lua_State * L) - { -- if (lua_type(L,2) == LUA_TSTRING) { -- const char *str = lua_tostring(L, 2); -+ int top = (lua_type(L,1) == LUA_TTABLE) ? 2 : 1 ; -+ if (lua_type(L,top) == LUA_TSTRING) { -+ const char *str = lua_tostring(L, top); - if (lua_key_eq(str,best_size)) { -- best_size = (int) lua_tointeger(L, 3); -+ best_size = (int) lua_tointeger(L, top+1); - } else if (lua_key_eq(str,least_page_cost)) { -- least_page_cost = (int) lua_tointeger(L, 3); -+ least_page_cost = (int) lua_tointeger(L, top+1); - } else { - halfword *n_ptr; - halfword n = 0; -- if (!lua_isnil(L, 3)) { -- n_ptr = check_isnode(L, 3); -+ if (!lua_isnil(L, top+1)) { -+ n_ptr = check_isnode(L, top+1); - n = *n_ptr; - } - if (lua_key_eq(str,page_ins_head)) { -@@ -2359,24 +2449,32 @@ static void init_nest_lib(lua_State * L) - static int getnest(lua_State * L) - { - list_state_record **nestitem; -- int t = lua_type(L, 2); -- if (t == LUA_TNUMBER) { -- int ptr = lua_tointeger(L, 2); -- if (ptr >= 0 && ptr <= nest_ptr) { -- nestitem = lua_newuserdata(L, sizeof(list_state_record *)); -- *nestitem = &nest[ptr]; -- luaL_getmetatable(L, NEST_METATABLE); -- lua_setmetatable(L, -2); -- } else { -- lua_pushnil(L); -- } -- } else if (t == LUA_TSTRING) { -- const char *s = lua_tostring(L, 2); -- if (lua_key_eq(s,ptr)) { -- lua_pushinteger(L, nest_ptr); -- } else { -- lua_pushnil(L); -+ int n = lua_gettop(L); -+ int p = -1 ; -+ if (n == 0) { -+ p = nest_ptr; -+ } else { -+ int t = lua_type(L, n); -+ if (t == LUA_TNUMBER) { -+ int ptr = lua_tointeger(L, n); -+ if (ptr >= 0 && ptr <= nest_ptr) { -+ p = ptr; -+ } -+ } else if (t == LUA_TSTRING) { -+ const char *s = lua_tostring(L, n); -+ if (lua_key_eq(s,top)) { -+ p = nest_ptr; -+ } else if (lua_key_eq(s,ptr)) { -+ lua_pushinteger(L, nest_ptr); -+ return 1; -+ } - } -+ } -+ if (p > -1) { -+ nestitem = lua_newuserdata(L, sizeof(list_state_record *)); -+ *nestitem = &nest[p]; -+ luaL_getmetatable(L, NEST_METATABLE); -+ lua_setmetatable(L, -2); - } else { - lua_pushnil(L); - } -@@ -2386,7 +2484,7 @@ static int getnest(lua_State * L) - static int setnest(lua_State * L) - { - luaL_error(L, "You can't modify the semantic nest array directly"); -- return 2; -+ return 0; - } - - static int do_integer_error(double m) -@@ -2859,7 +2957,7 @@ static int tex_run_linebreak(lua_State * L) - } - lua_key_rawgeti(pardir); - if (lua_type(L, -1) == LUA_TSTRING) { -- paragraph_dir = nodelib_getdir(L, -1, 1); -+ paragraph_dir = nodelib_getdir(L, -1); - } - lua_pop(L, 1); - -@@ -3117,8 +3215,21 @@ static int tex_save_box_resource(lua_State * L) - int type = 0; - int margin = pdf_xform_margin; - boolean immediate = false; -+ /* more or less same as scanner variant */ -+ if (lua_type(L,1) == LUA_TNUMBER) { -+ halfword boxnumber = lua_tointeger(L,1); -+ boxdata = box(boxnumber); -+ box(boxnumber) = null; -+ } else { -+ boxdata = nodelist_from_lua(L,1); -+ if (type(boxdata) != hlist_node && type(boxdata) != vlist_node) { -+ normal_error("pdf backend", "xforms can only be used with a box or [h|v]list"); -+ } -+ } -+ if (boxdata == null) { -+ normal_error("pdf backend", "xforms cannot be used with a void box or empty [h|v]list"); -+ } - /* box attributes resources */ -- halfword boxnumber = lua_tointeger(L,1); - if (lua_type(L,2) == LUA_TSTRING) { - lua_pushvalue(L, 2); - attributes = luaL_ref(L, LUA_REGISTRYINDEX); -@@ -3136,10 +3247,6 @@ static int tex_save_box_resource(lua_State * L) - if (lua_type(L,6) == LUA_TNUMBER) { - margin = lua_tointeger(L, 6); - } -- /* more or less same as scanner variant */ -- boxdata = box(boxnumber); -- if (boxdata == null) -- normal_error("pdf backend", "xforms cannot be used with a void box"); - static_pdf->xform_count++; - index = pdf_create_obj(static_pdf, obj_type_xform, static_pdf->xform_count); - set_obj_data_ptr(static_pdf, index, pdf_get_mem(static_pdf, pdfmem_xform_size)); -@@ -3153,7 +3260,6 @@ static int tex_save_box_resource(lua_State * L) - set_obj_xform_depth(static_pdf, index, depth(boxdata)); - set_obj_xform_type(static_pdf, index, type); - set_obj_xform_margin(static_pdf, index, margin); -- box(boxnumber) = null; - last_saved_box_index = index; - lua_pushinteger(L, index); - if (immediate) { -@@ -3229,12 +3335,35 @@ static int tex_get_box_resource_dimensions(lua_State * L) - return 4; - } - -+static int tex_get_box_resource_box(lua_State * L) -+{ -+ /* no checking yet as this might go */ -+ halfword b; -+ int index = lua_tointeger(L,1); -+ check_obj_type(static_pdf, obj_type_xform, index); -+ b = obj_xform_box(static_pdf, index); -+ nodelist_to_lua(L, b); -+ return 1; -+} -+ - static int tex_build_page(lua_State * L) - { - build_page(); - return 0; - } - -+static int lua_get_page_state(lua_State * L) -+{ -+ lua_pushinteger(L,page_contents); -+ return 1; -+} -+ -+static int lua_get_local_level(lua_State * L) -+{ -+ lua_pushinteger(L,current_local_level()); -+ return 1; -+} -+ - /* synctex */ - - static int lua_set_synctex_mode(lua_State * L) -@@ -3296,6 +3425,82 @@ static int lua_set_synctex_no_files(lua_State * L) - return 0; - } - -+/* -+ This is experimental and might change. In version 10 we hope to have the -+ final version available. It actually took quite a bit of time to understand -+ the implications of mixing lua prints in here. The current variant is (so far) -+ the most robust (wrt crashes and side effects). -+*/ -+ -+#define mode mode_par -+ -+/* -+ When we add save levels then we can get crashes when one flushed bad -+ groups due to out of order flushing. So we play safe! But still we can -+ have issues so best make sure you're in hmode. -+*/ -+ -+static int forcehmode(lua_State * L) -+{ -+ if (abs(mode) == vmode) { -+ if (lua_type(L,1) == LUA_TBOOLEAN) { -+ new_graf(lua_toboolean(L,1)); -+ } else { -+ new_graf(1); -+ } -+ } -+ return 0; -+} -+ -+static int runtoks(lua_State * L) -+{ -+ if (lua_type(L,1) == LUA_TFUNCTION) { -+ int old_mode = mode; -+ int ref; -+ pointer r = get_avail(); -+ pointer t = get_avail(); -+ token_info(r) = token_val(extension_cmd,end_local_code); -+ lua_pushvalue(L, 1); -+ ref = luaL_ref(L,LUA_REGISTRYINDEX); -+ token_info(t) = token_val(lua_local_call_cmd, ref); -+ begin_token_list(r,inserted); -+ begin_token_list(t,inserted); -+ if (luacstrings > 0) { -+ lua_string_start(); -+ } -+ if (tracing_nesting_par > 2) { -+ local_control_message("entering token scanner via function"); -+ } -+ mode = -hmode; -+ local_control(); -+ mode = old_mode; -+ luaL_unref(L,LUA_REGISTRYINDEX,ref); -+ } else { -+ int k = get_item_index(L, lua_gettop(L), toks_base); -+ halfword t = toks(k); -+ check_index_range(k, "gettoks"); -+ if (t != null) { -+ int old_mode = mode; -+ pointer r = get_avail(); -+ token_info(r) = token_val(extension_cmd,end_local_code); -+ begin_token_list(r,inserted); -+ /* new_save_level(semi_simple_group); */ -+ begin_token_list(t,local_text); -+ if (luacstrings > 0) { -+ lua_string_start(); -+ } -+ if (tracing_nesting_par > 2) { -+ local_control_message("entering token scanner via register"); -+ } -+ mode = -hmode; -+ local_control(); -+ mode = old_mode; -+ /* unsave(); */ -+ } -+ } -+ return 0; -+} -+ - /* till here */ - - void init_tex_table(lua_State * L) -@@ -3315,10 +3520,14 @@ static const struct luaL_Reg texlib[] = { - { "finish", tex_run_end }, /* may be needed */ - { "write", luacwrite }, - { "print", luacprint }, -+ { "sprint", luacsprint }, - { "tprint", luactprint }, - { "cprint", luaccprint }, -+ /* -+ { "twrite", luatwrite }, -+ { "nwrite", luanwrite }, -+ */ - { "error", texerror }, -- { "sprint", luacsprint }, - { "set", settex }, - { "get", gettex }, - { "isdimen", isdimen }, -@@ -3327,11 +3536,13 @@ static const struct luaL_Reg texlib[] = { - { "isskip", isskip }, - { "setskip", setskip }, - { "getskip", getskip }, -+ { "isglue", isskip }, - { "setglue", setglue }, - { "getglue", getglue }, - { "ismuskip", ismuskip }, - { "setmuskip", setmuskip }, - { "getmuskip", getmuskip }, -+ { "ismuglue", ismuskip }, - { "setmuglue", setmuglue }, - { "getmuglue", getmuglue }, - { "isattribute", isattribute }, -@@ -3350,7 +3561,7 @@ static const struct luaL_Reg texlib[] = { - { "splitbox", splitbox }, - { "setlist", setlist }, - { "getlist", getlist }, -- { "setnest", setnest }, -+ { "setnest", setnest }, /* only a message */ - { "getnest", getnest }, - { "setcatcode", setcatcode }, - { "getcatcode", getcatcode }, -@@ -3395,8 +3606,12 @@ static const struct luaL_Reg texlib[] = { - { "saveboxresource", tex_save_box_resource }, - { "useboxresource", tex_use_box_resource }, - { "getboxresourcedimensions", tex_get_box_resource_dimensions }, -+ /* might go, used when sanitizing backend */ -+ { "getboxresourcebox", tex_get_box_resource_box }, - /* just for testing: it will probably stay but maybe with options */ - { "triggerbuildpage", tex_build_page }, -+ { "getpagestate", lua_get_page_state }, -+ { "getlocallevel", lua_get_local_level }, - /* not the best place but better than in node */ - { "set_synctex_mode", lua_set_synctex_mode }, - { "get_synctex_mode", lua_get_synctex_mode }, -@@ -3407,6 +3622,9 @@ static const struct luaL_Reg texlib[] = { - { "force_synctex_line", lua_force_synctex_line }, - { "set_synctex_line", lua_set_synctex_line }, - { "get_synctex_line", lua_get_synctex_line }, -+ /* test */ -+ { "runtoks", runtoks }, -+ { "forcehmode", forcehmode }, - /* sentinel */ - { NULL, NULL } - }; -@@ -3451,6 +3669,8 @@ int luaopen_tex(lua_State * L) - spindles[0].tail = NULL; - spindle_size = 1; - /* a somewhat odd place for this assert, maybe */ -- assert(command_names[data_cmd].command_offset == data_cmd); -+ if (command_names[data_cmd].id != data_cmd) { -+ fatal_error("mismatch between tex and lua command name tables"); -+ }; - return 1; - } -diff --git a/texk/web2c/luatexdir/lua/luatex-api.h b/texk/web2c/luatexdir/lua/luatex-api.h -index 36b2f5979..399dccb04 100644 ---- a/texk/web2c/luatexdir/lua/luatex-api.h -+++ b/texk/web2c/luatexdir/lua/luatex-api.h -@@ -35,8 +35,10 @@ extern int draft_mode_value; - /* 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 output_mode get_o_mode(void); - extern void fix_o_mode(void); -+*/ - - /* till here */ - -@@ -66,8 +68,7 @@ typedef struct LoadS { - - extern lua_State *Luas; - --extern void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc, -- const char *setfunc); -+extern void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc, const char *setfunc); - - extern int luac_main(int argc, char *argv[]); - -@@ -76,6 +77,8 @@ extern int luaopen_pdf(lua_State * L); - extern int luaopen_texio(lua_State * L); - extern int luaopen_lang(lua_State * L); - -+extern int luapdfprint(lua_State * L); -+ - # define LUA_TEXFILEHANDLE "TEXFILE*" - - extern lua_State *luatex_error(lua_State * L, int fatal); -@@ -85,6 +88,7 @@ extern int luaopen_zip(lua_State * L); - extern int luaopen_lfs(lua_State * L); - extern int luaopen_lpeg(lua_State * L); - extern int luaopen_md5(lua_State * L); -+extern int luaopen_sha2(lua_State * L); - - #ifndef LuajitTeX - extern int luaopen_ffi(lua_State * L); -@@ -101,14 +105,13 @@ extern void luatex_socketlua_open(lua_State * L); - - extern int luaopen_img(lua_State * L); - extern int l_new_image(lua_State * L); --extern int luaopen_epdf(lua_State * L); -+extern int luaopen_pdfe(lua_State * L); - extern int luaopen_pdfscanner(lua_State * L); - extern int luaopen_mplib(lua_State * L); - extern int luaopen_fio(lua_State * L); - - extern void open_oslibext(lua_State * L); - extern void open_strlibext(lua_State * L); --extern void open_lfslibext(lua_State * L); - - extern void initfilecallbackids(int max); - extern void setinputfilecallbackid(int n, int i); -@@ -118,6 +121,8 @@ extern int getreadfilecallbackid(int n); - - extern void lua_initialize(int ac, char **av); - -+extern void luacall_vf(int p, int f, int c); -+ - extern int luaopen_kpse(lua_State * L); - - extern int luaopen_callback(lua_State * L); -@@ -138,12 +143,12 @@ extern void tokenlist_to_luastring(lua_State * L, int p); - extern int tokenlist_from_lua(lua_State * L); - - extern void lua_nodelib_push(lua_State * L); --extern int nodelib_getdir(lua_State * L, int n, int absolute_only); -+extern int nodelib_getdir(lua_State * L, int n); - extern int nodelib_getlist(lua_State * L, int n); - - extern int luaopen_node(lua_State * L); - extern void nodelist_to_lua(lua_State * L, int n); --extern int nodelist_from_lua(lua_State * L); -+extern int nodelist_from_lua(lua_State * L, int n); - - extern int dimen_to_number(lua_State * L, const char *s); - -@@ -158,8 +163,6 @@ extern const char *lc_ctype; - extern const char *lc_collate; - extern const char *lc_numeric; - -- -- - #ifdef LuajitTeX - extern int luajiton; - extern char *jithash_hashname ; -@@ -177,9 +180,9 @@ extern void unhide_lua_value(lua_State * lua, const char *name, const char *item - extern int hide_lua_value(lua_State * lua, const char *name, const char *item); - - typedef struct command_item_ { -- const char *cmd_name; -- int command_offset; -- const char **commands; -+ int id; -+ const char *name; -+ int lua; - } command_item; - - extern command_item command_names[]; -@@ -193,6 +196,9 @@ extern int luastate_bytes; - - extern int callback_count; - extern int saved_callback_count; -+extern int direct_callback_count; -+extern int late_callback_count; -+extern int function_callback_count; - - extern const char *luatex_banner; - extern const char *engine_name; -@@ -256,7 +262,13 @@ extern char **environ; - } - #endif - -+typedef struct lua_token { -+ int token; -+ int origin; -+} lua_token; -+ - extern int luatwrite(lua_State * L); -+extern int luanwrite(lua_State * L); - - /* - Same as in lnodelib.c, but with prefix G_ for now. -@@ -342,22 +354,58 @@ preassign these at startup time. */ - #define LOCAL_PAR_SIZE 5 - #define MATH_STYLE_NAME_SIZE 8 - #define APPEND_LIST_SIZE 5 --#define DIR_PAR_SIZE 8 --#define DIR_TEXT_SIZE 8 -+#define DIR_PAR_SIZE 4 -+#define DIR_TEXT_SIZE 4 - - extern int l_pack_type_index [PACK_TYPE_SIZE]; - extern int l_group_code_index [GROUP_CODE_SIZE]; - extern int l_local_par_index [LOCAL_PAR_SIZE]; - extern int l_math_style_name_index [MATH_STYLE_NAME_SIZE]; - extern int l_dir_par_index [DIR_PAR_SIZE]; --extern int l_dir_text_index [DIR_TEXT_SIZE]; -+extern int l_dir_text_index_normal [DIR_TEXT_SIZE]; -+extern int l_dir_text_index_cancel [DIR_TEXT_SIZE]; - - #define lua_push_pack_type(L,pack_type) lua_rawgeti(L, LUA_REGISTRYINDEX, l_pack_type_index[pack_type] ); - #define lua_push_group_code(L,group_code) lua_rawgeti(L, LUA_REGISTRYINDEX, l_group_code_index[group_code]); - #define lua_push_local_par_mode(L,par_mode) lua_rawgeti(L, LUA_REGISTRYINDEX, l_local_par_index[par_mode]); - #define lua_push_math_style_name(L,style_name) lua_rawgeti(L, LUA_REGISTRYINDEX, l_math_style_name_index[style_name]); --#define lua_push_dir_par(L,dir) lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_par_index[dir+dir_swap]) --#define lua_push_dir_text(L,dir) lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_text_index[dir+dir_swap]) -+ -+#define lua_push_direction(L,direction) \ -+ if (direction < 0) { \ -+ lua_pushnil(L); \ -+ } else { \ -+ lua_pushinteger(L,direction); \ -+ } -+ -+#define lua_push_dir_par(L,dir) \ -+ if (dir < 0) { \ -+ lua_pushnil(L); \ -+ } else { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_par_index[dir]); \ -+ } -+ -+#define lua_push_dir_text_normal(L,dir) \ -+ if (dir < 0) { \ -+ lua_pushnil(L); \ -+ } else { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_text_index_normal[dir]); \ -+ } -+ -+#define lua_push_dir_text_cancel(L,dir) \ -+ if (dir < 0) { \ -+ lua_pushnil(L); \ -+ } else { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_text_index_cancel[dir]); \ -+ } -+ -+#define lua_push_dir_text(L,dir,sub) \ -+ if (dir < 0) { \ -+ lua_pushnil(L); \ -+ } else if (sub) { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_text_index_cancel[dir]); \ -+ } else { \ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, l_dir_text_index_normal[dir]); \ -+ } - - #define lua_push_string_by_index(L,index) lua_rawgeti(L, LUA_REGISTRYINDEX, index) - #define lua_push_string_by_name(L,index) lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(index)) -@@ -414,21 +462,17 @@ l_math_style_name_index[cramped_script_script_style] = lua_key_index(crampedscri - l_dir_par_index[dir_TLT] = lua_key_index(TLT);\ - l_dir_par_index[dir_TRT] = lua_key_index(TRT);\ - l_dir_par_index[dir_LTL] = lua_key_index(LTL);\ --l_dir_par_index[dir_RTT] = lua_key_index(RTT);\ --l_dir_par_index[dir_TLT+4] = lua_key_index(TLT);\ --l_dir_par_index[dir_TRT+4] = lua_key_index(TRT);\ --l_dir_par_index[dir_LTL+4] = lua_key_index(LTL);\ --l_dir_par_index[dir_RTT+4] = lua_key_index(RTT);\ -+l_dir_par_index[dir_RTT] = lua_key_index(RTT); - - #define set_l_dir_text_index \ --l_dir_text_index[dir_TLT] = lua_key_index(mTLT);\ --l_dir_text_index[dir_TRT] = lua_key_index(mTRT);\ --l_dir_text_index[dir_LTL] = lua_key_index(mLTL);\ --l_dir_text_index[dir_RTT] = lua_key_index(mRTT);\ --l_dir_text_index[dir_TLT+4] = lua_key_index(pTLT);\ --l_dir_text_index[dir_TRT+4] = lua_key_index(pTRT);\ --l_dir_text_index[dir_LTL+4] = lua_key_index(pLTL);\ --l_dir_text_index[dir_RTT+4] = lua_key_index(pRTT);\ -+l_dir_text_index_normal[dir_TLT] = lua_key_index(pTLT);\ -+l_dir_text_index_normal[dir_TRT] = lua_key_index(pTRT);\ -+l_dir_text_index_normal[dir_LTL] = lua_key_index(pLTL);\ -+l_dir_text_index_normal[dir_RTT] = lua_key_index(pRTT);\ -+l_dir_text_index_cancel[dir_TLT] = lua_key_index(mTLT);\ -+l_dir_text_index_cancel[dir_TRT] = lua_key_index(mTRT);\ -+l_dir_text_index_cancel[dir_LTL] = lua_key_index(mLTL);\ -+l_dir_text_index_cancel[dir_RTT] = lua_key_index(mRTT); - - #define img_parms_max 25 - #define img_pageboxes_max 6 -@@ -438,6 +482,7 @@ extern int img_pageboxes [img_pageboxes_max]; - - # define set_l_img_keys_index \ - img_parms[ 0] = lua_key_index(attr); \ -+img_parms[ 0] = lua_key_index(attribute_list); \ - img_parms[ 1] = lua_key_index(bbox); \ - img_parms[ 2] = lua_key_index(colordepth); \ - img_parms[ 3] = lua_key_index(colorspace); \ -@@ -474,17 +519,16 @@ img_pageboxes[5] = lua_key_index(art); \ - #define lua_push_img_key(L,key) lua_rawgeti(L, LUA_REGISTRYINDEX, img_parms[key] ); - #define lua_push_img_pagebox(L,box) lua_rawgeti(L, LUA_REGISTRYINDEX, img_pageboxes[box]); - --extern int lua_show_valid_list(lua_State *L, const char **list, int max); -+extern int lua_show_valid_list(lua_State *L, const char **list, int offset, int max); - extern int lua_show_valid_keys(lua_State *L, int *list, int max); - - #define set_make_keys \ --make_lua_key(cmdname);make_lua_key(expandable);make_lua_key(protected);\ --make_lua_key(LTL);\ --make_lua_key(MathConstants);\ --make_lua_key(RTT);\ --make_lua_key(TLT);\ --make_lua_key(TRT);\ -+make_lua_key(__index);\ -+make_lua_key(above);\ -+make_lua_key(abovedisplayshortskip);\ -+make_lua_key(abovedisplayskip);\ - make_lua_key(accent);\ -+make_lua_key(accentkern);\ - make_lua_key(action);\ - make_lua_key(action_id);\ - make_lua_key(action_type);\ -@@ -496,53 +540,107 @@ make_lua_key(adjust_head);\ - make_lua_key(adjusted_hbox);\ - make_lua_key(adjustspacing);\ - make_lua_key(advance);\ -+make_lua_key(after_assignment);\ - make_lua_key(after_display);\ -+make_lua_key(after_group);\ - make_lua_key(after_output);\ -+make_lua_key(afterdisplaypenalty);\ - make_lua_key(align);\ - make_lua_key(align_head);\ -+make_lua_key(align_record);\ - make_lua_key(align_set);\ -+make_lua_key(align_stack);\ - make_lua_key(alignment);\ -+make_lua_key(always);\ - make_lua_key(annot);\ - make_lua_key(area);\ - make_lua_key(art);\ -+make_lua_key(assign_attr);\ -+make_lua_key(assign_box_dir);\ -+make_lua_key(assign_box_direction);\ -+make_lua_key(assign_dimen);\ -+make_lua_key(assign_dir);\ -+make_lua_key(assign_direction);\ -+make_lua_key(assign_font_dimen);\ -+make_lua_key(assign_font_int);\ -+make_lua_key(assign_glue);\ -+make_lua_key(assign_hang_indent);\ -+make_lua_key(assign_int);\ -+make_lua_key(assign_local_box);\ -+make_lua_key(assign_mu_glue);\ -+make_lua_key(assign_toks);\ - make_lua_key(attr);\ -+make_lua_key(attribute);\ -+make_lua_key(attribute_list);\ - make_lua_key(attributes);\ -+make_lua_key(automatic);\ -+make_lua_key(baselineskip);\ - make_lua_key(bbox);\ - make_lua_key(before_display);\ -+make_lua_key(beforedisplaypenalty);\ -+make_lua_key(begin_group);\ -+make_lua_key(beginmath);\ -+make_lua_key(belowdisplayshortskip);\ -+make_lua_key(belowdisplayskip);\ - make_lua_key(best_ins_ptr);\ - make_lua_key(best_page_break);\ - make_lua_key(best_size);\ -+make_lua_key(bin);\ - make_lua_key(bleed);\ - make_lua_key(bot);\ - make_lua_key(bot_accent);\ -+make_lua_key(bothflexible);\ - make_lua_key(bottom_left);\ - make_lua_key(bottom_right);\ - make_lua_key(boundary);\ - make_lua_key(box);\ - make_lua_key(box_left);\ - make_lua_key(box_left_width);\ -+make_lua_key(box_ref);\ - make_lua_key(box_right);\ - make_lua_key(box_right_width);\ -+make_lua_key(box_there);\ -+make_lua_key(break_penalty);\ - make_lua_key(broken_ins);\ - make_lua_key(broken_ptr);\ - make_lua_key(brokenpenalty);\ - make_lua_key(cache);\ - make_lua_key(cal_expand_ratio);\ -+make_lua_key(call);\ -+make_lua_key(cancel);\ -+make_lua_key(car_ret);\ -+make_lua_key(case_shift);\ -+make_lua_key(Catalog);\ - make_lua_key(catalog);\ -+make_lua_key(cell);\ - make_lua_key(char);\ -+make_lua_key(char_ghost);\ -+make_lua_key(char_given);\ -+make_lua_key(char_num);\ -+make_lua_key(character);\ - make_lua_key(characters);\ - make_lua_key(checksum);\ -+make_lua_key(choice);\ - make_lua_key(cidinfo);\ - make_lua_key(class);\ -+make_lua_key(cleaders);\ -+make_lua_key(close);\ - make_lua_key(clubpenalty);\ -+make_lua_key(cmd);\ -+make_lua_key(cmdname);\ -+make_lua_key(color_stack);\ - make_lua_key(colordepth);\ - make_lua_key(colorspace);\ -+make_lua_key(combinetoks);\ - make_lua_key(command);\ - make_lua_key(commands);\ - make_lua_key(comment);\ - make_lua_key(components);\ - make_lua_key(compresslevel);\ -+make_lua_key(conditionalmathskip);\ - make_lua_key(contrib_head);\ -+make_lua_key(convert);\ -+make_lua_key(copy_font);\ - make_lua_key(core);\ - make_lua_key(cost);\ - make_lua_key(count);\ -@@ -551,11 +649,21 @@ make_lua_key(crampedscript);\ - make_lua_key(crampedscriptscript);\ - make_lua_key(crampedtext);\ - make_lua_key(crop);\ -+make_lua_key(cs_name);\ - make_lua_key(csname);\ -+make_lua_key(current);\ - make_lua_key(data);\ -+make_lua_key(def);\ -+make_lua_key(def_char_code);\ -+make_lua_key(def_del_code);\ -+make_lua_key(def_family);\ -+make_lua_key(def_font);\ -+make_lua_key(def_lua_call);\ - make_lua_key(degree);\ - make_lua_key(delim);\ -+make_lua_key(delim_num);\ - make_lua_key(delimptr);\ -+make_lua_key(delta);\ - make_lua_key(demerits);\ - make_lua_key(denom);\ - make_lua_key(depth);\ -@@ -568,46 +676,92 @@ make_lua_key(direct);\ - make_lua_key(direction);\ - make_lua_key(dirs);\ - make_lua_key(disc);\ -+make_lua_key(discretionary);\ - make_lua_key(display);\ -+make_lua_key(divide);\ -+make_lua_key(dont_expand);\ - make_lua_key(doublehyphendemerits);\ - make_lua_key(down);\ - make_lua_key(embedding);\ - make_lua_key(emergencystretch);\ -+make_lua_key(empty);\ - make_lua_key(empty_string);\ - make_lua_key(encodingbytes);\ - make_lua_key(encodingname);\ - make_lua_key(end);\ --make_lua_key(etex);\ -+make_lua_key(end_cs_name);\ -+make_lua_key(end_group);\ -+make_lua_key(end_template);\ -+make_lua_key(endmath);\ -+make_lua_key(endv);\ -+make_lua_key(eq_no);\ - make_lua_key(equation);\ - make_lua_key(equation_number);\ -+make_lua_key(equationnumber);\ -+make_lua_key(equationnumberpenalty);\ -+make_lua_key(etex);\ -+make_lua_key(ex_space);\ - make_lua_key(exactly);\ -+make_lua_key(expand_after);\ -+make_lua_key(expand_font);\ -+make_lua_key(expandable);\ - make_lua_key(expansion_factor);\ -+make_lua_key(explicit);\ -+make_lua_key(expr_stack);\ - make_lua_key(ext);\ -+make_lua_key(extdef_del_code);\ -+make_lua_key(extdef_math_code);\ - make_lua_key(extend);\ - make_lua_key(extender);\ - make_lua_key(extensible);\ -+make_lua_key(extension);\ - make_lua_key(extra_space);\ - make_lua_key(fam);\ - make_lua_key(fast);\ -+make_lua_key(feedback);\ - make_lua_key(fence);\ -+make_lua_key(fi);\ -+make_lua_key(fi_or_else);\ -+make_lua_key(fil);\ - make_lua_key(file);\ - make_lua_key(filename);\ - make_lua_key(filepath);\ - make_lua_key(fill);\ -+make_lua_key(filll);\ -+make_lua_key(fillll);\ - make_lua_key(fin_row);\ - make_lua_key(finalhyphendemerits);\ -+make_lua_key(finalpenalty);\ -+make_lua_key(first);\ -+make_lua_key(fit);\ -+make_lua_key(fitb);\ -+make_lua_key(fitbh);\ -+make_lua_key(fitbv);\ -+make_lua_key(fith);\ -+make_lua_key(fitr);\ -+make_lua_key(fitv);\ -+make_lua_key(fixedboth);\ -+make_lua_key(fixedbottom);\ -+make_lua_key(fixedtop);\ - make_lua_key(font);\ -+make_lua_key(fontkern);\ - make_lua_key(fonts);\ - make_lua_key(format);\ - make_lua_key(fraction);\ - make_lua_key(fullname);\ -+make_lua_key(ghost);\ -+make_lua_key(gleaders);\ - make_lua_key(global);\ - make_lua_key(glue);\ - make_lua_key(glue_order);\ -+make_lua_key(glue_ref);\ - make_lua_key(glue_set);\ - make_lua_key(glue_sign);\ -+make_lua_key(glue_spec);\ - make_lua_key(glyph);\ -+make_lua_key(goto);\ - make_lua_key(h);\ -+make_lua_key(halign);\ - make_lua_key(hangafter);\ - make_lua_key(hangindent);\ - make_lua_key(hbox);\ -@@ -615,20 +769,37 @@ make_lua_key(head);\ - make_lua_key(height);\ - make_lua_key(hlist);\ - make_lua_key(hmode_par);\ -+make_lua_key(hmove);\ - make_lua_key(hold_head);\ - make_lua_key(horiz_variants);\ -+make_lua_key(hrule);\ - make_lua_key(hsize);\ -+make_lua_key(hskip);\ -+make_lua_key(hyph_data);\ -+make_lua_key(hyphenated);\ - make_lua_key(hyphenchar);\ - make_lua_key(id);\ - make_lua_key(identity);\ -+make_lua_key(if_stack);\ -+make_lua_key(if_test);\ -+make_lua_key(ignore_spaces);\ - make_lua_key(image);\ - make_lua_key(imagetype);\ - make_lua_key(immediate);\ -+make_lua_key(in_stream);\ -+make_lua_key(indent);\ - make_lua_key(index);\ - make_lua_key(info);\ -+make_lua_key(Info);\ -+make_lua_key(inner);\ -+make_lua_key(input);\ -+make_lua_key(ins);\ - make_lua_key(insert);\ -+make_lua_key(inserts_only);\ - make_lua_key(interlinepenalty);\ -+make_lua_key(ital_corr);\ - make_lua_key(italic);\ -+make_lua_key(italiccorrection);\ - make_lua_key(keepopen);\ - make_lua_key(kern);\ - make_lua_key(kerns);\ -@@ -636,95 +807,191 @@ make_lua_key(lang);\ - make_lua_key(large_char);\ - make_lua_key(large_fam);\ - make_lua_key(last_ins_ptr);\ -+make_lua_key(last_item);\ - make_lua_key(lastlinefit);\ -+make_lua_key(late_lua);\ - make_lua_key(leader);\ -+make_lua_key(leader_ship);\ -+make_lua_key(leaders);\ - make_lua_key(least_page_cost);\ - make_lua_key(left);\ - make_lua_key(left_boundary);\ -+make_lua_key(left_brace);\ - make_lua_key(left_protruding);\ -+make_lua_key(left_right);\ - make_lua_key(leftskip);\ -+make_lua_key(let);\ -+make_lua_key(letter);\ -+make_lua_key(letterspace_font);\ - make_lua_key(level);\ -+make_lua_key(ligature);\ - make_lua_key(ligatures);\ -+make_lua_key(limit_switch);\ -+make_lua_key(line);\ -+make_lua_key(linebreakpenalty);\ - make_lua_key(linepenalty);\ -+make_lua_key(lineskip);\ - make_lua_key(link_attr);\ - make_lua_key(list);\ - make_lua_key(local_box);\ -+make_lua_key(local_par);\ - make_lua_key(log);\ -+make_lua_key(long_call);\ -+make_lua_key(long_outer_call);\ - make_lua_key(looseness);\ -+make_lua_key(LTL);\ - make_lua_key(lua);\ -+make_lua_key(lua_bytecode_call);\ - make_lua_key(lua_bytecodes_indirect);\ -+make_lua_key(lua_call);\ -+make_lua_key(lua_expandable_call);\ -+make_lua_key(lua_local_call);\ -+make_lua_key(lua_function_call);\ - make_lua_key(lua_functions);\ - make_lua_key(luatex);\ - make_lua_key(luatex_node);\ - make_lua_key(luatex_token);\ --make_lua_key(mLTL);\ --make_lua_key(mRTT);\ --make_lua_key(mTLT);\ --make_lua_key(mTRT);\ -+make_lua_key(luatex_pdfe);\ -+make_lua_key(luatex_pdfe_dictionary);\ -+make_lua_key(luatex_pdfe_array);\ -+make_lua_key(luatex_pdfe_stream);\ -+make_lua_key(luatex_pdfe_reference);\ -+make_lua_key(mac_param);\ -+make_lua_key(make_box);\ -+make_lua_key(margin_kern);\ - make_lua_key(marginkern);\ - make_lua_key(mark);\ - make_lua_key(math);\ -+make_lua_key(math_accent);\ -+make_lua_key(math_char);\ -+make_lua_key(math_char_num);\ - make_lua_key(math_choice);\ -+make_lua_key(math_comp);\ -+make_lua_key(math_given);\ - make_lua_key(math_left);\ - make_lua_key(math_shift);\ -+make_lua_key(math_shift_cs);\ -+make_lua_key(math_style);\ -+make_lua_key(math_sub_box);\ -+make_lua_key(math_sub_mlist);\ -+make_lua_key(math_text_char);\ -+make_lua_key(MathConstants);\ - make_lua_key(mathdir);\ - make_lua_key(mathkern);\ -+make_lua_key(mathskip);\ - make_lua_key(mathstyle);\ - make_lua_key(media);\ -+make_lua_key(medmuskip);\ -+make_lua_key(message);\ - make_lua_key(mid);\ - make_lua_key(middle);\ -+make_lua_key(mkern);\ -+make_lua_key(mLTL);\ - make_lua_key(mode);\ - make_lua_key(modeline);\ -+make_lua_key(movement_stack);\ -+make_lua_key(mRTT);\ -+make_lua_key(mskip);\ -+make_lua_key(mTLT);\ -+make_lua_key(mTRT);\ -+make_lua_key(muglue);\ -+make_lua_key(multiply);\ - make_lua_key(name);\ - make_lua_key(named_id);\ - make_lua_key(names);\ -+make_lua_key(nested_list);\ -+make_lua_key(new);\ - make_lua_key(new_graf);\ - make_lua_key(new_window);\ - make_lua_key(next);\ - make_lua_key(no);\ -+make_lua_key(nolength);\ - make_lua_key(no_align);\ -+make_lua_key(no_expand);\ -+make_lua_key(no_super_sub_script);\ - make_lua_key(noad);\ -+make_lua_key(noadpenalty);\ - make_lua_key(node);\ - make_lua_key(node_properties);\ - make_lua_key(node_properties_indirect);\ -+make_lua_key(nohrule);\ - make_lua_key(nomath);\ -+make_lua_key(non_script);\ - make_lua_key(none);\ -+make_lua_key(nonew);\ - make_lua_key(nop);\ -+make_lua_key(normal);\ -+make_lua_key(novrule);\ - make_lua_key(nucleus);\ - make_lua_key(num);\ - make_lua_key(number);\ - make_lua_key(objcompression);\ - make_lua_key(objnum);\ - make_lua_key(oldmath);\ --make_lua_key(ordering);\ -+make_lua_key(omit);\ -+make_lua_key(opdisplaylimits);\ -+make_lua_key(open);\ -+make_lua_key(oplimits);\ -+make_lua_key(opnolimits);\ -+make_lua_key(option);\ - make_lua_key(options);\ -+make_lua_key(ord);\ -+make_lua_key(ordering);\ - make_lua_key(orientation);\ - make_lua_key(origin);\ -+make_lua_key(other_char);\ -+make_lua_key(outer_call);\ -+make_lua_key(outline);\ - make_lua_key(output);\ -+make_lua_key(over);\ - make_lua_key(overlay_accent);\ --make_lua_key(pLTL);\ --make_lua_key(pRTT);\ --make_lua_key(pTLT);\ --make_lua_key(pTRT);\ -+make_lua_key(ownerpassword);\ - make_lua_key(page);\ --make_lua_key(pages);\ - make_lua_key(page_discards_head);\ - make_lua_key(page_head);\ - make_lua_key(page_ins_head);\ -+make_lua_key(page_insert);\ - make_lua_key(pageattributes);\ - make_lua_key(pagebox);\ - make_lua_key(pageresources);\ -+make_lua_key(pages);\ -+make_lua_key(Pages);\ - make_lua_key(pagesattributes);\ -+make_lua_key(pagestate);\ -+make_lua_key(par_end);\ - make_lua_key(parameters);\ - make_lua_key(pardir);\ -+make_lua_key(parfillskip);\ - make_lua_key(parshape);\ -+make_lua_key(parskip);\ -+make_lua_key(passive);\ - make_lua_key(pdf);\ -+make_lua_key(pdfe);\ -+make_lua_key(pdf_action);\ -+make_lua_key(pdf_annot);\ -+make_lua_key(pdf_colorstack);\ - make_lua_key(pdf_data);\ -+make_lua_key(pdf_dest);\ - make_lua_key(pdf_destination);\ -+make_lua_key(pdf_end_link);\ -+make_lua_key(pdf_end_thread);\ -+make_lua_key(pdf_link_data);\ - make_lua_key(pdf_literal);\ -+make_lua_key(pdf_refobj);\ -+make_lua_key(pdf_restore);\ -+make_lua_key(pdf_save);\ -+make_lua_key(pdf_setmatrix);\ -+make_lua_key(pdf_setobj);\ -+make_lua_key(pdf_start);\ -+make_lua_key(pdf_start_link);\ -+make_lua_key(pdf_start_thread);\ -+make_lua_key(pdf_thread);\ -+make_lua_key(pdf_thread_data);\ -+make_lua_key(pdf_window);\ - make_lua_key(pen_broken);\ - make_lua_key(pen_inter);\ - make_lua_key(penalty);\ -+make_lua_key(pLTL);\ - make_lua_key(pop);\ - make_lua_key(post);\ - make_lua_key(post_linebreak);\ -@@ -734,35 +1001,71 @@ make_lua_key(pre_adjust_head);\ - make_lua_key(pre_align);\ - make_lua_key(pre_box);\ - make_lua_key(preamble);\ -+make_lua_key(prefix);\ - make_lua_key(pretolerance);\ - make_lua_key(prev);\ - make_lua_key(prevdepth);\ - make_lua_key(prevgraf);\ -+make_lua_key(protected);\ - make_lua_key(protrudechars);\ -+make_lua_key(protrusion);\ -+make_lua_key(pRTT);\ -+make_lua_key(pseudo_file);\ -+make_lua_key(pseudo_line);\ - make_lua_key(psname);\ -+make_lua_key(pTLT);\ - make_lua_key(ptr);\ -+make_lua_key(pTRT);\ -+make_lua_key(punct);\ - make_lua_key(push);\ - make_lua_key(quad);\ - make_lua_key(radical);\ - make_lua_key(raw);\ -+make_lua_key(read_to_cs);\ -+make_lua_key(recompress);\ - make_lua_key(ref_count);\ - make_lua_key(reg);\ -+make_lua_key(register);\ - make_lua_key(registry);\ -+make_lua_key(regular);\ -+make_lua_key(rel);\ -+make_lua_key(relax);\ -+make_lua_key(remove_item);\ - make_lua_key(renew);\ - make_lua_key(rep);\ - make_lua_key(replace);\ - make_lua_key(resources);\ - make_lua_key(right);\ - make_lua_key(right_boundary);\ -+make_lua_key(right_brace);\ - make_lua_key(right_protruding);\ - make_lua_key(rightskip);\ - make_lua_key(rotation);\ -+make_lua_key(RTT);\ - make_lua_key(rule);\ -+make_lua_key(save_pos);\ - make_lua_key(scale);\ - make_lua_key(script);\ - make_lua_key(scriptscript);\ -+make_lua_key(second);\ - make_lua_key(semi_simple);\ -+make_lua_key(set);\ -+make_lua_key(set_aux);\ -+make_lua_key(set_box);\ -+make_lua_key(set_box_dimen);\ -+make_lua_key(set_etex_shape);\ -+make_lua_key(set_font);\ -+make_lua_key(set_font_id);\ -+make_lua_key(set_interaction);\ -+make_lua_key(set_math_param);\ -+make_lua_key(set_page_dimen);\ -+make_lua_key(set_page_int);\ -+make_lua_key(set_prev_graf);\ -+make_lua_key(set_tex_shape);\ -+make_lua_key(shape);\ -+make_lua_key(shape_ref);\ - make_lua_key(shift);\ -+make_lua_key(shorthand_def);\ - make_lua_key(shrink);\ - make_lua_key(shrink_order);\ - make_lua_key(simple);\ -@@ -776,13 +1079,22 @@ make_lua_key(space);\ - make_lua_key(space_shrink);\ - make_lua_key(space_stretch);\ - make_lua_key(spacefactor);\ -+make_lua_key(spacer);\ -+make_lua_key(spaceskip);\ -+make_lua_key(span);\ -+make_lua_key(spec);\ - make_lua_key(special);\ - make_lua_key(split_discards_head);\ -+make_lua_key(split_insert);\ - make_lua_key(split_keep);\ - make_lua_key(split_off);\ -+make_lua_key(splittopskip);\ -+make_lua_key(squeeze);\ - make_lua_key(stack);\ - make_lua_key(start);\ -+make_lua_key(start_par);\ - make_lua_key(step);\ -+make_lua_key(stop);\ - make_lua_key(stream);\ - make_lua_key(streamfile);\ - make_lua_key(streamprovider);\ -@@ -791,72 +1103,122 @@ make_lua_key(stretch_order);\ - make_lua_key(string);\ - make_lua_key(style);\ - make_lua_key(sub);\ -+make_lua_key(sub_box);\ -+make_lua_key(sub_mark);\ -+make_lua_key(sub_mlist);\ - make_lua_key(subst_ex_font);\ - make_lua_key(subtype);\ - make_lua_key(sup);\ -+make_lua_key(sup_mark);\ -+make_lua_key(super_sub_script);\ - make_lua_key(supplement);\ - make_lua_key(surround);\ -+make_lua_key(tab_mark);\ -+make_lua_key(tabskip);\ - make_lua_key(tail);\ -+make_lua_key(temp);\ - make_lua_key(temp_head);\ - make_lua_key(term);\ - make_lua_key(term_and_log);\ - make_lua_key(tex);\ - make_lua_key(text);\ -+make_lua_key(the);\ -+make_lua_key(thickmuskip);\ -+make_lua_key(thinmuskip);\ -+make_lua_key(thread);\ - make_lua_key(thread_attr);\ - make_lua_key(thread_id);\ --make_lua_key(tolerance);\ -+make_lua_key(TLT);\ - make_lua_key(tok);\ - make_lua_key(token);\ -+make_lua_key(toks_register);\ -+make_lua_key(tolerance);\ - make_lua_key(top);\ - make_lua_key(top_accent);\ -+make_lua_key(top_bot_mark);\ - make_lua_key(top_left);\ - make_lua_key(top_right);\ -+make_lua_key(topskip);\ - make_lua_key(tounicode);\ - make_lua_key(tracingparagraphs);\ - make_lua_key(trailer);\ -+make_lua_key(Trailer);\ - make_lua_key(trailerid);\ - make_lua_key(transform);\ - make_lua_key(trim);\ -+make_lua_key(TRT);\ - make_lua_key(type);\ - make_lua_key(uchyph);\ -+make_lua_key(udelimiterover);\ -+make_lua_key(udelimiterunder);\ -+make_lua_key(un_hbox);\ -+make_lua_key(un_vbox);\ -+make_lua_key(undefined_cs);\ -+make_lua_key(under);\ -+make_lua_key(unhyphenated);\ - make_lua_key(units_per_em);\ -+make_lua_key(unknown);\ -+make_lua_key(unset);\ -+make_lua_key(uoverdelimiter);\ -+make_lua_key(uradical);\ -+make_lua_key(uroot);\ - make_lua_key(used);\ -+make_lua_key(user);\ -+make_lua_key(userpassword);\ -+make_lua_key(user_defined);\ - make_lua_key(user_id);\ -+make_lua_key(userkern);\ -+make_lua_key(userpenalty);\ -+make_lua_key(userskip);\ -+make_lua_key(uunderdelimiter);\ - make_lua_key(v);\ -+make_lua_key(vadjust);\ -+make_lua_key(valign);\ - make_lua_key(value);\ -+make_lua_key(variable);\ - make_lua_key(vbox);\ - make_lua_key(vcenter);\ - make_lua_key(version);\ - make_lua_key(vert_italic);\ - make_lua_key(vert_variants);\ --make_lua_key(vmode_par);\ - make_lua_key(visiblefilename);\ - make_lua_key(vlist);\ -+make_lua_key(vmode_par);\ -+make_lua_key(vmove);\ -+make_lua_key(vrule);\ -+make_lua_key(vskip);\ - make_lua_key(vtop);\ -+make_lua_key(whatsit);\ - make_lua_key(widowpenalty);\ - make_lua_key(width);\ -+make_lua_key(word);\ -+make_lua_key(wordpenalty);\ -+make_lua_key(write); \ -+make_lua_key(writingmode); \ - make_lua_key(x_height);\ - make_lua_key(xadvance);\ --make_lua_key(xformresources);\ - make_lua_key(xformattributes);\ -+make_lua_key(xformresources);\ -+make_lua_key(xleaders);\ -+make_lua_key(xmath_given);\ - make_lua_key(xoffset);\ -+make_lua_key(xray);\ - make_lua_key(xres);\ - make_lua_key(xsize);\ -+make_lua_key(xspaceskip);\ -+make_lua_key(xyz);\ - make_lua_key(xyz_zoom);\ - make_lua_key(yoffset); \ - make_lua_key(yres); \ --make_lua_key(ysize); \ --make_lua_key(writingmode); \ --make_lua_key(__index) -+make_lua_key(ysize); - - #define set_init_keys \ --init_lua_key(cmdname);init_lua_key(expandable);init_lua_key(protected);\ --init_lua_key(LTL);\ --init_lua_key(MathConstants);\ --init_lua_key(RTT);\ --init_lua_key(TLT);\ --init_lua_key(TRT);\ -+init_lua_key(__index);\ -+init_lua_key(above);\ -+init_lua_key(abovedisplayshortskip);\ -+init_lua_key(abovedisplayskip);\ - init_lua_key(accent);\ -+init_lua_key(accentkern);\ - init_lua_key(action);\ - init_lua_key(action_id);\ - init_lua_key(action_type);\ -@@ -868,53 +1230,107 @@ init_lua_key(adjust_head);\ - init_lua_key(adjusted_hbox);\ - init_lua_key(adjustspacing);\ - init_lua_key(advance);\ -+init_lua_key(after_assignment);\ - init_lua_key(after_display);\ -+init_lua_key(after_group);\ - init_lua_key(after_output);\ -+init_lua_key(afterdisplaypenalty);\ - init_lua_key(align);\ - init_lua_key(align_head);\ -+init_lua_key(align_record);\ - init_lua_key(align_set);\ -+init_lua_key(align_stack);\ - init_lua_key(alignment);\ -+init_lua_key(always);\ - init_lua_key(annot);\ - init_lua_key(area);\ - init_lua_key(art);\ -+init_lua_key(assign_attr);\ -+init_lua_key(assign_box_dir);\ -+init_lua_key(assign_box_direction);\ -+init_lua_key(assign_dimen);\ -+init_lua_key(assign_dir);\ -+init_lua_key(assign_direction);\ -+init_lua_key(assign_font_dimen);\ -+init_lua_key(assign_font_int);\ -+init_lua_key(assign_glue);\ -+init_lua_key(assign_hang_indent);\ -+init_lua_key(assign_int);\ -+init_lua_key(assign_local_box);\ -+init_lua_key(assign_mu_glue);\ -+init_lua_key(assign_toks);\ - init_lua_key(attr);\ -+init_lua_key(attribute);\ -+init_lua_key(attribute_list);\ - init_lua_key(attributes);\ -+init_lua_key(automatic);\ -+init_lua_key(baselineskip);\ - init_lua_key(bbox);\ - init_lua_key(before_display);\ -+init_lua_key(beforedisplaypenalty);\ -+init_lua_key(begin_group);\ -+init_lua_key(beginmath);\ -+init_lua_key(belowdisplayshortskip);\ -+init_lua_key(belowdisplayskip);\ - init_lua_key(best_ins_ptr);\ - init_lua_key(best_page_break);\ - init_lua_key(best_size);\ -+init_lua_key(bin);\ - init_lua_key(bleed);\ - init_lua_key(bot);\ - init_lua_key(bot_accent);\ -+init_lua_key(bothflexible);\ - init_lua_key(bottom_left);\ - init_lua_key(bottom_right);\ - init_lua_key(boundary);\ - init_lua_key(box);\ - init_lua_key(box_left);\ - init_lua_key(box_left_width);\ -+init_lua_key(box_ref);\ - init_lua_key(box_right);\ - init_lua_key(box_right_width);\ -+init_lua_key(box_there);\ -+init_lua_key(break_penalty);\ - init_lua_key(broken_ins);\ - init_lua_key(broken_ptr);\ - init_lua_key(brokenpenalty);\ - init_lua_key(cache);\ - init_lua_key(cal_expand_ratio);\ -+init_lua_key(call);\ -+init_lua_key(cancel);\ -+init_lua_key(car_ret);\ -+init_lua_key(case_shift);\ -+init_lua_key(Catalog);\ - init_lua_key(catalog);\ -+init_lua_key(cell);\ - init_lua_key(char);\ -+init_lua_key(char_ghost);\ -+init_lua_key(char_given);\ -+init_lua_key(char_num);\ -+init_lua_key(character);\ - init_lua_key(characters);\ - init_lua_key(checksum);\ -+init_lua_key(choice);\ - init_lua_key(cidinfo);\ - init_lua_key(class);\ -+init_lua_key(cleaders);\ -+init_lua_key(close);\ - init_lua_key(clubpenalty);\ -+init_lua_key(cmd);\ -+init_lua_key(cmdname);\ -+init_lua_key(color_stack);\ - init_lua_key(colordepth);\ - init_lua_key(colorspace);\ -+init_lua_key(combinetoks);\ - init_lua_key(command);\ - init_lua_key(commands);\ - init_lua_key(comment);\ - init_lua_key(components);\ - init_lua_key(compresslevel);\ -+init_lua_key(conditionalmathskip);\ - init_lua_key(contrib_head);\ -+init_lua_key(convert);\ -+init_lua_key(copy_font);\ - init_lua_key(core);\ - init_lua_key(cost);\ - init_lua_key(count);\ -@@ -923,11 +1339,21 @@ init_lua_key(crampedscript);\ - init_lua_key(crampedscriptscript);\ - init_lua_key(crampedtext);\ - init_lua_key(crop);\ -+init_lua_key(cs_name);\ - init_lua_key(csname);\ -+init_lua_key(current);\ - init_lua_key(data);\ -+init_lua_key(def);\ -+init_lua_key(def_char_code);\ -+init_lua_key(def_del_code);\ -+init_lua_key(def_family);\ -+init_lua_key(def_font);\ -+init_lua_key(def_lua_call);\ - init_lua_key(degree);\ - init_lua_key(delim);\ -+init_lua_key(delim_num);\ - init_lua_key(delimptr);\ -+init_lua_key(delta);\ - init_lua_key(demerits);\ - init_lua_key(denom);\ - init_lua_key(depth);\ -@@ -940,45 +1366,91 @@ init_lua_key(direct);\ - init_lua_key(direction);\ - init_lua_key(dirs);\ - init_lua_key(disc);\ -+init_lua_key(discretionary);\ - init_lua_key(display);\ -+init_lua_key(divide);\ -+init_lua_key(dont_expand);\ - init_lua_key(doublehyphendemerits);\ - init_lua_key(down);\ - init_lua_key(embedding);\ - init_lua_key(emergencystretch);\ -+init_lua_key(empty);\ - init_lua_key(encodingbytes);\ - init_lua_key(encodingname);\ - init_lua_key(end);\ --init_lua_key(etex);\ -+init_lua_key(end_cs_name);\ -+init_lua_key(end_group);\ -+init_lua_key(end_template);\ -+init_lua_key(endmath);\ -+init_lua_key(endv);\ -+init_lua_key(eq_no);\ - init_lua_key(equation);\ - init_lua_key(equation_number);\ -+init_lua_key(equationnumber);\ -+init_lua_key(equationnumberpenalty);\ -+init_lua_key(etex);\ -+init_lua_key(ex_space);\ - init_lua_key(exactly);\ -+init_lua_key(expand_after);\ -+init_lua_key(expand_font);\ -+init_lua_key(expandable);\ - init_lua_key(expansion_factor);\ -+init_lua_key(explicit);\ -+init_lua_key(expr_stack);\ - init_lua_key(ext);\ -+init_lua_key(extdef_del_code);\ -+init_lua_key(extdef_math_code);\ - init_lua_key(extend);\ - init_lua_key(extender);\ - init_lua_key(extensible);\ -+init_lua_key(extension);\ - init_lua_key(extra_space);\ - init_lua_key(fam);\ - init_lua_key(fast);\ -+init_lua_key(feedback);\ - init_lua_key(fence);\ -+init_lua_key(fi);\ -+init_lua_key(fi_or_else);\ -+init_lua_key(fil);\ - init_lua_key(file);\ - init_lua_key(filename);\ - init_lua_key(filepath);\ - init_lua_key(fill);\ -+init_lua_key(filll);\ -+init_lua_key(fillll);\ - init_lua_key(fin_row);\ - init_lua_key(finalhyphendemerits);\ -+init_lua_key(finalpenalty);\ -+init_lua_key(first);\ -+init_lua_key(fit);\ -+init_lua_key(fitb);\ -+init_lua_key(fitbh);\ -+init_lua_key(fitbv);\ -+init_lua_key(fith);\ -+init_lua_key(fitr);\ -+init_lua_key(fitv);\ -+init_lua_key(fixedboth);\ -+init_lua_key(fixedbottom);\ -+init_lua_key(fixedtop);\ - init_lua_key(font);\ -+init_lua_key(fontkern);\ - init_lua_key(fonts);\ - init_lua_key(format);\ - init_lua_key(fraction);\ - init_lua_key(fullname);\ -+init_lua_key(ghost);\ -+init_lua_key(gleaders);\ - init_lua_key(global);\ - init_lua_key(glue);\ - init_lua_key(glue_order);\ -+init_lua_key(glue_ref);\ - init_lua_key(glue_set);\ - init_lua_key(glue_sign);\ -+init_lua_key(glue_spec);\ - init_lua_key(glyph);\ -+init_lua_key(goto);\ - init_lua_key(h);\ -+init_lua_key(halign);\ - init_lua_key(hangafter);\ - init_lua_key(hangindent);\ - init_lua_key(hbox);\ -@@ -986,20 +1458,37 @@ init_lua_key(head);\ - init_lua_key(height);\ - init_lua_key(hlist);\ - init_lua_key(hmode_par);\ -+init_lua_key(hmove);\ - init_lua_key(hold_head);\ - init_lua_key(horiz_variants);\ -+init_lua_key(hrule);\ - init_lua_key(hsize);\ -+init_lua_key(hskip);\ -+init_lua_key(hyph_data);\ -+init_lua_key(hyphenated);\ - init_lua_key(hyphenchar);\ - init_lua_key(id);\ - init_lua_key(identity);\ -+init_lua_key(if_stack);\ -+init_lua_key(if_test);\ -+init_lua_key(ignore_spaces);\ - init_lua_key(image);\ - init_lua_key(imagetype);\ - init_lua_key(immediate);\ -+init_lua_key(in_stream);\ -+init_lua_key(indent);\ - init_lua_key(index);\ - init_lua_key(info);\ -+init_lua_key(Info);\ -+init_lua_key(inner);\ -+init_lua_key(input);\ -+init_lua_key(ins);\ - init_lua_key(insert);\ -+init_lua_key(inserts_only);\ - init_lua_key(interlinepenalty);\ -+init_lua_key(ital_corr);\ - init_lua_key(italic);\ -+init_lua_key(italiccorrection);\ - init_lua_key(keepopen);\ - init_lua_key(kern);\ - init_lua_key(kerns);\ -@@ -1007,82 +1496,179 @@ init_lua_key(lang);\ - init_lua_key(large_char);\ - init_lua_key(large_fam);\ - init_lua_key(last_ins_ptr);\ -+init_lua_key(last_item);\ - init_lua_key(lastlinefit);\ --init_lua_key(leftskip);\ -+init_lua_key(late_lua);\ - init_lua_key(leader);\ -+init_lua_key(leader_ship);\ -+init_lua_key(leaders);\ - init_lua_key(least_page_cost);\ - init_lua_key(left);\ - init_lua_key(left_boundary);\ -+init_lua_key(left_brace);\ - init_lua_key(left_protruding);\ -+init_lua_key(left_right);\ - init_lua_key(leftskip);\ -+init_lua_key(let);\ -+init_lua_key(letter);\ -+init_lua_key(letterspace_font);\ - init_lua_key(level);\ -+init_lua_key(ligature);\ - init_lua_key(ligatures);\ --init_lua_key(leftskip);\ -+init_lua_key(limit_switch);\ -+init_lua_key(line);\ -+init_lua_key(linebreakpenalty);\ - init_lua_key(linepenalty);\ -+init_lua_key(lineskip);\ - init_lua_key(link_attr);\ - init_lua_key(list);\ - init_lua_key(local_box);\ -+init_lua_key(local_par);\ - init_lua_key(log);\ -+init_lua_key(long_call);\ -+init_lua_key(long_outer_call);\ - init_lua_key(looseness);\ -+init_lua_key(LTL);\ - init_lua_key(lua);\ -+init_lua_key(lua_bytecode_call);\ - init_lua_key(lua_bytecodes_indirect);\ -+init_lua_key(lua_call);\ -+init_lua_key(lua_expandable_call);\ -+init_lua_key(lua_local_call);\ -+init_lua_key(lua_function_call);\ - init_lua_key(lua_functions);\ - init_lua_key(luatex);\ - init_lua_key(luatex_node);\ - init_lua_key(luatex_token);\ -+init_lua_key(luatex_pdfe);\ -+init_lua_key(luatex_pdfe_dictionary);\ -+init_lua_key(luatex_pdfe_array);\ -+init_lua_key(luatex_pdfe_stream);\ -+init_lua_key(luatex_pdfe_reference);\ -+init_lua_key(mac_param);\ -+init_lua_key(make_box);\ -+init_lua_key(margin_kern);\ - init_lua_key(marginkern);\ - init_lua_key(mark);\ - init_lua_key(math);\ -+init_lua_key(math_accent);\ -+init_lua_key(math_char);\ -+init_lua_key(math_char_num);\ - init_lua_key(math_choice);\ -+init_lua_key(math_comp);\ -+init_lua_key(math_given);\ - init_lua_key(math_left);\ - init_lua_key(math_shift);\ -+init_lua_key(math_shift_cs);\ -+init_lua_key(math_style);\ -+init_lua_key(math_sub_box);\ -+init_lua_key(math_sub_mlist);\ -+init_lua_key(math_text_char);\ -+init_lua_key(MathConstants);\ - init_lua_key(mathdir);\ - init_lua_key(mathkern);\ -+init_lua_key(mathskip);\ - init_lua_key(mathstyle);\ - init_lua_key(media);\ -+init_lua_key(medmuskip);\ -+init_lua_key(message);\ - init_lua_key(mid);\ - init_lua_key(middle);\ -+init_lua_key(mkern);\ - init_lua_key(mode);\ - init_lua_key(modeline);\ -+init_lua_key(movement_stack);\ -+init_lua_key(mskip);\ -+init_lua_key(muglue);\ -+init_lua_key(multiply);\ - init_lua_key(name);\ - init_lua_key(named_id);\ - init_lua_key(names);\ -+init_lua_key(nested_list);\ -+init_lua_key(new);\ - init_lua_key(new_graf);\ - init_lua_key(new_window);\ - init_lua_key(next);\ - init_lua_key(no);\ -+init_lua_key(nolength);\ - init_lua_key(no_align);\ -+init_lua_key(no_expand);\ -+init_lua_key(no_super_sub_script);\ - init_lua_key(noad);\ -+init_lua_key(noadpenalty);\ - init_lua_key(node);\ -+init_lua_key(nohrule);\ - init_lua_key(nomath);\ -+init_lua_key(non_script);\ - init_lua_key(none);\ -+init_lua_key(nonew);\ - init_lua_key(nop);\ -+init_lua_key(normal);\ -+init_lua_key(novrule);\ - init_lua_key(nucleus);\ - init_lua_key(num);\ - init_lua_key(number);\ - init_lua_key(objcompression);\ - init_lua_key(objnum);\ - init_lua_key(oldmath);\ -+init_lua_key(omit);\ -+init_lua_key(opdisplaylimits);\ -+init_lua_key(open);\ -+init_lua_key(oplimits);\ -+init_lua_key(opnolimits);\ -+init_lua_key(option);\ - init_lua_key(options);\ -+init_lua_key(ord);\ -+init_lua_key(ordering);\ - init_lua_key(orientation);\ - init_lua_key(origin);\ --init_lua_key(ordering);\ -+init_lua_key(other_char);\ -+init_lua_key(outer_call);\ -+init_lua_key(outline);\ - init_lua_key(output);\ -+init_lua_key(over);\ - init_lua_key(overlay_accent);\ -+init_lua_key(ownerpassword);\ - init_lua_key(page);\ --init_lua_key(pages);\ - init_lua_key(page_discards_head);\ - init_lua_key(page_head);\ - init_lua_key(page_ins_head);\ -+init_lua_key(page_insert);\ - init_lua_key(pageattributes);\ - init_lua_key(pagebox);\ - init_lua_key(pageresources);\ -+init_lua_key(pages);\ -+init_lua_key(Pages);\ - init_lua_key(pagesattributes);\ -+init_lua_key(pagestate);\ -+init_lua_key(par_end);\ - init_lua_key(parameters);\ - init_lua_key(pardir);\ -+init_lua_key(parfillskip);\ - init_lua_key(parshape);\ -+init_lua_key(parskip);\ -+init_lua_key(passive);\ -+init_lua_key(pdfe);\ -+init_lua_key(pdf_action);\ -+init_lua_key(pdf_annot);\ -+init_lua_key(pdf_colorstack);\ -+init_lua_key(pdf_dest);\ - init_lua_key(pdf_destination);\ -+init_lua_key(pdf_end_link);\ -+init_lua_key(pdf_end_thread);\ -+init_lua_key(pdf_link_data);\ - init_lua_key(pdf_literal);\ -+init_lua_key(pdf_refobj);\ -+init_lua_key(pdf_restore);\ -+init_lua_key(pdf_save);\ -+init_lua_key(pdf_setmatrix);\ -+init_lua_key(pdf_setobj);\ -+init_lua_key(pdf_start);\ -+init_lua_key(pdf_start_link);\ -+init_lua_key(pdf_start_thread);\ -+init_lua_key(pdf_thread);\ -+init_lua_key(pdf_thread_data);\ -+init_lua_key(pdf_window);\ - init_lua_key(pen_broken);\ - init_lua_key(pen_inter);\ - init_lua_key(penalty);\ -@@ -1095,35 +1681,68 @@ init_lua_key(pre_adjust_head);\ - init_lua_key(pre_align);\ - init_lua_key(pre_box);\ - init_lua_key(preamble);\ -+init_lua_key(prefix);\ - init_lua_key(pretolerance);\ - init_lua_key(prev);\ - init_lua_key(prevdepth);\ - init_lua_key(prevgraf);\ -+init_lua_key(protected);\ - init_lua_key(protrudechars);\ -+init_lua_key(protrusion);\ -+init_lua_key(pseudo_file);\ -+init_lua_key(pseudo_line);\ - init_lua_key(psname);\ - init_lua_key(ptr);\ -+init_lua_key(punct);\ - init_lua_key(push);\ - init_lua_key(quad);\ - init_lua_key(radical);\ - init_lua_key(raw);\ -+init_lua_key(read_to_cs);\ - init_lua_key(ref_count);\ -+init_lua_key(recompress);\ - init_lua_key(reg);\ -+init_lua_key(register);\ - init_lua_key(registry);\ -+init_lua_key(regular);\ -+init_lua_key(rel);\ -+init_lua_key(relax);\ -+init_lua_key(remove_item);\ - init_lua_key(renew);\ - init_lua_key(rep);\ - init_lua_key(replace);\ - init_lua_key(resources);\ - init_lua_key(right);\ - init_lua_key(right_boundary);\ -+init_lua_key(right_brace);\ - init_lua_key(right_protruding);\ - init_lua_key(rightskip);\ - init_lua_key(rotation);\ -+init_lua_key(RTT);\ - init_lua_key(rule);\ -+init_lua_key(save_pos);\ - init_lua_key(scale);\ - init_lua_key(script);\ - init_lua_key(scriptscript);\ -+init_lua_key(second);\ - init_lua_key(semi_simple);\ -+init_lua_key(set);\ -+init_lua_key(set_aux);\ -+init_lua_key(set_box);\ -+init_lua_key(set_box_dimen);\ -+init_lua_key(set_etex_shape);\ -+init_lua_key(set_font);\ -+init_lua_key(set_font_id);\ -+init_lua_key(set_interaction);\ -+init_lua_key(set_math_param);\ -+init_lua_key(set_page_dimen);\ -+init_lua_key(set_page_int);\ -+init_lua_key(set_prev_graf);\ -+init_lua_key(set_tex_shape);\ -+init_lua_key(shape);\ -+init_lua_key(shape_ref);\ - init_lua_key(shift);\ -+init_lua_key(shorthand_def);\ - init_lua_key(shrink);\ - init_lua_key(shrink_order);\ - init_lua_key(simple);\ -@@ -1137,13 +1756,22 @@ init_lua_key(space);\ - init_lua_key(space_shrink);\ - init_lua_key(space_stretch);\ - init_lua_key(spacefactor);\ -+init_lua_key(spacer);\ -+init_lua_key(spaceskip);\ -+init_lua_key(span);\ -+init_lua_key(spec);\ - init_lua_key(special);\ - init_lua_key(split_discards_head);\ -+init_lua_key(split_insert);\ - init_lua_key(split_keep);\ - init_lua_key(split_off);\ -+init_lua_key(splittopskip);\ -+init_lua_key(squeeze);\ - init_lua_key(stack);\ - init_lua_key(start);\ -+init_lua_key(start_par);\ - init_lua_key(step);\ -+init_lua_key(stop);\ - init_lua_key(stream);\ - init_lua_key(streamfile);\ - init_lua_key(streamprovider);\ -@@ -1152,67 +1780,123 @@ init_lua_key(stretch_order);\ - init_lua_key(string);\ - init_lua_key(style);\ - init_lua_key(sub);\ -+init_lua_key(sub_box);\ -+init_lua_key(sub_mark);\ -+init_lua_key(sub_mlist);\ - init_lua_key(subst_ex_font);\ - init_lua_key(subtype);\ - init_lua_key(sup);\ -+init_lua_key(sup_mark);\ -+init_lua_key(super_sub_script);\ - init_lua_key(supplement);\ - init_lua_key(surround);\ -+init_lua_key(tab_mark);\ -+init_lua_key(tabskip);\ - init_lua_key(tail);\ -+init_lua_key(temp);\ - init_lua_key(temp_head);\ - init_lua_key(term);\ - init_lua_key(tex);\ - init_lua_key(text);\ -+init_lua_key(the);\ -+init_lua_key(thickmuskip);\ -+init_lua_key(thinmuskip);\ -+init_lua_key(thread);\ - init_lua_key(thread_attr);\ - init_lua_key(thread_id);\ --init_lua_key(tolerance);\ -+init_lua_key(TLT);\ - init_lua_key(tok);\ - init_lua_key(token);\ -+init_lua_key(toks_register);\ -+init_lua_key(tolerance);\ - init_lua_key(top);\ - init_lua_key(top_accent);\ -+init_lua_key(top_bot_mark);\ - init_lua_key(top_left);\ - init_lua_key(top_right);\ -+init_lua_key(topskip);\ - init_lua_key(tounicode);\ - init_lua_key(tracingparagraphs);\ - init_lua_key(trailer);\ -+init_lua_key(Trailer);\ - init_lua_key(trailerid);\ - init_lua_key(transform);\ - init_lua_key(trim);\ -+init_lua_key(TRT);\ - init_lua_key(type);\ - init_lua_key(uchyph);\ -+init_lua_key(udelimiterover);\ -+init_lua_key(udelimiterunder);\ -+init_lua_key(un_hbox);\ -+init_lua_key(un_vbox);\ -+init_lua_key(undefined_cs);\ -+init_lua_key(under);\ -+init_lua_key(unhyphenated);\ - init_lua_key(units_per_em);\ -+init_lua_key(unknown);\ -+init_lua_key(unset);\ -+init_lua_key(uoverdelimiter);\ -+init_lua_key(uradical);\ -+init_lua_key(uroot);\ - init_lua_key(used);\ -+init_lua_key(user);\ -+init_lua_key(userpassword);\ -+init_lua_key(user_defined);\ - init_lua_key(user_id);\ -+init_lua_key(userkern);\ -+init_lua_key(userpenalty);\ -+init_lua_key(userskip);\ -+init_lua_key(uunderdelimiter);\ - init_lua_key(v);\ -+init_lua_key(vadjust);\ -+init_lua_key(valign);\ - init_lua_key(value);\ -+init_lua_key(variable);\ - init_lua_key(vbox);\ - init_lua_key(vcenter);\ - init_lua_key(version);\ - init_lua_key(vert_italic);\ - init_lua_key(vert_variants);\ --init_lua_key(vmode_par);\ - init_lua_key(visiblefilename);\ - init_lua_key(vlist);\ -+init_lua_key(vmode_par);\ -+init_lua_key(vmove);\ -+init_lua_key(vrule);\ -+init_lua_key(vskip);\ - init_lua_key(vtop);\ -+init_lua_key(whatsit);\ - init_lua_key(widowpenalty);\ - init_lua_key(width);\ -+init_lua_key(word);\ -+init_lua_key(wordpenalty);\ -+init_lua_key(write);\ -+init_lua_key(writingmode);\ - init_lua_key(x_height);\ - init_lua_key(xadvance);\ --init_lua_key(xformresources);\ - init_lua_key(xformattributes);\ -+init_lua_key(xformresources);\ -+init_lua_key(xleaders);\ -+init_lua_key(xmath_given);\ - init_lua_key(xoffset);\ -+init_lua_key(xray);\ - init_lua_key(xres);\ - init_lua_key(xsize);\ -+init_lua_key(xspaceskip);\ -+init_lua_key(xyz);\ - init_lua_key(xyz_zoom);\ - init_lua_key(yoffset);\ - init_lua_key(yres);\ - init_lua_key(ysize);\ --init_lua_key(writingmode);\ --init_lua_key(__index);\ - init_lua_key_alias(empty_string,"");\ - init_lua_key_alias(lua_bytecodes_indirect,"lua.bytecodes.indirect");\ - init_lua_key_alias(lua_functions,"lua.functions");\ - init_lua_key_alias(luatex_node, "luatex.node");\ - init_lua_key_alias(luatex_token, "luatex.token");\ -+init_lua_key_alias(luatex_pdfe, "luatex.pdfe");\ -+init_lua_key_alias(luatex_pdfe_dictionary, "luatex.pdfe.dictionary");\ -+init_lua_key_alias(luatex_pdfe_array, "luatex.pdfe.array");\ -+init_lua_key_alias(luatex_pdfe_stream, "luatex.pdfe.stream");\ -+init_lua_key_alias(luatex_pdfe_reference, "luatex.pdfe.reference");\ - init_lua_key_alias(mLTL,"-LTL");\ - init_lua_key_alias(mRTT,"-RTT");\ - init_lua_key_alias(mTLT,"-TLT");\ -@@ -1268,14 +1952,12 @@ extern FILE *_cairo_win_tmpfile( void ); - /* These keys have to available to different files */ - /* */ - --use_lua_key(cmdname);use_lua_key(expandable);use_lua_key(protected); -- --use_lua_key(LTL); --use_lua_key(MathConstants); --use_lua_key(RTT); --use_lua_key(TLT); --use_lua_key(TRT); -+use_lua_key(__index); -+use_lua_key(above); -+use_lua_key(abovedisplayshortskip); -+use_lua_key(abovedisplayskip); - use_lua_key(accent); -+use_lua_key(accentkern); - use_lua_key(action); - use_lua_key(action_id); - use_lua_key(action_type); -@@ -1287,53 +1969,107 @@ use_lua_key(adjust_head); - use_lua_key(adjusted_hbox); - use_lua_key(adjustspacing); - use_lua_key(advance); -+use_lua_key(after_assignment); - use_lua_key(after_display); -+use_lua_key(after_group); - use_lua_key(after_output); -+use_lua_key(afterdisplaypenalty); - use_lua_key(align); - use_lua_key(align_head); -+use_lua_key(align_record); - use_lua_key(align_set); -+use_lua_key(align_stack); - use_lua_key(alignment); -+use_lua_key(always); - use_lua_key(annot); - use_lua_key(area); - use_lua_key(art); -+use_lua_key(assign_attr); -+use_lua_key(assign_box_dir); -+use_lua_key(assign_box_direction); -+use_lua_key(assign_dimen); -+use_lua_key(assign_dir); -+use_lua_key(assign_direction); -+use_lua_key(assign_font_dimen); -+use_lua_key(assign_font_int); -+use_lua_key(assign_glue); -+use_lua_key(assign_hang_indent); -+use_lua_key(assign_int); -+use_lua_key(assign_local_box); -+use_lua_key(assign_mu_glue); -+use_lua_key(assign_toks); - use_lua_key(attr); -+use_lua_key(attribute); -+use_lua_key(attribute_list); - use_lua_key(attributes); -+use_lua_key(automatic); -+use_lua_key(baselineskip); - use_lua_key(bbox); - use_lua_key(before_display); -+use_lua_key(beforedisplaypenalty); -+use_lua_key(begin_group); -+use_lua_key(beginmath); -+use_lua_key(belowdisplayshortskip); -+use_lua_key(belowdisplayskip); - use_lua_key(best_ins_ptr); - use_lua_key(best_page_break); - use_lua_key(best_size); -+use_lua_key(bin); - use_lua_key(bleed); - use_lua_key(bot); - use_lua_key(bot_accent); -+use_lua_key(bothflexible); - use_lua_key(bottom_left); - use_lua_key(bottom_right); - use_lua_key(boundary); - use_lua_key(box); - use_lua_key(box_left); - use_lua_key(box_left_width); -+use_lua_key(box_ref); - use_lua_key(box_right); - use_lua_key(box_right_width); -+use_lua_key(box_there); -+use_lua_key(break_penalty); - use_lua_key(broken_ins); - use_lua_key(broken_ptr); - use_lua_key(brokenpenalty); - use_lua_key(cache); - use_lua_key(cal_expand_ratio); -+use_lua_key(call); -+use_lua_key(cancel); -+use_lua_key(car_ret); -+use_lua_key(case_shift); -+use_lua_key(Catalog); - use_lua_key(catalog); -+use_lua_key(cell); - use_lua_key(char); -+use_lua_key(char_ghost); -+use_lua_key(char_given); -+use_lua_key(char_num); -+use_lua_key(character); - use_lua_key(characters); - use_lua_key(checksum); -+use_lua_key(choice); - use_lua_key(cidinfo); - use_lua_key(class); -+use_lua_key(cleaders); -+use_lua_key(close); - use_lua_key(clubpenalty); -+use_lua_key(cmd); -+use_lua_key(cmdname); -+use_lua_key(color_stack); - use_lua_key(colordepth); - use_lua_key(colorspace); -+use_lua_key(combinetoks); - use_lua_key(command); - use_lua_key(commands); - use_lua_key(comment); - use_lua_key(components); - use_lua_key(compresslevel); -+use_lua_key(conditionalmathskip); - use_lua_key(contrib_head); -+use_lua_key(convert); -+use_lua_key(copy_font); - use_lua_key(core); - use_lua_key(cost); - use_lua_key(count); -@@ -1342,11 +2078,21 @@ use_lua_key(crampedscript); - use_lua_key(crampedscriptscript); - use_lua_key(crampedtext); - use_lua_key(crop); -+use_lua_key(cs_name); - use_lua_key(csname); -+use_lua_key(current); - use_lua_key(data); -+use_lua_key(def); -+use_lua_key(def_char_code); -+use_lua_key(def_del_code); -+use_lua_key(def_family); -+use_lua_key(def_font); -+use_lua_key(def_lua_call); - use_lua_key(degree); - use_lua_key(delim); -+use_lua_key(delim_num); - use_lua_key(delimptr); -+use_lua_key(delta); - use_lua_key(demerits); - use_lua_key(denom); - use_lua_key(depth); -@@ -1359,46 +2105,92 @@ use_lua_key(direct); - use_lua_key(direction); - use_lua_key(dirs); - use_lua_key(disc); -+use_lua_key(discretionary); - use_lua_key(display); -+use_lua_key(divide); -+use_lua_key(dont_expand); - use_lua_key(doublehyphendemerits); - use_lua_key(down); - use_lua_key(embedding); - use_lua_key(emergencystretch); -+use_lua_key(empty); - use_lua_key(empty_string); - use_lua_key(encodingbytes); - use_lua_key(encodingname); - use_lua_key(end); --use_lua_key(etex); -+use_lua_key(end_cs_name); -+use_lua_key(end_group); -+use_lua_key(end_template); -+use_lua_key(endmath); -+use_lua_key(endv); -+use_lua_key(eq_no); - use_lua_key(equation);\ - use_lua_key(equation_number);\ -+use_lua_key(equationnumber); -+use_lua_key(equationnumberpenalty); -+use_lua_key(etex); -+use_lua_key(ex_space); - use_lua_key(exactly); -+use_lua_key(expand_after); -+use_lua_key(expand_font); -+use_lua_key(expandable); - use_lua_key(expansion_factor); -+use_lua_key(explicit); -+use_lua_key(expr_stack); - use_lua_key(ext); -+use_lua_key(extdef_del_code); -+use_lua_key(extdef_math_code); - use_lua_key(extend); - use_lua_key(extender); - use_lua_key(extensible); -+use_lua_key(extension); - use_lua_key(extra_space); - use_lua_key(fam); - use_lua_key(fast); -+use_lua_key(feedback); - use_lua_key(fence); -+use_lua_key(fi); -+use_lua_key(fi_or_else); -+use_lua_key(fil); - use_lua_key(file); - use_lua_key(filename); - use_lua_key(filepath); - use_lua_key(fill); -+use_lua_key(filll); -+use_lua_key(fillll); - use_lua_key(fin_row); - use_lua_key(finalhyphendemerits); -+use_lua_key(finalpenalty); -+use_lua_key(first); -+use_lua_key(fit); -+use_lua_key(fitb); -+use_lua_key(fitbh); -+use_lua_key(fitbv); -+use_lua_key(fith); -+use_lua_key(fitr); -+use_lua_key(fitv); -+use_lua_key(fixedboth); -+use_lua_key(fixedbottom); -+use_lua_key(fixedtop); - use_lua_key(font); -+use_lua_key(fontkern); - use_lua_key(fonts); - use_lua_key(format); - use_lua_key(fraction); - use_lua_key(fullname); -+use_lua_key(ghost); -+use_lua_key(gleaders); - use_lua_key(global); - use_lua_key(glue); - use_lua_key(glue_order); -+use_lua_key(glue_ref); - use_lua_key(glue_set); - use_lua_key(glue_sign); -+use_lua_key(glue_spec); - use_lua_key(glyph); -+use_lua_key(goto); - use_lua_key(h); -+use_lua_key(halign); - use_lua_key(hangafter); - use_lua_key(hangindent); - use_lua_key(hbox); -@@ -1406,20 +2198,37 @@ use_lua_key(head); - use_lua_key(height); - use_lua_key(hlist); - use_lua_key(hmode_par); -+use_lua_key(hmove); - use_lua_key(hold_head); - use_lua_key(horiz_variants); -+use_lua_key(hrule); - use_lua_key(hsize); -+use_lua_key(hskip); -+use_lua_key(hyph_data); -+use_lua_key(hyphenated); - use_lua_key(hyphenchar); - use_lua_key(id); - use_lua_key(identity); -+use_lua_key(if_stack); -+use_lua_key(if_test); -+use_lua_key(ignore_spaces); - use_lua_key(image); - use_lua_key(imagetype); - use_lua_key(immediate); -+use_lua_key(in_stream); -+use_lua_key(indent); - use_lua_key(index); - use_lua_key(info); -+use_lua_key(Info); -+use_lua_key(inner); -+use_lua_key(input); -+use_lua_key(ins); - use_lua_key(insert); -+use_lua_key(inserts_only); - use_lua_key(interlinepenalty); -+use_lua_key(ital_corr); - use_lua_key(italic); -+use_lua_key(italiccorrection); - use_lua_key(keepopen); - use_lua_key(kern); - use_lua_key(kerns); -@@ -1427,95 +2236,191 @@ use_lua_key(lang); - use_lua_key(large_char); - use_lua_key(large_fam); - use_lua_key(last_ins_ptr); -+use_lua_key(last_item); - use_lua_key(lastlinefit); -+use_lua_key(late_lua); - use_lua_key(leader); -+use_lua_key(leader_ship); -+use_lua_key(leaders); - use_lua_key(least_page_cost); - use_lua_key(left); - use_lua_key(left_boundary); -+use_lua_key(left_brace); - use_lua_key(left_protruding); -+use_lua_key(left_right); - use_lua_key(leftskip); -+use_lua_key(let); -+use_lua_key(letter); -+use_lua_key(letterspace_font); - use_lua_key(level); -+use_lua_key(ligature); - use_lua_key(ligatures); -+use_lua_key(limit_switch); -+use_lua_key(line); -+use_lua_key(linebreakpenalty); - use_lua_key(linepenalty); -+use_lua_key(lineskip); - use_lua_key(link_attr); - use_lua_key(list); - use_lua_key(local_box); -+use_lua_key(local_par); - use_lua_key(log); -+use_lua_key(long_call); -+use_lua_key(long_outer_call); - use_lua_key(looseness); -+use_lua_key(LTL); - use_lua_key(lua); -+use_lua_key(lua_bytecode_call); - use_lua_key(lua_bytecodes_indirect); -+use_lua_key(lua_call); -+use_lua_key(lua_expandable_call); -+use_lua_key(lua_local_call); -+use_lua_key(lua_function_call); - use_lua_key(lua_functions); - use_lua_key(luatex); - use_lua_key(luatex_node); - use_lua_key(luatex_token); --use_lua_key(mLTL); --use_lua_key(mRTT); --use_lua_key(mTLT); --use_lua_key(mTRT); -+use_lua_key(luatex_pdfe); -+use_lua_key(luatex_pdfe_dictionary); -+use_lua_key(luatex_pdfe_array); -+use_lua_key(luatex_pdfe_stream); -+use_lua_key(luatex_pdfe_reference); -+use_lua_key(mac_param); -+use_lua_key(make_box); -+use_lua_key(margin_kern); - use_lua_key(marginkern); - use_lua_key(mark); - use_lua_key(math); -+use_lua_key(math_accent); -+use_lua_key(math_char); -+use_lua_key(math_char_num); - use_lua_key(math_choice); -+use_lua_key(math_comp); -+use_lua_key(math_given); - use_lua_key(math_left); - use_lua_key(math_shift); -+use_lua_key(math_shift_cs); -+use_lua_key(math_style); -+use_lua_key(math_sub_box); -+use_lua_key(math_sub_mlist); -+use_lua_key(math_text_char); -+use_lua_key(MathConstants); - use_lua_key(mathdir); - use_lua_key(mathkern); -+use_lua_key(mathskip); - use_lua_key(mathstyle); - use_lua_key(media); -+use_lua_key(medmuskip); -+use_lua_key(message); - use_lua_key(mid); - use_lua_key(middle); -+use_lua_key(mkern); -+use_lua_key(mLTL); - use_lua_key(mode); - use_lua_key(modeline); -+use_lua_key(movement_stack); -+use_lua_key(mRTT); -+use_lua_key(mskip); -+use_lua_key(mTLT); -+use_lua_key(mTRT); -+use_lua_key(muglue); -+use_lua_key(multiply); - use_lua_key(name); - use_lua_key(named_id); - use_lua_key(names); -+use_lua_key(nested_list); -+use_lua_key(new); - use_lua_key(new_graf); - use_lua_key(new_window); - use_lua_key(next); - use_lua_key(no); -+use_lua_key(nolength); - use_lua_key(no_align); -+use_lua_key(no_expand); -+use_lua_key(no_super_sub_script); - use_lua_key(noad); -+use_lua_key(noadpenalty); - use_lua_key(node); - use_lua_key(node_properties); - use_lua_key(node_properties_indirect); -+use_lua_key(nohrule); - use_lua_key(nomath); -+use_lua_key(non_script); - use_lua_key(none); -+use_lua_key(nonew); - use_lua_key(nop); -+use_lua_key(normal); -+use_lua_key(novrule); - use_lua_key(nucleus); - use_lua_key(num); - use_lua_key(number); - use_lua_key(objcompression); - use_lua_key(objnum); - use_lua_key(oldmath); -+use_lua_key(omit); -+use_lua_key(opdisplaylimits); -+use_lua_key(open); -+use_lua_key(oplimits); -+use_lua_key(opnolimits); -+use_lua_key(option); - use_lua_key(options); -+use_lua_key(ord); -+use_lua_key(ordering); - use_lua_key(orientation); - use_lua_key(origin); --use_lua_key(ordering); -+use_lua_key(other_char); -+use_lua_key(outer_call); -+use_lua_key(outline); - use_lua_key(output); -+use_lua_key(over); - use_lua_key(overlay_accent); --use_lua_key(pLTL); --use_lua_key(pRTT); --use_lua_key(pTLT); --use_lua_key(pTRT); -+use_lua_key(ownerpassword); - use_lua_key(page); --use_lua_key(pages); - use_lua_key(page_discards_head); - use_lua_key(page_head); - use_lua_key(page_ins_head); --use_lua_key(pagebox); -+use_lua_key(page_insert); - use_lua_key(pageattributes); -+use_lua_key(pagebox); - use_lua_key(pageresources); -+use_lua_key(pages); -+use_lua_key(Pages); - use_lua_key(pagesattributes); -+use_lua_key(pagestate); -+use_lua_key(par_end); - use_lua_key(parameters); - use_lua_key(pardir); -+use_lua_key(parfillskip); - use_lua_key(parshape); -+use_lua_key(parskip); -+use_lua_key(passive); - use_lua_key(pdf); -+use_lua_key(pdfe); -+use_lua_key(pdf_action); -+use_lua_key(pdf_annot); -+use_lua_key(pdf_colorstack); - use_lua_key(pdf_data); -+use_lua_key(pdf_dest); - use_lua_key(pdf_destination); -+use_lua_key(pdf_end_link); -+use_lua_key(pdf_end_thread); -+use_lua_key(pdf_link_data); - use_lua_key(pdf_literal); -+use_lua_key(pdf_refobj); -+use_lua_key(pdf_restore); -+use_lua_key(pdf_save); -+use_lua_key(pdf_setmatrix); -+use_lua_key(pdf_setobj); -+use_lua_key(pdf_start); -+use_lua_key(pdf_start_link); -+use_lua_key(pdf_start_thread); -+use_lua_key(pdf_thread); -+use_lua_key(pdf_thread_data); -+use_lua_key(pdf_window); - use_lua_key(pen_broken); - use_lua_key(pen_inter); - use_lua_key(penalty); -+use_lua_key(pLTL); - use_lua_key(pop); - use_lua_key(post); - use_lua_key(post_linebreak); -@@ -1525,35 +2430,71 @@ use_lua_key(pre_adjust_head); - use_lua_key(pre_align); - use_lua_key(pre_box); - use_lua_key(preamble); -+use_lua_key(prefix); - use_lua_key(pretolerance); - use_lua_key(prev); - use_lua_key(prevdepth); - use_lua_key(prevgraf); -+use_lua_key(protected); - use_lua_key(protrudechars); -+use_lua_key(protrusion); -+use_lua_key(pRTT); -+use_lua_key(pseudo_file); -+use_lua_key(pseudo_line); - use_lua_key(psname); -+use_lua_key(pTLT); - use_lua_key(ptr); -+use_lua_key(pTRT); -+use_lua_key(punct); - use_lua_key(push); - use_lua_key(quad); - use_lua_key(radical); - use_lua_key(raw); -+use_lua_key(read_to_cs); - use_lua_key(ref_count); -+use_lua_key(recompress); - use_lua_key(reg); -+use_lua_key(register); - use_lua_key(registry); -+use_lua_key(regular); -+use_lua_key(rel); -+use_lua_key(relax); -+use_lua_key(remove_item); - use_lua_key(renew); - use_lua_key(rep); - use_lua_key(replace); - use_lua_key(resources); - use_lua_key(right); - use_lua_key(right_boundary); -+use_lua_key(right_brace); - use_lua_key(right_protruding); - use_lua_key(rightskip); - use_lua_key(rotation); -+use_lua_key(RTT); - use_lua_key(rule); -+use_lua_key(save_pos); - use_lua_key(scale); - use_lua_key(script); - use_lua_key(scriptscript); -+use_lua_key(second); - use_lua_key(semi_simple); -+use_lua_key(set); -+use_lua_key(set_aux); -+use_lua_key(set_box); -+use_lua_key(set_box_dimen); -+use_lua_key(set_etex_shape); -+use_lua_key(set_font); -+use_lua_key(set_font_id); -+use_lua_key(set_interaction); -+use_lua_key(set_math_param); -+use_lua_key(set_page_dimen); -+use_lua_key(set_page_int); -+use_lua_key(set_prev_graf); -+use_lua_key(set_tex_shape); -+use_lua_key(shape); -+use_lua_key(shape_ref); - use_lua_key(shift); -+use_lua_key(shorthand_def); - use_lua_key(shrink); - use_lua_key(shrink_order); - use_lua_key(simple); -@@ -1567,13 +2508,22 @@ use_lua_key(space); - use_lua_key(space_shrink); - use_lua_key(space_stretch); - use_lua_key(spacefactor); -+use_lua_key(spacer); -+use_lua_key(spaceskip); -+use_lua_key(span); -+use_lua_key(spec); - use_lua_key(special); - use_lua_key(split_discards_head); -+use_lua_key(split_insert); - use_lua_key(split_keep); - use_lua_key(split_off); -+use_lua_key(splittopskip); -+use_lua_key(squeeze); - use_lua_key(stack); - use_lua_key(start); -+use_lua_key(start_par); - use_lua_key(step); -+use_lua_key(stop); - use_lua_key(stream); - use_lua_key(streamfile); - use_lua_key(streamprovider); -@@ -1582,60 +2532,111 @@ use_lua_key(stretch_order); - use_lua_key(string); - use_lua_key(style); - use_lua_key(sub); -+use_lua_key(sub_box); -+use_lua_key(sub_mark); -+use_lua_key(sub_mlist); - use_lua_key(subst_ex_font); - use_lua_key(subtype); - use_lua_key(sup); -+use_lua_key(sup_mark); -+use_lua_key(super_sub_script); - use_lua_key(supplement); - use_lua_key(surround); -+use_lua_key(tab_mark); -+use_lua_key(tabskip); - use_lua_key(tail); -+use_lua_key(temp); - use_lua_key(temp_head); - use_lua_key(term); - use_lua_key(term_and_log); - use_lua_key(tex); - use_lua_key(text); -+use_lua_key(the); -+use_lua_key(thickmuskip); -+use_lua_key(thinmuskip); -+use_lua_key(thread); - use_lua_key(thread_attr); - use_lua_key(thread_id); --use_lua_key(tolerance); -+use_lua_key(TLT); - use_lua_key(tok); - use_lua_key(token); -+use_lua_key(toks_register); -+use_lua_key(tolerance); - use_lua_key(top); - use_lua_key(top_accent); -+use_lua_key(top_bot_mark); - use_lua_key(top_left); - use_lua_key(top_right); -+use_lua_key(topskip); - use_lua_key(tounicode); - use_lua_key(tracingparagraphs); - use_lua_key(trailer); -+use_lua_key(Trailer); - use_lua_key(trailerid); - use_lua_key(transform); - use_lua_key(trim); -+use_lua_key(TRT); - use_lua_key(type); - use_lua_key(uchyph); -+use_lua_key(udelimiterover); -+use_lua_key(udelimiterunder); -+use_lua_key(un_hbox); -+use_lua_key(un_vbox); -+use_lua_key(undefined_cs); -+use_lua_key(under); -+use_lua_key(unhyphenated); - use_lua_key(units_per_em); -+use_lua_key(unknown); -+use_lua_key(unset); -+use_lua_key(uoverdelimiter); -+use_lua_key(uradical); -+use_lua_key(uroot); - use_lua_key(used); -+use_lua_key(user); -+use_lua_key(userpassword); -+use_lua_key(user_defined); - use_lua_key(user_id); -+use_lua_key(userkern); -+use_lua_key(userpenalty); -+use_lua_key(userskip); -+use_lua_key(uunderdelimiter); - use_lua_key(v); -+use_lua_key(vadjust); -+use_lua_key(valign); - use_lua_key(value); -+use_lua_key(variable); - use_lua_key(vbox); - use_lua_key(vcenter); - use_lua_key(version); - use_lua_key(vert_italic); - use_lua_key(vert_variants); --use_lua_key(vmode_par); - use_lua_key(visiblefilename); - use_lua_key(vlist); -+use_lua_key(vmode_par); -+use_lua_key(vmove); -+use_lua_key(vrule); -+use_lua_key(vskip); - use_lua_key(vtop); -+use_lua_key(whatsit); - use_lua_key(widowpenalty); - use_lua_key(width); -+use_lua_key(word); -+use_lua_key(wordpenalty); -+use_lua_key(write); -+use_lua_key(writingmode); - use_lua_key(x_height); - use_lua_key(xadvance); --use_lua_key(xformresources); - use_lua_key(xformattributes); -+use_lua_key(xformresources); -+use_lua_key(xleaders); -+use_lua_key(xmath_given); - use_lua_key(xoffset); -+use_lua_key(xray); - use_lua_key(xres); - use_lua_key(xsize); -+use_lua_key(xspaceskip); -+use_lua_key(xyz); - use_lua_key(xyz_zoom); - use_lua_key(yoffset); - use_lua_key(yres); - use_lua_key(ysize); --use_lua_key(writingmode); --use_lua_key(__index); -diff --git a/texk/web2c/luatexdir/lua/luatex-core.c b/texk/web2c/luatexdir/lua/luatex-core.c -index 6551b0bc4..5cb58af65 100644 ---- a/texk/web2c/luatexdir/lua/luatex-core.c -+++ b/texk/web2c/luatexdir/lua/luatex-core.c -@@ -17,7 +17,7 @@ int load_luatex_core_lua (lua_State * L) - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x5b, 0x27, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x2d, - 0x63, 0x6f, 0x72, 0x65, 0x27, 0x5d, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x31, 0x2e, -- 0x30, 0x30, 0x35, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d, -+ 0x30, 0x38, 0x30, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x27, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x69, - 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x27, 0x2c, 0x0a, 0x2d, - 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, -@@ -27,536 +27,609 @@ int load_luatex_core_lua (lua_State * L) - 0x3d, 0x20, 0x27, 0x4c, 0x75, 0x61, 0x54, 0x65, 0x58, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x27, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, - 0x7d, 0x0a, 0x0a, 0x4c, 0x55, 0x41, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x52, 0x45, 0x56, 0x45, 0x52, -- 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x35, 0x0a, 0x0a, 0x2d, 0x2d, -- 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6c, -- 0x6f, 0x61, 0x64, 0x73, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x4c, 0x75, 0x61, 0x20, 0x66, 0x75, -- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x61, -- 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x70, -- 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x0a, -- 0x2d, 0x2d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, -- 0x20, 0x61, 0x73, 0x20, 0x4c, 0x75, 0x61, 0x54, 0x65, 0x58, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, -- 0x30, 0x34, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x20, -- 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, -- 0x20, 0x75, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x6b, 0x65, 0x65, 0x70, 0x20, 0x74, 0x68, 0x65, 0x0a, -- 0x2d, 0x2d, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x20, 0x6c, -- 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x2e, 0x20, -- 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, -- 0x72, 0x6f, 0x62, 0x61, 0x62, 0x6c, 0x79, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x62, -- 0x69, 0x74, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, 0x0a, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x6e, 0x65, 0x78, 0x74, -- 0x2c, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x20, -- 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, -- 0x6e, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, -- 0x6c, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, -- 0x6c, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x2c, 0x20, 0x67, 0x73, 0x75, 0x62, 0x2c, 0x20, 0x66, 0x6f, -- 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, -- 0x6e, 0x64, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x2c, -- 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x0a, 0x0a, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6f, -- 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, -- 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, -- 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, -- 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x0a, 0x6c, -- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, -- 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, -- 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, -- 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, -- 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, -- 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, -- 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, -- 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, -- 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x74, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, -- 0x28, 0x69, 0x6f, 0x2e, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x6c, 0x6f, 0x63, 0x61, -- 0x6c, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, -- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, -- 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, -- 0x74, 0x75, 0x73, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, -- 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, -- 0x70, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, -- 0x74, 0x75, 0x73, 0x2e, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, -- 0x20, 0x2d, 0x2d, 0x20, 0x30, 0x20, 0x28, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x29, -- 0x20, 0x31, 0x20, 0x28, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x32, 0x20, -- 0x28, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x29, 0x0a, 0x6c, 0x6f, 0x63, -- 0x61, 0x6c, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, -- 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, -- 0x30, 0x20, 0x31, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, -- 0x5f, 0x6e, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, -- 0x20, 0x74, 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x0a, -- 0x0a, 0x69, 0x6f, 0x2e, 0x73, 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, -- 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, -- 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x6d, 0x74, 0x2e, 0x73, 0x61, 0x76, 0x65, -- 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, -- 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, -- 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, -- 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, -- 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, -- 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, -- 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, -- 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -- 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x68, 0x6f, 0x77, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x73, -- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x28, -- 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x77, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, -- 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, -- 0x65, 0x2c, 0x27, 0x77, 0x27, 0x29, 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, -- 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, -- 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x0a, 0x65, 0x6e, -- 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -- 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, -- 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, -- 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, -- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, -- 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x67, 0x73, 0x75, -- 0x62, 0x28, 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x5b, 0x5e, 0x72, 0x62, 0x5d, 0x27, 0x2c, 0x27, 0x27, -- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, 0x77, -- 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, -- 0x27, 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, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, -- 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, -- 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, -- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, 0x5f, -- 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, -- 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x0a, 0x65, 0x6e, -- 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -- 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x65, -- 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x2c, 0x20, 0x66, 0x6f, 0x75, 0x6e, -- 0x64, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, -- 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x69, 0x66, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x6f, -- 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x65, 0x6e, -- 0x28, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6c, 0x6f, 0x63, 0x61, -- 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, -- 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, -- 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, -- 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, -- 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x20, 0x6f, -- 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -- 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, -- 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, -- 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, -- 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x73, 0x6f, 0x6d, 0x65, -- 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x63, 0x20, 0x64, -- 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x6b, 0x69, 0x63, 0x6b, 0x20, 0x69, 0x6e, 0x20, 0x73, -- 0x6f, 0x20, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6c, 0x6f, -- 0x73, 0x65, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x74, 0x6c, 0x79, 0x0a, 0x2d, 0x2d, 0x20, 0x73, -- 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, -- 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, 0x2e, 0x0a, 0x0a, 0x6c, -- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, -- 0x20, 0x3d, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x0a, 0x0a, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, -- 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x6e, -- 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, -- 0x74, 0x79, 0x70, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x73, -- 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, -- 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x20, 0x6f, -- 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x38, 0x30, 0x20, 0x2d, 0x2d, 0x20, -+ 0x77, 0x65, 0x20, 0x72, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, -+ 0x75, 0x61, 0x74, 0x65, 0x78, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x68, -+ 0x65, 0x72, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x68, 0x61, 0x70, 0x70, -+ 0x65, 0x6e, 0x65, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, -+ 0x6c, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x20, 0x73, 0x6f, 0x6d, -+ 0x65, 0x20, 0x4c, 0x75, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, -+ 0x20, 0x54, 0x68, 0x65, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x76, 0x61, -+ 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x20, 0x74, -+ 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, -+ 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x20, 0x61, 0x73, 0x20, 0x4c, 0x75, 0x61, 0x54, -+ 0x65, 0x58, 0x20, 0x3c, 0x3d, 0x20, 0x31, 0x2e, 0x30, 0x34, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, -+ 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, -+ 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x74, 0x73, 0x20, 0x75, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x6b, -+ 0x65, 0x65, 0x70, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x72, 0x69, 0x67, 0x69, -+ 0x6e, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x20, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, -+ 0x20, 0x63, 0x6c, 0x65, 0x61, 0x6e, 0x2e, 0x20, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, -+ 0x6e, 0x63, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x62, 0x61, 0x62, 0x6c, 0x79, 0x20, -+ 0x65, 0x76, 0x65, 0x6e, 0x20, 0x61, 0x20, 0x62, 0x69, 0x74, 0x20, 0x62, 0x65, 0x74, 0x74, 0x65, -+ 0x72, 0x20, 0x6e, 0x6f, 0x77, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, 0x74, 0x65, -+ 0x73, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, -+ 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x64, -+ 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, -+ 0x65, 0x20, 0x64, 0x6f, 0x6e, 0x27, 0x74, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, -+ 0x20, 0x6f, 0x6e, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0a, 0x2d, 0x2d, 0x20, 0x61, 0x72, -+ 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, -+ 0x65, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x20, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, -+ 0x2e, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x20, 0x6e, -+ 0x65, 0x78, 0x74, 0x2c, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, -+ 0x65, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x79, 0x70, -+ 0x65, 0x2c, 0x20, 0x6e, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, -+ 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x0a, 0x6c, -+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6e, 0x64, 0x2c, 0x20, 0x67, 0x73, 0x75, 0x62, 0x2c, -+ 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, -+ 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, -+ 0x75, 0x62, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, -+ 0x74, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, -+ 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x6f, 0x5f, -+ 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, -+ 0x6c, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, -+ 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, -+ 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, -+ 0x6f, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, -+ 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, -+ 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b, -+ 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, -+ 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, -+ 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, -+ 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, -+ 0x20, 0x6d, 0x74, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, -+ 0x62, 0x6c, 0x65, 0x28, 0x69, 0x6f, 0x2e, 0x73, 0x74, 0x64, 0x65, 0x72, 0x72, 0x29, 0x0a, 0x6c, -+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x2e, 0x6c, 0x69, -+ 0x6e, 0x65, 0x73, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, -+ 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, -+ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x73, 0x61, 0x66, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x74, -+ 0x69, 0x6f, 0x6e, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, -+ 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, -+ 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x5f, 0x65, 0x73, 0x63, -+ 0x61, 0x70, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x30, 0x20, 0x28, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, -+ 0x65, 0x64, 0x29, 0x20, 0x31, 0x20, 0x28, 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x29, -+ 0x20, 0x32, 0x20, 0x28, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x65, 0x64, 0x29, 0x0a, -+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x61, 0x74, -+ 0x75, 0x73, 0x2e, 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x20, 0x20, 0x20, 0x20, -+ 0x2d, 0x2d, 0x20, 0x30, 0x20, 0x31, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x77, 0x72, -+ 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, -+ 0x6e, 0x6c, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, 0x73, 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, -+ 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, -+ 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, -+ 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x0a, 0x6d, 0x74, 0x2e, 0x73, -+ 0x61, 0x76, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, -+ 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x72, 0x65, 0x61, 0x64, 0x6f, -+ 0x6e, 0x6c, 0x79, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, -+ 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, -+ 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, -+ 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, -+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, -+ 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, - 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 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, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x20, 0x3d, -- 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 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, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 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, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x68, 0x6f, 0x77, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x27, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x27, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x66, 0x69, -+ 0x6e, 0x64, 0x28, 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x77, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, -+ 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, -+ 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x77, 0x27, 0x29, 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, 0x2d, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65, 0x20, -- 0x77, 0x68, 0x6f, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, -- 0x20, 0x77, 0x61, 0x79, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, -- 0x20, 0x27, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x27, 0x20, 0x63, 0x61, 0x6e, 0x27, -- 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x27, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x61, 0x6d, -- 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x27, 0x22, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, -- 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, -+ 0x20, 0x20, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, -+ 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, - 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, -- 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x72, -- 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, -- 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x6f, 0x2e, -- 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, -- 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x6d, 0x74, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, -- 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, -- 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, 0x61, 0x73, 0x73, -- 0x75, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x74, -- 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, -- 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, -- 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, -- 0x73, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x73, 0x65, 0x20, 0x69, 0x6e, -- 0x20, 0x43, 0x6f, 0x6e, 0x54, 0x65, 0x58, 0x74, 0x2e, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6b, 0x70, -- 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, -- 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x3d, -- 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x6c, -- 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x0a, -- 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, -- 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -- 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x73, -- 0x74, 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, -- 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, -- 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, -- 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x2e, 0x2e, 0x2e, -- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -- 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, -- 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x28, 0x66, 0x6f, 0x72, 0x6d, -- 0x61, 0x74, 0x28, 0x22, 0x73, 0x61, 0x66, 0x65, 0x72, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, -- 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x25, -- 0x71, 0x20, 0x69, 0x73, 0x20, 0x25, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x73, 0x74, -- 0x72, 0x2c, 0x66, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, -- 0x22, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x29, -- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, -- 0x65, 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, 0x69, 0x66, -- 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, -+ 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x28, 0x6e, 0x61, 0x6d, -+ 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x68, 0x6f, -+ 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, -+ 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, -+ 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, -+ 0x67, 0x73, 0x75, 0x62, 0x28, 0x68, 0x6f, 0x77, 0x2c, 0x27, 0x5b, 0x5e, 0x72, 0x62, 0x5d, 0x27, -+ 0x2c, 0x27, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, -+ 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x3d, 0x20, 0x27, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, -+ 0x20, 0x27, 0x72, 0x27, 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, 0x6c, 0x6f, 0x63, -+ 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, -+ 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, -+ 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, -+ 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, -+ 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, -+ 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, -+ 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x2c, 0x20, 0x66, -+ 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, -+ 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x20, 0x61, 0x6e, 0x64, -+ 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x70, 0x6f, -+ 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6c, -+ 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, -+ 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x6e, 0x61, -+ 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, -+ 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, 0x2d, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, -+ 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, -+ 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x2d, -+ 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, -+ 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, -+ 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, -+ 0x65, 0x73, 0x28, 0x29, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, -+ 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x46, 0x6f, 0x72, 0x20, 0x73, -+ 0x6f, 0x6d, 0x65, 0x20, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, -+ 0x63, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x6b, 0x69, 0x63, 0x6b, 0x20, 0x69, -+ 0x6e, 0x20, 0x73, 0x6f, 0x20, 0x77, 0x65, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, -+ 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x74, 0x6c, 0x79, 0x0a, 0x2d, -+ 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, -+ 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x65, 0x64, 0x2e, -+ 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, -+ 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x2c, 0x20, 0x74, 0x79, 0x70, -+ 0x65, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -+ 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, -+ 0x73, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x69, 0x66, 0x20, 0x74, 0x79, 0x70, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x3d, 0x3d, -+ 0x20, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x20, 0x3d, -+ 0x20, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, -+ 0x77, 0x20, 0x6f, 0x72, 0x20, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, -- 0x28, 0x2e, 0x2e, 0x2e, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, -- 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, -- 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x28, 0x73, 0x74, 0x72, 0x2c, 0x66, -- 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, -- 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, -- 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, -- 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, -- 0x75, 0x74, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, -- 0x77, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, -- 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x22, 0x29, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x20, 0x20, 0x20, 0x20, 0x3d, -- 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, -- 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, -- 0x73, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, -- 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x65, 0x6e, -- 0x76, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x64, -- 0x69, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, -- 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, -- 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, -- 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, -- 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, -- 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, -- 0x6e, 0x22, 0x2c, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, 0x65, -- 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, -- 0x20, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, -- 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x72, -- 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x72, -- 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, -- 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, -- 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x74, 0x6d, 0x70, 0x66, 0x69, -- 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, -- 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x74, 0x6d, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x29, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x20, 0x3d, -- 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, -- 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x6c, 0x66, 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, -- 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x63, -- 0x68, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x6c, -- 0x6f, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, -- 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x29, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x20, 0x20, -- 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, -- 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, -- 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x72, -- 0x6d, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x6d, -- 0x6b, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, -- 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x22, -- 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, -- 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x6f, 0x72, 0x20, 0x73, -- 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x7e, 0x3d, 0x20, 0x31, 0x20, -- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, -- 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x66, 0x66, 0x69, 0x27, 0x29, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x20, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x6e, -- 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x66, 0x69, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x20, 0x7e, 0x3d, 0x20, 0x27, 0x67, 0x63, 0x27, -+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, -+ 0x6c, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, -+ 0x28, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 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, 0x66, 0x3a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x29, 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, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 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, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x6f, -+ 0x73, 0x65, 0x20, 0x77, 0x68, 0x6f, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x69, 0x74, 0x20, 0x74, -+ 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x3a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x70, 0x61, 0x74, 0x63, -+ 0x68, 0x65, 0x64, 0x20, 0x27, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x27, 0x20, 0x63, -+ 0x61, 0x6e, 0x27, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x27, 0x22, 0x20, 0x2e, 0x2e, 0x20, -+ 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x22, 0x27, 0x22, 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, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, -+ 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, -+ 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, -+ 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, 0x66, 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, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x66, 0x69, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x28, -+ 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, -+ 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, -+ 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a, 0x6d, 0x74, 0x2e, 0x6c, 0x69, -+ 0x6e, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, -+ 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x57, 0x65, 0x20, -+ 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, -+ 0x74, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, -+ 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, -+ 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, -+ 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x61, 0x73, 0x65, -+ 0x20, 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x54, 0x65, 0x58, 0x74, 0x2e, 0x0a, 0x0a, 0x69, 0x66, -+ 0x20, 0x6b, 0x70, 0x73, 0x65, 0x75, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, -+ 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, -+ 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x6f, 0x70, -+ 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x20, -+ 0x3d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, 0x70, 0x6f, 0x70, 0x65, -+ 0x6e, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, 0x66, 0x65, 0x72, -+ 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, -+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, -+ 0x79, 0x28, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, -+ 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, -+ 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x66, 0x66, 0x69, 0x5b, 0x6b, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 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, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, -- 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x73, 0x2e, 0x5b, 0x65, 0x78, -- 0x65, 0x63, 0x75, 0x74, 0x65, 0x7c, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x7c, 0x6f, -- 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x5d, 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, 0x64, 0x79, 0x20, -- 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, -- 0x61, 0x77, 0x61, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6d, 0x64, 0x35, 0x20, -- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, -- 0x73, 0x75, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x73, 0x75, 0x62, 0x20, -- 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, 0x75, 0x62, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, -- 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, -- 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x0a, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, -- 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x28, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, -- 0x62, 0x28, 0x73, 0x75, 0x6d, 0x28, 0x6b, 0x29, 0x2c, 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, -- 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, -- 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x78, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, -- 0x28, 0x63, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, -- 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, -- 0x48, 0x45, 0x58, 0x41, 0x28, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x75, 0x6d, -- 0x28, 0x6b, 0x29, 0x2c, 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, -- 0x6f, 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e, 0x6c, 0x28, 0x66, -+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x22, 0x73, 0x61, 0x66, 0x65, 0x72, 0x20, 0x6f, 0x70, 0x74, -+ 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -+ 0x6e, 0x20, 0x25, 0x71, 0x20, 0x69, 0x73, 0x20, 0x25, 0x73, 0x22, 0x2c, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x73, 0x74, 0x72, 0x2c, 0x66, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x6c, 0x69, 0x6d, 0x69, -+ 0x74, 0x65, 0x64, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x22, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, -+ 0x64, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, -+ 0x74, 0x72, 0x75, 0x65, 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, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -+ 0x6e, 0x20, 0x66, 0x28, 0x2e, 0x2e, 0x2e, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, -+ 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x28, 0x73, 0x74, -+ 0x72, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, -+ 0x61, 0x6c, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x61, -+ 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, -+ 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, -+ 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, -+ 0x73, 0x70, 0x61, 0x77, 0x6e, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, -+ 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0x6e, -+ 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x20, 0x20, -+ 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, -+ 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x6f, 0x73, 0x2e, 0x73, 0x65, 0x74, 0x65, 0x6e, 0x76, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, -+ 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x73, 0x65, -+ 0x74, 0x65, 0x6e, 0x76, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x74, 0x65, -+ 0x6d, 0x70, 0x64, 0x69, 0x72, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, -+ 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x74, 0x65, 0x6d, 0x70, 0x64, 0x69, 0x72, -+ 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, -+ 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, -+ 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x70, 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x29, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, -+ 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, -+ 0x6f, 0x70, 0x65, 0x6e, 0x22, 0x2c, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x5f, 0x69, 0x6f, 0x5f, -+ 0x6f, 0x70, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x6f, 0x6e, 0x6c, 0x79, 0x29, 0x0a, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x20, 0x3d, -+ 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, -+ 0x73, 0x2e, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, -+ 0x73, 0x2e, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, -+ 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6f, 0x73, 0x2e, 0x72, 0x65, 0x6d, -+ 0x6f, 0x76, 0x65, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x74, 0x6d, -+ 0x70, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, -+ 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x74, 0x6d, 0x70, 0x66, 0x69, 0x6c, 0x65, -+ 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, -+ 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, -+ 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, 0x0a, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, -+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, -+ 0x73, 0x2e, 0x63, 0x68, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, -+ 0x73, 0x2e, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, -+ 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6c, 0x6f, 0x63, -+ 0x6b, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, -+ 0x68, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, -+ 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x22, 0x29, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, -+ 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, -+ 0x73, 0x2e, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x66, -+ 0x73, 0x2e, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x61, -+ 0x6c, 0x6c, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x28, 0x22, 0x6c, 0x66, 0x73, 0x2e, 0x6d, 0x6b, 0x64, -+ 0x69, 0x72, 0x22, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x73, 0x61, -+ 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x20, 0x6f, -+ 0x72, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x20, 0x7e, 0x3d, -+ 0x20, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, -+ 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x27, 0x66, 0x66, 0x69, 0x27, -+ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6b, 0x2c, 0x20, 0x76, 0x20, 0x69, -+ 0x6e, 0x20, 0x6e, 0x65, 0x78, 0x74, 0x2c, 0x20, 0x66, 0x66, 0x69, 0x20, 0x64, 0x6f, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6b, 0x20, 0x7e, 0x3d, 0x20, 0x27, -+ 0x67, 0x63, 0x27, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x66, 0x69, 0x5b, 0x6b, 0x5d, 0x20, 0x3d, 0x20, 0x6e, 0x69, -+ 0x6c, 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, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, -+ 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6f, 0x73, 0x2e, -+ 0x5b, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x7c, 0x6f, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, -+ 0x6e, 0x7c, 0x6f, 0x73, 0x2e, 0x65, 0x78, 0x65, 0x63, 0x5d, 0x20, 0x61, 0x6c, 0x72, 0x65, 0x61, -+ 0x64, 0x79, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x63, 0x61, -+ 0x70, 0x65, 0x20, 0x61, 0x77, 0x61, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6d, -+ 0x64, 0x35, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, -+ 0x61, 0x6c, 0x20, 0x73, 0x75, 0x6d, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x64, 0x35, 0x2e, -+ 0x73, 0x75, 0x6d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x73, -+ 0x75, 0x62, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, 0x73, -+ 0x75, 0x62, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x6f, 0x72, -+ 0x6d, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x6f, 0x72, -+ 0x6d, 0x61, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x79, -+ 0x74, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x62, 0x79, -+ 0x74, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, -+ 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, -+ 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x68, 0x65, 0x78, 0x61, 0x28, 0x6b, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x75, 0x6d, 0x28, 0x6b, 0x29, 0x2c, -+ 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, -+ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, -- 0x22, 0x25, 0x30, 0x32, 0x58, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, 0x29, 0x29, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, 0x29, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, -- 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x3a, 0x20, 0x74, 0x68, -- 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x67, 0x6f, 0x20, 0x61, 0x77, 0x61, 0x79, -- 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, -- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, -- 0x3d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x0a, 0x65, -- 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, -- 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, -- 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x65, -- 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, -- 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x74, -- 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x74, 0x72, 0x69, -- 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, -+ 0x22, 0x25, 0x30, 0x32, 0x78, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, 0x29, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x29, -+ 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, -+ 0x74, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, 0x58, 0x41, 0x20, 0x74, 0x68, -+ 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, -+ 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x64, 0x35, 0x2e, 0x73, 0x75, 0x6d, 0x48, 0x45, 0x58, 0x41, 0x28, -+ 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, -+ 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x67, 0x73, 0x75, 0x62, 0x28, 0x73, 0x75, 0x6d, 0x28, -+ 0x6b, 0x29, 0x2c, 0x20, 0x22, 0x2e, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -+ 0x6e, 0x28, 0x63, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d, -+ 0x61, 0x74, 0x28, 0x22, 0x25, 0x30, 0x32, 0x58, 0x22, 0x2c, 0x62, 0x79, 0x74, 0x65, 0x28, 0x63, -+ 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, -+ 0x6e, 0x64, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, - 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x3a, -- 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, 0x74, 0x61, 0x79, -- 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, 0x2e, 0x32, 0x3a, -- 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x0a, 0x0a, 0x65, 0x6c, 0x73, -- 0x65, 0x69, 0x66, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, 0x2e, 0x33, 0x3a, 0x20, 0x20, -- 0x62, 0x69, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2e, 0x6c, 0x75, 0x61, 0x2c, 0x20, 0x76, 0x20, 0x31, -- 0x2e, 0x32, 0x34, 0x20, 0x32, 0x30, 0x31, 0x34, 0x2f, 0x31, 0x32, 0x2f, 0x32, 0x36, 0x20, 0x31, -- 0x37, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x20, 0x72, 0x6f, 0x62, 0x65, 0x72, 0x74, 0x6f, 0x0a, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, -- 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x65, 0x6c, -- 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x2d, 0x2d, 0x20, -- 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, 0x3a, 0x20, 0x61, 0x72, 0x67, 0x20, -- 0x3d, 0x20, 0x7b, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x7d, 0x0a, 0x0a, 0x62, 0x69, 0x74, 0x33, 0x32, -- 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, -- 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, -- 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7e, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, -- 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, -- 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, -- 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, -- 0x2d, 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x26, -- 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, -- 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, -- 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x73, 0x65, 0x6c, 0x65, -- 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, -- 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, -- 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -+ 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x67, 0x6f, 0x20, 0x61, -+ 0x77, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x75, 0x6e, 0x70, 0x61, -+ 0x63, 0x6b, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x6e, 0x70, 0x61, -+ 0x63, 0x6b, 0x20, 0x3d, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x75, 0x6e, 0x70, 0x61, 0x63, -+ 0x6b, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x70, 0x61, -+ 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x68, -+ 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, -+ 0x6f, 0x61, 0x64, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, -+ 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, -+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x74, 0x72, 0x69, 0x6e, -+ 0x67, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x73, -+ 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x0a, 0x65, 0x6e, 0x64, -+ 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x69, -+ 0x74, 0x79, 0x3a, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x69, 0x67, 0x68, 0x74, 0x20, 0x73, -+ 0x74, 0x61, 0x79, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x74, 0x68, -+ 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, -+ 0x2e, 0x32, 0x3a, 0x20, 0x77, 0x65, 0x27, 0x72, 0x65, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x0a, 0x0a, -+ 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x75, 0x74, 0x66, 0x38, 0x20, 0x74, 0x68, 0x65, 0x6e, -+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x20, 0x35, 0x2e, 0x33, -+ 0x3a, 0x20, 0x20, 0x62, 0x69, 0x74, 0x77, 0x69, 0x73, 0x65, 0x2e, 0x6c, 0x75, 0x61, 0x2c, 0x20, -+ 0x76, 0x20, 0x31, 0x2e, 0x32, 0x34, 0x20, 0x32, 0x30, 0x31, 0x34, 0x2f, 0x31, 0x32, 0x2f, 0x32, -+ 0x36, 0x20, 0x31, 0x37, 0x3a, 0x32, 0x30, 0x3a, 0x35, 0x33, 0x20, 0x72, 0x6f, 0x62, 0x65, 0x72, -+ 0x74, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, -+ 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, -+ 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, -+ 0x2d, 0x2d, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, 0x3a, 0x20, 0x61, -+ 0x72, 0x67, 0x20, 0x3d, 0x20, 0x7b, 0x20, 0x2e, 0x2e, 0x2e, 0x20, 0x7d, 0x0a, 0x0a, 0x62, 0x69, -+ 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x3d, -+ 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x29, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x7e, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, -+ 0x20, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, - 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, -- 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x79, 0x20, 0x6f, -- 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, 0x20, -- 0x7c, 0x20, 0x79, 0x20, 0x7c, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, -- 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, 0x22, -- 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x7c, 0x20, 0x73, 0x65, 0x6c, -- 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -- 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, -- 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, -- 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, -- 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, -- 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -- 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7e, 0x20, 0x28, 0x79, -- 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, -+ 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, -+ 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, -- 0x78, 0x20, 0x7e, 0x20, 0x79, 0x20, 0x7e, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x78, 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, - 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x7e, 0x20, 0x73, -+ 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x73, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, - 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, -- 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, -+ 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, 0x20, 0x2e, -+ 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x7a, -+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7c, 0x20, 0x28, -+ 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, -+ 0x20, 0x78, 0x20, 0x7c, 0x20, 0x79, 0x20, 0x7c, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, -+ 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x7c, 0x20, -+ 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, -+ 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, 0x20, 0x7a, 0x2c, - 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, - 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, -- 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, 0x20, 0x26, 0x20, -- 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, 0x20, 0x26, 0x20, -- 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, -- 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, -- 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x73, 0x65, 0x6c, -- 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -- 0x6e, 0x20, 0x28, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, -- 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, -- 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, -- 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, -- 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, -- 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, -- 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, -- 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, -- 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x29, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x61, -+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x20, 0x7e, -+ 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x30, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, -+ 0x20, 0x3d, 0x20, 0x78, 0x20, 0x7e, 0x20, 0x79, 0x20, 0x7e, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, -+ 0x74, 0x28, 0x22, 0x23, 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, -+ 0x7e, 0x20, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, -+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, 0x74, 0x20, 0x3d, -+ 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x20, 0x79, 0x2c, -+ 0x20, 0x7a, 0x2c, 0x20, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, -+ 0x6e, 0x6f, 0x74, 0x20, 0x7a, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x28, 0x78, 0x20, 0x6f, 0x72, 0x20, -+ 0x2d, 0x31, 0x29, 0x20, 0x26, 0x20, 0x28, 0x79, 0x20, 0x6f, 0x72, 0x20, 0x2d, 0x31, 0x29, 0x29, -+ 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, -+ 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x78, -+ 0x20, 0x26, 0x20, 0x79, 0x20, 0x26, 0x20, 0x7a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, -+ 0x6f, 0x72, 0x20, 0x69, 0x3d, 0x31, 0x2c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x22, 0x23, -+ 0x22, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, -+ 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x28, 0x69, 0x2c, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x72, 0x65, 0x73, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, -+ 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, -+ 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -+ 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x29, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, - 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -- 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, -- 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, -- 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x20, 0x6f, 0x72, -- 0x20, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, -- 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x62, -- 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -- 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x7c, -- 0x20, 0x7e, 0x28, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x20, 0x3e, 0x3e, -- 0x20, 0x62, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, -- 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, -- 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x2c, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, -- 0x20, 0x62, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, -+ 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x29, 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, -+ 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, -+ 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, -- 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, -- 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, -- 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, -- 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, -- 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, -- 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x2d, 0x62, 0x20, 0x26, 0x20, -- 0x33, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, -- 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, -- 0x3d, 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, -- 0x3e, 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, -- 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, -- 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, -- 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, -- 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x66, 0x29, -- 0x20, 0x26, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, 0x20, 0x6f, 0x72, -- 0x20, 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x65, -- 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, -- 0x20, 0x28, 0x61, 0x2c, 0x20, 0x76, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x7e, -- 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, -- 0x26, 0x20, 0x7e, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3c, 0x3c, 0x20, 0x66, 0x29, 0x29, 0x20, -- 0x7c, 0x20, 0x28, 0x28, 0x76, 0x20, 0x26, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x20, 0x3c, 0x3c, -- 0x20, 0x66, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -- 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, -- 0x62, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, -- 0x20, 0x6c, 0x75, 0x61, 0x6a, 0x69, 0x74, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x77, -- 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x6c, -- 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, -- 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, -- 0x74, 0x2c, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, -- 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x20, -- 0x62, 0x69, 0x74, 0x2e, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, -- 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x0a, 0x0a, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, -- 0x7b, 0x0a, 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x62, 0x69, -- 0x74, 0x2e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x61, 0x6e, -- 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x62, -- 0x6e, 0x6f, 0x74, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x0a, 0x20, -- 0x20, 0x62, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, -- 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, -- 0x62, 0x69, 0x74, 0x2e, 0x62, 0x78, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x74, 0x65, 0x73, -- 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x2e, -- 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, -- 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, 0x0a, 0x20, 0x20, -- 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, -- 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x66, 0x2c, 0x77, 0x29, -- 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, -- 0x28, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x61, 0x2c, 0x66, 0x29, 0x2c, 0x32, 0x5e, 0x28, -- 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, -- 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x62, 0x69, -- 0x74, 0x2e, 0x72, 0x6f, 0x6c, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, -- 0x20, 0x3d, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x70, -- 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, -- 0x61, 0x2c, 0x76, 0x2c, 0x66, 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, -- 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x32, 0x5e, 0x28, 0x77, 0x20, 0x6f, -- 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -- 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x62, 0x6e, 0x6f, 0x74, 0x28, 0x6c, 0x73, -- 0x68, 0x69, 0x66, 0x74, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x66, 0x29, 0x29, 0x29, 0x2b, 0x6c, -- 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x76, 0x2c, 0x6d, 0x61, 0x73, -- 0x6b, 0x29, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, -- 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x6f, 0x72, -- 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x20, 0x3d, 0x20, 0x72, 0x73, -- 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -- 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x2d, 0x2d, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, -- 0x62, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x0a, 0x0a, 0x20, 0x20, -- 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, -- 0x65, 0x28, 0x22, 0x62, 0x69, 0x74, 0x33, 0x32, 0x22, 0x29, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, -- 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x65, 0x65, 0x64, -- 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x72, -- 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x22, 0x29, -- 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, -- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x70, -- 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x0a, 0x0a, 0x20, -- 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, -- 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, -- 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, -- 0x64, 0x65, 0x64, 0x5b, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, 0x6f, 0x72, 0x65, -- 0x22, 0x5d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, -- 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, -- 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, 0x69, 0x6d, 0x65, -- 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, 0x6d, 0x69, 0x6d, -- 0x65, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, -- 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x0a, 0x00 -+ 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x62, 0x20, 0x3c, 0x3d, 0x20, 0x30, -+ 0x20, 0x6f, 0x72, 0x20, 0x28, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x38, 0x30, 0x30, 0x30, 0x30, -+ 0x30, 0x30, 0x30, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, -+ 0x3e, 0x20, 0x62, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x62, -+ 0x29, 0x20, 0x7c, 0x20, 0x7e, 0x28, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x20, 0x3e, 0x3e, 0x20, 0x62, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, -+ 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, -+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x2c, 0x62, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x62, 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, -+ 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, -+ 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, -+ 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, -+ 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, -+ 0x61, 0x2c, 0x20, 0x62, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x2d, 0x62, -+ 0x20, 0x26, 0x20, 0x33, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x61, 0x20, 0x3d, 0x20, 0x61, 0x20, -+ 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x61, 0x20, 0x3d, 0x20, 0x28, 0x61, 0x20, 0x3c, 0x3c, 0x20, 0x62, 0x29, 0x20, 0x7c, 0x20, -+ 0x28, 0x61, 0x20, 0x3e, 0x3e, 0x20, 0x28, 0x33, 0x32, 0x20, 0x2d, 0x20, 0x62, 0x29, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x20, 0x26, 0x20, 0x30, -+ 0x78, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, -+ 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, -+ 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, 0x61, 0x20, 0x3e, 0x3e, -+ 0x20, 0x66, 0x29, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, -+ 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, -+ 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, -+ 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x61, 0x2c, 0x20, 0x76, 0x2c, 0x20, 0x66, 0x2c, 0x20, 0x77, 0x29, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, -+ 0x3d, 0x20, 0x7e, 0x28, 0x2d, 0x31, 0x20, 0x3c, 0x3c, 0x20, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, -+ 0x31, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x28, -+ 0x28, 0x61, 0x20, 0x26, 0x20, 0x7e, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3c, 0x3c, 0x20, 0x66, -+ 0x29, 0x29, 0x20, 0x7c, 0x20, 0x28, 0x28, 0x76, 0x20, 0x26, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x29, -+ 0x20, 0x3c, 0x3c, 0x20, 0x66, 0x29, 0x29, 0x20, 0x26, 0x20, 0x30, 0x78, 0x46, 0x46, 0x46, 0x46, -+ 0x46, 0x46, 0x46, 0x46, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, -+ 0x69, 0x66, 0x20, 0x62, 0x69, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x6a, 0x69, 0x74, 0x20, 0x28, 0x66, 0x6f, 0x72, 0x20, -+ 0x6e, 0x6f, 0x77, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, -+ 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x28, 0x20, 0x5b, 0x5b, 0x0a, 0x6c, 0x6f, 0x63, 0x61, -+ 0x6c, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x2c, 0x20, 0x72, 0x73, -+ 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, 0x20, 0x62, -+ 0x69, 0x74, 0x2e, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x6e, 0x6f, -+ 0x74, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x20, 0x62, -+ 0x69, 0x74, 0x2e, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x0a, 0x0a, 0x62, 0x69, 0x74, 0x33, 0x32, -+ 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x3d, -+ 0x20, 0x62, 0x69, 0x74, 0x2e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, -+ 0x62, 0x61, 0x6e, 0x64, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x2c, 0x0a, -+ 0x20, 0x20, 0x62, 0x6e, 0x6f, 0x74, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x6e, 0x6f, 0x74, -+ 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x6f, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x62, 0x69, -+ 0x74, 0x2e, 0x62, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, 0x78, 0x6f, 0x72, 0x20, 0x20, 0x20, -+ 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, 0x62, 0x78, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x62, -+ 0x74, 0x65, 0x73, 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, -+ 0x6e, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, -+ 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x30, -+ 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x65, 0x78, 0x74, 0x72, 0x61, 0x63, -+ 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x66, -+ 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, -+ 0x61, 0x6e, 0x64, 0x28, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x61, 0x2c, 0x66, 0x29, 0x2c, -+ 0x32, 0x5e, 0x28, 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x29, 0x0a, 0x20, 0x20, -+ 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, -+ 0x20, 0x62, 0x69, 0x74, 0x2e, 0x72, 0x6f, 0x6c, 0x2c, 0x0a, 0x20, 0x20, 0x6c, 0x73, 0x68, 0x69, -+ 0x66, 0x74, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x20, 0x20, -+ 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, -+ 0x6f, 0x6e, 0x28, 0x61, 0x2c, 0x76, 0x2c, 0x66, 0x2c, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x61, 0x73, 0x6b, 0x20, 0x3d, 0x20, 0x32, 0x5e, 0x28, -+ 0x77, 0x20, 0x6f, 0x72, 0x20, 0x31, 0x29, 0x2d, 0x31, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, -+ 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x61, 0x2c, 0x62, 0x6e, 0x6f, 0x74, -+ 0x28, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x6d, 0x61, 0x73, 0x6b, 0x2c, 0x66, 0x29, 0x29, -+ 0x29, 0x2b, 0x6c, 0x73, 0x68, 0x69, 0x66, 0x74, 0x28, 0x62, 0x61, 0x6e, 0x64, 0x28, 0x76, 0x2c, -+ 0x6d, 0x61, 0x73, 0x6b, 0x29, 0x2c, 0x66, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x2c, 0x0a, -+ 0x20, 0x20, 0x72, 0x72, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x62, 0x69, 0x74, 0x2e, -+ 0x72, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x20, 0x20, 0x3d, -+ 0x20, 0x72, 0x73, 0x68, 0x69, 0x66, 0x74, 0x2c, 0x0a, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x5d, 0x5d, 0x20, 0x29, 0x0a, 0x0a, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x68, 0x6f, 0x70, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, -+ 0x68, 0x65, 0x20, 0x62, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x0a, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x62, 0x69, 0x74, 0x33, 0x32, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, -+ 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x62, 0x69, 0x74, 0x33, 0x32, 0x22, 0x29, 0x0a, 0x0a, 0x65, -+ 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6e, -+ 0x65, 0x65, 0x64, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6e, -+ 0x67, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, -+ 0x74, 0x22, 0x29, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, -+ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, -+ 0x3d, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, -+ 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, -+ 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, -+ 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x20, 0x3d, 0x20, -+ 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x63, -+ 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, -+ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, 0x69, 0x6d, 0x65, -+ 0x20, 0x20, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6d, -+ 0x69, 0x6d, 0x65, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5b, 0x22, -+ 0x6d, 0x69, 0x6d, 0x65, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x5d, 0x20, 0x20, 0x20, 0x65, 0x6e, -+ 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x64, 0x6f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, -+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, -+ 0x74, 0x65, 0x73, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x61, 0x74, -+ 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, -+ 0x61, 0x6c, 0x20, 0x73, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, -+ 0x75, 0x74, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, 0x79, 0x6d, 0x6c, 0x69, -+ 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x0a, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x6e, -+ 0x6f, 0x77, 0x20, 0x62, 0x65, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, -+ 0x20, 0x6c, 0x66, 0x73, 0x20, 0x28, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x61, 0x64, 0x20, 0x73, -+ 0x6c, 0x6f, 0x77, 0x20, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x66, 0x69, -+ 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x66, -+ 0x69, 0x6c, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, -+ 0x6c, 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, 0x61, -+ 0x6d, 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x20, -+ 0x3d, 0x3d, 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x20, 0x3d, -+ 0x3d, 0x20, 0x22, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x64, -+ 0x69, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x69, 0x73, 0x64, -+ 0x69, 0x72, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x20, 0x3d, 0x20, 0x6c, -+ 0x66, 0x73, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, 0x61, 0x6d, -+ 0x65, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6d, 0x20, 0x3d, -+ 0x3d, 0x20, 0x22, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x0a, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, -+ 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x6e, -+ 0x61, 0x6d, 0x65, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x62, -+ 0x65, 0x20, 0x73, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x72, 0x6f, 0x70, 0x70, 0x65, -+ 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x73, 0x68, 0x6f, 0x72, -+ 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, -+ 0x73, 0x68, 0x6f, 0x72, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, -+ 0x72, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, -+ 0x20, 0x2d, 0x2d, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, -+ 0x20, 0x61, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x20, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x2c, -+ 0x20, 0x73, 0x6f, 0x20, 0x2e, 0x2e, 0x2e, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, -+ 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x6b, -+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x75, -+ 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x66, 0x73, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, -+ 0x69, 0x6e, 0x6b, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, -+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x79, 0x6d, -+ 0x6c, 0x69, 0x6e, 0x6b, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x28, 0x6e, -+ 0x61, 0x6d, 0x65, 0x2c, 0x22, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x29, 0x20, 0x6f, 0x72, -+ 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, -+ 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, -+ 0x2d, 0x20, 0x73, 0x6f, 0x20, 0x66, 0x61, 0x72, 0x0a, 0x0a, 0x00 - }; - return luaL_dostring(L, (const char*) luatex_core_lua); - } -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/lua/luatex-core.lua b/texk/web2c/luatexdir/lua/luatex-core.lua -index 35005d1c8..f2d55fd99 100644 ---- a/texk/web2c/luatexdir/lua/luatex-core.lua -+++ b/texk/web2c/luatexdir/lua/luatex-core.lua -@@ -1,419 +1,465 @@ ---- luatex-core security and io overloads ........... -- ---- if not modules then modules = { } end modules ['luatex-core'] = { ---- version = 1.005, ---- comment = 'companion to luatex', ---- author = 'Hans Hagen & Luigi Scarso', ---- copyright = 'LuaTeX Development Team', ---- } -- --LUATEXCOREVERSION = 1.005 -- ---- This file overloads some Lua functions. The readline variants provide the same ---- functionality as LuaTeX <= 1.04 and doing it this way permits us to keep the ---- original io libraries clean. Performance is probably even a bit better now. -- --local type, next, getmetatable, require = type, next, getmetatable, require --local find, gsub, format = string.find, string.gsub, string.format -- --local io_open = io.open --local io_popen = io.popen --local io_lines = io.lines -- --local fio_readline = fio.readline --local fio_checkpermission = fio.checkpermission --local fio_recordfilename = fio.recordfilename -- --local mt = getmetatable(io.stderr) --local mt_lines = mt.lines --local saferoption = status.safer_option --local shellescape = status.shell_escape -- 0 (disabled) 1 (anything) 2 (restricted) --local kpseused = status.kpse_used -- 0 1 -- --local write_nl = texio.write_nl -- --io.saved_lines = io_lines -- always readonly --mt.saved_lines = mt_lines -- always readonly -- --local function luatex_io_open(name,how) -- if not how then -- how = 'r' -- end -- local f = io_open(name,how) -- if f then -- if type(how) == 'string' and find(how,'w') then -- fio_recordfilename(name,'w') -- else -- fio_recordfilename(name,'r') -- end -- end -- return f --end -- --local function luatex_io_open_readonly(name,how) -- if how then -- how = 'r' -- else -- how = gsub(how,'[^rb]','') -- if how == '' then -- how = 'r' -- end -- end -- local f = io_open(name,how) -- if f then -- fio_recordfilename(name,'r') -- end -- return f --end -- --local function luatex_io_popen(name,...) -- local okay, found = fio_checkpermission(name) -- if okay and found then -- return io_popen(found,...) -- end --end -- ---- local function luatex_io_lines(name,how) ---- if name then ---- local f = io_open(name,how or 'r') ---- if f then ---- return function() ---- return fio_readline(f) ---- end ---- end ---- else ---- return io_lines() ---- end ---- end -- ---- For some reason the gc doesn't kick in so we need to close explitly ---- so that the handle is flushed. -- --local error, type = error, type -- --local function luatex_io_lines(name,how) -- if type(name) == "string" then -- local f = io_open(name,how or 'r') -- if f then -- return function() -- local l = fio_readline(f) -- if not l then -- f:close() -- end -- return l -- end -- else -- -- for those who like it this way: -- error("patched 'io.lines' can't open '" .. name .. "'") -- end -- else -- return io_lines() -- end --end -- --local function luatex_io_readline(f) -- return function() -- return fio_readline(f) -- end --end -- --io.lines = luatex_io_lines --mt.lines = luatex_io_readline -- ---- We assume management to be provided by the replacement of kpse. This is the ---- case in ConTeXt. -- --if kpseused == 1 then -- -- io.open = luatex_io_open -- io.popen = luatex_io_popen -- --end -- --if saferoption == 1 then -- -- local function installdummy(str,f) -- local reported = false -- return function(...) -- if not reported then -- write_nl(format("safer option set, function %q is %s", -- str,f and "limited" or "disabled")) -- reported = true -- end -- if f then -- return f(...) -- end -- end -- end -- -- local function installlimit(str,f) -- local reported = false -- end -- -- os.execute = installdummy("os.execute") -- os.spawn = installdummy("os.spawn") -- os.exec = installdummy("os.exec") -- os.setenv = installdummy("os.setenv") -- os.tempdir = installdummy("os.tempdir") -- -- io.popen = installdummy("io.popen") -- io.open = installdummy("io.open",luatex_io_open_readonly) -- -- os.rename = installdummy("os.rename") -- os.remove = installdummy("os.remove") -- -- io.tmpfile = installdummy("io.tmpfile") -- io.output = installdummy("io.output") -- -- lfs.chdir = installdummy("lfs.chdir") -- lfs.lock = installdummy("lfs.lock") -- lfs.touch = installdummy("lfs.touch") -- lfs.rmdir = installdummy("lfs.rmdir") -- lfs.mkdir = installdummy("lfs.mkdir") -- --end -- --if saferoption == 1 or shellescape ~= 1 then -- -- ffi = require('ffi') -- for k, v in next, ffi do -- if k ~= 'gc' then -- ffi[k] = nil -- end -- end -- ffi = nil -- --end -- ---- os.[execute|os.spawn|os.exec] already are shellescape aware) -- -- --if md5 then -- -- local sum = md5.sum -- local gsub = string.gsub -- local format = string.format -- local byte = string.byte -- -- function md5.sumhexa(k) -- return (gsub(sum(k), ".", function(c) -- return format("%02x",byte(c)) -- end)) -- end -- -- function md5.sumHEXA(k) -- return (gsub(sum(k), ".", function(c) -- return format("%02X",byte(c)) -- end)) -- end -- --end -- ---- compatibility: this might go away -- --if not unpack then -- unpack = table.unpack --end -- --if not package.loaders then -- package.loaders = package.searchers --end -- --if not loadstring then -- loadstring = load --end -- ---- compatibility: this might stay -- --if bit32 then -- -- -- lua 5.2: we're okay -- --elseif utf8 then -- -- -- lua 5.3: bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto -- -- bit32 = load ( [[ --local select = select -- instead of: arg = { ... } -- --bit32 = { -- bnot = function (a) -- return ~a & 0xFFFFFFFF -- end, -- band = function (x, y, z, ...) -- if not z then -- return ((x or -1) & (y or -1)) & 0xFFFFFFFF -- else -- local res = x & y & z -- for i=1,select("#",...) do -- res = res & select(i,...) -- end -- return res & 0xFFFFFFFF -- end -- end, -- bor = function (x, y, z, ...) -- if not z then -- return ((x or 0) | (y or 0)) & 0xFFFFFFFF -- else -- local res = x | y | z -- for i=1,select("#",...) do -- res = res | select(i,...) -- end -- return res & 0xFFFFFFFF -- end -- end, -- bxor = function (x, y, z, ...) -- if not z then -- return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF -- else -- local res = x ~ y ~ z -- for i=1,select("#",...) do -- res = res ~ select(i,...) -- end -- return res & 0xFFFFFFFF -- end -- end, -- btest = function (x, y, z, ...) -- if not z then -- return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 -- else -- local res = x & y & z -- for i=1,select("#",...) do -- res = res & select(i,...) -- end -- return (res & 0xFFFFFFFF) ~= 0 -- end -- end, -- lshift = function (a, b) -- return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF -- end, -- rshift = function (a, b) -- return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF -- end, -- arshift = function (a, b) -- a = a & 0xFFFFFFFF -- if b <= 0 or (a & 0x80000000) == 0 then -- return (a >> b) & 0xFFFFFFFF -- else -- return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF -- end -- end, -- lrotate = function (a ,b) -- b = b & 31 -- a = a & 0xFFFFFFFF -- a = (a << b) | (a >> (32 - b)) -- return a & 0xFFFFFFFF -- end, -- rrotate = function (a, b) -- b = -b & 31 -- a = a & 0xFFFFFFFF -- a = (a << b) | (a >> (32 - b)) -- return a & 0xFFFFFFFF -- end, -- extract = function (a, f, w) -- return (a >> f) & ~(-1 << (w or 1)) -- end, -- replace = function (a, v, f, w) -- local mask = ~(-1 << (w or 1)) -- return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF -- end, --} -- ]] ) -- --elseif bit then -- -- -- luajit (for now) -- -- bit32 = load ( [[ --local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift -- --bit32 = { -- arshift = bit.arshift, -- band = band, -- bnot = bnot, -- bor = bit.bor, -- bxor = bit.bxor, -- btest = function(...) -- return band(...) ~= 0 -- end, -- extract = function(a,f,w) -- return band(rshift(a,f),2^(w or 1)-1) -- end, -- lrotate = bit.rol, -- lshift = lshift, -- replace = function(a,v,f,w) -- local mask = 2^(w or 1)-1 -- return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) -- end, -- rrotate = bit.ror, -- rshift = rshift, --} -- ]] ) -- --else -- -- -- hope for the best or fail -- -- bit32 = require("bit32") -- --end -- ---- this is needed for getting require("socket") right -- --do -- -- local loaded = package.loaded -- -- if not loaded.socket then loaded.socket = loaded["socket.core"] end -- if not loaded.mime then loaded.mime = loaded["mime.core"] end -- --end -- ---- so far -- --if utilities and utilities.merger and utilities.merger.compact then -- -- local byte, format, gmatch = string.byte, string.format, string.gmatch -- local concat = table.concat -- -- local data = gsub(io.loaddata('luatex-core.lua'),'if%s+utilities.*','') -- -- local t = { } -- local r = { } -- local n = 0 -- local d = gsub(data,'\r\n','\n') -- be nice for unix -- local s = utilities.merger.compact(d) -- no comments and less spaces -- -- t[#t+1] = '/* generated from and by luatex-core.lua */' -- t[#t+1] = '' -- -- t[#t+1] = format('/*\n\n%s\n\n*/',d) -- -- t[#t+1] = '' -- t[#t+1] = '#include "lua.h"' -- t[#t+1] = '#include "lauxlib.h"' -- t[#t+1] = '' -- t[#t+1] = 'int load_luatex_core_lua (lua_State * L);' -- t[#t+1] = '' -- t[#t+1] = 'int load_luatex_core_lua (lua_State * L)' -- t[#t+1] = '{' -- t[#t+1] = ' static unsigned char luatex_core_lua[] = {' -- for c in gmatch(d,'.') do -- if n == 16 then -- n = 1 -- t[#t+1] = ' ' .. concat(r,', ') .. ',' -- else -- n = n + 1 -- end -- r[n] = format('0x%02x',byte(c)) -- end -- n = n + 1 -- r[n] = '0x00' -- t[#t+1] = ' ' .. concat(r,', ',1,n) -- t[#t+1] = ' };' -- -- t[#t+1] = format('unsigned int luatex_core_lua_len = 0x%x;',#d+1) -- t[#t+1] = ' return luaL_dostring(L, (const char*) luatex_core_lua);' -- t[#t+1] = '}' -- -- io.savedata('luatex-core.c',concat(t,'\n')) -- io.savedata('luatex-core-stripped.lua',s) -- --end -+-- luatex-core security and io overloads ........... -+ -+-- if not modules then modules = { } end modules ['luatex-core'] = { -+-- version = 1.080, -+-- comment = 'companion to luatex', -+-- author = 'Hans Hagen & Luigi Scarso', -+-- copyright = 'LuaTeX Development Team', -+-- } -+ -+LUATEXCOREVERSION = 1.080 -- we reflect the luatex version where changes happened -+ -+-- This file overloads some Lua functions. The readline variants provide the same -+-- functionality as LuaTeX <= 1.04 and doing it this way permits us to keep the -+-- original io libraries clean. Performance is probably even a bit better now. -+ -+-- We test for functions already being defined so that we don't overload ones that -+-- are provided in the startup script. -+ -+local type, next, getmetatable, require = type, next, getmetatable, require -+local find, gsub, format = string.find, string.gsub, string.format -+ -+local io_open = io.open -+local io_popen = io.popen -+local io_lines = io.lines -+ -+local fio_readline = fio.readline -+local fio_checkpermission = fio.checkpermission -+local fio_recordfilename = fio.recordfilename -+ -+local mt = getmetatable(io.stderr) -+local mt_lines = mt.lines -+local saferoption = status.safer_option -+local shellescape = status.shell_escape -- 0 (disabled) 1 (anything) 2 (restricted) -+local kpseused = status.kpse_used -- 0 1 -+ -+local write_nl = texio.write_nl -+ -+io.saved_lines = io_lines -- always readonly -+mt.saved_lines = mt_lines -- always readonly -+ -+local function luatex_io_open(name,how) -+ if not how then -+ how = 'r' -+ end -+ local f = io_open(name,how) -+ if f then -+ if type(how) == 'string' and find(how,'w') then -+ fio_recordfilename(name,'w') -+ else -+ fio_recordfilename(name,'r') -+ end -+ end -+ return f -+end -+ -+local function luatex_io_open_readonly(name,how) -+ if how then -+ how = 'r' -+ else -+ how = gsub(how,'[^rb]','') -+ if how == '' then -+ how = 'r' -+ end -+ end -+ local f = io_open(name,how) -+ if f then -+ fio_recordfilename(name,'r') -+ end -+ return f -+end -+ -+local function luatex_io_popen(name,...) -+ local okay, found = fio_checkpermission(name) -+ if okay and found then -+ return io_popen(found,...) -+ end -+end -+ -+-- local function luatex_io_lines(name,how) -+-- if name then -+-- local f = io_open(name,how or 'r') -+-- if f then -+-- return function() -+-- return fio_readline(f) -+-- end -+-- end -+-- else -+-- return io_lines() -+-- end -+-- end -+ -+-- For some reason the gc doesn't kick in so we need to close explitly -+-- so that the handle is flushed. -+ -+local error, type = error, type -+ -+local function luatex_io_lines(name,how) -+ if type(name) == "string" then -+ local f = io_open(name,how or 'r') -+ if f then -+ return function() -+ local l = fio_readline(f) -+ if not l then -+ f:close() -+ end -+ return l -+ end -+ else -+ -- for those who like it this way: -+ error("patched 'io.lines' can't open '" .. name .. "'") -+ end -+ else -+ return io_lines() -+ end -+end -+ -+local function luatex_io_readline(f) -+ return function() -+ return fio_readline(f) -+ end -+end -+ -+io.lines = luatex_io_lines -+mt.lines = luatex_io_readline -+ -+-- We assume management to be provided by the replacement of kpse. This is the -+-- case in ConTeXt. -+ -+if kpseused == 1 then -+ -+ io.open = luatex_io_open -+ io.popen = luatex_io_popen -+ -+end -+ -+if saferoption == 1 then -+ -+ local function installdummy(str,f) -+ local reported = false -+ return function(...) -+ if not reported then -+ write_nl(format("safer option set, function %q is %s", -+ str,f and "limited" or "disabled")) -+ reported = true -+ end -+ if f then -+ return f(...) -+ end -+ end -+ end -+ -+ local function installlimit(str,f) -+ local reported = false -+ end -+ -+ os.execute = installdummy("os.execute") -+ os.spawn = installdummy("os.spawn") -+ os.exec = installdummy("os.exec") -+ os.setenv = installdummy("os.setenv") -+ os.tempdir = installdummy("os.tempdir") -+ -+ io.popen = installdummy("io.popen") -+ io.open = installdummy("io.open",luatex_io_open_readonly) -+ -+ os.rename = installdummy("os.rename") -+ os.remove = installdummy("os.remove") -+ -+ io.tmpfile = installdummy("io.tmpfile") -+ io.output = installdummy("io.output") -+ -+ lfs.chdir = installdummy("lfs.chdir") -+ lfs.lock = installdummy("lfs.lock") -+ lfs.touch = installdummy("lfs.touch") -+ lfs.rmdir = installdummy("lfs.rmdir") -+ lfs.mkdir = installdummy("lfs.mkdir") -+ -+end -+ -+if saferoption == 1 or shellescape ~= 1 then -+ -+ ffi = require('ffi') -+ for k, v in next, ffi do -+ if k ~= 'gc' then -+ ffi[k] = nil -+ end -+ end -+ ffi = nil -+ -+end -+ -+-- os.[execute|os.spawn|os.exec] already are shellescape aware) -+ -+ -+if md5 then -+ -+ local sum = md5.sum -+ local gsub = string.gsub -+ local format = string.format -+ local byte = string.byte -+ -+ if not md5.sumhexa then -+ function md5.sumhexa(k) -+ return (gsub(sum(k), ".", function(c) -+ return format("%02x",byte(c)) -+ end)) -+ end -+ end -+ -+ if not md5.sumHEXA then -+ function md5.sumHEXA(k) -+ return (gsub(sum(k), ".", function(c) -+ return format("%02X",byte(c)) -+ end)) -+ end -+ end -+ -+end -+ -+-- compatibility: this might go away -+ -+if not unpack then -+ unpack = table.unpack -+end -+ -+if not package.loaders then -+ package.loaders = package.searchers -+end -+ -+if not loadstring then -+ loadstring = load -+end -+ -+-- compatibility: this might stay -+ -+if bit32 then -+ -+ -- lua 5.2: we're okay -+ -+elseif utf8 then -+ -+ -- lua 5.3: bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto -+ -+ bit32 = load ( [[ -+local select = select -- instead of: arg = { ... } -+ -+bit32 = { -+ bnot = function (a) -+ return ~a & 0xFFFFFFFF -+ end, -+ band = function (x, y, z, ...) -+ if not z then -+ return ((x or -1) & (y or -1)) & 0xFFFFFFFF -+ else -+ local res = x & y & z -+ for i=1,select("#",...) do -+ res = res & select(i,...) -+ end -+ return res & 0xFFFFFFFF -+ end -+ end, -+ bor = function (x, y, z, ...) -+ if not z then -+ return ((x or 0) | (y or 0)) & 0xFFFFFFFF -+ else -+ local res = x | y | z -+ for i=1,select("#",...) do -+ res = res | select(i,...) -+ end -+ return res & 0xFFFFFFFF -+ end -+ end, -+ bxor = function (x, y, z, ...) -+ if not z then -+ return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF -+ else -+ local res = x ~ y ~ z -+ for i=1,select("#",...) do -+ res = res ~ select(i,...) -+ end -+ return res & 0xFFFFFFFF -+ end -+ end, -+ btest = function (x, y, z, ...) -+ if not z then -+ return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 -+ else -+ local res = x & y & z -+ for i=1,select("#",...) do -+ res = res & select(i,...) -+ end -+ return (res & 0xFFFFFFFF) ~= 0 -+ end -+ end, -+ lshift = function (a, b) -+ return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF -+ end, -+ rshift = function (a, b) -+ return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF -+ end, -+ arshift = function (a, b) -+ a = a & 0xFFFFFFFF -+ if b <= 0 or (a & 0x80000000) == 0 then -+ return (a >> b) & 0xFFFFFFFF -+ else -+ return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF -+ end -+ end, -+ lrotate = function (a ,b) -+ b = b & 31 -+ a = a & 0xFFFFFFFF -+ a = (a << b) | (a >> (32 - b)) -+ return a & 0xFFFFFFFF -+ end, -+ rrotate = function (a, b) -+ b = -b & 31 -+ a = a & 0xFFFFFFFF -+ a = (a << b) | (a >> (32 - b)) -+ return a & 0xFFFFFFFF -+ end, -+ extract = function (a, f, w) -+ return (a >> f) & ~(-1 << (w or 1)) -+ end, -+ replace = function (a, v, f, w) -+ local mask = ~(-1 << (w or 1)) -+ return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF -+ end, -+} -+ ]] ) -+ -+elseif bit then -+ -+ -- luajit (for now) -+ -+ bit32 = load ( [[ -+local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift -+ -+bit32 = { -+ arshift = bit.arshift, -+ band = band, -+ bnot = bnot, -+ bor = bit.bor, -+ bxor = bit.bxor, -+ btest = function(...) -+ return band(...) ~= 0 -+ end, -+ extract = function(a,f,w) -+ return band(rshift(a,f),2^(w or 1)-1) -+ end, -+ lrotate = bit.rol, -+ lshift = lshift, -+ replace = function(a,v,f,w) -+ local mask = 2^(w or 1)-1 -+ return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) -+ end, -+ rrotate = bit.ror, -+ rshift = rshift, -+} -+ ]] ) -+ -+else -+ -+ -- hope for the best or fail -+ -+ bit32 = require("bit32") -+ -+end -+ -+-- this is needed for getting require("socket") right -+ -+do -+ -+ local loaded = package.loaded -+ -+ if not loaded.socket then loaded.socket = loaded["socket.core"] end -+ if not loaded.mime then loaded.mime = loaded["mime.core"] end -+ -+end -+ -+do -+ -+ local lfsattributes = lfs.attributes -+ local symlinkattributes = lfs.symlinkattributes -+ -+ -- these can now be done using lfs (was dead slow before) -+ -+ if not lfs.isfile then -+ function lfs.isfile(name) -+ local m = lfsattributes(name,"mode") -+ return m == "file" or m == "link" -+ end -+ end -+ -+ if not lfs.isdir then -+ function lfs.isdir(name) -+ local m = lfsattributes(name,"mode") -+ return m == "directory" -+ end -+ end -+ -+ -- shortnames have also be sort of dropped from kpse -+ -+ if not lfs.shortname then -+ function lfs.shortname(name) -+ return name -+ end -+ end -+ -+ -- now there is a target field, so ... -+ -+ if not lfs.readlink then -+ function lfs.readlink(name) -+ return symlinkattributes(name,"target") or nil -+ end -+ end -+ -+end -+ -+-- so far -+ -+if utilities and utilities.merger and utilities.merger.compact then -+ -+ local byte, format, gmatch = string.byte, string.format, string.gmatch -+ local concat = table.concat -+ -+ local data = gsub(io.loaddata('luatex-core.lua'),'if%s+utilities.*','') -+ -+ local t = { } -+ local r = { } -+ local n = 0 -+ local d = gsub(data,'\r\n','\n') -- be nice for unix -+ local s = utilities.merger.compact(d) -- no comments and less spaces -+ -+ t[#t+1] = '/* generated from and by luatex-core.lua */' -+ t[#t+1] = '' -+ -- t[#t+1] = format('/*\n\n%s\n\n*/',d) -+ -- t[#t+1] = '' -+ t[#t+1] = '#include "lua.h"' -+ t[#t+1] = '#include "lauxlib.h"' -+ t[#t+1] = '' -+ t[#t+1] = 'int load_luatex_core_lua (lua_State * L);' -+ t[#t+1] = '' -+ t[#t+1] = 'int load_luatex_core_lua (lua_State * L)' -+ t[#t+1] = '{' -+ t[#t+1] = ' static unsigned char luatex_core_lua[] = {' -+ for c in gmatch(d,'.') do -+ if n == 16 then -+ n = 1 -+ t[#t+1] = ' ' .. concat(r,', ') .. ',' -+ else -+ n = n + 1 -+ end -+ r[n] = format('0x%02x',byte(c)) -+ end -+ n = n + 1 -+ r[n] = '0x00' -+ t[#t+1] = ' ' .. concat(r,', ',1,n) -+ t[#t+1] = ' };' -+ -- t[#t+1] = format('unsigned int luatex_core_lua_len = 0x%x;',#d+1) -+ t[#t+1] = ' return luaL_dostring(L, (const char*) luatex_core_lua);' -+ t[#t+1] = '}' -+ -+ io.savedata('luatex-core.c',concat(t,'\n')) -+ io.savedata('luatex-core-stripped.lua',s) -+ -+end -diff --git a/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsepfa.c b/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsepfa.c -index 1cff6a485..df369b45e 100644 ---- a/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsepfa.c -+++ b/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsepfa.c -@@ -2667,9 +2667,9 @@ static void FontInfoFree(struct fontinfo *fi) { - void PSFontFree(FontDict *fd) { - int i; - -- if ( fd->encoding!=NULL ) -- for ( i=0; i<256; ++i ) -- free( fd->encoding[i]); -+ /*if ( fd->encoding!=NULL ): useless: fd->encoding is *char[256] */ -+ for ( i=0; i<256; ++i ) -+ free( fd->encoding[i]); - free(fd->fontname); - free(fd->cidfontname); - free(fd->registry); -diff --git a/texk/web2c/luatexdir/luafontloader/src/luafflib.c b/texk/web2c/luatexdir/luafontloader/src/luafflib.c -index 8717fe8e3..434413b00 100644 ---- a/texk/web2c/luatexdir/luafontloader/src/luafflib.c -+++ b/texk/web2c/luatexdir/luafontloader/src/luafflib.c -@@ -358,7 +358,7 @@ static void dump_intfield(lua_State * L, const char *name, long int field) - { - lua_checkstack(L, 2); - lua_pushstring(L, name); -- lua_pushnumber(L, field); -+ lua_pushinteger(L, field); - lua_rawset(L, -3); - } - -@@ -366,7 +366,7 @@ static void dump_uintfield(lua_State * L, const char *name, unsigned int field) - { - lua_checkstack(L, 2); - lua_pushstring(L, name); -- lua_pushnumber(L, field); -+ lua_pushinteger(L, field); - lua_rawset(L, -3); - } - -@@ -465,7 +465,7 @@ static void dump_subtable_name(lua_State * L, const char *name, struct lookup_su - next = b; \ - while (next != NULL) { \ - lua_checkstack(L,2); \ -- lua_pushnumber(L,k); k++; \ -+ lua_pushinteger(L,k); k++; \ - lua_createtable(L,0,c); \ - a(L, next); \ - lua_rawset(L,-3); \ -@@ -478,7 +478,7 @@ static void dump_subtable_name(lua_State * L, const char *name, struct lookup_su - next = b; \ - while (next != NULL) { \ - lua_checkstack(L,2); \ -- lua_pushnumber(L,k); k++; \ -+ lua_pushinteger(L,k); k++; \ - lua_createtable(L,0,d); \ - if (a(L, next, c)) \ - lua_rawset(L,-3); \ -@@ -498,7 +498,7 @@ static void do_handle_scriptlanglist(lua_State * L, struct scriptlanglist *sl) - lua_newtable(L); - for (k = 0; k < MAX_LANG; k++) { - if (sl->langs[k] != 0) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_pushstring(L, make_tag_string(sl->langs[k])); - lua_rawset(L, -3); - } -@@ -506,7 +506,7 @@ static void do_handle_scriptlanglist(lua_State * L, struct scriptlanglist *sl) - - if (sl->lang_cnt >= MAX_LANG) { - for (k = MAX_LANG; k < sl->lang_cnt; k++) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_pushstring(L, make_tag_string(sl->morelangs[k - MAX_LANG])); - lua_rawset(L, -3); - } -@@ -672,7 +672,7 @@ static void handle_splinecharlist(lua_State * L, struct splinecharlist *scl) - lua_checkstack(L, 10); - while (next != NULL) { - if (next->sc != NULL) { -- lua_pushnumber(L, k); -+ lua_pushinteger(L, k); - k++; - lua_pushstring(L, next->sc->name); - lua_rawset(L, -3); -@@ -772,8 +772,8 @@ static void do_handle_generic_pst(lua_State * L, struct generic_pst *pst) - } - } else if (pst->type == pst_lcaret) { - for (k = 0; k < pst->u.lcaret.cnt; k++) { -- lua_pushnumber(L, (k + 1)); -- lua_pushnumber(L, pst->u.lcaret.carets[k]); -+ lua_pushinteger(L, (k + 1)); -+ lua_pushinteger(L, pst->u.lcaret.carets[k]); - lua_rawset(L, -3); - } - } -@@ -800,7 +800,7 @@ static void handle_generic_pst(lua_State * L, struct generic_pst *pst) - lua_getfield(L, -1, next->subtable->subtable_name); - } - k = lua_rawlen(L, -1) + 1; -- lua_pushnumber(L, k); -+ lua_pushinteger(L, k); - lua_createtable(L, 0, 4); - do_handle_generic_pst(L, next); - lua_rawset(L, -3); -@@ -808,7 +808,7 @@ static void handle_generic_pst(lua_State * L, struct generic_pst *pst) - lua_pop(L, 1); /* pop the subtable */ - } else { - /* Found a pst without subtable, or without subtable name */ -- lua_pushnumber(L, l); -+ lua_pushinteger(L, l); - l++; - lua_createtable(L, 0, 4); - do_handle_generic_pst(L, next); -@@ -970,17 +970,17 @@ static void handle_splinechar(lua_State * L, struct splinechar *glyph, int hasvm - dump_stringfield(L, "name", glyph->name); - dump_intfield(L, "unicode", glyph->unicodeenc); - lua_createtable(L, 4, 0); -- lua_pushnumber(L, 1); -- lua_pushnumber(L, glyph->xmin); -+ lua_pushinteger(L, 1); -+ lua_pushinteger(L, glyph->xmin); - lua_rawset(L, -3); -- lua_pushnumber(L, 2); -- lua_pushnumber(L, glyph->ymin); -+ lua_pushinteger(L, 2); -+ lua_pushinteger(L, glyph->ymin); - lua_rawset(L, -3); -- lua_pushnumber(L, 3); -- lua_pushnumber(L, glyph->xmax); -+ lua_pushinteger(L, 3); -+ lua_pushinteger(L, glyph->xmax); - lua_rawset(L, -3); -- lua_pushnumber(L, 4); -- lua_pushnumber(L, glyph->ymax); -+ lua_pushinteger(L, 4); -+ lua_pushinteger(L, glyph->ymax); - lua_rawset(L, -3); - lua_setfield(L, -2, "boundingbox"); - if (hasvmetrics) { -@@ -1260,21 +1260,21 @@ static void handle_pfminfo(lua_State * L, struct pfminfo pfm) - dump_intfield(L, "os2_breakchar", pfm.os2_breakchar); - if (pfm.hascodepages) { - lua_newtable(L); -- lua_pushnumber(L, pfm.codepages[0]); -+ lua_pushinteger(L, pfm.codepages[0]); - lua_rawseti(L, -2, 1); -- lua_pushnumber(L, pfm.codepages[1]); -+ lua_pushinteger(L, pfm.codepages[1]); - lua_rawseti(L, -2, 2); - lua_setfield(L, -2, "codepages"); - } - if (pfm.hasunicoderanges) { - lua_newtable(L); -- lua_pushnumber(L, pfm.unicoderanges[0]); -+ lua_pushinteger(L, pfm.unicoderanges[0]); - lua_rawseti(L, -2, 1); -- lua_pushnumber(L, pfm.unicoderanges[1]); -+ lua_pushinteger(L, pfm.unicoderanges[1]); - lua_rawseti(L, -2, 2); -- lua_pushnumber(L, pfm.unicoderanges[2]); -+ lua_pushinteger(L, pfm.unicoderanges[2]); - lua_rawseti(L, -2, 3); -- lua_pushnumber(L, pfm.unicoderanges[3]); -+ lua_pushinteger(L, pfm.unicoderanges[3]); - lua_rawseti(L, -2, 4); - lua_setfield(L, -2, "unicoderanges"); - } -@@ -1292,8 +1292,8 @@ static char *do_handle_enc(lua_State * L, struct enc *enc) - if (enc->char_cnt && enc->unicode != NULL) { - lua_createtable(L, enc->char_cnt, 1); - for (i = 0; i < enc->char_cnt; i++) { -- lua_pushnumber(L, i); -- lua_pushnumber(L, enc->unicode[i]); -+ lua_pushinteger(L, i); -+ lua_pushinteger(L, enc->unicode[i]); - lua_rawset(L, -3); - } - lua_setfield(L, -2, "unicode"); -@@ -1302,7 +1302,7 @@ static char *do_handle_enc(lua_State * L, struct enc *enc) - if (enc->char_cnt && enc->psnames != NULL) { - lua_createtable(L, enc->char_cnt, 1); - for (i = 0; i < enc->char_cnt; i++) { -- lua_pushnumber(L, i); -+ lua_pushinteger(L, i); - lua_pushstring(L, enc->psnames[i]); - lua_rawset(L, -3); - } -@@ -1363,13 +1363,13 @@ static void handle_encmap(lua_State * L, struct encmap *map, int notdef_loc) - for (i = 0; i < map->encmax; i++) { - if (map->map[i] != -1) { - int l = map->map[i]; -- lua_pushnumber(L, i); -+ lua_pushinteger(L, i); - /* - if (l < notdef_loc) -- lua_pushnumber(L, (l + 1)); -+ lua_pushinteger(L, (l + 1)); - else - */ -- lua_pushnumber(L, l); -+ lua_pushinteger(L, l); - lua_rawset(L, -3); - } - } -@@ -1382,11 +1382,11 @@ static void handle_encmap(lua_State * L, struct encmap *map, int notdef_loc) - if (map->backmap[i] != -1) { - /* - if (i < notdef_loc) -- lua_pushnumber(L, (i + 1)); -+ lua_pushinteger(L, (i + 1)); - else - */ -- lua_pushnumber(L, i); -- lua_pushnumber(L, map->backmap[i]); -+ lua_pushinteger(L, i); -+ lua_pushinteger(L, map->backmap[i]); - lua_rawset(L, -3); - } - } -@@ -1488,7 +1488,7 @@ static int do_handle_kernclass(lua_State * L, struct kernclass *kerns, const cha - lua_checkstack(L, 4); - lua_createtable(L, kerns->first_cnt, 1); - for (k = 0; k < kerns->first_cnt; k++) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_pushstring(L, kerns->firsts[k]); - lua_rawset(L, -3); - } -@@ -1496,7 +1496,7 @@ static int do_handle_kernclass(lua_State * L, struct kernclass *kerns, const cha - - lua_createtable(L, kerns->second_cnt, 1); - for (k = 0; k < kerns->second_cnt; k++) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_pushstring(L, kerns->seconds[k]); - lua_rawset(L, -3); - } -@@ -1508,8 +1508,8 @@ static int do_handle_kernclass(lua_State * L, struct kernclass *kerns, const cha - lua_createtable(L, kerns->second_cnt * kerns->first_cnt, 1); - for (k = 0; k < (kerns->second_cnt * kerns->first_cnt); k++) { - if (kerns->offsets[k] != 0) { -- lua_pushnumber(L, (k + 1)); -- lua_pushnumber(L, kerns->offsets[k]); -+ lua_pushinteger(L, (k + 1)); -+ lua_pushinteger(L, kerns->offsets[k]); - lua_rawset(L, -3); - } - } -@@ -1529,8 +1529,8 @@ static void handle_kernclass(lua_State * L, struct kernclass *kerns, const char - int kk; \ - lua_newtable(L); \ - for (kk=0;kklookup_cnt > 0) { - lua_newtable(L); - for (k = 0; k < rule->lookup_cnt; k++) { -- lua_pushnumber(L, (rule->lookups[k].seq + 1)); -+ lua_pushinteger(L, (rule->lookups[k].seq + 1)); - if (rule->lookups[k].lookup != NULL) { - lua_pushstring(L, rule->lookups[k].lookup->lookup_name); - } else { -@@ -1650,7 +1650,7 @@ static void do_handle_generic_fpst(lua_State * L, struct generic_fpst *fpst) - if (fpst->rule_cnt > 0) { - lua_createtable(L, fpst->rule_cnt, 1); - for (k = 0; k < fpst->rule_cnt; k++) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_newtable(L); - handle_fpst_rule(L, &(fpst->rules[k]), fpst->format); - lua_rawset(L, -3); -@@ -1668,7 +1668,7 @@ static void handle_generic_fpst(lua_State * L, struct generic_fpst *fpst) - if (fpst->subtable != NULL && fpst->subtable->subtable_name != NULL) { - lua_pushstring(L, fpst->subtable->subtable_name); - } else { -- lua_pushnumber(L, k); -+ lua_pushinteger(L, k); - k++; - } - lua_createtable(L, 0, 10); -@@ -1680,7 +1680,7 @@ static void handle_generic_fpst(lua_State * L, struct generic_fpst *fpst) - if (next->subtable != NULL && next->subtable->subtable_name != NULL) { - lua_pushstring(L, next->subtable->subtable_name); - } else { -- lua_pushnumber(L, k); -+ lua_pushinteger(L, k); - k++; - } - lua_createtable(L, 0, 10); -@@ -1801,9 +1801,9 @@ static void handle_base(lua_State * L, struct Base *Base) - lua_newtable(L); - for (i = 0; i < Base->baseline_cnt; i++) { - if (next->baseline_pos != NULL) /* default omitted */ -- lua_pushnumber(L, next->baseline_pos[i]); -+ lua_pushinteger(L, next->baseline_pos[i]); - else -- lua_pushnumber(L, 0); -+ lua_pushinteger(L, 0); - lua_rawseti(L, -2, (i + 1)); - } - lua_setfield(L, -2, "baseline"); -@@ -1823,13 +1823,13 @@ static void handle_axismap(lua_State * L, struct axismap *am) - lua_checkstack(L, 3); - lua_newtable(L); - for (i = 0; i < am->points; i++) { -- lua_pushnumber(L, am->blends[i]); -+ lua_pushinteger(L, am->blends[i]); - lua_rawseti(L, -2, (i + 1)); - } - lua_setfield(L, -2, "blends"); - lua_newtable(L); - for (i = 0; i < am->points; i++) { -- lua_pushnumber(L, am->designs[i]); -+ lua_pushinteger(L, am->designs[i]); - lua_rawseti(L, -2, (i + 1)); - } - lua_setfield(L, -2, "designs"); -@@ -1853,7 +1853,7 @@ static void handle_mmset(lua_State * L, struct mmset *mm) - if (mm->instance_count > 0) { - lua_newtable(L); - for (i = 0; i < mm->instance_count * mm->axis_count; i++) { -- lua_pushnumber(L, mm->positions[i]); -+ lua_pushinteger(L, mm->positions[i]); - lua_rawseti(L, -2, (i + 1)); - } - lua_setfield(L, -2, "positions"); -@@ -1878,7 +1878,7 @@ static void handle_mmset(lua_State * L, struct mmset *mm) - - lua_newtable(L); - for (i = 0; i < mm->instance_count; i++) { -- lua_pushnumber(L, mm->defweights[i]); -+ lua_pushinteger(L, mm->defweights[i]); - lua_rawseti(L, -2, (i + 1)); - } - lua_setfield(L, -2, "defweights"); -@@ -1980,14 +1980,14 @@ static void handle_splinefont(lua_State * L, struct splinefont *sf) - } - for (k = 0; k < l; k++) { - if (sf->glyphs[k]) { -- lua_pushnumber(L, (k + 1)); -+ lua_pushinteger(L, (k + 1)); - lua_createtable(L, 0, 12); - handle_splinechar(L, sf->glyphs[k], sf->hasvmetrics); - lua_rawset(L, -3); - } - } - if (sf->glyphs != NULL && l < sf->glyphcnt) { -- lua_pushnumber(L, 0); -+ lua_pushinteger(L, 0); - if (sf->glyphs[l]) { - lua_createtable(L, 0, 12); - handle_splinechar(L, sf->glyphs[l], sf->hasvmetrics); -@@ -2000,7 +2000,7 @@ static void handle_splinefont(lua_State * L, struct splinefont *sf) - if ((l + 1) < sf->glyphcnt) { - for (k = (l + 1); k < sf->glyphcnt; k++) { - if (sf->glyphs[k]) { -- lua_pushnumber(L, k); -+ lua_pushinteger(L, k); - lua_createtable(L, 0, 12); - handle_splinechar(L, sf->glyphs[k], sf->hasvmetrics); - lua_rawset(L, -3); -@@ -2098,8 +2098,8 @@ static void handle_splinefont(lua_State * L, struct splinefont *sf) - dump_enumfield(L, "type", sf->texdata.type, tex_type_enum); - lua_newtable(L); - for (k = 0; k < 22; k++) { -- lua_pushnumber(L, k); -- lua_pushnumber(L, sf->texdata.params[k]); -+ lua_pushinteger(L, k); -+ lua_pushinteger(L, sf->texdata.params[k]); - lua_rawset(L, -3); - } - lua_setfield(L, -2, "params"); -@@ -2590,7 +2590,7 @@ static int ff_glyph_index(lua_State * L) - lua_pushstring(L, glyph->name); - break; - case GK_unicode: -- lua_pushnumber(L, glyph->unicodeenc); -+ lua_pushinteger(L, glyph->unicodeenc); - break; - case GK_boundingbox: - if (glyph->xmax == 0 && glyph->ymax == 0 && glyph->xmin == 0 && glyph->ymin == 0) { -@@ -2602,27 +2602,27 @@ static int ff_glyph_index(lua_State * L) - glyph->ymax = bb.maxy; - } - lua_createtable(L, 4, 0); -- lua_pushnumber(L, 1); -- lua_pushnumber(L, glyph->xmin); -+ lua_pushinteger(L, 1); -+ lua_pushinteger(L, glyph->xmin); - lua_rawset(L, -3); -- lua_pushnumber(L, 2); -- lua_pushnumber(L, glyph->ymin); -+ lua_pushinteger(L, 2); -+ lua_pushinteger(L, glyph->ymin); - lua_rawset(L, -3); -- lua_pushnumber(L, 3); -- lua_pushnumber(L, glyph->xmax); -+ lua_pushinteger(L, 3); -+ lua_pushinteger(L, glyph->xmax); - lua_rawset(L, -3); -- lua_pushnumber(L, 4); -- lua_pushnumber(L, glyph->ymax); -+ lua_pushinteger(L, 4); -+ lua_pushinteger(L, glyph->ymax); - lua_rawset(L, -3); - break; - case GK_vwidth: -- lua_pushnumber(L, glyph->vwidth); -+ lua_pushinteger(L, glyph->vwidth); - break; - case GK_width: -- lua_pushnumber(L, glyph->width); -+ lua_pushinteger(L, glyph->width); - break; - case GK_lsidebearing: -- lua_pushnumber(L, glyph->lsidebearing); -+ lua_pushinteger(L, glyph->lsidebearing); - break; - case GK_class: - if (glyph->glyph_class > 0) { -@@ -2692,31 +2692,31 @@ static int ff_glyph_index(lua_State * L) - break; - case GK_tex_height: - if (glyph->tex_height != TEX_UNDEF) { -- lua_pushnumber(L, glyph->tex_height); -+ lua_pushinteger(L, glyph->tex_height); - } else { - lua_pushnil(L); - } - break; - case GK_tex_depth: - if (glyph->tex_height != TEX_UNDEF) { -- lua_pushnumber(L, glyph->tex_depth); -+ lua_pushinteger(L, glyph->tex_depth); - } else { - lua_pushnil(L); - } - break; - case GK_is_extended_shape: -- lua_pushnumber(L, glyph->is_extended_shape); -+ lua_pushinteger(L, glyph->is_extended_shape); - break; - case GK_italic_correction: - if (glyph->italic_correction != TEX_UNDEF) { -- lua_pushnumber(L, glyph->italic_correction); -+ lua_pushinteger(L, glyph->italic_correction); - } else { - lua_pushnil(L); - } - break; - case GK_top_accent: - if (glyph->top_accent_horiz != TEX_UNDEF) { -- lua_pushnumber(L, glyph->top_accent_horiz); -+ lua_pushinteger(L, glyph->top_accent_horiz); - } else { - lua_pushnil(L); - } -@@ -2794,38 +2794,38 @@ static int ff_index(lua_State * L) - lua_pushstring(L, sf->version); - break; - case FK_italicangle: -- lua_pushnumber(L, sf->italicangle); -+ lua_pushinteger(L, sf->italicangle); - break; - case FK_upos: -- lua_pushnumber(L, sf->upos); -+ lua_pushinteger(L, sf->upos); - break; - case FK_uwidth: -- lua_pushnumber(L, sf->uwidth); -+ lua_pushinteger(L, sf->uwidth); - break; - case FK_ascent: -- lua_pushnumber(L, sf->ascent); -+ lua_pushinteger(L, sf->ascent); - break; - case FK_descent: -- lua_pushnumber(L, sf->descent); -+ lua_pushinteger(L, sf->descent); - break; - case FK_uniqueid: -- lua_pushnumber(L, sf->uniqueid); -+ lua_pushinteger(L, sf->uniqueid); - break; - case FK_glyphcnt: - if (sf->glyphcnt > 0) { -- lua_pushnumber(L, sf->glyphmax - sf->glyphmin + 1); -+ lua_pushinteger(L, sf->glyphmax - sf->glyphmin + 1); - } else { -- lua_pushnumber(L, 0); -+ lua_pushinteger(L, 0); - } - break; - case FK_glyphmax: -- lua_pushnumber(L, sf->glyphmax - 1); -+ lua_pushinteger(L, sf->glyphmax - 1); - break; - case FK_glyphmin: -- lua_pushnumber(L, sf->glyphmin); -+ lua_pushinteger(L, sf->glyphmin); - break; - case FK_units_per_em: -- lua_pushnumber(L, sf->units_per_em); -+ lua_pushinteger(L, sf->units_per_em); - break; - case FK_lookups: - if (sf->possub != NULL) { -@@ -2844,34 +2844,34 @@ static int ff_index(lua_State * L) - lua_setmetatable(L, -2); /* assign the metatable */ - break; - case FK_hasvmetrics: -- lua_pushnumber(L, sf->hasvmetrics); -+ lua_pushinteger(L, sf->hasvmetrics); - break; - case FK_onlybitmaps: -- lua_pushnumber(L, sf->onlybitmaps); -+ lua_pushinteger(L, sf->onlybitmaps); - break; - case FK_serifcheck: -- lua_pushnumber(L, sf->serifcheck); -+ lua_pushinteger(L, sf->serifcheck); - break; - case FK_isserif: -- lua_pushnumber(L, sf->isserif); -+ lua_pushinteger(L, sf->isserif); - break; - case FK_issans: -- lua_pushnumber(L, sf->issans); -+ lua_pushinteger(L, sf->issans); - break; - case FK_encodingchanged: -- lua_pushnumber(L, sf->encodingchanged); -+ lua_pushinteger(L, sf->encodingchanged); - break; - case FK_strokedfont: -- lua_pushnumber(L, sf->strokedfont); -+ lua_pushinteger(L, sf->strokedfont); - break; - case FK_use_typo_metrics: -- lua_pushnumber(L, sf->use_typo_metrics); -+ lua_pushinteger(L, sf->use_typo_metrics); - break; - case FK_weight_width_slope_only: -- lua_pushnumber(L, sf->weight_width_slope_only); -+ lua_pushinteger(L, sf->weight_width_slope_only); - break; - case FK_head_optimized_for_cleartype: -- lua_pushnumber(L, sf->head_optimized_for_cleartype); -+ lua_pushinteger(L, sf->head_optimized_for_cleartype); - break; - case FK_uni_interp: - lua_pushstring(L, uni_interp_enum[(sf->uni_interp + 1)]); -@@ -2967,8 +2967,8 @@ static int ff_index(lua_State * L) - dump_enumfield(L, "type", sf->texdata.type, tex_type_enum); - lua_newtable(L); - for (k = 0; k < 22; k++) { -- lua_pushnumber(L, k); -- lua_pushnumber(L, sf->texdata.params[k]); -+ lua_pushinteger(L, k); -+ lua_pushinteger(L, sf->texdata.params[k]); - lua_rawset(L, -3); - } - lua_setfield(L, -2, "params"); -@@ -3028,16 +3028,16 @@ static int ff_index(lua_State * L) - lua_pushstring(L, sf->chosenname); - break; - case FK_macstyle: -- lua_pushnumber(L, sf->macstyle); -+ lua_pushinteger(L, sf->macstyle); - break; - case FK_fondname: - lua_pushstring(L, sf->fondname); - break; - case FK_design_size: -- lua_pushnumber(L, sf->design_size); -+ lua_pushinteger(L, sf->design_size); - break; - case FK_fontstyle_id: -- lua_pushnumber(L, sf->fontstyle_id); -+ lua_pushinteger(L, sf->fontstyle_id); - break; - case FK_fontstyle_name: - if (sf->fontstyle_name != NULL) { -@@ -3048,13 +3048,13 @@ static int ff_index(lua_State * L) - } - break; - case FK_design_range_bottom: -- lua_pushnumber(L, sf->design_range_bottom); -+ lua_pushinteger(L, sf->design_range_bottom); - break; - case FK_design_range_top: -- lua_pushnumber(L, sf->design_range_top); -+ lua_pushinteger(L, sf->design_range_top); - break; - case FK_strokewidth: -- lua_pushnumber(L, sf->strokewidth); -+ lua_pushinteger(L, sf->strokewidth); - break; - case FK_mark_classes: - if (sf->mark_class_cnt > 0) { -@@ -3071,16 +3071,16 @@ static int ff_index(lua_State * L) - } - break; - case FK_creationtime: -- lua_pushnumber(L, sf->creationtime); -+ lua_pushinteger(L, sf->creationtime); - break; - case FK_modificationtime: -- lua_pushnumber(L, sf->modificationtime); -+ lua_pushinteger(L, sf->modificationtime); - break; - case FK_os2_version: -- lua_pushnumber(L, sf->os2_version); -+ lua_pushinteger(L, sf->os2_version); - break; - case FK_sfd_version: -- lua_pushnumber(L, sf->sfd_version); -+ lua_pushinteger(L, sf->sfd_version); - break; - case FK_math: - if (sf->MATH != NULL) { -@@ -3157,7 +3157,7 @@ static int ff_index(lua_State * L) - } - break; - case FK_extrema_bound: -- lua_pushnumber(L, sf->extrema_bound); -+ lua_pushinteger(L, sf->extrema_bound); - break; - case FK_notdef_loc: - lua_pushinteger(L, notdef_loc(sf)); -diff --git a/texk/web2c/luatexdir/luamd5/md5lib.c b/texk/web2c/luatexdir/luamd5/md5lib.c -index 40fd2de38..dfbc0865a 100644 ---- a/texk/web2c/luatexdir/luamd5/md5lib.c -+++ b/texk/web2c/luatexdir/luamd5/md5lib.c -@@ -5,7 +5,6 @@ - * @author Roberto Ierusalimschy - */ - -- - #include - #include - #include -@@ -15,22 +14,21 @@ - - #include "luamd5.h" - -- - /** - * Hash function. Returns a hash for a given string. - * @param message: arbitrary binary string. - * @return A 128-bit hash string. - */ -+ - static int lmd5 (lua_State *L) { -- char buff[16]; -- size_t l; -- const char *message = luaL_checklstring(L, 1, &l); -- md5(message, l, buff); -- lua_pushlstring(L, buff, 16L); -- return 1; -+ char buff[16]; -+ size_t l; -+ const char *message = luaL_checklstring(L, 1, &l); -+ md5(message, l, buff); -+ lua_pushlstring(L, buff, 16L); -+ return 1; - } - -- - /** - * X-Or. Does a bit-a-bit exclusive-or of two strings. - * @param s1: arbitrary binary string. -@@ -38,78 +36,73 @@ static int lmd5 (lua_State *L) { - * @return a binary string with same length as s1 and s2, - * where each bit is the exclusive-or of the corresponding bits in s1-s2. - */ -+ - static int ex_or (lua_State *L) { -- size_t l1, l2; -- const char *s1 = luaL_checklstring(L, 1, &l1); -- const char *s2 = luaL_checklstring(L, 2, &l2); -- luaL_Buffer b; -- luaL_argcheck( L, l1 == l2, 2, "lengths must be equal" ); -- luaL_buffinit(L, &b); -- while (l1--) luaL_addchar(&b, (*s1++)^(*s2++)); -- luaL_pushresult(&b); -- return 1; -+ size_t l1, l2; -+ const char *s1 = luaL_checklstring(L, 1, &l1); -+ const char *s2 = luaL_checklstring(L, 2, &l2); -+ luaL_Buffer b; -+ luaL_argcheck( L, l1 == l2, 2, "lengths must be equal" ); -+ luaL_buffinit(L, &b); -+ while (l1--) -+ luaL_addchar(&b, (*s1++)^(*s2++)); -+ luaL_pushresult(&b); -+ return 1; - } - -- - static void checkseed (lua_State *L) { -- if (lua_isnone(L, 3)) { /* no seed? */ -- time_t tm = time(NULL); /* for `random' seed */ -- lua_pushlstring(L, (char *)&tm, sizeof(tm)); -- } -+ if (lua_isnone(L, 3)) { /* no seed? */ -+ time_t tm = time(NULL); /* for `random' seed */ -+ lua_pushlstring(L, (char *)&tm, sizeof(tm)); -+ } - } - -- --#define MAXKEY 256 --#define BLOCKSIZE 16 -- -- -+#define MAXKEY 256 -+#define BLOCKSIZE 16 - - static int initblock (lua_State *L, const char *seed, int lseed, char *block) { -- size_t lkey; -- const char *key = luaL_checklstring(L, 2, &lkey); -- if (lkey > MAXKEY) -- luaL_error(L, "key too long (> %d)", MAXKEY); -- memset(block, 0, BLOCKSIZE); -- memcpy(block, seed, lseed); -- memcpy(block+BLOCKSIZE, key, lkey); -- return (int)lkey+BLOCKSIZE; -+ size_t lkey; -+ const char *key = luaL_checklstring(L, 2, &lkey); -+ if (lkey > MAXKEY) -+ luaL_error(L, "key too long (> %d)", MAXKEY); -+ memset(block, 0, BLOCKSIZE); -+ memcpy(block, seed, lseed); -+ memcpy(block+BLOCKSIZE, key, lkey); -+ return (int)lkey+BLOCKSIZE; - } - -- - static void codestream (lua_State *L, const char *msg, size_t lmsg, - char *block, int lblock) { -- luaL_Buffer b; -- luaL_buffinit(L, &b); -- while (lmsg > 0) { -- char code[BLOCKSIZE]; -- int i; -- md5(block, lblock, code); -- for (i=0; i 0; i++, lmsg--) -- code[i] ^= *msg++; -- luaL_addlstring(&b, code, i); -- memcpy(block, code, i); /* update seed */ -- } -- luaL_pushresult(&b); -+ luaL_Buffer b; -+ luaL_buffinit(L, &b); -+ while (lmsg > 0) { -+ char code[BLOCKSIZE]; -+ int i; -+ md5(block, lblock, code); -+ for (i=0; i 0; i++, lmsg--) -+ code[i] ^= *msg++; -+ luaL_addlstring(&b, code, i); -+ memcpy(block, code, i); /* update seed */ -+ } -+ luaL_pushresult(&b); - } - -- - static void decodestream (lua_State *L, const char *cypher, size_t lcypher, - char *block, int lblock) { -- luaL_Buffer b; -- luaL_buffinit(L, &b); -- while (lcypher > 0) { -- char code[BLOCKSIZE]; -- int i; -- md5(block, lblock, code); /* update seed */ -- for (i=0; i 0; i++, lcypher--) -- code[i] ^= *cypher++; -- luaL_addlstring(&b, code, i); -- memcpy(block, cypher-i, i); -- } -- luaL_pushresult(&b); -+ luaL_Buffer b; -+ luaL_buffinit(L, &b); -+ while (lcypher > 0) { -+ char code[BLOCKSIZE]; -+ int i; -+ md5(block, lblock, code); /* update seed */ -+ for (i=0; i 0; i++, lcypher--) -+ code[i] ^= *cypher++; -+ luaL_addlstring(&b, code, i); -+ memcpy(block, cypher-i, i); -+ } -+ luaL_pushresult(&b); - } - -- - /** - * Encrypts a string. Uses the hash function md5 in CFB (Cipher-feedback - * mode). -@@ -117,28 +110,29 @@ static void decodestream (lua_State *L, const char *cypher, size_t lcypher, - * @param key: arbitrary binary string to be used as a key. - * @param [seed]: optional arbitrary binary string to be used as a seed. - * if no seed is provided, the function uses the result of --* time() as a seed. -+* time() as a seed. - * @return The cyphertext (as a binary string). - */ -+ - static int crypt (lua_State *L) { -- size_t lmsg; -- const char *msg = luaL_checklstring(L, 1, &lmsg); -- size_t lseed; -- const char *seed; -- int lblock; -- char block[BLOCKSIZE+MAXKEY]; -- checkseed(L); -- seed = luaL_checklstring(L, 3, &lseed); -- if (lseed > BLOCKSIZE) -- luaL_error(L, "seed too long (> %d)", BLOCKSIZE); -- /* put seed and seed length at the beginning of result */ -- block[0] = (char)lseed; -- memcpy(block+1, seed, lseed); -- lua_pushlstring(L, block, lseed+1); /* to concat with result */ -- lblock = initblock(L, seed, lseed, block); -- codestream(L, msg, lmsg, block, lblock); -- lua_concat(L, 2); -- return 1; -+ size_t lmsg; -+ const char *msg = luaL_checklstring(L, 1, &lmsg); -+ size_t lseed; -+ const char *seed; -+ int lblock; -+ char block[BLOCKSIZE+MAXKEY]; -+ checkseed(L); -+ seed = luaL_checklstring(L, 3, &lseed); -+ if (lseed > BLOCKSIZE) -+ luaL_error(L, "seed too long (> %d)", BLOCKSIZE); -+ /* put seed and seed length at the beginning of result */ -+ block[0] = (char)lseed; -+ memcpy(block+1, seed, lseed); -+ lua_pushlstring(L, block, lseed+1); /* to concat with result */ -+ lblock = initblock(L, seed, lseed, block); -+ codestream(L, msg, lmsg, block, lblock); -+ lua_concat(L, 2); -+ return 1; - } - - -@@ -151,33 +145,104 @@ static int crypt (lua_State *L) { - * @return The plaintext. - */ - static int decrypt (lua_State *L) { -- size_t lcyphertext; -- const char *cyphertext = luaL_checklstring(L, 1, &lcyphertext); -- size_t lseed = cyphertext[0]; -- const char *seed = cyphertext+1; -- int lblock; -- char block[BLOCKSIZE+MAXKEY]; -- luaL_argcheck(L, lcyphertext >= lseed+1 && lseed <= BLOCKSIZE, 1, -- "invalid cyphered string"); -- cyphertext += lseed+1; -- lcyphertext -= lseed+1; -- lblock = initblock(L, seed, lseed, block); -- decodestream(L, cyphertext, lcyphertext, block, lblock); -- return 1; -+ size_t lcyphertext; -+ const char *cyphertext = luaL_checklstring(L, 1, &lcyphertext); -+ size_t lseed = cyphertext[0]; -+ const char *seed = cyphertext+1; -+ int lblock; -+ char block[BLOCKSIZE+MAXKEY]; -+ luaL_argcheck(L, lcyphertext >= lseed+1 && lseed <= BLOCKSIZE, 1, -+ "invalid cyphered string"); -+ cyphertext += lseed+1; -+ lcyphertext -= lseed+1; -+ lblock = initblock(L, seed, lseed, block); -+ decodestream(L, cyphertext, lcyphertext, block, lblock); -+ return 1; -+} -+ -+/* not now .. doesn't compile anyway -+ -+#include "../luapplib/util/utilmd5.h" -+ -+static int pdfelib_md_5(lua_State * L) -+{ -+ if (lua_type(L,1) == LUA_TSTRING) { -+ uint8_t result[16]; -+ size_t size = 0; -+ const char *data = lua_tolstring(L,1,&size); -+ md5(data,size,result); -+ lua_pushlstring(L,(const char *)result,16); -+ return 1; -+ } -+ return 0; - } - -+*/ - - static struct luaL_Reg md5lib[] = { -- {"sum", lmd5}, -- {"exor", ex_or}, -- {"crypt", crypt}, -- {"decrypt", decrypt}, -- {NULL, NULL} -+ { "sum", lmd5}, -+ { "exor", ex_or}, -+ { "crypt", crypt}, -+ { "decrypt", decrypt}, -+ { NULL, NULL} - }; - -+int luaopen_md5(lua_State *L) { -+ luaL_openlib(L, "md5", md5lib, 0); -+ return 1; -+} -+ -+/* We could use a different file but this is as easy. */ -+ -+#include "../luapplib/util/utilsha.h" -+ -+static int sha2_256(lua_State * L) -+{ -+ if (lua_type(L,1) == LUA_TSTRING) { -+ uint8_t result[SHA256_DIGEST_LENGTH]; -+ size_t size = 0; -+ const char *data = lua_tolstring(L,1,&size); -+ sha256(data,size,result); -+ lua_pushlstring(L,(const char *)result,SHA256_DIGEST_LENGTH); -+ return 1; -+ } -+ return 0; -+} -+ -+static int sha2_384(lua_State * L) -+{ -+ if (lua_type(L,1) == LUA_TSTRING) { -+ size_t size = 0; -+ uint8_t result[SHA384_DIGEST_LENGTH]; -+ const char *data = lua_tolstring(L,1,&size); -+ sha384(data,size,result); -+ lua_pushlstring(L,(const char *)result,SHA384_DIGEST_LENGTH); -+ return 1; -+ } -+ return 0; -+} - --int luaopen_md5 (lua_State *L) { -- luaL_openlib(L, "md5", md5lib, 0); -- return 1; -+static int sha2_512(lua_State * L) -+{ -+ if (lua_type(L,1) == LUA_TSTRING) { -+ uint8_t result[SHA512_DIGEST_LENGTH]; -+ size_t size = 0; -+ const char *data = lua_tolstring(L,1,&size); -+ sha512(data,size,result); -+ lua_pushlstring(L,(const char *)result,SHA512_DIGEST_LENGTH); -+ return 1; -+ } -+ return 0; - } - -+static struct luaL_Reg sha2lib[] = { -+ { "digest256", sha2_256 }, -+ { "digest384", sha2_384 }, -+ { "digest512", sha2_512 }, -+ { NULL, NULL} -+}; -+ -+int luaopen_sha2(lua_State *L) { -+ luaL_openlib(L, "sha2", sha2lib, 0); -+ return 1; -+} -diff --git a/texk/web2c/luatexdir/luasocket/src/lua_preload.c b/texk/web2c/luatexdir/luasocket/src/lua_preload.c -index e9433dfdb..838871c1d 100644 ---- a/texk/web2c/luatexdir/luasocket/src/lua_preload.c -+++ b/texk/web2c/luatexdir/luasocket/src/lua_preload.c -@@ -15,6 +15,7 @@ int luatex_http_lua_open(lua_State*); - int luatex_ftp_lua_open(lua_State*); - - -+extern void luatex_socketlua_open (lua_State *) ; - #include "ftp_lua.c" - #include "headers_lua.c" - #include "http_lua.c" -diff --git a/texk/web2c/luatexdir/luasocket/src/options.c b/texk/web2c/luatexdir/luasocket/src/options.c -index 20f4c2802..fabfe8ce3 100644 ---- a/texk/web2c/luatexdir/luasocket/src/options.c -+++ b/texk/web2c/luatexdir/luasocket/src/options.c -@@ -37,7 +37,7 @@ int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) - while (opt->name && strcmp(name, opt->name)) - opt++; - if (!opt->func) { -- char msg[45]; -+ char msg[57]; - sprintf(msg, "unsupported option `%.35s'", name); - luaL_argerror(L, 2, msg); - } -@@ -50,7 +50,7 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) - while (opt->name && strcmp(name, opt->name)) - opt++; - if (!opt->func) { -- char msg[45]; -+ char msg[57]; - sprintf(msg, "unsupported option `%.35s'", name); - luaL_argerror(L, 2, msg); - } -diff --git a/texk/web2c/luatexdir/luasocket/src/serial.c b/texk/web2c/luatexdir/luasocket/src/serial.c -index f121bbf0a..b666e61f9 100644 ---- a/texk/web2c/luatexdir/luasocket/src/serial.c -+++ b/texk/web2c/luatexdir/luasocket/src/serial.c -@@ -31,44 +31,44 @@ have only one object type. - /*=========================================================================*\ - * Internal function prototypes - \*=========================================================================*/ --static int global_create(lua_State *L); --static int meth_send(lua_State *L); --static int meth_receive(lua_State *L); --static int meth_close(lua_State *L); --static int meth_settimeout(lua_State *L); --static int meth_getfd(lua_State *L); --static int meth_setfd(lua_State *L); --static int meth_dirty(lua_State *L); --static int meth_getstats(lua_State *L); --static int meth_setstats(lua_State *L); -+/*static int global_create(lua_State *L);*/ -+/* static int meth_send(lua_State *L); */ -+/* static int meth_receive(lua_State *L); */ -+/* static int meth_close(lua_State *L); */ -+/* static int meth_settimeout(lua_State *L); */ -+/* static int meth_getfd(lua_State *L); */ -+/* static int meth_setfd(lua_State *L); */ -+/* static int meth_dirty(lua_State *L); */ -+/* static int meth_getstats(lua_State *L); */ -+/* static int meth_setstats(lua_State *L); */ - - /* serial object methods */ --static luaL_Reg serial_methods[] = { -- {"__gc", meth_close}, -- {"__tostring", auxiliar_tostring}, -- {"close", meth_close}, -- {"dirty", meth_dirty}, -- {"getfd", meth_getfd}, -- {"getstats", meth_getstats}, -- {"setstats", meth_setstats}, -- {"receive", meth_receive}, -- {"send", meth_send}, -- {"setfd", meth_setfd}, -- {"settimeout", meth_settimeout}, -- {NULL, NULL} --}; -+/* static luaL_Reg serial_methods[] = { */ -+/* {"__gc", meth_close}, */ -+/* {"__tostring", auxiliar_tostring}, */ -+/* {"close", meth_close}, */ -+/* {"dirty", meth_dirty}, */ -+/* {"getfd", meth_getfd}, */ -+/* {"getstats", meth_getstats}, */ -+/* {"setstats", meth_setstats}, */ -+/* {"receive", meth_receive}, */ -+/* {"send", meth_send}, */ -+/* {"setfd", meth_setfd}, */ -+/* {"settimeout", meth_settimeout}, */ -+/* {NULL, NULL} */ -+/* }; */ - - /*-------------------------------------------------------------------------*\ --* Initializes module -+* Initializes module (luatex extension, unused ) - \*-------------------------------------------------------------------------*/ --LUASOCKET_API int luaopen_socket_serial(lua_State *L) { -- /* create classes */ -- auxiliar_newclass(L, "serial{client}", serial_methods); -- /* create class groups */ -- auxiliar_add2group(L, "serial{client}", "serial{any}"); -- lua_pushcfunction(L, global_create); -- return 1; --} -+/* LUASOCKET_API int luaopen_socket_serial(lua_State *L) { */ -+/* /\* create classes *\/ */ -+/* auxiliar_newclass(L, "serial{client}", serial_methods); */ -+/* /\* create class groups *\/ */ -+/* auxiliar_add2group(L, "serial{client}", "serial{any}"); */ -+/* lua_pushcfunction(L, global_create); */ -+/* return 1; */ -+/* } */ - - /*=========================================================================*\ - * Lua methods -@@ -76,67 +76,67 @@ LUASOCKET_API int luaopen_socket_serial(lua_State *L) { - /*-------------------------------------------------------------------------*\ - * Just call buffered IO methods - \*-------------------------------------------------------------------------*/ --static int meth_send(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); -- return buffer_meth_send(L, &un->buf); --} -- --static int meth_receive(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); -- return buffer_meth_receive(L, &un->buf); --} -- --static int meth_getstats(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); -- return buffer_meth_getstats(L, &un->buf); --} -- --static int meth_setstats(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); -- return buffer_meth_setstats(L, &un->buf); --} -+/* static int meth_send(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); */ -+/* return buffer_meth_send(L, &un->buf); */ -+/* } */ -+ -+/* static int meth_receive(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); */ -+/* return buffer_meth_receive(L, &un->buf); */ -+/* } */ -+ -+/* static int meth_getstats(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); */ -+/* return buffer_meth_getstats(L, &un->buf); */ -+/* } */ -+ -+/* static int meth_setstats(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); */ -+/* return buffer_meth_setstats(L, &un->buf); */ -+/* } */ - - /*-------------------------------------------------------------------------*\ - * Select support methods - \*-------------------------------------------------------------------------*/ --static int meth_getfd(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); -- lua_pushnumber(L, (int) un->sock); -- return 1; --} -- --/* this is very dangerous, but can be handy for those that are brave enough */ --static int meth_setfd(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); -- un->sock = (t_socket) luaL_checknumber(L, 2); -- return 0; --} -- --static int meth_dirty(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); -- lua_pushboolean(L, !buffer_isempty(&un->buf)); -- return 1; --} -+/* static int meth_getfd(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); */ -+/* lua_pushnumber(L, (int) un->sock); */ -+/* return 1; */ -+/* } */ -+ -+/* /\* this is very dangerous, but can be handy for those that are brave enough *\/ */ -+/* static int meth_setfd(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); */ -+/* un->sock = (t_socket) luaL_checknumber(L, 2); */ -+/* return 0; */ -+/* } */ -+ -+/* static int meth_dirty(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); */ -+/* lua_pushboolean(L, !buffer_isempty(&un->buf)); */ -+/* return 1; */ -+/* } */ - - /*-------------------------------------------------------------------------*\ - * Closes socket used by object - \*-------------------------------------------------------------------------*/ --static int meth_close(lua_State *L) --{ -- p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); -- socket_destroy(&un->sock); -- lua_pushnumber(L, 1); -- return 1; --} -+/* static int meth_close(lua_State *L) */ -+/* { */ -+/* p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); */ -+/* socket_destroy(&un->sock); */ -+/* lua_pushnumber(L, 1); */ -+/* return 1; */ -+/* } */ - - - /*-------------------------------------------------------------------------*\ - * Just call tm methods - \*-------------------------------------------------------------------------*/ --static int meth_settimeout(lua_State *L) { -- p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); -- return timeout_meth_settimeout(L, &un->tm); --} -+/* static int meth_settimeout(lua_State *L) { */ -+/* p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); */ -+/* return timeout_meth_settimeout(L, &un->tm); */ -+/* } */ - - /*=========================================================================*\ - * Library functions -@@ -146,35 +146,35 @@ static int meth_settimeout(lua_State *L) { - /*-------------------------------------------------------------------------*\ - * Creates a serial object - \*-------------------------------------------------------------------------*/ --static int global_create(lua_State *L) { -- const char* path = luaL_checkstring(L, 1); -- -- /* allocate unix object */ -- p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); -- -- /* open serial device */ --#if defined(_WIN32) -- t_socket sock = open(path, O_RDWR); --#else -- t_socket sock = open(path, O_NOCTTY|O_RDWR); --#endif -- -- /*printf("open %s on %d\n", path, sock);*/ -- -- if (sock < 0) { -- lua_pushnil(L); -- lua_pushstring(L, socket_strerror(errno)); -- lua_pushnumber(L, errno); -- return 3; -- } -- /* set its type as client object */ -- auxiliar_setclass(L, "serial{client}", -1); -- /* initialize remaining structure fields */ -- socket_setnonblocking(&sock); -- un->sock = sock; -- io_init(&un->io, (p_send) socket_write, (p_recv) socket_read, -- (p_error) socket_ioerror, &un->sock); -- timeout_init(&un->tm, -1, -1); -- buffer_init(&un->buf, &un->io, &un->tm); -- return 1; --} -+/* static int global_create(lua_State *L) { */ -+/* const char* path = luaL_checkstring(L, 1); */ -+ -+/* /\* allocate unix object *\/ */ -+/* p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); */ -+ -+/* /\* open serial device *\/ */ -+/* #if defined(_WIN32) */ -+/* t_socket sock = open(path, O_RDWR); */ -+/* #else */ -+/* t_socket sock = open(path, O_NOCTTY|O_RDWR); */ -+/* #endif */ -+ -+/* /\*printf("open %s on %d\n", path, sock);*\/ */ -+ -+/* if (sock < 0) { */ -+/* lua_pushnil(L); */ -+/* lua_pushstring(L, socket_strerror(errno)); */ -+/* lua_pushnumber(L, errno); */ -+/* return 3; */ -+/* } */ -+/* /\* set its type as client object *\/ */ -+/* auxiliar_setclass(L, "serial{client}", -1); */ -+/* /\* initialize remaining structure fields *\/ */ -+/* socket_setnonblocking(&sock); */ -+/* un->sock = sock; */ -+/* io_init(&un->io, (p_send) socket_write, (p_recv) socket_read, */ -+/* (p_error) socket_ioerror, &un->sock); */ -+/* timeout_init(&un->tm, -1, -1); */ -+/* buffer_init(&un->buf, &un->io, &un->tm); */ -+/* return 1; */ -+/* } */ -diff --git a/texk/web2c/luatexdir/luatex.c b/texk/web2c/luatexdir/luatex.c -index 1c8694987..014d8bfd2 100644 ---- a/texk/web2c/luatexdir/luatex.c -+++ b/texk/web2c/luatexdir/luatex.c -@@ -32,9 +32,9 @@ - stick to "0" upto "9" so users can expect a number represented as string. - */ - --int luatex_version = 107; -+int luatex_version = 109; - int luatex_revision = '0'; --const char *luatex_version_string = "1.07.0"; -+const char *luatex_version_string = "1.09.0"; - const char *engine_name = my_name; - - #include -diff --git a/texk/web2c/luatexdir/luatex_svnversion.h b/texk/web2c/luatexdir/luatex_svnversion.h -index 770aabbeb..90d51ef70 100644 ---- a/texk/web2c/luatexdir/luatex_svnversion.h -+++ b/texk/web2c/luatexdir/luatex_svnversion.h -@@ -1 +1 @@ --#define luatex_svn_revision 6686 -+#define luatex_svn_revision 6924 -diff --git a/texk/web2c/luatexdir/luatexcallbackids.h b/texk/web2c/luatexdir/luatexcallbackids.h -index 9cdef26c5..a345edf64 100644 ---- a/texk/web2c/luatexdir/luatexcallbackids.h -+++ b/texk/web2c/luatexdir/luatexcallbackids.h -@@ -68,8 +68,13 @@ typedef enum { - call_edit_callback, - build_page_insert_callback, - glyph_stream_provider_callback, -+ font_descriptor_objnum_provider_callback, - finish_synctex_callback, -- total_callbacks -+ wrapup_run_callback, -+ new_graf_callback, -+ page_objnum_provider_callback, -+ make_extensible_callback, -+ total_callbacks, - } callback_callback_types; - - /* lcallbacklib.c */ -@@ -96,7 +101,6 @@ extern void get_lua_boolean(const char *table, const char *name, boolean * targe - extern void get_lua_number(const char *table, const char *name, int *target); - extern void get_lua_string(const char *table, const char *name, char **target); - --extern int lua_reader_callback(int callback_id, pointer *buffloc); - - extern char *get_lua_name(int i); - -diff --git a/texk/web2c/luatexdir/pdf/pdfgen.h b/texk/web2c/luatexdir/pdf/pdfgen.h -index 01b0e74cd..00df7f36e 100644 ---- a/texk/web2c/luatexdir/pdf/pdfgen.h -+++ b/texk/web2c/luatexdir/pdf/pdfgen.h -@@ -114,6 +114,19 @@ printing ones but the output is going to PDF buffer. Subroutines with suffix - pdf_out(pdf, '\n'); \ - } 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; -+ - extern __attribute__ ((format(printf, 2, 3))) - void pdf_printf(PDF, const char *, ...); - -@@ -125,6 +138,7 @@ extern void pdf_print_str(PDF, const char *); - extern void pdf_add_null(PDF); - extern void pdf_add_bool(PDF, int i); - extern void pdf_add_int(PDF, int i); -+extern void pdf_add_real(PDF, double d); - extern void pdf_add_longint(PDF, longinteger n); - extern void pdf_add_ref(PDF, int num); - extern void pdf_add_string(PDF, const char *s); -@@ -140,6 +154,18 @@ extern void pdf_dict_add_streaminfo(PDF); - extern void pdf_begin_stream(PDF); - extern void pdf_end_stream(PDF); - -+typedef unsigned char BYTE; -+typedef unsigned long ULONG; -+ -+typedef struct { -+ ULONG length; -+ BYTE *data; -+} pdf_obj; -+ -+extern pdf_obj *pdf_new_stream(void); -+extern void pdf_add_stream(pdf_obj * stream, unsigned char *buf, long len); -+extern void pdf_release_obj(pdf_obj * stream); -+ - extern void pdf_add_bp(PDF, scaled); - - extern strbuf_s *new_strbuf(size_t size, size_t limit); -@@ -191,8 +217,6 @@ extern char *convertStringToPDFString(const char *in, int len); - extern void initialize_start_time(PDF); - extern char *getcreationdate(PDF); - --extern void check_o_mode(PDF pdf, const char *s, int o_mode, boolean errorflag); -- - extern void set_job_id(PDF, int, int, int, int); - extern char *get_resname_prefix(PDF); - extern void pdf_begin_page(PDF pdf); -@@ -201,6 +225,10 @@ extern void print_pdf_table_string(PDF pdf, const char *s); - extern const char *get_pdf_table_string(const char *s); - extern int get_pdf_table_bool(PDF, const char *, int); - -+extern void pdf_open_file(PDF pdf); -+extern void pdf_write_header(PDF pdf); -+extern void pdf_finish_file(PDF pdf, int fatal_error); -+ - extern void ensure_output_state(PDF pdf, output_state s); - extern PDF init_pdf_struct(PDF pdf); - -@@ -210,8 +238,18 @@ extern halfword pdf_catalog_openaction; - extern halfword pdf_names_toks; /* additional keys of Names dictionary */ - extern halfword pdf_trailer_toks; /* additional keys of Trailer dictionary */ - extern void scan_pdfcatalog(PDF pdf); --extern void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision); - - extern shipping_mode_e global_shipping_mode; - -+extern void pdf_push_list(PDF pdf, scaledpos *saved_pos, int *saved_loc); -+extern void pdf_pop_list(PDF pdf, scaledpos *saved_pos, int *saved_loc); -+ -+extern void pdf_set_reference_point(PDF pdf, posstructure *refpoint); -+ -+/* not pdf specific */ -+ -+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); -+ -+ - #endif -diff --git a/texk/web2c/luatexdir/pdf/pdflistout.h b/texk/web2c/luatexdir/pdf/pdflistout.h -index 76c1d552f..dd3775816 100644 ---- a/texk/web2c/luatexdir/pdf/pdflistout.h -+++ b/texk/web2c/luatexdir/pdf/pdflistout.h -@@ -21,28 +21,12 @@ - #ifndef PDFLISTOUT_H - # define PDFLISTOUT_H - --# define pos_right(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h + (A) --# define pos_left(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h - (A) --# define pos_up(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v + (A) --# define pos_down(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v - (A) -- --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_struct; -- --extern pos_info_structure pos_info; -- --extern backend_function *backend_out; --extern backend_function *backend_out_whatsit; -- --extern void init_backend_functionpointers(output_mode o_mode); -+#define pos_right(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h + (A) -+#define pos_left(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h - (A) -+#define pos_up(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v + (A) -+#define pos_down(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v - (A) - - extern void hlist_out(PDF pdf, halfword this_box, int rule_callback_id); - extern void vlist_out(PDF pdf, halfword this_box, int rule_callback_id); --extern void out_what(PDF pdf, halfword p); - - #endif -diff --git a/texk/web2c/luatexdir/pdf/pdfobj.h b/texk/web2c/luatexdir/pdf/pdfobj.h -index f8fac35ee..f6e49450b 100644 ---- a/texk/web2c/luatexdir/pdf/pdfobj.h -+++ b/texk/web2c/luatexdir/pdf/pdfobj.h -@@ -35,6 +35,7 @@ - - # define OBJ_FLAG_ISSTREAM (1 << 0) - # define OBJ_FLAG_ISFILE (1 << 1) -+# define OBJ_FLAG_NOLENGTH (1 << 2) - - # define obj_obj_is_stream(pdf,A) ((obj_obj_flags((pdf), (A)) & OBJ_FLAG_ISSTREAM) != 0) - # define set_obj_obj_is_stream(pdf,A) ((obj_obj_flags((pdf), (A)) |= OBJ_FLAG_ISSTREAM)) -@@ -44,6 +45,10 @@ - # define set_obj_obj_is_file(pdf,A) ((obj_obj_flags((pdf), (A)) |= OBJ_FLAG_ISFILE)) - # define unset_obj_obj_is_file(pdf,A) ((obj_obj_flags((pdf), (A)) &= ~OBJ_FLAG_ISFILE)) - -+# define obj_obj_no_length(pdf,A) ((obj_obj_flags((pdf), (A)) & OBJ_FLAG_NOLENGTH) != 0) -+# define set_obj_obj_no_length(pdf,A) ((obj_obj_flags((pdf), (A)) |= OBJ_FLAG_NOLENGTH)) -+# define unset_obj_obj_no_length(pdf,A) ((obj_obj_flags((pdf), (A)) &= ~OBJ_FLAG_NOLENGTH)) -+ - extern void init_obj_obj(PDF pdf, int k); - extern void pdf_write_obj(PDF pdf, int n); - extern void scan_obj(PDF pdf); -diff --git a/texk/web2c/luatexdir/pdf/pdftables.h b/texk/web2c/luatexdir/pdf/pdftables.h -index e29c5603d..8aa7403c1 100644 ---- a/texk/web2c/luatexdir/pdf/pdftables.h -+++ b/texk/web2c/luatexdir/pdf/pdftables.h -@@ -139,6 +139,8 @@ typedef enum { - c_pdf_pk_fixed_dpi, - c_pdf_suppress_optional_info, - c_pdf_omit_cidset, -+ c_pdf_recompress, -+ c_pdf_omit_charset, - } pdf_backend_counters ; - - typedef enum { -@@ -187,6 +189,8 @@ extern int pdf_cur_form; - # define pdf_pk_fixed_dpi get_tex_extension_count_register(c_pdf_pk_fixed_dpi) - # define pdf_suppress_optional_info get_tex_extension_count_register(c_pdf_suppress_optional_info) - # define pdf_omit_cidset get_tex_extension_count_register(c_pdf_omit_cidset) -+# define pdf_omit_charset get_tex_extension_count_register(c_pdf_omit_charset) -+# define pdf_recompress get_tex_extension_count_register(c_pdf_recompress) - - # define pdf_h_origin get_tex_extension_dimen_register(d_pdf_h_origin) - # define pdf_v_origin get_tex_extension_dimen_register(d_pdf_v_origin) -@@ -208,7 +212,9 @@ extern int pdf_cur_form; - # define set_pdf_compress_level(i) set_tex_extension_count_register(c_pdf_compress_level,i) - # define set_pdf_obj_compress_level(i) set_tex_extension_count_register(c_pdf_obj_compress_level,i) - # define set_pdf_omit_cidset(i) set_tex_extension_count_register(c_pdf_omit_cidset,i) -+# define set_pdf_omit_charset(i) set_tex_extension_count_register(c_pdf_omit_charset,i) - # define set_pdf_gen_tounicode(i) set_tex_extension_count_register(c_pdf_gen_tounicode,i) -+# define set_pdf_recompress(i) set_tex_extension_count_register(c_pdf_recompress,i) - - # define set_pdf_decimal_digits(i) set_tex_extension_count_register(c_pdf_decimal_digits,i) - # define set_pdf_pk_resolution(i) set_tex_extension_count_register(c_pdf_pk_resolution,i) -diff --git a/texk/web2c/luatexdir/pdf/pdftypes.h b/texk/web2c/luatexdir/pdf/pdftypes.h -index c5f0393cc..ef6a31e16 100644 ---- a/texk/web2c/luatexdir/pdf/pdftypes.h -+++ b/texk/web2c/luatexdir/pdf/pdftypes.h -@@ -90,10 +90,7 @@ typedef struct { - typedef struct scaledpos_ { - int64_t h; - int64_t v; -- } scaledpos; -- -- -- -+} scaledpos; - - typedef struct scaled_whd_ { - scaled wd; /* TeX width */ -@@ -106,11 +103,11 @@ typedef struct posstructure_ { - int dir; /* direction of stuff to be put onto the page */ - } posstructure; - --typedef struct { -- scaledpos curpos; /* \pdflastpos position */ -- posstructure boxpos; /* box dir and position of the box origin on the page */ -- scaled_whd boxdim; /* box dimensions (in hlist/vlist coordinate system) */ --} pos_info_structure; -+/* typedef struct { */ -+/* scaledpos curpos; */ /* \pdflastpos position */ -+/* posstructure boxpos; */ /* box dir and position of the box origin on the page */ -+/* scaled_whd boxdim; */ /* box dimensions (in hlist/vlist coordinate system) */ -+/* } pos_info_structure; */ - - typedef enum { - PMODE_NONE, -@@ -159,6 +156,10 @@ typedef struct { - int need_tf; /* flag whether Tf needs to be set */ - int need_tm; /* flag whether Tm needs to be set */ - int cur_ex; /* the current glyph ex factor */ -+ int need_width; -+ int need_mode; -+ int done_width; -+ int done_mode; - } pdfstructure; - - typedef struct obj_entry_ { -@@ -292,9 +293,11 @@ typedef struct pdf_output_file_ { - int decimal_digits; - int gen_tounicode; - int omit_cidset; -+ int omit_charset; - int inclusion_copy_font; - int major_version; /* fixed major part of the PDF version */ - int minor_version; /* fixed minor part of the PDF version */ -+ int recompress; - int compress_level; /* level for zlib object stream compression */ - int objcompresslevel; /* fixed level for activating PDF object streams */ - char *job_id_string; /* the full job string */ -@@ -351,6 +354,8 @@ typedef struct pdf_output_file_ { - int xform_count; - int ximage_count; - -+ int force_file; -+ - pdf_resource_struct *page_resources; - - scaledpos page_size; /* width and height of page being shipped */ -diff --git a/texk/web2c/luatexdir/ptexlib.h b/texk/web2c/luatexdir/ptexlib.h -index 21bb9348c..f63f480b0 100644 ---- a/texk/web2c/luatexdir/ptexlib.h -+++ b/texk/web2c/luatexdir/ptexlib.h -@@ -153,7 +153,8 @@ size_t T##_limit - # include "tex/expand.h" - # include "tex/conditional.h" - --# include "pdf/pdftypes.h" /* the backend data structure, shared between dvi and pdf */ -+# include "pdf/pdftypes.h" /* the backend data structure, shared between dvi and pdf (might move to |tex/backend| */ -+# include "tex/backend.h" /* more backend data */ - - # include "synctex.h" - -@@ -254,7 +255,7 @@ int lua_appendtovlist_callback( - halfword box, int location, halfword prev_depth, boolean is_mirrored, - halfword * result, int * next_depth, boolean * prev_set); - --void lua_pdf_literal(PDF pdf, int i); -+void lua_pdf_literal(PDF pdf, int i, int noline); - void copy_pdf_literal(pointer r, pointer p); - void free_pdf_literal(pointer p); - void show_pdf_literal(pointer p); -@@ -277,7 +278,7 @@ void undump_luac_registers(void); - void luacstring_start(int n); - void luacstring_close(int n); - int luacstring_cattable(void); --int luacstring_input(void); -+int luacstring_input(halfword *n); - int luacstring_partial(void); - int luacstring_final_line(void); - -@@ -293,6 +294,7 @@ void flush_loggable_info(void); - - /* lua/luastuff.w */ - void luafunctioncall(int slot); -+void luabytecodecall(int slot); - - /* lua/luastuff.c */ - void luatokencall(int p, int nameptr); -diff --git a/texk/web2c/luatexdir/tex/commands.h b/texk/web2c/luatexdir/tex/commands.h -index 8eabaa4e7..c3a3ca304 100644 ---- a/texk/web2c/luatexdir/tex/commands.h -+++ b/texk/web2c/luatexdir/tex/commands.h -@@ -89,6 +89,7 @@ typedef enum { - char_num_cmd, /* character specified numerically ( \.{\\char} ) */ - math_char_num_cmd, /* explicit math code ( \.{\\mathchar} ) */ - mark_cmd, /* mark definition ( \.{\\mark} ) */ -+ node_cmd, - xray_cmd, /* peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~) */ - make_box_cmd, /* make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~) */ - hmove_cmd, /* horizontal motion ( \.{\\moveleft}, \.{\\moveright} ) */ -@@ -134,6 +135,9 @@ typedef enum { - normal_cmd, /* general extensions to \TeX\ that don't fit into a category */ - extension_cmd, /* extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~) */ - option_cmd, -+ lua_function_call_cmd, -+ lua_bytecode_call_cmd, -+ lua_call_cmd, - in_stream_cmd, /* files for reading ( \.{\\openin}, \.{\\closein} ) */ - begin_group_cmd, /* begin local grouping ( \.{\\begingroup} ) */ - end_group_cmd, /* end local grouping ( \.{\\endgroup} ) */ -@@ -179,7 +183,9 @@ typedef enum { - set_font_cmd, /* set current font ( font identifiers ) */ - def_font_cmd, /* define a font file ( \.{\\font} ) */ - register_cmd, /* internal register ( \.{\\count}, \.{\\dimen}, etc.~) */ -+ assign_box_direction_cmd, /* (\.{\\boxdirection}) */ - assign_box_dir_cmd, /* (\.{\\boxdir}) */ -+ assign_direction_cmd, /* (\.{\\pagedirection}, \.{\\textdirection}) */ - assign_dir_cmd, /* (\.{\\pagedir}, \.{\\textdir}) */ - # define max_internal_cmd assign_dir_cmd /* the largest code that can follow \.{\\the} */ - advance_cmd, /* advance a register or parameter ( \.{\\advance} ) */ -@@ -188,6 +194,7 @@ typedef enum { - prefix_cmd, /* qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} ) */ - let_cmd, /* assign a command code ( \.{\\let}, \.{\\futurelet} ) */ - shorthand_def_cmd, /* code definition ( \.{\\chardef}, \.{\\countdef}, etc.~) */ -+ def_lua_call_cmd, - read_to_cs_cmd, /* read into a control sequence ( \.{\\read} ) */ - def_cmd, /* macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} ) */ - set_box_cmd, /* set a box ( \.{\\setbox} ) */ -@@ -201,6 +208,8 @@ typedef enum { - expand_after_cmd, /* special expansion ( \.{\\expandafter} ) */ - no_expand_cmd, /* special nonexpansion ( \.{\\noexpand} ) */ - input_cmd, /* input a source file ( \.{\\input}, \.{\\endinput} or \.{\\scantokens} or \.{\\scantextokens} ) */ -+ lua_expandable_call_cmd, -+ lua_local_call_cmd, - if_test_cmd, /* conditional text ( \.{\\if}, \.{\\ifcase}, etc.~) */ - fi_or_else_cmd, /* delimiters for conditionals ( \.{\\else}, etc.~) */ - cs_name_cmd, /* make a control sequence from tokens ( \.{\\csname} ) */ -@@ -236,9 +245,12 @@ typedef enum { - - typedef enum { - number_code = 0, /* command code for \.{\\number} */ -- lua_function_code, /* command code for \.{\\luafunction} */ - lua_code, /* command code for \.{\\directlua} */ -+ lua_function_code, /* command code for \.{\\luafunction} */ -+ lua_bytecode_code, /* command code for \.{\\luabytecode} */ - expanded_code, /* command code for \.{\\expanded} */ -+ immediate_assignment_code, /* command code for \.{\\immediateassignment} */ -+ immediate_assigned_code, /* command code for \.{\\assigned} */ - math_style_code, /* command code for \.{\\mathstyle} */ - string_code, /* command code for \.{\\string} */ - cs_string_code, /* command code for \.{\\csstring} */ -@@ -324,6 +336,7 @@ typedef enum { - set_random_seed_code, - save_pos_code, - late_lua_code, -+ late_lua_call_code, - expand_font_code, - } normal_codes; - -diff --git a/texk/web2c/luatexdir/tex/conditional.h b/texk/web2c/luatexdir/tex/conditional.h -index b6abe7578..483496eec 100644 ---- a/texk/web2c/luatexdir/tex/conditional.h -+++ b/texk/web2c/luatexdir/tex/conditional.h -@@ -24,30 +24,31 @@ - # define unless_code 32 /* amount added for `\.{\\unless}' prefix */ - - typedef enum { -- if_char_code = 0, /* \.{\\if} */ -- if_cat_code = 1, /* \.{\\ifcat} */ -- if_int_code = 2, /* \.{\\ifnum} */ -- if_dim_code = 3, /* \.{\\ifdim} */ -- if_odd_code = 4, /* \.{\\ifodd} */ -- if_vmode_code = 5, /* \.{\\ifvmode} */ -- if_hmode_code = 6, /* \.{\\ifhmode} */ -- if_mmode_code = 7, /* \.{\\ifmmode} */ -- if_inner_code = 8, /* \.{\\ifinner} */ -- if_void_code = 9, /* \.{\\ifvoid} */ -- if_hbox_code = 10, /* \.{\\ifhbox} */ -- if_vbox_code = 11, /* \.{\\ifvbox} */ -- ifx_code = 12, /* \.{\\ifx} */ -- if_eof_code = 13, /* \.{\\ifeof} */ -- if_true_code = 14, /* \.{\\iftrue} */ -- if_false_code = 15, /* \.{\\iffalse} */ -- if_case_code = 16, /* \.{\\ifcase} */ -- if_def_code = 17, /* \.{\\ifdefined} */ -- if_cs_code = 18, /* \.{\\ifcsname} */ -- if_font_char_code = 19, /* \.{\\iffontchar} */ -- if_in_csname_code = 20, /* \.{\\ifincsname} */ -- if_primitive_code = 21, /* \.{\\ifprimitive} */ -- if_abs_num_code = 22, /* \.{\\ifabsnum} */ -- if_abs_dim_code = 23, /* \.{\\ifabsdim} */ -+ if_char_code = 0, /* \.{\\if} */ -+ if_cat_code = 1, /* \.{\\ifcat} */ -+ if_int_code = 2, /* \.{\\ifnum} */ -+ if_dim_code = 3, /* \.{\\ifdim} */ -+ if_odd_code = 4, /* \.{\\ifodd} */ -+ if_vmode_code = 5, /* \.{\\ifvmode} */ -+ if_hmode_code = 6, /* \.{\\ifhmode} */ -+ if_mmode_code = 7, /* \.{\\ifmmode} */ -+ if_inner_code = 8, /* \.{\\ifinner} */ -+ if_void_code = 9, /* \.{\\ifvoid} */ -+ if_hbox_code = 10, /* \.{\\ifhbox} */ -+ if_vbox_code = 11, /* \.{\\ifvbox} */ -+ if_x_code = 12, /* \.{\\ifx} */ -+ if_eof_code = 13, /* \.{\\ifeof} */ -+ if_true_code = 14, /* \.{\\iftrue} */ -+ if_false_code = 15, /* \.{\\iffalse} */ -+ if_case_code = 16, /* \.{\\ifcase} */ -+ if_def_code = 17, /* \.{\\ifdefined} */ -+ if_cs_code = 18, /* \.{\\ifcsname} */ -+ if_font_char_code = 19, /* \.{\\iffontchar} */ -+ if_in_csname_code = 20, /* \.{\\ifincsname} */ -+ if_primitive_code = 21, /* \.{\\ifprimitive} */ -+ if_abs_num_code = 22, /* \.{\\ifabsnum} */ -+ if_abs_dim_code = 23, /* \.{\\ifabsdim} */ -+ if_condition_code = 24, /* \.{\\ifcondition} */ - } if_type_codes; - - # define if_limit_subtype(A) subtype((A)+1) -diff --git a/texk/web2c/luatexdir/tex/directions.h b/texk/web2c/luatexdir/tex/directions.h -index 7ab524a1e..92d6cc18f 100644 ---- a/texk/web2c/luatexdir/tex/directions.h -+++ b/texk/web2c/luatexdir/tex/directions.h -@@ -22,43 +22,19 @@ - # define DIRECTIONS_H - - /* -- # define dir_TLT 0 -- # define dir_TRT 4 -- # define dir_LTL 9 -- # define dir_RTT 24 -- -- extern const char *dir_strings[128]; -+#define dir_swap 4 - */ - --extern const char *dir_strings[8]; -- --extern int dir_swap; -- --/* --# define RETURN_DIR_VALUES(a) \ -- if (s==luaS_##a##_ptr) { \ -- return (dir_##a); \ -- } else if (!absolute_only) { \ -- if (s==luaS_p##a##_ptr) \ -- return (dir_##a); \ -- else if (s==luaS_m##a##_ptr) \ -- return ((dir_##a)-4); \ -- } --*/ -+#define dir_min_value 0 -+#define dir_max_value 3 - --# define RETURN_DIR_VALUES(a) \ -- if (s==lua_key(a)) { \ -- return (dir_##a); \ -- } else if (!absolute_only) { \ -- if (s==lua_key_plus(a)) \ -- return (dir_##a); \ -- else if (s==lua_key_minus(a)) \ -- return ((dir_##a)-4); \ -- } -+#define check_dir_value(d) \ -+ if ((d < dir_min_value) || (d > dir_max_value)) \ -+ d = dir_min_value; - --# define is_mirrored(a) 0 -+#define is_mirrored(a) 0 - --# define is_rotated(a) (a == dir_RTT) -+#define is_rotated(a) (a == dir_RTT) - - /* - -@@ -90,10 +66,12 @@ extern int dir_swap; - (a == dir_RTT && b == dir_TRT) \ - ) - -+ # define dir_TLT_or_TRT(a) (a == dir_TLT || a == dir_TRT) -+ # define dir_LTL_or_RTT(a) (a == dir_LTL || a == dir_RTT) -+ - */ - --/* # define dir_TLT_or_TRT(a) (a == dir_TLT || a == dir_TRT) */ --/* # define dir_LTL_or_RTT(a) (a == dir_LTL || a == dir_RTT) */ -+/* TLT TRT LTL RTT */ - - # define dir_TLT_or_TRT(a) (a < 2) - # define dir_LTL_or_RTT(a) (a > 1) -@@ -174,7 +152,8 @@ extern void initialize_directions(void); - extern halfword new_dir(int s); - - extern const char *string_dir(int d); --extern void print_dir(int d); -+extern void print_dir_par(int d); -+extern void print_dir_text(halfword d); - - extern void scan_direction(void); - -diff --git a/texk/web2c/luatexdir/tex/equivalents.h b/texk/web2c/luatexdir/tex/equivalents.h -index f478b4a41..3ff9ac16d 100644 ---- a/texk/web2c/luatexdir/tex/equivalents.h -+++ b/texk/web2c/luatexdir/tex/equivalents.h -@@ -38,10 +38,10 @@ distinction. - # define biggest_reg 65535 /* the largest allowed register number; must be |< max_quarterword| */ - # define number_regs 65536 /* |biggest_reg+1| */ - # define number_attrs 65536 /* total numbeer of attributes */ --# define biggest_char 1114111 /* the largest allowed character number; must be |< max_halfword| */ --# define too_big_char 1114112 /* |biggest_char+1| */ --# define special_char 1114113 /* |biggest_char+2| */ --# define number_chars 1114112 /* |biggest_char+1| */ -+# define biggest_char 1114111 /* 0x10FFFF, the largest allowed character number; must be |< max_halfword| */ -+# define too_big_char (biggest_char+1) /* 1114112, |biggest_char+1| */ -+# define special_char (biggest_char+2) /* 1114113, |biggest_char+2| */ -+# define number_chars (biggest_char+3) /* 1114112, |biggest_char+1| */ - # define number_fonts (5535-font_base+1) - # define biggest_lang 32767 - # define too_big_lang 32768 -@@ -292,15 +292,22 @@ the |number_regs| \.{\\dimen} registers. - # define automatic_hyphen_penalty_code 101 - # define explicit_hyphen_penalty_code 102 - # define automatic_hyphen_mode_code 103 --# define break_after_dir_mode_code 104 -- --# define pre_bin_op_penalty_code 105 --# define pre_rel_penalty_code 106 --# define math_penalties_mode_code 107 --# define math_delimiters_mode_code 108 --# define math_script_box_mode_code 109 -- --# define suppress_primitive_error_code 110 -+# define compound_hyphen_mode_code 104 -+# define break_after_dir_mode_code 105 -+# define exception_penalty_code 106 -+ -+# define pre_bin_op_penalty_code 107 -+# define pre_rel_penalty_code 108 -+# define math_penalties_mode_code 109 -+# define math_delimiters_mode_code 110 -+# define math_script_box_mode_code 111 -+# define math_script_char_mode_code 112 -+# define math_rule_thickness_mode_code 113 -+# define math_flatten_mode_code 114 -+ -+# define copy_lua_input_nodes_code 115 -+# define suppress_primitive_error_code 116 -+# define fixup_boxes_code 117 - - # define math_option_code (suppress_primitive_error_code+1) - -@@ -441,7 +448,8 @@ We use the notation |saved(k)| to stand for an item that appears in location - # define saved_boxspec 14 - # define saved_boxdir 15 - # define saved_boxattr 16 --# define saved_boxpack 18 -+# define saved_boxpack 17 -+# define saved_attrlist 18 - # define saved_eqtb 19 - - extern void print_save_stack(void); -@@ -453,10 +461,9 @@ extern void print_save_stack(void); - - typedef enum { - c_mathoption_old_code = 0, /* this one is stable */ -- c_mathoption_no_italic_compensation_code, /* just for tracing, can change */ -- c_mathoption_no_char_italic_code, /* just for tracing, can change */ -- c_mathoption_use_old_fraction_scaling_code, /* just for tracing, can change */ -- c_mathoption_umathcode_meaning_code, /* this one is stable */ -+ /* -+ c_mathoption_umathcode_meaning_code, -+ */ - } math_option_codes ; - - # define mathoption_int_par(A) eqtb[mathoption_int_base+(A)].cint -@@ -525,7 +532,7 @@ typedef enum { - cramped_script_script_style, /* |subtype| for \.{\\crampedscriptscriptstyle} */ - } math_style_subtypes; - --typedef enum { -+typedef enum { /* this could move to directions.h */ - dir_TLT = 0, - dir_TRT, - dir_LTL, -@@ -663,6 +670,9 @@ extern halfword last_cs_name; - #define math_penalties_mode_par int_par(math_penalties_mode_code) - #define math_delimiters_mode_par int_par(math_delimiters_mode_code) - #define math_script_box_mode_par int_par(math_script_box_mode_code) -+#define math_script_char_mode_par int_par(math_script_char_mode_code) -+#define math_rule_thickness_mode_par int_par(math_rule_thickness_mode_code) -+#define math_flatten_mode_par int_par(math_flatten_mode_code) - #define null_delimiter_space_par dimen_par(null_delimiter_space_code) - #define disable_lig_par int_par(disable_lig_code) - #define disable_kern_par int_par(disable_kern_code) -@@ -757,12 +767,13 @@ extern halfword last_cs_name; - #define suppress_ifcsname_error_par int_par(suppress_ifcsname_error_code) - #define suppress_primitive_error_par int_par(suppress_primitive_error_code) - #define error_context_lines_par int_par(error_context_lines_code) -+#define copy_lua_input_nodes_par int_par(copy_lua_input_nodes_code) - - #define math_old_par mathoption_int_par(c_mathoption_old_code) --#define math_no_italic_compensation_par mathoption_int_par(c_mathoption_no_italic_compensation_code) --#define math_no_char_italic_par mathoption_int_par(c_mathoption_no_char_italic_code) --#define math_use_old_fraction_scaling_par mathoption_int_par(c_mathoption_use_old_fraction_scaling_code) -+ -+/* - #define math_umathcode_meaning_par mathoption_int_par(c_mathoption_umathcode_meaning_code) -+*/ - - #define math_pre_display_gap_factor_par int_par(math_pre_display_gap_factor_code) - -@@ -790,11 +801,15 @@ extern halfword last_cs_name; - #define automatic_hyphen_penalty_par int_par(automatic_hyphen_penalty_code) - #define explicit_hyphen_penalty_par int_par(explicit_hyphen_penalty_code) - #define automatic_hyphen_mode_par int_par(automatic_hyphen_mode_code) -+#define compound_hyphen_mode_par int_par(compound_hyphen_mode_code) - #define break_after_dir_mode_par int_par(break_after_dir_mode_code) -+#define exception_penalty_par int_par(exception_penalty_code) - - #define cur_lang_par int_par(cur_lang_code) - #define cur_font_par equiv(cur_font_loc) - -+#define fixup_boxes_par int_par(fixup_boxes_code) -+ - /* */ - - #define math_use_current_family_code 7 -diff --git a/texk/web2c/luatexdir/tex/extensions.h b/texk/web2c/luatexdir/tex/extensions.h -index b68395344..5e22ddf26 100644 ---- a/texk/web2c/luatexdir/tex/extensions.h -+++ b/texk/web2c/luatexdir/tex/extensions.h -@@ -136,9 +136,12 @@ typedef enum { - use_box_resource_code, - save_image_resource_code, - use_image_resource_code, -+ end_local_code, - /* backend */ - dvi_extension_code, - pdf_extension_code, - } extension_codes ; - -+extern void wrapup_leader(halfword p); -+ - #endif -diff --git a/texk/web2c/luatexdir/tex/inputstack.h b/texk/web2c/luatexdir/tex/inputstack.h -index 378fabe24..8c139a833 100644 ---- a/texk/web2c/luatexdir/tex/inputstack.h -+++ b/texk/web2c/luatexdir/tex/inputstack.h -@@ -306,6 +306,7 @@ typedef enum { - mark_text = 14, /* |token_type| code for \.{\\topmark}, etc. */ - every_eof_text = 15, /* |token_type| code for \.{\\everyeof} */ - write_text = 16, /* |token_type| code for \.{\\write} */ -+ local_text = 17, /* |token_type| code for special purposed */ - } token_types; - - extern pointer *param_stack; -diff --git a/texk/web2c/luatexdir/tex/linebreak.h b/texk/web2c/luatexdir/tex/linebreak.h -index 1f4927831..d1e1768f7 100644 ---- a/texk/web2c/luatexdir/tex/linebreak.h -+++ b/texk/web2c/luatexdir/tex/linebreak.h -@@ -20,9 +20,6 @@ - #ifndef LINEBREAK_H - # define LINEBREAK_H - --# define left_side 0 --# define right_side 1 -- - extern halfword just_box; /* the |hlist_node| for the last line of the new paragraph */ - - extern void line_break(boolean d, int line_break_context); -diff --git a/texk/web2c/luatexdir/tex/mainbody.h b/texk/web2c/luatexdir/tex/mainbody.h -index 4a5cb93a1..245535120 100644 ---- a/texk/web2c/luatexdir/tex/mainbody.h -+++ b/texk/web2c/luatexdir/tex/mainbody.h -@@ -139,6 +139,9 @@ extern int filelineerrorstylep; - extern int haltonerrorp; - extern boolean quoted_filename; - -+extern int total_pages; -+extern int dead_cycles; -+ - /* - In order to make efficient use of storage space, \TeX\ bases its major data - structures on a |memory_word|, which contains either a (signed) integer, -diff --git a/texk/web2c/luatexdir/tex/maincontrol.h b/texk/web2c/luatexdir/tex/maincontrol.h -index 13e3c6ff3..04608c11e 100644 ---- a/texk/web2c/luatexdir/tex/maincontrol.h -+++ b/texk/web2c/luatexdir/tex/maincontrol.h -@@ -151,6 +151,7 @@ extern void do_endv(void); - extern void cs_error(void); - extern void prefixed_command(void); - extern void fixup_directions(void); -+extern void fixup_directions_only(void); - - - /* Assignments from Lua need helpers. */ -@@ -205,5 +206,12 @@ extern void show_whatever(void); - - extern void initialize(void); /* this procedure gets things started properly */ - -+/*extern int local_level;*/ -+ -+extern void local_control(void); -+extern halfword local_scan_box(void); -+extern int current_local_level(void); -+extern void end_local_control(void); -+extern void local_control_message(const char *s); - - #endif -diff --git a/texk/web2c/luatexdir/tex/mlist.h b/texk/web2c/luatexdir/tex/mlist.h -index bd1562122..1a15afe3c 100644 ---- a/texk/web2c/luatexdir/tex/mlist.h -+++ b/texk/web2c/luatexdir/tex/mlist.h -@@ -31,5 +31,6 @@ extern void fixup_math_parameters(int fam_id, int size_id, int f, int lvl); - extern scaled get_math_quad_style(int a); - extern scaled get_math_quad_size(int a); - -+extern pointer make_extensible(internal_font_number fnt, halfword chr, scaled v, scaled min_overlap, int horizontal, halfword att); - - #endif -diff --git a/texk/web2c/luatexdir/tex/packaging.h b/texk/web2c/luatexdir/tex/packaging.h -index 6a0802e46..9353afeaf 100644 ---- a/texk/web2c/luatexdir/tex/packaging.h -+++ b/texk/web2c/luatexdir/tex/packaging.h -@@ -143,7 +143,8 @@ latter two are used denote \.{\\vbox} and \.{\\hbox}, respectively. - # define global_box_flag (box_flag+number_regs) /* context code for `\.{\\global\\setbox0}' */ - # define max_global_box_flag (global_box_flag+number_regs) - # define ship_out_flag (max_global_box_flag+1) /* context code for `\.{\\shipout}' */ --# define leader_flag ship_out_flag+1 /* context code for `\.{\\leaders}' */ -+# define lua_scan_flag (max_global_box_flag+2) /* context code for |scan_list| */ -+# define leader_flag (max_global_box_flag+3) /* context code for `\.{\\leaders}' */ - - extern void begin_box(int box_context); - -diff --git a/texk/web2c/luatexdir/tex/printing.h b/texk/web2c/luatexdir/tex/printing.h -index 1619c6072..79ca524ef 100644 ---- a/texk/web2c/luatexdir/tex/printing.h -+++ b/texk/web2c/luatexdir/tex/printing.h -@@ -77,7 +77,7 @@ extern void print_esc(str_number s); - extern void print_the_digs(eight_bits k); - extern void print_int(longinteger n); - extern void print_two(int n); --extern void print_hex(int n); -+extern void print_qhex(int n); - extern void print_roman_int(int n); - extern void print_current_string(void); - -diff --git a/texk/web2c/luatexdir/tex/scanning.h b/texk/web2c/luatexdir/tex/scanning.h -index f5f620c67..e4189a0f6 100644 ---- a/texk/web2c/luatexdir/tex/scanning.h -+++ b/texk/web2c/luatexdir/tex/scanning.h -@@ -63,9 +63,13 @@ extern void scan_fifty_one_bit_int(void); - # define hex_token (other_token+'"') /* double quote, indicates a hex constant */ - # define alpha_token (other_token+'`') /* reverse apostrophe, precedes alpha constants */ - # define point_token (other_token+'.') /* decimal point */ -+# define comma_token (other_token+',') /* decimal comma */ -+# define plus_token (other_token + '+') -+# define minus_token (other_token + '-') - # define continental_point_token (other_token+',') /* decimal point, Eurostyle */ - # define infinity 017777777777 /* the largest positive value that \TeX\ knows */ - # define zero_token (other_token+'0') /* zero, the smallest digit */ -+# define nine_token (other_token+'9') /* zero, the smallest digit */ - # define A_token (letter_token+'A') /* the smallest special hex digit */ - # define other_A_token (other_token+'A') /* special hex digit of type |other_char| */ - extern int radix; -@@ -78,7 +82,6 @@ extern int cur_order; - - extern void scan_dimen(boolean mu, boolean inf, boolean shortcut); - extern void scan_glue(int level); --extern void scan_scaled(void); - - extern halfword the_toks(void); - extern str_number the_scanned_result(void); -diff --git a/texk/web2c/luatexdir/tex/stringpool.h b/texk/web2c/luatexdir/tex/stringpool.h -index a969547e7..2ba156046 100644 ---- a/texk/web2c/luatexdir/tex/stringpool.h -+++ b/texk/web2c/luatexdir/tex/stringpool.h -@@ -1,5 +1,5 @@ - /* stringpool.h -- -+ - Copyright 2009 Taco Hoekwater - - This file is part of LuaTeX. -@@ -43,9 +43,10 @@ extern str_number init_str_ptr; - - # define get_nullstr() STRING_OFFSET - --# define biggest_char 1114111 --# define number_chars 1114112 --# define special_char 1114113 /* |biggest_char+2| */ -+# define biggest_char 1114111 /* 0x10FFFF, the largest allowed character number; must be |< max_halfword| */ -+# define too_big_char (biggest_char+1) /* 1114112, |biggest_char+1| */ -+# define special_char (biggest_char+2) /* 1114113, |biggest_char+2| */ -+# define number_chars (biggest_char+3) /* 1114112, |biggest_char+1| */ - - /* - Several of the elementary string operations are performed using -diff --git a/texk/web2c/luatexdir/tex/texmath.h b/texk/web2c/luatexdir/tex/texmath.h -index 24bb34dc9..23fc5a0e4 100644 ---- a/texk/web2c/luatexdir/tex/texmath.h -+++ b/texk/web2c/luatexdir/tex/texmath.h -@@ -38,22 +38,6 @@ extern halfword new_sub_box(halfword); - - # define default_code 010000000000 /* denotes |default_rule_thickness| */ - --typedef enum { -- ord_noad_type = 0, -- op_noad_type_normal, -- op_noad_type_limits, -- op_noad_type_no_limits, -- bin_noad_type, -- rel_noad_type, -- open_noad_type, -- close_noad_type, -- punct_noad_type, -- inner_noad_type, -- under_noad_type, -- over_noad_type, -- vcenter_noad_type, --} noad_types; -- - extern void initialize_math(void); - extern void initialize_math_spacing(void); - extern halfword math_vcenter_group(halfword); -diff --git a/texk/web2c/luatexdir/tex/texnodes.h b/texk/web2c/luatexdir/tex/texnodes.h -index eb9b2da4a..e77e2916e 100644 ---- a/texk/web2c/luatexdir/tex/texnodes.h -+++ b/texk/web2c/luatexdir/tex/texnodes.h -@@ -97,8 +97,30 @@ extern halfword do_set_attribute(halfword p, int i, int val); - # define list_offset 6 - - typedef enum { -+ user_skip_glue, -+ line_skip_glue, -+ baseline_skip_glue, -+ par_skip_glue, -+ above_display_skip_glue, -+ below_display_skip_glue, -+ above_display_short_skip_glue, -+ below_display_short_skip_glue, -+ left_skip_glue, -+ right_skip_glue, -+ top_skip_glue, -+ split_top_skip_glue, -+ tab_skip_glue, -+ space_skip_glue, -+ xspace_skip_glue, -+ par_fill_skip_glue, -+ math_skip_glue, -+ thin_mu_skip_glue, -+ med_mu_skip_glue, -+ thick_mu_skip_glue, -+ /* math */ - cond_math_glue = 98, /* special |subtype| to suppress glue in the next node */ - mu_glue, /* |subtype| for math glue */ -+ /* leaders */ - a_leaders, /* |subtype| for aligned leaders */ - c_leaders, /* |subtype| for centered leaders */ - x_leaders, /* |subtype| for expanded leaders */ -@@ -199,7 +221,7 @@ typedef enum { - # define disc_penalty(a) vlink((a)+2) - # define pre_break(a) vinfo((a)+3) - # define post_break(a) vlink((a)+3) --# define no_break(a) vlink((a)+4) -+# define no_break(a) vlink((a)+4) /* we have vinfo((a)+4) for later usage */ - - # define vlink_pre_break(a) vlink(pre_break_head(a)) - # define vlink_post_break(a) vlink(post_break_head(a)) -@@ -264,14 +286,17 @@ typedef enum { - math_under_rule, - math_fraction_rule, - math_radical_rule, -+ outline_rule, - } rule_subtypes; - --# define rule_node_size 8 -+# define rule_node_size 9 - # define rule_dir(a) vlink((a)+5) - # define rule_index(a) vinfo((a)+6) - # define rule_transform(a) vlink((a)+6) --# define synctex_tag_rule(a) vinfo((a)+7) --# define synctex_line_rule(a) vlink((a)+7) -+# define rule_left(a) vinfo((a)+7) -+# define rule_right(a) vlink((a)+7) -+# define synctex_tag_rule(a) vinfo((a)+8) -+# define synctex_line_rule(a) vlink((a)+8) - - # define rule_math_size rule_index - # define rule_math_font rule_transform -@@ -292,7 +317,7 @@ typedef enum { - # define x_displace(a) vinfo((a)+4) - # define y_displace(a) vlink((a)+4) - # define ex_glyph(a) vinfo((a)+5) /* expansion factor (hz) */ --# define x_advance(a) vlink((a)+5) /* obsolete, can become user field */ -+# define glyph_node_data(a) vlink((a)+5) - # define synctex_tag_glyph(a) vinfo((a)+6) - # define synctex_line_glyph(a) vlink((a)+6) - -@@ -318,11 +343,15 @@ typedef enum { - - /*@# {|subtype| of marginal kerns}*/ - --# define left_side 0 --# define right_side 1 -+typedef enum { -+ left_side = 0, -+ right_side -+} margin_kern_subtypes ; - --# define before 0 /* |subtype| for math node that introduces a formula */ --# define after 1 /* |subtype| for math node that winds up a formula */ -+typedef enum { -+ before = 0, -+ after -+} math_subtypes ; - - # define math_node_size 7 - /* define width(a) vinfo((a)+2) */ -@@ -487,6 +516,24 @@ typedef enum { - # define noadextra3(a) vlink((a)+7) /* see (!) below */ - # define noadextra4(a) vinfo((a)+7) /* used to store samesize */ - -+# define noad_fam(a) vlink((a)+6) /* noadextra1 */ -+ -+typedef enum { -+ ord_noad_type = 0, -+ op_noad_type_normal, -+ op_noad_type_limits, -+ op_noad_type_no_limits, -+ bin_noad_type, -+ rel_noad_type, -+ open_noad_type, -+ close_noad_type, -+ punct_noad_type, -+ inner_noad_type, -+ under_noad_type, -+ over_noad_type, -+ vcenter_noad_type, -+} noad_types; -+ - /* accent noads */ - - # define accent_noad_size 8 -@@ -495,6 +542,13 @@ typedef enum { - # define overlay_accent_chr(a) vinfo((a)+7) /* the |overlay_accent_chr| field of an accent noad */ - # define accentfraction(a) vlink((a)+7) - -+typedef enum { -+ bothflexible_accent, -+ fixedtop_accent, -+ fixedbottom_accent, -+ fixedboth_accent, -+} math_accent_subtypes ; -+ - /* left and right noads */ - - # define fence_noad_size 8 /* needs to match noad size */ -@@ -540,22 +594,36 @@ typedef enum { - noad_delimiter_mode_noshift = 0x01, - noad_delimiter_mode_italics = 0x02, - noad_delimiter_mode_ordinal = 0x04, -+ noad_delimiter_mode_samenos = 0x08, -+ noad_delimiter_mode_charnos = 0x10, - } delimiter_modes ; - - # define delimitermodenoshift ((math_delimiters_mode_par & noad_delimiter_mode_noshift) == noad_delimiter_mode_noshift) - # define delimitermodeitalics ((math_delimiters_mode_par & noad_delimiter_mode_italics) == noad_delimiter_mode_italics) - # define delimitermodeordinal ((math_delimiters_mode_par & noad_delimiter_mode_ordinal) == noad_delimiter_mode_ordinal) -+# define delimitermodesamenos ((math_delimiters_mode_par & noad_delimiter_mode_samenos) == noad_delimiter_mode_samenos) -+# define delimitermodecharnos ((math_delimiters_mode_par & noad_delimiter_mode_charnos) == noad_delimiter_mode_charnos) - - /* subtype of fence noads */ - -+/* - # define left_noad_side 1 - # define middle_noad_side 2 - # define right_noad_side 3 - # define no_noad_side 4 -+*/ -+ -+typedef enum { -+ unset_noad_side = 0, -+ left_noad_side = 1, -+ middle_noad_side = 2, -+ right_noad_side = 3, -+ no_noad_side = 4, -+} fence_subtypes ; - - /* fraction noads */ - --# define fraction_noad_size 7 -+# define fraction_noad_size 8 - # define thickness(a) vlink((a)+2) /* |thickness| field in a fraction noad */ - # define numerator(a) vlink((a)+3) /* |numerator| field in a fraction noad */ - # define denominator(a) vinfo((a)+3) /* |denominator| field in a fraction noad */ -@@ -563,6 +631,7 @@ typedef enum { - # define right_delimiter(a) vinfo((a)+5) /* second delimiter field of a fraction noad */ - # define middle_delimiter(a) vlink((a)+6) - # define fractionoptions(a) vinfo((a)+6) -+# define fraction_fam(a) vlink((a)+7) - - # define fractionoptionset(a) ((fractionoptions(a) & noad_option_set ) == noad_option_set ) - # define fractionexact(a) ((fractionoptions(a) & noad_option_exact ) == noad_option_exact ) -@@ -582,6 +651,16 @@ typedef enum { - # define radicalmiddle(a) ((radicaloptions(a) & noad_option_middle) == noad_option_middle) - # define radicalright(a) ((radicaloptions(a) & noad_option_right ) == noad_option_right) - -+typedef enum { -+ radical_noad_type, -+ uradical_noad_type, -+ uroot_noad_type, -+ uunderdelimiter_noad_type, -+ uoverdelimiter_noad_type, -+ udelimiterunder_noad_type, -+ udelimiterover_noad_type, -+} radical_subtypes; -+ - /* accessors for the |nucleus|-style node fields */ - - # define math_kernel_node_size 3 -@@ -659,6 +738,15 @@ typedef enum { - # define GLYPH_LEFT (1 << 3) - # define GLYPH_RIGHT (1 << 4) - -+typedef enum { -+ glyph_unset = 0, -+ glyph_character = GLYPH_CHARACTER, -+ glyph_ligature = GLYPH_LIGATURE, -+ glyph_ghost = GLYPH_GHOST, -+ glyph_left = GLYPH_LEFT, -+ glyph_right = GLYPH_RIGHT, -+} glyph_subtypes; -+ - # define is_character(p) ((subtype(p)) & GLYPH_CHARACTER) - # define is_ligature(p) ((subtype(p)) & GLYPH_LIGATURE ) - # define is_ghost(p) ((subtype(p)) & GLYPH_GHOST ) -@@ -698,6 +786,11 @@ typedef enum { - - # define special_node_size 3 - -+typedef enum { -+ normal_dir = 0, -+ cancel_dir, -+} dir_subtypes ; -+ - # define dir_node_size 5 - # define dir_dir(a) vinfo((a)+2) - # define dir_level(a) vlink((a)+2) -@@ -737,6 +830,7 @@ typedef enum { - /* type of literal data */ - - # define lua_refid_literal 1 /* not a |normal| string */ -+# define lua_refid_call 2 /* not a |normal| string */ - - /* begin of pdf backend nodes */ - -@@ -899,40 +993,60 @@ extern void print_short_node_contents(halfword n); - extern void show_node_list(int i); - extern pointer actual_box_width(pointer r, scaled base_width); - --/* from luanode.c */ -+typedef struct _subtype_info { -+ int id; -+ const char *name; -+ int lua; -+} subtype_info; -+ -+typedef struct _field_info { -+ const char *name; -+ int lua; -+} field_info; - - typedef struct _node_info { - int id; - int size; -- const char **fields; -+ subtype_info *subtypes; -+ field_info *fields; - const char *name; - int etex; -+ int lua; - } node_info; - - extern node_info node_data[]; - extern node_info whatsit_node_data[]; - --extern const char *node_subtypes_glue[]; --extern const char *node_subtypes_mathglue[]; --extern const char *node_subtypes_leader[]; --extern const char *node_subtypes_fill[]; --extern const char *node_subtypes_boundary[]; --extern const char *node_subtypes_penalty[]; --extern const char *node_subtypes_kern[]; --extern const char *node_subtypes_rule[]; --extern const char *node_subtypes_glyph[]; --extern const char *node_subtypes_disc[]; --extern const char *node_subtypes_marginkern[]; --extern const char *node_subtypes_list[]; --extern const char *node_subtypes_adjust[]; --extern const char *node_subtypes_math[]; --extern const char *node_subtypes_noad[]; --extern const char *node_subtypes_radical[]; --extern const char *node_subtypes_accent[]; --extern const char *node_subtypes_fence[]; -- --extern const char *node_subtypes_pdf_destination[]; --extern const char *node_subtypes_pdf_literal[]; -+extern subtype_info node_subtypes_dir[]; -+extern subtype_info node_subtypes_glue[]; -+extern subtype_info node_subtypes_mathglue[]; -+extern subtype_info node_subtypes_leader[]; -+extern subtype_info node_subtypes_boundary[]; -+extern subtype_info node_subtypes_penalty[]; -+extern subtype_info node_subtypes_kern[]; -+extern subtype_info node_subtypes_rule[]; -+extern subtype_info node_subtypes_glyph[]; -+extern subtype_info node_subtypes_disc[]; -+extern subtype_info node_subtypes_marginkern[]; -+extern subtype_info node_subtypes_list[]; -+extern subtype_info node_subtypes_adjust[]; -+extern subtype_info node_subtypes_math[]; -+extern subtype_info node_subtypes_noad[]; -+extern subtype_info node_subtypes_radical[]; -+extern subtype_info node_subtypes_accent[]; -+extern subtype_info node_subtypes_fence[]; -+ -+extern subtype_info node_values_pdf_destination[]; -+extern subtype_info node_values_pdf_literal[]; -+extern subtype_info node_values_pdf_literal[]; -+extern subtype_info node_values_pdf_action[]; -+extern subtype_info node_values_pdf_window[]; -+ -+extern subtype_info node_values_fill[]; -+extern subtype_info node_values_dir[]; -+extern subtype_info node_values_color_stack[]; -+ -+extern subtype_info other_values_page_states[]; - - extern halfword new_node(int i, int j); - extern void flush_node_list(halfword); -@@ -958,7 +1072,7 @@ extern void show_node_wrapup_dvi(halfword); - extern void show_node_wrapup_pdf(halfword); - - typedef enum { -- normal_g = 0, -+ normal_g = 0, /* normal */ - sfi, - fil, - fill, -@@ -1037,5 +1151,8 @@ extern void synctex_set_no_files(int flag); - extern int synctex_get_no_files(void); - extern int synctex_get_line(void); - -+extern void l_set_node_data(void) ; -+extern void l_set_whatsit_data(void) ; -+ - #endif - -diff --git a/texk/web2c/luatexdir/tex/textoken.h b/texk/web2c/luatexdir/tex/textoken.h -index 4f46a48c8..4b33b099a 100644 ---- a/texk/web2c/luatexdir/tex/textoken.h -+++ b/texk/web2c/luatexdir/tex/textoken.h -@@ -25,19 +25,19 @@ - # define null 0 - # define cs_token_flag 0x1FFFFFFF - --# define left_brace_token 0x200000 /* $2^{21}\cdot|left_brace|$ */ --# define right_brace_token 0x400000 /* $2^{21}\cdot|right_brace|$ */ --# define left_brace_limit 0x400000 /* $2^{21}\cdot(|left_brace|+1)$ */ --# define right_brace_limit 0x600000 /* $2^{21}\cdot(|right_brace|+1)$ */ --# define math_shift_token 0x600000 /* $2^{21}\cdot|math_shift|$ */ --# define tab_token 0x800000 /* $2^{21}\cdot|tab_mark|$ */ --# define out_param_token 0xA00000 /* $2^{21}\cdot|out_param|$ */ --# define space_token 0x1400020 /* $2^{21}\cdot|spacer|+|" "|$ */ --# define letter_token 0x1600000 /* $2^{21}\cdot|letter|$ */ --# define other_token 0x1800000 /* $2^{21}\cdot|other_char|$ */ --# define match_token 0x1A00000 /* $2^{21}\cdot|match|$ */ --# define end_match_token 0x1C00000 /* $2^{21}\cdot|end_match|$ */ --# define protected_token 0x1C00001 /* $2^{21}\cdot|end_match|+1$ */ -+# define left_brace_token 0x0200000 /* $2^{21}\cdot|left_brace|$ */ -+# define right_brace_token 0x0400000 /* $2^{21}\cdot|right_brace|$ */ -+# define left_brace_limit 0x0400000 /* $2^{21}\cdot(|left_brace|+1)$ */ -+# define right_brace_limit 0x0600000 /* $2^{21}\cdot(|right_brace|+1)$ */ -+# define math_shift_token 0x0600000 /* $2^{21}\cdot|math_shift|$ */ -+# define tab_token 0x0800000 /* $2^{21}\cdot|tab_mark|$ */ -+# define out_param_token 0x0A00000 /* $2^{21}\cdot|out_param|$ */ -+# define space_token 0x1400020 /* $2^{21}\cdot|spacer|+|" "|$ */ -+# define letter_token 0x1600000 /* $2^{21}\cdot|letter|$ */ -+# define other_token 0x1800000 /* $2^{21}\cdot|other_char|$ */ -+# define match_token 0x1A00000 /* $2^{21}\cdot|match|$ */ -+# define end_match_token 0x1C00000 /* $2^{21}\cdot|end_match|$ */ -+# define protected_token 0x1C00001 /* $2^{21}\cdot|end_match|+1$ */ - - # include "tex/stringpool.h" - -@@ -126,6 +126,7 @@ extern void make_token_table(lua_State * L, int cmd, int chr, int cs); - extern void get_next(void); - extern void check_outer_validity(void); - extern boolean scan_keyword(const char *); -+extern boolean scan_keyword_case_sensitive(const char *); - extern halfword active_to_cs(int, int); - extern void get_token_lua(void); - halfword string_to_toks(const char *); -@@ -183,4 +184,6 @@ extern void free_lstring(lstring * ls); - # define token_chr(A) ((A) & (STRING_OFFSET - 1)) - # define token_val(A,B) (((A)< -+ * separation of mpmathbinary from the the core -+ -+ - 2018-02-19 Luigi Scarso - * Small cleanup of the code - * Bump to version 2.0rc2: the current version is 2.00 -diff --git a/texk/web2c/mplibdir/am/libmplib.am b/texk/web2c/mplibdir/am/libmplib.am -index 3d5723119..a4be39e68 100644 ---- a/texk/web2c/mplibdir/am/libmplib.am -+++ b/texk/web2c/mplibdir/am/libmplib.am -@@ -5,15 +5,18 @@ - - ## libmplib.a, used by MetaPost and luaTeX - ## --EXTRA_LIBRARIES += libmplibcore.a libmplibbackends.a -+EXTRA_LIBRARIES += libmplibcore.a libmplibextramath.a libmplibbackends.a - --libmplibcore_a_CPPFLAGS = $(MPFR_INCLUDES) $(GMP_INCLUDES) $(LIBPNG_INCLUDES) $(ZLIB_INCLUDES) $(AM_CPPFLAGS) -I$(srcdir)/mplibdir -+ -+libmplibcore_a_CPPFLAGS = $(LIBPNG_INCLUDES) $(ZLIB_INCLUDES) $(AM_CPPFLAGS) -I$(srcdir)/mplibdir -+libmplibextramath_a_CPPFLAGS = $(MPFR_INCLUDES) $(GMP_INCLUDES) -I${top_builddir}/../../libs $(AM_CPPFLAGS) -I$(srcdir)/mplibdir - libmplibbackends_a_CPPFLAGS = $(MPFR_INCLUDES) $(GMP_INCLUDES) $(CAIRO_INCLUDES) $(PIXMAN_INCLUDES) \ - $(LIBPNG_INCLUDES) $(ZLIB_INCLUDES) $(AM_CPPFLAGS) -I$(srcdir)/mplibdir - --## libmplib C sources core + backends --nodist_libmplibcore_a_SOURCES = tfmin.c $(mp_c_h) $(mpmath_c_h) $(mpmathbinary_c_h) $(mpmathdecimal_c_h) \ -+## libmplib C sources core + extramath + backends -+nodist_libmplibcore_a_SOURCES = tfmin.c $(mp_c_h) $(mpmath_c_h) $(mpmathdecimal_c_h) \ - $(mpmathdouble_c_h) $(mpstrings_c_h) $(psout_c_h) -+nodist_libmplibextramath_a_SOURCES = $(mpmathbinary_c_h) - nodist_libmplibbackends_a_SOURCES = $(pngout_c_h) $(svgout_c_h) - - -@@ -84,15 +87,16 @@ libmplib_web += mplibdir/mpmath.w mplibdir/mpmathbinary.w mplibdir/mpmathdecimal - libmplib_web += mplibdir/mpmathdouble.w mplibdir/mpstrings.w mplibdir/tfmin.w - - ## core need headers backends --$(nodist_libmplibcore_a_SOURCES): $(svgout_c_h) $(pngout_c_h) -+$(nodist_libmplibcore_a_SOURCES): $(mpmathbinary_c_h) $(svgout_c_h) $(pngout_c_h) - --$(libmplibcore_a_OBJECTS): $(nodist_libmplibcore_a_SOURCES) $(KPATHSEA_DEPEND) $(MPFR_DEPEND) -+$(libmplibcore_a_OBJECTS): $(nodist_libmplibcore_a_SOURCES) $(KPATHSEA_DEPEND) -+$(libmplibextramath_a_OBJECTS): $(nodist_libmplibextramath_a_SOURCES) $(KPATHSEA_DEPEND) $(MPFR_DEPEND) - $(libmplibbackends_a_OBJECTS): $(nodist_libmplibbackends_a_SOURCES) $(KPATHSEA_DEPEND) $(CAIRO_DEPEND) $(MPFR_DEPEND) - - - EXTRA_DIST += $(libmplib_web) - --DISTCLEANFILES += $(nodist_libmplibcore_a_SOURCES) $(nodist_libmplibbackends_a_SOURCES) \ -- mp-tangle mpmath-tangle mpmathbinary-tangle mpmathdecimal-tangle mpmathdouble-tangle \ -+DISTCLEANFILES += $(nodist_libmplibcore_a_SOURCES) $(nodist_libmplibextramath_a_SOURCES) $(nodist_libmplibbackends_a_SOURCES) \ -+ mp-tangle mpmath-tangle mpmathdecimal-tangle mpmathdouble-tangle \ - mpstrings-tangle psout-tangle svgout-tangle pngout-tangle - -diff --git a/texk/web2c/mplibdir/am/mplib.am b/texk/web2c/mplibdir/am/mplib.am -index f58658de1..10b1fe4aa 100644 ---- a/texk/web2c/mplibdir/am/mplib.am -+++ b/texk/web2c/mplibdir/am/mplib.am -@@ -18,9 +18,7 @@ endif MP - EXTRA_PROGRAMS += mpost - - mpost_CPPFLAGS = $(AM_CPPFLAGS) $(ZLIB_INCLUDES) $(LIBPNG_INCLUDES) -I$(srcdir)/mplibdir --#mpost_LDADD = libmplib.a $(KPATHSEA_LIBS) $(MPFR_LIBS) $(GMP_LIBS) \ --# $(CAIRO_LIBS) $(PIXMAN_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) libmputil.a --mpost_LDADD = libmplibcore.a libmplibbackends.a $(KPATHSEA_LIBS) $(MPFR_LIBS) $(GMP_LIBS) \ -+mpost_LDADD = libmplibcore.a libmplibextramath.a libmplibbackends.a $(KPATHSEA_LIBS) $(MPFR_LIBS) $(GMP_LIBS) \ - $(CAIRO_LIBS) $(PIXMAN_LIBS) $(LIBPNG_LIBS) $(ZLIB_LIBS) libmputil.a - - -@@ -60,7 +58,7 @@ mpxout-tangle: ctangle$(EXEEXT) mplibdir/mpxout.w tangle-sh - mpost_web = mplibdir/mpost.w mplibdir/mpxout.w - - #$(mpost_OBJECTS): $(nodist_mpost_SOURCES) libmplib.a $(LIBPNG_DEPEND) --$(mpost_OBJECTS): $(nodist_mpost_SOURCES) libmplibcore.a libmplibbackends.a $(LIBPNG_DEPEND) -+$(mpost_OBJECTS): $(nodist_mpost_SOURCES) libmplibcore.a libmplibextramath.a libmplibbackends.a $(LIBPNG_DEPEND) - - EXTRA_DIST += mplibdir/ChangeLog $(mpost_web) - -diff --git a/texk/web2c/mplibdir/lmplib.c b/texk/web2c/mplibdir/lmplib.c -index d90482b88..eb8432bb5 100644 ---- a/texk/web2c/mplibdir/lmplib.c -+++ b/texk/web2c/mplibdir/lmplib.c -@@ -15,7 +15,9 @@ - License for more details. - - You should have received a copy of the GNU Lesser General Public License along -- with LuaTeX; if not, see . */ -+ with LuaTeX; if not, see . -+ -+*/ - - #include - #include -@@ -23,7 +25,7 @@ - #ifdef HAVE_UNISTD_H - #include - #endif --#include /* temporary */ -+#include - - #ifndef pdfTeX - # include -@@ -41,20 +43,23 @@ - #define luaL_reg luaL_Reg - #endif - -- - #ifndef lua_objlen - #define lua_objlen lua_rawlen - #endif - -- - #include "mplib.h" - #include "mplibps.h" - #include "mplibsvg.h" - #include "mplibpng.h" - --int luaopen_mplib(lua_State * L); /* forward */ -+int luaopen_mplib(lua_State * L); - --/* metatable identifiers and tests */ -+/*tex -+ -+ We need a few metatable identifiers in order to access the metatables for the -+ main object and result userdata. -+ -+*/ - - #define MPLIB_METATABLE "MPlib.meta" - #define MPLIB_FIG_METATABLE "MPlib.fig" -@@ -64,25 +69,33 @@ int luaopen_mplib(lua_State * L); /* forward */ - #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE) - #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE) - --/* Lua string pre-hashing */ -+/*tex - --#define mplib_init_S(a) do { \ -- lua_pushliteral(L,#a); \ -- mplib_##a##_ptr = lua_tostring(L,-1); \ -- mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ -- } while (0) -+ We pre-hash the \LUA\ strings which is much faster. The approach is similar to the one -+ used at the \TEX\ end. - --#define mplib_push_S(a) do { \ -- lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \ -- } while (0) -+*/ -+ -+#define mplib_init_S(a) do { \ -+ lua_pushliteral(L,#a); \ -+ mplib_##a##_ptr = lua_tostring(L,-1); \ -+ mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \ -+} while (0) -+ -+#define mplib_push_S(a) do { \ -+ lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \ -+} while (0) - --#define mplib_is_S(a,i) (mplib_##a##_ptr==lua_tostring(L,i)) -+#define mplib_is_S(a,i) \ -+ (mplib_##a##_ptr==lua_tostring(L,i)) - --#define mplib_make_S(a) \ -- static int mplib_##a##_index = 0; \ -- static const char *mplib_##a##_ptr = NULL -+#define mplib_make_S(a) \ -+ static int mplib_##a##_index = 0; \ -+ static const char *mplib_##a##_ptr = NULL - --static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */ -+/*tex In the next array entry 0 is not used */ -+ -+static int mplib_type_Ses[mp_special_code + 1] = { 0 }; - - mplib_make_S(term); - mplib_make_S(error); -@@ -94,6 +107,7 @@ mplib_make_S(memory); - mplib_make_S(hash); - mplib_make_S(params); - mplib_make_S(open); -+mplib_make_S(cycle); - - mplib_make_S(offset); - mplib_make_S(dashes); -@@ -153,6 +167,7 @@ static void mplib_init_Ses(lua_State * L) - mplib_init_S(hash); - mplib_init_S(params); - mplib_init_S(open); -+ mplib_init_S(cycle); - - mplib_init_S(offset); - mplib_init_S(dashes); -@@ -210,11 +225,15 @@ static void mplib_init_Ses(lua_State * L) - mplib_init_S(elliptical); - } - -+/*tex -+ -+ Here are some enumeration arrays to map MPlib enums to \LUA\ strings. If needed -+ we can also predefine keys here, as we do with nodes. - --/* Enumeration arrays to map MPlib enums to Lua strings */ -+*/ - - static const char *math_options[] = -- { "scaled", "double", "binary", "decimal", NULL }; -+ { "scaled", "double", "binary", "decimal", NULL }; - - static const char *interaction_options[] = - { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL }; -@@ -255,18 +274,34 @@ static const char *stop_clip_fields[] = - static const char *no_fields[] = - { NULL }; - -+/*tex - --/* The list of supported MPlib options (not all make sense) */ -+ The list of supported MPlib options (not all make sense). -+ -+*/ - - typedef enum { -- P_ERROR_LINE, P_MAX_LINE, P_RANDOM_SEED, P_MATH_MODE, -- P_INTERACTION, P_INI_VERSION, P_MEM_NAME, P_JOB_NAME, P_FIND_FILE, -- P_RUN_SCRIPT, P_MAKE_TEXT, P_SCRIPT_ERROR, P_EXTENSIONS, -- P__SENTINEL } mplib_parm_idx; -+ P_ERROR_LINE, -+ P_MAX_LINE, -+ P_RANDOM_SEED, -+ P_MATH_MODE, -+ P_INTERACTION, -+ P_INI_VERSION, -+ P_MEM_NAME, -+ P_JOB_NAME, -+ P_FIND_FILE, -+ P_RUN_SCRIPT, -+ P_MAKE_TEXT, -+ P_SCRIPT_ERROR, -+ P_EXTENSIONS, -+ P__SENTINEL -+} mplib_parm_idx; - - typedef struct { -- const char *name; /* parameter name */ -- mplib_parm_idx idx; /* parameter index */ -+ /*tex parameter name */ -+ const char *name; -+ /*tex parameter index */ -+ mplib_parm_idx idx; - } mplib_parm_struct; - - static mplib_parm_struct mplib_parms[] = { -@@ -284,10 +319,11 @@ static mplib_parm_struct mplib_parms[] = { - {NULL, P__SENTINEL } - }; - -+/*tex - --/* Start by defining the needed callback routines for the library */ -+ We start by defining the needed callback routines for the library. - --/* todo: make subtable in registry, beware, for all mp instances */ -+*/ - - static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype) - { -@@ -300,7 +336,7 @@ static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ft - lua_pushstring(L, fname); - lua_pushstring(L, fmode); - if (ftype >= mp_filetype_text) { -- lua_pushnumber(L, (lua_Number)(ftype - mp_filetype_text)); -+ lua_pushinteger(L, (ftype - mp_filetype_text)); - } else { - lua_pushstring(L, mplib_filetype_names[ftype]); - } -@@ -311,7 +347,8 @@ static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ft - x = lua_tostring(L, -1); - if (x != NULL) - s = strdup(x); -- lua_pop(L, 1); /* pop the string */ -+ /*tex pop the string */ -+ lua_pop(L, 1); - return s; - } else { - lua_pop(L, 1); -@@ -325,7 +362,8 @@ static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ft - static int mplib_find_file_function(lua_State * L) - { - if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { -- return 1; /* error */ -+ /*tex An error. */ -+ return 1; - } - lua_pushstring(L, "mplib.file_finder"); - lua_pushvalue(L, -2); -@@ -333,6 +371,11 @@ static int mplib_find_file_function(lua_State * L) - return 0; - } - -+static void mplib_warning(const char *str) -+{ -+ fprintf(stdout,"mplib warning: %s\n",str); -+} -+ - static void mplib_script_error(MP mp, const char *str) - { - lua_State *L = (lua_State *)mp_userdata(mp); -@@ -340,9 +383,10 @@ static void mplib_script_error(MP mp, const char *str) - lua_getfield(L, LUA_REGISTRYINDEX, "mplib.script_error"); - if (lua_isfunction(L, -1)) { - lua_pushstring(L, str); -- lua_pcall(L, 1, 0, 0); /* assume the function is ok */ -+ /*tex We assume that the function is okay. */ -+ lua_pcall(L, 1, 0, 0); - } else { -- fprintf(stdout,"Error in script: %s\n",str); -+ mplib_warning(str); - lua_pop(L, 1); - } - } -@@ -350,7 +394,8 @@ static void mplib_script_error(MP mp, const char *str) - static int mplib_script_error_function(lua_State * L) - { - if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { -- return 1; /* error */ -+ /*tex An error. */ -+ return 1; - } - lua_pushstring(L, "mplib.script_error"); - lua_pushvalue(L, -2); -@@ -368,13 +413,14 @@ static char *mplib_run_script(MP mp, const char *str) - const char *x = NULL; - lua_pushstring(L, str); - if (lua_pcall(L, 1, 1, 0) != 0) { -- mplib_script_error(mp, lua_tostring(L, -1)); -+ fprintf(stdout,"mplib warning: error in script: %s\n",lua_tostring(L, -1)); - return NULL; - } - x = lua_tostring(L, -1); - if (x != NULL) - s = strdup(x); -- lua_pop(L, 1); /* pop the string */ -+ /*tex Pop the string. */ -+ lua_pop(L, 1); - return s; - } else { - lua_pop(L, 1); -@@ -385,7 +431,7 @@ static char *mplib_run_script(MP mp, const char *str) - static int mplib_run_script_function(lua_State * L) - { - if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { -- return 1; /* error */ -+ return 1; /* error */ - } - lua_pushstring(L, "mplib.run_script"); - lua_pushvalue(L, -2); -@@ -410,7 +456,8 @@ static char *mplib_make_text(MP mp, const char *str, int mode) - x = lua_tostring(L, -1); - if (x != NULL) - s = strdup(x); -- lua_pop(L, 1); /* pop the string */ -+ /*tex Pop the string. */ -+ lua_pop(L, 1); - return s; - } else { - lua_pop(L, 1); -@@ -421,7 +468,8 @@ static char *mplib_make_text(MP mp, const char *str, int mode) - static int mplib_make_text_function(lua_State * L) - { - if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) { -- return 1; /* error */ -+ /*tex An error. */ -+ return 1; - } - lua_pushstring(L, "mplib.make_text"); - lua_pushvalue(L, -2); -@@ -487,7 +535,8 @@ static int mplib_new(lua_State * L) - int i; - struct MP_options *options = mp_options(); - options->userdata = (void *) L; -- options->noninteractive = 1; /* required ! */ -+ /*tex Required: */ -+ options->noninteractive = 1; - options->extensions = 0 ; - options->find_file = mplib_find_file; - options->run_script = mplib_run_script; -@@ -500,56 +549,59 @@ static int mplib_new(lua_State * L) - lua_getfield(L, 1, mplib_parms[i].name); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); -- continue; /* skip unset */ -+ continue; - } - switch (mplib_parms[i].idx) { -- case P_ERROR_LINE: -- options->error_line = (int)lua_tointeger(L, -1); -- if (options->error_line<60) options->error_line =60; -- if (options->error_line>250) options->error_line = 250; -- options->half_error_line = (options->error_line/2)+10; -- break; -- case P_MAX_LINE: -- options->max_print_line = (int)lua_tointeger(L, -1); -- if (options->max_print_line<60) options->max_print_line = 60; -- break; -- case P_RANDOM_SEED: -- options->random_seed = (int)lua_tointeger(L, -1); -- break; -- case P_INTERACTION: -- options->interaction = luaL_checkoption(L, -1, "errorstopmode", interaction_options); -- break; -- case P_MATH_MODE: -- options->math_mode = luaL_checkoption(L, -1, "scaled", math_options); -- break; -- case P_JOB_NAME: -- options->job_name = strdup(lua_tostring(L, -1)); -- break; -- case P_FIND_FILE: -- if (mplib_find_file_function(L)) { /* error here */ -- fprintf(stdout,"Invalid arguments to mp.new { find_file = ... }\n"); -- } -- break; -- case P_RUN_SCRIPT: -- if (mplib_run_script_function(L)) { /* error here */ -- fprintf(stdout,"Invalid arguments to mp.new { run_script = ... }\n"); -- } -- break; -- case P_MAKE_TEXT: -- if (mplib_make_text_function(L)) { /* error here */ -- fprintf(stdout,"Invalid arguments to mp.new { make_text = ... }\n"); -- } -- break; -- case P_SCRIPT_ERROR: -- if (mplib_script_error_function(L)) { /* error here */ -- fprintf(stdout,"Invalid arguments to mp.new { script_error = ... }\n"); -- } -- break; -- case P_EXTENSIONS: -- options->extensions = (int)lua_tointeger(L, -1); -- break; -- default: -- break; -+ case P_ERROR_LINE: -+ options->error_line = (int)lua_tointeger(L, -1); -+ if (options->error_line < 60) -+ options->error_line = 60; -+ if (options->error_line > 250) -+ options->error_line = 250; -+ options->half_error_line = (options->error_line/2)+10; -+ break; -+ case P_MAX_LINE: -+ options->max_print_line = (int)lua_tointeger(L, -1); -+ if (options->max_print_line < 60) -+ options->max_print_line = 60; -+ break; -+ case P_RANDOM_SEED: -+ options->random_seed = (int)lua_tointeger(L, -1); -+ break; -+ case P_INTERACTION: -+ options->interaction = luaL_checkoption(L, -1, "errorstopmode", interaction_options); -+ break; -+ case P_MATH_MODE: -+ options->math_mode = luaL_checkoption(L, -1, "scaled", math_options); -+ break; -+ case P_JOB_NAME: -+ options->job_name = strdup(lua_tostring(L, -1)); -+ break; -+ case P_FIND_FILE: -+ if (mplib_find_file_function(L)) { -+ mplib_warning("function expected for 'find_file'"); -+ } -+ break; -+ case P_RUN_SCRIPT: -+ if (mplib_run_script_function(L)) { -+ mplib_warning("function expected for 'run_script'"); -+ } -+ break; -+ case P_MAKE_TEXT: -+ if (mplib_make_text_function(L)) { -+ mplib_warning("function expected for 'make_text'"); -+ } -+ break; -+ case P_SCRIPT_ERROR: -+ if (mplib_script_error_function(L)) { -+ mplib_warning("function expected for 'script_error'"); -+ } -+ break; -+ case P_EXTENSIONS: -+ options->extensions = (int)lua_tointeger(L, -1); -+ break; -+ default: -+ break; - } - lua_pop(L, 1); - } -@@ -626,7 +678,7 @@ static int mplib_wrapresults(lua_State * L, mp_run_data *res, int status) - res->edges = NULL; - } - mplib_push_S(status); -- lua_pushnumber(L, (lua_Number)status); -+ lua_pushinteger(L, status); - lua_rawset(L,-3); - return 1; - } -@@ -716,16 +768,16 @@ static int mplib_statistics(lua_State * L) - if (*mp_ptr != NULL) { - lua_newtable(L); - mplib_push_S(memory); -- lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr)); -+ lua_pushinteger(L, mp_memory_usage(*mp_ptr)); - lua_rawset(L,-3); - mplib_push_S(hash); -- lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr)); -+ lua_pushinteger(L, mp_hash_usage(*mp_ptr)); - lua_rawset(L,-3); - mplib_push_S(params); -- lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr)); -+ lua_pushinteger(L, mp_param_usage(*mp_ptr)); - lua_rawset(L,-3); - mplib_push_S(open); -- lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr)); -+ lua_pushinteger(L, mp_open_usage(*mp_ptr)); - lua_rawset(L,-3); - } else { - lua_pushnil(L); -@@ -733,7 +785,6 @@ static int mplib_statistics(lua_State * L) - return 1; - } - -- - static int set_direction (lua_State * L, MP mp, mp_knot p) { - double direction_x = 0, direction_y = 0; - direction_x = (double)lua_tonumber(L,-1); -@@ -821,8 +872,8 @@ static int set_right_control (lua_State * L, MP mp, mp_knot p) { - return 1; - } - -- - #if 0 -+ - #define ROUNDED_ZERO(v) (fabs((v))<0.00001 ? 0 : (v)) - #define PI 3.1415926535897932384626433832795028841971 - #define RADIANS(a) (mp_number_as_double(mp,(a)) / 16.0) * PI/180.0 -@@ -915,6 +966,7 @@ void mp_dump_path (MP mp, mp_knot h) { - printf("cycle"); - printf (";\n"); - } -+ - #endif - - static int mplib_solve_path(lua_State * L) -@@ -938,10 +990,8 @@ static int mplib_solve_path(lua_State * L) - mp = *mp_ptr; - cyclic = lua_toboolean(L,3); - lua_pop(L,1); -- -- /* build up the path */ -+ /*tex We build up the path. */ - numpoints = lua_objlen(L,2); -- - first = p = NULL; - for (i=1;i<=numpoints;i++) { - int left_set = 0, right_set = 0; -@@ -951,7 +1001,6 @@ static int mplib_solve_path(lua_State * L) - errormsg = "Wrong argument types"; - goto BAD; - } -- - mplib_push_S(x_coord); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { -@@ -960,7 +1009,6 @@ static int mplib_solve_path(lua_State * L) - } - x_coord = (double)lua_tonumber(L,-1); - lua_pop(L,1); -- - mplib_push_S(y_coord); - lua_rawget(L,-2); - if (!lua_isnumber(L,-1)) { -@@ -969,11 +1017,14 @@ static int mplib_solve_path(lua_State * L) - } - y_coord = (double)lua_tonumber(L,-1); - lua_pop(L,1); -- - q = p; - if (q!=NULL) { -- /* we have to save the right_tension because |mp_append_knot| trashes -- it, believing that it is as yet uninitialized */ -+ /*tex -+ -+ We have to save the right_tension because |mp_append_knot| -+ trashes it, believing that it is as yet uninitialized. -+ -+ */ - double saved_tension = mp_number_as_double(mp, mp_knot_right_tension(mp,p)); - p = mp_append_knot(mp, p, x_coord, y_coord); - if ( ! p ) { -@@ -988,10 +1039,8 @@ static int mplib_solve_path(lua_State * L) - goto BAD; - } - } -- - if (first == NULL) - first = p; -- - mplib_push_S(left_curl); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1001,9 +1050,9 @@ static int mplib_solve_path(lua_State * L) - } - left_set = 1; - } else { -- lua_pop(L,1); /* a nil value */ -+ /*tex A |nil| value. */ -+ lua_pop(L,1); - } -- - mplib_push_S(left_tension); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1018,9 +1067,9 @@ static int mplib_solve_path(lua_State * L) - left_set = 1; - } - } else { -- lua_pop(L,1); /* a nil value */ -+ /*tex A |nil| value. */ -+ lua_pop(L,1); - } -- - mplib_push_S(left_x); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1036,7 +1085,6 @@ static int mplib_solve_path(lua_State * L) - } else { - lua_pop(L,1); - } -- - mplib_push_S(right_curl); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1046,9 +1094,9 @@ static int mplib_solve_path(lua_State * L) - } - right_set = 1; - } else { -- lua_pop(L,1); /* a nil value */ -+ /*tex A |nil| value. */ -+ lua_pop(L,1); - } -- - mplib_push_S(right_tension); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1065,7 +1113,6 @@ static int mplib_solve_path(lua_State * L) - } else { - lua_pop(L,1); - } -- - mplib_push_S(right_x); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1081,7 +1128,6 @@ static int mplib_solve_path(lua_State * L) - } else { - lua_pop(L,1); - } -- - mplib_push_S(direction_x); - lua_rawget(L,-2); - if (lua_isnumber(L,-1)) { -@@ -1090,12 +1136,12 @@ static int mplib_solve_path(lua_State * L) - goto BAD; - } - } else { -- lua_pop(L,1); /* a nil value */ -+ /*tex A |nil| value. */ -+ lua_pop(L,1); - } -- -- lua_pop(L,1); /* done with this item */ -+ /*tex Up the next item */ -+ lua_pop(L,1); - } -- - if (cyclic) { - mp_close_path_cycle (mp, p, first); - } else { -@@ -1104,12 +1150,12 @@ static int mplib_solve_path(lua_State * L) - #if 0 - mp_dump_path(mp,first); - #endif -- /* finished reading arguments */ -+ /*tex We're finished reading arguments. */ - if (!mp_solve_path(mp,first)) { - errormsg = "Failed to solve the path"; - goto BAD; - } -- /* squeeze the new values back into the table */ -+ /*tex Squeeze the new values back into the table. */ - p = first; - for (i=1;i<=numpoints;i++) { - lua_rawgeti(L,-1, i); -@@ -1117,14 +1163,14 @@ static int mplib_solve_path(lua_State * L) - mplib_push_S(left_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_left_y(mp, p))); lua_rawset(L,-3); - mplib_push_S(right_x); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_x(mp, p))); lua_rawset(L,-3); - mplib_push_S(right_y); lua_pushnumber(L, mp_number_as_double(mp, mp_knot_right_y(mp, p))); lua_rawset(L,-3); -- /* is this really needed */ -- mplib_push_S(left_tension); lua_pushnil(L); lua_rawset(L,-3); -- mplib_push_S(right_tension); lua_pushnil(L); lua_rawset(L,-3); -- mplib_push_S(left_curl); lua_pushnil(L); lua_rawset(L,-3); -- mplib_push_S(right_curl); lua_pushnil(L); lua_rawset(L,-3); -- mplib_push_S(direction_x); lua_pushnil(L); lua_rawset(L,-3); -- mplib_push_S(direction_y); lua_pushnil(L); lua_rawset(L,-3); -- /* till here */ -+ /*tex This is a bit overkill \unknown */ -+ mplib_push_S(left_tension); lua_pushnil(L); lua_rawset(L,-3); -+ mplib_push_S(right_tension); lua_pushnil(L); lua_rawset(L,-3); -+ mplib_push_S(left_curl); lua_pushnil(L); lua_rawset(L,-3); -+ mplib_push_S(right_curl); lua_pushnil(L); lua_rawset(L,-3); -+ mplib_push_S(direction_x); lua_pushnil(L); lua_rawset(L,-3); -+ mplib_push_S(direction_y); lua_pushnil(L); lua_rawset(L,-3); -+ /*tex \unknown\ till here. */ - mplib_push_S(left_type); lua_pushstring(L, knot_type_enum[mp_knot_left_type(mp, p)]); lua_rawset(L, -3); - mplib_push_S(right_type); lua_pushstring(L, knot_type_enum[mp_knot_right_type(mp, p)]); lua_rawset(L, -3); - lua_pop(L,1); -@@ -1132,7 +1178,7 @@ static int mplib_solve_path(lua_State * L) - } - lua_pushboolean(L, 1); - return 1; --BAD: -+ BAD: - if (p != NULL) { - mp_close_path (mp, p, first); - mp_free_path (mp, p); -@@ -1142,7 +1188,11 @@ BAD: - return 2; - } - --/* figure methods */ -+/*tex -+ -+ The next methods are for collecting the results from |fig|. -+ -+*/ - - static int mplib_fig_collect(lua_State * L) - { -@@ -1171,7 +1221,8 @@ static int mplib_fig_body(lua_State * L) - i++; - p = p->next; - } -- (*hh)->body = NULL; /* prevent double free */ -+ /*tex Prevent a double free: */ -+ (*hh)->body = NULL; - return 1; - } - -@@ -1233,7 +1284,6 @@ static int mplib_fig_svg(lua_State * L) - return 1; - } - -- - static int mplib_fig_png(lua_State * L) - { - mp_run_data *res; -@@ -1316,8 +1366,6 @@ static int mplib_fig_charcode(lua_State * L) - return 1; - } - -- -- - static int mplib_fig_bb(lua_State * L) - { - struct mp_edge_object **hh = is_fig(L, 1); -@@ -1333,7 +1381,11 @@ static int mplib_fig_bb(lua_State * L) - return 1; - } - --/* object methods */ -+/*tex -+ -+ The methods for the figure objects plus a few helpers. -+ -+*/ - - static int mplib_gr_collect(lua_State * L) - { -@@ -1413,7 +1465,6 @@ static double coord_range_y (mp_gr_knot h, double dz) { - return (zhi - zlo <= dz ? aspect_bound : aspect_default); - } - -- - static int mplib_gr_peninfo(lua_State * L) { - double x_coord, y_coord, left_x, left_y, right_x, right_y; - double wx, wy; -@@ -1481,6 +1532,13 @@ static int mplib_gr_peninfo(lua_State * L) { - return 1; - } - -+/*tex -+ -+ Here is a helper that reports the valid field names of the possible -+ objects. -+ -+*/ -+ - static int mplib_gr_fields(lua_State * L) - { - const char **fields; -@@ -1526,7 +1584,6 @@ static int mplib_gr_fields(lua_State * L) - return 1; - } - -- - #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)) - - #define MPLIB_PATH 0 -@@ -1534,7 +1591,7 @@ static int mplib_gr_fields(lua_State * L) - - static void mplib_push_path(lua_State * L, mp_gr_knot h, int is_pen) - { -- mp_gr_knot p; /* for scanning the path */ -+ mp_gr_knot p; - int i = 1; - p = h; - if (p != NULL) { -@@ -1583,16 +1640,63 @@ static void mplib_push_path(lua_State * L, mp_gr_knot h, int is_pen) - } - } - --/* this assumes that the top of the stack is a table -- or nil already in the case -+static int mplib_get_path(lua_State * L) -+{ -+ MP *mp = is_mp(L, 1); -+ if (*mp != NULL) { -+ size_t l; -+ const char *s = lua_tolstring(L, 2, &l); -+ if (s != NULL) { -+ mp_knot p = mp_get_path_value(*mp,s,l) ; -+ if (p != NULL) { -+ int i = 1; -+ mp_knot h = p; -+ lua_newtable(L); -+ do { -+ lua_createtable(L, 6, 1); -+ mplib_push_number(L, mp_number_as_double(*mp,p->x_coord)); -+ lua_rawseti(L,-2,1); -+ mplib_push_number(L, mp_number_as_double(*mp,p->y_coord)); -+ lua_rawseti(L,-2,2); -+ mplib_push_number(L, mp_number_as_double(*mp,p->left_x)); -+ lua_rawseti(L,-2,3); -+ mplib_push_number(L, mp_number_as_double(*mp,p->left_y)); -+ lua_rawseti(L,-2,4); -+ mplib_push_number(L, mp_number_as_double(*mp,p->right_x)); -+ lua_rawseti(L,-2,5); -+ mplib_push_number(L, mp_number_as_double(*mp,p->right_y)); -+ lua_rawseti(L,-2,6); -+ lua_rawseti(L,-2, i); -+ i++; -+ if (p->data.types.right_type == mp_endpoint) { -+ mplib_push_S(cycle); -+ lua_pushboolean(L,0); -+ lua_rawset(L,-3); -+ return 1; -+ } -+ p = p->next; -+ } while (p != h); -+ mplib_push_S(cycle); -+ lua_pushboolean(L,1); -+ lua_rawset(L,-3); -+ return 1; -+ } -+ } -+ } -+ return 0; -+} -+ -+/*tex -+ -+ This assumes that the top of the stack is a table or nil already in the case. - */ - - static void mplib_push_pentype(lua_State * L, mp_gr_knot h) - { -- mp_gr_knot p; /* for scanning the path */ -+ mp_gr_knot p; - p = h; - if (p == NULL) { -- /* do nothing */ -+ /*tex Do nothing. */ - } else if (p == p->next) { - mplib_push_S(type); - mplib_push_S(elliptical); -@@ -1643,7 +1747,11 @@ static void mplib_push_color(lua_State * L, struct mp_graphic_object *p) - } - } - --/* the dash scale is not exported, the field has no external value */ -+/*tex -+ -+ The dash scale is not exported, the field has no external value. -+ -+*/ - - static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h) - { -@@ -1811,7 +1919,6 @@ static int mplib_gr_index(lua_State * L) - struct mp_graphic_object **hh = is_gr_object(L, 1); - if (*hh) { - struct mp_graphic_object *h = *hh; -- - if (mplib_is_S(type, 2)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]); - } else { -@@ -1847,61 +1954,77 @@ static int mplib_gr_index(lua_State * L) - } - - static const struct luaL_reg mplib_meta[] = { -- {"__gc", mplib_collect}, -- {"__tostring", mplib_tostring}, -- {NULL, NULL} /* sentinel */ -+ { "__gc", mplib_collect }, -+ { "__tostring", mplib_tostring }, -+ /*tex sentinel */ -+ { NULL, NULL} - }; - - static const struct luaL_reg mplib_fig_meta[] = { -- {"__gc", mplib_fig_collect}, -- {"__tostring", mplib_fig_tostring}, -- {"objects", mplib_fig_body}, -- {"copy_objects", mplib_fig_copy_body}, -- {"filename", mplib_fig_filename}, -- {"postscript", mplib_fig_postscript}, -- {"png", mplib_fig_png}, -- {"svg", mplib_fig_svg}, -- {"boundingbox", mplib_fig_bb}, -- {"width", mplib_fig_width}, -- {"height", mplib_fig_height}, -- {"depth", mplib_fig_depth}, -- {"italcorr", mplib_fig_italcorr}, -- {"charcode", mplib_fig_charcode}, -- {NULL, NULL} /* sentinel */ -+ { "__gc", mplib_fig_collect }, -+ { "__tostring", mplib_fig_tostring }, -+ { "objects", mplib_fig_body }, -+ { "copy_objects", mplib_fig_copy_body }, -+ { "filename", mplib_fig_filename }, -+ { "postscript", mplib_fig_postscript }, -+ { "png", mplib_fig_png }, -+ { "svg", mplib_fig_svg }, -+ { "boundingbox", mplib_fig_bb }, -+ { "width", mplib_fig_width }, -+ { "height", mplib_fig_height }, -+ { "depth", mplib_fig_depth }, -+ { "italcorr", mplib_fig_italcorr }, -+ { "charcode", mplib_fig_charcode }, -+ /*tex sentinel */ -+ { NULL, NULL} - }; - - static const struct luaL_reg mplib_gr_meta[] = { -- {"__gc", mplib_gr_collect}, -- {"__tostring", mplib_gr_tostring}, -- {"__index", mplib_gr_index}, -- {NULL, NULL} /* sentinel */ -+ { "__gc", mplib_gr_collect}, -+ { "__tostring", mplib_gr_tostring}, -+ { "__index", mplib_gr_index}, -+ /*tex sentinel */ -+ { NULL, NULL} - }; - - static const struct luaL_reg mplib_d[] = { -- {"execute", mplib_execute}, -- {"finish", mplib_finish}, -- {"char_width", mplib_charwidth}, -- {"char_height", mplib_charheight}, -- {"char_depth", mplib_chardepth}, -- {"statistics", mplib_statistics}, -- {"solve_path", mplib_solve_path}, -- {"get_numeric", mplib_get_numeric}, -- {"get_number", mplib_get_numeric}, -- {"get_boolean", mplib_get_boolean}, -- {"get_string", mplib_get_string}, -- {NULL, NULL} /* sentinel */ -+ { "execute", mplib_execute }, -+ { "finish", mplib_finish }, -+ { "char_width", mplib_charwidth }, -+ { "char_height", mplib_charheight }, -+ { "char_depth", mplib_chardepth }, -+ { "statistics", mplib_statistics }, -+ { "solve_path", mplib_solve_path }, -+ { "get_numeric", mplib_get_numeric }, -+ { "get_number", mplib_get_numeric }, -+ { "get_boolean", mplib_get_boolean }, -+ { "get_string", mplib_get_string }, -+ { "get_path", mplib_get_path }, -+ /*tex sentinel */ -+ {NULL, NULL } - }; - - static const struct luaL_reg mplib_m[] = { -- {"new", mplib_new}, -- {"version", mplib_version}, -- {"fields", mplib_gr_fields}, -- {"pen_info", mplib_gr_peninfo}, -- {"get_numeric", mplib_get_numeric}, -- {"get_number", mplib_get_numeric}, -- {"get_boolean", mplib_get_boolean}, -- {"get_string", mplib_get_string}, -- {NULL, NULL} /* sentinel */ -+ { "new", mplib_new }, -+ { "version", mplib_version }, -+ { "fields", mplib_gr_fields }, -+ /* indirect */ -+ { "execute", mplib_execute }, -+ { "finish", mplib_finish }, -+ { "char_width", mplib_charwidth }, -+ { "char_height", mplib_charheight }, -+ { "char_depth", mplib_chardepth }, -+ { "statistics", mplib_statistics }, -+ { "solve_path", mplib_solve_path }, -+ /* helpers */ -+ { "pen_info", mplib_gr_peninfo }, -+ { "get_numeric", mplib_get_numeric }, -+ { "get_number", mplib_get_numeric }, -+ { "get_boolean", mplib_get_boolean }, -+ { "get_string", mplib_get_string }, -+ { "get_path", mplib_get_path }, -+ /*tex sentinel */ -+ { NULL, NULL} - }; - - int luaopen_mplib(lua_State * L) -@@ -1909,22 +2032,23 @@ int luaopen_mplib(lua_State * L) - mplib_init_Ses(L); - - luaL_newmetatable(L, MPLIB_GR_METATABLE); -- lua_pushvalue(L, -1); /* push metatable */ -- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ -- luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */ -+ lua_pushvalue(L, -1); -+ lua_setfield(L, -2, "__index"); -+ luaL_register(L, NULL, mplib_gr_meta); - lua_pop(L, 1); - - luaL_newmetatable(L, MPLIB_FIG_METATABLE); -- lua_pushvalue(L, -1); /* push metatable */ -- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ -- luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */ -+ lua_pushvalue(L, -1); -+ lua_setfield(L, -2, "__index"); -+ luaL_register(L, NULL, mplib_fig_meta); - lua_pop(L, 1); - - luaL_newmetatable(L, MPLIB_METATABLE); -- lua_pushvalue(L, -1); /* push metatable */ -- lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ -- luaL_register(L, NULL, mplib_meta); /* meta methods */ -- luaL_register(L, NULL, mplib_d); /* dict methods */ -- luaL_register(L, "mplib", mplib_m); /* module functions */ -+ lua_pushvalue(L, -1); -+ lua_setfield(L, -2, "__index"); -+ luaL_register(L, NULL, mplib_meta); -+ luaL_register(L, NULL, mplib_d); -+ luaL_register(L, "mplib", mplib_m); -+ - return 1; - } -diff --git a/texk/web2c/mplibdir/mp.w b/texk/web2c/mplibdir/mp.w -index 2c956ea5a..d52ad37ce 100644 ---- a/texk/web2c/mplibdir/mp.w -+++ b/texk/web2c/mplibdir/mp.w -@@ -139,7 +139,7 @@ typedef struct MP_instance { - - @ @c - /*\#define DEBUGENVELOPE */ --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - static int DEBUGENVELOPECOUNTER=0; - #define dbg_str(A) printf("\n--[==[%03d DEBUGENVELOPE ]==] %s", DEBUGENVELOPECOUNTER++, #A) - #define dbg_n(A) printf("\n--[==[%03d DEBUGENVELOPE ]==] ['%s']=%s, ", DEBUGENVELOPECOUNTER++, #A, number_tostring(A)) -@@ -176,8 +176,8 @@ static int DEBUGENVELOPECOUNTER=0; - #include /* for |PNG_LIBPNG_VER_STRING|, |png_libpng_ver| */ - /*\#include */ /* for |PIXMAN_VERSION_STRING|, |pixman_version_string()| */ - /*\#include */ /* for |CAIRO_VERSION_STRING|, |cairo_version_string()| */ --#include /* for |gmp_version| */ --#include /* for |MPFR_VERSION_STRING|, |mpfr_get_version()| */ -+/*\#include */ /* for |gmp_version| */ -+/*\#include */ /* for |MPFR_VERSION_STRING|, |mpfr_get_version()| */ - #include "mplib.h" - #include "mplibps.h" /* external header */ - /*\#include "mplibsvg.h" */ /* external header */ -@@ -189,7 +189,7 @@ static int DEBUGENVELOPECOUNTER=0; - #include "mpmath.h" /* internal header */ - #include "mpmathdouble.h" /* internal header */ - #include "mpmathdecimal.h" /* internal header */ --#include "mpmathbinary.h" /* internal header */ -+/*#include "mpmathbinary.h"*/ /* internal header */ - #include "mpstrings.h" /* internal header */ - /* BEGIN PATCH */ - mp_number dx_ap; /* approximation of dx */ -@@ -200,12 +200,19 @@ mp_number ueps_ap; /* epsilon for above approximations */ - boolean is_dxdy, is_dxindyin; - /* END PATCH */ - --@ We move the {\tt cairo} and {\tt pixman} libraries outside {\tt mp.w}, -+@ We move the {\tt cairo} and {\tt pixman} libraries outside {\tt mp.w}, - to minimize dependencies. - - @c - extern const char *COMPILED_CAIRO_VERSION_STRING; - extern const char* cairo_version_string (void); -+extern const char *COMPILED_MPFR_VERSION_STRING; -+extern const char* mpfr_get_version (void); -+extern void * mp_initialize_binary_math (MP mp) ; -+extern int COMPILED__GNU_MP_VERSION; -+extern int COMPILED__GNU_MP_VERSION_MINOR; -+extern int COMPILED__GNU_MP_VERSION_PATCHLEVEL; -+extern const char * const COMPILED_gmp_version; - extern const char *COMPILED_PIXMAN_VERSION_STRING; - extern const char* pixman_version_string (void); - extern void mp_png_backend_initialize (MP mp); -@@ -2628,7 +2635,7 @@ void mp_new_randoms (MP mp) { - mp->j_random = 54; - } - --@ To consume a random fraction, the program below will say `|next_random|'. -+@ To consume a random fraction, the program below will say `|next_random|'. - Now each number system has its own implementation, - true to the original as much as possibile. - -@@ -2657,7 +2664,7 @@ As said before, now each number system has its own implementation. - @c - /*Unused. - static void mp\_unif\_rand (MP mp, mp\_number *ret, mp\_number x\_orig) { -- mp\_number y; // trial value -+ mp\_number y; // trial value - mp\_number x, abs\_x; - mp\_number u; - new\_fraction (y); -@@ -2896,7 +2903,7 @@ void *do_alloc_node (MP mp, size_t size) { - - @c - void mp_xfree (void *x) { -- if (x != NULL) -+ if (x != NULL) - free (x); - } - void *mp_xrealloc (MP mp, void *p, size_t nmem, size_t size) { -@@ -3235,8 +3242,7 @@ mp_random_seed, /* initialize random number generator (\&{randomseed}) */ - mp_message_command, /* communicate to user (\&{message}, \&{errmessage}) */ - mp_every_job_command, /* designate a starting token (\&{everyjob}) */ - mp_delimiters, /* define a pair of delimiters (\&{delimiters}) */ --mp_special_command, /* output special info (\&{special}) -- or font map info (\&{fontmapfile}, \&{fontmapline}) */ -+mp_special_command, /* output special info (\&{special}) or font map info (\&{fontmapfile}, \&{fontmapline}) */ - mp_write_command, /* write text to a file (\&{write}) */ - mp_type_name, /* declare a type (\&{numeric}, \&{pair}, etc.) */ - mp_left_delimiter, /* the left delimiter of a matching pair */ -@@ -3275,15 +3281,13 @@ mp_left_bracket, /* the operator `\.[' */ - mp_right_bracket, /* the operator `\.]' */ - mp_right_brace, /* the operator `\.{\char`\}}' */ - mp_with_option, /* option for filling (\&{withpen}, \&{withweight}, etc.) */ --mp_thing_to_add, -- /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */ -+mp_thing_to_add, /* variant of \&{addto} (\&{contour}, \&{doublepath}, \&{also}) */ - mp_of_token, /* the operator `\&{of}' */ - mp_to_token, /* the operator `\&{to}' */ - mp_step_token, /* the operator `\&{step}' */ - mp_until_token, /* the operator `\&{until}' */ - mp_within_token, /* the operator `\&{within}' */ --mp_lig_kern_token, -- /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}', etc. */ -+mp_lig_kern_token, /* the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}', etc. */ - mp_assignment, /* the operator `\.{:=}' */ - mp_skip_to, /* the operation `\&{skipto}' */ - mp_bchar_label, /* the operator `\.{\char'174\char'174:}' */ -@@ -4046,6 +4050,7 @@ enum mp_given_internal { - mp_pausing, /* positive to display lines on the terminal before they are read */ - mp_showstopping, /* positive to stop after each \&{show} command */ - mp_fontmaking, /* positive if font metric output is to be produced */ -+ mp_texscriptmode, /* controls spacing in texmode */ - mp_linejoin, /* as in \ps: 0 for mitered, 1 for round, 2 for beveled */ - mp_linecap, /* as in \ps: 0 for butt, 1 for round, 2 for square */ - mp_miterlimit, /* controls miter length as in \ps */ -@@ -4196,6 +4201,8 @@ mp_primitive (mp, "showstopping", mp_internal_quantity, mp_showstopping); - @:mp_showstopping_}{\&{showstopping} primitive@>; - mp_primitive (mp, "fontmaking", mp_internal_quantity, mp_fontmaking); - @:mp_fontmaking_}{\&{fontmaking} primitive@>; -+mp_primitive (mp, "texscriptmode", mp_internal_quantity, mp_texscriptmode); -+@:mp_texscriptmode_}{\&{texscriptmode} primitive@>; - mp_primitive (mp, "linejoin", mp_internal_quantity, mp_linejoin); - @:mp_linejoin_}{\&{linejoin} primitive@>; - mp_primitive (mp, "linecap", mp_internal_quantity, mp_linecap); -@@ -4214,8 +4221,7 @@ mp_primitive (mp, "mpprocset", mp_internal_quantity, mp_procset); - @:mp_procset_}{\&{mpprocset} primitive@>; - mp_primitive (mp, "troffmode", mp_internal_quantity, mp_gtroffmode); - @:troffmode_}{\&{troffmode} primitive@>; --mp_primitive (mp, "defaultcolormodel", mp_internal_quantity, -- mp_default_color_model); -+mp_primitive (mp, "defaultcolormodel", mp_internal_quantity, mp_default_color_model); - @:mp_default_color_model_}{\&{defaultcolormodel} primitive@>; - mp_primitive (mp, "restoreclipcolor", mp_internal_quantity, mp_restore_clip_color); - @:mp_restore_clip_color_}{\&{restoreclipcolor} primitive@>; -@@ -4273,6 +4279,7 @@ set_internal_string (mp_output_format, mp_intern (mp, "eps")); - set_internal_string (mp_output_format_options, mp_intern (mp, "")); - set_internal_string (mp_number_system, mp_intern (mp, "scaled")); - set_internal_from_number (mp_number_precision, precision_default); -+set_internal_from_number (mp_texscriptmode, unity_t); - #if DEBUG - number_clone (internal_value (mp_tracing_titles), three_t); - number_clone (internal_value (mp_tracing_equations), three_t); -@@ -4320,6 +4327,7 @@ set_internal_name (mp_design_size, xstrdup ("designsize")); - set_internal_name (mp_pausing, xstrdup ("pausing")); - set_internal_name (mp_showstopping, xstrdup ("showstopping")); - set_internal_name (mp_fontmaking, xstrdup ("fontmaking")); -+set_internal_name (mp_texscriptmode, xstrdup ("texscriptmode")); - set_internal_name (mp_linejoin, xstrdup ("linejoin")); - set_internal_name (mp_linecap, xstrdup ("linecap")); - set_internal_name (mp_miterlimit, xstrdup ("miterlimit")); -@@ -4443,6 +4451,8 @@ class numbers in nonstandard extensions of \MP. - @d invalid_class 20 /* bad character in the input */ - @d max_class 20 /* the largest class number */ - -+@d semicolon_class 6 /* the ; */ -+ - @= - #define digit_class 0 /* the class number of \.{0123456789} */ - int char_class[256]; /* the class numbers */ -@@ -4843,10 +4853,26 @@ char *mp_get_string_value (MP mp, const char *s, size_t l) { - return NULL; - } - -+mp_knot mp_get_path_value (MP mp, const char *s, size_t l) { -+ char *ss = mp_xstrdup(mp,s); -+ if (ss) { -+ mp_sym sym = mp_id_lookup(mp,ss,l,false); -+ if (sym != NULL) { -+ if (mp_type(sym->v.data.node) == mp_path_type) { -+ mp_xfree (ss); -+ return (mp_knot) sym->v.data.node->data.p; -+ } -+ } -+ } -+ mp_xfree (ss); -+ return NULL; -+} -+ - @ @= - double mp_get_numeric_value(MP mp,const char *s,size_t l); - int mp_get_boolean_value(MP mp,const char *s,size_t l); - char *mp_get_string_value(MP mp,const char *s,size_t l); -+mp_knot mp_get_path_value(MP mp,const char *s,size_t l); - - @ We need to put \MP's ``primitive'' symbolic tokens into the hash - table, together with their command code (which will be the |eq_type|) -@@ -13270,26 +13296,26 @@ static mp_knot mp_offset_prep (MP mp, mp_knot c, mp_knot h) { - c0 = c; - k_needed = 0; - #ifdef DEBUGENVELOPE --dbg_nl;dbg_str(--[==[BEGIN]==]);dbg_nl; --dbg_str(return {);dbg_nl; -+dbg_nl;dbg_str(--[==[BEGIN]==]);dbg_nl; -+dbg_str(return {);dbg_nl; - dbg_n(w0->x_coord); - dbg_n(w0->y_coord); - #endif - do { - q = mp_next_knot (p); - #ifdef DEBUGENVELOPE --dbg_nl;dbg_open_t;dbg_str(--[==[begin loop]==]);dbg_nl; -+dbg_nl;dbg_open_t;dbg_str(--[==[begin loop]==]);dbg_nl; - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_n(p->right_x);dbg_n(p->right_y); - dbg_n(q->left_x);dbg_n(q->left_y); - dbg_n(q->x_coord);dbg_n(q->y_coord); - dbg_n(w0->x_coord); - dbg_n(w0->y_coord); --#endif -+#endif - @; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(end Split the cubic between |p| and |q|);dbg_open_t;dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord); - dbg_n(w0->x_coord);dbg_n(w0->y_coord); -@@ -13301,7 +13327,7 @@ dbg_close_t; dbg_comma;dbg_nl; - #ifdef DEBUGENVELOPE - dbg_n(w0->x_coord);dbg_n(w0->y_coord); - dbg_str(--[==[end loop]==]);dbg_nl; dbg_close_t;dbg_comma;dbg_nl; --#endif -+#endif - } while (q != c); - #ifdef DEBUGENVELOPE - dbg_key(Fix the offset change);dbg_open_t;dbg_nl; -@@ -13312,7 +13338,7 @@ dbg_str(--[==[end loop]==]);dbg_nl; dbg_close_t;dbg_comma;dbg_nl; - #endif - @; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_key_ival(info post,mp_knot_info(p));dbg_comma;dbg_nl; - dbg_n(c->x_coord);dbg_n(c->y_coord); -@@ -13412,7 +13438,7 @@ the testcase reported by Bogus\l{}aw Jackowski in tracker id 267, case 52c - on Sarovar.) - - @= --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(Advance |p| to node |q|);dbg_nl; - #endif - q0 = q; -@@ -13437,11 +13463,11 @@ if ((q != q0) && (q != c || c == c0)) - - @ @= - { -- #ifdef DEBUGENVELOPE -+ #ifdef DEBUGENVELOPE - dbg_key(Remove the cubic following p);dbg_open_t;dbg_nl; - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_key_ival(pre info p,mp_knot_info(p)); dbg_close_t;dbg_comma;dbg_nl; -- #endif -+ #endif - k_needed = mp_knot_info (p) - zero_off; - if (r == q) { - q = p; -@@ -13459,11 +13485,11 @@ if ((q != q0) && (q != c || c == c0)) - mp->spec_p2 = p; - r = p; - mp_remove_cubic (mp, p); -- #ifdef DEBUGENVELOPE -+ #ifdef DEBUGENVELOPE - dbg_key(Remove the cubic following p);dbg_open_t;dbg_nl; - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_key_ival(post info p,mp_knot_info (p)); dbg_close_t;dbg_comma;dbg_nl; -- #endif -+ #endif - } - - -@@ -13532,16 +13558,16 @@ We may have to split a cubic into many pieces before each - piece corresponds to a unique offset. - - @= --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(Split the cubic between |p| and |q|);dbg_nl; - dbg_key(Split the cubic);dbg_open_t;dbg_nl; - dbg_key_ival(pre info p,mp_knot_info(p));dbg_comma; - dbg_n(w0->x_coord);dbg_n(w0->y_coord); --#endif -+#endif - mp_knot_info (p) = zero_off + k_needed; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key_ival(post info p,mp_knot_info(p));dbg_close_t;dbg_comma; dbg_nl; --#endif -+#endif - k_needed = 0; - @; -@@ -13708,7 +13734,7 @@ void mp_fin_offset_prep (MP mp, mp_knot p, mp_knot w, mp_number - new_number(t2); - new_fraction(s); - new_fraction(t); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(mp_fin_offset_prep);dbg_open_t;dbg_nl; - #endif - while (1) { -@@ -13716,7 +13742,7 @@ dbg_key(mp_fin_offset_prep);dbg_open_t;dbg_nl; - ww = mp_next_knot (w); /* a pointer to $w\k$ */ - else - ww = mp_prev_knot (w); /* a pointer to $w_{k-1}$ */ --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(begin iteration); - dbg_open_t;dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord); -@@ -13727,11 +13753,11 @@ dbg_in(rise); - #endif - @; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(crossing_point); - #endif - crossing_point (t, t0, t1, t2); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_n(t);dbg_n(t0);dbg_n(t1);dbg_n(t2); - dbg_in(number_greaterequal(t, fraction_one_t)); - dbg_in(turn_amt); -@@ -13743,18 +13769,18 @@ dbg_close_t; dbg_comma;dbg_nl; - else - goto RETURN; - } --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(Split the cubic at $t$ and split off another cubic if the derivative crosses back); - #endif - @; - w = ww; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(end iteration); - #endif - } - RETURN: --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_comment(RETURN); - dbg_n(t); - #endif -@@ -13766,7 +13792,7 @@ dbg_n(t); - free_number (t0); - free_number (t1); - free_number (t2); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_close_t; dbg_comma;dbg_nl; - #endif - } -@@ -13782,7 +13808,7 @@ begins to fail. - mp_number abs_du, abs_dv; - new_number (abs_du); - new_number (abs_dv); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...);dbg_open_t;dbg_nl; - #endif - set_number_from_substraction(du, ww->x_coord, w->x_coord); -@@ -13791,7 +13817,7 @@ dbg_key(Compute test coefficients |(t0,t1,t2)| for $d(t)$ versus...);dbg_open_t; - number_abs(abs_du); - number_clone(abs_dv, dv); - number_abs(abs_dv); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_CUBIC; - dbg_n(w->x_coord);dbg_n(w->y_coord); - dbg_n(ww->x_coord);dbg_n(ww->y_coord); -@@ -13838,7 +13864,7 @@ dbg_in(number_greaterequal(abs_du, abs_dv)); - free_number (abs_dv); - if (number_negative(t0)) - set_number_to_zero(t0); /* should be positive without rounding error */ --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_n(t0);dbg_n(t1);dbg_n(t2); - dbg_close_t; dbg_comma;dbg_nl; - #endif -@@ -13981,19 +14007,19 @@ if (number_zero(dxin) && number_zero(dyin)) { - #ifdef DEBUGENVELOPE - dbg_key(dxin dyin before);dbg_open_t;dbg_nl; - dbg_n(dxin);dbg_n(dyin); --dbg_close_t;dbg_comma; -+dbg_close_t;dbg_comma; - #endif - #ifdef DEBUGENVELOPE - dbg_key(dxin dyin after);dbg_open_t;dbg_nl; - dbg_n(dxin);dbg_n(dyin); --dbg_close_t;dbg_comma; -+dbg_close_t;dbg_comma; - #endif - /* BEGIN PATCH */ - #ifdef DEBUGENVELOPE - dbg_key(dx dy dxin dyin after patch);dbg_open_t;dbg_nl; - dbg_n(dx);dbg_n(dy);dbg_n(dx_ap);dbg_n(dy_ap); - dbg_n(dxin);dbg_n(dyin);dbg_n(dxin_ap);dbg_n(dyin_ap); --dbg_close_t;dbg_comma; -+dbg_close_t;dbg_comma; - #endif - /* END PATCH ****/ - -@@ -14012,13 +14038,13 @@ right.) This code depends on |w0| being the offset for |(dxin,dyin)|. - #ifdef DEBUGENVELOPE - dbg_nl; - dbg_comment(Update |mp_knot_info(p)|);dbg_nl; --dbg_key(mp_get_turn_amt_dx_dy);dbg_open_t;dbg_str(--[==[call mp_get_turn_amt]==]);dbg_nl; -+dbg_key(mp_get_turn_amt_dx_dy);dbg_open_t;dbg_str(--[==[call mp_get_turn_amt]==]);dbg_nl; - dbg_n(w0->x_coord);dbg_n(w0->y_coord);dbg_n(dx);dbg_n(dy);dbg_in(number_nonnegative(ab_vs_cd)); - dbg_n(ab_vs_cd); - #endif - is_dxdy=true; - turn_amt = mp_get_turn_amt (mp, w0, dx, dy, number_nonnegative(ab_vs_cd)); -- is_dxdy=false; -+ is_dxdy=false; - #ifdef DEBUGENVELOPE - dbg_dn(turn_amt); - dbg_close_t;dbg_comma; -@@ -14078,20 +14104,20 @@ integer mp_get_turn_amt (MP mp, mp_knot w, mp_number dx, mp_number dy, boolean c - ab_vs_cd (t, dy, arg1, dx, arg2); - #ifdef DEBUGENVELOPE - dbg_sp; -- dbg_open_t;dbg_str(--[==[inside mp_get_turn_amt do loop ]==]);dbg_nl; -+ dbg_open_t;dbg_str(--[==[inside mp_get_turn_amt do loop ]==]);dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord);dbg_n(ww->x_coord);dbg_n(ww->y_coord); - dbg_n(t);dbg_n(dy);dbg_n(arg1);dbg_n(dx);dbg_n(arg2); - dbg_n(t_ap);dbg_n(dy_ap);dbg_n(dx_ap);dbg_n(dyin_ap);dbg_n(dxin_ap); - dbg_close_t;dbg_comma; - dbg_in(number_zero(dx) && number_zero(arg1) && number_positive(dy) && number_positive(arg2) && is_dxdy); -- dbg_in(is_dxdy && number_zero(dx) && number_zero(arg1) && number_negative(dy) && number_negative(arg2) && number_positive(dyin_ap)); -+ dbg_in(is_dxdy && number_zero(dx) && number_zero(arg1) && number_negative(dy) && number_negative(arg2) && number_positive(dyin_ap)); - dbg_in(is_dxindyin && number_zero(dx) && number_zero(arg1) && number_positive(dy) && number_positive(arg2) && number_negative(dyin_ap)); - dbg_in(number_zero(dy) && number_zero(arg2) && number_negative(dx) && number_negative(arg1)); - dbg_in(number_zero(dx) && number_zero(arg1) && number_negative(dy) && number_positive(arg2)); - dbg_in(number_zero(dy) && number_zero(arg2) && number_positive(dx) && number_negative(arg1)); - dbg_nl; - #endif -- if (number_negative(t)) -+ if (number_negative(t)) - break; - incr (s); - w = ww; -@@ -14104,7 +14130,7 @@ integer mp_get_turn_amt (MP mp, mp_knot w, mp_number dx, mp_number dy, boolean c - ab_vs_cd (t, dy, arg1, dx, arg2); - #ifdef DEBUGENVELOPE - dbg_sp; -- dbg_open_t;dbg_str(--[==[outside mp_get_turn_amt do loop ]==]);dbg_nl; -+ dbg_open_t;dbg_str(--[==[outside mp_get_turn_amt do loop ]==]);dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord);dbg_n(ww->x_coord);dbg_n(ww->y_coord); - dbg_n(t);dbg_n(dy);dbg_n(arg1);dbg_n(dx);dbg_n(arg2); - dbg_n(t_ap);dbg_n(dy_ap);dbg_n(dx_ap);dbg_n(dyin_ap);dbg_n(dxin_ap); -@@ -14120,7 +14146,7 @@ integer mp_get_turn_amt (MP mp, mp_knot w, mp_number dx, mp_number dy, boolean c - ab_vs_cd (t, dy, arg1, dx, arg2); - #ifdef DEBUGENVELOPE - dbg_sp; -- dbg_open_t;dbg_str(--[==[inside mp_get_turn_amt do loop for t<0 ]==]);dbg_nl; -+ dbg_open_t;dbg_str(--[==[inside mp_get_turn_amt do loop for t<0 ]==]);dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord);dbg_n(ww->x_coord);dbg_n(ww->y_coord); - dbg_n(t);dbg_n(dy);dbg_n(arg1);dbg_n(dx);dbg_n(arg2); - dbg_n(t_ap);dbg_n(dy_ap);dbg_n(dx_ap); -@@ -14173,14 +14199,14 @@ with respect to $d_{k-1}$, and apply |fin_offset_prep| to each part. - - @= - ww = mp_prev_knot (w); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(Complete the offset splitting process);dbg_open_t;dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord); - dbg_n(ww->x_coord);dbg_n(ww->y_coord); - dbg_close_t; dbg_comma;dbg_nl; - #endif - @; --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(after Compute test coeff);dbg_open_t;dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord); - dbg_n(ww->x_coord);dbg_n(ww->y_coord); -@@ -14189,7 +14215,7 @@ dbg_close_t; dbg_comma;dbg_nl; - @; - if (number_greater(t, fraction_one_t)) { --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(t > fraction_one_t);dbg_open_t;dbg_nl; - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_n(w->x_coord);dbg_n(w->y_coord); -@@ -14207,7 +14233,7 @@ dbg_close_t; dbg_comma;dbg_nl; - set_number_from_of_the_way(y1a, t, y0, y1); - set_number_from_of_the_way(y1, t, y1, y2); - set_number_from_of_the_way(y2a, t, y1a, y1); --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(t <= fraction_one_t);dbg_open_t;dbg_nl; - dbg_n(p->x_coord);dbg_n(p->y_coord); - dbg_n(t); -@@ -14245,7 +14271,7 @@ dbg_close_t; dbg_comma;dbg_nl; - mp_fin_offset_prep (mp, r, ww, x0, x1, x2, y0, y1, y2, -1, (-1 - turn_amt)); - } - } --#ifdef DEBUGENVELOPE -+#ifdef DEBUGENVELOPE - dbg_key(end Complete the offset splitting process);dbg_open_t;dbg_nl; - dbg_n(w->x_coord);dbg_n(w->y_coord); - dbg_n(w0->x_coord);dbg_n(w0->y_coord); -@@ -14278,7 +14304,7 @@ crossing and the first crossing cannot be antiparallel. - @= - #ifdef DEBUGENVELOPE - dbg_key(Find the first |t| where);dbg_open_t;dbg_nl; --#endif -+#endif - crossing_point (t, t0, t1, t2); - if (turn_amt >= 0) { - if (number_negative(t2)) { -@@ -14316,7 +14342,7 @@ if (turn_amt >= 0) { - #ifdef DEBUGENVELOPE - dbg_n(t); - dbg_close_t; dbg_comma;dbg_nl; --#endif -+#endif - - - @ @= -@@ -19845,6 +19871,7 @@ is less than |loop_text|. - @ @= - if (s != NULL) { - int k ; -+ mp_value new_expr; - size_t size = strlen(s); - memset(&new_expr,0,sizeof(mp_value)); - new_number(new_expr.data.n); -@@ -19860,7 +19887,6 @@ if (s != NULL) { - } - limit = (halfword) k; - (void) memcpy ((mp->buffer + mp->first), s, size); -- free(s); - mp->buffer[limit] = xord ('%'); - mp->first = (size_t) (limit + 1); - loc = start; -@@ -19891,26 +19917,42 @@ if (s != NULL) { - } else { - mp_back_input (mp); - if (cur_exp_str ()->len > 0) { -- mp_value new_expr; - char *s = mp->run_script(mp,(const char*) cur_exp_str()->str) ; - @ -+ free(s); - } - } - } - --@ @= -+@ The |texscriptmode| parameter controls how spaces and newlines get honoured in -+|btex| or |verbatimtex| ... |etex|. The default value is~1. Possible values are: -+0: no newlines, 1: newlines in |verbatimtex|, 2: newlines in |verbatimtex| and -+|etex|, 3: no leading and trailing strip in |verbatimtex|, 4: no leading and -+trailing strip in |verbatimtex| and |btex|. That way the Lua handler can do what -+it likes. An |etex| has to be followed by a space or |;| or be at the end of a -+line and preceded by a space or at the beginning of a line. -+ -+@= - { -- int first ; -- while ((loc < limit - 4) && (mp->buffer[loc] == ' ')) { -+ char *txt = NULL; -+ char *ptr = NULL; -+ int slin = line; -+ int size = 0; -+ int done = 0; -+ int mode = round_unscaled(internal_value(mp_texscriptmode)) ; /* default: 1 */ -+ int verb = cur_mod() == verbatim_code; -+ int first; -+ /* we had a (mandate) trailing space */ -+ if (loc <= limit && mp->char_class[mp->buffer[loc]] == space_class) { - incr(loc); -+ } else { -+ /* maybe issue an error message and quit */ - } -- first = loc ; -- if (mp->buffer[loc-1] == ' ') { -- decr(loc); -- } -- while (loc < limit - 5) { -- if (mp->buffer[loc] == ' ') { -- incr(loc); -+ /* we loop over lines */ -+ first = loc; -+ while (1) { -+ /* we don't need to check when we have less than 4 characters left */ -+ if (loc < limit - 4) { - if (mp->buffer[loc] == 'e') { - incr(loc); - if (mp->buffer[loc] == 't') { -@@ -19918,39 +19960,135 @@ if (s != NULL) { - if (mp->buffer[loc] == 'e') { - incr(loc) ; - if (mp->buffer[loc] == 'x') { -- /* start action */ -- char *s, *txt ; -- int size ; -- mp_value new_expr; -- size = loc - first + 1 - 4 ; -- if (size < 0) { -- size = 0 ; -- } else { -- while ((size > 1) && (mp->buffer[first+size-1] == ' ')) { -- decr(size); -- } -+ /* let's see if we have the right boundary */ -+ if (first == (loc - 3)) { -+ /* when we're at the start of a line no leading space is required */ -+ done = 1; -+ } else if (mp->char_class[mp->buffer[loc - 4]] == space_class) { -+ /* when we're beyond the start of a line a leading space is required */ -+ done = 2; - } -- txt = malloc(size+1); -- if (size > 0) { -- (void) memcpy (txt, mp->buffer + first, size); -+ if (done) { -+ if ((loc + 1) <= limit) { -+ quarterword c = mp->char_class[mp->buffer[loc + 1]] ; -+ if (c != letter_class) { -+ incr(loc) ; -+ /* we're past the 'x' */ -+ break; -+ } else { -+ /* this is no valid etex */ -+ done = 0; -+ } -+ } else { -+ /* when we're at the end of a line we're ok */ -+ incr(loc) ; -+ /* we're past the 'x' */ -+ break; -+ } - } -- txt[size] = '\0'; -- incr(loc); -- s = mp->make_text(mp,txt,(cur_mod() == verbatim_code)) ; /* we could pass the size */ -- @ -- /* done */ -- free(txt); -- break ; -- } else { -- // decr(loc) ; - } - } - } - } -+ } -+ /* no etex seen (yet) */ -+ if (loc >= limit) { -+ if (size) { -+ txt = realloc(txt, size + limit - first + 1); -+ } else { -+ txt = malloc(limit - first + 1); -+ } -+ (void) memcpy (txt + size, mp->buffer + first, limit - first); -+ size += limit - first + 1; -+ if (mode <= 0) { -+ txt[size - 1] = ' '; -+ } else if (verb) { -+ /* modes >= 1 permit a newline in verbatimtex */ -+ txt[size - 1] = '\n'; -+ } else if (mode >= 2) { -+ /* modes >= 2 permit a newline in btex */ -+ txt[size - 1] = '\n'; -+ } else { -+ txt[size - 1] = ' '; -+ } -+ if (move_to_next_line(mp)) { -+ /* we abort the scanning */ -+ goto FATAL_ERROR; -+ } -+ first = loc; - } else { - incr(loc); - } - } -+ if (done) { -+ /* we're past the 'x' */ -+ int l = loc - 5 ; // 4 -+ int n = l - first + 1 ; -+ /* we're before the 'etex' */ -+ if (done == 2) { -+ /* we had ' etex' */ -+ l -= 1; -+ n -= 1; -+ /* we're before the ' etex' */ -+ } -+ if (size) { -+ txt = realloc(txt, size + n + 1); -+ } else { -+ txt = malloc(n + 1); -+ } -+ (void) memcpy (txt + size, mp->buffer + first, n); /* 0 */ -+ size += n; -+ if (verb && mode >= 3) { -+ /* don't strip verbatimtex */ -+ txt[size] = '\0'; -+ ptr = txt; -+ } else if (mode >= 4) { -+ /* don't strip btex */ -+ txt[size] = '\0'; -+ ptr = txt; -+ } else { -+ /* strip trailing whitespace, we have a \0 so we're one off */ -+ /* while ((size > 1) && (mp->char_class[(ASCII_code) txt[size-2]] == space_class || txt[size-2] == '\n')) { */ -+ while ((size > 1) && (mp->char_class[(ASCII_code) txt[size-1]] == space_class || txt[size-1] == '\n')) { -+ decr(size); -+ } -+ /* prune the string */ -+ txt[size] = '\0'; -+ /* strip leading whitespace */ -+ ptr = txt; -+ while ((size > 1) && (mp->char_class[(ASCII_code) ptr[0]] == space_class || ptr[0] == '\n')) { -+ incr(ptr); -+ decr(size); -+ } -+ } -+ /* action */ -+ { -+ char *s = mp->make_text(mp,ptr,verb) ; -+ @ -+ free(s); -+ } -+ free(txt); -+ /* really needed */ -+ mp_get_next(mp); -+ return; -+ } -+ /* -+ we don't recover because in practice the graphic will be broken anyway and -+ we're not really interacting in mplib .. just fix the input -+ */ -+ FATAL_ERROR: -+ { -+ /* line numbers are not always meaningfull so we can get a 0 reported */ -+ char msg[256]; -+ const char *hlp[] = { "An 'etex' is missing at this input level, nothing gets done.", NULL }; -+ if (slin > 0) { -+ mp_snprintf(msg, 256, "No matching 'etex' for '%stex'.", verb ? "verbatim" : "b"); -+ } else { -+ mp_snprintf(msg, 256, "No matching 'etex' for '%stex' in line %d.", verb ? "verbatim" : "b",slin); -+ } -+ mp_error (mp, msg, hlp, false); -+ free(txt); -+ } - } - - @ @= -@@ -19964,7 +20102,7 @@ if (s != NULL) { - mp_value new_expr; - const char *hlp[] = { - "I'm going to flush this expression, since", -- "makete should be followed by a known string.", -+ "maketext should be followed by a known string.", - NULL }; - memset(&new_expr,0,sizeof(mp_value)); - new_number(new_expr.data.n); -@@ -19976,9 +20114,9 @@ if (s != NULL) { - } else { - mp_back_input (mp); - if (cur_exp_str ()->len > 0) { -- mp_value new_expr; - char *s = mp->make_text(mp,(const char*) cur_exp_str()->str,0) ; - @ -+ free(s); - } - } - } -@@ -23295,7 +23433,7 @@ RESTART: - - q = mp_get_value_node (mp); - mp_name_type (q) = mp_capsule; -- if (cur_cmd() == mp_comma) { -+ if (cur_cmd() == mp_comma) { - mp_init_color_node (mp, q); - r = value_node (q); - mp_stash_in (mp, y_part (r)); -@@ -23321,7 +23459,7 @@ RESTART: - } - mp_stash_in (mp, blue_part (r)); - -- if (cur_cmd() == mp_comma) { -+ if (cur_cmd() == mp_comma) { - mp_node t; /* a token */ - mp_init_cmykcolor_node (mp, q); - t = value_node (q); -@@ -23337,13 +23475,13 @@ RESTART: - set_dep_list (cyan_part(t),dep_list ((mp_value_node) red_part(r))); - set_prev_dep (cyan_part(t),prev_dep ((mp_value_node) red_part(r))); - set_mp_link (prev_dep (cyan_part(t)), (mp_node) cyan_part(t)); -- } -+ } - if ( ((mp_type (magenta_part (t))) != mp_independent) && ((mp_type (magenta_part (t))) != mp_known) ) { - /* Copy the dep list */ - set_dep_list (magenta_part(t),dep_list ((mp_value_node) green_part(r))); - set_prev_dep (magenta_part(t),prev_dep ((mp_value_node) green_part(r))); - set_mp_link (prev_dep (magenta_part(t)), (mp_node) magenta_part(t)); -- } -+ } - if ( ((mp_type (yellow_part (t))) != mp_independent) && ((mp_type (yellow_part (t))) != mp_known)) { - /* Copy the dep list */ - set_dep_list (yellow_part(t),dep_list ((mp_value_node) blue_part(r))); -@@ -28985,7 +29123,7 @@ static void mp_set_up_boundingpath (MP mp, mp_node p) { - unsigned char ljoin, lcap; - mp_number miterlim; - mp_knot q = mp_copy_path (mp, cur_exp_knot ()); /* the original path */ -- mp_knot pen; -+ mp_knot pen; - mp_knot qq; - - new_number(miterlim); -@@ -30671,8 +30809,8 @@ void mp_show_library_versions (void) { - fprintf(stdout, "Compiled with pixman %s; using %s\n",COMPILED_PIXMAN_VERSION_STRING, pixman_version_string()); - fprintf(stdout, "Compiled with libpng %s; using %s\n", PNG_LIBPNG_VER_STRING, png_libpng_ver); - fprintf(stdout, "Compiled with zlib %s; using %s\n", ZLIB_VERSION, zlibVersion()); -- fprintf(stdout, "Compiled with mpfr %s; using %s\n", MPFR_VERSION_STRING, mpfr_get_version()); -- fprintf(stdout, "Compiled with gmp %d.%d.%d; using %s\n\n", __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, __GNU_MP_VERSION_PATCHLEVEL, gmp_version); -+ fprintf(stdout, "Compiled with mpfr %s; using %s\n", COMPILED_MPFR_VERSION_STRING, mpfr_get_version()); -+ fprintf(stdout, "Compiled with gmp %d.%d.%d; using %s\n\n", COMPILED__GNU_MP_VERSION, COMPILED__GNU_MP_VERSION_MINOR, COMPILED__GNU_MP_VERSION_PATCHLEVEL, COMPILED_gmp_version); - } - - @ @= -@@ -33230,7 +33368,7 @@ We may need to cancel skips that span more than 127 lig/kern steps. - - - @ The header could contain ASCII zeroes, so can't use |strdup|. --The index |j| can be beyond the index |header_last|, hence we -+The index |j| can be beyond the index |header_last|, hence we - have to sure to update the end of stream marker to reflect the - actual position. - -@@ -34555,8 +34693,9 @@ extreme cases so it may have to be shortened on some systems. - - @= - { -- s = xmalloc (7, 1); -- mp_snprintf (s, 7, ".%i", (int) c); -+ s = xmalloc (12, 1); -+ mp_snprintf (s, 12, ".%i", (int) c); -+ s[7]='\0'; - } - - -diff --git a/texk/web2c/mplibdir/mpmath.w b/texk/web2c/mplibdir/mpmath.w -index 772f8042b..6c0ee6d00 100644 ---- a/texk/web2c/mplibdir/mpmath.w -+++ b/texk/web2c/mplibdir/mpmath.w -@@ -1,4 +1,4 @@ --% $Id$ -+% $Id: mpmath.w 2118 2017-02-15 17:49:54Z luigi $ - % - % This file is part of MetaPost; - % the MetaPost program is in the public domain. -diff --git a/texk/web2c/mplibdir/mpmathbinary.w b/texk/web2c/mplibdir/mpmathbinary.w -index c6df9ced4..f3d9ed947 100644 ---- a/texk/web2c/mplibdir/mpmathbinary.w -+++ b/texk/web2c/mplibdir/mpmathbinary.w -@@ -39,6 +39,19 @@ - #include "mpmp.h" /* internal header */ - #include - #include -+ -+#ifdef HAVE_CONFIG_H -+#include -+const char * const COMPILED_gmp_version = VERSION; -+#else -+const char * const COMPILED_gmp_version = "unknown"; -+#endif -+ -+const char *COMPILED_MPFR_VERSION_STRING = MPFR_VERSION_STRING; -+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 ; -+ - @; - #endif - -diff --git a/texk/web2c/mplibdir/mpmathdouble.w b/texk/web2c/mplibdir/mpmathdouble.w -index 4834876e5..cb1496936 100644 ---- a/texk/web2c/mplibdir/mpmathdouble.w -+++ b/texk/web2c/mplibdir/mpmathdouble.w -@@ -1,4 +1,4 @@ --% $Id$ -+% $Id: mpmathdouble.w 2118 2017-02-15 17:49:54Z luigi $ - % - % This file is part of MetaPost; - % the MetaPost program is in the public domain. ---- source/texk/web2c/pdftexdir/pdftoepdf.cc.orig 2020-11-07 13:23:37.163328041 +0100 -+++ source/texk/web2c/pdftexdir/pdftoepdf.cc 2020-11-07 13:39:34.880565627 +0100 -@@ -120,7 +120,7 @@ - - static InObj *inObjList; - static UsedEncoding *encodingList; --static GBool isInit = gFalse; -+static bool isInit = false; - - // -------------------------------------------------------------------- - // Maintain list of open embedded PDF files -@@ -275,7 +275,7 @@ - - static void copyObject(Object *); - --static void copyName(char *s) -+static void copyName(const char *s) - { - pdf_puts("/"); - for (; *s != 0; s++) { -@@ -292,7 +292,7 @@ - Object obj1; - copyName(obj->dictGetKey(i)); - pdf_puts(" "); -- obj1 = obj->dictGetValNF(i); -+ obj1 = obj->dictGetValNF(i).copy(); - copyObject(&obj1); - pdf_puts("\n"); - } -@@ -310,7 +310,7 @@ - static void copyFontDict(Object * obj, InObj * r) - { - int i, l; -- char *key; -+ const char *key; - if (!obj->isDict()) - pdftex_fail("PDF inclusion: invalid dict type <%s>", - obj->getTypeName()); -@@ -351,7 +351,7 @@ - obj->getTypeName()); - pdf_puts("/ProcSet [ "); - for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { -- procset = obj->arrayGetNF(i); -+ procset = obj->arrayGetNF(i).copy(); - if (!procset.isName()) - pdftex_fail("PDF inclusion: invalid ProcSet entry type <%s>", - procset.getTypeName()); -@@ -382,7 +382,7 @@ - return false; - } - --static void copyFont(char *tag, Object * fontRef) -+static void copyFont(const char *tag, Object * fontRef) - { - Object fontdict, subtype, basefont, fontdescRef, fontdesc, charset, - stemV; -@@ -406,7 +406,7 @@ - if (fontdict.isDict()) { - subtype = fontdict.dictLookup("Subtype"); - basefont = fontdict.dictLookup("BaseFont"); -- fontdescRef = fontdict.dictLookupNF("FontDescriptor"); -+ fontdescRef = fontdict.dictLookupNF("FontDescriptor").copy(); - if (fontdescRef.isRef()) { - fontdesc = fontdescRef.fetch(xref); - } -@@ -427,7 +427,7 @@ - charset = fontdesc.dictLookup("CharSet"); - if (!charset.isNull() && - charset.isString() && is_subsetable(fontmap)) -- epdf_mark_glyphs(fd, charset.getString()->getCString()); -+ epdf_mark_glyphs(fd, charset.getString()->c_str()); - else - embed_whole_font(fd); - addFontDesc(fontdescRef.getRef(), fd); -@@ -452,7 +452,7 @@ - obj->getTypeName()); - pdf_puts("/Font << "); - for (i = 0, l = obj->dictGetLength(); i < l; ++i) { -- fontRef = obj->dictGetValNF(i); -+ fontRef = obj->dictGetValNF(i).copy(); - if (fontRef.isRef()) - copyFont(obj->dictGetKey(i), &fontRef); - else if (fontRef.isDict()) { // some programs generate pdf with embedded font object -@@ -467,7 +467,7 @@ - pdf_puts(">>\n"); - } - --static void copyOtherResources(Object * obj, char *key) -+static void copyOtherResources(Object * obj, const char *key) - { - // copies all other resources (write_epdf handles Fonts and ProcSets), - -@@ -554,8 +554,8 @@ - Object obj1; - int i, l, c; - Ref ref; -- char *p; -- GString *s; -+ const char *p; -+ const GString *s; - if (obj->isBool()) { - pdf_printf("%s", obj->getBool()? "true" : "false"); - } else if (obj->isInt()) { -@@ -566,7 +566,7 @@ - pdf_printf("%s", convertNumToPDF(obj->getNum())); - } else if (obj->isString()) { - s = obj->getString(); -- p = s->getCString(); -+ p = s->c_str(); - l = s->getLength(); - if (strlen(p) == (unsigned int) l) { - pdf_puts("("); -@@ -595,7 +595,7 @@ - } else if (obj->isArray()) { - pdf_puts("["); - for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { -- obj1 = obj->arrayGetNF(i); -+ obj1 = obj->arrayGetNF(i).copy(); - if (!obj1.isName()) - pdf_puts(" "); - copyObject(&obj1); -@@ -664,7 +664,7 @@ - ("PDF inclusion: CID fonts are not supported" - " (try to disable font replacement to fix this)"); - } -- if ((s = ((Gfx8BitFont *) r->font)->getCharName(i)) != 0) -+ if ((s = (char *) ((Gfx8BitFont *) r->font)->getCharName(i)) != 0) - glyphNames[i] = s; - else - glyphNames[i] = notdef; -@@ -683,7 +683,7 @@ - } - - // get the pagebox according to the pagebox_spec --static PDFRectangle *get_pagebox(Page * page, int pagebox_spec) -+static const PDFRectangle *get_pagebox(Page * page, int pagebox_spec) - { - if (pagebox_spec == pdfboxspecmedia) - return page->getMediaBox(); -@@ -715,7 +715,7 @@ - { - PdfDocument *pdf_doc; - Page *page; -- PDFRectangle *pagebox; -+ const PDFRectangle *pagebox; - #ifdef POPPLER_VERSION - int pdf_major_version_found, pdf_minor_version_found; - #else -@@ -723,9 +723,9 @@ - #endif - // initialize - if (!isInit) { -- globalParams = new GlobalParams(); -- globalParams->setErrQuiet(gFalse); -- isInit = gTrue; -+ globalParams = std::unique_ptr(new GlobalParams()); -+ globalParams->setErrQuiet(false); -+ isInit = true; - } - // open PDF file - pdf_doc = find_add_document(image_name); -@@ -757,15 +757,14 @@ - if (page_name) { - // get page by name - GString name(page_name); -- LinkDest *link = pdf_doc->doc->findDest(&name); -+ std::unique_ptr link = pdf_doc->doc->findDest(&name); - if (link == 0 || !link->isOk()) - pdftex_fail("PDF inclusion: invalid destination <%s>", page_name); - Ref ref = link->getPageRef(); -- page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen); -+ page_num = pdf_doc->doc->getCatalog()->findPage(ref); - if (page_num == 0) - pdftex_fail("PDF inclusion: destination is not a page <%s>", - page_name); -- delete link; - } else { - // get page by number - if (page_num <= 0 || page_num > epdf_num_pages) -@@ -822,7 +821,7 @@ - Object groupDict; - bool writeSepGroup = false; - Object info; -- char *key; -+ const char *key; - char s[256]; - int i, l; - int rotate; -@@ -849,7 +848,7 @@ - pageObj = xref->fetch(pageRef->num, pageRef->gen); - pageDict = pageObj.getDict(); - rotate = page->getRotate(); -- PDFRectangle *pagebox; -+ const PDFRectangle *pagebox; - // write the Page header - pdf_puts("/Type /XObject\n"); - pdf_puts("/Subtype /Form\n"); -@@ -921,13 +920,13 @@ - pdf_puts(stripzeros(s)); - - // Metadata validity check (as a stream it must be indirect) -- dictObj = pageDict->lookupNF("Metadata"); -+ dictObj = pageDict->lookupNF("Metadata").copy(); - if (!dictObj.isNull() && !dictObj.isRef()) - pdftex_warn("PDF inclusion: /Metadata must be indirect object"); - - // copy selected items in Page dictionary except Resources & Group - for (i = 0; pageDictKeys[i] != NULL; i++) { -- dictObj = pageDict->lookupNF(pageDictKeys[i]); -+ dictObj = pageDict->lookupNF(pageDictKeys[i]).copy(); - if (!dictObj.isNull()) { - pdf_newline(); - pdf_printf("/%s ", pageDictKeys[i]); -@@ -936,7 +935,7 @@ - } - - // handle page group -- dictObj = pageDict->lookupNF("Group"); -+ dictObj = pageDict->lookupNF("Group").copy(); - if (!dictObj.isNull()) { - if (pdfpagegroupval == 0) { - // another pdf with page group was included earlier on the -@@ -977,8 +976,8 @@ - } - l = dic1.getLength(); - for (i = 0; i < l; i++) { -- groupDict.dictAdd(copyString(dic1.getKey(i)), -- dic1.getValNF(i)); -+ groupDict.dictAdd(dic1.getKey(i), -+ dic1.getValNF(i).copy()); - } - // end modification - pdf_printf("/Group %ld 0 R\n", (long)pdfpagegroupval); -@@ -1108,6 +1107,6 @@ - delete_document(p); - } - // see above for globalParams -- delete globalParams; -+ globalParams.reset(); - } - } ---- source/texk/web2c/pdftexdir/pdftosrc.cc.orig 2020-11-07 13:23:37.163328041 +0100 -+++ source/texk/web2c/pdftexdir/pdftosrc.cc 2020-11-07 13:40:55.764601960 +0100 -@@ -24,6 +24,15 @@ - POPPLER_VERSION should be defined. - */ - -+#ifdef POPPLER_VERSION -+#include -+#define xpdfVersion POPPLER_VERSION -+#define xpdfString "poppler" -+#else -+#include /* just to get the xpdf version */ -+#define xpdfString "xpdf" -+#endif -+ - #include - - #include -@@ -79,7 +88,7 @@ - exit(1); - } - fileName = new GString(argv[1]); -- globalParams = new GlobalParams(); -+ globalParams = std::unique_ptr(new GlobalParams()); - doc = new PDFDoc(fileName); - if (!doc->isOk()) { - fprintf(stderr, "Invalid PDF file\n"); -@@ -100,7 +109,7 @@ - if (objnum == 0) { - srcStream = catalogDict.dictLookup("SourceObject"); - static char const_SourceFile[] = "SourceFile"; -- if (!srcStream.isStream(const_SourceFile)) { -+ if (!(srcStream.isStream() && srcStream.getDict()->is(const_SourceFile))) { - fprintf(stderr, "No SourceObject found\n"); - exit(1); - } -@@ -109,7 +118,7 @@ - fprintf(stderr, "No SourceName found\n"); - exit(1); - } -- outname = srcName.getString()->getCString(); -+ outname = srcName.getString()->c_str(); - // We cannot free srcName, as objname shares its string. - // srcName.free(); - } else if (objnum > 0) { -@@ -118,7 +127,7 @@ - fprintf(stderr, "Not a Stream object\n"); - exit(1); - } -- sprintf(buf, "%s", fileName->getCString()); -+ sprintf(buf, "%s", fileName->c_str()); - if ((p = strrchr(buf, '.')) == 0) - p = strchr(buf, 0); - if (objgen == 0) -@@ -128,7 +137,7 @@ - outname = buf; - } else { // objnum < 0 means we are extracting the XRef table - extract_xref_table = true; -- sprintf(buf, "%s", fileName->getCString()); -+ sprintf(buf, "%s", fileName->c_str()); - if ((p = strrchr(buf, '.')) == 0) - p = strchr(buf, 0); - sprintf(p, ".xref"); -@@ -156,12 +165,11 @@ - (e->type == xrefEntryFree ? "f" : "n")); - else { // e->offset is the object number of the object stream - Stream *str; -- Lexer *lexer; - Parser *parser; - Object objStr, obj1, obj2; - int nObjects, first, n; - int localOffset = 0; -- Guint firstOffset; -+ unsigned int firstOffset; - - objStr = xref->fetch(e->offset, 0); - assert(objStr.isStream()); -@@ -173,9 +181,8 @@ - - // parse the header: object numbers and offsets - objStr.streamReset(); -- str = new EmbedStream(objStr.getStream(), Object(objNull), gTrue, first); -- lexer = new Lexer(xref, str); -- parser = new Parser(xref, lexer, gFalse); -+ str = new EmbedStream(objStr.getStream(), Object(objNull), true, first); -+ parser = new Parser(xref, str, false); - for (n = 0; n < nObjects; ++n) { - obj1 = parser->getObj(); - obj2 = parser->getObj(); -@@ -207,5 +214,5 @@ - fprintf(stderr, "Cross-reference table extracted to %s\n", outname); - fclose(outfile); - delete doc; -- delete globalParams; -+ globalParams.reset(); - } -diff -up source/texk/web2c/pdftexdir/utils.c.me source/texk/web2c/pdftexdir/utils.c ---- source/texk/web2c/pdftexdir/utils.c.me 2020-11-06 17:34:13.775699638 +0100 -+++ source/texk/web2c/pdftexdir/utils.c 2020-11-06 17:37:29.022637825 +0100 -@@ -32,14 +32,6 @@ with this program. If not, see - #include "ptexlib.h" - #include --#ifdef POPPLER_VERSION --#include --#define xpdfVersion POPPLER_VERSION --#define xpdfString "poppler" --#else --#include /* just to get the xpdf version */ --#define xpdfString "xpdf" --#endif - - #define check_nprintf(size_get, size_want) \ - if ((unsigned)(size_get) >= (unsigned)(size_want)) \ -@@ -977,12 +969,10 @@ void initversionstring(char **versions) - { - const_string fmt = - "Compiled with libpng %s; using libpng %s\n" -- "Compiled with zlib %s; using zlib %s\n" -- "Compiled with %s version %s\n"; -+ "Compiled with zlib %s; using zlib %s\n"; - size_t len = strlen(fmt) - + strlen(PNG_LIBPNG_VER_STRING) + strlen(png_libpng_ver) - + strlen(ZLIB_VERSION) + strlen(zlib_version) -- + strlen(xpdfString) + strlen(xpdfVersion) - + 1; - - /* len will be more than enough, because of the placeholder chars in fmt -@@ -990,7 +980,7 @@ void initversionstring(char **versions) - *versions = xmalloc(len); - sprintf(*versions, fmt, - PNG_LIBPNG_VER_STRING, png_libpng_ver, -- ZLIB_VERSION, zlib_version, xpdfString, xpdfVersion); -+ ZLIB_VERSION, zlib_version); - } - - -diff -up source/texk/web2c/luatexdir/luamd5/md5lib.c.me source/texk/web2c/luatexdir/luamd5/md5lib.c -diff -up source/texk/web2c/mplibdir/mpmathbinary.w.me source/texk/web2c/mplibdir/mpmathbinary.w ---- source/texk/web2c/mplibdir/mpmathbinary.w.me 2020-11-07 13:48:29.165195061 +0100 -+++ source/texk/web2c/mplibdir/mpmathbinary.w 2020-11-07 13:50:00.711463667 +0100 -@@ -41,8 +41,9 @@ - #include - - #ifdef HAVE_CONFIG_H --#include --const char * const COMPILED_gmp_version = VERSION; -+#define MP_STR_HELPER(x) #x -+#define MP_STR(x) MP_STR_HELPER(x) -+const char * const COMPILED_gmp_version = MP_STR(__GNU_MP_VERSION) "." MP_STR( __GNU_MP_VERSION_MINOR) "." MP_STR(__GNU_MP_VERSION_PATCHLEVEL); - #else - const char * const COMPILED_gmp_version = "unknown"; - #endif -diff -up source/texk/web2c/pdftexdir/pdftoepdf.cc.me source/texk/web2c/pdftexdir/pdftoepdf.cc ---- source/texk/web2c/pdftexdir/pdftoepdf.cc.me 2020-11-07 13:52:29.288114063 +0100 -+++ source/texk/web2c/pdftexdir/pdftoepdf.cc 2020-11-07 13:54:11.092270259 +0100 -@@ -418,7 +418,7 @@ static void copyFont(const char *tag, Ob - && fontdescRef.isRef() - && fontdesc.isDict() - && embeddableFont(&fontdesc) -- && (fontmap = lookup_fontmap(basefont.getName())) != NULL) { -+ && (fontmap = lookup_fontmap((char *)basefont.getName())) != NULL) { - // round /StemV value, since the PDF input is a float - // (see Font Descriptors in PDF reference), but we only store an - // integer, since we don't want to change the struct. -@@ -427,7 +427,7 @@ static void copyFont(const char *tag, Ob - charset = fontdesc.dictLookup("CharSet"); - if (!charset.isNull() && - charset.isString() && is_subsetable(fontmap)) -- epdf_mark_glyphs(fd, charset.getString()->c_str()); -+ epdf_mark_glyphs(fd, (char *)charset.getString()->c_str()); - else - embed_whole_font(fd); - addFontDesc(fontdescRef.getRef(), fd); -diff -up source/texk/web2c/pdftexdir/pdftosrc.cc.me source/texk/web2c/pdftexdir/pdftosrc.cc ---- source/texk/web2c/pdftexdir/pdftosrc.cc.me 2020-11-07 13:54:51.983680256 +0100 -+++ source/texk/web2c/pdftexdir/pdftosrc.cc 2020-11-07 13:55:20.247155069 +0100 -@@ -118,7 +118,7 @@ int main(int argc, char *argv[]) - fprintf(stderr, "No SourceName found\n"); - exit(1); - } -- outname = srcName.getString()->c_str(); -+ outname = (char *)srcName.getString()->c_str(); - // We cannot free srcName, as objname shares its string. - // srcName.free(); - } else if (objnum > 0) { -diff -up source/texk/web2c/xetexdir/pdfimage.cpp.me source/texk/web2c/xetexdir/pdfimage.cpp ---- source/texk/web2c/xetexdir/pdfimage.cpp.me 2020-11-07 19:05:23.805273334 +0100 -+++ source/texk/web2c/xetexdir/pdfimage.cpp 2020-11-07 19:06:44.778390280 +0100 -@@ -79,24 +79,26 @@ pdf_get_rect(char* filename, int page_nu - Page* page = doc->getCatalog()->getPage(page_num); - - PDFRectangle* r; -+ const PDFRectangle* cr; - switch (pdf_box) { - default: - case pdfbox_crop: -- r = page->getCropBox(); -+ cr = page->getCropBox(); - break; - case pdfbox_media: -- r = page->getMediaBox(); -+ cr = page->getMediaBox(); - break; - case pdfbox_bleed: -- r = page->getBleedBox(); -+ cr = page->getBleedBox(); - break; - case pdfbox_trim: -- r = page->getTrimBox(); -+ cr = page->getTrimBox(); - break; - case pdfbox_art: -- r = page->getArtBox(); -+ cr = page->getArtBox(); - break; - } -+ r = new PDFRectangle (cr->x1, cr->y1, cr->x2, cr->y2); - - int RotAngle = 0; - RotAngle = (int)page->getRotate() % 360; -diff -up source/texk/web2c/xetexdir/XeTeX_ext.c.me source/texk/web2c/xetexdir/XeTeX_ext.c ---- source/texk/web2c/xetexdir/XeTeX_ext.c.me 2020-11-07 19:03:59.638390812 +0100 -+++ source/texk/web2c/xetexdir/XeTeX_ext.c 2020-11-07 19:05:05.683581239 +0100 -@@ -38,7 +38,6 @@ authorization from the copyright holders - - #include - --#include - #include - #include - #include -commit 91d642115acc57be0abfabf36567fb905dd67f30 -Author: Luigi Scarso -Date: Wed Sep 5 21:32:42 2018 +0000 - - pplib for luatex - - git-svn-id: svn://tug.org/texlive/trunk/Build/source@48592 c570f23f-e606-0410-a88d-b1316a301751 - -diff --git a/texk/web2c/luatexdir/luapplib/ppapi.h b/texk/web2c/luatexdir/luapplib/ppapi.h -new file mode 100644 -index 000000000..6d591ca05 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppapi.h -@@ -0,0 +1,391 @@ -+ -+#ifndef PP_API_H -+#define PP_API_H -+ -+#include -+#include -+#include -+ -+#include "ppconf.h" -+ -+#define pplib_version "v0.97" -+#define pplib_author "p.jackowski@gust.org.pl" -+ -+/* types */ -+ -+typedef int64_t ppint; -+typedef size_t ppuint; // machine word -+ -+typedef double ppnum; -+typedef char * ppname; -+typedef char * ppstring; -+ -+typedef struct { -+ size_t size; -+ int flags; -+} _ppname; -+ -+typedef struct { -+ size_t size; -+ int flags; -+} _ppstring; -+ -+typedef struct ppobj ppobj; -+typedef struct ppref ppref; -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+typedef struct { -+ ppobj *data; -+ size_t size; -+ ppnum PPARRAY_ALIGNMENT; -+} pparray; -+#else -+typedef struct { -+ ppobj *data; -+ size_t size; -+} pparray; -+#endif -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+typedef struct { -+ ppobj *data; -+ ppname *keys; -+ size_t size; -+ ppnum PPDICT_ALIGNMENT; -+} ppdict; -+ -+#else -+typedef struct { -+ ppobj *data; -+ ppname *keys; -+ size_t size; -+} ppdict; -+#endif -+ -+ -+typedef struct { -+ ppdict *dict; -+ void *input, *I; -+ size_t offset; -+ size_t length; -+ ppstring cryptkey; -+ int flags; -+} ppstream; -+ -+#define PPSTREAM_COMPRESSED (1<<0) -+#define PPSTREAM_ENCRYPTED_AES (1<<1) -+#define PPSTREAM_ENCRYPTED_RC4 (1<<2) -+#define PPSTREAM_ENCRYPTED (PPSTREAM_ENCRYPTED_AES|PPSTREAM_ENCRYPTED_RC4) -+#define PPSTREAM_ENCRYPTED_OWN (1<<3) -+ -+#define ppstream_compressed(stream) ((stream)->flags & PPSTREAM_COMPRESSED) -+#define ppstream_encrypted(stream) ((stream)->flags & PPSTREAM_ENCRYPTED) -+ -+typedef enum { -+ PPNONE = 0, -+ PPNULL, -+ PPBOOL, -+ PPINT, -+ PPNUM, -+ PPNAME, -+ PPSTRING, -+ PPARRAY, -+ PPDICT, -+ PPSTREAM, -+ PPREF -+} ppobjtp; -+ -+PPDEF extern const char * ppobj_kind[]; -+ -+struct ppobj { -+ ppobjtp type; -+ union { -+ ppint integer; -+ ppnum number; -+ ppname name; -+ ppstring string; -+ pparray *array; -+ ppdict *dict; -+ ppstream *stream; -+ ppref *ref; -+ void *any; -+ }; -+}; -+ -+typedef struct ppxref ppxref; -+ -+struct ppref { -+ ppobj object; -+ ppuint number, version; -+ size_t offset; -+ size_t length; -+ ppxref *xref; -+}; -+ -+typedef struct ppdoc ppdoc; -+ -+/* object */ -+ -+#define ppobj_get_null(o) ((o)->type == PPNULL ? 1 : 0) -+#define ppobj_get_bool(o, v) ((o)->type == PPBOOL ? ((v = ((o)->integer != 0)), 1) : 0) -+#define ppobj_get_int(o, v) ((o)->type == PPINT ? ((v = (o)->integer), 1) : 0) -+#define ppobj_get_uint(o, v) ((o)->type == PPINT && (o)->integer >= 0 ? ((v = (ppuint)((o)->integer)), 1) : 0) -+#define ppobj_get_num(o, v) ((o)->type == PPNUM ? ((v = (o)->number), 1) : (((o)->type == PPINT ? ((v = (ppnum)((o)->integer)), 1) : 0))) -+#define ppobj_get_name(o) ((o)->type == PPNAME ? (o)->name : NULL) -+#define ppobj_get_string(o) ((o)->type == PPSTRING ? (o)->string : NULL) -+#define ppobj_get_array(o) ((o)->type == PPARRAY ? (o)->array : NULL) -+#define ppobj_get_dict(o) ((o)->type == PPDICT ? (o)->dict : NULL) -+#define ppobj_get_stream(o) ((o)->type == PPSTREAM ? (o)->stream : NULL) -+#define ppobj_get_ref(o) ((o)->type == PPREF ? (o)->ref : NULL) -+ -+#define ppobj_rget_obj(o) ((o)->type == PPREF ? ppref_obj((o)->ref) : o) -+#define ppobj_rget_null(o) ((o)->type == PPNULL ? 1 : ((o)->type == PPREF ? ppobj_get_null(ppref_obj((o)->ref)) : 0)) -+#define ppobj_rget_bool(o, v) ((o)->type == PPBOOL ? ((v = ((o)->integer != 0)), 1) : ((o)->type == PPREF ? ppobj_get_bool(ppref_obj((o)->ref), v) : 0)) -+#define ppobj_rget_int(o, v) ((o)->type == PPINT ? ((v = (o)->integer), 1) : ((o)->type == PPREF ? ppobj_get_int(ppref_obj((o)->ref), v) : 0)) -+#define ppobj_rget_uint(o, v) ((o)->type == PPINT && (o)->integer >= 0 ? ((v = (ppuint)((o)->integer)), 1) : ((o)->type == PPREF ? ppobj_get_uint(ppref_obj((o)->ref), v) : 0)) -+#define ppobj_rget_num(o, v) ((o)->type == PPNUM ? ((v = (o)->number), 1) : (((o)->type == PPINT ? ((v = (ppnum)((o)->integer)), 1) : ((o)->type == PPREF ? ppobj_get_num(ppref_obj((o)->ref), v) : 0)))) -+#define ppobj_rget_name(o) ((o)->type == PPNAME ? (o)->name : ((o)->type == PPREF ? ppobj_get_name(ppref_obj((o)->ref)) : NULL)) -+#define ppobj_rget_string(o) ((o)->type == PPSTRING ? (o)->string : ((o)->type == PPREF ? ppobj_get_string(ppref_obj((o)->ref)) : NULL)) -+#define ppobj_rget_array(o) ((o)->type == PPARRAY ? (o)->array : ((o)->type == PPREF ? ppobj_get_array(ppref_obj((o)->ref)) : NULL)) -+#define ppobj_rget_dict(o) ((o)->type == PPDICT ? (o)->dict : ((o)->type == PPREF ? ppobj_get_dict(ppref_obj((o)->ref)) : NULL)) -+#define ppobj_rget_stream(o) ((o)->type == PPSTREAM ? (o)->stream : ((o)->type == PPREF ? ppobj_get_stream(ppref_obj((o)->ref)) : NULL)) -+#define ppobj_rget_ref(o) ((o)->type == PPREF ? (o)->ref : ((o)->type == PPREF ? ppobj_get_ref(ppref_obj((o)->ref)) : NULL)) -+ -+#define ppobj_get_bool_value(o) ((o)->type == PPBOOL ? ((o)->integer != 0) : 0) -+#define ppobj_get_int_value(o) ((o)->type == PPINT ? (o)->integer : 0) -+#define ppobj_get_num_value(o) ((o)->type == PPNUM ? (o)->number : ((o)->type == PPINT ? (ppnum)((o)->integer) : 0.0)) -+ -+/* name */ -+ -+#define ppname_is(name, s) (memcmp(name, s, sizeof("" s) - 1) == 0) -+#define ppname_eq(name, n) (memcmp(name, s, ppname_size(name)) == 0) -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define _ppname_ghost(name) (((const _ppname *)((void *)name)) - 1) -+#else -+#define _ppname_ghost(name) (((const _ppname *)(name)) - 1) -+#endif -+ -+#define ppname_size(name) (_ppname_ghost(name)->size) -+#define ppname_exec(name) (_ppname_ghost(name)->flags & PPNAME_EXEC) -+ -+#define PPNAME_ENCODED (1 << 0) -+#define PPNAME_DECODED (1 << 1) -+#define PPNAME_EXEC (1 << 1) -+ -+PPAPI ppname ppname_decoded (ppname name); -+PPAPI ppname ppname_encoded (ppname name); -+ -+/* string */ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define _ppstring_ghost(string) (((const _ppstring *)((void *)string)) - 1) -+#else -+#define _ppstring_ghost(string) (((const _ppstring *)(string)) - 1) -+#endif -+ -+#define ppstring_size(string) (_ppstring_ghost(string)->size) -+ -+#define PPSTRING_ENCODED (1 << 0) -+#define PPSTRING_DECODED (1 << 1) -+//#define PPSTRING_EXEC (1 << 2) // postscript only -+#define PPSTRING_PLAIN 0 -+#define PPSTRING_BASE16 (1 << 3) -+#define PPSTRING_BASE85 (1 << 4) -+#define PPSTRING_UTF16BE (1 << 5) -+#define PPSTRING_UTF16LE (1 << 6) -+ -+#define ppstring_type(string) (_ppstring_ghost(string)->flags & (PPSTRING_BASE16|PPSTRING_BASE85)) -+#define ppstring_hex(string) (_ppstring_ghost(string)->flags & PPSTRING_BASE16) -+#define ppstring_utf(string) (_ppstring_ghost(string)->flags & (PPSTRING_UTF16BE|PPSTRING_UTF16LE)) -+ -+PPAPI ppstring ppstring_decoded (ppstring string); -+PPAPI ppstring ppstring_encoded (ppstring string); -+ -+/* array */ -+ -+#define pparray_size(array) ((array)->size) -+#define pparray_at(array, index) ((array)->data + index) -+ -+#define pparray_first(array, index, obj) ((index) = 0, (obj) = pparray_at(array, 0)) -+#define pparray_next(index, obj) (++(index), ++(obj)) -+ -+#define pparray_get(array, index) (index < (array)->size ? pparray_at(array, index) : NULL) -+ -+PPAPI ppobj * pparray_get_obj (pparray *array, size_t index); -+PPAPI int pparray_get_bool (pparray *array, size_t index, int *v); -+PPAPI int pparray_get_int (pparray *array, size_t index, ppint *v); -+PPAPI int pparray_get_uint (pparray *array, size_t index, ppuint *v); -+PPAPI int pparray_get_num (pparray *array, size_t index, ppnum *v); -+PPAPI ppname pparray_get_name (pparray *array, size_t index); -+PPAPI ppstring pparray_get_string (pparray *array, size_t index); -+PPAPI pparray * pparray_get_array (pparray *array, size_t index); -+PPAPI ppdict * pparray_get_dict (pparray *array, size_t index); -+//PPAPI ppstream * pparray_get_stream (pparray *array, size_t index); -+PPAPI ppref * pparray_get_ref (pparray *array, size_t index); -+ -+PPAPI ppobj * pparray_rget_obj (pparray *array, size_t index); -+PPAPI int pparray_rget_bool (pparray *array, size_t index, int *v); -+PPAPI int pparray_rget_int (pparray *array, size_t index, ppint *v); -+PPAPI int pparray_rget_uint (pparray *array, size_t index, ppuint *v); -+PPAPI int pparray_rget_num (pparray *array, size_t index, ppnum *v); -+PPAPI ppname pparray_rget_name (pparray *array, size_t index); -+PPAPI ppstring pparray_rget_string (pparray *array, size_t index); -+PPAPI pparray * pparray_rget_array (pparray *array, size_t index); -+PPAPI ppdict * pparray_rget_dict (pparray *array, size_t index); -+PPAPI ppstream * pparray_rget_stream (pparray *array, size_t index); -+PPAPI ppref * pparray_rget_ref (pparray *array, size_t index); -+ -+/* dict */ -+ -+#define ppdict_size(dict) ((dict)->size) -+#define ppdict_at(dict, index) ((dict)->data + index) -+#define ppdict_key(dict, index) ((dict)->keys[index]) -+ -+PPAPI ppobj * ppdict_get_obj (ppdict *dict, const char *name); -+PPAPI int ppdict_get_bool (ppdict *dict, const char *name, int *v); -+PPAPI int ppdict_get_int (ppdict *dict, const char *name, ppint *v); -+PPAPI int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v); -+PPAPI int ppdict_get_num (ppdict *dict, const char *name, ppnum *v); -+PPAPI ppname ppdict_get_name (ppdict *dict, const char *name); -+PPAPI ppstring ppdict_get_string (ppdict *dict, const char *name); -+PPAPI pparray * ppdict_get_array (ppdict *dict, const char *name); -+PPAPI ppdict * ppdict_get_dict (ppdict *dict, const char *name); -+//PPAPI ppstream * ppdict_get_stream (ppdict *dict, const char *name); -+PPAPI ppref * ppdict_get_ref (ppdict *dict, const char *name); -+ -+PPAPI ppobj * ppdict_rget_obj (ppdict *dict, const char *name); -+PPAPI int ppdict_rget_bool (ppdict *dict, const char *name, int *v); -+PPAPI int ppdict_rget_int (ppdict *dict, const char *name, ppint *v); -+PPAPI int ppdict_rget_uint (ppdict *dict, const char *name, ppuint *v); -+PPAPI int ppdict_rget_num (ppdict *dict, const char *name, ppnum *v); -+PPAPI ppname ppdict_rget_name (ppdict *dict, const char *name); -+PPAPI ppstring ppdict_rget_string (ppdict *dict, const char *name); -+PPAPI pparray * ppdict_rget_array (ppdict *dict, const char *name); -+PPAPI ppdict * ppdict_rget_dict (ppdict *dict, const char *name); -+PPAPI ppstream * ppdict_rget_stream (ppdict *dict, const char *name); -+PPAPI ppref * ppdict_rget_ref (ppdict *dict, const char *name); -+ -+#define ppdict_first(dict, pkey, obj) (pkey = (dict)->keys, obj = (dict)->data) -+#define ppdict_next(pkey, obj) (++(pkey), ++(obj)) -+ -+/* stream */ -+ -+#define ppstream_dict(stream) ((stream)->dict) -+ -+PPAPI uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode); -+PPAPI uint8_t * ppstream_next (ppstream *stream, size_t *size); -+PPAPI uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode); -+PPAPI void ppstream_done (ppstream *stream); -+ -+PPAPI void ppstream_init_buffers (void); -+PPAPI void ppstream_free_buffers (void); -+ -+/* ref */ -+ -+#define ppref_obj(ref) (&(ref)->object) -+ -+/* xref */ -+ -+PPAPI ppxref * ppdoc_xref (ppdoc *pdf); -+PPAPI ppxref * ppxref_prev (ppxref *xref); -+PPAPI ppdict * ppxref_trailer (ppxref *xref); -+PPAPI ppdict * ppxref_catalog (ppxref *xref); -+PPAPI ppdict * ppxref_info (ppxref *xref); -+PPAPI ppref * ppxref_pages (ppxref *xref); -+PPAPI ppref * ppxref_find (ppxref *xref, ppuint refnumber); -+ -+/* doc */ -+ -+PPAPI ppdoc * ppdoc_load (const char *filename); -+PPAPI ppdoc * ppdoc_mem (const void *data, size_t size); -+PPAPI void ppdoc_free (ppdoc *pdf); -+ -+#define ppdoc_trailer(pdf) ppxref_trailer(ppdoc_xref(pdf)) -+#define ppdoc_catalog(pdf) ppxref_catalog(ppdoc_xref(pdf)) -+#define ppdoc_info(pdf) ppxref_info(ppdoc_xref(pdf)) -+#define ppdoc_pages(pdf) ppxref_pages(ppdoc_xref(pdf)) -+ -+PPAPI ppuint ppdoc_page_count (ppdoc *pdf); -+PPAPI ppref * ppdoc_page (ppdoc *pdf, ppuint index); -+PPAPI ppref * ppdoc_first_page (ppdoc *pdf); -+PPAPI ppref * ppdoc_next_page (ppdoc *pdf); -+ -+PPAPI ppstream * ppcontents_first (ppdict *dict); -+PPAPI ppstream * ppcontents_next (ppdict *dict, ppstream *stream); -+ -+/* crypt */ -+ -+typedef enum { -+ PPCRYPT_NONE = 0, -+ PPCRYPT_DONE = 1, -+ PPCRYPT_FAIL = -1, -+ PPCRYPT_PASS = -2 -+} ppcrypt_status; -+ -+PPAPI ppcrypt_status ppdoc_crypt_status (ppdoc *pdf); -+PPAPI ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength); -+ -+/* permission flags, effect in Acrobat File -> Properties -> Security tab */ -+ -+PPAPI ppint ppdoc_permissions (ppdoc *pdf); -+ -+#define PPDOC_ALLOW_PRINT (1<<2) // printing -+#define PPDOC_ALLOW_MODIFY (1<<3) // filling form fields, signing, creating template pages -+#define PPDOC_ALLOW_COPY (1<<4) // copying, copying for accessibility -+#define PPDOC_ALLOW_ANNOTS (1<<5) // filling form fields, copying, signing -+#define PPDOC_ALLOW_EXTRACT (1<<9) // contents copying for accessibility -+#define PPDOC_ALLOW_ASSEMBLY (1<<10) // (no effect) -+#define PPDOC_ALLOW_PRINT_HIRES (1<<11) // (no effect) -+ -+/* context */ -+ -+typedef struct ppcontext ppcontext; -+ -+PPAPI ppcontext * ppcontext_new (void); -+PPAPI void ppcontext_done (ppcontext *context); -+PPAPI void ppcontext_free (ppcontext *context); -+ -+/* contents parser */ -+ -+PPAPI ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); -+PPAPI ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname); -+PPAPI ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize); -+ -+/* boxes and transforms */ -+ -+typedef struct { -+ ppnum lx, ly, rx, ry; -+} pprect; -+ -+PPAPI pprect * pparray_to_rect (pparray *array, pprect *rect); -+PPAPI pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect); -+PPAPI pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect); -+ -+typedef struct { -+ ppnum xx, xy, yx, yy, x, y; -+} ppmatrix; -+ -+PPAPI ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix); -+PPAPI ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix); -+ -+/* logger */ -+ -+typedef void (*pplogger_callback) (const char *message, void *alien); -+PPAPI void pplog_callback (pplogger_callback logger, void *alien); -+PPAPI int pplog_prefix (const char *prefix); -+ -+/* version */ -+ -+PPAPI const char * ppdoc_version_string (ppdoc *pdf); -+PPAPI int ppdoc_version_number (ppdoc *pdf, int *minor); -+ -+/* doc info */ -+ -+PPAPI size_t ppdoc_file_size (ppdoc *pdf); -+PPAPI ppuint ppdoc_objects (ppdoc *pdf); -+PPAPI size_t ppdoc_memory (ppdoc *pdf, size_t *waste); -+ -+#endif -diff --git a/texk/web2c/luatexdir/luapplib/pparray.c b/texk/web2c/luatexdir/luapplib/pparray.c -new file mode 100644 -index 000000000..25e8c4950 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/pparray.c -@@ -0,0 +1,146 @@ -+ -+#include "pplib.h" -+ -+pparray * pparray_create (const ppobj *stackpos, size_t size, ppheap **pheap) -+{ -+ pparray *array; -+ ppobj *data; -+ array = (pparray *)ppheap_take(pheap, sizeof(pparray) + size * sizeof(ppobj)); -+ array->size = size; -+ array->data = data = (ppobj *)(array + 1); -+ memcpy(data, stackpos, size * sizeof(ppobj)); -+ return array; -+} -+ -+ppobj * pparray_get_obj (pparray *array, size_t index) -+{ -+ return pparray_get(array, index); -+} -+ -+ppobj * pparray_rget_obj (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_obj(obj) : NULL; -+} -+ -+int pparray_get_bool (pparray *array, size_t index, int *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_bool(obj, *v) : 0; -+} -+ -+int pparray_rget_bool (pparray *array, size_t index, int *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_bool(obj, *v) : 0; -+} -+ -+int pparray_get_int (pparray *array, size_t index, ppint *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_int(obj, *v) : 0; -+} -+ -+int pparray_rget_int (pparray *array, size_t index, ppint *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_int(obj, *v) : 0; -+} -+ -+int pparray_get_uint (pparray *array, size_t index, ppuint *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_uint(obj, *v) : 0; -+} -+ -+int pparray_rget_uint (pparray *array, size_t index, ppuint *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_uint(obj, *v) : 0; -+} -+ -+int pparray_get_num (pparray *array, size_t index, ppnum *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_num(obj, *v) : 0; -+} -+ -+int pparray_rget_num (pparray *array, size_t index, ppnum *v) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_num(obj, *v) : 0; -+} -+ -+ppname pparray_get_name (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_name(obj) : NULL; -+} -+ -+ppname pparray_rget_name (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_name(obj) : NULL; -+} -+ -+ppstring pparray_get_string (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_string(obj) : NULL; -+} -+ -+ppstring pparray_rget_string (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_string(obj) : NULL; -+} -+ -+pparray * pparray_get_array (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_array(obj) : NULL; -+} -+ -+pparray * pparray_rget_array (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_array(obj) : NULL; -+} -+ -+ppdict * pparray_get_dict (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_dict(obj) : NULL; -+} -+ -+ppdict * pparray_rget_dict (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_dict(obj) : NULL; -+} -+ -+/* -+ppstream * pparray_get_stream (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_stream(obj) : NULL; -+} -+*/ -+ -+ppstream * pparray_rget_stream (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_stream(obj) : NULL; -+} -+ -+ppref * pparray_get_ref (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_get_ref(obj) : NULL; -+} -+ -+ppref * pparray_rget_ref (pparray *array, size_t index) -+{ -+ ppobj *obj; -+ return (obj = pparray_get(array, index)) != NULL ? ppobj_rget_ref(obj) : NULL; -+} -diff --git a/texk/web2c/luatexdir/luapplib/pparray.h b/texk/web2c/luatexdir/luapplib/pparray.h -new file mode 100644 -index 000000000..6fdd8b814 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/pparray.h -@@ -0,0 +1,7 @@ -+ -+#ifndef PP_ARRAY_H -+#define PP_ARRAY_H -+ -+pparray * pparray_create (const ppobj *stack, size_t size, ppheap **pheap); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppconf.h b/texk/web2c/luatexdir/luapplib/ppconf.h -new file mode 100644 -index 000000000..57edc205a ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppconf.h -@@ -0,0 +1,76 @@ -+ -+#ifndef PP_CONF_H -+#define PP_CONF_H -+ -+/* -+Aux flags: -+ PPDLL -- indicates a part of a shared library -+ PPEXE -- indicates a host program using shared library functions -+*/ -+ -+#if defined(_WIN32) || defined(_WIN64) -+# ifdef PPDLL -+# define PPAPI __declspec(dllexport) -+# define PPDEF __declspec(dllexport) -+# else -+# ifdef PPEXE -+# define PPAPI __declspec(dllimport) -+# define PPDEF -+# else -+# define PPAPI -+# define PPDEF -+# endif -+# endif -+#else -+# define PPAPI -+# define PPDEF -+#endif -+ -+/* platform vs integers */ -+ -+#if defined(_WIN32) || defined(WIN32) -+# ifdef _MSC_VER -+# if defined(_M_64) || defined(_WIN64) -+# define MSVC64 -+# else -+# define MSVC32 -+# endif -+# else -+# if defined(__MINGW64__) -+# define MINGW64 -+# else -+# if defined(__MINGW32__) -+# define MINGW32 -+# endif -+# endif -+# endif -+#endif -+ -+#if defined(_WIN64) || defined(__MINGW32__) -+# define PPINT64F "%I64d" -+# define PPUINT64F "%I64u" -+#else -+# define PPINT64F "%lld" -+# define PPUINT64F "%llu" -+#endif -+ -+#if defined(MSVC64) -+# define PPINT(N) N##I64 -+# define PPUINT(N) N##UI64 -+# define PPINTF PPINT64F -+# define PPUINTF PPUINT64F -+#elif defined(MINGW64) -+# define PPINT(N) N##LL -+# define PPUINT(N) N##ULL -+# define PPINTF PPINT64F -+# define PPUINTF PPUINT64F -+#else // 32bit or sane 64bit (LP64, where long is long indeed) -+# define PPINT(N) N##L -+# define PPUINT(N) N##UL -+# define PPINTF "%ld" -+# define PPUINTF "%lu" -+#endif -+ -+#define PPSIZEF PPUINTF -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppcrypt.c b/texk/web2c/luatexdir/luapplib/ppcrypt.c -new file mode 100644 -index 000000000..780ec78be ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppcrypt.c -@@ -0,0 +1,628 @@ -+ -+#include "utilmd5.h" -+#include "utilsha.h" -+ -+#include "pplib.h" -+ -+/* crypt struct */ -+ -+#define CRYPT_AES (1<<0) -+#define CRYPT_RC4 (1<<1) -+#define CRYPT_MD (1<<2) -+#define CRYPT_NOMD (1<<3) -+ -+static ppcrypt * ppcrypt_create (ppheap **pheap) -+{ -+ ppcrypt *crypt; -+ crypt = (ppcrypt *)ppheap_take(pheap, sizeof(ppcrypt)); -+ memset(crypt, 0, sizeof(ppcrypt)); -+ return crypt; -+} -+ -+static int ppcrypt_type (ppcrypt *crypt, ppname cryptname, ppuint *length, int *cryptflags) -+{ -+ ppdict *filterdict; -+ ppname filtertype; -+ int cryptmd = 0, default256 = 0; -+ -+ if (crypt->map == NULL || (filterdict = ppdict_rget_dict(crypt->map, cryptname)) == NULL) -+ return 0; -+ if ((filtertype = ppdict_get_name(filterdict, "CFM")) == NULL) -+ return 0; -+ *cryptflags = 0; -+ if (ppname_is(filtertype, "V2")) -+ *cryptflags |= CRYPT_RC4; -+ else if (ppname_is(filtertype, "AESV2")) -+ *cryptflags |= CRYPT_AES; -+ else if (ppname_is(filtertype, "AESV3")) -+ *cryptflags |= CRYPT_AES, default256 = 1; -+ else -+ return 0; -+ /* pdf spec page. 134: /Length is said to be optional bit-length of the key, but it seems to be a mistake, as Acrobat -+ produces /Length key with bytes lengths, opposite to /Length key of the main encrypt dict. */ -+ if (length != NULL) -+ if (!ppdict_get_uint(filterdict, "Length", length)) -+ *length = (*cryptflags & CRYPT_RC4) ? 5 : (default256 ? 32 : 16); -+ /* one of metadata flags is set iff there is an explicit EncryptMetadata key */ -+ if (ppdict_get_bool(filterdict, "EncryptMetadata", &cryptmd)) -+ *cryptflags |= (cryptmd ? CRYPT_MD : CRYPT_NOMD); -+ return 1; -+} -+ -+static const uint8_t padding_string[] = { -+ 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, -+ 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A -+}; -+ -+static void ppcrypt_set_userpass (ppcrypt *crypt, const void *userpass, size_t userpasslength) -+{ -+ crypt->userpasslength = userpasslength > 32 ? 32 : userpasslength; -+ memcpy(crypt->userpass, userpass, crypt->userpasslength); -+ memcpy(crypt->userpass + crypt->userpasslength, padding_string, 32 - crypt->userpasslength); -+ crypt->flags |= PPCRYPT_USER_PASSWORD; -+} -+ -+static void ppcrypt_set_ownerpass (ppcrypt *crypt, const void *ownerpass, size_t ownerpasslength) -+{ -+ crypt->ownerpasslength = ownerpasslength > 32 ? 32 : ownerpasslength; -+ memcpy(crypt->ownerpass, ownerpass, crypt->ownerpasslength); -+ memcpy(crypt->ownerpass + crypt->ownerpasslength, padding_string, 32 - crypt->ownerpasslength); -+ crypt->flags |= PPCRYPT_OWNER_PASSWORD; -+} -+ -+/* retrieving user password from owner password and owner key (variant < 5) */ -+ -+static void ppcrypt_retrieve_userpass (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize) -+{ -+ uint8_t temp[16], rc4key[32], rc4key2[32]; -+ uint8_t i; -+ ppuint k; -+ -+ md5init(); -+ md5add(crypt->ownerpass, 32); -+ md5put(rc4key); -+ if (crypt->algorithm_revision >= 3) -+ { -+ for (i = 0; i < 50; ++i) -+ { -+ pplib_md5(rc4key, 16, temp); -+ memcpy(rc4key, temp, 16); -+ } -+ } -+ rc4_decode_data(ownerkey, ownerkeysize, crypt->userpass, rc4key, crypt->filekeylength); -+ if (crypt->algorithm_revision >= 3) -+ { -+ for (i = 1; i <= 19; ++i) -+ { -+ for (k = 0; k < crypt->filekeylength; ++k) -+ rc4key2[k] = rc4key[k] ^ i; -+ rc4_decode_data(crypt->userpass, 32, crypt->userpass, rc4key2, crypt->filekeylength); -+ } -+ } -+ //crypt->userpasslength = 32; -+ for (crypt->userpasslength = 0; crypt->userpasslength < 32; ++crypt->userpasslength) -+ if (memcmp(&crypt->userpass[crypt->userpasslength], padding_string, 32 - crypt->userpasslength) == 0) -+ break; -+ crypt->flags |= PPCRYPT_USER_PASSWORD; -+} -+ -+/* generating file key; pdf spec p. 125 */ -+ -+static void ppcrypt_filekey (ppcrypt *crypt, const void *ownerkey, size_t ownerkeysize, const void *id, size_t idsize) -+{ -+ uint32_t p; -+ uint8_t permissions[4], temp[16]; -+ int i; -+ -+ md5init(); -+ md5add(crypt->userpass, 32); -+ md5add(ownerkey, ownerkeysize); -+ p = (uint32_t)crypt->permissions; -+ permissions[0] = get_byte1(p); -+ permissions[1] = get_byte2(p); -+ permissions[2] = get_byte3(p); -+ permissions[3] = get_byte4(p); -+ md5add(permissions, 4); -+ md5add(id, idsize); -+ if (crypt->algorithm_revision >= 4 && (crypt->flags & PPCRYPT_NO_METADATA)) -+ md5add("\xFF\xFF\xFF\xFF", 4); -+ md5put(crypt->filekey); -+ if (crypt->algorithm_revision >= 3) -+ { -+ for (i = 0; i < 50; ++i) -+ { -+ pplib_md5(crypt->filekey, (size_t)crypt->filekeylength, temp); -+ memcpy(crypt->filekey, temp, 16); -+ } -+ } -+} -+ -+/* generating userkey for comparison with /U; requires a general file key and id; pdf spec page 126-127 */ -+ -+static void ppcrypt_userkey (ppcrypt *crypt, const void *id, size_t idsize, uint8_t *password_hash) -+{ -+ uint8_t rc4key2[32]; -+ uint8_t i; -+ ppuint k; -+ -+ if (crypt->algorithm_revision <= 2) -+ { -+ rc4_encode_data(padding_string, 32, password_hash, crypt->filekey, crypt->filekeylength); -+ } -+ else -+ { -+ md5init(); -+ md5add(padding_string, 32); -+ md5add(id, idsize); -+ md5put(password_hash); -+ rc4_encode_data(password_hash, 16, password_hash, crypt->filekey, crypt->filekeylength); -+ for (i = 1; i <= 19; ++i) -+ { -+ for (k = 0; k < crypt->filekeylength; ++k) -+ rc4key2[k] = crypt->filekey[k] ^ i; -+ rc4_encode_data(password_hash, 16, password_hash, rc4key2, crypt->filekeylength); -+ } -+ for (i = 16; i < 32; ++i) -+ password_hash[i] = password_hash[i - 16] ^ i; /* arbitrary 16-bytes padding */ -+ } -+} -+ -+/* validating /Perms key (pdf 1.7, /V 5 /R 5 crypt) */ -+ -+static const uint8_t nulliv[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* AES-256 initialization vector */ -+ -+static ppcrypt_status ppcrypt_authenticate_perms (ppcrypt *crypt, ppstring perms) -+{ /* decode /Perms string overriding crypt setup (should match anyway) */ -+ uint8_t permsdata[16]; -+ //int64_t p; -+ //int i; -+ -+ aes_decode_data(perms, ppstring_size(perms), permsdata, crypt->filekey, crypt->filekeylength, nulliv, AES_NULL_PADDING); -+ -+ if (permsdata[9] != 'a' || permsdata[10] != 'd' || permsdata[11] != 'b') -+ return PPCRYPT_FAIL; -+ -+ // do not update permissions flags; they seem to be different inside crypt string -+ //for (p = 0, i = 0; i < 8; ++i) -+ // p = p + (permsdata[i] << (i << 3)); /* low order bytes first */ -+ //crypt->permissions = (ppint)(int32_t)(p & 0x00000000FFFFFFFFLL); /* unset bits 33..64, treat as 32-bit signed int */ -+ -+ if (permsdata[8] == 'T') -+ crypt->flags &= ~PPCRYPT_NO_METADATA; -+ else if (permsdata[8] == 'F') -+ crypt->flags |= PPCRYPT_NO_METADATA; -+ -+ return PPCRYPT_DONE; -+} -+ -+ppcrypt_status ppdoc_crypt_init (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength) -+{ -+ ppcrypt *crypt; -+ ppdict *trailer, *encrypt; -+ ppobj *obj; -+ ppname name, *pkey; -+ ppstring userkey, ownerkey, userkey_e = NULL, ownerkey_e = NULL; -+ size_t hashlength; -+ pparray *idarray; -+ ppstring id = NULL, perms = NULL; -+ int cryptflags, encryptmd; -+ size_t strkeylength, stmkeylength; -+ -+ uint8_t password_hash[32]; /* /U and /O are 48 bytes strings for AES-256, but here we use only 32 */ -+ uint8_t *validation_salt, *key_salt; -+ -+ /* Every xref could theoretically have a separate encryption info. Not clarified in pdf spec but it seems that the top -+ level xref encryption info is the one to be applied to all objects in all xrefs, including older. */ -+ trailer = ppxref_trailer(pdf->xref); -+ if ((obj = ppdict_get_obj(trailer, "Encrypt")) == NULL) -+ return PPCRYPT_NONE; -+ /* Typically this is all done early, before loading body, so if /Encrypt is indirect reference, it points nothing. We have to load it here. */ -+ obj = ppobj_preloaded(pdf, obj); -+ if (obj->type != PPDICT) -+ return PPCRYPT_FAIL; -+ encrypt = obj->dict; -+ for (ppdict_first(encrypt, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) -+ (void)ppobj_preloaded(pdf, obj); -+ -+ if ((name = ppdict_get_name(encrypt, "Filter")) != NULL && !ppname_is(name, "Standard")) -+ return PPCRYPT_FAIL; -+ -+ if ((crypt = pdf->crypt) == NULL) -+ crypt = pdf->crypt = ppcrypt_create(&pdf->heap); -+ if (!ppdict_get_uint(encrypt, "V", &crypt->algorithm_variant)) -+ crypt->algorithm_variant = 0; -+ if (crypt->algorithm_variant < 1 || crypt->algorithm_variant > 5) -+ return PPCRYPT_FAIL; -+ if (!ppdict_get_uint(encrypt, "R", &crypt->algorithm_revision)) -+ return PPCRYPT_FAIL; -+ if (crypt->algorithm_revision >= 3) -+ crypt->flags |= PPCRYPT_OBSCURITY; -+ if (!ppdict_get_int(encrypt, "P", &crypt->permissions)) -+ return PPCRYPT_FAIL; -+ if ((userkey = ppdict_get_string(encrypt, "U")) == NULL || (ownerkey = ppdict_get_string(encrypt, "O")) == NULL) -+ return PPCRYPT_FAIL; -+ userkey = ppstring_decoded(userkey); -+ ownerkey = ppstring_decoded(ownerkey); -+ /* for some reason acrobat pads /O and /U to 127 bytes with NULL, so we don't check the exact length but ensure the minimal */ -+ hashlength = crypt->algorithm_variant < 5 ? 32 : 48; -+ if (ppstring_size(userkey) < hashlength || ppstring_size(ownerkey) < hashlength) -+ return PPCRYPT_FAIL; -+ if (crypt->algorithm_variant < 5) -+ { // get first string from /ID (must not be ref) -+ if ((idarray = ppdict_get_array(trailer, "ID")) == NULL || (id = pparray_get_string(idarray, 0)) == NULL) -+ return PPCRYPT_FAIL; -+ id = ppstring_decoded(id); -+ } -+ else -+ { -+ if ((userkey_e = ppdict_get_string(encrypt, "UE")) == NULL || (ownerkey_e = ppdict_get_string(encrypt, "OE")) == NULL) -+ return PPCRYPT_FAIL; -+ userkey_e = ppstring_decoded(userkey_e); -+ ownerkey_e = ppstring_decoded(ownerkey_e); -+ if (ppstring_size(userkey_e) < 32 || ppstring_size(ownerkey_e) < 32) -+ return PPCRYPT_FAIL; -+ if ((perms = ppdict_get_string(encrypt, "Perms")) == NULL) -+ return PPCRYPT_FAIL; -+ perms = ppstring_decoded(perms); -+ if (ppstring_size(perms) != 16) -+ return PPCRYPT_FAIL; -+ } -+ -+ switch (crypt->algorithm_revision) -+ { -+ case 1: -+ crypt->filekeylength = 5; -+ crypt->flags |= PPCRYPT_RC4; -+ break; -+ case 2: case 3: -+ if (ppdict_get_uint(encrypt, "Length", &crypt->filekeylength)) -+ crypt->filekeylength >>= 3; /* 40..256 bits, 5..32 bytes*/ -+ else -+ crypt->filekeylength = 5; /* 40 bits, 5 bytes */ -+ crypt->flags |= PPCRYPT_RC4; -+ break; -+ case 4: case 5: -+ if ((crypt->map = ppdict_rget_dict(encrypt, "CF")) == NULL) -+ return PPCRYPT_FAIL; -+ for (ppdict_first(crypt->map, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) -+ (void)ppobj_preloaded(pdf, obj); -+ /* /EncryptMetadata relevant only for version >=4, may be also provided in crypt filter dictionary; which takes a precedence then? -+ we assume that if there is an explicit EncryptMetadata key, it overrides main encrypt dict flag or default flag (the default is true, -+ meaning that Metadata stream is encrypted as others) */ -+ if (ppdict_get_bool(encrypt, "EncryptMetadata", &encryptmd) && !encryptmd) -+ crypt->flags |= PPCRYPT_NO_METADATA; -+ -+ strkeylength = stmkeylength = 0; -+ /* streams filter */ -+ if ((name = ppdict_get_name(encrypt, "StmF")) != NULL && ppcrypt_type(crypt, name, &stmkeylength, &cryptflags)) -+ { -+ if (cryptflags & CRYPT_AES) -+ crypt->flags |= PPCRYPT_STREAM_AES; -+ else if (cryptflags & CRYPT_RC4) -+ crypt->flags |= PPCRYPT_STREAM_RC4; -+ if (cryptflags & CRYPT_NOMD) -+ crypt->flags |= PPCRYPT_NO_METADATA; -+ else if (cryptflags & CRYPT_MD) -+ crypt->flags &= ~PPCRYPT_NO_METADATA; -+ } /* else identity */ -+ /* strings filter */ -+ if ((name = ppdict_get_name(encrypt, "StrF")) != NULL && ppcrypt_type(crypt, name, &strkeylength, &cryptflags)) -+ { -+ if (cryptflags & CRYPT_AES) -+ crypt->flags |= PPCRYPT_STRING_AES; -+ else if (cryptflags & CRYPT_RC4) -+ crypt->flags |= PPCRYPT_STRING_RC4; -+ } /* else identity */ -+ -+ /* /Length of encrypt dict is irrelevant here, theoretically every crypt filter may have own length... It means that we should -+ actually keep a different file key for streams and strings. But it leads to nonsense, as /U and /O entries refers to a single -+ keylength, without a distinction for strings/streams. So we have to assume /Length is consistent. To expose the limitation: */ -+ if ((crypt->flags & PPCRYPT_STREAM) && (crypt->flags & PPCRYPT_STRING)) -+ if (strkeylength != stmkeylength) -+ return PPCRYPT_FAIL; -+ crypt->filekeylength = stmkeylength ? stmkeylength : strkeylength; -+ if ((crypt->flags & PPCRYPT_STREAM) || (crypt->flags & PPCRYPT_STRING)) -+ if (crypt->filekeylength == 0) -+ return PPCRYPT_FAIL; -+ break; -+ default: -+ return PPCRYPT_FAIL; -+ } -+ -+ /* password */ -+ -+ if (userpass != NULL) -+ { -+ ppcrypt_set_userpass(crypt, userpass, userpasslength); -+ } -+ else if (ownerpass != NULL) -+ { -+ if (crypt->algorithm_variant < 5) // fetch user password from owner password -+ ppcrypt_retrieve_userpass(crypt, ownerkey, ppstring_size(ownerkey)); -+ else // open the document using owner password -+ ppcrypt_set_ownerpass(crypt, ownerpass, ownerpasslength); -+ } -+ else -+ { -+ return PPCRYPT_FAIL; -+ } -+ -+ if (crypt->algorithm_variant < 5) -+ { /* authenticate by comparing a generated vs present /U entry; depending on variant 16 or 32 bytes to compare */ -+ ppcrypt_filekey(crypt, ownerkey, ppstring_size(ownerkey), id, ppstring_size(id)); -+ ppcrypt_userkey(crypt, id, ppstring_size(id), password_hash); /* needs file key so comes after key generation */ -+ if (memcmp(userkey, password_hash, (crypt->algorithm_revision >= 3 ? 16 : 32)) == 0) -+ return PPCRYPT_DONE; -+ return PPCRYPT_PASS; -+ } -+ if (crypt->flags & PPCRYPT_USER_PASSWORD) -+ { -+ validation_salt = (uint8_t *)userkey + 32; -+ key_salt = validation_salt + 8; -+ sha256init(); -+ sha256add(crypt->userpass, crypt->userpasslength); -+ sha256add(validation_salt, 8); -+ sha256put(password_hash); -+ if (memcmp(userkey, password_hash, 32) != 0) -+ return PPCRYPT_PASS; -+ sha256init(); -+ sha256add(crypt->userpass, crypt->userpasslength); -+ sha256add(key_salt, 8); -+ sha256put(password_hash); -+ aes_decode_data(userkey_e, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING); -+ return ppcrypt_authenticate_perms(crypt, perms); -+ } -+ if (crypt->flags & PPCRYPT_OWNER_PASSWORD) -+ { -+ validation_salt = (uint8_t *)ownerkey + 32; -+ key_salt = validation_salt + 8; -+ sha256init(); -+ sha256add(crypt->ownerpass, crypt->ownerpasslength); -+ sha256add(validation_salt, 8); -+ sha256add(userkey, 48); -+ sha256put(password_hash); -+ if (memcmp(ownerkey, password_hash, 32) != 0) -+ return PPCRYPT_PASS; -+ sha256init(); -+ sha256add(crypt->ownerpass, crypt->ownerpasslength); -+ sha256add(key_salt, 8); -+ sha256add(userkey, 48); -+ sha256put(password_hash); -+ aes_decode_data(ownerkey_e, 32, crypt->filekey, password_hash, 32, nulliv, AES_NULL_PADDING); -+ return ppcrypt_authenticate_perms(crypt, perms); -+ } -+ return PPCRYPT_FAIL; // should never get here -+} -+ -+/* decrypting strings */ -+ -+/* -+Since strings are generally rare, but might occur in mass (name trees). We generate decryption key when needed. -+All strings within the same reference are crypted with the same key. Both RC4 and AES algorithms expands -+the crypt key in some way and the result of expansion is the same for the same crypt key. Instead of recreating -+the ky for every string, we backup the initial decryption state. -+*/ -+ -+static void ppcrypt_strkey (ppcrypt *crypt, ppref *ref, int aes) -+{ -+ if (crypt->cryptkeylength > 0) -+ { /* crypt key already generated, just reinitialize crypt states */ -+ if (aes) -+ { /* aes codecs that works on c-strings do not modify aes_state flags at all, so we actually don't need to revitalize the state, -+ we only rewrite an initialization vector, which is modified during crypt procedure */ -+ } -+ else -+ { /* rc4 crypt map is modified during crypt procedure, so here we reinitialize rc4 bytes map */ -+ rc4_map_restore(&crypt->rc4state, &crypt->rc4copy); -+ } -+ return; -+ } -+ -+ if (crypt->algorithm_variant < 5) -+ { -+ crypt->filekey[crypt->filekeylength + 0] = get_byte1(ref->number); -+ crypt->filekey[crypt->filekeylength + 1] = get_byte2(ref->number); -+ crypt->filekey[crypt->filekeylength + 2] = get_byte3(ref->number); -+ crypt->filekey[crypt->filekeylength + 3] = get_byte1(ref->version); -+ crypt->filekey[crypt->filekeylength + 4] = get_byte2(ref->version); -+ -+ if (aes) -+ { -+ crypt->filekey[crypt->filekeylength + 5] = 0x73; -+ crypt->filekey[crypt->filekeylength + 6] = 0x41; -+ crypt->filekey[crypt->filekeylength + 7] = 0x6C; -+ crypt->filekey[crypt->filekeylength + 8] = 0x54; -+ } -+ -+ pplib_md5(crypt->filekey, crypt->filekeylength + (aes ? 9 : 5), crypt->cryptkey); -+ crypt->cryptkeylength = crypt->filekeylength + 5 >= 16 ? 16 : crypt->filekeylength + 5; -+ } -+ else -+ { -+ memcpy(crypt->cryptkey, crypt->filekey, 32); -+ crypt->cryptkeylength = 32; -+ } -+ -+ if (aes) -+ { -+ aes_decode_initialize(&crypt->aesstate, &crypt->aeskeyblock, crypt->cryptkey, crypt->cryptkeylength, NULL); -+ aes_pdf_mode(&crypt->aesstate); -+ } -+ else -+ { -+ rc4_state_initialize(&crypt->rc4state, &crypt->rc4map, crypt->cryptkey, crypt->cryptkeylength); -+ rc4_map_save(&crypt->rc4state, &crypt->rc4copy); -+ } -+} -+ -+int ppstring_decrypt (ppcrypt *crypt, const void *input, size_t size, void *output, size_t *newsize) -+{ -+ int aes, rc4; -+ aes = crypt->flags & PPCRYPT_STRING_AES; -+ rc4 = crypt->flags & PPCRYPT_STRING_RC4; -+ if (aes || rc4) -+ { -+ ppcrypt_strkey(crypt, crypt->ref, aes); -+ if (aes) -+ *newsize = aes_decode_state_data(&crypt->aesstate, input, size, output); -+ else // if (rc4) -+ *newsize = rc4_decode_state_data(&crypt->rc4state, input, size, output); -+ return 1; -+ } -+ return 0; // identity crypt -+} -+ -+/* decrypting streams */ -+ -+/* -+Streams are decrypted everytime when accessing the stream data. We need to be able to get or make -+the key for decryption as long as the stream is alive. And to get the key we need the reference -+number and version, plus document crypt info. First thought was to keep the reference to which -+the stream belongs; stream->ref and accessing the crypt info stream->ref->xref->pdf->crypt. -+It would be ok as long as absolutelly nothing happens with ref and crypt. At some point pplib -+may drift into rewriting support, which would imply ref/xref/crypt/pdf structures modifications. -+So I feel better with generating a crypt key for every stream in encrypted document, paying a cost -+of pplib_md5() for all streams, not necessarily those actually read. -+ -+Key generation is the same as for strings, but different for distinct encryption methods (rc4 vs aes). -+Since streams and strings might theoretically be encrypted with different filters. No reason to cacche -+decryption state here. -+*/ -+ -+static ppstring ppcrypt_stmkey (ppcrypt *crypt, ppref *ref, int aes, ppheap **pheap) -+{ -+ ppstring cryptkeystring; -+ //if (crypt->cryptkeylength > 0) -+ // return; -+ -+ if (crypt->algorithm_variant < 5) -+ { -+ crypt->filekey[crypt->filekeylength + 0] = get_byte1(ref->number); -+ crypt->filekey[crypt->filekeylength + 1] = get_byte2(ref->number); -+ crypt->filekey[crypt->filekeylength + 2] = get_byte3(ref->number); -+ crypt->filekey[crypt->filekeylength + 3] = get_byte1(ref->version); -+ crypt->filekey[crypt->filekeylength + 4] = get_byte2(ref->version); -+ -+ if (aes) -+ { -+ crypt->filekey[crypt->filekeylength + 5] = 0x73; -+ crypt->filekey[crypt->filekeylength + 6] = 0x41; -+ crypt->filekey[crypt->filekeylength + 7] = 0x6C; -+ crypt->filekey[crypt->filekeylength + 8] = 0x54; -+ } -+ -+ pplib_md5(crypt->filekey, crypt->filekeylength + (aes ? 9 : 5), crypt->cryptkey); -+ crypt->cryptkeylength = crypt->filekeylength + 5 >= 16 ? 16 : crypt->filekeylength + 5; // how about 256bits AES?? -+ } -+ else -+ { // we could actually generate this string once, but.. aes itself is way more expensive that we can earn here -+ memcpy(crypt->cryptkey, crypt->filekey, 32); // just for the record -+ crypt->cryptkeylength = 32; -+ } -+ cryptkeystring = ppstring_internal(crypt->cryptkey, crypt->cryptkeylength, pheap); -+ return ppstring_decoded(cryptkeystring); -+} -+ -+void ppstream_info (ppstream *stream, ppdoc *pdf) -+{ // just after the stream creation -+ ppdict *dict; -+ ppobj *fobj, *pobj; -+ pparray *farray; -+ ppname fname, owncryptfilter, tname; -+ ppcrypt *crypt; -+ ppref *ref; -+ size_t i; -+ int owncrypt, cflags; -+ -+ dict = stream->dict; -+ ppdict_rget_uint(dict, "Length", &stream->length); -+ -+ if ((fobj = ppdict_get_obj(dict, "Filter")) != NULL) -+ { -+ fobj = ppobj_preloaded(pdf, fobj); -+ switch (fobj->type) -+ { -+ case PPNAME: -+ stream->flags |= PPSTREAM_COMPRESSED; -+ break; -+ case PPARRAY: -+ if (fobj->array->size > 0) -+ stream->flags |= PPSTREAM_COMPRESSED; -+ break; -+ default: -+ break; -+ } -+ } -+ if ((crypt = pdf->crypt) == NULL || (ref = crypt->ref) == NULL) -+ return; -+ owncrypt = 0; -+ owncryptfilter = NULL; -+ if (fobj != NULL) -+ { -+ if ((pobj = ppdict_get_obj(dict, "DecodeParms")) != NULL) -+ pobj = ppobj_preloaded(pdf, pobj); -+ switch (fobj->type) -+ { -+ case PPNAME: -+ if (ppname_is(fobj->name, "Crypt")) -+ { -+ owncrypt = 1; -+ if (pobj != NULL && pobj->type == PPDICT) // /Type /CryptFilterDecodeParms -+ owncryptfilter = ppdict_get_name(pobj->dict, "Name"); -+ } -+ break; -+ case PPARRAY: -+ farray = fobj->array; -+ for (i = 0; i < farray->size; ++i) -+ { -+ if ((fname = pparray_get_name(farray, i)) != NULL && ppname_is(fname, "Crypt")) -+ { -+ owncrypt = 1; -+ if (pobj != NULL && pobj->type == PPARRAY && (pobj = pparray_get_obj(pobj->array, i)) != NULL) -+ { -+ pobj = ppobj_preloaded(pdf, pobj); -+ if (pobj != NULL && pobj->type == PPDICT) // /Type /CryptFilterDecodeParms -+ owncryptfilter = ppdict_get_name(pobj->dict, "Name"); -+ } -+ break; -+ } -+ } -+ break; -+ default: -+ break; -+ } -+ } -+ -+ if (owncrypt) -+ { -+ stream->flags |= PPSTREAM_ENCRYPTED_OWN; -+ /* Seems a common habit to use just /Crypt filter name with no params, which defaults to /Identity. -+ A real example with uncompressed metadata: <> */ -+ if (owncryptfilter != NULL && !ppname_is(owncryptfilter, "Identity")) -+ { -+ if (crypt->map != NULL && ppcrypt_type(crypt, owncryptfilter, NULL, &cflags)) -+ { -+ if (cflags & CRYPT_AES) -+ stream->flags |= PPSTREAM_ENCRYPTED_AES; -+ else if (cflags & CRYPT_RC4) -+ stream->flags |= PPSTREAM_ENCRYPTED_RC4; -+ } -+ } -+ } -+ else -+ { -+ if ((crypt->flags & PPCRYPT_NO_METADATA) && (tname = ppdict_get_name(dict, "Type")) != NULL && ppname_is(tname, "Metadata")) -+ ; /* special treatment of metadata stream; we assume that explicit /Filter /Crypt setup overrides document level setup of EncryptMetadata. */ -+ else -+ { -+ if (crypt->flags & PPCRYPT_STREAM_RC4) -+ stream->flags |= PPSTREAM_ENCRYPTED_RC4; -+ else if (crypt->flags & PPCRYPT_STREAM_AES) -+ stream->flags |= PPSTREAM_ENCRYPTED_AES; -+ } -+ } -+ -+ /* finally, if the stream is encrypted with non-identity crypt (implicit or explicit), make and save the crypt key */ -+ if (stream->flags & PPSTREAM_ENCRYPTED) -+ stream->cryptkey = ppcrypt_stmkey(crypt, ref, ((stream->flags & PPSTREAM_ENCRYPTED_AES) != 0), &pdf->heap); -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppcrypt.h b/texk/web2c/luatexdir/luapplib/ppcrypt.h -new file mode 100644 -index 000000000..fc74cfe37 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppcrypt.h -@@ -0,0 +1,61 @@ -+ -+#ifndef PP_CRYPT_H -+#define PP_CRYPT_H -+ -+#include "ppfilter.h" -+#include "utilcrypt.h" -+#include "utilcryptdef.h" -+ -+typedef struct { -+ ppuint algorithm_variant; /* /V entry of encrypt dict */ -+ ppuint algorithm_revision; /* /R entry of encrypt dict */ -+ ppint permissions; /* /P entry of encrypt dict */ -+ ppdict *map; /* /CF filters map of encrypt dict */ -+ uint8_t userpass[32]; /* padded user password */ -+ size_t userpasslength; /* the length of unpadded user password */ -+ uint8_t ownerpass[32]; /* padded owner password */ -+ size_t ownerpasslength; /* the length of unpadded owner password */ -+ uint8_t filekey[32+5+4]; /* generated file key with extra space of 5..9 bytes for salt */ -+ size_t filekeylength; /* key length; usually 5, 16 or 32 bytes */ -+ uint8_t cryptkey[32]; /* final crypt key for a given reference */ -+ size_t cryptkeylength; /* final crypt key length; usually keylength + 5 */ -+ ppref *ref; /* currently loaded ref (each ref may have a different key) */ -+ union { /* cached crypt states for strings encrypted/decrypted with the same key */ -+ struct { -+ rc4_state rc4state; -+ rc4_map rc4map; -+ rc4_map rc4copy; -+ }; -+ struct { -+ aes_state aesstate; -+ aes_keyblock aeskeyblock; -+ uint8_t ivcopy[16]; -+ }; -+ }; -+ int flags; -+} ppcrypt; -+ -+#define PPCRYPT_NO_METADATA (1<<0) -+#define PPCRYPT_USER_PASSWORD (1<<1) -+#define PPCRYPT_OWNER_PASSWORD (1<<2) -+#define PPCRYPT_STREAM_RC4 (1<<3) -+#define PPCRYPT_STRING_RC4 (1<<4) -+#define PPCRYPT_STREAM_AES (1<<5) -+#define PPCRYPT_STRING_AES (1<<6) -+#define PPCRYPT_OBSCURITY (1<<7) -+ -+#define PPCRYPT_STREAM (PPCRYPT_STREAM_AES|PPCRYPT_STREAM_RC4) -+#define PPCRYPT_STRING (PPCRYPT_STRING_AES|PPCRYPT_STRING_RC4) -+#define PPCRYPT_RC4 (PPCRYPT_STREAM_RC4|PPCRYPT_STRING_RC4) -+#define PPCRYPT_AES (PPCRYPT_STREAM_AES|PPCRYPT_STRING_AES) -+ -+ppcrypt_status ppdoc_crypt_init (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength); -+int ppstring_decrypt (ppcrypt *crypt, const void *input, size_t size, void *output, size_t *newsize); -+ -+#define ppcrypt_start_ref(crypt, r) ((crypt)->ref = r, (crypt)->cryptkeylength = 0) -+#define ppcrypt_end_ref(crypt) ((crypt)->ref = NULL, (crypt)->cryptkeylength = 0) -+#define ppcrypt_ref(pdf, crypt) ((crypt = (pdf)->crypt) != NULL && crypt->ref != NULL) -+ -+void ppstream_info (ppstream *stream, ppdoc *pdf); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppdict.c b/texk/web2c/luatexdir/luapplib/ppdict.c -new file mode 100644 -index 000000000..f04403d83 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppdict.c -@@ -0,0 +1,163 @@ -+ -+#include "pplib.h" -+ -+ppdict * ppdict_create (const ppobj *stackpos, size_t size, ppheap **pheap) -+{ -+ ppdict *dict; -+ ppobj *data; -+ ppname *pkey; -+ size_t i; -+ size >>= 1; -+ dict = (ppdict *)ppheap_take(pheap, sizeof(ppdict) + size * sizeof(ppobj) + (size + 1) * sizeof(ppname *)); // ? + size * sizeof(ppdict_map_node) -+ dict->size = 0; -+ dict->data = data = (ppobj *)(dict + 1); -+ dict->keys = pkey = (ppname *)(dict->data + size); -+ for (i = 0; i < size; ++i, stackpos += 2) -+ { -+ if (stackpos->type != PPNAME) // we need this check at lest for trailer hack -+ continue; -+ *pkey = stackpos->name; -+ *data = *(stackpos + 1); -+ ++pkey, ++data, ++dict->size; -+ } -+ *pkey = NULL; // sentinel for convinient iteration -+ return dict; -+} -+ -+ppobj * ppdict_get_obj (ppdict *dict, const char *name) -+{ // some lookup? will see -+ ppname *pkey; -+ ppobj *obj; -+ for (ppdict_first(dict, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) -+ if (strcmp(*pkey, name) == 0) // not ppname_eq() or ppname_is()!! -+ return obj; -+ return NULL; -+} -+ -+ppobj * ppdict_rget_obj (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_obj(obj) : NULL; -+} -+ -+int ppdict_get_bool (ppdict *dict, const char *name, int *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_bool(obj, *v) : 0; -+} -+ -+int ppdict_rget_bool (ppdict *dict, const char *name, int *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_bool(obj, *v) : 0; -+} -+ -+int ppdict_get_int (ppdict *dict, const char *name, ppint *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_int(obj, *v) : 0; -+} -+ -+int ppdict_rget_int (ppdict *dict, const char *name, ppint *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_int(obj, *v) : 0; -+} -+ -+int ppdict_get_uint (ppdict *dict, const char *name, ppuint *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_uint(obj, *v) : 0; -+} -+ -+int ppdict_rget_uint (ppdict *dict, const char *name, ppuint *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_uint(obj, *v) : 0; -+} -+ -+int ppdict_get_num (ppdict *dict, const char *name, ppnum *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_num(obj, *v) : 0; -+} -+ -+int ppdict_rget_num (ppdict *dict, const char *name, ppnum *v) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_num(obj, *v) : 0; -+} -+ -+ppname ppdict_get_name (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_name(obj) : NULL; -+} -+ -+ppname ppdict_rget_name (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_name(obj) : NULL; -+} -+ -+ppstring ppdict_get_string (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_string(obj) : NULL; -+} -+ -+ppstring ppdict_rget_string (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_string(obj) : NULL; -+} -+ -+pparray * ppdict_get_array (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_array(obj) : NULL; -+} -+ -+pparray * ppdict_rget_array (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_array(obj) : NULL; -+} -+ -+ppdict * ppdict_get_dict (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_dict(obj) : NULL; -+} -+ -+ppdict * ppdict_rget_dict (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_dict(obj) : NULL; -+} -+ -+/* -+ppstream * ppdict_get_stream (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_stream(obj) : NULL; -+} -+*/ -+ -+ppstream * ppdict_rget_stream (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_stream(obj) : NULL; -+} -+ -+ppref * ppdict_get_ref (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_get_ref(obj) : NULL; -+} -+ -+ppref * ppdict_rget_ref (ppdict *dict, const char *name) -+{ -+ ppobj *obj; -+ return (obj = ppdict_get_obj(dict, name)) != NULL ? ppobj_rget_ref(obj) : NULL; -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppdict.h b/texk/web2c/luatexdir/luapplib/ppdict.h -new file mode 100644 -index 000000000..5a808b772 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppdict.h -@@ -0,0 +1,7 @@ -+ -+#ifndef PP_DICT_H -+#define PP_DICT_H -+ -+ppdict * ppdict_create (const ppobj *stack, size_t size, ppheap **pheap); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppfilter.h b/texk/web2c/luatexdir/luapplib/ppfilter.h -new file mode 100644 -index 000000000..583aa8cf4 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppfilter.h -@@ -0,0 +1,10 @@ -+ -+#ifndef PP_FILTER_H -+#define PP_FILTER_H -+ -+#include "utilbasexx.h" -+#include "utilflate.h" -+#include "utillzw.h" -+#include "utilfpred.h" -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppheap.c b/texk/web2c/luatexdir/luapplib/ppheap.c -new file mode 100644 -index 000000000..f05e1b7a5 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppheap.c -@@ -0,0 +1,424 @@ -+ -+#include "pplib.h" -+ -+#define PPHEAP_BUFFER 0xFFFF -+#define PPHEAP_WASTE 0x00FF -+ -+#define ppheap_head(heap) ((uint8_t *)((heap) + 1)) -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+# define PPHEAP_ARCH_ARM -+# define PPHEAP_NEED_ALIGNMENT -+#endif -+ -+ -+ -+#ifdef PPHEAP_NEED_ALIGNMENT -+/* Tests has shown that long double seems to work: */ -+/* for 32bit aligned_data has algn: 64 as ppxref and ppref, */ -+/* the other algns divide algn: 64, so it's ok.*/ -+/* Hopefully it's ok for aarch64 too */ -+ -+/* These data are stored in ppheap.c.001t.tu */ -+/* made with gcc -fdump-tree-all-fdump-tree-all */ -+ -+ -+/* @2586 identifier_node strg: ppxref lngt: 6 */ -+/* @2565 record_type name: @2586 size: @679 algn: 64 */ -+/* tag : struct flds: @2587 */ -+ -+ -+/* @2672 identifier_node strg: ppxsec lngt: 6 */ -+/* @2648 type_decl name: @2672 type: @2623 scpe: @221 */ -+/* srcp: ppxref.h:16 chain: @2673 */ -+/* @2623 record_type name: @2648 unql: @2649 size: @593 */ -+/* algn: 32 tag : struct flds: @2650 */ -+ -+ -+/* @2642 identifier_node strg: ppstream lngt: 8 */ -+/* @2615 type_decl name: @2642 type: @2643 scpe: @221 */ -+/* srcp: ppapi.h:54 chain: @2644 */ -+/* @2643 record_type name: @2615 unql: @2614 size: @634 */ -+/* algn: 32 tag : struct flds: @2641 */ -+ -+ -+/* @2765 identifier_node strg: ppkids lngt: 6 */ -+/* @2743 type_decl name: @2765 type: @2766 scpe: @221 */ -+/* srcp: ppload.h:16 chain: @2767 */ -+/* @2766 record_type name: @2743 unql: @2742 size: @19 */ -+/* algn: 32 tag : struct flds: @2764 */ -+ -+ -+/* @2625 identifier_node strg: ppdoc lngt: 5 */ -+/* @2605 record_type name: @2625 size: @2626 algn: 32 */ -+/* tag : struct flds: @2627 */ -+ -+/* @2526 identifier_node strg: ppref lngt: 5 */ -+/* @2513 record_type name: @2526 size: @662 algn: 64 */ -+/* tag : struct flds: @2527 */ -+ -+ -+/* @2595 identifier_node strg: ppdict lngt: 6 */ -+/* @2576 type_decl name: @2595 type: @2596 scpe: @221 */ -+/* srcp: ppapi.h:45 chain: @2597 */ -+/* @2596 record_type name: @2576 unql: @2575 size: @593 */ -+/* algn: 32 tag : struct flds: @2594 */ -+ -+ -+/* @2769 identifier_node strg: ppcrypt_status lngt: 14 */ -+/* @2752 type_decl name: @2769 type: @2770 scpe: @221 */ -+/* srcp: ppapi.h:295 chain: @2771 */ -+/* @2770 enumeral_type name: @2752 unql: @2655 size: @5 */ -+/* algn: 32 prec: 32 sign: signed */ -+/* min : @6 max : @7 csts: @2681 */ -+ -+ -+/* @2558 identifier_node strg: pparray lngt: 7 */ -+/* @2541 type_decl name: @2558 type: @2559 scpe: @221 */ -+/* srcp: ppapi.h:39 chain: @2560 */ -+/* @2559 record_type name: @2541 unql: @2540 size: @19 */ -+/* algn: 32 tag : struct flds: @2557 */ -+ -+ -+/* @2817 identifier_node strg: aligned_data */ -+/* @2801 type_decl name: @2817 type: @2818 scpe: @221 */ -+/* srcp: ppheap.c:22 chain: @2819 */ -+/* @2818 real_type name: @2801 unql: @99 size: @19 */ -+/* algn: 64 prec: 64 */ -+ -+ -+typedef long double aligned_data; -+ -+ -+#define ALIGN_BUFF_BUCKET_SIZE 0x3000 /* heuristic value, found by running few tests */ -+#ifdef __SIZEOF_POINTER__ -+#define SIZE_OF_POINTER __SIZEOF_POINTER__ -+#else -+#define SIZE_OF_POINTER (sizeof(void *)) -+#endif -+ -+typedef struct _simplereg { -+ size_t bucket_pos; -+ size_t bucket_size; -+ size_t heap_instance; -+ aligned_data **align_data_set ; -+} simplereg; -+ -+/* By default static vars are initialized to NULL, but to be clear.. */ -+static simplereg *align_set = NULL ; -+ -+static void align_init_set(void){ -+ size_t size ; -+ -+ if (align_set) { -+ align_set->heap_instance++; -+ return ; -+ } -+ -+ align_set = malloc(sizeof(simplereg)); -+ if (!align_set) { -+ fprintf(stderr,"! fatal error: unable to setup master register for aligned pointers\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ size = SIZE_OF_POINTER*ALIGN_BUFF_BUCKET_SIZE; -+ align_set->align_data_set = malloc(size); -+ if (!align_set->align_data_set) { -+ fprintf(stderr,"! fatal error: unable to setup register for aligned pointers\n"); -+ exit(EXIT_FAILURE); -+ } -+ -+ align_set->bucket_pos = 0; -+ align_set->bucket_size = ALIGN_BUFF_BUCKET_SIZE; -+ align_set->heap_instance = 1; -+ memset(align_set->align_data_set, 0UL,size); -+} -+ -+static void align_save_into_set(aligned_data *p){ -+ if (align_set->bucket_pos >= align_set->bucket_size) { -+ size_t new_size; -+ aligned_data **align_data_set_new; -+ -+ if(!align_set->align_data_set){ -+ fprintf(stderr,"! fatal error: unable to save aligned pointer,corrupted set\n"); -+ exit(EXIT_FAILURE); -+ } -+ new_size = (ALIGN_BUFF_BUCKET_SIZE+align_set->bucket_size)*SIZE_OF_POINTER; -+ align_data_set_new = malloc(new_size); -+ if (!align_data_set_new) { -+ fprintf(stderr,"! fatal error: unable to save aligned pointer\n"); -+ exit(EXIT_FAILURE); -+ } -+ memset(align_data_set_new,0,new_size); -+ memcpy(align_data_set_new, align_set->align_data_set, align_set->bucket_size*SIZE_OF_POINTER); -+ free(align_set->align_data_set); -+ align_set->align_data_set = align_data_set_new ; -+ align_set->bucket_size += ALIGN_BUFF_BUCKET_SIZE; -+ } -+ if (align_set->bucket_pos>align_set->bucket_size){ -+ fprintf(stderr,"! fatal error: unable to save aligned pointer, wrong position\n"); -+ exit(EXIT_FAILURE); -+ } -+ align_set->align_data_set[align_set->bucket_pos] = p ; -+ align_set->bucket_pos++; -+ -+} -+ -+static void align_free_set(void){ -+ /* We don't know what heap does with its data, so free here is not secure */ -+ -+ if(align_set){ -+ if (align_set->heap_instance>1) { -+ align_set->heap_instance--; -+ } else if (align_set->heap_instance ==1) { -+ if (align_set->align_data_set){ -+ size_t p; -+ for(p=1;pbucket_pos;p++){ -+ if (align_set->align_data_set[p]) { -+ free(align_set->align_data_set[p]); -+ } -+ } -+ free(align_set->align_data_set); -+ align_set->align_data_set = NULL; -+ } -+ align_set->heap_instance=0; -+ free(align_set); -+ align_set = NULL ; -+ } -+ } -+} -+ -+#endif /* PPHEAP_NEED_ALIGNMENT */ -+ -+ -+static ppheap * ppheap_create (size_t size) -+{ -+ ppheap *heap; -+ heap = (ppheap *)pp_malloc(sizeof(ppheap) + size * sizeof(uint8_t)); -+ heap->size = size; -+ heap->space = size; -+ heap->data = ppheap_head(heap); -+ heap->prev = NULL; -+ return heap; -+} -+ -+ppheap * ppheap_new (void) -+{ -+#ifdef PPHEAP_NEED_ALIGNMENT -+ align_init_set(); -+#endif -+ return ppheap_create(PPHEAP_BUFFER); -+} -+ -+void ppheap_free (ppheap *heap) -+{ -+ ppheap *prev; -+ do -+ { -+ prev = heap->prev; -+ pp_free(heap); -+ heap = prev; -+ } while (heap != NULL); -+#ifdef PPHEAP_NEED_ALIGNMENT -+ align_free_set(); -+#endif -+ -+} -+ -+void ppheap_renew (ppheap *heap) -+{ // free all but first -+ ppheap *prev; -+ if ((prev = heap->prev) != NULL) -+ { -+ heap->prev = NULL; -+ ppheap_free(prev); -+ } -+ heap->size = heap->space; -+ heap->data = ppheap_head(heap); -+} -+ -+static ppheap * ppheap_insert_top (ppheap **pheap, size_t size) -+{ -+ ppheap *heap; -+ heap = ppheap_create(size); -+ heap->prev = (*pheap); -+ *pheap = heap; -+ return heap; -+} -+ -+static ppheap * ppheap_insert_sub (ppheap **pheap, size_t size) -+{ -+ ppheap *heap; -+ heap = ppheap_create(size); -+ heap->prev = (*pheap)->prev; -+ (*pheap)->prev = heap; -+ return heap; -+} -+ -+void * ppheap_take (ppheap **pheap, size_t size) -+{ -+ ppheap *heap; -+ uint8_t *data; -+#ifdef PPHEAP_NEED_ALIGNMENT -+ aligned_data *p_aligned_data; -+#endif -+ heap = *pheap; -+ if (size <= heap->size) -+ ; -+ else if (heap->size <= PPHEAP_WASTE && size <= (PPHEAP_BUFFER >> 1)) -+ heap = ppheap_insert_top(pheap, PPHEAP_BUFFER); -+ else -+ heap = ppheap_insert_sub(pheap, size); -+ data = heap->data; -+ heap->data += size; -+ heap->size -= size; -+#ifdef PPHEAP_NEED_ALIGNMENT -+ /* Todo: only if data%sizeof(aligned_data) != 0 */ -+ p_aligned_data = malloc(size); -+ memcpy(p_aligned_data,data,size); -+ align_save_into_set(p_aligned_data); -+ return (void *)p_aligned_data; -+#else -+ return (void *)data; -+#endif -+ -+} -+ -+ -+/* iof buffer tied to a heap */ -+ -+static ppheap * ppheap_resize (ppheap **pheap, size_t size) -+{ -+ ppheap *heap; -+ heap = ppheap_create(size); -+ heap->prev = (*pheap)->prev; -+ memcpy(heap->data, (*pheap)->data, (*pheap)->space); // (*pheap)->size is irrelevant -+ pp_free(*pheap); -+ *pheap = heap; -+ return heap; -+} -+ -+static size_t ppheap_buffer_handler (iof *O, iof_mode mode) -+{ -+ ppheap **pheap, *heap; -+ size_t objectsize, buffersize, neededsize; -+ uint8_t *copyfrom; -+ switch (mode) -+ { -+ case IOFWRITE: -+ /* apparently more space needed then assumed initsize */ -+ pheap = (ppheap **)O->link; -+ heap = *pheap; -+ objectsize = (size_t)(O->buf - heap->data); -+ buffersize = (size_t)(O->pos - O->buf); -+ neededsize = objectsize + (buffersize << 1); -+ if (ppheap_head(heap) < heap->data) -+ { -+ if (heap->size <= PPHEAP_WASTE && neededsize <= (PPHEAP_BUFFER >> 1)) -+ { -+ heap = ppheap_insert_top(pheap, PPHEAP_BUFFER); -+ copyfrom = heap->prev->data; -+ } -+ else -+ { -+ heap = ppheap_insert_sub(pheap, neededsize); -+ copyfrom = (*pheap)->data; -+ O->link = (void *)(&(*pheap)->prev); -+ } -+ memcpy(heap->data, copyfrom, objectsize + buffersize); -+ } -+ else -+ { /* the buffer was (re)initialized from a new empty heap and occupies its entire space */ -+ // ASSERT(ppheap_head(heap) == heap->data); -+ heap = ppheap_resize(pheap, neededsize); -+ } -+ O->buf = heap->data + objectsize; -+ O->pos = O->buf + buffersize; -+ O->end = heap->data + heap->size; -+ return (size_t)(O->end - O->pos); -+ case IOFFLUSH: -+ return 0; -+ case IOFCLOSE: -+ // O->buf = O->pos = O->end = NULL; -+ // O->link = NULL; -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+iof * ppheap_buffer (ppheap **pheap, size_t objectsize, size_t initsize) -+{ -+ static iof ppheap_buffer_iof = IOF_WRITER_STRUCT(ppheap_buffer_handler, NULL, NULL, 0, 0); -+ ppheap *heap; -+ size_t size; -+ size = objectsize + initsize; -+ heap = *pheap; -+ if (size <= heap->size) -+ ; -+ else if (heap->size <= PPHEAP_WASTE && size <= (PPHEAP_BUFFER >> 1)) -+ { -+ heap = ppheap_create(PPHEAP_BUFFER); -+ heap->prev = (*pheap); -+ *pheap = heap; -+ } -+ else -+ { -+ heap = ppheap_create(size); -+ heap->prev = (*pheap)->prev; -+ (*pheap)->prev = heap; -+ pheap = &(*pheap)->prev; // passed to ppheap_buffer_iof.link -+ } -+ ppheap_buffer_iof.buf = ppheap_buffer_iof.pos = heap->data + objectsize; -+ ppheap_buffer_iof.end = heap->data + heap->size; -+ ppheap_buffer_iof.link = pheap; // ASSERT(*pheap == heap) -+ return &ppheap_buffer_iof; -+} -+ -+/* -+void * ppheap_buffer_data (iof *O, size_t *psize) -+{ -+ ppheap *heap; -+ heap = *((ppheap **)(O->link)); -+ *psize = ppheap_buffer_size(O, heap); -+ return heap->data; -+} -+*/ -+ -+void * ppheap_flush (iof *O, size_t *psize) // not from explicit ppheap ** !!! -+{ -+ ppheap *heap; -+ uint8_t *data; -+ size_t size; -+#ifdef PPHEAP_NEED_ALIGNMENT -+ aligned_data *p_aligned_data; -+#endif -+ heap = *((ppheap **)(O->link)); -+ *psize = ppheap_buffer_size(O, heap); -+ size = *psize; -+ data = heap->data; -+/* heap->data += *psize; -+ heap->size -= *psize; -+*/ -+ heap->data += size; -+ heap->size -= size; -+ // O->buf = O->pos = O->end = NULL; -+ // O->link = NULL; -+ // iof_close(O); -+#ifdef PPHEAP_NEED_ALIGNMENT -+ /* Todo: only if data%sizeof(aligned_data) != 0 */ -+ p_aligned_data = malloc(size); -+ memcpy(p_aligned_data,data,size); -+ align_save_into_set(p_aligned_data); -+ return (void *)p_aligned_data; -+#else -+ return data; -+ -+#endif -+ -+ -+} -+ -+ -diff --git a/texk/web2c/luatexdir/luapplib/ppheap.h b/texk/web2c/luatexdir/luapplib/ppheap.h -new file mode 100644 -index 000000000..128f9c56d ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppheap.h -@@ -0,0 +1,29 @@ -+ -+#ifndef PP_HEAP_H -+#define PP_HEAP_H -+ -+#include "utilmem.h" -+ -+#define pp_malloc util_malloc -+#define pp_callic util_calloc -+#define pprealloc util_realloc -+#define pp_free util_free -+ -+typedef struct ppheap ppheap; -+struct ppheap { -+ size_t size; -+ size_t space; -+ uint8_t *data; -+ ppheap *prev; -+}; -+ -+ppheap * ppheap_new (void); -+void ppheap_free (ppheap *heap); -+void ppheap_renew (ppheap *heap); -+void * ppheap_take (ppheap **pheap, size_t size); -+iof * ppheap_buffer (ppheap **pheap, size_t objectsize, size_t initsize); -+#define ppheap_buffer_size(O, heap) (size_t)((O)->pos - (heap)->data) // == (size_t)(O->buf - heap->data) + (size_t)(O->pos - O->buf); -+//void * ppheap_buffer_data (iof *O, size_t *psize); -+void * ppheap_flush (iof *O, size_t *psize); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/pplib.h b/texk/web2c/luatexdir/luapplib/pplib.h -new file mode 100644 -index 000000000..e753cfa05 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/pplib.h -@@ -0,0 +1,22 @@ -+ -+#ifndef PP_LIB_H -+#define PP_LIB_H -+ -+#include -+#include -+#include -+#include -+ -+#include "utiliof.h" -+#include "utillog.h" -+ -+#include "ppapi.h" -+#include "ppheap.h" -+#include "ppdict.h" -+#include "ppstream.h" -+#include "pparray.h" -+#include "ppcrypt.h" -+#include "ppxref.h" -+#include "ppload.h" -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppload.c b/texk/web2c/luatexdir/luapplib/ppload.c -new file mode 100644 -index 000000000..0ad286e57 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppload.c -@@ -0,0 +1,2590 @@ -+ -+#include -+ -+#include "pplib.h" -+ -+const char * ppobj_kind[] = { "none", "null", "bool", "integer", "number", "name", "string", "array", "dict", "stream", "ref" }; -+ -+#define ignored_char(c) (c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09 || c == 0x00) -+#define newline_char(c) (c == 0x0A || c == 0x0D) -+#define IGNORED_CHAR_CASE 0x20: case 0x0A: case 0x0D: case 0x09: case 0x00 -+#define NEWLINE_CHAR_CASE 0x0A: case 0x0D -+#define DIGIT_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' -+#define OCTAL_CHAR_CASE '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7' -+ -+#define MAX_INT_DIGITS 32 -+ -+#define PP_LENGTH_UNKNOWN ((size_t)-1) -+ -+static const char * ppref_str (ppuint refnumber, ppuint refversion) -+{ -+ static char buffer[MAX_INT_DIGITS + 1 + MAX_INT_DIGITS + 1 + 1 + 1]; -+#if defined(MSVC64)|| defined(MINGW64) -+ sprintf(buffer, PPUINTF " " PPUINTF " R", refnumber, refversion); -+#else -+ sprintf(buffer, PPUINTF " " PPUINTF " R", (unsigned long)(refnumber), (unsigned long)(refversion)); -+#endif -+ return buffer; -+} -+ -+/* name */ -+ -+// pdf name delimiters: 0..32, ()<>[]{}/% -+// # treated specially -+// .+- are valid part of name; keep in mind names such as -| | |- .notdef ABCDEF+Font etc. -+const char ppname_byte_lookup[] = { -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 1, 1, '#', 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 -+}; -+ -+#define PPNAME_INIT (8+1) -+ -+#define ppname_flush(O, ghost, siz, flgs) \ -+ (iof_put(O, '\0'), \ -+ ghost = (_ppname *)ppheap_flush(O, &siz), \ -+ ghost->flags = flgs, \ -+ ghost->size = siz - sizeof(_ppname) - 1, \ -+ (ppname)(ghost + 1)) -+ -+#define ppname_flush_with_ego(O, ghost, siz, flgs) \ -+ (iof_put(O, '\0'), \ -+ iof_ensure(O, sizeof(ppname *)), \ -+ O->pos += sizeof(ppname *), \ -+ ghost = (_ppname *)ppheap_flush(O, &siz), \ -+ ghost->flags = flgs, \ -+ ghost->size = siz - sizeof(_ppname) - 1 - sizeof(ppname *), \ -+ (ppname)(ghost + 1)) -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define ppname_set_alter_ego(name, ghost, ego) do {\ -+ ppname temp;\ -+ ppname *temp1;\ -+ temp = (name + (ghost)->size + 1) ; \ -+ temp1 = (ppname *)((void*)temp); \ -+ *temp1= ego; \ -+ }while(0) -+#else -+#define ppname_set_alter_ego(name, ghost, ego) (*((ppname *)(name + (ghost)->size + 1)) = ego) -+#endif -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define ppname_get_alter_ego(name) (*((ppname *)( (void*)(name + ppname_size(name) + 1)))) -+#else -+#define ppname_get_alter_ego(name) (*((ppname *)(name + ppname_size(name) + 1))) -+#endif -+ -+ -+ -+ -+ -+static ppname ppscan_name (iof *I, ppheap **pheap) -+{ -+ int c, decode; -+ iof *O; -+ _ppname *ghost1, *ghost2; -+ ppname encoded, decoded; -+ size_t size; -+ const char *p, *e; -+ uint8_t v1, v2; -+ O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT); -+ for (decode = 0, c = iof_char(I); c >= 0 && ppname_byte_lookup[c]; c = iof_next(I)) -+ { -+ if (c == '#') -+ decode = 1; -+ iof_put(O, c); -+ } -+ if (!decode) -+ return ppname_flush(O, ghost1, size, 0); -+ encoded = ppname_flush_with_ego(O, ghost1, size, 0|PPNAME_ENCODED); -+ O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT); -+ for (p = encoded, e = encoded + ghost1->size; p < e; ++p) -+ { -+ if (*p == '#' && p + 2 < e ){ -+ v1 = base16_value(p[1]); -+ v2 = base16_value(p[2]); -+ iof_put(O, ((v1<<4)+v2)); -+ }else -+ iof_put(O, *p); -+ } -+ decoded = ppname_flush_with_ego(O, ghost2, size, 0|PPNAME_DECODED); -+ ppname_set_alter_ego(encoded, ghost1, decoded); -+ ppname_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+static ppname ppscan_exec (iof *I, ppheap **pheap, int first) -+{ -+ int c, decode; -+ iof *O; -+ _ppname *ghost1, *ghost2; -+ ppname encoded, decoded; -+ size_t size; -+ const char *p, *e; -+ uint8_t v1, v2; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT); -+ iof_put(O, first); -+ for (decode = 0, c = iof_char(I); c >= 0 && ppname_byte_lookup[c]; c = iof_next(I)) -+ { -+ if (c == '#') -+ decode = 1; -+ iof_put(O, c); -+ } -+ if (!decode) -+ return ppname_flush(O, ghost1, size, PPNAME_EXEC); -+ encoded = ppname_flush_with_ego(O, ghost1, size, PPNAME_EXEC|PPNAME_ENCODED); -+ O = ppheap_buffer(pheap, sizeof(_ppname), PPNAME_INIT); -+ for (p = encoded, e = encoded + ghost1->size; p < e; ++p) -+ { -+ if (*p == '#' && p + 2 < e ){ -+ v1 = base16_value(p[1]); -+ v2 = base16_value(p[2]); -+ iof_put(O, ((v1<<4)+v2)); -+ }else -+ iof_put(O, *p); -+ } -+ decoded = ppname_flush_with_ego(O, ghost2, size, PPNAME_EXEC|PPNAME_DECODED); -+ ppname_set_alter_ego(encoded, ghost1, decoded); -+ ppname_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+static ppname ppexec_internal (const void *data, size_t size, ppheap **pheap) -+{ // used only for artificial 'EI' operator name -+ iof *O; -+ _ppname *ghost1; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppname), size); -+ iof_write(O, data, size); -+ return ppname_flush(O, ghost1, size, PPNAME_EXEC); -+} -+ -+ppname ppname_decoded (ppname name) -+{ -+ const _ppname *ghost; -+ ghost = _ppname_ghost(name); -+ return (ghost->flags & PPNAME_ENCODED) ? ppname_get_alter_ego(name) : name; -+} -+ -+ppname ppname_encoded (ppname name) -+{ -+ const _ppname *ghost; -+ ghost = _ppname_ghost(name); -+ return (ghost->flags & PPNAME_DECODED) ? ppname_get_alter_ego(name) : name; -+} -+ -+/* string */ -+ -+#define PPSTRING_INIT (16+1) -+ -+#define ppstring_flush(O, ghost, siz, flgs) \ -+ (iof_put(O, '\0'), \ -+ ghost = (_ppstring *)ppheap_flush(O, &siz), \ -+ ghost->flags = flgs, \ -+ ghost->size = siz - sizeof(_ppstring) - 1, \ -+ (ppstring)(ghost + 1)) -+ -+#define ppstring_flush_with_ego(O, ghost, siz, flgs) \ -+ (iof_put(O, '\0'), \ -+ iof_ensure(O, sizeof(ppstring *)), \ -+ O->pos += sizeof(ppstring *), \ -+ ghost = (_ppstring *)ppheap_flush(O, &siz), \ -+ ghost->flags = flgs, \ -+ ghost->size = siz - sizeof(_ppstring) - 1 - sizeof(ppstring *), \ -+ (ppstring)(ghost + 1)) -+ -+#define ppstring_utf16be_bom(decoded) (decoded[0] == ((char)0xFE) && decoded[1] == ((char)0xFF) ) -+#define ppstring_utf16le_bom(decoded) (decoded[0] == ((char)0xFF) && decoded[1] == ((char)0xFE)) -+ -+#define ppstring_check_bom(decoded, ghost) ((void)\ -+ (ghost->size >= 2 ? (ppstring_utf16be_bom(decoded) ? (ghost->flags |= PPSTRING_UTF16BE) : \ -+ (ppstring_utf16le_bom(decoded) ? (ghost->flags |= PPSTRING_UTF16LE) : 0)) : 0)) -+ -+#define ppstring_check_bom2(decoded, ghost1, ghost2) ((void)\ -+ (ghost2->size >= 2 ? (ppstring_utf16be_bom(decoded) ? ((ghost1->flags |= PPSTRING_UTF16BE), (ghost2->flags |= PPSTRING_UTF16BE)) : \ -+ (ppstring_utf16le_bom(decoded) ? ((ghost1->flags |= PPSTRING_UTF16LE), (ghost2->flags |= PPSTRING_UTF16LE)) : 0)) : 0)) -+ -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define ppstring_set_alter_ego(string, ghost, ego) (*((ppstring *)((void *)(string + (ghost)->size + 1))) = ego) -+#else -+#define ppstring_set_alter_ego(string, ghost, ego) (*((ppstring *)(string + (ghost)->size + 1)) = ego) -+#endif -+ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define ppstring_get_alter_ego(string) (*((ppstring *)((void *)(string + ppstring_size(string) + 1)))) -+#else -+#define ppstring_get_alter_ego(string) (*((ppstring *)(string + ppstring_size(string) + 1))) -+#endif -+ -+ -+ -+ -+static ppstring ppscan_string (iof *I, ppheap **pheap) -+{ -+ int c, decode, balance; -+ iof *O; -+ _ppstring *ghost1, *ghost2; -+ uint8_t *p, *e; -+ ppstring encoded, decoded; -+ size_t size; -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ for (decode = 0, balance = 0, c = iof_char(I); c >= 0; ) -+ { -+ switch (c) -+ { -+ case '\\': -+ decode = 1; // unescaping later -+ iof_put(O, '\\'); -+ if ((c = iof_next(I)) >= 0) -+ { -+ iof_put(O, c); -+ c = iof_next(I); -+ } -+ break; -+ case '(': // may be unescaped if balanced -+ ++balance; -+ iof_put(O, '('); -+ c = iof_next(I); -+ break; -+ case ')': -+ if (balance == 0) -+ { -+ c = IOFEOF; -+ ++I->pos; -+ break; -+ } -+ --balance; -+ iof_put(O, ')'); -+ c = iof_next(I); -+ break; -+ default: -+ iof_put(O, c); -+ c = iof_next(I); -+ } -+ } -+ if (!decode) -+ { -+ encoded = ppstring_flush(O, ghost1, size, 0); -+ ppstring_check_bom(encoded, ghost1); // any bytes can be there -+ return encoded; -+ } -+ encoded = ppstring_flush_with_ego(O, ghost1, size, 0|PPSTRING_ENCODED); -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ for (p = (uint8_t *)encoded, e = (uint8_t *)encoded + ghost1->size; p < e; ++p) -+ { -+ if (*p == '\\') -+ { -+ if (++p >= e) -+ break; -+ switch (*p) -+ { -+ case OCTAL_CHAR_CASE: -+ c = *p - '0'; -+ if (++p < e && *p >= '0' && *p <= '7') -+ { -+ c = (c << 3) + *p - '0'; -+ if (++p < e && *p >= '0' && *p <= '7') -+ c = (c << 3) + *p - '0'; -+ } -+ iof_put(O, c); -+ break; -+ case 'n': -+ iof_put(O, '\n'); -+ break; -+ case 'r': -+ iof_put(O, '\r'); -+ break; -+ case 't': -+ iof_put(O, '\t'); -+ break; -+ case 'b': -+ iof_put(O, '\b'); -+ break; -+ case 'f': -+ iof_put(O, '\f'); -+ break; -+ case NEWLINE_CHAR_CASE: // not a part of the string, ignore (pdf spec page 55) -+ break; -+ case '(': case ')': case '\\': -+ default: // for enything else backslash is ignored (pdf spec page 54) -+ iof_put(O, *p); -+ break; -+ } -+ } -+ else -+ iof_put(O, *p); -+ } -+ decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED); -+ ppstring_check_bom2(decoded, ghost1, ghost2); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+/* Hex string may contain white characters. If odd number of digits, the last assumed to be '0' */ -+ -+static ppstring ppscan_base16 (iof *I, ppheap **pheap) -+{ -+ int c, v1, v2; -+ iof *O; -+ _ppstring *ghost1, *ghost2; -+ size_t size; -+ ppstring encoded, decoded; -+ uint8_t *p, *e; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ for (c = iof_char(I); c >= 0 && (base16_digit(c) || ignored_char(c)); c = iof_next(I)) -+ iof_put(O, c); -+ if (c == '>') -+ ++I->pos; -+ encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED); -+ O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost1->size >> 1) + 1); -+ for (p = (uint8_t *)encoded, e = (uint8_t *)encoded + ghost1->size; p < e; ++p) -+ { -+ if ((v1 = base16_value(*p)) < 0) // ignored -+ continue; -+ for (v2 = 0, ++p; p < e && (v2 = base16_value(*p)) < 0; ++p); -+ iof_put(O, (v1<<4)|v2); -+ } -+ decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED); -+ ppstring_check_bom2(decoded, ghost1, ghost2); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+/* internal use only; binary string */ -+ -+static ppstring ppstring_buffer (iof *O, ppheap **pheap) -+{ -+ _ppstring *ghost1, *ghost2; -+ ppstring encoded, decoded; -+ uint8_t *p, *e; -+ size_t size; -+ -+ decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED); -+ O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost2->size << 1) + 1); -+ for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p) -+ iof_set2(O, base16_uc_alphabet[(*p)>>4], base16_uc_alphabet[(*p)&15]); -+ encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+ppstring ppstring_internal (const void *data, size_t size, ppheap **pheap) -+{ // so far used only for crypt key -+ iof *O; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), size); -+ iof_write(O, data, size); -+ return ppstring_buffer(O, pheap); -+} -+ -+/* PDF spec says nothing about base85 strings, but streams might be (afair no leading '<~' but present trailing '~>') */ -+ -+static ppstring ppscan_base85 (iof *I, ppheap **pheap) -+{ // bawse85 alphabet is 33.117, adobe also hires 'z' and 'y' for compression -+ int c; -+ iof *O, B; -+ _ppstring *ghost1, *ghost2; -+ size_t size; -+ ppstring encoded, decoded; -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ for (c = iof_char(I); (c >= '!' && c <= 'u') || c == 'z' || c == 'y'; c = iof_next(I)) -+ iof_put(O, c); -+ if (c == '~') -+ if ((c = iof_next(I)) == '>') -+ ++I->pos; -+ encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE85|PPSTRING_ENCODED); -+ iof_string_reader(&B, encoded, ghost1->size); -+ O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost1->size * 5 / 4) + 1); -+ base85_decode(&B, O); -+ decoded = ppstring_flush_with_ego(O, ghost2, size, 0|PPSTRING_DECODED); -+ ppstring_check_bom2(decoded, ghost1, ghost2); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+/* -+Encrypted strings. In case of encrypted strings, we first need to decode the string (saving original form hardly makes sense), -+then decrypt the string, and encode it again. -+*/ -+ -+const char ppstring_byte_escape[] = { /* -1 escaped with octal, >0 escaped with \\, 0 left intact*/ -+ -1,-1,-1,-1,-1,-1,-1,-1,'b','t','n',-1,'f','r',-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ 0, 0, 0, 0, 0, 0, 0, 0,'(',')', 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+ -+static ppstring ppscan_crypt_string (iof *I, ppcrypt *crypt, ppheap **pheap) -+{ -+ int c, b, balance, encode; -+ iof *O; -+ _ppstring *ghost1, *ghost2; -+ ppstring encoded, decoded; -+ uint8_t *p, *e; -+ size_t size; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ for (balance = 0, encode = 0, c = iof_char(I); c >= 0; ) -+ { -+ switch (c) -+ { -+ case '\\': -+ if ((c = iof_next(I)) < 0) -+ break; -+ encode = 1; -+ switch (c) -+ { -+ case OCTAL_CHAR_CASE: -+ b = c - '0'; -+ if ((c = iof_next(I)) >= 0 && c >= '0' && c <= '7') -+ { -+ b = (b << 3) + c - '0'; -+ if ((c = iof_next(I)) >= 0 && c >= '0' && c <= '7') -+ { -+ b = (b << 3) + c - '0'; -+ c = iof_next(I); -+ } -+ } -+ iof_put(O, b); -+ // c is set to the next char -+ break; -+ case 'n': -+ iof_put(O, '\n'); -+ c = iof_next(I); -+ break; -+ case 'r': -+ iof_put(O, '\r'); -+ c = iof_next(I); -+ break; -+ case 't': -+ iof_put(O, '\t'); -+ c = iof_next(I); -+ break; -+ case 'b': -+ iof_put(O, '\b'); -+ c = iof_next(I); -+ break; -+ case 'f': -+ iof_put(O, '\f'); -+ c = iof_next(I); -+ break; -+ case NEWLINE_CHAR_CASE: // not a part of the string, ignore (pdf spec page 55) -+ c = iof_next(I); -+ break; -+ case '(': case ')': case '\\': -+ default: // for enything else backslash is ignored (pdf spec page 54) -+ iof_put(O, c); -+ c = iof_next(I); -+ break; -+ } -+ break; -+ case '(': -+ ++balance; -+ encode = 1; -+ iof_put(O, '('); -+ c = iof_next(I); -+ break; -+ case ')': -+ if (balance == 0) -+ { -+ c = IOFEOF; -+ ++I->pos; -+ } -+ else -+ { -+ --balance; -+ //encode = 1; -+ iof_put(O, ')'); -+ c = iof_next(I); -+ } -+ break; -+ default: -+ if (ppstring_byte_escape[c] != 0) -+ encode = 1; -+ iof_put(O, c); -+ c = iof_next(I); -+ } -+ } -+ /* decrypt the buffer in place, update size */ -+ if (ppstring_decrypt(crypt, O->buf, iof_size(O), O->buf, &size)) -+ O->pos = O->buf + size; -+ /* make encoded counterpart */ -+ if (!encode) -+ { -+ decoded = ppstring_flush(O, ghost2, size, 0); -+ ppstring_check_bom(decoded, ghost2); -+ return decoded; -+ } -+ decoded = ppstring_flush_with_ego(O, ghost2, size, PPSTRING_DECODED); -+ O = ppheap_buffer(pheap, sizeof(_ppstring), ghost2->size); -+ for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p) -+ { -+ switch ((b = ppstring_byte_escape[*p])) -+ { -+ case 0: -+ iof_put(O, *p); -+ break; -+ case -1: -+ iof_put4(O, '\\', (c >> 6) + '0', ((c >> 3) & 7) + '0', (c & 7) + '0'); -+ break; -+ default: -+ iof_put2(O, '\\', b); -+ break; -+ } -+ } -+ encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_ENCODED); -+ ppstring_check_bom2(decoded, ghost1, ghost2); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+ -+static ppstring ppscan_crypt_base16 (iof *I, ppcrypt *crypt, ppheap **pheap) -+{ -+ int c, v1, v2; -+ iof *O; -+ _ppstring *ghost1, *ghost2; -+ ppstring encoded, decoded; -+ uint8_t *p, *e; -+ size_t size; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ // base16_decode(I, O); // no info about the last char.. -+ for (c = iof_char(I); c != '>' && c >= 0; ) -+ { -+ if ((v1 = base16_value(c)) < 0) -+ { -+ if (ignored_char(c)) -+ { -+ c = iof_next(I); -+ continue; -+ } -+ break; -+ } -+ do { -+ c = iof_next(I); -+ if ((v2 = base16_value(c)) >= 0) -+ { -+ c = iof_next(I); -+ break; -+ } -+ if (!ignored_char(c)) // c == '>' || c < 0 or some crap -+ { -+ v2 = 0; -+ break; -+ } -+ } while (1); -+ iof_put(O, (v1 << 4)|v2); -+ } -+ if (c == '>') -+ ++I->pos; -+ /* decrypt the buffer in place, update size */ -+ if (ppstring_decrypt(crypt, O->buf, iof_size(O), O->buf, &size)) -+ O->pos = O->buf + size; -+ decoded = ppstring_flush_with_ego(O, ghost2, size, PPSTRING_DECODED); -+ /* recreate an encoded form */ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), (ghost2->size << 1) + 1); -+ for (p = (uint8_t *)decoded, e = (uint8_t *)decoded + ghost2->size; p < e; ++p) -+ iof_set2(O, base16_uc_alphabet[(*p)>>4], base16_uc_alphabet[(*p)&15]); -+ encoded = ppstring_flush_with_ego(O, ghost1, size, PPSTRING_BASE16|PPSTRING_ENCODED); -+ ppstring_check_bom2(decoded, ghost1, ghost2); -+ ppstring_set_alter_ego(encoded, ghost1, decoded); -+ ppstring_set_alter_ego(decoded, ghost2, encoded); -+ return encoded; -+} -+ -+/* ppstring alter ego switcher */ -+ -+ppstring ppstring_decoded (ppstring string) -+{ -+ const _ppstring *ghost; -+ ghost = _ppstring_ghost(string); -+ return (ghost->flags & PPSTRING_ENCODED) ? ppstring_get_alter_ego(string) : string; -+} -+ -+ppstring ppstring_encoded (ppstring string) -+{ -+ const _ppstring *ghost; -+ ghost = _ppstring_ghost(string); -+ return (ghost->flags & PPSTRING_DECODED) ? ppstring_get_alter_ego(string) : string; -+} -+ -+/* scanner stack */ -+ -+#define PPSTACK_BUFFER 512 -+ -+static void ppstack_init (ppstack *stack, ppheap **pheap) -+{ -+ stack->buf = stack->pos = (ppobj *)pp_malloc(PPSTACK_BUFFER * sizeof(ppobj)); -+ stack->size = 0; -+ stack->space = PPSTACK_BUFFER; -+ stack->pheap = pheap; -+} -+ -+#define ppstack_free_buffer(stack) (pp_free((stack)->buf)) -+ -+static void ppstack_resize (ppstack *stack) -+{ -+ ppobj *newbuffer; -+ stack->space <<= 1; -+ newbuffer = (ppobj *)pp_malloc(stack->space * sizeof(ppobj)); -+ memcpy(newbuffer, stack->buf, stack->size * sizeof(ppobj)); -+ ppstack_free_buffer(stack); -+ stack->buf = newbuffer; -+ stack->pos = newbuffer + stack->size; -+} -+ -+#define ppstack_push(stack) ((void)((stack)->size < (stack)->space || (ppstack_resize(stack), 0)), ++(stack)->size, (stack)->pos++) -+#define ppstack_pop(stack, n) ((stack)->size -= (n), (stack)->pos -= (n)) -+#define ppstack_at(stack, i) ((stack)->buf + i) -+#define ppstack_clear(stack) ((stack)->pos = (stack)->buf, (stack)->size = 0) -+ -+/* scanner commons */ -+ -+#define ppscan_uint(I, u) iof_get_uintlw(I, u) -+#define ppread_uint(s, u) string_to_uintlw((const char *)(s), u) -+ -+static ppobj * ppscan_numobj (iof *I, ppobj *obj, int negative) -+{ -+ ppint integer; -+ ppnum number; -+ int exponent; -+ int c; -+ c = iof_char(I); -+ iof_scan_integer(I, c, integer); -+ switch(c) -+ { -+ case '.': -+ { -+ number = (ppnum)integer; -+ c = iof_next(I); -+ iof_scan_fraction(I, c, number, exponent); -+ double_negative_exp10(number, exponent); -+ obj->type = PPNUM, obj->number = negative ? -number : number; -+ break; -+ } -+ default: -+ obj->type = PPINT, obj->integer = negative ? -integer : integer; -+ break; -+ } -+ return obj; -+} -+ -+static ppobj * ppscan_numobj_frac (iof *I, ppobj *obj, int negative) -+{ -+ ppnum number; -+ int c, exponent; -+ -+ number = 0.0; -+ c = iof_next(I); -+ iof_scan_fraction(I, c, number, exponent); -+ double_negative_exp10(number, exponent); -+ obj->type = PPNUM, obj->number = negative ? -number : number; -+ return obj; -+} -+ -+static int ppscan_find (iof *I) -+{ // skips whitechars and comments -+ int c; -+ for (c = iof_char(I); ; c = iof_next(I)) -+ { -+ switch (c) -+ { -+ case IGNORED_CHAR_CASE: -+ break; -+ case '%': { -+ do { -+ if ((c = iof_next(I)) < 0) -+ return c; -+ } while (!newline_char(c)); -+ break; -+ } -+ default: -+ return c; -+ } -+ } -+ return c; // never reached -+} -+ -+static int ppscan_keyword (iof *I, const char *keyword, size_t size) -+{ -+ size_t i; -+ int c; -+ if (iof_left(I) >= size) -+ { -+ if (memcmp(I->pos, keyword, size) != 0) -+ return 0; -+ I->pos += size; -+ return 1; -+ } -+ // sticky case, we can't go back -+ for (i = 0, c = iof_char(I); i < size; ++i, ++keyword, c = iof_next(I)) -+ if (i != c) -+ return 0; -+ return 1; -+} -+ -+#define ppscan_key(I, literal) ppscan_keyword(I, "" literal, sizeof(literal) - 1) -+ -+/* objects parser */ -+ -+static ppref * ppref_unresolved (ppheap **pheap, ppuint refnumber, ppuint refversion) -+{ -+ ppref *ref = (ppref *)ppheap_take(pheap, sizeof(ppref)); -+ memset(ref, 0, sizeof(ppref)); -+ ref->object.type = PPNONE; -+ ref->number = refnumber; -+ ref->version = refversion; -+ return ref; -+} -+ -+#define PPMARK PPNONE -+ -+static ppobj * ppscan_obj (iof *I, ppdoc *pdf, ppxref *xref) -+{ -+ int c; -+ ppobj *obj; -+ size_t mark, size; -+ ppuint refnumber, refversion; -+ ppref *ref; -+ ppstack *stack; -+ ppcrypt *crypt; -+ -+ stack = &pdf->stack; -+ c = iof_char(I); -+ switch (c) -+ { -+ case DIGIT_CHAR_CASE: -+ return ppscan_numobj(I, ppstack_push(stack), 0); -+ case '.': -+ return ppscan_numobj_frac(I, ppstack_push(stack), 0); -+ case '+': -+ ++I->pos; -+ return ppscan_numobj(I, ppstack_push(stack), 0); -+ case '-': -+ ++I->pos; -+ return ppscan_numobj(I, ppstack_push(stack), 1); -+ case '/': -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPNAME; -+ obj->name = ppscan_name(I, &pdf->heap); -+ return obj; -+ case '(': -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPSTRING; -+ if (ppcrypt_ref(pdf, crypt)) -+ obj->string = ppscan_crypt_string(I, crypt, &pdf->heap); -+ else -+ obj->string = ppscan_string(I, &pdf->heap); -+ return obj; -+ case '[': -+ mark = stack->size; -+ obj = ppstack_push(stack); -+ obj->type = PPMARK; // ppscan_obj() checks types backward for 'R', so set the type immediatelly (reserved for PPARRAY) -+ obj->any = NULL; -+ ++I->pos; -+ for (c = ppscan_find(I); c != ']'; c = ppscan_find(I)) -+ { -+ if (ppscan_obj(I, pdf, xref) == NULL) -+ { // callers assume that NULL returns means nothing pushed -+ size = stack->size - mark; // pop items AND the obj reserved for array -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ } -+ ++I->pos; -+ size = stack->size - mark - 1; -+ obj = ppstack_at(stack, mark); // stack might have been realocated -+ obj->type = PPARRAY; -+ obj->array = pparray_create(ppstack_at(stack, mark + 1), size, &pdf->heap); -+ ppstack_pop(stack, size); // pop array items, leave the array on top -+ return obj; -+ case '<': -+ if ((c = iof_next(I)) == '<') -+ { -+ mark = stack->size; -+ obj = ppstack_push(stack); -+ obj->type = PPMARK; -+ obj->any = NULL; -+ ++I->pos; -+ for (c = ppscan_find(I); c != '>'; c = ppscan_find(I)) -+ { -+ if (ppscan_obj(I, pdf, xref) == NULL) -+ { -+ size = stack->size - mark; -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ } -+ if (iof_next(I) == '>') -+ ++I->pos; -+ size = stack->size - mark - 1; -+ obj = ppstack_at(stack, mark); -+ obj->type = PPDICT; -+ obj->dict = ppdict_create(ppstack_at(stack, mark + 1), size, &pdf->heap); -+ ppstack_pop(stack, size); -+ return obj; -+ } -+ obj = ppstack_push(stack); -+ obj->type = PPSTRING; -+ if (ppcrypt_ref(pdf, crypt)) -+ obj->string = ppscan_crypt_base16(I, crypt, &pdf->heap); -+ else -+ obj->string = ppscan_base16(I, &pdf->heap); -+ return obj; -+ case 'R': -+ if (stack->size >= 2 && stack->pos[-1].type == PPINT && stack->pos[-2].type == PPINT) -+ { -+ ++I->pos; -+ obj = &stack->pos[-2]; -+ refnumber = (ppuint)obj->integer; -+ ppstack_pop(stack, 1); // pop version number, retype obj to a reference -+ if (xref == NULL || (ref = ppxref_find(xref, refnumber)) == NULL) -+ { /* pdf spec page 64: unresolvable reference is not an error, should just be treated as a reference to null. -+ we also need this to read trailer, where refs can't be resolved yet */ -+ refversion = (obj + 1)->integer; -+ //if (xref != NULL) -+ // loggerf("unresolved reference %s", ppref_str(refnumber, refversion)); -+ ref = ppref_unresolved(stack->pheap, refnumber, refversion); -+ } -+ obj->type = PPREF; -+ obj->ref = ref; -+ return obj; -+ } -+ break; -+ case 't': -+ if (iof_next(I) == 'r' && iof_next(I) == 'u' && iof_next(I) == 'e') -+ { -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPBOOL; -+ obj->integer = 1; -+ return obj; -+ } -+ break; -+ case 'f': -+ if (iof_next(I) == 'a' && iof_next(I) == 'l' && iof_next(I) == 's' && iof_next(I) == 'e') -+ { -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPBOOL; -+ obj->integer = 0; -+ return obj; -+ } -+ break; -+ case 'n': -+ if (iof_next(I) == 'u' && iof_next(I) == 'l' && iof_next(I) == 'l') -+ { -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPNULL; -+ obj->any = NULL; -+ return obj; -+ } -+ break; -+ } -+ return NULL; -+} -+ -+/* -+A variant for contents streams (aka postscript); wise of operators, blind to references. -+We are still PDF, so we don't care about postscript specific stuff such as radix numbers -+and scientific numbers notation. It takes ppstack * as context (no ppdoc *) to be able -+to run contents parser beyond the scope of ppdoc heap. -+*/ -+ -+static ppstring ppstring_inline (iof *I, ppdict *imagedict, ppheap **pheap); -+ -+static ppobj * ppscan_psobj (iof *I, ppstack *stack) -+{ -+ int c; -+ ppobj *obj, *op; -+ size_t size, mark; -+ ppname exec; -+ -+ c = iof_char(I); -+ switch (c) -+ { -+ case DIGIT_CHAR_CASE: -+ return ppscan_numobj(I, ppstack_push(stack), 0); -+ case '.': -+ return ppscan_numobj_frac(I, ppstack_push(stack), 0); -+ case '+': -+ c = iof_next(I); -+ if (base10_digit(c)) // '+.abc' is probably an executable name, but we are not in postscript -+ return ppscan_numobj(I, ppstack_push(stack), 0); -+ else if (c == '.') -+ return ppscan_numobj_frac(I, ppstack_push(stack), 0); -+ obj = ppstack_push(stack); -+ obj->type = PPNAME; -+ obj->name = ppscan_exec(I, stack->pheap, '+'); -+ return obj; -+ case '-': -+ c = iof_next(I); -+ if (base10_digit(c)) // ditto, we would handle type1 '-|' '|-' operators though -+ return ppscan_numobj(I, ppstack_push(stack), 1); -+ else if (c == '.') -+ return ppscan_numobj_frac(I, ppstack_push(stack), 1); -+ obj = ppstack_push(stack); -+ obj->type = PPNAME; -+ obj->name = ppscan_exec(I, stack->pheap, '-'); -+ return obj; -+ case '/': -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPNAME; -+ obj->name = ppscan_name(I, stack->pheap); -+ return obj; -+ case '(': -+ ++I->pos; -+ obj = ppstack_push(stack); -+ obj->type = PPSTRING; -+ obj->string = ppscan_string(I, stack->pheap); -+ return obj; -+ case '[': -+ mark = stack->size; -+ obj = ppstack_push(stack); -+ obj->type = PPMARK; -+ obj->any = NULL; -+ ++I->pos; -+ for (c = ppscan_find(I); c != ']'; c = ppscan_find(I)) -+ { -+ if (ppscan_psobj(I, stack) == NULL) -+ { -+ size = stack->size - mark; -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ } -+ ++I->pos; -+ size = stack->size - mark - 1; -+ obj = ppstack_at(stack, mark); -+ obj->type = PPARRAY; -+ obj->array = pparray_create(ppstack_at(stack, mark + 1), size, stack->pheap); -+ ppstack_pop(stack, size); -+ return obj; -+ case '<': -+ if ((c = iof_next(I)) == '<') -+ { -+ mark = stack->size; -+ obj = ppstack_push(stack); -+ obj->type = PPMARK; -+ obj->any = NULL; -+ ++I->pos; -+ for (c = ppscan_find(I); c != '>'; c = ppscan_find(I)) -+ { -+ if (ppscan_psobj(I, stack) == NULL) -+ { -+ size = stack->size - mark; -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ } -+ if (iof_next(I) == '>') -+ ++I->pos; -+ size = stack->size - mark - 1; -+ obj = ppstack_at(stack, mark); -+ obj->type = PPDICT; -+ obj->dict = ppdict_create(ppstack_at(stack, mark + 1), size, stack->pheap); -+ ppstack_pop(stack, size); -+ return obj; -+ } -+ obj = ppstack_push(stack); -+ obj->type = PPSTRING; -+ if (c == '~') -+ ++I->pos, obj->string = ppscan_base85(I, stack->pheap); -+ else -+ obj->string = ppscan_base16(I, stack->pheap); -+ return obj; -+ default: -+ if (c < 0 || !ppname_byte_lookup[c]) -+ break; // forbid empty names; dead loop otherwise -+ ++I->pos; -+ /* true false null practically don't occur in streams so it makes sense to assume that we get an operator name here. -+ If it happen to be a keyword we could give back those several bytes to the heap but.. heap buffer is tricky enough. */ -+ exec = ppscan_exec(I, stack->pheap, c); -+ obj = ppstack_push(stack); -+ switch (exec[0]) -+ { -+ case 't': -+ if (exec[1] == 'r' && exec[2] == 'u' && exec[3] == 'e' && exec[4] == '\0') -+ { -+ obj->type = PPBOOL; -+ obj->integer = 1; -+ // todo: drop exec -+ return obj; -+ } -+ break; -+ case 'f': -+ if (exec[1] == 'a' && exec[2] == 'l' && exec[3] == 's' && exec[4] == 'e' && exec[5] == '\0') -+ { -+ obj->type = PPBOOL; -+ obj->integer = 0; -+ // todo: drop exec -+ return obj; -+ } -+ break; -+ case 'n': -+ if (exec[1] == 'u' && exec[2] == 'l' && exec[3] == 'l' && exec[4] == '\0') -+ { -+ obj->type = PPNULL; -+ obj->any = NULL; -+ // todo: drop exec -+ return obj; -+ } -+ break; -+ case 'B': -+ /* -+ Inline images break rules of operand/operator syntax, so 'BI/ID' operators need to be treated as special syntactic keywords. -+ -+ BI IDEI -+ -+ We treat the image as a single syntactic token; BI starts collecting a dict, ID is the beginning of the data. Effectively EI -+ operator obtains two operands - dict and string. It is ok to put three items onto the stack, callers dont't assume there is just one. -+ */ -+ if (exec[1] == 'I' && exec[2] == '\0') -+ { -+ ppdict *imagedict; -+ /* key val pairs -> dict */ -+ mark = stack->size - 1; -+ obj->type = PPMARK; -+ obj->any = NULL; -+ for (c = ppscan_find(I); ; c = ppscan_find(I)) -+ { -+ if ((op = ppscan_psobj(I, stack)) == NULL) -+ { -+ size = stack->size - mark; -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ if (op->type == PPNAME && ppname_exec(op->name)) -+ { -+ if (!ppname_is(op->name, "ID")) -+ { // weird -+ size = stack->size - mark; -+ ppstack_pop(stack, size); -+ return NULL; -+ } -+ break; -+ } -+ } -+ size = stack->size - mark - 1; -+ obj = ppstack_at(stack, mark); -+ obj->type = PPDICT; -+ obj->dict = imagedict = ppdict_create(ppstack_at(stack, mark + 1), size, stack->pheap); -+ ppstack_pop(stack, size); -+ /* put image data string */ -+ obj = ppstack_push(stack); -+ obj->type = PPSTRING; -+ obj->string = ppstring_inline(I, imagedict, stack->pheap);; -+ /* put EI operator name */ -+ obj = ppstack_push(stack); -+ obj->type = PPNAME; -+ obj->name = ppexec_internal("EI", 2, stack->pheap); -+ return obj; -+ } -+ } -+ obj->type = PPNAME; -+ obj->name = exec; -+ return obj; -+ } -+ return NULL; -+} -+ -+/* -+We try to get the exact inline image length from its dict params. If cannot predict the length, we have to scan the input until 'EI'. -+I've checked on may examples that it gives the same results but one can never be sure, as 'EI' might happen to be a part of the data. -+Stripping white char is also very heuristic; \0 is a white char in PDF and very likely to be a data byte.. weak method. -+*/ -+ -+static size_t inline_image_length (ppdict *dict) -+{ -+ ppuint w, h, bpc, colors; -+ ppname cs; -+ -+ if (ppdict_get_uint(dict, "W", &w) && ppdict_get_uint(dict, "H", &h) && ppdict_get_uint(dict, "BPC", &bpc) && (cs = ppdict_get_name(dict, "CS")) != NULL) -+ { -+ if (ppname_is(cs, "DeviceGray")) -+ colors = 1; -+ else if (ppname_is(cs, "DeviceRGB")) -+ colors = 3; -+ else if (ppname_is(cs, "DeviceCMYK")) -+ colors = 4; -+ else -+ return PP_LENGTH_UNKNOWN; -+ return (w * h * bpc * colors + 7) >> 3; -+ } -+ return PP_LENGTH_UNKNOWN; -+} -+ -+static ppstring ppstring_inline (iof *I, ppdict *imagedict, ppheap **pheap) -+{ -+ iof *O; -+ int c, d, e; -+ size_t length, leftin, leftout, bytes; -+ -+ O = ppheap_buffer(pheap, sizeof(_ppstring), PPSTRING_INIT); -+ c = iof_char(I); -+ if (ignored_char(c)) -+ c = iof_next(I); -+ -+ length = inline_image_length(imagedict); -+ if (length != PP_LENGTH_UNKNOWN) -+ { -+ while (length > 0 && iof_readable(I) && iof_writable(O)) -+ { -+ leftin = iof_left(I); -+ leftout = iof_left(O); -+ bytes = length; -+ if (bytes > leftin) bytes = leftin; -+ if (bytes > leftout) bytes = leftout; -+ memcpy(O->pos, I->pos, bytes); -+ I->pos += bytes; -+ O->pos += bytes; -+ length -= bytes; -+ } -+ // gobble EI -+ if (ppscan_find(I) == 'E') -+ if (iof_next(I) == 'I') -+ ++I->pos; -+ } -+ else -+ { -+ while (c >= 0) -+ { -+ if (c == 'E') -+ { -+ d = iof_next(I); -+ if (d == 'I') -+ { -+ e = iof_next(I); -+ if (!ppname_byte_lookup[e]) -+ { /* strip one newline from the end and stop */ -+ if (O->pos - 2 >= O->buf) // sanity -+ { -+ c = *(O->pos - 1); -+ if (ignored_char(c)) -+ { -+ if (c == 0x0A && *(O->pos - 2) == 0x0D) -+ O->pos -= 2; -+ else -+ O->pos -= 1; -+ } -+ } -+ break; -+ } -+ iof_put2(O, c, d); -+ c = e; -+ } -+ else -+ { -+ iof_put(O, c); -+ c = d; -+ } -+ } -+ else -+ { -+ iof_put(O, c); -+ c = iof_next(I); -+ } -+ } -+ } -+ return ppstring_buffer(O, pheap); -+} -+ -+/* input reader */ -+ -+/* -+PDF input is a pseudo file that either keeps FILE * or data. Reader iof * is a proxy to input -+that provides byte-by-byte interface. Our iof structure is capable to link iof_file *input, -+but t avoid redundant checks on IOF_DATA flag, here we link iof *I directly to FILE * or mem buffer. -+When reading from file we need an internal buffer, which should be kept rather small, as it is -+only used to parse xrefs and objects (no streams). We allocate the buffer from a private heap -+(not static) to avoid conflicts when processing >1 pdfs at once. Besides, the input buffer may be -+needed after loading the document, eg. to access references raw data. -+*/ -+ -+#define PPDOC_BUFFER 0xFFF // keep that small, it is only used to parse body objects -+ -+static void ppdoc_reader_init (ppdoc *pdf, iof_file *input) -+{ -+ iof *I; -+ pdf->input = *input; -+ input = &pdf->input; -+ input->refcount = 1; -+ I = &pdf->reader; -+ if (input->flags & IOF_DATA) -+ { -+ pdf->buffer = NULL; // input iof_file is the buffer -+ iof_string_reader(I, NULL, 0); // gets IOF_DATA flag -+ } -+ else -+ { -+ pdf->buffer = (uint8_t *)ppheap_take(&pdf->heap, PPDOC_BUFFER); -+ iof_setup_file_handle_reader(I, NULL, 0, iof_file_get_fh(input)); // gets IOF_FILE_HANDLE flag and FILE * -+ I->space = PPDOC_BUFFER; // used on refill -+ } -+} -+ -+/* -+Whenever we need to read the input file, we fseek the to the given offset and fread to to the private buffer. -+The length we need is not always predictable, in which case PPDOC_BUFFER bytes are read (keep it small). -+I->buf = I->pos is set to the beginning, I->end set to the end (end is the first byte one shouldn't read). -+*/ -+ -+static iof * ppdoc_reader (ppdoc *pdf, size_t offset, size_t length) -+{ -+ iof_file *input; -+ iof *I; -+ input = &pdf->input; -+ I = &pdf->reader; -+ if (iof_file_seek(input, offset, SEEK_SET) != 0) -+ return NULL; -+ I->flags &= ~IOF_STOPPED; -+ if (input->flags & IOF_DATA) -+ { -+ I->buf = I->pos = input->pos; -+ I->end = (length == PP_LENGTH_UNKNOWN || I->pos + length >= input->end) ? input->end : (I->pos + length); -+ } -+ else -+ { -+ I->buf = I->pos = pdf->buffer; // ->buf is actually permanently equal pdf->buffer but we might need some tricks -+ if (length == PP_LENGTH_UNKNOWN || length > PPDOC_BUFFER) -+ length = PPDOC_BUFFER; -+ length = fread(I->buf, 1, length, I->file); -+ I->end = I->buf + length; -+ } -+ return I; -+} -+ -+/* The position from the beginning of input -+- for data buffer: (pdf->input.pos - pdf->input.buf) + (I->pos - I->buf) -+ I->buf == pdf->input.pos, so this resolves to (I->pos - pdf->input.buf), independent from I->buf -+- for file buffer: ftell(pdf->input.file) - (I->end - I->pos) -+*/ -+ -+#define ppdoc_reader_tell(pdf, I) ((size_t)(((pdf)->input.flags & IOF_DATA) ? ((I)->pos - (pdf)->input.buf) : (ftell(iof_file_get_fh(&(pdf)->input)) - ((I)->end - (I)->pos)))) -+ -+/* pdf */ -+ -+#define PPDOC_HEADER 10 // "%PDF-?.??\n" -+ -+static int ppdoc_header (ppdoc *pdf, uint8_t header[PPDOC_HEADER]) -+{ -+ size_t i; -+ if (memcmp(header, "%PDF-", 5) != 0) -+ return 0; -+ for (i = 5; i < PPDOC_HEADER - 1 && !ignored_char(header[i]); ++i) -+ pdf->version[i - 5] = header[i]; -+ pdf->version[i - 5] = '\0'; -+ return 1; -+} -+ -+static int ppdoc_tail (ppdoc *pdf, iof_file *input, size_t *pxrefoffset) -+{ -+ int c; -+ uint8_t tail[4*10], *p, back, tailbytes; -+ -+ if (iof_file_seek(input, 0, SEEK_END) != 0) -+ return 0; -+ pdf->filesize = (size_t)iof_file_tell(input); -+ // simple heuristic to avoif fgetc() / fseek(-2) hiccup: keep seeking back by len(startxref) + 1 == 10 -+ // until a letter found (assuming liberal white characters and tail length) -+ for (back = 1, tailbytes = 0; ; ++back) -+ { -+ if (iof_file_seek(input, -10, SEEK_CUR) != 0) -+ return 0; -+ tailbytes += 10; -+ c = iof_file_getc(input); -+ tailbytes -= 1; -+ switch (c) -+ { -+ case IGNORED_CHAR_CASE: -+ case DIGIT_CHAR_CASE: -+ case '%': case 'E': case 'O': case 'F': -+ if (back > 4) // 2 should be enough -+ return 0; -+ continue; -+ case 's': case 't': case 'a': case 'r': case 'x': case 'e': case 'f': -+ if (iof_file_read(tail, 1, tailbytes, input) != tailbytes) -+ return 0; -+ tail[tailbytes] = '\0'; -+ for (p = &tail[0]; ; ++p) -+ { -+ if (*p == '\0') -+ return 0; -+ if ((c = base10_value(*p)) >= 0) -+ break; -+ } -+ ppread_uint(p, pxrefoffset); -+ return 1; -+ default: -+ return 0; -+ } -+ } -+ return 0; -+} -+ -+/* xref/body */ -+ -+static int ppscan_start_entry (iof *I, ppref *ref) -+{ -+ ppuint u; -+ ppscan_find(I); if (!ppscan_uint(I, &u) || u != ref->number) return 0; -+ ppscan_find(I); if (!ppscan_uint(I, &u) || u != ref->version) return 0; -+ ppscan_find(I); if (!ppscan_key(I, "obj")) return 0; -+ ppscan_find(I); -+ return 1; -+} -+ -+static int ppscan_skip_entry (iof *I) -+{ -+ size_t u; -+ ppscan_find(I); if (!ppscan_uint(I, &u)) return 0; -+ ppscan_find(I); if (!ppscan_uint(I, &u)) return 0; -+ ppscan_find(I); if (!ppscan_key(I, "obj")) return 0; -+ ppscan_find(I); -+ return 1; -+} -+ -+static int ppscan_start_stream (iof *I, ppdoc *pdf, size_t *streamoffset) -+{ -+ int c; -+ ppscan_find(I); -+ if (ppscan_key(I, "stream")) -+ { // skip 1 or 2 whites (here we shouldn't just gobble all blanks) -+ c = iof_char(I); -+ if (ignored_char(c)) -+ { -+ c = iof_next(I); -+ if (ignored_char(c)) -+ ++I->pos; -+ } -+ *streamoffset = ppdoc_reader_tell(pdf, I); -+ return 1; -+ } -+ return 0; -+} -+ -+static ppxref * ppxref_load (ppdoc *pdf, size_t xrefoffset); -+static ppxref * ppxref_load_chain (ppdoc *pdf, ppxref *xref); -+ -+/* Parsing xref table -+ -+ 1 10 // first ref number and refs count -+ 0000000000 00000 n // 10-digits offset, 5 digits version, type identifier -+ 0000000000 00000 n // n states for normal I guess -+ 0000000000 00000 f // f states for free (not used) -+ ... -+ -+Free entries seem to be a relic of ancient times, completelly useless for us. To avoid parsing xref table twice, -+we waste some space on free entries by allocating one plane of refs for each section. Later on we slice sections, -+so that effectively free entries are not involved in map. -+ -+Subsequent refs gets number, version and offset. Other fields initialized when parsing PDF body. -+ -+Having xref table loaded, we sort sections for future binary search (xref with objects count == 0 is considered invalid). -+ -+Then we have to deal with the trailer dict. In general, to load objects and resolve references we need a complete chain -+of xrefs (not only the top). To load the previous xref, we need its offset, which is given in trailer. So we have to -+parse the trailer ignoring references, which might be unresolvable at this point (objects parser makes a dummy check -+for xref != NULL on refs resolving ppscan_obj(), which irritates me but I don't want a separate parser for trailer..). -+The same applies to xref streams, in which we have parse the trailer not having xref map at all. So the procedure is: -+ -+ - load xref map, initialize references, make it ready to search -+ - parse trailer ignoring references -+ - get /Prev xref offset and load older xref (linked list via ->prev) -+ - sort all refs in all xrefs by offset -+ - parse refs in order resolving references in contained objects -+ - fix trailer references -+ -+First created xref becomes a pdf->xref (top xref). We link that early to control offsets already read (insane loops?). -+*/ -+ -+// Every xref table item "0000000000 00000 n" is said to be terminated with 2-byte EOL but we don't like relying on whites. -+#define xref_item_length (10+1+5+1+1) -+ -+static ppxref * ppxref_load_table (iof *I, ppdoc *pdf, size_t xrefoffset) -+{ -+ ppxref *xref; -+ ppxsec *xrefsection; -+ ppref *ref; -+ ppuint first, count, refindex; -+ uint8_t buffer[xref_item_length + 1]; -+ const char *p; -+ const ppobj *obj; -+ -+ buffer[xref_item_length] = '\0'; -+ xref = ppxref_create(pdf, 0, xrefoffset); -+ if (pdf->xref == NULL) pdf->xref = xref; -+ for (ppscan_find(I); ppscan_uint(I, &first); ppscan_find(I)) -+ { -+ ppscan_find(I); -+ if (!ppscan_uint(I, &count)) -+ return NULL; -+ if (count == 0) // weird -+ continue; -+ xref->count += count; -+ xrefsection = NULL; -+ ref = (ppref *)ppheap_take(&pdf->heap, count * sizeof(ppref)); -+ for (refindex = 0; refindex < count; ++refindex, ++ref) -+ { -+ ref->xref = xref; -+ ref->number = first + refindex; -+ ppscan_find(I); -+ iof_read(I, buffer, xref_item_length); -+ switch (buffer[xref_item_length - 1]) -+ { -+ case 'n': -+ if (xrefsection == NULL) -+ { -+ xrefsection = ppxref_push_section(xref, &pdf->heap); -+ xrefsection->first = ref->number; -+ xrefsection->refs = ref; -+ } -+ xrefsection->last = ref->number; -+ for (p = (const char *)buffer; *p == '0'; ++p); -+ p = ppread_uint(p, &ref->offset); -+ for ( ; *p == ' ' || *p == '0'; ++p); -+ p = ppread_uint(p, &ref->version); -+ ref->object.type = PPNONE; // init for sanity -+ ref->object.any = NULL; -+ ref->length = 0; -+ break; -+ case 'f': -+ default: -+ --ref; -+ xrefsection = NULL; -+ --xref->count; -+ } -+ } -+ } -+ /* sort section */ -+ if (!ppxref_sort(xref)) -+ ; // case of xref->size == 0 handled by ppxref_load_chain() -+ /* get trailer ignoring refs */ -+ if (!ppscan_key(I, "trailer")) -+ return NULL; -+ ppscan_find(I); -+ if ((obj = ppscan_obj(I, pdf, NULL)) == NULL) -+ return NULL; -+ ppstack_pop(&pdf->stack, 1); -+ if (obj->type != PPDICT) -+ return NULL; -+ xref->trailer = *obj; -+ return ppxref_load_chain(pdf, xref); -+} -+ -+/* Parsing xref stream -+First we load the trailer, ignoring references. Dict defines sections and fields lengths: -+ -+ /Size % max ref number plus 1 -+ /Index [ first count first count ... ] % a pair of numbers for every section, defaults to [0 Size] -+ /W [w1 w2 w3] % fields lengths, 0 states for omitted field -+ -+xref stream data is a continuous stream of binary number triplets. First number is a type: -+ -+ 0 - free entry (as 'f' in xref table) -+ 1 - normal entry, followed by offset an version (as 'n' in xref table) -+ 2 - compressed entry, followed by parent object stream number and entry index -+ -+0 and 1 are handled as 'n' and 'f' entries in xref table. For type 2 we normally initialize -+ref->number and ref->version (the later is implicitly 0). ref->offset is set to 0 (invalid offset), -+which is recognized by objects loader. -+*/ -+ -+#define XREF_STREAM_MAX_FIELD 4 -+ -+static ppxref * ppxref_load_stream (iof *I, ppdoc *pdf, size_t xrefoffset) -+{ -+ ppxref *xref; -+ ppxsec *xrefsection; -+ ppref *ref; -+ ppobj *obj; -+ ppstream *xrefstream; -+ size_t streamoffset; -+ ppuint w1, w2, w3, w, bufferbytes; -+ uint8_t buffer[3 * XREF_STREAM_MAX_FIELD], *b; -+ ppuint first, count, f1, f2, f3; -+ pparray *fieldwidths, *sectionindices; -+ ppobj sectionmock[2], *sectionfirst, *sectioncount; -+ size_t sections, sectionindex, refindex; -+ -+ if (!ppscan_skip_entry(I)) -+ return NULL; -+ if ((obj = ppscan_obj(I, pdf, NULL)) == NULL) -+ return NULL; -+ ppstack_pop(&pdf->stack, 1); -+ if (obj->type != PPDICT || !ppscan_start_stream(I, pdf, &streamoffset)) -+ return NULL; -+ xrefstream = ppstream_create(pdf, obj->dict, streamoffset); -+ /* All normal streams go through ppstream_info(), but it makes no sense for trailer stream (no crypt allowed, no refs yet). -+ So we just record the length and informative flag. Here we have to expect that /Length and /Filter are not indirects. */ -+ if (!ppdict_get_uint(obj->dict, "Length", &xrefstream->length)) -+ return NULL; -+ if (ppdict_get_obj(obj->dict, "Filter") != NULL) -+ xrefstream->flags |= PPSTREAM_COMPRESSED; -+ if ((fieldwidths = ppdict_get_array(xrefstream->dict, "W")) != NULL) -+ { -+ if (!pparray_get_uint(fieldwidths, 0, &w1)) w1 = 0; -+ if (!pparray_get_uint(fieldwidths, 1, &w2)) w2 = 0; -+ if (!pparray_get_uint(fieldwidths, 2, &w3)) w3 = 0; -+ } -+ else -+ w1 = w2 = w3 = 0; -+ if (w1 > XREF_STREAM_MAX_FIELD || w2 > XREF_STREAM_MAX_FIELD || w3 > XREF_STREAM_MAX_FIELD) -+ return NULL; -+ bufferbytes = w1 + w2 + w3; -+ if ((sectionindices = ppdict_get_array(xrefstream->dict, "Index")) != NULL) -+ { -+ sections = sectionindices->size >> 1; -+ sectionfirst = sectionindices->data; -+ } -+ else -+ { -+ sections = 1; -+ sectionmock[0].type = PPINT; -+ sectionmock[0].integer = 0; -+ sectionmock[1].type = PPINT; -+ if (!ppdict_get_int(xrefstream->dict, "Size", §ionmock[1].integer)) -+ sectionmock[1].integer = 0; -+ sectionfirst = §ionmock[0]; -+ } -+ if ((I = ppstream_read(xrefstream, 1, 0)) == NULL) -+ return NULL; // we fseek() so original I is useless anyway -+ xref = ppxref_create(pdf, sections, xrefoffset); -+ if (pdf->xref == NULL) pdf->xref = xref; -+ xref->trailer.type = PPSTREAM; -+ xref->trailer.stream = xrefstream; -+ for (sectionindex = 0; sectionindex < sections; ++sectionindex, sectionfirst += 2) -+ { -+ sectioncount = sectionfirst + 1; -+ if (!ppobj_get_uint(sectionfirst, first) || !ppobj_get_uint(sectioncount, count)) -+ goto xref_stream_error; -+ if (count == 0) -+ continue; -+ xref->count += count; -+ xrefsection = NULL; -+ ref = (ppref *)ppheap_take(&pdf->heap, count * sizeof(ppref)); -+ for (refindex = 0; refindex < count; ++refindex, ++ref) -+ { -+ ref->xref = xref; -+ ref->number = first + refindex; -+ if (iof_read(I, buffer, bufferbytes) != bufferbytes) -+ goto xref_stream_error; -+ b = buffer; -+ if (w1 == 0) -+ f1 = 1; // default type is 1 -+ else -+ for (f1 = 0, w = 0; w < w1; f1 = (f1 << 8)|(*b), ++w, ++b); -+ for (f2 = 0, w = 0; w < w2; f2 = (f2 << 8)|(*b), ++w, ++b); -+ for (f3 = 0, w = 0; w < w3; f3 = (f3 << 8)|(*b), ++w, ++b); -+ switch (f1) -+ { -+ case 0: -+ //--ref; -+ xrefsection = NULL; -+ --xref->count; -+ break; -+ case 1: -+ if (xrefsection == NULL) -+ { -+ xrefsection = ppxref_push_section(xref, &pdf->heap); -+ xrefsection->first = ref->number; -+ xrefsection->refs = ref; -+ } -+ xrefsection->last = ref->number; -+ ref->offset = f2; -+ ref->version = f3; -+ ref->object.type = PPNONE; -+ ref->object.any = NULL; -+ ref->length = 0; -+ break; -+ case 2: -+ if (xrefsection == NULL) -+ { -+ xrefsection = ppxref_push_section(xref, &pdf->heap); -+ xrefsection->first = ref->number; -+ xrefsection->refs = ref; -+ } -+ xrefsection->last = ref->number; -+ ref->offset = 0; // f2 is parent objstm, f3 is index in parent, both useless -+ ref->version = 0; // compressed objects has implicit version == 0 -+ ref->object.type = PPNONE; -+ ref->object.any = NULL; -+ ref->length = 0; -+ break; -+ default: -+ goto xref_stream_error; -+ } -+ } -+ } -+ /* sort sections */ -+ if (!ppxref_sort(xref)) -+ ; // case of xref->size == 0 handled by ppxref_load_chain() -+ /* close the stream _before_ loading prev xref */ -+ ppstream_done(xrefstream); -+ /* load prev and return */ -+ return ppxref_load_chain(pdf, xref); -+xref_stream_error: -+ ppstream_done(xrefstream); -+ return NULL; -+} -+ -+/* -+The following procedure loads xref /Prev, links xref->prev and typically returns xref. -+Some docs contain empty xref (one section with zero objects) that is actually a proxy -+to xref stream referred as /XRefStm (genuine concept of xrefs old/new style xrefs in -+the same doc). In case of 0-length xref we ignore the proxy and return the target xref -+(otherwise we would need annoying sanity check for xref->size > 0 on every ref search). -+*/ -+ -+static ppxref * ppxref_load_chain (ppdoc *pdf, ppxref *xref) -+{ -+ ppdict *trailer; -+ ppuint xrefoffset; -+ ppxref *prevxref, *nextxref; -+ -+ trailer = ppxref_trailer(xref); -+ if (!ppdict_get_uint(trailer, "Prev", &xrefoffset)) // XRefStm is useless -+ return xref; // missing /Prev is obviously ok -+ for (nextxref = pdf->xref; nextxref != NULL; nextxref = nextxref->prev) -+ if (nextxref->offset == xrefoffset) // insane -+ return NULL; -+ if ((prevxref = ppxref_load(pdf, (size_t)xrefoffset)) == NULL) -+ return NULL; -+ if (xref->size > 0) -+ { -+ xref->prev = prevxref; -+ return xref; -+ } -+ if (pdf->xref == xref) -+ pdf->xref = prevxref; -+ return prevxref; -+} -+ -+static ppxref * ppxref_load (ppdoc *pdf, size_t xrefoffset) -+{ -+ iof *I; -+ if ((I = ppdoc_reader(pdf, xrefoffset, PP_LENGTH_UNKNOWN)) == NULL) -+ return NULL; -+ ppscan_find(I); -+ if (ppscan_key(I, "xref")) -+ return ppxref_load_table(I, pdf, xrefoffset); -+ return ppxref_load_stream(I, pdf, xrefoffset); -+ // iof_close(I) does nothing here -+} -+ -+static void ppoffmap_sort (ppref **left, ppref **right) -+{ -+ ppref **l, **r, *t; -+ ppuint pivot; -+ l = left, r = right; -+ pivot = (*(l + ((r - l) / 2)))->offset; -+ do -+ { // don't read from pointer! -+ while ((*l)->offset < pivot) ++l; -+ while ((*r)->offset > pivot) --r; -+ if (l <= r) -+ { -+ t = *l; -+ *l = *r; -+ *r = t; -+ ++l, --r; -+ } -+ } while (l <= r); -+ if (left < r) -+ ppoffmap_sort(left, r); -+ if (l < right) -+ ppoffmap_sort(l, right); -+} -+ -+ -+static void fix_trailer_references (ppdoc *pdf) -+{ -+ ppxref *xref; -+ ppdict *trailer; -+ ppname *pkey; -+ ppobj *obj; -+ ppref *ref; -+ for (xref = pdf->xref; xref != NULL; xref = xref->prev) -+ { -+ if ((trailer = ppxref_trailer(xref)) == NULL) -+ continue; -+ for (ppdict_first(trailer, pkey, obj); *pkey != NULL; ppdict_next(pkey, obj)) -+ { // no need to go deeper in structs, all items in trailer except info and root must be direct refs -+ if (obj->type != PPREF) -+ continue; -+ ref = obj->ref; -+ if (ref->offset == 0) // unresolved? -+ if ((ref = ppxref_find(xref, ref->number)) != NULL) -+ obj->ref = ref; // at this moment the reference still points nothing, but should be the one with the proper offset -+ } -+ } -+} -+ -+/* -+Here comes a procedure that loads all entries from all document bodies. We resolve references while -+parsing objects and to make resolving correct, we need a complete chain of xref maps, and a knowledge -+about possible linearized dict (first offset). So loading refs sorted by offsets makes sense (not sure -+if it matters nowadays but we also avoid fseek() by large offsets). -+ -+Here is the proc: -+ -+ - create a list of all refs in all bodies -+ - sort the list by offsets -+ - for every ref from the sorted list: -+ - estimate object length to avoid fread-ing more than necessary (not perfect but enough) -+ - fseek() to the proper offset, fread() entry data or its part -+ - parse the object with ppscan_obj(I, pdf, xref), where xref is not necessarily top pdf->xref -+ - save the actual ref->length (not sure if we need that?) -+ - make a stream if a dict is followed by "stream" keyword, also save the stream offset -+ - free the list -+*/ -+ -+static int ppdoc_load_objstm (ppstream *stream, ppdoc *pdf, ppxref *xref); -+ -+static void ppdoc_load_entries (ppdoc *pdf) -+{ -+ size_t objects, sectionindex, refnumber, offindex; -+ ppnum linearized; -+ ppref **offmap, **pref, *ref; -+ ppxref *xref; -+ ppxsec *xsec; -+ ppobj *obj; -+ ppname type; -+ int redundant_indirection = 0; -+ ppcrypt *crypt; -+ ppstream *stream; -+ -+ if ((objects = (size_t)ppdoc_objects(pdf)) == 0) // can't happen -+ return; -+ pref = offmap = (ppref **)pp_malloc(objects * sizeof(ppref *)); -+ objects = 0; // recount refs with offset > 0 -+ for (xref = pdf->xref; xref != NULL; xref = xref->prev) -+ for (sectionindex = 0, xsec = xref->sects; sectionindex < xref->size; ++sectionindex, ++xsec) -+ for (refnumber = xsec->first, ref = xsec->refs; refnumber <= xsec->last; ++refnumber, ++ref) -+ if (ref->offset > 0) // 0 means compressed or insane -+ *pref++ = ref, ++objects; -+ ppoffmap_sort(offmap, offmap + objects - 1); -+ -+ crypt = pdf->crypt; -+ for (offindex = 0, pref = offmap; offindex < objects; ) -+ { -+ ref = *pref; -+ ++pref; -+ ++offindex; -+ if (ref->object.type != PPNONE) // might be preloaded already (/Encrypt dict, stream filter dicts, stream /Length..) -+ continue; -+ if (offindex < objects) -+ ref->length = (*pref)->offset - ref->offset; -+ else -+ ref->length = pdf->filesize > ref->offset ? pdf->filesize - ref->offset : 0; -+ if (crypt != NULL) -+ { -+ ppcrypt_start_ref(crypt, ref); -+ obj = ppdoc_load_entry(pdf, ref); -+ ppcrypt_end_ref(crypt); -+ } -+ else -+ { -+ obj = ppdoc_load_entry(pdf, ref); -+ } -+ switch (obj->type) -+ { -+ case PPDICT: /* Check if the object at first offset is linearized dict. We need that to resolve all references properly. */ -+ if (offindex == 1 && ppdict_get_num(obj->dict, "Linearized", &linearized)) // /Linearized value is a version number, default 1.0 -+ pdf->flags |= PPDOC_LINEARIZED; -+ break; -+ case PPREF: -+ redundant_indirection = 1; -+ break; -+ default: -+ break; -+ } -+ // if pdf->crypt crypt->ref = NULL -+ } -+ -+ /* refs pointngs refs? cut. */ -+ if (redundant_indirection) -+ { -+ for (offindex = 0, pref = offmap; offindex < objects; ++offindex) -+ { -+ ref = *pref++; -+ if (ref->object.type == PPREF) -+ ref->object = ref->object.ref->object; // doing for all effectively cuts all insane chains -+ } -+ } -+ -+ /* now handle streams; update stream info (eg. /Length), load pdf 1.5 object streams -+ we could do earlier but then we would need to struggle with indirects */ -+ for (offindex = 0, pref = offmap; offindex < objects; ++offindex) -+ { -+ ref = *pref++; -+ obj = &ref->object; -+ if (obj->type != PPSTREAM) -+ continue; -+ stream = obj->stream; -+ if (crypt != NULL) -+ { -+ ppcrypt_start_ref(crypt, ref); -+ ppstream_info(stream, pdf); -+ ppcrypt_end_ref(crypt); -+ } -+ else -+ { -+ ppstream_info(stream, pdf); -+ } -+ if (ref->xref->trailer.type == PPSTREAM && (type = ppdict_get_name(stream->dict, "Type")) != NULL && ppname_is(type, "ObjStm")) // somewhat dummy.. -+ if (!ppdoc_load_objstm(stream, pdf, ref->xref)) -+ loggerf("invalid objects stream %s at offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset); -+ } -+ pp_free(offmap); -+} -+ -+ppobj * ppdoc_load_entry (ppdoc *pdf, ppref *ref) -+{ -+ iof *I; -+ size_t length; -+ ppxref *xref; -+ ppobj *obj; -+ ppstack *stack; -+ size_t streamoffset; -+ ppref *refref; -+ ppuint refnumber, refversion; -+ -+ length = ref->length > 0 ? ref->length : PP_LENGTH_UNKNOWN; // estimated or unknown -+ if ((I = ppdoc_reader(pdf, ref->offset, length)) == NULL || !ppscan_start_entry(I, ref)) -+ { -+ loggerf("invalid %s offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset); -+ return &ref->object; // PPNONE -+ } -+ stack = &pdf->stack; -+ xref = ref->xref; // to resolve indirects properly -+ if ((obj = ppscan_obj(I, pdf, xref)) == NULL) -+ { -+ loggerf("invalid %s object at offset " PPSIZEF, ppref_str(ref->number, ref->version), ref->offset); -+ return &ref->object; // PPNONE -+ } -+ ref->object = *obj; -+ ppstack_pop(stack, 1); -+ obj = &ref->object; -+ ref->length = ppdoc_reader_tell(pdf, I) - ref->offset; -+ if (obj->type == PPDICT) -+ { -+ if (ppscan_start_stream(I, pdf, &streamoffset)) -+ { -+ obj->type = PPSTREAM; -+ obj->stream = ppstream_create(pdf, obj->dict, streamoffset); -+ } -+ } -+ else if (obj->type == PPINT) -+ { -+ ppscan_find(I); -+ if (ppscan_uint(I, &refversion) && ppscan_find(I) == 'R') -+ { -+ refnumber = (ppuint)obj->integer; -+ if ((refref = ppxref_find(xref, refnumber)) != NULL) -+ { -+ obj->type = PPREF; -+ obj->ref = refref; -+ } -+ else -+ { -+ obj->type = PPNONE; // as ppref_unresolved() -+ obj->any = NULL; -+ } -+ } -+ } -+ return obj; -+} -+ -+/* Loading entries from object stream -+ -+ /N is the number of contained entries -+ /First is the offset of the first item -+ -+The stream consists of N pairs of numbers ... -+Offsets are ascending (relative to the first), but ref numbers order is arbitrary. -+PDF spec says there might be some additional data between objects, so we should obey offsets. -+Which means we should basically load the stream at once (may be needed anyway to grab the stream [...]). -+*/ -+ -+static int ppdoc_load_objstm (ppstream *stream, ppdoc *pdf, ppxref *xref) -+{ -+ ppdict *dict; // stream dict, actually still on stack -+ ppref *ref; -+ ppobj *obj; -+ ppuint items, firstoffset, offset, objnum, i, invalid = 0; -+ iof *I; -+ uint8_t *firstdata, *indexdata; -+ ppstack *stack; -+ -+ dict = stream->dict; -+ if (!ppdict_rget_uint(dict, "N", &items) || !ppdict_rget_uint(dict, "First", &firstoffset)) -+ return 0; -+ if ((I = ppstream_read(stream, 1, 1)) == NULL) -+ return 0; -+ firstdata = I->pos + firstoffset; -+ if (firstdata >= I->end) -+ goto invalid_objstm; -+ stack = &pdf->stack; -+ //if (pdf->crypt != NULL) -+ // ppcrypt_end_ref(pdf->crypt); // objects are not encrypted, pdf->crypt->ref ensured NULL -+ for (i = 0; i < items; ++i) -+ { -+ ppscan_find(I); -+ if (!ppscan_uint(I, &objnum)) -+ goto invalid_objstm; -+ ppscan_find(I); -+ if (!ppscan_uint(I, &offset)) -+ goto invalid_objstm; -+ if ((ref = ppxref_find_local(xref, objnum)) == NULL || ref->object.type != PPNONE) -+ { -+ loggerf("invalid compressed object number " PPUINTF " at position " PPUINTF, objnum, i); -+ ++invalid; -+ continue; -+ } -+ if (firstdata + offset >= I->end) -+ { -+ loggerf("invalid compressed object offset " PPUINTF " at position " PPUINTF, offset, i); -+ ++invalid; -+ continue; -+ } -+ indexdata = I->pos; // save position -+ I->pos = firstdata + offset; // go to the object -+ ppscan_find(I); -+ if ((obj = ppscan_obj(I, pdf, xref)) != NULL) -+ { -+ ref->object = *obj; -+ ppstack_pop(stack, 1); -+ // nothing more needed, as obj can never be indirect ref or stream -+ } -+ else -+ { -+ ++invalid; -+ loggerf("invalid compressed object %s at stream offset " PPUINTF, ppref_str(objnum, 0), offset); -+ } -+ I->pos = indexdata; // restore position and read next from index -+ } -+ ppstream_done(stream); -+ return invalid == 0; -+invalid_objstm: -+ ppstream_done(stream); -+ return 0; -+} -+ -+/* main PDF loader proc */ -+ -+ppcrypt_status ppdoc_crypt_pass (ppdoc *pdf, const void *userpass, size_t userpasslength, const void *ownerpass, size_t ownerpasslength) -+{ -+ switch (pdf->cryptstatus) -+ { -+ case PPCRYPT_NONE: -+ case PPCRYPT_DONE: -+ case PPCRYPT_FAIL: -+ break; -+ case PPCRYPT_PASS: // initial status or really needs password -+ pdf->cryptstatus = ppdoc_crypt_init(pdf, userpass, userpasslength, ownerpass, ownerpasslength); -+ switch (pdf->cryptstatus) -+ { -+ case PPCRYPT_NONE: -+ case PPCRYPT_DONE: -+ ppdoc_load_entries(pdf); -+ break; -+ case PPCRYPT_PASS: // user needs to check ppdoc_crypt_status() and recall ppdoc_crypt_pass() with the proper password -+ case PPCRYPT_FAIL: // hopeless.. -+ break; -+ } -+ break; -+ } -+ return pdf->cryptstatus; -+} -+ -+static ppdoc * ppdoc_read (ppdoc *pdf, iof_file *input) -+{ -+ uint8_t header[PPDOC_HEADER]; -+ size_t xrefoffset; -+ -+ input = &pdf->input; -+ if (iof_file_read(header, 1, PPDOC_HEADER, input) != PPDOC_HEADER || !ppdoc_header(pdf, header)) -+ return NULL; -+ if (!ppdoc_tail(pdf, input, &xrefoffset)) -+ return NULL; -+ if (ppxref_load(pdf, xrefoffset) == NULL) -+ return NULL; -+ fix_trailer_references(pdf); // after loading xrefs but before accessing trailer refs (/Encrypt might be a reference) -+ // check encryption, if any, try empty password -+ switch (ppdoc_crypt_pass(pdf, "", 0, NULL, 0)) -+ { -+ case PPCRYPT_NONE: // no encryption -+ case PPCRYPT_DONE: // encryption with an empty password -+ case PPCRYPT_PASS: // the user needs to check ppdoc_crypt_status() and call ppdoc_crypt_pass() -+ break; -+ case PPCRYPT_FAIL: // hopeless -+ //loggerf("decryption failed"); -+ //return NULL; -+ break; -+ } -+ return pdf; -+} -+ -+static void ppdoc_pages_init (ppdoc *pdf); -+ -+static ppdoc * ppdoc_create (iof_file *input) -+{ -+ ppdoc *pdf; -+ ppheap *heap; -+ -+ heap = ppheap_new(); -+ pdf = (ppdoc *)ppheap_take(&heap, sizeof(ppdoc)); -+ pdf->flags = 0; -+ pdf->heap = heap; -+ pdf->xref = NULL; -+ pdf->version[0] = '\0'; -+ pdf->crypt = NULL; -+ pdf->cryptstatus = PPCRYPT_PASS; // force encryption check on ppdoc_read() -> ppdoc_crypt_pass() -+ ppstack_init(&pdf->stack, &pdf->heap); -+ ppdoc_reader_init(pdf, input); -+ ppdoc_pages_init(pdf); -+ if (ppdoc_read(pdf, &pdf->input) != NULL) -+ return pdf; -+ ppdoc_free(pdf); -+ return NULL; -+} -+ -+ppdoc * ppdoc_load (const char *filename) -+{ -+ FILE *file; -+ iof_file input; -+ if ((file = fopen(filename, "rb")) == NULL) -+ return NULL; -+ iof_file_init(&input, file); -+ input.flags |= IOF_CLOSE_FILE; -+ return ppdoc_create(&input); -+} -+ -+ppdoc * ppdoc_mem (const void *data, size_t size) -+{ -+ iof_file input; -+ iof_file_rdata_init(&input, data, size); -+ input.flags |= IOF_BUFFER_ALLOC; // todo: 3 modes: borrow, take over, copy? -+ return ppdoc_create(&input); -+} -+ -+void ppdoc_free (ppdoc *pdf) -+{ -+ //iof_file_free(&pdf->input); -+ iof_file_decref(&pdf->input); -+ ppstack_free_buffer(&pdf->stack); -+ ppheap_free(pdf->heap); // last! -+} -+ -+ppcrypt_status ppdoc_crypt_status (ppdoc *pdf) -+{ -+ return pdf->cryptstatus; -+} -+ -+ppint ppdoc_permissions (ppdoc *pdf) -+{ -+ return pdf->crypt != NULL ? pdf->crypt->permissions : (ppint)0xFFFFFFFFFFFFFFFF; -+} -+ -+/* pages access */ -+ -+static pparray * pppage_node (ppdict *dict, ppuint *count, ppname *type) -+{ -+ ppname *pkey, key; -+ ppobj *obj; -+ pparray *kids = NULL; -+ *count = 0; -+ *type = NULL; -+ for (ppdict_first(dict, pkey, obj); (key = *pkey) != NULL; ppdict_next(pkey, obj)) -+ { -+ switch (key[0]) -+ { -+ case 'T': -+ if (ppname_is(key, "Type")) -+ *type = ppobj_get_name(obj); -+ break; -+ case 'C': -+ if (ppname_is(key, "Count")) -+ ppobj_get_uint(obj, *count); -+ break; -+ case 'K': -+ if (ppname_is(key, "Kids")) -+ kids = ppobj_rget_array(obj); -+ break; -+ } -+ } -+ return kids; -+} -+ -+#define ppname_is_page(type) (type != NULL && ppname_is(type, "Page")) -+ -+ppuint ppdoc_page_count (ppdoc *pdf) -+{ -+ ppref *ref; -+ ppname type; -+ ppuint count; -+ if ((ref = ppxref_pages(pdf->xref)) == NULL) -+ return 0; -+ if (pppage_node(ref->object.dict, &count, &type) == NULL) -+ return ppname_is_page(type) ? 1 : 0; // acrobat and ghostscript accept documents with root /Pages entry being a reference to a sole /Page object -+ return count; -+} -+ -+ppref * ppdoc_page (ppdoc *pdf, ppuint index) -+{ -+ ppdict *dict; -+ ppuint count; -+ pparray *kids; -+ size_t size, i; -+ ppobj *r, *o; -+ ppref *ref; -+ ppname type; -+ -+ -+ if ((ref = ppxref_pages(pdf->xref)) == NULL) -+ return NULL; -+ dict = ref->object.dict; -+ if ((kids = pppage_node(dict, &count, &type)) != NULL) -+ { -+ if (index < 1 || index > count) -+ return NULL; -+ } -+ else -+ { -+ return index == 1 && ppname_is_page(type) ? ref : NULL; -+ } -+scan_array: -+ if (index <= count / 2) -+ { // probably shorter way from the beginning -+ for (i = 0, size = kids->size, r = pparray_at(kids, 0); i < size; ++i, ++r) -+ { -+ if (r->type != PPREF) -+ return NULL; -+ o = &r->ref->object; -+ if (o->type != PPDICT) -+ return NULL; -+ dict = o->dict; -+ if ((kids = pppage_node(dict, &count, &type)) != NULL) -+ { -+ if (index <= count) -+ goto scan_array; -+ index -= count; -+ continue; -+ } -+ if (index == 1 && ppname_is_page(type)) -+ return r->ref; -+ --index; -+ } -+ } -+ else if ((size = kids->size) > 0) // for safe (size-1) -+ { // probably shorter way from the end -+ index = count - index + 1; -+ for (i = 0, r = pparray_at(kids, size - 1); i < size; ++i, --r) -+ { -+ if (r->type != PPREF) -+ return NULL; -+ o = &r->ref->object; -+ if (o->type != PPDICT) -+ return NULL; -+ dict = o->dict; -+ if ((kids = pppage_node(dict, &count, &type)) != NULL) -+ { -+ if (index <= count) -+ goto scan_array; -+ index -= count; -+ continue; -+ } -+ if (index == 1 && ppname_is_page(type)) -+ return r->ref; -+ --index; -+ } -+ } -+ return NULL; -+} -+ -+/* -+Through pages iterator. Iterating over pages tree just on the base of /Kids and /Parent keys -+is ineffective, as to get next pageref we need to take parent, find the pageref in /Kids, -+take next (or go upper).. Annoying. We use a dedicated stack for pages iterator. This could -+actually be done with pdf->stack, but some operations may clear it, so safer to keep it independent -+Besides, its depth is constant (set on first use), so no need for allocs. -+*/ -+ -+static void ppdoc_pages_init (ppdoc *pdf) -+{ -+ pppages *pages; -+ pages = &pdf->pages; -+ pages->root = pages->parent = pages->buffer; -+ pages->depth = 0; -+ pages->space = PPPAGES_STACK_DEPTH; -+} -+ -+static ppkids * pppages_push (ppdoc *pdf, pparray *kids) -+{ -+ ppkids *newroot, *bounds; -+ pppages *pages; -+ pages = &pdf->pages; -+ if (pages->depth == pages->space) -+ { -+ pages->space <<= 1; -+ newroot = (ppkids *)ppheap_take(&pdf->heap, pages->space * sizeof(ppkids)); -+ memcpy(newroot, pages->root, pages->depth * sizeof(ppkids)); -+ pages->root = newroot; -+ } -+ bounds = pages->parent = &pages->root[pages->depth++]; -+ bounds->current = pparray_at(kids, 0); -+ bounds->sentinel = pparray_at(kids, kids->size); -+ return bounds; -+} -+ -+#define pppages_pop(pages) (--((pages)->parent), --((pages)->depth)) -+ -+static ppref * ppdoc_pages_group_first (ppdoc *pdf, ppref *ref) -+{ -+ ppdict *dict; -+ pparray *kids; -+ ppuint count; -+ ppname type; -+ -+ dict = ref->object.dict; // typecheck made by callers -+ while ((kids = pppage_node(dict, &count, &type)) != NULL) -+ { -+ if ((ref = pparray_get_ref(kids, 0)) == NULL || ref->object.type != PPDICT) -+ return NULL; -+ pppages_push(pdf, kids); -+ dict = ref->object.dict; -+ } -+ return ppname_is_page(type) ? ref : NULL; -+} -+ -+ppref * ppdoc_first_page (ppdoc *pdf) -+{ -+ ppref *ref; -+ pppages *pages; -+ if ((ref = ppdoc_pages(pdf)) == NULL) -+ return NULL; -+ pages = &pdf->pages; -+ pages->parent = pages->root; -+ pages->depth = 0; -+ return ppdoc_pages_group_first(pdf, ref); -+} -+ -+ppref * ppdoc_next_page (ppdoc *pdf) -+{ -+ pppages *pages; -+ ppkids *bounds; -+ ppref *ref; -+ ppobj *obj; -+ pages = &pdf->pages; -+ while (pages->depth > 0) -+ { -+ bounds = pages->parent; -+ obj = ++bounds->current; -+ if (obj < bounds->sentinel) -+ { -+ if (obj->type != PPREF) -+ return NULL; -+ ref = obj->ref; -+ if (ref->object.type != PPDICT) -+ return NULL; -+ return ppdoc_pages_group_first(pdf, ref); -+ } -+ else -+ { // no next node, go upper -+ pppages_pop(pages); -+ } -+ } -+ return NULL; -+} -+ -+/* context */ -+ -+ppcontext * ppcontext_new (void) -+{ -+ ppheap *heap; -+ ppcontext *context; -+ heap = ppheap_new(); -+ context = (ppcontext *)pp_malloc(sizeof(ppcontext)); // not from priv heap, as we delete it on renew -+ context->heap = heap; -+ ppstack_init(&context->stack, &context->heap); -+ return context; -+} -+ -+void ppcontext_done (ppcontext *context) -+{ -+ ppheap_renew(context->heap); -+ ppstack_clear(&context->stack); -+} -+ -+void ppcontext_free (ppcontext *context) -+{ -+ ppstack_free_buffer(&context->stack); -+ ppheap_free(context->heap); -+ pp_free(context); -+} -+ -+/* page contents streams */ -+ -+//#define ppcontents_first_stream(array) pparray_rget_stream(array, 0) -+ -+static ppstream * ppcontents_first_stream (pparray *array) -+{ -+ size_t i; -+ ppobj *obj; -+ ppref *ref; -+ for (pparray_first(array, i, obj); i < array->size; pparray_next(i, obj)) -+ if ((ref = ppobj_get_ref(obj)) != NULL && ref->object.type == PPSTREAM) -+ return ref->object.stream; -+ return NULL; -+} -+ -+static ppstream * ppcontents_next_stream (pparray *array, ppstream *stream) -+{ -+ size_t i; -+ ppobj *obj; -+ ppref *ref; -+ for (pparray_first(array, i, obj); i < array->size; pparray_next(i, obj)) -+ if ((ref = ppobj_get_ref(obj)) != NULL && ref->object.type == PPSTREAM && ref->object.stream == stream) -+ if (++i < array->size && (ref = ppobj_get_ref(obj + 1)) != NULL && ref->object.type == PPSTREAM) -+ return ref->object.stream; -+ return NULL; -+} -+ -+ppstream * ppcontents_first (ppdict *dict) -+{ -+ ppobj *contentsobj; -+ if ((contentsobj = ppdict_rget_obj(dict, "Contents")) == NULL) -+ return NULL; -+ switch (contentsobj->type) -+ { -+ case PPARRAY: -+ return ppcontents_first_stream(contentsobj->array); -+ case PPSTREAM: -+ return contentsobj->stream; -+ default: -+ break; -+ } -+ return NULL; -+} -+ -+ppstream * ppcontents_next (ppdict *dict, ppstream *stream) -+{ -+ ppobj *contentsobj; -+ if ((contentsobj = ppdict_rget_obj(dict, "Contents")) == NULL) -+ return NULL; -+ switch (contentsobj->type) -+ { -+ case PPARRAY: -+ return ppcontents_next_stream(contentsobj->array, stream); -+ case PPSTREAM: -+ break; -+ default: -+ break; -+ } -+ return NULL; -+} -+ -+static ppobj * ppcontents_op (iof *I, ppstack *stack, size_t *psize, ppname *pname) -+{ -+ ppobj *obj; -+ ppstack_clear(stack); -+ do { -+ if (ppscan_find(I) < 0) -+ return NULL; -+ if ((obj = ppscan_psobj(I, stack)) == NULL) -+ return NULL; -+ } while (obj->type != PPNAME || !ppname_exec(obj->name)); -+ *pname = obj->name; -+ *psize = stack->size - 1; -+ return stack->buf; -+} -+ -+ppobj * ppcontents_first_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname) -+{ -+ iof *I; -+ if ((I = ppstream_read(stream, 1, 0)) == NULL) -+ return NULL; -+ return ppcontents_op(I, &context->stack, psize, pname); -+} -+ -+ppobj * ppcontents_next_op (ppcontext *context, ppstream *stream, size_t *psize, ppname *pname) -+{ -+ return ppcontents_op(ppstream_iof(stream), &context->stack, psize, pname); -+} -+ -+ppobj * ppcontents_parse (ppcontext *context, ppstream *stream, size_t *psize) -+{ -+ iof *I; -+ ppstack *stack; -+ ppobj *obj; -+ stack = &context->stack; -+ ppstack_clear(stack); -+ if ((I = ppstream_read(stream, 1, 0)) == NULL) -+ return NULL; -+ while (ppscan_find(I) >= 0) -+ if ((obj = ppscan_psobj(I, stack)) == NULL) -+ goto error; -+ *psize = stack->size; -+ ppstream_done(stream); -+ return stack->buf; -+error: -+ ppstream_done(stream); -+ return NULL; -+} -+ -+/* boxes */ -+ -+pprect * pparray_to_rect (pparray *array, pprect *rect) -+{ -+ ppobj *obj; -+ if (array->size != 4) -+ return NULL; -+ obj = pparray_at(array, 0); -+ if (!ppobj_get_num(obj, rect->lx)) return NULL; -+ obj = pparray_at(array, 1); -+ if (!ppobj_get_num(obj, rect->ly)) return NULL; -+ obj = pparray_at(array, 2); -+ if (!ppobj_get_num(obj, rect->rx)) return NULL; -+ obj = pparray_at(array, 3); -+ if (!ppobj_get_num(obj, rect->ry)) return NULL; -+ return rect; -+} -+ -+pprect * ppdict_get_rect (ppdict *dict, const char *name, pprect *rect) -+{ -+ pparray *array; -+ return (array = ppdict_rget_array(dict, name)) != NULL ? pparray_to_rect(array, rect) : NULL; -+} -+ -+pprect * ppdict_get_box (ppdict *dict, const char *name, pprect *rect) -+{ -+ do { -+ if (ppdict_get_rect(dict, name, rect) != NULL) -+ return rect; -+ dict = ppdict_rget_dict(dict, "Parent"); -+ } while (dict != NULL); -+ return NULL; -+} -+ -+ppmatrix * pparray_to_matrix (pparray *array, ppmatrix *matrix) -+{ -+ ppobj *obj; -+ if (array->size != 6) -+ return NULL; -+ obj = pparray_at(array, 0); -+ if (!ppobj_get_num(obj, matrix->xx)) return NULL; -+ obj = pparray_at(array, 1); -+ if (!ppobj_get_num(obj, matrix->xy)) return NULL; -+ obj = pparray_at(array, 2); -+ if (!ppobj_get_num(obj, matrix->yx)) return NULL; -+ obj = pparray_at(array, 3); -+ if (!ppobj_get_num(obj, matrix->yy)) return NULL; -+ obj = pparray_at(array, 4); -+ if (!ppobj_get_num(obj, matrix->x)) return NULL; -+ obj = pparray_at(array, 5); -+ if (!ppobj_get_num(obj, matrix->y)) return NULL; -+ return matrix; -+} -+ -+ppmatrix * ppdict_get_matrix (ppdict *dict, const char *name, ppmatrix *matrix) -+{ -+ pparray *array; -+ return (array = ppdict_rget_array(dict, name)) != NULL ? pparray_to_matrix(array, matrix) : NULL; -+} -+ -+/* logger */ -+ -+void pplog_callback (pplogger_callback logger, void *alien) -+{ -+ logger_callback((logger_function)logger, alien); -+} -+ -+int pplog_prefix (const char *prefix) -+{ -+ return logger_prefix(prefix); -+} -+ -+/* version */ -+ -+const char * ppdoc_version_string (ppdoc *pdf) -+{ -+ return pdf->version; -+} -+ -+int ppdoc_version_number (ppdoc *pdf, int *minor) -+{ -+ *minor = pdf->version[2] - '0'; -+ return pdf->version[0] - '0'; -+} -+ -+/* doc info */ -+ -+size_t ppdoc_file_size (ppdoc *pdf) -+{ -+ return pdf->filesize; -+} -+ -+ppuint ppdoc_objects (ppdoc *pdf) -+{ -+ ppuint count; -+ ppxref *xref; -+ for (count = 0, xref = pdf->xref; xref != NULL; xref = xref->prev) -+ count += xref->count; -+ return count; -+} -+ -+size_t ppdoc_memory (ppdoc *pdf, size_t *waste) -+{ -+ size_t used; -+ ppheap *heap; -+ used = 0, *waste = 0; -+ for (heap = pdf->heap; heap != NULL; heap = heap->prev) -+ { -+ used += heap->space; -+ *waste += heap->size; -+ } -+ return used; -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppload.h b/texk/web2c/luatexdir/luapplib/ppload.h -new file mode 100644 -index 000000000..163928398 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppload.h -@@ -0,0 +1,54 @@ -+ -+#ifndef PP_LOAD_H -+#define PP_LOAD_H -+ -+typedef struct { -+ ppobj *buf; // ppobjects buffer (allocated, not from our heap) -+ ppobj *pos; // current ppobj * -+ size_t size; // stack size -+ size_t space; // available space -+ ppheap **pheap; // allocator (parent pdf->stack->pheap or own) -+} ppstack; -+ -+typedef struct { -+ ppobj *current; -+ ppobj *sentinel; -+} ppkids; -+ -+#define PPPAGES_STACK_DEPTH 4 -+ -+typedef struct { -+ ppkids buffer[PPPAGES_STACK_DEPTH]; -+ ppkids *root; -+ ppkids *parent; -+ ppuint depth; -+ ppuint space; -+} pppages; -+ -+struct ppdoc { -+ char version[5]; -+ iof_file input; -+ iof reader; -+ uint8_t *buffer; -+ size_t filesize; -+ ppxref *xref; -+ ppheap *heap; -+ ppstack stack; -+ pppages pages; -+ int flags; -+ ppcrypt *crypt; -+ ppcrypt_status cryptstatus; -+}; -+ -+#define PPDOC_LINEARIZED (1 << 0) -+ -+ppobj * ppdoc_load_entry (ppdoc *pdf, ppref *ref); -+#define ppobj_preloaded(pdf, obj) ((obj)->type != PPREF ? (obj) : ((obj)->ref->object.type == PPNONE ? ppdoc_load_entry(pdf, (obj)->ref) : &(obj)->ref->object)) -+ppstring ppstring_internal (const void *data, size_t size, ppheap **pheap); -+ -+struct ppcontext { -+ ppheap *heap; -+ ppstack stack; -+}; -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/ppstream.c b/texk/web2c/luatexdir/luapplib/ppstream.c -new file mode 100644 -index 000000000..0e4be7b8e ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppstream.c -@@ -0,0 +1,310 @@ -+ -+#include "ppfilter.h" -+#include "pplib.h" -+ -+ppstream * ppstream_create (ppdoc *pdf, ppdict *dict, size_t offset) -+{ -+ ppstream *stream; -+ stream = (ppstream *)ppheap_take(&pdf->heap, sizeof(ppstream)); -+ stream->dict = dict; -+ stream->offset = offset; -+ //if (!ppdict_rget_uint(dict, "Length", &stream->length)) // may be indirect pointing PPNONE at this moment -+ // stream->length = 0; -+ stream->length = 0; -+ stream->input = &pdf->input; -+ stream->I = NULL; -+ stream->cryptkey = NULL; -+ stream->flags = 0; -+ return stream; -+} -+ -+/* codecs */ -+ -+enum { -+ PPSTREAM_UNKNOWN = -1, -+ PPSTREAM_BASE16 = 0, -+ PPSTREAM_BASE85, -+ PPSTREAM_RUNLENGTH, -+ PPSTREAM_FLATE, -+ PPSTREAM_LZW, -+ PPSTREAM_CCITT, -+ PPSTREAM_DCT, -+ PPSTREAM_JBIG2, -+ PPSTREAM_JPX, -+ PPSTREAM_CRYPT -+}; -+ -+static int ppstream_codec_type (ppname name) -+{ // one of those places where some hash wuld be nice.. -+ switch (name[0]) -+ { -+ case 'A': -+ if (ppname_is(name, "ASCIIHexDecode")) return PPSTREAM_BASE16; -+ if (ppname_is(name, "ASCII85Decode")) return PPSTREAM_BASE85; -+ break; -+ case 'R': -+ if (ppname_is(name, "RunLengthDecode")) return PPSTREAM_RUNLENGTH; -+ break; -+ case 'F': -+ if (ppname_is(name, "FlateDecode")) return PPSTREAM_FLATE; -+ break; -+ case 'L': -+ if (ppname_is(name, "LZWDecode")) return PPSTREAM_LZW; -+ break; -+ case 'D': -+ if (ppname_is(name, "DCTDecode")) return PPSTREAM_DCT; -+ break; -+ case 'C': -+ if (ppname_is(name, "CCITTFaxDecode")) return PPSTREAM_CCITT; -+ if (ppname_is(name, "Crypt")) return PPSTREAM_CRYPT; -+ break; -+ case 'J': -+ if (ppname_is(name, "JPXDecode")) return PPSTREAM_JPX; -+ if (ppname_is(name, "JBIG2Decode")) return PPSTREAM_JBIG2; -+ break; -+ } -+ return PPSTREAM_UNKNOWN; -+} -+ -+static iof * ppstream_predictor (ppdict *params, iof *N) -+{ -+ ppint predictor, rowsamples, components, samplebits; -+ -+ if (!ppdict_get_int(params, "Predictor", &predictor) || predictor <= 1) -+ return N; -+ if (!ppdict_get_int(params, "Columns", &rowsamples) || rowsamples == 0) // sanity, filter probably expects >0 -+ rowsamples = 1;; -+ if (!ppdict_get_int(params, "Colors", &components) || components == 0) // ditto -+ components = 1; -+ if (!ppdict_get_int(params, "BitsPerComponent", &samplebits) || samplebits == 0) -+ samplebits = 8; -+ return iof_filter_predictor_decoder(N, (int)predictor, (int)rowsamples, (int)components, (int)samplebits); -+} -+ -+static iof * ppstream_decoder (ppstream *stream, int codectype, ppdict *params, iof *N) -+{ -+ int flags; -+ iof *F, *P; -+ ppint earlychange; -+ ppstring cryptkey; -+ -+ switch (codectype) -+ { -+ case PPSTREAM_BASE16: -+ return iof_filter_base16_decoder(N); -+ case PPSTREAM_BASE85: -+ return iof_filter_base85_decoder(N); -+ case PPSTREAM_RUNLENGTH: -+ return iof_filter_runlength_decoder(N); -+ case PPSTREAM_FLATE: -+ if ((F = iof_filter_flate_decoder(N)) != NULL) -+ { -+ if (params != NULL) -+ { -+ if ((P = ppstream_predictor(params, F)) != NULL) -+ return P; -+ iof_close(F); -+ break; -+ } -+ return F; -+ } -+ break; -+ case PPSTREAM_LZW: -+ flags = LZW_DECODER_DEFAULTS; -+ if (params != NULL && ppdict_get_int(params, "EarlyChange", &earlychange) && earlychange == 0) // integer, not boolean -+ flags &= ~LZW_EARLY_INDEX; -+ if ((F = iof_filter_lzw_decoder(N, flags)) != NULL) -+ { -+ if (params != NULL) -+ { -+ if ((P = ppstream_predictor(params, F)) != NULL) -+ return P; -+ iof_close(F); -+ break; -+ } -+ return F; -+ } -+ break; -+ case PPSTREAM_CRYPT: -+ if ((cryptkey = stream->cryptkey) == NULL) -+ return N; // /Identity crypt -+ if (stream->flags & PPSTREAM_ENCRYPTED_AES) -+ return iof_filter_aes_decoder(N, cryptkey, ppstring_size(cryptkey)); -+ if (stream->flags & PPSTREAM_ENCRYPTED_RC4) -+ return iof_filter_rc4_decoder(N, cryptkey, ppstring_size(cryptkey)); -+ return NULL; // if neither AES or RC4 but cryptkey present, something went wrong; see ppstream_info() -+ case PPSTREAM_CCITT: -+ case PPSTREAM_DCT: -+ case PPSTREAM_JBIG2: -+ case PPSTREAM_JPX: -+ case PPSTREAM_UNKNOWN: -+ break; -+ } -+ return NULL; -+} -+ -+#define ppstream_image(type) (type == PPSTREAM_DCT || type == PPSTREAM_JBIG2 || PPSTREAM_JPX) -+ -+#define ppstream_source(stream) iof_filter_stream_coreader((iof_file *)((stream)->input), (size_t)((stream)->offset), (size_t)((stream)->length)) -+#define ppstream_auxsource(filename) iof_filter_file_reader(filename) -+ -+static ppname ppstream_filter_name (ppobj *filterobj, size_t index) -+{ -+ if (filterobj->type == PPNAME) -+ return index == 0 ? filterobj->name : NULL; -+ if (filterobj->type == PPARRAY) -+ return pparray_get_name(filterobj->array, index); -+ return NULL; -+} -+ -+static ppdict * ppstream_filter_params (ppobj *paramsobj, size_t index) -+{ -+ if (paramsobj->type == PPDICT) -+ return index == 0 ? paramsobj->dict : NULL; -+ if (paramsobj->type == PPARRAY) -+ return pparray_rget_dict(paramsobj->array, index); -+ return NULL; -+} -+ -+static const char * ppstream_aux_filename (ppobj *filespec) -+{ // mockup, here we should decode the string -+ if (filespec->type == PPSTRING) -+ { -+ return (const char *)(filespec->string); -+ } -+ // else might be a dict - todo -+ return NULL; -+} -+ -+iof * ppstream_read (ppstream *stream, int decode, int all) -+{ -+ ppdict *dict; -+ iof *I, *F; -+ int codectype, external, owncrypt; -+ ppobj *filterobj, *paramsobj, *filespecobj; -+ ppname filter; -+ ppdict *params; -+ size_t index; -+ const char *filename; -+ -+ if (ppstream_iof(stream) != NULL) -+ return NULL; // usage error -+ -+ dict = stream->dict; -+ if ((filespecobj = ppdict_rget_obj(dict, "F")) != NULL) -+ { -+ filename = ppstream_aux_filename(filespecobj); -+ I = filename != NULL ? ppstream_auxsource(filename) : NULL; -+ external = 1; -+ } -+ else -+ { -+ I = ppstream_source(stream); -+ external = 0; -+ } -+ if (I == NULL) -+ return NULL; -+ /* If the stream is encrypted, decipher is the first to be applied */ -+ owncrypt = (stream->flags & PPSTREAM_ENCRYPTED_OWN) != 0; -+ if (!owncrypt) -+ { -+ if (stream->cryptkey != NULL) -+ { /* implied global crypt */ -+ if ((F = ppstream_decoder(stream, PPSTREAM_CRYPT, NULL, I)) == NULL) -+ goto stream_error; -+ I = F; -+ } /* otherwise no crypt at all or /Identity */ -+ } -+ if (decode || owncrypt) -+ { -+ filterobj = ppdict_rget_obj(dict, external ? "FFilter" : "Filter"); -+ if (filterobj != NULL) -+ { -+ paramsobj = ppdict_rget_obj(dict, external ? "FDecodeParms" : "DecodeParms"); -+ for (index = 0, filter = ppstream_filter_name(filterobj, 0); filter != NULL; filter = ppstream_filter_name(filterobj, ++index)) -+ { -+ params = paramsobj != NULL ? ppstream_filter_params(paramsobj, index) : NULL; -+ codectype = ppstream_codec_type(filter); -+ if ((F = ppstream_decoder(stream, codectype, params, I)) != NULL) -+ { -+ I = F; -+ if (owncrypt && !decode && codectype == PPSTREAM_CRYPT) -+ break; // /Crypt filter should always be first, so in practise we return decrypted but compressed -+ continue; -+ } -+ if (!ppstream_image(codectype)) // something unexpected -+ goto stream_error; -+ else // just treat image data (jpeg/jbig) as the target data -+ break; -+ } -+ } -+ } -+ if (all) -+ iof_load(I); -+ else -+ iof_input(I); -+ stream->I = I; -+ return I; -+stream_error: -+ iof_close(I); -+ return NULL; -+} -+ -+uint8_t * ppstream_first (ppstream *stream, size_t *size, int decode) -+{ -+ iof *I; -+ if ((I = ppstream_read(stream, decode, 0)) != NULL) -+ { -+ *size = (size_t)iof_left(I); -+ return I->pos; -+ } -+ *size = 0; -+ return NULL; -+} -+ -+uint8_t * ppstream_next (ppstream *stream, size_t *size) -+{ -+ iof *I; -+ if ((I = ppstream_iof(stream)) != NULL) -+ { -+ I->pos = I->end; -+ if ((*size = iof_input(I)) > 0) -+ return I->pos; -+ } -+ *size = 0; -+ return NULL; -+} -+ -+uint8_t * ppstream_all (ppstream *stream, size_t *size, int decode) -+{ -+ iof *I; -+ if ((I = ppstream_read(stream, decode, 1)) != NULL) -+ { -+ *size = (size_t)iof_left(I); -+ return I->pos; -+ } -+ *size = 0; -+ return NULL; -+} -+ -+void ppstream_done (ppstream *stream) -+{ -+ iof *I; -+ if ((I = ppstream_iof(stream)) != NULL) -+ { -+ iof_close(I); -+ stream->I = NULL; -+ } -+} -+ -+/* */ -+ -+void ppstream_init_buffers (void) -+{ -+ iof_filters_init(); -+} -+ -+void ppstream_free_buffers (void) -+{ -+ iof_filters_free(); -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppstream.h b/texk/web2c/luatexdir/luapplib/ppstream.h -new file mode 100644 -index 000000000..ae5c19cd9 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppstream.h -@@ -0,0 +1,9 @@ -+ -+#ifndef PP_STREAM_H -+#define PP_STREAM_H -+ -+ppstream * ppstream_create (ppdoc *pdf, ppdict *dict, size_t offset); -+iof * ppstream_read (ppstream *stream, int decode, int all); -+#define ppstream_iof(stream) ((iof *)((stream)->I)) -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/pptest1.c b/texk/web2c/luatexdir/luapplib/pptest1.c -new file mode 100644 -index 000000000..4671849f5 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/pptest1.c -@@ -0,0 +1,86 @@ -+ -+#include -+#include "ppapi.h" -+ -+static const char * sizenum (size_t s) -+{ -+ static char buffer[32]; -+ if (s < 1000) -+ sprintf(buffer, "%uB", (unsigned)s); -+ else if (s < 1000000) -+ sprintf(buffer, "%.2fkB", (double)(s) / 1000); -+ else -+ sprintf(buffer, "%.2fMB", (double)(s) / 1000000); -+ return buffer; -+} -+ -+static const char * crypt_info (ppdoc *pdf) -+{ -+ switch (ppdoc_crypt_status(pdf)) -+ { -+ case PPCRYPT_NONE: -+ return "none"; -+ case PPCRYPT_DONE: -+ return "empty password"; -+ case PPCRYPT_PASS: -+ return "nonempty password"; -+ default: -+ break; -+ } -+ return "this shouldn't happen"; -+} -+ -+static void print_info (ppdoc *pdf) -+{ -+ ppdict *info; -+ ppstring creator, producer; -+ size_t memused, memwaste; -+ -+ if ((info = ppdoc_info(pdf)) != NULL) -+ { -+ if ((creator = ppdict_rget_string(info, "Creator")) != NULL) -+ printf(" creator: %s\n", ppstring_decoded(creator)); -+ if ((producer = ppdict_rget_string(info, "Producer")) != NULL) -+ printf(" producer: %s\n", ppstring_decoded(producer)); -+ } -+ printf(" version: %s\n", ppdoc_version_string(pdf)); -+ printf(" protection: %s\n", crypt_info(pdf)); -+ printf(" filesize: %s\n", sizenum(ppdoc_file_size(pdf))); -+ printf(" objects: " PPUINTF "\n", ppdoc_objects(pdf)); -+ printf(" pagecount: " PPUINTF "\n", ppdoc_page_count(pdf)); -+ memused = ppdoc_memory(pdf, &memwaste); -+ printf(" memused: %s\n", sizenum(memused)); -+ printf(" memwaste: %s\n", sizenum(memwaste)); -+} -+ -+static int usage (const char *argv0) -+{ -+ printf("pplib " pplib_version ", " pplib_author "\n"); -+ printf("usage: %s file1.pdf file2.pdf ...\n", argv0); -+ return 0; -+} -+ -+int main (int argc, const char **argv) -+{ -+ const char *filepath; -+ int a; -+ ppdoc *pdf; -+ -+ if (argc < 2) -+ return usage(argv[0]); -+ for (a = 1; a < argc; ++a) -+ { -+ filepath = argv[a]; -+ printf("loading %s... ", filepath); -+ pdf = ppdoc_load(filepath); -+ if (pdf == NULL) -+ { -+ printf("failed\n"); -+ continue; -+ } -+ printf("done.\n"); -+ print_info(pdf); -+ ppdoc_free(pdf); -+ } -+ return 0; -+} -diff --git a/texk/web2c/luatexdir/luapplib/pptest2.c b/texk/web2c/luatexdir/luapplib/pptest2.c -new file mode 100644 -index 000000000..4b7f66a01 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/pptest2.c -@@ -0,0 +1,139 @@ -+ -+#include -+#include -+#include "ppapi.h" -+ -+static const char * get_file_name (const char *path) -+{ -+ const char *fn, *p; -+ for (fn = p = path; *p != '\0'; ++p) -+ if (*p == '\\' || *p == '/') -+ fn = p + 1; -+ return fn; -+} -+ -+static void box_info (ppdict *pagedict, FILE *fh) -+{ -+ const char *boxes[] = {"MediaBox", "CropBox", "BleedBox", "TrimBox", "ArtBox"}; -+ pprect rect; -+ size_t i; -+ for (i = 0; i < sizeof(boxes) / sizeof(const char *); ++i) -+ if (ppdict_get_box(pagedict, boxes[i], &rect)) -+ fprintf(fh, "%%%% %s [%f %f %f %f]\n", boxes[i], rect.lx, rect.ly, rect.rx, rect.ry); -+} -+ -+static int usage (const char *argv0) -+{ -+ printf("pplib " pplib_version ", " pplib_author "\n"); -+ printf("usage: %s file1.pdf file2.pdf ...\n", argv0); -+ return 0; -+} -+ -+#define OUTDIR "." -+ -+static void log_callback (const char *message, void *alien) -+{ -+ fprintf((FILE *)alien, "\nooops: %s\n", message); -+} -+ -+int main (int argc, const char **argv) -+{ -+ const char *filepath, *filename; -+ int a; -+ ppdoc *pdf; -+ ppref *pageref; -+ ppdict *pagedict; -+ int pageno; -+ char outname[1024]; -+ FILE *fh; -+ ppstream *stream; -+ uint8_t *data; -+ size_t size; -+ ppcontext *context; -+ ppobj *obj; -+ ppname op; -+ size_t operators; -+ -+ if (argc < 2) -+ return usage(argv[0]); -+ ppstream_init_buffers(); -+ pplog_callback(log_callback, stderr); -+ context = ppcontext_new(); -+ for (a = 1; a < argc; ++a) -+ { -+ filepath = argv[a]; -+ printf("loading %s... ", filepath); -+ pdf = ppdoc_load(filepath); -+ if (pdf == NULL) -+ { -+ printf("failed\n"); -+ continue; -+ } -+ printf("done.\n"); -+ switch (ppdoc_crypt_status(pdf)) -+ { -+ case PPCRYPT_NONE: -+ case PPCRYPT_DONE: -+ break; -+ case PPCRYPT_PASS: -+ if (ppdoc_crypt_pass(pdf, "dummy", 5, NULL, 0) == PPCRYPT_DONE || ppdoc_crypt_pass(pdf, NULL, 0, "dummy", 5) == PPCRYPT_DONE) -+ break; -+ printf("sorry, password needed\n"); -+ ppdoc_free(pdf); -+ continue; -+ case PPCRYPT_FAIL: -+ printf("sorry, encryption failed\n"); -+ ppdoc_free(pdf); -+ continue; -+ } -+ filename = get_file_name(filepath); -+ sprintf(outname, OUTDIR "/%s.out", filename); -+ fh = fopen(outname, "wb"); -+ if (fh == NULL) -+ { -+ printf("can't open %s for writing\n", outname); -+ continue; -+ } -+ for (pageref = ppdoc_first_page(pdf), pageno = 1; -+ pageref != NULL; -+ pageref = ppdoc_next_page(pdf), ++pageno) -+ { -+ pagedict = pageref->object.dict; -+ /* decompress contents data */ -+ fprintf(fh, "%%%% PAGE %d\n", pageno); -+ box_info(pagedict, fh); -+ for (stream = ppcontents_first(pagedict); -+ stream != NULL; -+ stream = ppcontents_next(pagedict, stream)) -+ { -+ for (data = ppstream_first(stream, &size, 1); -+ data != NULL; -+ data = ppstream_next(stream, &size)) -+ fwrite(data, size, 1, fh); -+ ppstream_done(stream); -+ } -+ /* now parse contents */ -+ for (stream = ppcontents_first(pagedict); -+ stream != NULL; -+ stream = ppcontents_next(pagedict, stream)) -+ { -+ operators = 0; -+ for (obj = ppcontents_first_op(context, stream, &size, &op); -+ obj != NULL; -+ obj = ppcontents_next_op(context, stream, &size, &op)) -+ ++operators; -+ fprintf(fh, "%%%% OPERATORS count " PPSIZEF "\n", operators); -+ ppstream_done(stream); -+ //obj = ppcontents_parse(context, stream, &size); -+ //fprintf(fh, "%%%% items count " PPSIZEF "\n", size); -+ fprintf(fh, "\n"); -+ } -+ ppcontext_done(context); -+ } -+ fclose(fh); -+ ppdoc_free(pdf); -+ } -+ ppcontext_free(context); -+ ppstream_free_buffers(); -+ return 0; -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppxref.c b/texk/web2c/luatexdir/luapplib/ppxref.c -new file mode 100644 -index 000000000..984f6cbe3 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppxref.c -@@ -0,0 +1,162 @@ -+ -+#include "pplib.h" -+ -+#define PPXREF_MAP_INIT 16 // number of xref sections -+ -+ppxref * ppxref_create (ppdoc *pdf, size_t initsize, size_t xrefoffset) -+{ -+ ppxref *xref; -+ -+ if (initsize == 0) // unknown -+ initsize = PPXREF_MAP_INIT; -+ xref = (ppxref *)ppheap_take(&pdf->heap, sizeof(ppxref) + initsize * sizeof(ppxsec)); -+ xref->sects = (ppxsec *)(xref + 1); -+ xref->size = 0; -+ xref->space = initsize; -+ xref->count = 0; -+ xref->trailer.type = PPNONE; -+ xref->trailer.dict = NULL; -+ xref->prev = NULL; -+ xref->pdf = pdf; -+ xref->offset = xrefoffset; -+ //xref->crypt = NULL; -+ return xref; -+} -+ -+ppxsec * ppxref_push_section (ppxref *xref, ppheap **pheap) -+{ -+ ppxsec *sects; -+ if (xref->size < xref->space) -+ return &xref->sects[xref->size++]; -+ xref->space <<= 1; -+ sects = xref->sects; -+ xref->sects = (ppxsec *)ppheap_take(pheap, xref->space * sizeof(ppxsec)); // waste but rare -+ memcpy(xref->sects, sects, xref->size * sizeof(ppxsec)); -+ return &xref->sects[xref->size++]; -+} -+ -+static void ppxref_sort_sects (ppxsec *left, ppxsec *right) -+{ -+ ppxsec *l, *r, *m, t; -+ ppuint first, last; -+ l = left, r = right, m = l + ((r - l) / 2); -+ first = m->first, last = m->last; -+ do -+ { // don't take first/last from pointer -+ while (l->first < first) ++l; -+ while (r->first > last) --r; -+ if (l <= r) -+ { -+ t = *l; -+ *l = *r; -+ *r = t; -+ ++l, --r; -+ } -+ } while (l <= r); -+ if (l < right) -+ ppxref_sort_sects(l, right); -+ if (r > left) -+ ppxref_sort_sects(left, r); -+} -+ -+int ppxref_sort (ppxref *xref) -+{ -+ if (xref->size == 0) -+ return 0; -+ ppxref_sort_sects(xref->sects, xref->sects + xref->size - 1); -+ return 1; -+} -+ -+ppref * ppxref_find_local (ppxref *xref, ppuint refnumber) -+{ -+ ppxsec *left, *right, *mid; -+ //if (xref->size == 0) // we don't allow that -+ // return NULL; -+ left = xref->sects; -+ right = xref->sects + xref->size - 1; -+ do -+ { -+ mid = left + ((right - left) / 2); -+ if (refnumber > mid->last) -+ left = mid + 1; -+ else if (refnumber < mid->first) -+ right = mid - 1; -+ else -+ return &mid->refs[refnumber - mid->first]; -+ } while (left <= right); -+ return NULL; -+} -+ -+ppref * ppxref_find (ppxref *xref, ppuint refnumber) -+{ -+ ppref *ref; -+ ppxref *other; -+ -+ if ((ref = ppxref_find_local(xref, refnumber)) != NULL) -+ return ref; -+ if (xref->pdf->flags & PPDOC_LINEARIZED) -+ { -+ for (other = xref->pdf->xref; other != NULL; other = other->prev) -+ if (other != xref && (ref = ppxref_find_local(other, refnumber)) != NULL) -+ return ref; -+ } -+ else -+ { -+ for (other = xref->prev; other != NULL; other = other->prev) -+ if ((ref = ppxref_find_local(other, refnumber)) != NULL) -+ return ref; -+ /* This shouldn't happen, but I've met documents that have no linearized dict, -+ but their xrefs are prepared as for linearized; with "older" xrefs referring -+ to "newer". */ -+ for (other = xref->pdf->xref; other != NULL && other != xref; other = other->prev) -+ if ((ref = ppxref_find_local(other, refnumber)) != NULL) -+ return ref; -+ } -+ return NULL; -+} -+ -+ppdict * ppxref_trailer (ppxref *xref) -+{ -+ switch (xref->trailer.type) -+ { -+ case PPDICT: -+ return xref->trailer.dict; -+ case PPSTREAM: -+ return xref->trailer.stream->dict; -+ default: -+ break; -+ } -+ return NULL; -+} -+ -+ppxref * ppdoc_xref (ppdoc *pdf) -+{ -+ return pdf->xref; -+} -+ -+ppxref * ppxref_prev (ppxref *xref) -+{ -+ return xref->prev; -+} -+ -+ppdict * ppxref_catalog (ppxref *xref) -+{ -+ ppdict *trailer; -+ return (trailer = ppxref_trailer(xref)) != NULL ? ppdict_rget_dict(trailer, "Root") : NULL; -+} -+ -+ppdict * ppxref_info (ppxref *xref) -+{ -+ ppdict *trailer; -+ return (trailer = ppxref_trailer(xref)) != NULL ? ppdict_rget_dict(trailer, "Info") : NULL; -+} -+ -+ppref * ppxref_pages (ppxref *xref) -+{ -+ ppdict *dict; -+ ppref *ref; -+ -+ if ((dict = ppxref_catalog(xref)) == NULL || (ref = ppdict_get_ref(dict, "Pages")) == NULL) -+ return NULL; -+ return ref->object.type == PPDICT ? ref : NULL; -+} -diff --git a/texk/web2c/luatexdir/luapplib/ppxref.h b/texk/web2c/luatexdir/luapplib/ppxref.h -new file mode 100644 -index 000000000..86ab98a51 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/ppxref.h -@@ -0,0 +1,35 @@ -+ -+#ifndef PP_XREF_H -+#define PP_XREF_H -+ -+/* -+What we call xref is actually "xref section" in PDF spec and what we call section is "xref subsection". -+Our ppxref is a list of sections, sorted by xrefsection->first and xrefsection->last bounds. Every section -+keeps a list of ppref *refs, enumerated from xrefsection->first to xrefsection->last. To find a reference -+by number we make a binary search over sections bounds, then jump to the proper ppref *ref. -+*/ -+ -+typedef struct { -+ ppuint first; // first reference number in section -+ ppuint last; // last reference number in section -+ ppref *refs; // references list -+} ppxsec; -+ -+struct ppxref { -+ ppxsec *sects; // subsections list -+ size_t size; // actual sections size -+ size_t space; // available sections space -+ ppobj trailer; // trailer dict or stream -+ ppuint count; // count of references in all sections -+ ppxref *prev; // previous xref -+ ppdoc *pdf; // parent pdf to access entries in linearized docs -+ size_t offset; // file offset of xref -+ //ppcrypt *crypt; // per xref encryption state? -+}; -+ -+ppxref * ppxref_create (ppdoc *pdf, size_t initsize, size_t xrefoffset); -+ppxsec * ppxref_push_section (ppxref *xref, ppheap **pheap); -+int ppxref_sort (ppxref *xref); -+ppref * ppxref_find_local (ppxref *xref, ppuint refnumber); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilbasexx.c b/texk/web2c/luatexdir/luapplib/util/utilbasexx.c -new file mode 100644 -index 000000000..6fdd6fb58 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilbasexx.c -@@ -0,0 +1,2108 @@ -+ -+#include "utilnumber.h" -+#include "utilmem.h" -+#include "utilbasexx.h" -+ -+/* filters state structs */ -+ -+struct basexx_state { -+ size_t line, maxline; -+ size_t left; -+ int tail[5]; -+ int flush; -+}; -+ -+struct runlength_state { -+ int run; -+ int flush; -+ int c1, c2; -+ uint8_t *pos; -+}; -+ -+struct eexec_state { -+ int key; -+ int flush; -+ int binary; -+ int c1; -+ size_t line, maxline; /* ascii encoder only */ -+ const char *initbytes; -+}; -+ -+/* config */ -+ -+#if defined(BASEXX_PDF) -+# define ignored(c) (c == 0x20 || c == 0x0A || c == 0x0C || c == 0x0D || c == 0x09 || c == 0x00) -+# define base16_eof(c) (c == '>' || c < 0) -+# define base85_eof(c) (c == '~' || c < 0) -+#else -+# define ignored(c) (c == 0x20 || c == 0x0A || c == 0x0D || c == 0x09) -+# define base16_eof(c) (c < 0) -+# define base85_eof(c) (c < 0) -+#endif -+ -+#define base64_eof(c) (c == '=' || c < 0) -+ -+#define basexx_nl '\x0A' -+#define put_nl(O, line, maxline, n) ((void)((line += n) > maxline && ((line = n), iof_set(O, basexx_nl)))) -+ -+/* tail macros */ -+ -+#define set_tail1(state, c1) (state->left = 1, state->tail[0] = c1) -+#define set_tail2(state, c1, c2) (state->left = 2, state->tail[0] = c1, state->tail[1] = c2) -+#define set_tail3(state, c1, c2, c3) (state->left = 3, state->tail[0] = c1, state->tail[1] = c2, state->tail[2] = c3) -+#define set_tail4(state, c1, c2, c3, c4) (state->left = 4, state->tail[0] = c1, state->tail[1] = c2, state->tail[2] = c3, state->tail[3] = c4) -+#define set_tail5(state, c1, c2, c3, c4, c5) \ -+ (state->left = 5, state->tail[0] = c1, state->tail[1] = c2, state->tail[2] = c3, state->tail[3] = c4, state->tail[4] = c5) -+ -+#define get_tail1(state, c1) (state->left = 0, c1 = state->tail[0]) -+#define get_tail2(state, c1, c2) (state->left = 0, c1 = state->tail[0], c2 = state->tail[1]) -+#define get_tail3(state, c1, c2, c3) (state->left = 0, c1 = state->tail[0], c2 = state->tail[1], c3 = state->tail[2]) -+#define get_tail4(state, c1, c2, c3, c4) (state->left = 0, c1 = state->tail[0], c2 = state->tail[1], c3 = state->tail[2], c4 = state->tail[3]) -+ -+/* basexx state initialization */ -+ -+void basexx_state_init_ln (basexx_state *state, size_t line, size_t maxline) -+{ -+ state->line = line; -+ state->maxline = maxline; -+ state->left = 0; -+ state->flush = 0; -+} -+ -+/* base 16; xxxx|xxxx */ -+ -+iof_status base16_encoded_uc (const void *data, size_t size, iof *O) -+{ -+ const uint8_t *s, *e; -+ for (s = (const uint8_t *)data, e = s + size; s < e; ++s) -+ { -+ if (!iof_ensure(O, 2)) -+ return IOFFULL; -+ iof_set_uc_hex(O, *s); -+ } -+ return IOFEOF; -+} -+ -+iof_status base16_encoded_lc (const void *data, size_t size, iof *O) -+{ -+ const uint8_t *s, *e; -+ for (s = (const uint8_t *)data, e = s + size; s < e; ++s) -+ { -+ if (!iof_ensure(O, 2)) -+ return IOFFULL; -+ iof_set_lc_hex(O, *s); -+ } -+ return IOFEOF; -+} -+ -+iof_status base16_encoded_uc_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline) -+{ -+ const uint8_t *s, *e; -+ for (s = (const uint8_t *)data, e = s + size; s < e; ++s) -+ { -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ put_nl(O, line, maxline, 2); -+ iof_set_uc_hex(O, *s); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encoded_lc_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline) -+{ -+ const uint8_t *s, *e; -+ for (s = (const uint8_t *)data, e = s + size; s < e; ++s) -+ { -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ put_nl(O, line, maxline, 2); -+ iof_set_lc_hex(O, *s); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_uc (iof *I, iof *O) -+{ -+ register int c; -+ while (iof_ensure(O, 2)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return IOFEOF; -+ iof_set_uc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_state_uc (iof *I, iof *O, basexx_state *state) -+{ -+ register int c; -+ while (iof_ensure(O, 2)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ iof_set_uc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_lc (iof *I, iof *O) -+{ -+ register int c; -+ while (iof_ensure(O, 2)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return IOFEOF; -+ iof_set_lc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_state_lc (iof *I, iof *O, basexx_state *state) -+{ -+ register int c; -+ while (iof_ensure(O, 2)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ iof_set_lc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_uc_ln (iof *I, iof *O, size_t line, size_t maxline) -+{ -+ register int c; -+ while (iof_ensure(O, 3)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return IOFEOF; -+ put_nl(O, line, maxline, 2); -+ iof_set_uc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_state_uc_ln (iof *I, iof *O, basexx_state *state) -+{ -+ register int c; -+ while (iof_ensure(O, 3)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ put_nl(O, state->line, state->maxline, 2); -+ iof_set_uc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_lc_ln (iof *I, iof *O, size_t line, size_t maxline) -+{ -+ register int c; -+ while (iof_ensure(O, 3)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return IOFEOF; -+ put_nl(O, line, maxline, 2); -+ iof_set_lc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_encode_state_lc_ln (iof *I, iof *O, basexx_state *state) -+{ -+ register int c; -+ while (iof_ensure(O, 3)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ put_nl(O, state->line, state->maxline, 2); -+ iof_set_lc_hex(O, c); -+ } -+ return IOFFULL; -+} -+ -+int base16_getc (iof *I) -+{ -+ register int c1, c2; -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base16_eof(c1)) -+ return IOFEOF; -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base16_eof(c2)) -+ { -+ if ((c1 = base16_lookup[c1]) == -1) -+ return IOFERR; -+ return c1<<4; -+ } -+ if ((c1 = base16_lookup[c1]) == -1 || (c2 = base16_lookup[c2]) == -1) -+ return IOFERR; -+ return (c1<<4)|c2; -+} -+ -+int base16_lc_putc (iof *O, int c) -+{ -+ if (iof_ensure(O, 2)) -+ iof_set_lc_hex(O, c); -+ return IOFFULL; -+} -+ -+int base16_uc_putc (iof *O, int c) -+{ -+ if (iof_ensure(O, 2)) -+ iof_set_uc_hex(O, c); -+ return IOFFULL; -+} -+ -+ -+iof_status base16_decode (iof *I, iof *O) -+{ -+ register int c1, c2; -+ while (iof_ensure(O, 1)) -+ { -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base16_eof(c1)) -+ return IOFEOF; -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base16_eof(c2)) -+ { -+ if ((c1 = base16_lookup[c1]) == -1) -+ return IOFERR; -+ iof_set(O, c1<<4); // c2 := '0' -+ return IOFEOF; -+ } -+ if ((c1 = base16_lookup[c1]) == -1 || (c2 = base16_lookup[c2]) == -1) -+ return IOFERR; -+ iof_set(O, (c1<<4)|c2); -+ } -+ return IOFFULL; -+} -+ -+iof_status base16_decode_state (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, d1, d2; -+ if (!(iof_ensure(O, 1))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ } -+ while (iof_ensure(O, 1)) -+ { -+ byte0: -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base16_eof(c1)) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base16_eof(c2)) -+ { -+ set_tail1(state, c1); /* set tail to let the caller display invalid chars */ -+ if (state->flush) -+ { -+ if ((c1 = base16_lookup[c1]) == -1) -+ return IOFERR; -+ iof_set(O, c1<<4); // c2 := '0' -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ if ((d1 = base16_lookup[c1]) == -1 || (d2 = base16_lookup[c2]) == -1) -+ { -+ set_tail2(state, c1, c2); -+ return IOFERR; -+ } -+ iof_set(O, (d1<<4)|d2); -+ } -+ return IOFFULL; -+} -+ -+/* base 64; xxxxxx|xx xxxx|xxxx xx|xxxxxx */ -+ -+const char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -+ -+const int base64_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, -+ 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, -+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,9 ,10,11,12,13,14, -+ 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, -+ -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, -+ 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+#define base64_digit1(c1) base64_alphabet[c1>>2] -+#define base64_digit2(c1, c2) base64_alphabet[((c1&3)<<4)|(c2>>4)] -+#define base64_digit3(c2, c3) base64_alphabet[((c2&15)<<2)|(c3>>6)] -+#define base64_digit4(c3) base64_alphabet[c3&63] -+ -+#define base64_encode_word(O, c1, c2, c3) \ -+ iof_set4(O, base64_digit1(c1), base64_digit2(c1, c2), base64_digit3(c2, c3), base64_digit4(c3)) -+ -+#define base64_encode_tail2(O, c1, c2) \ -+ iof_set3(O, base64_digit1(c1), base64_digit2(c1, c2), base64_digit3(c2, 0)) -+ -+#define base64_encode_tail1(O, c1) \ -+ iof_set2(O, base64_digit1(c1), base64_digit2(c1, 0)) -+ -+iof_status base64_encoded (const void *data, size_t size, iof *O) -+{ -+ const uint8_t *s, *e; -+ uint8_t c1, c2, c3; -+ for (s = (const uint8_t *)data, e = s + size; s + 2 < e; ) -+ { -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s++; -+ base64_encode_word(O, c1, c2, c3); -+ } -+ switch (e - s) -+ { -+ case 0: -+ break; -+ case 1: -+ if (!iof_ensure(O, 2)) -+ return IOFFULL; -+ c1 = *s; -+ base64_encode_tail1(O, c1); -+ break; -+ case 2: -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s; -+ base64_encode_tail2(O, c1, c2); -+ break; -+ } -+ return IOFEOF; -+} -+ -+iof_status base64_encoded_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline) -+{ -+ const uint8_t *s, *e; -+ uint8_t c1, c2, c3; -+ for (s = (const uint8_t *)data, e = s + size; s + 2 < e; ) -+ { -+ if (!iof_ensure(O, 5)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s++; -+ put_nl(O, line, maxline, 4); -+ base64_encode_word(O, c1, c2, c3); -+ } -+ switch (e - s) -+ { -+ case 0: -+ break; -+ case 1: -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ c1 = *s; -+ put_nl(O, line, maxline, 2); -+ base64_encode_tail1(O, c1); -+ break; -+ case 2: -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s; -+ put_nl(O, line, maxline, 3); -+ base64_encode_tail2(O, c1, c2); -+ break; -+ } -+ return IOFEOF; -+} -+ -+iof_status base64_encode (iof *I, iof *O) -+{ -+ register int c1, c2, c3; -+ while(iof_ensure(O, 4)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return IOFEOF; -+ if ((c2 = iof_get(I)) < 0) -+ { -+ base64_encode_tail1(O, c1); -+ return IOFEOF; -+ } -+ if ((c3 = iof_get(I)) < 0) -+ { -+ base64_encode_tail2(O, c1, c2); -+ return IOFEOF; -+ } -+ base64_encode_word(O, c1, c2, c3); -+ } -+ return IOFFULL; -+} -+ -+iof_status base64_encode_state (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3; -+ if (!(iof_ensure(O, 4))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ } -+ while(iof_ensure(O, 4)) -+ { -+ byte0: -+ if ((c1 = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ if ((c2 = iof_get(I)) < 0) -+ return (state->flush ? (base64_encode_tail1(O, c1), IOFEOF) : (set_tail1(state, c1), IOFEMPTY)); -+ byte2: -+ if ((c3 = iof_get(I)) < 0) -+ return (state->flush ? (base64_encode_tail2(O, c1, c2), IOFEOF) : (set_tail2(state, c1, c2), IOFEMPTY)); -+ base64_encode_word(O, c1, c2, c3); -+ } -+ return IOFFULL; -+} -+ -+iof_status base64_encode_ln (iof *I, iof *O, size_t line, size_t maxline) -+{ -+ register int c1, c2, c3; -+ while(iof_ensure(O, 5)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return IOFEOF; -+ if ((c2 = iof_get(I)) < 0) -+ { -+ put_nl(O, line, maxline, 2); -+ base64_encode_tail1(O, c1); -+ return IOFEOF; -+ } -+ if ((c3 = iof_get(I)) < 0) -+ { -+ put_nl(O, line, maxline, 3); -+ base64_encode_tail2(O, c1, c2); -+ return IOFEOF; -+ } -+ put_nl(O, line, maxline, 4); -+ base64_encode_word(O, c1, c2, c3); -+ } -+ return IOFFULL; -+} -+ -+iof_status base64_encode_state_ln (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3; -+ if (!(iof_ensure(O, 5))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ } -+ while(iof_ensure(O, 5)) -+ { -+ byte0: -+ if ((c1 = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ if ((c2 = iof_get(I)) < 0) -+ return (state->flush ? (put_nl(O, state->line, state->maxline, 2), base64_encode_tail1(O, c1), IOFEOF) : (set_tail1(state, c1), IOFEMPTY)); -+ byte2: -+ if ((c3 = iof_get(I)) < 0) -+ return (state->flush ? (put_nl(O, state->line, state->maxline, 3), base64_encode_tail2(O, c1, c2), IOFEOF) : (set_tail2(state, c1, c2), IOFEMPTY)); -+ put_nl(O, state->line, state->maxline, 4); -+ base64_encode_word(O, c1, c2, c3); -+ } -+ return IOFFULL; -+} -+ -+// #define base64_code(c1, c2, c3, c4) ((c1<<18)|(c2<<12)|(c3<<6)|c4) -+ -+#define base64_decode_word(O, c1, c2, c3, c4) \ -+ iof_set3(O, (c1<<2)|(c2>>4), ((c2&15)<<4)|(c3>>2), ((c3&3)<<6)|c4) -+ -+#define base64_decode_tail3(O, c1, c2, c3) \ -+ iof_set2(O, (c1<<2)|(c2>>4), ((c2&15)<<4)|(c3>>2)) -+ -+#define base64_decode_tail2(O, c1, c2) \ -+ iof_set(O, (c1<<2)|(c2>>4)) -+ -+iof_status base64_decode (iof *I, iof *O) -+{ -+ register int c1, c2, c3, c4; -+ while(iof_ensure(O, 3)) -+ { -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base64_eof(c1)) -+ return IOFEOF; -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base64_eof(c2)) -+ return IOFERR; -+ do { c3 = iof_get(I); } while (ignored(c3)); -+ if (base64_eof(c3)) -+ { -+ if ((c1 = base64_lookup[c1]) == -1 || (c2 = base64_lookup[c2]) == -1) -+ return IOFERR; -+ base64_decode_tail2(O, c1, c2); -+ return IOFEOF; -+ } -+ do { c4 = iof_get(I); } while (ignored(c4)); -+ if (base64_eof(c4)) -+ { -+ if ((c1 = base64_lookup[c1]) == -1 || (c2 = base64_lookup[c2]) == -1 || (c3 = base64_lookup[c3]) == -1) -+ return IOFERR; -+ base64_decode_tail3(O, c1, c2, c3); -+ return IOFEOF; -+ } -+ if ((c1 = base64_lookup[c1]) == -1 || (c2 = base64_lookup[c2]) == -1 || -+ (c3 = base64_lookup[c3]) == -1 || (c4 = base64_lookup[c4]) == -1) -+ return IOFERR; -+ base64_decode_word(O, c1, c2, c3, c4); -+ } -+ return IOFFULL; -+} -+ -+iof_status base64_decode_state (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3, c4; -+ register int d1, d2, d3, d4; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ case 3: get_tail3(state, c1, c2, c3); goto byte3; -+ } -+ while(iof_ensure(O, 3)) -+ { -+ byte0: -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base64_eof(c1)) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base64_eof(c2)) -+ { -+ set_tail1(state, c1); /* set tail to let the caller make padding or display invalid char in case of error */ -+ return (state->flush ? IOFERR : IOFEMPTY); /* if state->flush then error; tail must have at least two bytes */ -+ } -+ byte2: -+ do { c3 = iof_get(I); } while (ignored(c3)); -+ if (base64_eof(c3)) -+ { -+ set_tail2(state, c1, c2); -+ if (state->flush) -+ { -+ if ((c1 = base64_lookup[c1]) == -1 || (c2 = base64_lookup[c2]) == -1) -+ return IOFERR; -+ base64_decode_tail2(O, c1, c2); -+ return IOFEOF; -+ } -+ else -+ return IOFEMPTY; -+ } -+ byte3: -+ do { c4 = iof_get(I); } while (ignored(c4)); -+ if (base64_eof(c4)) -+ { -+ set_tail3(state, c1, c2, c3); -+ if (state->flush) -+ { -+ if ((c1 = base64_lookup[c1]) == -1 || (c2 = base64_lookup[c2]) == -1 || (c3 = base64_lookup[c3]) == -1) -+ return IOFERR; -+ base64_decode_tail3(O, c1, c2, c3); -+ return IOFEOF; -+ } -+ else -+ return IOFEMPTY; -+ } -+ if ((d1 = base64_lookup[c1]) == -1 || (d2 = base64_lookup[c2]) == -1 || -+ (d3 = base64_lookup[c3]) == -1 || (d4 = base64_lookup[c4]) == -1) -+ { -+ set_tail4(state, c1, c2, c3, c4); -+ return IOFERR; -+ } -+ base64_decode_word(O, d1, d2, d3, d4); -+ } -+ return IOFFULL; -+} -+ -+/* base85 */ -+ -+const char base85_alphabet[] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"; /* for completness, not used below */ -+ -+const int base85_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, -+ 15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, -+ 31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46, -+ 47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62, -+ 63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78, -+ 79,80,81,82,83,84,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+#define base85_encode_word(O, code) \ -+ (*(O->pos+4) = '!' + code%85, code /= 85, *(O->pos+3) = '!' + code%85, code /= 85, \ -+ *(O->pos+2) = '!' + code%85, code /= 85, *(O->pos+1) = '!' + code%85, code /= 85, \ -+ *(O->pos) = '!' + code, \ -+ O->pos += 5) -+ -+#define base85_encode_tail3(O, code) \ -+ (*(O->pos+3) = '!' + code%85, code /= 85, *(O->pos+2) = '!' + code%85, code /= 85, \ -+ *(O->pos+1) = '!' + code%85, code /= 85, *(O->pos) = '!' + code, \ -+ O->pos += 4) -+ -+#define base85_encode_tail2(O, code) \ -+ (*(O->pos+2) = '!' + code%85, code /= 85, *(O->pos+1) = '!' + code%85, code /= 85, \ -+ *(O->pos) = '!' + code, \ -+ O->pos += 3) -+ -+#define base85_encode_tail1(O, code) \ -+ (*(O->pos+1) = '!' + code%85, code /= 85, *(O->pos) = '!' + code, \ -+ O->pos += 2) -+ -+iof_status base85_encoded (const void *data, size_t size, iof *O) -+{ -+ unsigned int code; -+ const uint8_t *s, *e; -+ uint8_t c1, c2, c3, c4; -+ for (s = (const uint8_t *)data, e = s + size; s + 3 < e; ) -+ { -+ if (!iof_ensure(O, 5)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s++; -+ c4 = *s++; -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ iof_set(O, 'z'); -+ continue; -+ } -+ base85_encode_word(O, code); -+ } -+ switch (e - s) -+ { -+ case 0: -+ break; -+ case 1: -+ if (!iof_ensure(O, 2)) -+ return IOFFULL; -+ c1 = *s; -+ code = (c1<<24)/85/85/85; -+ base85_encode_tail1(O, code); -+ break; -+ case 2: -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s; -+ code = ((c1<<24)|(c2<<16))/85/85; -+ base85_encode_tail2(O, code); -+ break; -+ case 3: -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s; -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ base85_encode_tail3(O, code); -+ break; -+ } -+ return IOFEOF; -+} -+ -+iof_status base85_encoded_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline) -+{ -+ unsigned int code; -+ const uint8_t *s, *e; -+ uint8_t c1, c2, c3, c4; -+ for (s = (const uint8_t *)data, e = s + size; s + 3 < e; ) -+ { -+ if (!iof_ensure(O, 6)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s++; -+ c4 = *s++; -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ put_nl(O, line, maxline, 1); -+ iof_set(O, 'z'); -+ continue; -+ } -+ put_nl(O, line, maxline, 5); -+ base85_encode_word(O, code); -+ } -+ switch (e - s) -+ { -+ case 0: -+ break; -+ case 1: -+ if (!iof_ensure(O, 3)) -+ return IOFFULL; -+ c1 = *s; -+ code = (c1<<24)/85/85/85; -+ put_nl(O, line, maxline, 2); -+ base85_encode_tail1(O, code); -+ break; -+ case 2: -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s; -+ code = ((c1<<24)|(c2<<16))/85/85; -+ put_nl(O, line, maxline, 3); -+ base85_encode_tail2(O, code); -+ break; -+ case 3: -+ if (!iof_ensure(O, 5)) -+ return IOFFULL; -+ c1 = *s++; -+ c2 = *s++; -+ c3 = *s; -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ put_nl(O, line, maxline, 4); -+ base85_encode_tail3(O, code); -+ break; -+ } -+ return IOFEOF; -+} -+ -+iof_status base85_encode (iof *I, iof *O) -+{ -+ register int c1, c2, c3, c4; -+ register unsigned int code; -+ while(iof_ensure(O, 5)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return IOFEOF; -+ if ((c2 = iof_get(I)) < 0) -+ { -+ code = (c1<<24)/85/85/85; -+ base85_encode_tail1(O, code); -+ return IOFEOF; -+ } -+ if ((c3 = iof_get(I)) < 0) -+ { -+ code = ((c1<<24)|(c2<<16))/85/85; -+ base85_encode_tail2(O, code); -+ return IOFEOF; -+ } -+ if ((c4 = iof_get(I)) < 0) -+ { -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ base85_encode_tail3(O, code); -+ return IOFEOF; -+ } -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ iof_set(O, 'z'); -+ continue; -+ } -+ /* in btoa 'y' character stays for 0x20202020, but pdf does not support this */ -+ /* if (code == 0x20202020) -+ { -+ iof_set(O, 'y'); -+ continue; -+ } */ -+ base85_encode_word(O, code); -+ } -+ return IOFFULL; -+} -+ -+iof_status base85_encode_state (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3, c4; -+ register unsigned int code; -+ if (!(iof_ensure(O, 5))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ case 3: get_tail3(state, c1, c2, c3); goto byte3; -+ } -+ while(iof_ensure(O, 5)) -+ { -+ byte0: -+ if ((c1 = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ if ((c2 = iof_get(I)) < 0) -+ { -+ set_tail1(state, c1); -+ if (state->flush) -+ { -+ code = (c1<<24)/85/85/85; -+ base85_encode_tail1(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte2: -+ if ((c3 = iof_get(I)) < 0) -+ { -+ set_tail2(state, c1, c2); -+ if (state->flush) -+ { -+ code = ((c1<<24)|(c2<<16))/85/85; -+ base85_encode_tail2(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte3: -+ if ((c4 = iof_get(I)) < 0) -+ { -+ set_tail3(state, c1, c2, c3); -+ if (state->flush) -+ { -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ base85_encode_tail3(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ iof_set(O, 'z'); -+ continue; -+ } -+ base85_encode_word(O, code); -+ } -+ return IOFFULL; -+} -+ -+iof_status base85_encode_ln (iof *I, iof *O, size_t line, size_t maxline) -+{ -+ register int c1, c2, c3, c4; -+ register unsigned int code; -+ while(iof_ensure(O, 6)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return IOFEOF; -+ if ((c2 = iof_get(I)) < 0) -+ { -+ code = (c1<<24)/85/85/85; -+ put_nl(O, line, maxline, 2); -+ base85_encode_tail1(O, code); -+ return IOFEOF; -+ } -+ if ((c3 = iof_get(I)) < 0) -+ { -+ code = ((c1<<24)|(c2<<16))/85/85; -+ put_nl(O, line, maxline, 3); -+ base85_encode_tail2(O, code); -+ return IOFEOF; -+ } -+ if ((c4 = iof_get(I)) < 0) -+ { -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ put_nl(O, line, maxline, 4); -+ base85_encode_tail3(O, code); -+ return IOFEOF; -+ } -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ put_nl(O, line, maxline, 1); -+ iof_set(O, 'z'); -+ continue; -+ } -+ put_nl(O, line, maxline, 5); -+ base85_encode_word(O, code); -+ } -+ return IOFFULL; -+} -+ -+iof_status base85_encode_state_ln (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3, c4; -+ register unsigned int code; -+ if (!(iof_ensure(O, 6))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ case 3: get_tail3(state, c1, c2, c3); goto byte3; -+ } -+ while(iof_ensure(O, 6)) -+ { -+ byte0: -+ if ((c1 = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ byte1: -+ if ((c2 = iof_get(I)) < 0) -+ { -+ set_tail1(state, c1); -+ if (state->flush) -+ { -+ code = (c1<<24)/85/85/85; -+ put_nl(O, state->line, state->maxline, 2); -+ base85_encode_tail1(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte2: -+ if ((c3 = iof_get(I)) < 0) -+ { -+ set_tail2(state, c1, c2); -+ if (state->flush) -+ { -+ code = ((c1<<24)|(c2<<16))/85/85; -+ put_nl(O, state->line, state->maxline, 3); -+ base85_encode_tail2(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte3: -+ if ((c4 = iof_get(I)) < 0) -+ { -+ set_tail3(state, c1, c2, c3); -+ if (state->flush) -+ { -+ code = ((c1<<24)|(c2<<16)|(c3<<8))/85; -+ put_nl(O, state->line, state->maxline, 4); -+ base85_encode_tail3(O, code); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ code = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ if (code == 0) -+ { -+ put_nl(O, state->line, state->maxline, 1); -+ iof_set(O, 'z'); -+ continue; -+ } -+ put_nl(O, state->line, state->maxline, 5); -+ base85_encode_word(O, code); -+ } -+ return IOFFULL; -+} -+ -+#define base85_code(c1, c2, c3, c4, c5) ((((c1*85+c2)*85+c3)*85+c4)*85+c5) -+ -+iof_status base85_decode (iof *I, iof *O) -+{ -+ register int c1, c2, c3, c4, c5; -+ register unsigned int code; -+ while (iof_ensure(O, 4)) -+ { -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base85_eof(c1)) -+ return IOFEOF; -+ switch (c1) -+ { -+ case 'z': -+ iof_set4(O, '\0', '\0', '\0', '\0'); -+ continue; -+ case 'y': -+ iof_set4(O, ' ', ' ', ' ', ' '); -+ continue; -+ } -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base85_eof(c2)) -+ return IOFERR; -+ do { c3 = iof_get(I); } while (ignored(c3)); -+ if (base85_eof(c3)) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, 84, 84, 84); /* padding with 'u' (117); 117-33 = 84 */ -+ iof_set(O, code>>24); -+ return IOFEOF; -+ } -+ do { c4 = iof_get(I); } while (ignored(c4)); -+ if (base85_eof(c4)) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1 || (c3 = base85_lookup[c3]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, c3, 84, 84); -+ iof_set2(O, code>>24, (code>>16)&255); -+ return IOFEOF; -+ } -+ do { c5 = iof_get(I); } while (ignored(c5)); -+ if (base85_eof(c5)) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1 || -+ (c3 = base85_lookup[c3]) == -1 || (c4 = base85_lookup[c4]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, c3, c4, 84); -+ iof_set3(O, code>>24, (code>>16)&255, (code>>8)&255); -+ return IOFEOF; -+ } -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1 || (c3 = base85_lookup[c3]) == -1 || -+ (c4 = base85_lookup[c4]) == -1 || (c5 = base85_lookup[c5]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, c3, c4, c5); -+ iof_set4(O, code>>24, (code>>16)&255, (code>>8)&255, code&255); -+ } -+ return IOFFULL; -+} -+ -+iof_status base85_decode_state (iof *I, iof *O, basexx_state *state) -+{ -+ register int c1, c2, c3, c4, c5; -+ register int d1, d2, d3, d4, d5; -+ register unsigned int code; -+ if (!(iof_ensure(O, 4))) -+ return IOFFULL; -+ switch(state->left) -+ { -+ case 0: goto byte0; -+ case 1: get_tail1(state, c1); goto byte1; -+ case 2: get_tail2(state, c1, c2); goto byte2; -+ case 3: get_tail3(state, c1, c2, c3); goto byte3; -+ case 4: get_tail4(state, c1, c2, c3, c4); goto byte4; -+ } -+ while (iof_ensure(O, 4)) -+ { -+ byte0: -+ do { c1 = iof_get(I); } while (ignored(c1)); -+ if (base85_eof(c1)) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ switch (c1) -+ { -+ case 'z': -+ iof_set4(O, '\0', '\0', '\0', '\0'); -+ continue; -+ case 'y': -+ iof_set4(O, ' ', ' ', ' ', ' '); -+ continue; -+ } -+ byte1: -+ do { c2 = iof_get(I); } while (ignored(c2)); -+ if (base85_eof(c2)) -+ { -+ set_tail1(state, c1); -+ return (state->flush ? IOFERR : IOFEMPTY); /* if state->flush then error; tail must have at least two bytes */ -+ } -+ byte2: -+ do { c3 = iof_get(I); } while (ignored(c3)); -+ if (base85_eof(c3)) -+ { -+ set_tail2(state, c1, c2); -+ if (state->flush) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, 84, 84, 84); -+ iof_set(O, code>>24); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte3: -+ do { c4 = iof_get(I); } while (ignored(c4)); -+ if (base85_eof(c4)) -+ { -+ set_tail3(state, c1, c2, c3); -+ if (state->flush) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1 || (c3 = base85_lookup[c3]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, c3, 84, 84); -+ iof_set2(O, code>>24, (code>>16)&255); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ byte4: -+ do { c5 = iof_get(I); } while (ignored(c5)); -+ if (base85_eof(c5)) -+ { -+ set_tail4(state, c1, c2, c3, c4); -+ if (state->flush) -+ { -+ if ((c1 = base85_lookup[c1]) == -1 || (c2 = base85_lookup[c2]) == -1 || -+ (c3 = base85_lookup[c3]) == -1 || (c4 = base85_lookup[c4]) == -1) -+ return IOFERR; -+ code = base85_code(c1, c2, c3, c4, 84); -+ iof_set3(O, code>>24, (code>>16)&255, (code>>8)&255); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+ } -+ if ((d1 = base85_lookup[c1]) == -1 || (d2 = base85_lookup[c2]) == -1 || (d3 = base85_lookup[c3]) == -1 || -+ (d4 = base85_lookup[c4]) == -1 || (d5 = base85_lookup[c5]) == -1) -+ { -+ set_tail5(state, c1, c2, c3, c4, c5); -+ return IOFERR; -+ } -+ code = base85_code(d1, d2, d3, d4, d5); -+ iof_set4(O, code>>24, (code>>16)&255, (code>>8)&255, code&255); -+ } -+ return IOFFULL; -+} -+ -+/* postscript run length */ -+ -+void runlength_state_init (runlength_state *state) -+{ -+ state->run = -1; -+ state->flush = 0; -+ state->c1 = 0; -+ state->c2 = 0; -+ state->pos = NULL; -+} -+ -+iof_status runlength_encode (iof *I, iof *O) -+{ -+ register int c1, c2, run = -1; -+ uint8_t *pos; -+ c1 = 0; /* avoid warning */ -+ while (iof_ensure(O, 1+128+1)) -+ { /* ensured space for single length byte, up to 128 bytes to be copied, possible eod marker */ -+ pos = O->pos++; -+ switch (run) -+ { -+ case -1: /* initial state; get first byte */ -+ if ((c1 = iof_get(I)) < 0) -+ return (*pos = 128, IOFEOF); -+ run = 0; -+ // fall through -+ case 0: /* `repeat' state; get another byte and compare */ -+ if ((c2 = iof_get(I)) < 0) -+ return (*pos = 0, iof_set2(O, c1, 128), IOFEOF); -+ run = (c1 == c2 ? 257-2 : 0); -+ break; -+ } -+ if (run < 128) -+ { /* single length byte, up to 128 bytes to be copied, possible eod marker */ -+ iof_set(O, c1); -+ for (c1 = c2, c2 = iof_char(I); c1 != c2 && run < 127; c1 = c2, c2 = iof_next(I)) -+ { -+ if (c2 < 0) /* O->pos must not change until next call to calling encoder!!! */ -+ return (*pos = (uint8_t)run+1, iof_set2(O, c1, 128), IOFEOF); -+ iof_set(O, c1); -+ ++run; -+ } -+ } -+ else // if run > 128 -+ { -+ for (c2 = iof_get(I); c1 == c2 && run > 129; c2 = iof_get(I)) -+ --run; -+ if (c2 < 0) -+ return (*pos = (uint8_t)run, iof_set2(O, c1, 128), IOFEOF); -+ iof_set(O, c1); -+ } -+ *pos = (uint8_t)run; -+ c1 = c2; -+ run = 0; -+ } -+ return IOFFULL; -+} -+ -+iof_status runlength_encode_state (iof *I, iof *O, runlength_state *state) -+{ -+ while (iof_ensure(O, 3)) /* single length byte, the byte to be repeated and eod */ -+ { -+ state->pos = O->pos++; -+ switch (state->run) -+ { -+ case -1: /* initial state; get first byte */ -+ if ((state->c1 = iof_get(I)) < 0) -+ return (state->flush ? (*state->pos = 128, IOFEOF) : IOFEMPTY); -+ state->run = 0; -+ // fall through -+ case 0: /* `repeat' state; get another byte and compare */ -+ if ((state->c2 = iof_get(I)) < 0) -+ return (state->flush ? (*state->pos = 0, iof_set2(O, state->c1, 128), IOFEOF) : IOFEMPTY); -+ state->run = (state->c1 == state->c2 ? 257-2 : 0); -+ break; -+ } -+ if (state->run < 128) -+ { /* ensure space for single length byte, up to 128 bytes to be copied, plus possible eod marker, minus those already copied */ -+ if (!iof_ensure(O, 1+128+1-state->run)) -+ return IOFFULL; -+ iof_set(O, state->c1); -+ for (state->c1 = state->c2, state->c2 = iof_char(I); -+ state->c1 != state->c2 && state->run < 127; -+ state->c1 = state->c2, state->c2 = iof_next(I)) -+ { -+ if (state->c2 < 0) /* O->pos must not change until next call to calling encoder!!! */ -+ return (state->flush ? (*state->pos = (uint8_t)state->run+1, iof_set2(O, state->c1, 128), IOFEOF) : IOFEMPTY); -+ iof_set(O, state->c1); -+ ++state->run; -+ } -+ } -+ else // if run > 128 -+ { -+ for (state->c2 = iof_get(I); state->c1 == state->c2 && state->run > 129; state->c2 = iof_get(I)) -+ --state->run; -+ if (state->c2 < 0) -+ return (state->flush ? (*state->pos = (uint8_t)state->run, iof_set2(O, state->c1, 128), IOFEOF) : IOFEMPTY); -+ iof_set(O, state->c1); -+ } -+ *state->pos = (uint8_t)state->run; -+ state->c1 = state->c2; -+ state->run = 0; -+ } -+ return IOFFULL; -+} -+ -+iof_status runlength_decode (iof *I, iof *O) -+{ -+ register int c, run = -1; -+ while (1) -+ { -+ if (run == -1) /* initial state */ -+ { -+ if ((run = iof_get(I)) < 0) -+ { -+ run = -1; /* don't assume IOFEOF == -1 */ -+ return IOFEOF; -+ } -+ } -+ if (run < 128) -+ { /* copy (run + 1) following bytes */ -+ while (run > -1) -+ { -+ if (iof_ensure(O, 1)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return IOFERR; -+ iof_set(O, c); -+ --run; -+ continue; -+ } -+ return IOFFULL; -+ } -+ } -+ else if (run > 128) -+ { /* replicate the following byte (257 - run) times */ -+ if ((c = iof_get(I)) < 0) /* cf. state-wise version; don't change input position until we got this byte */ -+ return IOFERR; -+ while (run < 257) -+ { -+ if (iof_ensure(O, 1)) -+ { -+ iof_set(O, c); -+ ++run; -+ continue; -+ } -+ return IOFFULL; -+ } -+ run = -1; -+ } -+ else // c == 128 -+ return IOFEOF; -+ } -+ // return IOFFULL; -+} -+ -+iof_status runlength_decode_state (iof *I, iof *O, runlength_state *state) -+{ -+ register int c; -+ while (1) -+ { -+ if (state->run == -1) /* initial state */ -+ { -+ if ((state->run = iof_char(I)) < 0) -+ { -+ state->run = -1; /* don't assume IOFEOF == -1 */ -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ } -+ ++I->pos; -+ } -+ if (state->run < 128) -+ { /* copy (state->run + 1) following bytes */ -+ while (state->run > -1) -+ { -+ if (iof_ensure(O, 1)) -+ { -+ if ((c = iof_char(I)) < 0) -+ return (state->flush ? IOFERR : IOFEMPTY); -+ ++I->pos; -+ iof_set(O, c); -+ --state->run; -+ continue; -+ } -+ return IOFFULL; -+ } -+ } -+ else if (state->run > 128) -+ { /* replicate the following byte (257 - state->run) times */ -+ if ((c = iof_char(I)) < 0) -+ return (state->flush ? IOFERR : IOFEMPTY); -+ ++I->pos; -+ while (state->run < 257) -+ { -+ if (iof_ensure(O, 1)) -+ { -+ iof_set(O, c); -+ ++state->run; -+ continue; -+ } -+ return IOFFULL; -+ } -+ state->run = -1; -+ } -+ else // c == 128 -+ return IOFEOF; -+ } -+ // return IOFFULL; -+} -+ -+/* eexec stream filter, type1 fonts spec page 63 */ -+ -+void eexec_state_init_ln (eexec_state *state, size_t line, size_t maxline, const char *initbytes) -+{ -+ state->key = -1; -+ state->flush = 0; -+ state->binary = maxline > 0; -+ state->c1 = -1; -+ state->line = line; -+ state->maxline = maxline; -+ state->initbytes = initbytes; -+} -+ -+#define eexec_getc(I, c1) if ((c1 = iof_get(I)) < 0) return c1 -+#define eexec_key(key, c1) (key = ((((c1) + key)*52845 + 22719) & 65535)) -+#define eexec_decipher(key, c1, c) (c = ((c1)^(key>>8)), eexec_key(key, c1)) -+#define eexec_encipher(key, c1, c) (c = ((c1)^(key>>8)), eexec_key(key, c)) -+ -+#ifndef lps_ignored_char -+# define lps_ignored_char(c) (c == 0x20 || c == 0x0A || c == 0x0C || c == 0x0D || c == 0x09 || c == 0x00) -+#endif -+ -+#define eexec_getx_(I, c) \ -+ do { c = iof_get(I); } while (lps_ignored_char(c)); \ -+ if (c < 0) return IOFEOF; \ -+ if ((c = base16_lookup[c]) < 0) return IOFERR -+ -+#define eexec_getx(I, c1, c2) eexec_getx_(I, c1); \ -+ do { c2 = iof_get(I); } while (lps_ignored_char(c2)); \ -+ if (c2 < 0) c2 = 0; else \ -+ if ((c2 = base16_lookup[c2]) < 0) return IOFERR -+ -+static int eexec_decode_init (iof *I, int *key, int *binary) -+{ -+ int c1, c2, c3, c4; -+ *key = 55665; -+ eexec_getc(I, c1); -+ eexec_getc(I, c2); -+ eexec_getc(I, c3); -+ eexec_getc(I, c4); /* four head bytes */ -+ -+ /* eexec data has no explicit data termination. The caller of eexec_decode() should ensure that either -+ the input iof allows to read no more then necessary, or the output has no more space then 512 bytes, -+ to land safely somewhere in 512 bytes that probably follows eexec */ -+ -+ *binary = (base16_lookup[c1] < 0 || base16_lookup[c2] < 0 || -+ base16_lookup[c3] < 0 || base16_lookup[c4] < 0); -+ if (*binary) -+ { /* gobble 4 random bytes keeping decipher key up-to-date */ -+ eexec_key(*key, c1); eexec_key(*key, c2); -+ eexec_key(*key, c3); eexec_key(*key, c4); -+ } -+ else /* pfa/postscript only, pdf requires binary eexec form */ -+ { /* gobble 4 random bytes (8 hex digits) keeping decipher key up-to-date */ -+ c1 = base16_lookup[c1], c2 = base16_lookup[c2], c3 = base16_lookup[c3], c4 = base16_lookup[c4]; -+ eexec_key(*key, (c1<<4)|c2); eexec_key(*key, (c3<<4)|c4); /* dummy bytes 1, 2 */ -+ eexec_getx(I, c1, c2); eexec_getx(I, c3, c4); -+ eexec_key(*key, (c1<<4)|c2); eexec_key(*key, (c3<<4)|c4); /* dummy bytes 3, 4 */ -+ } -+ return 0; -+} -+ -+iof_status eexec_decode (iof *I, iof *O) -+{ -+ int c, c1, c2, key, binary, status; -+ if ((status = eexec_decode_init(I, &key, &binary)) < 0) -+ return status; -+ if (binary) -+ { -+ while (iof_ensure(O, 1)) -+ { -+ eexec_getc(I, c1); -+ eexec_decipher(key, c1, c); -+ iof_set(O, c); -+ } -+ } -+ else -+ { -+ while (iof_ensure(O, 1)) -+ { -+ eexec_getx(I, c1, c2); -+ eexec_decipher(key, (c1<<4)|c2, c); -+ iof_set(O, c); -+ } -+ } -+ return IOFFULL; -+} -+ -+iof_status eexec_decode_state (iof *I, iof *O, eexec_state *state) -+{ -+ register int c, c1, c2, status; -+ if (state->key == -1) /* initial state */ -+ if ((status = eexec_decode_init(I, &state->key, &state->binary)) < 0) -+ return status; -+ if (state->binary) -+ { -+ while (iof_ensure(O, 1)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return (state->flush ? IOFEOF : IOFEMPTY); -+ else if (c1 < 0) -+ return c1; -+ eexec_decipher(state->key, c1, c); -+ iof_set(O, c); -+ } -+ } -+ else -+ { -+ if (state->c1 > -1) -+ { -+ c1 = state->c1; -+ state->c1 = -1; -+ goto byte2; -+ } -+ while (iof_ensure(O, 1)) -+ { -+ eexec_getx_(I, c1); -+ byte2: -+ do { c2 = iof_get(I); } while (lps_ignored_char(c2)); -+ if (c2 < 0) // odd number of hex bytes? hmm... assume c2 is zero -+ { -+ if (state->flush) -+ { -+ eexec_decipher(state->key, (c1<<4), c); -+ iof_set(O, c); -+ return IOFEOF; -+ } -+ state->c1 = c1; -+ return IOFEMPTY; -+ } -+ else if (c2 < 0) -+ return c2; -+ if ((c2 = base16_lookup[c2]) < 0) -+ return IOFERR; -+ eexec_decipher(state->key, (c1<<4)|c2, c); -+ iof_set(O, c); -+ } -+ } -+ return IOFFULL; -+} -+ -+#define EEXEC_INIT_BYTES "" -+ -+iof_status eexec_encode (iof *I, iof *O, size_t line, size_t maxline) -+{ -+ int c1, c, key; -+ const char *p; -+ -+ key = 55665; -+ p = EEXEC_INIT_BYTES; -+ if (maxline == 0) -+ { -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ eexec_encipher(key, p[0], c); iof_set(O, c); -+ eexec_encipher(key, p[1], c); iof_set(O, c); -+ eexec_encipher(key, p[2], c); iof_set(O, c); -+ eexec_encipher(key, p[3], c); iof_set(O, c); -+ while (iof_ensure(O, 1)) -+ { -+ eexec_getc(I, c1); -+ eexec_encipher(key, c1, c); -+ iof_set(O, c); -+ } -+ } -+ else -+ { -+ if (!iof_ensure(O, 8 + 1)) -+ return IOFFULL; -+ eexec_encipher(key, p[0], c); put_nl(O, line, maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(key, p[1], c); put_nl(O, line, maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(key, p[2], c); put_nl(O, line, maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(key, p[3], c); put_nl(O, line, maxline, 2); iof_set_uc_hex(O, c); -+ while (iof_ensure(O, 2 + 1)) -+ { -+ eexec_getc(I, c1); -+ eexec_encipher(key, c1, c); -+ put_nl(O, line, maxline, 2); -+ iof_set_uc_hex(O, c); -+ } -+ } -+ return IOFFULL; -+} -+ -+iof_status eexec_encode_state (iof *I, iof *O, eexec_state *state) -+{ -+ int c, c1; -+ const char *p; -+ -+ if (state->key == -1) -+ { -+ p = state->initbytes != NULL ? state->initbytes : EEXEC_INIT_BYTES; -+ if (state->binary) -+ { -+ if (!iof_ensure(O, 4)) -+ return IOFFULL; -+ state->key = 55665; -+ eexec_encipher(state->key, p[0], c); iof_set(O, c); -+ eexec_encipher(state->key, p[1], c); iof_set(O, c); -+ eexec_encipher(state->key, p[2], c); iof_set(O, c); -+ eexec_encipher(state->key, p[3], c); iof_set(O, c); -+ } -+ else -+ { -+ if (!iof_ensure(O, 8 + 1)) -+ return IOFFULL; -+ state->key = 55665; -+ eexec_encipher(state->key, p[0], c); put_nl(O, state->line, state->maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(state->key, p[1], c); put_nl(O, state->line, state->maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(state->key, p[2], c); put_nl(O, state->line, state->maxline, 2); iof_set_uc_hex(O, c); -+ eexec_encipher(state->key, p[3], c); put_nl(O, state->line, state->maxline, 2); iof_set_uc_hex(O, c); -+ } -+ } -+ if (state->binary) -+ { -+ while (iof_ensure(O, 1)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return c1 < 0 ? (state->flush ? IOFEOF : IOFEMPTY) : c1; -+ eexec_encipher(state->key, c1, c); -+ iof_set(O, c); -+ } -+ } -+ else -+ { -+ while (iof_ensure(O, 2 + 1)) -+ { -+ if ((c1 = iof_get(I)) < 0) -+ return c1 < 0 ? (state->flush ? IOFEOF : IOFEMPTY) : c1; -+ eexec_encipher(state->key, c1, c); -+ put_nl(O, state->line, state->maxline, 2); -+ iof_set_uc_hex(O, c); -+ } -+ } -+ return IOFFULL; -+} -+ -+/* -+Type1 charstrings are encoded/decoded in the same way, except that: -+- initial key is 4330 -+- initbytes might be other then 4; /lenIV key in Private dict -+Type1 spec page 63. In practise we don't need iof interface here, -+we always apply the codec in place. -+*/ -+ -+#define type1chstr_key(key, c1) (key = ((((c1) + key)*52845 + 22719) & 65535)) -+#define type1chstr_decipher(key, c1, c) (c = ((c1)^(key>>8)), type1chstr_key(key, c1)) -+#define type1chstr_encipher(key, c1, c) (c = ((c1)^(key>>8)), type1chstr_key(key, c)) -+ -+int type1_charstring_decode (void *data, size_t size, void *outdata, uint8_t leniv) -+{ /* data and outdata may be the same, output size is always size - leniv */ -+ uint8_t *input = (uint8_t *)data, *output = (uint8_t *)outdata; -+ size_t i; -+ int c, c1, key; -+ -+ if (size < 4) -+ return 0; -+ key = 4330; -+ for (i = 0; i < leniv; ++i) -+ { -+ c1 = input[i]; -+ type1chstr_key(key, c1); -+ } -+ for ( ; i < size; ++i) -+ { -+ c1 = input[i]; -+ type1chstr_decipher(key, c1, c); -+ output[i - leniv] = c; -+ } -+ return 1; -+} -+ -+#define TYPE1_CHSTR_INIT_BYTES EEXEC_INIT_BYTES -+ -+int type1_charstring_encode (void *data, size_t size, void *outdata, uint8_t leniv) -+{ /* outdata may be data - leniv, output size is always size + leniv */ -+ uint8_t *input = (uint8_t *)data, *output = (uint8_t *)outdata; -+ size_t i, j; -+ int c, c1, key; -+ -+ key = 4330; -+ for (i = 0, j = 0; i < leniv; ++i) -+ { -+ c1 = TYPE1_CHSTR_INIT_BYTES[j]; -+ //type1chstr_key(key, c1); -+ type1chstr_encipher(key, c1, c); -+ if (++j == 4) -+ j = 0; -+ output[i] = c; -+ } -+ for (i = 0; i < size; ++i) -+ { -+ c1 = input[i]; -+ type1chstr_encipher(key, c1, c); -+ output[i + leniv] = c; -+ } -+ return 1; -+} -+ -+/* filters */ -+ -+// base16 decoder function -+ -+static size_t base16_decoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ size_t tail; -+ -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ state = iof_filter_state(basexx_state *, F); -+ do { -+ status = base16_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "base16", status); -+ case IOFCLOSE: -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// base16 encoder function -+ -+static size_t base16_encoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(basexx_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = base16_encode_state_ln(F, F->next, state); -+ return iof_encoder_retval(F, "base16", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ base16_encoder(F, IOFFLUSH); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// base64 decoder function -+ -+static size_t base64_decoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ size_t tail; -+ -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ state = iof_filter_state(basexx_state *, F); -+ do { -+ status = base64_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "base64", status); -+ case IOFCLOSE: -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// base64 encoder function -+ -+static size_t base64_encoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(basexx_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = base64_encode_state_ln(F, F->next, state); -+ return iof_encoder_retval(F, "base64", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ base64_encoder(F, IOFFLUSH); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// base85 decoder function -+ -+static size_t base85_decoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ size_t tail; -+ -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ state = iof_filter_state(basexx_state *, F); -+ do { -+ status = base85_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "base85", status); -+ case IOFCLOSE: -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// base85 encoder function -+ -+static size_t base85_encoder (iof *F, iof_mode mode) -+{ -+ basexx_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(basexx_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = base85_encode_state_ln(F, F->next, state); -+ return iof_encoder_retval(F, "base85", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ base85_encoder(F, IOFFLUSH); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// runlength decoder function -+ -+static size_t runlength_decoder (iof *F, iof_mode mode) -+{ -+ runlength_state *state; -+ iof_status status; -+ size_t tail; -+ -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ state = iof_filter_state(runlength_state *, F); -+ do { -+ status = runlength_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "runlength", status); -+ case IOFCLOSE: -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// runlength encoder function -+ -+static size_t runlength_encoder (iof *F, iof_mode mode) -+{ -+ runlength_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(runlength_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = runlength_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "runlength", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ runlength_encoder(F, IOFFLUSH); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// eexec decoder function -+ -+static size_t eexec_decoder (iof *F, iof_mode mode) -+{ -+ eexec_state *state; -+ iof_status status; -+ size_t tail; -+ -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ state = iof_filter_state(eexec_state *, F); -+ do { -+ status = eexec_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "eexec", status); -+ case IOFCLOSE: -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// eexec encoder function -+ -+static size_t eexec_encoder (iof *F, iof_mode mode) -+{ -+ eexec_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(eexec_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = eexec_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "eexec", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ eexec_encoder(F, IOFFLUSH); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// -+ -+int iof_filter_basexx_encoder_ln (iof *F, size_t line, size_t maxline) -+{ -+ basexx_state *state; -+ if (maxline > 8 && line < maxline) -+ { -+ state = iof_filter_state(basexx_state *, F); -+ state->line = line; -+ state->maxline = maxline; -+ return 1; -+ } -+ return 0; -+} -+ -+/* base 16 */ -+ -+iof * iof_filter_base16_decoder (iof *N) -+{ -+ iof *I; -+ basexx_state *state; -+ I = iof_filter_reader(base16_decoder, sizeof(basexx_state), &state); -+ iof_setup_next(I, N); -+ basexx_state_init(state); -+ state->flush = 1; // means N is supposed to be continuous input -+ return I; -+} -+ -+iof * iof_filter_base16_encoder (iof *N) -+{ -+ iof *O; -+ basexx_state *state; -+ O = iof_filter_writer(base16_encoder, sizeof(basexx_state), &state); -+ iof_setup_next(O, N); -+ basexx_state_init(state); -+ return O; -+} -+ -+/* base 64 */ -+ -+iof * iof_filter_base64_decoder (iof *N) -+{ -+ iof *I; -+ basexx_state *state; -+ I = iof_filter_reader(base64_decoder, sizeof(basexx_state), &state); -+ iof_setup_next(I, N); -+ basexx_state_init(state); -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_base64_encoder (iof *N) -+{ -+ iof *O; -+ basexx_state *state; -+ O = iof_filter_writer(base64_encoder, sizeof(basexx_state), &state); -+ iof_setup_next(O, N); -+ basexx_state_init(state); -+ return O; -+} -+ -+/* base 85 */ -+ -+iof * iof_filter_base85_decoder (iof *N) -+{ -+ iof *I; -+ basexx_state *state; -+ I = iof_filter_reader(base85_decoder, sizeof(basexx_state), &state); -+ iof_setup_next(I, N); -+ basexx_state_init(state); -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_base85_encoder (iof *N) -+{ -+ iof *O; -+ basexx_state *state; -+ O = iof_filter_writer(base85_encoder, sizeof(basexx_state), &state); -+ iof_setup_next(O, N); -+ basexx_state_init(state); -+ return O; -+} -+ -+/* runlength stream filter */ -+ -+iof * iof_filter_runlength_decoder (iof *N) -+{ -+ iof *I; -+ runlength_state *state; -+ I = iof_filter_reader(runlength_decoder, sizeof(runlength_state), &state); -+ iof_setup_next(I, N); -+ runlength_state_init(state); -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_runlength_encoder (iof *N) -+{ -+ iof *O; -+ runlength_state *state; -+ O = iof_filter_writer(runlength_encoder, sizeof(runlength_state), &state); -+ iof_setup_next(O, N); -+ runlength_state_init(state); -+ return O; -+} -+ -+/* eexec stream filter, type1 fonts spec p. 63 */ -+ -+iof * iof_filter_eexec_decoder (iof *N) -+{ -+ iof *I; -+ eexec_state *state; -+ I = iof_filter_reader(eexec_decoder, sizeof(eexec_state), &state); -+ iof_setup_next(I, N); -+ eexec_state_init(state); -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_eexec_encoder (iof *N) -+{ -+ iof *O; -+ eexec_state *state; -+ O = iof_filter_writer(eexec_encoder, sizeof(eexec_state), &state); -+ iof_setup_next(O, N); -+ eexec_state_init(state); -+ return O; -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utilbasexx.h b/texk/web2c/luatexdir/luapplib/util/utilbasexx.h -new file mode 100644 -index 000000000..52aac3772 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilbasexx.h -@@ -0,0 +1,133 @@ -+ -+/* base encodings */ -+ -+#ifndef UTIL_BASEXX_H -+#define UTIL_BASEXX_H -+ -+#include "utiliof.h" -+ -+/* base codecs state */ -+ -+typedef struct basexx_state basexx_state; -+ -+#define BASEXX_MAXLINE 80 -+#define BASEXX_PDF -+ -+void basexx_state_init_ln (basexx_state *state, size_t line, size_t maxline); -+#define basexx_state_init(state) basexx_state_init_ln(state, 0, BASEXX_MAXLINE) -+ -+/* base16 */ -+ -+int base16_getc (iof *I); -+int base16_uc_putc (iof *I, int c); -+int base16_lc_putc (iof *I, int c); -+#define base16_putc base16_uc_putc -+ -+iof_status base16_encoded_uc (const void *data, size_t size, iof *O); -+iof_status base16_encoded_lc (const void *data, size_t size, iof *O); -+iof_status base16_encoded_uc_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline); -+iof_status base16_encoded_lc_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline); -+ -+iof_status base16_encode_uc (iof *I, iof *O); -+iof_status base16_encode_lc (iof *I, iof *O); -+iof_status base16_encode_uc_ln (iof *I, iof *O, size_t line, size_t maxline); -+iof_status base16_encode_lc_ln (iof *I, iof *O, size_t line, size_t maxline); -+iof_status base16_decode (iof *I, iof *O); -+ -+#define base16_encoded base16_encoded_uc -+#define base16_encoded_ln base16_encoded_uc_ln -+#define base16_encode base16_encode_uc -+#define base16_encode_ln base16_encode_uc_ln -+ -+iof_status base16_encode_state_uc (iof *I, iof *O, basexx_state *state); -+iof_status base16_encode_state_lc (iof *I, iof *O, basexx_state *state); -+iof_status base16_encode_state_uc_ln (iof *I, iof *O, basexx_state *state); -+iof_status base16_encode_state_lc_ln (iof *I, iof *O, basexx_state *state); -+iof_status base16_decode_state (iof *I, iof *O, basexx_state *state); -+ -+#define base16_encode_state base16_encode_state_uc -+#define base16_encode_state_ln base16_encode_state_uc_ln -+ -+/* base64 */ -+ -+extern const char base64_alphabet[]; -+extern const int base64_lookup[]; -+ -+iof_status base64_encoded (const void *data, size_t size, iof *O); -+iof_status base64_encoded_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline); -+ -+iof_status base64_encode (iof *I, iof *O); -+iof_status base64_encode_ln (iof *I, iof *O, size_t line, size_t maxline); -+iof_status base64_decode (iof *I, iof *O); -+ -+iof_status base64_encode_state (iof *I, iof *O, basexx_state *state); -+iof_status base64_encode_state_ln (iof *I, iof *O, basexx_state *state); -+iof_status base64_decode_state (iof *I, iof *O, basexx_state *state); -+ -+/* base85 */ -+ -+extern const char base85_alphabet[]; -+extern const int base85_lookup[]; -+ -+iof_status base85_encoded (const void *data, size_t size, iof *O); -+iof_status base85_encoded_ln (const void *data, size_t size, iof *O, size_t line, size_t maxline); -+ -+iof_status base85_encode (iof *I, iof *O); -+iof_status base85_encode_ln (iof *I, iof *O, size_t line, size_t maxline); -+iof_status base85_decode (iof *I, iof *O); -+ -+iof_status base85_encode_state (iof *I, iof *O, basexx_state *state); -+iof_status base85_encode_state_ln (iof *I, iof *O, basexx_state *state); -+iof_status base85_decode_state (iof *I, iof *O, basexx_state *state); -+ -+/* run length */ -+ -+typedef struct runlength_state runlength_state; -+ -+void runlength_state_init (runlength_state *state); -+ -+iof_status runlength_encode (iof *I, iof *O); -+iof_status runlength_encode_state (iof *I, iof *O, runlength_state *state); -+ -+iof_status runlength_decode (iof *I, iof *O); -+iof_status runlength_decode_state (iof *I, iof *O, runlength_state *state); -+ -+/* eexec */ -+ -+typedef struct eexec_state eexec_state; -+ -+#define EEXEC_MAXLINE 80 -+ -+void eexec_state_init_ln (eexec_state *state, size_t line, size_t maxline, const char *initbytes); -+#define eexec_state_init(state) eexec_state_init_ln(state, 0, EEXEC_MAXLINE, NULL) -+ -+iof_status eexec_decode (iof *I, iof *O); -+iof_status eexec_decode_state (iof *I, iof *O, eexec_state *state); -+ -+iof_status eexec_encode (iof *I, iof *O, size_t line, size_t maxline); -+iof_status eexec_encode_state (iof *I, iof *O, eexec_state *state); -+ -+iof_status type1_charstring_decode (void *data, size_t size, void *outdata, uint8_t leniv); -+iof_status type1_charstring_encode (void *data, size_t size, void *outdata, uint8_t leniv); -+ -+/* filters */ -+ -+int iof_filter_basexx_encoder_ln (iof *N, size_t line, size_t maxline); -+ -+iof * iof_filter_base16_decoder (iof *N); -+iof * iof_filter_base16_encoder (iof *N); -+ -+iof * iof_filter_base64_decoder (iof *N); -+iof * iof_filter_base64_encoder (iof *N); -+ -+iof * iof_filter_base85_decoder (iof *N); -+iof * iof_filter_base85_encoder (iof *N); -+ -+iof * iof_filter_runlength_decoder (iof *N); -+iof * iof_filter_runlength_encoder (iof *N); -+ -+iof * iof_filter_eexec_decoder (iof *N); -+iof * iof_filter_eexec_encoder (iof *N); -+ -+ -+#endif -diff --git a/texk/web2c/luatexdir/luapplib/util/utilcrypt.c b/texk/web2c/luatexdir/luapplib/util/utilcrypt.c -new file mode 100644 -index 000000000..1750d01bd ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilcrypt.c -@@ -0,0 +1,1191 @@ -+ -+#include "utilmem.h" -+#include "utilcrypt.h" -+#include "utilcryptdef.h" -+#include "utilmd5.h" -+ -+/* rc4 */ -+ -+/* -+Initializer arguments: -+- state - crypt state -+- map - a space for rc4 bytes map; may be left NULL in which case will be allocated -+- vkey - crypt key; may be left NULL iff map is provided and properly initialized -+- keylength - the length of crypt key (from 5 to 16 bytes) -+*/ -+ -+rc4_state * rc4_state_initialize (rc4_state *state, rc4_map *map, const void *vkey, size_t keylength) -+{ -+ int i, j; -+ uint8_t tmp; -+ const uint8_t *key; -+ key = (const uint8_t *)vkey; -+ if (keylength == 0 || keylength > 256) -+ return NULL; -+ state->flags = 0; -+ if (map != NULL) -+ { -+ state->map = map; -+ } -+ else -+ { -+ state->map = (rc4_map *)util_malloc(sizeof(rc4_map)); -+ state->flags |= RC4_STATE_ALLOC; -+ } -+ -+ if (key != NULL) -+ { -+ for (i = 0; i < 256; ++i) -+ state->smap[i] = (uint8_t)i; -+ for (i = 0, j = 0; i < 256; ++i) -+ { -+ j = (j + state->smap[i] + key[i % keylength]) & 255; -+ tmp = state->smap[i]; -+ state->smap[i] = state->smap[j]; -+ state->smap[j] = tmp; -+ } -+ } -+ state->i = 0; -+ state->j = 0; -+ state->flush = 0; /* caller is responsible to override if necessary */ -+ return state; -+} -+ -+void rc4_map_save (rc4_state *state, rc4_map *map) -+{ -+ memcpy(map, state->map, sizeof(rc4_map)); -+} -+ -+void rc4_map_restore (rc4_state *state, rc4_map *map) -+{ -+ memcpy(state->map, map, sizeof(rc4_map)); -+ //state->flags = 0; -+ //state->flush = 0; -+ state->i = 0; -+ state->j = 0; -+} -+ -+static uint8_t rc4_next_random_byte (rc4_state *state) -+{ -+ uint8_t tmp; -+ state->i = (state->i + 1) & 255; -+ state->j = (state->j + state->smap[state->i]) & 255; -+ tmp = state->smap[state->i]; -+ state->smap[state->i] = state->smap[state->j]; -+ state->smap[state->j] = tmp; -+ return state->smap[(state->smap[state->i] + state->smap[state->j]) & 255]; -+} -+ -+iof_status rc4_crypt_state (iof *I, iof *O, rc4_state *state) -+{ -+ uint8_t r; -+ int c; -+ while (iof_ensure(O, 1)) -+ { -+ if ((c = iof_get(I)) < 0) -+ return c == IOFERR ? IOFERR : (state->flush ? IOFEOF : IOFEMPTY); -+ r = rc4_next_random_byte(state); -+ //r = r ^ ((uint8_t)c); -+ //iof_set(O, r); -+ iof_set(O, r ^ ((uint8_t)c)); -+ } -+ return IOFFULL; -+} -+ -+iof_status rc4_crypt (iof *I, iof *O, const void *key, size_t keylength) -+{ -+ int ret; -+ rc4_state state; -+ rc4_map map; -+ if (rc4_state_initialize(&state, &map, key, keylength) == NULL) -+ return IOFERR; -+ state.flush = 1; -+ ret = rc4_crypt_state(I, O, &state); -+ rc4_state_close(&state); -+ return ret; -+} -+ -+/* -+Variants that operates on c-strings can worn inplace, so output and input can be the same address. -+Variant that takes rc4_state pointer expects the state properly initialized. Keep in mind -+the crypt procedure modifies rc4 bytes map. All returns the size of encrypted/decrypted -+data, which is the same as input data length for rc4. -+*/ -+ -+size_t rc4_crypt_data (const void *input, size_t length, void *output, const void *key, size_t keylength) -+{ -+ rc4_state state; -+ rc4_map map; -+ if (rc4_state_initialize(&state, &map, key, keylength) == NULL) -+ return 0; -+ return rc4_crypt_state_data(&state, input, length, output); -+ // no need to call rc4_state_close() -+} -+ -+size_t rc4_crypt_state_data (rc4_state *state, const void *input, size_t length, void *output) -+{ /* state assumed to be initialized and with the proper state of smap */ -+ const uint8_t *inp; -+ uint8_t r, *out; -+ size_t size; -+ inp = (const uint8_t *)input; -+ out = (uint8_t *)output; -+ for (size = 0; size < length; ++size, ++inp, ++out) -+ { -+ r = rc4_next_random_byte(state); -+ *out = r ^ *inp; -+ } -+ return length; -+} -+ -+void rc4_state_close (rc4_state *state) -+{ -+ if (state->smap != NULL && (state->flags & RC4_STATE_ALLOC)) -+ { -+ util_free(state->smap); -+ state->smap = NULL; -+ } -+} -+ -+/* aes; parts of code excerpted from https://github.com/kokke/tiny-AES128-C */ -+ -+static const uint8_t sbox[256] = { -+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, -+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, -+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, -+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, -+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, -+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, -+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, -+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, -+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, -+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, -+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, -+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, -+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, -+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, -+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, -+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; -+ -+static const uint8_t rsbox[256] = -+{ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, -+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, -+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, -+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, -+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, -+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, -+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, -+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, -+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, -+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, -+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, -+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, -+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, -+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, -+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, -+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; -+ -+/* -+The round constant word array, rcon[i], contains the values given by -+x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) -+Note that i starts at 1, not 0). -+*/ -+ -+static const uint8_t rcon[255] = { -+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, -+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, -+ 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, -+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, -+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, -+ 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, -+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, -+ 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, -+ 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, -+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, -+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, -+ 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, -+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, -+ 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, -+ 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, -+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb }; -+ -+/* block copying */ -+ -+#define aes_copy_block(output, input) memcpy(output, input, 16) -+ -+static void aes_copy_cbc (uint8_t *data, const uint8_t *input) -+{ -+ uint8_t i; -+ for (i = 0; i < 16; ++i) -+ data[i] ^= input[i]; -+} -+ -+static void aes_copy_xor (uint8_t *data, const uint8_t *input, const uint8_t *iv) -+{ -+ uint8_t i; -+ for (i = 0; i < 16; ++i) -+ data[i] = input[i] ^ iv[i]; -+} -+ -+/* key expansion */ -+ -+#define AES_COLUMNS 4 // constant in aes -+ -+static void key_expansion (aes_state *state, const uint8_t *key) -+{ -+ uint32_t i, j, k; -+ uint8_t t[4]; -+ uint8_t *keydata, keywords, columns; -+ -+ keywords = (uint8_t)(state->keylength >> 2); -+ keydata = (uint8_t *)state->keyblock; -+ -+ /* the first round key is the key itself */ -+ for(i = 0; i < keywords; ++i) -+ { -+ keydata[(i * 4) + 0] = key[(i * 4) + 0]; -+ keydata[(i * 4) + 1] = key[(i * 4) + 1]; -+ keydata[(i * 4) + 2] = key[(i * 4) + 2]; -+ keydata[(i * 4) + 3] = key[(i * 4) + 3]; -+ } -+ -+ /* others derived from the first */ -+ -+ for(columns = AES_COLUMNS * (state->rounds + 1); i < columns; ++i) -+ { -+ for(j = 0; j < 4; ++j) -+ t[j] = keydata[(i - 1) * 4 + j]; -+ if (i % keywords == 0) -+ { -+ /* rotate the 4 bytes in a word to the left once; [a0,a1,a2,a3] becomes [a1,a2,a3,a0] */ -+ k = t[0]; -+ t[0] = t[1]; -+ t[1] = t[2]; -+ t[2] = t[3]; -+ t[3] = k; -+ -+ /* take a four-byte input word and apply the S-box to each of the four bytes to produce an output word */ -+ t[0] = sbox[t[0]]; -+ t[1] = sbox[t[1]]; -+ t[2] = sbox[t[2]]; -+ t[3] = sbox[t[3]]; -+ -+ t[0] = t[0] ^ rcon[i / keywords]; -+ } -+ else if (keywords > 6 && i % keywords == 4) -+ { -+ t[0] = sbox[t[0]]; -+ t[1] = sbox[t[1]]; -+ t[2] = sbox[t[2]]; -+ t[3] = sbox[t[3]]; -+ } -+ keydata[i * 4 + 0] = keydata[(i - keywords) * 4 + 0] ^ t[0]; -+ keydata[i * 4 + 1] = keydata[(i - keywords) * 4 + 1] ^ t[1]; -+ keydata[i * 4 + 2] = keydata[(i - keywords) * 4 + 2] ^ t[2]; -+ keydata[i * 4 + 3] = keydata[(i - keywords) * 4 + 3] ^ t[3]; -+ } -+ -+} -+ -+/* -+An original implementation uses no private buffers except a keyblock. We need private buffers to -+keep a CBC vector between calls and to be able to read input data not necessarily in 16-bytes blocks. -+Encrypter would actually require only one such buffer, as CBC vector is applied on input data before -+the actual cipher procedure. And CBC for the next chunk is simply the output from the previous. -+Decrypter, however, applies the cipher first, then applies CBC to the output with a buffered init -+vector, and the vector for the next call is the row input before cipher. Hence we need two 16-bytes -+buffers for decrypter. -+*/ -+ -+/* -+aes_state * aes_state_initialize_ecb (aes_state *State, uint8_t *keyblock, const uint8_t *key) -+{ -+ state->flags = 0; -+ -+ state->flags |= AES_ECB_MODE; -+ -+ if (keyblock == NULL) -+ { -+ keyblock = util_malloc(sizeof(aes_keyblock)); -+ state->flags |= AES_STATE_ALLOC; -+ } -+ state->keyblock = keyblock; -+ key_expansion(state, key); -+ state->flush = 0; -+ return state; -+} -+*/ -+ -+void aes_pdf_mode (aes_state *state) -+{ -+ state->flags |= AES_INLINE_IV; -+ state->flags &= ~AES_NULL_PADDING; -+} -+ -+/* -+Initialize arguments: -+- state - crypt state -+- keyblock - a space for aes key expansion; can be left NULL in which case will be allocated -+- key - crypt key; can be left NULL iff keyblock is given and properly initialized -+- keylength - the length of the key (16 or 32 bytes) -+- iv - 16-bytes CBC initialization vector; -+ - if left NULL for encoder, one is generated and stored as state->iv -+ - can also be left NULL for decorer, but then AES_INLINE_IV must be set, as this informs decoder to take -+ an initialization vector from the beginning of the encrypted stream -+ -+At the first approach, an initialization vector was copied to state block during initialization and encoders -+assumed that the state block is the current initialization vector. This simplifies encrypting procedure, -+as the output from every 16-bytes chunk encryption is an initialization vector for the next chunk. However, -+it makes api usage cumbersome, as the user has to know that iv may need to be copied to state block -+before each call. -+*/ -+ -+static int aes_key_length (aes_state *state, size_t keylength) -+{ -+ state->keylength = keylength; -+ switch (keylength) -+ { -+ case 16: -+ state->rounds = 10; -+ break; -+ case 24: -+ state->rounds = 12; -+ break; -+ case 32: -+ state->rounds = 14; -+ break; -+ default: -+ return 0; -+ } -+ return 1; -+} -+ -+aes_state * aes_encode_initialize (aes_state *state, aes_keyblock *keyblock, const void *key, size_t keylength, const void *iv) -+{ -+ state->flags = 0; -+ if (!aes_key_length(state, keylength)) -+ return NULL; -+ if (iv != NULL) -+ aes_copy_block(state->iv, iv); -+ else -+ aes_generate_iv(state->iv); -+ state->flags |= AES_HAS_IV; -+ -+ if (keyblock == NULL) -+ { -+ keyblock = (aes_keyblock *)util_malloc(sizeof(aes_keyblock)); -+ state->flags |= AES_STATE_ALLOC; -+ } -+ state->keyblock = keyblock; -+ if (key != NULL) /* if NULL we assume keyblock is given and already expanded */ -+ key_expansion(state, (const uint8_t *)key); -+ state->flush = 0; -+ return state; -+} -+ -+aes_state * aes_decode_initialize (aes_state *state, aes_keyblock *keyblock, const void *key, size_t keylength, const void *iv) -+{ -+ state->flags = 0; -+ if (!aes_key_length(state, keylength)) -+ return NULL; -+ if (iv != NULL) -+ { -+ aes_copy_block(state->iv, iv); -+ state->flags |= AES_HAS_IV; -+ } -+ /* else if AES_INLINE_IV flag is set will be read from input */ -+ -+ if (keyblock == NULL) -+ { -+ keyblock = (aes_keyblock *)util_malloc(sizeof(aes_keyblock)); -+ state->flags |= AES_STATE_ALLOC; -+ } -+ state->keyblock = keyblock; -+ if (key != NULL) /* otherwise keyblock is assumed present and properly initialized */ -+ key_expansion(state, (const uint8_t *)key); -+ state->flush = 0; -+ return state; -+} -+ -+void aes_state_close (aes_state *state) -+{ -+ if (state->keyblock != NULL && (state->flags & AES_STATE_ALLOC)) -+ util_free(state->keyblock); -+} -+ -+/* add round key */ -+ -+static void aes_round_key (aes_block block, aes_block keyblock) -+{ -+ uint8_t i, j; -+ for(i = 0; i < 4; ++i) -+ for(j = 0; j < 4; ++j) -+ block[i][j] ^= keyblock[i][j]; -+} -+ -+#define aes_add_key(block, keyblock, round) aes_round_key(block, (*keyblock)[round]) -+ -+/* substitution */ -+ -+static void aes_encode_sub (aes_block block) -+{ -+ uint8_t i, j, v; -+ for(i = 0; i < 4; ++i) -+ for(j = 0; j < 4; ++j) -+ v = block[i][j], block[i][j] = sbox[v]; -+} -+ -+/* rows shift; the row index is the shift offset, the first order is not shifted */ -+ -+static void aes_encode_shift (aes_block block) -+{ -+ uint8_t tmp; -+ -+ /* 1st row rotated once */ -+ tmp = block[0][1]; -+ block[0][1] = block[1][1]; -+ block[1][1] = block[2][1]; -+ block[2][1] = block[3][1]; -+ block[3][1] = tmp; -+ -+ /* 2nd row rotated twice */ -+ tmp = block[0][2]; -+ block[0][2] = block[2][2]; -+ block[2][2] = tmp; -+ tmp = block[1][2]; -+ block[1][2] = block[3][2]; -+ block[3][2] = tmp; -+ -+ /* 3rd row rotated 3 times */ -+ tmp = block[0][3]; -+ block[0][3] = block[3][3]; -+ block[3][3] = block[2][3]; -+ block[2][3] = block[1][3]; -+ block[1][3] = tmp; -+} -+ -+static uint8_t xtime (uint8_t x) -+{ -+ return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); -+} -+ -+/* mix columns */ -+ -+static void aes_encode_mix (aes_block block) -+{ -+ uint8_t i, tmp, tm, t; -+ -+ for(i = 0; i < 4; ++i) -+ { -+ t = block[i][0]; -+ tmp = block[i][0] ^ block[i][1] ^ block[i][2] ^ block[i][3] ; -+ tm = block[i][0] ^ block[i][1]; tm = xtime(tm); block[i][0] ^= tm ^ tmp; -+ tm = block[i][1] ^ block[i][2]; tm = xtime(tm); block[i][1] ^= tm ^ tmp; -+ tm = block[i][2] ^ block[i][3]; tm = xtime(tm); block[i][2] ^= tm ^ tmp; -+ tm = block[i][3] ^ t ; tm = xtime(tm); block[i][3] ^= tm ^ tmp; -+ } -+} -+ -+/* multiply is used to multiply numbers in the field GF(2^8) */ -+ -+#define multiply(x, y) \ -+ ( ((y & 1) * x) ^ \ -+ ((y>>1 & 1) * xtime(x)) ^ \ -+ ((y>>2 & 1) * xtime(xtime(x))) ^ \ -+ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ -+ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ -+ -+/* mix columns */ -+ -+static void aes_decode_mix (aes_block block) -+{ -+ int i; -+ uint8_t a, b, c, d; -+ -+ for(i = 0; i < 4; ++i) -+ { -+ a = block[i][0]; -+ b = block[i][1]; -+ c = block[i][2]; -+ d = block[i][3]; -+ block[i][0] = multiply(a, 0x0e) ^ multiply(b, 0x0b) ^ multiply(c, 0x0d) ^ multiply(d, 0x09); -+ block[i][1] = multiply(a, 0x09) ^ multiply(b, 0x0e) ^ multiply(c, 0x0b) ^ multiply(d, 0x0d); -+ block[i][2] = multiply(a, 0x0d) ^ multiply(b, 0x09) ^ multiply(c, 0x0e) ^ multiply(d, 0x0b); -+ block[i][3] = multiply(a, 0x0b) ^ multiply(b, 0x0d) ^ multiply(c, 0x09) ^ multiply(d, 0x0e); -+ } -+} -+ -+/* inverse substitution */ -+ -+static void aes_decode_sub (aes_block block) -+{ -+ uint8_t i, j, v; -+ for(i = 0; i < 4; ++i) -+ for(j = 0; j < 4; ++j) -+ v = block[i][j], block[i][j] = rsbox[v]; -+} -+ -+/* inverse shift rows */ -+ -+static void aes_decode_shift (aes_block block) -+{ -+ uint8_t tmp; -+ -+ /* 1st row rotated once right */ -+ tmp = block[3][1]; -+ block[3][1] = block[2][1]; -+ block[2][1] = block[1][1]; -+ block[1][1] = block[0][1]; -+ block[0][1] = tmp; -+ -+ /* 2st row rotated twice right */ -+ tmp = block[0][2]; -+ block[0][2] = block[2][2]; -+ block[2][2] = tmp; -+ tmp = block[1][2]; -+ block[1][2] = block[3][2]; -+ block[3][2] = tmp; -+ -+ /* 3rd row rotated 3 times right */ -+ tmp = block[0][3]; -+ block[0][3] = block[1][3]; -+ block[1][3] = block[2][3]; -+ block[2][3] = block[3][3]; -+ block[3][3] = tmp; -+} -+ -+/* aes block encoder */ -+ -+static void aes_encode_cipher (aes_state *state) -+{ -+ uint8_t round; -+ aes_add_key(state->block, state->keyblock, 0); -+ for (round = 1; round < state->rounds; ++round) -+ { -+ aes_encode_sub(state->block); -+ aes_encode_shift(state->block); -+ aes_encode_mix(state->block); -+ aes_add_key(state->block, state->keyblock, round); -+ } -+ aes_encode_sub(state->block); -+ aes_encode_shift(state->block); -+ aes_add_key(state->block, state->keyblock, state->rounds); -+} -+ -+/* aes block decoder */ -+ -+static void aes_decode_cipher (aes_state *state) -+{ -+ uint8_t round; -+ aes_add_key(state->block, state->keyblock, state->rounds); -+ for(round = state->rounds - 1; round > 0; --round) -+ { -+ aes_decode_shift(state->block); -+ aes_decode_sub(state->block); -+ aes_add_key(state->block, state->keyblock, round); -+ aes_decode_mix(state->block); -+ } -+ aes_decode_shift(state->block); -+ aes_decode_sub(state->block); -+ aes_add_key(state->block, state->keyblock, 0); -+} -+ -+/* tail block padding; RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0; pdf spec p. 119 */ -+ -+#define aes_padding(state) ((state->flags & AES_NULL_PADDING) == 0) -+ -+static void aes_put_padding (aes_state *state, uint8_t length) -+{ -+ uint8_t pad; -+ pad = (aes_padding(state)) ? 16 - length : 0; -+ for (; length < 16; ++length) -+ state->data[length] = state->iv[length] ^ pad; -+} -+ -+static int aes_remove_padding (aes_state *state, uint8_t *data, uint8_t *length) -+{ -+ uint8_t pad; -+ *length = 16; /* block length 16 means leave intact */ -+ if (aes_padding(state)) -+ { -+ pad = data[16 - 1]; -+ if (pad > 16) -+ return IOFERR; -+ for ( ; *length > 16 - pad; --(*length)) -+ if (data[*length - 1] != pad) -+ return IOFERR; -+ } -+ else -+ { -+ for ( ; *length > 0; --(*length)) -+ if (data[*length - 1] != '\0') -+ break; -+ } -+ return IOFEOF; -+} -+ -+/* aes codec */ -+ -+/* make the cipher on input xor-ed with iv, save the output as a new iv, write the output */ -+#define aes_encode_output(state, output) \ -+ (aes_encode_cipher(state), aes_copy_block(state->iv, state->data), aes_copy_block(output, state->data), output += 16) -+ -+iof_status aes_encode_state (iof *I, iof *O, aes_state *state) -+{ -+ int c; -+ -+ if (!(state->flags & AES_HAS_IV)) // weird -+ return IOFERR; -+ if ((state->flags & AES_INLINE_IV) && !(state->flags & AES_CONTINUE)) -+ { /* write iv at the beginning of encrypted data */ -+ if (!iof_ensure(O, 16)) -+ return IOFFULL; -+ aes_copy_block(O->pos, state->iv); -+ O->pos += 16; -+ state->flags |= AES_CONTINUE; -+ } -+ while (iof_ensure(O, 16)) -+ { -+ while (state->buffered < 16) -+ { -+ if ((c = iof_get(I)) != IOFEOF) -+ { /* get input byte XORed with iv */ -+ state->data[state->buffered] = state->iv[state->buffered] ^ ((uint8_t)c); -+ ++state->buffered; -+ } -+ else -+ { -+ if (state->flush) -+ { -+ if (state->buffered > 0 || aes_padding(state)) -+ { /* pad the last input chunk; for input divisable by 16, add 16 bytes 0x0f */ -+ aes_put_padding(state, state->buffered); -+ state->buffered = 16; -+ aes_encode_output(state, O->pos); -+ } -+ return IOFEOF; -+ } -+ else -+ return IOFEMPTY; -+ } -+ } -+ aes_encode_output(state, O->pos); -+ state->buffered = 0; -+ } -+ return IOFFULL; -+} -+ -+/* write iv to the output, save the raw input just buffered as iv for the next chunk, make the cipher, write out xoring with iv */ -+#define aes_decode_output(state, output) \ -+ (aes_copy_block(output, state->iv), aes_copy_block(state->iv, state->data), aes_decode_cipher(state), aes_copy_cbc(output, state->data), output += 16) -+ -+iof_status aes_decode_state (iof *I, iof *O, aes_state *state) -+{ -+ int c, ret; -+ uint8_t lastlength; -+ -+ if ((state->flags & AES_INLINE_IV) && !(state->flags & AES_CONTINUE)) -+ { -+ while (state->buffered < 16) -+ { -+ if ((c = iof_get(I)) != IOFEOF) -+ state->iv[state->buffered++] = (uint8_t)c; -+ else -+ return state->flush ? IOFERR : IOFEMPTY; -+ } -+ state->flags |= AES_CONTINUE|AES_HAS_IV; -+ state->buffered = 0; -+ } -+ while (iof_ensure(O, 16)) -+ { -+ while (state->buffered < 16) -+ { -+ if ((c = iof_get(I)) != IOFEOF) -+ state->data[state->buffered++] = (uint8_t)c; -+ else -+ return state->flush ? IOFERR : IOFEMPTY; -+ } -+ aes_decode_output(state, O->pos); -+ if (state->flush) -+ { /* we have to check for EOF here, to remove eventual padding */ -+ if ((c = iof_get(I)) < 0) -+ { /* end of input at 16-bytes boundary; remove padding and quit */ -+ ret = aes_remove_padding(state, O->pos - 16, &lastlength); -+ O->pos -= 16 - lastlength; -+ return ret; -+ } -+ else -+ { /* beginning of the next block */ -+ state->buffered = 1; -+ state->data[0] = (uint8_t)c; -+ } -+ } -+ else -+ state->buffered = 0; -+ } -+ return IOFFULL; -+} -+ -+/* variants that works on c-strings; can work inplace (output==input) except encoder in pdf flavour */ -+ -+/* -+Codecs operating on c-string can generally work inplace (output==input), except encoder with AES_INLINE_IV flag set, -+which outputs 16 bytes of initialization vector at the beginning of encrypted data. All return the size of encrypted/decrypted -+data. Encoders output is the original length padded to a complete 16 bytes (plus eventual 16 bytes of initialization -+vector, if AES_INLINE_IV is used). Default padding is unambiguously removed during decryption. AES_NULL_PADDING flag -+forces using (ambiguous) NULL-byte padding, only if input length module 16 is greater then zero. -+ -+An input data is supposed to be a complete data to be encrypted or decrypted. It is possible, however, to use those -+codecs for scaterred data chunks by manipulating AES_INLINE_IV, AES_NULL_PADDING, AES_CONTINUE flags and data length. -+Caller may assume that c-string codecs do not modify state flags. -+ -+Encoder could actually be optimized by writing an initialization vector to a state block once. After every chunk encryption, -+the output is the initialization vector for the next chunk. Since we use c-string codec variants on short strings, -+the gain is neglectable in comparison with the weight of the aes crypt procedure. -+*/ -+ -+size_t aes_encode_data (const void *input, size_t length, void *output, const void *key, size_t keylength, const void *iv, int flags) -+{ -+ aes_state state; -+ aes_keyblock keyblock; -+ -+ if (aes_encode_initialize(&state, &keyblock, key, keylength, iv) == NULL) -+ return 0; -+ state.flags |= flags; -+ return aes_encode_state_data(&state, input, length, output); -+ // aes_state_close(&state); -+} -+ -+size_t aes_encode_state_data (aes_state *state, const void *input, size_t length, void *output) -+{ -+ const uint8_t *inp; -+ uint8_t *out, tail, t; -+ size_t size; -+ -+ inp = (const uint8_t *)input; -+ out = (uint8_t *)output; -+ -+ if (!(state->flags & AES_HAS_IV)) -+ return 0; -+ if ((state->flags & AES_INLINE_IV) && !(state->flags & AES_CONTINUE)) -+ { -+ aes_copy_block(out, state->iv); -+ out += 16; -+ } -+ // state->flags |= AES_CONTINUE; // do not modify state flags -+ -+ for (size = 0; size + 16 <= length; size += 16) -+ { -+ aes_copy_xor(state->data, inp, state->iv); -+ aes_encode_output(state, out); -+ inp += 16; -+ } -+ -+ if ((tail = (length % 16)) > 0 || aes_padding(state)) -+ { -+ for (t = 0; t < tail; ++t) -+ state->data[t] = inp[t] ^ state->iv[t]; -+ aes_put_padding(state, tail); -+ aes_encode_output(state, out); -+ size += 16; -+ } -+ if (state->flags & AES_INLINE_IV) -+ size += 16; /* iv written at the beginning of encoded data */ -+ -+ return size; -+} -+ -+size_t aes_decode_data (const void *input, size_t length, void *output, const void *key, size_t keylength, const void *iv, int flags) -+{ -+ aes_state state; -+ aes_keyblock keyblock; -+ -+ if (aes_decode_initialize(&state, &keyblock, key, keylength, iv) == NULL) -+ return 0; -+ state.flags |= flags; -+ return aes_decode_state_data(&state, input, length, output); -+ // aes_state_close(&state); -+} -+ -+size_t aes_decode_state_data (aes_state *state, const void *input, size_t length, void *output) -+{ -+ const uint8_t *inp; -+ uint8_t *out, lastlength; -+ size_t size; -+ -+ inp = (const uint8_t *)input; -+ out = (uint8_t *)output; -+ -+ if ((state->flags & AES_INLINE_IV) && !(state->flags & AES_CONTINUE)) -+ { -+ aes_copy_block(state->iv, inp); -+ // state->flags |= AES_HAS_IV; // do not modify state flags -+ inp += 16; -+ length = length >= 16 ? length - 16 : 0; -+ } -+ else if (!(state->flags & AES_HAS_IV)) -+ return 0; -+ // state->flags |= AES_CONTINUE; // do not modify state flags -+ for (size = 0; size + 16 <= length; size += 16) -+ { -+ aes_copy_block(state->data, inp); -+ aes_decode_output(state, out); -+ inp += 16; -+ } -+ -+ if (size >= 16) -+ { -+ aes_remove_padding(state, out - 16, &lastlength); -+ size = size - 16 + lastlength; -+ } -+ -+ return size; -+} -+ -+/* -+pseudo-random bytes chain exceprted from eexec; not expected to have strong cryptographic properties -+we only expect that it is (reasonably) unique and different for each call (not only function call, but also -+a program call). A current trick with mangling pointer value gives satisfactory results, generally different -+for every function call and a programm call. Note that the pseudo-input bytes starts from some inner address -+bits, as they vary better; without that, the first byte tends to be "lazy". -+*/ -+ -+void random_bytes (uint8_t *output, size_t size) -+{ -+ size_t i; -+ uint8_t p; -+ static uint16_t k = 55665; -+ for (i = 0; i < size; ++i) -+ { -+ p = ((uint8_t *)(&output))[(i + 2) % sizeof(uint8_t *)] ^ (uint8_t)size; // pseudo input byte ;) -+ k = (((p + k) * 52845 + 22719) & 65535); // xor-ed with pseudo-random sequence (kept between calls) -+ output[i] = p ^ (k >> 8); -+ } -+} -+ -+void aes_generate_iv (uint8_t output[16]) -+{ -+ random_bytes(output, 16); -+} -+ -+/* filters */ -+ -+// rc4 decoder function -+ -+static size_t rc4_decoder (iof *F, iof_mode mode) -+{ -+ rc4_state *state; -+ iof_status status; -+ size_t tail; -+ -+ state = iof_filter_state(rc4_state *, F); -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ do { -+ status = rc4_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "rc4", status); -+ case IOFCLOSE: -+ rc4_state_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// rc4 encoder function -+ -+static size_t rc4_encoder (iof *F, iof_mode mode) -+{ -+ rc4_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(rc4_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = rc4_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "rc4", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ rc4_encoder(F, IOFFLUSH); -+ rc4_state_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// aes decoder function -+ -+static size_t aes_decoder (iof *F, iof_mode mode) -+{ -+ aes_state *state; -+ iof_status status; -+ size_t tail; -+ -+ state = iof_filter_state(aes_state *, F); -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ do { -+ status = aes_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "aes", status); -+ case IOFCLOSE: -+ aes_state_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// aes encoder function -+ -+static size_t aes_encoder (iof *F, iof_mode mode) -+{ -+ aes_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(aes_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = aes_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "aes", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ aes_encoder(F, IOFFLUSH); -+ aes_state_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+iof * iof_filter_rc4_decoder (iof *N, const void *key, size_t keylength) -+{ -+ iof *I; -+ rc4_state *state; -+ -+ I = iof_filter_reader(rc4_decoder, sizeof(rc4_state), &state); -+ iof_setup_next(I, N); -+ if (rc4_state_init(state, key, keylength) == NULL) -+ { -+ iof_discard(I); -+ return NULL; -+ } -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_rc4_encoder (iof *N, const void *key, size_t keylength) -+{ -+ iof *O; -+ rc4_state *state; -+ -+ O = iof_filter_writer(rc4_encoder, sizeof(rc4_state), &state); -+ iof_setup_next(O, N); -+ if (rc4_state_init(state, key, keylength) == NULL) -+ { -+ iof_discard(O); -+ return NULL; -+ } -+ // state->flush = 1; -+ return O; -+} -+ -+/* aes crypt filters */ -+ -+iof * iof_filter_aes_decoder (iof *N, const void *key, size_t keylength) -+{ -+ iof *I; -+ aes_state *state; -+ -+ I = iof_filter_reader(aes_decoder, sizeof(aes_state), &state); -+ iof_setup_next(I, N); -+ if (aes_decode_init(state, key, keylength) == NULL) -+ { -+ iof_discard(I); -+ return NULL; -+ } -+ aes_pdf_mode(state); -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_aes_encoder (iof *N, const void *key, size_t keylength) -+{ -+ iof *O; -+ aes_state *state; -+ -+ O = iof_filter_writer(aes_encoder, sizeof(aes_state), &state); -+ iof_setup_next(O, N); -+ if (aes_encode_init(state, key, keylength) == NULL) -+ { -+ iof_discard(O); -+ return NULL; -+ } -+ aes_pdf_mode(state); -+ // state->flush = 1; -+ return O; -+} -+ -+/* test */ -+ -+/* -+static void show (void *p, size_t size, uint8_t round, uint8_t sym) -+{ -+ uint8_t i; -+ printf("%c%c:", round, sym); -+ for (i = 0; i < size; ++i) -+ printf("%02x", ((uint8_t *)p)[i]); -+ printf("\n"); -+} -+ -+void aes_test (void) -+{ -+ const uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; -+ const uint8_t iv[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; -+ const uint8_t inp[] = { -+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, -+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, -+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, -+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 }; -+ const uint8_t out[] = { -+ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, -+ 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, -+ 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, -+ 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 }; -+ -+ uint8_t input[64], output[64]; -+ size_t inpsize, outsize; -+ int flags = AES_NULL_PADDING; -+ -+ //////////////////////////////////////////////////////////////////////////// -+ -+//#define ENCODETO output -+#define ENCODETO input // inplace -+ -+ inpsize = 64; -+ memcpy(input, inp, inpsize); -+ show(input, inpsize, '>', '>'); -+ outsize = aes_encode_data(input, inpsize, ENCODETO, key, 16, iv, flags); -+ show(ENCODETO, outsize, '<', '<'); -+ if (outsize == inpsize && memcmp(ENCODETO, out, outsize) == 0) -+ printf("ENCODER SUCCESS\n"); -+ else -+ printf("ENCODER FAILURE\n"); -+ -+ //////////////////////////////////////////////////////////////////////////// -+ -+//#define DECODETO input -+#define DECODETO output // in place -+ -+ outsize = 64; -+ memcpy(output, out, outsize); -+ show(output, outsize, '<', '<'); -+ inpsize = aes_decode_data(output, outsize, DECODETO, key, 16, iv, flags); -+ show(DECODETO, inpsize, '>', '>'); -+ if (inpsize == outsize && memcmp(DECODETO, inp, inpsize) == 0) -+ printf("DECODER SUCCESS\n"); -+ else -+ printf("DECODER FAILURE\n"); -+} -+*/ -+ -+/* -+Some example vectors -+ -+================================ AES ECB 128-bit encryption mode ================================ -+ -+Encryption key: 2b7e151628aed2a6abf7158809cf4f3c -+ -+Test vector Cipher text -+6bc1bee22e409f96e93d7e117393172a 3ad77bb40d7a3660a89ecaf32466ef97 -+ae2d8a571e03ac9c9eb76fac45af8e51 f5d3d58503b9699de785895a96fdbaaf -+30c81c46a35ce411e5fbc1191a0a52ef 43b1cd7f598ece23881b00e3ed030688 -+f69f2445df4f9b17ad2b417be66c3710 7b0c785e27e8ad3f8223207104725dd4 -+ -+ -+================================ AES ECB 192-bit encryption mode ================================ -+ -+Encryption key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b -+ -+Test vector Cipher text -+6bc1bee22e409f96e93d7e117393172a bd334f1d6e45f25ff712a214571fa5cc -+ae2d8a571e03ac9c9eb76fac45af8e51 974104846d0ad3ad7734ecb3ecee4eef -+30c81c46a35ce411e5fbc1191a0a52ef ef7afd2270e2e60adce0ba2face6444e -+f69f2445df4f9b17ad2b417be66c3710 9a4b41ba738d6c72fb16691603c18e0e -+ -+ -+================================ AES ECB 256-bit encryption mode ================================ -+ -+Encryption key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 -+ -+Test vector Cipher text -+6bc1bee22e409f96e93d7e117393172a f3eed1bdb5d2a03c064b5a7e3db181f8 -+ae2d8a571e03ac9c9eb76fac45af8e51 591ccb10d410ed26dc5ba74a31362870 -+30c81c46a35ce411e5fbc1191a0a52ef b6ed21b99ca6f4f9f153e7b1beafed1d -+f69f2445df4f9b17ad2b417be66c3710 23304b7a39f9f3ff067d8d8f9e24ecc7 -+ -+================================ AES CBC 128-bit encryption mode ================================ -+ -+Encryption key: 2b7e151628aed2a6abf7158809cf4f3c -+ -+Initialization vector Test vector Cipher text -+000102030405060708090A0B0C0D0E0F 6bc1bee22e409f96e93d7e117393172a 7649abac8119b246cee98e9b12e9197d -+7649ABAC8119B246CEE98E9B12E9197D ae2d8a571e03ac9c9eb76fac45af8e51 5086cb9b507219ee95db113a917678b2 -+5086CB9B507219EE95DB113A917678B2 30c81c46a35ce411e5fbc1191a0a52ef 73bed6b8e3c1743b7116e69e22229516 -+73BED6B8E3C1743B7116E69E22229516 f69f2445df4f9b17ad2b417be66c3710 3ff1caa1681fac09120eca307586e1a7 -+ -+================================ AES CBC 192-bit encryption mode ================================ -+ -+Encryption key: 8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b -+ -+Initialization vector Test vector Cipher text -+000102030405060708090A0B0C0D0E0F 6bc1bee22e409f96e93d7e117393172a 4f021db243bc633d7178183a9fa071e8 -+4F021DB243BC633D7178183A9FA071E8 ae2d8a571e03ac9c9eb76fac45af8e51 b4d9ada9ad7dedf4e5e738763f69145a -+B4D9ADA9AD7DEDF4E5E738763F69145A 30c81c46a35ce411e5fbc1191a0a52ef 571b242012fb7ae07fa9baac3df102e0 -+571B242012FB7AE07FA9BAAC3DF102E0 f69f2445df4f9b17ad2b417be66c3710 08b0e27988598881d920a9e64f5615cd -+ -+================================ AES CBC 256-bit encryption mode ================================ -+ -+Encryption key: 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 -+ -+Initialization vector Test vector Cipher text -+000102030405060708090A0B0C0D0E0F 6bc1bee22e409f96e93d7e117393172a f58c4c04d6e5f1ba779eabfb5f7bfbd6 -+F58C4C04D6E5F1BA779EABFB5F7BFBD6 ae2d8a571e03ac9c9eb76fac45af8e51 9cfc4e967edb808d679f777bc6702c7d -+9CFC4E967EDB808D679F777BC6702C7D 30c81c46a35ce411e5fbc1191a0a52ef 39f23369a9d9bacfa530e26304231461 -+39F23369A9D9BACFA530E26304231461 f69f2445df4f9b17ad2b417be66c3710 b2eb05e2c39be9fcda6c19078c6a9d1b -+*/ -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilcrypt.h b/texk/web2c/luatexdir/luapplib/util/utilcrypt.h -new file mode 100644 -index 000000000..e5bf53cc5 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilcrypt.h -@@ -0,0 +1,90 @@ -+#ifndef UTIL_CRYPT_H -+#define UTIL_CRYPT_H -+ -+#include -+#include -+#include "utiliof.h" -+ -+#ifndef UTIL_CRYPT_TIME -+# define UTIL_CRYPT_TIME 0 -+#endif -+ -+/* RC4 */ -+ -+typedef uint8_t rc4_map[256]; -+ -+typedef struct rc4_state rc4_state; -+ -+#define RC4_STATE_ALLOC (1<<0) -+ -+UTILAPI rc4_state * rc4_state_initialize (rc4_state *state, rc4_map *map, const void *vkey, size_t keylength); -+#define rc4_state_init(state, vkey, keylength) rc4_state_initialize(state, NULL, vkey, keylength) -+UTILAPI void rc4_map_save (rc4_state *state, rc4_map *map); -+UTILAPI void rc4_map_restore (rc4_state *state, rc4_map *map); -+ -+/* Codecs operating on iof */ -+ -+UTILAPI iof_status rc4_crypt_state (iof *I, iof *O, rc4_state *state); -+#define rc4_encode_state(I, O, state) rc4_crypt_state(I, O, state) -+#define rc4_decode_state(I, O, state) rc4_crypt_state(I, O, state) -+ -+UTILAPI iof_status rc4_crypt (iof *I, iof *O, const void *key, size_t length); -+#define rc4_encode(I, O) rc4_crypt(I, O, key, length) -+#define rc4_decode(I, O) rc4_crypt(I, O, key, length) -+ -+UTILAPI size_t rc4_crypt_data (const void *input, size_t length, void *output, const void *key, size_t keylength); -+UTILAPI size_t rc4_crypt_state_data (rc4_state *state, const void *input, size_t length, void *output); -+#define rc4_encode_data(input, length, output, key, keylength) rc4_crypt_data(input, length, output, key, keylength) -+#define rc4_decode_data(input, length, output, key, keylength) rc4_crypt_data(input, length, output, key, keylength) -+#define rc4_encode_state_data(state, input, length, output) rc4_crypt_state_data(state, input, length, output) -+#define rc4_decode_state_data(state, input, length, output) rc4_crypt_state_data(state, input, length, output) -+ -+UTILAPI void rc4_state_close (rc4_state *state); -+ -+/* AES */ -+ -+typedef uint8_t aes_block[4][4]; -+typedef aes_block aes_keyblock[15]; // aes128 - 10+1, aes192 - 12+1, aes256 - 14+1 -+ -+typedef struct aes_state aes_state; -+ -+#define AES_STATE_ALLOC (1<<0) -+//#define AES_ECB_MODE (1<<2) -+#define AES_HAS_IV (1<<3) -+#define AES_INLINE_IV (1<<4) -+#define AES_CONTINUE (1<<5) -+#define AES_NULL_PADDING (1<<6) -+ -+UTILAPI void aes_pdf_mode (aes_state *state); -+//UTILAPI aes_state * aes_state_initialize_ecb (aes_state *State, uint8_t *roundkey, const uint8_t *key); -+UTILAPI aes_state * aes_encode_initialize (aes_state *state, aes_keyblock *keyblock, const void *key, size_t keylength, const void *iv); -+UTILAPI aes_state * aes_decode_initialize (aes_state *state, aes_keyblock *keyblock, const void *key, size_t keylength, const void *iv); -+#define aes_encode_init(state, key, keylength) aes_encode_initialize(state, NULL, key, keylength, NULL) -+#define aes_decode_init(state, key, keylength) aes_decode_initialize(state, NULL, key, keylength, NULL) -+ -+UTILAPI void aes_state_close (aes_state *state); -+ -+/* Codecs operating on iof */ -+ -+UTILAPI iof_status aes_encode_state (iof *I, iof *O, aes_state *state); -+UTILAPI iof_status aes_decode_state (iof *I, iof *O, aes_state *state); -+ -+UTILAPI size_t aes_encode_data (const void *input, size_t length, void *output, const void *key, size_t keylength, const void *iv, int flags); -+UTILAPI size_t aes_encode_state_data (aes_state *state, const void *input, size_t length, void *output); -+UTILAPI size_t aes_decode_data (const void *input, size_t length, void *output, const void *key, size_t keylength, const void *iv, int flags); -+UTILAPI size_t aes_decode_state_data (aes_state *state, const void *input, size_t length, void *output); -+ -+/* random bytes generator */ -+ -+UTILAPI void random_bytes (uint8_t *output, size_t size); -+UTILAPI void aes_generate_iv (uint8_t output[16]); -+ -+/* filters */ -+ -+iof * iof_filter_rc4_decoder (iof *N, const void *key, size_t keylength); -+iof * iof_filter_rc4_encoder (iof *N, const void *key, size_t keylength); -+ -+iof * iof_filter_aes_decoder (iof *N, const void *key, size_t keylength); -+iof * iof_filter_aes_encoder (iof *N, const void *key, size_t keylength); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilcryptdef.h b/texk/web2c/luatexdir/luapplib/util/utilcryptdef.h -new file mode 100644 -index 000000000..02d70aa5e ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilcryptdef.h -@@ -0,0 +1,30 @@ -+ -+#ifndef UTIL_CRYPTDEF_H -+#define UTIL_CRYPTDEF_H -+ -+struct rc4_state { -+ union { -+ rc4_map *map; -+ uint8_t *smap; -+ }; -+ int i, j; -+ int flush; -+ int flags; -+}; -+ -+struct aes_state { -+ size_t keylength; -+ int rounds; -+ //int keywords; -+ union { -+ aes_block block; -+ uint8_t data[16]; -+ }; -+ aes_keyblock *keyblock; -+ uint8_t iv[16]; -+ uint8_t buffered; -+ int flush; -+ int flags; -+}; -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utildecl.h b/texk/web2c/luatexdir/luapplib/util/utildecl.h -new file mode 100644 -index 000000000..94ef73413 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utildecl.h -@@ -0,0 +1,28 @@ -+ -+#ifndef UTIL_DECL_H -+#define UTIL_DECL_H -+ -+/* -+UTILDLL - when building .dll -+UTILEXE - when building .exe to import symbols from .dll -+*/ -+ -+#if defined (_WIN32) || defined(_WIN64) -+# ifdef UTILDLL -+# define UTILAPI __declspec(dllexport) -+# define UTILDEF __declspec(dllexport) -+# else -+# ifdef UTILEXE -+# define UTILAPI __declspec(dllimport) -+# define UTILDEF -+# else -+# define UTILAPI -+# define UTILDEF -+# endif -+# endif -+#else -+# define UTILAPI -+# define UTILDEF -+#endif -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilflate.c b/texk/web2c/luatexdir/luapplib/util/utilflate.c -new file mode 100644 -index 000000000..8ecc240c9 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilflate.c -@@ -0,0 +1,319 @@ -+ -+#include "utilmem.h" -+#include "utillog.h" -+#include "utilflate.h" -+#include -+ -+/* flate codec */ -+ -+/* -+Flate codec example provided at http://www.zlib.net/zpipe.c (http://www.zlib.net/zlib_how.html) uses the following scheme: -+- provide input data buffer -+- keep providing output until codec function uses it -+ -+For encoder: -+ -+ z->zalloc = z->zfree = z->zopaque = NULL; -+ deflateInit(z, compression_level); -+ do { -+ z->next_in = -+ z->avail_in = -+ do { -+ z->next_out = -+ z->avail_out = -+ deflate(z, flush); -+ // write obtained output from deflate -+ } while (z->avail_out == 0); -+ assert(z->avail_in == 0); -+ } while (flush != Z_FINISH); -+ deflateEnd(z); -+ -+'z' is an internal codec state of type z_stream, 'flush' is either Z_NO_FLUSH or Z_FINISH at the end of data. -+deflate() ensures to consume the entire input if there are no obstackles to write an output. The inner loop -+provides an output space as long as it is used by deflate(). When deflate() wrote everything it could, -+it leaves z->avail_out > 0, which breaks the inner loop. At this point z->avail_in should also be zero. -+The example documentation claims that the return codes from deflate() doesn't really need to be checked, -+as checking z->avail_out for zero is enough. -+ -+The scheme for decoder is pretty similar, but with substantial differences: -+- the end of stream is automatically found by decoder, so using Z_FINISH flag to indicate an end of stream -+ is not necessary, but if provided, it MUST be given only if the EOF marker actually occurs in the input chunk, -+ and subsequent calls to inflate() must consequently use Z_FINISH -+- calling inflate() as long as it uses the output buffer provided still works for decoder, but inflate() -+ does not ensure to consume the entire input, as it will read until end of stream marker -+- the return code from inflate() must be checked to ensure the proper reaction on invalid data stream and -+ end of stream signals -+- initialization must set an input buffer to NULL or to some existing chunk (the later helps zlib to perform -+ better on inflate(), but inflate() does the research on the first call anyway) -+ -+ z->zalloc = z->zfree = z->zopaque = NULL; -+ z->next_in = NULL, z->avail_in = 0; -+ inflateInit(z); -+ do { -+ z->next_in = -+ z->avail_in = -+ do { -+ z->next_out = -+ z->avail_out = -+ status = inflate(z, flush); -+ // check return status -+ // write obtained output from inflate -+ } while (z->avail_out == 0); -+ } while (status != Z_STREAM_END); -+ inflateEnd(z); -+ -+Our wrapper generally follows "prepare input, keep pomping output" scheme, but we need to support handler function -+breaks on IOFEMPTY and IOFFULL. For a consistent come back from those on subsequent calls to the handler function, -+we use 3 states: -+- FLATE_IN - get input, when got something then goto FALTE_OUT -+- FLATE_OUT - set z_stream buffers and keep writing output until enything to write, then goto FLATE_IN or FLATE_DONE -+- FLATE_DONE - we are done, no return from that state -+Distinction of FLATE_IN and FLATE_OUT states guarantees that we will not get more input until zlib consumes the stuff -+from the previous feed, possibly interrupted by IOFFULL return on filling the output buffer. This distinction is not -+critical, but makes the filter running according to the scheme described above. Note that we set zlib input buffer -+(z->next_in, z->avail_in) at the beginning of FLATE_OUT state. Also note that we always update our buffers according -+to updated avail_in / avail_out values, just after a call to inflate() / deflate(). So no matter what have happens -+between handler calls, zlib input buffer is in sync with ours. -+*/ -+ -+struct flate_state { -+ z_stream z; -+ int flush; -+ int status; -+ int level; /* encoder compression level -1..9 */ -+}; -+ -+enum { -+ FLATE_IN, -+ FLATE_OUT, -+ FLATE_DONE -+}; -+ -+flate_state * flate_decoder_init (flate_state *state) -+{ /* initialize zlib */ -+ z_stream *z = &state->z; -+ z->zalloc = Z_NULL; -+ z->zfree = Z_NULL; -+ z->opaque = Z_NULL; -+ z->avail_in = 0; /* must be initialized before inflateInit() */ -+ z->next_in = Z_NULL; /* ditto */ -+ if (inflateInit(z) != Z_OK) -+ return NULL; -+ state->status = FLATE_IN; -+ return state; -+} -+ -+flate_state * flate_encoder_init (flate_state *state) -+{ -+ z_stream *z = &state->z; -+ z->zalloc = Z_NULL; -+ z->zfree = Z_NULL; -+ z->opaque = Z_NULL; -+ z->avail_in = 0; -+ z->next_in = Z_NULL; -+ state->level = Z_DEFAULT_COMPRESSION; // will probably be moved upward -+ if (deflateInit(z, state->level) != Z_OK) -+ return NULL; -+ state->status = FLATE_IN; -+ return state; -+} -+ -+static const char * zmess (int zstatus) -+{ -+ switch (zstatus) -+ { -+ case Z_OK: return "ok"; -+ case Z_STREAM_END: return "end of stream"; -+ case Z_BUF_ERROR: return "buffer error"; -+ case Z_STREAM_ERROR: return "stream error"; -+ case Z_NEED_DICT: return "need dict"; -+ case Z_DATA_ERROR: return "data error"; -+ case Z_MEM_ERROR: return "memory error"; -+ case Z_VERSION_ERROR: return "version error"; -+ case Z_ERRNO: return "io error"; -+ default: -+ break; -+ } -+ return "unknown error"; -+} -+ -+iof_status flate_decode_state (iof *I, iof *O, flate_state *state) -+{ -+ z_stream *z; -+ int zstatus = Z_OK; -+ z = &state->z; -+ while (state->status != FLATE_DONE) -+ { -+ if (state->status == FLATE_IN) -+ { -+ if (!iof_readable(I)) -+ return state->flush ? IOFERR : IOFEMPTY; -+ state->status = FLATE_OUT; -+ } -+ z->next_in = (Bytef *)I->pos; -+ z->avail_in = (uInt)iof_left(I); -+ do { -+ if (!iof_writable(O)) -+ return IOFFULL; -+ z->next_out = (Bytef *)O->pos; -+ z->avail_out = (uInt)iof_left(O); -+ zstatus = inflate(z, Z_NO_FLUSH); -+ I->pos += iof_left(I) - z->avail_in; -+ O->pos += iof_left(O) - z->avail_out; -+ switch (zstatus) -+ { -+ case Z_OK: -+ case Z_STREAM_END: -+ break; -+ default: -+ loggerf("flate decoder %s (%d)", zmess(zstatus), zstatus); -+ return IOFERR; -+ } -+ } while (z->avail_out == 0); -+ state->status = zstatus == Z_STREAM_END ? FLATE_DONE : FLATE_IN; -+ } -+ return IOFEOF; -+} -+ -+iof_status flate_encode_state (iof *I, iof *O, flate_state *state) -+{ -+ z_stream *z; -+ int zstatus; -+ z = &state->z; -+ while (state->status != FLATE_DONE) -+ { -+ if (state->status == FLATE_IN) -+ { -+ if (!iof_readable(I)) -+ if (!state->flush) -+ return IOFEMPTY; -+ state->status = FLATE_OUT; -+ } -+ z->next_in = (Bytef *)I->pos; -+ z->avail_in = (uInt)iof_left(I); -+ do { -+ if (!iof_writable(O)) -+ return IOFFULL; -+ z->next_out = (Bytef *)O->pos; -+ z->avail_out = (uInt)iof_left(O); -+ zstatus = deflate(z, state->flush ? Z_FINISH : Z_NO_FLUSH); -+ I->pos += iof_left(I) - z->avail_in; -+ O->pos += iof_left(O) - z->avail_out; -+ switch (zstatus) -+ { -+ case Z_OK: -+ case Z_STREAM_END: -+ break; -+ default: -+ loggerf("flate encoder %s (%d)", zmess(zstatus), zstatus); -+ return IOFERR; -+ } -+ } while (z->avail_out == 0); -+ state->status = state->flush ? FLATE_DONE : FLATE_IN; -+ } -+ return IOFEOF; -+} -+ -+ -+void flate_decoder_close (flate_state *state) -+{ -+ inflateEnd(&state->z); -+} -+ -+void flate_encoder_close (flate_state *state) -+{ -+ deflateEnd(&state->z); -+} -+ -+/* filter */ -+ -+// flate decoder function -+ -+static size_t flate_decoder (iof *F, iof_mode mode) -+{ -+ flate_state *state; -+ iof_status status; -+ size_t tail; -+ -+ state = iof_filter_state(flate_state *, F); -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ do { -+ status = flate_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "flate", status); -+ case IOFCLOSE: -+ flate_decoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// flate encoder function -+ -+static size_t flate_encoder (iof *F, iof_mode mode) -+{ -+ flate_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(flate_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = flate_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "flate", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ flate_encoder(F, IOFFLUSH); -+ flate_encoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+iof * iof_filter_flate_decoder (iof *N) -+{ -+ iof *I; -+ flate_state *state; -+ I = iof_filter_reader(flate_decoder, sizeof(flate_state), &state); -+ iof_setup_next(I, N); -+ if (flate_decoder_init(state) == NULL) -+ { -+ iof_discard(I); -+ return NULL; -+ } -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_flate_encoder (iof *N) -+{ -+ iof *O; -+ flate_state *state; -+ O = iof_filter_writer(flate_encoder, sizeof(flate_state), &state); -+ iof_setup_next(O, N); -+ if (flate_encoder_init(state) == NULL) -+ { -+ iof_discard(O); -+ return NULL; -+ } -+ return O; -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utilflate.h b/texk/web2c/luatexdir/luapplib/util/utilflate.h -new file mode 100644 -index 000000000..09bdd6661 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilflate.h -@@ -0,0 +1,21 @@ -+#ifndef UTIL_FLATE_H -+#define UTIL_FLATE_H -+ -+#include "utiliof.h" -+ -+typedef struct flate_state flate_state; -+ -+flate_state * flate_decoder_init (flate_state *state); -+flate_state * flate_encoder_init (flate_state *state); -+ -+iof_status flate_decode_state (iof *I, iof *O, flate_state *state); -+iof_status flate_encode_state (iof *I, iof *O, flate_state *state); -+ -+void flate_decoder_close (flate_state *state); -+void flate_encoder_close (flate_state *state); -+ -+iof * iof_filter_flate_decoder (iof *N); -+iof * iof_filter_flate_encoder (iof *N); -+ -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilfpred.c b/texk/web2c/luatexdir/luapplib/util/utilfpred.c -new file mode 100644 -index 000000000..ce9c129e2 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilfpred.c -@@ -0,0 +1,783 @@ -+/* predictor filters; common for flate and lzw */ -+ -+#include "utilmem.h" -+#include "utillog.h" -+#include "utilfpred.h" -+ -+/* -+Here we implement predictor filters used with flate and lzw compressions in PDF streams. The main idea of data prediction -+is to compute and output the differences between data records instead of this records. Adjacent pixels in images are usually -+similar, so differences between pixel values tends to be zero. And both Flate and LZW performs better when the input -+is rather smooth. Although a preliminary use of predictors is related to bitmap data, The actual need for predictor filter -+came from the fact that xref streams may also be predicted (usually with PNG up-predictor). -+ -+PDF specification allows to use several predictor algorithms, specified by /Predictor key in /DecodeParms dictionary: -+ -+ 1 - no predictor (default) -+ 2 - TIFF horizontal predictor -+ 10 - PNG none predictor -+ 11 - PNG sub predictor -+ 12 - PNG up predictor -+ 13 - PNG average predictor -+ 14 - PNG paeth predictor -+ -+All PNG predictors works on bytes, regardless the image color-depth. While encoding, every input data byte is decreased -+by the appropriate byte of the previous pixel. Even if the pixel does not fit a full byte, PNG predictors use an artificial -+pixel size rounded up to a full byte. PNG predictors utilizes previous (left) pixel, pixel above and previous to above -+pixel. In case of PNG, the type of the predictor is written on a dedicated byte on the beginning of every scanline. It -+means all predictor functions must maintain and information about left, above and left-above pixels. -+ -+Despite the same differencing idea, TIFF predictors are different. The prediction process bases on pixel components, -+which are not necessarily bytes (component of a pixel is added/substracted from a relevant component of a previous -+pixel). In TIFF predictor 2, only the previous (the left) pixel is taken into account, there is no need to keep -+an information about other surrounding pixels. Also there is no expicit algorithm marker in data; the same prediction -+method is applied to all input rows. -+ -+Not surprisingly, predictor encoders and decoders are pretty similar. Encoders take some input value and the previous -+input value (or 0 at the beginning of the scanline) and output a difference between them. Decoders takes an input value, -+previously decoded value (or zero) and outputs their sum. When encoding, the result is cast to the proper unsigned integer, -+when decoding, modulo 256 (or appropriate) is used, which makes encoding and decoding looseless. -+ -+Some extra bits trickery is involved in TIFF predictor function, when components doesn't fit bytes boundary. In that case, -+an input is treated as an bits stream. Every input byte is "buffered" in a larger integer, as its lower bits (from right). -+Every output value is taken from its higher (left) bits. In a special case of bits-per-component equal 1, we buffer all -+pixel bits and use XOR to compute bits difference between pixels. I've excerpted that trick from poppler, but I'm not -+really sure if it works any better, especially when the number of components per pixel is 1. In that case we do a hard -+bit-by-bit work anyway. -+ -+Predictor codecs state keeps a notion of surrounding pixels. PNG predictors uses left, up and upleft -+pixel data, while TIFF predictor (2) only needs the previous (left) pixel. Important to note that PNG -+predictors always work on bytes, no matter of color-depth (bits per component), while TIFF predictor -+works on pixel components, which not necessarily fits into a complete byte. However, for PNG predictor -+the size of a pixel still matters, because 'left' and 'upleft' refers to a corresponding pixel byte, -+not necessarily previous byte. -+ -+In PNG prediction, we record every pixel byte (in decoded form) in state->rowsave. At the end of a scanline -+we copy state->rowsave to state->rowup, so that in the next scanline we can access up-pixel byte. -+Left pixel byte is accessed as state->rowsave (the byte recently stored or virtual left edge byte \0). -+Up-left pixel byte is accessed via state->rowup, but with state->pixelsize offset (same as left byte, possibly \0 -+at the left edge of the row). Both state->rowup and state->rowsave has a safe span of pixelsize bytes on the left, -+that are permanently \0. -+*/ -+ -+#define predictor_component_t unsigned short -+#define predictor_pixel1b_t unsigned int -+ -+typedef struct predictor_state { -+ int default_predictor; /* default predictor indicator */ -+ int current_predictor; /* current predictor, possibly taken from algorithm marker in PNG data */ -+ int rowsamples; /* number of pixels in a scanline (/DecodeParms << /Columns ... >>) */ -+ int compbits; /* number of bits per component (/DecodeParms << /BitsPerComponent ... >>) */ -+ int components; /* number of components (/DecodeParms << /Colors ... >>) */ -+ uint8_t *buffer; /* temporary private buffer area */ -+ uint8_t *rowin; /* an input row buffer position */ -+ int rowsize; /* size of a current scanline in bytes (rounded up) */ -+ int rowend; /* an input buffer end position */ -+ int rowindex; /* an output buffer position */ -+ union { -+ struct { /* used by PNG predictor codecs */ -+ uint8_t *rowup, *rowsave; /* previous scanline buffers */ -+ int predictorbyte; /* flag indicating that algorithm byte is read/written */ -+ int pixelsize; /* number of bytes per pixel (rounded up) */ -+ }; -+ struct { /* used by TIFF predictor codecs */ -+ union { -+ predictor_component_t *prevcomp; /* an array of left pixel components */ -+ predictor_pixel1b_t *prevpixel; /* left pixel value stored on a single integer (for 1bit color-depth) */ -+ }; -+ int compin, compout; /* bit stream buffers */ -+ int bitsin, bitsout; /* bit stream counters */ -+ int sampleindex; /* pixel counter */ -+ int compindex; /* component counter */ -+ int pixbufsize; /* size of pixel buffer in bytes */ -+ }; -+ }; -+ int flush; -+ int status; -+} predictor_state; -+ -+enum { -+ STATUS_LAST = 0, -+ STATUS_CONTINUE = 1 // any value different then IOFEOF, IOFERR, ... -+}; -+ -+predictor_state * predictor_decoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits) -+{ -+ int rowsize, pixelsize; -+#define storage_pos(b, p, size) ((b = p), (p += size)) -+ uint8_t *buffer, *p; -+ size_t buffersize; -+ -+ pixelsize = (components * compbits + 7) >> 3; // to bytes, rounded up -+ rowsize = (rowsamples * components * compbits + 7) >> 3; -+ -+ state->default_predictor = state->current_predictor = predictor; -+ state->rowsamples = rowsamples; -+ state->components = components; -+ state->compbits = compbits; -+ -+ if (predictor == 2) -+ { /* tiff predictor */ -+ size_t compbuf, pixbuf; -+ compbuf = state->components * sizeof(predictor_component_t); -+ pixbuf = 1 * sizeof(predictor_pixel1b_t); -+ state->pixbufsize = (int)(compbuf > pixbuf ? compbuf : pixbuf); -+ buffersize = rowsize + state->pixbufsize; -+ buffer = (uint8_t *)util_calloc(buffersize, 1); -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ { /*memory leak */ -+ predictor_component_t *c; -+ if (state->pixbufsize%(sizeof(predictor_component_t))) { -+ c = malloc(state->pixbufsize - state->pixbufsize%(sizeof(predictor_component_t)) + sizeof(predictor_component_t) ); -+ } else { -+ c = malloc(state->pixbufsize); -+ } -+ memcpy(c,(state->rowin + rowsize),state->pixbufsize); -+ if (state->prevcomp){ -+ free(state->prevcomp); -+ } -+ state->prevcomp = c; -+ } -+#else -+ state->prevcomp = (predictor_component_t *)(state->rowin + rowsize); -+#endif -+ state->sampleindex = state->compindex = 0; -+ state->bitsin = state->bitsout = 0; -+ state->compin = state->compout = 0; -+ } -+ else -+ { /* png predictors */ -+ buffersize = (3 * rowsize + 2 * pixelsize + 1) * sizeof(uint8_t); -+ p = buffer = (uint8_t *)util_calloc(buffersize, 1); -+ storage_pos(state->rowin, p, 1 + rowsize); // one extra byte for prediction algorithm tag -+ p += pixelsize; // pixelsize extra bytes for virtual left pixel at the edge, eg. rowup[-1] (permanently \0) -+ storage_pos(state->rowup, p, rowsize); // actual row byte -+ p += pixelsize; // ditto -+ storage_pos(state->rowsave, p, rowsize); -+ state->pixelsize = pixelsize; -+ state->predictorbyte = 0; -+ } -+ state->buffer = buffer; -+ state->rowsize = rowsize; -+ state->rowindex = 0; -+ state->rowend = 0; -+ state->status = STATUS_CONTINUE; -+ return state; -+} -+ -+predictor_state * predictor_encoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits) -+{ -+ return predictor_decoder_init(state, predictor, rowsamples, components, compbits); -+} -+ -+void predictor_decoder_close (predictor_state *state) -+{ -+ util_free(state->buffer); -+} -+ -+void predictor_encoder_close (predictor_state *state) -+{ -+ util_free(state->buffer); -+} -+ -+/* -+Predictor type identifiers (pdf spec 76). lpdf doesn't hire the codec if predictor is 1. Predictor 15 indicates -+that the type of PNG prediction algorithm may change in subsequent lines. We always check algorithm marker anyway. -+*/ -+ -+enum predictor_code { -+ NONE_PREDICTOR = 1, -+ TIFF_PREDICTOR = 2, -+ PNG_NONE_PREDICTOR = 10, -+ PNG_SUB_PREDICTOR = 11, -+ PNG_UP_PREDICTOR = 12, -+ PNG_AVERAGE_PREDICTOR = 13, -+ PNG_PAETH_PREDICTOR = 14, -+ PNG_OPTIMUM_PREDICTOR = 15 -+}; -+ -+/* -+All predoctor codecs first read the entire data row into a buffer. This is not crucial for the process, -+but allows to separate read/write states. In particular, there is one place in which codec functions -+may return on EOD. -+*/ -+ -+#define start_row(state) (state->rowindex = 0, state->rowin = state->buffer) -+ -+static int read_scanline (predictor_state *state, iof *I, int size) -+{ -+ int rowtail, left; -+ while ((rowtail = size - state->rowend) > 0) -+ { -+ left = (int)iof_left(I); -+ if (left >= rowtail) -+ { -+ memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail); -+ state->rowend += rowtail; -+ I->pos += rowtail; -+ start_row(state); -+ break; -+ } -+ else -+ { -+ if ((rowtail = left) > 0) -+ { -+ memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail); -+ state->rowend += rowtail; -+ I->pos += rowtail; -+ } -+ if (iof_input(I) == 0) -+ { -+ if (state->rowend == 0) // no scanline to process, no more input -+ return state->flush ? IOFEOF : IOFEMPTY; -+ /* If we are here, there is an incomplete scanline in buffer: -+ - if there is a chance for more (state->flush == 0), than wait for more -+ - otherwise encode/decode the last incomplete line? -+ pdf spec p. 76 says that "A row occupies a whole number of bytes", -+ so this situation should be considered abnormal (not found so far). -+ */ -+ if (!state->flush) -+ return IOFEMPTY; -+ loggerf("incomplete scanline in predictor filter"); -+ //return IOFERR; -+ state->status = STATUS_LAST; -+ state->rowsize -= size - state->rowend; -+ start_row(state); -+ break; -+ } -+ } -+ } -+ return STATUS_CONTINUE; -+} -+ -+#define read_row(state, I, size, status) if ((status = read_scanline(state, I, size)) != STATUS_CONTINUE) return status -+ -+#define ensure_output_bytes(O, n) if (!iof_ensure(O, n)) return IOFFULL -+ -+#define tobyte(c) ((unsigned char)(c)) -+#define tocomp(c) ((unsigned short)(c)) -+ -+#define row_byte(state) (state->rowin[state->rowindex]) -+ -+#define up_pixel_byte(state) (state->rowup[state->rowindex]) -+#define upleft_pixel_byte(state) (state->rowup[state->rowindex - state->pixelsize]) -+#define left_pixel_byte(state) (state->rowsave[state->rowindex - state->pixelsize]) -+ -+#define save_pixel_byte(state, c) (state->rowsave[state->rowindex] = c) -+ -+#define left_pixel_component(state) (state->prevcomp[state->compindex]) // tiff predictor with 2, 4, 8, 16 components -+#define left_pixel_value(state) (state->prevpixel[0]) // tiff predictor with 1bit components -+ -+#define save_pixel_component(state, c) ((void)\ -+ ((state->prevcomp[state->compindex] = c), \ -+ (++state->compindex < state->components || (state->compindex = 0)))) -+ -+#define save_pixel_value(state, c) (state->prevpixel[0] = c) -+ -+/* Once the codec function is done with the scanline, we set imaginary left pixel data to zero, and reset row counters to -+zero in order to allow buffering another input scanline. */ -+ -+#define reset_row(state) state->rowend = 0 -+ -+#define reset_png_row(state) (memcpy(state->rowup, state->rowsave, state->rowsize), state->predictorbyte = 0, reset_row(state)) -+ -+#define reset_tiff_row(state) \ -+ memset(state->prevcomp, 0, state->pixbufsize), \ -+ state->bitsin = state->bitsout = 0, \ -+ state->compin = state->compout = 0, \ -+ reset_row(state), \ -+ state->sampleindex = state->compindex = 0 -+ -+/* PNG paeth predictor function; http://www.libpng.org/pub/png/book/chapter09.html -+Compute the base value p := left + up - upleft, then choose that byte the closest -+(of the smallest absolute difference) to the base value. Left byte has a precedence. */ -+ -+ -+static int paeth (predictor_state *state) -+{ -+ int p, p1, p2, p3; -+ p = left_pixel_byte(state) + up_pixel_byte(state) - upleft_pixel_byte(state); -+ p1 = p >= left_pixel_byte(state) ? (p - left_pixel_byte(state)) : (left_pixel_byte(state) - p); -+ p2 = p >= up_pixel_byte(state) ? (p - up_pixel_byte(state)) : (up_pixel_byte(state) - p); -+ p3 = p >= upleft_pixel_byte(state) ? (p - upleft_pixel_byte(state)) : (upleft_pixel_byte(state) - p); -+ return (p1 <= p2 && p1 <= p3) ? left_pixel_byte(state) : (p2 <= p3 ? up_pixel_byte(state) : upleft_pixel_byte(state)); -+} -+ -+/* predictor decoder */ -+ -+iof_status predictor_decode_state (iof *I, iof *O, predictor_state *state) -+{ -+ int status, c, d, outbytes; -+ while (state->status == STATUS_CONTINUE) -+ { -+ if (state->default_predictor >= 10) // PNG predictor? -+ { -+ read_row(state, I, state->rowsize + 1, status); -+ if (state->predictorbyte == 0) -+ { // we could actually check state->rowin <> state->buffer, but we need this flag for encoder anyway -+ state->current_predictor = row_byte(state) + 10; -+ state->predictorbyte = 1; -+ ++state->rowin; -+ } -+ } -+ else -+ { -+ read_row(state, I, state->rowsize, status); -+ } -+ switch (state->current_predictor) -+ { -+ case NONE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ iof_set(O, c); -+ } -+ reset_row(state); -+ break; -+ case TIFF_PREDICTOR: -+ switch (state->compbits) -+ { -+ case 1: -+ outbytes = (state->components + 7) >> 3; -+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) -+ { -+ ensure_output_bytes(O, outbytes); -+ while (state->bitsin < state->components) -+ { -+ state->compin = (state->compin << 8) | row_byte(state); -+ state->bitsin += 8; -+ ++state->rowindex; -+ } -+ state->bitsin -= state->components; -+ d = state->compin >> state->bitsin; -+ state->compin &= (1 << state->bitsin) - 1; -+ c = d ^ left_pixel_value(state); -+ save_pixel_value(state, c); -+ state->compout = (state->compout << state->components) | c; -+ state->bitsout += state->components; -+ while (state->bitsout >= 8) -+ { -+ state->bitsout -= 8; -+ iof_set(O, state->compout >> state->bitsout); -+ state->compout &= (1 << state->bitsout) - 1; -+ } -+ } -+ if (state->bitsout > 0) -+ { -+ ensure_output_bytes(O, 1); -+ iof_set(O, state->compin << (8 - state->bitsout)); -+ } -+ break; -+ case 2: case 4: -+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) -+ { -+ for ( ; state->compindex < state->components; ) // state->compindex is ++ed by save_pixel_component() -+ { -+ ensure_output_bytes(O, 1); -+ if (state->bitsin < state->compbits) -+ { -+ state->compin = (state->compin << 8) | row_byte(state); -+ state->bitsin += 8; -+ ++state->rowindex; -+ } -+ state->bitsin -= state->compbits; -+ d = state->compin >> state->bitsin; -+ state->compin &= (1 << state->bitsin) - 1; -+ c = (d + left_pixel_component(state)) & 0xff; -+ save_pixel_component(state, c); -+ state->compout = (state->compout << state->compbits) | c; -+ state->bitsout += state->compbits; -+ if (state->bitsout >= 8) -+ { -+ state->bitsout -= 8; -+ iof_set(O, state->compout >> state->bitsout); -+ state->compout &= (1 << state->bitsout) - 1; -+ } -+ } -+ } -+ if (state->bitsout > 0) -+ { -+ ensure_output_bytes(O, 1); -+ iof_set(O, state->compin << (8 - state->bitsout)); -+ } -+ break; -+ case 8: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = (row_byte(state) + left_pixel_component(state)) & 0xff; -+ save_pixel_component(state, c); -+ iof_set(O, c); -+ } -+ break; -+ case 16: -+ for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 2); -+ d = row_byte(state) << 8; -+ ++state->rowindex; -+ d |= row_byte(state); -+ c = (d + left_pixel_component(state)) & 0xff; -+ save_pixel_component(state, c); -+ iof_set2(O, c >> 8, c & 0xff); -+ } -+ break; -+ default: -+ return IOFERR; -+ } -+ reset_tiff_row(state); -+ break; -+ case PNG_NONE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ save_pixel_byte(state, c); // next row may need it -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_SUB_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = (row_byte(state) + left_pixel_byte(state)) & 0xff; -+ save_pixel_byte(state, c); -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_UP_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = (row_byte(state) + up_pixel_byte(state)) & 0xff; -+ save_pixel_byte(state, c); -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_AVERAGE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = (row_byte(state) + ((up_pixel_byte(state) + left_pixel_byte(state)) / 2)) & 0xff; -+ save_pixel_byte(state, c); -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_PAETH_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = (row_byte(state) + paeth(state)) & 0xff; -+ save_pixel_byte(state, c); -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ //case PNG_OPTIMUM_PREDICTOR: // valid as default_redictor, but not as algorithm identifier byte -+ default: -+ return IOFERR; -+ } -+ } -+ return state->status == STATUS_LAST ? IOFERR : IOFEOF; -+} -+ -+/* predictor encoder */ -+ -+iof_status predictor_encode_state (iof *I, iof *O, predictor_state *state) -+{ -+ int status, c, d, outbytes; -+ while (state->status == STATUS_CONTINUE) -+ { -+ read_row(state, I, state->rowsize, status); -+ if (state->current_predictor >= 10 && state->predictorbyte == 0) -+ { -+ ensure_output_bytes(O, 1); -+ iof_set(O, state->current_predictor - 10); -+ state->predictorbyte = 1; -+ } -+ switch (state->current_predictor) -+ { -+ case NONE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ iof_set(O, c); -+ } -+ reset_row(state); -+ break; -+ case TIFF_PREDICTOR: -+ switch (state->compbits) -+ { -+ case 1: -+ outbytes = (state->components + 7) >> 3; -+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) -+ { -+ ensure_output_bytes(O, outbytes); -+ while (state->bitsin < state->components) -+ { -+ state->compin = (state->compin << 8) | row_byte(state); -+ state->bitsin += 8; -+ ++state->rowindex; -+ } -+ state->bitsin -= state->components; -+ c = state->compin >> state->bitsin; -+ state->compin &= (1 << state->bitsin) - 1; -+ d = c ^ left_pixel_value(state); -+ save_pixel_value(state, c); -+ state->compout = (state->compout << state->components) | d; -+ state->bitsout += state->components; -+ while (state->bitsout >= 8) -+ { -+ state->bitsout -= 8; -+ iof_set(O, state->compout >> state->bitsout); -+ state->compout &= (1 << state->bitsout) - 1; -+ } -+ } -+ if (state->bitsout > 0) -+ { -+ ensure_output_bytes(O, 1); -+ iof_set(O, state->compin << (8 - state->bitsout)); -+ } -+ break; -+ case 2: case 4: -+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex) -+ { -+ for ( ; state->compindex < state->components; ) -+ { -+ ensure_output_bytes(O, 1); -+ if (state->bitsin < state->compbits) -+ { -+ state->compin = (state->compin << 8) | row_byte(state); -+ state->bitsin += 8; -+ ++state->rowindex; -+ } -+ state->bitsin -= state->compbits; -+ c = state->compin >> state->bitsin; -+ state->compin &= (1 << state->bitsin) - 1; -+ d = tocomp(c - left_pixel_component(state)); -+ save_pixel_component(state, c); -+ state->compout = (state->compout << state->compbits) | d; -+ state->bitsout += state->compbits; -+ if (state->bitsout >= 8) -+ { -+ state->bitsout -= 8; -+ iof_set(O, state->compout >> state->bitsout); -+ state->compout &= (1 << state->bitsout) - 1; -+ } -+ } -+ } -+ if (state->bitsout > 0) -+ { -+ ensure_output_bytes(O, 1); -+ iof_set(O, state->compin << (8 - state->bitsout)); -+ } -+ break; -+ case 8: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ d = tobyte(c - left_pixel_component(state)); -+ save_pixel_component(state, c); -+ iof_set(O, d); -+ } -+ break; -+ case 16: -+ for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 2); -+ c = row_byte(state) << 8; -+ ++state->rowindex; -+ c |= row_byte(state); -+ d = tocomp(c - left_pixel_component(state)); -+ save_pixel_component(state, c); -+ iof_set2(O, d >> 8, d & 0xff); -+ } -+ break; -+ default: -+ return IOFERR; -+ } -+ reset_tiff_row(state); -+ break; -+ case PNG_NONE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ save_pixel_byte(state, c); // next row may need it -+ iof_set(O, c); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_SUB_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ d = tobyte(c - left_pixel_byte(state)); -+ save_pixel_byte(state, c); -+ iof_set(O, d); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_OPTIMUM_PREDICTOR: // not worthy to perform optimization -+ case PNG_UP_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ d = tobyte(c - up_pixel_byte(state)); -+ save_pixel_byte(state, c); -+ iof_set(O, d); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_AVERAGE_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ d = tobyte(c - ((up_pixel_byte(state) + left_pixel_byte(state)) >> 1)); -+ save_pixel_byte(state, c); -+ iof_set(O, d); -+ } -+ reset_png_row(state); -+ break; -+ case PNG_PAETH_PREDICTOR: -+ for ( ; state->rowindex < state->rowsize; ++state->rowindex) -+ { -+ ensure_output_bytes(O, 1); -+ c = row_byte(state); -+ d = tobyte(c - paeth(state)); -+ save_pixel_byte(state, c); -+ iof_set(O, d); -+ } -+ reset_png_row(state); -+ break; -+ default: -+ return IOFERR; -+ } -+ } -+ return state->status == STATUS_LAST ? IOFERR : IOFEOF; -+} -+ -+iof_status predictor_decode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits) -+{ -+ predictor_state state; -+ int ret; -+ predictor_decoder_init(&state, predictor, rowsamples, components, compbits); -+ state.flush = 1; -+ ret = predictor_decode_state(I, O, &state); -+ predictor_decoder_close(&state); -+ return ret; -+} -+ -+iof_status predictor_encode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits) -+{ -+ predictor_state state; -+ int ret; -+ predictor_encoder_init(&state, predictor, rowsamples, components, compbits); -+ state.flush = 1; -+ ret = predictor_encode_state(I, O, &state); -+ predictor_encoder_close(&state); -+ return ret; -+} -+ -+/* filters */ -+ -+// predictor decoder function -+ -+static size_t predictor_decoder (iof *F, iof_mode mode) -+{ -+ predictor_state *state; -+ iof_status status; -+ size_t tail; -+ -+ state = iof_filter_state(predictor_state *, F); -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ do { -+ status = predictor_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "predictor", status); -+ case IOFCLOSE: -+ predictor_decoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// predictor encoder function -+ -+static size_t predictor_encoder (iof *F, iof_mode mode) -+{ -+ predictor_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(predictor_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = predictor_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "predictor", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ predictor_encoder(F, IOFFLUSH); -+ predictor_encoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+iof * iof_filter_predictor_decoder (iof *N, int predictor, int rowsamples, int components, int compbits) -+{ -+ iof *I; -+ predictor_state *state; -+ I = iof_filter_reader(predictor_decoder, sizeof(predictor_state), &state); -+ iof_setup_next(I, N); -+ if (predictor_decoder_init(state, predictor, rowsamples, components, compbits) == NULL) -+ { -+ iof_discard(I); -+ return NULL; -+ } -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_predictor_encoder (iof *N, int predictor, int rowsamples, int components, int compbits) -+{ -+ iof *O; -+ predictor_state *state; -+ O = iof_filter_writer(predictor_encoder, sizeof(predictor_state), &state); -+ iof_setup_next(O, N); -+ if (predictor_encoder_init(state, predictor, rowsamples, components, compbits) == NULL) -+ { -+ iof_discard(O); -+ return NULL; -+ } -+ return O; -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utilfpred.h b/texk/web2c/luatexdir/luapplib/util/utilfpred.h -new file mode 100644 -index 000000000..6ae2f8935 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilfpred.h -@@ -0,0 +1,23 @@ -+#ifndef UTIL_FILTER_PREDICTOR_H -+#define UTIL_FILTER_PREDICTOR_H -+ -+#include "utiliof.h" -+ -+typedef struct predictor_state predictor_state; -+ -+predictor_state * predictor_decoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits); -+predictor_state * predictor_encoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits); -+ -+void predictor_decoder_close (predictor_state *state); -+void predictor_encoder_close (predictor_state *state); -+ -+iof_status predictor_decode_state (iof *I, iof *O, predictor_state *state); -+iof_status predictor_encode_state (iof *I, iof *O, predictor_state *state); -+ -+iof_status predictor_decode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits); -+iof_status predictor_encode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits); -+ -+iof * iof_filter_predictor_decoder (iof *N, int predictor, int rowsamples, int components, int compbits); -+iof * iof_filter_predictor_encoder (iof *N, int predictor, int rowsamples, int components, int compbits); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utiliof.c b/texk/web2c/luatexdir/luapplib/util/utiliof.c -new file mode 100644 -index 000000000..7d07cf12d ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utiliof.c -@@ -0,0 +1,2949 @@ -+/* input/iutput stream */ -+ -+#include -+#include -+#include -+ -+#include "utilmem.h" -+#include "utillog.h" -+#include "utiliof.h" -+ -+/* commons */ -+ -+void * iof_copy_data (const void *data, size_t size) -+{ -+ return memcpy(util_malloc(size), data, size); -+} -+ -+uint8_t * iof_copy_file_data (const char *filename, size_t *psize) -+{ -+ FILE *file; -+ size_t size; -+ uint8_t *data; -+ if ((file = fopen(filename, "rb")) == NULL) -+ return NULL; -+ fseek(file, 0, SEEK_END); -+ size = (size_t)ftell(file); -+ data = (uint8_t *)util_malloc(size); -+ fseek(file, 0, SEEK_SET); -+ if ((*psize = fread(data, 1, size, file)) != size) -+ { -+ util_free(data); -+ data = NULL; -+ } -+ fclose(file); -+ return data; -+} -+ -+uint8_t * iof_copy_file_handle_data (FILE *file, size_t *psize) -+{ -+ size_t size; -+ uint8_t *data; -+ //long offset = ftell(file); // keep offset intact? -+ fseek(file, 0, SEEK_END); -+ size = (size_t)ftell(file); -+ data = (uint8_t *)util_malloc(size); -+ fseek(file, 0, SEEK_SET); -+ if ((*psize = fread(data, 1, size, file)) != size) -+ { -+ util_free(data); -+ data = NULL; -+ } -+ //fseek(file, offset, SEEK_SET) -+ return data; -+} -+ -+FILE * iof_get_file (iof *F) -+{ -+ if (F->flags & IOF_FILE) -+ return iof_file_get_file(F->iofile); -+ if (F->flags & IOF_FILE_HANDLE) -+ return F->file; -+ return NULL; -+} -+ -+const char * iof_status_kind (iof_status status) -+{ -+ switch (status) -+ { -+ case IOFEOF: -+ return "IOFEOF"; -+ case IOFERR: -+ return "IOFERR"; -+ case IOFEMPTY: -+ return "IOFEMPTY"; -+ case IOFFULL: -+ return "IOFFULL"; -+ default: -+ break; -+ } -+ return "(unknown)"; -+} -+ -+/* shared pseudofile */ -+ -+#define IOF_FILE_DEFAULTS 0 -+ -+iof_file * iof_file_new (FILE *file) -+{ -+ iof_file *iofile = (iof_file *)util_malloc(sizeof(iof_file)); -+ iof_file_set_fh(iofile, file); -+ iofile->offset = NULL; -+ iofile->size = 0; -+ iofile->name = NULL; -+ iofile->refcount = 0; -+ iofile->flags = IOF_FILE_DEFAULTS|IOF_ALLOC; -+ return iofile; -+} -+ -+iof_file * iof_file_init (iof_file *iofile, FILE *file) -+{ -+ iof_file_set_fh(iofile, file); -+ iofile->offset = NULL; -+ iofile->size = 0; -+ iofile->name = NULL; -+ iofile->refcount = 0; -+ iofile->flags = IOF_FILE_DEFAULTS; -+ return iofile; -+} -+ -+iof_file * iof_file_rdata (const void *data, size_t size) -+{ -+ iof_file *iofile = (iof_file *)util_malloc(sizeof(iof_file)); -+ iofile->rbuf = iofile->rpos = (const uint8_t *)data; -+ iofile->rend = iofile->rbuf + size; -+ iofile->offset = NULL; -+ iofile->size = 0; -+ iofile->name = NULL; -+ iofile->refcount = 0; -+ iofile->flags = IOF_FILE_DEFAULTS|IOF_ALLOC|IOF_DATA; -+ return iofile; -+} -+ -+iof_file * iof_file_rdata_init (iof_file *iofile, const void *data, size_t size) -+{ -+ iofile->rbuf = iofile->rpos = (const uint8_t *)data; -+ iofile->rend = iofile->rbuf + size; -+ iofile->offset = NULL; -+ iofile->size = 0; // letse keep it consequently set to zero (only for user disposal) -+ iofile->name = NULL; -+ iofile->refcount = 0; -+ iofile->flags = IOF_FILE_DEFAULTS|IOF_DATA; -+ return iofile; -+} -+ -+iof_file * iof_file_wdata (void *data, size_t size) -+{ -+ return iof_file_rdata((const void *)data, size); -+} -+ -+iof_file * iof_file_wdata_init (iof_file *iofile, void *data, size_t size) -+{ -+ return iof_file_rdata_init(iofile, (const void *)data, size); -+} -+ -+/* typical uses so far */ -+ -+iof_file * iof_file_reader_from_file_handle (iof_file *iofile, const char *filename, FILE *file, int preload, int closefile) -+{ -+ uint8_t *data; -+ size_t size; -+ -+ if (preload) -+ { -+ if ((data = iof_copy_file_handle_data(file, &size)) == NULL) -+ { -+ if (closefile) -+ fclose(file); -+ return NULL; -+ } -+ if (iofile == NULL) -+ iofile = iof_file_rdata(data, size); -+ else -+ iof_file_rdata_init(iofile, data, size); -+ iofile->flags |= IOF_BUFFER_ALLOC; -+ if (closefile) -+ fclose(file); -+ } -+ else -+ { -+ if (iofile == NULL) -+ iofile = iof_file_new(file); -+ else -+ iof_file_init(iofile, file); -+ if (closefile) -+ iofile->flags |= IOF_CLOSE_FILE; -+ } -+ if (filename != NULL) -+ iof_file_set_name(iofile, filename); -+ return iofile; -+} -+ -+iof_file * iof_file_reader_from_file (iof_file *iofile, const char *filename, int preload) -+{ -+ FILE *file; -+ if ((file = fopen(filename, "rb")) == NULL) -+ return NULL; -+ return iof_file_reader_from_file_handle(iofile, filename, file, preload, 1); -+} -+ -+iof_file * iof_file_reader_from_data (iof_file *iofile, const void *data, size_t size, int preload, int freedata) -+{ -+ void *newdata; -+ if (data == NULL) -+ return NULL; -+ if (preload) -+ { -+ newdata = iof_copy_data(data, size); -+ if (iofile == NULL) -+ iofile = iof_file_rdata(newdata, size); -+ else -+ iof_file_rdata_init(iofile, newdata, size); -+ iofile->flags |= IOF_BUFFER_ALLOC; -+ //if (freedata) // hardly makes sense... we can't free const void * -+ // util_free((void *)data); -+ } -+ else -+ { -+ if (iofile == NULL) -+ iofile = iof_file_rdata(data, size); -+ else -+ iof_file_rdata_init(iofile, data, size); -+ if (freedata) -+ iofile->flags |= IOF_BUFFER_ALLOC; -+ } -+ return iofile; -+} -+ -+/* -+iof_file * iof_file_writer_from_file (iof_file *iofile, const char *filename) -+{ -+ FILE *file; -+ if ((file = fopen(filename, "wb")) == NULL) -+ return NULL; -+ if (iofile == NULL) -+ iofile = iof_file_new(file); -+ else -+ iof_file_init(iofile, file); -+ iofile->flags |= IOF_CLOSE_FILE; -+ iof_file_set_name(iofile, filename); -+ return iofile; -+} -+*/ -+ -+/* -+Because of limited number of FILE* handles available, we may need to close contained handle -+between accessing it. In applications so far (fonts, images) we typically need the source -+to parse the file on creation and to rewrite or reload the data on dump. All iof_file api -+functions assume that iofile has FILE* opened. Reopening it on every access (ftell, fseek, -+read/write) makes no sense, as we would effectively loose control. If the caller invalidates -+iofile by closing and nulling its file handle, it is also responsible to reopen when necessary. -+*/ -+ -+int iof_file_close_input (iof_file *iofile) -+{ -+ FILE *file; -+ if (iofile->flags & IOF_DATA) -+ return 0; -+ if ((file = iof_file_get_fh(iofile)) == NULL) -+ return 0; -+ fclose(file); -+ iof_file_set_fh(iofile, NULL); -+ iofile->flags &= ~IOF_RECLOSE_FILE; -+ iofile->flags |= IOF_REOPEN_FILE; -+ return 1; -+} -+ -+int iof_file_reopen_input (iof_file *iofile) -+{ // returns true if iofile readable -+ FILE *file; -+ const char *filename; -+ if (iofile->flags & IOF_DATA) -+ return 1; -+ if ((file = iof_file_get_fh(iofile)) != NULL) -+ return 1; // if present, assumed readable -+ if ((filename = iofile->name) == NULL || (file = fopen(filename, "rb")) == NULL) -+ return 0; -+ iof_file_set_fh(iofile, file); -+ iofile->flags &= ~IOF_REOPEN_FILE; -+ iofile->flags |= IOF_RECLOSE_FILE; -+ return 1; -+} -+ -+/* freeing iof_file */ -+ -+void iof_file_free (iof_file *iofile) -+{ -+ FILE *file; -+ if (iofile->flags & IOF_DATA) -+ { -+ if (iofile->flags & IOF_BUFFER_ALLOC) -+ { -+ iofile->flags &= ~IOF_BUFFER_ALLOC; -+ if (iofile->buf != NULL) -+ { -+ util_free(iofile->buf); -+ iofile->buf = iofile->pos = iofile->end = NULL; -+ } -+ } -+ } -+ else if ((file = iof_file_get_fh(iofile)) != NULL) -+ { -+ if (iofile->flags & IOF_CLOSE_FILE) -+ fclose(file); -+ iof_file_set_fh(iofile, NULL); -+ } -+ iof_file_set_name(iofile, NULL); -+ if (iofile->flags & IOF_ALLOC) -+ util_free(iofile); -+} -+ -+/* set filename for reopen */ -+ -+void iof_file_set_name (iof_file *iofile, const char *name) -+{ -+ if (iofile->name != NULL) -+ util_free(iofile->name); -+ if (name != NULL) -+ iofile->name = iof_copy_data(name, strlen(name) + 1); -+ else -+ iofile->name = NULL; -+} -+ -+/* seek */ -+ -+int iof_file_seek (iof_file *iofile, long offset, int whence) -+{ -+ if (iofile->flags & IOF_DATA) -+ { -+ switch (whence) -+ { -+ case SEEK_SET: -+ if (offset >= 0 && iofile->buf + offset <= iofile->end) -+ { -+ iofile->pos = iofile->buf + offset; -+ return 0; -+ } -+ return -1; -+ case SEEK_CUR: -+ if ((offset >= 0 && iofile->pos + offset <= iofile->end) || (offset < 0 && iofile->pos + offset >= iofile->buf)) -+ { -+ iofile->pos += offset; -+ return 0; -+ } -+ return -1; -+ case SEEK_END: -+ if (offset <= 0 && iofile->end + offset >= iofile->buf) -+ { -+ iofile->pos = iofile->end + offset; -+ return 0; -+ } -+ return -1; -+ } -+ return -1; -+ } -+ return fseek(iof_file_get_fh(iofile), offset, whence); -+} -+ -+/* */ -+ -+long iof_file_tell (iof_file *iofile) -+{ -+ return (iofile->flags & IOF_DATA) ? (long)(iofile->pos - iofile->buf) : ftell(iof_file_get_fh(iofile)); -+} -+ -+size_t iof_file_size (iof_file *iofile) -+{ -+ long pos, size; -+ FILE *file; -+ if (iofile->flags & IOF_DATA) -+ return (size_t)iof_space(iofile); -+ file = iof_file_get_fh(iofile); -+ pos = ftell(file); -+ fseek(file, 0, SEEK_END); -+ size = ftell(file); -+ fseek(file, pos, SEEK_SET); -+ return size; -+} -+ -+int iof_file_eof (iof_file *iofile) -+{ -+ if (iofile->flags & IOF_DATA) -+ return iofile->pos == iofile->end ? -1 : 0; -+ return feof(iof_file_get_fh(iofile)); -+} -+ -+int iof_file_flush (iof_file *iofile) -+{ -+ if (iofile->flags & IOF_DATA) -+ return 0; -+ return fflush(iof_file_get_fh(iofile)); -+} -+ -+size_t iof_file_read (void *ptr, size_t size, size_t items, iof_file *iofile) -+{ -+ if (iofile->flags & IOF_DATA) -+ { -+ size_t bytes = size * items; -+ if (bytes > (size_t)iof_left(iofile)) -+ bytes = (size_t)iof_left(iofile); -+ memcpy(ptr, iofile->pos, bytes); -+ iofile->pos += bytes; -+ return bytes / size; // number of elements read -+ } -+ return fread(ptr, size, items, iof_file_get_fh(iofile)); -+} -+ -+static size_t iof_file_data_resizeto (iof_file *iofile, size_t space) -+{ -+ uint8_t *newbuf; -+ size_t size; -+ size = iof_size(iofile); -+ if (iofile->flags & IOF_BUFFER_ALLOC) -+ { -+ newbuf = (uint8_t *)util_realloc(iofile->buf, space); -+ } -+ else -+ { -+ newbuf = (uint8_t *)util_malloc(space); -+ if (size > 0) -+ memcpy(newbuf, iofile->buf, size); -+ iofile->flags |= IOF_BUFFER_ALLOC; -+ } -+ iofile->buf = newbuf; -+ iofile->pos = newbuf + size; -+ iofile->end = newbuf + space; -+ return space - size; -+} -+ -+#define iof_file_data_resize(iofile) iof_file_data_resizeto(iofile, iof_space(iofile) << 1) -+ -+size_t iof_file_write (const void *ptr, size_t size, size_t items, iof_file *iofile) -+{ -+ if (iofile->flags & IOF_DATA) -+ { -+ size_t space, sizesofar, bytes; -+ bytes = size * items; -+ if (bytes > (size_t)iof_left(iofile)) -+ { -+ if ((space = iof_space(iofile)) == 0) // allow iofile->buf/end initially NULL -+ space = BUFSIZ; -+ for (sizesofar = iof_size(iofile), space <<= 1; sizesofar + bytes > space; space <<= 1) -+ ; -+ if (iof_file_data_resizeto(iofile, space) == 0) -+ return 0; -+ } -+ memcpy(iofile->pos, ptr, bytes); -+ iofile->pos += bytes; -+ return bytes / size; -+ } -+ return fwrite(ptr, size, items, iof_file_get_fh(iofile)); -+} -+ -+size_t iof_file_ensure (iof_file *iofile, size_t bytes) -+{ -+ if (iofile->flags & IOF_DATA) -+ { -+ size_t space, sizesofar, left; -+ left = (size_t)iof_left(iofile); -+ if (bytes > left) -+ { -+ if ((space = iof_space(iofile)) == 0) // allow iofile->buf/end initially NULL -+ space = BUFSIZ; -+ for (sizesofar = iof_size(iofile), space <<= 1; sizesofar + bytes > space; space <<= 1); -+ return iof_file_data_resizeto(iofile, space); -+ } -+ return left; -+ } -+ return 0; -+} -+ -+int iof_file_getc (iof_file *iofile) -+{ -+ if (iofile->flags & IOF_DATA) -+ return iofile->pos < iofile->end ? *iofile->pos++ : IOFEOF; -+ return fgetc(iof_file_get_fh(iofile)); -+} -+ -+int iof_file_putc (iof_file *iofile, int c) -+{ -+ if (iofile->flags & IOF_DATA) -+ { -+ if (iofile->pos >= iofile->end) -+ if (iof_file_data_resize(iofile) == 0) -+ return IOFEOF; -+ *iofile->pos++ = (uint8_t)c; -+ return c; -+ } -+ return fputc(c, iof_file_get_fh(iofile)); -+} -+ -+static int iof_file_sync (iof_file *iofile, size_t *offset) -+{ -+ if (iofile->offset != offset) -+ { -+ if (iofile->offset != NULL) -+ *iofile->offset = iof_file_tell(iofile); -+ iofile->offset = offset; -+ if (offset) // let offset be NULL -+ return iof_file_seek(iofile, (long)*offset, SEEK_SET); -+ } -+ return 0; -+} -+ -+//#define iof_file_unsync(iofile, poffset) (void)((iofile)->offset == poffset && (((iofile)->offset = NULL), 0)) -+#define iof_file_unsync(iofile, poffset) ((void)poffset, (iofile)->offset = NULL) -+ -+/* iof seek */ -+ -+#define iof_reader_reset(I) ((I)->pos = (I)->end = (I)->buf) -+#define iof_reader_reseek_file(I, offset, whence) (fseek((I)->file, offset, whence) == 0 ? (iof_reader_reset(I), 0) : -1) -+#define iof_reader_reseek_iofile(I, offset, whence) (iof_file_seek((I)->iofile, offset, whence) == 0 ? (iof_reader_reset(I), 0) : -1) -+ -+#define iof_writer_reset(O) ((O)->pos = (O)->buf) -+#define iof_writer_reseek_file(O, offset, whence) (iof_flush(O), (fseek((O)->file, offset, whence) == 0 ? (iof_writer_reset(O), 0) : -1)) -+#define iof_writer_reseek_iofile(O, offset, whence) (iof_flush(O), (iof_file_seek((O)->iofile, offset, whence) == 0 ? (iof_writer_reset(O), 0) : -1)) -+ -+static int iof_reader_seek_data (iof *I, long offset, int whence) -+{ -+ switch (whence) -+ { -+ case SEEK_SET: -+ if (offset >= 0 && I->buf + offset <= I->end) -+ { -+ I->pos = I->buf + offset; -+ return 0; -+ } -+ return -1; -+ case SEEK_CUR: -+ if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) -+ { -+ I->pos += offset; -+ return 0; -+ } -+ return -1; -+ case SEEK_END: -+ if (offset <= 0 && I->end + offset >= I->buf) -+ { -+ I->pos = I->end + offset; -+ return 0; -+ } -+ return -1; -+ } -+ return -1; -+} -+ -+static int iof_reader_seek_iofile (iof *I, long offset, int whence) -+{ -+ long fileoffset; -+ switch (whence) -+ { -+ case SEEK_SET: -+ fileoffset = iof_file_tell(I->iofile); -+ if (offset <= fileoffset && offset >= fileoffset - iof_space(I)) -+ { -+ I->pos = I->end - (fileoffset - offset); -+ return 0; -+ } -+ return iof_reader_reseek_iofile(I, offset, SEEK_SET); -+ case SEEK_CUR: -+ if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) -+ { -+ I->pos += offset; -+ return 0; -+ } -+ return iof_reader_reseek_iofile(I, offset, SEEK_CUR); -+ case SEEK_END: -+ return iof_reader_reseek_iofile(I, offset, SEEK_END); // can we do better? -+ } -+ return -1; -+} -+ -+static int iof_reader_seek_file (iof *I, long offset, int whence) -+{ -+ long fileoffset; -+ switch (whence) -+ { -+ case SEEK_SET: -+ fileoffset = ftell(I->file); -+ if (offset <= fileoffset && offset >= fileoffset - iof_space(I)) -+ { -+ I->pos = I->end - (fileoffset - offset); -+ return 0; -+ } -+ return iof_reader_reseek_file(I, offset, SEEK_SET); -+ case SEEK_CUR: -+ if ((offset >= 0 && I->pos + offset <= I->end) || (offset < 0 && I->pos + offset >= I->buf)) -+ { -+ I->pos += offset; -+ return 0; -+ } -+ return iof_reader_reseek_file(I, offset, SEEK_CUR); -+ case SEEK_END: -+ return iof_reader_reseek_file(I, offset, SEEK_END); // can we do better? -+ } -+ return -1; -+} -+ -+int iof_reader_seek (iof *I, long offset, int whence) -+{ -+ I->flags &= ~IOF_STOPPED; -+ if (I->flags & IOF_FILE) -+ return iof_reader_seek_iofile(I, offset, whence); -+ if (I->flags & IOF_FILE_HANDLE) -+ return iof_reader_seek_file(I, offset, whence); -+ if (I->flags & IOF_DATA) -+ return iof_reader_seek_data(I, offset, whence); -+ return -1; -+} -+ -+int iof_reader_reseek (iof *I, long offset, int whence) -+{ -+ I->flags &= ~IOF_STOPPED; -+ if (I->flags & IOF_FILE) -+ return iof_reader_reseek_iofile(I, offset, whence); -+ if (I->flags & IOF_FILE_HANDLE) -+ return iof_reader_reseek_file(I, offset, whence); -+ if (I->flags & IOF_DATA) -+ return iof_reader_seek_data(I, offset, whence); -+ return -1; -+} -+ -+static int iof_writer_seek_data (iof *O, long offset, int whence) -+{ -+ /* -+ fseek() allows to seek after the end of file. Seeking does not increase the output file. -+ No byte is written before fwirte(). It seems to fill the gap with zeros. Until we really need that, -+ no seeking out of bounds for writers. -+ */ -+ O->flags &= ~IOF_STOPPED; -+ return iof_reader_seek_data(O, offset, whence); -+} -+ -+static int iof_writer_seek_iofile (iof *O, long offset, int whence) -+{ -+ long fileoffset; -+ switch (whence) -+ { -+ case SEEK_SET: -+ fileoffset = iof_file_tell(O->iofile); -+ if (offset >= fileoffset && offset <= fileoffset + iof_space(O)) -+ { -+ O->pos = O->buf + (offset - fileoffset); -+ return 0; -+ } -+ return iof_writer_reseek_iofile(O, offset, SEEK_SET); -+ case SEEK_CUR: -+ if ((offset >=0 && O->pos + offset <= O->end) || (offset < 0 && O->pos + offset >= O->buf)) -+ { -+ O->pos += offset; -+ return 0; -+ } -+ return iof_writer_reseek_iofile(O, offset, SEEK_CUR); -+ case SEEK_END: -+ return iof_writer_reseek_iofile(O, offset, SEEK_END); -+ } -+ return -1; -+} -+ -+static int iof_writer_seek_file (iof *O, long offset, int whence) -+{ -+ long fileoffset; -+ switch (whence) -+ { -+ case SEEK_SET: -+ fileoffset = ftell(O->file); -+ if (offset >= fileoffset && offset <= fileoffset + iof_space(O)) -+ { -+ O->pos = O->buf + (offset - fileoffset); -+ return 0; -+ } -+ return iof_writer_reseek_file(O, offset, SEEK_SET); -+ case SEEK_CUR: -+ if ((offset >=0 && O->pos + offset <= O->end) || (offset < 0 && O->pos + offset >= O->buf)) -+ { -+ O->pos += offset; -+ return 0; -+ } -+ return iof_writer_reseek_file(O, offset, SEEK_CUR); -+ case SEEK_END: -+ return iof_writer_reseek_file(O, offset, SEEK_END); -+ } -+ return -1; -+} -+ -+int iof_writer_seek (iof *I, long offset, int whence) -+{ -+ I->flags &= ~IOF_STOPPED; -+ if (I->flags & IOF_FILE) -+ return iof_writer_seek_iofile(I, offset, whence); -+ if (I->flags & IOF_FILE_HANDLE) -+ return iof_writer_seek_file(I, offset, whence); -+ if (I->flags & IOF_DATA) -+ return iof_writer_seek_data(I, offset, whence); -+ return -1; -+} -+ -+int iof_writer_reseek (iof *I, long offset, int whence) -+{ -+ I->flags &= ~IOF_STOPPED; -+ if (I->flags & IOF_FILE) -+ return iof_writer_reseek_iofile(I, offset, whence); -+ if (I->flags & IOF_FILE_HANDLE) -+ return iof_writer_reseek_file(I, offset, whence); -+ if (I->flags & IOF_DATA) -+ return iof_writer_seek_data(I, offset, whence); -+ return -1; -+} -+ -+int iof_seek (iof *F, long offset, int whence) -+{ -+ return (F->flags & IOF_WRITER) ? iof_writer_seek(F, offset, whence) : iof_reader_seek(F, offset, whence); -+} -+ -+int iof_reseek (iof *F, long offset, int whence) -+{ -+ return (F->flags & IOF_WRITER) ? iof_writer_reseek(F, offset, whence) : iof_reader_reseek(F, offset, whence); -+} -+ -+/* tell */ -+ -+long iof_reader_tell (iof *I) -+{ -+ if (I->flags & IOF_FILE) -+ return iof_file_tell(I->iofile) - (long)iof_left(I); -+ if (I->flags & IOF_FILE_HANDLE) -+ return ftell(I->file) - (long)iof_left(I); -+ //if (I->flags & IOF_DATA) -+ return (long)iof_size(I); -+} -+ -+long iof_writer_tell (iof *O) -+{ -+ if (O->flags & IOF_FILE) -+ return iof_file_tell(O->iofile) + (long)iof_size(O); -+ if (O->flags & IOF_FILE_HANDLE) -+ return ftell(O->file) + (long)iof_size(O); -+ //if (I->flags & IOF_DATA) -+ return (long)iof_size(O); -+} -+ -+long iof_tell (iof *I) -+{ -+ return (I->flags & IOF_WRITER) ? iof_writer_tell(I) : iof_reader_tell(I); -+} -+ -+size_t iof_fsize (iof *I) -+{ -+ size_t pos, size; -+ if (I->flags & IOF_FILE) -+ return iof_file_size(I->iofile); -+ if (I->flags & IOF_FILE_HANDLE) -+ { -+ pos = (size_t)ftell(I->file); -+ fseek(I->file, 0, SEEK_END); -+ size = (size_t)ftell(I->file); -+ fseek(I->file, (long)pos, SEEK_SET); -+ return size; -+ } -+ //if (I->flags & IOF_DATA) -+ return (size_t)iof_space(I); -+} -+ -+/* save reader tail */ -+ -+size_t iof_save_tail (iof *I) -+{ -+ size_t size, left; -+ size = iof_size(I); -+ left = iof_left(I); -+ if (size >= left) -+ memcpy(I->buf, I->pos, left); -+ else -+ memmove(I->buf, I->pos, left); -+ return left; -+} -+ -+size_t iof_input_save_tail (iof *I, size_t back) -+{ -+ size_t size; -+ I->flags |= IOF_TAIL; -+ I->pos -= back; -+ size = iof_input(I); -+ I->pos += back; -+ I->flags &= ~IOF_TAIL; -+ return size; // + back - back -+} -+ -+/* read from file */ -+ -+/* iof free*/ -+ -+static size_t file_read (iof *I); -+static size_t file_load (iof *I); -+ -+static size_t file_reader (iof *I, iof_mode mode) -+{ -+ switch (mode) -+ { -+ case IOFREAD: -+ return file_read(I); -+ case IOFLOAD: -+ return file_load(I); -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_setup_file_handle_reader (iof *I, void *buffer, size_t space, FILE *f) -+{ -+ if (I == NULL) -+ iof_setup_reader(I, buffer, space); -+ else -+ iof_reader_buffer(I, buffer, space); -+ iof_setup_file(I, f); -+ I->more = file_reader; -+ return I; -+} -+ -+iof * iof_setup_file_reader (iof *I, void *buffer, size_t space, const char *filename) -+{ -+ FILE *f; -+ if ((f = fopen(filename, "rb")) == NULL) -+ return NULL; -+ if (I == NULL) -+ iof_setup_reader(I, buffer, space); -+ else -+ iof_reader_buffer(I, buffer, space); -+ iof_setup_file(I, f); -+ I->flags |= IOF_CLOSE_FILE; -+ I->more = file_reader; -+ return I; -+} -+ -+/* write to file */ -+ -+static size_t file_write (iof *O, int flush); -+ -+static size_t file_writer (iof *O, iof_mode mode) -+{ -+ switch (mode) -+ { -+ case IOFWRITE: -+ return file_write(O, 0); -+ case IOFFLUSH: -+ return file_write(O, 1); -+ case IOFCLOSE: -+ file_write(O, 1); -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_setup_file_handle_writer (iof *O, void *buffer, size_t space, FILE *f) -+{ -+ if (O == NULL) -+ iof_setup_writer(O, buffer, space); -+ else -+ iof_writer_buffer(O, buffer, space); -+ iof_setup_file(O, f); -+ O->more = file_writer; -+ return O; -+} -+ -+iof * iof_setup_file_writer (iof *O, void *buffer, size_t space, const char *filename) -+{ -+ FILE *f; -+ if ((f = fopen(filename, "wb")) == NULL) -+ return NULL; -+ if (O == NULL) -+ iof_setup_writer(O, buffer, space); -+ else -+ iof_writer_buffer(O, buffer, space); -+ iof_setup_file(O, f); -+ O->flags |= IOF_CLOSE_FILE; -+ O->more = file_writer; -+ return O; -+} -+ -+/* a dedicated handler for stdout/stderr */ -+ -+static size_t stdout_writer (iof *O, iof_mode mode) -+{ -+ switch(mode) -+ { -+ case IOFWRITE: -+ { -+ fwrite(O->buf, sizeof(uint8_t), iof_size(O), stdout); -+ O->pos = O->buf; -+ return O->space; -+ } -+ case IOFCLOSE: -+ case IOFFLUSH: -+ { -+ fwrite(O->buf, sizeof(uint8_t), iof_size(O), stdout); -+ fflush(stdout); -+ O->pos = O->buf; -+ return 0; -+ } -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static size_t stderr_writer (iof *O, iof_mode mode) -+{ -+ switch(mode) -+ { -+ case IOFWRITE: -+ { -+ fwrite(O->buf, sizeof(uint8_t), iof_size(O), stderr); -+ O->pos = O->buf; -+ return O->space; -+ } -+ case IOFCLOSE: -+ case IOFFLUSH: -+ { -+ fwrite(O->buf, sizeof(uint8_t), iof_size(O), stderr); -+ fflush(stderr); -+ O->pos = O->buf; -+ return 0; -+ } -+ default: -+ break; -+ } -+ return 0; -+} -+ -+static uint8_t iof_stdout_buffer[BUFSIZ]; -+iof iof_stdout = IOF_WRITER_STRUCT(stdout_writer, NULL, iof_stdout_buffer, BUFSIZ, 0); -+ -+static uint8_t iof_stderr_buffer[BUFSIZ]; -+iof iof_stderr = IOF_WRITER_STRUCT(stderr_writer, NULL, iof_stderr_buffer, BUFSIZ, 0); -+ -+/* read from somewhere */ -+ -+iof * iof_reader (iof *I, void *link, iof_handler reader, const void *m, size_t bytes) -+{ -+ I->space = 0; -+ I->link = link; -+ I->more = reader; -+ I->flags = 0; -+ I->refcount = 0; -+ if (m != NULL) -+ { -+ I->rbuf = I->rpos = (const uint8_t *)m; -+ I->rend = (const uint8_t *)m + bytes; -+ return I; -+ } -+ return NULL; -+} -+ -+iof * iof_string_reader (iof *I, const void *s, size_t bytes) -+{ -+ I->space = 0; -+ I->link = NULL; -+ I->more = NULL; -+ I->flags = 0; // iof_string() sets IOF_DATA -+ I->refcount = 0; -+ if (s != NULL) -+ return iof_string(I, s, bytes); -+ return NULL; -+} -+ -+/* write somewhere */ -+ -+iof * iof_writer (iof *O, void *link, iof_handler writer, void *m, size_t bytes) -+{ -+ O->space = 0; -+ O->link = link; -+ O->more = writer; -+ O->flags = 0; -+ O->refcount = 0; -+ if (m != NULL && bytes > 0) -+ { -+ O->buf = O->pos = (uint8_t *)m; -+ O->end = (uint8_t *)m + bytes; -+ return O; -+ } -+ // return iof_null(O); -+ return NULL; -+} -+ -+/* write to growing bytes buffer */ -+ -+static size_t iof_mem_handler (iof *O, iof_mode mode) -+{ -+ switch(mode) -+ { -+ case IOFWRITE: -+ return iof_resize_buffer(O); -+ case IOFCLOSE: -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_setup_buffer (iof *O, void *buffer, size_t space) -+{ -+ if (O == NULL) -+ iof_setup_writer(O, buffer, space); -+ else -+ iof_writer_buffer(O, buffer, space); -+ O->link = NULL; -+ O->flags |= IOF_DATA; -+ O->more = iof_mem_handler; -+ return O; -+} -+ -+iof * iof_setup_buffermin (iof *O, void *buffer, size_t space, size_t min) -+{ -+ if ((O = iof_setup_buffer(O, buffer, space)) != NULL && space < min) // just allocate min now to avoid further rewriting -+ { -+ O->buf = O->pos = (uint8_t *)util_malloc(min); -+ O->flags |= IOF_BUFFER_ALLOC; -+ O->end = O->buf + min; -+ } -+ return O; -+} -+ -+iof * iof_buffer_create (size_t space) -+{ -+ uint8_t *buffer; -+ iof *O; -+ space += sizeof(iof); -+ buffer = util_malloc(space); -+ if ((O = iof_setup_buffer(NULL, buffer, space)) != NULL) -+ O->flags |= IOF_ALLOC; -+ return O; -+} -+ -+/* set/get */ -+ -+int iof_getc (iof *I) -+{ -+ if (iof_readable(I)) -+ return *I->pos++; -+ return IOFEOF; -+} -+ -+int iof_putc (iof *O, int u) -+{ -+ if (iof_writable(O)) -+ { -+ iof_set(O, u); -+ return (uint8_t)u; -+ } -+ return IOFFULL; -+} -+ -+size_t iof_skip (iof *I, size_t bytes) -+{ -+ while (bytes) -+ { -+ if (iof_readable(I)) -+ ++I->pos; -+ else -+ break; -+ --bytes; -+ } -+ return bytes; -+} -+ -+/* from iof to iof */ -+ -+iof_status iof_pass (iof *I, iof *O) -+{ -+ size_t leftin, leftout; -+ if ((leftin = iof_left(I)) == 0) -+ leftin = iof_input(I); -+ while (leftin) -+ { -+ if ((leftout = iof_left(O)) == 0) -+ if ((leftout = iof_output(O)) == 0) -+ return IOFFULL; -+ while (leftin > leftout) -+ { -+ memcpy(O->pos, I->pos, leftout); -+ I->pos += leftout; -+ O->pos = O->end; /* eq. += leftout */ -+ leftin -= leftout; -+ if ((leftout = iof_output(O)) == 0) -+ return IOFFULL; -+ } -+ if (leftin) -+ { -+ memcpy(O->pos, I->pos, leftin); -+ I->pos = I->end; /* eq. += leftin */ -+ O->pos += leftin; -+ } -+ leftin = iof_input(I); -+ } -+ return IOFEOF; -+} -+ -+/* read n-bytes */ -+ -+size_t iof_read (iof *I, void *to, size_t size) -+{ -+ size_t leftin, done = 0; -+ char *s = (char *)to; -+ -+ if ((leftin = iof_left(I)) == 0) -+ if ((leftin = iof_input(I)) == 0) -+ return done; -+ while (size > leftin) -+ { -+ memcpy(s, I->pos, leftin * sizeof(uint8_t)); -+ size -= leftin; -+ done += leftin; -+ s += leftin; -+ I->pos = I->end; -+ if ((leftin = iof_input(I)) == 0) -+ return done; -+ } -+ if (size) -+ { -+ memcpy(s, I->pos, size * sizeof(uint8_t)); -+ I->pos += size; -+ done += size; -+ } -+ return done; -+} -+ -+/* rewrite FILE content (use fseek if needed) */ -+ -+size_t iof_write_file_handle (iof *O, FILE *file) -+{ -+ size_t leftout, size, readout; -+ if ((leftout = iof_left(O)) == 0) -+ if ((leftout = iof_output(O)) == 0) -+ return 0; -+ size = 0; -+ do { -+ readout = fread(O->pos, 1, leftout, file); -+ O->pos += readout; -+ size += readout; -+ } while(readout == leftout && (leftout = iof_output(O)) > 0); -+ return size; -+} -+ -+size_t iof_write_file (iof *O, const char *filename) -+{ -+ FILE *file; -+ size_t size; -+ if ((file = fopen(filename, "rb")) == NULL) -+ return 0; -+ size = iof_write_file_handle(O, file); -+ fclose(file); -+ return size; -+} -+ -+size_t iof_write_iofile (iof *O, iof_file *iofile, int savepos) -+{ -+ long offset; -+ size_t size; -+ FILE *file; -+ if (iofile->flags & IOF_DATA) -+ return iof_write(O, iofile->pos, (size_t)(iofile->end - iofile->pos)); -+ file = iof_file_get_fh(iofile); -+ if (savepos) -+ { -+ offset = ftell(file); -+ size = iof_write_file_handle(O, file); -+ fseek(file, offset, SEEK_SET); -+ return size; -+ } -+ return iof_write_file_handle(O, file); -+} -+ -+/* write n-bytes */ -+ -+size_t iof_write (iof *O, const void *data, size_t size) -+{ -+ size_t leftout, done = 0; -+ const char *s = (const char *)data; -+ if ((leftout = iof_left(O)) == 0) -+ if ((leftout = iof_output(O)) == 0) -+ return done; -+ while (size > leftout) -+ { -+ memcpy(O->pos, s, leftout * sizeof(uint8_t)); -+ size -= leftout; -+ done += leftout; -+ s += leftout; -+ O->pos = O->end; -+ if ((leftout = iof_output(O)) == 0) -+ return done; -+ } -+ if (size) -+ { -+ memcpy(O->pos, s, size * sizeof(uint8_t)); -+ O->pos += size; -+ done += size; -+ } -+ return done; -+} -+ -+/* write '\0'-terminated string */ -+ -+iof_status iof_puts (iof *O, const void *data) -+{ -+ const char *s = (const char *)data; -+ while (*s) -+ { -+ if (iof_writable(O)) -+ iof_set(O, *s++); -+ else -+ return IOFFULL; -+ } -+ return IOFEOF; // ? -+} -+ -+size_t iof_put_string (iof *O, const void *data) -+{ -+ const char *p, *s = (const char *)data; -+ for (p = s; *p != '\0' && iof_writable(O); iof_set(O, *p++)); -+ return p - s; -+} -+ -+/* write byte n-times */ -+ -+/* -+iof_status iof_repc (iof *O, char c, size_t bytes) -+{ -+ while (bytes) -+ { -+ if (iof_writable(O)) -+ iof_set(O, c); -+ else -+ return IOFFULL; -+ --bytes; -+ } -+ return IOFEOF; // ? -+} -+*/ -+ -+size_t iof_repc (iof *O, char c, size_t bytes) -+{ -+ size_t leftout, todo = bytes; -+ if ((leftout = iof_left(O)) == 0) -+ if ((leftout = iof_output(O)) == 0) -+ return 0; -+ while (bytes > leftout) -+ { -+ memset(O->pos, c, leftout); -+ bytes -= leftout; -+ O->pos = O->end; -+ if ((leftout = iof_output(O)) == 0) -+ return todo - bytes; -+ } -+ if (bytes) -+ { -+ memset(O->pos, c, bytes); -+ O->pos += bytes; -+ } -+ return todo; -+} -+ -+/* putfs */ -+ -+#define IOF_FMT_SIZE 1024 -+ -+size_t iof_putfs (iof *O, const char *format, ...) -+{ -+ static char buffer[IOF_FMT_SIZE]; -+ va_list args; -+ va_start(args, format); -+ if (vsnprintf(buffer, IOF_FMT_SIZE, format, args) > 0) -+ { -+ va_end(args); -+ return iof_put_string(O, buffer); -+ } -+ else -+ { -+ va_end(args); -+ return iof_write(O, buffer, IOF_FMT_SIZE); -+ } -+} -+ -+/* integer from iof; return 1 on success, 0 otherwise */ -+ -+int iof_get_int32 (iof *I, int32_t *number) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_intlw (iof *I, intlw_t *number) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_int64 (iof *I, int64_t *number) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_uint32 (iof *I, uint32_t *number) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ return 1; -+} -+ -+int iof_get_uintlw (iof *I, uintlw_t *number) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ return 1; -+} -+ -+int iof_get_uint64 (iof *I, uint64_t *number) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_integer(I, c, *number); -+ return 1; -+} -+ -+int iof_get_int32_radix (iof *I, int32_t *number, int radix) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ if (sign) *number = -*number; -+ return 1; -+ -+} -+ -+int iof_get_intlw_radix (iof *I, intlw_t *number, int radix) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_int64_radix (iof *I, int64_t *number, int radix) -+{ -+ int sign, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_uint32_radix (iof *I, uint32_t *number, int radix) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ return 1; -+} -+ -+int iof_get_uintlw_radix (iof *I, uintlw_t *number, int radix) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ return 1; -+} -+ -+int iof_get_uint64_radix (iof *I, uint64_t *number, int radix) -+{ -+ int c = iof_char(I); -+ if (!base10_digit(c)) return 0; -+ iof_read_radix(I, c, *number, radix); -+ return 1; -+} -+ -+/* get roman to uint16_t, cf. roman_to_uint16() from utilnumber.c*/ -+ -+/* todo: some trick in place of this macro horror? */ -+ -+#define roman1000(c) (c == 'M' || c == 'm') -+#define roman500(c) (c == 'D' || c == 'd') -+#define roman100(c) (c == 'C' || c == 'c') -+#define roman50(c) (c == 'L' || c == 'l') -+#define roman10(c) (c == 'X' || c == 'x') -+#define roman5(c) (c == 'V' || c == 'v') -+#define roman1(c) (c == 'I' || c == 'i') -+ -+#define roman100s(I, c) \ -+ (roman100(c) ? (100 + ((c = iof_next(I), roman100(c)) ? (100 + ((c = iof_next(I), roman100(c)) ? (c = iof_next(I), 100) : 0)) : 0)) : 0) -+#define roman10s(I, c) \ -+ (roman10(c) ? (10 + ((c = iof_next(I), roman10(c)) ? (10 + ((c = iof_next(I), roman10(c)) ? (c = iof_next(I), 10) : 0)) : 0)) : 0) -+#define roman1s(I, c) \ -+ (roman1(c) ? (1 + ((c = iof_next(I), roman1(c)) ? (1 + ((c = iof_next(I), roman1(c)) ? (c = iof_next(I), 1) : 0)) : 0)) : 0) -+ -+int iof_get_roman (iof *I, uint16_t *number) -+{ -+ int c; -+ /* M */ -+ for (*number = 0, c = iof_char(I); roman1000(c); *number += 1000, c = iof_next(I)); -+ /* D C */ -+ if (roman500(c)) -+ { -+ c = iof_next(I); -+ *number += 500 + roman100s(I, c); -+ } -+ else if (roman100(c)) -+ { -+ c = iof_next(I); -+ if (roman1000(c)) -+ { -+ c = iof_next(I); -+ *number += 900; -+ } -+ else if (roman500(c)) -+ { -+ c = iof_next(I); -+ *number += 400; -+ } -+ else -+ *number += 100 + roman100s(I, c); -+ } -+ /* L X */ -+ if (roman50(c)) -+ { -+ c = iof_next(I); -+ *number += 50 + roman10s(I, c); -+ } -+ else if (roman10(c)) -+ { -+ c = iof_next(I); -+ if (roman100(c)) -+ { -+ c = iof_next(I); -+ *number += 90; -+ } -+ else if (roman50(c)) -+ { -+ c = iof_next(I); -+ *number += 40; -+ } -+ else -+ *number += 10 + roman10s(I, c); -+ } -+ /* V I */ -+ if (roman5(c)) -+ { -+ c = iof_next(I); -+ *number += 5 + roman1s(I, c); -+ } -+ else if (roman1(c)) -+ { -+ c = iof_next(I); -+ if (roman10(c)) -+ { -+ c = iof_next(I); -+ *number += 9; -+ } -+ else if (roman5(c)) -+ { -+ c = iof_next(I); -+ *number += 4; -+ } -+ else -+ *number += 1 + roman1s(I, c); -+ } -+ return 1; -+} -+ -+/* double from iof; return 1 on success */ -+ -+int iof_get_double (iof *I, double *number) // cf. string_to_double() -+{ -+ int sign, exponent10, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ iof_scan_decimal(I, c, *number); -+ if (c == '.') -+ { -+ c = iof_next(I); -+ iof_scan_fraction(I, c, *number, exponent10); -+ } -+ else -+ exponent10 = 0; -+ if (c == 'e' || c == 'E') -+ { -+ c = iof_next(I); -+ iof_scan_exponent10(I, c, exponent10); -+ } -+ double_exp10(*number, exponent10); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_get_float (iof *I, float *number) // cf. string_to_float() in utilnumber.c -+{ -+ int sign, exponent10, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ iof_scan_decimal(I, c, *number); -+ if (c == '.') -+ { -+ c = iof_next(I); -+ iof_scan_fraction(I, c, *number, exponent10); -+ } -+ else -+ exponent10 = 0; -+ if (c == 'e' || c == 'E') -+ { -+ c = iof_next(I); -+ iof_scan_exponent10(I, c, exponent10); -+ } -+ float_exp10(*number, exponent10); -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_conv_double (iof *I, double *number) // cf. convert_to_double() in utilnumber.c -+{ -+ int sign, exponent10, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ iof_scan_decimal(I, c, *number); -+ if (c == '.' || c == ',') -+ { -+ c = iof_next(I); -+ iof_scan_fraction(I, c, *number, exponent10); -+ if (exponent10 < 0) -+ double_negative_exp10(*number, exponent10); -+ } -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+int iof_conv_float (iof *I, float *number) // cf. convert_to_float() -+{ -+ int sign, exponent10, c = iof_char(I); -+ iof_scan_sign(I, c, sign); -+ iof_scan_decimal(I, c, *number); -+ if (c == '.' || c == ',') -+ { -+ c = iof_next(I); -+ iof_scan_fraction(I, c, *number, exponent10); -+ if (exponent10 < 0) -+ float_negative_exp10(*number, exponent10); -+ } -+ if (sign) *number = -*number; -+ return 1; -+} -+ -+/* integer to iof; return a number of written bytes */ -+ -+#define iof_copy_number_buffer(O, s, p) for (p = s; *p && iof_writable(O); iof_set(O, *p), ++p) -+ -+size_t iof_put_int32 (iof *O, int32_t number) -+{ -+ const char *s, *p; -+ s = int32_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_intlw (iof *O, intlw_t number) -+{ -+ const char *s, *p; -+ s = intlw_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_int64 (iof *O, int64_t number) -+{ -+ const char *s, *p; -+ s = int64_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uint32 (iof *O, uint32_t number) -+{ -+ const char *s, *p; -+ s = uint32_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uintlw (iof *O, uintlw_t number) -+{ -+ const char *s, *p; -+ s = uintlw_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uint64 (iof *O, uint64_t number) -+{ -+ const char *s, *p; -+ s = uint64_to_string(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_int32_radix (iof *O, int32_t number, int radix) -+{ -+ const char *s, *p; -+ s = int32_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_intlw_radix (iof *O, intlw_t number, int radix) -+{ -+ const char *s, *p; -+ s = intlw_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_int64_radix (iof *O, int64_t number, int radix) -+{ -+ const char *s, *p; -+ s = int64_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uint32_radix (iof *O, uint32_t number, int radix) -+{ -+ const char *s, *p; -+ s = uint32_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uintlw_radix (iof *O, uintlw_t number, int radix) -+{ -+ const char *s, *p; -+ s = uintlw_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_uint64_radix (iof *O, uint64_t number, int radix) -+{ -+ const char *s, *p; -+ s = uint64_to_radix(number, radix); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+/* roman numerals */ -+ -+size_t iof_put_roman_uc (iof *O, uint16_t number) -+{ -+ const char *s, *p; -+ s = uint16_to_roman_uc(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_roman_lc (iof *O, uint16_t number) -+{ -+ const char *s, *p; -+ s = uint16_to_roman_lc(number); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+/* double/float to iof; return the number of written bytes */ -+ -+size_t iof_put_double (iof *O, double number, int digits) -+{ -+ const char *s, *p; -+ s = double_to_string(number, digits); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+size_t iof_put_float (iof *O, float number, int digits) -+{ -+ const char *s, *p; -+ s = float_to_string(number, digits); -+ iof_copy_number_buffer(O, s, p); -+ return p - s; -+} -+ -+/* iof to binary integer; pretty common */ -+ -+int iof_get_be_uint2 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c1<<8)|c2; -+ return 1; -+} -+ -+int iof_get_be_uint3 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2, c3; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c1<<16)|(c2<<8)|c3; -+ return 1; -+} -+ -+int iof_get_be_uint4 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2, c3, c4; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0 || (c4 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c1<<24)|(c2<<16)|(c3<<8)|c4; -+ return 1; -+} -+ -+int iof_get_le_uint2 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c2<<8)|c1; -+ return 1; -+} -+ -+int iof_get_le_uint3 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2, c3; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c3<<16)|(c2<<8)|c1; -+ return 1; -+} -+ -+int iof_get_le_uint4 (iof *I, uint32_t *pnumber) -+{ -+ int c1, c2, c3, c4; -+ if ((c1 = iof_get(I)) < 0 || (c2 = iof_get(I)) < 0 || (c3 = iof_get(I)) < 0 || (c4 = iof_get(I)) < 0) -+ return 0; -+ *pnumber = (c4<<24)|(c3<<16)|(c2<<8)|c1; -+ return 1; -+} -+ -+/* iof input data */ -+ -+uint8_t * iof_file_input_data (iof_file *iofile, size_t *psize, int *isnew) -+{ -+ uint8_t *data; -+ if (iofile->flags & IOF_DATA) -+ { -+ data = iofile->buf; -+ *psize = iofile->end - iofile->buf; -+ *isnew = 0; -+ return data; -+ } -+ if (iof_file_reopen(iofile)) -+ { -+ data = iof_copy_file_handle_data(iof_file_get_fh(iofile), psize); -+ *isnew = 1; -+ iof_file_reclose(iofile); -+ return data; -+ } -+ return NULL; -+} -+ -+/* -+uint8_t * iof_file_reader_data (iof_file *iofile, size_t *size) -+{ -+ uint8_t *data; -+ if (!(iofile->flags & IOF_DATA) || iofile->pos == NULL || (*size = (size_t)iof_left(iofile)) == 0) -+ return NULL; -+ if (iofile->flags & IOF_BUFFER_ALLOC) -+ { -+ data = iofile->buf; // iofile->pos; // returned must be freeable, makes sense when ->buf == ->pos -+ iofile->flags &= ~IOF_BUFFER_ALLOC; -+ iofile->buf = iofile->pos = iofile->end = NULL; -+ return data; -+ } -+ data = (uint8_t *)util_malloc(*size); -+ memcpy(data, iofile->buf, *size); -+ return data; -+} -+ -+uint8_t * iof_file_writer_data (iof_file *iofile, size_t *size) -+{ -+ uint8_t *data; -+ if (!(iofile->flags & IOF_DATA) || iofile->buf == NULL || (*size = (size_t)iof_size(iofile)) == 0) -+ return NULL; -+ if (iofile->flags & IOF_BUFFER_ALLOC) -+ { -+ iofile->flags &= ~IOF_BUFFER_ALLOC; -+ data = iofile->buf; -+ iofile->buf = iofile->pos = iofile->end = NULL; -+ return data; -+ } -+ data = (uint8_t *)util_malloc(*size); -+ memcpy(data, iofile->buf, *size); -+ return data; -+} -+*/ -+ -+uint8_t * iof_reader_data (iof *I, size_t *psize) -+{ -+ uint8_t *data; -+ *psize = (size_t)iof_left(I); -+ if (I->flags & IOF_BUFFER_ALLOC) -+ { -+ data = I->buf; // actually I->pos, but we have to return something freeable -+ I->flags &= ~IOF_BUFFER_ALLOC; -+ I->buf = NULL; -+ } -+ else -+ { -+ data = util_malloc(*psize); -+ memcpy(data, I->pos, *psize); -+ } -+ iof_close(I); -+ return data; -+} -+ -+ -+uint8_t * iof_writer_data (iof *O, size_t *psize) -+{ -+ uint8_t *data; -+ *psize = (size_t)iof_size(O); -+ if (O->flags & IOF_BUFFER_ALLOC) -+ { -+ data = O->buf; -+ O->flags &= ~IOF_BUFFER_ALLOC; -+ O->buf = NULL; -+ } -+ else -+ { -+ data = util_malloc(*psize); -+ memcpy(data, O->buf, *psize); -+ } -+ iof_close(O); -+ return data; -+} -+ -+size_t iof_reader_to_file_handle (iof *I, FILE *file) -+{ -+ size_t size; -+ for (size = 0; iof_readable(I); I->pos = I->end) -+ size += fwrite(I->buf, sizeof(uint8_t), iof_left(I), file); -+ return size; -+} -+ -+size_t iof_reader_to_file (iof *I, const char *filename) -+{ -+ FILE *file; -+ size_t size; -+ if ((file = fopen(filename, "wb")) == NULL) -+ return 0; -+ for (size = 0; iof_readable(I); I->pos = I->end) -+ size += fwrite(I->buf, sizeof(uint8_t), iof_left(I), file); -+ fclose(file); -+ return size; -+} -+ -+/* debug */ -+ -+size_t iof_data_to_file (const void *data, size_t size, const char *filename) -+{ -+ FILE *fh; -+ if ((fh = fopen(filename, "wb")) == NULL) -+ return 0; -+ // size = fwrite(data, size, sizeof(uint8_t), fh); // WRONG, this always returns 1, as fwrite returns the number of elements successfully written out -+ size = fwrite(data, sizeof(uint8_t), size, fh); -+ fclose(fh); -+ return size; -+} -+ -+size_t iof_result_to_file_handle (iof *F, FILE *file) -+{ -+ const void *data; -+ size_t size; -+ data = iof_result(F, size); -+ return iof_data_to_file_handle(data, size, file); -+} -+ -+size_t iof_result_to_file (iof *F, const char *filename) -+{ -+ const void *data; -+ size_t size; -+ data = iof_result(F, size); -+ return iof_data_to_file(data, size, filename); -+} -+ -+void iof_debug (iof *I, const char *filename) -+{ -+ FILE *file = fopen(filename, "wb"); -+ if (file != NULL) -+ { -+ fprintf(file, ">>> buf %p <<<\n", I->buf); -+ fwrite(I->buf, sizeof(uint8_t), iof_size(I), file); -+ fprintf(file, "\n>>> pos %p (%ld) <<<\n", I->pos, (long)iof_size(I)); -+ fwrite(I->pos, sizeof(uint8_t), iof_left(I), file); -+ fprintf(file, "\n>>> end %p (%ld) <<<\n", I->end, (long)iof_left(I)); -+ fwrite(I->end, sizeof(uint8_t), I->space - iof_space(I), file); -+ fprintf(file, "\n>>> end of buffer %p (%ld) <<<\n", I->buf + I->space, (long)(I->buf + I->space - I->end)); -+ fclose(file); -+ } -+} -+ -+/* common filters api */ -+ -+/* sizes of filter states on x64 -+size of iof_filter: 640 (no longer used; sizeof(iof) + sizeof larger state) -+size of file_state: 16 -+size of stream_state: 16 -+size of flate_state: 104 -+size of lzw_state: 56 -+size of predictor_state: 104 -+size of basexx_state: 48 -+size of basexx_state: 48 -+size of basexx_state: 48 -+size of eexec_state: 40 -+size of runlength_state: 24 -+size of rc4_state: 24 -+size of aes_state: 72 -+size of img_state: 576 -+size of img: 496 -+*/ -+ -+typedef struct iof_heap iof_heap; -+ -+struct iof_heap { -+ uint8_t *data, *pos; -+ size_t size, space; -+ iof_heap *next, *prev; -+ int refcount; -+}; -+ -+typedef struct { -+ iof_heap *heap; -+} iof_heap_ghost; -+ -+static iof_heap * iof_buffers_heap = NULL; -+static iof_heap * iof_filters_heap = NULL; -+ -+#define IOF_HEAP_FILTERS_COUNT 4 -+#define IOF_BUFFER_SIZE 262144 // (1<<18) -+#define IOF_FILTER_SIZE 1024 -+// sizeof(iof_filter) on x64 is now 640, img_state 576, img 496, others 16-104 -+#define IOF_BUFFER_HEAP_SIZE (IOF_HEAP_FILTERS_COUNT * (IOF_BUFFER_SIZE + sizeof(iof_heap_ghost))) -+#define IOF_FILTER_HEAP_SIZE (IOF_HEAP_FILTERS_COUNT * (IOF_FILTER_SIZE + sizeof(iof_heap_ghost))) -+ -+static iof_heap * iof_heap_new (size_t space) -+{ -+ iof_heap *iofheap; -+ iofheap = (iof_heap *)util_malloc(sizeof(iof_heap) + space); -+ iofheap->data = iofheap->pos = (uint8_t *)(iofheap + 1); -+ iofheap->size = iofheap->space = space; -+ iofheap->next = NULL; -+ iofheap->prev = NULL; -+ iofheap->refcount = 0; -+ return iofheap; -+} -+ -+#define iof_heap_free(iofheap) util_free(iofheap) -+ -+void iof_filters_init (void) -+{ -+ if (iof_buffers_heap == NULL) -+ iof_buffers_heap = iof_heap_new(IOF_BUFFER_HEAP_SIZE); -+ if (iof_filters_heap == NULL) -+ iof_filters_heap = iof_heap_new(IOF_FILTER_HEAP_SIZE); -+} -+ -+void iof_filters_free (void) -+{ -+ iof_heap *heap, *next; -+ for (heap = iof_buffers_heap; heap != NULL; heap = next) -+ { -+ next = heap->next; -+ if (heap->refcount != 0) -+ loggerf("not closed iof filters left (%d)", heap->refcount); -+ if (next != NULL) -+ loggerf("iof filters heap left"); -+ iof_heap_free(heap); -+ } -+ iof_buffers_heap = NULL; -+ for (heap = iof_filters_heap; heap != NULL; heap = next) -+ { -+ next = heap->next; -+ if (heap->refcount != 0) -+ loggerf("not closed iof buffers left (%d)", heap->refcount); -+ if (next != NULL) -+ loggerf("iof buffers heap left"); -+ iof_heap_free(heap); -+ } -+ iof_filters_heap = NULL; -+} -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#define iof_heap_get(hp, ghost, data, siz) \ -+ (ghost = (iof_heap_ghost *)((void*)((hp)->pos)), \ -+ ghost->heap = hp, \ -+ data = (uint8_t *)(ghost + 1), \ -+ (hp)->pos += siz, \ -+ (hp)->size -= siz, \ -+ ++(hp)->refcount) -+#else -+#define iof_heap_get(hp, ghost, data, siz) \ -+ (ghost = (iof_heap_ghost *)((hp)->pos), \ -+ ghost->heap = hp, \ -+ data = (uint8_t *)(ghost + 1), \ -+ (hp)->pos += siz, \ -+ (hp)->size -= siz, \ -+ ++(hp)->refcount) -+ -+#endif -+ -+ -+static void * iof_heap_take (iof_heap **pheap, size_t size) -+{ -+ uint8_t *data; -+ iof_heap_ghost *ghost; -+ iof_heap *heap, *newheap, *next; -+ -+ heap = *pheap; -+ size += sizeof(iof_heap_ghost); -+ if (heap->size >= size) -+ { /* take cheap mem from main heap */ -+ iof_heap_get(heap, ghost, data, size); -+ return data; -+ } -+ if (size <= heap->space >> 1) -+ { /* make new cheap heap, make it front */ -+ *pheap = newheap = iof_heap_new(heap->space); -+ newheap->next = heap; -+ heap->prev = newheap; -+ iof_heap_get(newheap, ghost, data, size); -+ return data; -+ } -+ /* size much larger than expected? should not happen. -+ make a single-item heap, keep the front heap intact. */ -+ newheap = iof_heap_new(size); -+ if ((next = heap->next) != NULL) -+ { -+ newheap->next = next; -+ next->prev = newheap; -+ } -+ heap->next = newheap; -+ newheap->prev = heap; -+ iof_heap_get(newheap, ghost, data, size); -+ return data; -+} -+ -+void iof_heap_back (void *data) -+{ -+ iof_heap_ghost *ghost; -+ iof_heap *heap, *next, *prev; -+ -+ ghost = ((iof_heap_ghost *)data) - 1; -+ heap = ghost->heap; -+ if (heap->refcount == 0) -+ loggerf("invalid use of iof heap, refcount < 0"); -+ if (--heap->refcount <= 0) -+ { -+ if ((prev = heap->prev) != NULL) -+ { /* free the heap */ -+ if ((next = heap->next) != NULL) -+ prev->next = next, next->prev = prev; -+ else -+ prev->next = NULL; -+ iof_heap_free(heap); -+ } -+ else -+ { /* this is the front heap, just reset */ -+ heap->pos = heap->data; -+ heap->size = heap->space; -+ } -+ } -+} -+ -+void * iof_filter_new (size_t size) -+{ // to be removed -+ void *data; -+ -+ iof_filters_init(); -+ data = iof_heap_take(&iof_filters_heap, size); -+ return memset(data, 0, size); -+} -+ -+static uint8_t * iof_filter_buffer_new (size_t *psize) -+{ -+ iof_filters_init(); -+ *psize = IOF_BUFFER_SIZE; -+ return iof_heap_take(&iof_buffers_heap, IOF_BUFFER_SIZE); -+} -+ -+iof * iof_filter_reader_new (iof_handler handler, size_t statesize, void **pstate) -+{ -+ iof *F; -+ void *filter; -+ uint8_t *buffer; -+ size_t buffersize; -+ -+ iof_filters_init(); -+ filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); -+ F = (iof *)memset(filter, 0, sizeof(iof) + statesize); -+ buffer = iof_filter_buffer_new(&buffersize); -+ iof_reader_buffer(F, buffer, buffersize); -+ F->flags |= IOF_HEAP|IOF_BUFFER_HEAP; -+ F->more = handler; -+ *pstate = (F + 1); -+ return F; -+} -+ -+iof * iof_filter_reader_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t buffersize) -+{ // for filters that has own buffer (string, some image filters) -+ iof *F; -+ void *filter; -+ iof_filters_init(); -+ filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); -+ F = (iof *)memset(filter, 0, sizeof(iof) + statesize); -+ iof_reader_buffer(F, buffer, buffersize); -+ F->flags |= IOF_HEAP; -+ F->more = handler; -+ *pstate = (F + 1); -+ return F; -+} -+ -+iof * iof_filter_writer_new (iof_handler handler, size_t statesize, void **pstate) -+{ -+ iof *F; -+ void *filter; -+ uint8_t *buffer; -+ size_t buffersize; -+ -+ iof_filters_init(); -+ filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); -+ F = (iof *)memset(filter, 0, sizeof(iof) + statesize); -+ buffer = iof_filter_buffer_new(&buffersize); -+ iof_writer_buffer(F, buffer, buffersize); -+ F->flags |= IOF_HEAP|IOF_BUFFER_HEAP; -+ F->more = handler; -+ *pstate = (F + 1); -+ return F; -+} -+ -+iof * iof_filter_writer_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t size) -+{ -+ iof *F; -+ void *filter; -+ size_t buffersize; -+ -+ iof_filters_init(); -+ filter = iof_heap_take(&iof_filters_heap, sizeof(iof) + statesize); -+ F = (iof *)memset(filter, 0, sizeof(iof) + statesize); -+ buffer = iof_filter_buffer_new(&buffersize); -+ iof_writer_buffer(F, buffer, buffersize); -+ F->flags |= IOF_HEAP; -+ F->more = handler; -+ *pstate = (F + 1); -+ return F; -+} -+ -+/* close */ -+ -+#define iof_close_next(F) ((void)(iof_decref((F)->next), (F)->next = NULL, 0)) -+/* when filter creation fails, we should take care to destroy the filter but leave ->next intact */ -+#define iof_clear_next(F) ((void)(iof_unref((F)->next), (F)->next = NULL, 0)) -+ -+#define iof_close_buffer(F) ((void)\ -+ ((F)->buf != NULL ? \ -+ ((F->flags & IOF_BUFFER_ALLOC) ? (util_free((F)->buf), (F)->buf = NULL, 0) : \ -+ ((F->flags & IOF_BUFFER_HEAP) ? (iof_filter_buffer_free((F)->buf), (F)->buf = NULL, 0) : ((F)->buf = NULL, 0))) : 0)) -+ -+/* closing underlying file handle */ -+ -+static void iof_close_file (iof *F) -+{ -+ FILE *file; -+ //if (F->flags & IOF_FILE_HANDLE) -+ //{ -+ if ((file = F->file) != NULL) -+ { -+ if (F->flags & IOF_CLOSE_FILE) -+ fclose(F->file); -+ F->file = NULL; -+ } -+ //} -+} -+ -+/* a very special variant for reader filters initiated with iof_file_reopen(). It also calls -+ iof_file_reclose(), which takes an effect only if previously reopened, but better to keep -+ all this thin ice separated. Used in filters: iofile_reader, iofile_stream_reader, image -+ decoders. */ -+ -+static void iof_close_iofile (iof *F) -+{ -+ iof_file *iofile; -+ //if (F->flags & IOF_FILE) -+ //{ -+ if ((iofile = F->iofile) != NULL) -+ { -+ iof_file_unsync(iofile, NULL); -+ iof_file_reclose(iofile); // takes an effect iff prevoiusly reopened -+ iof_file_decref(iofile); -+ F->iofile = NULL; -+ } -+ //} -+} -+ -+void iof_free (iof *F) -+{ -+ if (F->flags & IOF_FILE_HANDLE) -+ iof_close_file(F); -+ else if (F->flags & IOF_FILE) -+ iof_close_iofile(F); -+ else if (F->flags & IOF_NEXT) -+ iof_close_next(F); -+ iof_close_buffer(F); -+ if (F->flags & IOF_HEAP) -+ iof_filter_free(F); -+ else if (F->flags & IOF_ALLOC) -+ util_free(F); -+} -+ -+void iof_discard (iof *F) -+{ // so far used only on failed filters creation; as iof_free() but don't dare to release ->next -+ if (F->flags & IOF_FILE_HANDLE) -+ iof_close_file(F); -+ else if (F->flags & IOF_FILE) -+ iof_close_iofile(F); -+ else if (F->flags & IOF_NEXT) -+ iof_close_next(F); -+ iof_close_buffer(F); -+ if (F->flags & IOF_HEAP) -+ iof_filter_free(F); -+ else if (F->flags & IOF_ALLOC) -+ util_free(F); -+} -+ -+/* resizing buffer */ -+ -+size_t iof_resize_buffer_to (iof *O, size_t space) -+{ -+ uint8_t *buf; -+ -+ if (O->flags & IOF_BUFFER_ALLOC) -+ { -+ buf = (uint8_t *)util_realloc(O->buf, space); -+ } -+ else -+ { -+ buf = (uint8_t *)util_malloc(space); -+ memcpy(buf, O->buf, iof_size(O)); -+ if (O->flags & IOF_BUFFER_HEAP) -+ { -+ iof_filter_buffer_free(O->buf); -+ O->flags &= ~IOF_BUFFER_HEAP; -+ } -+ O->flags |= IOF_BUFFER_ALLOC; -+ -+ } -+ O->pos = buf + iof_size(O); -+ O->end = buf + space; -+ O->buf = buf; -+ O->space = space; -+ return iof_left(O); -+} -+ -+/* */ -+ -+size_t iof_decoder_retval (iof *I, const char *type, iof_status status) -+{ -+ switch (status) -+ { -+ case IOFERR: -+ case IOFEMPTY: // should never happen as we set state.flush = 1 on decoders init -+ loggerf("%s decoder error (%d, %s)", type, status, iof_status_kind(status)); -+ I->flags |= IOF_STOPPED; -+ return 0; -+ case IOFEOF: // this is the last chunk, -+ I->flags |= IOF_STOPPED; // so stop it and fall -+ case IOFFULL: // prepare pointers to read from I->buf -+ I->end = I->pos; -+ I->pos = I->buf; -+ return I->end - I->buf; -+ } -+ loggerf("%s decoder bug, invalid retval %d", type, status); -+ return 0; -+} -+ -+size_t iof_encoder_retval (iof *O, const char *type, iof_status status) -+{ -+ switch (status) -+ { -+ case IOFERR: -+ case IOFFULL: -+ loggerf("%s encoder error (%d, %s)", type, status, iof_status_kind(status)); -+ return 0; -+ case IOFEMPTY: -+ O->pos = O->buf; -+ O->end = O->buf + O->space; -+ return O->space; -+ case IOFEOF: -+ return 0; -+ } -+ loggerf("%s encoder bug, invalid retval %d", type, status); -+ return 0; -+} -+ -+/* file/stream state */ -+ -+typedef struct { -+ size_t length; -+ size_t offset; -+} file_state; -+ -+ -+#define file_state_init(state, off, len) ((state)->offset = off, (state)->length = len) -+ -+typedef struct { -+ size_t length; -+ size_t offset; -+} stream_state; -+ -+#define stream_state_init(state, off, len) ((state)->offset = off, (state)->length = len) -+ -+static size_t file_read (iof *I) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(I); -+ if ((bytes = tail + fread(I->buf + tail, sizeof(uint8_t), I->space - tail, I->file)) < I->space) -+ I->flags |= IOF_STOPPED; -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t iofile_read (iof *I, size_t *poffset) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED) -+ return 0; -+ iof_file_sync(I->iofile, poffset); -+ tail = iof_tail(I); -+ if ((bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), I->space - tail, I->iofile)) < I->space) -+ { -+ I->flags |= IOF_STOPPED; -+ iof_file_unsync(I->iofile, poffset); -+ } -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t file_load (iof *I) -+{ -+ size_t bytes, left, tail; -+ if (I->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(I); -+ I->pos = I->buf + tail; -+ I->end = I->buf + I->space; /* don't assume its done when initializing the filter */ -+ left = I->space - tail; -+ do { -+ bytes = fread(I->pos, sizeof(uint8_t), left, I->file); -+ I->pos += bytes; -+ } while (bytes == left && (left = iof_resize_buffer(I)) > 0); -+ I->flags |= IOF_STOPPED; -+ return iof_loaded(I); -+} -+ -+static size_t iofile_load (iof *I, size_t *poffset) -+{ -+ size_t bytes, left, tail; -+ if (I->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(I); -+ I->pos = I->buf + tail; -+ I->end = I->buf + I->space; /* don't assume its done when initializing the filter */ -+ left = I->space - tail; -+ iof_file_sync(I->iofile, poffset); -+ do { -+ bytes = iof_file_read(I->pos, sizeof(uint8_t), left, I->iofile); -+ I->pos += bytes; -+ } while (bytes == left && (left = iof_resize_buffer(I)) > 0); -+ I->flags |= IOF_STOPPED; -+ iof_file_unsync(I->iofile, poffset); -+ return iof_loaded(I); -+} -+ -+static size_t filter_file_reader (iof *I, iof_mode mode) -+{ -+ switch (mode) -+ { -+ case IOFREAD: -+ return file_read(I); -+ case IOFLOAD: -+ return file_load(I); -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+static size_t filter_iofile_reader (iof *I, iof_mode mode) -+{ -+ file_state *state; -+ state = iof_filter_state(file_state *, I); -+ switch (mode) -+ { -+ case IOFREAD: -+ return iofile_read(I, &state->offset); -+ case IOFLOAD: -+ return iofile_load(I, &state->offset); -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+static size_t file_write (iof *O, int flush) -+{ -+ size_t bytes; -+ if ((bytes = iof_size(O)) > 0) -+ if (bytes != fwrite(O->buf, sizeof(uint8_t), bytes, O->file)) -+ return 0; -+ if (flush) -+ fflush(O->file); -+ O->end = O->buf + O->space; // remains intact actually -+ O->pos = O->buf; -+ return O->space; -+} -+ -+static size_t iofile_write (iof *O, size_t *poffset, int flush) -+{ -+ size_t bytes; -+ iof_file_sync(O->iofile, poffset); -+ if ((bytes = iof_size(O)) > 0) -+ { -+ if (bytes != iof_file_write(O->buf, sizeof(uint8_t), bytes, O->iofile)) -+ { -+ iof_file_unsync(O->iofile, poffset); -+ return 0; -+ } -+ } -+ if (flush) -+ iof_file_flush(O->iofile); -+ O->end = O->buf + O->space; // remains intact actually -+ O->pos = O->buf; -+ return O->space; -+} -+ -+static size_t filter_file_writer (iof *O, iof_mode mode) -+{ -+ switch (mode) -+ { -+ case IOFWRITE: -+ return file_write(O, 0); -+ case IOFFLUSH: -+ return file_write(O, 1); -+ case IOFCLOSE: -+ file_write(O, 1); -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+static size_t filter_iofile_writer (iof *O, iof_mode mode) -+{ -+ file_state *state; -+ state = iof_filter_state(file_state *, O); -+ switch (mode) -+ { -+ case IOFWRITE: -+ return iofile_write(O, &state->offset, 0); -+ case IOFFLUSH: -+ return iofile_write(O, &state->offset, 1); -+ case IOFCLOSE: -+ iofile_write(O, &state->offset, 1); -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+/* filter from FILE* */ -+ -+iof * iof_filter_file_handle_reader (FILE *file) -+{ -+ iof *I; -+ file_state *state; -+ if (file == NULL) -+ return NULL; -+ I = iof_filter_reader(filter_file_reader, sizeof(file_state), &state); -+ iof_setup_file(I, file); -+ file_state_init(state, 0, 0); -+ return I; -+} -+ -+iof * iof_filter_file_handle_writer (FILE *file) -+{ -+ iof *O; -+ file_state *state; -+ if (file == NULL) -+ return NULL; -+ O = iof_filter_writer(filter_file_writer, sizeof(file_state), &state); -+ iof_setup_file(O, file); -+ file_state_init(state, 0, 0); -+ return O; -+} -+ -+/* filter from iof_file * */ -+ -+iof * iof_filter_iofile_reader (iof_file *iofile, size_t offset) -+{ -+ iof *I; -+ file_state *state; -+ if (!iof_file_reopen(iofile)) -+ return NULL; -+ I = iof_filter_reader(filter_iofile_reader, sizeof(file_state), &state); -+ iof_setup_iofile(I, iofile); -+ file_state_init(state, offset, 0); -+ return I; -+} -+ -+iof * iof_filter_iofile_writer (iof_file *iofile, size_t offset) -+{ -+ iof *O; -+ file_state *state; -+ O = iof_filter_writer(filter_iofile_writer, sizeof(file_state), &state); -+ iof_setup_iofile(O, iofile); -+ file_state_init(state, offset, 0); -+ return O; -+} -+ -+/* filter from filename */ -+ -+iof * iof_filter_file_reader (const char *filename) -+{ -+ iof *I; -+ file_state *state; -+ FILE *file; -+ if ((file = fopen(filename, "rb")) == NULL) -+ return NULL; -+ I = iof_filter_reader(filter_file_reader, sizeof(file_state), &state); -+ iof_setup_file(I, file); -+ file_state_init(state, 0, 0); -+ I->flags |= IOF_CLOSE_FILE; -+ return I; -+} -+ -+iof * iof_filter_file_writer (const char *filename) -+{ -+ iof *O; -+ file_state *state; -+ FILE *file; -+ if ((file = fopen(filename, "wb")) == NULL) -+ return NULL; -+ O = iof_filter_writer(filter_file_writer, sizeof(file_state), &state); -+ iof_setup_file(O, file); -+ file_state_init(state, 0, 0); -+ O->flags |= IOF_CLOSE_FILE; -+ return O; -+} -+ -+/* from string */ -+ -+static size_t dummy_handler (iof *I, iof_mode mode) -+{ -+ switch (mode) -+ { -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_filter_string_reader (const void *s, size_t length) -+{ -+ iof *I; -+ void *dummy; -+ I = iof_filter_reader_with_buffer(dummy_handler, 0, &dummy, NULL, 0); -+ I->rbuf = I->rpos = (const uint8_t *)s; -+ I->rend = (const uint8_t *)s + length; -+ // I->space = length; -+ return I; -+} -+ -+iof * iof_filter_string_writer (const void *s, size_t length) -+{ -+ iof *O; -+ void *dummy; -+ O = iof_filter_reader_with_buffer(dummy_handler, 0, &dummy, NULL, 0); -+ O->rbuf = O->rpos = (const uint8_t *)s; -+ O->rend = (const uint8_t *)s + length; -+ // O->space = length; -+ return O; -+} -+ -+iof * iof_filter_buffer_writer (size_t size) -+{ // filter alternative of iof_buffer_create() -+ iof *O; -+ void *dummy; -+ uint8_t *buffer; -+ if (size > IOF_BUFFER_SIZE) -+ { -+ buffer = (uint8_t *)util_malloc(size); -+ O = iof_filter_writer_with_buffer(iof_mem_handler, 0, &dummy, buffer, size); -+ O->flags |= IOF_BUFFER_ALLOC; -+ return O; -+ } -+ return iof_filter_writer(iof_mem_handler, 0, &dummy); -+} -+ -+/* stream */ -+ -+static size_t file_stream_read (iof *I, size_t *plength) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED || *plength == 0) -+ return 0; -+ tail = iof_tail(I); -+ if (I->space - tail >= *plength) -+ { -+ bytes = tail + fread(I->buf + tail, sizeof(uint8_t), *plength, I->file); -+ I->flags |= IOF_STOPPED; -+ *plength = 0; -+ } -+ else -+ { -+ bytes = tail + fread(I->buf + tail, sizeof(uint8_t), I->space - tail, I->file); -+ *plength -= bytes - tail; -+ } -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t iofile_stream_read (iof *I, size_t *plength, size_t *poffset) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED || *plength == 0) -+ return 0; -+ tail = iof_tail(I); -+ iof_file_sync(I->iofile, poffset); -+ if (I->space - tail >= *plength) -+ { -+ bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), *plength, I->iofile); -+ iof_file_unsync(I->iofile, poffset); -+ I->flags |= IOF_STOPPED; -+ *plength = 0; -+ } -+ else -+ { -+ bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), I->space - tail, I->iofile); -+ *plength -= bytes - tail; -+ } -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t file_stream_load (iof *I, size_t *plength) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED || *plength == 0) -+ return 0; -+ tail = iof_tail(I); -+ if (I->space - tail < *plength) -+ if (iof_resize_buffer_to(I, tail + *plength) == 0) -+ return 0; -+ bytes = tail + fread(I->buf + tail, sizeof(uint8_t), *plength, I->file); -+ I->flags |= IOF_STOPPED; -+ *plength = 0; -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t iofile_stream_load (iof *I, size_t *plength, size_t *poffset) -+{ -+ size_t bytes, tail; -+ if (I->flags & IOF_STOPPED || *plength == 0) -+ return 0; -+ iof_file_sync(I->iofile, poffset); -+ tail = iof_tail(I); -+ if (I->space - tail < *plength) -+ if (iof_resize_buffer_to(I, tail + *plength) == 0) -+ return 0; -+ bytes = tail + iof_file_read(I->buf + tail, sizeof(uint8_t), *plength, I->iofile); -+ iof_file_unsync(I->iofile, poffset); -+ I->flags |= IOF_STOPPED; -+ *plength = 0; -+ I->pos = I->buf; -+ I->end = I->buf + bytes; -+ return bytes; -+} -+ -+static size_t filter_file_stream_reader (iof *I, iof_mode mode) -+{ -+ stream_state *state; -+ state = iof_filter_state(stream_state *, I); -+ switch(mode) -+ { -+ case IOFREAD: -+ return file_stream_read(I, &state->length); -+ case IOFLOAD: -+ return file_stream_load(I, &state->length); -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+static size_t filter_iofile_stream_reader (iof *I, iof_mode mode) -+{ -+ stream_state *state; -+ state = iof_filter_state(stream_state *, I); -+ switch(mode) -+ { -+ case IOFREAD: -+ return iofile_stream_read(I, &state->length, &state->offset); -+ case IOFLOAD: -+ return iofile_stream_load(I, &state->length, &state->offset); -+ case IOFCLOSE: -+ iof_free(I); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_filter_stream_reader (FILE *file, size_t offset, size_t length) -+{ -+ iof *I; -+ stream_state *state; -+ I = iof_filter_reader(filter_file_stream_reader, sizeof(stream_state), &state); -+ iof_setup_file(I, file); -+ stream_state_init(state, offset, length); -+ fseek(file, (long)offset, SEEK_SET); // or perhaps it should be call in file_stream_read(), like iof_file_sync()? -+ return I; -+} -+ -+iof * iof_filter_stream_coreader (iof_file *iofile, size_t offset, size_t length) -+{ -+ iof *I; -+ stream_state *state; -+ if (!iof_file_reopen(iofile)) -+ return NULL; -+ I = iof_filter_reader(filter_iofile_stream_reader, sizeof(stream_state), &state); -+ iof_setup_iofile(I, iofile); -+ stream_state_init(state, offset, length); -+ return I; -+} -+ -+static size_t file_stream_write (iof *O, size_t *plength, int flush) -+{ -+ size_t bytes; -+ if ((bytes = iof_size(O)) > 0) -+ { -+ if (bytes != fwrite(O->buf, sizeof(uint8_t), bytes, O->file)) -+ { -+ *plength += bytes; -+ return 0; -+ } -+ } -+ if (flush) -+ fflush(O->file); -+ *plength += bytes; -+ O->end = O->buf + O->space; // remains intact -+ O->pos = O->buf; -+ return O->space; -+} -+ -+static size_t iofile_stream_write (iof *O, size_t *plength, size_t *poffset, int flush) -+{ -+ size_t bytes; -+ if ((bytes = iof_size(O)) > 0) -+ { -+ iof_file_sync(O->iofile, poffset); -+ if (bytes != iof_file_write(O->buf, sizeof(uint8_t), bytes, O->iofile)) -+ { -+ *plength += bytes; -+ iof_file_unsync(O->iofile, poffset); -+ return 0; -+ } -+ } -+ if (flush) -+ iof_file_flush(O->iofile); -+ *plength += bytes; -+ O->end = O->buf + O->space; // remains intact -+ O->pos = O->buf; -+ return O->space; -+} -+ -+static size_t filter_file_stream_writer (iof *O, iof_mode mode) -+{ -+ stream_state *state; -+ state = iof_filter_state(stream_state *, O); -+ switch (mode) -+ { -+ case IOFWRITE: -+ return file_stream_write(O, &state->length, 0); -+ case IOFFLUSH: -+ return file_stream_write(O, &state->length, 1); -+ case IOFCLOSE: -+ file_stream_write(O, &state->length, 1); -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+static size_t filter_iofile_stream_writer (iof *O, iof_mode mode) -+{ -+ stream_state *state; -+ state = iof_filter_state(stream_state *, O); -+ switch (mode) -+ { -+ case IOFWRITE: -+ return iofile_stream_write(O, &state->length, &state->offset, 0); -+ case IOFFLUSH: -+ return iofile_stream_write(O, &state->length, &state->offset, 1); -+ case IOFCLOSE: -+ iofile_stream_write(O, &state->length, &state->offset, 1); -+ iof_free(O); -+ return 0; -+ default: -+ return 0; -+ } -+} -+ -+iof * iof_filter_stream_writer (FILE *file) -+{ -+ iof *O; -+ stream_state *state; -+ O = iof_filter_writer(filter_file_stream_writer, sizeof(stream_state), &state); -+ iof_setup_file(O, file); -+ stream_state_init(state, 0, 0); -+ return O; -+} -+ -+iof * iof_filter_stream_cowriter (iof_file *iofile, size_t offset) -+{ -+ iof *O; -+ stream_state *state; -+ O = iof_filter_writer(filter_iofile_stream_writer, sizeof(stream_state), &state); -+ iof_setup_iofile(O, iofile); -+ stream_state_init(state, offset, 0); -+ return O; -+} -+ -+/* very specific for images; get input from already created strem filter, exchange the filter but keep the buffer */ -+ -+FILE * iof_filter_file_reader_source (iof *I, size_t *poffset, size_t *plength) -+{ -+ stream_state *sstate; -+ file_state *fstate; -+ if (I->more == filter_file_stream_reader) // I is the result of iof_filter_stream_reader() -+ { -+ sstate = iof_filter_state(stream_state *, I); -+ *poffset = sstate->offset; -+ *plength = sstate->length; // might be 0 but it is ok for file readers -+ return I->file; -+ } -+ if (I->more == filter_file_reader) -+ { -+ fstate = iof_filter_state(file_state *, I); -+ *poffset = fstate->offset; -+ *plength = fstate->length; // might be 0 but it is ok for file readers -+ return I->file; -+ } -+ return NULL; -+} -+ -+iof_file * iof_filter_file_coreader_source (iof *I, size_t *poffset, size_t *plength) -+{ -+ stream_state *sstate; -+ file_state *fstate; -+ if (I->more == filter_iofile_stream_reader) // I is the result of iof_filter_stream_coreader() -+ { -+ sstate = iof_filter_state(stream_state *, I); -+ *poffset = sstate->offset; -+ *plength = sstate->length; -+ return I->iofile; -+ } -+ if (I->more == filter_iofile_reader) -+ { -+ fstate = iof_filter_state(file_state *, I); -+ *poffset = fstate->offset; -+ *plength = fstate->length; -+ return I->iofile; -+ } -+ return NULL; -+} -+ -+iof * iof_filter_reader_replacement (iof *P, iof_handler handler, size_t statesize, void **pstate) -+{ // called after iof_filter_file_reader_source(), no need to check if F is filter from iof heap and if has buffer from iof heap -+ iof *F; -+ F = iof_filter_reader_with_buffer(handler, statesize, pstate, P->buf, P->space); -+ F->flags |= IOF_BUFFER_HEAP; -+ //iof_reader_buffer(P, NULL, 0); -+ //P->flags &= ~IOF_BUFFER_HEAP; -+ iof_filter_free(P); -+ return F; -+} -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/texk/web2c/luatexdir/luapplib/util/utiliof.h b/texk/web2c/luatexdir/luapplib/util/utiliof.h -new file mode 100644 -index 000000000..853a9ae52 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utiliof.h -@@ -0,0 +1,669 @@ -+ -+#ifndef UTIL_IOF_H -+#define UTIL_IOF_H -+ -+#include // for FILE * -+#include // for errno -+#include // for strerror() -+#include // for uintN_t -+ -+#include "utildecl.h" -+#include "utilnumber.h" -+ -+/* handler call modes */ -+ -+typedef enum { -+ IOFREAD = 0, /* read to buffer */ -+ IOFLOAD = 1, /* read all to buffer */ -+ IOFWRITE = 2, /* write buffer to the output */ -+ IOFFLUSH = 3, /* flush buffer to the output */ -+ IOFCLOSE = 4 /* (flush and) close */ -+} iof_mode; -+ -+/* return statuses */ -+ -+typedef enum { -+ IOFEOF = -1, /* end of input */ -+ IOFEMPTY = -2, /* end of input buffer*/ -+ IOFFULL = -3, /* end of output buffer */ -+ IOFERR = -4 /* error */ -+} iof_status; -+ -+const char * iof_status_kind (iof_status status); -+ -+/* iof_file */ -+ -+typedef struct iof_file { -+ union { -+ FILE *iofh; // access via iof_file_get_fh / iof_file_set_fh (below) -+ union { -+ struct { uint8_t *buf, *pos, *end; }; -+ struct { const uint8_t *rbuf, *rpos, *rend; }; // to trick compiler warnings about cast discarding const -+ }; -+ }; -+ size_t *offset; -+ char *name; -+ size_t size; -+ int refcount; -+ int flags; -+} iof_file; -+ -+/* iof handler function */ -+ -+typedef struct iof iof; -+typedef size_t (*iof_handler) (iof *I, iof_mode mode); -+ -+/* iof structure */ -+ -+#define IOF_MEMBERS \ -+ union { \ -+ struct { uint8_t *buf, *pos, *end; }; \ -+ struct { uint16_t *hbuf, *hpos, *hend; }; \ -+ struct { uint32_t *ibuf, *ipos, *iend; }; \ -+ struct { const uint8_t *rbuf, *rpos, *rend; }; \ -+ }; \ -+ size_t space; \ -+ iof_handler more; \ -+ union { iof *next; FILE *file; iof_file *iofile; void *link; }; \ -+ int flags; \ -+ int refcount -+ -+/* -+ buf -- the beginning of buffer -+ pos -- the current position -+ end -- the end of buffer -+ space -- private space size, not always eq. (end - buf) -+ more -- handler function -+ next/file/iofile/link -- reader source or writer target -+ source -- source filter -+ flags -- private filter info -+ refcount -- refcount -+*/ -+ -+struct iof { -+ IOF_MEMBERS; -+}; -+ -+typedef void (*iof_dump_function) (const void *value, iof *O); -+ -+/* flags */ -+ -+#define IOF_ALLOC (1<<0) // iof is allocated -+#define IOF_HEAP (1<<1) // iof taken from iof heap -+#define IOF_BUFFER_ALLOC (1<<2) // buffer allocated -+#define IOF_BUFFER_HEAP (1<<3) // buffer taken from iof heap -+ -+#define IOF_SHORT (1<<4) // buffer uses 16bit integers -+#define IOF_LONG (1<<5) // buffer uses 32bit integers -+ -+#define IOF_TAIL (1<<6) // preserve reader tail -+#define IOF_READER (1<<7) // is reader -+#define IOF_WRITER (1<<8) // is writer -+ -+#define IOF_DATA (1<<9) // binds some memory -+#define IOF_FILE_HANDLE (1<<10) // links FILE * -+#define IOF_FILE (1<<11) // links iof_file * -+#define IOF_NEXT (1<<12) // links next iof * -+#define IOF_CLOSE_FILE (1<<13) // close FILE * on free -+#define IOF_REOPEN_FILE (1<<14) // close/reopen mode for iof_file -+#define IOF_RECLOSE_FILE (1<<15) // ditto -+ -+#define IOF_STOPPED (1<<16) // stopped -+ -+// #define IOF_CUSTOM (1<<17) // first custom flag -+ -+#define IOF_BUFSIZ (sizeof(iof) + BUFSIZ*sizeof(uint8_t)) -+ -+/* -+reading buffer -- all of buf, pos, end pointers are initialized to the beginning of the private buffer, -+ next call to a handler function moves the end pointer to bufer+space -+writer -- buf and pos pointers initialized to the beginning of the buffer, end initialized to bufer+space -+ -+Every call to handler returns size_t number of bytes -+available (to write/read) or 0 if there is no more space. -+ -+We usually align the data buffer just after the iof structure. -+This is convenient, especially when a memory for the structure -+and its buffer is to be allocated. In the case of growing output -+buffers we used to check if the memory of the buffer is allocated -+by the handler function using test (O->buf != (O+1)). We don't use -+it any longer not to rely on little secrets. Now there is an explicit -+IOF_BUFFER_ALLOC flag for that. IOF_ALLOC tells if the structure -+itself is taken from malloc (not used so far). Assuming the buffer size -+is way larger the sizeof(iof) -+*/ -+ -+/* initializers */ -+ -+#define IOF_READER_STRUCT(handler, file, buffer, size, flags) \ -+ { {{ (uint8_t *)(buffer), (uint8_t *)(buffer), (uint8_t *)(buffer) }}, size, handler, { file }, flags|IOF_READER, 0 } -+ -+#define IOF_WRITER_STRUCT(handler, file, buffer, size, flags) \ -+ { {{ (uint8_t *)(buffer), (uint8_t *)(buffer), (uint8_t *)(buffer) + size }}, size, handler, { file }, flags|IOF_WRITER, 0 } -+ -+#define IOF_STRING_STRUCT(buffer, size) \ -+ { {{ (uint8_t *)(buffer), (uint8_t *)(buffer), (uint8_t *)(buffer) + size }}, size, NULL, { NULL }, 0|IOF_READER|IOF_DATA, 0 } -+ -+#define IOF_STRING() IOF_STRING_STRUCT(0, 0) -+ -+/* refcount */ -+ -+#define iof_incref(I) (++(I)->refcount) -+#define iof_decref(I) ((void)(--(I)->refcount <= 0 && iof_close(I))) -+#define iof_unref(I) (--(I)->refcount) -+ -+/* setting up iof and buffer from mem buffer of a given size */ -+ -+#define iof_setup_reader(I, buffer, size) \ -+ ((I) = (iof *)(buffer), iof_reader_buffer(I, (I)+1, size - sizeof(iof))) -+ -+#define iof_setup_writer(O, buffer, size) \ -+ ((O) = (iof *)buffer, iof_writer_buffer(O, (O)+1, size - sizeof(iof))) -+ -+/* binding buffer of a given size */ -+ -+#define iof_reader_buffer(I, buffer, size) \ -+ ((I)->buf = (I)->pos = (I)->end = (uint8_t *)(buffer), \ -+ (I)->space = size, (I)->flags = 0|IOF_READER, (I)->refcount = 0) -+ -+#define iof_writer_buffer(O, buffer, size) \ -+ ((O)->buf = (O)->pos = (uint8_t *)(buffer), \ -+ (O)->end = (uint8_t *)(buffer) + size, \ -+ (O)->space = size, (O)->flags = 0|IOF_WRITER, (O)->refcount = 0) -+ -+/* basics */ -+ -+#define iof_space(I) ((I)->end - (I)->buf) -+#define iof_left(I) ((I)->end - (I)->pos) -+#define iof_size(I) ((I)->pos - (I)->buf) -+ -+#define iof_input(I) ((I)->more ? (I)->more((I), IOFREAD) : 0lu) -+#define iof_load(I) ((I)->more ? (I)->more((I), IOFLOAD) : 0lu) -+ -+#define iof_output(O) ((O)->more ? (O)->more((O), IOFWRITE) : 0lu) -+//#define iof_flush(O) ((O)->pos > (O)->buf && (O)->more ? (O)->more(O, IOFFLUSH) : 0lu) -+// flush should be unconditional, because encoders emits EOD markers only on flush -+#define iof_flush(O) ((O)->more ? (O)->more(O, IOFFLUSH) : 0lu) -+#define iof_close(O) ((O)->more ? (O)->more(O, IOFCLOSE) : 0lu) -+ -+#define iof_stop(F) ((void)(F->pos = F->end = F->buf, F->flags |= IOF_STOPPED)) -+ -+/* -+Rewriting reader tail to the beginning of new data portion; readers reacting on IOFREAD -+mode must be aware of some not yet read data, but treat it necessary only if IOF_TAIL flag is set. -+Parsers using iof input may protect not yet read data when there may be a need to put bytes -+back to the stream. This is trivial when I->pos > I->buf, as we can make a move by --I->pos. -+But when there is a need to put back more then one byte, we can protect the data tail, so that -+realoder will rewrite it to the beginning of new data chunk. -+ -+ iof_tail(I) - internal, used by iof handlers at IOFREAD mode -+ iof_protect_tail(I) - used by parsers to ensure some bytes chunk in one piece -+ -+*/ -+ -+size_t iof_save_tail (iof *I); -+#define iof_tail(I) (((I)->flags & IOF_TAIL) && (I)->pos < (I)->end ? iof_save_tail(I) : 0) -+ -+size_t iof_input_save_tail (iof *I, size_t back); -+#define iof_protect_tail(I, back, length) ((iof_left(I) >= (length) - (back)) ? 1 : (iof_input_save_tail(I, back) >= length - back)) -+ -+//uint8_t * iof_tail_data (iof *I, size_t *ptail); -+//#define iof_tail_free(data) util_free(data) -+ -+/* panic */ -+ -+// #define iof_panic(mess) return 0 -+#ifndef iof_panic -+ #define iof_panic(mess) (fputs(mess, stderr), abort()) -+#endif -+//#define iof_memory_error() iof_panic(strerror(errno)) -+#define iof_fwrite_error() iof_panic(strerror(errno)) -+ -+/* generic helpers */ -+ -+UTILAPI uint8_t * iof_copy_file_data (const char *filename, size_t *psize); -+UTILAPI uint8_t * iof_copy_file_handle_data (FILE *file, size_t *psize); -+ -+/* In the future we may need releasing file handle and restoring it from iofile->name, so access file handle via macros */ -+ -+#define iof_file_get_fh(iofile) ((iofile)->iofh) -+#define iof_file_set_fh(iofile, fh) ((iofile)->iofh = fh) -+#define iof_file_get_file(iofile) (((iofile)->flags & IOF_DATA) ? NULL : iof_file_get_fh(iofile)) -+FILE * iof_get_file (iof *F); -+ -+/* basic iof_file interface */ -+ -+iof_file * iof_file_new (FILE *file); -+iof_file * iof_file_init (iof_file *iofile, FILE *file); -+ -+iof_file * iof_file_rdata (const void *data, size_t size); -+iof_file * iof_file_wdata (void *data, size_t size); -+ -+iof_file * iof_file_rdata_init (iof_file *iofile, const void *data, size_t size); -+iof_file * iof_file_wdata_init (iof_file *iofile, void *data, size_t size); -+ -+iof_file * iof_file_reader_from_file_handle (iof_file *iofile, const char *filename, FILE *file, int preload, int closefile); -+iof_file * iof_file_reader_from_file (iof_file *iofile, const char *filename, int preload); -+iof_file * iof_file_reader_from_data (iof_file *iofile, const void *data, size_t size, int preload, int freedata); -+//iof_file * iof_file_writer_from_file (iof_file *iofile, const char *filename); -+ -+void * iof_copy_data (const void *data, size_t size); -+#define iof_data_free(data) util_free(data) -+#define iof_file_wdata_copy(data, size) iof_file_wdata(iof_copy_data(data, size), size) -+#define iof_file_rdata_copy(data, size) iof_file_rdata(iof_copy_data(data, size), size) -+ -+void iof_file_free (iof_file *iofile); -+ -+#define iof_file_get_name(iofile) ((iofile)->name) -+void iof_file_set_name (iof_file *iofile, const char *name); -+ -+#define iof_file_incref(iofile) (++(iofile)->refcount) -+#define iof_file_decref(iofile) ((void)(--(iofile)->refcount <= 0 && (iof_file_free(iofile), 0))) -+ -+int iof_file_seek (iof_file *iofile, long offset, int whence); -+long iof_file_tell (iof_file *iofile); -+size_t iof_file_size (iof_file *iofile); -+int iof_file_eof (iof_file *iofile); -+ -+size_t iof_file_read (void *ptr, size_t size, size_t items, iof_file *iofile); -+size_t iof_file_write (const void *ptr, size_t size, size_t items, iof_file *iofile); -+size_t iof_file_ensure (iof_file *iofile, size_t bytes); -+int iof_file_flush (iof_file *iofile); -+ -+int iof_file_getc (iof_file *iofile); -+int iof_file_putc (iof_file *iofile, int c); -+ -+int iof_file_close_input (iof_file *iofile); -+int iof_file_reopen_input (iof_file *iofile); -+ -+#define iof_file_reopen(iofile) (((iofile)->flags & IOF_REOPEN_FILE) ? iof_file_reopen_input(iofile) : 1) -+#define iof_file_reclose(iofile) (void)(((iofile)->flags & IOF_RECLOSE_FILE) ? iof_file_close_input(iofile) : 0) -+ -+/* wrappers of basic operations for iof */ -+ -+int iof_reader_seek (iof *I, long offset, int whence); -+int iof_reader_reseek (iof *I, long offset, int whence); -+int iof_writer_seek (iof *I, long offset, int whence); -+int iof_writer_reseek (iof *I, long offset, int whence); -+ -+int iof_seek (iof *I, long offset, int whence); -+int iof_reseek (iof *I, long offset, int whence); -+ -+long iof_reader_tell (iof *I); -+long iof_writer_tell (iof *I); -+long iof_tell (iof *I); -+size_t iof_fsize (iof *I); -+ -+#define iof_setup_iofile(I, f) (iof_file_incref(f), (I)->iofile = f, (I)->flags |= IOF_FILE) -+#define iof_setup_file(I, fh) ((I)->file = fh, (I)->flags |= IOF_FILE_HANDLE) -+#define iof_setup_next(I, N) ((I)->next = N, iof_incref(N), (I)->flags |= IOF_NEXT) -+ -+/* file handler reader and writer */ -+ -+UTILAPI iof * iof_setup_file_handle_reader (iof *I, void *buffer, size_t space, FILE *f); -+UTILAPI iof * iof_setup_file_handle_writer (iof *O, void *buffer, size_t space, FILE *f); -+ -+#define iof_get_file_handle_reader(buffer, space, fh) iof_setup_file_handle_reader(NULL, buffer, space, fh) -+#define iof_get_file_handle_writer(buffer, space, fh) iof_setup_file_handle_writer(NULL, buffer, space, fh) -+ -+/* file reader and writer */ -+ -+UTILAPI iof * iof_setup_file_reader (iof *I, void *buffer, size_t space, const char *filename); -+UTILAPI iof * iof_setup_file_writer (iof *O, void *buffer, size_t space, const char *filename); -+ -+#define iof_get_file_reader(buffer, space, filename) iof_setup_file_reader(NULL, buffer, space, filename) -+#define iof_get_file_writer(buffer, space, filename) iof_setup_file_writer(NULL, buffer, space, filename) -+ -+/* mem writer */ -+ -+UTILAPI iof * iof_setup_buffer (iof *O, void *buffer, size_t space); -+UTILAPI iof * iof_setup_buffermin (iof *O, void *buffer, size_t space, size_t min); -+ -+#define iof_buffer(buffer, space) iof_setup_buffer(NULL, buffer, space) -+#define iof_buffermin(buffer, space, min) iof_setup_buffermin(NULL, buffer, space, min) -+ -+UTILAPI iof * iof_buffer_create (size_t space); -+#define iof_buffer_new() iof_buffer_create(BUFSIZ) -+ -+/* custom handler */ -+ -+UTILAPI iof * iof_reader (iof *I, void *link, iof_handler reader, const void *s, size_t bytes); -+UTILAPI iof * iof_writer (iof *O, void *link, iof_handler writer, void *s, size_t bytes); -+ -+/* stdout wrapper */ -+ -+extern UTILAPI iof iof_stdout; -+extern UTILAPI iof iof_stderr; -+ -+/* simple string reader */ -+ -+UTILAPI iof * iof_string_reader (iof *I, const void *s, size_t bytes); -+ -+#define iof_string(I, s, bytes) \ -+ (((I)->rbuf = (I)->rpos = (const uint8_t *)s), ((I)->rend = (I)->rbuf + (bytes)), ((I)->flags |= IOF_DATA), (I)) -+ -+/* dummies */ -+ -+UTILAPI iof * iof_dummy (void *buffer, size_t space); -+UTILAPI iof * iof_null (void *buffer, size_t space); -+ -+/* checking available space */ -+ -+#define iof_loadable(I) ((I)->pos < (I)->end || iof_load(I)) -+#define iof_readable(I) ((I)->pos < (I)->end || iof_input(I)) -+#define iof_writable(O) ((O)->pos < (O)->end || iof_output(O)) -+ -+#define iof_hloadable iof_loadable -+#define iof_iloadable iof_loadable -+ -+#define iof_hreadable iof_readable -+#define iof_ireadable iof_readable -+ -+#define iof_hwritable iof_writable -+#define iof_iwritable iof_writable -+ -+/* ensure space to write several bytes (several means less then I->space) */ -+ -+#define iof_ensure(O, n) ((O)->pos+(n)-1 < (O)->end || iof_output(O)) // iof_ensure(O, 1) eq iof_writable(O) -+#define iof_hensure(O, n) ((O)->hpos+(n)-1 < (O)->hend || iof_output(O)) -+#define iof_iensure(O, n) ((O)->ipos+(n)-1 < (O)->iend || iof_output(O)) -+ -+/* reading */ -+ -+UTILAPI int iof_getc (iof *I); -+UTILAPI int iof_hgetc (iof *I); -+UTILAPI int iof_igetc (iof *I); -+ -+// UTILAPI int iof_cmp (iof *I, const char *s); -+// UTILAPI int iof_cmpn (iof *I, const char *s, size_t bytes); -+ -+UTILAPI iof_status iof_pass (iof *I, iof *O); -+#define iof_hpass iof_pass -+#define iof_ipass iof_pass -+ -+/* readers helpers */ -+ -+UTILAPI size_t iof_read (iof *I, void *s, size_t bytes); -+UTILAPI size_t iof_hread (iof *I, void *s, size_t bytes); -+UTILAPI size_t iof_iread (iof *I, void *s, size_t bytes); -+ -+UTILAPI size_t iof_skip (iof *I, size_t bytes); -+UTILAPI size_t iof_hskip (iof *I, size_t bytes); -+UTILAPI size_t iof_iskip (iof *I, size_t bytes); -+ -+/* get */ -+ -+#define iof_pos(I) (*(I)->pos++) -+#define iof_hpos(I) (*(I)->hpos++) -+#define iof_ipos(I) (*(I)->ipos++) -+ -+#define iof_get(I) (iof_readable(I) ? (int)(*(I)->pos++) : IOFEOF) -+#define iof_hget(I) (iof_hreadable(I) ? (int)(*(I)->hpos++) : IOFEOF) -+#define iof_iget(I) (iof_ireadable(I) ? (int)(*(I)->ipos++) : IOFEOF) -+ -+#define iof_char(I) (iof_readable(I) ? (int)(*(I)->pos) : IOFEOF) -+#define iof_hcurr(I) (iof_hreadable(I) ? (int)(*(I)->hpos) : IOFEOF) -+#define iof_icurr(I) (iof_ireadable(I) ? (int)(*(I)->ipos) : IOFEOF) -+ -+#define iof_next(I) (++(I)->pos, iof_char(I)) -+#define iof_hnext(I) (++(I)->hpos, iof_hcurr(I)) -+#define iof_inext(I) (++(I)->ipos, iof_icurr(I)) -+ -+/* unget */ -+ -+/* -+If possible, we just move the position backward. If it is not possible to -+move backward, we call iof_backup(I, c) that sets all pointers to the end of -+a private backup space, then moves buf AND pos pointers backward and set c at -+pos (==buf). We can backup characters as long as there is a private space. If -+several calls to iof_backup() are followed by iof_get(), pos pointer -+increases in normal way and so the use of another iof_unget() works just fine -+by moving the position. Once we swallow all backup characters (when -+pos==end), backup handler restores the previous pointers. -+ -+Obviously we assume that the character provided to iof_unget() is always the -+character just obtained from iof_get(). We CAN'T just overwrite the character -+at a given position as the space we read may not be writable. -+ -+When backup is in use, we can only get bytes until automatically restored. -+*/ -+ -+/* backup */ -+ -+/* -+#define iof_uses_backup(I) ((I)->more == iof_unget_handler) -+ -+#define iof_save(I, B) \ -+ ((B)->buf = (I)->buf, (B)->pos = (I)->pos, (B)->end = (I)->end, (B)->space = (I)->space, \ -+ (B)->link = I->link, (B)->more = (I)->more, (B)->flags = (I)->flags) -+#define iof_restore(B, I) iof_save(I, B) -+ -+#define iof_unget(I, c) \ -+ ((void)(c == (uint8_t)c ? ((I)->pos > (I)->buf ? --(I)->pos : iof_backup(I, c)) : 0) -+int iof_backup (iof *I, int c); -+*/ -+ -+/* writing */ -+ -+UTILAPI size_t iof_write_file_handle (iof *O, FILE *file); -+UTILAPI size_t iof_write_file (iof *O, const char *filename); -+UTILAPI size_t iof_write_iofile (iof *O, iof_file *iofile, int savepos); -+ -+UTILAPI int iof_putc (iof *O, int u); -+UTILAPI int iof_hputc (iof *O, int u); -+UTILAPI int iof_iputc (iof *O, int u); -+ -+UTILAPI size_t iof_write (iof *O, const void *data, size_t size); -+UTILAPI size_t iof_hwrite (iof *O, const void *data, size_t size); -+UTILAPI size_t iof_iwrite (iof *O, const void *data, size_t size); -+ -+UTILAPI iof_status iof_puts (iof *O, const void *data); -+UTILAPI size_t iof_put_string (iof *O, const void *data); -+UTILAPI size_t iof_putfs (iof *O, const char *format, ...); -+UTILAPI size_t iof_repc (iof *O, char c, size_t bytes); -+ -+#define iof_putl(O, s) iof_write(O, "" s, sizeof(s)-1) -+//#define iof_putl iof_puts -+ -+#define iof_set(O, c) (*(O)->pos++ = (uint8_t)(c)) -+#define iof_set2(O, c1, c2) (iof_set(O, c1), iof_set(O, c2)) -+#define iof_set3(O, c1, c2, c3) (iof_set(O, c1), iof_set(O, c2), iof_set(O, c3)) -+#define iof_set4(O, c1, c2, c3, c4) (iof_set(O, c1), iof_set(O, c2), iof_set(O, c3), iof_set(O, c4)) -+#define iof_set5(O, c1, c2, c3, c4, c5) (iof_set(O, c1), iof_set(O, c2), iof_set(O, c3), iof_set(O, c4), iof_set(O, c5)) -+ -+#define iof_hset(O, c) (*(O)->hpos++ = (uint16_t)(c)) -+#define iof_iset(O, c) (*(O)->ipos++ = (uint32_t)(c)) -+ -+#define iof_put(O, c) ((void)iof_ensure(O, 1), iof_set(O, c)) -+#define iof_put2(O, c1, c2) ((void)iof_ensure(O, 2), iof_set2(O, c1, c2)) -+#define iof_put3(O, c1, c2, c3) ((void)iof_ensure(O, 3), iof_set3(O, c1, c2, c3)) -+#define iof_put4(O, c1, c2, c3, c4) ((void)iof_ensure(O, 4), iof_set4(O, c1, c2, c3, c4)) -+#define iof_put5(O, c1, c2, c3, c4, c5) ((void)iof_ensure(O, 5), iof_set5(O, c1, c2, c3, c4, c5)) -+ -+#define iof_hput(O, c) ((void)iof_hensure(O, 1), iof_hset(O, c)) -+#define iof_iput(O, c) ((void)iof_iensure(O, 1), iof_iset(O, c)) -+ -+#define iof_put_uc_hex(O, c) iof_put2(O, base16_uc_digit1(c), base16_uc_digit2(c)) -+#define iof_put_lc_hex(O, c) iof_put2(O, base16_lc_digit1(c), base16_lc_digit2(c)) -+#define iof_set_uc_hex(O, c) iof_set2(O, base16_uc_digit1(c), base16_uc_digit2(c)) -+#define iof_set_lc_hex(O, c) iof_set2(O, base16_lc_digit1(c), base16_lc_digit2(c)) -+#define iof_put_hex iof_put_uc_hex -+#define iof_set_hex iof_set_uc_hex -+ -+/* number from iof; return 1 on success, 0 otherwise */ -+ -+#define iof_scan_sign(I, c, sign) _scan_sign(c, sign, iof_next(I)) -+#define iof_scan_integer(I, c, number) _scan_integer(c, number, iof_next(I)) -+#define iof_scan_radix(I, c, number, radix) _scan_radix(c, number, radix, iof_next(I)) -+#define iof_read_integer(I, c, number) _read_integer(c, number, iof_next(I)) -+#define iof_read_radix(I, c, number, radix) _read_radix(c, number, radix, iof_next(I)) -+ -+#define iof_scan_decimal(I, c, number) _scan_decimal(c, number, iof_next(I)) -+#define iof_scan_fraction(I, c, number, exponent10) _scan_fraction(c, number, exponent10, iof_next(I)) -+#define iof_scan_exponent10(I, c, exponent10) _scan_exponent10(c, exponent10, iof_next(I)) -+ -+UTILAPI int iof_get_int32 (iof *I, int32_t *number); -+UTILAPI int iof_get_intlw (iof *I, intlw_t *number); -+UTILAPI int iof_get_int64 (iof *I, int64_t *number); -+ -+UTILAPI int iof_get_uint32 (iof *I, uint32_t *number); -+UTILAPI int iof_get_uintlw (iof *I, uintlw_t *number); -+UTILAPI int iof_get_uint64 (iof *I, uint64_t *number); -+ -+UTILAPI int iof_get_int32_radix (iof *I, int32_t *number, int radix); -+UTILAPI int iof_get_intlw_radix (iof *I, intlw_t *number, int radix); -+UTILAPI int iof_get_int64_radix (iof *I, int64_t *number, int radix); -+ -+UTILAPI int iof_get_uint32_radix (iof *I, uint32_t *number, int radix); -+UTILAPI int iof_get_uintlw_radix (iof *I, uintlw_t *number, int radix); -+UTILAPI int iof_get_uint64_radix (iof *I, uint64_t *number, int radix); -+ -+UTILAPI int iof_get_roman (iof *I, unsigned short int *number); -+ -+UTILAPI int iof_get_double (iof *I, double *number); -+UTILAPI int iof_get_float (iof *I, float *number); -+ -+UTILAPI int iof_conv_double (iof *I, double *number); -+UTILAPI int iof_conv_float (iof *I, float *number); -+ -+/* number to iof; return a number of written bytes */ -+ -+UTILAPI size_t iof_put_int32 (iof *O, int32_t number); -+UTILAPI size_t iof_put_intlw (iof *O, intlw_t number); -+UTILAPI size_t iof_put_int64 (iof *O, int64_t number); -+ -+UTILAPI size_t iof_put_uint32 (iof *O, uint32_t number); -+UTILAPI size_t iof_put_uintlw (iof *O, uintlw_t number); -+UTILAPI size_t iof_put_uint64 (iof *O, uint64_t number); -+ -+UTILAPI size_t iof_put_int32_radix (iof *O, int32_t number, int radix); -+UTILAPI size_t iof_put_intlw_radix (iof *O, intlw_t number, int radix); -+UTILAPI size_t iof_put_int64_radix (iof *O, int64_t number, int radix); -+ -+UTILAPI size_t iof_put_uint32_radix (iof *O, uint32_t number, int radix); -+UTILAPI size_t iof_put_uintlw_radix (iof *O, uintlw_t number, int radix); -+UTILAPI size_t iof_put_uint64_radix (iof *O, uint64_t number, int radix); -+ -+UTILAPI size_t iof_put_roman_uc (iof *O, uint16_t number); -+UTILAPI size_t iof_put_roman_lc (iof *O, uint16_t number); -+#define iof_put_roman(I, number) iof_put_roman_uc(I, number) -+ -+UTILAPI size_t iof_put_double(iof *O, double number, int digits); -+UTILAPI size_t iof_put_float(iof *O, float number, int digits); -+ -+/* common stuff for binary integers */ -+ -+UTILAPI int iof_get_be_uint2 (iof *I, uint32_t *pnumber); -+UTILAPI int iof_get_be_uint3 (iof *I, uint32_t *pnumber); -+UTILAPI int iof_get_be_uint4 (iof *I, uint32_t *pnumber); -+ -+UTILAPI int iof_get_le_uint2 (iof *I, uint32_t *pnumber); -+UTILAPI int iof_get_le_uint3 (iof *I, uint32_t *pnumber); -+UTILAPI int iof_get_le_uint4 (iof *I, uint32_t *pnumber); -+ -+// iof_set() and iof_put() suite casts arguments to uint8_t, so we don't need &0xff mask -+ -+#define iof_set_be_uint1(O, u) iof_set(O, u) -+#define iof_set_be_uint2(O, u) iof_set2(O, (u)>>8, u) -+#define iof_set_be_uint3(O, u) iof_set3(O, (u)>>16, (u)>>8, u) -+#define iof_set_be_uint4(O, u) iof_set4(O, (u)>>24, (u)>>16, (u)>>8, u) -+ -+#define iof_set_le_uint1(O, u) iof_set(O, u) -+#define iof_set_le_uint2(O, u) iof_set2(O, u, (u)>>8) -+#define iof_set_le_uint3(O, u) iof_set3(O, u, (u)>>8, (u)>>16) -+#define iof_set_le_uint4(O, u) iof_set4(O, u, (u)>>8, (u)>>16, (u)>>24) -+ -+#define iof_put_be_uint1(O, u) iof_put(O, u) -+#define iof_put_be_uint2(O, u) iof_put2(O, (u)>>8, u) -+#define iof_put_be_uint3(O, u) iof_put3(O, (u)>>16, (u)>>8, u) -+#define iof_put_be_uint4(O, u) iof_put4(O, (u)>>24, (u)>>16, (u)>>8, u) -+ -+#define iof_put_le_uint1(O, u) iof_put(O, u) -+#define iof_put_le_uint2(O, u) iof_put2(O, u, (u)>>8) -+#define iof_put_le_uint3(O, u) iof_put3(O, u, (u)>>8, (u)>>16) -+#define iof_put_le_uint4(O, u) iof_put4(O, u, (u)>>8, (u)>>16, (u)>>24) -+ -+/* buffer results */ -+ -+#define iof_reader_result(I, size) ((size = iof_left(I)), (I)->pos) -+#define iof_writer_result(I, size) ((size = iof_size(I)), (I)->buf) -+#define iof_result(I, size) (((I)->flags & IOF_READER) ? iof_reader_result(I, size) : iof_writer_result(I, size)) -+ -+uint8_t * iof_file_input_data (iof_file *iofile, size_t *psize, int *isnew); -+//uint8_t * iof_file_reader_data (iof_file *iofile, size_t *size); -+//uint8_t * iof_file_writer_data (iof_file *iofile, size_t *size); -+ -+uint8_t * iof_reader_data (iof *I, size_t *psize); -+uint8_t * iof_writer_data (iof *O, size_t *psize); -+size_t iof_reader_to_file_handle (iof *I, FILE *file); -+size_t iof_reader_to_file (iof *I, const char *filename); -+ -+#define iof_loaded(I) ((I)->end = (I)->pos, (I)->pos = (I)->buf, iof_left(I)) -+ -+#define iof_data_to_file_handle(data, size, file) fwrite(data, sizeof(uint8_t), size, file) -+UTILAPI size_t iof_data_to_file (const void *data, size_t size, const char *filename); -+ -+UTILAPI size_t iof_result_to_file_handle (iof *F, FILE *file); -+UTILAPI size_t iof_result_to_file (iof *F, const char *filename); -+UTILAPI void iof_debug (iof *I, const char *filename); -+ -+/* common filters allocator */ -+ -+void iof_filters_init (void); -+void iof_filters_free (void); -+ -+void * iof_filter_new (size_t size); -+void iof_heap_back (void *data); -+#define iof_filter_free(F) iof_heap_back(F) -+#define iof_filter_buffer_free(data) iof_heap_back(data) -+ -+// &((void *)pstate -+ -+iof * iof_filter_reader_new (iof_handler handler, size_t statesize, void **pstate); -+#define iof_filter_reader(handler, statesize, pstate) iof_filter_reader_new(handler, statesize, (void **)(pstate)) -+iof * iof_filter_reader_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t buffersize); -+#define iof_filter_reader_with_buffer(handler, statesize, pstate, buffer, buffersize) iof_filter_reader_with_buffer_new(handler, statesize, (void **)(pstate), buffer, buffersize) -+iof * iof_filter_writer_new (iof_handler handler, size_t statesize, void **pstate); -+#define iof_filter_writer(handler, statesize, pstate) iof_filter_writer_new(handler, statesize, (void **)(pstate)) -+iof * iof_filter_writer_with_buffer_new (iof_handler handler, size_t statesize, void **pstate, void *buffer, size_t buffersize); -+#define iof_filter_writer_with_buffer(handler, statesize, pstate, buffer, buffersize) iof_filter_writer_with_buffer_new(handler, statesize, (void **)(pstate), buffer, buffersize) -+ -+#define iof_filter_state(statetype, F) (statetype)((F) + 1) -+ -+void iof_free (iof *F); -+void iof_discard (iof *F); -+ -+size_t iof_resize_buffer_to (iof *O, size_t space); -+#define iof_resize_buffer(O) iof_resize_buffer_to(O, (O)->space << 1) -+ -+size_t iof_decoder_retval (iof *I, const char *type, iof_status status); -+size_t iof_encoder_retval (iof *O, const char *type, iof_status status); -+ -+/* filters */ -+ -+iof * iof_filter_file_handle_reader (FILE *file); -+iof * iof_filter_file_handle_writer (FILE *file); -+ -+iof * iof_filter_iofile_reader (iof_file *iofile, size_t offset); -+iof * iof_filter_iofile_writer (iof_file *iofile, size_t offset); -+ -+iof * iof_filter_file_reader (const char *filename); -+iof * iof_filter_file_writer (const char *filename); -+ -+iof * iof_filter_string_reader (const void *s, size_t length); -+iof * iof_filter_string_writer (const void *s, size_t length); -+ -+iof * iof_filter_buffer_writer (size_t size); -+ -+iof * iof_filter_stream_reader (FILE *file, size_t offset, size_t length); -+iof * iof_filter_stream_coreader (iof_file *iofile, size_t offset, size_t length); -+ -+iof * iof_filter_stream_writer (FILE *file); -+iof * iof_filter_stream_cowriter (iof_file *iofile, size_t offset); -+ -+FILE * iof_filter_file_reader_source (iof *I, size_t *poffset, size_t *plength); -+iof_file * iof_filter_file_coreader_source (iof *I, size_t *poffset, size_t *plength); -+iof * iof_filter_reader_replacement (iof *P, iof_handler handler, size_t statesize, void **pstate); -+#define iof_filter_reader_replace(P, handler, statesize, pstate) iof_filter_reader_replacement(P, handler, statesize, (void **)(pstate)) -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utillog.c b/texk/web2c/luatexdir/luapplib/util/utillog.c -new file mode 100644 -index 000000000..1b38f7467 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utillog.c -@@ -0,0 +1,60 @@ -+ -+#include -+#include // strlen -+#include -+#include "utillog.h" -+ -+#define LOGGER_BUFFER_SIZE 256 -+#define LOGGER_PREFIX_SIZE 32 -+ -+typedef struct { -+ logger_function callback; -+ void *context; -+ size_t pfxlen; -+} logger_struct; -+ -+static logger_struct logger = { 0, NULL, 0 }; -+ -+static char logger_buffer[LOGGER_BUFFER_SIZE+LOGGER_PREFIX_SIZE]; -+ -+void loggerf (const char *format, ...) -+{ -+ va_list args; -+ int length; -+ -+ va_start(args, format); -+ length = vsnprintf(logger_buffer + logger.pfxlen, LOGGER_BUFFER_SIZE, format, args); -+ if (length > 0) -+ { -+ if (length > LOGGER_BUFFER_SIZE) -+ length = LOGGER_BUFFER_SIZE; -+ } -+ else -+ { -+ loggerf("logger encoding error '%s'", format); -+ length = (int)strlen(logger_buffer); -+ } -+ length += (int)logger.pfxlen; -+ if (logger.callback) -+ logger.callback(logger_buffer, logger.context); -+ else -+ printf("\n%s\n", logger_buffer); -+ va_end(args); -+} -+ -+void logger_callback (logger_function callback, void *context) -+{ -+ logger.callback = callback; -+ logger.context = context; -+} -+ -+int logger_prefix (const char *prefix) -+{ -+ size_t pfxlen; -+ pfxlen = strlen(prefix); -+ if (pfxlen > LOGGER_PREFIX_SIZE) -+ return 0; -+ memcpy(logger_buffer, prefix, pfxlen); -+ logger.pfxlen = pfxlen; -+ return 1; -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utillog.h b/texk/web2c/luatexdir/luapplib/util/utillog.h -new file mode 100644 -index 000000000..c30e0ff0f ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utillog.h -@@ -0,0 +1,10 @@ -+ -+#ifndef UTIL_LOG_H -+#define UTIL_LOG_H -+ -+typedef void (*logger_function) (const char *message, void *alien); -+void loggerf (const char *format, ...); -+void logger_callback (logger_function callback, void *context); -+int logger_prefix (const char *prefix); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utillzw.c b/texk/web2c/luatexdir/luapplib/util/utillzw.c -new file mode 100644 -index 000000000..4cd221214 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utillzw.c -@@ -0,0 +1,701 @@ -+/* lzw implementation for postscript/pdf filters -+# Notes on LZW -+ -+# Encoder -+ -+Initially the table contains 256 entires for single bytes. Encoder consumes -+input bytes trying to find the longest sequence stored so far in the table. -+Once it finds a sequence that is not present in the table, it outputs the table -+index of the longest sequence found (accumulated bytes except the last -+consumed) and pushes the new sequence (accumulated bytes including the last -+one) on the top of the table. The last taken byte is not yet written to the -+output, it becomes the beginning of the new sequence to accumulate. Initially, -+encoder outputs 9-bit codes. While the table grows, the number of bits for each -+code increases up to 12. In example, after adding a table entry of index 511 it -+is high time to switch to 10-bit bytes. /EarlyChange=true parameter in stream -+dictionary (both postscript and pdf) informs to increase the number of bits one -+code earlier then necessary. Looks pretty much like an early days bug that -+became a specification :) I have never found a PDF having /EarlyChange key -+specified anyway. -+ -+Once the table becomes full (or when encoder decides it is worthy), -+a clear-table marker (code 256) purges the table and restores codes length to -+9. End-of-data marker (code 257) ends the stream. Conventionally, the beginning -+of the stream starts with clear-table marker. -+ -+Postscript allows to provide a /UnitLength which determines the bit length of -+codes. The above description assumes UnitLength=8 (default). Allowed values are -+from 3 to 8. Different UnitLength also affects markers; clear-table is then -+2^UnitLength and end-of-data marker is 2^UnitLenth+1. -+ -+Encoder outputs 9-12bit codes that are packed into bytes using high-bits-first -+scheme (default) or low-bits-scheme. -+ -+PDF spec p. 73 (PS spec p. 135 gives an mistaken output sequence and so -+mistaken output bytes) -+ -+Input character sequence (decimal) -+45 45 45 45 45 65 45 45 45 66 -+ -+Output 9bit codes (decimal) -+256 45 258 258 65 259 66 257 -+ -+Output 9bit codes (binary) -+100000000 000101101 100000010 100000010 001000001 100000011 001000010 100000001 -+ -+Output bytes (LowBitsFirst=false); eight high-order bits of code becomes -+the first byte, remaining low-order bit of code becomes the high-order bit of the -+next byte; -+10000000 00001011 01100000 01010000 00100010 00001100 00001100 10000101 00000001 -+-> 80 0B 60 50 22 0C 0C 85 01 -+ -+Output bytes (binary, LowBitsFirst=true); eight low-order bits of code becomes -+the first byte, remaining high-order bit of code becomes low-order bit of the -+next byte; -+00000000 01011011 00001000 00010100 00011000 01100100 10100000 10000000 10010000 -+-> 00 5B 08 14 18 64 A0 80 90 -+ -+# Decoder -+ -+Decoder consumes input bytes transforming them to 9 to 12 bit codes. Initially -+it starts with 9bit codes and the table of 258 fixed codes (same as encoder). -+Basically, it interprets incoming codes as table indices (except 256 and 257 -+markers) and it outputs byte sequences stored at given indices. It also -+upbuilds the table and changes the number of bits of codes when necessary. The -+key point on lzw is that both encoder and decoder builds the table -+synchronously. -+ -+However, decoder needs some "knowledge" about how encoder works to be able to -+interpret a table index that it doesn't have so far. Look that the output from -+encoder in the example above. The first output code is conventional clear-table -+(256). Then comes a code 45. So far so good, decoder interprets code 45 as -+a (fixed) entry of the table, emitting byte 45. The next code is 258, which is -+should be interpreted as an index in the table. Oops, encoder doesn't have one -+yet. If that occurs, it means that encoder was able to output the new entry -+code just after adding it to a table. It means that -+ -+ sequence_before + next_byte == next_byte + sequence_after -+ -+This may happen not only for sequences like 45 45 45, but also symmetric series -+such as abcbabcba; abcb + a == a + bcba. Decoder must be aware of that and if -+it gets a code one larger than the top table index, it should create one on-fly -+by appending last entry sequence by the first by of the last entry. -+ -+# UnitLength -+ -+Postscript specification mentions about UnitLength parameter that can be used -+in LZW decoder (not allowed in encoder), with possible values from 3 to 8. This -+parameter determines the number of bits per code; form UnitLength + 1 to 12. It -+also determines which codes are used for clear-table marker (2^UnitLength) and -+end-of-data marker ((2^UnitLength)+1). Postscript specification says (page 134): -+ -+"Initially, the code length is (UnitLength + 1) bits and the table contains only -+entries for the (2^UnitLength + 2) fixed codes. As encoding proceeds, entries are -+appended to the table, associating new codes with longer and longer input character -+sequences. The encoding and decoding filters maintain identical copies of -+this table." -+ -+Later on page 136 Postscript specification says: -+ -+"Data that has been LZW-encoded with a UnitLength less than 8 consists only of -+codes in the range 0 to 2^UnitLength - 1; consequently, the LZWDecode filter produces -+only codes in that range when read. UnitLength also affects the encoded -+representation, as described above." -+ -+UnitLength (Postscript only) and LowBitsFirst are used only by decoder. -+EarlyChange should obviously be respected by both encoder and decoder. When -+table index reaches current bit length boundary (511, 1023, ...) it must react -+by increasing the number of bits of input code. But if the index reaches it -+maximum value (when the table is full), decoder is NOT supposed to clear the -+table. When the table is full, encoder must emit clear-table marker and it -+emits this code using 12 bits and reinitialize code bits after that. It means -+that, when the table is full, decoder should get one more 12-bit code (which -+should be clear-table marker) and actually clear the table and reinitialize -+code bits after that. -+ -+# Clear-table vs last entry track (after tries and checks) -+ -+It is also not quite clear what should actually happen when encoder gets a full -+table and it is supposed to emit clear-table marker. When it gets full, it -+means that it has just appended another entry to the table. And that happens -+only the input sequence collected so far plus the last byte is not present in -+the table. Encoder is supposed to output the table index of the present -+sequence and set the recent byte as a starting index of the new sequence to be -+collected. Even if it is time to clear the table, encoder is still supposed to -+keep the track of the last table entry. Decoder, however, must drop the track of the -+last code on clear-table. -+ -+# Decoder table vs encoder table -+ -+While decoding we need query lzw table by (subsequent) numeric codes and output -+character sequences stored in the table. While encoding we need to query the -+table on every input byte and fetch indices pointing to character sequences. -+Note that we never need to query the entire table for the longest sequence -+found so far. The encoder table do not need to access the longest character -+sequence at one piece. It is enough to keep the track of the current table -+index and the very next byte. We organize an encoder table into a search tree, -+where every node contains its table index (value) and last byte (key). Except -+initial tree content, every node is created on the base of the previous node -+and it conceptually point the sequence represented by that nodo consists of the -+previous node sequence plus the next byte. -+ -+Every new node is a descendant of the node it has been derived from. Every node -+has a map (a search subtree) indexed by suffix byte value, pointing to -+descendants nodes. Every node also has binary tentackles (left/right fields) -+necessary to search the map (except initials, every node lives in a map of some -+ancestor node). The key point is that on every input byte we don't search the -+entire tree, but only the map of the current node children. The map tree is -+a simple binary tree with no balancing mechanism (not worthy to optimize an -+ephemeric structure that may be upbuilt more often then queried). -+ -+In our implementation, decoder table requires 4069 entries (topmost index 4095). -+Encoder table, however, needs 4097 entries to handle the case when EarlyIndex -+parameter is 0 (I have never a chance to test that in practise). The node of index -+4096 might be added to a search tree, but its code is never emitted; the lookup -+is purged just after adding that node. -+ -+todo: -+- support for LowBitsFirst encoding -+*/ -+ -+#include "utilmem.h" -+#include "utillzw.h" -+ -+/* filter state struct */ -+ -+typedef struct lzw_entry { -+ union { -+ const char *rdata; // to be able to init with string literal -+ char *data; -+ }; -+ int size; -+} lzw_entry; -+ -+#define lzw_index short -+ -+typedef struct lzw_node lzw_node; -+ -+struct lzw_node { -+ lzw_index index; -+ unsigned char suffix; -+ lzw_node *left; -+ lzw_node *right; -+ lzw_node *map; -+}; -+ -+struct lzw_state { -+ union { -+ lzw_node *lookup; /* encoder table */ -+ lzw_entry *table; /* decoder table */ -+ }; -+ lzw_index index; /* table index */ -+ union { -+ lzw_node *lastnode; /* previous encoder table node */ -+ struct { -+ lzw_entry *lastentry; /* previous decoder table entry */ -+ int tailbytes; /* num of bytes of lastentry not yet written out */ -+ }; -+ }; -+ int basebits; /* /UnitLength parameter (8) */ -+ int codebits; /* current code bits */ -+ int lastbyte; /* previosly read byte */ -+ int tailbits; /* lastbyte bits not yet consumed */ -+ int flush; /* encoder */ -+ int flags; /* options */ -+}; -+ -+/* macros */ -+ -+#define LZW_MIN_BITS 3 -+#define LZW_MAX_BITS 12 -+#define LZW_TABLE_SIZE (1 << LZW_MAX_BITS) -+#define LZW_LOOKUP_SIZE (LZW_TABLE_SIZE + 1) -+ -+#define lzw_bit_range(bits) (bits >= LZW_MIN_BITS && bits <= LZW_BASE_BITS) -+#define lzw_base_bits(flags) (flags & ((1 << 4) - 1)) // 4 low bits of flags is basebits (UnitLength) -+ -+#define lzw_initial_codes(state) (1 << state->basebits) -+#define lzw_clear_code(state) lzw_initial_codes(state) -+#define lzw_eod_code(state) (lzw_initial_codes(state) + 1) -+#define lzw_initial_index(state) (lzw_initial_codes(state) + 2) -+ -+#define lzw_max_index(state) ((1 << state->codebits) - ((state->flags & LZW_EARLY_INDEX) ? 1 : 0)) -+#define lzw_check_bits(state) ((void)(state->index == lzw_max_index(state) && state->codebits < LZW_MAX_BITS && ++state->codebits)) -+ -+#define lzw_malloc util_malloc -+#define lzw_free util_free -+ -+/* decoder */ -+ -+static struct lzw_entry lzw_initial_table[] = { -+ {{"\x00"}, 1}, {{"\x01"}, 1}, {{"\x02"}, 1}, {{"\x03"}, 1}, {{"\x04"}, 1}, {{"\x05"}, 1}, {{"\x06"}, 1}, {{"\x07"}, 1}, {{"\x08"}, 1}, {{"\x09"}, 1}, {{"\x0A"}, 1}, {{"\x0B"}, 1}, {{"\x0C"}, 1}, {{"\x0D"}, 1}, {{"\x0E"}, 1}, {{"\x0F"}, 1}, -+ {{"\x10"}, 1}, {{"\x11"}, 1}, {{"\x12"}, 1}, {{"\x13"}, 1}, {{"\x14"}, 1}, {{"\x15"}, 1}, {{"\x16"}, 1}, {{"\x17"}, 1}, {{"\x18"}, 1}, {{"\x19"}, 1}, {{"\x1A"}, 1}, {{"\x1B"}, 1}, {{"\x1C"}, 1}, {{"\x1D"}, 1}, {{"\x1E"}, 1}, {{"\x1F"}, 1}, -+ {{"\x20"}, 1}, {{"\x21"}, 1}, {{"\x22"}, 1}, {{"\x23"}, 1}, {{"\x24"}, 1}, {{"\x25"}, 1}, {{"\x26"}, 1}, {{"\x27"}, 1}, {{"\x28"}, 1}, {{"\x29"}, 1}, {{"\x2A"}, 1}, {{"\x2B"}, 1}, {{"\x2C"}, 1}, {{"\x2D"}, 1}, {{"\x2E"}, 1}, {{"\x2F"}, 1}, -+ {{"\x30"}, 1}, {{"\x31"}, 1}, {{"\x32"}, 1}, {{"\x33"}, 1}, {{"\x34"}, 1}, {{"\x35"}, 1}, {{"\x36"}, 1}, {{"\x37"}, 1}, {{"\x38"}, 1}, {{"\x39"}, 1}, {{"\x3A"}, 1}, {{"\x3B"}, 1}, {{"\x3C"}, 1}, {{"\x3D"}, 1}, {{"\x3E"}, 1}, {{"\x3F"}, 1}, -+ {{"\x40"}, 1}, {{"\x41"}, 1}, {{"\x42"}, 1}, {{"\x43"}, 1}, {{"\x44"}, 1}, {{"\x45"}, 1}, {{"\x46"}, 1}, {{"\x47"}, 1}, {{"\x48"}, 1}, {{"\x49"}, 1}, {{"\x4A"}, 1}, {{"\x4B"}, 1}, {{"\x4C"}, 1}, {{"\x4D"}, 1}, {{"\x4E"}, 1}, {{"\x4F"}, 1}, -+ {{"\x50"}, 1}, {{"\x51"}, 1}, {{"\x52"}, 1}, {{"\x53"}, 1}, {{"\x54"}, 1}, {{"\x55"}, 1}, {{"\x56"}, 1}, {{"\x57"}, 1}, {{"\x58"}, 1}, {{"\x59"}, 1}, {{"\x5A"}, 1}, {{"\x5B"}, 1}, {{"\x5C"}, 1}, {{"\x5D"}, 1}, {{"\x5E"}, 1}, {{"\x5F"}, 1}, -+ {{"\x60"}, 1}, {{"\x61"}, 1}, {{"\x62"}, 1}, {{"\x63"}, 1}, {{"\x64"}, 1}, {{"\x65"}, 1}, {{"\x66"}, 1}, {{"\x67"}, 1}, {{"\x68"}, 1}, {{"\x69"}, 1}, {{"\x6A"}, 1}, {{"\x6B"}, 1}, {{"\x6C"}, 1}, {{"\x6D"}, 1}, {{"\x6E"}, 1}, {{"\x6F"}, 1}, -+ {{"\x70"}, 1}, {{"\x71"}, 1}, {{"\x72"}, 1}, {{"\x73"}, 1}, {{"\x74"}, 1}, {{"\x75"}, 1}, {{"\x76"}, 1}, {{"\x77"}, 1}, {{"\x78"}, 1}, {{"\x79"}, 1}, {{"\x7A"}, 1}, {{"\x7B"}, 1}, {{"\x7C"}, 1}, {{"\x7D"}, 1}, {{"\x7E"}, 1}, {{"\x7F"}, 1}, -+ {{"\x80"}, 1}, {{"\x81"}, 1}, {{"\x82"}, 1}, {{"\x83"}, 1}, {{"\x84"}, 1}, {{"\x85"}, 1}, {{"\x86"}, 1}, {{"\x87"}, 1}, {{"\x88"}, 1}, {{"\x89"}, 1}, {{"\x8A"}, 1}, {{"\x8B"}, 1}, {{"\x8C"}, 1}, {{"\x8D"}, 1}, {{"\x8E"}, 1}, {{"\x8F"}, 1}, -+ {{"\x90"}, 1}, {{"\x91"}, 1}, {{"\x92"}, 1}, {{"\x93"}, 1}, {{"\x94"}, 1}, {{"\x95"}, 1}, {{"\x96"}, 1}, {{"\x97"}, 1}, {{"\x98"}, 1}, {{"\x99"}, 1}, {{"\x9A"}, 1}, {{"\x9B"}, 1}, {{"\x9C"}, 1}, {{"\x9D"}, 1}, {{"\x9E"}, 1}, {{"\x9F"}, 1}, -+ {{"\xA0"}, 1}, {{"\xA1"}, 1}, {{"\xA2"}, 1}, {{"\xA3"}, 1}, {{"\xA4"}, 1}, {{"\xA5"}, 1}, {{"\xA6"}, 1}, {{"\xA7"}, 1}, {{"\xA8"}, 1}, {{"\xA9"}, 1}, {{"\xAA"}, 1}, {{"\xAB"}, 1}, {{"\xAC"}, 1}, {{"\xAD"}, 1}, {{"\xAE"}, 1}, {{"\xAF"}, 1}, -+ {{"\xB0"}, 1}, {{"\xB1"}, 1}, {{"\xB2"}, 1}, {{"\xB3"}, 1}, {{"\xB4"}, 1}, {{"\xB5"}, 1}, {{"\xB6"}, 1}, {{"\xB7"}, 1}, {{"\xB8"}, 1}, {{"\xB9"}, 1}, {{"\xBA"}, 1}, {{"\xBB"}, 1}, {{"\xBC"}, 1}, {{"\xBD"}, 1}, {{"\xBE"}, 1}, {{"\xBF"}, 1}, -+ {{"\xC0"}, 1}, {{"\xC1"}, 1}, {{"\xC2"}, 1}, {{"\xC3"}, 1}, {{"\xC4"}, 1}, {{"\xC5"}, 1}, {{"\xC6"}, 1}, {{"\xC7"}, 1}, {{"\xC8"}, 1}, {{"\xC9"}, 1}, {{"\xCA"}, 1}, {{"\xCB"}, 1}, {{"\xCC"}, 1}, {{"\xCD"}, 1}, {{"\xCE"}, 1}, {{"\xCF"}, 1}, -+ {{"\xD0"}, 1}, {{"\xD1"}, 1}, {{"\xD2"}, 1}, {{"\xD3"}, 1}, {{"\xD4"}, 1}, {{"\xD5"}, 1}, {{"\xD6"}, 1}, {{"\xD7"}, 1}, {{"\xD8"}, 1}, {{"\xD9"}, 1}, {{"\xDA"}, 1}, {{"\xDB"}, 1}, {{"\xDC"}, 1}, {{"\xDD"}, 1}, {{"\xDE"}, 1}, {{"\xDF"}, 1}, -+ {{"\xE0"}, 1}, {{"\xE1"}, 1}, {{"\xE2"}, 1}, {{"\xE3"}, 1}, {{"\xE4"}, 1}, {{"\xE5"}, 1}, {{"\xE6"}, 1}, {{"\xE7"}, 1}, {{"\xE8"}, 1}, {{"\xE9"}, 1}, {{"\xEA"}, 1}, {{"\xEB"}, 1}, {{"\xEC"}, 1}, {{"\xED"}, 1}, {{"\xEE"}, 1}, {{"\xEF"}, 1}, -+ {{"\xF0"}, 1}, {{"\xF1"}, 1}, {{"\xF2"}, 1}, {{"\xF3"}, 1}, {{"\xF4"}, 1}, {{"\xF5"}, 1}, {{"\xF6"}, 1}, {{"\xF7"}, 1}, {{"\xF8"}, 1}, {{"\xF9"}, 1}, {{"\xFA"}, 1}, {{"\xFB"}, 1}, {{"\xFC"}, 1}, {{"\xFD"}, 1}, {{"\xFE"}, 1}, {{"\xFF"}, 1} -+}; -+ -+#define lzw_entry_at(state, index) (&state->table[index]) -+ -+static lzw_state * lzw_decoder_init_table (lzw_state *state, lzw_entry *table, int flags) -+{ -+ state->basebits = lzw_base_bits(flags); // first four bits or flags -+ if (!lzw_bit_range(state->basebits)) -+ return NULL; -+ state->flags = flags; -+ if ((state->table = table) == NULL) -+ { -+ state->table = (lzw_entry *)lzw_malloc(LZW_TABLE_SIZE * sizeof(lzw_entry)); -+ state->flags |= LZW_TABLE_ALLOC; -+ } -+ memcpy(state->table, lzw_initial_table, (size_t)lzw_initial_codes(state)*sizeof(lzw_entry)); -+ // memset(&state->table[lzw_initial_codes(state)], 0, 2*sizeof(lzw_entry)); // eod and clear entries never accessed -+ state->codebits = state->basebits + 1; -+ state->index = lzw_initial_index(state); -+ state->lastentry = NULL; -+ state->tailbytes = 0; -+ state->lastbyte = 0; -+ state->tailbits = 0; -+ return state; -+} -+ -+lzw_state * lzw_decoder_init (lzw_state *state, int flags) -+{ -+ return lzw_decoder_init_table(state, NULL, flags); -+} -+ -+static void lzw_decoder_clear (lzw_state *state) -+{ -+ lzw_entry *entry; -+ lzw_index initindex = lzw_initial_index(state); -+ while (state->index > initindex) -+ { -+ entry = lzw_entry_at(state, --state->index); -+ lzw_free(entry->data); -+ // entry->data = NULL; -+ // entry->size = 0; -+ } -+ state->lastentry = NULL; -+ state->tailbytes = 0; -+ state->codebits = state->basebits + 1; -+} -+ -+void lzw_decoder_close (lzw_state *state) -+{ -+ lzw_decoder_clear(state); -+ if (state->flags & LZW_TABLE_ALLOC) -+ lzw_free(state->table); -+} -+ -+static int lzw_next_entry (lzw_state *state, lzw_entry *nextentry) -+{ -+ lzw_entry *lastentry, *newentry; -+ if ((lastentry = state->lastentry) == NULL) -+ return 1; /* its ok */ -+ if (state->index == LZW_TABLE_SIZE) -+ return 0; /* invalid input; eod marker expected earlier */ -+ /* put the new entry on the top of the table */ -+ newentry = lzw_entry_at(state, state->index++); -+ /* its size is the last entrtyy size plus 1 */ -+ newentry->size = lastentry->size + 1; -+ /* its content is the content of the last entry, */ -+ newentry->data = (char *)lzw_malloc((size_t)newentry->size); -+ memcpy(newentry->data, lastentry->data, lastentry->size); -+ /* plus the first byte of the new entry (usually fixed code entry) */ -+ newentry->data[newentry->size - 1] = nextentry->data[0]; -+ return 1; -+} -+ -+#define lzw_write_bytes(O, state) ((state->tailbytes -= (int)iof_write(O, state->lastentry->data, (size_t)state->tailbytes)) == 0) -+ -+iof_status lzw_decode_state (iof *I, iof *O, lzw_state *state) -+{ -+ const lzw_index clear = lzw_clear_code(state), eod = lzw_eod_code(state); -+ lzw_index code; -+ lzw_entry *entry; -+ if (state->lastentry != NULL) -+ { /* write out the tail from the last call */ -+ if (state->tailbytes > 0 && !lzw_write_bytes(O, state)) -+ return IOFFULL; -+ /* do what we normally do at the end of the loop body below */ -+ lzw_check_bits(state); -+ } -+ // if (state->flags & LZW_LOW_BITS_FIRST) -+ // return IOFERR; -+ while (1) -+ { -+ /* get input code of length state->codebits */ -+ code = (state->lastbyte & ((1 << state->tailbits) - 1)) << (state->codebits - state->tailbits); -+ for (state->tailbits -= state->codebits; state->tailbits < 0; ) -+ { -+ get_code: -+ if ((state->lastbyte = iof_get(I)) < 0) -+ return state->flush ? IOFEOF : state->lastbyte; -+ state->tailbits += 8; -+ if (state->tailbits < 0) -+ { -+ code |= (state->lastbyte << (-state->tailbits)); -+ goto get_code; -+ } -+ else -+ { -+ code |= (state->lastbyte >> state->tailbits); -+ break; -+ } -+ } -+ /* interpret the code */ -+ if (code < state->index) -+ { /* single byte code or special marker */ -+ if (code == clear) -+ { -+ lzw_decoder_clear(state); -+ continue; -+ } -+ if (code == eod) -+ return IOFEOF; -+ entry = lzw_entry_at(state, code); -+ if (!lzw_next_entry(state, entry)) -+ return IOFERR; -+ } -+ else if (code == state->index) -+ { /* apparently encoder has emitted the code of the key just created (see notes) */ -+ if (!lzw_next_entry(state, state->lastentry)) -+ return IOFERR; -+ entry = lzw_entry_at(state, state->index - 1); -+ } -+ else -+ { /* invalid input code */ -+ return IOFERR; -+ } -+ /* record the entry found */ -+ state->lastentry = entry; -+ /* emit the sequence pointed by that entry */ -+ state->tailbytes = entry->size; -+ if (!lzw_write_bytes(O, state)) -+ return IOFFULL; -+ /* check and update code bits */ -+ lzw_check_bits(state); -+ } -+ return state->lastbyte; // never reached -+} -+ -+/* encoder */ -+ -+#define lzw_node_at(state, index) (&state->lookup[index]) -+ -+#define lzw_node_init(node, i, c) (node->index = i, node->suffix = c, node->left = NULL, node->right = NULL, node->map = NULL) -+ -+static lzw_state * lzw_encoder_init_table (lzw_state *state, lzw_node *lookup, int flags) -+{ -+ lzw_index index; -+ lzw_node *node; -+ state->basebits = lzw_base_bits(flags); // first four bits of flags is base bits of code (default 8) -+ if (!lzw_bit_range(state->basebits)) -+ return NULL; -+ state->flags = flags; -+ if ((state->lookup = lookup) == NULL) -+ { -+ state->lookup = lzw_malloc(LZW_LOOKUP_SIZE*sizeof(lzw_node)); -+ state->flags |= LZW_TABLE_ALLOC; -+ } -+ state->index = lzw_initial_index(state); -+ for (index = 0; index < lzw_initial_codes(state); ++index) -+ { -+ node = lzw_node_at(state, index); -+ lzw_node_init(node, index, (unsigned char)index); -+ } -+ state->codebits = state->basebits + 1; -+ state->lastnode = NULL; -+ state->lastbyte = 0; -+ state->tailbits = 0; -+ return state; -+} -+ -+lzw_state * lzw_encoder_init (lzw_state *state, int flags) -+{ -+ return lzw_encoder_init_table(state, NULL, flags); -+} -+ -+void lzw_encoder_close (lzw_state *state) -+{ -+ if (state->flags & LZW_TABLE_ALLOC) -+ lzw_free(state->lookup); -+} -+ -+static void lzw_encoder_clear (lzw_state *state) -+{ -+ lzw_node *node; -+ lzw_index index; -+ /* clear fixed nodes */ -+ for (index = 0; index < lzw_initial_codes(state); ++index) -+ { -+ node = lzw_node_at(state, index); -+ lzw_node_init(node, index, (unsigned char)index); -+ } -+ /* reset table index */ -+ state->index = lzw_initial_index(state); -+ /* reset code bits */ -+ state->codebits = state->basebits + 1; -+} -+ -+static void lzw_put_code (iof *O, lzw_state *state, lzw_index code, int todobits) -+{ -+ int leftbits, rightbits; -+ do -+ { -+ leftbits = 8 - state->tailbits; -+ rightbits = todobits - leftbits; -+ if (rightbits >= 0) -+ { -+ state->lastbyte |= (code >> rightbits); -+ iof_put(O, state->lastbyte); -+ code = code & ((1 << rightbits) - 1); -+ todobits -= leftbits; -+ state->lastbyte = 0; -+ state->tailbits = 0; -+ } -+ else -+ { -+ state->lastbyte |= (code << (-rightbits)); -+ state->tailbits += todobits; -+ return; -+ } -+ } while (1); -+} -+ -+static iof_status lzw_encode_last (iof *O, lzw_state *state) -+{ -+ if (state->flush) -+ { -+ /* put the last code if any */ -+ if (state->lastnode != NULL) -+ lzw_put_code(O, state, state->lastnode->index, state->codebits); -+ /* put eod marker, */ -+ lzw_put_code(O, state, lzw_eod_code(state), state->codebits); -+ /* with tail bits set to 0 */ -+ if (state->tailbits > 0) -+ lzw_put_code(O, state, 0, 8 - state->tailbits); -+ return IOFEOF; -+ } -+ return IOFEMPTY; -+} -+ -+static lzw_node * lzw_node_push (lzw_state *state, unsigned char suffix) -+{ -+ lzw_node *node; -+ node = lzw_node_at(state, state->index); -+ lzw_node_init(node, state->index, suffix); -+ ++state->index; -+ return node; -+} -+ -+static int lzw_next_node (lzw_state *state, unsigned char suffix) -+{ -+ lzw_node *node; -+ if ((node = state->lastnode->map) == NULL) -+ { -+ state->lastnode->map = lzw_node_push(state, suffix); -+ return 0; -+ } -+ while (1) -+ { -+ if (suffix < node->suffix) -+ { -+ if (node->left == NULL) -+ { -+ node->left = lzw_node_push(state, suffix); -+ return 0; -+ } -+ node = node->left; -+ } -+ else if (suffix > node->suffix) -+ { -+ if (node->right == NULL) -+ { -+ node->right = lzw_node_push(state, suffix); -+ return 0; -+ } -+ node = node->right; -+ } -+ else -+ { -+ state->lastnode = node; -+ return 1; -+ } -+ } -+ return 0; // never reached -+} -+ -+iof_status lzw_encode_state (iof *I, iof *O, lzw_state *state) -+{ -+ int byte; -+ if (state->lastnode == NULL) -+ { /* first call only; following convention, put clear-table marker */ -+ if (!iof_ensure(O, 2)) -+ return IOFFULL; -+ lzw_put_code(O, state, lzw_clear_code(state), state->codebits); -+ /* get the first input byte and initialize the current table entry */ -+ if ((byte = iof_get(I)) < 0) -+ return lzw_encode_last(O, state); -+ state->lastnode = lzw_node_at(state, byte); -+ } -+ while (iof_ensure(O, 2)) -+ { /* we need to write at most 2 bytes on each iteration */ -+ if ((byte = iof_get(I)) < 0) -+ return lzw_encode_last(O, state); -+ if (lzw_next_node(state, (unsigned char)byte) == 0) -+ { /* means that the key hasn't been found and the new entry has just been created */ -+ /* output the code pointing the longest sequence so far */ -+ lzw_put_code(O, state, state->lastnode->index, state->codebits); -+ /* update code bits */ -+ if (state->index == lzw_max_index(state) + 1) -+ { -+ if (state->codebits < LZW_MAX_BITS) -+ ++state->codebits; -+ else -+ { -+ /* put clear-table marker */ -+ lzw_put_code(O, state, lzw_clear_code(state), state->codebits); -+ /* reset the table */ -+ lzw_encoder_clear(state); -+ } -+ } -+ /* in any case, recent byte becomes the current table code */ -+ state->lastnode = lzw_node_at(state, byte); -+ } -+ /* otherwise no new entry is appended and state->lastnode points the longer sequence just found */ -+ } -+ return IOFFULL; -+} -+ -+/* single call codecs */ -+ -+iof_status lzw_decode (iof *I, iof *O, int flags) -+{ -+ lzw_state state = { { 0 } }; // shut overactive warnings -+ lzw_entry table[LZW_TABLE_SIZE]; -+ int ret; -+ lzw_decoder_init_table(&state, table, flags); -+ state.flush = 1; -+ ret = lzw_decode_state(I, O, &state); -+ // iof_flush(O); // ? -+ lzw_decoder_close(&state); -+ return ret; -+} -+ -+iof_status lzw_encode (iof *I, iof *O, int flags) -+{ -+ lzw_state state; -+ lzw_node lookup[LZW_LOOKUP_SIZE]; -+ int ret; -+ lzw_encoder_init_table(&state, lookup, flags); -+ state.flush = 1; -+ ret = lzw_encode_state(I, O, &state); -+ // iof_flush(O); // ? -+ lzw_encoder_close(&state); -+ return ret; -+} -+ -+/* filters */ -+ -+// lzw decoder function -+ -+static size_t lzw_decoder (iof *F, iof_mode mode) -+{ -+ lzw_state *state; -+ iof_status status; -+ size_t tail; -+ -+ state = iof_filter_state(lzw_state *, F); -+ switch(mode) -+ { -+ case IOFLOAD: -+ case IOFREAD: -+ if (F->flags & IOF_STOPPED) -+ return 0; -+ tail = iof_tail(F); -+ F->pos = F->buf + tail; -+ F->end = F->buf + F->space; -+ do { -+ status = lzw_decode_state(F->next, F, state); -+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F)); -+ return iof_decoder_retval(F, "lzw", status); -+ case IOFCLOSE: -+ lzw_decoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+// lzw encoder function -+ -+static size_t lzw_encoder (iof *F, iof_mode mode) -+{ -+ lzw_state *state; -+ iof_status status; -+ -+ state = iof_filter_state(lzw_state *, F); -+ switch (mode) -+ { -+ case IOFFLUSH: -+ state->flush = 1; -+ // fall through -+ case IOFWRITE: -+ F->end = F->pos; -+ F->pos = F->buf; -+ status = lzw_encode_state(F, F->next, state); -+ return iof_encoder_retval(F, "lzw", status); -+ case IOFCLOSE: -+ if (!state->flush) -+ lzw_encoder(F, IOFFLUSH); -+ lzw_encoder_close(state); -+ iof_free(F); -+ return 0; -+ default: -+ break; -+ } -+ return 0; -+} -+ -+iof * iof_filter_lzw_decoder (iof *N, int flags) -+{ -+ iof *I; -+ lzw_state *state; -+ I = iof_filter_reader(lzw_decoder, sizeof(lzw_state), &state); -+ iof_setup_next(I, N); -+ if (lzw_decoder_init(state, flags) == NULL) -+ { -+ iof_discard(I); -+ return NULL; -+ } -+ state->flush = 1; -+ return I; -+} -+ -+iof * iof_filter_lzw_encoder (iof *N, int flags) -+{ -+ iof *O; -+ lzw_state *state; -+ O = iof_filter_writer(lzw_encoder, sizeof(lzw_state), &state); -+ iof_setup_next(O, N); -+ if (lzw_encoder_init(state, flags) == NULL) -+ { -+ iof_discard(O); -+ return NULL; -+ } -+ return O; -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utillzw.h b/texk/web2c/luatexdir/luapplib/util/utillzw.h -new file mode 100644 -index 000000000..9e3a085d4 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utillzw.h -@@ -0,0 +1,30 @@ -+#ifndef UTIL_LZW_H -+#define UTIL_LZW_H -+ -+#include "utiliof.h" -+ -+typedef struct lzw_state lzw_state; -+ -+#define LZW_BASE_BITS 8 -+#define LZW_TABLE_ALLOC (1<<4) -+#define LZW_EARLY_INDEX (1<<5) -+//#define LZW_LOW_BITS_FIRST (1<<6) -+#define LZW_DECODER_DEFAULTS (LZW_BASE_BITS|LZW_EARLY_INDEX|0) -+#define LZW_ENCODER_DEFAULTS (LZW_BASE_BITS|LZW_EARLY_INDEX|0) -+ -+lzw_state * lzw_decoder_init (lzw_state *state, int flags); -+lzw_state * lzw_encoder_init (lzw_state *state, int flags); -+ -+void lzw_decoder_close (lzw_state *state); -+void lzw_encoder_close (lzw_state *state); -+ -+iof_status lzw_encode_state (iof *I, iof *O, lzw_state *state); -+iof_status lzw_decode_state (iof *I, iof *O, lzw_state *state); -+ -+iof_status lzw_encode (iof *I, iof *O, int flags); -+iof_status lzw_decode (iof *I, iof *O, int flags); -+ -+iof * iof_filter_lzw_decoder (iof *N, int flags); -+iof * iof_filter_lzw_encoder (iof *N, int flags); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilmd5.c b/texk/web2c/luatexdir/luapplib/util/utilmd5.c -new file mode 100644 -index 000000000..a2926b0aa ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilmd5.c -@@ -0,0 +1,413 @@ -+/* md5 implementation by Peter Deutsch (ghost@aladdin.com) with some convenience shorthands */ -+ -+/* begin of md5.c */ -+ -+/* -+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. -+ -+ This software is provided 'as-is', without any express or implied -+ warranty. In no event will the authors be held liable for any damages -+ arising from the use of this software. -+ -+ Permission is granted to anyone to use this software for any purpose, -+ including commercial applications, and to alter it and redistribute it -+ freely, subject to the following restrictions: -+ -+ 1. The origin of this software must not be misrepresented; you must not -+ claim that you wrote the original software. If you use this software -+ in a product, an acknowledgment in the product documentation would be -+ appreciated but is not required. -+ 2. Altered source versions must be plainly marked as such, and must not be -+ misrepresented as being the original software. -+ 3. This notice may not be removed or altered from any source distribution. -+ -+ L. Peter Deutsch -+ ghost@aladdin.com -+ -+ */ -+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -+/* -+ Independent implementation of MD5 (RFC 1321). -+ -+ This code implements the MD5 Algorithm defined in RFC 1321, whose -+ text is available at -+ http://www.ietf.org/rfc/rfc1321.txt -+ The code is derived from the text of the RFC, including the test suite -+ (section A.5) but excluding the rest of Appendix A. It does not include -+ any code or documentation that is identified in the RFC as being -+ copyrighted. -+ -+ The original and principal author of md5.c is L. Peter Deutsch -+ . Other authors are noted in the change history -+ that follows (in reverse chronological order): -+ -+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order -+ either statically or dynamically; added missing #include -+ in library. -+ 2002-03-11 lpd Corrected argument list for main(), and added int return -+ type, in test program and T value program. -+ 2002-02-21 lpd Added missing #include in test program. -+ 2000-07-03 lpd Patched to eliminate warnings about "constant is -+ unsigned in ANSI C, signed in traditional"; made test program -+ self-checking. -+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. -+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). -+ 1999-05-03 lpd Original version. -+ */ -+ -+//#include "md5.h" -+#include "utilmd5.h" -+#include -+ -+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -+#ifdef ARCH_IS_BIG_ENDIAN -+# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -+#else -+# define BYTE_ORDER 0 -+#endif -+ -+#define T_MASK ((uint32_t)~0) -+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -+#define T3 0x242070db -+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -+#define T6 0x4787c62a -+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -+#define T9 0x698098d8 -+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -+#define T13 0x6b901122 -+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -+#define T16 0x49b40821 -+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -+#define T19 0x265e5a51 -+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -+#define T22 0x02441453 -+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -+#define T25 0x21e1cde6 -+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -+#define T28 0x455a14ed -+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -+#define T31 0x676f02d9 -+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -+#define T35 0x6d9d6122 -+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -+#define T38 0x4bdecfa9 -+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -+#define T41 0x289b7ec6 -+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -+#define T44 0x04881d05 -+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -+#define T47 0x1fa27cf8 -+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -+#define T50 0x432aff97 -+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -+#define T53 0x655b59c3 -+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -+#define T57 0x6fa87e4f -+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -+#define T60 0x4e0811a1 -+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -+#define T63 0x2ad7d2bb -+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) -+ -+ -+static void -+md5_process(md5_state_t *pms, const uint8_t *data /*[64]*/) -+{ -+ uint32_t -+ a = pms->abcd[0], b = pms->abcd[1], -+ c = pms->abcd[2], d = pms->abcd[3]; -+ uint32_t t; -+#if BYTE_ORDER > 0 -+ /* Define storage only for big-endian CPUs. */ -+ uint32_t X[16]; -+#else -+ /* Define storage for little-endian or both types of CPUs. */ -+ uint32_t xbuf[16]; -+ const uint32_t *X; -+#endif -+ -+ { -+#if BYTE_ORDER == 0 -+ /* -+ * Determine dynamically whether this is a big-endian or -+ * little-endian machine, since we can use a more efficient -+ * algorithm on the latter. -+ */ -+ static const int w = 1; -+ -+ if (*((const uint8_t *)&w)) /* dynamic little-endian */ -+#endif -+#if BYTE_ORDER <= 0 /* little-endian */ -+ { -+ /* -+ * On little-endian machines, we can process properly aligned -+ * data without copying it. -+ */ -+ if (!((data - (const uint8_t *)0) & 3)) { -+ /* data are properly aligned */ -+ X = (const uint32_t *)data; -+ } else { -+ /* not aligned */ -+ memcpy(xbuf, data, 64); -+ X = xbuf; -+ } -+ } -+#endif -+#if BYTE_ORDER == 0 -+ else /* dynamic big-endian */ -+#endif -+#if BYTE_ORDER >= 0 /* big-endian */ -+ { -+ /* -+ * On big-endian machines, we must arrange the bytes in the -+ * right order. -+ */ -+ const uint8_t *xp = data; -+ int i; -+ -+# if BYTE_ORDER == 0 -+ X = xbuf; /* (dynamic only) */ -+# else -+# define xbuf X /* (static only) */ -+# endif -+ for (i = 0; i < 16; ++i, xp += 4) -+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); -+ } -+#endif -+ } -+ -+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) -+ -+ /* Round 1. */ -+ /* Let [abcd k s i] denote the operation -+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -+#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -+#define SET(a, b, c, d, k, s, Ti)\ -+ t = a + F(b,c,d) + X[k] + Ti;\ -+ a = ROTATE_LEFT(t, s) + b -+ /* Do the following 16 operations. */ -+ SET(a, b, c, d, 0, 7, T1); -+ SET(d, a, b, c, 1, 12, T2); -+ SET(c, d, a, b, 2, 17, T3); -+ SET(b, c, d, a, 3, 22, T4); -+ SET(a, b, c, d, 4, 7, T5); -+ SET(d, a, b, c, 5, 12, T6); -+ SET(c, d, a, b, 6, 17, T7); -+ SET(b, c, d, a, 7, 22, T8); -+ SET(a, b, c, d, 8, 7, T9); -+ SET(d, a, b, c, 9, 12, T10); -+ SET(c, d, a, b, 10, 17, T11); -+ SET(b, c, d, a, 11, 22, T12); -+ SET(a, b, c, d, 12, 7, T13); -+ SET(d, a, b, c, 13, 12, T14); -+ SET(c, d, a, b, 14, 17, T15); -+ SET(b, c, d, a, 15, 22, T16); -+#undef SET -+ -+ /* Round 2. */ -+ /* Let [abcd k s i] denote the operation -+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -+#define SET(a, b, c, d, k, s, Ti)\ -+ t = a + G(b,c,d) + X[k] + Ti;\ -+ a = ROTATE_LEFT(t, s) + b -+ /* Do the following 16 operations. */ -+ SET(a, b, c, d, 1, 5, T17); -+ SET(d, a, b, c, 6, 9, T18); -+ SET(c, d, a, b, 11, 14, T19); -+ SET(b, c, d, a, 0, 20, T20); -+ SET(a, b, c, d, 5, 5, T21); -+ SET(d, a, b, c, 10, 9, T22); -+ SET(c, d, a, b, 15, 14, T23); -+ SET(b, c, d, a, 4, 20, T24); -+ SET(a, b, c, d, 9, 5, T25); -+ SET(d, a, b, c, 14, 9, T26); -+ SET(c, d, a, b, 3, 14, T27); -+ SET(b, c, d, a, 8, 20, T28); -+ SET(a, b, c, d, 13, 5, T29); -+ SET(d, a, b, c, 2, 9, T30); -+ SET(c, d, a, b, 7, 14, T31); -+ SET(b, c, d, a, 12, 20, T32); -+#undef SET -+ -+ /* Round 3. */ -+ /* Let [abcd k s t] denote the operation -+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -+#define H(x, y, z) ((x) ^ (y) ^ (z)) -+#define SET(a, b, c, d, k, s, Ti)\ -+ t = a + H(b,c,d) + X[k] + Ti;\ -+ a = ROTATE_LEFT(t, s) + b -+ /* Do the following 16 operations. */ -+ SET(a, b, c, d, 5, 4, T33); -+ SET(d, a, b, c, 8, 11, T34); -+ SET(c, d, a, b, 11, 16, T35); -+ SET(b, c, d, a, 14, 23, T36); -+ SET(a, b, c, d, 1, 4, T37); -+ SET(d, a, b, c, 4, 11, T38); -+ SET(c, d, a, b, 7, 16, T39); -+ SET(b, c, d, a, 10, 23, T40); -+ SET(a, b, c, d, 13, 4, T41); -+ SET(d, a, b, c, 0, 11, T42); -+ SET(c, d, a, b, 3, 16, T43); -+ SET(b, c, d, a, 6, 23, T44); -+ SET(a, b, c, d, 9, 4, T45); -+ SET(d, a, b, c, 12, 11, T46); -+ SET(c, d, a, b, 15, 16, T47); -+ SET(b, c, d, a, 2, 23, T48); -+#undef SET -+ -+ /* Round 4. */ -+ /* Let [abcd k s t] denote the operation -+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -+#define I(x, y, z) ((y) ^ ((x) | ~(z))) -+#define SET(a, b, c, d, k, s, Ti)\ -+ t = a + I(b,c,d) + X[k] + Ti;\ -+ a = ROTATE_LEFT(t, s) + b -+ /* Do the following 16 operations. */ -+ SET(a, b, c, d, 0, 6, T49); -+ SET(d, a, b, c, 7, 10, T50); -+ SET(c, d, a, b, 14, 15, T51); -+ SET(b, c, d, a, 5, 21, T52); -+ SET(a, b, c, d, 12, 6, T53); -+ SET(d, a, b, c, 3, 10, T54); -+ SET(c, d, a, b, 10, 15, T55); -+ SET(b, c, d, a, 1, 21, T56); -+ SET(a, b, c, d, 8, 6, T57); -+ SET(d, a, b, c, 15, 10, T58); -+ SET(c, d, a, b, 6, 15, T59); -+ SET(b, c, d, a, 13, 21, T60); -+ SET(a, b, c, d, 4, 6, T61); -+ SET(d, a, b, c, 11, 10, T62); -+ SET(c, d, a, b, 2, 15, T63); -+ SET(b, c, d, a, 9, 21, T64); -+#undef SET -+ -+ /* Then perform the following additions. (That is increment each -+ of the four registers by the value it had before this block -+ was started.) */ -+ pms->abcd[0] += a; -+ pms->abcd[1] += b; -+ pms->abcd[2] += c; -+ pms->abcd[3] += d; -+} -+ -+void -+pplib_md5_init(md5_state_t *pms) -+{ -+ pms->count[0] = pms->count[1] = 0; -+ pms->abcd[0] = 0x67452301; -+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; -+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; -+ pms->abcd[3] = 0x10325476; -+} -+ -+void -+md5_add(md5_state_t *pms, const void *input, size_t size) -+{ -+ const uint8_t *p = (const uint8_t *)input; -+ int nbytes = (int)size; // PJ -+ int left = nbytes; -+ int offset = (pms->count[0] >> 3) & 63; -+ uint32_t nbits = (uint32_t)(nbytes << 3); -+ -+ if (nbytes <= 0) -+ return; -+ -+ /* Update the message length. */ -+ pms->count[1] += nbytes >> 29; -+ pms->count[0] += nbits; -+ if (pms->count[0] < nbits) -+ pms->count[1]++; -+ -+ /* Process an initial partial block. */ -+ if (offset) { -+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); -+ -+ memcpy(pms->buf + offset, p, copy); -+ if (offset + copy < 64) -+ return; -+ p += copy; -+ left -= copy; -+ md5_process(pms, pms->buf); -+ } -+ -+ /* Process full blocks. */ -+ for (; left >= 64; p += 64, left -= 64) -+ md5_process(pms, p); -+ -+ /* Process a final partial block. */ -+ if (left) -+ memcpy(pms->buf, p, left); -+} -+ -+void -+md5_put(md5_state_t *pms, uint8_t digest[16]) -+{ -+ static const uint8_t pad[64] = { -+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -+ }; -+ uint8_t data[8]; -+ int i; -+ -+ /* Save the length before padding. */ -+ for (i = 0; i < 8; ++i) -+ data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3)); -+ /* Pad to 56 bytes mod 64. */ -+ md5_add(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); -+ /* Append the length. */ -+ md5_add(pms, data, 8); -+ for (i = 0; i < 16; ++i) -+ digest[i] = (uint8_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -+} -+ -+/* end of md5.h */ -+ -+static md5_state_t state; -+ -+void pplib_md5 (const void *input, size_t length, uint8_t output[16]) -+{ -+ pplib_md5_init(&state); -+ md5_add(&state, input, length); -+ md5_put(&state, output); -+} -+ -+void md5init (void) -+{ -+ pplib_md5_init(&state); -+} -+ -+void md5add (const void *input, size_t length) -+{ -+ md5_add(&state, input, length); -+} -+ -+void md5put (uint8_t output[16]) -+{ -+ md5_put(&state, output); -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utilmd5.h b/texk/web2c/luatexdir/luapplib/util/utilmd5.h -new file mode 100644 -index 000000000..2fb4bc58d ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilmd5.h -@@ -0,0 +1,115 @@ -+#ifndef UTIL_MD5_H -+#define UTIL_MD5_H -+ -+#include // for uintX8_t -+#include // for size_t -+#include "utildecl.h" -+ -+/* begin of md5.h */ -+ -+/* -+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. -+ -+ This software is provided 'as-is', without any express or implied -+ warranty. In no event will the authors be held liable for any damages -+ arising from the use of this software. -+ -+ Permission is granted to anyone to use this software for any purpose, -+ including commercial applications, and to alter it and redistribute it -+ freely, subject to the following restrictions: -+ -+ 1. The origin of this software must not be misrepresented; you must not -+ claim that you wrote the original software. If you use this software -+ in a product, an acknowledgment in the product documentation would be -+ appreciated but is not required. -+ 2. Altered source versions must be plainly marked as such, and must not be -+ misrepresented as being the original software. -+ 3. This notice may not be removed or altered from any source distribution. -+ -+ L. Peter Deutsch -+ ghost@aladdin.com -+ -+ */ -+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -+/* -+ Independent implementation of MD5 (RFC 1321). -+ -+ This code implements the MD5 Algorithm defined in RFC 1321, whose -+ text is available at -+ http://www.ietf.org/rfc/rfc1321.txt -+ The code is derived from the text of the RFC, including the test suite -+ (section A.5) but excluding the rest of Appendix A. It does not include -+ any code or documentation that is identified in the RFC as being -+ copyrighted. -+ -+ The original and principal author of md5.h is L. Peter Deutsch -+ . Other authors are noted in the change history -+ that follows (in reverse chronological order): -+ -+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed -+ references to Ghostscript; clarified derivation from RFC 1321; -+ now handles byte order either statically or dynamically. -+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. -+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); -+ added conditionalization for C++ compilation from Martin -+ Purschke . -+ 1999-05-03 lpd Original version. -+ */ -+ -+//#ifndef md5_INCLUDED -+//# define md5_INCLUDED -+ -+/* -+ * This package supports both compile-time and run-time determination of CPU -+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be -+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is -+ * defined as non-zero, the code will be compiled to run only on big-endian -+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to -+ * run on either big- or little-endian CPUs, but will run slightly less -+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. -+ */ -+ -+// PJ: replaced with uint8_t and uint32_t -+//typedef unsigned char md5_byte_t; /* 8-bit byte */ -+//typedef unsigned int md5_word_t; /* 32-bit word */ -+ -+/* Define the state of the MD5 Algorithm. */ -+typedef struct md5_state_s { -+ uint32_t count[2]; /* message length in bits, lsw first */ -+ uint32_t abcd[4]; /* digest buffer */ -+ uint8_t buf[64]; /* accumulate block */ -+} md5_state_t; -+ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+/* Initialize the algorithm. */ -+UTILAPI void pplib_md5_init (md5_state_t *pms); -+ -+/* Append a string to the message. */ -+//void md5_add(md5_state_t *pms, const uint8_t *data, int nbytes); // PJ -+UTILAPI void md5_add (md5_state_t *pms, const void *input, size_t size); -+ -+/* Finish the message and return the digest. */ -+//void md5_finish(md5_state_t *pms, uint8_t digest[16]); // PJ -+UTILAPI void md5_put (md5_state_t *pms, uint8_t digest[16]); -+ -+#ifdef __cplusplus -+} /* end extern "C" */ -+#endif -+ -+//#endif /* md5_INCLUDED */ -+ -+/* end of md5.h */ -+ -+#define md5_state md5_state_t -+ -+UTILAPI void md5init (void); -+UTILAPI void md5add (const void *input, size_t length); -+UTILAPI void md5put (uint8_t output[16]); -+ -+UTILAPI void pplib_md5 (const void *input, size_t length, uint8_t output[16]); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilmem.c b/texk/web2c/luatexdir/luapplib/util/utilmem.c -new file mode 100644 -index 000000000..1fa00a0c1 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilmem.c -@@ -0,0 +1,68 @@ -+ -+#include // for memcpy -+ -+#include "utilmem.h" -+#include "utillog.h" -+ -+#ifndef util_memerr -+# if defined(_WIN64) || defined(__MINGW32__) -+# define util_memerr(size) { loggerf("ooops, not enough memory (%I64u)", ((unsigned long long)(size))); abort(); } -+# else -+# define util_memerr(size) { loggerf("ooops, not enough memory (%llu)", ((unsigned long long)(size))); abort(); } -+# endif -+#endif -+ -+void * util_malloc (size_t size) -+{ -+ void *m; -+ if ((m = malloc(size)) == NULL) -+ util_memerr(size); -+ return m; -+} -+ -+void * util_calloc (size_t num, size_t size) -+{ -+ void *m; -+ if ((m = calloc(num, size)) == NULL) -+ util_memerr(size); -+ return m; -+} -+ -+void * util_realloc (void *m, size_t size) -+{ -+ if ((m = realloc(m, size)) == NULL) -+ util_memerr(size); -+ return m; -+} -+ -+/* common array resizer -+ -+data -- the beginning of array -+unit -- sizeof array element -+size -- current array size -+extra -- requested extra size -+space -- pointer to available space -+allocated -- flag indicating if *data has been allocated (with malloc) -+ -+*/ -+ -+void util_resize (void **data, size_t unit, size_t size, size_t extra, size_t *space, int allocated) -+{ -+ if (*space == 0) -+ *space = 4; // ... better keep *space non-zero to avoid it -+ do { *space <<= 1; } -+ while (size + extra > *space); -+ -+ if (allocated) -+ { -+ *data = util_realloc(*data, *space * unit); -+ } -+ else -+ { -+ void *newdata = util_malloc(*space * unit); -+ if (*data != NULL) -+ memcpy(newdata, *data, size * unit); -+ *data = newdata; -+ } -+} -+ -diff --git a/texk/web2c/luatexdir/luapplib/util/utilmem.h b/texk/web2c/luatexdir/luapplib/util/utilmem.h -new file mode 100644 -index 000000000..e2d128618 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilmem.h -@@ -0,0 +1,59 @@ -+ -+#ifndef UTIL_MEM_H -+#define UTIL_MEM_H -+ -+#include // for size_t and alloc functions -+#include "utildecl.h" -+ -+UTILAPI void * util_malloc (size_t size); -+UTILAPI void * util_calloc (size_t num, size_t size); -+UTILAPI void * util_realloc (void *m, size_t size); -+ -+#define util_free free // not a call -+ -+/* arrays */ -+ -+#define array_header(element_type, integer_type) \ -+ element_type *data; integer_type size; integer_type space -+ -+#define array_of(element_type) array_header(element_type, size_t) -+ -+#define array_data_is_allocated(array) ((array)->data != (void *)((array) + 1)) -+ -+#define array_create(array, array_type, element_type, init) \ -+ (array = (array_type *)util_malloc(sizeof(array_type) + ((init) > 0 ? ((init) * sizeof(element_type)) : 1)), \ -+ array_init(array, element_type, init)) -+ -+#define array_init(array, element_type, init) \ -+ ((array)->data = (element_type *)((array) + 1), (array)->size = 0, (array)->space = init) -+ -+#define array_init_data(array, element_type, init) \ -+ ((array)->data = (element_type *)util_malloc((init) * sizeof(element_type)), (array)->size = 0, (array)->space = init) -+ -+#define array_free_data(array) \ -+ ((void)(array_data_is_allocated(array) && (util_free((array)->data), 0))) -+ -+#define array_free(array) \ -+ ((void)(array_free_data(array), (util_free(array), 0))) -+ -+void util_resize (void **data, size_t unit, size_t size, size_t extra, size_t *space, int allocated); -+ -+#define array_ensure(array, unit, extra) \ -+ ((void)((array)->size + (extra) > (array)->space && \ -+ (util_resize((void **)(&(array)->data), unit, (array)->size, extra, &(array)->space, array_data_is_allocated(array)), 0))) -+ -+#define array_ensure_alloc(array, unit, extra, isalloc) \ -+ ((void)((array)->size + (extra) > (array)->space && \ -+ (util_resize((void **)(&(array)->data), unit, (array)->size, extra, &(array)->space, isalloc), 0))) -+ -+#define array_at(array, index) ((array)->data + index) -+#define array_index(array, index) (index < (array)->size ? array_at(array, index) : NULL) -+#define array_top(array) ((array)->data + (array)->size - 1) -+ -+#define array_from_bottom(array, index) array_at(array, index - 1) -+#define array_from_top(array, negindex) array_at(array, (array)->size + (negindex)) -+ -+#define array_push(array) ((array)->data + ((array)->size)++) -+#define array_pop(array) ((array)->data + --((array)->size)) -+ -+#endif -diff --git a/texk/web2c/luatexdir/luapplib/util/utilnumber.c b/texk/web2c/luatexdir/luapplib/util/utilnumber.c -new file mode 100644 -index 000000000..c87261e15 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilnumber.c -@@ -0,0 +1,1325 @@ -+ -+#include /* for log10() and floor() */ -+#include /* for printf() */ -+ -+#include "utilnumber.h" -+ -+const int base10_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+const int base16_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, -+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+const int base26_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, -+ 16,17,18,19,20,21,22,23,24,25,26,-1,-1,-1,-1,-1, -+ -1, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, -+ 16,17,18,19,20,21,22,23,24,25,26,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+const int base36_lookup[] = { -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, -+ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, -+ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, -+ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, -+ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 -+}; -+ -+/* integer from string; return a pointer to character next to the last digit */ -+ -+#define string_scan_sign(s, c, sign) _scan_sign(c, sign, *++s) -+#define string_scan_integer(s, c, number) _scan_integer(c, number, *++s) -+#define string_scan_radix(s, c, number, radix) _scan_radix(c, number, radix, *++s) -+#define string_read_integer(s, c, number) _read_integer(c, number, *++s) -+#define string_read_radix(s, c, number, radix) _read_radix(c, number, radix, *++s) -+ -+const char * string_to_int32 (const char *s, int32_t *number) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_integer(s, c, *number); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * string_to_intlw (const char *s, intlw_t *number) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_integer(s, c, *number); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * string_to_int64 (const char *s, int64_t *number) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_integer(s, c, *number); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * string_to_uint32 (const char *s, uint32_t *number) -+{ -+ int c = *s; -+ string_scan_integer(s, c, *number); -+ return s; -+} -+ -+const char * string_to_uintlw (const char *s, uintlw_t *number) -+{ -+ int c = *s; -+ string_scan_integer(s, c, *number); -+ return s; -+} -+ -+const char * string_to_uint64 (const char *s, uint64_t *number) -+{ -+ int c = *s; -+ string_scan_integer(s, c, *number); -+ return s; -+} -+ -+const char * radix_to_int32 (const char *s, int32_t *number, int radix) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_radix(s, c, *number, radix); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * radix_to_intlw (const char *s, intlw_t *number, int radix) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_radix(s, c, *number, radix); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * radix_to_int64 (const char *s, int64_t *number, int radix) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_radix(s, c, *number, radix); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * radix_to_uint32 (const char *s, uint32_t *number, int radix) -+{ -+ int c = *s; -+ string_scan_radix(s, c, *number, radix); -+ return s; -+} -+ -+const char * radix_to_uintlw (const char *s, uintlw_t *number, int radix) -+{ -+ int c = *s; -+ string_scan_radix(s, c, *number, radix); -+ return s; -+} -+ -+const char * radix_to_uint64 (const char *s, uint64_t *number, int radix) -+{ -+ int c = *s; -+ string_scan_radix(s, c, *number, radix); -+ return s; -+} -+ -+/* roman to uint16_t */ -+ -+#define roman1000(c) (c == 'M' || c == 'm') -+#define roman500(c) (c == 'D' || c == 'd') -+#define roman100(c) (c == 'C' || c == 'c') -+#define roman50(c) (c == 'L' || c == 'l') -+#define roman10(c) (c == 'X' || c == 'x') -+#define roman5(c) (c == 'V' || c == 'v') -+#define roman1(c) (c == 'I' || c == 'i') -+ -+#define roman100s(p) (roman100(*p) ? (100 + ((++p, roman100(*p)) ? (100 + ((++p, roman100(*p)) ? (++p, 100) : 0)) : 0)) : 0) -+#define roman10s(p) (roman10(*p) ? (10 + ((++p, roman10(*p)) ? (10 + ((++p, roman10(*p)) ? (++p, 10) : 0)) : 0)) : 0) -+#define roman1s(p) (roman1(*p) ? (1 + ((++p, roman1(*p)) ? (1 + ((++p, roman1(*p)) ? (++p, 1) : 0)) : 0)) : 0) -+ -+const char * roman_to_uint16 (const char *s, uint16_t *number) -+{ -+ const char *p; -+ /* M */ -+ for (*number = 0, p = s; roman1000(*p); *number += 1000, ++p); -+ /* D C */ -+ if (roman500(*p)) -+ { -+ ++p; -+ *number += 500 + roman100s(p); -+ } -+ else if (roman100(*p)) -+ { -+ ++p; -+ if (roman1000(*p)) -+ { -+ ++p; -+ *number += 900; -+ } -+ else if (roman500(*p)) -+ { -+ ++p; -+ *number += 400; -+ } -+ else -+ *number += 100 + roman100s(p); -+ } -+ /* L X */ -+ if (roman50(*p)) -+ { -+ ++p; -+ *number += 50 + roman10s(p); -+ } -+ else if (roman10(*p)) -+ { -+ ++p; -+ if (roman100(*p)) -+ { -+ ++p; -+ *number += 90; -+ } -+ else if (roman50(*p)) -+ { -+ ++p; -+ *number += 40; -+ } -+ else -+ *number += 10 + roman10s(p); -+ } -+ /* V I */ -+ if (roman5(*p)) -+ { -+ ++p; -+ *number += 5 + roman1s(p); -+ } -+ else if (roman1(*p)) -+ { -+ ++p; -+ if (roman10(*p)) -+ { -+ ++p; -+ *number += 9; -+ } -+ else if (roman5(*p)) -+ { -+ ++p; -+ *number += 4; -+ } -+ else -+ *number += 1 + roman1s(p); -+ } -+ return p; -+} -+ -+/* integer to string; return a pointer to null-terminated static const string */ -+ -+static char integer_buffer[MAX_INTEGER_DIGITS] = {'\0'}; -+#define end_of_integer_buffer (integer_buffer + MAX_INTEGER_DIGITS - 1) -+ -+/* writing integers */ -+ -+#define number_printrev_signed(p, number, quotient) \ -+ do { \ -+ quotient = number; number /= 10; \ -+ *--p = base10_palindrome[9 + (quotient - number*10)]; \ -+ } while (number); \ -+ if (quotient < 0) *--p = '-' -+ -+#define number_printrev_unsigned(p, number, quotient) \ -+ do { \ -+ quotient = number; number /= 10; \ -+ *--p = (char)(quotient - integer_multiplied10(number)) + '0'; \ -+ } while (number) -+ -+char * int32_as_string (int32_t number, char **e) -+{ -+ char *p; -+ int quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed(p, number, quotient); -+ return p; -+} -+ -+char * intlw_as_string (intlw_t number, char **e) -+{ -+ char *p; -+ intlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed(p, number, quotient); -+ return p; -+} -+ -+char * int64_as_string (int64_t number, char **e) -+{ -+ char *p; -+ int64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed(p, number, quotient); -+ return p; -+} -+ -+char * uint32_as_string (uint32_t number, char **e) -+{ -+ char *p; -+ uint32_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned(p, number, quotient); -+ return p; -+} -+ -+char * uintlw_as_string (uintlw_t number, char **e) -+{ -+ char *p; -+ uintlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned(p, number, quotient); -+ return p; -+} -+ -+char * uint64_as_string (uint64_t number, char **e) -+{ -+ char *p; -+ uint64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned(p, number, quotient); -+ return p; -+} -+ -+/* radix variant */ -+ -+#define number_printrev_signed_radix_uc(p, number, radix, quotient) \ -+ do { \ -+ quotient = number; number /= radix; \ -+ *--p = base36_uc_palindrome[MAX_RADIX - 1 + (quotient - number*radix)]; \ -+ } while (number) -+ -+#define number_printrev_signed_radix_lc(p, number, radix, quotient) \ -+ do { \ -+ quotient = number; number /= radix; \ -+ *--p = base36_lc_palindrome[MAX_RADIX - 1 + (quotient - number*radix)]; \ -+ } while (number) -+ -+#define number_printrev_signed_radix(p, number, radix, quotient) \ -+ do { \ -+ if (radix > 0) { number_printrev_signed_radix_uc(p, number, radix, quotient); } \ -+ else { radix = -radix; number_printrev_signed_radix_lc(p, number, radix, quotient); } \ -+ if (quotient < 0) *--p = '-'; \ -+ } while (0) -+ -+#define number_printrev_unsigned_radix_uc(p, number, radix, quotient) \ -+ do { \ -+ quotient = number; number /= radix; \ -+ *--p = base36_uc_alphabet[quotient % radix]; \ -+ } while (number) -+ -+#define number_printrev_unsigned_radix_lc(p, number, radix, quotient) \ -+ do { \ -+ quotient = number; number /= radix; \ -+ *--p = base36_lc_alphabet[quotient % radix]; \ -+ } while (number) -+ -+#define number_printrev_unsigned_radix(p, number, radix, quotient) \ -+ do { \ -+ if (radix > 0) { number_printrev_unsigned_radix_uc(p, number, radix, quotient); } \ -+ else { radix = -radix; number_printrev_unsigned_radix_lc(p, number, radix, quotient); } \ -+ } while (0) -+ -+char * int32_as_radix (int number, int radix, char **e) -+{ -+ char *p; -+ int quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed_radix(p, number, radix, quotient); -+ return p; -+} -+ -+char * intlw_as_radix (intlw_t number, int radix, char **e) -+{ -+ char *p; -+ intlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed_radix(p, number, radix, quotient); -+ return p; -+} -+ -+char * int64_as_radix (int64_t number, int radix, char **e) -+{ -+ char *p; -+ int64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_signed_radix(p, number, radix, quotient); -+ return p; -+} -+ -+char * uint32_as_radix (uint32_t number, int radix, char **e) -+{ -+ char *p; -+ uint32_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_radix(p, number, radix, quotient); -+ return p; -+} -+ -+char * uintlw_as_radix (uintlw_t number, int radix, char **e) -+{ -+ char *p; -+ uintlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_radix(p, number, radix, quotient); -+ return p; -+} -+ -+char * uint64_as_radix (uint64_t number, int radix, char **e) -+{ -+ char *p; -+ uint64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_radix(p, number, radix, quotient); -+ return p; -+} -+ -+/* aaa, aab, aac, ...; unsigned only. 0 gives empty string */ -+ -+#define string_scan_alpha(s, c, number, radix) \ -+ for (number = 0, c = *s; (c = base26_value(c)) > 0; number = number * radix + c, c = *++s) -+ -+const char * alpha_to_uint32 (const char *s, uint32_t *number) -+{ -+ int c; -+ string_scan_alpha(s, c, *number, 26); -+ return s; -+} -+ -+const char * alpha_to_uintlw (const char *s, uintlw_t *number) -+{ -+ int c; -+ string_scan_alpha(s, c, *number, 26); -+ return s; -+} -+ -+const char * alpha_to_uint64 (const char *s, uint64_t *number) -+{ -+ int c; -+ string_scan_alpha(s, c, *number, 26); -+ return s; -+} -+ -+#define number_printrev_unsigned_alpha_uc(p, number, radix, quotient) \ -+ while (number > 0) { \ -+ quotient = --number; number /= radix; \ -+ *--p = base26_uc_alphabet[quotient % radix]; \ -+ } -+ -+#define number_printrev_unsigned_alpha_lc(p, number, radix, quotient) \ -+ while (number > 0) { \ -+ quotient = --number; number /= radix; \ -+ *--p = base26_lc_alphabet[quotient % radix]; \ -+ } -+ -+char * uint32_as_alpha_uc (uint32_t number, char **e) -+{ -+ char *p; -+ uint32_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_uc(p, number, 26, quotient); -+ return p; -+} -+ -+char * uint32_as_alpha_lc (uint32_t number, char **e) -+{ -+ char *p; -+ uint32_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_lc(p, number, 26, quotient); -+ return p; -+} -+ -+char * uintlw_as_alpha_uc (uintlw_t number, char **e) -+{ -+ char *p; -+ uintlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_uc(p, number, 26, quotient); -+ return p; -+} -+ -+char * uintlw_as_alpha_lc (uintlw_t number, char **e) -+{ -+ char *p; -+ uintlw_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_lc(p, number, 26, quotient); -+ return p; -+} -+ -+char * uint64_as_alpha_uc (uint64_t number, char **e) -+{ -+ char *p; -+ uint64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_uc(p, number, 26, quotient); -+ return p; -+} -+ -+char * uint64_as_alpha_lc (uint64_t number, char **e) -+{ -+ char *p; -+ uint64_t quotient; -+ p = end_of_integer_buffer; *p = '\0'; -+ if (e != NULL) *e = p; -+ number_printrev_unsigned_alpha_lc(p, number, 26, quotient); -+ return p; -+} -+ -+/* a variant of alphabetic, a, b, c, ..., z, aa, bb, cc, ..., zz (eg. pdf page labelling) */ -+ -+#define string_scan_alphan(s, c, number, radix) \ -+ do { \ -+ number = 0; \ -+ if ((c = base26_value(*s)) > 0) { \ -+ number = c; \ -+ while (c == base26_value(*++s)) number += radix; \ -+ } \ -+ } while (0) -+ -+const char * alphan_to_uint32 (const char *s, uint32_t *number) -+{ -+ int c; -+ string_scan_alphan(s, c, *number, 26); -+ return s; -+} -+ -+const char * alphan_to_uintlw (const char *s, uintlw_t *number) -+{ -+ int c; -+ string_scan_alphan(s, c, *number, 26); -+ return s; -+} -+ -+const char * alphan_to_uint64 (const char *s, uintlw_t *number) -+{ -+ int c; -+ string_scan_alphan(s, c, *number, 26); -+ return s; -+} -+ -+#define number_print_alphan_uc(s, c, number, radix) \ -+ if (number > 0) { \ -+ for (c = (--number) % radix, number -= c; ; number -= radix) { \ -+ *s++ = base26_uc_alphabet[c]; \ -+ if (number == 0 || p >= end_of_integer_buffer) break; \ -+ } \ -+ } -+ -+#define number_print_alphan_lc(s, c, number, radix) \ -+ if (number > 0) { \ -+ for (c = (--number) % radix, number -= c; ; number -= radix) { \ -+ *s++ = base26_lc_alphabet[c]; \ -+ if (number == 0 || p >= end_of_integer_buffer) break; \ -+ } \ -+ } -+ -+char * uint32_as_alphan_uc (uint32_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_uc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+char * uint32_as_alphan_lc (uint32_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_lc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+char * uintlw_as_alphan_uc (uintlw_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_uc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+char * uintlw_as_alphan_lc (uintlw_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_lc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+char * uint64_as_alphan_uc (uint64_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_uc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+char * uint64_as_alphan_lc (uint64_t number, char **e) -+{ -+ char *p; -+ uint8_t c; -+ p = integer_buffer; -+ number_print_alphan_lc(p, c, number, 26); -+ *p = '\0'; if (e != NULL) *e = p; -+ return integer_buffer; -+} -+ -+/* roman numeral */ -+ -+/* todo: large roman numerals? http://mathforum.org/library/drmath/view/57569.html */ -+ -+#define base_roman_uc_alphabet "MDCLXVI" -+#define base_roman_lc_alphabet "mdclxvi" -+ -+static const uint32_t base_roman_values[] = { 1000, 500, 100, 50, 10, 5, 1 }; -+ -+#define integer_to_roman(p, number, alphabet) \ -+ { \ -+ uint32_t k, j, v, u; \ -+ for (j = 0, v = base_roman_values[0]; number > 0; ) \ -+ { \ -+ if (number >= v) \ -+ { \ -+ *p++ = alphabet[j]; \ -+ number -= v; \ -+ continue; \ -+ } \ -+ if (j & 1) \ -+ k = j + 1; \ -+ else \ -+ k = j + 2; \ -+ u = base_roman_values[k]; \ -+ if (number + u >= v) \ -+ { \ -+ *p++ = alphabet[k]; \ -+ number += u; \ -+ } \ -+ else \ -+ v = base_roman_values[++j]; \ -+ } \ -+ } -+ -+char * uint16_as_roman_uc (uint16_t number, char **e) -+{ -+ char *p = integer_buffer; -+ integer_to_roman(p, number, base_roman_uc_alphabet); -+ if (e != NULL) -+ *e = p; -+ *p = '\0'; -+ return integer_buffer; -+} -+ -+char * uint16_as_roman_lc (uint16_t number, char **e) -+{ -+ char *p = integer_buffer; -+ integer_to_roman(p, number, base_roman_lc_alphabet); -+ if (e != NULL) -+ *e = p; -+ *p = '\0'; -+ return integer_buffer; -+} -+ -+/* IEEE-754 */ -+ -+#define BINARY_MODF 1 -+ -+#define NOT_A_NUMBER_STRING "NaN" -+#define INFINITY_STRING "INF" -+#define SIGNED_INFINITY 1 -+#define SIGNED_ZERO 0 -+#define SIGNED_NOT_A_NUMBER 0 -+#define RADIX_CHAR '.' -+ -+/* double/float to decimal */ -+ -+typedef struct ieee_double { -+ union { -+ double number; -+ uint64_t bits; -+ }; -+ uint64_t fraction; -+ int exponent, sign; -+} ieee_double; -+ -+typedef struct ieee_float { -+ union { -+ float number; -+ uint32_t bits; -+ }; -+ uint32_t fraction; -+ int exponent, sign; -+} ieee_float; -+ -+#define IEEE_DOUBLE_BIAS 1023 -+#define IEEE_DOUBLE_MIN_EXPONENT -1023 -+#define IEEE_DOUBLE_MAX_EXPONENT (0x7ff - IEEE_DOUBLE_BIAS) -+ -+#define IEEE_FLOAT_BIAS 127 -+#define IEEE_FLOAT_MIN_EXPONENT -127 -+#define IEEE_FLOAT_MAX_EXPONENT (0xff - IEEE_FLOAT_BIAS) -+ -+#define ieee_double_fraction(i) (i & 0x000fffffffffffffull) -+#define ieee_double_exponent(i) ((0x7ff & (i >> 52)) - IEEE_DOUBLE_BIAS) -+#define ieee_double_sign(ieee_number) ((void)((ieee_number.sign = ieee_number.bits >> 63) && (ieee_number.number = -ieee_number.number))) -+#define ieee_double_init(ieee_number, number) \ -+ ieee_number.number = number, \ -+ ieee_number.fraction = ieee_double_fraction(ieee_number.bits), \ -+ ieee_number.exponent = ieee_double_exponent(ieee_number.bits) -+ -+#define ieee_float_fraction(i) (i & 0x007fffff) -+#define ieee_float_exponent(i) ((0xff & (i >> 23)) - IEEE_FLOAT_BIAS) -+#define ieee_float_sign(ieee_number) ((void)((ieee_number.sign = ieee_number.bits >> 31) && (ieee_number.number = -ieee_number.number))) -+#define ieee_float_init(ieee_number, number) \ -+ ieee_number.number = number, \ -+ ieee_number.fraction = ieee_float_fraction(ieee_number.bits), \ -+ ieee_number.exponent = ieee_float_exponent(ieee_number.bits) -+ -+/* special cases */ -+ -+#define ieee_double_is_zero(ieee_number) (ieee_number.number == 0) // || ieee_double_too_small(ieee_number) ? -+#define ieee_double_too_small(ieee_number) (ieee_number.exponent == 0 && ieee_number.fraction != 0) // denormalized, implicit fracion bit not set -+ -+#define ieee_float_is_zero(ieee_number) (ieee_number.number == 0) // || ieee_float_too_small(ieee_number) ? -+#define ieee_float_too_small(ieee_number) (ieee_number.exponent == 0 && ieee_number.fraction != 0) -+ -+#define ieee_double_zero_string(ieee_number) (SIGNED_ZERO && ieee_number.sign ? "-0" : "0") -+#define ieee_double_infinity_string(ieee_number) (SIGNED_INFINITY && ieee_number.sign ? "-" INFINITY_STRING : INFINITY_STRING) -+ -+#define ieee_float_zero_string ieee_double_zero_string -+#define ieee_float_infinity_string ieee_double_infinity_string -+ -+#define ieee_double_special_case(ieee_number) (ieee_number.exponent == IEEE_DOUBLE_MAX_EXPONENT) -+#define ieee_double_special_string(ieee_number) (ieee_number.fraction ? NOT_A_NUMBER_STRING : ieee_double_infinity_string(ieee_number)) -+ -+#define ieee_float_special_case(ieee_number) (ieee_number.exponent == IEEE_FLOAT_MAX_EXPONENT) -+#define ieee_float_special_string(ieee_number) (ieee_number.fraction ? NOT_A_NUMBER_STRING : ieee_float_infinity_string(ieee_number)) -+ -+#if 0 -+ -+const double double_binary_power10[] = -+{ -+ 1.0e1, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 -+}; -+ -+const float float_binary_power10[] = -+{ -+ 1.0e1, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e32 -+}; -+ -+const double double_binary_negpower10[] = -+{ -+ 1.0e-1, 1.0e-2, 1.0e-4, 1.0e-8, 1.0e-16, 1.0e-32 -+}; -+ -+const float float_binary_negpower10[] = -+{ -+ 1.0e-1, 1.0e-2, 1.0e-4, 1.0e-8, 1.0e-16, 1.0e-32 -+}; -+ -+#else -+ -+const double double_decimal_power10[] = { -+ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, -+ 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, -+ 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, -+ 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, -+ 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, -+ 1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, -+ 1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, -+ 1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, -+ 1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, -+ 1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, -+ 1.0e100, 1.0e101, 1.0e102, 1.0e103, 1.0e104, 1.0e105, 1.0e106, 1.0e107, 1.0e108, 1.0e109, -+ 1.0e110, 1.0e111, 1.0e112, 1.0e113, 1.0e114, 1.0e115, 1.0e116, 1.0e117, 1.0e118, 1.0e119, -+ 1.0e120, 1.0e121, 1.0e122, 1.0e123, 1.0e124, 1.0e125, 1.0e126, 1.0e127, 1.0e128, 1.0e129, -+ 1.0e130, 1.0e131, 1.0e132, 1.0e133, 1.0e134, 1.0e135, 1.0e136, 1.0e137, 1.0e138, 1.0e139, -+ 1.0e140, 1.0e141, 1.0e142, 1.0e143, 1.0e144, 1.0e145, 1.0e146, 1.0e147, 1.0e148, 1.0e149, -+ 1.0e150, 1.0e151, 1.0e152, 1.0e153, 1.0e154, 1.0e155, 1.0e156, 1.0e157, 1.0e158, 1.0e159, -+ 1.0e160, 1.0e161, 1.0e162, 1.0e163, 1.0e164, 1.0e165, 1.0e166, 1.0e167, 1.0e168, 1.0e169, -+ 1.0e170, 1.0e171, 1.0e172, 1.0e173, 1.0e174, 1.0e175, 1.0e176, 1.0e177, 1.0e178, 1.0e179, -+ 1.0e180, 1.0e181, 1.0e182, 1.0e183, 1.0e184, 1.0e185, 1.0e186, 1.0e187, 1.0e188, 1.0e189, -+ 1.0e190, 1.0e191, 1.0e192, 1.0e193, 1.0e194, 1.0e195, 1.0e196, 1.0e197, 1.0e198, 1.0e199, -+ 1.0e200, 1.0e201, 1.0e202, 1.0e203, 1.0e204, 1.0e205, 1.0e206, 1.0e207, 1.0e208, 1.0e209, -+ 1.0e210, 1.0e211, 1.0e212, 1.0e213, 1.0e214, 1.0e215, 1.0e216, 1.0e217, 1.0e218, 1.0e219, -+ 1.0e220, 1.0e221, 1.0e222, 1.0e223, 1.0e224, 1.0e225, 1.0e226, 1.0e227, 1.0e228, 1.0e229, -+ 1.0e230, 1.0e231, 1.0e232, 1.0e233, 1.0e234, 1.0e235, 1.0e236, 1.0e237, 1.0e238, 1.0e239, -+ 1.0e240, 1.0e241, 1.0e242, 1.0e243, 1.0e244, 1.0e245, 1.0e246, 1.0e247, 1.0e248, 1.0e249, -+ 1.0e250, 1.0e251, 1.0e252, 1.0e253, 1.0e254, 1.0e255, 1.0e256, 1.0e257, 1.0e258, 1.0e259, -+ 1.0e260, 1.0e261, 1.0e262, 1.0e263, 1.0e264, 1.0e265, 1.0e266, 1.0e267, 1.0e268, 1.0e269, -+ 1.0e270, 1.0e271, 1.0e272, 1.0e273, 1.0e274, 1.0e275, 1.0e276, 1.0e277, 1.0e278, 1.0e279, -+ 1.0e280, 1.0e281, 1.0e282, 1.0e283, 1.0e284, 1.0e285, 1.0e286, 1.0e287, 1.0e288, 1.0e289, -+ 1.0e290, 1.0e291, 1.0e292, 1.0e293, 1.0e294, 1.0e295, 1.0e296, 1.0e297, 1.0e298, 1.0e299, -+ 1.0e300, 1.0e301, 1.0e302, 1.0e303, 1.0e304, 1.0e305, 1.0e306, 1.0e307, 1.0e308 -+}; -+ -+const float float_decimal_power10[] = { -+ 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, -+ 1.0e10f, 1.0e11f, 1.0e12f, 1.0e13f, 1.0e14f, 1.0e15f, 1.0e16f, 1.0e17f, 1.0e18f, 1.0e19f, -+ 1.0e20f, 1.0e21f, 1.0e22f, 1.0e23f, 1.0e24f, 1.0e25f, 1.0e26f, 1.0e27f, 1.0e28f, 1.0e29f, -+ 1.0e30f, 1.0e31f, 1.0e32f, 1.0e33f, 1.0e34f, 1.0e35f, 1.0e36f, 1.0e37f, 1.0e38f -+}; -+ -+const double double_decimal_negpower10[] = { -+ 1.0e0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9, -+ 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16, 1.0e-17, 1.0e-18, 1.0e-19, -+ 1.0e-20, 1.0e-21, 1.0e-22, 1.0e-23, 1.0e-24, 1.0e-25, 1.0e-26, 1.0e-27, 1.0e-28, 1.0e-29, -+ 1.0e-30, 1.0e-31, 1.0e-32, 1.0e-33, 1.0e-34, 1.0e-35, 1.0e-36, 1.0e-37, 1.0e-38, 1.0e-39, -+ 1.0e-40, 1.0e-41, 1.0e-42, 1.0e-43, 1.0e-44, 1.0e-45, 1.0e-46, 1.0e-47, 1.0e-48, 1.0e-49, -+ 1.0e-50, 1.0e-51, 1.0e-52, 1.0e-53, 1.0e-54, 1.0e-55, 1.0e-56, 1.0e-57, 1.0e-58, 1.0e-59, -+ 1.0e-60, 1.0e-61, 1.0e-62, 1.0e-63, 1.0e-64, 1.0e-65, 1.0e-66, 1.0e-67, 1.0e-68, 1.0e-69, -+ 1.0e-70, 1.0e-71, 1.0e-72, 1.0e-73, 1.0e-74, 1.0e-75, 1.0e-76, 1.0e-77, 1.0e-78, 1.0e-79, -+ 1.0e-80, 1.0e-81, 1.0e-82, 1.0e-83, 1.0e-84, 1.0e-85, 1.0e-86, 1.0e-87, 1.0e-88, 1.0e-89, -+ 1.0e-90, 1.0e-91, 1.0e-92, 1.0e-93, 1.0e-94, 1.0e-95, 1.0e-96, 1.0e-97, 1.0e-98, 1.0e-99, -+ 1.0e-100, 1.0e-101, 1.0e-102, 1.0e-103, 1.0e-104, 1.0e-105, 1.0e-106, 1.0e-107, 1.0e-108, 1.0e-109, -+ 1.0e-110, 1.0e-111, 1.0e-112, 1.0e-113, 1.0e-114, 1.0e-115, 1.0e-116, 1.0e-117, 1.0e-118, 1.0e-119, -+ 1.0e-120, 1.0e-121, 1.0e-122, 1.0e-123, 1.0e-124, 1.0e-125, 1.0e-126, 1.0e-127, 1.0e-128, 1.0e-129, -+ 1.0e-130, 1.0e-131, 1.0e-132, 1.0e-133, 1.0e-134, 1.0e-135, 1.0e-136, 1.0e-137, 1.0e-138, 1.0e-139, -+ 1.0e-140, 1.0e-141, 1.0e-142, 1.0e-143, 1.0e-144, 1.0e-145, 1.0e-146, 1.0e-147, 1.0e-148, 1.0e-149, -+ 1.0e-150, 1.0e-151, 1.0e-152, 1.0e-153, 1.0e-154, 1.0e-155, 1.0e-156, 1.0e-157, 1.0e-158, 1.0e-159, -+ 1.0e-160, 1.0e-161, 1.0e-162, 1.0e-163, 1.0e-164, 1.0e-165, 1.0e-166, 1.0e-167, 1.0e-168, 1.0e-169, -+ 1.0e-170, 1.0e-171, 1.0e-172, 1.0e-173, 1.0e-174, 1.0e-175, 1.0e-176, 1.0e-177, 1.0e-178, 1.0e-179, -+ 1.0e-180, 1.0e-181, 1.0e-182, 1.0e-183, 1.0e-184, 1.0e-185, 1.0e-186, 1.0e-187, 1.0e-188, 1.0e-189, -+ 1.0e-190, 1.0e-191, 1.0e-192, 1.0e-193, 1.0e-194, 1.0e-195, 1.0e-196, 1.0e-197, 1.0e-198, 1.0e-199, -+ 1.0e-200, 1.0e-201, 1.0e-202, 1.0e-203, 1.0e-204, 1.0e-205, 1.0e-206, 1.0e-207, 1.0e-208, 1.0e-209, -+ 1.0e-210, 1.0e-211, 1.0e-212, 1.0e-213, 1.0e-214, 1.0e-215, 1.0e-216, 1.0e-217, 1.0e-218, 1.0e-219, -+ 1.0e-220, 1.0e-221, 1.0e-222, 1.0e-223, 1.0e-224, 1.0e-225, 1.0e-226, 1.0e-227, 1.0e-228, 1.0e-229, -+ 1.0e-230, 1.0e-231, 1.0e-232, 1.0e-233, 1.0e-234, 1.0e-235, 1.0e-236, 1.0e-237, 1.0e-238, 1.0e-239, -+ 1.0e-240, 1.0e-241, 1.0e-242, 1.0e-243, 1.0e-244, 1.0e-245, 1.0e-246, 1.0e-247, 1.0e-248, 1.0e-249, -+ 1.0e-250, 1.0e-251, 1.0e-252, 1.0e-253, 1.0e-254, 1.0e-255, 1.0e-256, 1.0e-257, 1.0e-258, 1.0e-259, -+ 1.0e-260, 1.0e-261, 1.0e-262, 1.0e-263, 1.0e-264, 1.0e-265, 1.0e-266, 1.0e-267, 1.0e-268, 1.0e-269, -+ 1.0e-270, 1.0e-271, 1.0e-272, 1.0e-273, 1.0e-274, 1.0e-275, 1.0e-276, 1.0e-277, 1.0e-278, 1.0e-279, -+ 1.0e-280, 1.0e-281, 1.0e-282, 1.0e-283, 1.0e-284, 1.0e-285, 1.0e-286, 1.0e-287, 1.0e-288, 1.0e-289, -+ 1.0e-290, 1.0e-291, 1.0e-292, 1.0e-293, 1.0e-294, 1.0e-295, 1.0e-296, 1.0e-297, 1.0e-298, 1.0e-299, -+ 1.0e-300, 1.0e-301, 1.0e-302, 1.0e-303, 1.0e-304, 1.0e-305, 1.0e-306, 1.0e-307, 1.0e-308 -+}; -+ -+const float float_decimal_negpower10[] = { -+ 1.0e0f, 1.0e-1f, 1.0e-2f, 1.0e-3f, 1.0e-4f, 1.0e-5f, 1.0e-6f, 1.0e-7f, 1.0e-8f, 1.0e-9f, -+ 1.0e-10f, 1.0e-11f, 1.0e-12f, 1.0e-13f, 1.0e-14f, 1.0e-15f, 1.0e-16f, 1.0e-17f, 1.0e-18f, 1.0e-19f, -+ 1.0e-20f, 1.0e-21f, 1.0e-22f, 1.0e-23f, 1.0e-24f, 1.0e-25f, 1.0e-26f, 1.0e-27f, 1.0e-28f, 1.0e-29f, -+ 1.0e-30f, 1.0e-31f, 1.0e-32f, 1.0e-33f, 1.0e-34f, 1.0e-35f, 1.0e-36f, 1.0e-37f, 1.0e-38f -+}; -+ -+#endif -+ -+/* scale number by floor(log10(number)) + 1 so that the result is in range [0.1, 1) */ -+ -+#define ieee_double_exponent10(ieee_number) ((int)floor(log10(ieee_number.number)) + 1) -+#define ieee_float_exponent10(ieee_number) ((int)floorf(log10f(ieee_number.number)) + 1) // floorf, log10f ? -+ -+#define ieee_double_exp10(ieee_number, exponent10) \ -+ exponent10 = ieee_double_exponent10(ieee_number); \ -+ if (exponent10 > 0) { \ -+ double_negative_exp10(ieee_number.number, -exponent10); \ -+ ieee_number.fraction = ieee_double_fraction(ieee_number.bits); \ -+ ieee_number.exponent = ieee_double_exponent(ieee_number.bits); \ -+ } else if (exponent10 < 0) { \ -+ double_positive_exp10(ieee_number.number, -exponent10); \ -+ ieee_number.fraction = ieee_double_fraction(ieee_number.bits); \ -+ ieee_number.exponent = ieee_double_exponent(ieee_number.bits); \ -+ } -+ -+#define ieee_float_exp10(ieee_number, exponent10) \ -+ exponent10 = ieee_float_exponent10(ieee_number); \ -+ if (exponent10 > 0) { \ -+ float_negative_exp10(ieee_number.number, -exponent10); \ -+ ieee_number.fraction = ieee_float_fraction(ieee_number.bits); \ -+ ieee_number.exponent = ieee_float_exponent(ieee_number.bits); \ -+ } else if (exponent10 < 0) { \ -+ float_positive_exp10(ieee_number.number, -exponent10); \ -+ ieee_number.fraction = ieee_float_fraction(ieee_number.bits); \ -+ ieee_number.exponent = ieee_float_exponent(ieee_number.bits); \ -+ } -+ -+#if BINARY_MODF -+ -+/* unhide implicit bit 53, produce 56-bit denormalised fraction (binary exponent already in range [-4, -1]) */ -+ -+#define ieee_double_denormalize(ieee_number) \ -+ (ieee_number.exponent == IEEE_DOUBLE_MIN_EXPONENT ? (++ieee_number.exponent, 0) : (ieee_number.fraction |= (1ull<<52))), \ -+ ieee_number.fraction <<= (ieee_number.exponent + 4) -+ -+/* unhide implicit bit 24, produce 27-bit denormalized fraction (binary exponent already in range [-4, -1]) */ -+ -+#define ieee_float_denormalize(ieee_number) \ -+ (ieee_number.exponent == IEEE_FLOAT_MIN_EXPONENT ? (++ieee_number.exponent, 0) : (ieee_number.fraction |= (1<<23))), \ -+ ieee_number.fraction <<= (ieee_number.exponent + 4) -+ -+/* turn off significant bits over 56 (integer part), multiply by 10, return new integer part (subsequent decimal digit) */ -+ -+#define ieee_double_binary_fraction(ieee_number) \ -+ (ieee_number.fraction &= ((1ull<<56) - 1), \ -+ ieee_number.fraction = (ieee_number.fraction << 1) + (ieee_number.fraction << 3), \ -+ ieee_number.fraction >> 56) -+ -+/* turn off significant bits over 27 (integer part), multiply by 10, return the integer part (subsequent decimal digit) */ -+ -+#define ieee_float_binary_fraction(ieee_number) \ -+ (ieee_number.fraction &= ((1<<27) - 1), \ -+ ieee_number.fraction = (ieee_number.fraction << 1) + (ieee_number.fraction << 3), \ -+ ieee_number.fraction >> 27) -+ -+#define ieee_double_decimal(ieee_number, exponent10, digits, p) \ -+ ieee_number_decimal(ieee_double_binary_fraction, ieee_number, exponent10, digits, p) -+#define ieee_float_decimal(ieee_number, exponent10, digits, p) \ -+ ieee_number_decimal(ieee_float_binary_fraction, ieee_number, exponent10, digits, p) -+#define ieee_double_decimal_dot(ieee_number, exponent10, digits, p, dot) \ -+ ieee_number_decimal_dot(ieee_double_binary_fraction, ieee_number, exponent10, digits, p, dot) -+#define ieee_float_decimal_dot(ieee_number, exponent10, digits, p, dot) \ -+ ieee_number_decimal_dot(ieee_float_binary_fraction, ieee_number, exponent10, digits, p, dot) -+ -+#else -+ -+/* generic method */ -+ -+#define ieee_double_decimal_fraction(ieee_number, i) (ieee_number.number = modf(10*ieee_number.number, &i), i) -+#define ieee_float_decimal_fraction(ieee_number, i) (ieee_number.number = (float)modf(10*ieee_number.number, &i), i) // ??? -+ -+#define ieee_double_decimal(ieee_number, exponent10, digits, p) \ -+ ieee_number_decimal(ieee_double_decimal_fraction, ieee_number, exponent10, digits, p) -+#define ieee_float_decimal(ieee_number, exponent10, digits, p) \ -+ ieee_number_decimal(ieee_float_decimal_fraction, ieee_number, exponent10, digits, p) -+#define ieee_double_decimal_dot(ieee_number, exponent10, digits, p, dot) \ -+ ieee_number_decimal_dot(ieee_double_decimal_fraction, ieee_number, exponent10, digits, p, dot) -+#define ieee_float_decimal_dot(ieee_number, exponent10, digits, p, dot) \ -+ ieee_number_decimal_dot(ieee_float_decimal_fraction, ieee_number, exponent10, digits, p, dot) -+ -+#endif -+ -+#define ieee_number_decimal(method, ieee_number, exponent10, digits, p) \ -+ ieee_double_denormalize(ieee_number); \ -+ if (ieee_number.sign) *p++ = '-'; \ -+ if (exponent10 <= 0) \ -+ for (*p++ = '0', *p++ = RADIX_CHAR; exponent10 && digits; *p++ = '0', ++exponent10, --digits); \ -+ else \ -+ { \ -+ do { *p++ = '0' + (char)method(ieee_number); } while (--exponent10); \ -+ *p++ = RADIX_CHAR; \ -+ } \ -+ for ( ; digits && ieee_number.fraction; --digits) \ -+ *p++ = '0' + (char)method(ieee_number) -+ -+#define ieee_number_decimal_dot(method, ieee_number, exponent10, digits, p, dot) \ -+ ieee_double_denormalize(ieee_number); \ -+ if (ieee_number.sign) *p++ = '-'; \ -+ if (exponent10 <= 0) \ -+ { \ -+ *p++ = '0'; \ -+ if (dot != NULL) *dot = p; \ -+ for (*p++ = RADIX_CHAR; exponent10 && digits; *p++ = '0', ++exponent10, --digits); \ -+ } \ -+ else \ -+ { \ -+ do { *p++ = '0' + (char)method(ieee_number); } while (--exponent10); \ -+ if (dot != NULL) *dot = p; \ -+ *p++ = RADIX_CHAR; \ -+ } \ -+ for ( ; digits && ieee_number.fraction; --digits) \ -+ *p++ = '0' + (char)method(ieee_number) -+ -+/* rounding to nearest integer */ -+ -+#if BINARY_MODF -+/* check if the mantissa has the most significant bit set, means >= 0.5 */ -+# define ieee_double_half(ieee_number) (ieee_number.fraction & (1ull<<55)) -+# define ieee_float_half(ieee_number) (ieee_number.fraction & (1<<26)) -+#else -+# define ieee_double_half(ieee_number) (ieee_number.number >= 0.5) -+# define ieee_float_half(ieee_number) (ieee_number.number >= 0.5) -+#endif -+ -+/* rounding to nearest integer */ -+ -+#define buffer_ceil(s, p, sign) \ -+ { \ -+ while (*--p == '9'); \ -+ if (*p != RADIX_CHAR) ++*p++; \ -+ else { \ -+ char *q; \ -+ for (q = p - 1; ; --q) { \ -+ if (*q < '9') { ++*q; break; } \ -+ *q = '0'; \ -+ if (q == s) \ -+ *--s = '1'; \ -+ else if (sign && q - 1 == s) \ -+ *s = '1', *--s = '-'; \ -+ } \ -+ } \ -+ } -+ -+#define buffer_remove_trailing_zeros(s, p, sign) \ -+ { \ -+ while (*--p == '0'); \ -+ if (*p != RADIX_CHAR) \ -+ ++p; \ -+ else if (!SIGNED_ZERO && sign && p - 2 == s && *(p - 1) == '0') \ -+ p -= 2, *p++ = '0'; \ -+ } -+ -+// if digits parameter was initially less then exponent10, then exponent10 > 0 and ieee_double_half(ieee_number) is irrelevant -+#define ieee_double_round(ieee_number, exponent10, s, p) \ -+ if (exponent10 == 0 && ieee_double_half(ieee_number)) \ -+ { buffer_ceil(s, p, ieee_number.sign); } \ -+ else \ -+ { buffer_remove_trailing_zeros(s, p, ieee_number.sign); } -+ -+#define ieee_float_round(ieee_number, exponent10, s, p) \ -+ if (exponent10 == 0 && ieee_float_half(ieee_number)) \ -+ { buffer_ceil(s, p, ieee_number.sign); } \ -+ else \ -+ { buffer_remove_trailing_zeros(s, p, ieee_number.sign); } -+ -+/* double to decimal */ -+ -+static char number_buffer[512]; -+ -+#define ieee_copy_special_string(special, p, _p) \ -+ for (p = (char *)number_buffer, _p = special; ; ++p, ++_p) { \ -+ if ((*p = *_p) == '\0') break; \ -+ } -+ -+#define ieee_copy_special_string_re(special, p, _p, r, e) \ -+ for (p = (char *)number_buffer, _p = special; ; ++p, ++_p) { \ -+ if ((*p = *_p) == '\0') { \ -+ if (r != NULL) *r = NULL; \ -+ if (e != NULL) *e = p; \ -+ break; \ -+ } \ -+ } -+ -+char * double_to_string (double number, int digits) -+{ -+ ieee_double ieee_number; -+ int exponent10; -+ char *s, *p; const char *_p; -+ ieee_double_init(ieee_number, number); -+ ieee_double_sign(ieee_number); -+ if (ieee_double_is_zero(ieee_number)) // to avoid crash on log10(number) -+ { -+ ieee_copy_special_string(ieee_double_zero_string(ieee_number), p, _p); -+ return (char *)number_buffer; -+ } -+ if (ieee_double_special_case(ieee_number)) -+ { -+ ieee_copy_special_string(ieee_double_special_string(ieee_number), p, _p); -+ return (char *)number_buffer; -+ } -+ s = p = number_buffer + 1; -+ ieee_double_exp10(ieee_number, exponent10); -+ ieee_double_decimal(ieee_number, exponent10, digits, p); -+ ieee_double_round(ieee_number, exponent10, s, p); -+ *p = '\0'; -+ return s; -+} -+ -+char * double_as_string (double number, int digits, char **r, char **e) -+{ -+ ieee_double ieee_number; -+ int exponent10; -+ char *s, *p; const char *_p; -+ s = p = number_buffer + 1; -+ ieee_double_init(ieee_number, number); -+ ieee_double_sign(ieee_number); -+ if (ieee_double_is_zero(ieee_number)) // to avoid crash on log10(number) -+ { -+ ieee_copy_special_string_re(ieee_double_zero_string(ieee_number), p, _p, r, e); -+ return (char *)number_buffer; -+ } -+ if (ieee_double_special_case(ieee_number)) -+ { -+ ieee_copy_special_string_re(ieee_double_special_string(ieee_number), p, _p, r, e); -+ return (char *)number_buffer; -+ } -+ ieee_double_exp10(ieee_number, exponent10); -+ ieee_double_decimal_dot(ieee_number, exponent10, digits, p, r); -+ ieee_double_round(ieee_number, exponent10, s, p); -+ if (e != NULL) *e = p; -+ *p = '\0'; -+ return s; -+} -+ -+/* float to decimal */ -+ -+char * float_to_string (float number, int digits) -+{ -+ ieee_float ieee_number; -+ int exponent10; -+ char *s, *p; const char *_p; -+ ieee_float_init(ieee_number, number); -+ ieee_float_sign(ieee_number); -+ if (ieee_float_is_zero(ieee_number)) -+ { -+ ieee_copy_special_string(ieee_float_zero_string(ieee_number), p, _p); -+ return (char *)number_buffer; -+ } -+ if (ieee_float_special_case(ieee_number)) -+ { -+ ieee_copy_special_string(ieee_float_special_string(ieee_number), p, _p); -+ return (char *)number_buffer; -+ } -+ s = p = number_buffer + 1; -+ ieee_float_exp10(ieee_number, exponent10); -+ ieee_float_decimal(ieee_number, exponent10, digits, p); -+ ieee_float_round(ieee_number, exponent10, s, p); -+ *p = '\0'; -+ return s; -+} -+ -+char * float_as_string (float number, int digits, char **r, char **e) -+{ -+ ieee_float ieee_number; -+ int exponent10; -+ char *s, *p; const char *_p; -+ s = p = number_buffer + 1; -+ ieee_float_init(ieee_number, number); -+ ieee_float_sign(ieee_number); -+ if (ieee_float_is_zero(ieee_number)) -+ { -+ ieee_copy_special_string_re(ieee_float_zero_string(ieee_number), p, _p, r, e); -+ return (char *)number_buffer; -+ } -+ if (ieee_float_special_case(ieee_number)) -+ { -+ ieee_copy_special_string_re(ieee_float_special_string(ieee_number), p, _p, r, e); -+ return (char *)number_buffer; -+ } -+ ieee_float_exp10(ieee_number, exponent10); -+ ieee_float_decimal_dot(ieee_number, exponent10, digits, p, r); -+ ieee_float_round(ieee_number, exponent10, s, p); -+ if (e != NULL) *e = p; -+ *p = '\0'; -+ return s; -+} -+ -+/* decimal string to double/float */ -+ -+#define string_scan_decimal(s, c, number) _scan_decimal(c, number, *++s) -+#define string_scan_fraction(s, c, number, exponent10) _scan_fraction(c, number, exponent10, *++s) -+#define string_scan_exponent10(s, c, exponent10) _scan_exponent10(c, exponent10, *++s) -+ -+const char * string_to_double (const char *s, double *number) -+{ -+ int sign, exponent10, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_decimal(s, c, *number); -+ if (c == '.') -+ { -+ c = *++s; -+ string_scan_fraction(s, c, *number, exponent10); -+ } -+ else -+ exponent10 = 0; -+ if (c == 'e' || c == 'E') -+ { -+ c = *++s; -+ string_scan_exponent10(s, c, exponent10); -+ } -+ double_exp10(*number, exponent10); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * string_to_float (const char *s, float *number) -+{ -+ int sign, exponent10, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_decimal(s, c, *number); -+ if (c == '.') -+ { -+ c = *++s; -+ string_scan_fraction(s, c, *number, exponent10); -+ } -+ else -+ exponent10 = 0; -+ if (c == 'e' || c == 'E') -+ { -+ c = *++s; -+ string_scan_exponent10(s, c, exponent10); -+ } -+ float_exp10(*number, exponent10); -+ if (sign) *number = -*number; -+ return s; -+} -+ -+/* conventional form */ -+ -+const char * convert_to_double (const char *s, double *number) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_decimal(s, c, *number); -+ if (c == '.' || c == ',') -+ { -+ int exponent10; -+ c = *++s; -+ string_scan_fraction(s, c, *number, exponent10); -+ if (exponent10 < 0) -+ double_negative_exp10(*number, exponent10); -+ } -+ if (sign) *number = -*number; -+ return s; -+} -+ -+const char * convert_to_float (const char *s, float *number) -+{ -+ int sign, c = *s; -+ string_scan_sign(s, c, sign); -+ string_scan_decimal(s, c, *number); -+ if (c == '.' || c == ',') -+ { -+ int exponent10; -+ c = *++s; -+ string_scan_fraction(s, c, *number, exponent10); -+ if (exponent10 < 0) -+ float_negative_exp10(*number, exponent10); -+ } -+ if (sign) *number = -*number; -+ return s; -+} -+ -+/* pretty common stuff */ -+ -+size_t bytes_to_hex_lc (const void *input, size_t size, unsigned char *output) -+{ -+ size_t i; -+ const unsigned char *p; -+ for (i = 0, p = (const unsigned char *)input; i < size; ++i, ++p) -+ { -+ *output++ = base16_lc_digit1(*p); -+ *output++ = base16_lc_digit2(*p); -+ } -+ *output = '\0'; -+ return 2*size + 1; -+} -+ -+size_t bytes_to_hex_uc (const void *input, size_t size, unsigned char *output) -+{ -+ size_t i; -+ const unsigned char *p; -+ for (i = 0, p = (const unsigned char *)input; i < size; ++i, ++p) -+ { -+ *output++ = base16_uc_digit1(*p); -+ *output++ = base16_uc_digit2(*p); -+ } -+ *output = '\0'; -+ return 2*size + 1; -+} -+ -+size_t hex_to_bytes (const void *input, size_t size, unsigned char *output) -+{ -+ size_t i; -+ int c1, c2; -+ const unsigned char *p; -+ for (i = 1, p = (const unsigned char *)input; i < size; i += 2) -+ { -+ c1 = base16_value(*p); -+ ++p; -+ c2 = base16_value(*p); -+ ++p; -+ if (c1 >= 0 && c2 >= 0) -+ *output++ = (unsigned char)((c1<<4)|c2); -+ else -+ break; -+ } -+ return i >> 1; -+} -+ -+void print_as_hex (const void *input, size_t bytes) -+{ -+ const unsigned char *p; -+ for (p = (const unsigned char *)input; bytes > 0; --bytes, ++p) -+ printf("%02x", *p); -+} -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilnumber.h b/texk/web2c/luatexdir/luapplib/util/utilnumber.h -new file mode 100644 -index 000000000..3c96571b5 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilnumber.h -@@ -0,0 +1,354 @@ -+#ifndef UTIL_NUMBER_H -+#define UTIL_NUMBER_H -+ -+#include // for size_t -+ -+#include "utilplat.h" -+#include "utildecl.h" -+ -+/* since 'long' isn't long for msvc64/mingw64, we need a type for machine word */ -+ -+#if !defined(__cplusplus) || !defined(_MSC_VER) -+# include // int*_t types are in standard in msvc++ -+#endif -+ -+//#if defined(MSVC64) || defined(__MINGW64__) || defined(__x86_64__) || UINTPTR_MAX > 0xffffffff -+//# define BIT64 -+//#else -+//# define BIT64 -+//#endif -+ -+#if defined(_WIN64) || defined(__MINGW32__) -+# define INT64F "%I64d" -+# define UINT64F "%I64u" -+#else -+# define INT64F "%lld" -+# define UINT64F "%llu" -+#endif -+ -+#if defined(MSVC64) -+# define intlw_t int64_t -+# define uintlw_t uint64_t -+# define INTLW(N) N##I64 -+# define UINTLW(N) N##UI64 -+# define INTLWF INT64F -+# define UINTLWF UINT64F -+#elif defined(__MINGW64__) -+# define intlw_t int64_t -+# define uintlw_t uint64_t -+# define INTLW(N) N##LL -+# define UINTLW(N) N##ULL -+# define INTLWF INT64F -+# define UINTLWF UINT64F -+#else // 32bit or sane 64bit (LP64) -+# define intlw_t long -+# define uintlw_t size_t /*unsigned long*/ -+# define INTLW(N) N##L -+# define UINTLW(N) N##UL -+# define INTLWF "%ld" -+# define UINTLWF "%lu" -+#endif -+ -+/* basic constants */ -+ -+#define MAX_RADIX 36 -+// #define MAX_INTEGER_DIGITS 65 /* 64-bit number in binary form plus '\0' */ -+#define MAX_INTEGER_DIGITS 128 // to handle romannumeral of short int -+ -+#define base36_uc_alphabet "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+#define base36_lc_alphabet "0123456789abcdefghijklmnopqrstuvwxyz" -+ -+#define base26_uc_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+#define base26_lc_alphabet "abcdefghijklmnopqrstuvwxyz" -+extern const int base26_lookup[]; -+ -+#define base36_lc_palindrome "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" -+#define base36_uc_palindrome "ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ -+extern const int base36_lookup[]; -+ -+#define base10_palindrome "9876543210123456789" -+#define base10_alphabet "0123456789" -+extern const int base10_lookup[]; -+ -+#define base16_uc_alphabet "0123456789ABCDEF" -+#define base16_lc_alphabet "0123456789abcdef" -+extern const int base16_lookup[]; -+ -+#define base16_uc_digit1(c) base16_uc_alphabet[(c)>>4] -+#define base16_uc_digit2(c) base16_uc_alphabet[(c)&15] -+#define base16_lc_digit1(c) base16_lc_alphabet[(c)>>4] -+#define base16_lc_digit2(c) base16_lc_alphabet[(c)&15] -+ -+#define base8_digit(c) ((unsigned)(c - '0') <= (unsigned)('7' - '0')) -+#define base8_value(c) (base8_digit(c) ? (c) - '0' : -1) -+ -+#define base10_digit(c) ((unsigned)(c - '0') <= (unsigned)('9' - '0')) -+#define base10_value(c) (base10_lookup[(uint8_t)c]) -+ -+#define base16_digit(c) (base16_lookup[(uint8_t)c] >= 0) -+#define base16_value(c) (base16_lookup[(uint8_t)c]) -+ -+#define base26_digit(c) (base26_lookup[(uint8_t)c] >= 0) -+#define base26_value(c) (base26_lookup[(uint8_t)c]) -+ -+#define base36_digit(c) (base36_lookup[(uint8_t)c] >= 0) -+#define base36_value(c) (base36_lookup[(uint8_t)c]) -+ -+//#define base_digit(c, radix) ((unsigned)(base36_lookup[c]) < (unsigned)(radix)) -+//#define base_value(c, radix) (base_digit(c, radix) ? base36_lookup[c] : -1) -+ -+/* integer from string; return a pointer to character next to the last digit */ -+ -+UTILAPI const char * string_to_int32 (const char *s, int32_t *number); -+UTILAPI const char * string_to_intlw (const char *s, intlw_t *number); -+UTILAPI const char * string_to_int64 (const char *s, int64_t *number); -+ -+UTILAPI const char * string_to_uint32 (const char *s, uint32_t *number); -+UTILAPI const char * string_to_uintlw (const char *s, uintlw_t *number); -+UTILAPI const char * string_to_uint64 (const char *s, uint64_t *number); -+ -+UTILAPI const char * radix_to_int32 (const char *s, int32_t *number, int radix); -+UTILAPI const char * radix_to_intlw (const char *s, intlw_t *number, int radix); -+UTILAPI const char * radix_to_int64 (const char *s, int64_t *number, int radix); -+ -+UTILAPI const char * radix_to_uint32 (const char *s, uint32_t *number, int radix); -+UTILAPI const char * radix_to_uintlw (const char *s, uintlw_t *number, int radix); -+UTILAPI const char * radix_to_uint64 (const char *s, uint64_t *number, int radix); -+ -+UTILAPI const char * roman_to_uint16 (const char *s, uint16_t *number); -+ -+UTILAPI const char * alpha_to_uint32 (const char *s, uint32_t *number); -+UTILAPI const char * alpha_to_uintlw (const char *s, uintlw_t *number); -+UTILAPI const char * alpha_to_uint64 (const char *s, uint64_t *number); -+ -+UTILAPI const char * alphan_to_uint32 (const char *s, uint32_t *number); -+UTILAPI const char * alphan_to_uintlw (const char *s, uintlw_t *number); -+UTILAPI const char * alphan_to_uint64 (const char *s, uintlw_t *number); -+ -+/* -+integer to string; return a pointer to null-terminated static const string -+same but also stores pointer to trailing null (to be used for firther formatting) -+*/ -+ -+UTILAPI char * int32_as_string (int32_t number, char **e); -+UTILAPI char * intlw_as_string (intlw_t number, char **e); -+UTILAPI char * int64_as_string (int64_t number, char **e); -+ -+UTILAPI char * uint32_as_string (uint32_t number, char **e); -+UTILAPI char * uintlw_as_string (uintlw_t number, char **e); -+UTILAPI char * uint64_as_string (uint64_t number, char **e); -+ -+#define int32_to_string(number) int32_as_string(number, NULL) -+#define intlw_to_string(number) intlw_as_string(number, NULL) -+#define int64_to_string(number) int64_as_string(number, NULL) -+ -+#define uint32_to_string(number) uint32_as_string(number, NULL) -+#define uintlw_to_string(number) uintlw_as_string(number, NULL) -+#define uint64_to_string(number) uint64_as_string(number, NULL) -+ -+UTILAPI char * int32_as_radix (int32_t number, int radix, char **e); -+UTILAPI char * intlw_as_radix (intlw_t number, int radix, char **e); -+UTILAPI char * int64_as_radix (int64_t number, int radix, char **e); -+ -+UTILAPI char * uint32_as_radix (uint32_t number, int radix, char **e); -+UTILAPI char * uintlw_as_radix (uintlw_t number, int radix, char **e); -+UTILAPI char * uint64_as_radix (uint64_t number, int radix, char **e); -+ -+#define int32_to_radix(number, radix) int32_as_radix(number, radix, NULL) -+#define intlw_to_radix(number, radix) intlw_as_radix(number, radix, NULL) -+#define int64_to_radix(number, radix) int64_as_radix(number, radix, NULL) -+ -+#define uint32_to_radix(number, radix) uint32_as_radix(number, radix, NULL) -+#define uintlw_to_radix(number, radix) uintlw_as_radix(number, radix, NULL) -+#define uint64_to_radix(number, radix) uint64_as_radix(number, radix, NULL) -+ -+UTILAPI char * uint32_as_alpha_uc (uint32_t number, char **e); -+UTILAPI char * uint32_as_alpha_lc (uint32_t number, char **e); -+UTILAPI char * uintlw_as_alpha_uc (uintlw_t number, char **e); -+UTILAPI char * uintlw_as_alpha_lc (uintlw_t number, char **e); -+UTILAPI char * uint64_as_alpha_uc (uint64_t number, char **e); -+UTILAPI char * uint64_as_alpha_lc (uint64_t number, char **e); -+ -+#define uint32_to_alpha_uc(number) uint32_as_alpha_uc(number, NULL) -+#define uint32_to_alpha_lc(number) uint32_as_alpha_lc(number, NULL) -+#define uintlw_to_alpha_uc(number) uintlw_as_alpha_uc(number, NULL) -+#define uintlw_to_alpha_lc(number) uintlw_as_alpha_lc(number, NULL) -+#define uint64_to_alpha_uc(number) uint64_as_alpha_uc(number, NULL) -+#define uint64_to_alpha_lc(number) uint64_as_alpha_lc(number, NULL) -+ -+UTILAPI char * uint32_as_alphan_uc (uint32_t number, char **e); -+UTILAPI char * uint32_as_alphan_lc (uint32_t number, char **e); -+UTILAPI char * uintlw_as_alphan_uc (uintlw_t number, char **e); -+UTILAPI char * uintlw_as_alphan_lc (uintlw_t number, char **e); -+UTILAPI char * uint64_as_alphan_uc (uint64_t number, char **e); -+UTILAPI char * uint64_as_alphan_lc (uint64_t number, char **e); -+ -+#define uint32_to_alphan_uc(number) uint32_as_alpha_uc(number, NULL) -+#define uint32_to_alphan_lc(number) uint32_as_alpha_lc(number, NULL) -+#define uintlw_to_alphan_uc(number) uintlw_as_alpha_uc(number, NULL) -+#define uintlw_to_alphan_lc(number) uintlw_as_alpha_lc(number, NULL) -+#define uint64_to_alphan_uc(number) uint64_as_alpha_uc(number, NULL) -+#define uint64_to_alphan_lc(number) uint64_as_alpha_lc(number, NULL) -+ -+/* roman numeral (limited to uint16_t) */ -+ -+UTILAPI char * uint16_as_roman_uc (uint16_t number, char **e); -+UTILAPI char * uint16_as_roman_lc (uint16_t number, char **e); -+ -+#define uint16_to_roman_uc(number) uint16_as_roman_uc(number, NULL) -+#define uint16_to_roman_lc(number) uint16_as_roman_lc(number, NULL) -+ -+#define uint16_as_roman(number) uint16_as_roman_uc(number) -+#define uint16_to_roman(number) uint16_to_roman_uc(number) -+ -+/* double/float to string */ -+ -+UTILAPI char * double_to_string (double number, int digits); -+UTILAPI char * float_to_string (float number, int digits); -+ -+UTILAPI char * double_as_string (double number, int digits, char **r, char **e); -+UTILAPI char * float_as_string (float number, int digits, char **r, char **e); -+ -+/* string to double/float */ -+ -+UTILAPI const char * string_to_double (const char *s, double *number); -+UTILAPI const char * string_to_float (const char *s, float *number); -+ -+/* convenience form accepting comma among a dot, with not exp notation (eg. pdf) */ -+ -+UTILAPI const char * convert_to_double (const char *s, double *number); -+UTILAPI const char * convert_to_float (const char *s, float *number); -+ -+/* binary data parsers helpers */ -+ -+#define get_byte1(i) ((i)&255) -+#define get_byte2(i) (((i)>>8)&255) -+#define get_byte3(i) (((i)>>16)&255) -+#define get_byte4(i) (((i)>>24)&255) -+ -+#define read_uint16be_as(s, int_type) ((int_type)((s[0]<<8)|s[1])) -+#define read_uint32be_as(s, int_type) ((int_type)((s[0]<<24)|(s[1]<<16)|(s[2]<<8)|s[3])) -+ -+#define read_uint16le_as(s, int_type) ((int_type)((s[1]<<8)|s[0])) -+#define read_uint32le_as(s, int_type) ((int_type)((s[3]<<24)|(s[2]<<16)|(s[1]<<8)|s[0])) -+ -+#define read_uint16_native(s) (*((uint16_t *)(s))) -+#define read_uint32_native(s) (*((uint32_t *)(s))) -+#define read_int16_native(s) (*((int16_t *)(s))) -+#define read_int32_native(s) (*((int32_t *)(s))) -+ -+#define scan_uint16be_as(s, int_type) (s += 2, (int_type)((s[-2]<<8)|s[-1])) -+#define scan_uint32be_as(s, int_type) (s += 4, (int_type)((s[-4]<<24)|(s[-3]<<16)|(s[-2]<<8)|s[-1])) -+ -+#define scan_uint16le_as(s, int_type) (s += 2, (int_type)((s[-1]<<8)|s[-2])) -+#define scan_uint32le_as(s, int_type) (s += 4, (int_type)((s[-1]<<24)|(s[-2]<<16)|(s[-3]<<8)|s[-4])) -+ -+#define scan_uint16_native(s) (s += 2, read_uint16_native(s-2)) -+#define scan_uint32_native(s) (s += 4, read_uint32_native(s-4)) -+#define scan_int16_native(s) (s += 2, read_int16_native(s-2)) -+#define scan_int32_native(s) (s += 4, read_int32_native(s-4)) -+ -+#define read_fixed16_16_as(s, float_type) (((float_type)read_uint32be_as(s, signed int))/(1<<16)) -+#define read_fixed2_14_as(s, float_type) (((float_type)read_uint16be_as(s, signed short))/(1<<14)) -+ -+#define scan_fixed16_16_as(s, float_type) (((float_type)scan_uint32be_as(s, signed int))/(1<<16)) -+#define scan_fixed2_14_as(s, float_type) (((float_type)scan_uint16be_as(s, signed short))/(1<<14)) -+ -+/* internal procedures */ -+ -+#define _scan_sign(c, sign, next) \ -+ do { if (c == '-') { sign = 1; c = next; } else if (c == '+') { sign = 0; c = next; } else sign = 0; } while (0) -+ -+#define integer_multiplied10(number) (((number) << 1) + ((number) << 3)) -+ -+#define _scan_integer(c, number, next) \ -+ for (number = 0; base10_digit(c); number = integer_multiplied10(number) + (c - '0'), c = next) -+#define _scan_radix(c, number, radix, next) \ -+ for (number = 0; (c = base36_value(c)) >= 0 && c < radix; number = number * radix + c, c = next) -+ -+#define _read_integer(c, number, next) \ -+ for (number = c - '0', c = next; base10_digit(c); number = integer_multiplied10(number) + (c - '0'), c = next) -+#define _read_radix(c, number, radix, next) \ -+ for (number = c - '0', c = next; (c = base36_value(c)) >= 0 && c < radix; number = number * radix + c, c = next) -+ -+/* rationals */ -+ -+#define _scan_decimal(c, number, next) \ -+ for (number = 0; base10_digit(c); number = number*10 + (c - '0'), c = next) -+#define _scan_fraction(c, number, exponent10, next) \ -+ for (exponent10 = 0; base10_digit(c); --exponent10, number = number*10 + (c - '0'), c = next) -+ -+#define _scan_exponent10(c, exponent10, next) \ -+ do { \ -+ int eexponent10, eexpsign; \ -+ _scan_sign(c, eexpsign, next); \ -+ _scan_integer(c, eexponent10, next); \ -+ if (eexpsign) \ -+ exponent10 -= eexponent10; \ -+ else \ -+ exponent10 += eexponent10; \ -+ } while(0) -+ -+#if 0 -+ -+// kept just for sentiment ;) -+ -+extern const double double_binary_power10[]; -+extern const float float_binary_power10[]; -+extern const double double_binary_negpower10[]; -+extern const float float_binary_negpower10[]; -+ -+#define double_negative_exp10(number, exponent) \ -+{ const double *bp10; int e = ((exponent) < 511 ? 511 : -(exponent)); \ -+ for (bp10 = double_binary_negpower10; e > 0; e >>= 1, ++bp10) \ -+ if (e & 1) number *= *bp10; } -+ -+#define float_negative_exp10(number, exponent) \ -+{ const float *bp10; int e = ((exponent) < 64 ? 64 : -(exponent)); \ -+ for (bp10 = float_binary_negpower10; e > 0; e >>= 1, ++bp10) \ -+ if (e & 1) number *= *bp10; } -+ -+#define double_positive_exp10(number, exponent) \ -+{ const double *bp10; int e = ((exponent) > 511 ? 511 : (exponent)); \ -+ for (bp10 = double_binary_power10; e > 0; e >>= 1, ++bp10) \ -+ if (e & 1) number *= *bp10; } -+ -+#define float_positive_exp10(number, exponent) \ -+{ const float *bp10; int e = ((exponent) > 64 ? 64 : (exponent)); \ -+ for (bp10 = double_binary_power10; e > 0; e >>= 1, ++bp10) \ -+ if (e & 1) number *= *bp10; } -+ -+#define double_exp10(number, exponent) \ -+ if ((exponent) < 0) double_negative_exp10(number, exponent) else if ((exponent) > 0) double_positive_exp10(number, exponent) -+ -+#define float_exp10(number, exponent) \ -+ if ((exponent) < 0) float_negative_exp10(number, exponent) else if ((exponent) > 0) float_positive_exp10(number, exponent) -+ -+#else -+ -+extern const double double_decimal_power10[]; -+extern const float float_decimal_power10[]; -+extern const double double_decimal_negpower10[]; -+extern const float float_decimal_negpower10[]; -+ -+#define double_negative_exp10(number, exponent) ((number) *= double_decimal_negpower10[(exponent) < -308 ? 308 : -(exponent)]) -+#define double_positive_exp10(number, exponent) ((number) *= double_decimal_power10[(exponent) > 308 ? 308 : (exponent)]) -+ -+#define float_negative_exp10(number, exponent) ((number) *= float_decimal_negpower10[(exponent) < -38 ? 38 : -(exponent)]) -+#define float_positive_exp10(number, exponent) ((number) *= float_decimal_power10[(exponent) > 38 ? 38 : (exponent)]) -+ -+#define double_exp10(number, exponent) ((void)(((exponent) < 0 && double_negative_exp10(number, exponent)) || (((exponent) > 0 && double_positive_exp10(number, exponent))))) -+#define float_exp10(number, exponent) ((void)(((exponent) < 0 && float_negative_exp10(number, exponent)) || (((exponent) > 0 && float_positive_exp10(number, exponent))))) -+ -+#endif -+ -+/* pretty common stuff */ -+ -+#define bytes_to_hex(input, size, output) bytes_to_hex_lc(input, size, output) -+UTILAPI size_t bytes_to_hex_lc (const void *input, size_t size, uint8_t *output); -+UTILAPI size_t bytes_to_hex_uc (const void *input, size_t size, uint8_t *output); -+UTILAPI size_t hex_to_bytes (const void *input, size_t size, uint8_t *output); -+UTILAPI void print_as_hex (const void *input, size_t bytes); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilplat.h b/texk/web2c/luatexdir/luapplib/util/utilplat.h -new file mode 100644 -index 000000000..037a1e231 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilplat.h -@@ -0,0 +1,23 @@ -+ -+#ifndef UTIL_PLAT_H -+#define UTIL_PLAT_H -+ -+#if defined(_WIN32) || defined(WIN32) -+# ifdef _MSC_VER -+# if defined(_M_64) || defined(_WIN64) -+# define MSVC64 -+# else -+# define MSVC32 -+# endif -+# else -+# if defined(__MINGW64__) -+# define MINGW64 -+# else -+# if defined(__MINGW32__) -+# define MINGW32 -+# endif -+# endif -+# endif -+#endif -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/util/utilsha.c b/texk/web2c/luatexdir/luapplib/util/utilsha.c -new file mode 100644 -index 000000000..665320730 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilsha.c -@@ -0,0 +1,1290 @@ -+/* sha2 implementation by Aaron D. Gifford (http://www.aarongifford.com) */ -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#include -+#endif -+ -+#ifndef BYTE_ORDER -+#define BYTE_ORDER LITTLE_ENDIAN -+#endif -+/* begin of sha2.c */ -+ -+/* -+ * FILE: sha2.c -+ * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ -+ * -+ * Copyright (c) 2000-2001, Aaron D. Gifford -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the copyright holder nor the names of contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * -+ * $Id: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $ -+ */ -+ -+#include /* memcpy()/memset() or bcopy()/bzero() */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+#include -+#endif -+#include /* assert() */ -+//#include "sha2.h" -+#include "utilsha.h" -+ -+/* -+ * ASSERT NOTE: -+ * Some sanity checking code is included using assert(). On my FreeBSD -+ * system, this additional code can be removed by compiling with NDEBUG -+ * defined. Check your own systems manpage on assert() to see how to -+ * compile WITHOUT the sanity checking code on your system. -+ * -+ * UNROLLED TRANSFORM LOOP NOTE: -+ * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform -+ * loop version for the hash transform rounds (defined using macros -+ * later in this file). Either define on the command line, for example: -+ * -+ * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c -+ * -+ * or define below: -+ * -+ * #define SHA2_UNROLL_TRANSFORM -+ * -+ */ -+ -+ -+/*** SHA-256/384/512 Machine Architecture Definitions *****************/ -+/* -+ * BYTE_ORDER NOTE: -+ * -+ * Please make sure that your system defines BYTE_ORDER. If your -+ * architecture is little-endian, make sure it also defines -+ * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are -+ * equivilent. -+ * -+ * If your system does not define the above, then you can do so by -+ * hand like this: -+ * -+ * #define LITTLE_ENDIAN 1234 -+ * #define BIG_ENDIAN 4321 -+ * -+ * And for little-endian machines, add: -+ * -+ * #define BYTE_ORDER LITTLE_ENDIAN -+ * -+ * Or for big-endian machines: -+ * -+ * #define BYTE_ORDER BIG_ENDIAN -+ * -+ * The FreeBSD machine this was written on defines BYTE_ORDER -+ * appropriately by including (which in turn includes -+ * where the appropriate definitions are actually -+ * made). -+ */ -+#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) -+#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN -+#endif -+ -+/* -+ * Define the followingsha2_* types to types of the correct length on -+ * the native archtecture. Most BSD systems and Linux define u_intXX_t -+ * types. Machines with very recent ANSI C headers, can use the -+ * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H -+ * during compile or in the sha.h header file. -+ * -+ * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t -+ * will need to define these three typedefs below (and the appropriate -+ * ones in sha.h too) by hand according to their system architecture. -+ * -+ * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t -+ * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. -+ * -+ * PJ: replace by uintX_t -+ */ -+ -+//typedef uint8_t sha2_byte; /* Exactly 1 byte */ -+//typedef uint32_t sha2_word32; /* Exactly 4 bytes */ -+//typedef uint64_t sha2_word64; /* Exactly 8 bytes */ -+ -+/*** SHA-256/384/512 Various Length Definitions ***********************/ -+/* NOTE: Most of these are in sha2.h */ -+#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) -+#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) -+#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) -+ -+ -+/*** ENDIAN REVERSAL MACROS *******************************************/ -+#if BYTE_ORDER == LITTLE_ENDIAN -+#define REVERSE32(w,x) { \ -+ uint32_t tmp = (w); \ -+ tmp = (tmp >> 16) | (tmp << 16); \ -+ (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ -+} -+#define REVERSE64(w,x) { \ -+ uint64_t tmp = (w); \ -+ tmp = (tmp >> 32) | (tmp << 32); \ -+ tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ -+ ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ -+ (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ -+ ((tmp & 0x0000ffff0000ffffULL) << 16); \ -+} -+#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -+ -+/* -+ * Macro for incrementally adding the unsigned 64-bit integer n to the -+ * unsigned 128-bit integer (represented using a two-element array of -+ * 64-bit words): -+ */ -+#define ADDINC128(w,n) { \ -+ (w)[0] += (uint64_t)(n); \ -+ if ((w)[0] < (n)) { \ -+ (w)[1]++; \ -+ } \ -+} -+ -+/* -+ * Macros for copying blocks of memory and for zeroing out ranges -+ * of memory. Using these macros makes it easy to switch from -+ * using memset()/memcpy() and using bzero()/bcopy(). -+ * -+ * Please define either SHA2_USE_MEMSET_MEMCPY or define -+ * SHA2_USE_BZERO_BCOPY depending on which function set you -+ * choose to use: -+ */ -+#if !defined(SHA2_USE_MEMSET_MEMCPY) && !defined(SHA2_USE_BZERO_BCOPY) -+/* Default to memset()/memcpy() if no option is specified */ -+#define SHA2_USE_MEMSET_MEMCPY 1 -+#endif -+#if defined(SHA2_USE_MEMSET_MEMCPY) && defined(SHA2_USE_BZERO_BCOPY) -+/* Abort with an error if BOTH options are defined */ -+#error Define either SHA2_USE_MEMSET_MEMCPY or SHA2_USE_BZERO_BCOPY, not both! -+#endif -+ -+#ifdef SHA2_USE_MEMSET_MEMCPY -+#define MEMSET_BZERO(p,l) memset((p), 0, (l)) -+#define MEMCPY_BCOPY(d,s,l) memcpy((d), (s), (l)) -+#endif -+#ifdef SHA2_USE_BZERO_BCOPY -+#define MEMSET_BZERO(p,l) bzero((p), (l)) -+#define MEMCPY_BCOPY(d,s,l) bcopy((s), (d), (l)) -+#endif -+ -+ -+/*** THE SIX LOGICAL FUNCTIONS ****************************************/ -+/* -+ * Bit shifting and rotation (used by the six SHA-XYZ logical functions: -+ * -+ * NOTE: The naming of R and S appears backwards here (R is a SHIFT and -+ * S is a ROTATION) because the SHA-256/384/512 description document -+ * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this -+ * same "backwards" definition. -+ */ -+/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ -+#define R(b,x) ((x) >> (b)) -+/* 32-bit Rotate-right (used in SHA-256): */ -+#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) -+/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ -+#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) -+ -+/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ -+#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -+#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -+ -+/* Four of six logical functions used in SHA-256: */ -+#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) -+#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) -+#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) -+#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) -+ -+/* Four of six logical functions used in SHA-384 and SHA-512: */ -+#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) -+#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) -+#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) -+#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) -+ -+/*** INTERNAL FUNCTION PROTOTYPES *************************************/ -+/* NOTE: These should not be accessed directly from outside this -+ * library -- they are intended for private internal visibility/use -+ * only. -+ */ -+static void SHA512_Last(SHA512_CTX*); -+static void SHA256_Transform(SHA256_CTX*, const uint32_t*); -+static void SHA512_Transform(SHA512_CTX*, const uint64_t*); -+ -+ -+/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ -+/* Hash constant words K for SHA-256: */ -+static const uint32_t K256[64] = { -+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, -+ 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, -+ 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, -+ 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, -+ 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, -+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, -+ 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, -+ 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, -+ 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, -+ 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, -+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, -+ 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, -+ 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, -+ 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, -+ 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, -+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -+}; -+ -+/* Initial hash value H for SHA-256: */ -+static const uint32_t sha256_initial_hash_value[8] = { -+ 0x6a09e667UL, -+ 0xbb67ae85UL, -+ 0x3c6ef372UL, -+ 0xa54ff53aUL, -+ 0x510e527fUL, -+ 0x9b05688cUL, -+ 0x1f83d9abUL, -+ 0x5be0cd19UL -+}; -+ -+/* Hash constant words K for SHA-384 and SHA-512: */ -+static const uint64_t K512[80] = { -+ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, -+ 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, -+ 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, -+ 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, -+ 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, -+ 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, -+ 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, -+ 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, -+ 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, -+ 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, -+ 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, -+ 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, -+ 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, -+ 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, -+ 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, -+ 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, -+ 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, -+ 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, -+ 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, -+ 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, -+ 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, -+ 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, -+ 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, -+ 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, -+ 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, -+ 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, -+ 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, -+ 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, -+ 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, -+ 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, -+ 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, -+ 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, -+ 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, -+ 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, -+ 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, -+ 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, -+ 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, -+ 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, -+ 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, -+ 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -+}; -+ -+/* Initial hash value H for SHA-384 */ -+static const uint64_t sha384_initial_hash_value[8] = { -+ 0xcbbb9d5dc1059ed8ULL, -+ 0x629a292a367cd507ULL, -+ 0x9159015a3070dd17ULL, -+ 0x152fecd8f70e5939ULL, -+ 0x67332667ffc00b31ULL, -+ 0x8eb44a8768581511ULL, -+ 0xdb0c2e0d64f98fa7ULL, -+ 0x47b5481dbefa4fa4ULL -+}; -+ -+/* Initial hash value H for SHA-512 */ -+static const uint64_t sha512_initial_hash_value[8] = { -+ 0x6a09e667f3bcc908ULL, -+ 0xbb67ae8584caa73bULL, -+ 0x3c6ef372fe94f82bULL, -+ 0xa54ff53a5f1d36f1ULL, -+ 0x510e527fade682d1ULL, -+ 0x9b05688c2b3e6c1fULL, -+ 0x1f83d9abfb41bd6bULL, -+ 0x5be0cd19137e2179ULL -+}; -+ -+/* -+ * Constant used by SHA256/384/512_End() functions for converting the -+ * digest to a readable hexadecimal character string: -+ */ -+ -+//static const char *sha2_hex_digits = "0123456789abcdef"; // PJ -+ -+ -+/*** SHA-256: *********************************************************/ -+static void SHA256_Init(SHA256_CTX* context) { -+ if (context == (SHA256_CTX*)0) { -+ return; -+ } -+ MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); -+ MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); -+ context->bitcount = 0; -+} -+ -+#ifdef SHA2_UNROLL_TRANSFORM -+ -+/* Unrolled SHA-256 round macros: */ -+ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ -+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ -+ REVERSE32(*data++, W256[j]); \ -+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ -+ K256[j] + W256[j]; \ -+ (d) += T1; \ -+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ -+ j++ -+ -+ -+#else /* BYTE_ORDER == LITTLE_ENDIAN */ -+ -+#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ -+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ -+ K256[j] + (W256[j] = *data++); \ -+ (d) += T1; \ -+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ -+ j++ -+ -+#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -+ -+#define ROUND256(a,b,c,d,e,f,g,h) \ -+ s0 = W256[(j+1)&0x0f]; \ -+ s0 = sigma0_256(s0); \ -+ s1 = W256[(j+14)&0x0f]; \ -+ s1 = sigma1_256(s1); \ -+ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ -+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ -+ (d) += T1; \ -+ (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ -+ j++ -+ -+void SHA256_Transform(SHA256_CTX* context, const uint32_t* data) { -+ uint32_t a, b, c, d, e, f, g, h, s0, s1; -+ uint32_t T1, *W256; -+ int j; -+ -+ W256 = (uint32_t*)context->buffer; -+ -+ /* Initialize registers with the prev. intermediate value */ -+ a = context->state[0]; -+ b = context->state[1]; -+ c = context->state[2]; -+ d = context->state[3]; -+ e = context->state[4]; -+ f = context->state[5]; -+ g = context->state[6]; -+ h = context->state[7]; -+ -+ j = 0; -+ do { -+ /* Rounds 0 to 15 (unrolled): */ -+ ROUND256_0_TO_15(a,b,c,d,e,f,g,h); -+ ROUND256_0_TO_15(h,a,b,c,d,e,f,g); -+ ROUND256_0_TO_15(g,h,a,b,c,d,e,f); -+ ROUND256_0_TO_15(f,g,h,a,b,c,d,e); -+ ROUND256_0_TO_15(e,f,g,h,a,b,c,d); -+ ROUND256_0_TO_15(d,e,f,g,h,a,b,c); -+ ROUND256_0_TO_15(c,d,e,f,g,h,a,b); -+ ROUND256_0_TO_15(b,c,d,e,f,g,h,a); -+ } while (j < 16); -+ -+ /* Now for the remaining rounds to 64: */ -+ do { -+ ROUND256(a,b,c,d,e,f,g,h); -+ ROUND256(h,a,b,c,d,e,f,g); -+ ROUND256(g,h,a,b,c,d,e,f); -+ ROUND256(f,g,h,a,b,c,d,e); -+ ROUND256(e,f,g,h,a,b,c,d); -+ ROUND256(d,e,f,g,h,a,b,c); -+ ROUND256(c,d,e,f,g,h,a,b); -+ ROUND256(b,c,d,e,f,g,h,a); -+ } while (j < 64); -+ -+ /* Compute the current intermediate hash value */ -+ context->state[0] += a; -+ context->state[1] += b; -+ context->state[2] += c; -+ context->state[3] += d; -+ context->state[4] += e; -+ context->state[5] += f; -+ context->state[6] += g; -+ context->state[7] += h; -+ -+ /* Clean up */ -+ a = b = c = d = e = f = g = h = T1 = 0; -+} -+ -+#else /* SHA2_UNROLL_TRANSFORM */ -+ -+static void SHA256_Transform(SHA256_CTX* context, const uint32_t* data) { -+ uint32_t a, b, c, d, e, f, g, h, s0, s1; -+ uint32_t T1, T2, *W256; -+ int j; -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ W256 = (uint32_t*)((void *)context->buffer); -+#else -+ W256 = (uint32_t*)context->buffer; -+#endif -+ -+ -+ /* Initialize registers with the prev. intermediate value */ -+ a = context->state[0]; -+ b = context->state[1]; -+ c = context->state[2]; -+ d = context->state[3]; -+ e = context->state[4]; -+ f = context->state[5]; -+ g = context->state[6]; -+ h = context->state[7]; -+ -+ j = 0; -+ do { -+#if BYTE_ORDER == LITTLE_ENDIAN -+ /* Copy data while converting to host byte order */ -+ REVERSE32(*data++,W256[j]); -+ /* Apply the SHA-256 compression function to update a..h */ -+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; -+#else /* BYTE_ORDER == LITTLE_ENDIAN */ -+ /* Apply the SHA-256 compression function to update a..h with copy */ -+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); -+#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -+ T2 = Sigma0_256(a) + Maj(a, b, c); -+ h = g; -+ g = f; -+ f = e; -+ e = d + T1; -+ d = c; -+ c = b; -+ b = a; -+ a = T1 + T2; -+ -+ j++; -+ } while (j < 16); -+ -+ do { -+ /* Part of the message block expansion: */ -+ s0 = W256[(j+1)&0x0f]; -+ s0 = sigma0_256(s0); -+ s1 = W256[(j+14)&0x0f]; -+ s1 = sigma1_256(s1); -+ -+ /* Apply the SHA-256 compression function to update a..h */ -+ T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + -+ (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); -+ T2 = Sigma0_256(a) + Maj(a, b, c); -+ h = g; -+ g = f; -+ f = e; -+ e = d + T1; -+ d = c; -+ c = b; -+ b = a; -+ a = T1 + T2; -+ -+ j++; -+ } while (j < 64); -+ -+ /* Compute the current intermediate hash value */ -+ context->state[0] += a; -+ context->state[1] += b; -+ context->state[2] += c; -+ context->state[3] += d; -+ context->state[4] += e; -+ context->state[5] += f; -+ context->state[6] += g; -+ context->state[7] += h; -+ -+ /* Clean up */ -+ a = b = c = d = e = f = g = h = T1 = T2 = 0; -+} -+ -+#endif /* SHA2_UNROLL_TRANSFORM */ -+ -+static void SHA256_Update(SHA256_CTX* context, const uint8_t *data, size_t len) { -+ unsigned int freespace, usedspace; -+ -+ if (len == 0) { -+ /* Calling with no data is valid - we do nothing */ -+ return; -+ } -+ -+ /* Sanity check: */ -+ assert(context != (SHA256_CTX*)0 && data != (uint8_t*)0); -+ -+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -+ if (usedspace > 0) { -+ /* Calculate how much free space is available in the buffer */ -+ freespace = SHA256_BLOCK_LENGTH - usedspace; -+ -+ if (len >= freespace) { -+ /* Fill the buffer completely and process it */ -+ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); -+ context->bitcount += freespace << 3; -+ len -= freespace; -+ data += freespace; -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA256_Transform(context, (uint32_t*)((void *)context->buffer)); -+#else -+ SHA256_Transform(context, (uint32_t*)context->buffer); -+#endif -+ -+ } else { -+ /* The buffer is not yet full */ -+ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); -+ context->bitcount += len << 3; -+ /* Clean up: */ -+ usedspace = freespace = 0; -+ return; -+ } -+ } -+ while (len >= SHA256_BLOCK_LENGTH) { -+ /* Process as many complete blocks as we can */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA256_Transform(context, (const uint32_t*)(const void *)(data)); -+#else -+ SHA256_Transform(context, (const uint32_t*)data); -+#endif -+ -+ context->bitcount += SHA256_BLOCK_LENGTH << 3; -+ len -= SHA256_BLOCK_LENGTH; -+ data += SHA256_BLOCK_LENGTH; -+ } -+ if (len > 0) { -+ /* There's left-overs, so save 'em */ -+ MEMCPY_BCOPY(context->buffer, data, len); -+ context->bitcount += len << 3; -+ } -+ /* Clean up: */ -+ usedspace = freespace = 0; -+} -+ -+static void SHA256_Final(uint8_t digest[], SHA256_CTX* context) { -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ uint32_t *d ; -+#else -+ uint32_t *d = (uint32_t*)digest; -+ -+#endif -+ unsigned int usedspace; -+ -+ /* Sanity check: */ -+ assert(context != (SHA256_CTX*)0); -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ d = malloc(sizeof(uint32_t)*8); /* why 8 ? see below for loop */ -+ assert(d); -+#endif -+ -+ /* If no digest buffer is passed, we don't bother doing this: */ -+ if (digest != (uint8_t*)0) { -+ usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; -+#if BYTE_ORDER == LITTLE_ENDIAN -+ /* Convert FROM host byte order */ -+ REVERSE64(context->bitcount,context->bitcount); -+#endif -+ if (usedspace > 0) { -+ /* Begin padding with a 1 bit: */ -+ context->buffer[usedspace++] = 0x80; -+ -+ if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { -+ /* Set-up for the last transform: */ -+ MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); -+ } else { -+ if (usedspace < SHA256_BLOCK_LENGTH) { -+ MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); -+ } -+ /* Do second-to-last transform: */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA256_Transform(context, (uint32_t*)(void *)(context->buffer)); -+#else -+ SHA256_Transform(context, (uint32_t*)context->buffer); -+#endif -+ -+ -+ /* And set-up for the last transform: */ -+ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); -+ } -+ } else { -+ /* Set-up for the last transform: */ -+ MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); -+ -+ /* Begin padding with a 1 bit: */ -+ *context->buffer = 0x80; -+ } -+ /* Set the bit count: */ -+ //*(uint64_t*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; // aliasing violation warning -+ context->buffer64[SHA256_SHORT_BLOCK_LENGTH / sizeof(uint64_t)] = context->bitcount; -+ -+ /* Final transform: */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA256_Transform(context, (uint32_t*)((void *)(context->buffer))); -+ -+#else -+ SHA256_Transform(context, (uint32_t*)context->buffer); -+ -+#endif -+ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ { -+ /* Convert TO host byte order */ -+ int j; -+ for (j = 0; j < 8; j++) { -+ REVERSE32(context->state[j],context->state[j]); -+ *d++ = context->state[j]; -+ } -+ } -+#else -+ MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); -+#endif -+ } -+ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ memcpy(digest,d,SHA256_DIGEST_LENGTH); -+ free(d); -+#endif -+ -+ /* Clean up state data: */ -+ MEMSET_BZERO(context, sizeof(*context)); -+ usedspace = 0; -+} -+ -+/* -+static char *SHA256_End(SHA256_CTX* context, char buffer[]) { -+ uint8_t digest[SHA256_DIGEST_LENGTH], *d = digest; -+ int i; -+ -+ / * Sanity check: * / -+ assert(context != (SHA256_CTX*)0); -+ -+ if (buffer != (char*)0) { -+ SHA256_Final(digest, context); -+ -+ for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { -+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; -+ *buffer++ = sha2_hex_digits[*d & 0x0f]; -+ d++; -+ } -+ *buffer = (char)0; -+ } else { -+ MEMSET_BZERO(context, sizeof(context)); -+ } -+ MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); -+ return buffer; -+} -+ -+static char* SHA256_Data(const uint8_t* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { -+ SHA256_CTX context; -+ -+ SHA256_Init(&context); -+ SHA256_Update(&context, data, len); -+ return SHA256_End(&context, digest); -+} -+*/ -+ -+ -+/*** SHA-512: *********************************************************/ -+static void SHA512_Init(SHA512_CTX* context) { -+ if (context == (SHA512_CTX*)0) { -+ return; -+ } -+ MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); -+ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); -+ context->bitcount[0] = context->bitcount[1] = 0; -+} -+ -+#ifdef SHA2_UNROLL_TRANSFORM -+ -+/* Unrolled SHA-512 round macros: */ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ -+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ -+ REVERSE64(*data++, W512[j]); \ -+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ -+ K512[j] + W512[j]; \ -+ (d) += T1, \ -+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ -+ j++ -+ -+ -+#else /* BYTE_ORDER == LITTLE_ENDIAN */ -+ -+#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ -+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ -+ K512[j] + (W512[j] = *data++); \ -+ (d) += T1; \ -+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ -+ j++ -+ -+#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -+ -+#define ROUND512(a,b,c,d,e,f,g,h) \ -+ s0 = W512[(j+1)&0x0f]; \ -+ s0 = sigma0_512(s0); \ -+ s1 = W512[(j+14)&0x0f]; \ -+ s1 = sigma1_512(s1); \ -+ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ -+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ -+ (d) += T1; \ -+ (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ -+ j++ -+ -+static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) { -+ uint64_t a, b, c, d, e, f, g, h, s0, s1; -+ uint64_t T1, *W512 = (uint64_t*)context->buffer; -+ int j; -+ -+ /* Initialize registers with the prev. intermediate value */ -+ a = context->state[0]; -+ b = context->state[1]; -+ c = context->state[2]; -+ d = context->state[3]; -+ e = context->state[4]; -+ f = context->state[5]; -+ g = context->state[6]; -+ h = context->state[7]; -+ -+ j = 0; -+ do { -+ ROUND512_0_TO_15(a,b,c,d,e,f,g,h); -+ ROUND512_0_TO_15(h,a,b,c,d,e,f,g); -+ ROUND512_0_TO_15(g,h,a,b,c,d,e,f); -+ ROUND512_0_TO_15(f,g,h,a,b,c,d,e); -+ ROUND512_0_TO_15(e,f,g,h,a,b,c,d); -+ ROUND512_0_TO_15(d,e,f,g,h,a,b,c); -+ ROUND512_0_TO_15(c,d,e,f,g,h,a,b); -+ ROUND512_0_TO_15(b,c,d,e,f,g,h,a); -+ } while (j < 16); -+ -+ /* Now for the remaining rounds up to 79: */ -+ do { -+ ROUND512(a,b,c,d,e,f,g,h); -+ ROUND512(h,a,b,c,d,e,f,g); -+ ROUND512(g,h,a,b,c,d,e,f); -+ ROUND512(f,g,h,a,b,c,d,e); -+ ROUND512(e,f,g,h,a,b,c,d); -+ ROUND512(d,e,f,g,h,a,b,c); -+ ROUND512(c,d,e,f,g,h,a,b); -+ ROUND512(b,c,d,e,f,g,h,a); -+ } while (j < 80); -+ -+ /* Compute the current intermediate hash value */ -+ context->state[0] += a; -+ context->state[1] += b; -+ context->state[2] += c; -+ context->state[3] += d; -+ context->state[4] += e; -+ context->state[5] += f; -+ context->state[6] += g; -+ context->state[7] += h; -+ -+ /* Clean up */ -+ a = b = c = d = e = f = g = h = T1 = 0; -+} -+ -+#else /* SHA2_UNROLL_TRANSFORM */ -+ -+static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) { -+ uint64_t a, b, c, d, e, f, g, h, s0, s1; -+ uint64_t T1, T2, *W512 = (uint64_t*)((void *)context->buffer); -+ int j; -+ -+ /* Initialize registers with the prev. intermediate value */ -+ a = context->state[0]; -+ b = context->state[1]; -+ c = context->state[2]; -+ d = context->state[3]; -+ e = context->state[4]; -+ f = context->state[5]; -+ g = context->state[6]; -+ h = context->state[7]; -+ -+ j = 0; -+ do { -+#if BYTE_ORDER == LITTLE_ENDIAN -+ /* Convert TO host byte order */ -+ REVERSE64(*data++, W512[j]); -+ /* Apply the SHA-512 compression function to update a..h */ -+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; -+#else /* BYTE_ORDER == LITTLE_ENDIAN */ -+ /* Apply the SHA-512 compression function to update a..h with copy */ -+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); -+#endif /* BYTE_ORDER == LITTLE_ENDIAN */ -+ T2 = Sigma0_512(a) + Maj(a, b, c); -+ h = g; -+ g = f; -+ f = e; -+ e = d + T1; -+ d = c; -+ c = b; -+ b = a; -+ a = T1 + T2; -+ -+ j++; -+ } while (j < 16); -+ -+ do { -+ /* Part of the message block expansion: */ -+ s0 = W512[(j+1)&0x0f]; -+ s0 = sigma0_512(s0); -+ s1 = W512[(j+14)&0x0f]; -+ s1 = sigma1_512(s1); -+ -+ /* Apply the SHA-512 compression function to update a..h */ -+ T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + -+ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); -+ T2 = Sigma0_512(a) + Maj(a, b, c); -+ h = g; -+ g = f; -+ f = e; -+ e = d + T1; -+ d = c; -+ c = b; -+ b = a; -+ a = T1 + T2; -+ -+ j++; -+ } while (j < 80); -+ -+ /* Compute the current intermediate hash value */ -+ context->state[0] += a; -+ context->state[1] += b; -+ context->state[2] += c; -+ context->state[3] += d; -+ context->state[4] += e; -+ context->state[5] += f; -+ context->state[6] += g; -+ context->state[7] += h; -+ -+ /* Clean up */ -+ a = b = c = d = e = f = g = h = T1 = T2 = 0; -+} -+ -+#endif /* SHA2_UNROLL_TRANSFORM */ -+ -+static void SHA512_Update(SHA512_CTX* context, const uint8_t *data, size_t len) { -+ unsigned int freespace, usedspace; -+ -+ if (len == 0) { -+ /* Calling with no data is valid - we do nothing */ -+ return; -+ } -+ -+ /* Sanity check: */ -+ assert(context != (SHA512_CTX*)0 && data != (uint8_t*)0); -+ -+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; -+ if (usedspace > 0) { -+ /* Calculate how much free space is available in the buffer */ -+ freespace = SHA512_BLOCK_LENGTH - usedspace; -+ -+ if (len >= freespace) { -+ /* Fill the buffer completely and process it */ -+ MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); -+ ADDINC128(context->bitcount, freespace << 3); -+ len -= freespace; -+ data += freespace; -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA512_Transform(context, (uint64_t*)((void *)context->buffer)); -+#else -+ SHA512_Transform(context, (uint64_t*)context->buffer); -+#endif -+ } else { -+ /* The buffer is not yet full */ -+ MEMCPY_BCOPY(&context->buffer[usedspace], data, len); -+ ADDINC128(context->bitcount, len << 3); -+ /* Clean up: */ -+ usedspace = freespace = 0; -+ return; -+ } -+ } -+ while (len >= SHA512_BLOCK_LENGTH) { -+ /* Process as many complete blocks as we can */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA512_Transform(context, (uint64_t*)((void *)context->buffer)); -+#else -+ SHA512_Transform(context, (uint64_t*)context->buffer); -+#endif -+ ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); -+ len -= SHA512_BLOCK_LENGTH; -+ data += SHA512_BLOCK_LENGTH; -+ } -+ if (len > 0) { -+ /* There's left-overs, so save 'em */ -+ MEMCPY_BCOPY(context->buffer, data, len); -+ ADDINC128(context->bitcount, len << 3); -+ } -+ /* Clean up: */ -+ usedspace = freespace = 0; -+} -+ -+static void SHA512_Last(SHA512_CTX* context) { -+ unsigned int usedspace; -+ -+ usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; -+#if BYTE_ORDER == LITTLE_ENDIAN -+ /* Convert FROM host byte order */ -+ REVERSE64(context->bitcount[0],context->bitcount[0]); -+ REVERSE64(context->bitcount[1],context->bitcount[1]); -+#endif -+ if (usedspace > 0) { -+ /* Begin padding with a 1 bit: */ -+ context->buffer[usedspace++] = 0x80; -+ -+ if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { -+ /* Set-up for the last transform: */ -+ MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); -+ } else { -+ if (usedspace < SHA512_BLOCK_LENGTH) { -+ MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); -+ } -+ /* Do second-to-last transform: */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA512_Transform(context, (uint64_t*)((void *)context->buffer)); -+#else -+ SHA512_Transform(context, (uint64_t*)context->buffer); -+#endif -+ -+ -+ /* And set-up for the last transform: */ -+ MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); -+ } -+ } else { -+ /* Prepare for final transform: */ -+ MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); -+ -+ /* Begin padding with a 1 bit: */ -+ *context->buffer = 0x80; -+ } -+ /* Store the length of input data (in bits): */ -+ //*(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; // aliasing violation warning -+ //*(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; -+ context->buffer64[SHA512_SHORT_BLOCK_LENGTH / sizeof(uint64_t)] = context->bitcount[1]; -+ context->buffer64[SHA512_SHORT_BLOCK_LENGTH / sizeof(uint64_t) + 1] = context->bitcount[0]; -+ -+ /* Final transform: */ -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ SHA512_Transform(context, (uint64_t*)((void *)context->buffer)); -+#else -+ SHA512_Transform(context, (uint64_t*)context->buffer); -+#endif -+ -+} -+ -+static void SHA512_Final(uint8_t digest[], SHA512_CTX* context) { -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ uint64_t *d ; -+#else -+ uint64_t *d = (uint64_t*)digest; -+ -+#endif -+ -+ /* Sanity check: */ -+ assert(context != (SHA512_CTX*)0); -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ d = malloc(sizeof(uint64_t)*8); /* why 8 ? see below for loop */ -+ assert(d); -+#endif -+ -+ /* If no digest buffer is passed, we don't bother doing this: */ -+ if (digest != (uint8_t*)0) { -+ SHA512_Last(context); -+ -+ /* Save the hash data for output: */ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ { -+ /* Convert TO host byte order */ -+ int j; -+ for (j = 0; j < 8; j++) { -+ REVERSE64(context->state[j],context->state[j]); -+ *d++ = context->state[j]; -+ } -+ } -+#else -+ MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); -+#endif -+ } -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ memcpy(digest,d,SHA512_DIGEST_LENGTH); -+ free(d); -+#endif -+ -+ /* Zero out state data */ -+ MEMSET_BZERO(context, sizeof(*context)); -+} -+ -+/* -+static char *SHA512_End(SHA512_CTX* context, char buffer[]) { -+ uint8_t digest[SHA512_DIGEST_LENGTH], *d = digest; -+ int i; -+ -+ / * Sanity check: * / -+ assert(context != (SHA512_CTX*)0); -+ -+ if (buffer != (char*)0) { -+ SHA512_Final(digest, context); -+ -+ for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { -+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; -+ *buffer++ = sha2_hex_digits[*d & 0x0f]; -+ d++; -+ } -+ *buffer = (char)0; -+ } else { -+ MEMSET_BZERO(context, sizeof(context)); -+ } -+ MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); -+ return buffer; -+} -+ -+static char* SHA512_Data(const uint8_t* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { -+ SHA512_CTX context; -+ -+ SHA512_Init(&context); -+ SHA512_Update(&context, data, len); -+ return SHA512_End(&context, digest); -+} -+*/ -+ -+/*** SHA-384: *********************************************************/ -+static void SHA384_Init(SHA384_CTX* context) { -+ if (context == (SHA384_CTX*)0) { -+ return; -+ } -+ MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); -+ MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); -+ context->bitcount[0] = context->bitcount[1] = 0; -+} -+ -+static void SHA384_Update(SHA384_CTX* context, const uint8_t* data, size_t len) { -+ SHA512_Update((SHA512_CTX*)context, data, len); -+} -+ -+static void SHA384_Final(uint8_t digest[], SHA384_CTX* context) { -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ uint64_t *d; -+#else -+ uint64_t *d = (uint64_t*)digest; -+#endif -+ -+ -+ -+ /* Sanity check: */ -+ assert(context != (SHA384_CTX*)0); -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ d = malloc(sizeof(uint64_t)*6); /* why 6 ? see below for loop */ -+ assert(d); -+#endif -+ -+ /* If no digest buffer is passed, we don't bother doing this: */ -+ if (digest != (uint8_t*)0) { -+ SHA512_Last((SHA512_CTX*)context); -+ -+ /* Save the hash data for output: */ -+#if BYTE_ORDER == LITTLE_ENDIAN -+ { -+ /* Convert TO host byte order */ -+ int j; -+ for (j = 0; j < 6; j++) { -+ REVERSE64(context->state[j],context->state[j]); -+ *d++ = context->state[j]; -+ } -+ } -+#else -+ MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); -+#endif -+ } -+#if defined __arm__ || defined __ARM__ || defined ARM || defined __ARM || defined __arm || defined __ARM_ARCH ||defined __aarch64__ -+ memcpy(digest,d,SHA384_DIGEST_LENGTH); -+ free(d); -+#endif -+ /* Zero out state data */ -+ MEMSET_BZERO(context, sizeof(*context)); -+} -+ -+/* -+static char *SHA384_End(SHA384_CTX* context, char buffer[]) { -+ uint8_t digest[SHA384_DIGEST_LENGTH], *d = digest; -+ int i; -+ -+ / * Sanity check: * / -+ assert(context != (SHA384_CTX*)0); -+ -+ if (buffer != (char*)0) { -+ SHA384_Final(digest, context); -+ -+ for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { -+ *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; -+ *buffer++ = sha2_hex_digits[*d & 0x0f]; -+ d++; -+ } -+ *buffer = (char)0; -+ } else { -+ MEMSET_BZERO(context, sizeof(context)); -+ } -+ MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); -+ return buffer; -+} -+ -+static char* SHA384_Data(const uint8_t* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { -+ SHA384_CTX context; -+ -+ SHA384_Init(&context); -+ SHA384_Update(&context, data, len); -+ return SHA384_End(&context, digest); -+} -+*/ -+ -+/* end of sha2.c */ -+ -+void sha256_init (sha256_state *state) -+{ -+ SHA256_Init(state); -+} -+ -+void sha384_init (sha384_state *state) -+{ -+ SHA384_Init(state); -+} -+ -+void sha512_init (sha512_state *state) -+{ -+ SHA512_Init(state); -+} -+ -+ -+void sha256_add (sha256_state *state, const void *data, size_t size) -+{ -+ SHA256_Update(state, (const uint8_t *)data, size); -+} -+ -+void sha384_add (sha384_state *state, const void *data, size_t size) -+{ -+ SHA384_Update(state, (const uint8_t *)data, size); -+} -+ -+void sha512_add (sha512_state *state, const void *data, size_t size) -+{ -+ SHA512_Update(state, (const uint8_t *)data, size); -+} -+ -+ -+void sha256_put (sha256_state *state, uint8_t digest[SHA256_DIGEST_LENGTH]) -+{ -+ SHA256_Final(digest, state); -+} -+ -+void sha384_put (sha384_state *state, uint8_t digest[SHA384_DIGEST_LENGTH]) -+{ -+ SHA384_Final(digest, state); -+} -+ -+void sha512_put (sha384_state *state, uint8_t digest[SHA512_DIGEST_LENGTH]) -+{ -+ SHA512_Final(digest, state); -+} -+ -+ -+void sha256 (const void *data, size_t size, uint8_t digest[SHA256_DIGEST_LENGTH]) -+{ -+ sha256_state state; -+ SHA256_Init(&state); -+ SHA256_Update(&state, (const uint8_t *)data, size); -+ SHA256_Final(digest, &state); -+} -+ -+void sha384 (const void *data, size_t size, uint8_t digest[SHA384_DIGEST_LENGTH]) -+{ -+ sha384_state state; -+ SHA384_Init(&state); -+ SHA384_Update(&state, (const uint8_t *)data, size); -+ SHA384_Final(digest, &state); -+} -+ -+void sha512 (const void *data, size_t size, uint8_t digest[SHA512_DIGEST_LENGTH]) -+{ -+ sha512_state state; -+ SHA512_Init(&state); -+ SHA512_Update(&state, (const uint8_t *)data, size); -+ SHA512_Final(digest, &state); -+} -+ -+static sha256_state sha256state; -+static sha384_state sha384state; -+static sha512_state sha512state; -+ -+ -+void sha256init (void) -+{ -+ SHA256_Init(&sha256state); -+} -+ -+void sha384init (void) -+{ -+ SHA384_Init(&sha384state); -+} -+ -+void sha512init (void) -+{ -+ SHA512_Init(&sha512state); -+} -+ -+ -+void sha256add (const void *data, size_t size) -+{ -+ SHA256_Update(&sha256state, (const uint8_t *)data, size); -+} -+ -+void sha384add (const void *data, size_t size) -+{ -+ SHA384_Update(&sha384state, (const uint8_t *)data, size); -+} -+ -+void sha512add (const void *data, size_t size) -+{ -+ SHA512_Update(&sha512state, (const uint8_t *)data, size); -+} -+ -+ -+void sha256put (uint8_t digest[SHA256_DIGEST_LENGTH]) -+{ -+ SHA256_Final(digest, &sha256state); -+} -+ -+void sha384put (uint8_t digest[SHA384_DIGEST_LENGTH]) -+{ -+ SHA384_Final(digest, &sha384state); -+} -+ -+void sha512put (uint8_t digest[SHA512_DIGEST_LENGTH]) -+{ -+ SHA512_Final(digest, &sha512state); -+} -diff --git a/texk/web2c/luatexdir/luapplib/util/utilsha.h b/texk/web2c/luatexdir/luapplib/util/utilsha.h -new file mode 100644 -index 000000000..53f354581 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/util/utilsha.h -@@ -0,0 +1,134 @@ -+/* sha2 implementation by Aaron D. Gifford (http://www.aarongifford.com) */ -+ -+#ifndef UTIL_SHA_H -+#define UTIL_SHA_H -+ -+#include -+#include -+#include "utildecl.h" -+ -+/* begin of sha2.h */ -+ -+/* -+ * FILE: sha2.h -+ * AUTHOR: Aaron D. Gifford - http://www.aarongifford.com/ -+ * -+ * Copyright (c) 2000-2001, Aaron D. Gifford -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. Neither the name of the copyright holder nor the names of contributors -+ * may be used to endorse or promote products derived from this software -+ * without specific prior written permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND -+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE -+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -+ * SUCH DAMAGE. -+ * -+ * $Id: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ -+ */ -+ -+/*** SHA-256/384/512 Various Length Definitions ***********************/ -+ -+#define SHA256_BLOCK_LENGTH 64 -+#define SHA256_DIGEST_LENGTH 32 -+#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) -+#define SHA384_BLOCK_LENGTH 128 -+#define SHA384_DIGEST_LENGTH 48 -+#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) -+#define SHA512_BLOCK_LENGTH 128 -+#define SHA512_DIGEST_LENGTH 64 -+#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) -+ -+typedef struct _SHA256_CTX { -+ uint32_t state[8]; -+ uint64_t bitcount; -+ union { -+ uint8_t buffer[SHA256_BLOCK_LENGTH]; -+ uint64_t buffer64[SHA256_BLOCK_LENGTH / sizeof(uint64_t)]; // to avoid warnings about violating aliasing rules -+ }; -+} SHA256_CTX; -+ -+typedef struct _SHA512_CTX { -+ uint64_t state[8]; -+ uint64_t bitcount[2]; -+ union { -+ uint8_t buffer[SHA512_BLOCK_LENGTH]; -+ uint64_t buffer64[SHA512_BLOCK_LENGTH / sizeof(uint64_t)]; -+ }; -+} SHA512_CTX; -+ -+typedef SHA512_CTX SHA384_CTX; -+ -+/*** SHA-256/384/512 Function Prototypes ******************************/ -+ -+/* -+void SHA256_Init(SHA256_CTX *); -+void SHA256_Update(SHA256_CTX*, const u_int8_t*, size_t); -+void SHA256_Final(u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); -+char* SHA256_End(SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH]); -+char* SHA256_Data(const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH]); -+ -+void SHA384_Init(SHA384_CTX*); -+void SHA384_Update(SHA384_CTX*, const u_int8_t*, size_t); -+void SHA384_Final(u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); -+char* SHA384_End(SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH]); -+char* SHA384_Data(const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH]); -+ -+void SHA512_Init(SHA512_CTX*); -+void SHA512_Update(SHA512_CTX*, const u_int8_t*, size_t); -+void SHA512_Final(u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); -+char* SHA512_End(SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH]); -+char* SHA512_Data(const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH]); -+*/ -+ -+/* end of sha2.h */ -+ -+#define sha256_state SHA256_CTX -+#define sha384_state SHA384_CTX -+#define sha512_state SHA512_CTX -+ -+UTILAPI void sha256_init (sha256_state *state); -+UTILAPI void sha384_init (sha384_state *state); -+UTILAPI void sha512_init (sha512_state *state); -+ -+UTILAPI void sha256_add (sha256_state *state, const void *data, size_t size); -+UTILAPI void sha384_add (sha384_state *state, const void *data, size_t size); -+UTILAPI void sha512_add (sha512_state *state, const void *data, size_t size); -+ -+UTILAPI void sha256_put (sha256_state *state, uint8_t digest[SHA256_DIGEST_LENGTH]); -+UTILAPI void sha384_put (sha384_state *state, uint8_t digest[SHA384_DIGEST_LENGTH]); -+UTILAPI void sha512_put (sha512_state *state, uint8_t digest[SHA512_DIGEST_LENGTH]); -+ -+UTILAPI void sha256 (const void *data, size_t size, uint8_t digest[SHA256_DIGEST_LENGTH]); -+UTILAPI void sha384 (const void *data, size_t size, uint8_t digest[SHA384_DIGEST_LENGTH]); -+UTILAPI void sha512 (const void *data, size_t size, uint8_t digest[SHA512_DIGEST_LENGTH]); -+ -+UTILAPI void sha256init (void); -+UTILAPI void sha384init (void); -+UTILAPI void sha512init (void); -+ -+UTILAPI void sha256add (const void *data, size_t size); -+UTILAPI void sha384add (const void *data, size_t size); -+UTILAPI void sha512add (const void *data, size_t size); -+ -+UTILAPI void sha256put (uint8_t digest[SHA256_DIGEST_LENGTH]); -+UTILAPI void sha384put (uint8_t digest[SHA384_DIGEST_LENGTH]); -+UTILAPI void sha512put (uint8_t digest[SHA512_DIGEST_LENGTH]); -+ -+#endif -\ No newline at end of file -diff --git a/texk/web2c/luatexdir/luapplib/zlib/zconf.h b/texk/web2c/luatexdir/luapplib/zlib/zconf.h -new file mode 100644 -index 000000000..02ce56c43 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/zlib/zconf.h -@@ -0,0 +1,428 @@ -+/* zconf.h -- configuration of the zlib compression library -+ * Copyright (C) 1995-2010 Jean-loup Gailly. -+ * For conditions of distribution and use, see copyright notice in zlib.h -+ */ -+ -+/* @(#) $Id$ */ -+ -+#ifndef ZCONF_H -+#define ZCONF_H -+ -+/* -+ * If you *really* need a unique prefix for all types and library functions, -+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. -+ * Even better than compiling with -DZ_PREFIX would be to use configure to set -+ * this permanently in zconf.h using "./configure --zprefix". -+ */ -+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ -+ -+/* all linked symbols */ -+# define _dist_code z__dist_code -+# define _length_code z__length_code -+# define _tr_align z__tr_align -+# define _tr_flush_block z__tr_flush_block -+# define _tr_init z__tr_init -+# define _tr_stored_block z__tr_stored_block -+# define _tr_tally z__tr_tally -+# define adler32 z_adler32 -+# define adler32_combine z_adler32_combine -+# define adler32_combine64 z_adler32_combine64 -+# define compress z_compress -+# define compress2 z_compress2 -+# define compressBound z_compressBound -+# define crc32 z_crc32 -+# define crc32_combine z_crc32_combine -+# define crc32_combine64 z_crc32_combine64 -+# define deflate z_deflate -+# define deflateBound z_deflateBound -+# define deflateCopy z_deflateCopy -+# define deflateEnd z_deflateEnd -+# define deflateInit2_ z_deflateInit2_ -+# define deflateInit_ z_deflateInit_ -+# define deflateParams z_deflateParams -+# define deflatePrime z_deflatePrime -+# define deflateReset z_deflateReset -+# define deflateSetDictionary z_deflateSetDictionary -+# define deflateSetHeader z_deflateSetHeader -+# define deflateTune z_deflateTune -+# define deflate_copyright z_deflate_copyright -+# define get_crc_table z_get_crc_table -+# define gz_error z_gz_error -+# define gz_intmax z_gz_intmax -+# define gz_strwinerror z_gz_strwinerror -+# define gzbuffer z_gzbuffer -+# define gzclearerr z_gzclearerr -+# define gzclose z_gzclose -+# define gzclose_r z_gzclose_r -+# define gzclose_w z_gzclose_w -+# define gzdirect z_gzdirect -+# define gzdopen z_gzdopen -+# define gzeof z_gzeof -+# define gzerror z_gzerror -+# define gzflush z_gzflush -+# define gzgetc z_gzgetc -+# define gzgets z_gzgets -+# define gzoffset z_gzoffset -+# define gzoffset64 z_gzoffset64 -+# define gzopen z_gzopen -+# define gzopen64 z_gzopen64 -+# define gzprintf z_gzprintf -+# define gzputc z_gzputc -+# define gzputs z_gzputs -+# define gzread z_gzread -+# define gzrewind z_gzrewind -+# define gzseek z_gzseek -+# define gzseek64 z_gzseek64 -+# define gzsetparams z_gzsetparams -+# define gztell z_gztell -+# define gztell64 z_gztell64 -+# define gzungetc z_gzungetc -+# define gzwrite z_gzwrite -+# define inflate z_inflate -+# define inflateBack z_inflateBack -+# define inflateBackEnd z_inflateBackEnd -+# define inflateBackInit_ z_inflateBackInit_ -+# define inflateCopy z_inflateCopy -+# define inflateEnd z_inflateEnd -+# define inflateGetHeader z_inflateGetHeader -+# define inflateInit2_ z_inflateInit2_ -+# define inflateInit_ z_inflateInit_ -+# define inflateMark z_inflateMark -+# define inflatePrime z_inflatePrime -+# define inflateReset z_inflateReset -+# define inflateReset2 z_inflateReset2 -+# define inflateSetDictionary z_inflateSetDictionary -+# define inflateSync z_inflateSync -+# define inflateSyncPoint z_inflateSyncPoint -+# define inflateUndermine z_inflateUndermine -+# define inflate_copyright z_inflate_copyright -+# define inflate_fast z_inflate_fast -+# define inflate_table z_inflate_table -+# define uncompress z_uncompress -+# define zError z_zError -+# define zcalloc z_zcalloc -+# define zcfree z_zcfree -+# define zlibCompileFlags z_zlibCompileFlags -+# define zlibVersion z_zlibVersion -+ -+/* all zlib typedefs in zlib.h and zconf.h */ -+# define Byte z_Byte -+# define Bytef z_Bytef -+# define alloc_func z_alloc_func -+# define charf z_charf -+# define free_func z_free_func -+# define gzFile z_gzFile -+# define gz_header z_gz_header -+# define gz_headerp z_gz_headerp -+# define in_func z_in_func -+# define intf z_intf -+# define out_func z_out_func -+# define uInt z_uInt -+# define uIntf z_uIntf -+# define uLong z_uLong -+# define uLongf z_uLongf -+# define voidp z_voidp -+# define voidpc z_voidpc -+# define voidpf z_voidpf -+ -+/* all zlib structs in zlib.h and zconf.h */ -+# define gz_header_s z_gz_header_s -+# define internal_state z_internal_state -+ -+#endif -+ -+#if defined(__MSDOS__) && !defined(MSDOS) -+# define MSDOS -+#endif -+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -+# define OS2 -+#endif -+#if defined(_WINDOWS) && !defined(WINDOWS) -+# define WINDOWS -+#endif -+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -+# ifndef WIN32 -+# define WIN32 -+# endif -+#endif -+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -+# ifndef SYS16BIT -+# define SYS16BIT -+# endif -+# endif -+#endif -+ -+/* -+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more -+ * than 64k bytes at a time (needed on systems with 16-bit int). -+ */ -+#ifdef SYS16BIT -+# define MAXSEG_64K -+#endif -+#ifdef MSDOS -+# define UNALIGNED_OK -+#endif -+ -+#ifdef __STDC_VERSION__ -+# ifndef STDC -+# define STDC -+# endif -+# if __STDC_VERSION__ >= 199901L -+# ifndef STDC99 -+# define STDC99 -+# endif -+# endif -+#endif -+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -+# define STDC -+#endif -+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -+# define STDC -+#endif -+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -+# define STDC -+#endif -+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -+# define STDC -+#endif -+ -+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -+# define STDC -+#endif -+ -+#ifndef STDC -+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -+# define const /* note: need a more gentle solution here */ -+# endif -+#endif -+ -+/* Some Mac compilers merge all .h files incorrectly: */ -+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -+# define NO_DUMMY_DECL -+#endif -+ -+/* Maximum value for memLevel in deflateInit2 */ -+#ifndef MAX_MEM_LEVEL -+# ifdef MAXSEG_64K -+# define MAX_MEM_LEVEL 8 -+# else -+# define MAX_MEM_LEVEL 9 -+# endif -+#endif -+ -+/* Maximum value for windowBits in deflateInit2 and inflateInit2. -+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files -+ * created by gzip. (Files created by minigzip can still be extracted by -+ * gzip.) -+ */ -+#ifndef MAX_WBITS -+# define MAX_WBITS 15 /* 32K LZ77 window */ -+#endif -+ -+/* The memory requirements for deflate are (in bytes): -+ (1 << (windowBits+2)) + (1 << (memLevel+9)) -+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) -+ plus a few kilobytes for small objects. For example, if you want to reduce -+ the default memory requirements from 256K to 128K, compile with -+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" -+ Of course this will generally degrade compression (there's no free lunch). -+ -+ The memory requirements for inflate are (in bytes) 1 << windowBits -+ that is, 32K for windowBits=15 (default value) plus a few kilobytes -+ for small objects. -+*/ -+ -+ /* Type declarations */ -+ -+#ifndef OF /* function prototypes */ -+# ifdef STDC -+# define OF(args) args -+# else -+# define OF(args) () -+# endif -+#endif -+ -+/* The following definitions for FAR are needed only for MSDOS mixed -+ * model programming (small or medium model with some far allocations). -+ * This was tested only with MSC; for other MSDOS compilers you may have -+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, -+ * just define FAR to be empty. -+ */ -+#ifdef SYS16BIT -+# if defined(M_I86SM) || defined(M_I86MM) -+ /* MSC small or medium model */ -+# define SMALL_MEDIUM -+# ifdef _MSC_VER -+# define FAR _far -+# else -+# define FAR far -+# endif -+# endif -+# if (defined(__SMALL__) || defined(__MEDIUM__)) -+ /* Turbo C small or medium model */ -+# define SMALL_MEDIUM -+# ifdef __BORLANDC__ -+# define FAR _far -+# else -+# define FAR far -+# endif -+# endif -+#endif -+ -+#if defined(WINDOWS) || defined(WIN32) -+ /* If building or using zlib as a DLL, define ZLIB_DLL. -+ * This is not mandatory, but it offers a little performance increase. -+ */ -+# ifdef ZLIB_DLL -+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -+# ifdef ZLIB_INTERNAL -+# define ZEXTERN extern __declspec(dllexport) -+# else -+# define ZEXTERN extern __declspec(dllimport) -+# endif -+# endif -+# endif /* ZLIB_DLL */ -+ /* If building or using zlib with the WINAPI/WINAPIV calling convention, -+ * define ZLIB_WINAPI. -+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. -+ */ -+# ifdef ZLIB_WINAPI -+# ifdef FAR -+# undef FAR -+# endif -+# include -+ /* No need for _export, use ZLIB.DEF instead. */ -+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -+# define ZEXPORT WINAPI -+# ifdef WIN32 -+# define ZEXPORTVA WINAPIV -+# else -+# define ZEXPORTVA FAR CDECL -+# endif -+# endif -+#endif -+ -+#if defined (__BEOS__) -+# ifdef ZLIB_DLL -+# ifdef ZLIB_INTERNAL -+# define ZEXPORT __declspec(dllexport) -+# define ZEXPORTVA __declspec(dllexport) -+# else -+# define ZEXPORT __declspec(dllimport) -+# define ZEXPORTVA __declspec(dllimport) -+# endif -+# endif -+#endif -+ -+#ifndef ZEXTERN -+# define ZEXTERN extern -+#endif -+#ifndef ZEXPORT -+# define ZEXPORT -+#endif -+#ifndef ZEXPORTVA -+# define ZEXPORTVA -+#endif -+ -+#ifndef FAR -+# define FAR -+#endif -+ -+#if !defined(__MACTYPES__) -+typedef unsigned char Byte; /* 8 bits */ -+#endif -+typedef unsigned int uInt; /* 16 bits or more */ -+typedef unsigned long uLong; /* 32 bits or more */ -+ -+#ifdef SMALL_MEDIUM -+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -+# define Bytef Byte FAR -+#else -+ typedef Byte FAR Bytef; -+#endif -+typedef char FAR charf; -+typedef int FAR intf; -+typedef uInt FAR uIntf; -+typedef uLong FAR uLongf; -+ -+#ifdef STDC -+ typedef void const *voidpc; -+ typedef void FAR *voidpf; -+ typedef void *voidp; -+#else -+ typedef Byte const *voidpc; -+ typedef Byte FAR *voidpf; -+ typedef Byte *voidp; -+#endif -+ -+#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ -+# define Z_HAVE_UNISTD_H -+#endif -+ -+#ifdef STDC -+# include /* for off_t */ -+#endif -+ -+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and -+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even -+ * though the former does not conform to the LFS document), but considering -+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as -+ * equivalently requesting no 64-bit operations -+ */ -+#if -_LARGEFILE64_SOURCE - -1 == 1 -+# undef _LARGEFILE64_SOURCE -+#endif -+ -+#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -+# include /* for SEEK_* and off_t */ -+# ifdef VMS -+# include /* for off_t */ -+# endif -+# ifndef z_off_t -+# define z_off_t off_t -+# endif -+#endif -+ -+#ifndef SEEK_SET -+# define SEEK_SET 0 /* Seek from beginning of file. */ -+# define SEEK_CUR 1 /* Seek from current position. */ -+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -+#endif -+ -+#ifndef z_off_t -+# define z_off_t long -+#endif -+ -+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 -+# define z_off64_t off64_t -+#else -+# define z_off64_t z_off_t -+#endif -+ -+#if defined(__OS400__) -+# define NO_vsnprintf -+#endif -+ -+#if defined(__MVS__) -+# define NO_vsnprintf -+#endif -+ -+/* MVS linker does not support external names larger than 8 bytes */ -+#if defined(__MVS__) -+ #pragma map(deflateInit_,"DEIN") -+ #pragma map(deflateInit2_,"DEIN2") -+ #pragma map(deflateEnd,"DEEND") -+ #pragma map(deflateBound,"DEBND") -+ #pragma map(inflateInit_,"ININ") -+ #pragma map(inflateInit2_,"ININ2") -+ #pragma map(inflateEnd,"INEND") -+ #pragma map(inflateSync,"INSY") -+ #pragma map(inflateSetDictionary,"INSEDI") -+ #pragma map(compressBound,"CMBND") -+ #pragma map(inflate_table,"INTABL") -+ #pragma map(inflate_fast,"INFA") -+ #pragma map(inflate_copyright,"INCOPY") -+#endif -+ -+#endif /* ZCONF_H */ -diff --git a/texk/web2c/luatexdir/luapplib/zlib/zlib.h b/texk/web2c/luatexdir/luapplib/zlib/zlib.h -new file mode 100644 -index 000000000..bfbba83e8 ---- /dev/null -+++ b/texk/web2c/luatexdir/luapplib/zlib/zlib.h -@@ -0,0 +1,1613 @@ -+/* zlib.h -- interface of the 'zlib' general purpose compression library -+ version 1.2.5, April 19th, 2010 -+ -+ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler -+ -+ This software is provided 'as-is', without any express or implied -+ warranty. In no event will the authors be held liable for any damages -+ arising from the use of this software. -+ -+ Permission is granted to anyone to use this software for any purpose, -+ including commercial applications, and to alter it and redistribute it -+ freely, subject to the following restrictions: -+ -+ 1. The origin of this software must not be misrepresented; you must not -+ claim that you wrote the original software. If you use this software -+ in a product, an acknowledgment in the product documentation would be -+ appreciated but is not required. -+ 2. Altered source versions must be plainly marked as such, and must not be -+ misrepresented as being the original software. -+ 3. This notice may not be removed or altered from any source distribution. -+ -+ Jean-loup Gailly Mark Adler -+ jloup@gzip.org madler@alumni.caltech.edu -+ -+ -+ The data format used by the zlib library is described by RFCs (Request for -+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt -+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -+*/ -+ -+#ifndef ZLIB_H -+#define ZLIB_H -+ -+#include "zconf.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#define ZLIB_VERSION "1.2.5" -+#define ZLIB_VERNUM 0x1250 -+#define ZLIB_VER_MAJOR 1 -+#define ZLIB_VER_MINOR 2 -+#define ZLIB_VER_REVISION 5 -+#define ZLIB_VER_SUBREVISION 0 -+ -+/* -+ The 'zlib' compression library provides in-memory compression and -+ decompression functions, including integrity checks of the uncompressed data. -+ This version of the library supports only one compression method (deflation) -+ but other algorithms will be added later and will have the same stream -+ interface. -+ -+ Compression can be done in a single step if the buffers are large enough, -+ or can be done by repeated calls of the compression function. In the latter -+ case, the application must provide more input and/or consume the output -+ (providing more output space) before each call. -+ -+ The compressed data format used by default by the in-memory functions is -+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped -+ around a deflate stream, which is itself documented in RFC 1951. -+ -+ The library also supports reading and writing files in gzip (.gz) format -+ with an interface similar to that of stdio using the functions that start -+ with "gz". The gzip format is different from the zlib format. gzip is a -+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. -+ -+ This library can optionally read and write gzip streams in memory as well. -+ -+ The zlib format was designed to be compact and fast for use in memory -+ and on communications channels. The gzip format was designed for single- -+ file compression on file systems, has a larger header than zlib to maintain -+ directory information, and uses a different, slower check method than zlib. -+ -+ The library does not install any signal handler. The decoder checks -+ the consistency of the compressed data, so the library should never crash -+ even in case of corrupted input. -+*/ -+ -+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -+typedef void (*free_func) OF((voidpf opaque, voidpf address)); -+ -+struct internal_state; -+ -+typedef struct z_stream_s { -+ Bytef *next_in; /* next input byte */ -+ uInt avail_in; /* number of bytes available at next_in */ -+ uLong total_in; /* total nb of input bytes read so far */ -+ -+ Bytef *next_out; /* next output byte should be put there */ -+ uInt avail_out; /* remaining free space at next_out */ -+ uLong total_out; /* total nb of bytes output so far */ -+ -+ char *msg; /* last error message, NULL if no error */ -+ struct internal_state FAR *state; /* not visible by applications */ -+ -+ alloc_func zalloc; /* used to allocate the internal state */ -+ free_func zfree; /* used to free the internal state */ -+ voidpf opaque; /* private data object passed to zalloc and zfree */ -+ -+ int data_type; /* best guess about the data type: binary or text */ -+ uLong adler; /* adler32 value of the uncompressed data */ -+ uLong reserved; /* reserved for future use */ -+} z_stream; -+ -+typedef z_stream FAR *z_streamp; -+ -+/* -+ gzip header information passed to and from zlib routines. See RFC 1952 -+ for more details on the meanings of these fields. -+*/ -+typedef struct gz_header_s { -+ int text; /* true if compressed data believed to be text */ -+ uLong time; /* modification time */ -+ int xflags; /* extra flags (not used when writing a gzip file) */ -+ int os; /* operating system */ -+ Bytef *extra; /* pointer to extra field or Z_NULL if none */ -+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ -+ uInt extra_max; /* space at extra (only when reading header) */ -+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ -+ uInt name_max; /* space at name (only when reading header) */ -+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ -+ uInt comm_max; /* space at comment (only when reading header) */ -+ int hcrc; /* true if there was or will be a header crc */ -+ int done; /* true when done reading gzip header (not used -+ when writing a gzip file) */ -+} gz_header; -+ -+typedef gz_header FAR *gz_headerp; -+ -+/* -+ The application must update next_in and avail_in when avail_in has dropped -+ to zero. It must update next_out and avail_out when avail_out has dropped -+ to zero. The application must initialize zalloc, zfree and opaque before -+ calling the init function. All other fields are set by the compression -+ library and must not be updated by the application. -+ -+ The opaque value provided by the application will be passed as the first -+ parameter for calls of zalloc and zfree. This can be useful for custom -+ memory management. The compression library attaches no meaning to the -+ opaque value. -+ -+ zalloc must return Z_NULL if there is not enough memory for the object. -+ If zlib is used in a multi-threaded application, zalloc and zfree must be -+ thread safe. -+ -+ On 16-bit systems, the functions zalloc and zfree must be able to allocate -+ exactly 65536 bytes, but will not be required to allocate more than this if -+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers -+ returned by zalloc for objects of exactly 65536 bytes *must* have their -+ offset normalized to zero. The default allocation function provided by this -+ library ensures this (see zutil.c). To reduce memory requirements and avoid -+ any allocation of 64K objects, at the expense of compression ratio, compile -+ the library with -DMAX_WBITS=14 (see zconf.h). -+ -+ The fields total_in and total_out can be used for statistics or progress -+ reports. After compression, total_in holds the total size of the -+ uncompressed data and may be saved for use in the decompressor (particularly -+ if the decompressor wants to decompress everything in a single step). -+*/ -+ -+ /* constants */ -+ -+#define Z_NO_FLUSH 0 -+#define Z_PARTIAL_FLUSH 1 -+#define Z_SYNC_FLUSH 2 -+#define Z_FULL_FLUSH 3 -+#define Z_FINISH 4 -+#define Z_BLOCK 5 -+#define Z_TREES 6 -+/* Allowed flush values; see deflate() and inflate() below for details */ -+ -+#define Z_OK 0 -+#define Z_STREAM_END 1 -+#define Z_NEED_DICT 2 -+#define Z_ERRNO (-1) -+#define Z_STREAM_ERROR (-2) -+#define Z_DATA_ERROR (-3) -+#define Z_MEM_ERROR (-4) -+#define Z_BUF_ERROR (-5) -+#define Z_VERSION_ERROR (-6) -+/* Return codes for the compression/decompression functions. Negative values -+ * are errors, positive values are used for special but normal events. -+ */ -+ -+#define Z_NO_COMPRESSION 0 -+#define Z_BEST_SPEED 1 -+#define Z_BEST_COMPRESSION 9 -+#define Z_DEFAULT_COMPRESSION (-1) -+/* compression levels */ -+ -+#define Z_FILTERED 1 -+#define Z_HUFFMAN_ONLY 2 -+#define Z_RLE 3 -+#define Z_FIXED 4 -+#define Z_DEFAULT_STRATEGY 0 -+/* compression strategy; see deflateInit2() below for details */ -+ -+#define Z_BINARY 0 -+#define Z_TEXT 1 -+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -+#define Z_UNKNOWN 2 -+/* Possible values of the data_type field (though see inflate()) */ -+ -+#define Z_DEFLATED 8 -+/* The deflate compression method (the only one supported in this version) */ -+ -+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ -+ -+#define zlib_version zlibVersion() -+/* for compatibility with versions < 1.0.2 */ -+ -+ -+ /* basic functions */ -+ -+ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -+/* The application can compare zlibVersion and ZLIB_VERSION for consistency. -+ If the first character differs, the library code actually used is not -+ compatible with the zlib.h header file used by the application. This check -+ is automatically made by deflateInit and inflateInit. -+ */ -+ -+/* -+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); -+ -+ Initializes the internal stream state for compression. The fields -+ zalloc, zfree and opaque must be initialized before by the caller. If -+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default -+ allocation functions. -+ -+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: -+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all -+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION -+ requests a default compromise between speed and compression (currently -+ equivalent to level 6). -+ -+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough -+ memory, Z_STREAM_ERROR if level is not a valid compression level, or -+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible -+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null -+ if there is no error message. deflateInit does not perform any compression: -+ this will be done by deflate(). -+*/ -+ -+ -+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -+/* -+ deflate compresses as much data as possible, and stops when the input -+ buffer becomes empty or the output buffer becomes full. It may introduce -+ some output latency (reading input without producing any output) except when -+ forced to flush. -+ -+ The detailed semantics are as follows. deflate performs one or both of the -+ following actions: -+ -+ - Compress more input starting at next_in and update next_in and avail_in -+ accordingly. If not all input can be processed (because there is not -+ enough room in the output buffer), next_in and avail_in are updated and -+ processing will resume at this point for the next call of deflate(). -+ -+ - Provide more output starting at next_out and update next_out and avail_out -+ accordingly. This action is forced if the parameter flush is non zero. -+ Forcing flush frequently degrades the compression ratio, so this parameter -+ should be set only when necessary (in interactive applications). Some -+ output may be provided even if flush is not set. -+ -+ Before the call of deflate(), the application should ensure that at least -+ one of the actions is possible, by providing more input and/or consuming more -+ output, and updating avail_in or avail_out accordingly; avail_out should -+ never be zero before the call. The application can consume the compressed -+ output when it wants, for example when the output buffer is full (avail_out -+ == 0), or after each call of deflate(). If deflate returns Z_OK and with -+ zero avail_out, it must be called again after making room in the output -+ buffer because there might be more output pending. -+ -+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to -+ decide how much data to accumulate before producing output, in order to -+ maximize compression. -+ -+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is -+ flushed to the output buffer and the output is aligned on a byte boundary, so -+ that the decompressor can get all input data available so far. (In -+ particular avail_in is zero after the call if enough output space has been -+ provided before the call.) Flushing may degrade compression for some -+ compression algorithms and so it should be used only when necessary. This -+ completes the current deflate block and follows it with an empty stored block -+ that is three bits plus filler bits to the next byte, followed by four bytes -+ (00 00 ff ff). -+ -+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the -+ output buffer, but the output is not aligned to a byte boundary. All of the -+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. -+ This completes the current deflate block and follows it with an empty fixed -+ codes block that is 10 bits long. This assures that enough bytes are output -+ in order for the decompressor to finish the block before the empty fixed code -+ block. -+ -+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as -+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to -+ seven bits of the current block are held to be written as the next byte after -+ the next deflate block is completed. In this case, the decompressor may not -+ be provided enough bits at this point in order to complete decompression of -+ the data provided so far to the compressor. It may need to wait for the next -+ block to be emitted. This is for advanced applications that need to control -+ the emission of deflate blocks. -+ -+ If flush is set to Z_FULL_FLUSH, all output is flushed as with -+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can -+ restart from this point if previous compressed data has been damaged or if -+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade -+ compression. -+ -+ If deflate returns with avail_out == 0, this function must be called again -+ with the same value of the flush parameter and more output space (updated -+ avail_out), until the flush is complete (deflate returns with non-zero -+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that -+ avail_out is greater than six to avoid repeated flush markers due to -+ avail_out == 0 on return. -+ -+ If the parameter flush is set to Z_FINISH, pending input is processed, -+ pending output is flushed and deflate returns with Z_STREAM_END if there was -+ enough output space; if deflate returns with Z_OK, this function must be -+ called again with Z_FINISH and more output space (updated avail_out) but no -+ more input data, until it returns with Z_STREAM_END or an error. After -+ deflate has returned Z_STREAM_END, the only possible operations on the stream -+ are deflateReset or deflateEnd. -+ -+ Z_FINISH can be used immediately after deflateInit if all the compression -+ is to be done in a single step. In this case, avail_out must be at least the -+ value returned by deflateBound (see below). If deflate does not return -+ Z_STREAM_END, then it must be called again as described above. -+ -+ deflate() sets strm->adler to the adler32 checksum of all input read -+ so far (that is, total_in bytes). -+ -+ deflate() may update strm->data_type if it can make a good guess about -+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered -+ binary. This field is only for information purposes and does not affect the -+ compression algorithm in any manner. -+ -+ deflate() returns Z_OK if some progress has been made (more input -+ processed or more output produced), Z_STREAM_END if all input has been -+ consumed and all output has been produced (only when flush is set to -+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example -+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible -+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not -+ fatal, and deflate() can be called again with more input and more output -+ space to continue compressing. -+*/ -+ -+ -+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -+/* -+ All dynamically allocated data structures for this stream are freed. -+ This function discards any unprocessed input and does not flush any pending -+ output. -+ -+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the -+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed -+ prematurely (some input or output was discarded). In the error case, msg -+ may be set but then points to a static string (which must not be -+ deallocated). -+*/ -+ -+ -+/* -+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); -+ -+ Initializes the internal stream state for decompression. The fields -+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by -+ the caller. If next_in is not Z_NULL and avail_in is large enough (the -+ exact value depends on the compression method), inflateInit determines the -+ compression method from the zlib header and allocates all data structures -+ accordingly; otherwise the allocation will be deferred to the first call of -+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to -+ use default allocation functions. -+ -+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough -+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the -+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are -+ invalid, such as a null pointer to the structure. msg is set to null if -+ there is no error message. inflateInit does not perform any decompression -+ apart from possibly reading the zlib header if present: actual decompression -+ will be done by inflate(). (So next_in and avail_in may be modified, but -+ next_out and avail_out are unused and unchanged.) The current implementation -+ of inflateInit() does not process any header information -- that is deferred -+ until inflate() is called. -+*/ -+ -+ -+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -+/* -+ inflate decompresses as much data as possible, and stops when the input -+ buffer becomes empty or the output buffer becomes full. It may introduce -+ some output latency (reading input without producing any output) except when -+ forced to flush. -+ -+ The detailed semantics are as follows. inflate performs one or both of the -+ following actions: -+ -+ - Decompress more input starting at next_in and update next_in and avail_in -+ accordingly. If not all input can be processed (because there is not -+ enough room in the output buffer), next_in is updated and processing will -+ resume at this point for the next call of inflate(). -+ -+ - Provide more output starting at next_out and update next_out and avail_out -+ accordingly. inflate() provides as much output as possible, until there is -+ no more input data or no more space in the output buffer (see below about -+ the flush parameter). -+ -+ Before the call of inflate(), the application should ensure that at least -+ one of the actions is possible, by providing more input and/or consuming more -+ output, and updating the next_* and avail_* values accordingly. The -+ application can consume the uncompressed output when it wants, for example -+ when the output buffer is full (avail_out == 0), or after each call of -+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be -+ called again after making room in the output buffer because there might be -+ more output pending. -+ -+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, -+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much -+ output as possible to the output buffer. Z_BLOCK requests that inflate() -+ stop if and when it gets to the next deflate block boundary. When decoding -+ the zlib or gzip format, this will cause inflate() to return immediately -+ after the header and before the first block. When doing a raw inflate, -+ inflate() will go ahead and process the first block, and will return when it -+ gets to the end of that block, or when it runs out of data. -+ -+ The Z_BLOCK option assists in appending to or combining deflate streams. -+ Also to assist in this, on return inflate() will set strm->data_type to the -+ number of unused bits in the last byte taken from strm->next_in, plus 64 if -+ inflate() is currently decoding the last block in the deflate stream, plus -+ 128 if inflate() returned immediately after decoding an end-of-block code or -+ decoding the complete header up to just before the first byte of the deflate -+ stream. The end-of-block will not be indicated until all of the uncompressed -+ data from that block has been written to strm->next_out. The number of -+ unused bits may in general be greater than seven, except when bit 7 of -+ data_type is set, in which case the number of unused bits will be less than -+ eight. data_type is set as noted here every time inflate() returns for all -+ flush options, and so can be used to determine the amount of currently -+ consumed input in bits. -+ -+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the -+ end of each deflate block header is reached, before any actual data in that -+ block is decoded. This allows the caller to determine the length of the -+ deflate block header for later use in random access within a deflate block. -+ 256 is added to the value of strm->data_type when inflate() returns -+ immediately after reaching the end of the deflate block header. -+ -+ inflate() should normally be called until it returns Z_STREAM_END or an -+ error. However if all decompression is to be performed in a single step (a -+ single call of inflate), the parameter flush should be set to Z_FINISH. In -+ this case all pending input is processed and all pending output is flushed; -+ avail_out must be large enough to hold all the uncompressed data. (The size -+ of the uncompressed data may have been saved by the compressor for this -+ purpose.) The next operation on this stream must be inflateEnd to deallocate -+ the decompression state. The use of Z_FINISH is never required, but can be -+ used to inform inflate that a faster approach may be used for the single -+ inflate() call. -+ -+ In this implementation, inflate() always flushes as much output as -+ possible to the output buffer, and always uses the faster approach on the -+ first call. So the only effect of the flush parameter in this implementation -+ is on the return value of inflate(), as noted below, or when it returns early -+ because Z_BLOCK or Z_TREES is used. -+ -+ If a preset dictionary is needed after this call (see inflateSetDictionary -+ below), inflate sets strm->adler to the adler32 checksum of the dictionary -+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets -+ strm->adler to the adler32 checksum of all output produced so far (that is, -+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described -+ below. At the end of the stream, inflate() checks that its computed adler32 -+ checksum is equal to that saved by the compressor and returns Z_STREAM_END -+ only if the checksum is correct. -+ -+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped -+ deflate data. The header type is detected automatically, if requested when -+ initializing with inflateInit2(). Any information contained in the gzip -+ header is not retained, so applications that need that information should -+ instead use raw inflate, see inflateInit2() below, or inflateBack() and -+ perform their own processing of the gzip header and trailer. -+ -+ inflate() returns Z_OK if some progress has been made (more input processed -+ or more output produced), Z_STREAM_END if the end of the compressed data has -+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a -+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was -+ corrupted (input stream not conforming to the zlib format or incorrect check -+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example -+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, -+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the -+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and -+ inflate() can be called again with more input and more output space to -+ continue decompressing. If Z_DATA_ERROR is returned, the application may -+ then call inflateSync() to look for a good compression block if a partial -+ recovery of the data is desired. -+*/ -+ -+ -+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -+/* -+ All dynamically allocated data structures for this stream are freed. -+ This function discards any unprocessed input and does not flush any pending -+ output. -+ -+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state -+ was inconsistent. In the error case, msg may be set but then points to a -+ static string (which must not be deallocated). -+*/ -+ -+ -+ /* Advanced functions */ -+ -+/* -+ The following functions are needed only in some special applications. -+*/ -+ -+/* -+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, -+ int level, -+ int method, -+ int windowBits, -+ int memLevel, -+ int strategy)); -+ -+ This is another version of deflateInit with more compression options. The -+ fields next_in, zalloc, zfree and opaque must be initialized before by the -+ caller. -+ -+ The method parameter is the compression method. It must be Z_DEFLATED in -+ this version of the library. -+ -+ The windowBits parameter is the base two logarithm of the window size -+ (the size of the history buffer). It should be in the range 8..15 for this -+ version of the library. Larger values of this parameter result in better -+ compression at the expense of memory usage. The default value is 15 if -+ deflateInit is used instead. -+ -+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits -+ determines the window size. deflate() will then generate raw deflate data -+ with no zlib header or trailer, and will not compute an adler32 check value. -+ -+ windowBits can also be greater than 15 for optional gzip encoding. Add -+ 16 to windowBits to write a simple gzip header and trailer around the -+ compressed data instead of a zlib wrapper. The gzip header will have no -+ file name, no extra data, no comment, no modification time (set to zero), no -+ header crc, and the operating system will be set to 255 (unknown). If a -+ gzip stream is being written, strm->adler is a crc32 instead of an adler32. -+ -+ The memLevel parameter specifies how much memory should be allocated -+ for the internal compression state. memLevel=1 uses minimum memory but is -+ slow and reduces compression ratio; memLevel=9 uses maximum memory for -+ optimal speed. The default value is 8. See zconf.h for total memory usage -+ as a function of windowBits and memLevel. -+ -+ The strategy parameter is used to tune the compression algorithm. Use the -+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a -+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no -+ string match), or Z_RLE to limit match distances to one (run-length -+ encoding). Filtered data consists mostly of small values with a somewhat -+ random distribution. In this case, the compression algorithm is tuned to -+ compress them better. The effect of Z_FILTERED is to force more Huffman -+ coding and less string matching; it is somewhat intermediate between -+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as -+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The -+ strategy parameter only affects the compression ratio but not the -+ correctness of the compressed output even if it is not set appropriately. -+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler -+ decoder for special applications. -+ -+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough -+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid -+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is -+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is -+ set to null if there is no error message. deflateInit2 does not perform any -+ compression: this will be done by deflate(). -+*/ -+ -+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, -+ const Bytef *dictionary, -+ uInt dictLength)); -+/* -+ Initializes the compression dictionary from the given byte sequence -+ without producing any compressed output. This function must be called -+ immediately after deflateInit, deflateInit2 or deflateReset, before any call -+ of deflate. The compressor and decompressor must use exactly the same -+ dictionary (see inflateSetDictionary). -+ -+ The dictionary should consist of strings (byte sequences) that are likely -+ to be encountered later in the data to be compressed, with the most commonly -+ used strings preferably put towards the end of the dictionary. Using a -+ dictionary is most useful when the data to be compressed is short and can be -+ predicted with good accuracy; the data can then be compressed better than -+ with the default empty dictionary. -+ -+ Depending on the size of the compression data structures selected by -+ deflateInit or deflateInit2, a part of the dictionary may in effect be -+ discarded, for example if the dictionary is larger than the window size -+ provided in deflateInit or deflateInit2. Thus the strings most likely to be -+ useful should be put at the end of the dictionary, not at the front. In -+ addition, the current implementation of deflate will use at most the window -+ size minus 262 bytes of the provided dictionary. -+ -+ Upon return of this function, strm->adler is set to the adler32 value -+ of the dictionary; the decompressor may later use this value to determine -+ which dictionary has been used by the compressor. (The adler32 value -+ applies to the whole dictionary even if only a subset of the dictionary is -+ actually used by the compressor.) If a raw deflate was requested, then the -+ adler32 value is not computed and strm->adler is not set. -+ -+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a -+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is -+ inconsistent (for example if deflate has already been called for this stream -+ or if the compression method is bsort). deflateSetDictionary does not -+ perform any compression: this will be done by deflate(). -+*/ -+ -+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, -+ z_streamp source)); -+/* -+ Sets the destination stream as a complete copy of the source stream. -+ -+ This function can be useful when several compression strategies will be -+ tried, for example when there are several ways of pre-processing the input -+ data with a filter. The streams that will be discarded should then be freed -+ by calling deflateEnd. Note that deflateCopy duplicates the internal -+ compression state which can be quite large, so this strategy is slow and can -+ consume lots of memory. -+ -+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not -+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent -+ (such as zalloc being Z_NULL). msg is left unchanged in both source and -+ destination. -+*/ -+ -+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -+/* -+ This function is equivalent to deflateEnd followed by deflateInit, -+ but does not free and reallocate all the internal compression state. The -+ stream will keep the same compression level and any other attributes that -+ may have been set by deflateInit2. -+ -+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent (such as zalloc or state being Z_NULL). -+*/ -+ -+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, -+ int level, -+ int strategy)); -+/* -+ Dynamically update the compression level and compression strategy. The -+ interpretation of level and strategy is as in deflateInit2. This can be -+ used to switch between compression and straight copy of the input data, or -+ to switch to a different kind of input data requiring a different strategy. -+ If the compression level is changed, the input available so far is -+ compressed with the old level (and may be flushed); the new level will take -+ effect only at the next call of deflate(). -+ -+ Before the call of deflateParams, the stream state must be set as for -+ a call of deflate(), since the currently available input may have to be -+ compressed and flushed. In particular, strm->avail_out must be non-zero. -+ -+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source -+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if -+ strm->avail_out was zero. -+*/ -+ -+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, -+ int good_length, -+ int max_lazy, -+ int nice_length, -+ int max_chain)); -+/* -+ Fine tune deflate's internal compression parameters. This should only be -+ used by someone who understands the algorithm used by zlib's deflate for -+ searching for the best matching string, and even then only by the most -+ fanatic optimizer trying to squeeze out the last compressed bit for their -+ specific input data. Read the deflate.c source code for the meaning of the -+ max_lazy, good_length, nice_length, and max_chain parameters. -+ -+ deflateTune() can be called after deflateInit() or deflateInit2(), and -+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. -+ */ -+ -+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, -+ uLong sourceLen)); -+/* -+ deflateBound() returns an upper bound on the compressed size after -+ deflation of sourceLen bytes. It must be called after deflateInit() or -+ deflateInit2(), and after deflateSetHeader(), if used. This would be used -+ to allocate an output buffer for deflation in a single pass, and so would be -+ called before deflate(). -+*/ -+ -+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, -+ int bits, -+ int value)); -+/* -+ deflatePrime() inserts bits in the deflate output stream. The intent -+ is that this function is used to start off the deflate output with the bits -+ leftover from a previous deflate stream when appending to it. As such, this -+ function can only be used for raw deflate, and must be used before the first -+ deflate() call after a deflateInit2() or deflateReset(). bits must be less -+ than or equal to 16, and that many of the least significant bits of value -+ will be inserted in the output. -+ -+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent. -+*/ -+ -+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, -+ gz_headerp head)); -+/* -+ deflateSetHeader() provides gzip header information for when a gzip -+ stream is requested by deflateInit2(). deflateSetHeader() may be called -+ after deflateInit2() or deflateReset() and before the first call of -+ deflate(). The text, time, os, extra field, name, and comment information -+ in the provided gz_header structure are written to the gzip header (xflag is -+ ignored -- the extra flags are set according to the compression level). The -+ caller must assure that, if not Z_NULL, name and comment are terminated with -+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are -+ available there. If hcrc is true, a gzip header crc is included. Note that -+ the current versions of the command-line version of gzip (up through version -+ 1.3.x) do not support header crc's, and will report that it is a "multi-part -+ gzip file" and give up. -+ -+ If deflateSetHeader is not used, the default gzip header has text false, -+ the time set to zero, and os set to 255, with no extra, name, or comment -+ fields. The gzip header is returned to the default state by deflateReset(). -+ -+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent. -+*/ -+ -+/* -+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, -+ int windowBits)); -+ -+ This is another version of inflateInit with an extra parameter. The -+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized -+ before by the caller. -+ -+ The windowBits parameter is the base two logarithm of the maximum window -+ size (the size of the history buffer). It should be in the range 8..15 for -+ this version of the library. The default value is 15 if inflateInit is used -+ instead. windowBits must be greater than or equal to the windowBits value -+ provided to deflateInit2() while compressing, or it must be equal to 15 if -+ deflateInit2() was not used. If a compressed stream with a larger window -+ size is given as input, inflate() will return with the error code -+ Z_DATA_ERROR instead of trying to allocate a larger window. -+ -+ windowBits can also be zero to request that inflate use the window size in -+ the zlib header of the compressed stream. -+ -+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits -+ determines the window size. inflate() will then process raw deflate data, -+ not looking for a zlib or gzip header, not generating a check value, and not -+ looking for any check values for comparison at the end of the stream. This -+ is for use with other formats that use the deflate compressed data format -+ such as zip. Those formats provide their own check values. If a custom -+ format is developed using the raw deflate format for compressed data, it is -+ recommended that a check value such as an adler32 or a crc32 be applied to -+ the uncompressed data as is done in the zlib, gzip, and zip formats. For -+ most applications, the zlib format should be used as is. Note that comments -+ above on the use in deflateInit2() applies to the magnitude of windowBits. -+ -+ windowBits can also be greater than 15 for optional gzip decoding. Add -+ 32 to windowBits to enable zlib and gzip decoding with automatic header -+ detection, or add 16 to decode only the gzip format (the zlib format will -+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a -+ crc32 instead of an adler32. -+ -+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough -+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the -+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are -+ invalid, such as a null pointer to the structure. msg is set to null if -+ there is no error message. inflateInit2 does not perform any decompression -+ apart from possibly reading the zlib header if present: actual decompression -+ will be done by inflate(). (So next_in and avail_in may be modified, but -+ next_out and avail_out are unused and unchanged.) The current implementation -+ of inflateInit2() does not process any header information -- that is -+ deferred until inflate() is called. -+*/ -+ -+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, -+ const Bytef *dictionary, -+ uInt dictLength)); -+/* -+ Initializes the decompression dictionary from the given uncompressed byte -+ sequence. This function must be called immediately after a call of inflate, -+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor -+ can be determined from the adler32 value returned by that call of inflate. -+ The compressor and decompressor must use exactly the same dictionary (see -+ deflateSetDictionary). For raw inflate, this function can be called -+ immediately after inflateInit2() or inflateReset() and before any call of -+ inflate() to set the dictionary. The application must insure that the -+ dictionary that was used for compression is provided. -+ -+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a -+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is -+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the -+ expected one (incorrect adler32 value). inflateSetDictionary does not -+ perform any decompression: this will be done by subsequent calls of -+ inflate(). -+*/ -+ -+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -+/* -+ Skips invalid compressed data until a full flush point (see above the -+ description of deflate with Z_FULL_FLUSH) can be found, or until all -+ available input is skipped. No output is provided. -+ -+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR -+ if no more input was provided, Z_DATA_ERROR if no flush point has been -+ found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the -+ success case, the application may save the current current value of total_in -+ which indicates where valid compressed data was found. In the error case, -+ the application may repeatedly call inflateSync, providing more input each -+ time, until success or end of the input data. -+*/ -+ -+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, -+ z_streamp source)); -+/* -+ Sets the destination stream as a complete copy of the source stream. -+ -+ This function can be useful when randomly accessing a large stream. The -+ first pass through the stream can periodically record the inflate state, -+ allowing restarting inflate at those points when randomly accessing the -+ stream. -+ -+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not -+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent -+ (such as zalloc being Z_NULL). msg is left unchanged in both source and -+ destination. -+*/ -+ -+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -+/* -+ This function is equivalent to inflateEnd followed by inflateInit, -+ but does not free and reallocate all the internal decompression state. The -+ stream will keep attributes that may have been set by inflateInit2. -+ -+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent (such as zalloc or state being Z_NULL). -+*/ -+ -+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, -+ int windowBits)); -+/* -+ This function is the same as inflateReset, but it also permits changing -+ the wrap and window size requests. The windowBits parameter is interpreted -+ the same as it is for inflateInit2. -+ -+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if -+ the windowBits parameter is invalid. -+*/ -+ -+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, -+ int bits, -+ int value)); -+/* -+ This function inserts bits in the inflate input stream. The intent is -+ that this function is used to start inflating at a bit position in the -+ middle of a byte. The provided bits will be used before any bytes are used -+ from next_in. This function should only be used with raw inflate, and -+ should be used before the first inflate() call after inflateInit2() or -+ inflateReset(). bits must be less than or equal to 16, and that many of the -+ least significant bits of value will be inserted in the input. -+ -+ If bits is negative, then the input stream bit buffer is emptied. Then -+ inflatePrime() can be called again to put bits in the buffer. This is used -+ to clear out bits leftover after feeding inflate a block description prior -+ to feeding inflate codes. -+ -+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent. -+*/ -+ -+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); -+/* -+ This function returns two values, one in the lower 16 bits of the return -+ value, and the other in the remaining upper bits, obtained by shifting the -+ return value down 16 bits. If the upper value is -1 and the lower value is -+ zero, then inflate() is currently decoding information outside of a block. -+ If the upper value is -1 and the lower value is non-zero, then inflate is in -+ the middle of a stored block, with the lower value equaling the number of -+ bytes from the input remaining to copy. If the upper value is not -1, then -+ it is the number of bits back from the current bit position in the input of -+ the code (literal or length/distance pair) currently being processed. In -+ that case the lower value is the number of bytes already emitted for that -+ code. -+ -+ A code is being processed if inflate is waiting for more input to complete -+ decoding of the code, or if it has completed decoding but is waiting for -+ more output space to write the literal or match data. -+ -+ inflateMark() is used to mark locations in the input data for random -+ access, which may be at bit positions, and to note those cases where the -+ output of a code may span boundaries of random access blocks. The current -+ location in the input stream can be determined from avail_in and data_type -+ as noted in the description for the Z_BLOCK flush parameter for inflate. -+ -+ inflateMark returns the value noted above or -1 << 16 if the provided -+ source stream state was inconsistent. -+*/ -+ -+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, -+ gz_headerp head)); -+/* -+ inflateGetHeader() requests that gzip header information be stored in the -+ provided gz_header structure. inflateGetHeader() may be called after -+ inflateInit2() or inflateReset(), and before the first call of inflate(). -+ As inflate() processes the gzip stream, head->done is zero until the header -+ is completed, at which time head->done is set to one. If a zlib stream is -+ being decoded, then head->done is set to -1 to indicate that there will be -+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be -+ used to force inflate() to return immediately after header processing is -+ complete and before any actual data is decompressed. -+ -+ The text, time, xflags, and os fields are filled in with the gzip header -+ contents. hcrc is set to true if there is a header CRC. (The header CRC -+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max -+ contains the maximum number of bytes to write to extra. Once done is true, -+ extra_len contains the actual extra field length, and extra contains the -+ extra field, or that field truncated if extra_max is less than extra_len. -+ If name is not Z_NULL, then up to name_max characters are written there, -+ terminated with a zero unless the length is greater than name_max. If -+ comment is not Z_NULL, then up to comm_max characters are written there, -+ terminated with a zero unless the length is greater than comm_max. When any -+ of extra, name, or comment are not Z_NULL and the respective field is not -+ present in the header, then that field is set to Z_NULL to signal its -+ absence. This allows the use of deflateSetHeader() with the returned -+ structure to duplicate the header. However if those fields are set to -+ allocated memory, then the application will need to save those pointers -+ elsewhere so that they can be eventually freed. -+ -+ If inflateGetHeader is not used, then the header information is simply -+ discarded. The header is always checked for validity, including the header -+ CRC if present. inflateReset() will reset the process to discard the header -+ information. The application would need to call inflateGetHeader() again to -+ retrieve the header from the next gzip stream. -+ -+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source -+ stream state was inconsistent. -+*/ -+ -+/* -+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, -+ unsigned char FAR *window)); -+ -+ Initialize the internal stream state for decompression using inflateBack() -+ calls. The fields zalloc, zfree and opaque in strm must be initialized -+ before the call. If zalloc and zfree are Z_NULL, then the default library- -+ derived memory allocation routines are used. windowBits is the base two -+ logarithm of the window size, in the range 8..15. window is a caller -+ supplied buffer of that size. Except for special applications where it is -+ assured that deflate was used with small window sizes, windowBits must be 15 -+ and a 32K byte window must be supplied to be able to decompress general -+ deflate streams. -+ -+ See inflateBack() for the usage of these routines. -+ -+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of -+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not be -+ allocated, or Z_VERSION_ERROR if the version of the library does not match -+ the version of the header file. -+*/ -+ -+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); -+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); -+ -+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, -+ in_func in, void FAR *in_desc, -+ out_func out, void FAR *out_desc)); -+/* -+ inflateBack() does a raw inflate with a single call using a call-back -+ interface for input and output. This is more efficient than inflate() for -+ file i/o applications in that it avoids copying between the output and the -+ sliding window by simply making the window itself the output buffer. This -+ function trusts the application to not change the output buffer passed by -+ the output function, at least until inflateBack() returns. -+ -+ inflateBackInit() must be called first to allocate the internal state -+ and to initialize the state with the user-provided window buffer. -+ inflateBack() may then be used multiple times to inflate a complete, raw -+ deflate stream with each call. inflateBackEnd() is then called to free the -+ allocated state. -+ -+ A raw deflate stream is one with no zlib or gzip header or trailer. -+ This routine would normally be used in a utility that reads zip or gzip -+ files and writes out uncompressed files. The utility would decode the -+ header and process the trailer on its own, hence this routine expects only -+ the raw deflate stream to decompress. This is different from the normal -+ behavior of inflate(), which expects either a zlib or gzip header and -+ trailer around the deflate stream. -+ -+ inflateBack() uses two subroutines supplied by the caller that are then -+ called by inflateBack() for input and output. inflateBack() calls those -+ routines until it reads a complete deflate stream and writes out all of the -+ uncompressed data, or until it encounters an error. The function's -+ parameters and return types are defined above in the in_func and out_func -+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the -+ number of bytes of provided input, and a pointer to that input in buf. If -+ there is no input available, in() must return zero--buf is ignored in that -+ case--and inflateBack() will return a buffer error. inflateBack() will call -+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() -+ should return zero on success, or non-zero on failure. If out() returns -+ non-zero, inflateBack() will return with an error. Neither in() nor out() -+ are permitted to change the contents of the window provided to -+ inflateBackInit(), which is also the buffer that out() uses to write from. -+ The length written by out() will be at most the window size. Any non-zero -+ amount of input may be provided by in(). -+ -+ For convenience, inflateBack() can be provided input on the first call by -+ setting strm->next_in and strm->avail_in. If that input is exhausted, then -+ in() will be called. Therefore strm->next_in must be initialized before -+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called -+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in -+ must also be initialized, and then if strm->avail_in is not zero, input will -+ initially be taken from strm->next_in[0 .. strm->avail_in - 1]. -+ -+ The in_desc and out_desc parameters of inflateBack() is passed as the -+ first parameter of in() and out() respectively when they are called. These -+ descriptors can be optionally used to pass any information that the caller- -+ supplied in() and out() functions need to do their job. -+ -+ On return, inflateBack() will set strm->next_in and strm->avail_in to -+ pass back any unused input that was provided by the last in() call. The -+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR -+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error -+ in the deflate stream (in which case strm->msg is set to indicate the nature -+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized. -+ In the case of Z_BUF_ERROR, an input or output error can be distinguished -+ using strm->next_in which will be Z_NULL only if in() returned an error. If -+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning -+ non-zero. (in() will always be called before out(), so strm->next_in is -+ assured to be defined if out() returns non-zero.) Note that inflateBack() -+ cannot return Z_OK. -+*/ -+ -+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -+/* -+ All memory allocated by inflateBackInit() is freed. -+ -+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream -+ state was inconsistent. -+*/ -+ -+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -+/* Return flags indicating compile-time options. -+ -+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: -+ 1.0: size of uInt -+ 3.2: size of uLong -+ 5.4: size of voidpf (pointer) -+ 7.6: size of z_off_t -+ -+ Compiler, assembler, and debug options: -+ 8: DEBUG -+ 9: ASMV or ASMINF -- use ASM code -+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention -+ 11: 0 (reserved) -+ -+ One-time table building (smaller code, but not thread-safe if true): -+ 12: BUILDFIXED -- build static block decoding tables when needed -+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed -+ 14,15: 0 (reserved) -+ -+ Library content (indicates missing functionality): -+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking -+ deflate code when not needed) -+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect -+ and decode gzip streams (to avoid linking crc code) -+ 18-19: 0 (reserved) -+ -+ Operation variations (changes in library functionality): -+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate -+ 21: FASTEST -- deflate algorithm with only one, lowest compression level -+ 22,23: 0 (reserved) -+ -+ The sprintf variant used by gzprintf (zero is best): -+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format -+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! -+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned -+ -+ Remainder: -+ 27-31: 0 (reserved) -+ */ -+ -+ -+ /* utility functions */ -+ -+/* -+ The following utility functions are implemented on top of the basic -+ stream-oriented functions. To simplify the interface, some default options -+ are assumed (compression level and memory usage, standard memory allocation -+ functions). The source code of these utility functions can be modified if -+ you need special options. -+*/ -+ -+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, -+ const Bytef *source, uLong sourceLen)); -+/* -+ Compresses the source buffer into the destination buffer. sourceLen is -+ the byte length of the source buffer. Upon entry, destLen is the total size -+ of the destination buffer, which must be at least the value returned by -+ compressBound(sourceLen). Upon exit, destLen is the actual size of the -+ compressed buffer. -+ -+ compress returns Z_OK if success, Z_MEM_ERROR if there was not -+ enough memory, Z_BUF_ERROR if there was not enough room in the output -+ buffer. -+*/ -+ -+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, -+ const Bytef *source, uLong sourceLen, -+ int level)); -+/* -+ Compresses the source buffer into the destination buffer. The level -+ parameter has the same meaning as in deflateInit. sourceLen is the byte -+ length of the source buffer. Upon entry, destLen is the total size of the -+ destination buffer, which must be at least the value returned by -+ compressBound(sourceLen). Upon exit, destLen is the actual size of the -+ compressed buffer. -+ -+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough -+ memory, Z_BUF_ERROR if there was not enough room in the output buffer, -+ Z_STREAM_ERROR if the level parameter is invalid. -+*/ -+ -+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -+/* -+ compressBound() returns an upper bound on the compressed size after -+ compress() or compress2() on sourceLen bytes. It would be used before a -+ compress() or compress2() call to allocate the destination buffer. -+*/ -+ -+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, -+ const Bytef *source, uLong sourceLen)); -+/* -+ Decompresses the source buffer into the destination buffer. sourceLen is -+ the byte length of the source buffer. Upon entry, destLen is the total size -+ of the destination buffer, which must be large enough to hold the entire -+ uncompressed data. (The size of the uncompressed data must have been saved -+ previously by the compressor and transmitted to the decompressor by some -+ mechanism outside the scope of this compression library.) Upon exit, destLen -+ is the actual size of the uncompressed buffer. -+ -+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not -+ enough memory, Z_BUF_ERROR if there was not enough room in the output -+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. -+*/ -+ -+ -+ /* gzip file access functions */ -+ -+/* -+ This library supports reading and writing files in gzip (.gz) format with -+ an interface similar to that of stdio, using the functions that start with -+ "gz". The gzip format is different from the zlib format. gzip is a gzip -+ wrapper, documented in RFC 1952, wrapped around a deflate stream. -+*/ -+ -+typedef voidp gzFile; /* opaque gzip file descriptor */ -+ -+/* -+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); -+ -+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as -+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or -+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only -+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' -+ for fixed code compression as in "wb9F". (See the description of -+ deflateInit2 for more information about the strategy parameter.) Also "a" -+ can be used instead of "w" to request that the gzip stream that will be -+ written be appended to the file. "+" will result in an error, since reading -+ and writing to the same gzip file is not supported. -+ -+ gzopen can be used to read a file which is not in gzip format; in this -+ case gzread will directly read from the file without decompression. -+ -+ gzopen returns NULL if the file could not be opened, if there was -+ insufficient memory to allocate the gzFile state, or if an invalid mode was -+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). -+ errno can be checked to determine if the reason gzopen failed was that the -+ file could not be opened. -+*/ -+ -+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -+/* -+ gzdopen associates a gzFile with the file descriptor fd. File descriptors -+ are obtained from calls like open, dup, creat, pipe or fileno (if the file -+ has been previously opened with fopen). The mode parameter is as in gzopen. -+ -+ The next call of gzclose on the returned gzFile will also close the file -+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor -+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, -+ mode);. The duplicated descriptor should be saved to avoid a leak, since -+ gzdopen does not close fd if it fails. -+ -+ gzdopen returns NULL if there was insufficient memory to allocate the -+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not -+ provided, or '+' was provided), or if fd is -1. The file descriptor is not -+ used until the next gz* read, write, seek, or close operation, so gzdopen -+ will not detect if fd is invalid (unless fd is -1). -+*/ -+ -+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); -+/* -+ Set the internal buffer size used by this library's functions. The -+ default buffer size is 8192 bytes. This function must be called after -+ gzopen() or gzdopen(), and before any other calls that read or write the -+ file. The buffer memory allocation is always deferred to the first read or -+ write. Two buffers are allocated, either both of the specified size when -+ writing, or one of the specified size and the other twice that size when -+ reading. A larger buffer size of, for example, 64K or 128K bytes will -+ noticeably increase the speed of decompression (reading). -+ -+ The new buffer size also affects the maximum length for gzprintf(). -+ -+ gzbuffer() returns 0 on success, or -1 on failure, such as being called -+ too late. -+*/ -+ -+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -+/* -+ Dynamically update the compression level or strategy. See the description -+ of deflateInit2 for the meaning of these parameters. -+ -+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not -+ opened for writing. -+*/ -+ -+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -+/* -+ Reads the given number of uncompressed bytes from the compressed file. If -+ the input file was not in gzip format, gzread copies the given number of -+ bytes into the buffer. -+ -+ After reaching the end of a gzip stream in the input, gzread will continue -+ to read, looking for another gzip stream, or failing that, reading the rest -+ of the input file directly without decompression. The entire input file -+ will be read if gzread is called until it returns less than the requested -+ len. -+ -+ gzread returns the number of uncompressed bytes actually read, less than -+ len for end of file, or -1 for error. -+*/ -+ -+ZEXTERN int ZEXPORT gzwrite OF((gzFile file, -+ voidpc buf, unsigned len)); -+/* -+ Writes the given number of uncompressed bytes into the compressed file. -+ gzwrite returns the number of uncompressed bytes written or 0 in case of -+ error. -+*/ -+ -+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); -+/* -+ Converts, formats, and writes the arguments to the compressed file under -+ control of the format string, as in fprintf. gzprintf returns the number of -+ uncompressed bytes actually written, or 0 in case of error. The number of -+ uncompressed bytes written is limited to 8191, or one less than the buffer -+ size given to gzbuffer(). The caller should assure that this limit is not -+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with -+ nothing written. In this case, there may also be a buffer overflow with -+ unpredictable consequences, which is possible only if zlib was compiled with -+ the insecure functions sprintf() or vsprintf() because the secure snprintf() -+ or vsnprintf() functions were not available. This can be determined using -+ zlibCompileFlags(). -+*/ -+ -+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -+/* -+ Writes the given null-terminated string to the compressed file, excluding -+ the terminating null character. -+ -+ gzputs returns the number of characters written, or -1 in case of error. -+*/ -+ -+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -+/* -+ Reads bytes from the compressed file until len-1 characters are read, or a -+ newline character is read and transferred to buf, or an end-of-file -+ condition is encountered. If any characters are read or if len == 1, the -+ string is terminated with a null character. If no characters are read due -+ to an end-of-file or len < 1, then the buffer is left untouched. -+ -+ gzgets returns buf which is a null-terminated string, or it returns NULL -+ for end-of-file or in case of error. If there was an error, the contents at -+ buf are indeterminate. -+*/ -+ -+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -+/* -+ Writes c, converted to an unsigned char, into the compressed file. gzputc -+ returns the value that was written, or -1 in case of error. -+*/ -+ -+ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -+/* -+ Reads one byte from the compressed file. gzgetc returns this byte or -1 -+ in case of end of file or error. -+*/ -+ -+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -+/* -+ Push one character back onto the stream to be read as the first character -+ on the next read. At least one character of push-back is allowed. -+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will -+ fail if c is -1, and may fail if a character has been pushed but not read -+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the -+ output buffer size of pushed characters is allowed. (See gzbuffer above.) -+ The pushed character will be discarded if the stream is repositioned with -+ gzseek() or gzrewind(). -+*/ -+ -+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -+/* -+ Flushes all pending output into the compressed file. The parameter flush -+ is as in the deflate() function. The return value is the zlib error number -+ (see function gzerror below). gzflush is only permitted when writing. -+ -+ If the flush parameter is Z_FINISH, the remaining data is written and the -+ gzip stream is completed in the output. If gzwrite() is called again, a new -+ gzip stream will be started in the output. gzread() is able to read such -+ concatented gzip streams. -+ -+ gzflush should be called only when strictly necessary because it will -+ degrade compression if called too often. -+*/ -+ -+/* -+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, -+ z_off_t offset, int whence)); -+ -+ Sets the starting position for the next gzread or gzwrite on the given -+ compressed file. The offset represents a number of bytes in the -+ uncompressed data stream. The whence parameter is defined as in lseek(2); -+ the value SEEK_END is not supported. -+ -+ If the file is opened for reading, this function is emulated but can be -+ extremely slow. If the file is opened for writing, only forward seeks are -+ supported; gzseek then compresses a sequence of zeroes up to the new -+ starting position. -+ -+ gzseek returns the resulting offset location as measured in bytes from -+ the beginning of the uncompressed stream, or -1 in case of error, in -+ particular if the file is opened for writing and the new starting position -+ would be before the current position. -+*/ -+ -+ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -+/* -+ Rewinds the given file. This function is supported only for reading. -+ -+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -+*/ -+ -+/* -+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); -+ -+ Returns the starting position for the next gzread or gzwrite on the given -+ compressed file. This position represents a number of bytes in the -+ uncompressed data stream, and is zero when starting, even if appending or -+ reading a gzip stream from the middle of a file using gzdopen(). -+ -+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -+*/ -+ -+/* -+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); -+ -+ Returns the current offset in the file being read or written. This offset -+ includes the count of bytes that precede the gzip stream, for example when -+ appending or when using gzdopen() for reading. When reading, the offset -+ does not include as yet unused buffered input. This information can be used -+ for a progress indicator. On error, gzoffset() returns -1. -+*/ -+ -+ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -+/* -+ Returns true (1) if the end-of-file indicator has been set while reading, -+ false (0) otherwise. Note that the end-of-file indicator is set only if the -+ read tried to go past the end of the input, but came up short. Therefore, -+ just like feof(), gzeof() may return false even if there is no more data to -+ read, in the event that the last read request was for the exact number of -+ bytes remaining in the input file. This will happen if the input file size -+ is an exact multiple of the buffer size. -+ -+ If gzeof() returns true, then the read functions will return no more data, -+ unless the end-of-file indicator is reset by gzclearerr() and the input file -+ has grown since the previous end of file was detected. -+*/ -+ -+ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -+/* -+ Returns true (1) if file is being copied directly while reading, or false -+ (0) if file is a gzip stream being decompressed. This state can change from -+ false to true while reading the input file if the end of a gzip stream is -+ reached, but is followed by data that is not another gzip stream. -+ -+ If the input file is empty, gzdirect() will return true, since the input -+ does not contain a gzip stream. -+ -+ If gzdirect() is used immediately after gzopen() or gzdopen() it will -+ cause buffers to be allocated to allow reading the file to determine if it -+ is a gzip file. Therefore if gzbuffer() is used, it should be called before -+ gzdirect(). -+*/ -+ -+ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -+/* -+ Flushes all pending output if necessary, closes the compressed file and -+ deallocates the (de)compression state. Note that once file is closed, you -+ cannot call gzerror with file, since its structures have been deallocated. -+ gzclose must not be called more than once on the same file, just as free -+ must not be called more than once on the same allocation. -+ -+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a -+ file operation error, or Z_OK on success. -+*/ -+ -+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); -+/* -+ Same as gzclose(), but gzclose_r() is only for use when reading, and -+ gzclose_w() is only for use when writing or appending. The advantage to -+ using these instead of gzclose() is that they avoid linking in zlib -+ compression or decompression code that is not used when only reading or only -+ writing respectively. If gzclose() is used, then both compression and -+ decompression code will be included the application when linking to a static -+ zlib library. -+*/ -+ -+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -+/* -+ Returns the error message for the last error which occurred on the given -+ compressed file. errnum is set to zlib error number. If an error occurred -+ in the file system and not in the compression library, errnum is set to -+ Z_ERRNO and the application may consult errno to get the exact error code. -+ -+ The application must not modify the returned string. Future calls to -+ this function may invalidate the previously returned string. If file is -+ closed, then the string previously returned by gzerror will no longer be -+ available. -+ -+ gzerror() should be used to distinguish errors from end-of-file for those -+ functions above that do not distinguish those cases in their return values. -+*/ -+ -+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -+/* -+ Clears the error and end-of-file flags for file. This is analogous to the -+ clearerr() function in stdio. This is useful for continuing to read a gzip -+ file that is being written concurrently. -+*/ -+ -+ -+ /* checksum functions */ -+ -+/* -+ These functions are not related to compression but are exported -+ anyway because they might be useful in applications using the compression -+ library. -+*/ -+ -+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -+/* -+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and -+ return the updated checksum. If buf is Z_NULL, this function returns the -+ required initial value for the checksum. -+ -+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed -+ much faster. -+ -+ Usage example: -+ -+ uLong adler = adler32(0L, Z_NULL, 0); -+ -+ while (read_buffer(buffer, length) != EOF) { -+ adler = adler32(adler, buffer, length); -+ } -+ if (adler != original_adler) error(); -+*/ -+ -+/* -+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, -+ z_off_t len2)); -+ -+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 -+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for -+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of -+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. -+*/ -+ -+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -+/* -+ Update a running CRC-32 with the bytes buf[0..len-1] and return the -+ updated CRC-32. If buf is Z_NULL, this function returns the required -+ initial value for the for the crc. Pre- and post-conditioning (one's -+ complement) is performed within this function so it shouldn't be done by the -+ application. -+ -+ Usage example: -+ -+ uLong crc = crc32(0L, Z_NULL, 0); -+ -+ while (read_buffer(buffer, length) != EOF) { -+ crc = crc32(crc, buffer, length); -+ } -+ if (crc != original_crc) error(); -+*/ -+ -+/* -+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); -+ -+ Combine two CRC-32 check values into one. For two sequences of bytes, -+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were -+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 -+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and -+ len2. -+*/ -+ -+ -+ /* various hacks, don't look :) */ -+ -+/* deflateInit and inflateInit are macros to allow checking the zlib version -+ * and the compiler's view of z_stream: -+ */ -+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, -+ const char *version, int stream_size)); -+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, -+ const char *version, int stream_size)); -+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, -+ int windowBits, int memLevel, -+ int strategy, const char *version, -+ int stream_size)); -+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, -+ const char *version, int stream_size)); -+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, -+ unsigned char FAR *window, -+ const char *version, -+ int stream_size)); -+#define deflateInit(strm, level) \ -+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) -+#define inflateInit(strm) \ -+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) -+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ -+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ -+ (strategy), ZLIB_VERSION, sizeof(z_stream)) -+#define inflateInit2(strm, windowBits) \ -+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) -+#define inflateBackInit(strm, windowBits, window) \ -+ inflateBackInit_((strm), (windowBits), (window), \ -+ ZLIB_VERSION, sizeof(z_stream)) -+ -+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or -+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if -+ * both are true, the application gets the *64 functions, and the regular -+ * functions are changed to 64 bits) -- in case these are set on systems -+ * without large file support, _LFS64_LARGEFILE must also be true -+ */ -+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 -+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); -+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); -+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); -+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); -+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); -+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); -+#endif -+ -+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0 -+# define gzopen gzopen64 -+# define gzseek gzseek64 -+# define gztell gztell64 -+# define gzoffset gzoffset64 -+# define adler32_combine adler32_combine64 -+# define crc32_combine crc32_combine64 -+# ifdef _LARGEFILE64_SOURCE -+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); -+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); -+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); -+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); -+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); -+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -+# endif -+#else -+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); -+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); -+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); -+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); -+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); -+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); -+#endif -+ -+/* hack for buggy compilers */ -+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) -+ struct internal_state {int dummy;}; -+#endif -+ -+/* undocumented functions */ -+ZEXTERN const char * ZEXPORT zError OF((int)); -+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); -+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* ZLIB_H */ -commit d35e544671d94a9e6ebf87ff5f7d747fda616f27 -Author: Luigi Scarso -Date: Wed Sep 5 21:57:30 2018 +0000 - - luatex: correct automake file for pplib; replaced cweb files with c files. - - git-svn-id: svn://tug.org/texlive/trunk/Build/source@48594 c570f23f-e606-0410-a88d-b1316a301751 - -diff --git a/texk/web2c/luatexdir/am/luapplib.am b/texk/web2c/luatexdir/am/luapplib.am -new file mode 100644 -index 000000000..513062325 ---- /dev/null -+++ b/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 -+## 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/texk/web2c/luatexdir/dvi/dvigen.c b/texk/web2c/luatexdir/dvi/dvigen.c -new file mode 100644 -index 000000000..8e285917a ---- /dev/null -+++ b/texk/web2c/luatexdir/dvi/dvigen.c -@@ -0,0 +1,1558 @@ -+/* -+ -+dvigen.w -+ -+Copyright 2009-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/dvi/dvigen.w b/texk/web2c/luatexdir/dvi/dvigen.w -deleted file mode 100644 -index d991445a5..000000000 ---- a/texk/web2c/luatexdir/dvi/dvigen.w -+++ /dev/null -@@ -1,1258 +0,0 @@ --% dvigen.w --% --% Copyright 2009-2013 Taco Hoekwater --% --% 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 . -- --\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/texk/web2c/luatexdir/font/dofont.w b/texk/web2c/luatexdir/font/dofont.c -similarity index 63% -rename from texk/web2c/luatexdir/font/dofont.w -rename to texk/web2c/luatexdir/font/dofont.c -index b91bec106..b23368d83 100644 ---- a/texk/web2c/luatexdir/font/dofont.w -+++ b/texk/web2c/luatexdir/font/dofont.c -@@ -1,42 +1,42 @@ --% dofont.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/font/mapfile.c b/texk/web2c/luatexdir/font/mapfile.c -new file mode 100644 -index 000000000..5ea1e7ca0 ---- /dev/null -+++ b/texk/web2c/luatexdir/font/mapfile.c -@@ -0,0 +1,770 @@ -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+#include -+#include -+#include -+#include -+ -+#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 {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/texk/web2c/luatexdir/font/mapfile.w b/texk/web2c/luatexdir/font/mapfile.w -deleted file mode 100644 -index f47c5b504..000000000 ---- a/texk/web2c/luatexdir/font/mapfile.w -+++ /dev/null -@@ -1,715 +0,0 @@ --% mapfile.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @c -- -- --#include "ptexlib.h" --#include --#include --#include --#include -- --#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: ' 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/texk/web2c/luatexdir/font/pkin.w b/texk/web2c/luatexdir/font/pkin.c -similarity index 55% -rename from texk/web2c/luatexdir/font/pkin.w -rename to texk/web2c/luatexdir/font/pkin.c -index a5d3eb4bc..afebdef33 100644 ---- a/texk/web2c/luatexdir/font/pkin.w -+++ b/texk/web2c/luatexdir/font/pkin.c -@@ -1,63 +1,56 @@ --% pkin.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -+/* - --@ --NAME -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2008 Taco Hoekwater - --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 . - --May 1997: Eric Delaunay 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 -+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 . -+May 1997: Eric Delaunay 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 redesigned the code and later Han -+The Thanh 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/texk/web2c/luatexdir/font/sfnt.w b/texk/web2c/luatexdir/font/sfnt.c -similarity index 79% -rename from texk/web2c/luatexdir/font/sfnt.w -rename to texk/web2c/luatexdir/font/sfnt.c -index 83e38990d..c7f4723c4 100644 ---- a/texk/web2c/luatexdir/font/sfnt.w -+++ b/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 --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -- --@ Based on dvipdfmx-0.13.2c --@c -+/* - -+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata, -+the dvipdfmx project team -+Copyright 2006-2008 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+/*tex -+ -+ The code below is originally based on |dvipdfmx-0.13.2c|: -+ -+*/ - - #include "ptexlib.h" - --#if HAVE_CONFIG_H -+#if HAVE_CONFIG_H - # include --#endif /* |HAVE_CONFIG_H_| */ -+#endif - - #include - - #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/texk/web2c/luatexdir/font/subfont.w b/texk/web2c/luatexdir/font/subfont.c -similarity index 69% -rename from texk/web2c/luatexdir/font/subfont.w -rename to texk/web2c/luatexdir/font/subfont.c -index 0616bdad4..d2f5f8d2f 100644 ---- a/texk/web2c/luatexdir/font/subfont.w -+++ b/texk/web2c/luatexdir/font/subfont.c -@@ -1,30 +1,28 @@ --% subfont.w --% --% Copyright 2005-2006 Han The Thanh --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2005-2006 Han The Thanh -+Copyright 2006-2008 Taco Hoekwater - -+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 . -+ -+*/ - - #include "ptexlib.h" - #include - --@ @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/texk/web2c/luatexdir/font/texfont.w b/texk/web2c/luatexdir/font/texfont.c -similarity index 89% -rename from texk/web2c/luatexdir/font/texfont.w -rename to texk/web2c/luatexdir/font/texfont.c -index ce463326a..332a8a344 100644 ---- a/texk/web2c/luatexdir/font/texfont.w -+++ b/texk/web2c/luatexdir/font/texfont.c -@@ -1,41 +1,52 @@ --% texfont.w --% --% Copyright 2006-2013 Taco Hoekwater --% --% 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 . -- --@* 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 -+ -+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 . -+ -+*/ -+ -+/*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/texk/web2c/luatexdir/font/tfmofm.c b/texk/web2c/luatexdir/font/tfmofm.c -new file mode 100644 -index 000000000..f5d8c2e92 ---- /dev/null -+++ b/texk/web2c/luatexdir/font/tfmofm.c -@@ -0,0 +1,1186 @@ -+/* -+ -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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=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 ((zec)) 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/texk/web2c/luatexdir/font/tounicode.w b/texk/web2c/luatexdir/font/tounicode.c -similarity index 64% -rename from texk/web2c/luatexdir/font/tounicode.w -rename to texk/web2c/luatexdir/font/tounicode.c -index 441a10dd5..f0449aff9 100644 ---- a/texk/web2c/luatexdir/font/tounicode.w -+++ b/texk/web2c/luatexdir/font/tounicode.c -@@ -1,41 +1,46 @@ --% tounicode.w --% --% Copyright 2006 Han The Thanh, --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2006 Han The Thanh, -+Copyright 2006-2010 Taco Hoekwater - -+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 . -+ -+*/ - - #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> \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> \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], >ab[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> \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> \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/texk/web2c/luatexdir/font/tt_glyf.w b/texk/web2c/luatexdir/font/tt_glyf.c -similarity index 76% -rename from texk/web2c/luatexdir/font/tt_glyf.w -rename to texk/web2c/luatexdir/font/tt_glyf.c -index c0f17e5ab..750e126aa 100644 ---- a/texk/web2c/luatexdir/font/tt_glyf.w -+++ b/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 --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -+/* - --@* Subsetting glyf, updating loca, hmtx, etc. -+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata, -+the dvipdfmx project team -+Copyright 2006-2012 Taco Hoekwater - --@ @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 . -+ -+*/ - - #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/texk/web2c/luatexdir/font/tt_table.w b/texk/web2c/luatexdir/font/tt_table.c -similarity index 86% -rename from texk/web2c/luatexdir/font/tt_table.w -rename to texk/web2c/luatexdir/font/tt_table.c -index a4164f39d..dfcd4d650 100644 ---- a/texk/web2c/luatexdir/font/tt_table.w -+++ b/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 --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata, the dvipdfmx project -+ team -+Copyright 2006-2010 Taco Hoekwater - -+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 . -+ -+*/ - -+#include "ptexlib.h" - #include - #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/texk/web2c/luatexdir/font/vfovf.c b/texk/web2c/luatexdir/font/vfovf.c -new file mode 100644 -index 000000000..e1fdb903e ---- /dev/null -+++ b/texk/web2c/luatexdir/font/vfovf.c -@@ -0,0 +1,1444 @@ -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/font/vfpacket.c b/texk/web2c/luatexdir/font/vfpacket.c -new file mode 100644 -index 000000000..41132c54a ---- /dev/null -+++ b/texk/web2c/luatexdir/font/vfpacket.c -@@ -0,0 +1,445 @@ -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/font/vfpacket.w b/texk/web2c/luatexdir/font/vfpacket.w -deleted file mode 100644 -index d2329916a..000000000 ---- a/texk/web2c/luatexdir/font/vfpacket.w -+++ /dev/null -@@ -1,424 +0,0 @@ --% vfpacket.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2013 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/font/writeenc.w b/texk/web2c/luatexdir/font/writeenc.c -similarity index 71% -rename from texk/web2c/luatexdir/font/writeenc.w -rename to texk/web2c/luatexdir/font/writeenc.c -index 1a7ed3891..554c246a5 100644 ---- a/texk/web2c/luatexdir/font/writeenc.w -+++ b/texk/web2c/luatexdir/font/writeenc.c -@@ -1,34 +1,37 @@ --% writeenc.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/font/writefont.w b/texk/web2c/luatexdir/font/writefont.c -similarity index 65% -rename from texk/web2c/luatexdir/font/writefont.w -rename to texk/web2c/luatexdir/font/writefont.c -index 2ba81d617..5d75ef80c 100644 ---- a/texk/web2c/luatexdir/font/writefont.w -+++ b/texk/web2c/luatexdir/font/writefont.c -@@ -1,69 +1,69 @@ --% writefont.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/font/writet3.w b/texk/web2c/luatexdir/font/writet3.c -similarity index 90% -rename from texk/web2c/luatexdir/font/writet3.w -rename to texk/web2c/luatexdir/font/writet3.c -index 879cef8d5..6121c24a1 100644 ---- a/texk/web2c/luatexdir/font/writet3.w -+++ b/texk/web2c/luatexdir/font/writet3.c -@@ -1,25 +1,24 @@ --% writet3.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2011 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2011 Taco Hoekwater - -+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 . -+ -+*/ - - #include "ptexlib.h" - #include -@@ -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) { -- /* .dpi/.pk */ -+ /*tex |.dpi/.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/texk/web2c/luatexdir/font/writettf.w b/texk/web2c/luatexdir/font/writettf.c -similarity index 65% -rename from texk/web2c/luatexdir/font/writettf.w -rename to texk/web2c/luatexdir/font/writettf.c -index 4a016cbe4..cf034e98d 100644 ---- a/texk/web2c/luatexdir/font/writettf.w -+++ b/texk/web2c/luatexdir/font/writettf.c -@@ -1,32 +1,31 @@ --% writettf.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #include "ptexlib.h" - #include "font/writettf.h" - #include - - #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/texk/web2c/luatexdir/font/writetype0.w b/texk/web2c/luatexdir/font/writetype0.c -similarity index 69% -rename from texk/web2c/luatexdir/font/writetype0.w -rename to texk/web2c/luatexdir/font/writetype0.c -index ebf4be667..7a81d58c9 100644 ---- a/texk/web2c/luatexdir/font/writetype0.w -+++ b/texk/web2c/luatexdir/font/writetype0.c -@@ -1,29 +1,34 @@ --% writetype0.w --% --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2006-2008 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/font/writetype2.w b/texk/web2c/luatexdir/font/writetype2.c -similarity index 65% -rename from texk/web2c/luatexdir/font/writetype2.w -rename to texk/web2c/luatexdir/font/writetype2.c -index 81aefb1fb..b8a746090 100644 ---- a/texk/web2c/luatexdir/font/writetype2.w -+++ b/texk/web2c/luatexdir/font/writetype2.c -@@ -1,24 +1,23 @@ --% writetype2.w --% --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/image/pdftoepdf.c b/texk/web2c/luatexdir/image/pdftoepdf.c -new file mode 100644 -index 000000000..b29493b07 ---- /dev/null -+++ b/texk/web2c/luatexdir/image/pdftoepdf.c -@@ -0,0 +1,1049 @@ -+/* -+pdftoepdf.w -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2015 Taco Hoekwater -+ -+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 . -+*/ -+ -+#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; isize; -+ pdf_begin_dict(pdf); -+ for (i=0; idict; /* 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; itype) { -+ 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; iarray,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/texk/web2c/luatexdir/image/pdftoepdf.w b/texk/web2c/luatexdir/image/pdftoepdf.w -deleted file mode 100644 -index d69795926..000000000 ---- a/texk/web2c/luatexdir/image/pdftoepdf.w -+++ /dev/null -@@ -1,972 +0,0 @@ --% pdftoepdf.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2015 Taco Hoekwater --% --% 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 . -- --@ @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 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/texk/web2c/luatexdir/image/writeimg.w b/texk/web2c/luatexdir/image/writeimg.c -similarity index 70% -rename from texk/web2c/luatexdir/image/writeimg.w -rename to texk/web2c/luatexdir/image/writeimg.c -index ef414d5d4..e3e3f608f 100644 ---- a/texk/web2c/luatexdir/image/writeimg.w -+++ b/texk/web2c/luatexdir/image/writeimg.c -@@ -1,109 +1,82 @@ --% writeimg.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -- --@* Image inclusion. -- --@ @c -+/* -+ -+writeimg.c -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #include "ptexlib.h" - #include - #include - --@ @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 || 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 || to |alt_rule| */ -+ /*tex This scans || 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/texk/web2c/luatexdir/image/writejbig2.w b/texk/web2c/luatexdir/image/writejbig2.c -similarity index 80% -rename from texk/web2c/luatexdir/image/writejbig2.w -rename to texk/web2c/luatexdir/image/writejbig2.c -index a58313ce8..77a1ddb07 100644 ---- a/texk/web2c/luatexdir/image/writejbig2.w -+++ b/texk/web2c/luatexdir/image/writejbig2.c -@@ -1,27 +1,30 @@ --% writejbig2.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2013 Taco Hoekwater --% Copyright 2003-2013 Hartmut Henkel --% --% 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 . -- --@ --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 -+Copyright 2006-2013 Taco Hoekwater -+Copyright 2003-2013 Hartmut Henkel -+ -+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 . -+ -+*/ -+ -+/*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 - #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/texk/web2c/luatexdir/image/writejp2.w b/texk/web2c/luatexdir/image/writejp2.c -similarity index 82% -rename from texk/web2c/luatexdir/image/writejp2.w -rename to texk/web2c/luatexdir/image/writejp2.c -index cb317e119..0ea001708 100644 ---- a/texk/web2c/luatexdir/image/writejp2.w -+++ b/texk/web2c/luatexdir/image/writejp2.c -@@ -1,38 +1,42 @@ --% writejp2.w --% --% Copyright 2011-2013 Taco Hoekwater --% Copyright 2011-2013 Hartmut Henkel --% --% 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 . -+/* - --@ @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 -+Copyright 2011-2013 Hartmut Henkel -+ -+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 . -+ -+*/ -+ -+/*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 - #include - #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/texk/web2c/luatexdir/image/writejpg.w b/texk/web2c/luatexdir/image/writejpg.c -similarity index 76% -rename from texk/web2c/luatexdir/image/writejpg.w -rename to texk/web2c/luatexdir/image/writejpg.c -index 54ed47f0f..f58dc2aa6 100644 ---- a/texk/web2c/luatexdir/image/writejpg.w -+++ b/texk/web2c/luatexdir/image/writejpg.c -@@ -1,31 +1,30 @@ --% writejpg.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+writejpg.w -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #include "ptexlib.h" - #include - #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/texk/web2c/luatexdir/image/writepng.w b/texk/web2c/luatexdir/image/writepng.c -similarity index 85% -rename from texk/web2c/luatexdir/image/writepng.w -rename to texk/web2c/luatexdir/image/writepng.c -index 412000c42..165e202f4 100644 ---- a/texk/web2c/luatexdir/image/writepng.w -+++ b/texk/web2c/luatexdir/image/writepng.c -@@ -1,36 +1,32 @@ --% writepng.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2013 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+writepng.c -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2013 Taco Hoekwater -+ -+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 . -+ -+*/ - - #include "ptexlib.h" - #include - #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/texk/web2c/luatexdir/lang/hnjalloc.c b/texk/web2c/luatexdir/lang/hnjalloc.c -new file mode 100644 -index 000000000..3ebeee9e4 ---- /dev/null -+++ b/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 -+#include -+#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/texk/web2c/luatexdir/lang/hnjalloc.w b/texk/web2c/luatexdir/lang/hnjalloc.w -deleted file mode 100644 -index 91fefec9e..000000000 ---- a/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 --#include --#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/texk/web2c/luatexdir/lang/hyphen.w b/texk/web2c/luatexdir/lang/hyphen.c -similarity index 61% -rename from texk/web2c/luatexdir/lang/hyphen.w -rename to texk/web2c/luatexdir/lang/hyphen.c -index 35befb743..3a96f195b 100644 ---- a/texk/web2c/luatexdir/lang/hyphen.w -+++ b/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 /* for NULL, malloc */ --#include /* for fprintf */ --#include /* for strdup */ --#include /* for malloc used by substring inclusion */ -+#include /* for NULL, malloc */ -+#include /* for fprintf */ -+#include /* for strdup */ -+#include /* for malloc used by substring inclusion */ - - #define MAXPATHS 40960 - - #ifdef UNX --# include /* for exit */ -+# include /* for exit */ - #endif - - #include -@@ -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/texk/web2c/luatexdir/lang/texlang.w b/texk/web2c/luatexdir/lang/texlang.c -similarity index 59% -rename from texk/web2c/luatexdir/lang/texlang.w -rename to texk/web2c/luatexdir/lang/texlang.c -index 337d2eca5..04f96660f 100644 ---- a/texk/web2c/luatexdir/lang/texlang.w -+++ b/texk/web2c/luatexdir/lang/texlang.c -@@ -1,31 +1,32 @@ --% texlang.w --% --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+texlang.w -+ -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #include "ptexlib.h" - #include - #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/texk/web2c/luatexdir/lua/helpers.c b/texk/web2c/luatexdir/lua/helpers.c -new file mode 100644 -index 000000000..e7be7a2c2 ---- /dev/null -+++ b/texk/web2c/luatexdir/lua/helpers.c -@@ -0,0 +1,29 @@ -+/* -+ -+helpers.w -+ -+Copyright 2017 LuaTeX team -+ -+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 . -+ -+*/ -+ -+/*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/texk/web2c/luatexdir/lua/helpers.w b/texk/web2c/luatexdir/lua/helpers.w -deleted file mode 100644 -index d12e47690..000000000 ---- a/texk/web2c/luatexdir/lua/helpers.w -+++ /dev/null -@@ -1,26 +0,0 @@ --% helpers.w --% --% Copyright 2017 LuaTeX team --% --% 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 . -- --@ 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/texk/web2c/luatexdir/lua/llfslibext.c b/texk/web2c/luatexdir/lua/llfslibext.c -deleted file mode 100644 -index eba5778df..000000000 ---- a/texk/web2c/luatexdir/lua/llfslibext.c -+++ /dev/null -@@ -1,171 +0,0 @@ --/* llfslibext.c -- -- Copyright 2010-2011 Taco Hoekwater -- -- 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 . */ -- --#include "ptexlib.h" --#include "lua/luatex-api.h" -- --#include --#include --#include -- -- --#ifdef _WIN32 --# include --#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/texk/web2c/luatexdir/lua/lpdfelib.c b/texk/web2c/luatexdir/lua/lpdfelib.c -new file mode 100644 -index 000000000..31fad9f63 ---- /dev/null -+++ b/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 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() -+ \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;iarray->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;idictionary->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 argument: string or lightuserdata expected"); -+ break; -+ } -+ if (docstream == NULL) { -+ luaL_error(L, "bad 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 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, " stream has an invalid id"); -+ } -+ if (strlen(file_id) > STREAM_FILE_ID_LEN ) { -+ /* a limit to the length of the string */ -+ luaL_error(L, " 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 -+ = getstring (array|dict|ref,index|key) -+ = getinteger (array|dict|ref,index|key) -+ = getnumber (array|dict|ref,index|key) -+ = getboolean (array|dict|ref,index|key) -+ = getname (array|dict|ref,index|key) -+ = getdictionary(array|dict|ref,index|key) -+ = getarray (array|dict|ref,index|key) -+ , = 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 expected"); \ -+ } else if (t == LUA_TNUMBER) { \ -+ normal_warning("pdfe lib","lua 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 or "); \ -+ } \ -+} 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/texk/web2c/luatexdir/lua/lpdfscannerlib.c b/texk/web2c/luatexdir/lua/lpdfscannerlib.c -new file mode 100644 -index 000000000..6c3bc8876 ---- /dev/null -+++ b/texk/web2c/luatexdir/lua/lpdfscannerlib.c -@@ -0,0 +1,1110 @@ -+/* lpdfscannerlib.c -+ -+ Copyright 2013 Taco Hoekwater -+ -+ 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 . -+ -+*/ -+ -+/*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 -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "luapplib/pplib.h" -+ -+#include -+ -+#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 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 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/texk/web2c/luatexdir/lua/luainit.w b/texk/web2c/luatexdir/lua/luainit.c -similarity index 76% -rename from texk/web2c/luatexdir/lua/luainit.w -rename to texk/web2c/luatexdir/lua/luainit.c -index dec76b021..60c654aa0 100644 ---- a/texk/web2c/luatexdir/lua/luainit.w -+++ b/texk/web2c/luatexdir/lua/luainit.c -@@ -1,23 +1,25 @@ --% luainit.w --% --% Copyright 2006-2018 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+luainit.w -+ -+Copyright 2006-2018 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/lua/luanode.w b/texk/web2c/luatexdir/lua/luanode.c -similarity index 64% -rename from texk/web2c/luatexdir/lua/luanode.w -rename to texk/web2c/luatexdir/lua/luanode.c -index ef2f0b926..3182b6097 100644 ---- a/texk/web2c/luatexdir/lua/luanode.w -+++ b/texk/web2c/luatexdir/lua/luanode.c -@@ -1,33 +1,32 @@ --% luanode.w --% --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -+/* - --/* 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 -+ -+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 . -+ -+*/ - - #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(" "); - break; - } -- if (pdf_literal_type(p) == normal) { -+ if (t == normal) { - print_mark(pdf_literal_data(p)); -+ } else if (t == lua_refid_literal) { -+ tprint(" "); - } else { -- lua_rawgeti(Luas, LUA_REGISTRYINDEX, pdf_literal_data(p)); -- tprint("\""); -- tprint(lua_tostring(Luas, -1)); -- tprint("\""); -- lua_pop(Luas, 1); -+ tprint(" "); - } - } - --@ @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(" "); -+ } else if (t == lua_refid_call) { -+ tprint(" "); -+ } else { -+ tprint(" "); - } - } -diff --git a/texk/web2c/luatexdir/lua/luastuff.w b/texk/web2c/luatexdir/lua/luastuff.c -similarity index 56% -rename from texk/web2c/luatexdir/lua/luastuff.w -rename to texk/web2c/luatexdir/lua/luastuff.c -index a2b1dd143..0d9342223 100644 ---- a/texk/web2c/luatexdir/lua/luastuff.w -+++ b/texk/web2c/luatexdir/lua/luastuff.c -@@ -1,30 +1,32 @@ --% luastuff.w --% --% Copyright 2006-2013 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+luastuff.w -+ -+Copyright 2006-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #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 *//* |[{}]| */ -- lua_pushstring(L, tab); /* |[{},"dimen"]| */ -- lua_newtable(L); /* |[{},"dimen",{}]| */ -- lua_settable(L, -3); /* |[{}]| */ -- /* fetch it back */ -- lua_pushstring(L, tab); /* |[{},"dimen"]| */ -- lua_gettable(L, -2); /* |[{},{}]| */ -- /* make the meta entries */ -- luaL_newmetatable(L, mttab); /* |[{},{},{}]| */ -- lua_pushstring(L, "__index"); /* |[{},{},{},"__index"]| */ -- lua_pushstring(L, getfunc); /* |[{},{},{},"__index","getdimen"]| */ -- lua_gettable(L, -5); /* |[{},{},{},"__index",]| */ -- lua_settable(L, -3); /* |[{},{},{}]| */ -- lua_pushstring(L, "__newindex"); /* |[{},{},{},"__newindex"]| */ -- lua_pushstring(L, setfunc); /* |[{},{},{},"__newindex","setdimen"]| */ -- lua_gettable(L, -5); /* |[{},{},{},"__newindex",]| */ -- lua_settable(L, -3); /* |[{},{},{}]| */ -- lua_setmetatable(L, -2); /* |[{},{}]| : assign the metatable */ -- lua_pop(L, 1); /* |[{}]| : clean the stack */ -+ /*tex make the table *//* |[{}]| */ -+ /*tex |[{},"dimen"]| */ -+ lua_pushstring(L, tab); -+ /*tex |[{},"dimen",{}]| */ -+ lua_newtable(L); -+ /*tex |[{}]| */ -+ lua_settable(L, -3); -+ /*tex fetch it back */ -+ /*tex |[{},"dimen"]| */ -+ lua_pushstring(L, tab); -+ /*tex |[{},{}]| */ -+ lua_gettable(L, -2); -+ /*tex make the meta entries */ -+ /*tex |[{},{},{}]| */ -+ luaL_newmetatable(L, mttab); -+ /*tex |[{},{},{},"__index"]| */ -+ lua_pushstring(L, "__index"); -+ /*tex |[{},{},{},"__index","getdimen"]| */ -+ lua_pushstring(L, getfunc); -+ /*tex |[{},{},{},"__index",]| */ -+ lua_gettable(L, -5); -+ /*tex |[{},{},{}]| */ -+ lua_settable(L, -3); -+ lua_pushstring(L, "__newindex"); /*tex |[{},{},{},"__newindex"]| */ -+ /*tex |[{},{},{},"__newindex","setdimen"]| */ -+ lua_pushstring(L, setfunc); -+ /*tex |[{},{},{},"__newindex",]| */ -+ lua_gettable(L, -5); -+ /*tex |[{},{},{}]| */ -+ lua_settable(L, -3); -+ /*tex |[{},{}]| : assign the metatable */ -+ lua_setmetatable(L, -2); -+ /*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/texk/web2c/luatexdir/lua/luatoken.c b/texk/web2c/luatexdir/lua/luatoken.c -new file mode 100644 -index 000000000..fb197b68f ---- /dev/null -+++ b/texk/web2c/luatexdir/lua/luatoken.c -@@ -0,0 +1,585 @@ -+/* -+ -+luatoken.w -+ -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/lua/luatoken.w b/texk/web2c/luatexdir/lua/luatoken.w -deleted file mode 100644 -index e9740ffc6..000000000 ---- a/texk/web2c/luatexdir/lua/luatoken.w -+++ /dev/null -@@ -1,424 +0,0 @@ --% luatoken.w --% --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/lua/mplibstuff.c b/texk/web2c/luatexdir/lua/mplibstuff.c -new file mode 100644 -index 000000000..f1713ae0e ---- /dev/null -+++ b/texk/web2c/luatexdir/lua/mplibstuff.c -@@ -0,0 +1,115 @@ -+/* -+ -+mplibstuff.w -+ -+Copyright 2017 LuaTeX team -+ -+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 . -+ -+*/ -+ -+/*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 -+ -+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/texk/web2c/luatexdir/lua/mplibstuff.w b/texk/web2c/luatexdir/lua/mplibstuff.w -deleted file mode 100644 -index 3104a2870..000000000 ---- a/texk/web2c/luatexdir/lua/mplibstuff.w -+++ /dev/null -@@ -1,93 +0,0 @@ --% mplibstuff.w --% --% Copyright 2017 LuaTeX team --% --% 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 . -- --@ 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 -- --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/texk/web2c/luatexdir/lua/texluac.c b/texk/web2c/luatexdir/lua/texluac.c -new file mode 100644 -index 000000000..61016cfdb ---- /dev/null -+++ b/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 -+ -+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 -+#include -+#include -+#include -+#include -+ -+#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; itop+(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; ip[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; i1); -+ 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; ik[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; pc0) -+ 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; isizelocvars; -+ printf("locals (%d) for %p:\n",n,VOID(f)); -+ for (i=0; ilocvars[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; iupvalues[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; ip[i],full); -+} -diff --git a/texk/web2c/luatexdir/lua/texluac.w b/texk/web2c/luatexdir/lua/texluac.w -deleted file mode 100644 -index 424c74c77..000000000 ---- a/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 --% --% 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 --#include --#include --#include --#include -- --#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; itop+(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; ip[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; i1); -- 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; ik[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; pc0) 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; isizelocvars; -- printf("locals (%d) for %p:\n",n,VOID(f)); -- for (i=0; ilocvars[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; iupvalues[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; ip[i],full); --} -diff --git a/texk/web2c/luatexdir/lua/texluajitc.c b/texk/web2c/luatexdir/lua/texluajitc.c -new file mode 100644 -index 000000000..5cac5d65a ---- /dev/null -+++ b/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 -+#include -+#include -+ -+#define luajit_c -+ -+#include "lua.h" -+#include "lauxlib.h" -+#include "lualib.h" -+#include "luajit.h" -+ -+#include "lj_arch.h" -+ -+#if LJ_TARGET_POSIX -+#include -+#define lua_stdin_is_tty() isatty(0) -+#elif LJ_TARGET_WINDOWS -+#include -+#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 -+#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("")) - 1); -+ if (strstr(msg, LUA_QL("")) == 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/texk/web2c/luatexdir/lua/texluajitc.w b/texk/web2c/luatexdir/lua/texluajitc.w -deleted file mode 100644 -index f54f9c8d4..000000000 ---- a/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 --#include --#include -- --#define luajit_c -- --#include "lua.h" --#include "lauxlib.h" --#include "lualib.h" --#include "luajit.h" -- --#include "lj_arch.h" -- --#if LJ_TARGET_POSIX --#include --#define lua_stdin_is_tty() isatty(0) --#elif LJ_TARGET_WINDOWS --#include --#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 --#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("")) - 1); -- if (strstr(msg, LUA_QL("")) == 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/texk/web2c/luatexdir/pdf/pdfaction.w b/texk/web2c/luatexdir/pdf/pdfaction.c -similarity index 85% -rename from texk/web2c/luatexdir/pdf/pdfaction.w -rename to texk/web2c/luatexdir/pdf/pdfaction.c -index bb0d6e06d..2909ac6ad 100644 ---- a/texk/web2c/luatexdir/pdf/pdfaction.w -+++ b/texk/web2c/luatexdir/pdf/pdfaction.c -@@ -1,29 +1,29 @@ --% pdfaction.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfannot.w b/texk/web2c/luatexdir/pdf/pdfannot.c -similarity index 66% -rename from texk/web2c/luatexdir/pdf/pdfannot.w -rename to texk/web2c/luatexdir/pdf/pdfannot.c -index 43ee3692b..e501947c7 100644 ---- a/texk/web2c/luatexdir/pdf/pdfannot.w -+++ b/texk/web2c/luatexdir/pdf/pdfannot.c -@@ -1,27 +1,26 @@ --% pdfannot.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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 || 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/texk/web2c/luatexdir/pdf/pdfcolorstack.w b/texk/web2c/luatexdir/pdf/pdfcolorstack.c -similarity index 79% -rename from texk/web2c/luatexdir/pdf/pdfcolorstack.w -rename to texk/web2c/luatexdir/pdf/pdfcolorstack.c -index ac117d6ba..fbb88692f 100644 ---- a/texk/web2c/luatexdir/pdf/pdfcolorstack.w -+++ b/texk/web2c/luatexdir/pdf/pdfcolorstack.c -@@ -1,43 +1,53 @@ --% pdfcolorstack.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - --#include "ptexlib.h" -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . - --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/texk/web2c/luatexdir/pdf/pdfdest.w b/texk/web2c/luatexdir/pdf/pdfdest.c -similarity index 83% -rename from texk/web2c/luatexdir/pdf/pdfdest.w -rename to texk/web2c/luatexdir/pdf/pdfdest.c -index 74e8e4b1f..346cd26e0 100644 ---- a/texk/web2c/luatexdir/pdf/pdfdest.w -+++ b/texk/web2c/luatexdir/pdf/pdfdest.c -@@ -1,37 +1,40 @@ --% pdfdest.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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 || 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/texk/web2c/luatexdir/pdf/pdffont.w b/texk/web2c/luatexdir/pdf/pdffont.c -similarity index 51% -rename from texk/web2c/luatexdir/pdf/pdffont.w -rename to texk/web2c/luatexdir/pdf/pdffont.c -index 278efa9d6..1e1f0f8d9 100644 ---- a/texk/web2c/luatexdir/pdf/pdffont.w -+++ b/texk/web2c/luatexdir/pdf/pdffont.c -@@ -1,48 +1,50 @@ --% pdffont.w --% --% Copyright 2009-2014 Taco Hoekwater --% --% 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 . -- --\def\pdfTeX{pdf\TeX} -- --@ @c -+/* -+ -+Copyright 2009-2014 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfgen.w b/texk/web2c/luatexdir/pdf/pdfgen.c -similarity index 61% -rename from texk/web2c/luatexdir/pdf/pdfgen.w -rename to texk/web2c/luatexdir/pdf/pdfgen.c -index 26b7112ed..0409dbc33 100644 ---- a/texk/web2c/luatexdir/pdf/pdfgen.w -+++ b/texk/web2c/luatexdir/pdf/pdfgen.c -@@ -1,26 +1,26 @@ --% pdfgen.w --% --% Copyright 2009-2013 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #include "ptexlib.h" - --@ @c - #include - #include - #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", <); -- /* 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/texk/web2c/luatexdir/pdf/pdfglyph.w b/texk/web2c/luatexdir/pdf/pdfglyph.c -similarity index 63% -rename from texk/web2c/luatexdir/pdf/pdfglyph.w -rename to texk/web2c/luatexdir/pdf/pdfglyph.c -index 0703beed2..c7cf04392 100644 ---- a/texk/web2c/luatexdir/pdf/pdfglyph.w -+++ b/texk/web2c/luatexdir/pdf/pdfglyph.c -@@ -1,40 +1,47 @@ --% pdfglyph.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfimage.w b/texk/web2c/luatexdir/pdf/pdfimage.c -similarity index 50% -rename from texk/web2c/luatexdir/pdf/pdfimage.w -rename to texk/web2c/luatexdir/pdf/pdfimage.c -index fd3642438..a8cffb0c8 100644 ---- a/texk/web2c/luatexdir/pdf/pdfimage.w -+++ b/texk/web2c/luatexdir/pdf/pdfimage.c -@@ -1,38 +1,39 @@ --% pdfimage.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdflink.w b/texk/web2c/luatexdir/pdf/pdflink.c -similarity index 69% -rename from texk/web2c/luatexdir/pdf/pdflink.w -rename to texk/web2c/luatexdir/pdf/pdflink.c -index b21d0774e..55521b176 100644 ---- a/texk/web2c/luatexdir/pdf/pdflink.w -+++ b/texk/web2c/luatexdir/pdf/pdflink.c -@@ -1,31 +1,34 @@ --% pdflink.w --% --% Copyright 2009-2012 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdflistout.w b/texk/web2c/luatexdir/pdf/pdflistout.c -similarity index 66% -rename from texk/web2c/luatexdir/pdf/pdflistout.w -rename to texk/web2c/luatexdir/pdf/pdflistout.c -index 53ed24af6..9dbdaeefa 100644 ---- a/texk/web2c/luatexdir/pdf/pdflistout.w -+++ b/texk/web2c/luatexdir/pdf/pdflistout.c -@@ -1,120 +1,48 @@ --% pdflistout.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -+/* - --\def\pdfTeX{pdf\TeX} -+Copyright 2009-2010 Taco Hoekwater - --@ @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 . - --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/texk/web2c/luatexdir/pdf/pdfliteral.w b/texk/web2c/luatexdir/pdf/pdfliteral.c -similarity index 64% -rename from texk/web2c/luatexdir/pdf/pdfliteral.w -rename to texk/web2c/luatexdir/pdf/pdfliteral.c -index 94bb2c93c..e8b00a64e 100644 ---- a/texk/web2c/luatexdir/pdf/pdfliteral.w -+++ b/texk/web2c/luatexdir/pdf/pdfliteral.c -@@ -1,27 +1,26 @@ --% pdfliteral.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfobj.w b/texk/web2c/luatexdir/pdf/pdfobj.c -similarity index 72% -rename from texk/web2c/luatexdir/pdf/pdfobj.w -rename to texk/web2c/luatexdir/pdf/pdfobj.c -index e5ca09de6..71d6a943f 100644 ---- a/texk/web2c/luatexdir/pdf/pdfobj.w -+++ b/texk/web2c/luatexdir/pdf/pdfobj.c -@@ -1,44 +1,48 @@ --% pdfobj.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #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/texk/web2c/luatexdir/pdf/pdfoutline.w b/texk/web2c/luatexdir/pdf/pdfoutline.c -similarity index 82% -rename from texk/web2c/luatexdir/pdf/pdfoutline.w -rename to texk/web2c/luatexdir/pdf/pdfoutline.c -index 6c0a30a88..ae17e29da 100644 ---- a/texk/web2c/luatexdir/pdf/pdfoutline.w -+++ b/texk/web2c/luatexdir/pdf/pdfoutline.c -@@ -1,36 +1,46 @@ --% pdfoutline.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfpage.w b/texk/web2c/luatexdir/pdf/pdfpage.c -similarity index 74% -rename from texk/web2c/luatexdir/pdf/pdfpage.w -rename to texk/web2c/luatexdir/pdf/pdfpage.c -index ecc51ddfd..211248a02 100644 ---- a/texk/web2c/luatexdir/pdf/pdfpage.w -+++ b/texk/web2c/luatexdir/pdf/pdfpage.c -@@ -1,23 +1,23 @@ --% pdfpage.w --% --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #include "ptexlib.h" - -@@ -26,7 +26,6 @@ - #include - #include - --@ @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/texk/web2c/luatexdir/pdf/pdfpagetree.w b/texk/web2c/luatexdir/pdf/pdfpagetree.c -similarity index 56% -rename from texk/web2c/luatexdir/pdf/pdfpagetree.w -rename to texk/web2c/luatexdir/pdf/pdfpagetree.c -index 76d008c43..4fcd48e34 100644 ---- a/texk/web2c/luatexdir/pdf/pdfpagetree.w -+++ b/texk/web2c/luatexdir/pdf/pdfpagetree.c -@@ -1,38 +1,39 @@ --% pdfpagetree.w --% --% Copyright 2006-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - --#include "ptexlib.h" -+Copyright 2006-2011 Taco Hoekwater -+ -+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 . - --@ @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/texk/web2c/luatexdir/pdf/pdfrule.w b/texk/web2c/luatexdir/pdf/pdfrule.c -similarity index 56% -rename from texk/web2c/luatexdir/pdf/pdfrule.w -rename to texk/web2c/luatexdir/pdf/pdfrule.c -index df4979088..de689a147 100644 ---- a/texk/web2c/luatexdir/pdf/pdfrule.w -+++ b/texk/web2c/luatexdir/pdf/pdfrule.c -@@ -1,29 +1,26 @@ --% pdfrule.w --% --% Copyright 2010-2011 Taco Hoekwater --% --% 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 . -+/* - --@ @c --#include "ptexlib.h" --#include "pdf/pdfpage.h" -+Copyright 2010-2011 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/pdf/pdfsaverestore.w b/texk/web2c/luatexdir/pdf/pdfsaverestore.c -similarity index 63% -rename from texk/web2c/luatexdir/pdf/pdfsaverestore.w -rename to texk/web2c/luatexdir/pdf/pdfsaverestore.c -index 0d91de544..abfb48142 100644 ---- a/texk/web2c/luatexdir/pdf/pdfsaverestore.w -+++ b/texk/web2c/luatexdir/pdf/pdfsaverestore.c -@@ -1,32 +1,30 @@ --% pdfsaverestore.w --% --% Copyright 2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfsetmatrix.w b/texk/web2c/luatexdir/pdf/pdfsetmatrix.c -similarity index 65% -rename from texk/web2c/luatexdir/pdf/pdfsetmatrix.w -rename to texk/web2c/luatexdir/pdf/pdfsetmatrix.c -index b107033b9..f19c1721d 100644 ---- a/texk/web2c/luatexdir/pdf/pdfsetmatrix.w -+++ b/texk/web2c/luatexdir/pdf/pdfsetmatrix.c -@@ -1,34 +1,36 @@ --% pdfsetmatrix.w --% --% Copyright 2009 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfshipout.w b/texk/web2c/luatexdir/pdf/pdfshipout.c -similarity index 75% -rename from texk/web2c/luatexdir/pdf/pdfshipout.w -rename to texk/web2c/luatexdir/pdf/pdfshipout.c -index 8665f685e..084efc086 100644 ---- a/texk/web2c/luatexdir/pdf/pdfshipout.w -+++ b/texk/web2c/luatexdir/pdf/pdfshipout.c -@@ -1,51 +1,55 @@ --% pdfshipout.w --% --% Copyright 2010-2012 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2010-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdftables.w b/texk/web2c/luatexdir/pdf/pdftables.c -similarity index 79% -rename from texk/web2c/luatexdir/pdf/pdftables.w -rename to texk/web2c/luatexdir/pdf/pdftables.c -index 31fc2c9ad..180c23234 100644 ---- a/texk/web2c/luatexdir/pdf/pdftables.w -+++ b/texk/web2c/luatexdir/pdf/pdftables.c -@@ -1,27 +1,26 @@ --% pdftables.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfthread.w b/texk/web2c/luatexdir/pdf/pdfthread.c -similarity index 88% -rename from texk/web2c/luatexdir/pdf/pdfthread.w -rename to texk/web2c/luatexdir/pdf/pdfthread.c -index 6b3dd4b94..20cc7bf0a 100644 ---- a/texk/web2c/luatexdir/pdf/pdfthread.w -+++ b/texk/web2c/luatexdir/pdf/pdfthread.c -@@ -1,28 +1,32 @@ --% pdfthread.w --% --% Copyright 2009-2012 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+Copyright 2009-2012 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/pdf/pdfxform.w b/texk/web2c/luatexdir/pdf/pdfxform.c -similarity index 74% -rename from texk/web2c/luatexdir/pdf/pdfxform.w -rename to texk/web2c/luatexdir/pdf/pdfxform.c -index 731dc2290..7fd4eef1d 100644 ---- a/texk/web2c/luatexdir/pdf/pdfxform.w -+++ b/texk/web2c/luatexdir/pdf/pdfxform.c -@@ -1,28 +1,30 @@ --% pdfxform.w --% --% Copyright 2009-2011 Taco Hoekwater --% --% 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 . -+/* -+ -+Copyright 2009-2011 Taco Hoekwater -+ -+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 . -+ -+*/ - --@ @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 || 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/texk/web2c/luatexdir/tex/align.c b/texk/web2c/luatexdir/tex/align.c -new file mode 100644 -index 000000000..b2384cc62 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/align.c -@@ -0,0 +1,1297 @@ -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 \ token list: */ -+ -+#define u_part(A) vlink((A)+depth_offset) -+ -+/*tex The pointer to \ 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 \, 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 \, 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 \ 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 \ 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 \ 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 \ 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 k1$. 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) { -+ 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/texk/web2c/luatexdir/tex/align.w b/texk/web2c/luatexdir/tex/align.w -deleted file mode 100644 -index dd0ed1033..000000000 ---- a/texk/web2c/luatexdir/tex/align.w -+++ /dev/null -@@ -1,1144 +0,0 @@ --% align.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --\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 \ token list */ --#define v_part(A) vinfo((A)+depth_offset) /* pointer to \ 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 \, 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 \, 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 \ --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 \ 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 \ 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 \ 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 k1$. --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) { -- 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/texk/web2c/luatexdir/tex/arithmetic.c b/texk/web2c/luatexdir/tex/arithmetic.c -new file mode 100644 -index 000000000..2782c2534 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/arithmetic.c -@@ -0,0 +1,815 @@ -+/* -+ -+arithmetic.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 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= 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=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/texk/web2c/luatexdir/tex/arithmetic.w b/texk/web2c/luatexdir/tex/arithmetic.w -deleted file mode 100644 -index 56fb9568a..000000000 ---- a/texk/web2c/luatexdir/tex/arithmetic.w -+++ /dev/null -@@ -1,735 +0,0 @@ --% arithmetic.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --\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 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= 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=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/texk/web2c/luatexdir/tex/backend.c b/texk/web2c/luatexdir/tex/backend.c -new file mode 100644 -index 000000000..d8c7daed2 ---- /dev/null -+++ b/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/texk/web2c/luatexdir/tex/backend.h b/texk/web2c/luatexdir/tex/backend.h -new file mode 100644 -index 000000000..5cfbd06fb ---- /dev/null -+++ b/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/texk/web2c/luatexdir/tex/buildpage.c b/texk/web2c/luatexdir/tex/buildpage.c -new file mode 100644 -index 000000000..81e69dc3b ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/buildpage.c -@@ -0,0 +1,1164 @@ -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/tex/buildpage.w b/texk/web2c/luatexdir/tex/buildpage.w -deleted file mode 100644 -index cba07cbf6..000000000 ---- a/texk/web2c/luatexdir/tex/buildpage.w -+++ /dev/null -@@ -1,1013 +0,0 @@ --% buildpage.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/tex/commands.w b/texk/web2c/luatexdir/tex/commands.c -similarity index 92% -rename from texk/web2c/luatexdir/tex/commands.w -rename to texk/web2c/luatexdir/tex/commands.c -index 38975eb16..aceb0eb09 100644 ---- a/texk/web2c/luatexdir/tex/commands.w -+++ b/texk/web2c/luatexdir/tex/commands.c -@@ -1,34 +1,36 @@ --% commands.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --\def\eTeX{e-\TeX} -- --@ @c -+/* - -+commands.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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; -- @; -- @; -- @; --} -- - --@ These are in a separate module due to a CWEAVE limitation. -- --@= -- -- /* -+ /*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. -- --@= - 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. -- --@= - 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/texk/web2c/luatexdir/tex/conditional.w b/texk/web2c/luatexdir/tex/conditional.c -similarity index 61% -rename from texk/web2c/luatexdir/tex/conditional.w -rename to texk/web2c/luatexdir/tex/conditional.c -index 318775141..948db5803 100644 ---- a/texk/web2c/luatexdir/tex/conditional.w -+++ b/texk/web2c/luatexdir/tex/conditional.c -@@ -1,67 +1,73 @@ --% conditional.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+conditional.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/directions.w b/texk/web2c/luatexdir/tex/directions.c -similarity index 61% -rename from texk/web2c/luatexdir/tex/directions.w -rename to texk/web2c/luatexdir/tex/directions.c -index c844e934c..59b2f7dcd 100644 ---- a/texk/web2c/luatexdir/tex/directions.w -+++ b/texk/web2c/luatexdir/tex/directions.c -@@ -1,27 +1,28 @@ --% directions.w --% --% Copyright 2009-2014 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+directions.w -+ -+Copyright 2009-2014 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/dumpdata.w b/texk/web2c/luatexdir/tex/dumpdata.c -similarity index 56% -rename from texk/web2c/luatexdir/tex/dumpdata.w -rename to texk/web2c/luatexdir/tex/dumpdata.c -index 9d06f1c8e..0091685fb 100644 ---- a/texk/web2c/luatexdir/tex/dumpdata.w -+++ b/texk/web2c/luatexdir/tex/dumpdata.c -@@ -1,84 +1,97 @@ --% dumpdata.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+dumpdata.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/equivalents.w b/texk/web2c/luatexdir/tex/equivalents.c -similarity index 57% -rename from texk/web2c/luatexdir/tex/equivalents.w -rename to texk/web2c/luatexdir/tex/equivalents.c -index 271fc67ff..3d260d5c5 100644 ---- a/texk/web2c/luatexdir/tex/equivalents.w -+++ b/texk/web2c/luatexdir/tex/equivalents.c -@@ -1,29 +1,31 @@ --% equivalents.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+equivalents.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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 |save_level(p)| should replace the corresponding -+entry in |xeq_level| (if |save_value(p)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/texk/web2c/luatexdir/tex/errors.c b/texk/web2c/luatexdir/tex/errors.c -new file mode 100644 -index 000000000..b630422ee ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/errors.c -@@ -0,0 +1,1032 @@ -+/* -+ -+errors.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 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/texk/web2c/luatexdir/tex/errors.w b/texk/web2c/luatexdir/tex/errors.w -deleted file mode 100644 -index 93dbe141b..000000000 ---- a/texk/web2c/luatexdir/tex/errors.w -+++ /dev/null -@@ -1,972 +0,0 @@ --% errors.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ 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 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/texk/web2c/luatexdir/tex/expand.c b/texk/web2c/luatexdir/tex/expand.c -new file mode 100644 -index 000000000..a0a317db2 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/expand.c -@@ -0,0 +1,967 @@ -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 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 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/texk/web2c/luatexdir/tex/expand.w b/texk/web2c/luatexdir/tex/expand.w -deleted file mode 100644 -index c912863b2..000000000 ---- a/texk/web2c/luatexdir/tex/expand.w -+++ /dev/null -@@ -1,829 +0,0 @@ --% expand.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @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 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 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/texk/web2c/luatexdir/tex/extensions.c b/texk/web2c/luatexdir/tex/extensions.c -new file mode 100644 -index 000000000..d5914db8a ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/extensions.c -@@ -0,0 +1,1329 @@ -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/tex/extensions.w b/texk/web2c/luatexdir/tex/extensions.w -deleted file mode 100644 -index 73dc3ba45..000000000 ---- a/texk/web2c/luatexdir/tex/extensions.w -+++ /dev/null -@@ -1,1211 +0,0 @@ --% extensions.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --\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.) --@^ -- --@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/texk/web2c/luatexdir/tex/filename.w b/texk/web2c/luatexdir/tex/filename.c -similarity index 56% -rename from texk/web2c/luatexdir/tex/filename.w -rename to texk/web2c/luatexdir/tex/filename.c -index 9e5d9c5cc..fdc6641ef 100644 ---- a/texk/web2c/luatexdir/tex/filename.w -+++ b/texk/web2c/luatexdir/tex/filename.c -@@ -1,59 +1,62 @@ --% filename.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+filename.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/inputstack.w b/texk/web2c/luatexdir/tex/inputstack.c -similarity index 53% -rename from texk/web2c/luatexdir/tex/inputstack.w -rename to texk/web2c/luatexdir/tex/inputstack.c -index 68b22e1a3..c64111edc 100644 ---- a/texk/web2c/luatexdir/tex/inputstack.w -+++ b/texk/web2c/luatexdir/tex/inputstack.c -@@ -1,51 +1,85 @@ --% inputstack.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+inputstack.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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(" "); - break; -+ case local_text: -+ tprint_nl(" "); -+ 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(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(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/texk/web2c/luatexdir/tex/linebreak.c b/texk/web2c/luatexdir/tex/linebreak.c -new file mode 100644 -index 000000000..df13931e1 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/linebreak.c -@@ -0,0 +1,2520 @@ -+/* -+ -+Copyright 2006-2008 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/tex/linebreak.w b/texk/web2c/luatexdir/tex/linebreak.w -deleted file mode 100644 -index 345a1a424..000000000 ---- a/texk/web2c/luatexdir/tex/linebreak.w -+++ /dev/null -@@ -1,2164 +0,0 @@ --% linebreak.w --% --% Copyright 2006-2008 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/tex/mainbody.c b/texk/web2c/luatexdir/tex/mainbody.c -new file mode 100644 -index 000000000..ca9a79dbb ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/mainbody.c -@@ -0,0 +1,769 @@ -+/* -+ -+mainbody.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/tex/mainbody.w b/texk/web2c/luatexdir/tex/mainbody.w -deleted file mode 100644 -index 4d38b9d4a..000000000 ---- a/texk/web2c/luatexdir/tex/mainbody.w -+++ /dev/null -@@ -1,708 +0,0 @@ --% mainbody.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --\def\eTeX{e-\TeX} --\def\Aleph{Aleph} --\def\pdfTeX{pdf\TeX} -- --@ @c -- -- --#include "ptexlib.h" -- --@ --pdfTeX is copyright (C) 1996-2006 Han The Thanh, . -- --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/texk/web2c/luatexdir/tex/maincontrol.w b/texk/web2c/luatexdir/tex/maincontrol.c -similarity index 66% -rename from texk/web2c/luatexdir/tex/maincontrol.w -rename to texk/web2c/luatexdir/tex/maincontrol.c -index 7b4cf9065..295e2c6cc 100644 ---- a/texk/web2c/luatexdir/tex/maincontrol.w -+++ b/texk/web2c/luatexdir/tex/maincontrol.c -@@ -1,80 +1,79 @@ --% maincontrol.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+maincontrol.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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 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 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 '.", -- "I found the , but there's no suitable", -- ", so I'm ignoring these leaders."); -+ help3( -+ "You should say `\\leaders '.", -+ "I found the , but there's no suitable", -+ ", 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 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 to \\cs'.", -- "I'm going to look for the \\cs now."); -+ help2( -+ "You should have said `\\read 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= 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/texk/web2c/luatexdir/tex/mathcodes.w b/texk/web2c/luatexdir/tex/mathcodes.c -similarity index 80% -rename from texk/web2c/luatexdir/tex/mathcodes.w -rename to texk/web2c/luatexdir/tex/mathcodes.c -index a0a357e53..42e8b0b15 100644 ---- a/texk/web2c/luatexdir/tex/mathcodes.w -+++ b/texk/web2c/luatexdir/tex/mathcodes.c -@@ -1,81 +1,88 @@ --% mathnodes.w --% --% Copyright 2006-2012 Taco Hoekwater --% Copyright 2012 Khaled Hosny --% --% 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 . -- --@ @c -+/* -+ -+mathnodes.w -+ -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/memoryword.c b/texk/web2c/luatexdir/tex/memoryword.c -new file mode 100644 -index 000000000..7bf758dd0 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/memoryword.c -@@ -0,0 +1,29 @@ -+/* -+memoryword.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+ -+/*tex -+ -+The debug code is no longer present! -+ -+*/ -diff --git a/texk/web2c/luatexdir/tex/memoryword.w b/texk/web2c/luatexdir/tex/memoryword.w -deleted file mode 100644 -index b596abb37..000000000 ---- a/texk/web2c/luatexdir/tex/memoryword.w -+++ /dev/null -@@ -1,55 +0,0 @@ --% memoryword.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/tex/mlist.w b/texk/web2c/luatexdir/tex/mlist.c -similarity index 66% -rename from texk/web2c/luatexdir/tex/mlist.w -rename to texk/web2c/luatexdir/tex/mlist.c -index 291ce8c48..8f6d71eb2 100644 ---- a/texk/web2c/luatexdir/tex/mlist.w -+++ b/texk/web2c/luatexdir/tex/mlist.c -@@ -1,71 +1,72 @@ --% mlist.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --% (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 -+ -+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 . -+ -+*/ -+ -+/*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 ..{}{}} : */ -+ /*tex for \.{\\Uroot ..{}{}} : */ - 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/texk/web2c/luatexdir/tex/nesting.c b/texk/web2c/luatexdir/tex/nesting.c -new file mode 100644 -index 000000000..0e50c1031 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/nesting.c -@@ -0,0 +1,429 @@ -+/* -+ -+nesting.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/tex/nesting.w b/texk/web2c/luatexdir/tex/nesting.w -deleted file mode 100644 -index d9e7cf744..000000000 ---- a/texk/web2c/luatexdir/tex/nesting.w -+++ /dev/null -@@ -1,436 +0,0 @@ --% nesting.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @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/texk/web2c/luatexdir/tex/packaging.w b/texk/web2c/luatexdir/tex/packaging.c -similarity index 62% -rename from texk/web2c/luatexdir/tex/packaging.w -rename to texk/web2c/luatexdir/tex/packaging.c -index f094a0d96..e2b007f11 100644 ---- a/texk/web2c/luatexdir/tex/packaging.w -+++ b/texk/web2c/luatexdir/tex/packaging.c -@@ -1,84 +1,68 @@ --% packaging.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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 to ';", -- "will look for the next."); -+ help2( -+ "I'm working on `\\vsplit to ';", -+ "will look for the 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/texk/web2c/luatexdir/tex/postlinebreak.w b/texk/web2c/luatexdir/tex/postlinebreak.c -similarity index 52% -rename from texk/web2c/luatexdir/tex/postlinebreak.w -rename to texk/web2c/luatexdir/tex/postlinebreak.c -index dd85cf01b..cbc77e556 100644 ---- a/texk/web2c/luatexdir/tex/postlinebreak.w -+++ b/texk/web2c/luatexdir/tex/postlinebreak.c -@@ -1,60 +1,65 @@ --% postlinebreak.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -+/* - --@ @c -+postlinebreak.w - -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/primitive.c b/texk/web2c/luatexdir/tex/primitive.c -new file mode 100644 -index 000000000..f16d69a33 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/primitive.c -@@ -0,0 +1,785 @@ -+/* -+ -+primitive.w -+ -+Copyright 2008-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 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 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 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/texk/web2c/luatexdir/tex/primitive.w b/texk/web2c/luatexdir/tex/primitive.w -deleted file mode 100644 -index 8c6592c9e..000000000 ---- a/texk/web2c/luatexdir/tex/primitive.w -+++ /dev/null -@@ -1,664 +0,0 @@ --% primitive.w --% --% Copyright 2008-2010 Taco Hoekwater --% --% 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 . -- --@ @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 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 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 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/texk/web2c/luatexdir/tex/printing.w b/texk/web2c/luatexdir/tex/printing.c -similarity index 63% -rename from texk/web2c/luatexdir/tex/printing.w -rename to texk/web2c/luatexdir/tex/printing.c -index 724441564..0a961071b 100644 ---- a/texk/web2c/luatexdir/tex/printing.w -+++ b/texk/web2c/luatexdir/tex/printing.c -@@ -1,87 +1,137 @@ --% printing.w --% --% Copyright 2009-2013 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+printing.w -+ -+Copyright 2009-2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #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 -+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 xyz --3 xyz -+3 xyz - 4 - 5 --6 xyz -+6 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/texk/web2c/luatexdir/tex/scanning.c b/texk/web2c/luatexdir/tex/scanning.c -new file mode 100644 -index 000000000..8f7e1d591 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/scanning.c -@@ -0,0 +1,2743 @@ -+/* -+ -+Copyright 2009-2012 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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_cmdmax_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= 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/texk/web2c/luatexdir/tex/scanning.w b/texk/web2c/luatexdir/tex/scanning.w -deleted file mode 100644 -index 7bed4d290..000000000 ---- a/texk/web2c/luatexdir/tex/scanning.w -+++ /dev/null -@@ -1,2621 +0,0 @@ --% scanning.w --% --% Copyright 2009-2012 Taco Hoekwater --% --% 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 . -- --@ @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_cmdmax_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= 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/texk/web2c/luatexdir/tex/stringpool.w b/texk/web2c/luatexdir/tex/stringpool.c -similarity index 53% -rename from texk/web2c/luatexdir/tex/stringpool.w -rename to texk/web2c/luatexdir/tex/stringpool.c -index 5972657f5..bc09f814b 100644 ---- a/texk/web2c/luatexdir/tex/stringpool.w -+++ b/texk/web2c/luatexdir/tex/stringpool.c -@@ -1,69 +1,89 @@ --% stringpool.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+stringpool.w -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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= 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/texk/web2c/luatexdir/tex/texdeffont.w b/texk/web2c/luatexdir/tex/texdeffont.c -similarity index 50% -rename from texk/web2c/luatexdir/tex/texdeffont.w -rename to texk/web2c/luatexdir/tex/texdeffont.c -index 7fe5ae1e1..f0b057d40 100644 ---- a/texk/web2c/luatexdir/tex/texdeffont.w -+++ b/texk/web2c/luatexdir/tex/texdeffont.c -@@ -1,57 +1,73 @@ --% texdeffont.w --% --% Copyright 2008-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - -+texdeffont.w -+ -+Copyright 2008-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/texfileio.c b/texk/web2c/luatexdir/tex/texfileio.c -new file mode 100644 -index 000000000..143e694e1 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/texfileio.c -@@ -0,0 +1,1509 @@ -+/* -+ -+Copyright 2009-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+ -+#include -+#include -+ -+/*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 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 -+ 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 \.{}: */ -+ 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} \.= \.{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" "|. -+ -+*/ -+ -+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/texk/web2c/luatexdir/tex/texfileio.w b/texk/web2c/luatexdir/tex/texfileio.w -deleted file mode 100644 -index a10e9ba63..000000000 ---- a/texk/web2c/luatexdir/tex/texfileio.w -+++ /dev/null -@@ -1,1389 +0,0 @@ --% texfileio.w --% --% Copyright 2009-2010 Taco Hoekwater --% --% 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 . -- --@ @c -- -- --#include "ptexlib.h" -- --#include --#include -- --@ 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 -- --@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 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 \.{} */ -- 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} \.= \.{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 -- --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" "|. -- --@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/texk/web2c/luatexdir/tex/texmath.w b/texk/web2c/luatexdir/tex/texmath.c -similarity index 61% -rename from texk/web2c/luatexdir/tex/texmath.w -rename to texk/web2c/luatexdir/tex/texmath.c -index 6d4b87a38..69e58b0ea 100644 ---- a/texk/web2c/luatexdir/tex/texmath.w -+++ b/texk/web2c/luatexdir/tex/texmath.c -@@ -1,46 +1,43 @@ --% texmath.w --% --% Copyright 2008-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+Copyright 2008-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #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(""); -- 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(""); -+ 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/texk/web2c/luatexdir/tex/texnodes.c b/texk/web2c/luatexdir/tex/texnodes.c -new file mode 100644 -index 000000000..1dd28cdf5 ---- /dev/null -+++ b/texk/web2c/luatexdir/tex/texnodes.c -@@ -0,0 +1,4770 @@ -+/* -+ -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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 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(""); -+ 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/texk/web2c/luatexdir/tex/texnodes.w b/texk/web2c/luatexdir/tex/texnodes.w -deleted file mode 100644 -index 0c8bdb837..000000000 ---- a/texk/web2c/luatexdir/tex/texnodes.w -+++ /dev/null -@@ -1,3910 +0,0 @@ --% texnodes.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @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 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(""); -- 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/texk/web2c/luatexdir/tex/textcodes.w b/texk/web2c/luatexdir/tex/textcodes.c -similarity index 84% -rename from texk/web2c/luatexdir/tex/textcodes.w -rename to texk/web2c/luatexdir/tex/textcodes.c -index 89e936841..a6a0b3a55 100644 ---- a/texk/web2c/luatexdir/tex/textcodes.w -+++ b/texk/web2c/luatexdir/tex/textcodes.c -@@ -1,27 +1,35 @@ --% textcodes.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -- --@ @c -+/* -+ -+textcodes.w -+ -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ - - #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/texk/web2c/luatexdir/tex/textoken.w b/texk/web2c/luatexdir/tex/textoken.c -similarity index 63% -rename from texk/web2c/luatexdir/tex/textoken.w -rename to texk/web2c/luatexdir/tex/textoken.c -index d58aa3dc4..6056bba25 100644 ---- a/texk/web2c/luatexdir/tex/textoken.w -+++ b/texk/web2c/luatexdir/tex/textoken.c -@@ -1,40 +1,26 @@ --% textoken.w --% --% Copyright 2006-2011 Taco Hoekwater --% --% 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 . -- --@ @c -+/* - --#include "ptexlib.h" -+Copyright 2006-2011 Taco Hoekwater - --@ @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 . - --/* --#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 -- --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= 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 ^^ -+ 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 ^^ -+ \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/texk/web2c/luatexdir/utils/avlstuff.c b/texk/web2c/luatexdir/utils/avlstuff.c -new file mode 100644 -index 000000000..887ba4f46 ---- /dev/null -+++ b/texk/web2c/luatexdir/utils/avlstuff.c -@@ -0,0 +1,63 @@ -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2009 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#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/texk/web2c/luatexdir/utils/avlstuff.w b/texk/web2c/luatexdir/utils/avlstuff.w -deleted file mode 100644 -index 1ea148b09..000000000 ---- a/texk/web2c/luatexdir/utils/avlstuff.w -+++ /dev/null -@@ -1,61 +0,0 @@ --% avlstuff.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2009 Taco Hoekwater --% --% 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 . -- --@* 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/texk/web2c/luatexdir/utils/managed-sa.w b/texk/web2c/luatexdir/utils/managed-sa.c -similarity index 79% -rename from texk/web2c/luatexdir/utils/managed-sa.w -rename to texk/web2c/luatexdir/utils/managed-sa.c -index 6ac4a68ac..6cf10e301 100644 ---- a/texk/web2c/luatexdir/utils/managed-sa.w -+++ b/texk/web2c/luatexdir/utils/managed-sa.c -@@ -1,36 +1,36 @@ --% managed-sa.w --% --% Copyright 2006-2010 Taco Hoekwater --% --% 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 . -+/* - --@* Sparse arrays with an embedded save stack. -+Copyright 2006-2010 Taco Hoekwater - --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 . -+ -+*/ -+ -+/*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/texk/web2c/luatexdir/utils/unistring.w b/texk/web2c/luatexdir/utils/unistring.c -similarity index 75% -rename from texk/web2c/luatexdir/utils/unistring.w -rename to texk/web2c/luatexdir/utils/unistring.c -index a5b365a5f..6c95ee31e 100644 ---- a/texk/web2c/luatexdir/utils/unistring.w -+++ b/texk/web2c/luatexdir/utils/unistring.c -@@ -1,34 +1,29 @@ --% unistring.w --% --% Copyright 2013 Taco Hoekwater --% --% 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 . -- --@ @c -- -- --@ @c -+/* -+ -+Copyright 2013 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #include "ptexlib.h" - #include - --@ @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/texk/web2c/luatexdir/utils/utils.w b/texk/web2c/luatexdir/utils/utils.c -similarity index 63% -rename from texk/web2c/luatexdir/utils/utils.w -rename to texk/web2c/luatexdir/utils/utils.c -index 420f5cfe4..55ff1cb3e 100644 ---- a/texk/web2c/luatexdir/utils/utils.w -+++ b/texk/web2c/luatexdir/utils/utils.c -@@ -1,51 +1,52 @@ --% utils.w --% --% Copyright 1996-2006 Han The Thanh --% Copyright 2006-2012 Taco Hoekwater --% --% 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 . -- --@ @c -- -- --@ @c -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2012 Taco Hoekwater -+ -+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 . -+ -+*/ -+ - #include "ptexlib.h" - --#include /* 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 - #include "sys/types.h" - #include - #include - #include - #include --#include /* for |DBL_EPSILON| */ -+ -+/*tex For |DBL_EPSILON|: */ -+ -+#include -+ - #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 -+ - 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 -- * Adrian Johnson -- */ -+ -+/* -+ -+ _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 -+ Adrian Johnson -+ -+*/ - - #include - #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 - #include - --/* 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 ---- texlive-source/texk/web2c/luatexdir/font/luafont.c.me 1970-01-01 01:00:00.000000000 +0100 -+++ texlive-source/texk/web2c/luatexdir/font/luafont.c 2020-11-07 15:50:28.079336523 +0100 -@@ -0,0 +1,2420 @@ -+/* -+ -+Copyright 2006-2011 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+#include "lua/luatex-api.h" -+ -+#define noVERBOSE -+ -+/*tex -+ -+ Todo: make these keys. -+ -+*/ -+ -+const char *font_type_strings[] = { -+ "unknown", "virtual", "real", NULL -+}; -+ -+const char *font_writingmode_strings[] = { -+ "unknown", "horizontal", "vertical", NULL -+}; -+ -+const char *font_identity_strings[] = { -+ "unknown", "horizontal", "vertical", NULL -+}; -+ -+const char *font_format_strings[] = { -+ "unknown", "type1", "type3", "truetype", "opentype", NULL -+}; -+ -+const char *font_embedding_strings[] = { -+ "unknown", "no", "subset", "full", NULL -+}; -+ -+const char *ligature_type_strings[] = { -+ "=:", "=:|", "|=:", "|=:|", "", "=:|>", "|=:>", "|=:|>", "", "", "", "|=:|>>", NULL -+}; -+ -+const char *MATH_param_names[] = { -+ "nil", -+ "ScriptPercentScaleDown", -+ "ScriptScriptPercentScaleDown", -+ "DelimitedSubFormulaMinHeight", -+ "DisplayOperatorMinHeight", -+ "MathLeading", -+ "AxisHeight", -+ "AccentBaseHeight", -+ "FlattenedAccentBaseHeight", -+ "SubscriptShiftDown", -+ "SubscriptTopMax", -+ "SubscriptBaselineDropMin", -+ "SuperscriptShiftUp", -+ "SuperscriptShiftUpCramped", -+ "SuperscriptBottomMin", -+ "SuperscriptBaselineDropMax", -+ "SubSuperscriptGapMin", -+ "SuperscriptBottomMaxWithSubscript", -+ "SpaceAfterScript", -+ "UpperLimitGapMin", -+ "UpperLimitBaselineRiseMin", -+ "LowerLimitGapMin", -+ "LowerLimitBaselineDropMin", -+ "StackTopShiftUp", -+ "StackTopDisplayStyleShiftUp", -+ "StackBottomShiftDown", -+ "StackBottomDisplayStyleShiftDown", -+ "StackGapMin", -+ "StackDisplayStyleGapMin", -+ "StretchStackTopShiftUp", -+ "StretchStackBottomShiftDown", -+ "StretchStackGapAboveMin", -+ "StretchStackGapBelowMin", -+ "FractionNumeratorShiftUp", -+ "FractionNumeratorDisplayStyleShiftUp", -+ "FractionDenominatorShiftDown", -+ "FractionDenominatorDisplayStyleShiftDown", -+ "FractionNumeratorGapMin", -+ "FractionNumeratorDisplayStyleGapMin", -+ "FractionRuleThickness", -+ "FractionDenominatorGapMin", -+ "FractionDenominatorDisplayStyleGapMin", -+ "SkewedFractionHorizontalGap", -+ "SkewedFractionVerticalGap", -+ "OverbarVerticalGap", -+ "OverbarRuleThickness", -+ "OverbarExtraAscender", -+ "UnderbarVerticalGap", -+ "UnderbarRuleThickness", -+ "UnderbarExtraDescender", -+ "RadicalVerticalGap", -+ "RadicalDisplayStyleVerticalGap", -+ "RadicalRuleThickness", -+ "RadicalExtraAscender", -+ "RadicalKernBeforeDegree", -+ "RadicalKernAfterDegree", -+ "RadicalDegreeBottomRaisePercent", -+ "MinConnectorOverlap", -+ "SubscriptShiftDownWithSuperscript", -+ "FractionDelimiterSize", -+ "FractionDelimiterDisplayStyleSize", -+ "NoLimitSubFactor", -+ "NoLimitSupFactor", -+ NULL, -+}; -+ -+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]); -+ -+int ff_checkoption (lua_State *L, int narg, const char *def, const char *const lst[]) { -+ const char *name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg); -+ int i; -+ for (i=0; lst[i]; i++) -+ if (strcmp(lst[i], name) == 0) -+ return i; -+ return -1; -+} -+ -+#define dump_intfield(L,n,c) \ -+ lua_push_string_by_name(L,n); \ -+ lua_pushinteger(L, c); \ -+ lua_rawset(L, -3); \ -+ -+#define dump_stringfield(L,n,c) \ -+ lua_push_string_by_name(L,n); \ -+ lua_pushstring(L, c); \ -+ lua_rawset(L, -3); -+ -+#define dump_booleanfield(L,n,c) \ -+ lua_push_string_by_name(L,n); \ -+ lua_pushboolean(L, c); \ -+ lua_rawset(L, -3); -+ -+static void dump_math_kerns(lua_State * L, charinfo * co, int l, int id) -+{ -+ int i; -+ for (i = 0; i < l; i++) { -+ lua_newtable(L); -+ if (id==top_left_kern) { -+ dump_intfield(L, height, co->top_left_math_kern_array[(2*i)]); -+ dump_intfield(L, kern, co->top_left_math_kern_array[(2*i)+1]); -+ } else if (id==top_right_kern) { -+ dump_intfield(L, height, co->top_right_math_kern_array[(2*i)]); -+ dump_intfield(L, kern, co->top_right_math_kern_array[(2*i)+1]); -+ } else if (id==bottom_right_kern) { -+ dump_intfield(L, height, co->bottom_right_math_kern_array[(2*i)]); -+ dump_intfield(L, kern, co->bottom_right_math_kern_array[(2*i)+1]); -+ } else if (id==bottom_left_kern) { -+ dump_intfield(L, height, co->bottom_left_math_kern_array[(2*i)]); -+ dump_intfield(L, kern, co->bottom_left_math_kern_array[(2*i)+1]); -+ } -+ lua_rawseti(L, -2, (i + 1)); -+ } -+} -+ -+static void font_char_to_lua(lua_State * L, internal_font_number f, charinfo * co) -+{ -+ liginfo *l; -+ kerninfo *ki; -+ lua_createtable(L, 0, 10); -+ dump_intfield(L,width,get_charinfo_width(co)); -+ dump_intfield(L,height,get_charinfo_height(co)); -+ dump_intfield(L,depth,get_charinfo_depth(co)); -+ if (get_charinfo_italic(co) != 0) { -+ dump_intfield(L,italic,get_charinfo_italic(co)); -+ } -+ if (get_charinfo_vert_italic(co) != 0) { -+ dump_intfield(L,vert_italic,get_charinfo_vert_italic(co)); -+ } -+ if (get_charinfo_top_accent(co) !=0 && get_charinfo_top_accent(co) != INT_MIN) { -+ dump_intfield(L,top_accent,get_charinfo_top_accent(co)); -+ } -+ if (get_charinfo_bot_accent(co) != 0 && get_charinfo_bot_accent(co) != INT_MIN) { -+ dump_intfield(L,bot_accent,get_charinfo_bot_accent(co)); -+ } -+ if (get_charinfo_ef(co) != 1000) { -+ dump_intfield(L,expansion_factor,get_charinfo_ef(co)); -+ } -+ if (get_charinfo_lp(co) != 0) { -+ dump_intfield(L,left_protruding,get_charinfo_lp(co)); -+ } -+ if (get_charinfo_rp(co) != 0) { -+ dump_intfield(L,right_protruding,get_charinfo_rp(co)); -+ } -+ if (font_encodingbytes(f) == 2) { -+ dump_intfield(L,index,get_charinfo_index(co)); -+ } -+ if (get_charinfo_name(co) != NULL) { -+ dump_stringfield(L,name,get_charinfo_name(co)); -+ } -+ if (get_charinfo_tounicode(co) != NULL) { -+ dump_stringfield(L,tounicode,get_charinfo_tounicode(co)); -+ } -+ if (get_charinfo_tag(co) == list_tag) { -+ dump_intfield(L,next,get_charinfo_remainder(co)); -+ } -+ if (get_charinfo_used(co)) { -+ dump_booleanfield(L,used,(get_charinfo_used(co) ? true : false)); -+ } -+ if (get_charinfo_tag(co) == ext_tag) { -+ extinfo *h; -+ h = get_charinfo_hor_variants(co); -+ if (h != NULL) { -+ int i = 1; -+ lua_push_string_by_name(L,horiz_variants); -+ lua_newtable(L); -+ while (h != NULL) { -+ lua_createtable(L, 0, 5); -+ dump_intfield(L, glyph, h->glyph); -+ dump_intfield(L, extender, h->extender); -+ dump_intfield(L, start, h->start_overlap); -+ dump_intfield(L, end, h->end_overlap); -+ dump_intfield(L, advance, h->advance); -+ lua_rawseti(L, -2, i); -+ i++; -+ h = h->next; -+ } -+ lua_rawset(L, -3); -+ } -+ h = get_charinfo_vert_variants(co); -+ if (h != NULL) { -+ int i = 1; -+ lua_push_string_by_name(L,vert_variants); -+ lua_newtable(L); -+ while (h != NULL) { -+ lua_createtable(L, 0, 5); -+ dump_intfield(L, glyph, h->glyph); -+ dump_intfield(L, extender, h->extender); -+ dump_intfield(L, start, h->start_overlap); -+ dump_intfield(L, end, h->end_overlap); -+ dump_intfield(L, advance, h->advance); -+ lua_rawseti(L, -2, i); -+ i++; -+ h = h->next; -+ } -+ lua_rawset(L, -3); -+ } -+ } -+ ki = get_charinfo_kerns(co); -+ if (ki != NULL) { -+ int i; -+ lua_push_string_by_name(L,kerns); -+ lua_createtable(L, 10, 1); -+ for (i = 0; !kern_end(ki[i]); i++) { -+ if (kern_disabled(ki[i])) { -+ /*tex Skip like in lookup. */ -+ } else { -+ lua_rawgeti(L, -1, kern_char(ki[i])); -+ if (lua_type(L,-1) == LUA_TNIL) { -+ lua_pop(L,1); -+ if (kern_char(ki[i]) == right_boundarychar) { -+ lua_push_string_by_name(L,right_boundary); -+ } else { -+ lua_pushinteger(L, kern_char(ki[i])); -+ } -+ lua_pushinteger(L, kern_kern(ki[i])); -+ lua_rawset(L, -3); -+ } else { -+ /*tex The first one wins. */ -+ lua_pop(L,1); -+ } -+ } -+ } -+ lua_rawset(L, -3); -+ } -+ l = get_charinfo_ligatures(co); -+ if (l != NULL) { -+ int i; -+ lua_push_string_by_name(L,ligatures); -+ lua_createtable(L, 10, 1); -+ for (i = 0; !lig_end(l[i]); i++) { -+ if (lig_char(l[i]) == right_boundarychar) { -+ lua_push_string_by_name(L,right_boundary); -+ } else { -+ lua_pushinteger(L, lig_char(l[i])); -+ } -+ lua_createtable(L, 0, 2); -+ lua_push_string_by_name(L,type); -+ lua_pushinteger(L, lig_type(l[i])); -+ lua_rawset(L, -3); -+ lua_push_string_by_name(L,char); -+ lua_pushinteger(L, lig_replacement(l[i])); -+ lua_rawset(L, -3); -+ lua_rawset(L, -3); -+ } -+ lua_rawset(L, -3); -+ } -+ lua_push_string_by_name(L,mathkern); -+ lua_newtable(L); -+ { -+ int i, j; -+ i = get_charinfo_math_kerns(co, top_right_kern); -+ j = 0; -+ if (i > 0) { -+ j++; -+ lua_push_string_by_name(L,top_right); -+ lua_newtable(L); -+ dump_math_kerns(L, co, i, top_right_kern); -+ lua_rawset(L, -3); -+ } -+ i = get_charinfo_math_kerns(co, top_left_kern); -+ if (i > 0) { -+ j++; -+ lua_push_string_by_name(L,top_left); -+ lua_newtable(L); -+ dump_math_kerns(L, co, i, top_left_kern); -+ lua_rawset(L, -3); -+ } -+ i = get_charinfo_math_kerns(co, bottom_right_kern); -+ if (i > 0) { -+ j++; -+ lua_push_string_by_name(L,bottom_right); -+ lua_newtable(L); -+ dump_math_kerns(L, co, i, bottom_right_kern); -+ lua_rawset(L, -3); -+ } -+ i = get_charinfo_math_kerns(co, bottom_left_kern); -+ if (i > 0) { -+ j++; -+ lua_push_string_by_name(L,bottom_left); -+ lua_newtable(L); -+ dump_math_kerns(L, co, i, bottom_left_kern); -+ lua_rawset(L, -3); -+ } -+ if (j > 0) -+ lua_rawset(L, -3); -+ else -+ lua_pop(L, 2); -+ } -+} -+ -+static void write_lua_parameters(lua_State * L, int f) -+{ -+ int k; -+ lua_push_string_by_name(L,parameters); -+ lua_newtable(L); -+ for (k = 1; k <= font_params(f); k++) { -+ switch (k) { -+ case slant_code: -+ dump_intfield(L,slant,font_param(f, k)); -+ break; -+ case space_code: -+ dump_intfield(L,space,font_param(f, k)); -+ break; -+ case space_stretch_code: -+ dump_intfield(L,space_stretch,font_param(f, k)); -+ break; -+ case space_shrink_code: -+ dump_intfield(L,space_shrink,font_param(f, k)); -+ break; -+ case x_height_code: -+ dump_intfield(L,x_height,font_param(f, k)); -+ break; -+ case quad_code: -+ dump_intfield(L,quad,font_param(f, k)); -+ break; -+ case extra_space_code: -+ dump_intfield(L,extra_space,font_param(f, k)); -+ break; -+ default: -+ lua_pushinteger(L, font_param(f, k)); -+ lua_rawseti(L, -2, k); -+ } -+ } -+ lua_rawset(L, -3); -+} -+ -+static void write_lua_math_parameters(lua_State * L, int f) -+{ -+ int k; -+ lua_push_string_by_name(L,MathConstants); -+ lua_newtable(L); -+ for (k = 1; k <= font_math_params(f); k++) { -+ lua_pushinteger(L, font_math_param(f, k)); -+ if (k <= MATH_param_max) { -+ lua_setfield(L, -2, MATH_param_names[k]); -+ } else { -+ lua_rawseti(L, -2, k); -+ } -+ } -+ lua_rawset(L, -3); -+} -+ -+int font_to_lua(lua_State * L, int f) -+{ -+ int k; -+ charinfo *co; -+ if (font_cache_id(f) > 0) { -+ /*tex Fetch the table from the registry if it was saved there by |font_from_lua|. */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, font_cache_id(f)); -+ /*tex Font dimenensions can be changed from \TEX\ code. */ -+ write_lua_parameters(L, f); -+ return 1; -+ } -+ lua_newtable(L); -+ lua_push_string_by_name(L,name); -+ lua_pushstring(L, font_name(f)); -+ lua_rawset(L, -3); -+ if (font_area(f) != NULL) { -+ dump_stringfield(L,area,font_area(f)); -+ } -+ if (font_filename(f) != NULL) { -+ dump_stringfield(L,filename,font_filename(f)); -+ } -+ if (font_fullname(f) != NULL) { -+ dump_stringfield(L,fullname,font_fullname(f)); -+ } -+ if (font_psname(f) != NULL) { -+ dump_stringfield(L,psname,font_psname(f)); -+ } -+ if (font_encodingname(f) != NULL) { -+ dump_stringfield(L,encodingname,font_encodingname(f)); -+ } -+ dump_booleanfield(L,used,(font_used(f) ? true : false)); -+ dump_stringfield(L,type,font_type_strings[font_type(f)]); -+ dump_stringfield(L,format,font_format_strings[font_format(f)]); -+ dump_stringfield(L,writingmode,font_writingmode_strings[font_writingmode(f)]); -+ dump_stringfield(L,identity,font_identity_strings[font_identity(f)]); -+ dump_stringfield(L,embedding,font_embedding_strings[font_embedding(f)]); -+ dump_intfield(L,streamprovider,font_streamprovider(f)); -+ dump_intfield(L,units_per_em,font_units_per_em(f)); -+ dump_intfield(L,size,font_size(f)); -+ dump_intfield(L,designsize,font_dsize(f)); -+ dump_intfield(L,checksum,font_checksum(f)); -+ dump_intfield(L,slant,font_slant(f)); -+ dump_intfield(L,extend,font_extend(f)); -+ dump_intfield(L,squeeze,font_squeeze(f)); -+ dump_intfield(L,mode,font_mode(f)); -+ dump_intfield(L,width,font_width(f)); -+ dump_intfield(L,direction,font_natural_dir(f)); -+ dump_intfield(L,encodingbytes,font_encodingbytes(f)); -+ dump_booleanfield(L,oldmath,font_oldmath(f)); -+ dump_intfield(L,tounicode,font_tounicode(f)); -+ /*tex The next one is read only: */ -+ if (font_max_shrink(f) != 0) { -+ dump_intfield(L,shrink,font_max_shrink(f)); -+ } -+ if (font_max_stretch(f) != 0) { -+ dump_intfield(L,stretch,font_max_stretch(f)); -+ } -+ if (font_step(f) != 0) { -+ dump_intfield(L,step,font_step(f)); -+ } -+ if (pdf_font_attr(f) != 0) { -+ char *s = makecstring(pdf_font_attr(f)); -+ dump_stringfield(L,attributes,s); -+ free(s); -+ } -+ /*tex Parameters: */ -+ write_lua_parameters(L, f); -+ write_lua_math_parameters(L, f); -+ /*tex Characters: */ -+ lua_push_string_by_name(L,characters); -+ lua_createtable(L, font_tables[f]->charinfo_size, 0); -+ if (has_left_boundary(f)) { -+ co = get_charinfo(f, left_boundarychar); -+ lua_push_string_by_name(L,left_boundary); -+ font_char_to_lua(L, f, co); -+ lua_rawset(L, -3); -+ } -+ if (has_right_boundary(f)) { -+ co = get_charinfo(f, right_boundarychar); -+ lua_push_string_by_name(L,right_boundary); -+ font_char_to_lua(L, f, co); -+ lua_rawset(L, -3); -+ } -+ for (k = font_bc(f); k <= font_ec(f); k++) { -+ if (quick_char_exists(f, k)) { -+ lua_pushinteger(L, k); -+ co = get_charinfo(f, k); -+ font_char_to_lua(L, f, co); -+ lua_rawset(L, -3); -+ } -+ } -+ lua_rawset(L, -3); -+ if (font_cache_id(f) == 0) { -+ /*tex Renew the cache. */ -+ int r; -+ lua_pushvalue(L, -1); -+ r = luaL_ref(L, LUA_REGISTRYINDEX); -+ set_font_cache_id(f, r); -+ } -+ return 1; -+} -+ -+#define count_hash_items(L,name,n) \ -+ n = 0; \ -+ lua_key_rawgeti(name); \ -+ if (lua_type(L, -1) == LUA_TTABLE) { \ -+ lua_pushnil(L); \ -+ while (lua_next(L, -2) != 0) { \ -+ n++; \ -+ lua_pop(L, 1); \ -+ } \ -+ } \ -+ if (n) { \ -+ /*tex Keep the table on stack. */ \ -+ } else{ \ -+ lua_pop(L, 1); \ -+ } -+ -+#define streq(a,b) (strcmp(a,b)==0) -+ -+#define append_packet(k) { *(cp++) = (eight_bits) (k); } -+ -+#define do_store_four(l) { \ -+ append_packet((l & 0xFF000000) >> 24); \ -+ append_packet((l & 0x00FF0000) >> 16); \ -+ append_packet((l & 0x0000FF00) >> 8); \ -+ append_packet((l & 0x000000FF)); \ -+} -+ -+static void append_float(eight_bits ** cpp, float a) -+{ -+ unsigned int i; -+ eight_bits *cp = *cpp; -+ union U { -+ float a; -+ eight_bits b[sizeof(float)]; -+ } u; -+ u.a = a; -+ for (i = 0; i < sizeof(float); i++) -+ append_packet(u.b[i]); -+ *cpp = cp; -+} -+ -+static int n_enum_field(lua_State * L, int name_index, int dflt, const char **values) -+{ -+ int k, t; -+ const char *s; -+ int i = dflt; -+ /*tex Fetch the string pointer: */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); -+ lua_rawget(L, -2); -+ t = lua_type(L,-1); -+ if (t == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -1); -+ } else if (t == LUA_TSTRING) { -+ s = lua_tostring(L, -1); -+ k = 0; -+ while (values[k] != NULL) { -+ if (strcmp(values[k], s) == 0) { -+ i = k; -+ break; -+ } -+ k++; -+ } -+ } -+ lua_pop(L, 1); -+ return i; -+} -+ -+static int n_boolean_field(lua_State * L, int name_index, int dflt) -+{ -+ int i = dflt; -+ /*tex Fetch the string pointer: */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); -+ lua_rawget(L, -2); -+ if (lua_isboolean(L, -1)) { -+ i = lua_toboolean(L, -1); -+ } -+ lua_pop(L, 1); -+ return i; -+} -+ -+static char *n_string_field_copy(lua_State * L, int name_index, const char *dflt) -+{ -+ char *i; -+ /*tex Fetch the string pointer: */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); -+ lua_rawget(L, -2); -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ i = xstrdup(lua_tostring(L, -1)); -+ } else if (dflt == NULL) { -+ i = NULL; -+ } else { -+ i = xstrdup(dflt); -+ } -+ lua_pop(L, 1); -+ return i; -+} -+ -+static const char *n_string_field(lua_State * L, int name_index) -+{ -+ /*tex Fetch the string pointer: */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); -+ lua_rawget(L, -2); -+ return lua_tostring(L,-1); -+} -+ -+static int n_some_field(lua_State * L, int name_index) -+{ -+ /*tex Fetch the string pointer: */ -+ lua_rawgeti(L, LUA_REGISTRYINDEX, name_index); -+ lua_rawget(L, -2); -+ return lua_type(L,-1); -+} -+ -+static int count_char_packet_bytes(lua_State * L) -+{ -+ register int i; -+ register int ts; -+ register int l = 0; -+ int ff = 0; -+ for (i = 1; i <= (int) lua_rawlen(L, -1); i++) { -+ lua_rawgeti(L, -1, i); -+ if (lua_istable(L, -1)) { -+ lua_rawgeti(L, -1, 1); -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ const char *s = lua_tostring(L, -1); -+ if (lua_key_eq(s, font)) { -+ l += 5; -+ ff = 1; -+ } else if (lua_key_eq(s, char)) { -+ if (ff == 0) { -+ l += 5; -+ } -+ l += 5; -+ ff = 1; -+ } else if (lua_key_eq(s, slot)) { -+ l += 10; -+ } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) { -+ ; -+ } else if (lua_key_eq(s, push) || lua_key_eq(s, pop)) { -+ l++; -+ } else if (lua_key_eq(s, rule)) { -+ l += 9; -+ } else if (lua_key_eq(s, right) || lua_key_eq(s, node) || lua_key_eq(s, down) || lua_key_eq(s, image) || lua_key_eq(s, lua)) { -+ l += 5; -+ } else if (lua_key_eq(s, scale)) { -+ l += sizeof(float) + 1; -+ } else if (lua_key_eq(s, pdf)) { -+ size_t len; -+ l += 5; -+ ts = lua_rawlen(L, -2); -+ lua_rawgeti(L, -2, 2); -+ if (ts == 3) { -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ /*tex There is no need to do something. */ -+ } else if (lua_type(L,-1) == LUA_TNUMBER) { -+ /*tex There is no need to do something. */ -+ } else { -+ normal_error("vf command","invalid packet pdf literal category"); -+ } -+ lua_rawgeti(L, -3, 3); -+ } -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ (void) lua_tolstring(L, -1, &len); -+ if (len > 0) { -+ l = (int) (l + 5 + (int) len); -+ } -+ } else { -+ normal_error("vf command","invalid packet pdf literal"); -+ } -+ lua_pop(L, ts == 3 ? 2 : 1); -+ } else if (lua_key_eq(s, special)) { -+ size_t len; -+ lua_rawgeti(L, -2, 2); -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ (void) lua_tolstring(L, -1, &len); -+ if (len > 0) { -+ l = (int) (l + 5 + (int) len); -+ } -+ } else { -+ normal_error("vf command","invalid packet special"); -+ } -+ lua_pop(L, 1); -+ } else { -+ normal_error("vf command","unknown packet command"); -+ } -+ } else { -+ normal_error("vf command","no packet command"); -+ } -+ /*tex Pop the command name: */ -+ lua_pop(L, 1); -+ } -+ /*tex Pop this item: */ -+ lua_pop(L, 1); -+ } -+ return l; -+} -+ -+static scaled sp_to_dvi(halfword sp, halfword atsize) -+{ -+ double result, mult; -+ mult = (double) (atsize / 65536.0); -+ result = (double) (sp * 16.0); -+ return floor(result / mult); -+} -+ -+static void read_char_packets(lua_State * L, int *l_fonts, charinfo * co, internal_font_number f, int atsize) -+{ -+ int i, n, m; -+ size_t l; -+ int cmd; -+ const char *s; -+ eight_bits *cpackets, *cp; -+ int ff = 0; -+ int sf = 0; -+ int ts = 0; -+ int max_f = 0; -+ int pc = count_char_packet_bytes(L); -+ if (pc <= 0) -+ return; -+ while (l_fonts[(max_f + 1)] != 0) -+ max_f++; -+ cp = cpackets = xmalloc((unsigned) (pc + 1)); -+ for (i = 1; i <= (int) lua_rawlen(L, -1); i++) { -+ lua_rawgeti(L, -1, i); -+ if (lua_istable(L, -1)) { -+ /*tex fetch the command code */ -+ lua_rawgeti(L, -1, 1); -+ if (lua_type(L,-1) == LUA_TSTRING) { -+ s = lua_tostring(L, -1); -+ cmd = 0; -+ if (lua_key_eq(s, font)) { -+ cmd = packet_font_code; -+ } else if (lua_key_eq(s, char)) { -+ cmd = packet_char_code; -+ if (ff == 0) { -+ append_packet(packet_font_code); -+ ff = l_fonts[1]; -+ do_store_four(ff); -+ } -+ } else if (lua_key_eq(s, slot)) { -+ /*tex we could be sparse but no real reason */ -+ cmd = packet_nop_code; -+ lua_rawgeti(L, -2, 2); -+ n = (int) lua_roundnumber(L, -1); -+ if (n == 0) { -+ sf = f; -+ } else { -+ sf = (n > max_f ? l_fonts[1] : l_fonts[n]); -+ } -+ lua_rawgeti(L, -3, 3); -+ n = (int) lua_roundnumber(L, -1); -+ lua_pop(L, 2); -+ append_packet(packet_font_code); -+ do_store_four(sf); -+ append_packet(packet_char_code); -+ do_store_four(n); -+ } else if (lua_key_eq(s, comment) || lua_key_eq(s, nop)) { -+ cmd = packet_nop_code; -+ } else if (lua_key_eq(s, node)) { -+ cmd = packet_node_code; -+ } else if (lua_key_eq(s, push)) { -+ cmd = packet_push_code; -+ } else if (lua_key_eq(s, pop)) { -+ cmd = packet_pop_code; -+ } else if (lua_key_eq(s, rule)) { -+ cmd = packet_rule_code; -+ } else if (lua_key_eq(s, right)) { -+ cmd = packet_right_code; -+ } else if (lua_key_eq(s, down)) { -+ cmd = packet_down_code; -+ } else if (lua_key_eq(s, pdf)) { -+ cmd = packet_pdf_code; -+ } else if (lua_key_eq(s, special)) { -+ cmd = packet_special_code; -+ } else if (lua_key_eq(s, image)) { -+ cmd = packet_image_code; -+ } else if (lua_key_eq(s, scale)) { -+ cmd = packet_scale_code; -+ } else if (lua_key_eq(s, lua)) { -+ cmd = packet_lua_code; -+ } -+ switch (cmd) { -+ case packet_push_code: -+ case packet_pop_code: -+ append_packet(cmd); -+ break; -+ case packet_font_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = (int) lua_roundnumber(L, -1); -+ if (n == 0) { -+ ff = n; -+ } else { -+ ff = (n > max_f ? l_fonts[1] : l_fonts[n]); -+ } -+ do_store_four(ff); -+ lua_pop(L, 1); -+ break; -+ case packet_node_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = copy_node_list(nodelist_from_lua(L,-1)); -+ do_store_four(n); -+ lua_pop(L, 1); -+ break; -+ case packet_char_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = (int) lua_roundnumber(L, -1); -+ do_store_four(n); -+ lua_pop(L, 1); -+ break; -+ case packet_right_code: -+ case packet_down_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = (int) lua_roundnumber(L, -1); -+ do_store_four(sp_to_dvi(n, atsize)); -+ lua_pop(L, 1); -+ break; -+ case packet_rule_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = (int) lua_roundnumber(L, -1); -+ do_store_four(sp_to_dvi(n, atsize)); -+ lua_rawgeti(L, -3, 3); -+ n = (int) lua_roundnumber(L, -1); -+ do_store_four(sp_to_dvi(n, atsize)); -+ lua_pop(L, 2); -+ break; -+ case packet_pdf_code: -+ ts = (int) lua_rawlen(L, -2); -+ lua_rawgeti(L, -2, 2); -+ if (ts == 3) { -+ /*tex mode on stack */ -+ s = lua_tostring(L, -1); -+ if (lua_type(L, -1) == LUA_TSTRING) { -+ /*tex | | */ -+ if (lua_key_eq(s, mode)) { -+ cmd = packet_pdf_mode; -+ lua_rawgeti(L, -3, 3); -+ /*tex mode on stack */ -+ s = lua_tostring(L, -1); -+ } -+ } else { -+ /*tex | | */ -+ } -+ if (lua_type(L, -1) == LUA_TSTRING) { -+ if (lua_key_eq(s, direct)) { -+ n = direct_always; -+ } else if (lua_key_eq(s, page)) { -+ n = direct_page; -+ } else if (lua_key_eq(s, text)) { -+ n = direct_text; -+ } else if (lua_key_eq(s, font)) { -+ n = direct_font; -+ } else if (lua_key_eq(s, raw)) { -+ n = direct_raw; -+ } else if (lua_key_eq(s, origin)) { -+ n = set_origin; -+ } else { -+ n = set_origin ; -+ } -+ } else { -+ n = (int) lua_roundnumber(L, -1); -+ if (n < set_origin || n >= scan_special) { -+ n = set_origin ; -+ } -+ } -+ if (cmd == packet_pdf_code) { -+ /*tex string on stack */ -+ lua_rawgeti(L, -3, 3); -+ } -+ } else { -+ n = set_origin; -+ } -+ append_packet(cmd); -+ do_store_four(n); -+ if (cmd == packet_pdf_code) { -+ s = luaL_checklstring(L, -1, &l); -+ do_store_four(l); -+ if (l > 0) { -+ m = (int) l; -+ while (m > 0) { -+ n = *s++; -+ m--; -+ append_packet(n); -+ } -+ } -+ } -+ lua_pop(L,ts == 3 ? 2 : 1); -+ break; -+ case packet_special_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ s = luaL_checklstring(L, -1, &l); -+ if (l > 0) { -+ do_store_four(l); -+ m = (int) l; -+ while (m > 0) { -+ n = *s++; -+ m--; -+ append_packet(n); -+ } -+ } -+ lua_pop(L, 1); -+ break; -+ case packet_lua_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ n = luaL_ref(L, LUA_REGISTRYINDEX); -+ do_store_four(n); -+ break; -+ case packet_image_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ if (lua_istable(L, -1)) { -+ lua_getglobal(L, "img"); -+ lua_pushstring(L, "new"); -+ lua_gettable(L, -2); -+ lua_insert(L, -3); -+ lua_pop(L, 1); -+ lua_call(L, 1, 1); -+ } -+ luaL_checkudata(L, -1, TYPE_IMG); -+ n = luaL_ref(L, LUA_REGISTRYINDEX); -+ do_store_four(n); -+ break; -+ case packet_nop_code: -+ break; -+ case packet_scale_code: -+ append_packet(cmd); -+ lua_rawgeti(L, -2, 2); -+ append_float(&cp, (float) luaL_checknumber(L, -1)); -+ lua_pop(L, 1); -+ break; -+ default: -+ normal_error("vf command","invalid packet code"); -+ } -+ } -+ /*tex Command code: */ -+ lua_pop(L, 1); -+ } else { -+ normal_error("vf command","commands has to be a table"); -+ } -+ /*tex Command table: */ -+ lua_pop(L, 1); -+ } -+ append_packet(packet_end_code); -+ set_charinfo_packets(co, cpackets); -+ return; -+} -+ -+static void read_lua_cidinfo(lua_State * L, int f) -+{ -+ int i; -+ char *s; -+ lua_key_rawgeti(cidinfo); -+ if (lua_istable(L, -1)) { -+ i = lua_numeric_field_by_index(L,lua_key_index(version), 0); -+ set_font_cidversion(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(supplement), 0); -+ set_font_cidsupplement(f, i); -+ s = n_string_field_copy(L, lua_key_index(registry), "Adobe"); -+ set_font_cidregistry(f, s); -+ s = n_string_field_copy(L, lua_key_index(ordering), "Identity"); -+ set_font_cidordering(f, s); -+ } -+ lua_pop(L, 1); -+} -+ -+static void read_lua_parameters(lua_State * L, int f) -+{ -+ int i, n, t; -+ const char *s; -+ lua_key_rawgeti(parameters); -+ if (lua_istable(L, -1)) { -+ /*tex The number of parameters is the |max(IntegerKeys(L)),7)| */ -+ n = 7; -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ if (lua_type(L, -2) == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -2); -+ if (i > n) -+ n = i; -+ } -+ lua_pop(L, 1); -+ } -+ if (n > 7) -+ set_font_params(f, n); -+ /*tex Sometimes it is handy to have all integer keys: */ -+ for (i = 1; i <= 7; i++) { -+ lua_rawgeti(L, -1, i); -+ if (lua_type(L, -1) == LUA_TNUMBER) { -+ n = lua_roundnumber(L, -1); -+ set_font_param(f, i, n); -+ } -+ lua_pop(L, 1); -+ } -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ t = lua_type(L,-2); -+ if (t == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -2); -+ if (i >= 8) { -+ if (lua_type(L,-1) == LUA_TNUMBER) { -+ n = lua_roundnumber(L, -1); -+ } else { -+ n = 0; -+ } -+ set_font_param(f, i, n); -+ } -+ } else if (t == LUA_TSTRING) { -+ s = lua_tostring(L, -2); -+ if (lua_type(L,-1) == LUA_TNUMBER) { -+ n = lua_roundnumber(L, -1); -+ } else { -+ n = 0; -+ } -+ if (lua_key_eq(s, slant)) { -+ set_font_param(f, slant_code, n); -+ } else if (lua_key_eq(s, space)) { -+ set_font_param(f, space_code, n); -+ } else if (lua_key_eq(s, space_stretch)) { -+ set_font_param(f, space_stretch_code, n); -+ } else if (lua_key_eq(s, space_shrink)) { -+ set_font_param(f, space_shrink_code, n); -+ } else if (lua_key_eq(s, x_height)) { -+ set_font_param(f, x_height_code, n); -+ } else if (lua_key_eq(s, quad)) { -+ set_font_param(f, quad_code, n); -+ } else if (lua_key_eq(s, extra_space)) { -+ set_font_param(f, extra_space_code, n); -+ } -+ } -+ lua_pop(L, 1); -+ } -+ } -+ lua_pop(L, 1); -+ -+} -+ -+static void read_lua_math_parameters(lua_State * L, int f) -+{ -+ int i = 0, n = 0, t; -+ lua_key_rawgeti(MathConstants); -+ if (lua_istable(L, -1)) { -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ t = lua_type(L,-2); -+ if (t == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -2); -+ } else if (t == LUA_TSTRING) { -+ i = ff_checkoption(L, -2, NULL, MATH_param_names); -+ } -+ n = (int) lua_roundnumber(L, -1); -+ if (i > 0) { -+ set_font_math_param(f, i, n); -+ } -+ lua_pop(L, 1); -+ } -+ set_font_oldmath(f,false); -+ } else { -+ set_font_oldmath(f,true); -+ } -+ lua_pop(L, 1); -+} -+ -+#define MIN_INF -0x7FFFFFFF -+ -+static void store_math_kerns(lua_State * L, int index, charinfo * co, int id) -+{ -+ int l, k; -+ scaled ht, krn; -+ lua_key_direct_rawgeti(index); -+ if (lua_istable(L, -1) && ((k = (int) lua_rawlen(L, -1)) > 0)) { -+ for (l = 0; l < k; l++) { -+ lua_rawgeti(L, -1, (l + 1)); -+ if (lua_istable(L, -1)) { -+ ht = (scaled) lua_numeric_field_by_index(L, lua_key_index(height), MIN_INF); -+ krn = (scaled) lua_numeric_field_by_index(L, lua_key_index(kern), MIN_INF); -+ if (krn > MIN_INF && ht > MIN_INF) -+ add_charinfo_math_kern(co, id, ht, krn); -+ } -+ lua_pop(L, 1); -+ } -+ } -+ lua_pop(L, 1); -+} -+ -+static void font_char_from_lua(lua_State * L, internal_font_number f, int i, int *l_fonts, boolean has_math) -+{ -+ int k, r, t, lt, u, n; -+ charinfo *co; -+ kerninfo *ckerns; -+ liginfo *cligs; -+ scaled j; -+ const char *s; -+ /*tex The number of ligature table items: */ -+ int nl = 0; -+ /*tex The number of kern table items: */ -+ int nk = 0; -+ int ctr = 0; -+ int atsize = font_size(f); -+ if (lua_istable(L, -1)) { -+ co = get_charinfo(f, i); -+ set_charinfo_tag(co, 0); -+ j = lua_numeric_field_by_index(L, lua_key_index(width), 0); -+ set_charinfo_width(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(height), 0); -+ set_charinfo_height(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(depth), 0); -+ set_charinfo_depth(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(italic), 0); -+ set_charinfo_italic(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(vert_italic), 0); -+ set_charinfo_vert_italic(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(index), 0); -+ set_charinfo_index(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(expansion_factor), 1000); -+ set_charinfo_ef(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(left_protruding), 0); -+ set_charinfo_lp(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(right_protruding), 0); -+ set_charinfo_rp(co, j); -+ k = n_boolean_field(L, lua_key_index(used), 0); -+ set_charinfo_used(co, k); -+ s = n_string_field(L, lua_key_index(name)); -+ if (s != NULL) -+ set_charinfo_name(co, xstrdup(s)); -+ else -+ set_charinfo_name(co, NULL); -+ /*tex |n_string_field| leaves a value on stack*/ -+ lua_pop(L,1); -+ u = n_some_field(L,lua_key_index(tounicode)); -+ if (u == LUA_TNUMBER) { -+ u = lua_tointeger(L,-1); -+ if (u < 0) { -+ set_charinfo_tounicode(co, NULL); -+ } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { -+ char *s = malloc(5); -+ sprintf(s,"%04X",(unsigned int) u); -+ set_charinfo_tounicode(co,s); -+ } else { -+ char *s = malloc(11); -+ u = u - 0x10000; -+ sprintf(s,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00)); -+ set_charinfo_tounicode(co,s); -+ } -+ } else if (u == LUA_TTABLE) { -+ n = lua_rawlen(L,-1); -+ u = 0; -+ for (k = 1; k <= n; k++) { -+ lua_rawgeti(L, -1, k); -+ if (lua_type(L,-1) == LUA_TNUMBER) { -+ u = lua_tointeger(L,-1); -+ } else { -+ lua_pop(L, 1); -+ break; -+ } -+ if (u < 0) { -+ u = -1; -+ lua_pop(L, 1); -+ break; -+ } else if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { -+ u = u + 4; -+ } else { -+ u = u + 8; -+ } -+ lua_pop(L, 1); -+ } -+ if (u>0) { -+ char *s = malloc(u+1); -+ char *t = s ; -+ for (k = 1; k <= n; k++) { -+ lua_rawgeti(L, -1, k); -+ u = lua_tointeger(L,-1); -+ if (u < 0xD7FF || (u > 0xDFFF && u <= 0xFFFF)) { -+ sprintf(t,"%04X",(unsigned int) u); -+ t += 4; -+ } else { -+ u = u - 0x10000; -+ sprintf(t,"%04X%04X",(unsigned int) (floor(u/1024)+0xD800),(unsigned int) (u%1024+0xDC00)); -+ t += 8; -+ } -+ lua_pop(L, 1); -+ } -+ set_charinfo_tounicode(co,s); -+ } else { -+ set_charinfo_tounicode(co, NULL); -+ } -+ } else if (u == LUA_TSTRING) { -+ s = lua_tostring(L,-1); -+ set_charinfo_tounicode(co, xstrdup(s)); -+ } else { -+ set_charinfo_tounicode(co, NULL); -+ } -+ lua_pop(L,1); -+ if (has_math) { -+ j = lua_numeric_field_by_index(L, lua_key_index(top_accent), INT_MIN); -+ set_charinfo_top_accent(co, j); -+ j = lua_numeric_field_by_index(L, lua_key_index(bot_accent), INT_MIN); -+ set_charinfo_bot_accent(co, j); -+ k = lua_numeric_field_by_index(L, lua_key_index(next), -1); -+ if (k >= 0) { -+ set_charinfo_tag(co, list_tag); -+ set_charinfo_remainder(co, k); -+ } -+ lua_key_rawgeti(extensible); -+ if (lua_istable(L, -1)) { -+ int top, bot, mid, rep; -+ top = lua_numeric_field_by_index(L, lua_key_index(top), 0); -+ bot = lua_numeric_field_by_index(L, lua_key_index(bot), 0); -+ mid = lua_numeric_field_by_index(L, lua_key_index(mid), 0); -+ rep = lua_numeric_field_by_index(L, lua_key_index(rep), 0); -+ if (top != 0 || bot != 0 || mid != 0 || rep != 0) { -+ set_charinfo_tag(co, ext_tag); -+ set_charinfo_extensible(co, top, bot, mid, rep); -+ } else { -+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid extensible field", font_name(f), (int) i); -+ } -+ } -+ lua_pop(L, 1); -+ lua_key_rawgeti(horiz_variants); -+ if (lua_istable(L, -1)) { -+ int glyph, startconnect, endconnect, advance, extender; -+ extinfo *h; -+ set_charinfo_tag(co, ext_tag); -+ set_charinfo_hor_variants(co, NULL); -+ for (k = 1;; k++) { -+ lua_rawgeti(L, -1, k); -+ if (lua_istable(L, -1)) { -+ glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0); -+ extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0); -+ startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0); -+ endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0); -+ advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0); -+ h = new_variant(glyph, startconnect, endconnect, advance, extender); -+ add_charinfo_hor_variant(co, h); -+ lua_pop(L, 1); -+ } else { -+ lua_pop(L, 1); -+ break; -+ } -+ } -+ } -+ lua_pop(L, 1); -+ lua_key_rawgeti(vert_variants); -+ if (lua_istable(L, -1)) { -+ int glyph, startconnect, endconnect, advance, extender; -+ extinfo *h; -+ set_charinfo_tag(co, ext_tag); -+ set_charinfo_vert_variants(co, NULL); -+ for (k = 1;; k++) { -+ lua_rawgeti(L, -1, k); -+ if (lua_istable(L, -1)) { -+ glyph = lua_numeric_field_by_index(L, lua_key_index(glyph), 0); -+ extender = lua_numeric_field_by_index(L, lua_key_index(extender), 0); -+ startconnect = lua_numeric_field_by_index(L, lua_key_index(start), 0); -+ endconnect = lua_numeric_field_by_index(L, lua_key_index(end), 0); -+ advance = lua_numeric_field_by_index(L, lua_key_index(advance), 0); -+ h = new_variant(glyph, startconnect, endconnect, advance, extender); -+ add_charinfo_vert_variant(co, h); -+ lua_pop(L, 1); -+ } else { -+ lua_pop(L, 1); -+ break; -+ } -+ } -+ } -+ lua_pop(L, 1); -+ /*tex -+ Here is a complete example: -+ -+ \starttyping -+ mathkern = { -+ bottom_left = { { height = 420, kern = 80 }, { height = 520, kern = 4 } }, -+ bottom_right = { { height = 0, kern = 48 } }, -+ top_left = { { height = 620, kern = 0 }, { height = 720, kern = -80 } }, -+ top_right = { { height = 676, kern = 115 }, { height = 776, kern = 45 } }, -+ } -+ \stoptyping -+ -+ */ -+ lua_key_rawgeti(mathkern); -+ if (lua_istable(L, -1)) { -+ store_math_kerns(L,lua_key_index(top_left), co, top_left_kern); -+ store_math_kerns(L,lua_key_index(top_right), co, top_right_kern); -+ store_math_kerns(L,lua_key_index(bottom_right), co, bottom_right_kern); -+ store_math_kerns(L,lua_key_index(bottom_left), co, bottom_left_kern); -+ } -+ lua_pop(L, 1); -+ } -+ /*tex end of |has_math| */ -+ count_hash_items(L, kerns, nk); -+ if (nk > 0) { -+ /*tex The kerns table is still on stack. */ -+ ckerns = xcalloc((unsigned) (nk + 1), sizeof(kerninfo)); -+ ctr = 0; -+ /*tex Traverse the hash. */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ k = non_boundarychar; -+ lt = lua_type(L,-2); -+ if (lt == LUA_TNUMBER) { -+ /*tex Adjacent char: */ -+ k = (int) lua_tointeger(L, -2); -+ if (k < 0) -+ k = non_boundarychar; -+ } else if (lt == LUA_TSTRING) { -+ s = lua_tostring(L, -2); -+ if (lua_key_eq(s, right_boundary)) { -+ k = right_boundarychar; -+ if (!has_right_boundary(f)) -+ set_right_boundary(f, get_charinfo(f, right_boundarychar)); -+ } -+ } -+ j = lua_roundnumber(L, -1); -+ if (k != non_boundarychar) { -+ set_kern_item(ckerns[ctr], k, j); -+ ctr++; -+ } else { -+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kern field", font_name(f), (int) i); -+ } -+ lua_pop(L, 1); -+ } -+ /*tex A guard against empty tables. */ -+ if (ctr > 0) { -+ set_kern_item(ckerns[ctr], end_kern, 0); -+ set_charinfo_kerns(co, ckerns); -+ } else { -+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid kerns field", font_name(f), (int) i); -+ } -+ lua_pop(L, 1); -+ } -+ /*tex Packet commands. */ -+ lua_key_rawgeti(commands); -+ if (lua_istable(L, -1)) { -+ lua_pushnil(L); -+ if (lua_next(L, -2) != 0) { -+ lua_pop(L, 2); -+ read_char_packets(L, (int *) l_fonts, co, f, atsize); -+ } -+ } -+ lua_pop(L, 1); -+ /*tex The ligatures. */ -+ count_hash_items(L, ligatures, nl); -+ if (nl > 0) { -+ /*tex The ligatures table still on stack. */ -+ cligs = xcalloc((unsigned) (nl + 1), sizeof(liginfo)); -+ ctr = 0; -+ /*tex Traverse the hash. */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ k = non_boundarychar; -+ lt = lua_type(L,-2); -+ if (lt == LUA_TNUMBER) { -+ /*tex Adjacent char: */ -+ k = (int) lua_tointeger(L, -2); -+ if (k < 0) { -+ k = non_boundarychar; -+ } -+ } else if (lt == LUA_TSTRING) { -+ s = lua_tostring(L, -2); -+ if (lua_key_eq(s, right_boundary)) { -+ k = right_boundarychar; -+ if (!has_right_boundary(f)) -+ set_right_boundary(f, get_charinfo(f, right_boundarychar)); -+ } -+ } -+ r = -1; -+ if (lua_istable(L, -1)) { -+ /*tex Ligature: */ -+ r = lua_numeric_field_by_index(L, lua_key_index(char), -1); -+ } -+ if (r != -1 && k != non_boundarychar) { -+ t = n_enum_field(L, lua_key_index(type), 0, ligature_type_strings); -+ set_ligature_item(cligs[ctr], (char) ((t * 2) + 1), k, r); -+ ctr++; -+ } else { -+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligature field", font_name(f), (int) i); -+ } -+ /*tex The iterator value: */ -+ lua_pop(L, 1); -+ } -+ /*tex A guard against empty tables. */ -+ if (ctr > 0) { -+ set_ligature_item(cligs[ctr], 0, end_ligature, 0); -+ set_charinfo_ligatures(co, cligs); -+ } else { -+ formatted_warning("font", "lua-loaded font %s char U+%X has an invalid ligatures field", font_name(f), (int) i); -+ } -+ /*tex The ligatures table. */ -+ lua_pop(L, 1); -+ } -+ } -+} -+ -+/*tex -+ -+ The caller has to fix the state of the lua stack when there is an error! -+ -+*/ -+ -+int font_from_lua(lua_State * L, int f) -+{ -+ int i, n, r, t, lt; -+ int s_top; -+ int bc; -+ int ec; -+ char *s; -+ const char *ss; -+ int *l_fonts = NULL; -+ int save_ref ; -+ boolean no_math = false; -+ /*tex Will we save a cache of the \LUA\ table? */ -+ save_ref = 1; -+ ss = NULL; -+ ss = n_string_field(L, lua_key_index(cache)); -+ if (lua_key_eq(ss, no)) -+ save_ref = -1; -+ else if (lua_key_eq(ss, renew)) -+ save_ref = 0; -+ /*tex |n_string_field| leaves a value on stack. */ -+ lua_pop(L,1); -+ /*tex The table is at stack |index -1| */ -+ s = n_string_field_copy(L,lua_key_index(area), ""); -+ set_font_area(f, s); -+ s = n_string_field_copy(L, lua_key_index(filename), NULL); -+ set_font_filename(f, s); -+ s = n_string_field_copy(L, lua_key_index(encodingname), NULL); -+ set_font_encodingname(f, s); -+ s = n_string_field_copy(L, lua_key_index(name), NULL); -+ set_font_name(f, s); -+ s = n_string_field_copy(L, lua_key_index(fullname), font_name(f)); -+ set_font_fullname(f, s); -+ if (s == NULL) { -+ formatted_error("font","lua-loaded font '%d' has no name!", f); -+ return false; -+ } -+ s = n_string_field_copy(L, lua_key_index(psname), NULL); -+ set_font_psname(f, s); -+ i = lua_numeric_field_by_index(L,lua_key_index(units_per_em), 0); -+ set_font_units_per_em(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(designsize), 655360); -+ set_font_dsize(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(size), font_dsize(f)); -+ set_font_size(f, i); -+ set_font_checksum(f, (unsigned)(lua_unsigned_numeric_field_by_index(L,lua_key_index(checksum), 0))) ; -+ i = lua_numeric_field_by_index(L,lua_key_index(direction), 0); -+ set_font_natural_dir(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(encodingbytes), 0); -+ set_font_encodingbytes(f, (char) i); -+ i = lua_numeric_field_by_index(L,lua_key_index(streamprovider), 0); -+ set_font_streamprovider(f, (char) i); -+ i = n_boolean_field(L,lua_key_index(oldmath), 0); -+ set_font_oldmath(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(tounicode), 0); -+ set_font_tounicode(f, (char) i); -+ i = lua_numeric_field_by_index(L,lua_key_index(slant), 0); -+ if (i < FONT_SLANT_MIN) -+ i = FONT_SLANT_MIN; -+ if (i > FONT_SLANT_MAX) -+ i = FONT_SLANT_MAX; -+ set_font_slant(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(extend), 1000); -+ if (i < FONT_EXTEND_MIN) -+ i = FONT_EXTEND_MIN; -+ if (i > FONT_EXTEND_MAX) -+ i = FONT_EXTEND_MAX; -+ set_font_extend(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(squeeze), 1000); -+ if (i < FONT_SQUEEZE_MIN) -+ i = FONT_SQUEEZE_MIN; -+ if (i > FONT_SQUEEZE_MAX) -+ i = FONT_SQUEEZE_MAX; -+ set_font_squeeze(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(width), 0); -+ if (i < FONT_WIDTH_MIN) -+ i = FONT_WIDTH_MIN; -+ if (i > FONT_WIDTH_MAX) -+ i = FONT_WIDTH_MAX; -+ set_font_width(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(mode), 0); -+ if (i < FONT_MODE_MIN) -+ i = FONT_MODE_MIN; -+ if (i > FONT_MODE_MAX) -+ i = FONT_MODE_MAX; -+ set_font_mode(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(hyphenchar), default_hyphen_char_par); -+ set_hyphen_char(f, i); -+ i = lua_numeric_field_by_index(L,lua_key_index(skewchar), default_skew_char_par); -+ set_skew_char(f, i); -+ i = n_boolean_field(L, lua_key_index(used), 0); -+ set_font_used(f, (char) i); -+ s = n_string_field_copy(L, lua_key_index(attributes), NULL); -+ if (s != NULL && strlen(s) > 0) { -+ i = maketexstring(s); -+ set_pdf_font_attr(f, i); -+ } -+ free(s); -+ i = n_enum_field(L, lua_key_index(type), unknown_font_type, font_type_strings); -+ set_font_type(f, i); -+ i = n_enum_field(L, lua_key_index(format), unknown_format, font_format_strings); -+ set_font_format(f, i); -+ i = n_enum_field(L, lua_key_index(writingmode), unknown_writingmode, font_writingmode_strings); -+ set_font_writingmode(f, i); -+ i = n_enum_field(L, lua_key_index(identity), unknown_identity, font_identity_strings); -+ set_font_identity(f, i); -+ i = n_enum_field(L, lua_key_index(embedding), unknown_embedding, font_embedding_strings); -+ set_font_embedding(f, i); -+ if (font_encodingbytes(f) == 0 && (font_format(f) == opentype_format || font_format(f) == truetype_format)) { -+ set_font_encodingbytes(f, 2); -+ } -+ /*tex Now fetch the base fonts, if needed. */ -+ count_hash_items(L, fonts, n); -+ if (n > 0) { -+ /*tex The font table still on stack. */ -+ l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int))); -+ memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int))); -+ for (i = 1; i <= n; i++) { -+ lua_rawgeti(L, -1, i); -+ if (lua_istable(L, -1)) { -+ lua_key_rawgeti(id); -+ if (lua_isnumber(L, -1)) { -+ l_fonts[i] = (int) lua_tointeger(L, -1); -+ if (l_fonts[i] == 0) { -+ l_fonts[i] = (int) f; -+ } -+ /*tex Pop id and entry. */ -+ lua_pop(L, 2); -+ continue; -+ } -+ /*tex Pop id. */ -+ lua_pop(L, 1); -+ }; -+ ss = NULL; -+ if (lua_istable(L, -1)) { -+ ss = n_string_field(L, lua_key_index(name)); -+ /*tex The string is anchored. */ -+ lua_pop(L,1); -+ } -+ if (ss != NULL) { -+ t = lua_numeric_field_by_index(L, lua_key_index(size), -1000); -+ /*tex The stack is messed up, otherwise this explicit resizing would not be needed! */ -+ s_top = lua_gettop(L); -+ if (strcmp(font_name(f), ss) == 0) -+ l_fonts[i] = f; -+ else -+ l_fonts[i] = find_font_id(ss, t); -+ lua_settop(L, s_top); -+ } else { -+ formatted_error("font","invalid local font at index %i in lua-loaded font '%s' (1)",i,font_name(f)); -+ } -+ /*tex Pop the list entry. */ -+ lua_pop(L, 1); -+ } -+ /*tex Pop the font table. */ -+ lua_pop(L, 1); -+ } else if (font_type(f) == virtual_font_type) { -+ /*tex -+ We no longer do this check but instead create an entry. This permits -+ (valid) tricks. -+ */ -+ /* -+ formatted_error("font","invalid local fonts in lua-loaded font '%s' (2)", font_name(f)); -+ */ -+ } else { -+ l_fonts = xmalloc(3 * sizeof(int)); -+ l_fonts[0] = 0; -+ l_fonts[1] = f; -+ l_fonts[2] = 0; -+ } -+ /*tex The parameters. */ -+ no_math = n_boolean_field(L, lua_key_index(nomath), 0); -+ read_lua_parameters(L, f); -+ if (!no_math) { -+ read_lua_math_parameters(L, f); -+ if (n_boolean_field(L, lua_key_index(oldmath), 0)) { -+ set_font_oldmath(f,true); -+ } -+ -+ } else { -+ set_font_oldmath(f,true); -+ } -+ read_lua_cidinfo(L, f); -+ /*tex The characters. */ -+ lua_key_rawgeti(characters); -+ if (lua_istable(L, -1)) { -+ /*tex Find the array size values; |num| holds the number of characters to add. */ -+ int num = 0; -+ ec = 0; -+ bc = -1; -+ /*tex The first key: */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ if (lua_isnumber(L, -2)) { -+ i = (int) lua_tointeger(L, -2); -+ if (i >= 0) { -+ if (lua_istable(L, -1)) { -+ num++; -+ if (i > ec) -+ ec = i; -+ if (bc < 0) -+ bc = i; -+ if (bc >= 0 && i < bc) -+ bc = i; -+ } -+ } -+ } -+ lua_pop(L, 1); -+ } -+ if (bc != -1) { -+ int fstep; -+ font_malloc_charinfo(f, num); -+ set_font_bc(f, bc); -+ set_font_ec(f, ec); -+ /*tex The first key: */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ lt = lua_type(L,-2); -+ if (lt == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -2); -+ if (i >= 0) { -+ font_char_from_lua(L, f, i, l_fonts, !no_math); -+ } -+ } else if (lt == LUA_TSTRING) { -+ const char *ss1 = lua_tostring(L, -2); -+ if (lua_key_eq(ss1, left_boundary)) { -+ font_char_from_lua(L, f, left_boundarychar, l_fonts, !no_math); -+ } else if (lua_key_eq(ss1, right_boundary)) { -+ font_char_from_lua(L, f, right_boundarychar, l_fonts, !no_math); -+ } -+ } -+ lua_pop(L, 1); -+ } -+ lua_pop(L, 1); -+ /*tex -+ -+ Handle font expansion last: the |copy_font| routine is called eventually, -+ and that needs to know |bc| and |ec|. We permits virtual fonts to use -+ expansion as one can always turn it off. -+ -+ */ -+ fstep = lua_numeric_field_by_index(L, lua_key_index(step), 0); -+ if (fstep < 0) -+ fstep = 0; -+ if (fstep > 100) -+ fstep = 100; -+ if (fstep != 0) { -+ int fshrink = lua_numeric_field_by_index(L, lua_key_index(shrink), 0); -+ int fstretch= lua_numeric_field_by_index(L, lua_key_index(stretch), 0); -+ if (fshrink < 0) -+ fshrink = 0; -+ if (fshrink > 500) -+ fshrink = 500; -+ fshrink -= (fshrink % fstep); -+ if (fshrink < 0) -+ fshrink = 0; -+ if (fstretch < 0) -+ fstretch = 0; -+ if (fstretch > 1000) -+ fstretch = 1000; -+ fstretch -= (fstretch % fstep); -+ if (fstretch < 0) -+ fstretch = 0; -+ set_expand_params(f, fstretch, fshrink, fstep); -+ } -+ -+ } else { -+ formatted_warning("font","lua-loaded font '%d' with name '%s' has no characters", f, font_name(f)); -+ } -+ if (save_ref > 0) { -+ /*tex This pops the table. */ -+ r = luaL_ref(L, LUA_REGISTRYINDEX); -+ set_font_cache_id(f, r); -+ } else { -+ lua_pop(L, 1); -+ set_font_cache_id(f, save_ref); -+ } -+ } else { -+ formatted_warning("font","lua-loaded font '%d' with name '%s' has no character table", f, font_name(f)); -+ } -+ if (l_fonts != NULL) -+ free(l_fonts); -+ return true; -+} -+ -+int characters_from_lua(lua_State * L, int f) -+{ -+ int i, n, t, lt; -+ int *l_fonts = NULL; -+ int s_top; -+ const char *ss; -+ boolean no_math = false; -+ /*tex Speedup: */ -+ no_math = n_boolean_field(L, lua_key_index(nomath), 0); -+ /*tex Type: */ -+ i = n_enum_field(L, lua_key_index(type), font_type(f), font_type_strings); -+ set_font_type(f, i); -+ /*tex Fonts: */ -+ count_hash_items(L, fonts, n); -+ if (n > 0) { -+ /*tex The font table still on stack. */ -+ l_fonts = xmalloc((unsigned) ((unsigned) (n + 2) * sizeof(int))); -+ memset(l_fonts, 0, (size_t) ((unsigned) (n + 2) * sizeof(int))); -+ for (i = 1; i <= n; i++) { -+ lua_rawgeti(L, -1, i); -+ if (lua_istable(L, -1)) { -+ lua_key_rawgeti(id); -+ if (lua_isnumber(L, -1)) { -+ l_fonts[i] = (int) lua_tointeger(L, -1); -+ if (l_fonts[i] == 0) { -+ l_fonts[i] = (int) f; -+ } -+ /*tex Pop id and entry. */ -+ lua_pop(L, 2); -+ continue; -+ } -+ /*tex Pop id. */ -+ lua_pop(L, 1); -+ }; -+ ss = NULL; -+ if (lua_istable(L, -1)) { -+ ss = n_string_field(L, lua_key_index(name)); -+ /* string is anchored */ -+ lua_pop(L,1); -+ } -+ if (ss != NULL) { -+ t = lua_numeric_field_by_index(L, lua_key_index(size), -1000); -+ /*tex the stack is messed up, otherwise this explicit resizing would not be needed! */ -+ s_top = lua_gettop(L); -+ if (strcmp(font_name(f), ss) == 0) -+ l_fonts[i] = f; -+ else -+ l_fonts[i] = find_font_id(ss, t); -+ lua_settop(L, s_top); -+ } else { -+ formatted_error("font","invalid local font in lua-loaded font '%s' (3)", font_name(f)); -+ } -+ /*tex Pop list entry. */ -+ lua_pop(L, 1); -+ } -+ /*tex Pop font table. */ -+ lua_pop(L, 1); -+ } else if (font_type(f) == virtual_font_type) { -+ formatted_error("font","invalid local fonts in lua-loaded font '%s' (4)", font_name(f)); -+ } else { -+ l_fonts = xmalloc(3 * sizeof(int)); -+ l_fonts[0] = 0; -+ l_fonts[1] = f; -+ l_fonts[2] = 0; -+ } -+ /*tex The characters. */ -+ lua_key_rawgeti(characters); -+ if (lua_istable(L, -1)) { -+ /*tex Find the array size values; |num| has the amount. */ -+ int num = 0; -+ int todo = 0; -+ int bc = font_bc(f); -+ int ec = font_ec(f); -+ /*tex First key: */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ if (lua_isnumber(L, -2)) { -+ i = (int) lua_tointeger(L, -2); -+ if (i >= 0) { -+ if (lua_istable(L, -1)) { -+ todo++; -+ if (! quick_char_exists(f,i)) { -+ num++; -+ if (i > ec) -+ ec = i; -+ if (bc < 0) -+ bc = i; -+ if (bc >= 0 && i < bc) -+ bc = i; -+ } -+ } -+ } -+ } -+ lua_pop(L, 1); -+ } -+ if (todo > 0) { -+ font_malloc_charinfo(f, num); -+ set_font_bc(f, bc); -+ set_font_ec(f, ec); -+ /*tex First key: */ -+ lua_pushnil(L); -+ while (lua_next(L, -2) != 0) { -+ lt = lua_type(L,-2); -+ if (lt == LUA_TNUMBER) { -+ i = (int) lua_tointeger(L, -2); -+ if (i >= 0) { -+ if (quick_char_exists(f,i)) { -+ charinfo *co = char_info(f, i); -+ set_charinfo_name(co, NULL); -+ set_charinfo_tounicode(co, NULL); -+ set_charinfo_packets(co, NULL); -+ set_charinfo_ligatures(co, NULL); -+ set_charinfo_kerns(co, NULL); -+ set_charinfo_vert_variants(co, NULL); -+ set_charinfo_hor_variants(co, NULL); -+ } -+ font_char_from_lua(L, f, i, l_fonts, !no_math); -+ } -+ } -+ lua_pop(L, 1); -+ } -+ lua_pop(L, 1); -+ } -+ } -+ if (l_fonts != NULL) -+ free(l_fonts); -+ return true; -+} -+ -+/*tex Ligaturing starts here */ -+ -+static void nesting_append(halfword nest1, halfword newn) -+{ -+ halfword tail = tlink(nest1); -+ if (tail == null) { -+ couple_nodes(nest1, newn); -+ } else { -+ couple_nodes(tail, newn); -+ } -+ tlink(nest1) = newn; -+} -+ -+static void nesting_prepend(halfword nest1, halfword newn) -+{ -+ halfword head = vlink(nest1); -+ couple_nodes(nest1, newn); -+ if (head == null) { -+ tlink(nest1) = newn; -+ } else { -+ couple_nodes(newn, head); -+ } -+} -+ -+static void nesting_prepend_list(halfword nest1, halfword newn) -+{ -+ halfword head = vlink(nest1); -+ couple_nodes(nest1, newn); -+ if (head == null) { -+ tlink(nest1) = tail_of_list(newn); -+ } else { -+ halfword tail = tail_of_list(newn); -+ couple_nodes(tail, head); -+ } -+} -+ -+static int test_ligature(liginfo * lig, halfword left, halfword right) -+{ -+ if (type(left) != glyph_node) -+ return 0; -+ if (font(left) != font(right)) -+ return 0; -+ if (is_ghost(left) || is_ghost(right)) -+ return 0; -+ *lig = get_ligature(font(left), character(left), character(right)); -+ if (is_valid_ligature(*lig)) { -+ return 1; -+ } -+ return 0; -+} -+ -+static int try_ligature(halfword * frst, halfword fwd) -+{ -+ halfword cur = *frst; -+ liginfo lig; -+ if (test_ligature(&lig, cur, fwd)) { -+ int move_after = (lig_type(lig) & 0x0C) >> 2; -+ int keep_right = ((lig_type(lig) & 0x01) != 0); -+ int keep_left = ((lig_type(lig) & 0x02) != 0); -+ halfword newgl = raw_glyph_node(); -+ font(newgl) = font(cur); -+ character(newgl) = lig_replacement(lig); -+ set_is_ligature(newgl); -+ /*tex -+ Below might not be correct in contrived border case. but we use it -+ only for debugging. -+ */ -+ if (character(cur) < 0) { -+ set_is_leftboundary(newgl); -+ } -+ if (character(fwd) < 0) { -+ set_is_rightboundary(newgl); -+ } -+ if (character(cur) < 0) { -+ if (character(fwd) < 0) { -+ build_attribute_list(newgl); -+ } else { -+ add_node_attr_ref(node_attr(fwd)); -+ node_attr(newgl) = node_attr(fwd); -+ } -+ } else { -+ add_node_attr_ref(node_attr(cur)); -+ node_attr(newgl) = node_attr(cur); -+ } -+ /*tex -+ Maybe if this ligature is consists of another ligature we should add -+ it's |lig_ptr| to the new glyphs |lig_ptr| (and cleanup the no longer -+ needed node). This has a very low priority, so low that it might -+ never happen. -+ */ -+ /*tex Left side: */ -+ if (keep_left) { -+ halfword new_first = copy_node(cur); -+ lig_ptr(newgl) = new_first; -+ couple_nodes(cur, newgl); -+ if (move_after) { -+ move_after--; -+ cur = newgl; -+ } -+ } else { -+ halfword prev = alink(cur); -+ uncouple_node(cur); -+ lig_ptr(newgl) = cur; -+ couple_nodes(prev, newgl); -+ cur = newgl; /* as cur has disappeared */ -+ } -+ /*tex Right side: */ -+ if (keep_right) { -+ halfword new_second = copy_node(fwd); -+ /*tex This is correct, because we {\em know} |lig_ptr| points to {\em one} node. */ -+ couple_nodes(lig_ptr(newgl), new_second); -+ couple_nodes(newgl, fwd); -+ if (move_after) { -+ move_after--; -+ cur = fwd; -+ } -+ } else { -+ halfword next = vlink(fwd); -+ uncouple_node(fwd); -+ /*tex This works because we {\em know} |lig_ptr| points to {\em one} node. */ -+ couple_nodes(lig_ptr(newgl), fwd); -+ if (next != null) { -+ couple_nodes(newgl, next); -+ } -+ } -+ /*tex Check and return. */ -+ *frst = cur; -+ return 1; -+ } -+ return 0; -+} -+ -+/*tex -+ -+ There shouldn't be any ligatures here - we only add them at the end of -+ |xxx_break| in a \.{DISC-1 - DISC-2} situation and we stop processing -+ \.{DISC-1} (we continue with \.{DISC-1}'s |post_| and |no_break|. -+ -+*/ -+ -+static halfword handle_lig_nest(halfword root, halfword cur) -+{ -+ if (cur == null) -+ return root; -+ while (vlink(cur) != null) { -+ halfword fwd = vlink(cur); -+ if (type(cur) == glyph_node && type(fwd) == glyph_node && -+ font(cur) == font(fwd) && try_ligature(&cur, fwd)) { -+ continue; -+ } -+ cur = vlink(cur); -+ } -+ tlink(root) = cur; -+ return root; -+} -+ -+static halfword handle_lig_word(halfword cur) -+{ -+ halfword right = null; -+ if (type(cur) == boundary_node) { -+ halfword prev = alink(cur); -+ halfword fwd = vlink(cur); -+ /*tex There is no need to uncouple |cur|, it is freed. */ -+ flush_node(cur); -+ if (fwd == null) { -+ vlink(prev) = fwd; -+ return prev; -+ } -+ couple_nodes(prev, fwd); -+ if (type(fwd) != glyph_node) -+ return prev; -+ cur = fwd; -+ } else if (has_left_boundary(font(cur))) { -+ halfword prev = alink(cur); -+ halfword p = new_glyph(font(cur), left_boundarychar); -+ couple_nodes(prev, p); -+ couple_nodes(p, cur); -+ cur = p; -+ } -+ if (has_right_boundary(font(cur))) { -+ right = new_glyph(font(cur), right_boundarychar); -+ } -+ while (1) { -+ /*tex A glyph followed by \unknown */ -+ if (type(cur) == glyph_node) { -+ halfword fwd = vlink(cur); -+ if (fwd == null) { -+ /*tex The last character of a paragraph. */ -+ if (right == null) -+ break; -+ /*tex |par| prohibits the use of |couple_nodes| here. */ -+ try_couple_nodes(cur, right); -+ right = null; -+ continue; -+ } -+ if (type(fwd) == glyph_node) { -+ /*tex a glyph followed by a glyph */ -+ if (font(cur) != font(fwd)) -+ break; -+ if (try_ligature(&cur, fwd)) -+ continue; -+ } else if (type(fwd) == disc_node) { -+ /*tex a glyph followed by a disc */ -+ halfword pre = vlink_pre_break(fwd); -+ halfword nob = vlink_no_break(fwd); -+ halfword next, tail; -+ liginfo lig; -+ /*tex Check on: |a{b?}{?}{?}| and |a+b=>B| : |{B?}{?}{a?}| */ -+ /*tex Check on: |a{?}{?}{b?}| and |a+b=>B| : |{a?}{?}{B?}| */ -+ if ((pre != null && type(pre) == glyph_node && test_ligature(&lig, cur, pre)) -+ || (nob != null && type(nob) == glyph_node && test_ligature(&lig, cur, nob))) { -+ /*tex Move |cur| from before disc to skipped part */ -+ halfword prev = alink(cur); -+ uncouple_node(cur); -+ couple_nodes(prev, fwd); -+ nesting_prepend(no_break(fwd), cur); -+ /*tex Now ligature the |pre_break|. */ -+ nesting_prepend(pre_break(fwd), copy_node(cur)); -+ /*tex As we have removed cur, we need to start again. */ -+ cur = prev; -+ } -+ /*tex Check on: |a{?}{?}{}b| and |a+b=>B| : |{a?}{?b}{B}|. */ -+ next = vlink(fwd); -+ if (nob == null && next != null && type(next) == glyph_node && test_ligature(&lig, cur, next)) { -+ /*tex Move |cur| from before |disc| to |no_break| part. */ -+ halfword prev = alink(cur); -+ uncouple_node(cur); -+ couple_nodes(prev, fwd); -+ /*tex We {\em know} it's empty. */ -+ couple_nodes(no_break(fwd), cur); -+ /*tex Now copy |cur| the |pre_break|. */ -+ nesting_prepend(pre_break(fwd), copy_node(cur)); -+ /*tex Move next from after disc to |no_break| part. */ -+ tail = vlink(next); -+ uncouple_node(next); -+ try_couple_nodes(fwd, tail); -+ /*tex We {\em know} this works. */ -+ couple_nodes(cur, next); -+ /*tex Make sure the list is correct. */ -+ tlink(no_break(fwd)) = next; -+ /*tex Now copy next to the |post_break|. */ -+ nesting_append(post_break(fwd), copy_node(next)); -+ /*tex As we have removed cur, we need to start again. */ -+ cur = prev; -+ } -+ /*tex We are finished with the |pre_break|. */ -+ handle_lig_nest(pre_break(fwd), vlink_pre_break(fwd)); -+ } else if (type(fwd) == boundary_node) { -+ halfword next = vlink(fwd); -+ try_couple_nodes(cur, next); -+ flush_node(fwd); -+ if (right != null) { -+ /*tex Shame, didn't need it. */ -+ flush_node(right); -+ /*tex No need to reset |right|, we're going to leave the loop anyway. */ -+ } -+ break; -+ } else { -+ /*tex Is something unknown. */ -+ if (right == null) -+ break; -+ couple_nodes(cur, right); -+ couple_nodes(right, fwd); -+ right = null; -+ continue; -+ } -+ /*tex A discretionary followed by \unknown */ -+ } else if (type(cur) == disc_node) { -+ /*tex If |{?}{x}{?}| or |{?}{?}{y}| then: */ -+ if (vlink_no_break(cur) != null || vlink_post_break(cur) != null) { -+ halfword prev = 0; -+ halfword fwd; -+ liginfo lig; -+ if (subtype(cur) == select_disc) { -+ prev = alink(cur); -+ if (vlink_post_break(cur) != null) -+ handle_lig_nest(post_break(prev), vlink_post_break(prev)); -+ if (vlink_no_break(cur) != null) -+ handle_lig_nest(no_break(prev), vlink_no_break(prev)); -+ } -+ if (vlink_post_break(cur) != null) -+ handle_lig_nest(post_break(cur), vlink_post_break(cur)); -+ if (vlink_no_break(cur) != null) -+ handle_lig_nest(no_break(cur), vlink_no_break(cur)); -+ while ((fwd = vlink(cur)) != null) { -+ halfword nob, pst, next; -+ if (type(fwd) != glyph_node) -+ break; -+ if (subtype(cur) != select_disc) { -+ nob = tlink_no_break(cur); -+ pst = tlink_post_break(cur); -+ if ((nob == null || !test_ligature(&lig, nob, fwd)) && -+ (pst == null || !test_ligature(&lig, pst, fwd))) -+ break; -+ nesting_append(no_break(cur), copy_node(fwd)); -+ handle_lig_nest(no_break(cur), nob); -+ } else { -+ int dobreak = 0; -+ nob = tlink_no_break(prev); -+ pst = tlink_post_break(prev); -+ if ((nob == null || !test_ligature(&lig, nob, fwd)) && -+ (pst == null || !test_ligature(&lig, pst, fwd))) -+ dobreak = 1; -+ if (!dobreak) { -+ nesting_append(no_break(prev), copy_node(fwd)); -+ handle_lig_nest(no_break(prev), nob); -+ nesting_append(post_break(prev), copy_node(fwd)); -+ handle_lig_nest(post_break(prev), pst); -+ } -+ dobreak = 0; -+ nob = tlink_no_break(cur); -+ pst = tlink_post_break(cur); -+ if ((nob == null || !test_ligature(&lig, nob, fwd)) && -+ (pst == null || !test_ligature(&lig, pst, fwd))) -+ dobreak = 1; -+ if (!dobreak) { -+ nesting_append(no_break(cur), copy_node(fwd)); -+ handle_lig_nest(no_break(cur), nob); -+ } -+ if (dobreak) -+ break; -+ } -+ next = vlink(fwd); -+ uncouple_node(fwd); -+ try_couple_nodes(cur, next); -+ nesting_append(post_break(cur), fwd); -+ handle_lig_nest(post_break(cur), pst); -+ } -+ if (fwd != null && type(fwd) == disc_node) { -+ halfword next = vlink(fwd); -+ if (vlink_no_break(fwd) == null -+ && vlink_post_break(fwd) == null -+ && next != null -+ && type(next) == glyph_node -+ && ((tlink_post_break(cur) != null && test_ligature(&lig, tlink_post_break(cur), next)) || -+ (tlink_no_break (cur) != null && test_ligature(&lig, tlink_no_break (cur), next)))) { -+ /*tex Building an |init_disc| followed by a |select_disc|: |{a-}{b}{AB} {-}{}{} c| */ -+ halfword last1 = vlink(next), tail; -+ uncouple_node(next); -+ try_couple_nodes(fwd, last1); -+ /*tex |{a-}{b}{AB} {-}{c}{}| */ -+ nesting_append(post_break(fwd), copy_node(next)); -+ /*tex |{a-}{b}{AB} {-}{c}{-}| */ -+ if (vlink_no_break(cur) != null) { -+ nesting_prepend(no_break(fwd), copy_node(vlink_pre_break(fwd))); -+ } -+ /*tex |{a-}{b}{AB} {b-}{c}{-}| */ -+ if (vlink_post_break(cur) != null) -+ nesting_prepend_list(pre_break(fwd), copy_node_list(vlink_post_break(cur))); -+ /*tex |{a-}{b}{AB} {b-}{c}{AB-}| */ -+ if (vlink_no_break(cur) != null) { -+ nesting_prepend_list(no_break(fwd), copy_node_list(vlink_no_break(cur))); -+ } -+ /*tex |{a-}{b}{ABC} {b-}{c}{AB-}| */ -+ tail = tlink_no_break(cur); -+ nesting_append(no_break(cur), copy_node(next)); -+ handle_lig_nest(no_break(cur), tail); -+ /*tex |{a-}{BC}{ABC} {b-}{c}{AB-}| */ -+ tail = tlink_post_break(cur); -+ nesting_append(post_break(cur), next); -+ handle_lig_nest(post_break(cur), tail); -+ /*tex Set the subtypes: */ -+ subtype(cur) = init_disc; -+ subtype(fwd) = select_disc; -+ } -+ } -+ } -+ -+ } else { -+ /*tex We have glyph nor disc. */ -+ return cur; -+ } -+ /*tex Goto the next node, where |\par| allows |vlink(cur)| to be NULL. */ -+ cur = vlink(cur); -+ } -+ return cur; -+} -+ -+/*tex The return value is the new tail, head should be a dummy: */ -+ -+halfword handle_ligaturing(halfword head, halfword tail) -+{ -+ /*tex A trick to allow explicit |node==null| tests. */ -+ halfword save_tail1 = null; -+ halfword cur, prev; -+ if (vlink(head) == null) -+ return tail; -+ if (tail != null) { -+ save_tail1 = vlink(tail); -+ vlink(tail) = null; -+ } -+ if (fix_node_lists) { -+ fix_node_list(head); -+ } -+ prev = head; -+ cur = vlink(prev); -+ while (cur != null) { -+ if (type(cur) == glyph_node || (type(cur) == boundary_node)) { -+ cur = handle_lig_word(cur); -+ } -+ prev = cur; -+ cur = vlink(cur); -+ } -+ if (prev == null) { -+ prev = tail; -+ } -+ if (tail != null) { -+ try_couple_nodes(prev, save_tail1); -+ } -+ return prev; -+} -+ -+ -+/*tex Kerning starts here: */ -+ -+static void add_kern_before(halfword left, halfword right) -+{ -+ if ((!is_rightghost(right)) && -+ font(left) == font(right) && has_kern(font(left), character(left))) { -+ int k = raw_get_kern(font(left), character(left), character(right)); -+ if (k != 0) { -+ halfword kern = new_kern(k); -+ halfword prev = alink(right); -+ couple_nodes(prev, kern); -+ couple_nodes(kern, right); -+ /*tex Update the attribute list (inherit from left): */ -+ delete_attribute_ref(node_attr(kern)); -+ add_node_attr_ref(node_attr(left)); -+ node_attr(kern) = node_attr(left); -+ } -+ } -+} -+ -+static void add_kern_after(halfword left, halfword right, halfword aft) -+{ -+ if ((!is_rightghost(right)) && -+ font(left) == font(right) && has_kern(font(left), character(left))) { -+ int k = raw_get_kern(font(left), character(left), character(right)); -+ if (k != 0) { -+ halfword kern = new_kern(k); -+ halfword next = vlink(aft); -+ couple_nodes(aft, kern); -+ try_couple_nodes(kern, next); -+ /*tex Update the attribute list (inherit from left == aft): */ -+ delete_attribute_ref(node_attr(kern)); -+ add_node_attr_ref(node_attr(aft)); -+ node_attr(kern) = node_attr(aft); -+ } -+ } -+} -+ -+static void do_handle_kerning(halfword root, halfword init_left, halfword init_right) -+{ -+ halfword cur = vlink(root); -+ halfword left = null; -+ if (cur == null) { -+ if (init_left != null && init_right != null) { -+ add_kern_after(init_left, init_right, root); -+ tlink(root) = vlink(root); -+ } -+ return; -+ } -+ if (type(cur) == glyph_node) { -+ set_is_glyph(cur); -+ if (init_left != null) -+ add_kern_before(init_left, cur); -+ left = cur; -+ } -+ while ((cur = vlink(cur)) != null) { -+ if (type(cur) == glyph_node) { -+ set_is_glyph(cur); -+ if (left != null) { -+ add_kern_before(left, cur); -+ if (character(left) < 0 || is_ghost(left)) { -+ halfword prev = alink(left); -+ couple_nodes(prev, cur); -+ flush_node(left); -+ } -+ } -+ left = cur; -+ } else { -+ if (type(cur) == disc_node) { -+ halfword right = type(vlink(cur)) == glyph_node ? vlink(cur) : null; -+ do_handle_kerning(pre_break(cur), left, null); -+ if (vlink_pre_break(cur) != null) -+ tlink_pre_break(cur) = tail_of_list(vlink_pre_break(cur)); -+ do_handle_kerning(post_break(cur), null, right); -+ if (vlink_post_break(cur) != null) -+ tlink_post_break(cur) = tail_of_list(vlink_post_break(cur)); -+ do_handle_kerning(no_break(cur), left, right); -+ if (vlink_no_break(cur) != null) -+ tlink_no_break(cur) = tail_of_list(vlink_no_break(cur)); -+ } -+ if (left != null) { -+ if (character(left) < 0 || is_ghost(left)) { -+ halfword prev = alink(left); -+ couple_nodes(prev, cur); -+ flush_node(left); -+ } -+ left = null; -+ } -+ } -+ } -+ if (left != null) { -+ if (init_right != null) -+ add_kern_after(left, init_right, left); -+ if (character(left) < 0 || is_ghost(left)) { -+ halfword prev = alink(left); -+ halfword next = vlink(left); -+ if (next != null) { -+ couple_nodes(prev, next); -+ tlink(root) = next; -+ } else if (prev != root) { -+ vlink(prev) = null; -+ tlink(root) = prev; -+ } else { -+ vlink(root) = null; -+ tlink(root) = null; -+ } -+ flush_node(left); -+ } -+ } -+} -+ -+halfword handle_kerning(halfword head, halfword tail) -+{ -+ halfword save_link = null; -+ if (tail == null) { -+ tlink(head) = null; -+ do_handle_kerning(head, null, null); -+ } else { -+ save_link = vlink(tail); -+ vlink(tail) = null; -+ tlink(head) = tail; -+ do_handle_kerning(head, null, null); -+ tail = tlink(head); -+ if (valid_node(save_link)) { -+ try_couple_nodes(tail, save_link); -+ } -+ } -+ return tail; -+} -+ -+/*tex The ligaturing and kerning \LUA\ interface: */ -+ -+static halfword run_lua_ligkern_callback(halfword head, halfword tail, int callback_id) -+{ -+ int i; -+ int top = lua_gettop(Luas); -+ if (!get_callback(Luas, callback_id)) { -+ lua_settop(Luas, top); -+ return tail; -+ } -+ nodelist_to_lua(Luas, head); -+ nodelist_to_lua(Luas, tail); -+ if ((i=lua_pcall(Luas, 2, 0, 0)) != 0) { -+ formatted_warning("ligkern","error: %s",lua_tostring(Luas, -1)); -+ lua_settop(Luas, top); -+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1)); -+ return tail; -+ } -+ if (fix_node_lists) { -+ fix_node_list(head); -+ } -+ lua_settop(Luas, top); -+ return tail; -+} -+ -+halfword new_ligkern(halfword head, halfword tail) -+{ -+ int callback_id = 0; -+ if (vlink(head) == null) -+ return tail; -+ callback_id = callback_defined(ligaturing_callback); -+ if (callback_id > 0) { -+ tail = run_lua_ligkern_callback(head, tail, callback_id); -+ if (tail == null) -+ tail = tail_of_list(head); -+ } else if (callback_id == 0) { -+ tail = handle_ligaturing(head, tail); -+ } -+ callback_id = callback_defined(kerning_callback); -+ if (callback_id > 0) { -+ tail = run_lua_ligkern_callback(head, tail, callback_id); -+ if (tail == null) { -+ tail = tail_of_list(head); -+ } -+ } else if (callback_id == 0) { -+ halfword nest1 = new_node(nesting_node, 1); -+ halfword cur = vlink(head); -+ halfword aft = vlink(tail); -+ couple_nodes(nest1, cur); -+ tlink(nest1) = tail; -+ vlink(tail) = null; -+ do_handle_kerning(nest1, null, null); -+ couple_nodes(head, vlink(nest1)); -+ tail = tlink(nest1); -+ try_couple_nodes(tail, aft); -+ flush_node(nest1); -+ } -+ return tail; -+} ---- texlive-source/texk/web2c/luatexdir/font/writecff.c.me 1970-01-01 01:00:00.000000000 +0100 -+++ texlive-source/texk/web2c/luatexdir/font/writecff.c 2020-11-07 15:50:28.081338255 +0100 -@@ -0,0 +1,3156 @@ -+/* -+ -+Copyright 2006-2010 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+#include "lua/luatex-api.h" -+#include "font/writecff.h" -+ -+extern int cidset; -+ -+#define get_offset(s,n) get_unsigned(s, (n)) -+#define get_card8(a) (card8)(a->stream[a->offset++]) -+#define get_card16(a) (card16)(get_unsigned(a,2)) -+#define get_card32(a) (get_unsigned(a,4)) -+ -+#undef b0 -+#undef b1 -+#undef b2 -+#undef b3 -+ -+#define WORK_BUFFER_SIZE 1024 -+ -+static char work_buffer[WORK_BUFFER_SIZE]; -+ -+static unsigned long get_unsigned(cff_font * cff, int n) -+{ -+ unsigned long v = 0; -+ while (n-- > 0) -+ v = v * 256 + get_card8(cff); -+ return v; -+} -+ -+const char *const cff_stdstr[CFF_STDSTR_MAX] = { -+ ".notdef", "space", "exclam", "quotedbl", "numbersign", -+ "dollar", "percent", "ampersand", "quoteright", "parenleft", -+ "parenright", "asterisk", "plus", "comma", "hyphen", -+ "period", "slash", "zero", "one", "two", -+ "three", "four", "five", "six", "seven", -+ "eight", "nine", "colon", "semicolon", "less", -+ "equal", "greater", "question", "at", "A", -+ "B", "C", "D", "E", "F", -+ "G", "H", "I", "J", "K", -+ "L", "M", "N", "O", "P", -+ "Q", "R", "S", "T", "U", -+ "V", "W", "X", "Y", "Z", -+ "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", -+ "quoteleft", "a", "b", "c", "d", -+ "e", "f", "g", "h", "i", -+ "j", "k", "l", "m", "n", -+ "o", "p", "q", "r", "s", -+ "t", "u", "v", "w", "x", -+ "y", "z", "braceleft", "bar", "braceright", -+ "asciitilde", "exclamdown", "cent", "sterling", "fraction", -+ "yen", "florin", "section", "currency", "quotesingle", -+ "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", -+ "fl", "endash", "dagger", "daggerdbl", "periodcentered", -+ "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", -+ "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", -+ "acute", "circumflex", "tilde", "macron", "breve", -+ "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", -+ "ogonek", "caron", "emdash", "AE", "ordfeminine", -+ "Lslash", "Oslash", "OE", "ordmasculine", "ae", -+ "dotlessi", "lslash", "oslash", "oe", "germandbls", -+ "onesuperior", "logicalnot", "mu", "trademark", "Eth", -+ "onehalf", "plusminus", "Thorn", "onequarter", "divide", -+ "brokenbar", "degree", "thorn", "threequarters", "twosuperior", -+ "registered", "minus", "eth", "multiply", "threesuperior", -+ "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", -+ "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", -+ "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", -+ "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", -+ "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", -+ "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", -+ "aacute", "acircumflex", "adieresis", "agrave", "aring", -+ "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", -+ "egrave", "iacute", "icircumflex", "idieresis", "igrave", -+ "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", -+ "otilde", "scaron", "uacute", "ucircumflex", "udieresis", -+ "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", -+ "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", -+ "Acutesmall", -+ "parenleftsuperior", "parenrightsuperior", "twodotenleader", -+ "onedotenleader", "zerooldstyle", -+ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", -+ "fiveoldstyle", -+ "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", -+ "commasuperior", -+ "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", -+ "bsuperior", -+ "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", -+ "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", -+ "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", -+ "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", -+ "Asmall", -+ "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", -+ "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", -+ "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", -+ "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", -+ "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", -+ "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", -+ "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", -+ "Dieresissmall", -+ "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", -+ "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", -+ "questiondownsmall", -+ "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", -+ "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", -+ "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", -+ "oneinferior", -+ "twoinferior", "threeinferior", "fourinferior", "fiveinferior", -+ "sixinferior", -+ "seveninferior", "eightinferior", "nineinferior", "centinferior", -+ "dollarinferior", -+ "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", -+ "Acircumflexsmall", -+ "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", -+ "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", -+ "Igravesmall", -+ "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", -+ "Ntildesmall", -+ "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", -+ "Odieresissmall", -+ "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", -+ "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", -+ "001.000", "001.001", "001.002", "001.003", -+ "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" -+}; -+ -+/*tex Only read the header part and forget about the body */ -+ -+cff_index *cff_get_index_header(cff_font * cff) -+{ -+ cff_index *idx; -+ card16 i, count; -+ idx = xcalloc(1, sizeof(cff_index)); -+ if (cff->header_major == 2) { -+ idx->count = count = get_card32(cff); -+ } else { -+ idx->count = count = get_card16(cff); -+ } -+ if (count > 0) { -+ idx->offsize = get_card8(cff); -+ if (idx->offsize < 1 || idx->offsize > 4) -+ normal_error("cff","invalid offsize data (1)"); -+ idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset))); -+ for (i = 0; i offset)[i] = get_offset(cff, idx->offsize); -+ if (i == USHRT_MAX) -+ break; -+ } -+ if (idx->offset[0] != 1) -+ normal_error("cff","invalid index data"); -+ idx->data = NULL; -+ } else { -+ idx->offsize = 0; -+ idx->offset = NULL; -+ idx->data = NULL; -+ } -+ return idx; -+} -+ -+cff_index *cff_get_index(cff_font * cff) -+{ -+ cff_index *idx; -+ card16 i, count; -+ size_t length; -+ idx = xcalloc(1, sizeof(cff_index)); -+ idx->count = count = get_card16(cff); -+ if (count > 0) { -+ idx->offsize = get_card8(cff); -+ if (idx->offsize < 1 || idx->offsize > 4) -+ normal_error("cff","invalid offsize data (2)"); -+ idx->offset = xmalloc((unsigned) (((unsigned) count + 1) * sizeof(l_offset))); -+ for (i = 0; i < count + 1; i++) { -+ idx->offset[i] = get_offset(cff, idx->offsize); -+ } -+ if (idx->offset[0] != 1) -+ normal_error("cff","invalid index offset data"); -+ length = (size_t) (idx->offset[count] - idx->offset[0]); -+ idx->data = xmalloc((unsigned) length * sizeof(card8)); -+ memcpy(idx->data, &cff->stream[cff->offset], length); -+ cff->offset += length; -+ } else { -+ idx->offsize = 0; -+ idx->offset = NULL; -+ idx->data = NULL; -+ } -+ return idx; -+} -+ -+static cff_index *cff_empty_index(cff_font * cff) -+{ -+ cff_index *idx; -+ idx = xcalloc(1, sizeof(cff_index)); -+ idx->count = 0; -+ idx->offsize = 0; -+ idx->offset = NULL; -+ idx->data = NULL; -+ return idx; -+} -+ -+static cff_index *cff_get_index2(cff_font * cff) -+{ -+ /*tex We fake a dict array. */ -+ cff_index *idx; -+ size_t length; -+ idx = xcalloc(1, sizeof(cff_index)); -+ length = (size_t) cff->header_offsize; -+ idx->offsize = 2; -+ idx->count = 1; -+ idx->offset = xmalloc((unsigned) (((unsigned) 2) * sizeof(l_offset))); -+ idx->offset[0] = 1; -+ idx->offset[1] = length + 1; -+ idx->data = xmalloc((unsigned) length * sizeof(card8)); -+ memcpy(idx->data, &cff->stream[cff->offset], length ); -+ cff->offset += length ; -+ return idx; -+} -+ -+long cff_pack_index(cff_index * idx, card8 * dest, long destlen) -+{ -+ long len = 0; -+ unsigned long datalen; -+ card16 i; -+ if (idx->count < 1) { -+ if (destlen < 2) -+ normal_error("cff","not enough space available"); -+ memset(dest, 0, 2); -+ return 2; -+ } -+ len = cff_index_size(idx); -+ datalen = idx->offset[idx->count] - 1; -+ if (destlen < len) -+ normal_error("cff","not enough space available"); -+ *(dest++) = (card8) ((idx->count >> 8) & 0xff); -+ *(dest++) = (card8) (idx->count & 0xff); -+ if (datalen < 0xffUL) { -+ idx->offsize = 1; -+ *(dest++) = 1; -+ for (i = 0; i <= idx->count; i++) { -+ *(dest++) = (card8) (idx->offset[i] & 0xff); -+ } -+ } else if (datalen < 0xffffUL) { -+ idx->offsize = 2; -+ *(dest++) = 2; -+ for (i = 0; i <= idx->count; i++) { -+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff); -+ *(dest++) = (card8) (idx->offset[i] & 0xff); -+ } -+ } else if (datalen < 0xffffffUL) { -+ idx->offsize = 3; -+ *(dest++) = 3; -+ for (i = 0; i <= idx->count; i++) { -+ *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff); -+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff); -+ *(dest++) = (card8) (idx->offset[i] & 0xff); -+ } -+ } else { -+ idx->offsize = 4; -+ *(dest++) = 4; -+ for (i = 0; i <= idx->count; i++) { -+ *(dest++) = (card8) ((idx->offset[i] >> 24) & 0xff); -+ *(dest++) = (card8) ((idx->offset[i] >> 16) & 0xff); -+ *(dest++) = (card8) ((idx->offset[i] >> 8) & 0xff); -+ *(dest++) = (card8) (idx->offset[i] & 0xff); -+ } -+ } -+ memmove(dest, idx->data, idx->offset[idx->count] - 1); -+ return len; -+} -+ -+long cff_index_size(cff_index * idx) -+{ -+ if (idx->count > 0) { -+ l_offset datalen; -+ datalen = idx->offset[idx->count] - 1; -+ if (datalen < 0xffUL) { -+ idx->offsize = 1; -+ } else if (datalen < 0xffffUL) { -+ idx->offsize = 2; -+ } else if (datalen < 0xffffffUL) { -+ idx->offsize = 3; -+ } else { -+ idx->offsize = 4; -+ } -+ return (3 + (idx->offsize) * (idx->count + 1) + (long) datalen); -+ } else { -+ return 2; -+ } -+} -+ -+cff_index *cff_new_index(card16 count) -+{ -+ cff_index *idx; -+ idx = xcalloc(1, sizeof(cff_index)); -+ idx->count = count; -+ idx->offsize = 0; -+ if (count > 0) { -+ idx->offset = xcalloc((unsigned) (count + 1), sizeof(l_offset)); -+ (idx->offset)[0] = 1; -+ } else { -+ idx->offset = NULL; -+ } -+ idx->data = NULL; -+ return idx; -+} -+ -+void cff_release_index(cff_index * idx) -+{ -+ if (idx) { -+ xfree(idx->data); -+ xfree(idx->offset); -+ xfree(idx); -+ } -+} -+ -+void cff_release_dict(cff_dict * dict) -+{ -+ if (dict) { -+ if (dict->entries) { -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ xfree((dict->entries)[i].values); -+ } -+ xfree(dict->entries); -+ } -+ xfree(dict); -+ } -+} -+ -+void cff_release_encoding(cff_encoding * encoding) -+{ -+ if (encoding) { -+ switch (encoding->format & (~0x80)) { -+ case 0: -+ xfree(encoding->data.codes); -+ break; -+ case 1: -+ xfree(encoding->data.range1); -+ break; -+ default: -+ normal_error("cff","unknown encoding format"); -+ } -+ if (encoding->format & 0x80) -+ xfree(encoding->supp); -+ xfree(encoding); -+ } -+} -+ -+void cff_release_charsets(cff_charsets * charset) -+{ -+ if (charset) { -+ switch (charset->format) { -+ case 0: -+ xfree(charset->data.glyphs); -+ break; -+ case 1: -+ xfree(charset->data.range1); -+ break; -+ case 2: -+ xfree(charset->data.range2); -+ break; -+ default: -+ break; -+ } -+ xfree(charset); -+ } -+} -+ -+void cff_release_fdselect(cff_fdselect * fdselect) -+{ -+ if (fdselect) { -+ if (fdselect->format == 0) { -+ xfree(fdselect->data.fds); -+ } else if (fdselect->format == 3) { -+ xfree(fdselect->data.ranges); -+ } -+ xfree(fdselect); -+ } -+} -+ -+void cff_close(cff_font * cff) -+{ -+ card16 i; -+ if (cff) { -+ xfree(cff->fontname); -+ if (cff->name) -+ cff_release_index(cff->name); -+ if (cff->topdict) -+ cff_release_dict(cff->topdict); -+ if (cff->string) -+ cff_release_index(cff->string); -+ if (cff->gsubr) -+ cff_release_index(cff->gsubr); -+ if (cff->encoding) -+ cff_release_encoding(cff->encoding); -+ if (cff->charsets) -+ cff_release_charsets(cff->charsets); -+ if (cff->fdselect) -+ cff_release_fdselect(cff->fdselect); -+ if (cff->cstrings) -+ cff_release_index(cff->cstrings); -+ if (cff->fdarray) { -+ for (i = 0; i < cff->num_fds; i++) { -+ if (cff->fdarray[i]) -+ cff_release_dict(cff->fdarray[i]); -+ } -+ xfree(cff->fdarray); -+ } -+ if (cff->private) { -+ for (i = 0; i < cff->num_fds; i++) { -+ if (cff->private[i]) -+ cff_release_dict(cff->private[i]); -+ } -+ xfree(cff->private); -+ } -+ if (cff->subrs) { -+ for (i = 0; i < cff->num_fds; i++) { -+ if (cff->subrs[i]) -+ cff_release_index(cff->subrs[i]); -+ } -+ xfree(cff->subrs); -+ } -+ if (cff->_string) -+ cff_release_index(cff->_string); -+ xfree(cff); -+ } -+ return; -+} -+ -+char *cff_get_name(cff_font * cff) -+{ -+ char *fontname; -+ l_offset len; -+ cff_index *idx; -+ idx = cff->name; -+ len = idx->offset[cff->index + 1] - idx->offset[cff->index]; -+ fontname = xmalloc((unsigned) (len + 1) * sizeof(char)); -+ memcpy(fontname, idx->data + idx->offset[cff->index] - 1, len); -+ fontname[len] = '\0'; -+ return fontname; -+} -+ -+long cff_set_name(cff_font * cff, char *name) -+{ -+ cff_index *idx; -+ if (strlen(name) > 127) -+ normal_error("cff","FontName string length too large"); -+ if (cff->name) -+ cff_release_index(cff->name); -+ cff->name = idx = xcalloc(1, sizeof(cff_index)); -+ idx->count = 1; -+ idx->offsize = 1; -+ idx->offset = xmalloc(2 * sizeof(l_offset)); -+ (idx->offset)[0] = 1; -+ (idx->offset)[1] = strlen(name) + 1; -+ idx->data = xmalloc((unsigned) strlen(name) * sizeof(card8)); -+ /*tex No trailing |\0| */ -+ memmove(idx->data, name, strlen(name)); -+ return (long) (5 + strlen(name)); -+} -+ -+long cff_put_header(cff_font * cff, card8 * dest, long destlen) -+{ -+ if (destlen < 4) -+ normal_error("cff","not enough space available"); -+ /*tex cff->header_major */ -+ *(dest++) = 1; -+ *(dest++) = cff->header_minor; -+ *(dest++) = 4; -+ /*tex -+ Additional data in between header and Name INDEX is ignored. We will set -+ all offset (0) to a four-byte integer. -+ */ -+ *(dest++) = 4; -+ cff->header_offsize = 4; -+ return 4; -+} -+ -+#define CFF_PARSE_OK 0 -+#define CFF_CFF_ERROR_PARSE_CFF_ERROR -1 -+#define CFF_CFF_ERROR_STACK_OVERFLOW -2 -+#define CFF_CFF_ERROR_STACK_UNDERFLOW -3 -+#define CFF_CFF_ERROR_STACK_RANGECHECK -4 -+ -+#define DICT_ENTRY_MAX 16 -+ -+cff_dict *cff_new_dict(void) -+{ -+ cff_dict *dict; -+ dict = xcalloc(1, sizeof(cff_dict)); -+ dict->max = DICT_ENTRY_MAX; -+ dict->count = 0; -+ dict->entries = xcalloc((unsigned) dict->max, sizeof(cff_dict_entry)); -+ return dict; -+} -+ -+/*tex -+ -+ Operand stack: only numbers are stored (as double). Operand types are: -+ -+ \startitemize -+ \startitem number: double (integer or real) \stopitem -+ \startitem boolean: stored as a number \stopitem -+ \startitem SID: stored as a number \stopitem -+ \startitem array: array of numbers \stopitem -+ \startitem delta: array of numbers \stopitem -+ \stopitemize -+ -+*/ -+ -+#define CFF_DICT_STACK_LIMIT 64 -+static int stack_top = 0; -+static double arg_stack[CFF_DICT_STACK_LIMIT]; -+ -+/* The CFF DICT encoding: */ -+ -+#define CFF_LAST_DICT_OP1 26 -+#define CFF_LAST_DICT_OP2 39 -+#define CFF_LAST_DICT_OP (CFF_LAST_DICT_OP1 + CFF_LAST_DICT_OP2) -+ -+static struct { -+ const char *opname; -+ int argtype; -+} dict_operator[CFF_LAST_DICT_OP] = { -+ { "version", CFF_TYPE_SID }, -+ { "Notice", CFF_TYPE_SID }, -+ { "FullName", CFF_TYPE_SID }, -+ { "FamilyName", CFF_TYPE_SID }, -+ { "Weight", CFF_TYPE_SID }, -+ { "FontBBox", CFF_TYPE_ARRAY }, -+ { "BlueValues", CFF_TYPE_DELTA }, -+ { "OtherBlues", CFF_TYPE_DELTA }, -+ { "FamilyBlues", CFF_TYPE_DELTA }, -+ { "FamilyOtherBlues", CFF_TYPE_DELTA }, -+ { "StdHW", CFF_TYPE_NUMBER }, -+ { "StdVW", CFF_TYPE_NUMBER }, -+ { NULL, -1 }, -+ { "UniqueID", CFF_TYPE_NUMBER }, -+ { "XUID", CFF_TYPE_ARRAY }, -+ { "charset", CFF_TYPE_OFFSET }, -+ { "Encoding", CFF_TYPE_OFFSET }, -+ { "CharStrings", CFF_TYPE_OFFSET }, -+ { "Private", CFF_TYPE_SZOFF }, -+ { "Subrs", CFF_TYPE_OFFSET }, -+ { "defaultWidthX", CFF_TYPE_NUMBER }, -+ { "nominalWidthX", CFF_TYPE_NUMBER }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ /*tex two CFF2 instructions */ -+ { "vstore", CFF_TYPE_OFFSET }, -+ { "maxstack", CFF_TYPE_NUMBER }, -+ /*tex Here we start with operator 2 of 12. */ -+ { "Copyright", CFF_TYPE_SID }, -+ { "IsFixedPitch", CFF_TYPE_BOOLEAN }, -+ { "ItalicAngle", CFF_TYPE_NUMBER }, -+ { "UnderlinePosition", CFF_TYPE_NUMBER }, -+ { "UnderlineThickness", CFF_TYPE_NUMBER }, -+ { "PaintType", CFF_TYPE_NUMBER }, -+ { "CharstringType", CFF_TYPE_NUMBER }, -+ { "FontMatrix", CFF_TYPE_ARRAY }, -+ { "StrokeWidth", CFF_TYPE_NUMBER }, -+ { "BlueScale", CFF_TYPE_NUMBER }, -+ { "BlueShift", CFF_TYPE_NUMBER }, -+ { "BlueFuzz", CFF_TYPE_NUMBER }, -+ { "StemSnapH", CFF_TYPE_DELTA }, -+ { "StemSnapV", CFF_TYPE_DELTA }, -+ { "ForceBold", CFF_TYPE_BOOLEAN }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { "LanguageGroup", CFF_TYPE_NUMBER }, -+ { "ExpansionFactor", CFF_TYPE_NUMBER }, -+ { "InitialRandomSeed", CFF_TYPE_NUMBER }, -+ { "SyntheticBase", CFF_TYPE_NUMBER }, -+ { "PostScript", CFF_TYPE_SID }, -+ { "BaseFontName", CFF_TYPE_SID }, -+ { "BaseFontBlend", CFF_TYPE_DELTA }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { NULL, -1 }, -+ { "ROS", CFF_TYPE_ROS }, -+ { "CIDFontVersion", CFF_TYPE_NUMBER }, -+ { "CIDFontRevision", CFF_TYPE_NUMBER }, -+ { "CIDFontType", CFF_TYPE_NUMBER }, -+ { "CIDCount", CFF_TYPE_NUMBER }, -+ { "UIDBase", CFF_TYPE_NUMBER }, -+ { "FDArray", CFF_TYPE_OFFSET }, -+ { "FDSelect", CFF_TYPE_OFFSET }, -+ { "FontName", CFF_TYPE_SID } -+}; -+ -+/*tex Parse DICT data */ -+ -+static double get_integer(card8 ** data, card8 * endptr, int *status) -+{ -+ long result = 0; -+ card8 b0, b1, b2; -+ -+ b0 = *(*data)++; -+ if (b0 == 28 && *data < endptr - 2) { -+ /*tex shortint */ -+ b1 = *(*data)++; -+ b2 = *(*data)++; -+ result = b1 * 256 + b2; -+ if (result > 0x7fffL) -+ result -= 0x10000L; -+ } else if (b0 == 29 && *data < endptr - 4) { -+ /*tex longint */ -+ int i; -+ result = *(*data)++; -+ if (result > 0x7f) -+ result -= 0x100; -+ for (i = 0; i < 3; i++) { -+ result = result * 256 + (**data); -+ *data += 1; -+ } -+ } else if (b0 >= 32 && b0 <= 246) { -+ /*tex int (1) */ -+ result = b0 - 139; -+ } else if (b0 >= 247 && b0 <= 250) { -+ /*tex int (2) */ -+ b1 = *(*data)++; -+ result = (b0 - 247) * 256 + b1 + 108; -+ } else if (b0 >= 251 && b0 <= 254) { -+ b1 = *(*data)++; -+ result = -(b0 - 251) * 256 - b1 - 108; -+ } else { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ } -+ return (double) result; -+} -+ -+/*tex Simply uses |strtod|: */ -+ -+static double get_real(card8 ** data, card8 * endptr, int *status) -+{ -+ double result = 0.0; -+ int nibble = 0, pos = 0; -+ int len = 0, fail = 0; -+ -+ if (**data != 30 || *data >= endptr - 1) { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ return 0.0; -+ } -+ /*tex Skip the first byte (30): */ -+ *data += 1; -+ pos = 0; -+ while ((!fail) && len < WORK_BUFFER_SIZE - 2 && *data < endptr) { -+ /*tex Get a nibble. */ -+ if (pos % 2) { -+ nibble = **data & 0x0f; -+ *data += 1; -+ } else { -+ nibble = (**data >> 4) & 0x0f; -+ } -+ if (nibble >= 0x00 && nibble <= 0x09) { -+ work_buffer[len++] = (char) (nibble + '0'); -+ } else if (nibble == 0x0a) { /* . */ -+ work_buffer[len++] = '.'; -+ } else if (nibble == 0x0b || nibble == 0x0c) { -+ /*tex E, E- */ -+ work_buffer[len++] = 'e'; -+ if (nibble == 0x0c) -+ work_buffer[len++] = '-'; -+ } else if (nibble == 0x0e) { -+ /*tex the minus */ -+ work_buffer[len++] = '-'; -+ } else if (nibble == 0x0d) { -+ /*tex do nothing */ -+ } else if (nibble == 0x0f) { -+ /*tex we're done */ -+ work_buffer[len++] = '\0'; -+ if (((pos % 2) == 0) && (**data != 0xff)) { -+ fail = 1; -+ } -+ break; -+ } else { -+ /*tex invalid */ -+ fail = 1; -+ } -+ pos++; -+ } -+ /*tex the returned values */ -+ if (fail || nibble != 0x0f) { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ } else { -+ char *s; -+ errno=0; -+ result = strtod(work_buffer, &s); -+ if ((result==0.0 && work_buffer==s) || errno) { -+ /*tex Conversion is not possible. */ -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ } -+ } -+ return result; -+} -+ -+/*tex Operators */ -+ -+static void add_dict(cff_dict * dict, card8 ** data, card8 * endptr, int *status) -+{ -+ int id, argtype, t; -+ id = **data; -+ if (id == 0x0c) { -+ *data += 1; -+ if (*data >= endptr || -+ (id = **data + CFF_LAST_DICT_OP1) >= CFF_LAST_DICT_OP) { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ return; -+ } -+ } else if (id >= CFF_LAST_DICT_OP1) { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ return; -+ } -+ argtype = dict_operator[id].argtype; -+ if (dict_operator[id].opname == NULL || argtype < 0) { -+ *status = CFF_CFF_ERROR_PARSE_CFF_ERROR; -+ return; -+ } -+ if (dict->count >= dict->max) { -+ dict->max += DICT_ENTRY_MAX; -+ /*tex Not zeroed! */ -+ dict->entries = xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry))); -+ } -+ (dict->entries)[dict->count].id = id; -+ (dict->entries)[dict->count].key = dict_operator[id].opname; -+ if (argtype == CFF_TYPE_NUMBER || -+ argtype == CFF_TYPE_BOOLEAN || -+ argtype == CFF_TYPE_SID || argtype == CFF_TYPE_OFFSET) { -+ /*tex Check for underflow here, as exactly one operand is expected. */ -+ if (stack_top < 1) { -+ *status = CFF_CFF_ERROR_STACK_UNDERFLOW; -+ return; -+ } -+ stack_top--; -+ (dict->entries)[dict->count].count = 1; -+ (dict->entries)[dict->count].values = xcalloc(1, sizeof(double)); -+ (dict->entries)[dict->count].values[0] = arg_stack[stack_top]; -+ dict->count += 1; -+ } else { -+ /*tex -+ Just ignore operator if there were no operands provided. Don't treat -+ this as underflow, e.g. |StemSnapV| in |TemporaLGCUni-Italic.otf|. -+ */ -+ if ((t = stack_top) > 0) { -+ (dict->entries)[dict->count].count = stack_top; -+ (dict->entries)[dict->count].values = -+ xmalloc((unsigned) ((unsigned) stack_top * sizeof(double))); -+ while (stack_top > 0) { -+ stack_top--; -+ (dict->entries)[dict->count].values[stack_top] = -+ arg_stack[stack_top]; -+ } -+ if (t > 3 && strcmp(dict_operator[id].opname, "FontMatrix") == 0) { -+ (dict->entries)[dict->count].values[0] = 0.001; -+ (dict->entries)[dict->count].values[3] = 0.001; -+ } -+ dict->count += 1; -+ } -+ } -+ *data += 1; -+ return; -+} -+ -+/*tex -+ -+ All operands are treated as number or array of numbers. -+ -+ \startitemize -+ \startitem |Private|: two numbers, size and offset \stopitem -+ \startitem |ROS|: hree numbers, SID, SID, and a number \stopitem -+ \stopitemize -+ -+*/ -+ -+cff_dict *cff_dict_unpack(card8 * data, card8 * endptr) -+{ -+ cff_dict *dict; -+ int status = CFF_PARSE_OK; -+ stack_top = 0; -+ dict = cff_new_dict(); -+ while (data < endptr && status == CFF_PARSE_OK) { -+ if (*data < CFF_LAST_DICT_OP1) { -+ /*tex Some operator. */ -+ add_dict(dict, &data, endptr, &status); -+ } else if (*data == 30) { -+ /*tex First byte of a sequence (variable). */ -+ if (stack_top < CFF_DICT_STACK_LIMIT) { -+ arg_stack[stack_top] = get_real(&data, endptr, &status); -+ stack_top++; -+ } else { -+ status = CFF_CFF_ERROR_STACK_OVERFLOW; -+ } -+ } else if (*data == 255 || (*data >= CFF_LAST_DICT_OP1 && *data <= 27)) { -+ /*tex Reserved. */ -+ data++; -+ } else { -+ /*tex Everything else is an integer. */ -+ if (stack_top < CFF_DICT_STACK_LIMIT) { -+ arg_stack[stack_top] = get_integer(&data, endptr, &status); -+ stack_top++; -+ } else { -+ status = CFF_CFF_ERROR_STACK_OVERFLOW; -+ } -+ } -+ } -+ if (status != CFF_PARSE_OK) { -+ formatted_error("cff","parsing DICT failed (error=%d)", status); -+ } else if (stack_top != 0) { -+ normal_warning("cff","garbage in DICT data"); -+ stack_top = 0; -+ } -+ return dict; -+} -+ -+int cff_dict_known(cff_dict * dict, const char *key) -+{ -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ if (key && strcmp(key, (dict->entries)[i].key) == 0 -+ && (dict->entries)[i].count > 0) -+ return 1; -+ } -+ return 0; -+} -+ -+double cff_dict_get(cff_dict * dict, const char *key, int idx) -+{ -+ double value = 0.0; -+ int i; -+ assert(key && dict); -+ for (i = 0; i < dict->count; i++) { -+ if (strcmp(key, (dict->entries)[i].key) == 0) { -+ if ((dict->entries)[i].count > idx) -+ value = (dict->entries)[i].values[idx]; -+ else -+ normal_error("cff","invalid index number"); -+ break; -+ } -+ } -+ if (i == dict->count) -+ formatted_error("cff","DICT entry '%s' not found", key); -+ return value; -+} -+ -+card8 cff_fdselect_lookup(cff_font * cff, card16 gid) -+{ -+ card8 fd = 0xff; -+ cff_fdselect *fdsel; -+ if (cff->fdselect == NULL) -+ normal_error("cff","FDSelect not available"); -+ fdsel = cff->fdselect; -+ if (gid >= cff->num_glyphs) -+ normal_error("cff","invalid glyph index"); -+ switch (fdsel->format) { -+ case 0: -+ fd = fdsel->data.fds[gid]; -+ break; -+ case 3: -+ { -+ if (gid == 0) { -+ fd = (fdsel->data).ranges[0].fd; -+ } else { -+ card16 i; -+ for (i = 1; i < (fdsel->num_entries); i++) { -+ if (gid < (fdsel->data).ranges[i].first) -+ break; -+ } -+ fd = (fdsel->data).ranges[i - 1].fd; -+ } -+ } -+ break; -+ default: -+ normal_error("cff","invalid FDSelect format"); -+ break; -+ } -+ if (fd >= cff->num_fds) -+ normal_error("cff","invalid Font DICT index"); -+ return fd; -+} -+ -+long cff_read_subrs(cff_font * cff) -+{ -+ long len = 0; -+ long offset; -+ int i; -+ if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdselect == NULL) { -+ cff_read_fdselect(cff); -+ } -+ if ((cff->flag & FONTTYPE_CIDFONT) && cff->fdarray == NULL) { -+ cff_read_fdarray(cff); -+ } -+ if (cff->private == NULL) -+ cff_read_private(cff); -+ if (cff->gsubr == NULL) { -+ cff->offset = cff->gsubr_offset; -+ cff->gsubr = cff_get_index(cff); -+ } -+ cff->subrs = xcalloc(cff->num_fds, sizeof(cff_index *)); -+ if (cff->flag & FONTTYPE_CIDFONT) { -+ for (i = 0; i < cff->num_fds; i++) { -+ if (cff->private[i] == NULL || -+ !cff_dict_known(cff->private[i], "Subrs")) { -+ (cff->subrs)[i] = NULL; -+ } else { -+ offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1); -+ offset += (long) cff_dict_get(cff->private[i], "Subrs", 0); -+ cff->offset = (l_offset) offset; -+ (cff->subrs)[i] = cff_get_index(cff); -+ len += cff_index_size((cff->subrs)[i]); -+ } -+ } -+ } else if (cff->private[0] == NULL || !cff_dict_known(cff->private[0], "Subrs")) { -+ (cff->subrs)[0] = NULL; -+ } else { -+ offset = (long) cff_dict_get(cff->topdict, "Private", 1); -+ offset += (long) cff_dict_get(cff->private[0], "Subrs", 0); -+ cff->offset = (l_offset) offset; -+ (cff->subrs)[0] = cff_get_index(cff); -+ len += cff_index_size((cff->subrs)[0]); -+ } -+ return len; -+} -+ -+long cff_read_fdarray(cff_font * cff) -+{ -+ long len = 0; -+ cff_index *idx; -+ long offset, size; -+ card16 i; -+ if (cff->topdict == NULL) -+ normal_error("cff","top DICT not found"); -+ if (!(cff->flag & FONTTYPE_CIDFONT)) -+ return 0; -+ offset = (long) cff_dict_get(cff->topdict, "FDArray", 0); -+ cff->offset = (l_offset) offset; -+ idx = cff_get_index(cff); -+ cff->num_fds = (card8) idx->count; -+ cff->fdarray = xmalloc((unsigned) (idx->count * sizeof(cff_dict *))); -+ for (i = 0; i < idx->count; i++) { -+ card8 *data = idx->data + (idx->offset)[i] - 1; -+ size = (long) ((idx->offset)[i + 1] - (idx->offset)[i]); -+ if (size > 0) { -+ (cff->fdarray)[i] = cff_dict_unpack(data, data + size); -+ } else { -+ (cff->fdarray)[i] = NULL; -+ } -+ } -+ len = cff_index_size(idx); -+ cff_release_index(idx); -+ return len; -+} -+ -+long cff_read_private(cff_font * cff) -+{ -+ long len = 0; -+ card8 *data; -+ long offset, size; -+ if (cff->flag & FONTTYPE_CIDFONT) { -+ int i; -+ if (cff->fdarray == NULL) -+ cff_read_fdarray(cff); -+ cff->private = xmalloc((unsigned) (cff->num_fds * sizeof(cff_dict *))); -+ for (i = 0; i < cff->num_fds; i++) { -+ if (cff->fdarray[i] != NULL && -+ cff_dict_known(cff->fdarray[i], "Private") && -+ (size = (long) cff_dict_get(cff->fdarray[i], "Private", 0)) > 0) { -+ offset = (long) cff_dict_get(cff->fdarray[i], "Private", 1); -+ cff->offset = (l_offset) offset; -+ data = xmalloc((unsigned) size * sizeof(card8)); -+ memcpy(data, &cff->stream[cff->offset], (size_t) size); -+ cff->offset = (l_offset) size; -+ (cff->private)[i] = cff_dict_unpack(data, data + size); -+ xfree(data); -+ len += size; -+ } else { -+ (cff->private)[i] = NULL; -+ } -+ } -+ } else { -+ cff->num_fds = 1; -+ cff->private = xmalloc(sizeof(cff_dict *)); -+ if (cff_dict_known(cff->topdict, "Private") && -+ (size = (long) cff_dict_get(cff->topdict, "Private", 0)) > 0) { -+ offset = (long) cff_dict_get(cff->topdict, "Private", 1); -+ cff->offset = (l_offset) offset; -+ data = xmalloc((unsigned) size * sizeof(card8)); -+ memcpy(data, &cff->stream[cff->offset], (size_t) size); -+ cff->offset = (l_offset) size; -+ cff->private[0] = cff_dict_unpack(data, data + size); -+ xfree(data); -+ len += size; -+ } else { -+ (cff->private)[0] = NULL; -+ len = 0; -+ } -+ } -+ return len; -+} -+ -+cff_font *read_cff(unsigned char *buf, long buflength, int n) -+{ -+ cff_font *cff; -+ cff_index *idx; -+ long offset; -+ cff = xcalloc(1, sizeof(cff_font)); -+ cff->stream = buf; -+ cff->stream_size = (l_offset) buflength; -+ cff->index = n; -+ cff->header_major = get_card8(cff); -+ cff->header_minor = get_card8(cff); -+ cff->header_hdr_size = get_card8(cff); -+ if (cff->header_major == 2) { -+ /*tex We have only one top dictionary. */ -+ cff->header_offsize = get_card16(cff); -+ } else { -+ cff->header_offsize = get_card8(cff); -+ if (cff->header_offsize < 1 || cff->header_offsize > 4) { -+ normal_warning("cff","invalid offsize data (4)"); -+ cff_close(cff); -+ return NULL; -+ } -+ } -+ if (cff->header_major > 2) { -+ formatted_warning("cff","major version %u not supported", cff->header_major); -+ cff_close(cff); -+ return NULL; -+ } -+ cff->offset = cff->header_hdr_size; -+ /*tex The name index. */ -+ if (cff->header_major == 2) { -+ cff->name = cff_empty_index(cff); -+ } else { -+ idx = cff_get_index(cff); -+ if (n > idx->count - 1) { -+ normal_warning("cff","invalid fontset index number"); -+ cff_close(cff); -+ return NULL; -+ } -+ cff->name = idx; -+ cff->fontname = cff_get_name(cff); -+ } -+ /*tex The top dict index. */ -+ if (cff->header_major == 2) { -+ /*tex we fake an index (just one entry) */ -+ idx = cff_get_index2(cff); -+ } else { -+ idx = cff_get_index(cff); -+ } -+ if (n > idx->count - 1) { -+ normal_warning("cff","top DICT not exist"); -+ cff_close(cff); -+ return NULL; -+ } -+ cff->topdict = cff_dict_unpack(idx->data + idx->offset[n] - 1, idx->data + idx->offset[n + 1] - 1); -+ if (!cff->topdict) { -+ normal_warning("cff","parsing top DICT data failed"); -+ cff_close(cff); -+ return NULL; -+ } -+ cff_release_index(idx); -+ if (cff_dict_known(cff->topdict, "CharstringType") && -+ cff_dict_get(cff->topdict, "CharstringType", 0) != 2) { -+ normal_warning("cff","only type 2 charstrings supported"); -+ cff_close(cff); -+ return NULL; -+ } -+ if (cff_dict_known(cff->topdict, "SyntheticBase")) { -+ normal_warning("cff","synthetic font not supported"); -+ cff_close(cff); -+ return NULL; -+ } -+ /*tex The string index. */ -+ if (cff->header_major == 2) { -+ /*tex do nothing */ -+ } else { -+ cff->string = cff_get_index(cff); -+ } -+ /*tex The offset to subroutines. */ -+ cff->gsubr_offset = cff->offset; -+ /*tex The number of glyphs. */ -+ offset = (long) cff_dict_get(cff->topdict, "CharStrings", 0); -+ cff->offset = (l_offset) offset; -+ cff->num_glyphs = get_card16(cff); -+ /*tex Check for font type. */ -+ if (cff_dict_known(cff->topdict, "ROS")) { -+ cff->flag |= FONTTYPE_CIDFONT; -+ } else { -+ cff->flag |= FONTTYPE_FONT; -+ } -+ /*tex Check for the encoding. */ -+ if (cff_dict_known(cff->topdict, "Encoding")) { -+ offset = (long) cff_dict_get(cff->topdict, "Encoding", 0); -+ if (offset == 0) { /* predefined */ -+ cff->flag |= ENCODING_STANDARD; -+ } else if (offset == 1) { -+ cff->flag |= ENCODING_EXPERT; -+ } -+ } else { -+ cff->flag |= ENCODING_STANDARD; -+ } -+ cff->offset = cff->gsubr_offset; -+ return cff; -+} -+ -+/*tex Write CFF data for an \OPENTYPE\ font. We need to pack dictionary data. */ -+ -+static long pack_integer(card8 * dest, long destlen, long value) -+{ -+ long len = 0; -+ if (value >= -107 && value <= 107) { -+ if (destlen < 1) -+ normal_error("cff","buffer overflow (1)"); -+ dest[0] = (card8) ((value + 139) & 0xff); -+ len = 1; -+ } else if (value >= 108 && value <= 1131) { -+ if (destlen < 2) -+ normal_error("cff","buffer overflow (2)"); -+ value = (long) 0xf700u + value - 108; -+ dest[0] = (card8) ((value >> 8) & 0xff); -+ dest[1] = (card8) (value & 0xff); -+ len = 2; -+ } else if (value >= -1131 && value <= -108) { -+ if (destlen < 2) -+ normal_error("cff","buffer overflow (3)"); -+ value = (long) 0xfb00u - value - 108; -+ dest[0] = (card8) ((value >> 8) & 0xff); -+ dest[1] = (card8) (value & 0xff); -+ len = 2; -+ } else if (value >= -32768 && value <= 32767) { -+ /*tex shortint */ -+ if (destlen < 3) -+ normal_error("cff","buffer overflow (4)"); -+ dest[0] = 28; -+ dest[1] = (card8) ((value >> 8) & 0xff); -+ dest[2] = (card8) (value & 0xff); -+ len = 3; -+ } else { -+ /*tex longint */ -+ if (destlen < 5) -+ normal_error("cff","buffer overflow (5)"); -+ dest[0] = 29; -+ dest[1] = (card8) ((value >> 24) & 0xff); -+ dest[2] = (card8) ((value >> 16) & 0xff); -+ dest[3] = (card8) ((value >> 8) & 0xff); -+ dest[4] = (card8) (value & 0xff); -+ len = 5; -+ } -+ return len; -+} -+ -+static long pack_real(card8 * dest, long destlen, double value) -+{ -+ long e; -+ int i = 0, pos = 2; -+ int res; -+#define CFF_REAL_MAX_LEN 17 -+ if (destlen < 2) -+ normal_error("cff","buffer overflow (6)"); -+ dest[0] = 30; -+ if (value == 0.0) { -+ dest[1] = 0x0f; -+ return 2; -+ } -+ if (value < 0.0) { -+ dest[1] = 0xe0; -+ value *= -1.0; -+ pos++; -+ } -+ e = 0; -+ if (value >= 10.0) { -+ while (value >= 10.0) { -+ value /= 10.0; -+ e++; -+ } -+ } else if (value < 1.0) { -+ while (value < 1.0) { -+ value *= 10.0; -+ e--; -+ } -+ } -+ res = sprintf(work_buffer, "%1.14g", value); -+ if (res<0) -+ normal_error("cff","invalid conversion"); -+ if (res>CFF_REAL_MAX_LEN) -+ res=CFF_REAL_MAX_LEN; -+ for (i = 0; i < res; i++) { -+ unsigned char ch = 0; -+ if (work_buffer[i] == '\0') { -+ /*tex In fact |res| should prevent this. */ -+ break; -+ } else if (work_buffer[i] == '.') { -+ ch = 0x0a; -+ } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') { -+ ch = (unsigned char) (work_buffer[i] - '0'); -+ } else { -+ normal_error("cff","invalid character"); -+ } -+ if (destlen < pos / 2 + 1) -+ normal_error("cff","buffer overflow (7)"); -+ -+ if (pos % 2) { -+ dest[pos / 2] = (card8) (dest[pos / 2] + ch); -+ } else { -+ dest[pos / 2] = (card8) (ch << 4); -+ } -+ pos++; -+ } -+ if (e > 0) { -+ if (pos % 2) { -+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0b); -+ } else { -+ if (destlen < pos / 2 + 1) -+ normal_error("cff","buffer overflow (8)"); -+ dest[pos / 2] = (card8) (0xb0); -+ } -+ pos++; -+ } else if (e < 0) { -+ if (pos % 2) { -+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0c); -+ } else { -+ if (destlen < pos / 2 + 1) -+ normal_error("cff","buffer overflow (9)"); -+ dest[pos / 2] = (card8) (0xc0); -+ } -+ e *= -1; -+ pos++; -+ } -+ if (e != 0) { -+ sprintf(work_buffer, "%ld", e); -+ for (i = 0; i < CFF_REAL_MAX_LEN; i++) { -+ unsigned char ch = 0; -+ if (work_buffer[i] == '\0') { -+ break; -+ } else if (work_buffer[i] == '.') { -+ ch = 0x0a; -+ } else if (work_buffer[i] >= '0' && work_buffer[i] <= '9') { -+ ch = (unsigned char) (work_buffer[i] - '0'); -+ } else { -+ normal_error("cff","invalid character"); -+ } -+ if (destlen < pos / 2 + 1) -+ normal_error("cff","buffer overflow (10)"); -+ if (pos % 2) { -+ dest[pos / 2] = (card8) (dest[pos / 2] + ch); -+ } else { -+ dest[pos / 2] = (card8) (ch << 4); -+ } -+ pos++; -+ } -+ } -+ if (pos % 2) { -+ dest[pos / 2] = (card8) (dest[pos / 2] + 0x0f); -+ pos++; -+ } else { -+ if (destlen < pos / 2 + 1) -+ normal_error("cff","buffer overflow (11)"); -+ dest[pos / 2] = (card8) (0xff); -+ pos += 2; -+ } -+ return pos / 2; -+} -+ -+static long cff_dict_put_number(double value, card8 * dest, long destlen, int type) -+{ -+ long len = 0; -+ double nearint; -+ nearint = floor(value + 0.5); -+ if (type == CFF_TYPE_OFFSET) { -+ long lvalue; -+ lvalue = (long) value; -+ if (destlen < 5) -+ normal_error("cff","buffer overflow (12)"); -+ dest[0] = 29; -+ dest[1] = (card8) ((lvalue >> 24) & 0xff); -+ dest[2] = (card8) ((lvalue >> 16) & 0xff); -+ dest[3] = (card8) ((lvalue >> 8) & 0xff); -+ dest[4] = (card8) (lvalue & 0xff); -+ len = 5; -+ } else if (value > CFF_INT_MAX || value < CFF_INT_MIN || (fabs(value - nearint) > 1.0e-5)) { -+ /*tex A real */ -+ len = pack_real(dest, destlen, value); -+ } else { -+ /*tex An integer */ -+ len = pack_integer(dest, destlen, (long) nearint); -+ } -+ return len; -+} -+ -+static long put_dict_entry(cff_dict_entry * de, card8 * dest, long destlen) -+{ -+ long len = 0; -+ int i, type, id; -+ if (de->count > 0) { -+ id = de->id; -+ if (dict_operator[id].argtype == CFF_TYPE_OFFSET || -+ dict_operator[id].argtype == CFF_TYPE_SZOFF) { -+ type = CFF_TYPE_OFFSET; -+ } else { -+ type = CFF_TYPE_NUMBER; -+ } -+ for (i = 0; i < de->count; i++) { -+ len += cff_dict_put_number(de->values[i], dest + len, destlen - len, type); -+ } -+ if (id >= 0 && id < CFF_LAST_DICT_OP1) { -+ if (len + 1 > destlen) -+ normal_error("cff","buffer overflow (13)"); -+ dest[len++] = (card8) id; -+ } else if (id >= 0 && id < CFF_LAST_DICT_OP) { -+ if (len + 2 > destlen) -+ normal_error("cff","buffer overflow (14)"); -+ dest[len++] = 12; -+ dest[len++] = (card8) (id - CFF_LAST_DICT_OP1); -+ } else { -+ normal_error("cff","invalid DICT operator ID"); -+ } -+ } -+ return len; -+} -+ -+long cff_dict_pack(cff_dict * dict, card8 * dest, long destlen) -+{ -+ long len = 0; -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ if (!strcmp(dict->entries[i].key, "ROS")) { -+ len += put_dict_entry(&dict->entries[i], dest, destlen); -+ break; -+ } -+ } -+ for (i = 0; i < dict->count; i++) { -+ if (strcmp(dict->entries[i].key, "ROS")) { -+ len += put_dict_entry(&dict->entries[i], dest + len, destlen - len); -+ } -+ } -+ return len; -+} -+ -+void cff_dict_add(cff_dict * dict, const char *key, int count) -+{ -+ int id, i; -+ for (id = 0; id < CFF_LAST_DICT_OP; id++) { -+ if (key && dict_operator[id].opname && -+ strcmp(dict_operator[id].opname, key) == 0) -+ break; -+ } -+ if (id == CFF_LAST_DICT_OP) -+ normal_error("cff","unknown DICT operator"); -+ for (i = 0; i < dict->count; i++) { -+ if ((dict->entries)[i].id == id) { -+ if ((dict->entries)[i].count != count) -+ normal_error("cff","inconsistent DICT argument number"); -+ return; -+ } -+ } -+ if (dict->count + 1 >= dict->max) { -+ dict->max += 8; -+ dict->entries = -+ xrealloc(dict->entries, (unsigned) ((unsigned) dict->max * sizeof(cff_dict_entry))); -+ } -+ (dict->entries)[dict->count].id = id; -+ (dict->entries)[dict->count].key = dict_operator[id].opname; -+ (dict->entries)[dict->count].count = count; -+ if (count > 0) { -+ (dict->entries)[dict->count].values = xcalloc((unsigned) count, sizeof(double)); -+ } else { -+ (dict->entries)[dict->count].values = NULL; -+ } -+ dict->count += 1; -+ return; -+} -+ -+void cff_dict_remove(cff_dict * dict, const char *key) -+{ -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ if (key && strcmp(key, (dict->entries)[i].key) == 0) { -+ (dict->entries)[i].count = 0; -+ xfree((dict->entries)[i].values); -+ } -+ } -+} -+ -+void cff_dict_set(cff_dict * dict, const char *key, int idx, double value) -+{ -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ if (strcmp(key, (dict->entries)[i].key) == 0) { -+ if ((dict->entries)[i].count > idx) -+ (dict->entries)[i].values[idx] = value; -+ else -+ normal_error("cff","invalid index number"); -+ break; -+ } -+ } -+ if (i == dict->count) -+ formatted_error("cff","DICT entry '%s' not found", key); -+} -+ -+ -+/*tex Strings */ -+ -+char *cff_get_string(cff_font * cff, s_SID id) -+{ -+ char *result = NULL; -+ size_t len; -+ if (id < CFF_STDSTR_MAX) { -+ len = strlen(cff_stdstr[id]); -+ result = xmalloc((unsigned) (len + 1) * sizeof(char)); -+ memcpy(result, cff_stdstr[id], len); -+ result[len] = '\0'; -+ } else if (cff && cff->string) { -+ cff_index *strings = cff->string; -+ id = (s_SID) (id - CFF_STDSTR_MAX); -+ if (id < strings->count) { -+ len = (strings->offset)[id + 1] - (strings->offset)[id]; -+ result = xmalloc((unsigned) (len + 1) * sizeof(char)); -+ memmove(result, strings->data + (strings->offset)[id] - 1, len); -+ result[len] = '\0'; -+ } -+ } -+ return result; -+} -+ -+long cff_get_sid(cff_font * cff, const char *str) -+{ -+ card16 i; -+ if (!cff || !str) -+ return -1; -+ /*tex We search the string index first. */ -+ if (cff && cff->string) { -+ cff_index *idx = cff->string; -+ for (i = 0; i < idx->count; i++) { -+ if (strlen(str) == (idx->offset)[i + 1] - (idx->offset)[i] && -+ !memcmp(str, (idx->data) + (idx->offset)[i] - 1, strlen(str))) -+ return (i + CFF_STDSTR_MAX); -+ } -+ } -+ for (i = 0; i < CFF_STDSTR_MAX; i++) { -+ if (!strcmp(str, cff_stdstr[i])) -+ return i; -+ } -+ return -1; -+} -+ -+void cff_update_string(cff_font * cff) -+{ -+ if (cff == NULL) -+ normal_error("cff","CFF font not opened"); -+ if (cff->string) -+ cff_release_index(cff->string); -+ cff->string = cff->_string; -+ cff->_string = NULL; -+} -+ -+s_SID cff_add_string(cff_font * cff, const char *str) -+{ -+ card16 idx; -+ cff_index *strings; -+ l_offset offset, size; -+ if (cff == NULL) { -+ normal_error("cff","CFF font not opened"); -+ } -+ if (cff->_string == NULL) { -+ cff->_string = cff_new_index(0); -+ } -+ strings = cff->_string; -+ for (idx = 0; idx < strings->count; idx++) { -+ size = strings->offset[idx + 1] - strings->offset[idx]; -+ offset = strings->offset[idx]; -+ if (size == strlen(str) && !memcmp(strings->data + offset - 1, str, strlen(str))) { -+ return (s_SID) (idx + CFF_STDSTR_MAX); -+ } -+ } -+ for (idx = 0; idx < CFF_STDSTR_MAX; idx++) { -+ if (cff_stdstr[idx] && !strcmp(cff_stdstr[idx], str)) { -+ return idx; -+ } -+ } -+ offset = (strings->count > 0) ? strings->offset[strings->count] : 1; -+ strings->offset = xrealloc(strings->offset, (unsigned) (((unsigned) strings->count + 2) * sizeof(l_offset))); -+ if (strings->count == 0) -+ strings->offset[0] = 1; -+ idx = strings->count; -+ strings->count = (card16) (strings->count + 1); -+ strings->offset[strings->count] = offset + strlen(str); -+ strings->data = xrealloc(strings->data, (unsigned) ((offset + strlen(str) - 1) * sizeof(card8))); -+ memcpy(strings->data + offset - 1, str, strlen(str)); -+ return (s_SID) (idx + CFF_STDSTR_MAX); -+} -+ -+void cff_dict_update(cff_dict * dict, cff_font * cff) -+{ -+ int i; -+ for (i = 0; i < dict->count; i++) { -+ if ((dict->entries)[i].count > 0) { -+ char *str; -+ int id; -+ id = (dict->entries)[i].id; -+ if (dict_operator[id].argtype == CFF_TYPE_SID) { -+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]); -+ if (str != NULL) { -+ (dict->entries)[i].values[0] = cff_add_string(cff, str); -+ xfree(str); -+ } -+ } else if (dict_operator[id].argtype == CFF_TYPE_ROS) { -+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[0]); -+ if (str != NULL) { -+ (dict->entries)[i].values[0] = cff_add_string(cff, str); -+ xfree(str); -+ } -+ str = cff_get_string(cff, (s_SID) (dict->entries)[i].values[1]); -+ if (str != NULL) { -+ (dict->entries)[i].values[1] = cff_add_string(cff, str); -+ xfree(str); -+ } -+ } -+ } -+ } -+} -+ -+/*tex The charsets. */ -+ -+long cff_read_charsets(cff_font * cff) -+{ -+ cff_charsets *charset; -+ long offset, length; -+ card16 count, i; -+ if (cff->topdict == NULL) -+ normal_error("cff","top DICT not available"); -+ if (!cff_dict_known(cff->topdict, "charset")) { -+ cff->flag |= CHARSETS_ISOADOBE; -+ cff->charsets = NULL; -+ return 0; -+ } -+ offset = (long) cff_dict_get(cff->topdict, "charset", 0); -+ if (offset == 0) { -+ /*tex predefined */ -+ cff->flag |= CHARSETS_ISOADOBE; -+ cff->charsets = NULL; -+ return 0; -+ } else if (offset == 1) { -+ cff->flag |= CHARSETS_EXPERT; -+ cff->charsets = NULL; -+ return 0; -+ } else if (offset == 2) { -+ cff->flag |= CHARSETS_EXPSUB; -+ cff->charsets = NULL; -+ return 0; -+ } -+ cff->offset = (l_offset) offset; -+ cff->charsets = charset = xcalloc(1, sizeof(cff_charsets)); -+ charset->format = get_card8(cff); -+ charset->num_entries = 0; -+ count = (card16) (cff->num_glyphs - 1); -+ length = 1; -+ /*tex Not well documented. */ -+ switch (charset->format) { -+ case 0: -+ charset->num_entries = (card16) (cff->num_glyphs - 1); /* no .notdef */ -+ charset->data.glyphs = -+ xmalloc((unsigned) (charset->num_entries * sizeof(s_SID))); -+ length += (charset->num_entries) * 2; -+ for (i = 0; i < (charset->num_entries); i++) { -+ charset->data.glyphs[i] = get_card16(cff); -+ } -+ count = 0; -+ break; -+ case 1: -+ { -+ cff_range1 *ranges = NULL; -+ while (count > 0 && charset->num_entries < cff->num_glyphs) { -+ ranges = -+ xrealloc(ranges, -+ (unsigned) (((unsigned) charset->num_entries + -+ 1) * sizeof(cff_range1))); -+ ranges[charset->num_entries].first = get_card16(cff); -+ ranges[charset->num_entries].n_left = get_card8(cff); -+ count = (card16) (count - ranges[charset->num_entries].n_left + 1); /* no-overrap */ -+ charset->num_entries++; -+ charset->data.range1 = ranges; -+ } -+ length += (charset->num_entries) * 3; -+ } -+ break; -+ case 2: -+ { -+ cff_range2 *ranges = NULL; -+ while (count > 0 && charset->num_entries < cff->num_glyphs) { -+ ranges = -+ xrealloc(ranges, -+ (unsigned) (((unsigned) charset->num_entries + -+ 1) * sizeof(cff_range2))); -+ ranges[charset->num_entries].first = get_card16(cff); -+ ranges[charset->num_entries].n_left = get_card16(cff); -+ count = (card16) (count - (ranges[charset->num_entries].n_left + 1)); /* non-overrapping */ -+ charset->num_entries++; -+ } -+ charset->data.range2 = ranges; -+ length += (charset->num_entries) * 4; -+ } -+ break; -+ default: -+ xfree(charset); -+ normal_error("cff","unknown charset format"); -+ break; -+ } -+ if (count > 0) { -+ normal_warning("cff","charset data possibly broken (too many glyphs)"); -+ } -+ return length; -+} -+ -+long cff_pack_charsets(cff_font * cff, card8 * dest, long destlen) -+{ -+ long len = 0; -+ card16 i; -+ cff_charsets *charset; -+ if (cff->flag & HAVE_STANDARD_CHARSETS || cff->charsets == NULL) -+ return 0; -+ if (destlen < 1) -+ normal_error("cff","buffer overflow (15)"); -+ charset = cff->charsets; -+ dest[len++] = charset->format; -+ switch (charset->format) { -+ case 0: -+ if (destlen < len + (charset->num_entries) * 2) -+ normal_error("cff","buffer overflow (16)"); -+ for (i = 0; i < (charset->num_entries); i++) { -+ s_SID sid = (charset->data).glyphs[i]; /* or CID */ -+ dest[len++] = (card8) ((sid >> 8) & 0xff); -+ dest[len++] = (card8) (sid & 0xff); -+ } -+ break; -+ case 1: -+ { -+ if (destlen < len + (charset->num_entries) * 3) -+ normal_error("cff","buffer overflow (17)"); -+ for (i = 0; i < (charset->num_entries); i++) { -+ dest[len++] = (card8) (((charset->data).range1[i].first >> 8) & 0xff); -+ dest[len++] = (card8) ((charset->data).range1[i].first & 0xff); -+ dest[len++] = (card8) ((charset->data).range1[i].n_left); -+ } -+ } -+ break; -+ case 2: -+ { -+ if (destlen < len + (charset->num_entries) * 4) -+ normal_error("cff","buffer overflow (18)"); -+ for (i = 0; i < (charset->num_entries); i++) { -+ dest[len++] = (card8) (((charset->data).range2[i].first >> 8) & 0xff); -+ dest[len++] = (card8) ((charset->data).range2[i].first & 0xff); -+ dest[len++] = (card8) (((charset->data).range2[i].n_left >> 8) & 0xff); -+ dest[len++] = (card8) ((charset->data).range2[i].n_left & 0xff); -+ } -+ } -+ break; -+ default: -+ normal_error("cff","unknown charset format"); -+ break; -+ } -+ return len; -+} -+ -+/*tex -+ -+ Here we decode and encode Type 2 charstring. All local/global subroutine -+ calls in a given charstring is replace by the content of subroutine -+ charstrings. We do this because some PostScript RIP may have problems with -+ sparse subroutine array. Workaround for this is to re-order subroutine array -+ so that no gap appears in the subroutine array, or put dummy charstrings that -+ contains only `return' in the gap. However, re-ordering of subroutine is -+ rather difficult for Type 2 charstrings due to the bias which depends on the -+ total number of subroutines. Replacing callgsubr/callsubr calls with the -+ content of the corresponding subroutine charstring may be more efficient than -+ putting dummy subroutines in the case of subsetted font. Adobe distiller -+ seems doing same thing. -+ -+ And also note that subroutine numbers within subroutines can depend on the -+ content of operand stack as follows: -+ -+ \startyping -+ \.{ ... l m callsubr << subr \#(m+bias): n add callsubr >> ...} -+ \stoptyping -+ -+ I've not implemented the `random' operator which generates a pseudo-random -+ number in the range (0, 1] and push them into argument stack. How -+ pseudo-random sequences are generated is not documented in the Type 2 -+ charstring spec. -+ -+*/ -+ -+#define CS_TYPE2_DEBUG_STR "Type2 Charstring Parser" -+#define CS_TYPE2_DEBUG 5 -+ -+#define CS_BUFFER_CFF_ERROR -3 -+#define CS_STACK_CFF_ERROR -2 -+#define CS_PARSE_CFF_ERROR -1 -+#define CS_PARSE_OK 0 -+#define CS_PARSE_END 1 -+#define CS_SUBR_RETURN 2 -+#define CS_CHAR_END 3 -+ -+static int status = CS_PARSE_CFF_ERROR; -+ -+#define DST_NEED(a,b) {if ((a) < (b)) { status = CS_BUFFER_CFF_ERROR ; return ; }} -+#define SRC_NEED(a,b) {if ((a) < (b)) { status = CS_PARSE_CFF_ERROR ; return ; }} -+#define NEED(a,b) {if ((a) < (b)) { status = CS_STACK_CFF_ERROR ; return ; }} -+ -+/*tex The hintmask and cntrmask need the number of stem zones. */ -+ -+static int num_stems = 0; -+static int phase = 0; -+ -+/*tex Subroutine nesting. -+*/ -+static int cs2_nest = 0; -+ -+/*tex The advance width. */ -+ -+static int have_width = 0; -+static double width = 0.0; -+ -+/*tex -+ -+ Standard Encoding Accented Characters: Optional four arguments for endchar. -+ See, CFF spec., p.35. This is obsolete feature and is no longer supported. -+ -+ \starttyping -+ static double seac[4] = { 0.0, 0.0, 0.0, 0.0 }; // gone -+ \stoptyping -+ -+*/ -+ -+/*tex Operand stack and Transient array */ -+ -+static int cs2_stack_top = 0; -+static double cs2_arg_stack[CS_ARG_STACK_MAX]; -+static double trn_array[CS_TRANS_ARRAY_MAX]; -+ -+/*tex -+ -+ Type 2 CharString encoding, first the 1 byte operators: -+ -+*/ -+ -+/* RESERVED 0 */ -+#define cs_hstem 1 -+/* RESERVED 2 */ -+#define cs_vstem 3 -+#define cs_vmoveto 4 -+#define cs_rlineto 5 -+#define cs_hlineto 6 -+#define cs_vlineto 7 -+#define cs_rrcurveto 8 -+/* cs_closepath 9 */ -+#define cs_callsubr 10 -+#define cs_return 11 -+#define cs_escape 12 -+/* cs_hsbw 13 */ -+#define cs_endchar 14 -+#define cs_setvsindex 15 -+#define cs_blend 16 -+/* RESERVED 17 */ -+#define cs_hstemhm 18 -+#define cs_hintmask 19 -+#define cs_cntrmask 20 -+#define cs_rmoveto 21 -+#define cs_hmoveto 22 -+#define cs_vstemhm 23 -+#define cs_rcurveline 24 -+#define cs_rlinecurve 25 -+#define cs_vvcurveto 26 -+#define cs_hhcurveto 27 -+/* SHORTINT 28 */ -+#define cs_callgsubr 29 -+#define cs_vhcurveto 30 -+#define cs_hvcurveto 31 -+ -+/*tex -+ -+ Next the two byte CharString operators: -+ -+*/ -+ -+#define cs_dotsection 0 -+/* cs_vstem3 1 */ -+/* cs_hstem3 2 */ -+#define cs_and 3 -+#define cs_or 4 -+#define cs_not 5 -+/* cs_seac 6 */ -+/* cs_sbw 7 */ -+/* RESERVED 8 */ -+#define cs_abs 9 -+#define cs_add 10 -+#define cs_sub 11 -+#define cs_div 12 -+/* RESERVED 13 */ -+#define cs_neg 14 -+#define cs_eq 15 -+/* cs_callothersubr 16 */ -+/* cs_pop| 17 */ -+#define cs_drop 18 -+/* RESERVED 19 */ -+#define cs_put 20 -+#define cs_get 21 -+#define cs_ifelse 22 -+#define cs_random 23 -+#define cs_mul 24 -+/* RESERVED 25 */ -+#define cs_sqrt 26 -+#define cs_dup 27 -+#define cs_exch 28 -+#define cs_index 29 -+#define cs_roll 30 -+/* cs_setcurrentpoint 31 */ -+/* RESERVED 32 */ -+/* RESERVED 33 */ -+#define cs_hflex 34 -+#define cs_flex 35 -+#define cs_hflex1 36 -+#define cs_flex1 37 -+ -+/*tex |clear_stack| put all operands sotred in operand stack to dest. */ -+ -+static void clear_stack(card8 ** dest, card8 * limit) -+{ -+ int i; -+ for (i = 0; i < cs2_stack_top; i++) { -+ double value; -+ long ivalue; -+ value = cs2_arg_stack[i]; -+ /*tex The nearest integer value. */ -+ ivalue = (long) floor(value + 0.5); -+ if (value >= 0x8000L || value <= (-0x8000L - 1)) { -+ /*tex -+ This number cannot be represented as a single operand. We must -+ use |a b mul ...| or |a c div| to represent large values. -+ */ -+ normal_error("cff","argument value too large (this is bug)"); -+ } else if (fabs(value - (double) ivalue) > 3.0e-5) { -+ /*tex A 16.16-bit signed fixed value */ -+ DST_NEED(limit, *dest + 5); -+ *(*dest)++ = 255; -+ /*tex The mantissa. */ -+ ivalue = (long) floor(value); -+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff); -+ *(*dest)++ = (card8) (ivalue & 0xff); -+ /*tex The fraction. */ -+ ivalue = (long) ((value - (double) ivalue) * 0x10000l); -+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff); -+ *(*dest)++ = (card8) (ivalue & 0xff); -+ /*tex Everything else is integer. */ -+ } else if (ivalue >= -107 && ivalue <= 107) { -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = (card8) (ivalue + 139); -+ } else if (ivalue >= 108 && ivalue <= 1131) { -+ DST_NEED(limit, *dest + 2); -+ ivalue = (long) 0xf700u + ivalue - 108; -+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff); -+ *(*dest)++ = (card8) (ivalue & 0xff); -+ } else if (ivalue >= -1131 && ivalue <= -108) { -+ DST_NEED(limit, *dest + 2); -+ ivalue = (long) 0xfb00u - ivalue - 108; -+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff); -+ *(*dest)++ = (card8) (ivalue & 0xff); -+ } else if (ivalue >= -32768 && ivalue <= 32767) { -+ /*tex A shortint. */ -+ DST_NEED(limit, *dest + 3); -+ *(*dest)++ = 28; -+ *(*dest)++ = (card8) ((ivalue >> 8) & 0xff); -+ *(*dest)++ = (card8) ((ivalue) & 0xff); -+ } else { -+ normal_error("cff","unexpected error"); -+ } -+ } -+ /*tex Clear the stack. */ -+ cs2_stack_top = 0; -+ return; -+} -+ -+/*tex -+ Single byte operators: Path construction, Operator for finishing a path, Hint -+ operators. Phases: -+ -+ \starttabulate -+ \NC \type{0} \NC inital state \NC \NR -+ \NC \type{1} \NC hint declaration, first stack-clearing operator appeared \NC \NR -+ \NC \type{2} \NC in path construction \NC \NR -+ \stoptabulate -+ -+*/ -+ -+static void do_operator1(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr) -+{ -+ card8 op = **data; -+ -+ *data += 1; -+ -+ switch (op) { -+ case cs_hstemhm: -+ case cs_vstemhm: -+ /*tex A charstring may have a hintmask if the above operator has been seen. */ -+ case cs_hstem: -+ case cs_vstem: -+ if (phase == 0 && (cs2_stack_top % 2)) { -+ have_width = 1; -+ width = cs2_arg_stack[0]; -+ } -+ num_stems += cs2_stack_top / 2; -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ phase = 1; -+ break; -+ case cs_hintmask: -+ case cs_cntrmask: -+ if (phase < 2) { -+ if (phase == 0 && (cs2_stack_top % 2)) { -+ have_width = 1; -+ width = cs2_arg_stack[0]; -+ } -+ num_stems += cs2_stack_top / 2; -+ } -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ if (num_stems > 0) { -+ int masklen = (num_stems + 7) / 8; -+ DST_NEED(limit, *dest + masklen); -+ SRC_NEED(endptr, *data + masklen); -+ memmove(*dest, *data, (size_t) masklen); -+ *data += masklen; -+ *dest += masklen; -+ } -+ phase = 2; -+ break; -+ case cs_rmoveto: -+ if (phase == 0 && (cs2_stack_top % 2)) { -+ have_width = 1; -+ width = cs2_arg_stack[0]; -+ } -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ phase = 2; -+ break; -+ case cs_hmoveto: -+ case cs_vmoveto: -+ if (phase == 0 && (cs2_stack_top % 2) == 0) { -+ have_width = 1; -+ width = cs2_arg_stack[0]; -+ } -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ phase = 2; -+ break; -+ case cs_endchar: -+ if (cs2_stack_top == 1) { -+ have_width = 1; -+ width = cs2_arg_stack[0]; -+ clear_stack(dest, limit); -+ } else if (cs2_stack_top == 4 || cs2_stack_top == 5) { -+ normal_warning("cff","'seac' character deprecated in type 2 charstring"); -+ status = CS_PARSE_CFF_ERROR; -+ return; -+ } else if (cs2_stack_top > 0) { -+ normal_warning("cff","operand stack not empty"); -+ } -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ status = CS_CHAR_END; -+ break; -+ /*tex The above operators are candidate for first stack clearing operator. */ -+ case cs_setvsindex: -+ /* -+ vsindex = cs2_arg_stack[cs2_stack_top-1]; -+ cs2_stack_top -= 1; -+ */ -+ normal_warning("cff2","unsupported setvindex operator"); -+ status = CS_PARSE_CFF_ERROR; -+ break; -+ case cs_blend: -+ /* -+ blends = cs2_arg_stack[cs2_stack_top-1]; -+ cs2_stack_top -= 1; -+ cs2_stack_top -= blends * regions ; -+ */ -+ normal_warning("cff2","unsupported blend operator"); -+ status = CS_PARSE_CFF_ERROR; -+ break; -+ case cs_rlineto: -+ case cs_hlineto: -+ case cs_vlineto: -+ case cs_rrcurveto: -+ case cs_rcurveline: -+ case cs_rlinecurve: -+ case cs_vvcurveto: -+ case cs_hhcurveto: -+ case cs_vhcurveto: -+ case cs_hvcurveto: -+ if (phase < 2) { -+ normal_warning("cff","broken type 2 charstring"); -+ status = CS_PARSE_CFF_ERROR; -+ return; -+ } -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 1); -+ *(*dest)++ = op; -+ break; -+ /*tex All the operotors above are stack clearing. */ -+ case cs_return: -+ normal_error("cff","unexpected return"); -+ case cs_callgsubr: -+ normal_error("cff","unexpected callgsubr"); -+ case cs_callsubr: -+ normal_error("cff","unexpected callsubr"); -+ break; -+ default: -+ formatted_warning("cff","%s: unknown charstring operator: 0x%02x", CS_TYPE2_DEBUG_STR, op); -+ status = CS_PARSE_CFF_ERROR; -+ break; -+ } -+ return; -+} -+ -+/*tex -+ -+ Double byte operators: Flex, arithmetic, conditional, and storage operators. -+ The following operators are not supported: random but How random ? -+ -+*/ -+ -+static void do_operator2(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr) -+{ -+ card8 op; -+ *data += 1; -+ SRC_NEED(endptr, *data + 1); -+ op = **data; -+ *data += 1; -+ switch (op) { -+ case cs_dotsection: -+ normal_warning("cff","Operator 'dotsection' deprecated in type 2 charstring"); -+ status = CS_PARSE_CFF_ERROR; -+ return; -+ break; -+ case cs_hflex: -+ case cs_flex: -+ case cs_hflex1: -+ case cs_flex1: -+ if (phase < 2) { -+ formatted_warning("cff","%s: broken type 2 charstring", CS_TYPE2_DEBUG_STR); -+ status = CS_PARSE_CFF_ERROR; -+ return; -+ } -+ clear_stack(dest, limit); -+ DST_NEED(limit, *dest + 2); -+ *(*dest)++ = cs_escape; -+ *(*dest)++ = op; -+ break; -+ /*tex All operators above are stack clearing. */ -+ case cs_and: -+ NEED(cs2_stack_top, 2); -+ cs2_stack_top--; -+ if (cs2_arg_stack[cs2_stack_top] && cs2_arg_stack[cs2_stack_top - 1]) { -+ cs2_arg_stack[cs2_stack_top - 1] = 1.0; -+ } else { -+ cs2_arg_stack[cs2_stack_top - 1] = 0.0; -+ } -+ break; -+ case cs_or: -+ NEED(cs2_stack_top, 2); -+ cs2_stack_top--; -+ if (cs2_arg_stack[cs2_stack_top] || cs2_arg_stack[cs2_stack_top - 1]) { -+ cs2_arg_stack[cs2_stack_top - 1] = 1.0; -+ } else { -+ cs2_arg_stack[cs2_stack_top - 1] = 0.0; -+ } -+ break; -+ case cs_not: -+ NEED(cs2_stack_top, 1); -+ if (cs2_arg_stack[cs2_stack_top - 1]) { -+ cs2_arg_stack[cs2_stack_top - 1] = 0.0; -+ } else { -+ cs2_arg_stack[cs2_stack_top - 1] = 1.0; -+ } -+ break; -+ case cs_abs: -+ NEED(cs2_stack_top, 1); -+ cs2_arg_stack[cs2_stack_top - 1] = -+ fabs(cs2_arg_stack[cs2_stack_top - 1]); -+ break; -+ case cs_add: -+ NEED(cs2_stack_top, 2); -+ cs2_arg_stack[cs2_stack_top - 2] += cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_stack_top--; -+ break; -+ case cs_sub: -+ NEED(cs2_stack_top, 2); -+ cs2_arg_stack[cs2_stack_top - 2] -= cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_stack_top--; -+ break; -+ case cs_div: -+ NEED(cs2_stack_top, 2); -+ cs2_arg_stack[cs2_stack_top - 2] /= cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_stack_top--; -+ break; -+ case cs_neg: -+ NEED(cs2_stack_top, 1); -+ cs2_arg_stack[cs2_stack_top - 1] *= -1.0; -+ break; -+ case cs_eq: -+ NEED(cs2_stack_top, 2); -+ cs2_stack_top--; -+ if (cs2_arg_stack[cs2_stack_top] == cs2_arg_stack[cs2_stack_top - 1]) { -+ cs2_arg_stack[cs2_stack_top - 1] = 1.0; -+ } else { -+ cs2_arg_stack[cs2_stack_top - 1] = 0.0; -+ } -+ break; -+ case cs_drop: -+ NEED(cs2_stack_top, 1); -+ cs2_stack_top--; -+ break; -+ case cs_put: -+ NEED(cs2_stack_top, 2); -+ { -+ int idx = (int) cs2_arg_stack[--cs2_stack_top]; -+ NEED(CS_TRANS_ARRAY_MAX, idx); -+ trn_array[idx] = cs2_arg_stack[--cs2_stack_top]; -+ } -+ break; -+ case cs_get: -+ NEED(cs2_stack_top, 1); -+ { -+ int idx = (int) cs2_arg_stack[cs2_stack_top - 1]; -+ NEED(CS_TRANS_ARRAY_MAX, idx); -+ cs2_arg_stack[cs2_stack_top - 1] = trn_array[idx]; -+ } -+ break; -+ case cs_ifelse: -+ NEED(cs2_stack_top, 4); -+ cs2_stack_top -= 3; -+ if (cs2_arg_stack[cs2_stack_top + 1] > cs2_arg_stack[cs2_stack_top + 2]) { -+ cs2_arg_stack[cs2_stack_top - 1] = cs2_arg_stack[cs2_stack_top]; -+ } -+ break; -+ case cs_mul: -+ NEED(cs2_stack_top, 2); -+ cs2_arg_stack[cs2_stack_top - 2] = -+ cs2_arg_stack[cs2_stack_top - 2] * cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_stack_top--; -+ break; -+ case cs_sqrt: -+ NEED(cs2_stack_top, 1); -+ cs2_arg_stack[cs2_stack_top - 1] = -+ sqrt(cs2_arg_stack[cs2_stack_top - 1]); -+ break; -+ case cs_dup: -+ NEED(cs2_stack_top, 1); -+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1); -+ cs2_arg_stack[cs2_stack_top] = cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_stack_top++; -+ break; -+ case cs_exch: -+ NEED(cs2_stack_top, 2); -+ { -+ double save = cs2_arg_stack[cs2_stack_top - 2]; -+ cs2_arg_stack[cs2_stack_top - 2] = cs2_arg_stack[cs2_stack_top - 1]; -+ cs2_arg_stack[cs2_stack_top - 1] = save; -+ } -+ break; -+ case cs_index: -+ NEED(cs2_stack_top, 2); -+ { -+ int idx = (int) cs2_arg_stack[cs2_stack_top - 1]; -+ if (idx < 0) { -+ cs2_arg_stack[cs2_stack_top - 1] = -+ cs2_arg_stack[cs2_stack_top - 2]; -+ } else { -+ NEED(cs2_stack_top, idx + 2); -+ cs2_arg_stack[cs2_stack_top - 1] = -+ cs2_arg_stack[cs2_stack_top - idx - 2]; -+ } -+ } -+ break; -+ case cs_roll: -+ NEED(cs2_stack_top, 2); -+ { -+ int N, J; -+ J = (int) cs2_arg_stack[--cs2_stack_top]; -+ N = (int) cs2_arg_stack[--cs2_stack_top]; -+ NEED(cs2_stack_top, N); -+ if (J > 0) { -+ J = J % N; -+ while (J-- > 0) { -+ double save = cs2_arg_stack[cs2_stack_top - 1]; -+ int i = cs2_stack_top - 1; -+ while (i > cs2_stack_top - N) { -+ cs2_arg_stack[i] = cs2_arg_stack[i - 1]; -+ i--; -+ } -+ cs2_arg_stack[i] = save; -+ } -+ } else { -+ J = (-J) % N; -+ while (J-- > 0) { -+ double save = cs2_arg_stack[cs2_stack_top - N]; -+ int i = cs2_stack_top - N; -+ while (i < cs2_stack_top - 1) { -+ cs2_arg_stack[i] = cs2_arg_stack[i + 1]; -+ i++; -+ } -+ cs2_arg_stack[i] = save; -+ } -+ } -+ } -+ break; -+ case cs_random: -+ formatted_warning("cff","%s: Charstring operator 'random' found.", CS_TYPE2_DEBUG_STR); -+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1); -+ cs2_arg_stack[cs2_stack_top++] = 1.0; -+ break; -+ default: -+ formatted_warning("cff","%s: unknown charstring operator: 0x0c%02x", CS_TYPE2_DEBUG_STR, op); -+ status = CS_PARSE_CFF_ERROR; -+ break; -+ } -+ return; -+} -+ -+/*tex integer: exactly the same as the DICT encoding (except 29) */ -+ -+static void cs2_get_integer(card8 ** data, card8 * endptr) -+{ -+ long result = 0; -+ card8 b0 = **data, b1, b2; -+ *data += 1; -+ if (b0 == 28) { -+ /*tex shortint */ -+ SRC_NEED(endptr, *data + 2); -+ b1 = **data; -+ b2 = *(*data + 1); -+ result = b1 * 256 + b2; -+ if (result > 0x7fff) -+ result -= 0x10000L; -+ *data += 2; -+ } else if (b0 >= 32 && b0 <= 246) { -+ /*tex int (1) */ -+ result = b0 - 139; -+ } else if (b0 >= 247 && b0 <= 250) { -+ /*tex int (2) */ -+ SRC_NEED(endptr, *data + 1); -+ b1 = **data; -+ result = (b0 - 247) * 256 + b1 + 108; -+ *data += 1; -+ } else if (b0 >= 251 && b0 <= 254) { -+ SRC_NEED(endptr, *data + 1); -+ b1 = **data; -+ result = -(b0 - 251) * 256 - b1 - 108; -+ *data += 1; -+ } else { -+ status = CS_PARSE_CFF_ERROR; -+ return; -+ } -+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1); -+ cs2_arg_stack[cs2_stack_top++] = (double) result; -+ return; -+} -+ -+/*tex Signed 16.16-bits fixed number for Type 2 charstring encoding. */ -+ -+static void get_fixed(card8 ** data, card8 * endptr) -+{ -+ long ivalue; -+ double rvalue; -+ *data += 1; -+ SRC_NEED(endptr, *data + 4); -+ ivalue = *(*data) * 0x100 + *(*data + 1); -+ rvalue = (double) ((ivalue > 0x7fffL) ? (ivalue - 0x10000L) : ivalue); -+ ivalue = *(*data + 2) * 0x100 + *(*data + 3); -+ rvalue += ((double) ivalue) / 0x10000L; -+ NEED(CS_ARG_STACK_MAX, cs2_stack_top + 1); -+ cs2_arg_stack[cs2_stack_top++] = rvalue; -+ *data += 4; -+ return; -+} -+ -+/*tex -+ -+Subroutines: the bias for subroutine number is introduced in type 2 -+charstrings. -+ -+\starttabulate -+\NC \type {subr} \NC set to a pointer to the subroutine charstring \NC \NR -+\NC \type {len} \NC set to the length of subroutine charstring \NC \NR -+\NC \type {subr_idx} \NC CFF INDEX data that contains subroutines \NC \NR -+\NC \type {id} \NC biased subroutine number \NC \NR -+\stoptabulate -+ -+*/ -+ -+static void get_subr(card8 ** subr, long *len, cff_index * subr_idx, long id) -+{ -+ card16 count; -+ if (subr_idx == NULL) -+ formatted_error("cff","%s: subroutine called but no subroutine found",CS_TYPE2_DEBUG_STR); -+ count = subr_idx->count; -+ /*tex addi the bias number */ -+ if (count < 1240) { -+ id += 107; -+ } else if (count < 33900) { -+ id += 1131; -+ } else { -+ id += 32768; -+ } -+ if (id > count) -+ formatted_error("cff","%s: invalid subroutine index: %ld (max=%u)", CS_TYPE2_DEBUG_STR, id, count); -+ *len = (long) ((subr_idx->offset)[id + 1] - (subr_idx->offset)[id]); -+ *subr = subr_idx->data + (subr_idx->offset)[id] - 1; -+ return; -+} -+ -+/*tex -+ -+ The Type 2 interpretation of a number encoded in five-bytes (those with an -+ initial byte value of 255) differs from how it is interpreted in the Type 1 -+ format. -+ -+*/ -+ -+static void do_charstring(card8 ** dest, card8 * limit, card8 ** data, card8 * endptr, -+ cff_index * gsubr_idx, cff_index * subr_idx, int cff2) -+{ -+ card8 b0 = 0, *subr; -+ long len; -+ if (cs2_nest > CS_SUBR_NEST_MAX) -+ formatted_error("cff","%s: subroutine nested too deeply", CS_TYPE2_DEBUG_STR); -+ cs2_nest++; -+ while (*data < endptr && status == CS_PARSE_OK) { -+ b0 = **data; -+ if (b0 == 255) { -+ /*tex A 16-bit.16-bit fixed signed number. */ -+ get_fixed(data, endptr); -+ } else if (b0 == cs_return) { -+ status = CS_SUBR_RETURN; -+ } else if (b0 == cs_callgsubr) { -+ if (cs2_stack_top < 1) { -+ status = CS_STACK_CFF_ERROR; -+ } else { -+ cs2_stack_top--; -+ get_subr(&subr, &len, gsubr_idx, (long) cs2_arg_stack[cs2_stack_top]); -+ if (*dest + len > limit) -+ formatted_error("cff","%s: possible buffer overflow (1)", CS_TYPE2_DEBUG_STR); -+ do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2); -+ *data += 1; -+ } -+ } else if (b0 == cs_callsubr) { -+ if (cs2_stack_top < 1) { -+ status = CS_STACK_CFF_ERROR; -+ } else { -+ cs2_stack_top--; -+ get_subr(&subr, &len, subr_idx, (long) cs2_arg_stack[cs2_stack_top]); -+ if (limit < *dest + len) -+ formatted_error("cff","%s: possible buffer overflow (2)", CS_TYPE2_DEBUG_STR); -+ do_charstring(dest, limit, &subr, subr + len, gsubr_idx, subr_idx, cff2); -+ *data += 1; -+ } -+ } else if (b0 == cs_escape) { -+ do_operator2(dest, limit, data, endptr); -+ } else if (b0 < 32 && b0 != 28) { -+ do_operator1(dest, limit, data, endptr); -+ } else if ((b0 <= 22 && b0 >= 27) || b0 == 31) { -+ status = CS_PARSE_CFF_ERROR; -+ } else { -+ cs2_get_integer(data, endptr); -+ } -+ } -+ if (cff2) { -+ DST_NEED(limit, *dest + 1); -+ ++endptr; -+ *(*dest)++ = cs_endchar; -+ } else if (status == CS_SUBR_RETURN) { -+ status = CS_PARSE_OK; -+ } else if (status == CS_CHAR_END && *data < endptr) { -+ formatted_warning("cff","%s: garbage after endchar", CS_TYPE2_DEBUG_STR); -+ } else if (status < CS_PARSE_OK) { -+ formatted_error("cff","%s: parsing charstring failed: (status=%d, stack=%d)", CS_TYPE2_DEBUG_STR, status, cs2_stack_top); -+ } -+ cs2_nest--; -+ return; -+} -+ -+static void cs_parse_init(void) -+{ -+ status = CS_PARSE_OK; -+ cs2_nest = 0; -+ phase = 0; -+ num_stems = 0; -+ cs2_stack_top = 0; -+} -+ -+/*tex Not just copying \unknown */ -+ -+static long cs_copy_charstring(card8 * dst, long dstlen, card8 * src, long srclen, cff_index * gsubr, -+ cff_index * subr, double default_width, double nominal_width, cs_ginfo * ginfo, int cff2) -+{ -+ card8 *save = dst; -+ -+ cs_parse_init(); -+ -+ width = 0.0; -+ have_width = 0; -+ -+ /* expand call(g)subrs */ -+ do_charstring(&dst, dst + dstlen, &src, src + srclen, gsubr, subr, cff2); -+ -+ if (ginfo) { -+ ginfo->flags = 0; /* not used */ -+ if (have_width) { -+ ginfo->wx = nominal_width + width; -+ } else { -+ ginfo->wx = default_width; -+ } -+ } -+ -+ return (long) (dst - save); -+} -+ -+/*tex CID-Keyed font specific. */ -+ -+long cff_read_fdselect(cff_font * cff) -+{ -+ cff_fdselect *fdsel; -+ long offset, length; -+ card16 i; -+ if (cff->topdict == NULL) -+ normal_error("cff","top DICT not available"); -+ if (!(cff->flag & FONTTYPE_CIDFONT)) -+ return 0; -+ offset = (long) cff_dict_get(cff->topdict, "FDSelect", 0); -+ cff->offset = (l_offset) offset; -+ cff->fdselect = fdsel = xcalloc(1, sizeof(cff_fdselect)); -+ fdsel->format = get_card8(cff); -+ length = 1; -+ switch (fdsel->format) { -+ case 0: -+ fdsel->num_entries = cff->num_glyphs; -+ (fdsel->data).fds = xmalloc(fdsel->num_entries * sizeof(card8)); -+ for (i = 0; i < (fdsel->num_entries); i++) { -+ (fdsel->data).fds[i] = get_card8(cff); -+ } -+ length += fdsel->num_entries; -+ break; -+ case 3: -+ { -+ cff_range3 *ranges; -+ fdsel->num_entries = get_card16(cff); -+ fdsel->data.ranges = ranges = -+ xcalloc(fdsel->num_entries, sizeof(cff_range3)); -+ for (i = 0; i < (fdsel->num_entries); i++) { -+ ranges[i].first = get_card16(cff); -+ ranges[i].fd = get_card8(cff); -+ } -+ if (ranges[0].first != 0) -+ normal_error("cff","range not starting with 0"); -+ if (cff->num_glyphs != get_card16(cff)) -+ normal_error("cff","sentinel value mismatched with number of glyphs"); -+ length += (fdsel->num_entries) * 3 + 4; -+ } -+ break; -+ default: -+ xfree(fdsel); -+ normal_error("cff","unknown FDSelect format"); -+ break; -+ } -+ return length; -+} -+ -+long cff_pack_fdselect(cff_font * cff, card8 * dest, long destlen) -+{ -+ cff_fdselect *fdsel; -+ long len = 0; -+ card16 i; -+ if (cff->fdselect == NULL) -+ return 0; -+ if (destlen < 1) -+ normal_error("cff","buffer overflow (23)"); -+ fdsel = cff->fdselect; -+ dest[len++] = fdsel->format; -+ switch (fdsel->format) { -+ case 0: -+ if (fdsel->num_entries != cff->num_glyphs) -+ normal_error("cff","invalid data"); -+ if (destlen < len + fdsel->num_entries) -+ normal_error("cff","buffer overflow (24)"); -+ for (i = 0; i < fdsel->num_entries; i++) { -+ dest[len++] = (fdsel->data).fds[i]; -+ } -+ break; -+ case 3: -+ { -+ if (destlen < len + 2) -+ normal_error("cff","buffer overflow (25)"); -+ len += 2; -+ for (i = 0; i < (fdsel->num_entries); i++) { -+ if (destlen < len + 3) -+ normal_error("cff","buffer overflow (26)"); -+ dest[len++] = -+ (card8) (((fdsel->data).ranges[i].first >> 8) & 0xff); -+ dest[len++] = (card8) ((fdsel->data).ranges[i].first & 0xff); -+ dest[len++] = (card8) ((fdsel->data).ranges[i].fd); -+ } -+ if (destlen < len + 2) -+ normal_error("cff","buffer overflow (27)"); -+ dest[len++] = (card8) ((cff->num_glyphs >> 8) & 0xff); -+ dest[len++] = (card8) (cff->num_glyphs & 0xff); -+ dest[1] = (card8) (((len / 3 - 1) >> 8) & 0xff); -+ dest[2] = (card8) ((len / 3 - 1) & 0xff); -+ } -+ break; -+ default: -+ normal_error("cff","unknown FDSelect format"); -+ break; -+ } -+ return len; -+} -+ -+/*tex Create an instance of embeddable font. */ -+ -+static void write_fontfile(PDF pdf, cff_font * cffont, char *fullname) -+{ -+ cff_index *topdict, *fdarray, *private; -+ unsigned char *dest; -+ long destlen = 0, i, size; -+ long offset, topdict_offset, fdarray_offset; -+ topdict = cff_new_index(1); -+ fdarray = cff_new_index(cffont->num_fds); -+ private = cff_new_index(cffont->num_fds); -+ cff_dict_remove(cffont->topdict, "UniqueID"); -+ cff_dict_remove(cffont->topdict, "XUID"); -+ /*tex A bad font may have this: */ -+ cff_dict_remove(cffont->topdict, "Private"); -+ /*tex A bad font may have this: */ -+ cff_dict_remove(cffont->topdict, "Encoding"); -+ /*tex This is CFF2 specific: */ -+ cff_dict_remove(cffont->topdict, "vstore"); -+ /*tex This is CFF2 specific: */ -+ cff_dict_remove(cffont->topdict, "maxstack"); -+ topdict->offset[1] = (l_offset) cff_dict_pack(cffont->topdict, (card8 *) work_buffer, WORK_BUFFER_SIZE) + 1; -+ for (i = 0; i < cffont->num_fds; i++) { -+ size = 0; -+ if (cffont->private && cffont->private[i]) { -+ size = cff_dict_pack(cffont->private[i], (card8 *) work_buffer, WORK_BUFFER_SIZE); -+ if (size < 1) { -+ /*tex |Private| contains only |Subr|: */ -+ cff_dict_remove(cffont->fdarray[i], "Private"); -+ } -+ } -+ (private->offset)[i + 1] = (unsigned long) ((private->offset)[i] + (unsigned) size); -+ (fdarray->offset)[i + 1] = (unsigned long) ((fdarray->offset)[i] -+ + (unsigned) cff_dict_pack(cffont->fdarray[i], (card8 *) work_buffer, WORK_BUFFER_SIZE)); -+ } -+ /*tex The header size: */ -+ destlen = 4; -+ destlen += cff_set_name(cffont, fullname); -+ destlen += cff_index_size(topdict); -+ destlen += cff_index_size(cffont->string); -+ destlen += cff_index_size(cffont->gsubr); -+ /*tex |charset| format 0 */ -+ destlen += (cffont->charsets->num_entries) * 2 + 1; -+ /*tex |fdselect| format 3 */ -+ destlen += (cffont->fdselect->num_entries) * 3 + 5; -+ destlen += cff_index_size(cffont->cstrings); -+ destlen += cff_index_size(fdarray); -+ /* |Private| is not indexed */ -+ destlen = (long) (destlen + (long) private->offset[private->count] - 1); -+ dest = xcalloc((unsigned) destlen, sizeof(card8)); -+ offset = 0; -+ /*tex |Header| */ -+ offset += cff_put_header(cffont, dest + offset, destlen - offset); -+ /*tex |Name| */ -+ offset += cff_pack_index(cffont->name, dest + offset, destlen - offset); -+ /*tex |Top DICT| */ -+ topdict_offset = offset; -+ offset += cff_index_size(topdict); -+ /*tex |Strings| */ -+ offset += cff_pack_index(cffont->string, dest + offset, destlen - offset); -+ /*tex |Global Subrs| */ -+ offset += cff_pack_index(cffont->gsubr, dest + offset, destlen - offset); -+ /*tex |charset| */ -+ cff_dict_set(cffont->topdict, "charset", 0, (double) offset); -+ offset += cff_pack_charsets(cffont, dest + offset, destlen - offset); -+ /*tex |FDSelect| */ -+ cff_dict_set(cffont->topdict, "FDSelect", 0, (double) offset); -+ offset += cff_pack_fdselect(cffont, dest + offset, destlen - offset); -+ /*tex |CharStrings| */ -+ cff_dict_set(cffont->topdict, "CharStrings", 0, (double) offset); -+ offset += cff_pack_index(cffont->cstrings, dest + offset, cff_index_size(cffont->cstrings)); -+ cff_release_index(cffont->cstrings); -+ /*tex |Charstring|s can consume a lot of memory. */ -+ cffont->cstrings = NULL; -+ /*tex |FDArray| and |Private| */ -+ cff_dict_set(cffont->topdict, "FDArray", 0, (double) offset); -+ fdarray_offset = offset; -+ offset += cff_index_size(fdarray); -+ fdarray->data = xcalloc((unsigned) (fdarray->offset[fdarray->count] - 1), sizeof(card8)); -+ for (i = 0; i < cffont->num_fds; i++) { -+ size = (long) (private->offset[i + 1] - private->offset[i]); -+ if (cffont->private[i] && size > 0) { -+ cff_dict_pack(cffont->private[i], dest + offset, size); -+ cff_dict_set(cffont->fdarray[i], "Private", 0, (double) size); -+ cff_dict_set(cffont->fdarray[i], "Private", 1, (double) offset); -+ } -+ cff_dict_pack(cffont->fdarray[i], fdarray->data + (fdarray->offset)[i] - 1, (long) (fdarray->offset[fdarray->count] - 1)); -+ offset += size; -+ } -+ cff_pack_index(fdarray, dest + fdarray_offset, cff_index_size(fdarray)); -+ cff_release_index(fdarray); -+ cff_release_index(private); -+ /*tex Finally the |Top DICT| */ -+ topdict->data = xcalloc((unsigned) (topdict->offset[topdict->count] - 1), sizeof(card8)); -+ cff_dict_pack(cffont->topdict, topdict->data, (long) (topdict->offset[topdict->count] - 1)); -+ cff_pack_index(topdict, dest + topdict_offset, cff_index_size(topdict)); -+ cff_release_index(topdict); -+ for (i = 0; i < offset; i++) { -+ strbuf_putchar(pdf->fb, dest[i]); -+ } -+ xfree(dest); -+ return; -+} -+ -+void write_cff(PDF pdf, cff_font * cffont, fd_entry * fd) -+{ -+ cff_index *charstrings, *cs_idx; -+ long charstring_len, max_len; -+ long size, offset = 0; -+ card8 *data; -+ card16 num_glyphs, cs_count1, code, gid, last_cid; -+ double nominal_width, default_width; -+ char *fontname; -+ char *fullname; -+ glw_entry *glyph, *found; -+ struct avl_traverser t; -+ cffont->_string = NULL; -+ fontname = xcalloc((unsigned) (1 + strlen(fd->fontname)), 1); -+ sprintf(fontname, "%s", fd->fontname); -+ fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1); -+ sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname); -+ /*tex Finish parsing the CFF. */ -+ cff_read_private(cffont); -+ cff_read_subrs(cffont); -+ /*tex The |Width|s. */ -+ if (cffont->private[0] && cff_dict_known(cffont->private[0], "defaultWidthX")) { -+ default_width = (double) cff_dict_get(cffont->private[0], "defaultWidthX", 0); -+ } else { -+ default_width = CFF_DEFAULTWIDTHX_DEFAULT; -+ } -+ if (cffont->private[0] && cff_dict_known(cffont->private[0], "nominalWidthX")) { -+ nominal_width = (double) cff_dict_get(cffont->private[0], "nominalWidthX", 0); -+ } else { -+ nominal_width = CFF_NOMINALWIDTHX_DEFAULT; -+ } -+ num_glyphs = 0; -+ last_cid = 0; -+ glyph = xtalloc(1, glw_entry); -+ /*tex insert |notdef| */ -+ glyph->id = 0; -+ if (avl_find(fd->gl_tree, glyph) == NULL) { -+ avl_insert(fd->gl_tree, glyph); -+ glyph = xtalloc(1, glw_entry); -+ } -+ avl_t_init(&t, fd->gl_tree); -+ for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree); -+ found != NULL; found = (glw_entry *) avl_t_next(&t)) { -+ if (found->id > last_cid) -+ last_cid = (card16) found->id; -+ num_glyphs++; -+ } -+ { -+ cff_fdselect *fdselect; -+ fdselect = xcalloc(1, sizeof(cff_fdselect)); -+ fdselect->format = 3; -+ fdselect->num_entries = 1; -+ fdselect->data.ranges = xcalloc(1, sizeof(cff_range3)); -+ fdselect->data.ranges[0].first = 0; -+ fdselect->data.ranges[0].fd = 0; -+ cffont->fdselect = fdselect; -+ } -+ { -+ cff_charsets *charset; -+ charset = xcalloc(1, sizeof(cff_charsets)); -+ charset->format = 0; -+ charset->num_entries = (card16) (num_glyphs - 1); -+ charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID)); -+ gid = 0; -+ avl_t_init(&t, fd->gl_tree); -+ for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree); -+ found != NULL; found = (glw_entry *) avl_t_next(&t)) { -+ if (found->id != 0) { -+ charset->data.glyphs[gid] = (s_SID) found->id; -+ gid++; -+ } -+ } -+ cffont->charsets = charset; -+ if (cffont->header_major == 2) { -+ cff_dict_add(cffont->topdict, "charset", 1); -+ } -+ } -+ cff_dict_add(cffont->topdict, "CIDCount", 1); -+ cff_dict_set(cffont->topdict, "CIDCount", 0, last_cid + 1); -+ if (cffont->header_major == 2) { -+ cff_dict_add(cffont->topdict, "FullName", 1); -+ cff_dict_set(cffont->topdict, "FullName", 0, (double) cff_add_string(cffont, fontname)); -+ cff_dict_add(cffont->topdict, "FontBBox", 4); -+ cff_dict_set(cffont->topdict, "FontBBox", 0, fd->font_dim[FONTBBOX1_CODE].val); -+ cff_dict_set(cffont->topdict, "FontBBox", 1, fd->font_dim[FONTBBOX2_CODE].val); -+ cff_dict_set(cffont->topdict, "FontBBox", 2, fd->font_dim[FONTBBOX3_CODE].val); -+ cff_dict_set(cffont->topdict, "FontBBox", 3, fd->font_dim[FONTBBOX4_CODE].val); -+ } -+ cffont->fdarray = xcalloc(1, sizeof(cff_dict *)); -+ cffont->fdarray[0] = cff_new_dict(); -+ cff_dict_add(cffont->fdarray[0], "FontName", 1); -+ /*tex fix: skip XXXXXX+ */ -+ cff_dict_set(cffont->fdarray[0], "FontName", 0, (double) cff_add_string(cffont, fullname)); -+ cff_dict_add(cffont->fdarray[0], "Private", 2); -+ cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0); -+ cff_dict_set(cffont->fdarray[0], "Private", 0, 0.0); -+ /*tex |FDArray| index offset, not known yet */ -+ cff_dict_add(cffont->topdict, "FDArray", 1); -+ cff_dict_set(cffont->topdict, "FDArray", 0, 0.0); -+ /*tex |FDSelect| offset, not known yet */ -+ cff_dict_add(cffont->topdict, "FDSelect", 1); -+ cff_dict_set(cffont->topdict, "FDSelect", 0, 0.0); -+ cff_dict_remove(cffont->topdict, "UniqueID"); -+ cff_dict_remove(cffont->topdict, "XUID"); -+ cff_dict_remove(cffont->topdict, "Private"); -+ cff_dict_remove(cffont->topdict, "Encoding"); -+ cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0); -+ cs_idx = cff_get_index_header(cffont); -+ offset = (long) cffont->offset; -+ cs_count1 = cs_idx->count; -+ if (cs_count1 < 2) { -+ normal_error("cff","no valid charstring data found"); -+ } -+ /*tex Build the new charstrings entry. */ -+ charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1)); -+ max_len = 2 * CS_STR_LEN_MAX; -+ charstrings->data = xcalloc((unsigned) max_len, sizeof(card8)); -+ charstring_len = 0; -+ gid = 0; -+ data = xcalloc(CS_STR_LEN_MAX, sizeof(card8)); -+ { -+ int i; -+ int tex_font = fd->tex_font; -+ int streamprovider = 0; -+ int callback_id = 0 ; -+ if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) { -+ streamprovider = font_streamprovider(tex_font); -+ callback_id = callback_defined(glyph_stream_provider_callback); -+ } -+ for (i = 0; i < cs_count1; i++) { -+ code = (card16) i; -+ glyph->id = code; -+ if ((avl_find(fd->gl_tree,glyph) != NULL)) { -+ /*tex This code is the same as below, apart from small details */ -+ if (callback_id > 0) { -+ lstring * result; -+ run_callback(callback_id, "ddd->L", tex_font, i, streamprovider, &result); /* this call can be sped up */ -+ size = (size_t) result->l ; -+ if (size > 0) { -+ if (charstring_len + CS_STR_LEN_MAX >= max_len) { -+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX); -+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8))); -+ } -+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1); -+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1); -+ memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t) size); -+ charstring_len += size; -+ xfree(result); -+ } -+ } else { -+ size = (long)(cs_idx->offset[code+1] - cs_idx->offset[code]); -+ if (size > CS_STR_LEN_MAX) { -+ formatted_error("cff","charstring too long: gid=%u, %ld bytes", code, size); -+ } -+ if (charstring_len + CS_STR_LEN_MAX >= max_len) { -+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX); -+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8))); -+ } -+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1); -+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[code] - 1); -+ memcpy(data,&cffont->stream[cffont->offset],(size_t)size); -+ charstring_len += cs_copy_charstring( -+ charstrings->data + charstring_len, -+ max_len - charstring_len, -+ data, size, -+ cffont->gsubr, (cffont->subrs)[0], -+ default_width, nominal_width, NULL, -+ cffont->header_major == 2 -+ ); -+ } -+ gid++; -+ } -+ } -+ } -+ /*tex -+ The |CIDSet| is a table of bits indexed by cid, bytes with high order bit -+ first, each (set) bit is a (present) CID. -+ */ -+ if (1) { -+ int cid; -+ cidset = pdf_create_obj(pdf, obj_type_others, 0); -+ if (cidset != 0) { -+ size_t l = (last_cid/8)+1; -+ char *stream = xmalloc(l); -+ memset(stream, 0, l); -+ for (cid = 1; cid <= (long) last_cid; cid++) { -+ glyph->id = cid; -+ if (avl_find(fd->gl_tree,glyph) != NULL) { -+ stream[(cid / 8)] |= (1 << (7 - (cid % 8))); -+ } -+ } -+ pdf_begin_obj(pdf, cidset, OBJSTM_NEVER); -+ pdf_begin_dict(pdf); -+ pdf_dict_add_streaminfo(pdf); -+ pdf_end_dict(pdf); -+ pdf_begin_stream(pdf); -+ pdf_out_block(pdf, stream, l); -+ pdf_end_stream(pdf); -+ pdf_end_obj(pdf); -+ } -+ } -+ /*tex -+ This happens if the internal metrics do not agree with the actual disk -+ font. -+ */ -+ if (gid < num_glyphs) { -+ formatted_warning("cff","embedded subset is smaller than expected: %d instead of %d glyphs", gid, num_glyphs); -+ num_glyphs = gid; -+ } -+ xfree(data); -+ cff_release_index(cs_idx); -+ (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1); -+ charstrings->count = num_glyphs; -+ cffont->num_glyphs = num_glyphs; -+ cffont->cstrings = charstrings; -+ /*tex -+ We don't use subroutines at all. -+ */ -+ if (cffont->gsubr) -+ cff_release_index(cffont->gsubr); -+ cffont->gsubr = cff_new_index(0); -+ if (cffont->subrs && cffont->subrs[0]) -+ cff_release_index(cffont->subrs[0]); -+ cffont->subrs[0] = NULL; -+ if (cffont->private && (cffont->private)[0]) { -+ cff_dict_remove((cffont->private)[0], "Subrs"); /* no Subrs */ -+ } -+ cff_dict_update(cffont->topdict, cffont); -+ cff_add_string(cffont, "Adobe"); -+ cff_add_string(cffont, "Identity"); -+ if (cffont->header_major == 2) { -+ /*tex A crash. */ -+ } else { -+ cff_dict_update(cffont->private[0], cffont); -+ } -+ cff_update_string(cffont); -+ /* CFF code need to be rewritten */ -+ cff_dict_add(cffont->topdict, "ROS", 3); -+ cff_dict_set(cffont->topdict, "ROS", 0, (double) cff_get_sid(cffont, "Adobe")); -+ cff_dict_set(cffont->topdict, "ROS", 1, (double) cff_get_sid(cffont, "Identity")); -+ cff_dict_set(cffont->topdict, "ROS", 2, 0.0); -+ write_fontfile(pdf, cffont, fullname); -+ xfree(fontname); -+ xfree(fullname); -+ cff_close(cffont); -+} -+ -+#define is_cidfont(a) ((a)->flag & FONTTYPE_CIDFONT) -+#define CID_MAX 65535 -+ -+void write_cid_cff(PDF pdf, cff_font * cffont, fd_entry * fd) -+{ -+ cff_index *charstrings, *cs_idx; -+ long charstring_len, max_len; -+ long size, offset = 0; -+ int tex_font = fd->tex_font; -+ int streamprovider = 0; -+ int callback_id = 0 ; -+ card8 *data; -+ card16 num_glyphs, cs_count1, gid, last_cid; -+ int fdsel, prev_fd, cid_count, cid ; -+ char *fullname; -+ glw_entry *glyph; -+ unsigned char *CIDToGIDMap = NULL; -+ cff_fdselect *fdselect = NULL; -+ cff_charsets *charset = NULL; -+ if (!is_cidfont(cffont)) { -+ normal_error("cff","invalid CIDfont"); -+ return; -+ } -+ if ((tex_font > 0) && (font_streamprovider(tex_font) == 1)) { -+ streamprovider = font_streamprovider(tex_font); -+ callback_id = callback_defined(glyph_stream_provider_callback); -+ } -+ fullname = xcalloc((unsigned) (8 + strlen(fd->fontname)), 1); -+ sprintf(fullname, "%s+%s", fd->subset_tag, fd->fontname); -+ /*tex Finish parsing the CFF. */ -+ if (cff_dict_known(cffont->topdict, "CIDCount")) { -+ cid_count = (card16) cff_dict_get(cffont->topdict, "CIDCount", 0); -+ } else { -+ cid_count = CFF_CIDCOUNT_DEFAULT; -+ } -+ if (cffont->header_major == 2) { -+ /*tex hm */ -+ } else { -+ cff_read_charsets(cffont); -+ } -+ CIDToGIDMap = xmalloc((unsigned) ((2 * (unsigned) cid_count) * sizeof(unsigned char))); -+ memset(CIDToGIDMap, 0, (size_t) (2 * cid_count)); -+ glyph = xtalloc(1, glw_entry); -+ /*tex insert |notdef| */ -+ glyph->id = 0; -+ if (avl_find(fd->gl_tree, glyph) == NULL) { -+ avl_insert(fd->gl_tree, glyph); -+ glyph = xtalloc(1, glw_entry); -+ } -+ last_cid = 0; -+ num_glyphs = 0; -+ for (cid = 0; cid <= CID_MAX; cid++) { -+ glyph->id = (unsigned) cid; -+ if (avl_find(fd->gl_tree, glyph) != NULL) { -+ gid = (card16) cid; -+ CIDToGIDMap[2 * cid] = (unsigned char) ((gid >> 8) & 0xff); -+ CIDToGIDMap[2 * cid + 1] = (unsigned char) (gid & 0xff); -+ last_cid = (card16) cid; -+ num_glyphs++; -+ } -+ } -+ if (cffont->header_major == 2) { -+ /*tex hm */ -+ } else if (last_cid >= cffont->num_glyphs) { -+ formatted_error("cff font","bad glyph index %i",last_cid); -+ } -+ /*tex -+ The |CIDSet| table is a table of bits indexed by cid, bytes with high -+ order bit first, each (set) bit is a (present) CID. -+ */ -+ if (1) { -+ cidset = pdf_create_obj(pdf, obj_type_others, 0); -+ if (cidset != 0) { -+ size_t l = (last_cid / 8) + 1; -+ char *stream = xmalloc(l); -+ memset(stream, 0, l); -+ for (cid = 1; cid <= (long) last_cid; cid++) { -+ if (CIDToGIDMap[2 * cid] || CIDToGIDMap[2 * cid + 1]) { -+ stream[(cid / 8)] |= (1 << (7 - (cid % 8))); -+ } -+ } -+ pdf_begin_obj(pdf, cidset, OBJSTM_NEVER); -+ pdf_begin_dict(pdf); -+ pdf_dict_add_streaminfo(pdf); -+ pdf_end_dict(pdf); -+ pdf_begin_stream(pdf); -+ pdf_out_block(pdf, stream, l); -+ pdf_end_stream(pdf); -+ pdf_end_obj(pdf); -+ xfree(stream); -+ } -+ } -+ cff_read_fdselect(cffont); -+ cff_read_fdarray(cffont); -+ cff_read_private(cffont); -+ cff_read_subrs(cffont); -+ cffont->offset = (l_offset) cff_dict_get(cffont->topdict, "CharStrings", 0); -+ cs_idx = cff_get_index_header(cffont); -+ offset = (long) cffont->offset; -+ cs_count1 = cs_idx->count; -+ if (cs_count1 < 2) { -+ normal_error("cff","no valid charstring data found"); -+ } -+ charset = xcalloc(1, sizeof(cff_charsets)); -+ charset->format = 0; -+ charset->num_entries = 0; -+ charset->data.glyphs = xcalloc(num_glyphs, sizeof(s_SID)); -+ fdselect = xcalloc(1, sizeof(cff_fdselect)); -+ fdselect->format = 3; -+ fdselect->num_entries = 0; -+ fdselect->data.ranges = xcalloc(num_glyphs, sizeof(cff_range3)); -+ charstrings = cff_new_index((card16) (cs_count1==USHRT_MAX?cs_count1: cs_count1 + 1)); -+ max_len = 2 * CS_STR_LEN_MAX; -+ charstrings->data = xcalloc((unsigned) max_len, sizeof(card8)); -+ charstring_len = 0; -+ prev_fd = -1; -+ gid = 0; -+ data = xcalloc(CS_STR_LEN_MAX, sizeof(card8)); -+ for (cid = 0; cid <= last_cid; cid++) { -+ unsigned short gid_org; -+ glyph->id = (unsigned) cid; -+ if (avl_find(fd->gl_tree, glyph) == NULL) -+ continue; -+ gid_org = (short unsigned) ((CIDToGIDMap[2 * cid] << 8) | (CIDToGIDMap[2 * cid + 1])); -+ fdsel = cff_fdselect_lookup(cffont, gid_org); -+ if (callback_id > 0) { -+ /*tex The next blob is not yet tested \unknown\ I need a font. */ -+ lstring * result; -+ run_callback(callback_id, "ddd->L", tex_font, gid_org, streamprovider, &result); -+ size = (size_t) result->l ; -+ if (size > 0) { -+ if (charstring_len + CS_STR_LEN_MAX >= max_len) { -+ max_len = (long)(charstring_len + 2 * CS_STR_LEN_MAX); -+ charstrings->data = xrealloc(charstrings->data, (unsigned)((unsigned)max_len*sizeof(card8))); -+ } -+ (charstrings->offset)[gid] = (unsigned)(charstring_len + 1); -+ cffont->offset = (l_offset)((unsigned)offset + (cs_idx->offset)[gid_org] - 1); -+ memcpy(charstrings->data+charstring_len,(const char *) result->s,(size_t)size); -+ charstring_len += size; -+ xfree(result); -+ } -+ } else { -+ size = (long) (cs_idx->offset[gid_org + 1] - cs_idx->offset[gid_org]); -+ if (size > CS_STR_LEN_MAX) { -+ formatted_error("cff","charstring too long: gid=%u, %ld bytes", cid, size); -+ } -+ if (charstring_len + CS_STR_LEN_MAX >= max_len) { -+ max_len = charstring_len + 2 * CS_STR_LEN_MAX; -+ charstrings->data = xrealloc(charstrings->data, (unsigned) ((unsigned) max_len * sizeof(card8))); -+ } -+ (charstrings->offset)[gid] = (l_offset) (charstring_len + 1); -+ cffont->offset = (l_offset) ((unsigned) offset + (cs_idx->offset)[gid_org] - 1); -+ memcpy(data, &cffont->stream[cffont->offset], (size_t) size); -+ charstring_len += cs_copy_charstring( -+ charstrings->data + charstring_len, -+ max_len - charstring_len, -+ data, size, -+ cffont->gsubr, (cffont->subrs)[fdsel], -+ 0, 0, NULL, -+ cffont->header_major == 2 -+ ); -+ } -+ if (cid > 0 && gid_org > 0) { -+ charset->data.glyphs[charset->num_entries] = (s_SID) cid; -+ charset->num_entries++; -+ } -+ if (fdsel != prev_fd) { -+ fdselect->data.ranges[fdselect->num_entries].first = gid; -+ fdselect->data.ranges[fdselect->num_entries].fd = (card8) fdsel; -+ fdselect->num_entries++; -+ prev_fd = fdsel; -+ } -+ gid++; -+ } -+ if (gid != num_glyphs) -+ formatted_error("cff","unexpected error: %i != %i", gid, num_glyphs); -+ xfree(data); -+ cff_release_index(cs_idx); -+ xfree(CIDToGIDMap); -+ (charstrings->offset)[num_glyphs] = (l_offset) (charstring_len + 1); -+ charstrings->count = num_glyphs; -+ cffont->num_glyphs = num_glyphs; -+ cffont->cstrings = charstrings; -+ cff_release_charsets(cffont->charsets); -+ cffont->charsets = charset; -+ cff_release_fdselect(cffont->fdselect); -+ cffont->fdselect = fdselect; -+ /*tex -+ We don't use subroutines at all. -+ */ -+ if (cffont->gsubr) -+ cff_release_index(cffont->gsubr); -+ cffont->gsubr = cff_new_index(0); -+ for (fdsel = 0; fdsel < cffont->num_fds; fdsel++) { -+ if (cffont->subrs && cffont->subrs[fdsel]) { -+ cff_release_index(cffont->subrs[fdsel]); -+ cffont->subrs[fdsel] = NULL; -+ } -+ if (cffont->private && (cffont->private)[fdsel]) { -+ cff_dict_remove((cffont->private)[fdsel], "Subrs"); /* no Subrs */ -+ } -+ } -+ write_fontfile(pdf, cffont, fullname); -+ xfree(fullname); -+ cff_close(cffont); -+} -+ -+/*tex -+ -+ Here is a sneaky trick: fontforge knows how to convert Type1 to CFF, so I -+ have defined a utility function in luafflib.c that does exactly that. If it -+ works out ok, I will clean up this code. -+ -+*/ -+ -+void writetype1w(PDF pdf, fd_entry * fd) -+{ -+ cff_font *cff; -+ int i; -+ FILE *fp; -+ ff_entry *ff; -+ unsigned char *tfm_buffer = NULL; -+ int tfm_size = 0; -+ ff = check_ff_exist(fd->fm->ff_name, 0); -+ fp = fopen(ff->ff_path, "rb"); -+ cur_file_name = ff->ff_path; -+ if (!fp) { -+ formatted_error("cff","could not open Type1 font: %s", cur_file_name); -+ } -+ fclose(fp); -+ if (is_subsetted(fd->fm)) { -+ report_start_file(filetype_subset,cur_file_name); -+ } else { -+ report_start_file(filetype_font,cur_file_name); -+ } -+ (void) ff_createcff(ff->ff_path, &tfm_buffer, &tfm_size); -+ if (tfm_size > 0) { -+ cff = read_cff(tfm_buffer, tfm_size, 0); -+ if (cff != NULL) { -+ write_cff(pdf, cff, fd); -+ } else { -+ for (i = 0; i < tfm_size; i++) -+ strbuf_putchar(pdf->fb, tfm_buffer[i]); -+ } -+ fd->ff_found = 1; -+ } else { -+ formatted_error("cff","could not understand Type1 font: %s",cur_file_name); -+ } -+ if (is_subsetted(fd->fm)) { -+ report_stop_file(filetype_subset); -+ } else { -+ report_stop_file(filetype_font); -+ } -+ cur_file_name = NULL; -+} ---- texlive-source/texk/web2c/luatexdir/font/writet1.c.me 1970-01-01 01:00:00.000000000 +0100 -+++ texlive-source/texk/web2c/luatexdir/font/writet1.c 2020-11-07 15:50:28.081338255 +0100 -@@ -0,0 +1,1693 @@ -+/* -+ -+Copyright 1996-2006 Han The Thanh -+Copyright 2006-2009 Taco Hoekwater -+ -+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 . -+ -+*/ -+ -+#include "ptexlib.h" -+#include -+ -+#define get_length1() t1_length1 = t1_offset() - t1_save_offset -+#define get_length2() t1_length2 = t1_offset() - t1_save_offset -+#define get_length3() t1_length3 = fixedcontent? t1_offset() - t1_save_offset : 0 -+#define save_offset() t1_save_offset = t1_offset() -+#define t1_putchar(A) strbuf_putchar(pdf->fb, (A)) -+#define t1_offset() strbuf_offset(pdf->fb) -+#define out_eexec_char t1_putchar -+#define end_last_eexec_line() t1_eexec_encrypt = false -+#define t1_char(c) c -+#define embed_all_glyphs(tex_font) fm_cur->all_glyphs -+#define extra_charset() fm_cur->charset -+#define fixedcontent false -+ -+int t1_length1, t1_length2, t1_length3; -+static int t1_save_offset; -+static int t1_fontname_offset; -+ -+static unsigned char *t1_buffer = NULL; -+static int t1_size = 0; -+static int t1_curbyte = 0; -+ -+#define t1_read_file() readbinfile(t1_file,&t1_buffer,&t1_size) -+#define t1_close() xfclose(t1_file,cur_file_name) -+#define t1_getchar() t1_buffer[t1_curbyte++] -+#define t1_ungetchar(c) t1_curbyte-- -+#define t1_eof() (t1_curbyte>t1_size) -+ -+#define t1_prefix(s) str_prefix(t1_line_array, s) -+#define t1_buf_prefix(s) str_prefix(t1_buf_array, s) -+#define t1_suffix(s) str_suffix(t1_line_array, t1_line_ptr, s) -+#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s) -+#define t1_charstrings() strstr(t1_line_array, charstringname) -+#define t1_subrs() t1_prefix("/Subrs") -+#define t1_end_eexec() t1_suffix("mark currentfile closefile") -+#define t1_cleartomark() t1_prefix("cleartomark") -+ -+static unsigned char *enc_buffer = NULL; -+static int enc_size = 0; -+static int enc_curbyte = 0; -+ -+#define enc_open(a) (enc_file = fopen((char *)(a), FOPEN_RBIN_MODE)) -+#define enc_read_file() readbinfile(enc_file,&enc_buffer,&enc_size) -+#define enc_close() xfclose(enc_file,cur_file_name) -+#define enc_getchar() enc_buffer[enc_curbyte++] -+#define enc_eof() (enc_curbyte>enc_size) -+ -+#define valid_code(c) (c >= 0 && c < 256) -+#define fixedcontent false -+ -+static const char *standard_glyph_names[256] = { -+ /* 0x00 */ -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ /* 0x10 */ -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ /* 0x20 */ -+ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", -+ "ampersand", "quoteright", "parenleft", "parenright", "asterisk", -+ "plus", "comma", "hyphen", "period", "slash", -+ /* 0x30 */ -+ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", -+ "nine", "colon", "semicolon", "less", "equal", "greater", "question", -+ /* 0x40 */ -+ "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", -+ "O", -+ /* 0x50 */ -+ "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", -+ "backslash", "bracketright", "asciicircum", "underscore", -+ /* 0x60 */ -+ "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", -+ "m", "n", "o", -+ /* 0x70 */ -+ "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", -+ "braceright", "asciitilde", notdef, -+ /* 0x80 */ -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ /* 0x90 */ -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ /* 0xa0 */ -+ notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", -+ "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", -+ "guilsinglleft", "guilsinglright", "fi", "fl", -+ /* 0xb0 */ -+ notdef, "endash", "dagger", "daggerdbl", "periodcentered", notdef, -+ "paragraph", "bullet", "quotesinglbase", "quotedblbase", -+ "quotedblright", "guillemotright", "ellipsis", "perthousand", notdef, -+ "questiondown", -+ /* 0xc0 */ -+ notdef, "grave", "acute", "circumflex", "tilde", "macron", "breve", -+ "dotaccent", "dieresis", notdef, -+ "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", -+ /* 0xd0 */ -+ "emdash", notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ notdef, notdef, notdef, notdef, notdef, notdef, notdef, -+ /* 0xe0 */ -+ notdef, "AE", notdef, "ordfeminine", notdef, notdef, notdef, notdef, -+ "Lslash", "Oslash", "OE", "ordmasculine", notdef, notdef, notdef, -+ notdef, -+ /* 0xf0 */ -+ notdef, "ae", notdef, notdef, notdef, "dotlessi", notdef, notdef, "lslash", -+ "oslash", "oe", "germandbls", notdef, notdef, notdef, notdef -+}; -+ -+static fd_entry *fd_cur; -+ -+static char charstringname[] = "/CharStrings"; -+ -+enum { ENC_STANDARD, ENC_BUILTIN } t1_encoding; -+ -+#define T1_BUF_SIZE 0x0010 -+#define ENC_BUF_SIZE 0x1000 -+ -+#define CS_HSTEM 1 -+#define CS_VSTEM 3 -+#define CS_VMOVETO 4 -+#define CS_RLINETO 5 -+#define CS_HLINETO 6 -+#define CS_VLINETO 7 -+#define CS_RRCURVETO 8 -+#define CS_CLOSEPATH 9 -+#define CS_CALLSUBR 10 -+#define CS_RETURN 11 -+#define CS_ESCAPE 12 -+#define CS_HSBW 13 -+#define CS_ENDCHAR 14 -+#define CS_RMOVETO 21 -+#define CS_HMOVETO 22 -+#define CS_VHCURVETO 30 -+#define CS_HVCURVETO 31 -+#define CS_1BYTE_MAX (CS_HVCURVETO + 1) -+ -+#define CS_DOTSECTION CS_1BYTE_MAX + 0 -+#define CS_VSTEM3 CS_1BYTE_MAX + 1 -+#define CS_HSTEM3 CS_1BYTE_MAX + 2 -+#define CS_SEAC CS_1BYTE_MAX + 6 -+#define CS_SBW CS_1BYTE_MAX + 7 -+#define CS_DIV CS_1BYTE_MAX + 12 -+#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16 -+#define CS_POP CS_1BYTE_MAX + 17 -+#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33 -+#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1) -+#define CS_MAX CS_2BYTE_MAX -+ -+typedef unsigned char byte; -+ -+/*tex A |CharString| command: */ -+ -+typedef struct { -+ /*tex number of arguments */ -+ byte nargs; -+ /*tex take arguments from bottom of stack? */ -+ boolean bottom; -+ /*tex clear stack? */ -+ boolean clear; -+ boolean valid; -+} cc_entry; -+ -+typedef struct { -+ /*tex glyph name (or |notdef| for |Subrs| entry) */ -+ char *name; -+ byte *data; -+ /*tex length of the whole string */ -+ unsigned short len; -+ /*tex length of the encoded part of the string */ -+ unsigned short cslen; -+ boolean used; -+ boolean valid; -+} cs_entry; -+ -+static unsigned short t1_dr, t1_er; -+static const unsigned short t1_c1 = 52845, t1_c2 = 22719; -+static unsigned short t1_cslen; -+static short t1_lenIV; -+static char enc_line[ENC_BUF_SIZE]; -+ -+#define t1_line_entry char -+define_array(t1_line); -+ -+#define t1_buf_entry char -+define_array(t1_buf); -+ -+static int cs_start; -+ -+static cs_entry *cs_tab, *cs_ptr, *cs_notdef; -+static char *cs_dict_start, *cs_dict_end; -+static int cs_counter, cs_size, cs_size_pos; -+ -+static cs_entry *subr_tab; -+static char *subr_array_start, *subr_array_end; -+static int subr_max, subr_size, subr_size_pos; -+ -+/*tex -+ -+ This list contains the begin/end tokens commonly used in the |/Subrs| array of -+ a Type 1 font. -+ -+*/ -+ -+static const char *cs_token_pairs_list[][2] = { -+ { " RD", "NP" }, -+ { " -|", "|" }, -+ { " RD", "noaccess put" }, -+ { " -|", "noaccess put" }, -+ { NULL, NULL } -+}; -+ -+static const char **cs_token_pair; -+ -+static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic; -+ -+/*tex This one becomes 0 before 1 during and 2 after |eexec| encryption. */ -+ -+static int t1_in_eexec; -+ -+static long t1_block_length; -+static int last_hexbyte; -+static FILE *t1_file; -+static FILE *enc_file; -+ -+static void enc_getline(void) -+{ -+ char *p; -+ char c; -+ restart: -+ if (enc_eof()) -+ normal_error("type 1","unexpected end of file"); -+ p = enc_line; -+ do { -+ c = (char) enc_getchar(); -+ append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE); -+ } -+ while (c != 10 && !enc_eof()); -+ append_eol(p, enc_line, ENC_BUF_SIZE); -+ if (p - enc_line < 2 || *enc_line == '%') -+ goto restart; -+} -+ -+/*tex -+ -+ Read encoding from .enc file, return |glyph_names array|, or |pdffail|. -+ -+*/ -+ -+char **load_enc_file(char *enc_name) -+{ -+ int callback_id = 0; -+ int file_opened = 0; -+ char buf[ENC_BUF_SIZE], *p, *r; -+ int i, names_count; -+ char **glyph_names; -+ cur_file_name = luatex_find_file(enc_name, find_enc_file_callback); -+ if (cur_file_name == NULL) { -+ formatted_error("type 1","cannot find encoding file '%s' for reading", enc_name); -+ } -+ callback_id = callback_defined(read_enc_file_callback); -+ enc_curbyte = 0; -+ enc_size = 0; -+ if (callback_id > 0) { -+ if (run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &enc_buffer, &enc_size)) { -+ if ((!file_opened) || enc_size == 0) { -+ formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name); -+ } -+ } -+ } else { -+ if (!enc_open(cur_file_name)) { -+ formatted_error("type 1","cannot open encoding file '%s' for reading", cur_file_name); -+ } -+ enc_read_file(); -+ enc_close(); -+ } -+ glyph_names = xtalloc(256, char *); -+ for (i = 0; i < 256; i++) -+ glyph_names[i] = (char *) notdef; -+ report_start_file(filetype_map,cur_file_name); -+ enc_getline(); -+ if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) { -+ remove_eol(r, enc_line); -+ formatted_error("type 1","invalid encoding vector (a name or '[' missing): '%s'", enc_line); -+ } -+ names_count = 0; -+ /*tex Skip |[|: */ -+ r++; -+ skip_char(r, ' '); -+ for (;;) { -+ while (*r == '/') { -+ for (p = buf, r++; -+ *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); -+ *p = 0; -+ skip_char(r, ' '); -+ if (names_count >= 256) -+ normal_error("type 1","encoding vector contains more than 256 names"); -+ if (strcmp(buf, notdef) != 0) -+ glyph_names[names_count] = xstrdup(buf); -+ names_count++; -+ } -+ if (*r != 10 && *r != '%') { -+ if (strncmp(r, "] def", strlen("] def")) == 0) -+ goto done; -+ else { -+ remove_eol(r, enc_line); -+ formatted_error("type 1","invalid encoding vector: a name or '] def' expected: `%s'",enc_line); -+ } -+ } -+ enc_getline(); -+ r = enc_line; -+ } -+ done: -+ report_stop_file(filetype_map); -+ cur_file_name = NULL; -+ xfree(enc_buffer); -+ return glyph_names; -+} -+ -+static void t1_check_pfa(void) -+{ -+ const int c = t1_getchar(); -+ t1_pfa = (c != 128) ? true : false; -+ t1_ungetchar(c); -+} -+ -+static int t1_getbyte(void) -+{ -+ int c = t1_getchar(); -+ if (t1_pfa) -+ return c; -+ if (t1_block_length == 0) { -+ if (c != 128) -+ normal_error("type 1","invalid marker"); -+ c = t1_getchar(); -+ if (c == 3) { -+ while (!t1_eof()) -+ (void) t1_getchar(); -+ return EOF; -+ } -+ t1_block_length = t1_getchar() & 0xff; -+ t1_block_length |= (t1_getchar() & 0xff) << 8; -+ t1_block_length |= (t1_getchar() & 0xff) << 16; -+ t1_block_length |= (t1_getchar() & 0xff) << 24; -+ c = t1_getchar(); -+ } -+ t1_block_length--; -+ return c; -+} -+ -+static int hexval(int c) -+{ -+ if (c >= 'A' && c <= 'F') -+ return c - 'A' + 10; -+ else if (c >= 'a' && c <= 'f') -+ return c - 'a' + 10; -+ else if (c >= '0' && c <= '9') -+ return c - '0'; -+ else -+ return -1; -+} -+ -+static byte edecrypt(byte cipher) -+{ -+ byte plain; -+ if (t1_pfa) { -+ while (cipher == 10 || cipher == 13) -+ cipher = (byte) t1_getbyte(); -+ last_hexbyte = cipher = (byte) ((hexval(cipher) << 4) + hexval(t1_getbyte())); -+ } -+ plain = (byte) (cipher ^ (t1_dr >> 8)); -+ t1_dr = (unsigned short) ((cipher + t1_dr) * t1_c1 + t1_c2); -+ return plain; -+} -+ -+static byte cdecrypt(byte cipher, unsigned short *cr) -+{ -+ const byte plain = (byte) (cipher ^ (*cr >> 8)); -+ *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2); -+ return plain; -+} -+ -+static byte eencrypt(byte plain) -+{ -+ const byte cipher = (byte) (plain ^ (t1_er >> 8)); -+ t1_er = (unsigned short) ((cipher + t1_er) * t1_c1 + t1_c2); -+ return cipher; -+} -+ -+static byte cencrypt(byte plain, unsigned short *cr) -+{ -+ const byte cipher = (byte) (plain ^ (*cr >> 8)); -+ *cr = (unsigned short) ((cipher + *cr) * t1_c1 + t1_c2); -+ return cipher; -+} -+ -+static char *eol(char *s) -+{ -+ char *p = strend(s); -+ if (p - s > 1 && p[-1] != 10) { -+ *p++ = 10; -+ *p = 0; -+ } -+ return p; -+} -+ -+static float t1_scan_num(char *p, char **r) -+{ -+ float f; -+ skip_char(p, ' '); -+ if (sscanf(p, "%g", &f) != 1) { -+ remove_eol(p, t1_line_array); -+ formatted_error("type 1","a number expected: '%s'", t1_line_array); -+ } -+ if (r != NULL) { -+ for (; isdigit((unsigned char)*p) || *p == '.' || -+ *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++); -+ *r = p; -+ } -+ return f; -+} -+ -+static boolean str_suffix(const char *begin_buf, const char *end_buf, const char *s) -+{ -+ const char *s1 = end_buf - 1, *s2 = strend(s) - 1; -+ if (*s1 == 10) -+ s1--; -+ while (s1 >= begin_buf && s2 >= s) { -+ if (*s1-- != *s2--) -+ return false; -+ } -+ return s2 < s; -+} -+ -+static void t1_getline(void) -+{ -+ int c, l, eexec_scan; -+ char *p; -+ static const char eexec_str[] = "currentfile eexec"; -+ static int eexec_len = 17; -+ restart: -+ if (t1_eof()) -+ normal_error("type 1","unexpected end of file"); -+ t1_line_ptr = t1_line_array; -+ alloc_array(t1_line, 1, T1_BUF_SIZE); -+ t1_cslen = 0; -+ eexec_scan = 0; -+ c = t1_getbyte(); -+ if (c == EOF) -+ goto exit; -+ while (!t1_eof()) { -+ if (t1_in_eexec == 1) -+ c = edecrypt((byte) c); -+ alloc_array(t1_line, 1, T1_BUF_SIZE); -+ { -+ char cc = (char) c; -+ append_char_to_buf(cc, t1_line_ptr, t1_line_array, t1_line_limit); -+ } -+ if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) { -+ if (t1_line_array[eexec_scan] == eexec_str[eexec_scan]) -+ eexec_scan++; -+ else -+ eexec_scan = -1; -+ } -+ if (c == 10 || c == 13 -+ || (t1_pfa && eexec_scan == eexec_len && c == 32)) { -+ break; -+ } -+ if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) && -+ (t1_suffix(" RD ") || t1_suffix(" -| "))) { -+ p = t1_line_ptr - 5; -+ while (*p != ' ') -+ p--; -+ l = (int) t1_scan_num(p + 1, 0); -+ t1_cslen = (unsigned short) l; -+ /*tex |cs_start| is an index now */ -+ cs_start = (int) (t1_line_ptr - t1_line_array); -+ alloc_array(t1_line, l, T1_BUF_SIZE); -+ while (l-- > 0) -+ *t1_line_ptr++ = (t1_line_entry) edecrypt((byte) t1_getbyte()); -+ } -+ c = t1_getbyte(); -+ } -+ /*tex |append_eol| can append 2 chars */ -+ alloc_array(t1_line, 2, T1_BUF_SIZE); -+ append_eol(t1_line_ptr, t1_line_array, t1_line_limit); -+ if (t1_line_ptr - t1_line_array < 2) -+ goto restart; -+ if (eexec_scan == eexec_len) -+ t1_in_eexec = 1; -+ exit: -+ /*tex Ensure that |t1_buf_array| has as much room as |t1_line_array|. */ -+ t1_buf_ptr = t1_buf_array; -+ alloc_array(t1_buf, t1_line_limit, t1_line_limit); -+} -+ -+static void t1_putline(PDF pdf) -+{ -+ char *p = t1_line_array; -+ if (t1_line_ptr - t1_line_array <= 1) -+ return; -+ if (t1_eexec_encrypt) { -+ while (p < t1_line_ptr) -+ t1_putchar((eight_bits) eencrypt((byte) * p++)); -+ } else -+ while (p < t1_line_ptr) -+ t1_putchar((eight_bits) * p++); -+} -+ -+static void t1_puts(PDF pdf, const char *s) -+{ -+ if (s != t1_line_array) -+ strcpy(t1_line_array, s); -+ t1_line_ptr = strend(t1_line_array); -+ t1_putline(pdf); -+} -+ -+__attribute__ ((format(printf, 2, 3))) -+static void t1_printf(PDF pdf, const char *fmt, ...) -+{ -+ va_list args; -+ va_start(args, fmt); -+ vsprintf(t1_line_array, fmt, args); -+ t1_puts(pdf, t1_line_array); -+ va_end(args); -+} -+ -+static void t1_init_params(int open_name_prefix) -+{ -+ report_start_file(open_name_prefix,cur_file_name); -+ t1_lenIV = 4; -+ t1_dr = 55665; -+ t1_er = 55665; -+ t1_in_eexec = 0; -+ t1_cs = false; -+ t1_scan = true; -+ t1_synthetic = false; -+ t1_eexec_encrypt = false; -+ t1_block_length = 0; -+ t1_check_pfa(); -+} -+ -+static void t1_close_font_file(int close_name_suffix) -+{ -+ report_stop_file(close_name_suffix); -+ cur_file_name = NULL; -+} -+ -+static void t1_check_block_len(boolean decrypt) -+{ -+ int l, c; -+ if (t1_block_length == 0) -+ return; -+ c = t1_getbyte(); -+ if (decrypt) -+ c = edecrypt((byte) c); -+ l = (int) t1_block_length; -+ if (!(l == 0 && (c == 10 || c == 13))) { -+ formatted_error("type 1","%i bytes more than expected were ignored", l + 1); -+ } -+} -+ -+static void t1_start_eexec(PDF pdf) -+{ -+ int i; -+ get_length1(); -+ save_offset(); -+ if (!t1_pfa) -+ t1_check_block_len(false); -+ for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) { -+ edecrypt((byte) t1_getbyte()); -+ *t1_line_ptr++ = 0; -+ } -+ t1_eexec_encrypt = true; -+ /*tex To put the first four bytes: */ -+ t1_putline(pdf); -+} -+ -+static void t1_stop_eexec(PDF pdf) -+{ -+ int c; -+ get_length2(); -+ save_offset(); -+ t1_eexec_encrypt = false; -+ if (!t1_pfa) -+ t1_check_block_len(true); -+ else { -+ c = edecrypt((byte) t1_getbyte()); -+ if (!(c == 10 || c == 13)) { -+ if (last_hexbyte == 0) -+ t1_puts(pdf, "00"); -+ else -+ normal_error("type 1","unexpected data after eexec"); -+ } -+ } -+ t1_cs = false; -+ t1_in_eexec = 2; -+} -+ -+/*tex Macros for various transforms; unused, left for reference: */ -+ -+#ifdef T1TRANSFORMMACROS -+# define do_xshift(x,a) {x[4]+=a;} -+# define do_yshift(x,a) {x[5]+=a;} -+# define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;} -+# define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;} -+# define do_extend(x,a) {do_xscale(x,a);} -+# define do_scale(x,a) {do_xscale(x,a); do_yscale(x,a);} -+# define do_slant(x,a) {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);} -+# define do_shear(x,a) {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);} -+ -+# define do_rotate(x,a) { \ -+ float t, u=cos(a), v=sin(a); \ -+ t =x[0]*u+x[1]*-v; \ -+ x[1] =x[0]*v+x[1]* u; x[0]=t; \ -+ t =x[2]*u+x[3]*-v; \ -+ x[3] =x[2]*v+x[3]* u; x[2]=t; \ -+ t =x[4]*u+x[5]*-v; \ -+ x[5] =x[4]*v+x[5]* u; x[4]=t; \ -+} -+#endif -+ -+static void t1_scan_keys(PDF pdf) -+{ -+ int i, k; -+ char *p, *q, *r; -+ const key_entry *key; -+ if (t1_prefix("/FontType")) { -+ p = t1_line_array + strlen("FontType") + 1; -+ if ((i = (int) t1_scan_num(p, 0)) != 1) -+ formatted_error("type 1","Type%d fonts unsupported by backend", i); -+ return; -+ } -+ for (key = (const key_entry *) font_key; key - font_key < FONT_KEYS_NUM; -+ key++) { -+ if (key->t1name[0] != '\0' -+ && str_prefix(t1_line_array + 1, key->t1name)) -+ break; -+ } -+ if (key - font_key == FONT_KEYS_NUM) -+ return; -+ p = t1_line_array + strlen(key->t1name) + 1; -+ skip_char(p, ' '); -+ if ((k = (int) (key - font_key)) == FONTNAME_CODE) { -+ if (*p != '/') { -+ remove_eol(p, t1_line_array); -+ formatted_error("type 1","a name expected: '%s'", t1_line_array); -+ } -+ /*tex Skip the slash. */ -+ r = ++p; -+ for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++); -+ *q = 0; -+ xfree(fd_cur->fontname); -+ fd_cur->fontname = xstrdup(t1_buf_array); -+ /*tex -+ -+ At this moment we cannot call |make_subset_tag| yet, as the encoding -+ is not read; thus we mark the offset of the subset tag and write it -+ later. -+ -+ */ -+ if (is_subsetted(fd_cur->fm)) { -+ t1_fontname_offset = (int) (t1_offset() + (r - t1_line_array)); -+ strcpy(t1_buf_array, p); -+ sprintf(r, "ABCDEF+%s%s", fd_cur->fontname, t1_buf_array); -+ t1_line_ptr = eol(r); -+ } -+ return; -+ } -+ if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && (*p == '[' || *p == '{')) -+ p++; -+ if (k == FONTBBOX1_CODE) { -+ for (i = 0; i < 4; i++, k++) { -+ fd_cur->font_dim[k].val = (int) t1_scan_num(p, &r); -+ fd_cur->font_dim[k].set = true; -+ p = r; -+ } -+ return; -+ } -+ fd_cur->font_dim[k].val = (int) t1_scan_num(p, 0); -+ fd_cur->font_dim[k].set = true; -+} -+ -+static void t1_scan_param(PDF pdf) -+{ -+ static const char *lenIV = "/lenIV"; -+ if (!t1_scan || *t1_line_array != '/') -+ return; -+ if (t1_prefix(lenIV)) { -+ t1_lenIV = (short) t1_scan_num(t1_line_array + strlen(lenIV), 0); -+ if (t1_lenIV < 0) -+ normal_error("type 1","negative value of lenIV is not supported"); -+ return; -+ } -+ t1_scan_keys(pdf); -+} -+ -+static void copy_glyph_names(char **glyph_names, int a, int b) -+{ -+ if (glyph_names[b] != notdef) { -+ xfree(glyph_names[b]); -+ glyph_names[b] = (char *) notdef; -+ } -+ if (glyph_names[a] != notdef) { -+ glyph_names[b] = xstrdup(glyph_names[a]); -+ } -+} -+ -+/*tex Read encoding from Type1 font file, return |glyph_names| array, or |pdffail|. */ -+ -+static char **t1_builtin_enc(void) -+{ -+ int i, a, b, c, counter = 0; -+ char *r, *p, **glyph_names; -+ /*tex At this moment |/Encoding| is the prefix of |t1_line_array|. */ -+ glyph_names = xtalloc(256, char *); -+ for (i = 0; i < 256; i++) -+ glyph_names[i] = (char *) notdef; -+ if (t1_suffix("def")) { -+ /*tex A predefined encoding: */ -+ sscanf(t1_line_array + strlen("/Encoding"), "%255s", t1_buf_array); -+ if (strcmp(t1_buf_array, "StandardEncoding") == 0) { -+ t1_encoding = ENC_STANDARD; -+ for (i = 0; i < 256; i++) { -+ if (standard_glyph_names[i] != notdef) -+ glyph_names[i] = xstrdup(standard_glyph_names[i]); -+ } -+ return glyph_names; -+ } else -+ formatted_error("type 1","cannot subset font (unknown predefined encoding '%s')",t1_buf_array); -+ } -+ /* -+ -+ At this moment |/Encoding| is the prefix of |t1_line_array|, and the -+ encoding is not a predefined encoding. We have two possible forms of -+ vector. The first case is -+ -+ \starttyping -+ /Encoding [ -+ /a /b /c ... -+ ] readonly def -+ \stoptyping -+ -+ and the second case can look like -+ -+ \starttyping -+ /Encoding 256 array 0 1 255 { -+ 1 index exch /.notdef put} for -+ dup 0 /x put -+ dup 1 /y put -+ ... -+ } readonly def -+ \stoptyping -+ -+ */ -+ t1_encoding = ENC_BUILTIN; -+ if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) { /* the first case */ -+ r = strchr(t1_line_array, '[') + 1; -+ skip_char(r, ' '); -+ for (;;) { -+ while (*r == '/') { -+ for (p = t1_buf_array, r++; *r != 32 && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); -+ *p = 0; -+ skip_char(r, ' '); -+ if (counter > 255) -+ normal_error("type 1","encoding vector contains more than 256 names"); -+ if (strcmp(t1_buf_array, notdef) != 0) -+ glyph_names[counter] = xstrdup(t1_buf_array); -+ counter++; -+ } -+ if (*r != 10 && *r != '%') { -+ if (str_prefix(r, "] def") || str_prefix(r, "] readonly def")) -+ break; -+ else { -+ remove_eol(r, t1_line_array); -+ formatted_error("type 1","a name or '] def' or '] readonly def' expected: '%s'", t1_line_array); -+ } -+ } -+ t1_getline(); -+ r = t1_line_array; -+ } -+ } else { -+ /*tex The second case. */ -+ p = strchr(t1_line_array, 10); -+ for (;;) { -+ if (*p == 10) { -+ t1_getline(); -+ p = t1_line_array; -+ } -+ /*tex Check for |dup put|. */ -+ if (sscanf(p, "dup %i%255s put", &i, t1_buf_array) == 2 && -+ *t1_buf_array == '/' && valid_code(i)) { -+ if (strcmp(t1_buf_array + 1, notdef) != 0) -+ glyph_names[i] = xstrdup(t1_buf_array + 1); -+ p = strstr(p, " put") + strlen(" put"); -+ skip_char(p, ' '); -+ } -+ /*tex Check for |dup dup exch get put|. */ -+ else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2 && valid_code(a) && valid_code(b)) { -+ copy_glyph_names(glyph_names, a, b); -+ p = strstr(p, " get put") + strlen(" get put"); -+ skip_char(p, ' '); -+ } -+ /*tex Check for |dup dup getinterval exch putinterval|. */ -+ else if (sscanf(p, "dup dup %i %i getinterval %i exch putinterval", -+ &a, &c, &b) == 3 && valid_code(a) && valid_code(b) && valid_code(c)) { -+ for (i = 0; i < c; i++) -+ copy_glyph_names(glyph_names, a + i, b + i); -+ p = strstr(p, " putinterval") + strlen(" putinterval"); -+ skip_char(p, ' '); -+ } -+ /*tex Check for |def or |readonly def|. */ -+ else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' ')) && strcmp(p, "def\n") == 0) { -+ return glyph_names; -+ } else { -+ /*tex Skip an unrecognizable word. */ -+ while (*p != ' ' && *p != 10) -+ p++; -+ skip_char(p, ' '); -+ } -+ } -+ } -+ return glyph_names; -+} -+ -+static void t1_check_end(PDF pdf) -+{ -+ if (t1_eof()) -+ return; -+ t1_getline(); -+ if (t1_prefix("{restore}")) -+ t1_putline(pdf); -+} -+ -+static boolean t1_open_fontfile(int open_name_prefix) -+{ -+ ff_entry *ff; -+ int callback_id = 0; -+ int file_opened = 0; -+ t1_curbyte = 0; -+ t1_size = 0; -+ ff = check_ff_exist(fd_cur->fm->ff_name, is_truetype(fd_cur->fm)); -+ if (ff->ff_path == NULL) { -+ formatted_error("type 1","cannot open file for reading '%s'",fd_cur->fm->ff_name); -+ return false; -+ } -+ cur_file_name = luatex_find_file(ff->ff_path, find_type1_file_callback); -+ if (cur_file_name == NULL) { -+ formatted_error("type 1","cannot open file for reading '%s'", ff->ff_path); -+ return false; -+ } -+ callback_id = callback_defined(read_type1_file_callback); -+ if (callback_id > 0) { -+ if (!run_callback(callback_id, "S->bSd", cur_file_name, &file_opened, &t1_buffer, &t1_size) -+ && file_opened && t1_size > 0) { -+ formatted_warning("type 1","cannot open file for reading '%s'",cur_file_name); -+ return false; -+ } -+ } else { -+ t1_file = xfopen(cur_file_name, FOPEN_RBIN_MODE); -+ t1_read_file(); -+ t1_close(); -+ } -+ recorder_record_input(cur_file_name); -+ t1_init_params(open_name_prefix); -+ return true; -+} -+ -+static void t1_include(PDF pdf) -+{ -+ do { -+ t1_getline(); -+ t1_scan_param(pdf); -+ t1_putline(pdf); -+ } -+ while (t1_in_eexec == 0); -+ t1_start_eexec(pdf); -+ do { -+ t1_getline(); -+ t1_scan_param(pdf); -+ t1_putline(pdf); -+ } -+ while (!(t1_charstrings() || t1_subrs())); -+ t1_cs = true; -+ do { -+ t1_getline(); -+ t1_putline(pdf); -+ } -+ while (!t1_end_eexec()); -+ t1_stop_eexec(pdf); -+ if (fixedcontent) { -+ /*tex Copy 512 zeros (not needed for \PDF). */ -+ do { -+ t1_getline(); -+ t1_putline(pdf); -+ } -+ while (!t1_cleartomark()); -+ /*tex Write |{restore} if| if found. */ -+ t1_check_end(pdf); -+ } -+ get_length3(); -+} -+ -+#define check_subr(subr) \ -+ if (subr >= subr_size || subr < 0) \ -+ formatted_error("type 1","Subrs array: entry index out of range '%i'", subr); -+ -+static const char **check_cs_token_pair(void) -+{ -+ const char **p = (const char **) cs_token_pairs_list; -+ for (; p[0] != NULL; ++p) -+ if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1])) -+ return p; -+ return NULL; -+} -+ -+static void cs_store(boolean is_subr) -+{ -+ char *p; -+ cs_entry *ptr; -+ int subr; -+ for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' '; -+ *t1_buf_ptr++ = *p++); -+ *t1_buf_ptr = 0; -+ if (is_subr) { -+ subr = (int) t1_scan_num(p + 1, 0); -+ check_subr(subr); -+ ptr = subr_tab + subr; -+ } else { -+ ptr = cs_ptr++; -+ if (cs_ptr - cs_tab > cs_size) -+ formatted_error("type 1","CharStrings dict: more entries than dict size '%i'", cs_size); -+ if (strcmp(t1_buf_array + 1, notdef) == 0) /* skip the slash */ -+ ptr->name = (char *) notdef; -+ else -+ ptr->name = xstrdup(t1_buf_array + 1); -+ } -+ /*tex Copy |" RD " + cs data| to |t1_buf_array|. */ -+ memcpy(t1_buf_array, t1_line_array + cs_start - 4, (unsigned) (t1_cslen + 4)); -+ /*tex Copy the end of cs data to |t1_buf_array|. */ -+ for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr = -+ t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++); -+ *t1_buf_ptr++ = 10; -+ if (is_subr && cs_token_pair == NULL) -+ cs_token_pair = check_cs_token_pair(); -+ ptr->len = (unsigned short) (t1_buf_ptr - t1_buf_array); -+ ptr->cslen = t1_cslen; -+ xfree(ptr->data); -+ ptr->data = xtalloc(ptr->len, byte); -+ memcpy(ptr->data, t1_buf_array, ptr->len); -+ ptr->valid = true; -+} -+ -+#define store_subr() cs_store(true) -+#define store_cs() cs_store(false) -+ -+#define CC_STACK_SIZE 24 -+ -+static int cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack; -+static cc_entry cc_tab[CS_MAX]; -+static boolean is_cc_init = false; -+ -+#define cc_pop(N) \ -+ if (stack_ptr - cc_stack < (N)) \ -+ stack_error(N); \ -+ stack_ptr -= N -+ -+#define stack_error(N) { \ -+ formatted_error("type 1","CharString: invalid access '%i' to stack, '%i' entries", (int) N, (int)(stack_ptr - cc_stack)); \ -+ goto cs_error; \ -+} -+ -+#define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N))) -+#define cc_push(V) *stack_ptr++ = V -+#define cc_clear() stack_ptr = cc_stack -+ -+#define set_cc(N, B, A, C) \ -+ cc_tab[N].nargs = A; \ -+ cc_tab[N].bottom = B; \ -+ cc_tab[N].clear = C; \ -+ cc_tab[N].valid = true -+ -+static void cc_init(void) -+{ -+ int i; -+ if (is_cc_init) -+ return; -+ for (i = 0; i < CS_MAX; i++) -+ cc_tab[i].valid = false; -+ set_cc(CS_HSTEM, true, 2, true); -+ set_cc(CS_VSTEM, true, 2, true); -+ set_cc(CS_VMOVETO, true, 1, true); -+ set_cc(CS_RLINETO, true, 2, true); -+ set_cc(CS_HLINETO, true, 1, true); -+ set_cc(CS_VLINETO, true, 1, true); -+ set_cc(CS_RRCURVETO, true, 6, true); -+ set_cc(CS_CLOSEPATH, false, 0, true); -+ set_cc(CS_CALLSUBR, false, 1, false); -+ set_cc(CS_RETURN, false, 0, false); -+ set_cc(CS_HSBW, true, 2, true); -+ set_cc(CS_ENDCHAR, false, 0, true); -+ set_cc(CS_RMOVETO, true, 2, true); -+ set_cc(CS_HMOVETO, true, 1, true); -+ set_cc(CS_VHCURVETO, true, 4, true); -+ set_cc(CS_HVCURVETO, true, 4, true); -+ set_cc(CS_DOTSECTION, false, 0, true); -+ set_cc(CS_VSTEM3, true, 6, true); -+ set_cc(CS_HSTEM3, true, 6, true); -+ set_cc(CS_SEAC, true, 5, true); -+ set_cc(CS_SBW, true, 4, true); -+ set_cc(CS_DIV, false, 2, false); -+ set_cc(CS_CALLOTHERSUBR, false, 0, false); -+ set_cc(CS_POP, false, 0, false); -+ set_cc(CS_SETCURRENTPOINT, true, 2, true); -+ is_cc_init = true; -+} -+ -+#define cs_getchar() cdecrypt(*data++, &cr) -+ -+#define mark_subr(n) cs_mark(0, n) -+#define mark_cs(s) cs_mark(s, 0) -+ -+static void cs_fail(const char *cs_name, int subr, const char *fmt, ...) -+{ -+ char buf[SMALL_BUF_SIZE]; -+ va_list args; -+ va_start(args, fmt); -+ vsprintf(buf, fmt, args); -+ va_end(args); -+ if (cs_name == NULL) -+ formatted_error("type 1","Subr '%i': %s", (int) subr, buf); -+ else -+ formatted_error("type 1","CharString (/%s): %s", cs_name, buf); -+} -+ -+/*tex Fix a return-less subr by appending |CS_RETURN|. */ -+ -+static void append_cs_return(cs_entry * ptr) -+{ -+ unsigned short cr; -+ int i; -+ byte *p, *q, *data, *new_data; -+ /*tex Decrypt the cs data to |t1_buf_array|, append |CS_RETURN|. */ -+ p = (byte *) t1_buf_array; -+ data = ptr->data + 4; -+ cr = 4330; -+ for (i = 0; i < ptr->cslen; i++) -+ *p++ = cs_getchar(); -+ *p = CS_RETURN; -+ /*tex Encrypt the new cs data to |new_data|. */ -+ new_data = xtalloc((unsigned) (ptr->len + 1), byte); -+ memcpy(new_data, ptr->data, 4); -+ p = new_data + 4; -+ q = (byte *) t1_buf_array; -+ cr = 4330; -+ for (i = 0; i < ptr->cslen + 1; i++) -+ *p++ = cencrypt(*q++, &cr); -+ memcpy(p, ptr->data + 4 + ptr->cslen, (size_t) (ptr->len - ptr->cslen - 4)); -+ /*tex Update |*ptr|. */ -+ xfree(ptr->data); -+ ptr->data = new_data; -+ ptr->len++; -+ ptr->cslen++; -+} -+ -+static void cs_mark(const char *cs_name, int subr) -+{ -+ byte *data; -+ int i, b, cs_len; -+ int last_cmd = 0; -+ int a, a1, a2; -+ unsigned short cr; -+ /*tex The argument of last call to |OtherSubrs[3]|. */ -+ static int lastargOtherSubr3 = 3; -+ cs_entry *ptr; -+ cc_entry *cc; -+ if (cs_name == NULL) { -+ check_subr(subr); -+ ptr = subr_tab + subr; -+ if (!ptr->valid) -+ return; -+ } else if (cs_notdef != NULL && (cs_name == notdef || strcmp(cs_name, notdef) == 0)) { -+ ptr = cs_notdef; -+ }else { -+ for (ptr = cs_tab; ptr < cs_ptr; ptr++) -+ if (strcmp(ptr->name, cs_name) == 0) -+ break; -+ if (ptr == cs_ptr) { -+ formatted_warning("type 1","glyph '%s' undefined", cs_name); -+ return; -+ } -+ if (ptr->name == notdef) -+ cs_notdef = ptr; -+ } -+ /*tex -+ Only marked CharString entries and invalid entries can be skipped; valid -+ marked subrs must be parsed to keep the stack in sync. -+ */ -+ if (!ptr->valid || (ptr->used && cs_name != NULL)) -+ return; -+ ptr->used = true; -+ cr = 4330; -+ cs_len = ptr->cslen; -+ data = ptr->data + 4; -+ for (i = 0; i < t1_lenIV; i++, cs_len--) -+ cs_getchar(); -+ while (cs_len > 0) { -+ --cs_len; -+ b = cs_getchar(); -+ if (b >= 32) { -+ if (b <= 246) -+ a = b - 139; -+ else if (b <= 250) { -+ --cs_len; -+ a = ((b - 247) << 8) + 108 + cs_getchar(); -+ } else if (b <= 254) { -+ --cs_len; -+ a = -((b - 251) << 8) - 108 - cs_getchar(); -+ } else { -+ cs_len -= 4; -+ a = (cs_getchar() & 0xff) << 24; -+ a |= (cs_getchar() & 0xff) << 16; -+ a |= (cs_getchar() & 0xff) << 8; -+ a |= (cs_getchar() & 0xff) << 0; -+ if (sizeof(int) > 4 && (a & 0x80000000)) -+ a |= ~0x7FFFFFFF; -+ } -+ cc_push(a); -+ } else { -+ if (b == CS_ESCAPE) { -+ b = cs_getchar() + CS_1BYTE_MAX; -+ cs_len--; -+ } -+ if (b >= CS_MAX) { -+ cs_fail(cs_name, subr, "command value out of range: %i", (int) b); -+ goto cs_error; -+ } -+ cc = cc_tab + b; -+ if (!cc->valid) { -+ cs_fail(cs_name, subr, "command not valid: %i", (int) b); -+ goto cs_error; -+ } -+ if (cc->bottom) { -+ if (stack_ptr - cc_stack < cc->nargs) -+ cs_fail(cs_name, subr, -+ "less arguments on stack '%i' than required '%i'", -+ (int) (stack_ptr - cc_stack), (int) cc->nargs); -+ else if (stack_ptr - cc_stack > cc->nargs) -+ cs_fail(cs_name, subr, -+ "more arguments on stack '%i' than required '%i'", -+ (int) (stack_ptr - cc_stack), (int) cc->nargs); -+ } -+ last_cmd = b; -+ switch (cc - cc_tab) { -+ case CS_CALLSUBR: -+ a1 = cc_get(-1); -+ cc_pop(1); -+ mark_subr(a1); -+ if (!subr_tab[a1].valid) { -+ cs_fail(cs_name, subr, "cannot call subr '%i'", (int) a1); -+ goto cs_error; -+ } -+ break; -+ case CS_DIV: -+ cc_pop(2); -+ cc_push(0); -+ break; -+ case CS_CALLOTHERSUBR: -+ if (cc_get(-1) == 3) -+ lastargOtherSubr3 = cc_get(-3); -+ a1 = cc_get(-2) + 2; -+ cc_pop(a1); -+ break; -+ case CS_POP: -+ cc_push(lastargOtherSubr3); -+ /*tex -+ The only case when we care about the value being pushed -+ onto stack is when |POP| follows |CALLOTHERSUBR| changing -+ hints by |OtherSubrs[3]|. -+ */ -+ break; -+ case CS_SEAC: -+ a1 = cc_get(3); -+ a2 = cc_get(4); -+ cc_clear(); -+ mark_cs(standard_glyph_names[a1]); -+ mark_cs(standard_glyph_names[a2]); -+ break; -+ default: -+ if (cc->clear) -+ cc_clear(); -+ } -+ } -+ } -+ if (cs_name == NULL && last_cmd != CS_RETURN) { -+ formatted_warning("type 1", -+ "last command in subr '%i' is not a RETURN; I will add it now but please consider fixing the font", -+ (int) subr); -+ append_cs_return(ptr); -+ } -+ return; -+ /*tex An error occured during parsing: */ -+ cs_error: -+ cc_clear(); -+ ptr->valid = false; -+ ptr->used = false; -+} -+ -+/* AVL search tree for glyph code by glyph name. */ -+ -+static int comp_t1_glyphs(const void *pa, const void *pb, void *p -+ __attribute__ ((unused))) -+{ -+ return strcmp(*(const char *const *) pa, *(const char *const *) pb); -+} -+ -+static struct avl_table *create_t1_glyph_tree(char **glyph_names) -+{ -+ int i; -+ void **aa; -+ static struct avl_table *gl_tree; -+ gl_tree = avl_create(comp_t1_glyphs, NULL, &avl_xallocator); -+ for (i = 0; i < 256; i++) { -+ if (glyph_names[i] != notdef && -+ (char **) avl_find(gl_tree, &glyph_names[i]) == NULL) { -+ /*tex No |strdup| here, just point to the |glyph_names| array members. */ -+ aa = avl_probe(gl_tree, &glyph_names[i]); -+ if (aa == NULL) { -+ /*tex Is this a problem? */ -+ } -+ } -+ } -+ return gl_tree; -+} -+ -+static void destroy_t1_glyph_tree(struct avl_table *gl_tree) -+{ -+ avl_destroy(gl_tree, NULL); -+} -+ -+static void t1_subset_ascii_part(PDF pdf) -+{ -+ int j, *p; -+ char *glyph, **gg, **glyph_names; -+ struct avl_table *gl_tree; -+ struct avl_traverser t; -+ void **aa; -+ t1_getline(); -+ while (!t1_prefix("/Encoding")) { -+ t1_scan_param(pdf); -+ t1_putline(pdf); -+ t1_getline(); -+ } -+ glyph_names = t1_builtin_enc(); -+ fd_cur->builtin_glyph_names = glyph_names; -+ if (is_subsetted(fd_cur->fm)) { -+ if (fd_cur->tx_tree != NULL) { -+ /*tex Take over collected non-reencoded characters from \TeX. */ -+ avl_t_init(&t, fd_cur->tx_tree); -+ for (p = (int *) avl_t_first(&t, fd_cur->tx_tree); p != NULL; -+ p = (int *) avl_t_next(&t)) { -+ if ((char *) avl_find(fd_cur->gl_tree, glyph_names[*p]) == NULL) { -+ glyph = xstrdup(glyph_names[*p]); -+ aa = avl_probe(fd_cur->gl_tree, glyph); -+ assert(aa != NULL); -+ } -+ } -+ } -+ make_subset_tag(fd_cur); -+ strncpy((char *) pdf->fb->data + t1_fontname_offset, fd_cur->subset_tag,6); -+ } -+ /*tex Now really all glyphs needed from this font are in the |fd_cur->gl_tree|. */ -+ if (t1_encoding == ENC_STANDARD) -+ t1_puts(pdf, "/Encoding StandardEncoding def\n"); -+ else { -+ t1_puts(pdf,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"); -+ gl_tree = create_t1_glyph_tree(glyph_names); -+ avl_t_init(&t, fd_cur->gl_tree); -+ j = 0; -+ for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL; -+ glyph = (char *) avl_t_next(&t)) { -+ if ((gg = (char **) avl_find(gl_tree, &glyph)) != NULL) { -+ t1_printf(pdf, "dup %i /%s put\n", (int) (gg - glyph_names),*gg); -+ j++; -+ } -+ } -+ destroy_t1_glyph_tree(gl_tree); -+ if (j == 0) { -+ /*tex -+ We didn't mark anything for the Encoding array. We add |{dup 0 -+ /.notdef put}| for compatibility with Acrobat 5.0. -+ */ -+ t1_puts(pdf, "dup 0 /.notdef put\n"); -+ } -+ t1_puts(pdf, "readonly def\n"); -+ } -+ do { -+ t1_getline(); -+ t1_scan_param(pdf); -+ if (!t1_prefix("/UniqueID")) { -+ /*tex Ignore |/UniqueID| for subsetted fonts. */ -+ t1_putline(pdf); -+ } -+ } -+ while (t1_in_eexec == 0); -+} -+ -+static void cs_init(void) -+{ -+ cs_ptr = cs_tab = NULL; -+ cs_dict_start = cs_dict_end = NULL; -+ cs_counter = cs_size = cs_size_pos = 0; -+ cs_token_pair = NULL; -+ subr_tab = NULL; -+ subr_array_start = subr_array_end = NULL; -+ subr_max = subr_size = subr_size_pos = 0; -+} -+ -+static void init_cs_entry(cs_entry * cs) -+{ -+ cs->data = NULL; -+ cs->name = NULL; -+ cs->len = 0; -+ cs->cslen = 0; -+ cs->used = false; -+ cs->valid = false; -+} -+ -+static void t1_read_subrs(PDF pdf) -+{ -+ int i, s; -+ cs_entry *ptr; -+ t1_getline(); -+ while (!(t1_charstrings() || t1_subrs())) { -+ t1_scan_param(pdf); -+ if (!t1_prefix("/UniqueID")) { -+ /*tex Ignore |/UniqueID| for subsetted fonts. */ -+ t1_putline(pdf); -+ } -+ t1_getline(); -+ } -+ found: -+ t1_cs = true; -+ t1_scan = false; -+ if (!t1_subrs()) -+ return; -+ subr_size_pos = strlen("/Subrs") + 1; -+ /*tex |subr_size_pos| points to the number indicating dict size after |Subrs|. */ -+ subr_size = (int) t1_scan_num(t1_line_array + subr_size_pos, 0); -+ if (subr_size == 0) { -+ while (!t1_charstrings()) -+ t1_getline(); -+ return; -+ } -+ subr_tab = xtalloc((unsigned) subr_size, cs_entry); -+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) -+ init_cs_entry(ptr); -+ subr_array_start = xstrdup(t1_line_array); -+ t1_getline(); -+ while (t1_cslen) { -+ store_subr(); -+ t1_getline(); -+ } -+ /*tex Mark the first four entries without parsing. */ -+ for (i = 0; i < subr_size && i < 4; i++) -+ subr_tab[i].used = true; -+ /*tex -+ -+ The end of the |Subrs| array might have more than one line so we need to -+ concatenate them to |subr_array_end|. Unfortunately some fonts don't have -+ the |Subrs| array followed by the |CharStrings| dict immediately (synthetic -+ fonts). If we cannot find |CharStrings| in next |POST_SUBRS_SCAN| lines -+ then we will treat the font as synthetic and ignore everything until next -+ |Subrs| is found. -+ -+ */ -+#define POST_SUBRS_SCAN 5 -+ s = 0; -+ *t1_buf_array = 0; -+ for (i = 0; i < POST_SUBRS_SCAN; i++) { -+ if (t1_charstrings()) -+ break; -+ s = (int) (s + t1_line_ptr - t1_line_array); -+ alloc_array(t1_buf, s, T1_BUF_SIZE); -+ strcat(t1_buf_array, t1_line_array); -+ t1_getline(); -+ } -+ subr_array_end = xstrdup(t1_buf_array); -+ if (i == POST_SUBRS_SCAN) { -+ /*tex |CharStrings| not found: assume a synthetic font. */ -+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) -+ if (ptr->valid) -+ xfree(ptr->data); -+ xfree(subr_tab); -+ xfree(subr_array_start); -+ xfree(subr_array_end); -+ cs_init(); -+ t1_cs = false; -+ t1_synthetic = true; -+ while (!(t1_charstrings() || t1_subrs())) -+ t1_getline(); -+ goto found; -+ } -+} -+ -+#define t1_subr_flush() t1_flush_cs(pdf, true) -+#define t1_cs_flush() t1_flush_cs(pdf, false) -+ -+static void t1_flush_cs(PDF pdf, boolean is_subr) -+{ -+ char *p; -+ byte *r, *return_cs = NULL; -+ cs_entry *tab, *end_tab, *ptr; -+ char *start_line, *line_end; -+ int count, size_pos; -+ unsigned short cr, cs_len; -+ if (is_subr) { -+ start_line = subr_array_start; -+ line_end = subr_array_end; -+ size_pos = subr_size_pos; -+ tab = subr_tab; -+ count = subr_max + 1; -+ end_tab = subr_tab + count; -+ } else { -+ start_line = cs_dict_start; -+ line_end = cs_dict_end; -+ size_pos = cs_size_pos; -+ tab = cs_tab; -+ end_tab = cs_ptr; -+ count = cs_counter; -+ } -+ t1_line_ptr = t1_line_array; -+ for (p = start_line; p - start_line < size_pos;) -+ *t1_line_ptr++ = *p++; -+ while (isdigit((unsigned char)*p)) -+ p++; -+ sprintf(t1_line_ptr, "%u", count); -+ strcat(t1_line_ptr, p); -+ t1_line_ptr = eol(t1_line_array); -+ t1_putline(pdf); -+ /*tex For |-Wall|. */ -+ cs_len = 0; -+ /*tex Create |return_cs| to replace unsused |subr|s. */ -+ if (is_subr) { -+ cr = 4330; -+ cs_len = 0; -+ /*tex -+ At this point we have |t1_lenIV >= 0;| a negative value would be -+ caught in |t1_scan_param|. -+ */ -+ return_cs = xtalloc((unsigned) (t1_lenIV + 1), byte); -+ for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++) -+ *r = cencrypt(0x00, &cr); -+ *r = cencrypt(CS_RETURN, &cr); -+ cs_len++; -+ } -+ for (ptr = tab; ptr < end_tab; ptr++) { -+ if (ptr->used) { -+ if (is_subr) -+ sprintf(t1_line_array, "dup %li %u", (long int) (ptr - tab), -+ ptr->cslen); -+ else -+ sprintf(t1_line_array, "/%s %u", ptr->name, ptr->cslen); -+ p = strend(t1_line_array); -+ memcpy(p, ptr->data, ptr->len); -+ t1_line_ptr = p + ptr->len; -+ t1_putline(pdf); -+ } else { -+ /*tex Replace unsused subr's by |return_cs|. */ -+ if (is_subr) { -+ sprintf(t1_line_array, "dup %li %u%s ", (long int) (ptr - tab), -+ cs_len, cs_token_pair[0]); -+ p = strend(t1_line_array); -+ memcpy(p, return_cs, cs_len); -+ t1_line_ptr = p + cs_len; -+ t1_putline(pdf); -+ sprintf(t1_line_array, " %s", cs_token_pair[1]); -+ t1_line_ptr = eol(t1_line_array); -+ t1_putline(pdf); -+ } -+ } -+ xfree(ptr->data); -+ if (is_subr) -+ ptr->valid = false; -+ if (ptr->name != notdef) -+ xfree(ptr->name); -+ } -+ sprintf(t1_line_array, "%s", line_end); -+ t1_line_ptr = eol(t1_line_array); -+ t1_putline(pdf); -+ if (is_subr) { -+ end_tab = subr_tab + subr_size; -+ for (ptr = tab; ptr < end_tab; ptr++) { -+ if (ptr->valid) { -+ xfree(ptr->data); -+ if (ptr->name != notdef) -+ xfree(ptr->name); -+ } -+ } -+ xfree(return_cs); -+ } -+ xfree(tab); -+ xfree(start_line); -+ xfree(line_end); -+} -+ -+static void t1_mark_glyphs(void) -+{ -+ char *glyph; -+ struct avl_traverser t; -+ cs_entry *ptr; -+ if (t1_synthetic || fd_cur->all_glyphs) { -+ /*tex Mark everything. */ -+ if (cs_tab != NULL) -+ for (ptr = cs_tab; ptr < cs_ptr; ptr++) -+ if (ptr->valid) -+ ptr->used = true; -+ if (subr_tab != NULL) { -+ for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) -+ if (ptr->valid) -+ ptr->used = true; -+ subr_max = subr_size - 1; -+ } -+ return; -+ } -+ mark_cs(notdef); -+ avl_t_init(&t, fd_cur->gl_tree); -+ for (glyph = (char *) avl_t_first(&t, fd_cur->gl_tree); glyph != NULL; -+ glyph = (char *) avl_t_next(&t)) { -+ mark_cs(glyph); -+ } -+ if (subr_tab != NULL) -+ for (subr_max = -1, ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) -+ if (ptr->used && ptr - subr_tab > subr_max) -+ subr_max = (int) (ptr - subr_tab); -+} -+ -+ -+/*tex -+ -+ When |t1_subset_charstrings| is called, the |t1_line_array| contains -+ |/CharStrings|. When we hit a case like this: -+ -+ \starttyping -+ dup/CharStrings -+ 229 dict dup begin -+ \stoptyping -+ -+ we read the next line and concatenate to |t1_line_array| before moving on. -+ That is what |t1_check_unusual_charstring| is for. -+ -+*/ -+ -+static void t1_check_unusual_charstring(void) -+{ -+ char *p = strstr(t1_line_array, charstringname) + strlen(charstringname); -+ int i; -+ /*tex If no number follows |/CharStrings|, let's read the next line. */ -+ if (sscanf(p, "%i", &i) != 1) { -+ strcpy(t1_buf_array, t1_line_array); -+ t1_getline(); -+ strcat(t1_buf_array, t1_line_array); -+ strcpy(t1_line_array, t1_buf_array); -+ t1_line_ptr = eol(t1_line_array); -+ } -+} -+ -+static void t1_subset_charstrings(PDF pdf) -+{ -+ cs_entry *ptr; -+ t1_check_unusual_charstring(); -+ cs_size_pos = (int) (strstr(t1_line_array, charstringname) + strlen(charstringname) - t1_line_array + 1); -+ /*tex |cs_size_pos| points to the number indicating dict size after |/CharStrings|. */ -+ cs_size = (int) t1_scan_num(t1_line_array + cs_size_pos, 0); -+ cs_ptr = cs_tab = xtalloc((unsigned) cs_size, cs_entry); -+ for (ptr = cs_tab; ptr - cs_tab < cs_size; ptr++) -+ init_cs_entry(ptr); -+ cs_notdef = NULL; -+ cs_dict_start = xstrdup(t1_line_array); -+ t1_getline(); -+ while (t1_cslen) { -+ store_cs(); -+ t1_getline(); -+ } -+ cs_dict_end = xstrdup(t1_line_array); -+ t1_mark_glyphs(); -+ if (subr_tab != NULL) { -+ if (cs_token_pair == NULL) -+ formatted_error("type 1","mismatched subroutine begin/end token pairs"); -+ t1_subr_flush(); -+ } -+ for (cs_counter = 0, ptr = cs_tab; ptr < cs_ptr; ptr++) -+ if (ptr->used) -+ cs_counter++; -+ t1_cs_flush(); -+} -+ -+static void t1_subset_end(PDF pdf) -+{ -+ if (t1_synthetic) { -+ /*tex Copy to |dup /FontName get exch definefont pop|. */ -+ while (!strstr(t1_line_array, "definefont")) { -+ t1_getline(); -+ t1_putline(pdf); -+ } -+ while (!t1_end_eexec()) { -+ /*tex Ignore the rest. */ -+ t1_getline(); -+ } -+ /*tex Write \.{mark currentfile closefile}. */ -+ t1_putline(pdf); -+ } else { -+ while (!t1_end_eexec()) { -+ /*tex Copy to \.{mark currentfile closefile}. */ -+ t1_getline(); -+ t1_putline(pdf); -+ } -+ } -+ t1_stop_eexec(pdf); -+ if (fixedcontent) { -+ /*tex Copy 512 zeros (not needed for PDF). */ -+ while (!t1_cleartomark()) { -+ t1_getline(); -+ t1_putline(pdf); -+ } -+ /*tex Don't check \.{{restore}if} for synthetic fonts. */ -+ if (!t1_synthetic) { -+ /*tex Write \.{{restore}if} if found. */ -+ t1_check_end(pdf); -+ } -+ } -+ get_length3(); -+} -+ -+void writet1(PDF pdf, fd_entry * fd) -+{ -+ /*tex |fd_cur| is global inside |writet1.c|. */ -+ fd_cur = fd; -+ assert(fd_cur->fm != NULL); -+ assert(is_type1(fd->fm)); -+ assert(is_included(fd->fm)); -+ -+ t1_save_offset = 0; -+ if (!is_subsetted(fd_cur->fm)) { -+ /*tex Include entire font. */ -+ if (!(fd->ff_found = t1_open_fontfile(filetype_font))) -+ return; -+ t1_include(pdf); -+ t1_close_font_file(filetype_font); -+ xfree(t1_buffer); -+ return; -+ } -+ /*tex Partial downloading. */ -+ if (!(fd->ff_found = t1_open_fontfile(filetype_subset))) -+ return; -+ t1_subset_ascii_part(pdf); -+ t1_start_eexec(pdf); -+ cc_init(); -+ cs_init(); -+ t1_read_subrs(pdf); -+ t1_subset_charstrings(pdf); -+ t1_subset_end(pdf); -+ t1_close_font_file(filetype_subset); -+ xfree(t1_buffer); -+} -+ -+void t1_free(void) -+{ -+ xfree(t1_line_array); -+ xfree(t1_buf_array); -+} diff --git a/SPECS/texlive.spec b/SPECS/texlive.spec index b7d1659..b090eb5 100644 --- a/SPECS/texlive.spec +++ b/SPECS/texlive.spec @@ -15,7 +15,7 @@ Name: texlive Version: %{source_date} -Release: 28%{?dist} +Release: 29%{?dist} Epoch: %{tl_epoch} Summary: TeX formatting system Group: Applications/Publishing @@ -54,6 +54,7 @@ BuildRequires: libtool BuildRequires: gmp-devel BuildRequires: mpfr-devel BuildRequires: chrpath +BuildRequires: dos2unix Requires: texlive-scheme-basic Requires: texlive-collection-latexrecommended @@ -882,6 +883,10 @@ Patch15: texlive-20180414-poppler-20.11.0-luatex.patch Patch16: texlive-xdvi-ghostcripts.patch Patch17: texlive-20180414-beamer-doc.patch +# upstream patch +# LuaTeX Security Vulnerabilities CVE-2023-32700 +Patch100: texlive-2018-luatex-CVE-2023-32700.patch + %description The TeX Live software distribution offers a complete TeX system for a variety of Unix, Macintosh, Windows and other platforms. It @@ -23821,25 +23826,27 @@ words. %setup -q -c -T xz -dc %{SOURCE0} | tar x [ -e %{source_name} ] && mv %{source_name} source -%patch1 -p0 -%patch2 -p1 -%patch3 -p1 -%patch5 -p0 +%patch -P1 -p0 +%patch -P2 -p1 +%patch -P3 -p1 +%patch -P5 -p0 %if 0%{?fedora} >= 28 || 0%{?rhel} >= 8 -%patch7 -p1 -b .newpoppler +%patch -P7 -p1 -b .newpoppler %endif -%patch11 -p1 -b .annocheck -%patch12 -p1 -%patch13 -p1 +%patch -P11 -p1 -b .annocheck +%patch -P12 -p1 +%patch -P13 -p1 pushd source -%patch15 -p1 -%patch16 -p1 +%patch -P15 -p1 +%patch -P16 -p1 popd # Setup copies of the licenses for l in `unxz -c %{SOURCE2} | tar t`; do ln -s %{_texdir}/licenses/$l $l done - +# covert to unix fileformat +dos2unix source/texk/web2c/luatexdir/lua/luatex-core.lua +%patch -P100 -p1 %build export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing -Werror=format-security" @@ -24644,26 +24651,22 @@ xz -dc %{SOURCE8033} | tar x -C %{buildroot}%{_texdir}/texmf-dist # Patches to component tarballs pushd %{buildroot}%{_texdir}/texmf-dist patch -p1 < %{_sourcedir}/texlive-20180414-tlmgr-ignore-warning.patch -# %%patch14 -p1 popd # XML validity pushd %{buildroot}%{_texdir}/texmf-dist/ patch -p0 < %{_sourcedir}/texlive-20180414-xml.patch -# %%patch8 -p0 rm -f doc/otherformats/xmltex/base/{englishutf16.xml,russiankoi8.xml} popd # support python3 and fix mangling shebang pushd %{buildroot}%{_texdir}/texmf-dist/ patch -p0 < %{_sourcedir}/texlive-2017-python3.patch -# %%patch9 -p0 popd # Patch beamer.doc pushd %{buildroot}%{_texdir}/texmf-dist/ patch -p0 < %{_sourcedir}/texlive-20180414-beamer-doc.patch -# %%patch17 -p0 popd # adjust python3 shebang to make it point at #!%%{_python3} @@ -27261,9 +27264,12 @@ fi %doc %{_texdir}/texmf-dist/doc/latex/translator/ %changelog -* Wed Jul 26 2023 MSVSphere Packaging Team - 7:20180414-28 +* Wed Jul 26 2023 MSVSphere Packaging Team - 7:20180414-29 - Rebuilt for MSVSphere 8.8 +* Thu May 25 2023 Than Ngo - 7:20180414-29 +- Resolves: #2209870, CVE-2023-32700 + * Mon Dec 12 2022 Than Ngo - 7:20180414-28 - Related: #2150727, fix rpminspect issues