summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/lua
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
committerKarl Berry <karl@freefriends.org>2021-02-25 19:22:25 +0000
commitad547a6b5986815fda458221149728d9d9ab1d87 (patch)
tree16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/luatexdir/lua
parent947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff)
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/lua')
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/helpers.c29
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lauxlib_bridge.h40
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lcallbacklib.c615
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lepdflib.cc19
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lepdflib.cc.orig2939
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lfontlib.c525
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/limglib.c857
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/liolibext.c1108
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lkpselib.c936
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/llanglib.c311
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/llualib.c425
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lnewtokenlib.c1413
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lnodelib.c9141
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/loslibext.c1073
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfelib.c1759
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdflib.c1398
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c1110
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lstatslib.c527
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/lstrlibext.c525
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/ltexiolib.c185
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/ltexlib.c3739
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luainit.c1212
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luanode.c467
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luastuff.c760
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatex-api.h2727
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatex-core.c676
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatex-core.lua490
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/luatoken.c585
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/mplibstuff.c115
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluac.c537
-rw-r--r--Build/source/texk/web2c/luatexdir/lua/texluajitc.c650
31 files changed, 36893 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/lua/helpers.c b/Build/source/texk/web2c/luatexdir/lua/helpers.c
new file mode 100644
index 00000000000..e7be7a2c2fe
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/helpers.c
@@ -0,0 +1,29 @@
+/*
+
+helpers.w
+
+Copyright 2017 LuaTeX team <bugs@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+We might move here some helpers common to code that are now in weird places,
+probably organized in texhelpers, luahelpers, pdfhelpers.
+
+*/
diff --git a/Build/source/texk/web2c/luatexdir/lua/lauxlib_bridge.h b/Build/source/texk/web2c/luatexdir/lua/lauxlib_bridge.h
new file mode 100644
index 00000000000..802ed6f6394
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lauxlib_bridge.h
@@ -0,0 +1,40 @@
+/*
+** lauxlib_bridge.h,
+** Auxiliary functions bridge from luatex lua5.2 luajit 2.0
+** See Copyright Notice in lua.h
+*/
+
+
+#ifndef lauxlib_bridge_h
+#define lauxlib_bridge_h
+
+#include "lauxlib.h"
+
+
+
+/* compatibility with luatex lua5.2 */
+/*
+#define LUA_OK 0
+#define LUA_OPEQ 0
+#define LUA_OPLT 1
+#define LUA_OPLE 2
+*/
+
+/* http://lua.2524044.n2.nabble.com/converting-modules-in-written-in-C-for-Lua-5-1-to-Lua-5-2-td7642941.html */
+#define luaL_setmetatable(L, tname) luaL_getmetatable(L, tname);lua_setmetatable(L, -2);
+
+
+
+LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
+LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
+LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) ;
+LUA_API int lua_compare (lua_State *L, int index1, int index2, int op);
+
+#if !defined(lua_lock)
+#define lua_lock(L) ((void) 0)
+#define lua_unlock(L) ((void) 0)
+#endif
+
+#define luaL_newlibtable(L,l) lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
+
+#endif
diff --git a/Build/source/texk/web2c/luatexdir/lua/lcallbacklib.c b/Build/source/texk/web2c/luatexdir/lua/lcallbacklib.c
new file mode 100644
index 00000000000..c4472c07f7f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lcallbacklib.c
@@ -0,0 +1,615 @@
+/* lcallbacklib.c
+
+ Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+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 };
+
+/* See also callback_callback_type in luatexcallbackids.h: they must have the same order ! */
+
+static const char *const callbacknames[] = {
+ "", /* empty on purpose */
+ "find_write_file",
+ "find_output_file",
+ "find_image_file",
+ "find_format_file",
+ "find_read_file", "open_read_file",
+ "find_vf_file", "read_vf_file",
+ "find_data_file", "read_data_file",
+ "find_font_file", "read_font_file",
+ "find_map_file", "read_map_file",
+ "find_enc_file", "read_enc_file",
+ "find_type1_file", "read_type1_file",
+ "find_truetype_file", "read_truetype_file",
+ "find_opentype_file", "read_opentype_file",
+ "find_cidmap_file", "read_cidmap_file",
+ "find_pk_file", "read_pk_file",
+ "show_error_hook",
+ "process_input_buffer", "process_output_buffer",
+ "process_jobname",
+ "start_page_number", "stop_page_number",
+ "start_run", "stop_run",
+ "define_font",
+ "pre_output_filter",
+ "buildpage_filter",
+ "hpack_filter", "vpack_filter",
+ "glyph_not_found", "glyph_info",
+ "hyphenate",
+ "ligaturing",
+ "kerning",
+ "pre_linebreak_filter",
+ "linebreak_filter",
+ "post_linebreak_filter",
+ "append_to_vlist_filter",
+ "mlist_to_hlist",
+ "finish_pdffile",
+ "finish_pdfpage",
+ "pre_dump","start_file", "stop_file",
+ "show_error_message","show_lua_error_hook",
+ "show_warning_message",
+ "hpack_quality", "vpack_quality",
+ "process_rule",
+ "insert_local_par",
+ "contribute_filter",
+ "call_edit",
+ "build_page_insert",
+ "glyph_stream_provider",
+ "font_descriptor_objnum_provider",
+ "finish_synctex",
+ "wrapup_run",
+ "new_graf",
+ "page_order_index",
+ "make_extensible",
+ "process_pdf_image_content",
+ "provide_charproc_data",
+ "input_level_string",
+ NULL
+};
+
+int callback_callbacks_id = 0;
+
+int debug_callback_defined(int i)
+{
+ printf ("callback_defined(%s)\n", callbacknames[i]);
+ return callback_set[i];
+}
+
+void get_lua_boolean(const char *table, const char *name, boolean * target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_getglobal(Luas, table);
+ if (lua_istable(Luas, -1)) {
+ int t;
+ lua_getfield(Luas, -1, name);
+ t = lua_type(Luas, -1);
+ if (t == LUA_TBOOLEAN) {
+ *target = (boolean) (lua_toboolean(Luas, -1));
+ } else if (t == LUA_TNUMBER) {
+ *target = (boolean) (lua_tointeger(Luas, -1) == 0 ? 0 : 1);
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+void get_saved_lua_boolean(int r, const char *name, boolean * target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
+ if (lua_istable(Luas, -1)) {
+ int t;
+ lua_getfield(Luas, -1, name);
+ t = lua_type(Luas, -1);
+ if (t == LUA_TBOOLEAN) {
+ *target = (boolean) lua_toboolean(Luas, -1);
+ } else if (t == LUA_TNUMBER) {
+ *target = (boolean) (lua_tointeger(Luas, -1) == 0 ? 0 : 1);
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+void get_lua_number(const char *table, const char *name, int *target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_getglobal(Luas, table);
+ if (lua_istable(Luas, -1)) {
+ lua_getfield(Luas, -1, name);
+ if (lua_type(Luas, -1) == LUA_TNUMBER) {
+ *target = (int) lua_roundnumber(Luas, -1); /* was lua_tointeger */
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+void get_saved_lua_number(int r, const char *name, int *target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
+ if (lua_istable(Luas, -1)) {
+ lua_getfield(Luas, -1, name);
+ if (lua_type(Luas, -1) == LUA_TNUMBER) {
+ *target = (int) lua_tointeger(Luas, -1);
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+void get_lua_string(const char *table, const char *name, char **target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_getglobal(Luas, table);
+ if (lua_type(Luas, -1) == LUA_TTABLE) {
+ lua_getfield(Luas, -1, name);
+ if (lua_type(Luas, -1) == LUA_TSTRING) {
+ *target = xstrdup(lua_tostring(Luas, -1));
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+void get_saved_lua_string(int r, const char *name, char **target)
+{
+ int stacktop = lua_gettop(Luas);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
+ if (lua_type(Luas, -1) == LUA_TTABLE) {
+ lua_getfield(Luas, -1, name);
+ if (lua_type(Luas, -1) == LUA_TSTRING) {
+ *target = xstrdup(lua_tostring(Luas, -1));
+ }
+ }
+ lua_settop(Luas, stacktop);
+ return;
+}
+
+#define CALLBACK_BOOLEAN 'b'
+#define CALLBACK_INTEGER 'd'
+#define CALLBACK_FLOAT 'f'
+#define CALLBACK_LINE 'l'
+#define CALLBACK_STRNUMBER 's'
+#define CALLBACK_STRING 'S'
+#define CALLBACK_RESULT 'R' /* a string but nil is also ok */
+#define CALLBACK_CHARNUM 'c'
+#define CALLBACK_LSTRING 'L'
+#define CALLBACK_NODE 'N'
+#define CALLBACK_DIR 'D'
+
+int run_saved_callback(int r, const char *name, const char *values, ...)
+{
+ va_list args;
+ int ret = 0;
+ int stacktop = lua_gettop(Luas);
+ va_start(args, values);
+ luaL_checkstack(Luas, 2, "out of stack space");
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, r);
+ lua_pushstring(Luas, name);
+ lua_rawget(Luas, -2);
+ if (lua_isfunction(Luas, -1)) {
+ saved_callback_count++;
+ ret = do_run_callback(2, values, args);
+ }
+ va_end(args);
+ lua_settop(Luas, stacktop);
+ return ret;
+}
+
+boolean get_callback(lua_State * L, int i)
+{
+ luaL_checkstack(L, 2, "out of stack space");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id);
+ lua_rawgeti(L, -1, i);
+ if (lua_isfunction(L, -1)) {
+ callback_count++;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int run_and_save_callback(int i, const char *values, ...)
+{
+ va_list args;
+ int ret = 0;
+ int stacktop = lua_gettop(Luas);
+ va_start(args, values);
+ if (get_callback(Luas, i)) {
+ ret = do_run_callback(1, values, args);
+ }
+ va_end(args);
+ if (ret > 0) {
+ ret = luaL_ref(Luas, LUA_REGISTRYINDEX);
+ }
+ lua_settop(Luas, stacktop);
+ return ret;
+}
+
+int run_callback(int i, const char *values, ...)
+{
+ va_list args;
+ int ret = 0;
+ int stacktop = lua_gettop(Luas);
+ va_start(args, values);
+ if (get_callback(Luas, i)) {
+ ret = do_run_callback(0, values, args);
+ }
+ va_end(args);
+ lua_settop(Luas, stacktop);
+ return ret;
+}
+
+int do_run_callback(int special, const char *values, va_list vl)
+{
+ int ret;
+ size_t len;
+ int narg, nres;
+ const char *s;
+ lstring *lstr;
+ char cs;
+ int *bufloc;
+ char *ss = NULL;
+ int retval = 0;
+ if (special == 2) { /* copy the enclosing table */
+ luaL_checkstack(Luas, 1, "out of stack space");
+ lua_pushvalue(Luas, -2);
+ }
+ ss = strchr(values, '>');
+ luaL_checkstack(Luas, (int) (ss - values + 1), "out of stack space");
+ ss = NULL;
+ for (narg = 0; *values; narg++) {
+ switch (*values++) {
+ case CALLBACK_CHARNUM: /* an ascii char! */
+ cs = (char) va_arg(vl, int);
+ lua_pushlstring(Luas, &cs, 1);
+ break;
+ case CALLBACK_STRING: /* C string */
+ s = va_arg(vl, char *);
+ lua_pushstring(Luas, s);
+ break;
+ case CALLBACK_LSTRING: /* 'lstring' */
+ lstr = va_arg(vl, lstring *);
+ lua_pushlstring(Luas, (const char *)lstr->s, lstr->l);
+ break;
+ case CALLBACK_INTEGER: /* int */
+ lua_pushinteger(Luas, va_arg(vl, int));
+ break;
+ case CALLBACK_FLOAT: /* double */
+ lua_pushnumber(Luas, va_arg(vl, double));
+ break;
+ case CALLBACK_STRNUMBER: /* TeX string */
+ s = makeclstring(va_arg(vl, int), &len);
+ lua_pushlstring(Luas, s, len);
+ break;
+ case CALLBACK_BOOLEAN: /* boolean */
+ lua_pushboolean(Luas, va_arg(vl, int));
+ break;
+ case CALLBACK_LINE: /* a buffer section, with implied start */
+ lua_pushlstring(Luas, (char *) (buffer + first), (size_t) va_arg(vl, int));
+ break;
+ case CALLBACK_NODE:
+ lua_nodelib_push_fast(Luas, va_arg(vl, int));
+ break;
+ case CALLBACK_DIR:
+ lua_push_dir_par(Luas, va_arg(vl, int));
+ break;
+ case '-':
+ narg--;
+ break;
+ case '>':
+ goto ENDARGS;
+ default:
+ ;
+ }
+ }
+ ENDARGS:
+ nres = (int) strlen(values);
+ if (special == 1) {
+ nres++;
+ }
+ if (special == 2) {
+ narg++;
+ }
+ {
+ int i;
+ lua_active++;
+ i = lua_pcall(Luas, narg, nres, 0);
+ lua_active--;
+ /* lua_remove(L, base); *//* remove traceback function */
+ if (i != 0) {
+ /* Can't be more precise here, could be called before
+ * TeX initialization is complete
+ */
+ if (!log_opened_global) {
+ fprintf(stderr, "error in callback: %s\n", lua_tostring(Luas, -1));
+ error();
+ } else {
+ lua_gc(Luas, LUA_GCCOLLECT, 0);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ }
+ return 0;
+ }
+ }
+ if (nres == 0) {
+ return 1;
+ }
+ nres = -nres;
+ while (*values) {
+ int b, t;
+ double d;
+ halfword p;
+ t = lua_type(Luas, nres);
+ switch (*values++) {
+ case CALLBACK_BOOLEAN:
+ if (t == LUA_TNIL) {
+ b = 0;
+ } else if (t != LUA_TBOOLEAN) {
+ fprintf(stderr, "callback should return a boolean, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ } else {
+ b = lua_toboolean(Luas, nres);
+ }
+ *va_arg(vl, boolean *) = (boolean) b;
+ break;
+ case CALLBACK_INTEGER:
+ if (t != LUA_TNUMBER) {
+ fprintf(stderr, "callback should return a number, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ b = lua_tointeger(Luas, nres);
+ *va_arg(vl, int *) = b;
+ break;
+ case CALLBACK_FLOAT:
+ if (t != LUA_TNUMBER) {
+ fprintf(stderr, "callback should return a number, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ d = lua_tonumber(Luas, nres);
+ *va_arg(vl, double *) = d;
+ break;
+ case CALLBACK_LINE: /* TeX line ... happens frequently when we have a plug-in */
+ if (t == LUA_TNIL) {
+ bufloc = 0;
+ goto EXIT;
+ } else if (t == LUA_TSTRING) {
+ s = lua_tolstring(Luas, nres, &len);
+ if (s == NULL) { /* |len| can be zero */
+ bufloc = 0;
+ } else if (len == 0) {
+ bufloc = 0;
+ } else {
+ bufloc = va_arg(vl, int *);
+ ret = *bufloc;
+ check_buffer_overflow(ret + (int) len);
+ strncpy((char *) (buffer + ret), s, len);
+ *bufloc += (int) len;
+ /* while (len--) { buffer[(*bufloc)++] = *s++; } */
+ while ((*bufloc) - 1 > ret && buffer[(*bufloc) - 1] == ' ')
+ (*bufloc)--;
+ }
+ } else {
+ fprintf(stderr, "callback should return a string, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ break;
+ case CALLBACK_STRNUMBER: /* TeX string */
+ if (t != LUA_TSTRING) {
+ fprintf(stderr, "callback should return a string, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ s = lua_tolstring(Luas, nres, &len);
+ if (s == NULL) /* |len| can be zero */
+ *va_arg(vl, int *) = 0;
+ else {
+ *va_arg(vl, int *) = maketexlstring(s, len);
+ }
+ break;
+ case CALLBACK_STRING: /* C string aka buffer */
+ if (t != LUA_TSTRING) {
+ fprintf(stderr, "callback should return a string, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ s = lua_tolstring(Luas, nres, &len);
+ if (s == NULL) /* |len| can be zero */
+ *va_arg(vl, int *) = 0;
+ else {
+ ss = xmalloc((unsigned) (len + 1));
+ (void) memcpy(ss, s, (len + 1));
+ *va_arg(vl, char **) = ss;
+ }
+ break;
+ case CALLBACK_RESULT: /* C string aka buffer */
+ if (t == LUA_TNIL) {
+ *va_arg(vl, int *) = 0;
+ } else if (t == LUA_TBOOLEAN) {
+ b = lua_toboolean(Luas, nres);
+ if (b == 0) {
+ *va_arg(vl, int *) = 0;
+ } else {
+ fprintf(stderr, "callback should return a string, false or nil, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ } else if (t != LUA_TSTRING) {
+ fprintf(stderr, "callback should return a string, false or nil, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ } else {
+ s = lua_tolstring(Luas, nres, &len);
+ if (s == NULL) /* |len| can be zero */
+ *va_arg(vl, int *) = 0;
+ else {
+ ss = xmalloc((unsigned) (len + 1));
+ (void) memcpy(ss, s, (len + 1));
+ *va_arg(vl, char **) = ss;
+ }
+ }
+ break;
+ case CALLBACK_LSTRING: /* lstring */
+ if (t != LUA_TSTRING) {
+ fprintf(stderr, "callback should return a string, not: %s\n", lua_typename(Luas, t));
+ goto EXIT;
+ }
+ s = lua_tolstring(Luas, nres, &len);
+ if (s == NULL) /* |len| can be zero */
+ *va_arg(vl, int *) = 0;
+ else {
+ lstring *ret = xmalloc(sizeof(lstring));
+ ret->s = xmalloc((unsigned) (len + 1));
+ (void) memcpy(ret->s, s, (len + 1));
+ ret->l = len;
+ *va_arg(vl, lstring **) = ret;
+ }
+ break;
+ case CALLBACK_NODE:
+ if (t == LUA_TNIL) {
+ p = null;
+ } else {
+ p = *check_isnode(Luas,nres);
+ }
+ *va_arg(vl, int *) = p;
+ break;
+ default:
+ fprintf(stdout, "callback returned an invalid value type");
+ goto EXIT;
+ }
+ nres++;
+ }
+ retval = 1;
+ EXIT:
+ return retval;
+}
+
+void destroy_saved_callback(int i)
+{
+ luaL_unref(Luas, LUA_REGISTRYINDEX, i);
+}
+
+static int callback_register(lua_State * L)
+{
+ int cb;
+ const char *s;
+ int t1 = lua_type(L,1);
+ int t2 = lua_type(L,2);
+ if (t1 != LUA_TSTRING) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Invalid arguments to callback.register, first argument must be string.");
+ return 2;
+ }
+ if ((t2 != LUA_TFUNCTION) && (t2 != LUA_TNIL) && ((t2 != LUA_TBOOLEAN) && (lua_toboolean(L, 2) == 0))) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Invalid arguments to callback.register.");
+ return 2;
+ }
+ s = lua_tostring(L, 1);
+ for (cb = 0; cb < total_callbacks; cb++) {
+ if (strcmp(callbacknames[cb], s) == 0)
+ break;
+ }
+ if (cb == total_callbacks) {
+ lua_pushnil(L);
+ lua_pushstring(L, "No such callback exists.");
+ return 2;
+ }
+ if (t2 == LUA_TFUNCTION) {
+ callback_set[cb] = cb;
+ } else if (t2 == LUA_TBOOLEAN) {
+ callback_set[cb] = -1;
+ } else {
+ callback_set[cb] = 0;
+ }
+ luaL_checkstack(L, 2, "out of stack space");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id); /* push the table */
+ lua_pushvalue(L, 2); /* the function or nil */
+ lua_rawseti(L, -2, cb);
+ lua_rawseti(L, LUA_REGISTRYINDEX, callback_callbacks_id);
+ lua_pushinteger(L, cb);
+ return 1;
+}
+
+static int callback_find(lua_State * L)
+{
+ int cb;
+ const char *s;
+ if (lua_type(L, 1) != LUA_TSTRING) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Invalid arguments to callback.find.");
+ return 2;
+ }
+ s = lua_tostring(L, 1);
+ for (cb = 0; cb < total_callbacks; cb++) {
+ if (strcmp(callbacknames[cb], s) == 0)
+ break;
+ }
+ if (cb == total_callbacks) {
+ lua_pushnil(L);
+ lua_pushstring(L, "No such callback exists.");
+ return 2;
+ }
+ luaL_checkstack(L, 2, "out of stack space");
+ lua_rawgeti(L, LUA_REGISTRYINDEX, callback_callbacks_id); /* push the table */
+ lua_rawgeti(L, -1, cb);
+ return 1;
+}
+
+static int callback_listf(lua_State * L)
+{
+ int i;
+ luaL_checkstack(L, 3, "out of stack space");
+ lua_newtable(L);
+ for (i = 1; callbacknames[i]; i++) {
+ lua_pushstring(L, callbacknames[i]);
+ if (callback_defined(i)) {
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
+static const struct luaL_Reg callbacklib[] = {
+ {"find", callback_find},
+ {"register", callback_register},
+ {"list", callback_listf},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_callback(lua_State * L)
+{
+ luaL_register(L, "callback", callbacklib);
+ luaL_checkstack(L, 1, "out of stack space");
+ lua_newtable(L);
+ callback_callbacks_id = luaL_ref(L, LUA_REGISTRYINDEX);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc b/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc
new file mode 100644
index 00000000000..ea8ed96b051
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc
@@ -0,0 +1,19 @@
+/* lepdflib.cc
+
+ Copyright 2009-2015 Taco Hoekwater <taco@luatex.org>
+ Copyright 2009-2013 Hartmut Henkel <hartmut@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
diff --git a/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc.orig b/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc.orig
new file mode 100644
index 00000000000..ec5c90e8e00
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lepdflib.cc.orig
@@ -0,0 +1,2939 @@
+/* lepdflib.cc
+
+ Copyright 2009-2015 Taco Hoekwater <taco@luatex.org>
+ Copyright 2009-2013 Hartmut Henkel <hartmut@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+
+#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 */
+
+/* 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);
+
+/* These two can go away as we don't change the document. */
+
+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;
+}
+
+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
+}
+
+#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 const struct luaL_Reg epdflib_f[] = {
+ {"open", l_open_PDFDoc},
+ {"openMemStream", l_open_MemStreamPDFDoc},
+ {"StructElement_Type", l_StructElement_Type},
+ {"Attribute_Type", l_Attribute_Type},
+ {"AttributeOwner_Type",l_AttributeOwner_Type},
+ {"Object_Type", l_Object_Type},
+ {NULL, NULL}
+};
+
+#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 = ((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}
+};
+
+/* 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}
+};
+
+/* Array */
+
+m_poppler_get_INT(Array, getLength);
+
+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[] = {
+ {"getLength", m_Array_getLength},
+ {"get", m_Array_get},
+ {"getNF", m_Array_getNF},
+ {"getString", m_Array_getString},
+ {"__tostring", m_Array__tostring},
+ {NULL, NULL}
+};
+
+/* 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}
+};
+
+/* Dict */
+
+m_poppler_get_INT(Dict, getLength);
+
+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[] = {
+ {"getLength", m_Dict_getLength},
+ {"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}
+};
+
+/* 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}
+};
+
+/* 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}
+};
+
+/* 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}
+};
+
+/* 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}
+};
+
+/* Links */
+
+m_poppler_get_INT(Links, getNumLinks);
+
+m_poppler__tostring(Links);
+
+static const struct luaL_Reg Links_m[] = {
+ {"getNumLinks", m_Links_getNumLinks},
+ {"__tostring", m_Links__tostring},
+ {NULL, NULL}
+};
+
+/* 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_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 = ((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_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_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[] = {
+ {"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},
+ {"arrayGet", m_Object_arrayGet},
+ {"arrayGetNF", m_Object_arrayGetNF},
+ {"dictGetLength", m_Object_dictGetLength},
+ {"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},
+ {"streamGetChar", m_Object_streamGetChar},
+ {"streamLookChar", m_Object_streamLookChar},
+ {"streamGetPos", m_Object_streamGetPos},
+ {"streamSetPos", m_Object_streamSetPos},
+ {"streamGetDict", m_Object_streamGetDict},
+ {"__tostring", m_Object__tostring},
+ {"__gc", m_Object__gc},
+ {NULL, NULL}
+};
+
+/* 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}
+};
+
+/* 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},
+ {"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},
+ {NULL, NULL}
+};
+
+/* 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}
+};
+
+/* 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},
+ {NULL, NULL}
+};
+
+/* 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},
+ {"getPos", m_Stream_getPos},
+ {"isBinary", m_Stream_isBinary},
+ {"getUndecodedStream", m_Stream_getUndecodedStream},
+ {"getDict", m_Stream_getDict},
+ {"__tostring", m_Stream__tostring},
+ {NULL, NULL}
+};
+
+/* 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}
+};
+
+/* 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);
+
+m_poppler_get_BOOL(Attribute, isHidden);
+
+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__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},
+ {"isHidden",m_Attribute_isHidden},
+ {"getFormattedValue",m_Attribute_getFormattedValue},
+ {"__gc", m_Attribute__gc},
+ {"__tostring", m_Attribute__tostring},
+ {NULL, NULL}
+};
+
+/* 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++ function 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_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_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_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},
+ {"getTitle",m_StructElement_getTitle},
+ {"getExpandedAbbr",m_StructElement_getExpandedAbbr},
+ {"getNumChildren",m_StructElement_getNumChildren},
+ {"getChild",m_StructElement_getChild},
+ {"getNumAttributes",m_StructElement_getNumAttributes},
+ {"getAttribute",m_StructElement_getAttribute},
+ {"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}
+};
+
+/* 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_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},
+ {"findParentElement",m_StructTreeRoot_findParentElement},
+ {"__tostring", m_StructTreeRoot__tostring},
+ {NULL, NULL}
+};
+
+/* 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);
+
+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},
+ {"getNumEntry", m_XRef_getNumEntry},
+ {"getTrailerDict", m_XRef_getTrailerDict},
+ {"__tostring", m_XRef__tostring},
+ {NULL, NULL}
+};
+
+/* XRefEntry */
+
+m_poppler__tostring(XRefEntry);
+
+static const struct luaL_Reg XRefEntry_m[] = {
+ {"__tostring", m_XRefEntry__tostring},
+ {NULL, NULL}
+};
+
+/* Done */
+
+#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/Build/source/texk/web2c/luatexdir/lua/lfontlib.c b/Build/source/texk/web2c/luatexdir/lua/lfontlib.c
new file mode 100644
index 00000000000..92d60a80c7d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lfontlib.c
@@ -0,0 +1,525 @@
+/* lfontlib.c
+
+ Copyright 2006-2014 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define TIMERS 0
+
+#if TIMERS
+# include <sys/time.h>
+#endif
+
+static int get_fontid(void)
+{
+ if (font_tables == NULL || font_tables[0] == NULL) {
+ create_null_font();
+ }
+ return new_font();
+}
+
+static int font_read_tfm(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ const char *cnom = lua_tostring(L, 1);
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ scaled s = (int) lua_roundnumber(L, 2);
+ if (strlen(cnom)) {
+ internal_font_number f = get_fontid();
+ if (read_tfm_info(f, cnom, s)) {
+ int k = font_to_lua(L, f, 0);
+ delete_font(f);
+ return k;
+ } else {
+ delete_font(f);
+ luaL_error(L, "font loading failed");
+ }
+ } else {
+ luaL_error(L, "expected tfm name as first argument");
+ }
+ } else {
+ luaL_error(L, "expected an integer size as second argument");
+ }
+ } else {
+ luaL_error(L, "expected tfm name as first argument");
+ }
+ return 2; /* not reached */
+}
+
+
+static int font_read_vf(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ const char *cnom = lua_tostring(L, 1);
+ if (strlen(cnom)) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ int i = lua_roundnumber(L, 2);
+ return make_vf_table(L, cnom, (scaled) i);
+ } else {
+ luaL_error(L, "expected an integer size as second argument");
+ return 2;
+ }
+ }
+ }
+ luaL_error(L, "expected vf name as first argument");
+ return 2; /* not reached */
+}
+
+static int tex_current_font(lua_State * L)
+{
+ int i = luaL_optinteger(L, 1, 0);
+ if (i > 0) {
+ if (is_valid_font(i)) {
+ zset_cur_font(i);
+ return 0;
+ } else {
+ luaL_error(L, "expected a valid font id");
+ return 2; /* not reached */
+ }
+ } else {
+ lua_pushinteger(L, get_cur_font());
+ return 1;
+ }
+}
+
+static int tex_max_font(lua_State * L)
+{
+ lua_pushinteger(L, max_font_id());
+ return 1;
+}
+
+
+static int tex_each_font_next(lua_State * L)
+{
+ int m = lua_tointeger(L, 1);
+ int i = lua_tointeger(L, 2);
+ i++;
+ while (i <= m && !is_valid_font(i))
+ i++;
+ if (i > m) {
+ lua_pushnil(L);
+ return 1;
+ } else {
+ lua_pushinteger(L, i);
+ if (!font_to_lua(L, i, 1))
+ lua_pushnil(L);
+ return 2;
+ }
+}
+
+static int tex_each_font(lua_State * L)
+{
+ lua_pushcclosure(L, tex_each_font_next, 0);
+ lua_pushinteger(L, max_font_id());
+ lua_pushinteger(L, 0);
+ return 3;
+}
+
+static int frozenfont(lua_State * L)
+{
+ int i = luaL_checkinteger(L, 1);
+ if (i) {
+ if (is_valid_font(i)) {
+ if (font_touched(i) || font_used(i)) {
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ } else {
+ luaL_error(L, "expected an integer argument");
+ }
+ return 0; /* not reached */
+}
+
+
+static int setfont(lua_State * L)
+{
+ int t = lua_gettop(L);
+ int i = luaL_checkinteger(L,1);
+ if (i) {
+ luaL_checktype(L, t, LUA_TTABLE);
+ if (is_valid_font(i)) {
+ if (! (font_touched(i) || font_used(i))) {
+ font_from_lua(L, i);
+ } else {
+ luaL_error(L, "that font has been accessed already, changing it is forbidden");
+ }
+ } else {
+ luaL_error(L, "that integer id is not a valid font");
+ }
+ }
+ return 0;
+}
+
+static int addcharacters(lua_State * L)
+{
+ int t = lua_gettop(L);
+ int i = luaL_checkinteger(L,1);
+ if (i) {
+ luaL_checktype(L, t, LUA_TTABLE);
+ if (is_valid_font(i)) {
+ characters_from_lua(L, i);
+ } else {
+ luaL_error(L, "that integer id is not a valid font");
+ }
+ }
+ return 0;
+}
+
+static int setexpansion(lua_State * L)
+{
+ int f = luaL_checkinteger(L,1);
+ if (f) {
+ if (is_valid_font(f)) {
+ int fstretch = luaL_checkinteger(L,2);
+ int fshrink = luaL_checkinteger(L,3);
+ int fstep = luaL_checkinteger(L,4);
+ set_expand_params(f, fstretch, fshrink, fstep);
+ } else {
+ luaL_error(L, "that integer id is not a valid font");
+ }
+ }
+ return 0;
+}
+
+/* font.define(id,table) */
+/* font.define(table) */
+
+static int deffont(lua_State * L)
+{
+ int i = 0;
+ int t = lua_gettop(L);
+ if (t == 2) {
+ i = lua_tointeger(L,1);
+ if ((i <= 0) || ! is_valid_font(i)) {
+ lua_pop(L, 1); /* pop the broken table */
+ luaL_error(L, "font creation failed, invalid id passed");
+ }
+ } else if (t == 1) {
+ i = get_fontid();
+ } else {
+ luaL_error(L, "font creation failed, no table passed");
+ return 0;
+ }
+ luaL_checktype(L, -1, LUA_TTABLE);
+ if (font_from_lua(L, i)) {
+ lua_pushinteger(L, i);
+ return 1;
+ } else {
+ lua_pop(L, 1); /* pop the broken table */
+ delete_font(i);
+ luaL_error(L, "font creation failed, error in table");
+ }
+ return 0; /* not reached */
+}
+
+/* this returns the expected (!) next fontid. */
+/* first arg true will keep the id */
+
+static int nextfontid(lua_State * L)
+{
+ int b = ((lua_gettop(L) == 1) && lua_toboolean(L,1));
+ int i = get_fontid();
+ lua_pushinteger(L, i);
+ if (b == 0) {
+ delete_font(i);
+ }
+ return 1;
+}
+
+static int getfont(lua_State * L)
+{
+ int i = luaL_checkinteger(L, -1);
+ if (i && is_valid_font(i) && font_to_lua(L, i, 1))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int getcopy(lua_State * L)
+{
+ int i = luaL_checkinteger(L, -1);
+ if (i && is_valid_font(i) && font_to_lua(L, i, 0))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int getparameters(lua_State * L)
+{
+ int i = luaL_checkinteger(L, -1);
+ if (i && is_valid_font(i)) {
+ return font_parameters_to_lua(L,i);
+ }
+ return 0;
+}
+
+static int getfontid(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ size_t ff;
+ const char *s = lua_tolstring(L, 1, &ff);
+ int cs = string_lookup(s, ff);
+ int f;
+ if (cs == undefined_control_sequence || cs == undefined_cs_cmd || eq_type(cs) != set_font_cmd) {
+ lua_pushstring(L, "not a valid font csname");
+ f = -1;
+ } else {
+ f = equiv(cs);
+ }
+ lua_pushinteger(L, f);
+ } else {
+ luaL_error(L, "expected font csname string as argument");
+ }
+ return 1;
+}
+
+static const struct luaL_Reg fontlib[] = {
+ {"read_tfm", font_read_tfm},
+ {"read_vf", font_read_vf},
+ {"current", tex_current_font},
+ {"max", tex_max_font},
+ {"each", tex_each_font},
+ {"getfont", getfont},
+ {"getcopy", getcopy},
+ {"getparameters", getparameters},
+ {"setfont", setfont},
+ {"addcharacters", addcharacters},
+ {"setexpansion", setexpansion},
+ {"define", deffont},
+ {"nextid", nextfontid},
+ {"id", getfontid},
+ {"frozen", frozenfont},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_font(lua_State * L)
+{
+ luaL_openlib(L, "font", fontlib, 0);
+ make_table(L, "fonts", "tex.fonts", "getfont", "setfont");
+ return 1;
+}
+
+/**********************************************************************/
+/* "vf" library: Lua functions within virtual fonts */
+
+static int l_vf_char(lua_State * L)
+{
+ int k, w;
+ vf_struct *vsp = static_pdf->vfstruct;
+ packet_stack_record *mat_p;
+ internal_font_number lf = vsp->lf;
+ int ex_glyph = vsp->ex_glyph/1000;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.char() outside virtual font");
+ k = luaL_checkinteger(L, 1);
+ if (!char_exists(lf, k)) {
+ char_warning(lf, k);
+ } else {
+ if (has_packet(lf, k))
+ do_vf_packet(static_pdf, lf, k, ex_glyph);
+ else
+ backend_out[glyph_node] (static_pdf, lf, k, ex_glyph);
+ }
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ w = char_width(lf, k);
+ 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;
+}
+
+static int l_vf_down(lua_State * L)
+{
+ scaled i;
+ vf_struct *vsp = static_pdf->vfstruct;
+ packet_stack_record *mat_p;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.down() outside virtual font");
+ i = (scaled) luaL_checkinteger(L, 1);
+ i = store_scaled_f(i, vsp->fs_f);
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ mat_p->pos.v += i;
+ synch_pos_with_cur(static_pdf->posstruct, vsp->refpos, mat_p->pos);
+ return 0;
+}
+
+static int l_vf_fontid(lua_State * L)
+{
+ vf_struct *vsp = static_pdf->vfstruct;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.fontid() outside virtual font");
+ vsp->lf = (int) luaL_checkinteger(L, 1);
+ return 0;
+}
+
+static int l_vf_image(lua_State * L)
+{
+ int k;
+ vf_struct *vsp = static_pdf->vfstruct;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.image() outside virtual font");
+ k = (int) luaL_checkinteger(L, 1);
+ vf_out_image(static_pdf, k);
+ return 0;
+}
+
+static int l_vf_node(lua_State * L)
+{
+ int k;
+ vf_struct *vsp = static_pdf->vfstruct;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.node() outside virtual font");
+ k = (int) luaL_checkinteger(L, 1);
+ hlist_out(static_pdf, (halfword) k, 0);
+ return 0;
+}
+
+static int l_vf_nop(lua_State * L)
+{
+ vf_struct *vsp = static_pdf->vfstruct;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.nop() outside virtual font");
+ return 0;
+}
+
+static int l_vf_pop(lua_State * L)
+{
+ vf_struct *vsp = static_pdf->vfstruct;
+ packet_stack_record *mat_p;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.pop() outside virtual font");
+ if (vsp->packet_stack_level == vsp->packet_stack_minlevel)
+ normal_error("vf", "packet_stack_level underflow");
+ vsp->packet_stack_level--;
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ synch_pos_with_cur(static_pdf->posstruct, vsp->refpos, mat_p->pos);
+ return 0;
+}
+
+static int l_vf_push(lua_State * L)
+{
+ vf_struct *vsp = static_pdf->vfstruct;
+ packet_stack_record *mat_p;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.push() outside virtual font");
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ vsp->packet_stack_level++;
+ if (vsp->packet_stack_level == packet_stack_size)
+ normal_error("vf", "packet_stack_level overflow");
+ vsp->packet_stack[vsp->packet_stack_level] = *mat_p;
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ return 0;
+}
+
+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);
+ return 0;
+}
+
+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)
+ backend_out[rule_node](static_pdf, 0, size); /* the 0 is unused */
+ mat_p = &(vsp->packet_stack[vsp->packet_stack_level]);
+ mat_p->pos.h += size.h;
+ synch_pos_with_cur(static_pdf->posstruct, vsp->refpos, mat_p->pos);
+ return 0;
+}
+
+static int l_vf_special(lua_State * L)
+{
+ const_lstring st;
+ int texstr;
+ vf_struct *vsp = static_pdf->vfstruct;
+ if (!vsp->vflua)
+ normal_error("vf", "vf.special() outside virtual font");
+ st.s = lua_tolstring(L, 1, &(st.l));
+ texstr = maketexlstring(st.s, st.l);
+ pdf_literal(static_pdf, texstr, scan_special, false);
+ flush_str(texstr);
+ 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},
+ /* {"font", l_vf_font}, */
+ {"fontid", l_vf_fontid},
+ {"image", l_vf_image},
+ /* {"lua", l_vf_lua}, */
+ {"node", l_vf_node},
+ {"nop", l_vf_nop},
+ {"pop", l_vf_pop},
+ {"push", l_vf_push},
+ {"right", l_vf_right},
+ {"rule", l_vf_rule},
+ /* {"scale", l_vf_scale}, */
+ /* {"slot", l_vf_slot}, */
+ {"special", l_vf_special},
+ {"pdf", l_vf_pdf},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_vf(lua_State * L)
+{
+ luaL_openlib(L, "vf", vflib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/limglib.c b/Build/source/texk/web2c/luatexdir/lua/limglib.c
new file mode 100644
index 00000000000..734e591a4d3
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/limglib.c
@@ -0,0 +1,857 @@
+/* limglib.c
+
+ Copyright 2006-2013 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#include <stdio.h>
+#include <string.h>
+#include "lua.h"
+#include "lauxlib.h"
+
+#define img_types_max 8
+
+const char *img_types[] = {
+ "none",
+ "pdf",
+ "png",
+ "jpg",
+ "jp2",
+ "jbig2",
+ "stream",
+ "memstream",
+ "rawstream",
+ NULL
+};
+
+static void copy_image(lua_State * L, lua_Number scale)
+{
+ image *a, **aa, *b, **bb;
+ image_dict *d;
+ if (lua_gettop(L) == 0)
+ luaL_error(L, "img.copy needs an image as argument");
+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* a */
+ lua_pop(L, 1); /* - */
+ a = *aa;
+ bb = (image **) lua_newuserdata(L, sizeof(image *)); /* b */
+ luaL_getmetatable(L, TYPE_IMG); /* m b */
+ lua_setmetatable(L, -2); /* b */
+ b = *bb = new_image();
+ if (!is_wd_running(a))
+ img_width(b) = do_zround(img_width(a) * scale);
+ if (!is_ht_running(a))
+ img_height(b) = do_zround(img_height(a) * scale);
+ if (!is_dp_running(a))
+ img_depth(b) = do_zround(img_depth(a) * scale);
+ img_transform(b) = img_transform(a);
+ img_dict(b) = img_dict(a);
+ if (img_dictref(a) != LUA_NOREF) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, img_dictref(a)); /* ad b */
+ img_dictref(b) = luaL_ref(L, LUA_REGISTRYINDEX); /* b */
+ d = img_dict(*aa);
+ img_luaref(d) += 1;
+ } else if (img_state(img_dict(a)) < DICT_REFERED) {
+ luaL_error(L, "img.copy needs an proper image as argument");
+ }
+}
+
+static void lua_to_image(lua_State * L, image * a, image_dict * d);
+
+int l_new_image(lua_State * L)
+{
+ image *a, **aa;
+ image_dict **add;
+ if (lua_gettop(L) > 0 && ! lua_istable(L, -1)) {
+ luaL_error(L, "img.new needs table as optional argument"); /* (t) */
+ }
+ aa = (image **) lua_newuserdata(L, sizeof(image *)); /* i (t) */
+ luaL_getmetatable(L, TYPE_IMG); /* m i (t) */
+ lua_setmetatable(L, -2); /* i (t) */
+ a = *aa = new_image();
+ add = (image_dict **) lua_newuserdata(L, sizeof(image_dict *)); /* ad i (t) */
+ luaL_getmetatable(L, TYPE_IMG_DICT); /* m ad i (t) */
+ lua_setmetatable(L, -2); /* ad i (t) */
+ img_dict(a) = *add = new_image_dict();
+ img_dictref(a) = luaL_ref(L, LUA_REGISTRYINDEX); /* i (t) */
+ img_luaref(*add) += 1;
+ if (lua_gettop(L) == 2) { /* i t, else just i */
+ lua_insert(L, -2); /* t i */
+ lua_pushnil(L); /* n t i (1st key for iterator) */
+ while (lua_next(L, -2) != 0) { /* v k t i */
+ lua_to_image(L, a, *add); /* v k t i */
+ lua_pop(L, 1); /* k t i */
+ } /* t i */
+ lua_pop(L, 1); /* i */
+ } /* i */
+ return 1; /* i */
+}
+
+static int l_copy_image(lua_State * L)
+{
+ if (lua_gettop(L) != 1) {
+ luaL_error(L, "img.copy needs an image as argument");
+ } else if (lua_istable(L, 1)) {
+ (void) l_new_image(L);
+ } else {
+ (void) copy_image(L, 1.0);
+ }
+ return 1;
+}
+
+static void read_scale_img(image * a)
+{
+ image_dict *ad;
+ if (a == NULL) {
+ luaL_error(Luas, "the image scaler needs a valid image");
+ } else {
+ ad = img_dict(a);
+ if (ad == NULL) {
+ luaL_error(Luas, "the image scaler needs a valid dictionary");
+ } else {
+ if (img_state(ad) == DICT_NEW) {
+ if (img_type(ad) == IMG_TYPE_PDFSTREAM)
+ check_pdfstream_dict(ad);
+ else {
+ read_img(ad);
+ }
+ }
+ if ((img_type(ad) == IMG_TYPE_NONE) || (img_state(ad) == DICT_NEW)) {
+ normal_warning("image","don't rely on the image data to be okay");
+ img_width(a) = 0;
+ img_height(a) = 0;
+ img_depth(a) = 0;
+ } else if (is_wd_running(a) || is_ht_running(a) || is_dp_running(a)) {
+ img_dimen(a) = scale_img(ad, img_dimen(a), img_transform(a));
+ }
+ }
+ }
+}
+
+static int l_scan_image(lua_State * L)
+{
+ image *a, **aa;
+ if (lua_gettop(L) != 1)
+ luaL_error(L, "img.scan needs exactly 1 argument");
+ if (lua_istable(L, 1))
+ (void) l_new_image(L);
+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG);
+ a = *aa;
+ check_o_mode(static_pdf, "img.scan", 1 << OMODE_PDF, false);
+ read_scale_img(a);
+ return 1;
+}
+
+static halfword img_to_node(lua_State * L, image * a)
+{
+ image_dict *ad;
+ halfword n = null;
+ if (a == NULL) {
+ luaL_error(L, "img.tonode needs a valid image");
+ } else {
+ ad = img_dict(a);
+ if (a == NULL) {
+ luaL_error(L, "img.tonode image has no dictionary");
+ } else if (img_objnum(ad) == 0) {
+ luaL_error(L, "img.tonode got image without object number");
+ } else {
+ n = new_rule(image_rule);
+ rule_index(n) = img_index(ad);
+ width(n) = img_width(a);
+ height(n) = img_height(a);
+ depth(n) = img_depth(a);
+ rule_transform(n) = img_transform(a);
+ }
+ }
+ return n;
+}
+
+typedef enum {
+ WR_WRITE,
+ WR_IMMEDIATEWRITE,
+ WR_NODE,
+ WR_VF_IMG
+} wrtype_e;
+
+const char *wrtype_s[] = {
+ "img.write()",
+ "img.immediatewrite()",
+ "img.node()",
+ "write vf image"
+};
+
+static void setup_image(PDF pdf, image * a, wrtype_e writetype)
+{
+ image_dict *ad;
+ if (a == NULL)
+ luaL_error(Luas, "no valid image passed"); /* todo, also check in caller */
+ ad = img_dict(a);
+ check_o_mode(pdf, wrtype_s[writetype], 1 << OMODE_PDF, false);
+ read_scale_img(a);
+ if (img_objnum(ad) == 0) { /* latest needed just before out_img() */
+ pdf->ximage_count++;
+ img_objnum(ad) = pdf_create_obj(pdf, obj_type_ximage, pdf->ximage_count);
+ img_index(ad) = pdf->ximage_count;
+ idict_to_array(ad); /* from now on ad is read-only */
+ obj_data_ptr(pdf, pdf->obj_ptr) = img_index(ad);
+ }
+}
+
+static void write_image_or_node(lua_State * L, wrtype_e writetype)
+{
+ image *a, **aa;
+ image_dict *ad;
+ halfword n;
+ if (lua_gettop(L) != 1)
+ luaL_error(L, "%s expects an argument", wrtype_s[writetype]);
+ if (lua_istable(L, 1))
+ (void) l_new_image(L);
+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG);
+ a = *aa;
+ ad = img_dict(a);
+ setup_image(static_pdf, a, writetype);
+ switch (writetype) {
+ case WR_WRITE:
+ n = img_to_node(L, a);
+ tail_append(n);
+ break;
+ case WR_IMMEDIATEWRITE:
+ write_img(static_pdf, ad);
+ break;
+ case WR_NODE:
+ lua_pop(L, 1); /* - */
+ n = img_to_node(L, a);
+ lua_nodelib_push_fast(L, n);
+ break;
+ default:
+ luaL_error(L, "%s expects an valid image", wrtype_s[writetype]);
+ }
+ if (img_state(ad) < DICT_REFERED)
+ 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);
+ return 1;
+}
+
+static int l_immediatewrite_image(lua_State * L)
+{
+ check_o_mode(static_pdf, "img.immediatewrite", 1 << OMODE_PDF, true);
+ if (global_shipping_mode != NOT_SHIPPING) {
+ luaL_error(L, "img.immediatewrite can not be used with \\latelua");
+ } else {
+ write_image_or_node(L, WR_IMMEDIATEWRITE);
+ }
+ 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);
+ return 1;
+}
+
+static int l_image_keys(lua_State * L)
+{
+ return lua_show_valid_keys(L, img_parms, img_parms_max);
+}
+
+static int l_image_types(lua_State * L)
+{
+ return lua_show_valid_list(L, img_types, 0, img_types_max);
+}
+
+static int l_image_boxes(lua_State * L)
+{
+ return lua_show_valid_keys(L, img_pageboxes, img_pageboxes_max);
+}
+
+static const struct luaL_Reg imglib_f[] = {
+ { "new", l_new_image },
+ { "copy", l_copy_image },
+ { "scan", l_scan_image },
+ { "write", l_write_image },
+ { "immediatewrite", l_immediatewrite_image },
+ { "immediatewriteobject", l_immediatewrite_image_object },
+ { "node", l_image_node },
+ { "fields", l_image_keys },
+ { "types", l_image_types },
+ { "boxes", l_image_boxes },
+ /* for a while: */
+ { "keys", l_image_keys },
+ { NULL, NULL }
+};
+
+void vf_out_image(PDF pdf, unsigned i)
+{
+ image *a, **aa;
+ image_dict *ad;
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, (int) i);
+ aa = (image **) luaL_checkudata(Luas, -1, TYPE_IMG);
+ a = *aa;
+ ad = img_dict(a);
+ if (ad == NULL) {
+ luaL_error(Luas, "invalid image dictionary");
+ }
+ setup_image(pdf, a, WR_VF_IMG);
+ place_img(pdf, ad, img_dimen(a), img_transform(a));
+ lua_pop(Luas, 1);
+}
+
+/* metamethods for image */
+
+static int m_img_get(lua_State * L)
+{
+ int j;
+ const char *s;
+ image **a = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* k u */
+ image_dict *d = img_dict(*a);
+ if (d == NULL) {
+ luaL_error(L, "invalid image dictionary");
+ }
+ s = lua_tostring(L, 2);
+ if (lua_key_eq(s,width)) {
+ if (is_wd_running(*a)) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_width(*a));
+ }
+ } else if (lua_key_eq(s,height)) {
+ if (is_ht_running(*a)) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_height(*a));
+ }
+ } else if (lua_key_eq(s,depth)) {
+ if (is_dp_running(*a)) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_depth(*a));
+ }
+ } else if (lua_key_eq(s,transform)) {
+ lua_pushinteger(L, img_transform(*a));
+ } else if (lua_key_eq(s,filename)) {
+ if (img_filename(d) == NULL || strlen(img_filename(d)) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, img_filename(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,notype)) {
+ lua_pushboolean(L, img_notype(d));
+ } else if (lua_key_eq(s,nobbox)) {
+ lua_pushboolean(L, img_nobbox(d));
+ } else if (lua_key_eq(s,filepath)) {
+ if (img_filepath(d) == NULL || strlen(img_filepath(d)) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, img_filepath(d));
+ }
+ } else if (lua_key_eq(s,attr)) {
+ if (img_attr(d) == NULL || strlen(img_attr(d)) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, img_attr(d));
+ }
+ } else if (lua_key_eq(s,page)) {
+ if (img_pagename(d) != NULL && strlen(img_pagename(d)) != 0) {
+ lua_pushstring(L, img_pagename(d));
+ } else {
+ lua_pushinteger(L, img_pagenum(d));
+ }
+ } else if (lua_key_eq(s,pages)) {
+ lua_pushinteger(L, img_totalpages(d));
+ } else if (lua_key_eq(s,xsize)) {
+ if ((img_rotation(d) & 1) == 0) {
+ lua_pushinteger(L, img_xsize(d));
+ } else {
+ lua_pushinteger(L, img_ysize(d));
+ }
+ } else if (lua_key_eq(s,ysize)) {
+ if ((img_rotation(d) & 1) == 0) {
+ lua_pushinteger(L, img_ysize(d));
+ } else {
+ lua_pushinteger(L, img_xsize(d));
+ }
+ } else if (lua_key_eq(s,xres)) {
+ lua_pushinteger(L, img_xres(d));
+ } else if (lua_key_eq(s,yres)) {
+ lua_pushinteger(L, img_yres(d));
+ } else if (lua_key_eq(s,rotation)) {
+ lua_pushinteger(L, img_rotation(d));
+ } else if (lua_key_eq(s,orientation)) {
+ lua_pushinteger(L, img_orientation(d));
+ } else if (lua_key_eq(s,colorspace)) {
+ if (img_colorspace(d) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_colorspace(d));
+ }
+ } else if (lua_key_eq(s,colordepth)) {
+ if (img_colordepth(d) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_colordepth(d));
+ }
+ } else if (lua_key_eq(s,imagetype)) {
+ j = img_type(d);
+ if (j >= 0 && j <= img_types_max) {
+ if (j == IMG_TYPE_NONE) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, img_types[j]);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (lua_key_eq(s,pagebox)) {
+ j = img_pagebox(d);
+ if (j < 0 || j >= img_pageboxes_max) {
+ j = 0;
+ }
+ lua_push_img_pagebox(L, j);
+ } else if (lua_key_eq(s,bbox)) {
+ if (!img_is_bbox(d)) {
+ img_bbox(d)[0] = img_xorig(d);
+ img_bbox(d)[1] = img_yorig(d);
+ img_bbox(d)[2] = img_xorig(d) + img_xsize(d);
+ img_bbox(d)[3] = img_yorig(d) + img_ysize(d);
+ }
+ lua_newtable(L);
+ lua_pushinteger(L, 1);
+ lua_pushinteger(L, img_bbox(d)[0]);
+ lua_settable(L, -3);
+ lua_pushinteger(L, 2);
+ lua_pushinteger(L, img_bbox(d)[1]);
+ lua_settable(L, -3);
+ lua_pushinteger(L, 3);
+ lua_pushinteger(L, img_bbox(d)[2]);
+ lua_settable(L, -3);
+ lua_pushinteger(L, 4);
+ lua_pushinteger(L, img_bbox(d)[3]);
+ lua_settable(L, -3);
+ } else if (lua_key_eq(s,objnum)) {
+ if (img_objnum(d) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_objnum(d));
+ }
+ } else if (lua_key_eq(s,index)) {
+ if (img_index(d) == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, img_index(d));
+ }
+ } else if (lua_key_eq(s,stream)) {
+ if (img_type(d) != IMG_TYPE_PDFSTREAM
+ || img_pdfstream_ptr(d) == NULL
+ || img_pdfstream_stream(d) == NULL
+ || 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_ownerpassword(d));
+ }
+ } else if (lua_key_eq(s,ref_count)) {
+ lua_pushinteger(L, img_luaref(d));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static void lua_to_image(lua_State * L, image * a, image_dict * d)
+{
+ int i, t;
+ const char *s;
+ s = lua_tostring(L,-2);
+ t = lua_type(L, -1);
+ if (lua_key_eq(s,width)) {
+ if (t == LUA_TNIL) {
+ set_wd_running(a);
+ } else if (t == LUA_TNUMBER) {
+ img_width(a) = (int) lua_roundnumber(L, -1);
+ } else if (t == LUA_TSTRING) {
+ img_width(a) = dimen_to_number(L, lua_tostring(L, -1));
+ } else {
+ luaL_error(L, "img.width needs integer or nil value or dimension string");
+ }
+ } else if (lua_key_eq(s,height)) {
+ if (t == LUA_TNIL) {
+ set_ht_running(a);
+ } else if (t == LUA_TNUMBER) {
+ img_height(a) = (int) lua_roundnumber(L, -1);
+ } else if (t == LUA_TSTRING) {
+ img_height(a) = dimen_to_number(L, lua_tostring(L, -1));
+ } else {
+ luaL_error(L, "img.height needs integer or nil value or dimension string");
+ }
+ } else if (lua_key_eq(s,depth)) {
+ if (t == LUA_TNIL) {
+ set_dp_running(a);
+ } else if (t == LUA_TNUMBER) {
+ img_depth(a) = (int) lua_roundnumber(L, -1);
+ } else if (t == LUA_TSTRING) {
+ img_depth(a) = dimen_to_number(L, lua_tostring(L, -1));
+ } else {
+ luaL_error(L, "img.depth needs integer or nil value or dimension string");
+ }
+ } else if (lua_key_eq(s,transform)) {
+ if (t == LUA_TNUMBER) {
+ img_transform(a) = (int) lua_tointeger(L, -1);
+ } else {
+ luaL_error(L, "img.transform needs integer value");
+ }
+ } else if (lua_key_eq(s,filename)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.filename is now read-only");
+ } else if (img_type(d) == IMG_TYPE_PDFSTREAM) {
+ /* just ignore */
+ } else if (t == LUA_TSTRING) {
+ xfree(img_filename(d));
+ img_filename(d) = xstrdup(lua_tostring(L, -1));
+ } else {
+ luaL_error(L, "img.filename needs string value");
+ }
+ } else if (lua_key_eq(s,visiblefilename)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.visiblefilename is now read-only");
+ } else if (img_type(d) == IMG_TYPE_PDFSTREAM) {
+ 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, "img.visiblefilename needs string value");
+ }
+ } else if (lua_key_eq(s,userpassword)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.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, "img.userpassword needs string value");
+ }
+ } else if (lua_key_eq(s,ownerpassword)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.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, "img.ownerpassword needs string value");
+ }
+ } else if (lua_key_eq(s,attr)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.attr is now read-only");
+ } else if (t == LUA_TSTRING) {
+ xfree(img_attr(d));
+ img_attr(d) = xstrdup(lua_tostring(L, -1));
+ } else if (t == LUA_TNIL) {
+ xfree(img_attr(d));
+ } else {
+ luaL_error(L, "img.attr needs string or nil value");
+ }
+ } else if (lua_key_eq(s,page)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.page is now read-only");
+ } else if (t == LUA_TSTRING) {
+ xfree(img_pagename(d));
+ img_pagename(d) = xstrdup(lua_tostring(L, -1));
+ img_pagenum(d) = 0;
+ } else if (t == LUA_TNUMBER) {
+ img_pagenum(d) = (int) lua_tointeger(L, -1);
+ xfree(img_pagename(d));
+ } else {
+ luaL_error(L, "img.page needs integer or string value");
+ }
+ } else if (lua_key_eq(s,colorspace)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.colorspace is now read-only");
+ } else if (t == LUA_TNIL) {
+ img_colorspace(d) = 0;
+ } else if (t == LUA_TNUMBER) {
+ img_colorspace(d) = (int) lua_tointeger(L, -1);
+ } else {
+ luaL_error(L, "img.colorspace needs integer or nil value");
+ }
+ } else if (lua_key_eq(s,pagebox)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.pagebox is now read-only");
+ } else if (t == LUA_TNIL) {
+ img_pagebox(d) = PDF_BOX_SPEC_MEDIA;
+ } else if (t == LUA_TNUMBER) {
+ i = lua_tointeger(L,-1);
+ if (i < 0 || i >= img_pageboxes_max) {
+ img_pagebox(d) = PDF_BOX_SPEC_MEDIA;
+ } else {
+ img_pagebox(d) = i;
+ }
+ } else if (t == LUA_TSTRING) {
+ img_pagebox(d) = PDF_BOX_SPEC_MEDIA;
+ for (i = 0; i < img_pageboxes_max; i++) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, img_pageboxes[i]);
+ if (lua_rawequal(L,-1,-2)) {
+ img_pagebox(d) = i;
+ lua_pop(L, 1);
+ break;
+ } else {
+ lua_pop(L, 1);
+ }
+ }
+ } else {
+ luaL_error(L, "img.pagebox needs string, number or nil value");
+ }
+ } else if (lua_key_eq(s,keepopen)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.keepopen is now read-only");
+ } else if (t != LUA_TBOOLEAN) {
+ luaL_error(L, "img.bbox needs boolean value");
+ } 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,notype)) {
+ img_notype(d) = lua_toboolean(L, -1);
+ } else if (lua_key_eq(s,nobbox)) {
+ img_nobbox(d) = lua_toboolean(L, -1);
+ } else if (lua_key_eq(s,bbox)) {
+ if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.bbox is now read-only");
+ } else if (t != LUA_TTABLE) {
+ luaL_error(L, "img.bbox needs table value");
+ } else if (lua_rawlen(L, -1) != 4) {
+ luaL_error(L, "img.bbox table must have exactly 4 elements");
+ } else {
+ for (i = 1; i <= 4; i++) { /* v k t ... */
+ lua_pushinteger(L, i); /* idx v k t ... */
+ lua_gettable(L, -2); /* int v k t ... */
+ t = lua_type(L, -1);
+ if (t == LUA_TNUMBER) {
+ img_bbox(d)[i - 1] = (int) lua_roundnumber(L, -1);
+ } else if (t == LUA_TSTRING) {
+ img_bbox(d)[i - 1] = dimen_to_number(L, lua_tostring(L, -1));
+ } else {
+ luaL_error(L, "img.bbox table needs integer value or dimension string elements");
+ }
+ lua_pop(L, 1); /* v k t ... */
+ }
+ img_set_bbox(d);
+ }
+ } else if (lua_key_eq(s,stream)) {
+ if (img_filename(d) != NULL) {
+ luaL_error(L, "img.stream can't be used with image.filename");
+ } else if (img_state(d) >= DICT_FILESCANNED) {
+ luaL_error(L, "img.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_size(d) = size;
+ img_pdfstream_stream(d) = xmalloc(size);
+ memcpy(img_pdfstream_stream(d),stream,size);
+ img_type(d) = IMG_TYPE_PDFSTREAM;
+ }
+ } else {
+ /*tex Let's be a bit more tolerant to adding private keys. */
+ /* luaL_error(L, "img.%s can not be set", s); */
+ }
+}
+
+static int m_img_set(lua_State * L)
+{
+ image **a = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* v k u */
+ image_dict *d = img_dict(*a);
+ if (d == NULL) {
+ luaL_error(L, "invalid image dictionary");
+ } else {
+ lua_to_image(L, *a, d);
+ }
+ return 0;
+}
+
+static int m_img_mul(lua_State * L)
+{
+ lua_Number scale;
+ if (lua_type(L, 1) == LUA_TNUMBER) { /* u? n */
+ (void) luaL_checkudata(L, 2, TYPE_IMG); /* u n */
+ lua_insert(L, -2); /* n a */
+ } else if (lua_type(L, 2) != LUA_TNUMBER) { /* n u? */
+ (void) luaL_checkudata(L, 1, TYPE_IMG); /* n a */
+ } /* n a */
+ scale = lua_tonumber(L, 2); /* float */ /* n a */
+ lua_pop(L, 1); /* a */
+ copy_image(L, scale); /* b */
+ return 1;
+}
+
+static int m_img_print(lua_State * L)
+{
+ image **aa;
+ image_dict *d;
+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG);
+ d = img_dict(*aa);
+ /* formatted a bit like a node */
+ if (img_filename(d) == NULL) {
+ if (img_pagename(d) != NULL && strlen(img_pagename(d)) != 0) {
+ lua_pushfstring(L, "<img unset : %d >", img_dictref(*aa));
+ } else {
+ lua_pushfstring(L, "<img unset : %d >", img_dictref(*aa));
+ }
+ } else {
+ if (img_pagename(d) != NULL && strlen(img_pagename(d)) != 0) {
+ lua_pushfstring(L, "<img %s : %s : %d >", img_filename(d), img_pagename(d), img_dictref(*aa));
+ } else {
+ lua_pushfstring(L, "<img %s : %d : %d >", img_filename(d), img_pagenum(d), img_dictref(*aa));
+ }
+ }
+ return 1;
+}
+
+/* this finalizes instance */
+
+static int m_img_gc(lua_State * L)
+{
+ image *a, **aa;
+ image_dict *d;
+ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG);
+ a = *aa;
+ d = img_dict(*aa);
+ luaL_unref(L, LUA_REGISTRYINDEX, img_dictref(a));
+ img_luaref(d) -= 1;
+ /* we need to check this */
+ if (!img_is_refered(d)) {
+ xfree(a);
+ }
+ /* till here */
+ return 0;
+}
+
+/* the instance */
+
+static const struct luaL_Reg img_m[] = {
+ {"__index", m_img_get},
+ {"__newindex", m_img_set},
+ {"__mul", m_img_mul},
+ {"__tostring", m_img_print},
+ {"__gc", m_img_gc},
+ {NULL, NULL}
+};
+
+/* this finalizes the dict */
+
+static int m_img_dict_gc(lua_State * L)
+{
+ image_dict *ad, **add;
+ add = (image_dict **) luaL_checkudata(L, 1, TYPE_IMG_DICT);
+ ad = *add;
+ if (img_luaref(ad) > 0) {
+ luaL_error(L, "disposing image dict that has references");
+ } else {
+ /* we need to check this */
+ if (img_state(ad) < DICT_REFERED) {
+ free_image_dict(ad);
+ }
+ /* till here */
+ }
+ return 0;
+}
+
+/* the (shared) dict */
+
+static const struct luaL_Reg img_dict_m[] = {
+ {"__gc", m_img_dict_gc},
+ {NULL, NULL}
+};
+
+int luaopen_img(lua_State * L)
+{
+ luaL_newmetatable(L, TYPE_IMG);
+#ifdef LuajitTeX
+ luaL_openlib(L, NULL, img_m, 0);
+ luaL_newmetatable(L, TYPE_IMG_DICT);
+ luaL_openlib(L, NULL, img_dict_m, 0);
+#else
+ luaL_setfuncs(L, img_m, 0);
+ luaL_newmetatable(L, TYPE_IMG_DICT);
+ luaL_setfuncs(L, img_dict_m, 0);
+#endif
+ luaL_openlib(L, "img", imglib_f, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/liolibext.c b/Build/source/texk/web2c/luatexdir/lua/liolibext.c
new file mode 100644
index 00000000000..ce1e78f6c73
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/liolibext.c
@@ -0,0 +1,1108 @@
+/* liolibext.c
+
+ Copyright 2014 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#ifdef LuajitTeX
+#include "lua/lauxlib_bridge.h"
+#else
+#include "lauxlib.h"
+#endif
+#include "lualib.h"
+
+#ifdef LuajitTeX
+/* luajit has its own way for io, which is a mix of */
+/* lua 5.1 and lua 5.2 . We use the stock luajit. */
+#else
+/*
+** {======================================================
+** lua_popen spawns a new process connected to the current
+** one through the file streams.
+** =======================================================
+*/
+
+#if defined(_WIN32)
+
+#ifdef _MSC_VER
+#define lua_popen(L,c,m) ((void)L, win32_popen(c,m))
+#define lua_pclose(L,file) ((void)L, win32_pclose(file))
+#else
+#define lua_popen(L,c,m) ((void)L, _popen(c,m))
+#define lua_pclose(L,file) ((void)L, _pclose(file))
+#endif
+
+#else
+
+#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
+#define lua_pclose(L,file) ((void)L, pclose(file))
+
+#endif
+
+/* }====================================================== */
+
+#if defined(LUA_USE_POSIX)
+
+#define l_fseek(f,o,w) fseeko(f,o,w)
+#define l_ftell(f) ftello(f)
+#define l_seeknum off_t
+
+#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
+ && defined(_MSC_VER) && (_MSC_VER >= 1400)
+/* Windows (but not DDK) and Visual C++ 2005 or higher */
+
+#define l_fseek(f,o,w) _fseeki64(f,o,w)
+#define l_ftell(f) _ftelli64(f)
+#define l_seeknum __int64
+
+#elif defined(__MINGW32__)
+
+#define l_fseek(f,o,w) fseeko64(f,o,w)
+#define l_ftell(f) ftello64(f)
+#define l_seeknum int64_t
+
+#else
+
+#define l_fseek(f,o,w) fseek(f,o,w)
+#define l_ftell(f) ftell(f)
+#define l_seeknum long
+
+#endif
+
+#endif/* #ifdef LuajitTeX */
+
+static FILE *tofile (lua_State *L) {
+#ifdef LuajitTeX
+ FILE **f = luaL_checkudata(L,1,LUA_FILEHANDLE);
+ if (*f == NULL)
+ luaL_error(L,"attempt to use a closed file");
+ return *f;
+#else
+ luaL_Stream *p = ((luaL_Stream *)luaL_checkudata(L, 1, LUA_FILEHANDLE));
+ if ((p)->closef == NULL)
+ luaL_error(L, "attempt to use a closed file");
+ lua_assert(p->f);
+ return p->f;
+#endif
+}
+
+#define uchar(c) ((unsigned char)(c))
+
+/*
+ HH: A few helpers to avoid reading numbers as strings. For now we put them in their
+ own namespace. We also have a few helpers that can make io functions tex friendly.
+*/
+
+static int readcardinal1(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, a);
+ return 1;
+}
+
+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 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p]);
+ lua_pushinteger(L, a);
+ }
+ return 1;
+}
+
+static int readcardinal2(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ if (b == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<8) | b */
+ lua_pushinteger(L, 0x100 * a + b);
+ return 1;
+}
+static int readcardinal2_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<8) | b */
+ lua_pushinteger(L, 0x100 * a + b);
+ return 1;
+}
+
+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+1 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p++]);
+ int b = uchar(s[p]);
+ lua_pushinteger(L, 0x100 * a + b);
+ }
+ return 1;
+}
+static int readcardinal2_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+1 >= l) {
+ lua_pushnil(L);
+ } else {
+ int b = uchar(s[p++]);
+ int a = uchar(s[p]);
+ lua_pushinteger(L, 0x100 * a + b);
+ }
+ return 1;
+}
+
+static int readcardinal3(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ int c = getc(f);
+ if (c == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<16) | (b<<8) | c */
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ return 1;
+}
+static int readcardinal3_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int c = getc(f);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<16) | (b<<8) | c */
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ return 1;
+}
+
+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+2 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int c = uchar(s[p]);
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ }
+ return 1;
+}
+static int readcardinal3_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+2 >= l) {
+ lua_pushnil(L);
+ } else {
+ int c = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int a = uchar(s[p]);
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ }
+ return 1;
+}
+
+static int readcardinal4(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ int c = getc(f);
+ int d = getc(f);
+ if (d == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<24) | (b<<16) | (c<<8) | d */
+ lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d);
+ return 1;
+}
+static int readcardinal4_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int d = getc(f);
+ int c = getc(f);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else
+ /* (a<<24) | (b<<16) | (c<<8) | d */
+ lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d);
+ return 1;
+}
+
+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+3 >= l) {
+ lua_pushnil(L);
+ } 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);
+ }
+ return 1;
+}
+static int readcardinal4_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+3 >= l) {
+ lua_pushnil(L);
+ } else {
+ int d = uchar(s[p++]);
+ int c = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int a = uchar(s[p]);
+ lua_pushinteger(L,0x1000000 * a + 0x10000 * b + 0x100 * c + d);
+ }
+ 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);
+ if (a == EOF)
+ lua_pushnil(L);
+ else if (a >= 0x80)
+ lua_pushinteger(L, a - 0x100);
+ else
+ lua_pushinteger(L, a);
+ return 1;
+}
+
+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 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p]);
+ if (a >= 0x80)
+ lua_pushinteger(L, a - 0x100);
+ else
+ lua_pushinteger(L, a);
+ }
+ return 1;
+}
+
+static int readinteger2(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ if (b == EOF)
+ lua_pushnil(L);
+ else if (a >= 0x80)
+ lua_pushinteger(L, 0x100 * a + b - 0x10000);
+ else
+ lua_pushinteger(L, 0x100 * a + b);
+ return 1;
+}
+static int readinteger2_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else if (a >= 0x80)
+ lua_pushinteger(L, 0x100 * a + b - 0x10000);
+ else
+ lua_pushinteger(L, 0x100 * a + b);
+ return 1;
+}
+
+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+1 >= l) {
+ lua_pushnil(L);
+ } 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);
+ }
+ return 1;
+}
+static int readinteger2_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+1 >= l) {
+ lua_pushnil(L);
+ } else {
+ int b = uchar(s[p++]);
+ int a = uchar(s[p]);
+ if (a >= 0x80)
+ lua_pushinteger(L, 0x100 * a + b - 0x10000);
+ else
+ lua_pushinteger(L, 0x100 * a + b);
+ }
+ return 1;
+}
+
+static int readinteger3(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ int c = getc(f);
+ if (c == EOF)
+ lua_pushnil(L);
+ else if (a >= 0x80)
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
+ else
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ return 1;
+}
+static int readinteger3_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int c = getc(f);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ else if (a >= 0x80)
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
+ else
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ return 1;
+}
+
+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+2 >= l) {
+ lua_pushnil(L);
+ } 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);
+ }
+ return 1;
+}
+static int readinteger3_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+2 >= l) {
+ lua_pushnil(L);
+ } else {
+ int c = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int a = uchar(s[p]);
+ if (a >= 0x80)
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c - 0x1000000);
+ else
+ lua_pushinteger(L, 0x10000 * a + 0x100 * b + c);
+ }
+ return 1;
+}
+
+static int readinteger4(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ int c = getc(f);
+ int d = getc(f);
+ if (d == EOF)
+ lua_pushnil(L);
+ 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);
+ return 1;
+}
+static int readinteger4_le(lua_State *L) {
+ FILE *f = tofile(L);
+ int d = getc(f);
+ int c = getc(f);
+ int b = getc(f);
+ int a = getc(f);
+ if (a == EOF)
+ lua_pushnil(L);
+ 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);
+ return 1;
+}
+
+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+3 >= l) {
+ lua_pushnil(L);
+ } 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);
+ }
+ return 1;
+}
+static int readinteger4_s_le(lua_State *L) {
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ size_t p = luaL_checkinteger(L, 2) - 1;
+ if (p+3 >= l) {
+ lua_pushnil(L);
+ } else {
+ int d = uchar(s[p++]);
+ int c = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int a = 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);
+ }
+ 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;
+}
+
+/* from ff */
+
+static int readfixed2(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ if (b == EOF) {
+ lua_pushnil(L);
+ } else {
+ int n = 0x100 * a + b;
+ lua_pushnumber(L,(double) ((n>>8) + ((n&0xff)/256.0)));
+ }
+ return 1;
+}
+
+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+3 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p++]);
+ int b = uchar(s[p]);
+ int n = 0x100 * a + b;
+ lua_pushnumber(L,(double) ((n>>8) + ((n&0xff)/256.0)));
+ }
+ return 1;
+}
+
+static int readfixed4(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ int c = getc(f);
+ int d = getc(f);
+ if (d == EOF) {
+ lua_pushnil(L);
+ } else {
+ int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d;
+ lua_pushnumber(L,(double) ((n>>16) + ((n&0xffff)/65536.0)));
+ }
+ return 1;
+}
+
+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+3 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p++]);
+ int b = uchar(s[p++]);
+ int c = uchar(s[p++]);
+ int d = uchar(s[p]);
+ int n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d;
+ lua_pushnumber(L,(double) ((n>>16) + ((n&0xffff)/65536.0)));
+ }
+ return 1;
+}
+
+static int read2dot14(lua_State *L) {
+ FILE *f = tofile(L);
+ int a = getc(f);
+ int b = getc(f);
+ if (b == EOF) {
+ lua_pushnil(L);
+ } else {
+ int n = 0x100 * a + b;
+ /* from ff */
+ lua_pushnumber(L,(double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)));
+ }
+ return 1;
+}
+
+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+1 >= l) {
+ lua_pushnil(L);
+ } else {
+ int a = uchar(s[p++]);
+ int b = uchar(s[p]);
+ int n = 0x100 * a + b;
+ lua_pushnumber(L,(double) (((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0)));
+ }
+ return 1;
+}
+
+static int getposition(lua_State *L) {
+ FILE *f = tofile(L);
+ long p = ftell(f);
+ if (p<0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, p);
+ return 1;
+}
+
+static int setposition(lua_State *L) {
+ FILE *f = tofile(L);
+ long p = lua_tointeger(L,2);
+ p = fseek(f,p,SEEK_SET);
+ if (p<0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, p);
+ return 1;
+}
+
+static int skipposition(lua_State *L) {
+ FILE *f = tofile(L);
+ long p = lua_tointeger(L,2);
+ p = fseek(f,ftell(f)+p,SEEK_SET);
+ if (p<0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, p);
+ return 1;
+}
+
+static int readbytetable(lua_State *L) {
+ FILE *f = tofile(L);
+ int n = lua_tointeger(L,2);
+ int i ;
+ lua_createtable(L, n, 0);
+ for (i=1;i<=n;i++) {
+ int a = getc(f);
+ if (a == EOF) {
+ break;
+ } else {
+ /*
+ lua_pushinteger(L, i);
+ lua_pushinteger(L, a);
+ lua_rawset(L, -3);
+ */
+ lua_pushinteger(L, a);
+ lua_rawseti(L,-2,i);
+ }
+ }
+ return 1;
+}
+
+static int readbytetable_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);
+ if (p >= l) {
+ lua_pushnil(L);
+ } else {
+ int i ;
+ if (p + n >= l) {
+ n = l - p ;
+ }
+ lua_createtable(L, n, 0);
+ for (i=1;i<=n;i++) {
+ int a = uchar(s[p++]);
+ lua_pushinteger(L, a);
+ lua_rawseti(L,-2,i);
+ }
+ }
+ return 1;
+}
+
+static int readbytes(lua_State *L) {
+ FILE *f = tofile(L);
+ int n = lua_tointeger(L,2);
+ int i = 0;
+ for (i=1;i<=n;i++) {
+ int a = getc(f);
+ if (a == EOF) {
+ return i-1;
+ } else {
+ lua_pushinteger(L, a);
+ }
+ }
+ return n;
+}
+
+static int readbytes_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);
+ if (p >= l) {
+ return 0;
+ } else {
+ int i ;
+ if (p + n >= l) {
+ n = l - p ;
+ }
+ lua_createtable(L, n, 0);
+ for (i=1;i<=n;i++) {
+ int a = uchar(s[p++]);
+ lua_pushinteger(L, a);
+ }
+ return n;
+ }
+}
+
+static int readline(lua_State *L)
+{
+ luaL_Buffer buf;
+ int c, d;
+ FILE *f = tofile(L);
+ luaL_buffinit(L, &buf);
+ while (1) {
+ c = fgetc(f);
+ if (c == EOF) {
+ luaL_pushresult(&buf);
+ if (lua_rawlen(L, -1) == 0) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ }
+ return 1;
+ } else if (c == '\n') {
+ luaL_pushresult(&buf);
+ return 1;
+ } else if (c == '\r') {
+ d = fgetc(f);
+ if (d != EOF && d != '\n') {
+ ungetc(d, f);
+ }
+ luaL_pushresult(&buf);
+ return 1;
+ } else {
+ luaL_addchar(&buf, c);
+ }
+ }
+}
+
+static const luaL_Reg fiolib[] = {
+ /* helpers */
+ { "readcardinal1", readcardinal1 },
+ { "readcardinal2", readcardinal2 },
+ { "readcardinal3", readcardinal3 },
+ { "readcardinal4", readcardinal4 },
+ { "readcardinal1le", readcardinal1 },
+ { "readcardinal2le", readcardinal2_le },
+ { "readcardinal3le", readcardinal3_le },
+ { "readcardinal4le", readcardinal4_le },
+ { "readcardinaltable", readcardinaltable },
+ { "readinteger1", readinteger1 },
+ { "readinteger2", readinteger2 },
+ { "readinteger3", readinteger3 },
+ { "readinteger4", readinteger4 },
+ { "readinteger1le", readinteger1 },
+ { "readinteger2le", readinteger2_le },
+ { "readinteger3le", readinteger3_le },
+ { "readinteger4le", readinteger4_le },
+ { "readintegertable", readintegertable },
+ { "readfixed2", readfixed2 },
+ { "readfixed4", readfixed4 },
+ { "read2dot14", read2dot14 },
+ { "setposition", setposition },
+ { "getposition", getposition },
+ { "skipposition", skipposition },
+ { "readbytes", readbytes },
+ { "readbytetable", readbytetable },
+ { "readline", readline },
+ /* done */
+ { NULL, NULL }
+};
+
+static const luaL_Reg siolib[] = {
+ { "readcardinal1", readcardinal1_s },
+ { "readcardinal2", readcardinal2_s },
+ { "readcardinal3", readcardinal3_s },
+ { "readcardinal4", readcardinal4_s },
+ { "readcardinal1le", readcardinal1_s },
+ { "readcardinal2le", readcardinal2_s_le },
+ { "readcardinal3le", readcardinal3_s_le },
+ { "readcardinal4le", readcardinal4_s_le },
+ { "readcardinaltable", readcardinaltable_s },
+ { "readinteger1", readinteger1_s },
+ { "readinteger2", readinteger2_s },
+ { "readinteger3", readinteger3_s },
+ { "readinteger4", readinteger4_s },
+ { "readinteger1le", readinteger1_s },
+ { "readinteger2le", readinteger2_s_le },
+ { "readinteger3le", readinteger3_s_le },
+ { "readinteger4le", readinteger4_s_le },
+ { "readintegertable", readintegertable_s },
+ { "readfixed2", readfixed2_s },
+ { "readfixed4", readfixed4_s },
+ { "read2dot14", read2dot14_s },
+ { "readbytes", readbytes_s },
+ { "readbytetable", readbytetable_s },
+ /* done */
+ { NULL, NULL }
+};
+
+/*
+ The sio helpers are experimental and might be handy at some point. Speed-wise
+ there is no gain over file access because with ssd and caching we basically
+ operate in memory too. We keep them as complement to the file ones. I did
+ consider using an userdata object for the position etc but some simple tests
+ demonstrated that there is no real gain and the current ones permits to wrap
+ up whatever interface one likes.
+*/
+
+int luaopen_fio(lua_State *L) {
+ luaL_openlib(L, "fio", fiolib, 0);
+ luaL_openlib(L, "sio", siolib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lkpselib.c b/Build/source/texk/web2c/luatexdir/lua/lkpselib.c
new file mode 100644
index 00000000000..353b6dce934
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lkpselib.c
@@ -0,0 +1,936 @@
+/* lkpselib.c
+
+ Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef MF_LUA
+#define EXTERN extern
+#if defined(JIT)
+#include "mfluajitd.h"
+#else
+#include "mfluad.h"
+#endif
+#include <kpathsea/version.h>
+#define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0)
+#else
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#endif
+#include <kpathsea/expand.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/tex-glyph.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/pathsearch.h>
+#include <kpathsea/str-list.h>
+#include <kpathsea/tex-file.h>
+#include <kpathsea/paths.h>
+
+
+static const unsigned filetypes[] = {
+ kpse_gf_format,
+ kpse_pk_format,
+ kpse_any_glyph_format,
+ kpse_tfm_format,
+ kpse_afm_format,
+ kpse_base_format,
+ kpse_bib_format,
+ kpse_bst_format,
+ kpse_cnf_format,
+ kpse_db_format,
+ kpse_fmt_format,
+ kpse_fontmap_format,
+ kpse_mem_format,
+ kpse_mf_format,
+ kpse_mfpool_format,
+ kpse_mft_format,
+ kpse_mp_format,
+ kpse_mppool_format,
+ kpse_mpsupport_format,
+ kpse_ocp_format,
+ kpse_ofm_format,
+ kpse_opl_format,
+ kpse_otp_format,
+ kpse_ovf_format,
+ kpse_ovp_format,
+ kpse_pict_format,
+ kpse_tex_format,
+ kpse_texdoc_format,
+ kpse_texpool_format,
+ kpse_texsource_format,
+ kpse_tex_ps_header_format,
+ kpse_troff_font_format,
+ kpse_type1_format,
+ kpse_vf_format,
+ kpse_dvips_config_format,
+ kpse_ist_format,
+ kpse_truetype_format,
+ kpse_type42_format,
+ kpse_web2c_format,
+ kpse_program_text_format,
+ kpse_program_binary_format,
+ kpse_miscfonts_format,
+ kpse_web_format,
+ kpse_cweb_format,
+ kpse_enc_format,
+ kpse_cmap_format,
+ kpse_sfd_format,
+ kpse_opentype_format,
+ kpse_pdftex_config_format,
+ kpse_lig_format,
+ kpse_texmfscripts_format,
+ kpse_lua_format,
+ kpse_fea_format,
+ kpse_cid_format,
+ kpse_mlbib_format,
+ kpse_mlbst_format,
+ kpse_clua_format
+};
+
+static const char *const filetypenames[] = {
+ "gf",
+ "pk",
+ "bitmap font",
+ "tfm",
+ "afm",
+ "base",
+ "bib",
+ "bst",
+ "cnf",
+ "ls-R",
+ "fmt",
+ "map",
+ "mem",
+ "mf",
+ "mfpool",
+ "mft",
+ "mp",
+ "mppool",
+ "MetaPost support",
+ "ocp",
+ "ofm",
+ "opl",
+ "otp",
+ "ovf",
+ "ovp",
+ "graphic/figure",
+ "tex",
+ "TeX system documentation",
+ "texpool",
+ "TeX system sources",
+ "PostScript header",
+ "Troff fonts",
+ "type1 fonts",
+ "vf",
+ "dvips config",
+ "ist",
+ "truetype fonts",
+ "type42 fonts",
+ "web2c files",
+ "other text files",
+ "other binary files",
+ "misc fonts",
+ "web",
+ "cweb",
+ "enc files",
+ "cmap files",
+ "subfont definition files",
+ "opentype fonts",
+ "pdftex config",
+ "lig files",
+ "texmfscripts",
+ "lua",
+ "font feature files",
+ "cid maps",
+ "mlbib",
+ "mlbst",
+ "clua",
+ NULL
+};
+
+
+#ifdef MF
+#define KPATHSEA_METATABLE "mflua.kpathsea"
+#else
+#define KPATHSEA_METATABLE "luatex.kpathsea"
+#endif
+
+/* set to 1 by the |program_name| function */
+
+#ifdef MF
+int program_name_set = 1;
+#else
+int program_name_set = 0;
+#endif
+
+#define TEST_PROGRAM_NAME_SET do { \
+ if (! program_name_set) { \
+ return luaL_error(L, "Please call kpse.set_program_name() before using the library"); \
+ } \
+ } while (0)
+
+static int find_file(lua_State * L)
+{
+ int i, t;
+ const char *st;
+ unsigned ftype = kpse_tex_format;
+ int mexist = 0;
+ TEST_PROGRAM_NAME_SET;
+ if (lua_type(L, 1) != LUA_TSTRING) {
+ luaL_error(L, "not a file name");
+ }
+ st = lua_tostring(L, 1);
+ i = lua_gettop(L);
+ while (i > 1) {
+ t = lua_type(L, i) ;
+ if (t == LUA_TBOOLEAN) {
+ mexist = lua_toboolean(L, i);
+ } else if (t == LUA_TNUMBER) {
+ mexist = (int) lua_tointeger(L, i);
+ } else if (t == LUA_TSTRING) {
+ int op = luaL_checkoption(L, i, NULL, filetypenames);
+ ftype = filetypes[op];
+ } else {
+ /* ignore */
+ }
+ i--;
+ }
+ if (ftype == kpse_pk_format ||
+ ftype == kpse_gf_format || ftype == kpse_any_glyph_format) {
+ /* ret.format, ret.name, ret.dpi */
+ kpse_glyph_file_type ret;
+ lua_pushstring(L, kpse_find_glyph(st, (unsigned) mexist, ftype, &ret));
+ } else {
+ if (mexist > 0)
+ mexist = 1;
+ if (mexist < 0)
+ mexist = 0;
+ lua_pushstring(L, kpse_find_file(st, ftype, mexist));
+ }
+ return 1;
+}
+
+
+static int lua_kpathsea_find_file(lua_State * L)
+{
+ int i, t;
+ unsigned ftype = kpse_tex_format;
+ int mexist = 0;
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *st = luaL_checkstring(L, 2);
+ i = lua_gettop(L);
+ while (i > 2) {
+ t = lua_type(L, i) ;
+ if (t == LUA_TBOOLEAN) {
+ mexist = (boolean) lua_toboolean(L, i);
+ } else if (t == LUA_TNUMBER) {
+ mexist = (int) lua_tointeger(L, i);
+ } else if (t == LUA_TSTRING) {
+ int op = luaL_checkoption(L, i, NULL, filetypenames);
+ ftype = filetypes[op];
+ } else {
+ /* ignore */
+ }
+ i--;
+ }
+ if (ftype == kpse_pk_format || ftype == kpse_gf_format || ftype == kpse_any_glyph_format) {
+ /* ret.format, ret.name, ret.dpi */
+ kpse_glyph_file_type ret;
+ lua_pushstring(L, kpathsea_find_glyph(*kp, st, (unsigned) mexist, ftype, &ret));
+ } else {
+ if (mexist > 0)
+ mexist = 1;
+ if (mexist < 0)
+ mexist = 0;
+ lua_pushstring(L, kpathsea_find_file(*kp, st, ftype, mexist));
+ }
+ return 1;
+
+}
+
+static int show_texmfcnf(lua_State * L)
+{
+ lua_pushstring(L, DEFAULT_TEXMFCNF);
+ return 1;
+}
+
+static int show_path(lua_State * L)
+{
+ int op = luaL_checkoption(L, -1, "tex", filetypenames);
+ unsigned user_format = filetypes[op];
+ TEST_PROGRAM_NAME_SET;
+ if (!kpse_format_info[user_format].type) /* needed if arg was numeric */
+ kpse_init_format(user_format);
+ lua_pushstring(L, kpse_format_info[user_format].path);
+ return 1;
+}
+
+static int lua_kpathsea_show_path(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ int op = luaL_checkoption(L, -1, "tex", filetypenames);
+ unsigned user_format = filetypes[op];
+ if (!(*kp)->format_info[user_format].type) /* needed if arg was numeric */
+ kpathsea_init_format(*kp, user_format);
+ lua_pushstring(L, (*kp)->format_info[user_format].path);
+ return 1;
+}
+
+static int expand_path(lua_State * L)
+{
+ const char *st = luaL_checkstring(L, 1);
+ TEST_PROGRAM_NAME_SET;
+ lua_pushstring(L, kpse_path_expand(st));
+ return 1;
+}
+
+static int lua_kpathsea_expand_path(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *st = luaL_checkstring(L, 2);
+ lua_pushstring(L, kpathsea_path_expand(*kp, st));
+ return 1;
+}
+
+static int expand_braces(lua_State * L)
+{
+ const char *st = luaL_checkstring(L, 1);
+ TEST_PROGRAM_NAME_SET;
+ lua_pushstring(L, kpse_brace_expand(st));
+ return 1;
+}
+
+static int lua_kpathsea_expand_braces(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *st = luaL_checkstring(L, 2);
+ lua_pushstring(L, kpathsea_brace_expand(*kp, st));
+ return 1;
+}
+
+
+static int expand_var(lua_State * L)
+{
+ const char *st = luaL_checkstring(L, 1);
+ TEST_PROGRAM_NAME_SET;
+ lua_pushstring(L, kpse_var_expand(st));
+ return 1;
+}
+
+static int lua_kpathsea_expand_var(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *st = luaL_checkstring(L, 2);
+ lua_pushstring(L, kpathsea_var_expand(*kp, st));
+ return 1;
+}
+
+
+static int var_value(lua_State * L)
+{
+ const char *st = luaL_checkstring(L, 1);
+ TEST_PROGRAM_NAME_SET;
+ lua_pushstring(L, kpse_var_value(st));
+ return 1;
+}
+
+static int lua_kpathsea_var_value(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *st = luaL_checkstring(L, 2);
+ lua_pushstring(L, kpathsea_var_value(*kp, st));
+ return 1;
+}
+
+static unsigned find_dpi(const_string s)
+{
+ unsigned dpi_number = 0;
+ const_string extension = find_suffix(s);
+
+ if (extension != NULL)
+ sscanf(extension, "%u", &dpi_number);
+
+ return dpi_number;
+}
+
+/*
+ Return newly-allocated NULL-terminated list of strings from MATCHES
+ that are prefixed with any of the subdirectories in SUBDIRS. That
+ is, for a string S in MATCHES, its dirname must end with one of the
+ elements in SUBDIRS. For instance, if subdir=foo/bar, that will
+ match a string foo/bar/baz or /some/texmf/foo/bar/baz.
+
+ We don't reallocate the actual strings, just the list elements.
+ Perhaps later we will implement wildcards or "//" or something.
+*/
+
+static string *subdir_match(str_list_type subdirs, string * matches)
+{
+ string *ret = XTALLOC1(string);
+ unsigned len = 1;
+ unsigned m;
+
+ for (m = 0; matches[m]; m++) {
+ size_t loc;
+ unsigned e;
+ string s = xstrdup(matches[m]);
+ for (loc = strlen(s); loc > 0 && !IS_DIR_SEP(s[loc - 1]); loc--);
+ while (loc > 0 && IS_DIR_SEP(s[loc - 1])) {
+ loc--;
+ }
+ s[loc] = 0; /* wipe out basename */
+
+ for (e = 0; e < STR_LIST_LENGTH(subdirs); e++) {
+ string subdir = STR_LIST_ELT(subdirs, e);
+ size_t subdir_len = strlen(subdir);
+ while (subdir_len > 0 && IS_DIR_SEP(subdir[subdir_len - 1])) {
+ subdir_len--;
+ subdir[subdir_len] = 0; /* remove trailing slashes from subdir spec */
+ }
+ if (FILESTRCASEEQ(subdir, s + loc - subdir_len)) {
+ /* matched, save this one. */
+ XRETALLOC(ret, len + 1, string);
+ ret[len - 1] = matches[m];
+ len++;
+ }
+ }
+ free(s);
+ }
+ ret[len - 1] = NULL;
+ return ret;
+}
+
+/* Use the file type from -format if that was specified (i.e., the
+ user_format global variable), else guess dynamically from NAME.
+ Return kpse_last_format if undeterminable. This function is also
+ used to parse the -format string, a case which we distinguish by
+ setting is_filename to false.
+
+ A few filenames have been hard-coded for format types that
+ differ from what would be inferred from their extensions. */
+
+static kpse_file_format_type
+find_format(kpathsea kpse, const_string name, boolean is_filename)
+{
+ kpse_file_format_type ret;
+
+ if (FILESTRCASEEQ(name, "config.ps")) {
+ ret = kpse_dvips_config_format;
+ } else if (FILESTRCASEEQ(name, "dvipdfmx.cfg")) {
+ ret = kpse_program_text_format;
+ } else if (FILESTRCASEEQ(name, "fmtutil.cnf")) {
+ ret = kpse_web2c_format;
+ } else if (FILESTRCASEEQ(name, "glyphlist.txt")) {
+ ret = kpse_fontmap_format;
+ } else if (FILESTRCASEEQ(name, "mktex.cnf")) {
+ ret = kpse_web2c_format;
+ } else if (FILESTRCASEEQ(name, "pdfglyphlist.txt")) {
+ ret = kpse_fontmap_format;
+ } else if (FILESTRCASEEQ(name, "pdftex.cfg")) {
+ ret = kpse_pdftex_config_format;
+ } else if (FILESTRCASEEQ(name, "texmf.cnf")) {
+ ret = kpse_cnf_format;
+ } else if (FILESTRCASEEQ(name, "updmap.cfg")) {
+ ret = kpse_web2c_format;
+ } else if (FILESTRCASEEQ(name, "XDvi")) {
+ ret = kpse_program_text_format;
+ } else {
+ int f = 0; /* kpse_file_format_type */
+ size_t name_len = strlen(name);
+
+/* Have to rely on `try_len' being declared here, since we can't assume
+ GNU C and statement expressions. */
+#define TRY_SUFFIX(ftry) (\
+ try_len = (ftry) ? strlen (ftry) : 0, \
+ (ftry) && try_len <= name_len \
+ && FILESTRCASEEQ (ftry, name + name_len - try_len))
+
+ while (f != kpse_last_format) {
+ size_t try_len;
+ const_string *ext;
+ const_string ftry;
+ boolean found = false;
+
+ if (!kpse->format_info[f].type)
+ kpathsea_init_format(kpse, (kpse_file_format_type) f);
+
+ if (!is_filename) {
+ /* Allow the long name, but only in the -format option. We don't
+ want a filename confused with a format name. */
+ ftry = kpse->format_info[f].type;
+ found = TRY_SUFFIX(ftry);
+ }
+ for (ext = kpse->format_info[f].suffix; !found && ext && *ext;
+ ext++) {
+ found = TRY_SUFFIX(*ext);
+ }
+ for (ext = kpse->format_info[f].alt_suffix; !found && ext && *ext;
+ ext++) {
+ found = TRY_SUFFIX(*ext);
+ }
+
+ if (found)
+ break;
+
+ /* Some trickery here: the extensions for kpse_fmt_format can
+ * clash with other extensions in use, and we prefer for those
+ * others to be preferred. And we don't want to change the
+ * integer value of kpse_fmt_format. So skip it when first
+ * enountered, then use it when we've done everything else,
+ * and use it as the end-guard.
+ */
+ if (f == kpse_fmt_format) {
+ f = kpse_last_format;
+ } else if (++f == kpse_fmt_format) {
+ f++;
+ } else if (f == kpse_last_format) {
+ f = kpse_fmt_format;
+ }
+ }
+
+ /* If there was a match, f will be one past the correct value. */
+ ret = f;
+ }
+
+ return ret;
+}
+
+/* kpse:lookup("plain.tex", {}) */
+static int do_lua_kpathsea_lookup(lua_State * L, kpathsea kpse, int idx)
+{
+ int i;
+ string ret = NULL;
+ string *ret_list = NULL;
+ const_string name = NULL;
+ string user_path = NULL;
+ boolean show_all = false;
+ boolean must_exist = false;
+ kpse_file_format_type user_format = kpse_last_format;
+ int dpi = 600;
+ str_list_type subdir_paths = { 0, NULL };
+ unsigned saved_debug = kpse->debug;
+ int saved_mktexpk = kpse->format_info[kpse_pk_format].program_enabled_p;
+ int saved_mktexmf = kpse->format_info[kpse_mf_format].program_enabled_p;
+ int saved_mktextex = kpse->format_info[kpse_tex_format].program_enabled_p;
+ int saved_mktextfm = kpse->format_info[kpse_tfm_format].program_enabled_p;
+ name = luaL_checkstring(L, idx);
+ /* todo: fetch parameter values */
+
+ if (lua_type(L, idx + 1) == LUA_TTABLE) {
+ lua_pushstring(L, "format");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ int op = luaL_checkoption(L, -1, NULL, filetypenames);
+ user_format = filetypes[op];
+ }
+ lua_pop(L, 1);
+ lua_pushstring(L, "dpi");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ dpi = (int) lua_tointeger(L, -1);
+ }
+ lua_pop(L, 1);
+ lua_pushstring(L, "debug");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ int d = 0;
+ d = (int) lua_tointeger(L, -1);
+ kpse->debug |= d;
+ }
+ lua_pop(L, 1);
+ lua_pushstring(L, "path");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ user_path = xstrdup(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+ lua_pushstring(L, "all");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ show_all = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "mktexpk");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ kpathsea_maketex_option(kpse, "pk", lua_toboolean(L, -1));
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "mktextex");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ kpathsea_maketex_option(kpse, "tex", lua_toboolean(L, -1));
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "mktexmf");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ kpathsea_maketex_option(kpse, "mf", lua_toboolean(L, -1));
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "mktextfm");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ kpathsea_maketex_option(kpse, "tfm", lua_toboolean(L, -1));
+ }
+ lua_pop(L, 1);
+
+
+ lua_pushstring(L, "mustexist");
+ lua_gettable(L, idx + 1);
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ must_exist = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+ lua_pushstring(L, "subdir");
+ lua_gettable(L, idx + 1);
+ if (lua_istable(L, -1)) {
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) { /* numeric value */
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ char *s = xstrdup(lua_tostring(L, -1));
+ str_list_add(&subdir_paths, s);
+ xfree(s);
+ }
+ lua_pop(L, 1);
+ }
+ } else if (lua_type(L, -1) == LUA_TSTRING) {
+ char *s = xstrdup(lua_tostring(L, -1));
+ str_list_add(&subdir_paths, s);
+ xfree(s);
+ }
+ lua_pop(L, 1);
+ if (STR_LIST_LENGTH(subdir_paths) > 0) {
+ show_all = 1;
+ }
+ }
+ if (user_path) {
+ /* Translate ; to : if that's our ENV_SEP. See cnf.c. */
+ if (IS_ENV_SEP(':')) {
+ string loc;
+ for (loc = user_path; *loc; loc++) {
+ if (*loc == ';')
+ *loc = ':';
+ }
+ }
+ user_path = kpathsea_path_expand(kpse, user_path);
+ if (show_all) {
+ ret_list = kpathsea_all_path_search(kpse, user_path, name);
+ } else {
+ ret = kpathsea_path_search(kpse, user_path, name, must_exist);
+ }
+ free(user_path);
+ } else {
+ /* No user-specified search path, check user format or guess from NAME. */
+ kpse_file_format_type fmt;
+ if (user_format != kpse_last_format)
+ fmt = user_format;
+ else
+ fmt = find_format(kpse, name, true);
+
+ switch (fmt) {
+ case kpse_pk_format:
+ case kpse_gf_format:
+ case kpse_any_glyph_format:
+ {
+ kpse_glyph_file_type glyph_ret;
+ string temp = remove_suffix (name);
+ /* Try to extract the resolution from the name. */
+ unsigned local_dpi = find_dpi(name);
+ if (!local_dpi)
+ local_dpi = (unsigned) dpi;
+ ret =
+ kpathsea_find_glyph(kpse, temp, local_dpi,
+ fmt, &glyph_ret);
+ if (temp != name)
+ free (temp);
+ }
+ break;
+
+ case kpse_last_format:
+ /* If the suffix isn't recognized, assume it's a tex file. */
+ fmt = kpse_tex_format;
+ /* fall through */
+
+ default:
+ if (show_all) {
+ ret_list =
+ kpathsea_find_file_generic(kpse, name, fmt, must_exist,
+ true);
+ } else {
+ ret = kpathsea_find_file(kpse, name, fmt, must_exist);
+ }
+ }
+ }
+
+ /* Turn single return into a null-terminated list for uniform treatment. */
+ if (ret) {
+ ret_list = XTALLOC(2, string);
+ ret_list[0] = ret;
+ ret_list[1] = NULL;
+ }
+
+ /* Filter by subdirectories, if specified. */
+ if (STR_LIST_LENGTH(subdir_paths) > 0) {
+ string *new_list = subdir_match(subdir_paths, ret_list);
+ free(ret_list);
+ ret_list = new_list;
+ }
+ kpse->debug = saved_debug;
+ kpse->format_info[kpse_pk_format].program_enabled_p = saved_mktexpk;
+ kpse->format_info[kpse_mf_format].program_enabled_p = saved_mktexmf;
+ kpse->format_info[kpse_tex_format].program_enabled_p = saved_mktextex;
+ kpse->format_info[kpse_tfm_format].program_enabled_p = saved_mktextfm;
+
+ /* Print output. */
+ i = 0;
+ if (ret_list) {
+ for (; ret_list[i]; i++) {
+ lua_pushstring(L, ret_list[i]);
+ }
+ free(ret_list);
+ }
+ if (i == 0) {
+ i++;
+ lua_pushnil(L);
+ }
+ return i;
+}
+
+
+static int lua_kpathsea_lookup(lua_State * L)
+{
+ kpathsea *kpsep = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ kpathsea kpse = *kpsep;
+ return do_lua_kpathsea_lookup(L, kpse, 2);
+}
+
+static int lua_kpse_lookup(lua_State * L)
+{
+ TEST_PROGRAM_NAME_SET;
+ return do_lua_kpathsea_lookup(L, kpse_def, 1);
+}
+
+
+/* Engine support is a bit of a problem, because we do not want
+ * to interfere with the normal format discovery of |luatex|.
+ * Current approach: run |os.setenv()| if you have to.
+ */
+
+static int set_program_name(lua_State * L)
+{
+ const char *exe_name = luaL_checkstring(L, 1);
+ const char *prog_name = luaL_optstring(L, 2, exe_name);
+ if (!program_name_set) {
+ kpse_set_program_name(exe_name, prog_name);
+ program_name_set = 1;
+ } else {
+ kpse_reset_program_name(prog_name);
+ }
+ /* fix up the texconfig entry */
+ lua_checkstack(L, 3);
+ lua_getglobal(L, "texconfig");
+ if (lua_istable(L, -1)) {
+ lua_pushstring(L, "kpse_init");
+ lua_pushboolean(L, 0);
+ lua_rawset(L, -3);
+ }
+ lua_pop(L, 1);
+ return 0;
+}
+
+static int init_prog(lua_State * L)
+{
+ const char *prefix = luaL_checkstring(L, 1);
+ unsigned dpi = (unsigned) luaL_checkinteger(L, 2);
+ const char *mode = luaL_checkstring(L, 3);
+ const char *fallback = luaL_optstring(L, 4, NULL);
+ TEST_PROGRAM_NAME_SET;
+ kpse_init_prog(prefix, dpi, mode, fallback);
+ return 0;
+}
+
+static int lua_kpathsea_init_prog(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ const char *prefix = luaL_checkstring(L, 2);
+ unsigned dpi = (unsigned) luaL_checkinteger(L, 3);
+ const char *mode = luaL_checkstring(L, 4);
+ const char *fallback = luaL_optstring(L, 5, NULL);
+ kpathsea_init_prog(*kp, prefix, dpi, mode, fallback);
+ return 0;
+}
+
+static int lua_kpse_version(lua_State * L)
+{
+ lua_pushstring(L, kpathsea_version_string);
+ return 1;
+}
+
+static int readable_file(lua_State * L)
+{
+ char *name = xstrdup(luaL_checkstring(L, 1));
+ TEST_PROGRAM_NAME_SET;
+ lua_pushstring(L, kpse_readable_file(name));
+ free(name);
+ return 1;
+}
+
+static int lua_kpathsea_readable_file(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ char *name = xstrdup(luaL_checkstring(L, 2));
+ lua_pushstring(L, kpathsea_readable_file(*kp, name));
+ free(name);
+ return 1;
+}
+
+
+static int lua_kpathsea_finish(lua_State * L)
+{
+ kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE);
+ kpathsea_finish(*kp);
+ return 0;
+}
+
+static int lua_kpathsea_new(lua_State * L)
+{
+ kpathsea kpse = NULL;
+ kpathsea *kp = NULL;
+ const char *av = luaL_checkstring(L, 1);
+ const char *liar = luaL_optstring(L, 2, av);
+ kpse = kpathsea_new();
+ kpathsea_set_program_name(kpse, av, liar);
+ kp = (kpathsea *) lua_newuserdata(L, sizeof(kpathsea *));
+ *kp = kpse;
+ luaL_getmetatable(L, KPATHSEA_METATABLE);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int lua_record_input_file(lua_State * L)
+{
+ const char *name = lua_tostring(L, 1);
+ if (name != NULL) {
+ recorder_record_input(name);
+ }
+ return 0;
+}
+
+static int lua_record_output_file(lua_State * L)
+{
+ const char *name = lua_tostring(L, 1);
+ if (name != NULL) {
+ recorder_record_output(name);
+ }
+ return 0;
+}
+
+/*tex moved here */
+
+static int lua_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 const struct luaL_Reg kpselib_m[] = {
+ {"__gc", lua_kpathsea_finish},
+ {"init_prog", lua_kpathsea_init_prog},
+ {"readable_file", lua_kpathsea_readable_file},
+ {"find_file", lua_kpathsea_find_file},
+ {"expand_path", lua_kpathsea_expand_path},
+ {"expand_var", lua_kpathsea_expand_var},
+ {"expand_braces", lua_kpathsea_expand_braces},
+ {"var_value", lua_kpathsea_var_value},
+ {"show_path", lua_kpathsea_show_path},
+ {"lookup", lua_kpathsea_lookup},
+ {"version", lua_kpse_version},
+ {"default_texmfcnf", show_texmfcnf},
+ {"record_input_file", lua_record_input_file},
+ {"record_output_file", lua_record_output_file},
+ /* sentinel */
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg kpselib_l[] = {
+ {"new", lua_kpathsea_new},
+ {"set_program_name", set_program_name},
+ {"init_prog", init_prog},
+ {"readable_file", readable_file},
+ {"find_file", find_file},
+ {"expand_path", expand_path},
+ {"expand_var", expand_var},
+ {"expand_braces", expand_braces},
+ {"var_value", var_value},
+ {"show_path", show_path},
+ {"lookup", lua_kpse_lookup},
+ {"version", lua_kpse_version},
+ {"default_texmfcnf", show_texmfcnf},
+ {"record_input_file", lua_record_input_file},
+ {"record_output_file", lua_record_output_file},
+ /* extra */
+ {"check_permission", lua_check_permissions},
+ /* sentinel */
+ {NULL, NULL}
+};
+
+int luaopen_kpse(lua_State * L)
+{
+ luaL_newmetatable(L, KPATHSEA_METATABLE);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_openlib(L, NULL, kpselib_m, 0);
+ luaL_openlib(L, "kpse", kpselib_l, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/llanglib.c b/Build/source/texk/web2c/luatexdir/lua/llanglib.c
new file mode 100644
index 00000000000..8f4e35f46e2
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/llanglib.c
@@ -0,0 +1,311 @@
+/* llanglib.c
+
+ Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define LANG_METATABLE "luatex.lang"
+
+#define check_islang(L,b) (struct tex_language **)luaL_checkudata(L,b,LANG_METATABLE)
+
+static int lang_new(lua_State * L)
+{
+ struct tex_language **lang;
+ if (lua_gettop(L) == 0) {
+ lang = lua_newuserdata(L, sizeof(struct tex_language *));
+ *lang = new_language(-1);
+ if (!*lang) {
+ return luaL_error(L, "lang.new(): no room for a new language");
+ }
+ } else {
+ int lualang;
+ lang = lua_newuserdata(L, sizeof(struct tex_language *));
+ lualang = lua_tointeger(L, 1);
+ *lang = get_language(lualang);
+ if (!*lang) {
+ return luaL_error(L, "lang.new(%d): undefined language", lualang);
+ }
+ }
+ luaL_getmetatable(L, LANG_METATABLE);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int lang_id(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ lua_pushinteger(L, (*lang_ptr)->id);
+ return 1;
+}
+
+static int lang_patterns(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TSTRING) {
+ return luaL_error(L, "lang.patterns(): argument should be a string");
+ }
+ load_patterns(*lang_ptr, (const unsigned char *) lua_tostring(L, 2));
+ return 0;
+ } else {
+ if ((*lang_ptr)->patterns != NULL) {
+ lua_pushstring(L, (char *) hnj_serialize((*lang_ptr)->patterns));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ }
+}
+
+static int lang_clear_patterns(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ clear_patterns(*lang_ptr);
+ return 0;
+}
+
+static int lang_hyphenation(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TSTRING) {
+ return luaL_error(L, "lang.hyphenation(): argument should be a string");
+ }
+ load_hyphenation(*lang_ptr, (const unsigned char *) lua_tostring(L, 2));
+ return 0;
+ } else {
+ if ((*lang_ptr)->exceptions != 0) {
+ lua_pushstring(L, exception_strings(*lang_ptr));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ }
+}
+
+static int lang_pre_hyphen_char(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.prehyphenchar(): argument should be a character number");
+ }
+ (*lang_ptr)->pre_hyphen_char = (int) lua_tointeger(L, 2);
+ return 0;
+ } else {
+ lua_pushinteger(L, (*lang_ptr)->pre_hyphen_char);
+ return 1;
+ }
+}
+
+static int lang_post_hyphen_char(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.posthyphenchar(): argument should be a character number");
+ }
+ (*lang_ptr)->post_hyphen_char = (int) lua_tointeger(L, 2);
+ return 0;
+ } else {
+ lua_pushinteger(L, (*lang_ptr)->post_hyphen_char);
+ return 1;
+ }
+}
+
+static int lang_pre_exhyphen_char(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.preexhyphenchar(): argument should be a character number");
+ }
+ (*lang_ptr)->pre_exhyphen_char = (int) lua_tointeger(L, 2);
+ return 0;
+ } else {
+ lua_pushinteger(L, (*lang_ptr)->pre_exhyphen_char);
+ return 1;
+ }
+}
+
+static int lang_sethjcode(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.sethjcode(): argument should be a character number");
+ } else {
+ int i = (int) lua_tointeger(L, 2) ;
+ if (lua_type(L, 3) == LUA_TNUMBER) {
+ set_hj_code((*lang_ptr)->id,i,(int) lua_tointeger(L, 3),-1);
+ } else {
+ set_hj_code((*lang_ptr)->id,i,i,-1);
+ }
+ }
+ return 0;
+}
+
+static int lang_gethjcode(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.gethjcode(): argument should be a character number");
+ } else {
+ lua_pushinteger(L, get_hj_code((*lang_ptr)->id,lua_tointeger(L, 2)));
+ }
+ return 1;
+}
+
+static int lang_post_exhyphen_char(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.postexhyphenchar(): argument should be a character number");
+ }
+ (*lang_ptr)->post_exhyphen_char = (int) lua_tointeger(L, 2);
+ return 0;
+ } else {
+ lua_pushinteger(L, (*lang_ptr)->post_exhyphen_char);
+ return 1;
+ }
+}
+
+static int lang_hyphenation_min(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lua_gettop(L) != 1) {
+ if (lua_type(L, 2) != LUA_TNUMBER) {
+ return luaL_error(L, "lang.hyphenationmin(): argument should be a number");
+ }
+ (*lang_ptr)->hyphenation_min = (int) lua_tointeger(L, 2);
+ return 0;
+ } else {
+ lua_pushinteger(L, (*lang_ptr)->hyphenation_min);
+ return 1;
+ }
+}
+
+static int lang_clear_hyphenation(lua_State * L)
+{
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ clear_hyphenation(*lang_ptr);
+ return 0;
+}
+
+static int do_lang_clean(lua_State * L)
+{
+ char *cleaned;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ (void) clean_hyphenation(cur_lang_par, lua_tostring(L, 1), &cleaned);
+ } else {
+ struct tex_language **lang_ptr;
+ lang_ptr = check_islang(L, 1);
+ if (lang_ptr == NULL) {
+ return luaL_error(L, "lang.clean(): first argument should be a string or language");
+ } else if (lua_type(L, 2) != LUA_TSTRING) {
+ return luaL_error(L, "lang.clean(): second argument should be a string");
+ } else {
+ (void) clean_hyphenation((*lang_ptr)->id,lua_tostring(L, 2), &cleaned);
+ }
+ }
+ lua_pushstring(L, cleaned);
+ return 1;
+}
+
+static int do_lang_hyphenate(lua_State * L)
+{
+ halfword t = null;
+ halfword h = *check_isnode(L, 1);
+ if (lua_isuserdata(L, 2)) {
+ t = *check_isnode(L, 2);
+ }
+ if (t == null) {
+ t = h;
+ while (vlink(t) != null) {
+ t = vlink(t);
+ }
+ }
+ hnj_hyphenation(h, t);
+ lua_nodelib_push_fast(L, h);
+ lua_nodelib_push_fast(L, t);
+ lua_pushboolean(L, 1);
+ return 3;
+}
+
+static const struct luaL_Reg langlib_d[] = {
+ {"clear_patterns", lang_clear_patterns},
+ {"clear_hyphenation", lang_clear_hyphenation},
+ {"patterns", lang_patterns},
+ {"hyphenation", lang_hyphenation},
+ {"prehyphenchar", lang_pre_hyphen_char},
+ {"posthyphenchar", lang_post_hyphen_char},
+ {"preexhyphenchar", lang_pre_exhyphen_char},
+ {"postexhyphenchar", lang_post_exhyphen_char},
+ {"hyphenationmin", lang_hyphenation_min},
+ {"sethjcode", lang_sethjcode},
+ {"gethjcode", lang_gethjcode},
+ {"id", lang_id},
+ /*tex sentinel */
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg langlib[] = {
+ {"clear_patterns", lang_clear_patterns},
+ {"clear_hyphenation", lang_clear_hyphenation},
+ {"patterns", lang_patterns},
+ {"hyphenation", lang_hyphenation},
+ {"prehyphenchar", lang_pre_hyphen_char},
+ {"posthyphenchar", lang_post_hyphen_char},
+ {"preexhyphenchar", lang_pre_exhyphen_char},
+ {"postexhyphenchar", lang_post_exhyphen_char},
+ {"hyphenationmin", lang_hyphenation_min},
+ {"sethjcode", lang_sethjcode},
+ {"gethjcode", lang_gethjcode},
+ {"id", lang_id},
+ {"clean", do_lang_clean},
+ {"hyphenate", do_lang_hyphenate},
+ {"new", lang_new},
+ /*tex sentinel */
+ {NULL, NULL}
+};
+
+int luaopen_lang(lua_State * L)
+{
+ luaL_newmetatable(L, LANG_METATABLE);
+ /*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/Build/source/texk/web2c/luatexdir/lua/llualib.c b/Build/source/texk/web2c/luatexdir/lua/llualib.c
new file mode 100644
index 00000000000..0586aba026e
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/llualib.c
@@ -0,0 +1,425 @@
+/* llualib.c
+
+ Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#define LOAD_BUF_SIZE 64*1024
+#define UINT_MAX32 0xFFFFFFFF
+
+typedef struct {
+ unsigned char *buf;
+ int size;
+ /* int done; */
+ int alloc;
+} bytecode;
+
+static bytecode *lua_bytecode_registers = NULL;
+
+int luabytecode_max = -1;
+unsigned int luabytecode_bytes = 0;
+
+char *luanames[65536] = { NULL };
+
+char *get_lua_name(int i)
+{
+ if (i < 0 || i > 65535)
+ return NULL;
+ return luanames[i];
+}
+
+void dump_luac_registers(void)
+{
+ int x;
+ int k, n;
+ bytecode b;
+ dump_int(luabytecode_max);
+ if (lua_bytecode_registers != NULL) {
+ n = 0;
+ for (k = 0; k <= luabytecode_max; k++) {
+ if (lua_bytecode_registers[k].size != 0)
+ n++;
+ }
+ dump_int(n);
+ for (k = 0; k <= luabytecode_max; k++) {
+ b = lua_bytecode_registers[k];
+ if (b.size != 0) {
+ dump_int(k);
+ dump_int(b.size);
+ do_zdump((char *) b.buf, 1, (b.size), DUMP_FILE);
+ }
+ }
+ }
+ for (k = 0; k < 65536; k++) {
+ char *a = luanames[k];
+ if (a != NULL) {
+ x = (int) strlen(a) + 1;
+ dump_int(x);
+ dump_things(*a, x);
+ } else {
+ x = 0;
+ dump_int(x);
+ }
+ }
+}
+
+void undump_luac_registers(void)
+{
+ int x;
+ int k, n;
+ unsigned int i;
+ bytecode b;
+ undump_int(luabytecode_max);
+ if (luabytecode_max >= 0) {
+ i = (unsigned) (luabytecode_max + 1);
+ if ((int) (UINT_MAX32 / (int) sizeof(bytecode) + 1) <= i) {
+ fatal_error("Corrupt format file");
+ }
+ 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].size = 0;
+ lua_bytecode_registers[i].buf = NULL;
+ }
+ undump_int(n);
+ for (i = 0; i < (unsigned) n; i++) {
+ undump_int(k);
+ undump_int(x);
+ b.size = x;
+ b.buf = xmalloc((unsigned) b.size);
+ luabytecode_bytes += (unsigned) b.size;
+ memset(b.buf, 0, (size_t) b.size);
+ do_zundump((char *) b.buf, 1, b.size, DUMP_FILE);
+ lua_bytecode_registers[k].size = b.size;
+ lua_bytecode_registers[k].alloc = b.size;
+ lua_bytecode_registers[k].buf = b.buf;
+ }
+ }
+ for (k = 0; k < 65536; k++) {
+ undump_int(x);
+ if (x > 0) {
+ char *s = xmalloc((unsigned) x);
+ undump_things(*s, x);
+ luanames[k] = s;
+ }
+ }
+}
+
+static void bytecode_register_shadow_set(lua_State * L, int k)
+{
+ /* the stack holds the value to be set */
+ lua_get_metatablelua(lua_bytecodes_indirect);
+ if (lua_istable(L, -1)) {
+ lua_pushvalue(L, -2);
+ lua_rawseti(L, -2, k);
+ }
+ lua_pop(L, 1); /* pop table or nil */
+ lua_pop(L, 1); /* pop value */
+}
+
+
+static int bytecode_register_shadow_get(lua_State * L, int k)
+{
+ /* the stack holds the value to be set */
+ int ret = 0;
+ lua_get_metatablelua(lua_bytecodes_indirect);
+ if (lua_istable(L, -1)) {
+ lua_rawgeti(L, -1, k);
+ if (!lua_isnil(L, -1))
+ ret = 1;
+ lua_insert(L, -3); /* store the value or nil, deeper down */
+ lua_pop(L, 1); /* pop the value or nil at top */
+ }
+ lua_pop(L, 1); /* pop table or nil */
+ return ret;
+}
+
+
+static int writer(lua_State * L, const void *b, size_t size, void *B)
+{
+ bytecode *buf = (bytecode *) B;
+ (void) L; /* for -Wunused */
+ if ((int) (buf->size + (int) size) > buf->alloc) {
+ buf->buf = xrealloc(buf->buf, (unsigned) (buf->alloc + (int) size + LOAD_BUF_SIZE));
+ buf->alloc = buf->alloc + (int) size + LOAD_BUF_SIZE;
+ }
+ memcpy(buf->buf + buf->size, b, size);
+ buf->size += (int) size;
+ luabytecode_bytes += (unsigned) size;
+ return 0;
+}
+
+static const char *reader(lua_State * L, void *ud, size_t * size)
+{
+ bytecode *buf = (bytecode *) ud;
+ (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;
+}
+
+static int get_bytecode(lua_State * L)
+{
+ int k;
+ k = (int) luaL_checkinteger(L, -1);
+ if (k < 0) {
+ lua_pushnil(L);
+ } else if (!bytecode_register_shadow_get(L, k)) {
+ if (k <= luabytecode_max && lua_bytecode_registers[k].buf != NULL) {
+ if (lua_load
+ (L, reader, (void *) (lua_bytecode_registers + k),
+#ifdef LuajitTeX
+ "bytecode")) {
+#else
+ "bytecode", NULL)) {
+#endif
+ return luaL_error(L, "bad bytecode register");
+ } else {
+ lua_pushvalue(L, -1);
+ bytecode_register_shadow_set(L, k);
+ }
+ } else {
+ lua_pushnil(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;
+ unsigned int i;
+ int strip = 0;
+ int top = lua_gettop(L);
+ if (lua_type(L,top) == LUA_TBOOLEAN) {
+ strip = lua_toboolean(L,top);
+ lua_settop(L,top - 1);
+ }
+ k = (int) luaL_checkinteger(L, -2);
+ i = (unsigned) k + 1;
+ if ((int) (UINT_MAX32 / sizeof(bytecode) + 1) < i) {
+ luaL_error(L, "value too large");
+ }
+ if (k < 0) {
+ luaL_error(L, "negative values not allowed");
+ }
+ ltype = lua_type(L, -1);
+ if (ltype != LUA_TFUNCTION && ltype != LUA_TNIL) {
+ luaL_error(L, "unsupported type");
+ }
+ if (k > luabytecode_max) {
+ i = (unsigned) (sizeof(bytecode) * ((unsigned) k + 1));
+ lua_bytecode_registers = xrealloc(lua_bytecode_registers, i);
+ if (luabytecode_max == -1) {
+ luabytecode_bytes +=
+ (unsigned) (sizeof(bytecode) * (unsigned) (k + 1));
+ } else {
+ luabytecode_bytes +=
+ (unsigned) (sizeof(bytecode) *
+ (unsigned) (k + 1 - luabytecode_max));
+ }
+ 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; */
+ }
+ luabytecode_max = k;
+ }
+ if (lua_bytecode_registers[k].buf != NULL) {
+ 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_pushnil(L);
+ bytecode_register_shadow_set(L, k);
+ }
+ if (ltype == LUA_TFUNCTION) {
+ lua_bytecode_registers[k].buf = xmalloc(LOAD_BUF_SIZE);
+ lua_bytecode_registers[k].alloc = LOAD_BUF_SIZE;
+ memset(lua_bytecode_registers[k].buf, 0, LOAD_BUF_SIZE);
+#ifdef LuajitTeX
+ RESERVED_lua_dump(L, writer, (void *) (lua_bytecode_registers + k),strip);
+ /*lua_dump(L, writer, (void *) (lua_bytecode_registers + k));*/
+#else
+#if LUA_VERSION_NUM == 503
+ 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));
+#endif
+#endif
+ }
+ lua_pop(L, 1);
+ return 0;
+}
+
+
+static int set_luaname(lua_State * L)
+{
+ int k;
+ const char *s;
+ if (lua_gettop(L) == 3) {
+ k = (int) luaL_checkinteger(L, 2);
+ if (k > 65535 || k < 0) {
+ /* error */
+ } else {
+ if (luanames[k] != NULL) {
+ free(luanames[k]);
+ luanames[k] = NULL;
+ }
+ if (lua_type(L,3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (s != NULL)
+ luanames[k] = xstrdup(s);
+ }
+ }
+ }
+ return 0;
+}
+
+static int get_luaname(lua_State * L)
+{
+ int k = (int) luaL_checkinteger(L, 2);
+ if (k > 65535 || k < 0) {
+ /* error */
+ lua_pushnil(L);
+ } else {
+ if (luanames[k] != NULL)
+ lua_pushstring(L, luanames[k]);
+ else
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_functions_get_table(lua_State * L) /* hh */
+{
+ lua_get_metatablelua(lua_functions);
+ return 1;
+}
+
+static int new_table(lua_State * L) /* hh */
+{
+ int i = (int) luaL_checkinteger(L, 1);
+ int h = (int) luaL_checkinteger(L, 2);
+ lua_createtable(L,i,h);
+ 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 int get_code_page(lua_State *L)
+{
+# ifdef _WIN32
+ lua_pushinteger(L,(int) GetOEMCP());
+ lua_pushinteger(L,(int) GetACP());
+# else
+ lua_pushboolean(L,0);
+ lua_pushboolean(L,0);
+# endif
+ return 2;
+}
+
+static const struct luaL_Reg lualib[] = {
+ /* *INDENT-OFF* */
+ {"getluaname", get_luaname},
+ {"setluaname", set_luaname},
+ {"getbytecode", get_bytecode},
+ {"setbytecode", set_bytecode},
+ {"newtable", new_table},
+ {"get_functions_table",lua_functions_get_table},
+ {"getstacktop", get_stack_top},
+ {"getcalllevel", get_call_level},
+ {"getcodepage", get_code_page },
+ /* *INDENT-ON* */
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_lua(lua_State * L, char *fname)
+{
+ luaL_openlib(L, "lua", lualib, 0);
+ make_table(L, "bytecode", "tex.bytecode", "getbytecode", "setbytecode");
+ make_table(L, "name", "tex.name", "getluaname", "setluaname");
+ lua_newtable(L);
+ lua_setfield(L, LUA_REGISTRYINDEX, "lua.bytecodes.indirect");
+ lua_pushstring(L, LUA_VERSION);
+ lua_setfield(L, -2, "version");
+ if (fname == NULL) {
+ lua_pushnil(L);
+ } else {
+ lua_pushstring(L, fname);
+ }
+ lua_setfield(L, -2, "startupfile");
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lnewtokenlib.c b/Build/source/texk/web2c/luatexdir/lua/lnewtokenlib.c
new file mode 100644
index 00000000000..d0047919c7f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lnewtokenlib.c
@@ -0,0 +1,1413 @@
+/* lnewtokenlib.c
+
+ Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+
+/*
+ This module is unfinished and an intermediate step to removal of the old
+ token lib. Between version 0.80 and 0.85 the transition will be complete
+ and at the same time the input (buffer) handling will be cleaned up and
+ simplified. At that moment we can feed back tokens into the input.
+
+ The code can be optimized a bit by faster key checking. The scan functions
+ implemented here will stay functionally the same but can be improved if
+ needed. The old triplet model will disappear.
+
+*/
+
+#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;
+ int origin;
+ int save_cmd, save_chr, save_cs, save_tok;
+} saved_tex_scanner;
+
+#define save_tex_scanner(a) do { \
+ a.save_cmd = cur_cmd; \
+ a.save_chr = cur_chr; \
+ a.save_cs = cur_cs; \
+ a.save_tok = cur_tok; \
+ } while (0)
+
+#define unsave_tex_scanner(a) do { \
+ cur_cmd = a.save_cmd; \
+ cur_chr = a.save_chr; \
+ cur_cs = a.save_cs; \
+ cur_tok = a.save_tok; \
+ } while (0)
+
+#define TEX_ORIGIN 0 /* not used yet */
+#define LUA_ORIGIN 1
+
+static lua_token *check_istoken(lua_State * L, int ud);
+
+#define TOKEN_METATABLE "luatex.token"
+
+#define DEBUG 0
+#define DEBUG_OUT stdout
+
+#define DEFAULT_SCAN_CODE_SET 2048 + 4096 /* default: letter and other */
+
+/* two core helpers */
+
+#define is_active_string(s) (strlen((char *)s)>3 && *s==0xEF && *(s+1)==0xBF && *(s+2)==0xBF)
+
+void make_token_table(lua_State * L, int cmd, int chr, int cs)
+{
+ lua_createtable(L, 3, 0);
+ lua_pushinteger(L, cmd);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, chr);
+ lua_rawseti(L, -2, 2);
+ lua_pushinteger(L, cs);
+ lua_rawseti(L, -2, 3);
+}
+
+static unsigned char *get_cs_text(int cs)
+{
+ if (cs == null_cs)
+ return (unsigned char *) xstrdup("\\csname\\endcsname");
+ else if ((cs_text(cs) < 0) || (cs_text(cs) >= str_ptr))
+ return (unsigned char *) xstrdup("");
+ else
+ return (unsigned char *) makecstring(cs_text(cs));
+}
+
+/* maybe this qualify as a macro, not function */
+
+static lua_token *maybe_istoken(lua_State * L, int ud)
+{
+ lua_token *p = lua_touserdata(L, ud);
+ if (p != NULL) {
+ if (lua_getmetatable(L, ud)) {
+ lua_get_metatablelua(luatex_token);
+ if (!lua_rawequal(L, -1, -2))
+ p = NULL;
+ lua_pop(L, 2);
+ }
+ }
+ return p;
+}
+
+/* we could make the message a function and just inline the rest (via a macro) */
+
+lua_token *check_istoken(lua_State * L, int ud)
+{
+ lua_token *p = maybe_istoken(L, ud);
+ if (p != NULL)
+ return p;
+ formatted_error("token lib","lua <token> expected, not an object with type %s", luaL_typename(L, ud));
+ return NULL;
+}
+
+/* token library functions */
+
+static void make_new_token(lua_State * L, int cmd, int chr, int cs)
+{
+ int tok = 0;
+ lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
+ thetok->origin = LUA_ORIGIN;
+ fast_get_avail(thetok->token);
+ tok = (cs ? cs_token_flag + cs : token_val(cmd, chr));
+ set_token_info(thetok->token, tok);
+ lua_get_metatablelua(luatex_token);
+ lua_setmetatable(L, -2);
+}
+
+static void push_token(lua_State * L, int tok)
+{
+ lua_token *thetok = lua_newuserdata(L, sizeof(lua_token));
+ thetok->origin = LUA_ORIGIN;
+ thetok->token = tok;
+ lua_get_metatablelua(luatex_token);
+ lua_setmetatable(L, -2);
+}
+
+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)
+{
+ saved_tex_scanner texstate;
+ save_tex_scanner(texstate);
+ get_next();
+ make_new_token(L, cur_cmd, cur_chr, cur_cs);
+ unsave_tex_scanner(texstate);
+ return 1;
+}
+
+/*
+ This is experimental code:
+
+ local t1 = token.get_next()
+ local t2 = token.get_next()
+ local t3 = token.get_next()
+ local t4 = token.get_next()
+ -- watch out, we flush in sequence
+ token.put_next { t1, t2 }
+ -- but this one gets pushed in front
+ token.put_next ( t3, t4 )
+ -- so when we get wxyz we put yzwx!
+
+ At some point we can consider a token.print that delays and goes via
+ the same rope mechanism as texio.prints and friends but then one can
+ as well serialize the tokens and do a normal print so there is no real
+ gain in it. After all, the tokenlib operates at the input level so we
+ might as well keep it there.
+
+*/
+
+inline static int run_put_next(lua_State * L)
+{
+ int n = lua_gettop(L);
+ int m = 0;
+ int i = 0;
+ halfword h = null;
+ halfword t = null;
+ halfword x = null;
+ lua_token *p ;
+ if (n == 0) {
+ /* we accept a single nil argument */
+ return 0;
+ }
+ lua_get_metatablelua(luatex_token);
+ m = lua_gettop(L);
+ if (lua_type(L,1) == LUA_TTABLE) {
+ if (n>1) {
+ normal_error("token lib","only one table permitted in put_next");
+ } else {
+ for (i = 1;; i++) {
+ lua_rawgeti(L, 1, i); /* table mt token */
+ if (lua_type(L,-1) == LUA_TNIL) {
+ break;
+ } else {
+ p = lua_touserdata(L, -1);
+ if (p == NULL) {
+ normal_error("token lib","lua <token> expected in put_next (1)");
+ } else if (!lua_getmetatable(L, -1)) { /* table mt token mt */
+ normal_error("token lib","lua <token> expected in put_next (2)");
+ } else if (!lua_rawequal(L, m, -1)) {
+ normal_error("token lib","lua <token> expected in put_next (3)");
+ } else {
+ fast_get_avail(x) ;
+ token_info(x) = token_info(p->token);
+ if (h == null) {
+ h = x;
+ } else {
+ token_link(t) = x;
+ }
+ t = x;
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ }
+ }
+ }
+ } else {
+ for (i = 1; i <= n; i++) {
+ p = lua_touserdata(L,i);
+ if (p == NULL) {
+ normal_error("token lib","lua <token> expected in put_next (4)");
+ } else if (!lua_getmetatable(L, i)) { /* table mt token mt */
+ normal_error("token lib","lua <token> expected in put_next (5)");
+ } else if (!lua_rawequal(L, m, -1)) {
+ normal_error("token lib","lua <token> expected in put_next (6)");
+ } else {
+ fast_get_avail(x) ;
+ token_info(x) = token_info(p->token);
+ if (h == null) {
+ h = x;
+ } else {
+ token_link(t) = x;
+ }
+ t = x;
+ }
+ lua_pop(L, 1);
+ }
+ }
+ if (h == null) {
+ /* can't happen */
+ } else {
+ begin_token_list(h,0);
+ }
+ lua_settop(L,n);
+ return 0;
+}
+
+static int run_scan_keyword(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(s)) {
+ v = 1;
+ }
+ unsave_tex_scanner(texstate);
+ }
+ lua_pushboolean(L,v);
+ 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;
+ int t;
+ saved_tex_scanner texstate;
+ save_tex_scanner(texstate);
+ get_next();
+ t = (cur_cs ? cs_token_flag + cur_cs : token_val(cur_cmd, cur_chr));
+ if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
+ if (is_active_string(s))
+ lua_pushstring(L, (char *) (s + 3));
+ else
+ lua_pushstring(L, (char *) s);
+ } else {
+ lua_pushnil(L);
+ }
+ unsave_tex_scanner(texstate);
+ return 1;
+}
+
+static int run_scan_int(lua_State * L)
+{
+ saved_tex_scanner texstate;
+ int v = 0;
+ save_tex_scanner(texstate);
+ scan_int();
+ v = cur_val;
+ unsave_tex_scanner(texstate);
+ lua_pushinteger(L,(int)v);
+ 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 <= 127) { \
+ luaL_addchar(&b,(unsigned) (char) chr); \
+ } else { \
+ uindex = uni2string((char *)word,(unsigned int) 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;
+ int v = 0, o = 0;
+ int inf = false, mu = false;
+ int t = lua_gettop(L);
+ if (t>0)
+ inf = lua_toboolean(L,1); /* inf values allowed ?*/
+ if (t>1)
+ mu = lua_toboolean(L,2); /* mu units required ?*/
+ save_tex_scanner(texstate);
+ scan_dimen(mu,inf, false); /* arg3 = shortcut */
+ v = cur_val;
+ o = cur_order;
+ unsave_tex_scanner(texstate);
+ lua_pushinteger(L,v);
+ if (inf) {
+ lua_pushinteger(L,(lua_Number)o);
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+static int run_scan_glue(lua_State * L)
+{
+ saved_tex_scanner texstate;
+ int v = 0;
+ int mu = false;
+ int t = lua_gettop(L);
+ if (t>0)
+ mu = lua_toboolean(L,1); /* mu units required ?*/
+ save_tex_scanner(texstate);
+ scan_glue((mu ? mu_val_level : glue_val_level));
+ v = cur_val; /* which is a glue_spec node */
+ unsave_tex_scanner(texstate);
+ lua_nodelib_push_fast(L,(halfword)v);
+ return 1;
+}
+
+static int run_scan_toks(lua_State * L)
+{
+ saved_tex_scanner texstate;
+ int macro_def = false, xpand = false;
+ halfword t, saved_defref;
+ int i = 1;
+ int top = lua_gettop(L);
+ if (top>0)
+ macro_def = lua_toboolean(L,1); /* \\def ? */
+ if (top>1)
+ xpand = lua_toboolean(L,2); /* expand ? */
+ save_tex_scanner(texstate);
+ saved_defref = def_ref;
+ (void) scan_toks(macro_def, xpand);
+ t = def_ref;
+ unsave_tex_scanner(texstate);
+ def_ref = saved_defref;
+ /* 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. */
+ lua_newtable(L);
+ while (token_link(t)) {
+ t = token_link(t);
+ push_token(L,t);
+ lua_rawseti(L,-2,i++);
+ }
+ return 1;
+}
+
+static int run_scan_string(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_x_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);
+ flush_list(t);
+ } else if (cur_cmd == call_cmd) {
+ t = token_link(cur_chr);
+ tokenlist_to_luastring(L,t);
+ flush_list(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 {
+ 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) {
+ int exp = 1;
+ if (lua_type(L, 1) == LUA_TBOOLEAN) {
+ exp = lua_toboolean(L, 1);
+ }
+ back_input();
+ saved_defref = def_ref;
+ (void) scan_toks(false, exp);
+ t = def_ref;
+ def_ref = saved_defref;
+ tokenlist_to_luastring(L,t);
+ flush_list(t);
+ } else if (cur_cmd == call_cmd) {
+ halfword saved_cur_tok = cur_tok;
+ int exp = 1;
+ if (lua_type(L, 1) == LUA_TBOOLEAN) {
+ exp = lua_toboolean(L, 1);
+ }
+ cur_tok = right_brace_token + '}';
+ back_input();
+ if (exp) {
+ cur_tok = saved_cur_tok;
+ back_input();
+ } else {
+ expand();
+ }
+ cur_tok = left_brace_token + '{';
+ back_input();
+ saved_defref = def_ref;
+ (void) scan_toks(false, exp);
+ t = def_ref;
+ def_ref = saved_defref;
+ tokenlist_to_luastring(L,t);
+ flush_list(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 {
+ back_input();
+ lua_pushnil(L);
+ }
+ unsave_tex_scanner(texstate);
+ return 1;
+}
+
+static int run_scan_word(lua_State * L) /* HH */
+{
+ saved_tex_scanner texstate;
+ save_tex_scanner(texstate);
+ do {
+ get_x_token();
+ } while ((cur_cmd == spacer_cmd) || (cur_cmd == relax_cmd));
+ 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 {
+ back_input();
+ lua_pushnil(L);
+ }
+ unsave_tex_scanner(texstate);
+ return 1;
+}
+
+static int run_scan_code(lua_State * L) /* HH */
+{
+ saved_tex_scanner texstate;
+ int cc = DEFAULT_SCAN_CODE_SET ;
+ save_tex_scanner(texstate);
+ get_x_token();
+ if (cur_cmd < 16) {
+ if (lua_gettop(L)>0) {
+ cc = (int) lua_tointeger(L,-1);
+ if (cc == null) {
+ /* todo: message that we choose a default */
+ cc = DEFAULT_SCAN_CODE_SET ;
+ }
+ }
+ if (cc & (1<<(cur_cmd))) {
+ lua_pushinteger(L,(int)cur_chr);
+ } else {
+ lua_pushnil(L);
+ back_input();
+ }
+ } else {
+ lua_pushnil(L);
+ back_input();
+ }
+ unsave_tex_scanner(texstate);
+ return 1;
+}
+
+static int lua_tokenlib_is_token(lua_State * L) /* HH */
+{
+ lua_pushboolean(L,maybe_istoken(L,1)==NULL ? 0 : 1);
+ return 1;
+}
+
+static int run_expand(lua_State * L)
+{
+ (void) L;
+ expand();
+ return 0;
+}
+
+static int run_lookup(lua_State * L)
+{
+ const char *s;
+ size_t l;
+ int cs, cmd, chr;
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ s = lua_tolstring(L, -1, &l);
+ if (l > 0) {
+ cs = string_lookup(s, l);
+ cmd = eq_type(cs);
+ chr = equiv(cs);
+ make_new_token(L, cmd, chr, cs);
+ return 1;
+ }
+ }
+ lua_pushnil(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 lua_tokenlib_is_defined(lua_State * L)
+{
+ int b = 0;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ size_t l;
+ const char *s = lua_tolstring(L, 1, &l);
+ if (l > 0) {
+ int cs = string_lookup(s, l);
+ if (lua_toboolean(L, 2)) {
+ b = cs != undefined_control_sequence;
+ } else {
+ b = eq_type(cs) != undefined_cs_cmd;
+ }
+ }
+ }
+ lua_pushboolean(L, b);
+ return 1;
+}
+
+static int run_build(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int cs = 0;
+ int chr = (int) lua_tointeger(L, 1);
+ int cmd = (int) luaL_optinteger(L, 2, get_cat_code(cat_code_table_par,chr));
+ if (cmd == 0 || cmd == 9 || cmd == 14 || cmd == 15) {
+ formatted_warning("token lib","not a good token, catcode %i can not be returned, so 12 will be used",(int) cmd);
+ cmd = 12;
+ } else if (cmd == 13) {
+ cs = active_to_cs(chr, false);
+ cmd = eq_type(cs);
+ chr = equiv(cs);
+ }
+ make_new_token(L, cmd, chr, cs);
+ return 1;
+ } else {
+ return run_lookup(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)
+{
+ lua_token *n;
+ n = check_istoken(L, 1);
+ if (n->origin == LUA_ORIGIN) {
+ free_avail(n->token);
+ }
+ return 1;
+}
+
+/* fast accessors */
+
+inline static int lua_tokenlib_get_command(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ if (t >= cs_token_flag) {
+ lua_pushinteger(L,(int) eq_type((t - cs_token_flag)));
+ } else {
+ lua_pushinteger(L, token_cmd(t));
+ }
+ return 1;
+}
+
+inline static int lua_tokenlib_get_index(lua_State * L)
+{
+ int cmd, chr;
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ if (t >= cs_token_flag) {
+ cmd = eq_type(t - cs_token_flag);
+ chr = equiv(t - cs_token_flag);
+ } else {
+ cmd = token_cmd(t);
+ chr = token_chr(t);
+ }
+ switch (cmd) {
+ case assign_int_cmd:
+ chr -= count_base;
+ break;
+ case assign_attr_cmd:
+ chr -= attribute_base;
+ break;
+ case assign_dimen_cmd:
+ chr -= scaled_base;
+ break;
+ case assign_glue_cmd:
+ chr -= skip_base;
+ break;
+ case assign_mu_glue_cmd:
+ chr -= mu_skip_base;
+ break;
+ case assign_toks_cmd:
+ chr -= toks_base;
+ break;
+ default:
+ break;
+ }
+ if (chr >= 0 && chr <= 65535) {
+ lua_pushinteger(L, chr);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+inline static int lua_tokenlib_get_mode(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ if (t >= cs_token_flag) {
+ lua_pushinteger(L, equiv(t - cs_token_flag));
+ } else {
+ lua_pushinteger(L, token_chr(t));
+ }
+ return 1;
+}
+
+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_push_string_by_index(L, command_names[cmd].lua);
+ return 1;
+}
+
+inline static int lua_tokenlib_get_csname(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ unsigned char *s;
+ if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
+ if (is_active_string(s))
+ lua_pushstring(L, (char *) (s + 3));
+ else
+ lua_pushstring(L, (char *) s);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+inline static int lua_tokenlib_get_id(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ lua_pushinteger(L, n->token);
+ return 1;
+}
+
+inline static int lua_tokenlib_get_tok(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ lua_pushinteger(L, t);
+ return 1;
+}
+
+inline static int lua_tokenlib_get_active(lua_State * L)
+{
+ lua_token *n = check_istoken(L, 1);
+ halfword t = token_info(n->token);
+ unsigned char *s;
+ if (t >= cs_token_flag && ((s = get_cs_text(t - cs_token_flag)) != (unsigned char *) NULL)) {
+ if (is_active_string(s))
+ lua_pushboolean(L,1);
+ else
+ lua_pushboolean(L,0);
+ free(s);
+ } else {
+ lua_pushboolean(L,0);
+ }
+ return 1;
+}
+
+inline static int lua_tokenlib_get_expandable(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));
+ if (cmd > max_command_cmd) {
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ return 1;
+}
+
+inline static int lua_tokenlib_get_protected(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));
+ if (cmd > max_command_cmd && (cmd >= call_cmd) && (cmd < end_template_cmd)) {
+ int chr = (t >= cs_token_flag ? equiv(t - cs_token_flag) : token_chr(t));
+ if (token_info(token_link(chr)) == protected_token) {
+ lua_pushboolean(L, 1);
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ } else {
+ lua_pushboolean(L, 0);
+ }
+ return 1;
+}
+
+static int lua_tokenlib_getfield(lua_State * L)
+{
+ const char *s = lua_tostring(L, 2);
+ if (lua_key_eq(s, command)) {
+ return lua_tokenlib_get_command(L);
+ } else if (lua_key_eq(s, index)) {
+ return lua_tokenlib_get_index(L);
+ } else if (lua_key_eq(s, mode)) {
+ return lua_tokenlib_get_mode(L);
+ } else if (lua_key_eq(s, cmdname)) {
+ return lua_tokenlib_get_cmdname(L);
+ } else if (lua_key_eq(s, csname)) {
+ return lua_tokenlib_get_csname(L);
+ } else if (lua_key_eq(s, id)) {
+ return lua_tokenlib_get_id(L);
+ } else if (lua_key_eq(s, tok)) {
+ return lua_tokenlib_get_tok(L);
+ } else if (lua_key_eq(s, active)) {
+ return lua_tokenlib_get_active(L);
+ } else if (lua_key_eq(s, expandable)) {
+ return lua_tokenlib_get_expandable(L);
+ } else if (lua_key_eq(s, protected)) {
+ return lua_tokenlib_get_protected(L);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/* end */
+
+static int lua_tokenlib_equal(lua_State * L)
+{
+ lua_token *n, *m;
+ n = check_istoken(L, 1);
+ m = check_istoken(L, 2);
+ if (token_info(n->token) == token_info(m->token)) {
+ lua_pushboolean(L,1);
+ return 1;
+ }
+ lua_pushboolean(L,0);
+ return 1;
+}
+
+static int lua_tokenlib_tostring(lua_State * L)
+{
+ char *msg;
+ lua_token *n;
+ n = check_istoken(L, 1);
+ msg = xmalloc(256);
+ snprintf(msg, 255, "<%s token %d: %d>", (n->origin==LUA_ORIGIN?"lua":"tex"), n->token , token_info(n->token));
+ lua_pushstring(L, msg);
+ free(msg);
+ return 1;
+}
+
+static int lua_tokenlib_type(lua_State * L)
+{
+ if (maybe_istoken(L,1)!=NULL) {
+ lua_pushstring(L,"token");
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int run_scan_token(lua_State * L)
+{
+ saved_tex_scanner texstate;
+ save_tex_scanner(texstate);
+ get_x_token();
+ make_new_token(L, cur_cmd, cur_chr, cur_cs);
+ unsave_tex_scanner(texstate);
+ 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} */
+/* [catcodetable] csname content global : \gdef\csname{content} */
+/* [catcodetable] csname : \def\csname{} */
+
+/* TODO: check for a quick way to set a macro to empty (HH) */
+
+static int get_meaning(lua_State * L)
+{
+ const char *name = null;
+ size_t lname = 0;
+ int cs, cmd;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ name = lua_tolstring(L, 1, &lname);
+ cs = string_lookup(name, lname);
+ cmd = eq_type(cs);
+ if (cmd >= call_cmd) {
+ int chr = equiv(cs);
+ char *str = tokenlist_to_cstring(chr, true, NULL);
+ lua_pushstring(L, str);
+ free(str);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int get_macro(lua_State * L)
+{
+ const char *name = null;
+ size_t lname = 0;
+ int cs, cmd;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ name = lua_tolstring(L, 1, &lname);
+ cs = string_lookup(name, lname);
+ cmd = eq_type(cs);
+ if (cmd >= call_cmd) {
+ /*
+ Expanding would expand in-place, unless we make a copy which we don't want to
+ do. So, we just pass the meaning i.e. no: expand_macros_in_tokenlist(chr).
+
+ Actually it would be nice to adapt tokenlist_to_cstring with an extra argument
+ indicating that we are not interested in the before -> part.
+ */
+ int chr = equiv(cs);
+ char *str = tokenlist_to_xstring(chr, true, NULL);
+ lua_pushstring(L, str);
+ free(str);
+ return 1;
+ }
+ }
+ 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;
+ const char *str = null;
+ const char *s = null;
+ size_t lname = 0;
+ size_t lstr = 0;
+ int cs, cc, ct;
+ int n = lua_gettop(L);
+ int a = 0 ; /* global state */
+ int nncs = no_new_control_sequence;
+ if (n == 0) {
+ return 0 ;
+ }
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ if (n == 1)
+ return 0;
+ ct = (int) lua_tointeger(L, 1);
+ if (!valid_catcode_table(ct)) {
+ ct = cat_code_table_par;
+ }
+ name = lua_tolstring(L, 2, &lname);
+ if (n > 2)
+ str = lua_tolstring(L, 3, &lstr);
+ if (n > 3)
+ s = lua_tostring(L, 4);
+ } else {
+ ct = cat_code_table_par;
+ name = lua_tolstring(L, 1, &lname);
+ if (n > 1)
+ str = lua_tolstring(L, 2, &lstr);
+ if (n > 2)
+ s = lua_tostring(L, 3);
+ }
+ if (name == null) {
+ return 0 ;
+ }
+ if (s && (lua_key_eq(s, global))) {
+ a = 4;
+ }
+ no_new_control_sequence = false ;
+ cs = string_lookup(name, lname);
+ no_new_control_sequence = nncs;
+ if (lstr > 0) {
+ 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 */
+ const char *se = str + lstr;
+ p = temp_token_head;
+ set_token_link(p, null);
+ /* this left brace is used to store the number of arguments */
+ fast_store_new_token(left_brace_token);
+ /* and this ends the not present arguments, and no: we will not support arguments here*/
+ fast_store_new_token(end_match_token);
+ while (str < se) {
+ /* hh: str2uni could return len too (also elsewhere) */
+ t = (halfword) str2uni((const unsigned char *) str);
+ str += utf8_size(t);
+ cc = get_cat_code(ct,t);
+ /* this is a relating simple converter; if more is needed one can just use */
+ /* tex.print with a regular \def or \gdef and feed the string into the regular */
+ /* scanner; */
+ if (cc == 0) {
+ /* we have a potential control sequence so we check for it */
+ int _lname = 0 ;
+ int _s = 0 ;
+ int _c = 0 ;
+ halfword _cs = null ;
+ const char *_name = str ;
+ while (str < se) {
+ t = (halfword) str2uni((const unsigned char *) str);
+ _s = utf8_size(t);
+ _c = get_cat_code(ct,t);
+ if (_c == 11) {
+ str += _s ;
+ _lname = _lname + _s ;
+ } else if (_c == 10) {
+ /* we ignore a trailing space like normal scanning does */
+ str += _s ;
+ break ;
+ } else {
+ if (_lname == 0) {
+ _lname = _lname + _s ;
+ str += _s ;
+ }
+ break ;
+ }
+ }
+ if (_lname > 0) {
+ /* we have a potential \cs */
+ _cs = string_lookup(_name, _lname);
+ if (_cs == undefined_control_sequence) {
+ /* let's play safe and backtrack */
+ t = cc * (1<<21) + t ;
+ str = _name ;
+ } else {
+ 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 */
+ t = cc * (1<<21) + t ;
+ str = _name ;
+ }
+
+ } else {
+ /* whatever token, so for instance $x^2$ just works given a tex */
+ /* catcode regime */
+ t = cc * (1<<21) + t ;
+ }
+ fast_store_new_token(t);
+ }
+ /* there is no fast_store_new_token(right_brace_token) needed */
+ define(cs, call_cmd + (a % 4), token_link(temp_token_head));
+ } else {
+ halfword p ;
+ halfword q; /* new node being added to the token list via |store_new_token| */
+ p = temp_token_head;
+ set_token_info(p,null);
+ fast_store_new_token(left_brace_token);
+ fast_store_new_token(end_match_token);
+ define(cs, call_cmd + (a % 4), token_link(temp_token_head));
+ }
+ 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 },
+ { "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 */
+ { "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 },
+ { "get_mode", lua_tokenlib_get_mode },
+ { "get_cmdname", lua_tokenlib_get_cmdname },
+ { "get_csname", lua_tokenlib_get_csname },
+ { "get_id", lua_tokenlib_get_id },
+ { "get_tok", lua_tokenlib_get_tok },
+ { "get_active", lua_tokenlib_get_active },
+ { "get_expandable", lua_tokenlib_get_expandable },
+ { "get_protected", lua_tokenlib_get_protected },
+ { "get_macro", get_macro },
+ { "get_meaning", get_meaning },
+ /* setters */
+ { "set_macro", set_macro },
+ { "set_char", set_char },
+ { "set_lua", set_lua },
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg tokenlib_m[] = {
+ {"__index", lua_tokenlib_getfield},
+ {"__tostring", lua_tokenlib_tostring},
+ {"__eq", lua_tokenlib_equal},
+ {"__gc", lua_tokenlib_free},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_token(lua_State * L)
+{
+ /* the main metatable of token userdata */
+ luaL_newmetatable(L, TOKEN_METATABLE);
+ luaL_openlib(L, NULL, tokenlib_m, 0);
+ luaL_openlib(L, "token", tokenlib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lnodelib.c b/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
new file mode 100644
index 00000000000..0cd68038415
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lnodelib.c
@@ -0,0 +1,9141 @@
+/* lnodelib.c
+
+ Copyright 2006-2013 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+
+ After doing lots of tests with luatex and luajittex, with and without jit,
+ and with and without ffi, we came to the conclusion that userdata prevents
+ a speedup. We also found that the checking of metatables as well as assignment
+ comes with overhead that can't be neglected. This is normally not really a
+ problem but when processing fonts for more complex scripts it's quite some
+ overhead.
+
+ Because the userdata approach has some benefits, we stick to this. We did
+ some experiments with fast access (assuming nodes), but eventually settled for
+ the direct approach. For code that is proven to be okay, one can use the
+ direct variants and operate on nodes more directly. Currently these are
+ numbers but don't rely on that property; treat them as abstractions. An
+ important aspect is that one cannot mix both methods, although with
+ node.direct.tonode and node.direct.todirect one can cast representations.
+
+ So the advice is: use the indexed approach when possible and investigate the
+ direct one when speed might be an issue. For that reason we also provide some
+ get* and set* functions in the top level node namespace. There is a limited set
+ of getters for nodes and a generic getfield to complement them. The direct
+ namespace has a few more.
+
+ Keep in mind that such speed considerations only make sense when we're accessing
+ nodes millions of times (which happens in font processing for instance). Setters
+ are less important as documents have not that many content related nodes and
+ setting many thousands of properties is hardly a burden contrary to millions of
+ consultations. And with millions, we're talking of tens of millions which is not
+ that common.
+
+ Another change is that __index and __newindex are (as expected) exposed to
+ users but do no checking. The getfield and setfield functions do check. In
+ fact, a fast mode can be simulated by fast_getfield = __index but the (measured)
+ benefit on average runs is not that large (some 5% when we also use the other
+ fast ones) which is easily nilled by inefficient coding. The direct variants
+ on the other hand can be significantly faster but with the drawback of lack
+ of userdata features. With respect to speed: keep in mind that measuring
+ a speedup on these functions is not representative for a normal run, where
+ much more happens.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#ifdef LuajitTeX
+#include "lua/lauxlib_bridge.h"
+#else
+#include "lauxlib.h"
+#endif
+
+/*
+
+ These macros create and access pointers (indices) to keys which is faster. The
+ shortcuts are created as part of the initialization.
+
+*/
+
+/*
+
+ When the first argument to an accessor is a node, we can use it's metatable
+ entry when we are returning nodes, which saves a lookup.
+
+*/
+
+#define fast_metatable(n) do { \
+ a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
+ *a = n; \
+ lua_getmetatable(L,1); \
+ lua_setmetatable(L,-2); \
+} while (0)
+
+#define fast_metatable_or_nil(n) do { \
+ if (n) { \
+ a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
+ *a = n; \
+ lua_getmetatable(L,1); \
+ lua_setmetatable(L,-2); \
+ } else { \
+ lua_pushnil(L); \
+ } \
+} while (0)
+
+#define fast_metatable_or_nil_alink(n) do { \
+ if (n) { \
+ alink(n) = null; \
+ a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
+ *a = n; \
+ lua_getmetatable(L,1); \
+ lua_setmetatable(L,-2); \
+ } else { \
+ lua_pushnil(L); \
+ } \
+} while (0)
+
+#define fast_metatable_top(n) do { \
+ a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
+ *a = n; \
+ lua_getmetatable(L,-2); \
+ lua_setmetatable(L,-2); \
+} while (0)
+
+/*
+
+ This is a first step towards abstract direct nodes. When we have Lua 5.3 we
+ need to check all returned values for being integers. This might be another
+ level of abtraction.
+
+*/
+
+#define nodelib_pushdirect(n) lua_pushinteger(L,n)
+#define nodelib_popdirect(n) lua_tointeger(L,n)
+
+#define nodelib_pushdirect_or_nil(n) do { \
+ if (n==null) { \
+ lua_pushnil(L); \
+ } else { \
+ lua_pushinteger(L,n); \
+ } \
+} while (0)
+
+#define nodelib_pushdirect_or_nil_alink(n) do { \
+ if (n==null) { \
+ lua_pushnil(L); \
+ } else { \
+ alink(n) = null; \
+ lua_pushinteger(L,n); \
+ } \
+} while (0)
+
+#define nodelib_setattr(L, s, n) reassign_attribute(n,nodelib_getlist(L,s))
+
+#define nodelib_gettoks(L,a) tokenlist_from_lua(L)
+
+#define nodelib_getspec nodelib_getlist
+#define nodelib_getaction nodelib_getlist
+
+/* fetching a field from a node .. we can often use the reuse bot-of-stack metatable */
+
+#define nodelib_pushlist(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
+#define nodelib_pushattr(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
+#define nodelib_pushaction(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
+#define nodelib_pushstring(L,n) { char *ss=makecstring(n); lua_pushstring(L,ss); free(ss); }
+
+/* find prev, and fix backlinks .. can be a macro instead (only used a few times) */
+
+#define set_t_to_prev(head,current) \
+t = head; \
+while (vlink(t)!=current && t != null) { \
+ if (vlink(t)!=null) \
+ alink(vlink(t)) = t; \
+ t = vlink(t); \
+}
+
+#define direct_check_index_range(j,s) \
+ if (j<0 || j > 65535) { \
+ luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s); \
+ }
+
+#define NODE_METATABLE "luatex.node"
+
+#define DEBUG 0
+#define DEBUG_OUT stdout
+
+/* maybe these qualify as macros, not functions */
+
+static halfword *maybe_isnode(lua_State * L, int i)
+{
+ halfword *p = lua_touserdata(L, i);
+ if (p != NULL) {
+ if (lua_getmetatable(L, i)) {
+ lua_get_metatablelua(luatex_node);
+ if (!lua_rawequal(L, -1, -2))
+ p = NULL;
+ lua_pop(L, 2);
+ }
+ }
+ return p;
+}
+
+/* we could make the message a function and just inline the rest (via a macro) */
+
+halfword *check_isnode(lua_State * L, int i)
+{
+ halfword *p = maybe_isnode(L, i);
+ if (p != NULL)
+ return p;
+ formatted_error("node lib","lua <node> expected, not an object with type %s", luaL_typename(L, 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
+ lua stack index |n|. If it is not a valid node type, returns -1
+
+*/
+
+/* 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)
+{
+ 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;
+}
+
+static int get_valid_node_type_id(lua_State * L, int n)
+{
+ int i = -1;
+ int t = lua_type(L, n);
+ if (t == LUA_TSTRING) {
+ i = get_node_type_id_from_name(L,n,node_data);
+ if (i < 0) {
+ luaL_error(L, "invalid node type id: %s", lua_tostring(L, n));
+ }
+ } else if (t == LUA_TNUMBER) {
+ i = lua_tointeger(L,n);
+ if (! known_node_type(i)) {
+ luaL_error(L, "invalid node type id: %d", i);
+ }
+ } else {
+ luaL_error(L, "invalid node type id");
+ }
+ return i;
+}
+
+static int get_valid_node_subtype_id(lua_State * L, int n)
+{
+ int i = -1;
+ int t = lua_type(L, n);
+ if (t == LUA_TSTRING) {
+ i = get_node_type_id_from_name(L,n,whatsit_node_data);
+ if (i<0) {
+ luaL_error(L, "invalid whatsit type id: %s", lua_tostring(L, n));
+ }
+ } else if (t == LUA_TNUMBER) {
+ i = lua_tointeger(L,n);
+ if (! known_whatsit_type(i)) {
+ luaL_error(L, "invalid whatsit type id: %d", i);
+ }
+ } else {
+ luaL_error(L, "invalid whatsit type id");
+ }
+ return i;
+}
+
+/* enable fixer ... more fixers can be added in the future */
+
+static int lua_nodelib_fix_node_lists(lua_State * L)
+{
+ if (lua_type(L, -1) == LUA_TBOOLEAN) {
+ fix_node_lists = lua_toboolean(L,-1);
+ } else if (lua_type(L, -1) == LUA_TNUMBER) {
+ fix_node_lists = lua_tointeger(L,-1);
+ }
+ return 0;
+}
+
+
+/* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
+
+static int lua_nodelib_next(lua_State * L)
+{
+ halfword *p = maybe_isnode(L,1);
+ if (p != NULL && *p && vlink(*p)) {
+ lua_nodelib_push_fast(L,vlink(*p));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_prev(lua_State * L)
+{
+ halfword *p = maybe_isnode(L,1);
+ if (p != NULL && *p && alink(*p)) {
+ lua_nodelib_push_fast(L,alink(*p));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/*
+
+ Creates a userdata object for a number found at the stack top, if it is
+ representing a node (i.e. an pointer into |varmem|). It replaces the
+ stack entry with the new userdata, or pushes |nil| if the number is |null|,
+ or if the index is definately out of range. This test could be improved.
+
+*/
+
+void lua_nodelib_push(lua_State * L)
+{
+ halfword n;
+ halfword *a;
+ n = -1;
+ if (lua_type(L, -1) == LUA_TNUMBER)
+ n = (int) lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ if ((n == null) || (n < 0) || (n > var_mem_max)) {
+ lua_pushnil(L);
+ } else {
+ a = lua_newuserdata(L, sizeof(halfword));
+ *a = n;
+ lua_get_metatablelua(luatex_node);
+ lua_setmetatable(L, -2);
+ }
+ return;
+}
+
+void lua_nodelib_push_fast(lua_State * L, halfword n)
+{
+ halfword *a;
+ if (n) {
+ a = lua_newuserdata(L, sizeof(halfword));
+ *a = n;
+ lua_get_metatablelua(luatex_node);
+ lua_setmetatable(L, -2);
+ } else {
+ lua_pushnil(L);
+ }
+ 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)
+{
+ if (lua_type(L,1) == LUA_TSTRING) {
+ int i = get_node_type_id_from_name(L, 1, node_data);
+ if (i >= 0) {
+ lua_pushinteger(L, i);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/* node.direct.getid */
+
+static int lua_nodelib_direct_getid(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ lua_pushinteger(L, type(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+ /* node.getid */
+
+ static int lua_nodelib_getid(lua_State * L)
+ {
+ /* [given-node] [...] */
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ return 1;
+ }
+ /* [given-node] [mt-given-node] */
+ lua_get_metatablelua(luatex_node);
+ /* [given-node] [mt-given-node] [mt-node] */
+ if (!lua_rawequal(L, -1, -2)) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, type(*p));
+ }
+ return 1;
+ }
+
+/* node.direct.getsubtype */
+/* node.direct.setsubtype */
+
+static int lua_nodelib_direct_getsubtype(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ lua_pushinteger(L, subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setsubtype(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (lua_type(L,2) == LUA_TNUMBER)) {
+ subtype(n) = (halfword) lua_tointeger(L, 2);
+ }
+ return 0;
+}
+
+ /* node.getsubtype */
+
+ static int lua_nodelib_getsubtype(lua_State * L)
+ {
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ } else {
+ lua_get_metatablelua(luatex_node);
+ if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, subtype(*p));
+ }
+ }
+ 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 */
+
+static int lua_nodelib_direct_getfont(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ halfword t = type(n);
+ if (t == glyph_node) {
+ lua_pushinteger(L, font(n));
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ lua_pushinteger(L, fam_fnt(math_fam(n), 0));
+ } else if (t == delim_node) {
+ lua_pushinteger(L, fam_fnt(small_fam(n), 0));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setfont(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && type(n) == glyph_node) {
+ font(n) = (halfword) lua_tointeger(L,2);
+ /* optional char */
+ if ((lua_type(L, 3) == LUA_TNUMBER)) {
+ character(n) = (halfword) lua_tointeger(L, 3);
+ }
+ }
+ return 0;
+}
+
+ /* node.getfont */
+
+ static int lua_nodelib_getfont(lua_State * L)
+ {
+ halfword *n = lua_touserdata(L, 1);
+ if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ } else {
+ halfword t = type(*n);
+ if (t == glyph_node) {
+ lua_pushinteger(L, font(*n));
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ lua_pushinteger(L, fam_fnt(math_fam(*n), 0));
+ } else if (t == delim_node) {
+ lua_pushinteger(L, fam_fnt(small_fam(*n), 0));
+ } else {
+ lua_pushnil(L);
+ }
+ }
+ return 1;
+ }
+
+/* node.direct.getchar */
+/* node.direct.setchar */
+
+static int lua_nodelib_direct_getchar(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == glyph_node) {
+ lua_pushinteger(L, character(n));
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ lua_pushinteger(L, math_character(n));
+ } else if (t == delim_node) {
+ /* used in wide fonts */
+ lua_pushinteger(L, small_char(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_getfam(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if ((t == math_char_node) || (t == math_text_char_node)) {
+ 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);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setchar(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
+ halfword t = type(n);
+ if (t == glyph_node) {
+ character(n) = (halfword) lua_tointeger(L, 2);
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ math_character(n) = (halfword) lua_tointeger(L, 2);
+ } else if (t == delim_node) {
+ /* used in wide fonts */
+ small_char(n) = (halfword) lua_tointeger(L, 2);
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_setfam(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
+ halfword t = type(n);
+ if ((t == math_char_node) || (t == math_text_char_node)) {
+ 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;
+}
+
+ /* node.getchar */
+
+static int lua_nodelib_getchar(lua_State * L)
+ {
+ halfword *n = lua_touserdata(L, 1);
+ if ((n == NULL) || (! lua_getmetatable(L,1))) {
+ lua_pushnil(L);
+ } else {
+ halfword t = type(*n);
+ if (t == glyph_node) {
+ lua_pushinteger(L, character(*n));
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ lua_pushinteger(L, math_character(*n));
+ } else if (t == delim_node) {
+ /* used in wide fonts */
+ lua_pushinteger(L, small_char(*n));
+ } else {
+ lua_pushnil(L);
+ }
+ }
+ return 1;
+ }
+
+/* node.direct.getcomponents */
+/* node.direct.setcomponents */
+
+static int lua_nodelib_direct_getcomponents(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glyph_node)) {
+ nodelib_pushdirect_or_nil(lig_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setcomponents(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glyph_node)) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ lig_ptr(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ lig_ptr(n) = null;
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getlang */
+/* node.direct.setlang */
+
+static int lua_nodelib_direct_getlang(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glyph_node)) {
+ lua_pushinteger(L, char_lang(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setlang(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glyph_node)) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ set_char_lang(n,lua_tointeger(L, 2));
+ } else {
+ /* nothing */
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getattributelist */
+/* node.direct.setattributelist */
+
+static int lua_nodelib_direct_getattributelist(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && nodetype_has_attributes(type(n)) && node_attr(n) != null) {
+ lua_pushinteger(L, node_attr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setattributelist(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && nodetype_has_attributes(type(n))) {
+ 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);
+ } else if (nodetype_has_attributes(type(a))) {
+ reassign_attribute(n,node_attr(a));
+ } 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);
+ }
+ return 0;
+ }
+ return 0;
+}
+/* node.direct.getpenalty */
+/* node.direct.setpenalty */
+
+static int lua_nodelib_direct_getpenalty(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == penalty_node) {
+ lua_pushinteger(L, penalty(n));
+ } else if (t == disc_node) {
+ lua_pushinteger(L, disc_penalty(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setpenalty(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == penalty_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ penalty(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ penalty(n) = 0;
+ }
+ } else if (t == disc_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ disc_penalty(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ penalty(n) = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getnucleus */
+/* node.direct.getsub */
+/* node.direct.getsup */
+
+static int lua_nodelib_direct_getnucleus(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ nodelib_pushdirect_or_nil(nucleus(n));
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_direct_setnucleus(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ nucleus(n) = lua_tointeger(L,2);
+ } else {
+ nucleus(n) = null;
+ }
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_getsub(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ nodelib_pushdirect_or_nil(subscr(n));
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_direct_setsub(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ subscr(n) = lua_tointeger(L,2);
+ } else {
+ subscr(n) = null;
+ }
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_getsup(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ nodelib_pushdirect_or_nil(supscr(n));
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_direct_setsup(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == simple_noad || t == accent_noad || t == radical_noad) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ supscr(n) = lua_tointeger(L,2);
+ } else {
+ supscr(n) = null;
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getkern (overlaps with getwidth) */
+/* node.direct.setkern (overlaps with getwidth) */
+
+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) {
+ lua_pushnumber(L, width(n));
+ if (lua_toboolean(L,2)) {
+ lua_pushinteger(L, ex_kern(n));
+ return 2;
+ }
+ } else if (t == margin_kern_node) {
+ lua_pushinteger(L, width(n));
+ } else if (t == math_node) {
+ lua_pushinteger(L, surround(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setkern(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ halfword t = type(n);
+ if (t == kern_node || t == margin_kern_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ width(n) = (halfword) lua_roundnumber(L, 2);
+ } else {
+ width(n) = 0;
+ }
+ if (lua_type(L, 3) == LUA_TNUMBER) {
+ subtype(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (t == math_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ surround(n) = (halfword) lua_roundnumber(L, 2);
+ } else {
+ surround(n) = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getdir */
+/* node.direct.setdir */
+
+static int lua_nodelib_direct_getdir(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == dir_node) {
+ 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) {
+ lua_push_dir_par(L, rule_dir(n));
+ } else if (t == local_par_node) {
+ lua_push_dir_par(L, local_par_dir(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(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) {
+ nodelib_setdir_text(L, 2, n);
+ } else if (t == hlist_node || type(n) == vlist_node) {
+ box_dir(n) = nodelib_getdir_par(L, 2);
+ } else if (t == rule_node) {
+ rule_dir(n) = nodelib_getdir_par(L, 2);
+ } else if (t == local_par_node) {
+ 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;
+}
+
+/* node.direct.getoffsets */
+/* node.direct.setoffsets */
+
+static int lua_nodelib_direct_getoffsets(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ if (type(n) == glyph_node) {
+ lua_pushinteger(L, x_displace(n));
+ lua_pushinteger(L, y_displace(n));
+ return 2;
+ } else if (type(n) == rule_node) {
+ lua_pushinteger(L, rule_left(n));
+ lua_pushinteger(L, rule_right(n));
+ return 2;
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_setoffsets(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ if (type(n) == glyph_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ x_displace(n) = (halfword) lua_roundnumber(L, 2);
+ }
+ if (lua_type(L, 3) == LUA_TNUMBER) {
+ y_displace(n) = (halfword) lua_roundnumber(L, 3);
+ }
+ } else if (type(n) == rule_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ rule_left(n) = (halfword) lua_roundnumber(L, 2);
+ }
+ if (lua_type(L, 3) == LUA_TNUMBER) {
+ rule_right(n) = (halfword) lua_roundnumber(L, 3);
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getdisc */
+/* node.direct.setdisc */
+
+static int lua_nodelib_direct_getdisc(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == disc_node)) {
+ nodelib_pushdirect_or_nil(vlink(pre_break(n)));
+ nodelib_pushdirect_or_nil(vlink(post_break(n)));
+ nodelib_pushdirect_or_nil(vlink(no_break(n)));
+ if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
+ nodelib_pushdirect_or_nil(tlink(pre_break(n)));
+ nodelib_pushdirect_or_nil(tlink(post_break(n)));
+ nodelib_pushdirect_or_nil(tlink(no_break(n)));
+ return 6;
+ }
+ return 3;
+ } else {
+ return 0;
+ }
+}
+
+static int lua_nodelib_direct_setdisc(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (type(n) == disc_node) {
+ int t = lua_gettop(L) ;
+ if (t > 1) {
+ set_disc_field(pre_break(n), lua_tointeger(L,2));
+ if (t > 2) {
+ set_disc_field(post_break(n), lua_tointeger(L,3));
+ if (t > 3) {
+ set_disc_field(no_break(n), lua_tointeger(L,4));
+ if (t > 4) {
+ subtype(n) = (quarterword) lua_tointeger(L,5);
+ if (t > 5) {
+ disc_penalty(n) = lua_tointeger(L,6);
+ }
+ }
+ } else {
+ set_disc_field(no_break(n), null);
+ }
+ } else {
+ set_disc_field(post_break(n), null);
+ set_disc_field(no_break(n), null);
+ }
+ } else {
+ set_disc_field(pre_break(n), null);
+ set_disc_field(post_break(n), null);
+ set_disc_field(no_break(n), null);
+ }
+ }
+ return 0;
+}
+
+ /* node.getdisc */
+
+ static int lua_nodelib_getdisc(lua_State * L)
+ {
+ halfword *a;
+ halfword *n = lua_touserdata(L, 1);
+ if ((n != NULL) && (type(*n) == disc_node)) {
+ fast_metatable_or_nil(vlink(pre_break(*n)));
+ fast_metatable_or_nil(vlink(post_break(*n)));
+ fast_metatable_or_nil(vlink(no_break(*n)));
+ if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
+ fast_metatable_or_nil(tlink(pre_break(*n)));
+ fast_metatable_or_nil(tlink(post_break(*n)));
+ fast_metatable_or_nil(tlink(no_break(*n)));
+ return 6;
+ }
+ return 3;
+ }
+ return 0;
+ }
+
+/* node.direct.getwhd */
+/* node.direct.setwhd */
+
+# define push_list_whd(n) do { \
+ lua_pushinteger(L, width(n)); \
+ lua_pushinteger(L, height(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_ehd(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))); \
+ lua_pushinteger(L, ex_glyph(n)); \
+} while (0)
+
+static int lua_nodelib_direct_getwhd(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ halfword t = type(n);
+ if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
+ push_list_whd(n);
+ return 3;
+ } else if (t == glyph_node) {
+ 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) {
+ t = type(l) ;
+ if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
+ push_list_whd(l);
+ return 3;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_setwhd(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ halfword t = type(n);
+ if (t == glue_node) {
+ n = leader_ptr(n);
+ if (n == null) {
+ return 0;
+ } else {
+ t = type(n);
+ }
+ }
+ if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
+ int t = lua_gettop(L) ;
+ if (t > 1) {
+ if ((lua_type(L, 2) == LUA_TNUMBER)) {
+ width(n) = (halfword) lua_roundnumber(L, 2);
+ } else {
+ /* leave as is */
+ }
+ if (t > 2) {
+ if ((lua_type(L, 3) == LUA_TNUMBER)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ /* leave as is */
+ }
+ if (t > 3) {
+ if ((lua_type(L, 4) == LUA_TNUMBER)) {
+ depth(n) = (halfword) lua_roundnumber(L, 4);
+ } else {
+ /* leave as is */
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+ /* node.getwhd */
+
+ static int lua_nodelib_getwhd(lua_State * L)
+ {
+ halfword *n = lua_touserdata(L, 1);
+ if (n != NULL) {
+ halfword t = type(*n);
+ if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
+ push_list_whd(*n);
+ return 3;
+ } else if (t == glyph_node) {
+ 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) {
+ t = type(l) ;
+ if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
+ push_list_whd(l);
+ return 3;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+/* node.direct.getlist */
+
+static int lua_nodelib_direct_getlist(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ halfword t = type(n) ;
+ if ((t == hlist_node) || (t == vlist_node)) {
+ nodelib_pushdirect_or_nil_alink(list_ptr(n));
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ nodelib_pushdirect_or_nil_alink(math_list(n));
+ } else if (t == ins_node) {
+ nodelib_pushdirect_or_nil_alink(ins_ptr(n));
+ } else if (t == adjust_node) {
+ nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setlist(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ halfword t = type(n) ;
+ if ((t == hlist_node) || (t == vlist_node)) {
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ list_ptr(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ list_ptr(n) = null;
+ }
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ math_list(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ math_list(n) = null;
+ }
+ } else if (t == ins_node) {
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ ins_ptr(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ ins_ptr(n) = null;
+ }
+ } else if (t == adjust_node) {
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ adjust_ptr(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ adjust_ptr(n) = null;
+ }
+ }
+ }
+ return 0;
+}
+
+ /* node.getlist */
+
+ static int lua_nodelib_getlist(lua_State * L)
+ {
+ halfword *a;
+ halfword *n = lua_touserdata(L, 1);
+ if ((n == NULL) || (! lua_getmetatable(L,1))) {
+ lua_pushnil(L);
+ } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
+ fast_metatable_or_nil_alink(list_ptr(*n));
+ } else if ((type(*n) == sub_box_node) || (type(*n) == sub_mlist_node)) {
+ fast_metatable_or_nil_alink(math_list(*n));
+ } else if (type(*n) == ins_node) {
+ fast_metatable_or_nil_alink(ins_ptr(*n));
+ } else if (type(*n) == adjust_node) {
+ fast_metatable_or_nil_alink(adjust_ptr(*n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ }
+
+/* node.direct.getleader */
+/* node.direct.setleader */
+
+static int lua_nodelib_direct_getleader(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glue_node)) {
+ nodelib_pushdirect_or_nil(leader_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setleader(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if ((n) && (type(n) == glue_node)) {
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ leader_ptr(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ leader_ptr(n) = null;
+ }
+ }
+ return 0;
+}
+
+/* node.getleader */
+
+ static int lua_nodelib_getleader(lua_State * L)
+ {
+ halfword *a;
+ halfword *n = lua_touserdata(L, 1);
+ if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ } else if (type(*n) == glue_node) {
+ fast_metatable_or_nil(leader_ptr(*n));
+ } else {
+ lua_pushnil(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 xget_write_direct_value(L,n) do { \
+ tokenlist_to_lua(L, write_tokens(n)); \
+} while (0)
+
+#define get_write_direct_value(L,n) do { \
+ int l; \
+ char *s; \
+ expand_macros_in_tokenlist(n); \
+ s = tokenlist_to_cstring(def_ref, 1, &l); \
+ lua_pushlstring(L, s, (size_t) l); \
+ free(s); \
+ flush_list(def_ref); \
+} 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 */
+
+static int lua_nodelib_direct_getnext(lua_State * L)
+{
+ halfword p = lua_tointeger(L, 1);
+ if (p == null) {
+ lua_pushnil(L);
+ } else {
+ nodelib_pushdirect_or_nil(vlink(p));
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setnext(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ vlink(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ vlink(n) = null;
+ }
+ }
+ return 0;
+}
+
+ /* node.getnext */
+
+ static int lua_nodelib_getnext(lua_State * L)
+ {
+ halfword *a;
+ /* [given-node] [...]*/
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ } else {
+ /* [given-node] [mt-given-node]*/
+ lua_get_metatablelua(luatex_node);
+ /* [given-node] [mt-given-node] [mt-node]*/
+ if (!lua_rawequal(L, -1, -2)) {
+ lua_pushnil(L);
+ } else {
+ fast_metatable_or_nil(vlink(*p));
+ }
+ }
+ return 1; /* just one*/
+ }
+
+/* node.direct.getprev */
+/* node.direct.setprev */
+
+static int lua_nodelib_direct_getprev(lua_State * L)
+{
+ halfword p = lua_tointeger(L, 1);
+ if (p == null) {
+ lua_pushnil(L);
+ } else {
+ nodelib_pushdirect_or_nil(alink(p));
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setprev(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ alink(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ alink(n) = null;
+ }
+ }
+ return 0;
+}
+
+ /* node.getprev */
+
+ static int lua_nodelib_getprev(lua_State * L)
+ {
+ halfword *a;
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ } else {
+ lua_get_metatablelua(luatex_node);
+ if (!lua_rawequal(L, -1, -2)) {
+ lua_pushnil(L);
+ } else {
+ fast_metatable_or_nil(alink(*p));
+ }
+ }
+ return 1;
+ }
+
+/* node.direct.getboth */
+/* node.direct.setboth */
+
+static int lua_nodelib_direct_getboth(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ nodelib_pushdirect_or_nil(alink(n));
+ nodelib_pushdirect_or_nil(vlink(n));
+ } else {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ }
+ return 2;
+}
+
+static int lua_nodelib_direct_setboth(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ alink(n) = (halfword) lua_tointeger(L, 2);
+ } else {
+ alink(n) = null;
+ }
+ if (lua_type(L, 3) == LUA_TNUMBER) {
+ vlink(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ vlink(n) = null;
+ }
+ }
+ return 0;
+}
+
+ /* node.getboth */
+
+ static int lua_nodelib_getboth(lua_State * L)
+ {
+ halfword *a;
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ } else {
+ lua_get_metatablelua(luatex_node);
+ if (lua_rawequal(L, -1, -2)) {
+ fast_metatable_or_nil(alink(*p));
+ fast_metatable_or_nil(vlink(*p));
+ } else {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ }
+ }
+ return 2;
+ }
+
+/* node.direct.setlink */
+/* node.direct.setsplit */
+
+/*
+ a b b nil c d : prev-a-b-c-next
+ nil a b b nil c d nil : nil-a-b-c-nil
+*/
+
+static int lua_nodelib_direct_setlink(lua_State * L)
+{
+ int n = lua_gettop(L);
+ int i;
+ halfword h = null; /* head node */
+ halfword t = null; /* tail node */
+ halfword c = null; /* current node */
+ for (i=1;i<=n;i++) {
+ /*
+ we don't go for the tail of the current node because we can inject
+ between existing nodes and the nodes themselves can have old values
+ for prev and next, so ... only single nodes are looked at!
+ */
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ c = lua_tointeger(L, i);
+ if (c != t) {
+ if (t != null) {
+ vlink(t) = c;
+ alink(c) = t;
+ } else if (i > 1) {
+ /* we assume that the first node is a kind of head */
+ alink(c) = null;
+ }
+ t = c;
+ if (h == null) {
+ h = t;
+ }
+ } else {
+ /* we ignore duplicate nodes which can be tails or the previous */
+ }
+ } else if (t == null) {
+ /* we just ignore nil nodes and have no tail yet */
+ } else {
+ /* safeguard: a nil in the list can be meant as end so we nil the next of tail */
+ vlink(t) = null;
+ }
+ }
+ if (h == null) {
+ /* no head */
+ lua_pushnil(L);
+ } else {
+ /* first valid head */
+ lua_pushinteger(L,h);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setsplit(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER && (lua_type(L, 2) == LUA_TNUMBER)) {
+ halfword l = lua_tointeger(L, 1);
+ halfword r = lua_tointeger(L, 2);
+ if (l != r) {
+ alink(vlink(l)) = null;
+ vlink(alink(r)) = null;
+ }
+ vlink(l) = null;
+ alink(r) = null;
+ }
+ return 0;
+}
+
+/* node.subtype (maybe also return them for other node types now) */
+
+static int lua_nodelib_subtype(lua_State * L)
+{
+ if (lua_type(L,1) == LUA_TSTRING) {
+ int i = get_node_type_id_from_name(L,1,whatsit_node_data);
+ if (i >= 0) {
+ lua_pushinteger(L, i);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/* node.type (converts id numbers to type names) */
+
+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_push_string_by_index(L, node_data[i].lua);
+ return 1;
+ }
+ } else if (maybe_isnode(L, 1) != NULL) {
+ /* lua_pushstring(L,"node"); */
+ lua_push_string_by_name(L,node);
+ return 1;
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+/* node.new (allocate a new node) */
+
+static halfword lua_nodelib_new_node(lua_State * L)
+{
+ int i, j;
+ int t = lua_type(L, 1);
+ if (t == LUA_TNUMBER) {
+ i = lua_tointeger(L,1);
+ if (! known_node_type(i)) {
+ i = -1;
+ }
+ } else if (t == LUA_TSTRING) {
+ i = get_node_type_id_from_name(L,1,node_data);
+ } else {
+ i = -1;
+ }
+ if (i < 0) {
+ luaL_error(L, "invalid node id for creating new node");
+ }
+ t = lua_type(L, 2);
+ if (i == whatsit_node) {
+ if (t == LUA_TNUMBER) {
+ j = lua_tointeger(L,2);
+ if (! known_whatsit_type(j)) {
+ j = -1;
+ }
+ } else if (t == LUA_TSTRING) {
+ j = get_node_type_id_from_name(L,2,whatsit_node_data);
+ } else {
+ j = -1;
+ }
+ if (j < 0) {
+ luaL_error(L, "creating a whatsit requires the subtype number as a second argument");
+ }
+ } 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;
+ }
+ 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 */
+
+static int lua_nodelib_direct_new(lua_State * L)
+{
+ halfword n = lua_nodelib_new_node(L);
+ lua_pushinteger(L,n);
+ return 1;
+}
+
+/* node.free (this function returns the 'next' node, because that may be helpful) */
+
+static int lua_nodelib_free(lua_State * L)
+{
+ halfword n;
+ halfword p;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ return 1;
+ } else if (lua_isnil(L, 1)) {
+ return 1; /* the nil itself */
+ }
+ n = *(check_isnode(L, 1));
+ p = vlink(n);
+ flush_node(n);
+ /* can be: lua_nodelib_push_fast(L, p); */
+ lua_pushinteger(L, p);
+ lua_nodelib_push(L);
+ return 1;
+}
+
+/* node.direct.free */
+
+static int lua_nodelib_direct_free(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ halfword p = vlink(n);
+ flush_node(n);
+ if (p == 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L,p);
+ }
+ }
+ return 1;
+}
+
+/* node.flush_node (no next returned) */
+
+static int lua_nodelib_flush_node(lua_State * L)
+{
+ if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
+ return 0;
+ } else {
+ halfword n = *(check_isnode(L, 1));
+ flush_node(n);
+ return 0;
+ }
+}
+
+/* node.direct.flush_node */
+
+static int lua_nodelib_direct_flush_node(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ if (n == null)
+ return 0;
+ flush_node(n);
+ return 0;
+}
+
+/* node.flush_list */
+
+static int lua_nodelib_flush_list(lua_State * L)
+{
+ if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
+ return 0;
+ } else {
+ halfword n_ptr = *check_isnode(L, 1);
+ flush_node_list(n_ptr);
+ return 0;
+ }
+}
+
+/* node.direct.flush_list */
+
+static int lua_nodelib_direct_flush_list(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ if (n == null)
+ return 0;
+ flush_node_list(n);
+ return 0;
+}
+
+/* remove a node from a list */
+
+#if DEBUG
+
+ static void show_node_links (halfword l, const char * p)
+ {
+ halfword t = l;
+ while (t) {
+ fprintf(DEBUG_OUT, "%s t = %d, prev = %d, next = %d\n", p, (int)t, (int)alink(t), (int)vlink(t));
+ t = vlink(t);
+ }
+ }
+
+#endif
+
+/* node.remove */
+
+static int lua_nodelib_remove(lua_State * L)
+{
+ halfword head, current, t;
+ if (lua_gettop(L) < 2)
+ luaL_error(L, "Not enough arguments for node.remove()");
+ head = *(check_isnode(L, 1));
+ if (lua_isnil(L, 2))
+ return 2; /* the arguments, as they are */
+ current = *(check_isnode(L, 2));
+ if (head == current) {
+ if (alink(current)){
+ vlink(alink(current)) = vlink(current);
+ }
+ if (vlink(current)){
+ alink( vlink(current)) = alink(current);
+ }
+
+ head = vlink(current);
+ current = vlink(current);
+ } else {
+ t = alink(current);
+ if (t == null || vlink(t) != current) {
+ set_t_to_prev(head, current);
+ if (t == null) /* error! */
+ luaL_error(L,"Attempt to node.remove() a non-existing node");
+ }
+ /* t is now the previous node */
+ vlink(t) = vlink(current);
+ if (vlink(current) != null)
+ alink(vlink(current)) = t;
+ current = vlink(current);
+ }
+ /* can be: lua_nodelib_push_fast(L, head); */
+ lua_pushinteger(L, head);
+ lua_nodelib_push(L);
+ /* can be: lua_nodelib_push_fast(L, current); */
+ lua_pushinteger(L, current);
+ lua_nodelib_push(L);
+ return 2;
+}
+
+/* node.direct.remove */
+
+static int lua_nodelib_direct_remove(lua_State * L)
+{
+ halfword current, t;
+ halfword head = lua_tointeger(L,1);
+ if (head == null) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ return 2 ;
+ }
+ current = (halfword) lua_tointeger(L,2);
+ if (current == null) {
+ lua_pushinteger(L, head);
+ lua_pushnil(L);
+ return 2 ;
+ }
+ if (head == current) {
+ if (alink(current)){
+ vlink( alink(current) ) = vlink(current);
+ }
+ if (vlink(current)){
+ alink( vlink(current) ) = alink(current);
+ }
+ head = vlink(current);
+ current = vlink(current);
+ } else {
+ t = alink(current);
+ if (t == null || vlink(t) != current) {
+ set_t_to_prev(head, current);
+ if (t == null) {
+ luaL_error(L,"Attempt to node.direct.remove() a non-existing node");
+ }
+ }
+ vlink(t) = vlink(current);
+ if (vlink(current) != null)
+ alink(vlink(current)) = t;
+ current = vlink(current);
+ }
+ if (head == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, head);
+ }
+ if (current == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, current);
+ }
+ return 2;
+}
+
+/* node.insert_before (insert a node in a list) */
+
+static int lua_nodelib_insert_before(lua_State * L)
+{
+ halfword head, current, n, t;
+ if (lua_gettop(L) < 3) {
+ luaL_error(L, "Not enough arguments for node.insert_before()");
+ }
+ if (lua_isnil(L, 3)) {
+ lua_pop(L, 1);
+ return 2;
+ } else {
+ n = *(check_isnode(L, 3));
+ }
+ if (lua_isnil(L, 1)) { /* no head */
+ vlink(n) = null;
+ alink(n) = null;
+ lua_nodelib_push_fast(L, n);
+ lua_pushvalue(L, -1);
+ return 2;
+ } else {
+ head = *(check_isnode(L, 1));
+ }
+ if (lua_isnil(L, 2)) {
+ current = tail_of_list(head);
+ } else {
+ current = *(check_isnode(L, 2));
+ }
+ if (head != current) {
+ t = alink(current);
+ if (t == null || vlink(t) != current) {
+ set_t_to_prev(head, current);
+ if (t == null) { /* error! */
+ luaL_error(L, "Attempt to node.insert_before() a non-existing node");
+ }
+ }
+ couple_nodes(t, n);
+ }
+ couple_nodes(n, current);
+ if (head == current) {
+ lua_nodelib_push_fast(L, n);
+ } else {
+ lua_nodelib_push_fast(L, head);
+ }
+ lua_nodelib_push_fast(L, n);
+ return 2;
+}
+
+/* node.direct.insert_before */
+
+static int lua_nodelib_direct_insert_before(lua_State * L)
+{
+ halfword head, current;
+ halfword n = lua_tointeger(L,3);
+ if (n == null){
+ /* no node */
+ lua_pop(L, 1);
+ return 2 ;
+ }
+ head = (halfword) lua_tointeger(L,1);
+ current = (halfword) lua_tointeger(L,2);
+ /* no head, ignore current */
+ if (head == null) {
+ vlink(n) = null;
+ alink(n) = null;
+ lua_pushinteger(L, n);
+ lua_pushvalue(L, -1);
+ /* n, n */
+ return 2;
+ }
+ /* no current */
+ if (current == null)
+ current = tail_of_list(head);
+ if (head != current) {
+ halfword t = alink(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) */
+ if (head == current) {
+ lua_pushinteger(L, n);
+ } else {
+ lua_pushinteger(L, head);
+ }
+ lua_pushinteger(L, n);
+ return 2;
+}
+
+/* node.insert_after */
+
+static int lua_nodelib_insert_after(lua_State * L)
+{
+ halfword head, current, n;
+ if (lua_gettop(L) < 3) {
+ luaL_error(L, "Not enough arguments for node.insert_after()");
+ }
+ if (lua_isnil(L, 3)) {
+ lua_pop(L, 1);
+ return 2;
+ } else {
+ n = *(check_isnode(L, 3));
+ }
+ if (lua_isnil(L, 1)) { /* no head */
+ vlink(n) = null;
+ alink(n) = null;
+ lua_nodelib_push_fast(L, n);
+ lua_pushvalue(L, -1);
+ return 2;
+ } else {
+ head = *(check_isnode(L, 1));
+ }
+ if (lua_isnil(L, 2)) {
+ current = head;
+ while (vlink(current) != null)
+ current = vlink(current);
+ } else {
+ current = *(check_isnode(L, 2));
+ }
+ try_couple_nodes(n, vlink(current));
+ couple_nodes(current, n);
+
+ lua_pop(L, 2);
+ lua_nodelib_push_fast(L, n);
+ return 2;
+}
+
+/* node.direct.insert_after */
+
+static int lua_nodelib_direct_insert_after(lua_State * L)
+{
+ halfword head, current;
+ /*[head][current][new]*/
+ halfword n = lua_tointeger(L,3);
+ if (n == null) {
+ /* no node */
+ return 2 ;
+ }
+ head = (halfword) lua_tointeger(L,1);
+ current = (halfword) lua_tointeger(L,2);
+ if (head == null) {
+ /* no head, ignore current */
+ vlink(n) = null;
+ alink(n) = null;
+ lua_pushinteger(L,n);
+ lua_pushvalue(L, -1);
+ /* n, n */
+ return 2;
+ }
+ if (current == null) {
+ /* no current */
+ current = head;
+ while (vlink(current) != null)
+ current = vlink(current);
+ }
+ try_couple_nodes(n, vlink(current)); /* nice but incompatible: try_couple_nodes(tail_of_list(n), vlink(current)); */
+ couple_nodes(current, n);
+ lua_pop(L, 2);
+ lua_pushinteger(L, n);
+ return 2;
+}
+
+/* node.copy_list */
+
+/*
+ we need to use an intermediate variable as otherwise target is used in the loop
+ and subfields get overwritten (or something like that) which results in crashes
+ and unexpected side effects
+*/
+
+static int lua_nodelib_copy_list(lua_State * L)
+{
+ halfword n, s = null;
+ halfword m;
+ if (lua_isnil(L, 1))
+ return 1; /* the nil itself */
+ n = *check_isnode(L, 1);
+ if ((lua_gettop(L) > 1) && (!lua_isnil(L,2)))
+ s = *check_isnode(L, 2);
+ m = do_copy_node_list(n, s);
+ lua_nodelib_push_fast(L,m);
+ return 1;
+}
+
+/* node.direct.copy_list */
+
+static int lua_nodelib_direct_copy_list(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ halfword s = lua_tointeger(L,2);
+ halfword m;
+ if (s == null) {
+ m = do_copy_node_list(n,null);
+ } else {
+ m = do_copy_node_list(n,s);
+ }
+ lua_pushinteger(L,m);
+ }
+ return 1;
+}
+
+/* node.copy (deep copy) */
+
+static int lua_nodelib_copy(lua_State * L)
+{
+ halfword n;
+ if (lua_isnil(L, 1))
+ return 1; /* the nil itself */
+ n = *check_isnode(L, 1);
+ n = copy_node(n);
+ lua_nodelib_push_fast(L, n);
+ return 1;
+}
+
+/* node.direct.copy (deep copy) */
+
+static int lua_nodelib_direct_copy(lua_State * L)
+{
+ if (lua_isnil(L, 1)) {
+ return 1; /* the nil itself */
+ } else {
+ /* beware, a glue node can have number 0 (zeropt) so we cannot test for null) */
+ halfword n = lua_tointeger(L, 1);
+ n = copy_node(n);
+ lua_pushinteger(L, n);
+ return 1;
+ }
+}
+
+
+/* node.write (output a node to tex's processor) */
+
+static int lua_nodelib_append(lua_State * L)
+{
+ halfword n;
+ int i;
+ int j = lua_gettop(L);
+ for (i = 1; i <= j; i++) {
+ n = *check_isnode(L, i);
+ tail_append(n);
+ if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
+ build_attribute_list(n);
+ }
+ while (vlink(n) != null) {
+ n = vlink(n);
+ tail_append(n);
+ if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
+ build_attribute_list(n);
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.write */
+
+static int lua_nodelib_direct_append(lua_State * L)
+{
+ halfword m;
+ int i;
+ int j = lua_gettop(L);
+ for (i = 1; i <= j; i++) {
+ halfword n = lua_tointeger(L,i); /*lua_getnumber(L, i);*/
+ if (n != null) {
+ m = n ;
+ tail_append(m);
+ if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
+ build_attribute_list(n);
+ }
+ while (vlink(m) != null) {
+ m = vlink(m);
+ tail_append(m);
+ if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
+ build_attribute_list(n);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.last */
+
+static int lua_nodelib_last_node(lua_State * L)
+{
+ halfword m = pop_tail();
+ /* can be: lua_nodelib_push_fast(L, m); */
+ lua_pushinteger(L, m);
+ lua_nodelib_push(L);
+ return 1;
+}
+
+/* node.direct.last */
+
+static int lua_nodelib_direct_last_node(lua_State * L)
+{
+ halfword m = pop_tail();
+ lua_pushinteger(L, m);
+ return 1;
+}
+
+/* node.hpack (build a hbox) */
+
+static int lua_nodelib_hpack(lua_State * L)
+{
+ halfword p;
+ const char *s;
+ int w = 0;
+ int m = 1;
+ int d = -1;
+ halfword n = *(check_isnode(L, 1));
+ if (lua_gettop(L) > 1) {
+ w = lua_roundnumber(L, 2);
+ if (lua_gettop(L) > 2) {
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (lua_key_eq(s, exactly)) {
+ m = 0;
+ } else if (lua_key_eq(s, additional)) {
+ m = 1;
+ } else if (lua_key_eq(s, cal_expand_ratio)) {
+ m = 2;
+ } else if (lua_key_eq(s, subst_ex_font)) {
+ m = 3;
+ }
+ } else if (lua_type(L, 3) == LUA_TNUMBER) {
+ m = (int) lua_tointeger(L, 3);
+ }
+ if ((m<0) || (m>3)) {
+ luaL_error(L, "wrong mode in hpack");
+ }
+ if (lua_gettop(L) > 3) {
+ 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");
+ }
+ }
+ }
+ }
+ p = hpack(n, w, m, d);
+ lua_nodelib_push_fast(L, p);
+ lua_pushinteger(L, last_badness);
+ return 2;
+}
+
+/* node.direct.hpack */
+
+static int lua_nodelib_direct_hpack(lua_State * L)
+{
+ halfword p;
+ const char *s;
+ int w = 0;
+ int m = 1;
+ int d = -1;
+ halfword n = lua_tointeger(L,1);
+ /* could be macro */
+ if (lua_gettop(L) > 1) {
+ w = lua_roundnumber(L, 2);
+ if (lua_gettop(L) > 2) {
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (lua_key_eq(s, additional)) {
+ m = 1;
+ } else if (lua_key_eq(s, exactly)) {
+ m = 0;
+ } else if (lua_key_eq(s, cal_expand_ratio)) {
+ m = 2;
+ } else if (lua_key_eq(s, subst_ex_font)) {
+ m = 3;
+ } else {
+ luaL_error(L, "3rd argument should be either additional or exactly");
+ }
+ } else if (lua_type(L, 3) == LUA_TNUMBER) {
+ m = (int) lua_tointeger(L, 3);
+ } else {
+ lua_pushstring(L, "incorrect 3rd argument");
+ }
+ if (lua_gettop(L) > 3) {
+ 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");
+ }
+ }
+ }
+ }
+ /* till here */
+ p = hpack(n, w, m, d);
+ lua_pushinteger(L, p);
+ lua_pushinteger(L, last_badness);
+ return 2;
+}
+
+/* node.vpack (build a vbox) */
+
+static int lua_nodelib_vpack(lua_State * L)
+{
+ halfword p;
+ const char *s;
+ int w = 0;
+ int m = 1;
+ int d = -1;
+ halfword n = *(check_isnode(L, 1));
+ if (lua_gettop(L) > 1) {
+ w = lua_roundnumber(L, 2);
+ if (lua_gettop(L) > 2) {
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (lua_key_eq(s, additional)) {
+ m = 1;
+ } else if (lua_key_eq(s, exactly)) {
+ m = 0;
+ } else {
+ luaL_error(L, "3rd argument should be either additional or exactly");
+ }
+
+ if (lua_gettop(L) > 3) {
+ 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");
+ }
+ }
+ }
+
+ else if (lua_type(L, 3) == LUA_TNUMBER) {
+ m= (int) lua_tointeger(L, 3);
+ } else {
+ lua_pushstring(L, "incorrect 3rd argument");
+ }
+ }
+ }
+ p = vpackage(n, w, m, max_dimen, d);
+ lua_nodelib_push_fast(L, p);
+ lua_pushinteger(L, last_badness);
+ return 2;
+}
+
+/* node.direct.vpack */
+
+static int lua_nodelib_direct_vpack(lua_State * L)
+{
+ halfword p;
+ const char *s;
+ int w = 0;
+ int m = 1;
+ int d = -1;
+ halfword n = (halfword) lua_tointeger(L,1);
+ if (lua_gettop(L) > 1) {
+ w = lua_roundnumber(L, 2);
+ if (lua_gettop(L) > 2) {
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (lua_key_eq(s, additional)) {
+ m = 1;
+ } else if (lua_key_eq(s, exactly)) {
+ m = 0;
+ } else {
+ luaL_error(L, "3rd argument should be either additional or exactly");
+ }
+
+ if (lua_gettop(L) > 3) {
+ 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");
+ }
+ }
+ }
+
+ else if (lua_type(L, 3) == LUA_TNUMBER) {
+ m= (int) lua_tointeger(L, 3);
+ } else {
+ lua_pushstring(L, "incorrect 3rd argument");
+ }
+ }
+ }
+ p = vpackage(n, w, m, max_dimen, d);
+ lua_pushinteger(L, p);
+ lua_pushinteger(L, last_badness);
+ return 2;
+}
+
+/* node.dimensions (of a hlist or vlist) */
+
+static int lua_nodelib_dimensions(lua_State * L)
+{
+ int top = lua_gettop(L);
+ if (top > 0) {
+ scaled_whd siz;
+ glue_ratio g_mult = 1.0;
+ int g_sign = normal;
+ int g_order = normal;
+ int i = 1;
+ int d = -1;
+ halfword n = null, p = null;
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ if (top < 4) {
+ lua_pushnil(L);
+ return 1;
+ }
+ i += 3;
+ g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
+ g_sign = (int) lua_tointeger(L, 2);
+ g_order = (int) lua_tointeger(L, 3);
+ }
+ 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_par(L, (i + 1));
+ } else {
+ p = *(check_isnode(L, (i + 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);
+ lua_pushinteger(L, siz.dp);
+ return 3;
+ } else {
+ luaL_error(L, "missing argument to 'dimensions' (node expected)");
+ }
+ return 0; /* not reached */
+}
+
+static int lua_nodelib_rangedimensions(lua_State * L) /* parent, first, last */
+{
+ int top = lua_gettop(L);
+ if (top > 1) {
+ scaled_whd siz;
+ halfword l = *(check_isnode(L, 1)); /* parent */
+ halfword n = *(check_isnode(L, 2)); /* first */
+ halfword p = null;
+ if (top > 2) {
+ p = *(check_isnode(L, 3)); /* last */
+ }
+ siz = natural_sizes(n, p, (glue_ratio) glue_set(l), glue_sign(l), glue_order(l), box_dir(l));
+ lua_pushinteger(L, siz.wd);
+ lua_pushinteger(L, siz.ht);
+ lua_pushinteger(L, siz.dp);
+ return 3;
+ } else {
+ luaL_error(L, "missing argument to 'rangedimensions' (2 or more nodes expected)");
+ }
+ return 0; /* not reached */
+}
+
+/* node.direct.dimensions*/
+
+static int lua_nodelib_direct_dimensions(lua_State * L)
+{
+ int top = lua_gettop(L);
+ if (top > 0) {
+ scaled_whd siz;
+ glue_ratio g_mult = 1.0;
+ int g_sign = normal;
+ int g_order = normal;
+ int i = 1;
+ int d = -1;
+ halfword n = null;
+ halfword p = null;
+ if (top > 3) {
+ i += 3;
+ g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
+ g_sign = (int) lua_tointeger(L, 2);
+ g_order = (int) lua_tointeger(L, 3);
+ }
+ 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_par(L, (i + 1));
+ } else {
+ p = (halfword) lua_tointeger(L,i+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);
+ lua_pushinteger(L, siz.dp);
+ return 3;
+ } else {
+ luaL_error(L, "missing argument to 'dimensions' (direct node expected)");
+ }
+ return 0; /* not reached */
+}
+
+static int lua_nodelib_direct_rangedimensions(lua_State * L) /* parent, first, last */
+{
+ int top = lua_gettop(L);
+ if (top > 1) {
+ scaled_whd siz;
+ halfword l = (halfword) lua_tointeger(L,1); /* parent */
+ halfword n = (halfword) lua_tointeger(L,2); /* first */
+ halfword p = null;
+ if (top > 2) {
+ p = (halfword) lua_tointeger(L,3); /* last */
+ }
+ siz = natural_sizes(n, p, (glue_ratio) glue_set(l), glue_sign(l), glue_order(l), box_dir(l));
+ lua_pushinteger(L, siz.wd);
+ lua_pushinteger(L, siz.ht);
+ lua_pushinteger(L, siz.dp);
+ return 3;
+ } else {
+ luaL_error(L, "missing argument to 'rangedimensions' (2 or more direct nodes expected)");
+ }
+ return 0; /* not reached */
+}
+
+/* node.mlist_to_hlist (create a hlist from a formula) */
+
+static int lua_nodelib_mlist_to_hlist(lua_State * L)
+{
+ int w;
+ boolean m;
+ halfword n = *(check_isnode(L, 1));
+ assign_math_style(L,2,w);
+ luaL_checkany(L, 3);
+ m = lua_toboolean(L, 3);
+ mlist_to_hlist(n, m, w);
+ alink(vlink(temp_head)) = null;
+ lua_nodelib_push_fast(L, vlink(temp_head));
+ return 1;
+}
+
+/* node.family_font */
+
+static int lua_nodelib_mfont(lua_State * L)
+{
+ int s;
+ int f = luaL_checkinteger(L, 1);
+ if (lua_gettop(L) == 2)
+ s = lua_tointeger(L, 2); /* this should be a multiple of 256 ! */
+ else
+ s = 0;
+ lua_pushinteger(L, fam_fnt(f,s));
+ return 1;
+}
+
+/*
+ This function is similar to |get_node_type_id|, for field
+ identifiers. It has to do some more work, because not all
+ identifiers are valid for all types of nodes.
+
+ We can make this faster if needed but when this needs to
+ be called often something is wrong with the code.
+
+*/
+
+static int get_node_field_id(lua_State * L, int n, int node)
+{
+ int t = type(node);
+ const char *s = lua_tostring(L, n);
+
+ if (s == NULL)
+ return -2;
+
+ if (lua_key_eq(s, next)) {
+ return 0;
+ } else if (lua_key_eq(s, id)) {
+ return 1;
+ } else if (lua_key_eq(s, subtype)) {
+ if (nodetype_has_subtype(t)) {
+ return 2;
+ }
+ } else if (lua_key_eq(s, attr)) {
+ if (nodetype_has_attributes(t)) {
+ return 3;
+ }
+ } else if (lua_key_eq(s, prev)) {
+ if (nodetype_has_prev(t)) {
+ return -1;
+ }
+ } else {
+ int j;
+ 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].lua != 0; j++) {
+ // if (strcmp(s, fields[j]) == 0) {
+ if (fields[j].name == s) {
+ return j + 3;
+ }
+ }
+ }
+ }
+ return -2;
+}
+
+/* node.has_field */
+
+static int lua_nodelib_has_field(lua_State * L)
+{
+ int i = -2;
+ if (!lua_isnil(L, 1))
+ i = get_node_field_id(L, 2, *(check_isnode(L, 1)));
+ lua_pushboolean(L, (i != -2));
+ return 1;
+}
+
+/* node.is_char (node[,font]) */
+
+static int lua_nodelib_is_char(lua_State * L)
+{
+ halfword n = *(check_isnode(L, 1));
+ if (type(n) != glyph_node) {
+ lua_pushnil(L); /* no glyph at all */
+ lua_pushinteger(L,type(n)); /* can save a lookup call */
+ return 2;
+ } else if (subtype(n) >= 256) {
+ lua_pushboolean(L,0); /* a done glyph */
+ } else if (lua_type(L,2) == LUA_TNUMBER) {
+ halfword f = lua_tointeger(L, 2);
+ if (f && f == font(n)) {
+ lua_pushinteger(L,character(n)); /* a todo glyph in the asked font */
+ } else {
+ lua_pushboolean(L,0); /* a todo glyph in another font */
+ }
+ } else {
+ lua_pushinteger(L,character(n)); /* a todo glyph */
+ }
+ return 1;
+}
+
+static int lua_nodelib_is_glyph(lua_State * L)
+{
+ halfword n = *(check_isnode(L, 1));
+ if (type(n) != glyph_node) {
+ lua_pushboolean(L,0);
+ lua_pushinteger(L,type(n));
+ } else {
+ lua_pushinteger(L,character(n));
+ lua_pushinteger(L,font(n));
+ }
+ return 2;
+}
+
+/* node.direct.has_field */
+
+static int lua_nodelib_direct_has_field(lua_State * L)
+{
+ int i = -2;
+ halfword n = lua_tointeger(L, 1);
+ if (n != null)
+ i = get_node_field_id(L, 2, n);
+ lua_pushboolean(L, (i != -2));
+ return 1;
+}
+
+/* fetch the list of valid node types */
+
+static int do_lua_nodelib_types(lua_State * L, node_info * data)
+{
+ int i;
+ lua_newtable(L);
+ for (i = 0; data[i].id != -1; i++) {
+ lua_pushstring(L, data[i].name);
+ lua_rawseti(L, -2, data[i].id);
+ }
+ return 1;
+}
+
+/* node.types */
+
+static int lua_nodelib_types(lua_State * L)
+{
+ return do_lua_nodelib_types(L, node_data);
+}
+
+/* node.whatsits */
+
+static int lua_nodelib_whatsits(lua_State * L)
+{
+ return do_lua_nodelib_types(L, whatsit_node_data);
+}
+
+/* node.fields (fetch the list of valid fields) */
+
+static int lua_nodelib_fields(lua_State * L)
+{
+ int i = -1;
+ int offset = 2;
+ field_info *fields;
+ int t = get_valid_node_type_id(L, 1);
+ if (t == whatsit_node) {
+ t = get_valid_node_subtype_id(L, 2);
+ fields = whatsit_node_data[t].fields;
+ } else {
+ fields = node_data[t].fields;
+ }
+ lua_checkstack(L, 2);
+ lua_newtable(L);
+ lua_push_string_by_name(L,next);
+ lua_rawseti(L, -2, 0);
+ lua_push_string_by_name(L,id);
+ lua_rawseti(L, -2, 1);
+ if (nodetype_has_subtype(t)) {
+ lua_push_string_by_name(L,subtype);
+ lua_rawseti(L, -2, 2);
+ offset++;
+ }
+ if (nodetype_has_prev(t)) {
+ lua_push_string_by_name(L,prev);
+ lua_rawseti(L, -2, -1);
+ }
+ if (fields != NULL) {
+ 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;
+ 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;
+ 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;
+ else if (lua_key_eq(s,rule)) subtypes = node_subtypes_rule;
+ else if (lua_key_eq(s,list)
+ || lua_key_eq(s,hlist)
+ || 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_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;
+ else if (lua_key_eq(s,radical)) subtypes = node_subtypes_radical;
+ 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_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;
+ 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;
+ else if (t == rule_node) subtypes = node_subtypes_rule;
+ else if((t == hlist_node)
+ || (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_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;
+ else if (t == radical_noad) subtypes = node_subtypes_radical;
+ 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_values_pdf_destination;
+ else if (t == pdf_literal_node) subtypes = node_values_pdf_literal;
+ }
+ if (subtypes != NULL) {
+ lua_checkstack(L, 2);
+ lua_newtable(L);
+ 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);
+ }
+ return 1;
+}
+
+/* node.slide (find the end of a list and add prev links) */
+
+static int lua_nodelib_slide(lua_State * L)
+{
+ halfword n;
+ if (lua_isnil(L, 1))
+ return 1; /* the nil itself */
+ n = *check_isnode(L, 1);
+ if (n == null)
+ return 1; /* the old userdata */
+ /* alink(t) = null; */ /* don't do this, |t|'s |alink| may be a valid pointer */
+ while (vlink(n) != null) {
+ alink(vlink(n)) = n;
+ n = vlink(n);
+ }
+ lua_nodelib_push_fast(L, n);
+ return 1;
+}
+
+/* node.direct.slide */
+
+static int lua_nodelib_direct_slide(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ while (vlink(n) != null) {
+ alink(vlink(n)) = n;
+ n = vlink(n);
+ }
+ lua_pushinteger(L, n);
+ }
+ return 1;
+}
+
+/* node.tail (find the end of a list) */
+
+static int lua_nodelib_tail(lua_State * L)
+{
+ halfword n;
+ if (lua_isnil(L, 1))
+ return 1; /* the nil itself */
+ n = *check_isnode(L, 1);
+ if (n == null)
+ return 1; /* the old userdata */
+ while (vlink(n) != null)
+ n = vlink(n);
+ lua_nodelib_push_fast(L, n);
+ return 1;
+}
+
+/* node.direct.tail */
+
+static int lua_nodelib_direct_tail(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ while (vlink(n) != null)
+ n = vlink(n);
+ lua_pushinteger(L, n);
+ }
+ return 1;
+}
+
+/* node.end_of_math (skip over math and return last) */
+
+static int lua_nodelib_end_of_math(lua_State * L)
+{
+ halfword n;
+ if (lua_isnil(L, 1))
+ return 0;
+ n = *check_isnode(L, 1);
+ if (n == null)
+ return 0;
+ if (type(n) == math_node && (subtype(n) == 1)) {
+ lua_nodelib_push_fast(L, n);
+ return 1;
+ }
+ while (vlink(n) != null) {
+ n = vlink(n);
+ if (n && (type(n) == math_node) && (subtype(n) == 1)) {
+ lua_nodelib_push_fast(L, n);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* node.direct.end_of_math */
+
+static int lua_nodelib_direct_end_of_math(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null)
+ return 0;
+ if ((type(n)==math_node && (subtype(n)==1))) {
+ lua_pushinteger(L, n);
+ return 1;
+ }
+ while (vlink(n) != null) {
+ n = vlink(n);
+ if (n && (type(n)==math_node) && (subtype(n)==1)) {
+ lua_pushinteger(L, n);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* node.has_attribute (gets attribute) */
+
+static int lua_nodelib_has_attribute(lua_State * L)
+{
+ int i, val;
+ halfword n = *check_isnode(L, 1);
+ if (n != null) {
+ i = lua_tointeger(L, 2);
+ val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
+ if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, val);
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+/* node.direct.has_attribute */
+
+static int lua_nodelib_direct_has_attribute(lua_State * L)
+{
+ int i, val;
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ i = lua_tointeger(L, 2);
+ val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
+ if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, val);
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+/* node.get_attribute */
+
+static int lua_nodelib_get_attribute(lua_State * L)
+{
+ halfword p = *check_isnode(L, 1);
+ if (nodetype_has_attributes(type(p))) {
+ p = node_attr(p);
+ if (p != null) {
+ p = vlink(p);
+ if (p != null) {
+ 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);
+ if (ret == UNUSED_ATTRIBUTE) {
+ break;
+ } else {
+ lua_pushinteger(L,ret);
+ return 1;
+ }
+ } else if (attribute_id(p) > i) {
+ break;
+ }
+ p = vlink(p);
+ }
+ }
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_find_attribute(lua_State * L) /* returns attr value and node */
+{
+ halfword c = *check_isnode(L, 1);
+ halfword p ;
+ int i = lua_tointeger(L, 2);
+ while (c != null) {
+ if (nodetype_has_attributes(type(c))) {
+ p = node_attr(c);
+ if (p != null) {
+ p = vlink(p);
+ while (p != null) {
+ if (attribute_id(p) == i) {
+ int ret = attribute_value(p);
+ if (ret == UNUSED_ATTRIBUTE) {
+ break;
+ } else {
+ lua_pushinteger(L,ret);
+ lua_nodelib_push_fast(L, c );
+ return 2;
+ }
+ } else if (attribute_id(p) > i) {
+ break;
+ }
+ p = vlink(p);
+ }
+ }
+ }
+ c = vlink(c);
+ }
+ /*
+ lua_pushnil(L);
+ lua_pushnil(L);
+ return 2;
+ */
+ return 0;
+}
+
+/* node.direct.get_attribute */
+/* node.direct.set_attribute */
+/* node.direct.unset_attribute */
+/* node.direct.find_attribute */
+
+static int lua_nodelib_direct_get_attribute(lua_State * L)
+{
+ register halfword p = lua_tointeger(L, 1);
+ if (nodetype_has_attributes(type(p))) {
+ p = node_attr(p);
+ if (p != null) {
+ p = vlink(p);
+ if (p != null) {
+ 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);
+ if (ret == UNUSED_ATTRIBUTE) {
+ break;
+ } else {
+ lua_pushinteger(L,ret);
+ return 1;
+ }
+ } else if (attribute_id(p) > i) {
+ break;
+ }
+ p = vlink(p);
+ }
+ }
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_direct_set_attribute(lua_State * L)
+{
+ int i, val;
+ halfword n = lua_tointeger(L, 1);
+ if (n == null)
+ return 0;
+ if (lua_gettop(L) == 3) {
+ i = (int) lua_tointeger(L, 2);
+ val = (int) lua_tointeger(L, 3);
+ if (val == UNUSED_ATTRIBUTE) {
+ (void) unset_attribute(n, i, val);
+ } else {
+ set_attribute(n, i, val);
+ }
+ } else {
+ luaL_error(L, "incorrect number of arguments");
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_find_attribute(lua_State * L) /* returns attr value and node */
+{
+ halfword c = lua_tointeger(L, 1);
+ halfword p ;
+ int i = lua_tointeger(L, 2);
+ while (c != null) {
+ if (nodetype_has_attributes(type(c))) {
+ p = node_attr(c);
+ if (p != null) {
+ p = vlink(p);
+ while (p != null) {
+ if (attribute_id(p) == i) {
+ int ret = attribute_value(p);
+ if (ret == UNUSED_ATTRIBUTE) {
+ break;
+ } else {
+ lua_pushinteger(L,ret);
+ lua_pushinteger(L,c);
+ return 2;
+ }
+ } else if (attribute_id(p) > i) {
+ break;
+ }
+ p = vlink(p);
+ }
+ }
+ }
+ c = vlink(c);
+ }
+ /*
+ lua_pushnil(L);
+ lua_pushnil(L);
+ return 2;
+ */
+ return 0;
+}
+
+static int lua_nodelib_direct_unset_attribute(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
+ int i = (int)luaL_checknumber(L, 2);
+ int val = (int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
+ int ret = unset_attribute(n, i, val);
+ if (ret > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, ret);
+ } else {
+ lua_pushnil(L);
+ }
+ } else { /* can go */
+ return luaL_error(L, "incorrect number of arguments");
+ }
+ return 1;
+}
+
+/* node.set_attribute */
+/* node.unset_attribute */
+
+static int lua_nodelib_set_attribute(lua_State * L)
+{
+ if (lua_gettop(L) == 3) {
+ int i = lua_tointeger(L, 2);
+ int val = lua_tointeger(L, 3);
+ halfword n = *check_isnode(L, 1);
+ if (val == UNUSED_ATTRIBUTE) {
+ (void) unset_attribute(n, i, val);
+ } else {
+ set_attribute(n, i, val);
+ }
+ } else {
+ luaL_error(L, "incorrect number of arguments");
+ }
+ return 0;
+}
+
+static int lua_nodelib_unset_attribute(lua_State * L)
+{
+ if (lua_gettop(L) <= 3) {
+ int i = luaL_checknumber(L, 2);
+ int val = luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
+ halfword n = *check_isnode(L, 1);
+ int ret = unset_attribute(n, i, val);
+ if (ret > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, ret);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ } else {
+ return luaL_error(L, "incorrect number of arguments");
+ }
+}
+
+/* node.direct.getwidth */
+/* node.direct.setwidth */
+/* node.direct.getheight (for consistency) */
+/* node.direct.setheight (for consistency) */
+/* node.direct.getdepth (for consistency) */
+/* node.direct.setdepth (for consistency) */
+
+/* split ifs for clearity .. compiler will optimize */
+
+static int lua_nodelib_direct_getwidth(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == hlist_node || t == vlist_node || t == rule_node) {
+ lua_pushinteger(L,width(n));
+ } else if (t == glyph_node) {
+ lua_pushnumber(L, char_width(font(n),character(n)));
+ if (lua_toboolean(L,2)) {
+ lua_pushinteger(L, ex_glyph(n));
+ return 2;
+ }
+ } 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) {
+ lua_pushinteger(L, width(n));
+ if (lua_toboolean(L,2)) {
+ lua_pushinteger(L, ex_kern(n));
+ return 2;
+ }
+ } else if (t == margin_kern_node) {
+ lua_pushinteger(L,width(n));
+ } else if (t == unset_node) {
+ lua_pushinteger(L,width(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setwidth(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ 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 == fraction_noad || t == radical_noad ) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ width(n) = lua_roundnumber(L,2);
+ } else {
+ width(n) = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_getheight(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == hlist_node || t == vlist_node || t == rule_node) {
+ lua_pushinteger(L,height(n));
+ } else if (t == glyph_node) {
+ 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);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+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) {
+ height(n) = h;
+ } else if (t == fence_noad) {
+ delimiterheight(n) = h;
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_getdepth(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == hlist_node || t == vlist_node || t == rule_node) {
+ lua_pushinteger(L,depth(n));
+ } else if (t == glyph_node) {
+ 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);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+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) {
+ depth(n) = d;
+ } else if (t == fence_noad) {
+ delimiterdepth(n) = d;
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getshift */
+/* node.direct.setshift */
+
+static int lua_nodelib_direct_getshift(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == hlist_node || t == vlist_node) {
+ lua_pushinteger(L,shift_amount(n));
+ return 1;
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int lua_nodelib_direct_setshift(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == hlist_node || t == vlist_node) {
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ shift_amount(n) = lua_roundnumber(L,2);
+ } else {
+ shift_amount(n) = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/* node.direct.getglue */
+/* node.direct.setglue */
+/* node.direct.is_zero_glue */
+
+static int lua_nodelib_direct_get_glue(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+ lua_pushinteger(L,width(n));
+ lua_pushinteger(L,stretch(n));
+ lua_pushinteger(L,shrink(n));
+ lua_pushinteger(L,stretch_order(n));
+ lua_pushinteger(L,shrink_order(n));
+ return 5;
+ } else if (t == hlist_node || t == vlist_node) {
+ lua_pushnumber(L, (double) glue_set(n)); /* float */
+ lua_pushinteger(L,glue_order(n));
+ lua_pushinteger(L,glue_sign(n));
+ return 3;
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_set_glue(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ int top = lua_gettop(L);
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node) {
+ width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
+ stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
+ shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
+ stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
+ shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
+ } else if (t == hlist_node || t == vlist_node) {
+ glue_set(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? (glue_ratio) lua_tonumber(L,2) : 0;
+ glue_order(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
+ glue_sign(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
+ return 3;
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_is_zero_glue(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+ lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
+ return 1;
+ } else if (t == hlist_node || t == vlist_node) {
+ lua_pushboolean(L,(glue_set(n) == 0 && glue_order(n) == 0 && glue_sign(n) == 0));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* node.getglue */
+/* node.setglue */
+/* node.is_zero_glue */
+
+static int lua_nodelib_get_glue(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ if (n) {
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+ lua_pushinteger(L,width(n));
+ lua_pushinteger(L,stretch(n));
+ lua_pushinteger(L,shrink(n));
+ lua_pushinteger(L,stretch_order(n));
+ lua_pushinteger(L,shrink_order(n));
+ return 5;
+ } else if (t == hlist_node || t == vlist_node) {
+ lua_pushnumber(L, (double) glue_set(n)); /* float */
+ lua_pushinteger(L,glue_order(n));
+ lua_pushinteger(L,glue_sign(n));
+ return 3;
+ }
+ }
+ return luaL_error(L, "glue (spec) or list expected");
+}
+
+static int lua_nodelib_set_glue(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ int top = lua_gettop(L) ;
+ if (n) {
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node) {
+ width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
+ stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
+ shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
+ stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
+ shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
+ } else if (t == hlist_node || t == vlist_node) {
+ glue_set(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? (glue_ratio) lua_tonumber(L,2) : 0;
+ glue_order(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
+ glue_sign(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
+ return 3;
+ }
+ return 0;
+ }
+ return luaL_error(L, "glue (spec) or list expected");
+}
+
+static int lua_nodelib_is_zero_glue(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ if (n != null) {
+ halfword t = type(n);
+ if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
+ lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
+ return 1;
+ } else if (t == hlist_node || t == vlist_node) {
+ lua_pushboolean(L,(glue_set(n) == 0 && glue_order(n) == 0 && glue_sign(n) == 0));
+ return 1;
+ }
+ }
+ return luaL_error(L, "glue (spec) or list expected");
+}
+
+/* iteration */
+
+static int nodelib_aux_nil(lua_State * L)
+{
+ lua_pushnil(L);
+ return 1;
+}
+
+/* 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)
+{
+ halfword t; /* traverser */
+ int i = (int) lua_tointeger(L, lua_upvalueindex(1));
+ 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) != i) {
+ t = vlink(t);
+ }
+ if (t == null) {
+ lua_pushnil(L);
+ return 1;
+ } else {
+ lua_pushinteger(L,t);
+ lua_pushinteger(L,subtype(t));
+ return 2;
+ }
+}
+
+static int lua_nodelib_direct_traverse_filtered(lua_State * L)
+{
+ halfword n;
+ if (lua_isnil(L, 2)) {
+ lua_pushcclosure(L, nodelib_aux_nil, 0);
+ return 1;
+ }
+ n = (halfword) lua_tointeger(L, 2);
+ if (n == null)
+ return 0;
+ lua_pop(L, 1);
+ lua_pushcclosure(L, nodelib_direct_aux_next_filtered, 1);
+ lua_pushinteger(L,n);
+ lua_pushnil(L);
+ return 3;
+}
+
+static int nodelib_direct_aux_next_char(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) == 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;
+ }
+}
+
+static int lua_nodelib_direct_traverse_char(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_char, 0);
+ lua_pushinteger(L,n);
+ lua_pushnil(L);
+ return 3;
+}
+
+static int nodelib_direct_aux_next_glyph(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) != 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 3;
+}
+
+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)) {
+ 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_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;
+}
+
+static int nodelib_aux_next_char(lua_State * L)
+{
+ halfword t; /* traverser */
+ halfword *a;
+ 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) == 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;
+ }
+}
+
+static int lua_nodelib_traverse_char(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_char, 0);
+ lua_nodelib_push_fast(L, n);
+ lua_pushnil(L);
+ return 3;
+}
+
+static int nodelib_aux_next_glyph(lua_State * L)
+{
+ halfword t; /* traverser */
+ halfword *a;
+ 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) != 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;
+ }
+}
+
+static int lua_nodelib_traverse_glyph(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_glyph, 0);
+ lua_nodelib_push_fast(L, n);
+ lua_pushnil(L);
+ return 3;
+}
+
+static int nodelib_aux_next_list(lua_State * L)
+{
+ halfword t; /* traverser */
+ halfword *a;
+ 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) != 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;
+ }
+}
+
+static int lua_nodelib_traverse_list(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_list, 1);
+ lua_nodelib_push_fast(L, n);
+ lua_pushnil(L);
+ return 3;
+}
+
+/* counting */
+
+static int do_lua_nodelib_count(lua_State * L, halfword match, int i, halfword first1)
+{
+ int count = 0;
+ int t = first1;
+ while (t != match) {
+ if (i < 0 || type(t) == i)
+ count++;
+ t = vlink(t);
+ }
+ lua_pushinteger(L, count);
+ return 1;
+}
+
+/* node.direct.length */
+/* node.direct.count */
+
+static int lua_nodelib_direct_length(lua_State * L)
+{
+ halfword m;
+ halfword n = lua_tointeger(L, 1);
+ if (n == 0) {
+ lua_pushinteger(L, 0);
+ return 1;
+ }
+ m = (halfword) lua_tointeger(L, 2);
+ return do_lua_nodelib_count(L, m, -1, n);
+}
+
+static int lua_nodelib_direct_count(lua_State * L)
+{
+ return do_lua_nodelib_count(L,
+ (halfword) lua_tointeger(L, 3), /* m */
+ (int) lua_tointeger(L, 1), /* i */
+ (halfword) lua_tointeger(L, 2) /* n */
+ );
+}
+
+/* node.length */
+/* node.count */
+
+static int lua_nodelib_length(lua_State * L)
+{
+ halfword n;
+ halfword m = null;
+ if (lua_isnil(L, 1)) {
+ lua_pushinteger(L, 0);
+ return 1;
+ }
+ n = *check_isnode(L, 1);
+ if (lua_gettop(L) == 2)
+ m = *check_isnode(L, 2);
+ return do_lua_nodelib_count(L, m, -1, n);
+}
+
+static int lua_nodelib_count(lua_State * L)
+{
+ halfword n;
+ halfword m = null;
+ int i = lua_tointeger(L, 1);
+ if (lua_isnil(L, 2)) {
+ lua_pushinteger(L, 0);
+ return 1;
+ }
+ n = *check_isnode(L, 2);
+ if (lua_gettop(L) == 3)
+ m = *check_isnode(L, 3);
+ return do_lua_nodelib_count(L, m, i, n);
+}
+
+/* node.direct.getfield */
+
+static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s)
+{
+ int t = subtype(n);
+ if (t == user_defined_node) {
+ if (lua_key_eq(s, user_id)) {
+ lua_pushinteger(L, user_node_id(n));
+ } 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_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) || 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) {
+ /*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 {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_annot_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_annot_objnum(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_annot_data(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_dest_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_dest_named_id(n));
+ } else if (lua_key_eq(s, dest_id)) {
+ if (pdf_dest_named_id(n) == 1)
+ tokenlist_to_luastring(L, pdf_dest_id(n));
+ else
+ lua_pushinteger(L, pdf_dest_id(n));
+ } else if (lua_key_eq(s, dest_type)) {
+ lua_pushinteger(L, pdf_dest_type(n));
+ } else if (lua_key_eq(s, xyz_zoom)) {
+ lua_pushinteger(L, pdf_dest_xyz_zoom(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_dest_objnum(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_setmatrix_node) {
+ if (lua_key_eq(s, data)) {
+ get_pdf_setmatrix_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_colorstack_node) {
+ if (lua_key_eq(s, stack)) {
+ lua_pushinteger(L, pdf_colorstack_stack(n));
+ } else if (lua_key_eq(s, command)) {
+ lua_pushinteger(L, pdf_colorstack_cmd(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_colorstack_data(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_refobj_node) {
+ if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_obj_objnum(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == write_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else if (lua_key_eq(s, data)) {
+ get_write_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == special_node) {
+ if (lua_key_eq(s, data)) {
+ get_special_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_start_link_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_link_objnum(n));
+ } else if (lua_key_eq(s, link_attr)) {
+ tokenlist_to_luastring(L, pdf_link_attr(n));
+ } else if (lua_key_eq(s, action)) {
+ nodelib_pushaction(L, pdf_link_action(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_action_node) {
+ if (lua_key_eq(s, action_type)) {
+ lua_pushinteger(L, pdf_action_type(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_action_named_id(n));
+ } else if (lua_key_eq(s, action_id)) {
+ if (pdf_action_named_id(n) == 1) {
+ tokenlist_to_luastring(L, pdf_action_id(n));
+ } else {
+ lua_pushinteger(L, pdf_action_id(n));
+ }
+ } else if (lua_key_eq(s, file)) {
+ tokenlist_to_luastring(L, pdf_action_file(n));
+ } else if (lua_key_eq(s, new_window)) {
+ lua_pushinteger(L, pdf_action_new_window(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_action_tokens(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_thread_named_id(n));
+ } else if (lua_key_eq(s, thread_id)) {
+ if (pdf_thread_named_id(n) == 1) {
+ tokenlist_to_luastring(L, pdf_thread_id(n));
+ } else {
+ lua_pushinteger(L, pdf_thread_id(n));
+ }
+ } else if (lua_key_eq(s, thread_attr)) {
+ tokenlist_to_luastring(L, pdf_thread_attr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == open_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else if (lua_key_eq(s, name)) {
+ nodelib_pushstring(L, open_name(n));
+ } else if (lua_key_eq(s, area)) {
+ nodelib_pushstring(L, open_area(n));
+ } else if (lua_key_eq(s, ext)) {
+ nodelib_pushstring(L, open_ext(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == close_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+}
+
+static int lua_nodelib_fast_getfield(lua_State * L)
+{
+ /*
+ the order is somewhat determined by the occurance of nodes and
+ importance of fields
+ */
+
+ halfword *a;
+ const char *s;
+
+ halfword n = *((halfword *) lua_touserdata(L, 1));
+ int t = type(n);
+
+ /*
+
+ somenode[9] as interface to attributes ... 30% faster than has_attribute
+ (1) because there is no lua function overhead, and (2) because we already
+ know that we deal with a node so no checking is needed. The fast typecheck
+ is needed (lua_check... is a slow down actually).
+
+ */
+
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+
+ halfword p;
+ int i;
+
+ if (! nodetype_has_attributes(t)) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ p = node_attr(n);
+ if (p == null || vlink(p) == null) {
+ lua_pushnil(L);
+ return 1;
+ }
+ i = (int) lua_tointeger(L, 2);
+ p = vlink(p);
+ while (p != null) {
+ if (attribute_id(p) == i) {
+ if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, (int) attribute_value(p));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ } else if (attribute_id(p) > i) {
+ lua_pushnil(L);
+ return 1;
+ }
+ p = vlink(p);
+ }
+ lua_pushnil(L);
+ return 1;
+ }
+
+ s = lua_tostring(L, 2);
+
+ if (lua_key_eq(s, id)) {
+ lua_pushinteger(L, t);
+ } else if (lua_key_eq(s, next)) {
+ fast_metatable_or_nil(vlink(n));
+ } else if (lua_key_eq(s, prev)) {
+ fast_metatable_or_nil(alink(n));
+ } else if (lua_key_eq(s, attr)) {
+ if (! nodetype_has_attributes(t)) {
+ lua_pushnil(L);
+ } else {
+ nodelib_pushattr(L, node_attr(n));
+ }
+ } else if (t == glyph_node) {
+ /* candidates: fontchar (font,char) whd (width,height,depth) */
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, font)) {
+ lua_pushinteger(L, font(n));
+ } else if (lua_key_eq(s, char)) {
+ lua_pushinteger(L, character(n));
+ } else if (lua_key_eq(s, xoffset)) {
+ 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, 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)) {
+ lua_pushinteger(L, char_height(font(n),character(n)));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, char_depth(font(n),character(n)));
+ } else if (lua_key_eq(s, expansion_factor)) {
+ lua_pushinteger(L, ex_glyph(n));
+ } else if (lua_key_eq(s, components)) {
+ fast_metatable_or_nil(lig_ptr(n));
+ } else if (lua_key_eq(s, lang)) {
+ lua_pushinteger(L, char_lang(n));
+ } else if (lua_key_eq(s, left)) {
+ lua_pushinteger(L, char_lhmin(n));
+ } else if (lua_key_eq(s, right)) {
+ lua_pushinteger(L, char_rhmin(n));
+ } else if (lua_key_eq(s, uchyph)) {
+ lua_pushinteger(L, char_uchyph(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == hlist_node) || (t == vlist_node)) {
+ /* candidates: whd (width,height,depth) */
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
+ fast_metatable_or_nil_alink(list_ptr(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, shift_amount(n));
+ } else if (lua_key_eq(s, glue_order)) {
+ lua_pushinteger(L, glue_order(n));
+ } else if (lua_key_eq(s, glue_sign)) {
+ lua_pushinteger(L, glue_sign(n));
+ } else if (lua_key_eq(s, glue_set)) {
+ lua_pushnumber(L, (double) glue_set(n)); /* float */
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == disc_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, pre)) {
+ fast_metatable_or_nil(vlink(pre_break(n)));
+ } else if (lua_key_eq(s, post)) {
+ fast_metatable_or_nil(vlink(post_break(n)));
+ } else if (lua_key_eq(s, replace)) {
+ fast_metatable_or_nil(vlink(no_break(n)));
+ } else if (lua_key_eq(s, penalty)) {
+ lua_pushinteger(L, disc_penalty(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == glue_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else if (lua_key_eq(s, leader)) {
+ fast_metatable_or_nil(leader_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, kern)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, expansion_factor)) {
+ lua_pushinteger(L, ex_kern(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == penalty_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, penalty)) {
+ lua_pushinteger(L, penalty(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == rule_node) {
+ /* candidates: whd (width,height,depth) */
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, rule_index(n));
+ } else if (lua_key_eq(s, transform)) {
+ lua_pushinteger(L,rule_transform(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == dir_node) {
+ if (lua_key_eq(s, direction)) {
+ lua_push_direction(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 */
+ lua_pushinteger(L, subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == local_par_node) {
+ if (lua_key_eq(s, pen_inter)) {
+ 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_push_direction(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)) {
+ /* can be: fast_metatable_or_nil(local_box_left(n)) */
+ nodelib_pushlist(L, local_box_left(n));
+ } else if (lua_key_eq(s, box_left_width)) {
+ lua_pushinteger(L, local_box_left_width(n));
+ } else if (lua_key_eq(s, box_right)) {
+ /* can be: fast_metatable_or_nil(local_box_right(n)) */
+ nodelib_pushlist(L, local_box_right(n));
+ } else if (lua_key_eq(s, box_right_width)) {
+ lua_pushinteger(L, local_box_right_width(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == glue_spec_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == whatsit_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else {
+ lua_nodelib_getfield_whatsit(L, n, s);
+ }
+ } else if (t == simple_noad) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, nucleus)) {
+ fast_metatable_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ fast_metatable_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ fast_metatable_or_nil(supscr(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, noadoptions(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ /* candidates: famchar (fam,char) */
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, fam)) {
+ lua_pushinteger(L, math_fam(n));
+ } else if (lua_key_eq(s, char)) {
+ lua_pushinteger(L, math_character(n));
+ } else if (lua_key_eq(s, font)) {
+ lua_pushinteger(L, fam_fnt(math_fam(n), 0));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == mark_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, class)) {
+ lua_pushinteger(L, mark_class(n));
+ } else if (lua_key_eq(s, mark)) {
+ tokenlist_to_lua(L, mark_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == ins_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, cost)) {
+ lua_pushinteger(L, float_cost(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) { /* already mapped */
+ fast_metatable_or_nil_alink(ins_ptr(n));
+ /* glue parameters */
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == math_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, surround)) {
+ lua_pushinteger(L, surround(n));
+ /* glue parameters */
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == fraction_noad) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, thickness(n));
+ } else if (lua_key_eq(s, num)) {
+ fast_metatable_or_nil(numerator(n));
+ } else if (lua_key_eq(s, denom)) {
+ fast_metatable_or_nil(denominator(n));
+ } else if (lua_key_eq(s, left)) {
+ fast_metatable_or_nil(left_delimiter(n));
+ } else if (lua_key_eq(s, right)) {
+ 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 {
+ lua_pushnil(L);
+ }
+ } else if (t == style_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, style)) {
+ lua_push_math_style_name(L,subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == accent_noad) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, nucleus)) {
+ fast_metatable_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ fast_metatable_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ fast_metatable_or_nil(supscr(n));
+ } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
+ fast_metatable_or_nil(top_accent_chr(n));
+ } else if (lua_key_eq(s, bot_accent)) {
+ fast_metatable_or_nil(bot_accent_chr(n));
+ } else if (lua_key_eq(s, overlay_accent)) {
+ fast_metatable_or_nil(overlay_accent_chr(n));
+ } else if (lua_key_eq(s, fraction)) {
+ lua_pushinteger(L, accentfraction(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == fence_noad) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, delim)) {
+ fast_metatable_or_nil(delimiter(n));
+ } else if (lua_key_eq(s, italic)) {
+ lua_pushinteger(L, delimiteritalic(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, delimiterheight(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, delimiterdepth(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, delimiteroptions(n));
+ } else if (lua_key_eq(s, class)) {
+ lua_pushinteger(L, delimiterclass(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == delim_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, small_fam)) {
+ lua_pushinteger(L, small_fam(n));
+ } else if (lua_key_eq(s, small_char)) {
+ lua_pushinteger(L, small_char(n));
+ } else if (lua_key_eq(s, large_fam)) {
+ lua_pushinteger(L, large_fam(n));
+ } else if (lua_key_eq(s, large_char)) {
+ lua_pushinteger(L, large_char(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ fast_metatable_or_nil_alink(math_list(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == radical_noad) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, nucleus)) {
+ fast_metatable_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ fast_metatable_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ fast_metatable_or_nil(supscr(n));
+ } else if (lua_key_eq(s, left)) {
+ fast_metatable_or_nil(left_delimiter(n));
+ } else if (lua_key_eq(s, degree)) {
+ fast_metatable_or_nil(degree(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, radicalwidth(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, radicaloptions(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == margin_kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, glyph)) {
+ fast_metatable_or_nil(margin_char(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == split_up_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ fast_metatable_or_nil(last_ins_ptr(n));
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ fast_metatable_or_nil(best_ins_ptr(n));
+ } else if (lua_key_eq(s, broken_ptr)) {
+ fast_metatable_or_nil(broken_ptr(n));
+ } else if (lua_key_eq(s, broken_ins)) {
+ fast_metatable_or_nil(broken_ins(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == choice_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, display)) {
+ fast_metatable_or_nil(display_mlist(n));
+ } else if (lua_key_eq(s, text)) {
+ fast_metatable_or_nil(text_mlist(n));
+ } else if (lua_key_eq(s, script)) {
+ fast_metatable_or_nil(script_mlist(n));
+ } else if (lua_key_eq(s, scriptscript)) {
+ fast_metatable_or_nil(script_script_mlist(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == inserting_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ fast_metatable_or_nil(last_ins_ptr(n));
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ fast_metatable_or_nil(best_ins_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == attribute_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, number)) {
+ lua_pushinteger(L, attribute_id(n));
+ } else if (lua_key_eq(s, value)) {
+ lua_pushinteger(L, attribute_value(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == adjust_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ fast_metatable_or_nil_alink(adjust_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == unset_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, glue_shrink(n));
+ } else if (lua_key_eq(s, glue_order)) {
+ lua_pushinteger(L, glue_order(n));
+ } else if (lua_key_eq(s, glue_sign)) {
+ lua_pushinteger(L, glue_sign(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, glue_stretch(n));
+ } else if (lua_key_eq(s, count)) {
+ lua_pushinteger(L, span_count(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ fast_metatable_or_nil_alink(list_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == attribute_list_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == boundary_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, value)) {
+ lua_pushinteger(L, boundary_value(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_getfield(lua_State * L)
+{
+ /* [given-node] [...]*/
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ lua_pushnil(L) ;
+ return 1;
+ }
+ /* [given-node] [mt-given-node]*/
+ lua_get_metatablelua(luatex_node);
+ /* [given-node] [mt-given-node] [mt-node]*/
+ if (!lua_rawequal(L, -1, -2)) {
+ lua_pushnil(L) ;
+ return 1;
+ }
+ /* prune stack and call getfield */
+ lua_settop(L,2);
+ return lua_nodelib_fast_getfield(L);
+}
+
+/* node.direct.getfield */
+
+static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char *s)
+{
+ int t = subtype(n);
+ if (t == user_defined_node) {
+ if (lua_key_eq(s, user_id)) {
+ lua_pushinteger(L, user_node_id(n));
+ } else if (lua_key_eq(s, type)) {
+ lua_pushinteger(L, user_node_type(n));
+ } else if (lua_key_eq(s, value)) {
+ 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) || 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) {
+ /*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 {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_annot_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_annot_objnum(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_annot_data(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_dest_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_dest_named_id(n));
+ } else if (lua_key_eq(s, dest_id)) {
+ if (pdf_dest_named_id(n) == 1)
+ tokenlist_to_luastring(L, pdf_dest_id(n));
+ else
+ lua_pushinteger(L, pdf_dest_id(n));
+ } else if (lua_key_eq(s, dest_type)) {
+ lua_pushinteger(L, pdf_dest_type(n));
+ } else if (lua_key_eq(s, xyz_zoom)) {
+ lua_pushinteger(L, pdf_dest_xyz_zoom(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_dest_objnum(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_setmatrix_node) {
+ if (lua_key_eq(s, data)) {
+ get_pdf_setmatrix_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_colorstack_node) {
+ if (lua_key_eq(s, stack)) {
+ lua_pushinteger(L, pdf_colorstack_stack(n));
+ } else if (lua_key_eq(s, command)) {
+ lua_pushinteger(L, pdf_colorstack_cmd(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_colorstack_data(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_refobj_node) {
+ if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_obj_objnum(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == write_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else if (lua_key_eq(s, data)) {
+ get_write_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == special_node) {
+ if (lua_key_eq(s, data)) {
+ get_special_direct_value(L,n);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_start_link_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, objnum)) {
+ lua_pushinteger(L, pdf_link_objnum(n));
+ } else if (lua_key_eq(s, link_attr)) {
+ tokenlist_to_luastring(L, pdf_link_attr(n));
+ } else if (lua_key_eq(s, action)) {
+ nodelib_pushaction(L, pdf_link_action(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == pdf_action_node) {
+ if (lua_key_eq(s, action_type)) {
+ lua_pushinteger(L, pdf_action_type(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_action_named_id(n));
+ } else if (lua_key_eq(s, action_id)) {
+ if (pdf_action_named_id(n) == 1) {
+ tokenlist_to_luastring(L, pdf_action_id(n));
+ } else {
+ lua_pushinteger(L, pdf_action_id(n));
+ }
+ } else if (lua_key_eq(s, file)) {
+ tokenlist_to_luastring(L, pdf_action_file(n));
+ } else if (lua_key_eq(s, new_window)) {
+ lua_pushinteger(L, pdf_action_new_window(n));
+ } else if (lua_key_eq(s, data)) {
+ tokenlist_to_luastring(L, pdf_action_tokens(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if (lua_key_eq(s, named_id)) {
+ lua_pushinteger(L, pdf_thread_named_id(n));
+ } else if (lua_key_eq(s, thread_id)) {
+ if (pdf_thread_named_id(n) == 1) {
+ tokenlist_to_luastring(L, pdf_thread_id(n));
+ } else {
+ lua_pushinteger(L, pdf_thread_id(n));
+ }
+ } else if (lua_key_eq(s, thread_attr)) {
+ tokenlist_to_luastring(L, pdf_thread_attr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == open_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else if (lua_key_eq(s, name)) {
+ nodelib_pushstring(L, open_name(n));
+ } else if (lua_key_eq(s, area)) {
+ nodelib_pushstring(L, open_area(n));
+ } else if (lua_key_eq(s, ext)) {
+ nodelib_pushstring(L, open_ext(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == close_node) {
+ if (lua_key_eq(s, stream)) {
+ lua_pushinteger(L, write_stream(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+}
+
+static int lua_nodelib_direct_getfield(lua_State * L)
+{
+
+ const char *s;
+ halfword n = lua_tointeger(L, 1);
+ int t = type(n);
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ halfword p;
+ int i;
+ if (! nodetype_has_attributes(t)) {
+ lua_pushnil(L) ;
+ return 1;
+ }
+ p = node_attr(n);
+ if (p == null || vlink(p) == null) {
+ lua_pushnil(L) ;
+ return 1;
+ }
+ i = (int) lua_tointeger(L, 2);
+ p = vlink(p);
+ while (p != null) {
+ if (attribute_id(p) == i) {
+ if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
+ lua_pushinteger(L, (int) attribute_value(p));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ } else if (attribute_id(p) > i) {
+ lua_pushnil(L) ;
+ return 1;
+ }
+ p = vlink(p);
+ }
+ lua_pushnil(L) ;
+ return 1;
+ }
+
+ s = lua_tostring(L, 2);
+
+ if (lua_key_eq(s, id)) {
+ lua_pushinteger(L, t);
+ } else if (lua_key_eq(s, next)) {
+ nodelib_pushdirect_or_nil(vlink(n));
+ } else if (lua_key_eq(s, prev)) {
+ nodelib_pushdirect_or_nil(alink(n));
+ } else if (lua_key_eq(s, subtype)) {
+ if (t == glue_spec_node) {
+ lua_pushinteger(L, 0); /* dummy, the only one */
+ } else {
+ lua_pushinteger(L, subtype(n));
+ }
+ } else if (lua_key_eq(s, attr)) {
+ if (! nodetype_has_attributes(t)) {
+ lua_pushnil(L);
+ } else {
+ /* nodelib_pushattr(L, node_attr(n)); */
+ lua_pushinteger(L, node_attr(n));
+ }
+ } else if (t == glyph_node) {
+ if (lua_key_eq(s, font)) {
+ lua_pushinteger(L, font(n));
+ } else if (lua_key_eq(s, char)) {
+ lua_pushinteger(L, character(n));
+ } else if (lua_key_eq(s, xoffset)) {
+ 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, 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)) {
+ lua_pushinteger(L, char_height(font(n),character(n)));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, char_depth(font(n),character(n)));
+ } else if (lua_key_eq(s, expansion_factor)) {
+ lua_pushinteger(L, ex_glyph(n));
+ } else if (lua_key_eq(s, components)) {
+ nodelib_pushdirect_or_nil(lig_ptr(n));
+ } else if (lua_key_eq(s, lang)) {
+ lua_pushinteger(L, char_lang(n));
+ } else if (lua_key_eq(s, left)) {
+ lua_pushinteger(L, char_lhmin(n));
+ } else if (lua_key_eq(s, right)) {
+ lua_pushinteger(L, char_rhmin(n));
+ } else if (lua_key_eq(s, uchyph)) {
+ lua_pushinteger(L, char_uchyph(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == hlist_node) || (t == vlist_node)) {
+ /* candidates: whd (width,height,depth) */
+ if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
+ nodelib_pushdirect_or_nil_alink(list_ptr(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, shift_amount(n));
+ } else if (lua_key_eq(s, glue_order)) {
+ lua_pushinteger(L, glue_order(n));
+ } else if (lua_key_eq(s, glue_sign)) {
+ lua_pushinteger(L, glue_sign(n));
+ } else if (lua_key_eq(s, glue_set)) {
+ lua_pushnumber(L, (double) glue_set(n)); /* float */
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == disc_node) {
+ if (lua_key_eq(s, pre)) {
+ nodelib_pushdirect_or_nil(vlink(pre_break(n)));
+ } else if (lua_key_eq(s, post)) {
+ nodelib_pushdirect_or_nil(vlink(post_break(n)));
+ } else if (lua_key_eq(s, replace)) {
+ nodelib_pushdirect_or_nil(vlink(no_break(n)));
+ } else if (lua_key_eq(s, penalty)) {
+ lua_pushinteger(L, disc_penalty(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == glue_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else if (lua_key_eq(s, leader)) {
+ nodelib_pushdirect_or_nil(leader_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == kern_node) {
+ if (lua_key_eq(s, kern)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, expansion_factor)) {
+ lua_pushinteger(L, ex_kern(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == penalty_node) {
+ if (lua_key_eq(s, penalty)) {
+ lua_pushinteger(L, penalty(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == rule_node) {
+ /* candidates: whd (width,height,depth) */
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, rule_index(n));
+ } else if (lua_key_eq(s, transform)) {
+ lua_pushinteger(L,rule_transform(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == dir_node) {
+ if (lua_key_eq(s, direction)) {
+ lua_push_direction(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 */
+ lua_pushinteger(L, subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == local_par_node) {
+ if (lua_key_eq(s, pen_inter)) {
+ 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_push_direction(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)) {
+ nodelib_pushdirect_or_nil(local_box_left(n));
+ } else if (lua_key_eq(s, box_left_width)) {
+ lua_pushinteger(L, local_box_left_width(n));
+ } else if (lua_key_eq(s, box_right)) {
+ nodelib_pushdirect_or_nil(local_box_right(n));
+ } else if (lua_key_eq(s, box_right_width)) {
+ lua_pushinteger(L, local_box_right_width(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == whatsit_node) {
+ lua_nodelib_direct_getfield_whatsit(L, n, s);
+ } else if (t == simple_noad) {
+ if (lua_key_eq(s, nucleus)) {
+ nodelib_pushdirect_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ nodelib_pushdirect_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ nodelib_pushdirect_or_nil(supscr(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, noadoptions(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ if (lua_key_eq(s, fam)) {
+ lua_pushinteger(L, math_fam(n));
+ } else if (lua_key_eq(s, char)) {
+ lua_pushinteger(L, math_character(n));
+ } else if (lua_key_eq(s, font)) {
+ lua_pushinteger(L, fam_fnt(math_fam(n), 0));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == mark_node) {
+ if (lua_key_eq(s, class)) {
+ lua_pushinteger(L, mark_class(n));
+ } else if (lua_key_eq(s, mark)) {
+ tokenlist_to_lua(L, mark_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == ins_node) {
+ if (lua_key_eq(s, cost)) {
+ lua_pushinteger(L, float_cost(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, depth(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, height(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ nodelib_pushdirect_or_nil_alink(ins_ptr(n));
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == math_node) {
+ if (lua_key_eq(s, surround)) {
+ lua_pushinteger(L, surround(n));
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == fraction_noad) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, thickness(n));
+ } else if (lua_key_eq(s, num)) {
+ nodelib_pushdirect_or_nil(numerator(n));
+ } else if (lua_key_eq(s, denom)) {
+ nodelib_pushdirect_or_nil(denominator(n));
+ } else if (lua_key_eq(s, left)) {
+ nodelib_pushdirect_or_nil(left_delimiter(n));
+ } else if (lua_key_eq(s, right)) {
+ 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 {
+ lua_pushnil(L);
+ }
+ } else if (t == style_node) {
+ if (lua_key_eq(s, style)) {
+ lua_push_math_style_name(L,subtype(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == accent_noad) {
+ if (lua_key_eq(s, nucleus)) {
+ nodelib_pushdirect_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ nodelib_pushdirect_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ nodelib_pushdirect_or_nil(supscr(n));
+ } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
+ nodelib_pushdirect_or_nil(top_accent_chr(n));
+ } else if (lua_key_eq(s, bot_accent)) {
+ nodelib_pushdirect_or_nil(bot_accent_chr(n));
+ } else if (lua_key_eq(s, overlay_accent)) {
+ nodelib_pushdirect_or_nil(overlay_accent_chr(n));
+ } else if (lua_key_eq(s, fraction)) {
+ lua_pushinteger(L, accentfraction(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == fence_noad) {
+ if (lua_key_eq(s, delim)) {
+ nodelib_pushdirect_or_nil(delimiter(n));
+ } else if (lua_key_eq(s, italic)) {
+ lua_pushinteger(L, delimiteritalic(n));
+ } else if (lua_key_eq(s, height)) {
+ lua_pushinteger(L, delimiterheight(n));
+ } else if (lua_key_eq(s, depth)) {
+ lua_pushinteger(L, delimiterdepth(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, delimiteroptions(n));
+ } else if (lua_key_eq(s, class)) {
+ lua_pushinteger(L, delimiterclass(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == delim_node) {
+ if (lua_key_eq(s, small_fam)) {
+ lua_pushinteger(L, small_fam(n));
+ } else if (lua_key_eq(s, small_char)) {
+ lua_pushinteger(L, small_char(n));
+ } else if (lua_key_eq(s, large_fam)) {
+ lua_pushinteger(L, large_fam(n));
+ } else if (lua_key_eq(s, large_char)) {
+ lua_pushinteger(L, large_char(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ nodelib_pushdirect_or_nil_alink(math_list(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == radical_noad) {
+ if (lua_key_eq(s, nucleus)) {
+ nodelib_pushdirect_or_nil(nucleus(n));
+ } else if (lua_key_eq(s, sub)) {
+ nodelib_pushdirect_or_nil(subscr(n));
+ } else if (lua_key_eq(s, sup)) {
+ nodelib_pushdirect_or_nil(supscr(n));
+ } else if (lua_key_eq(s, left)) {
+ nodelib_pushdirect_or_nil(left_delimiter(n));
+ } else if (lua_key_eq(s, degree)) {
+ nodelib_pushdirect_or_nil(degree(n));
+ } else if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, radicalwidth(n));
+ } else if (lua_key_eq(s, options)) {
+ lua_pushinteger(L, radicaloptions(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == margin_kern_node) {
+ if (lua_key_eq(s, kern) ||lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, glyph)) {
+ nodelib_pushdirect_or_nil(margin_char(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == split_up_node) {
+ if (lua_key_eq(s, last_ins_ptr)) {
+ nodelib_pushdirect_or_nil(last_ins_ptr(n));
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ nodelib_pushdirect_or_nil(best_ins_ptr(n));
+ } else if (lua_key_eq(s, broken_ptr)) {
+ nodelib_pushdirect_or_nil(broken_ptr(n));
+ } else if (lua_key_eq(s, broken_ins)) {
+ nodelib_pushdirect_or_nil(broken_ins(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == choice_node) {
+ if (lua_key_eq(s, display)) {
+ nodelib_pushdirect_or_nil(display_mlist(n));
+ } else if (lua_key_eq(s, text)) {
+ nodelib_pushdirect_or_nil(text_mlist(n));
+ } else if (lua_key_eq(s, script)) {
+ nodelib_pushdirect_or_nil(script_mlist(n));
+ } else if (lua_key_eq(s, scriptscript)) {
+ nodelib_pushdirect_or_nil(script_script_mlist(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == inserting_node) {
+ if (lua_key_eq(s, last_ins_ptr)) {
+ nodelib_pushdirect_or_nil(last_ins_ptr(n));
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ nodelib_pushdirect_or_nil(best_ins_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == attribute_node) {
+ if (lua_key_eq(s, number)) {
+ lua_pushinteger(L, attribute_id(n));
+ } else if (lua_key_eq(s, value)) {
+ lua_pushinteger(L, attribute_value(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == adjust_node) {
+ if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == unset_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, height)) {
+ 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_push_direction(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)) {
+ lua_pushinteger(L, glue_shrink(n));
+ } else if (lua_key_eq(s, glue_order)) {
+ lua_pushinteger(L, glue_order(n));
+ } else if (lua_key_eq(s, glue_sign)) {
+ lua_pushinteger(L, glue_sign(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, glue_stretch(n));
+ } else if (lua_key_eq(s, count)) {
+ lua_pushinteger(L, span_count(n));
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ nodelib_pushdirect_or_nil_alink(list_ptr(n));
+ } else {
+ lua_pushnil(L);
+ }
+ /* } else if (t == attribute_list_node) { */
+ /* lua_pushnil(L); */
+ } else if (t == boundary_node) {
+ if (lua_key_eq(s, subtype)) {
+ lua_pushinteger(L, subtype(n));
+ } else if (lua_key_eq(s, value)) {
+ lua_pushinteger(L, boundary_value(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (t == glue_spec_node) {
+ if (lua_key_eq(s, width)) {
+ lua_pushinteger(L, width(n));
+ } else if (lua_key_eq(s, stretch)) {
+ lua_pushinteger(L, stretch(n));
+ } else if (lua_key_eq(s, shrink)) {
+ lua_pushinteger(L, shrink(n));
+ } else if (lua_key_eq(s, stretch_order)) {
+ lua_pushinteger(L, stretch_order(n));
+ } else if (lua_key_eq(s, shrink_order)) {
+ lua_pushinteger(L, shrink_order(n));
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+/* msg could be preallocated and shared */
+
+static void lua_nodelib_do_tostring(lua_State * L, halfword n, const char *tag)
+{
+ char *msg;
+ char a[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
+ char v[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
+ msg = xmalloc(256);
+ if ((alink(n) != null) && (type(n) != attribute_node))
+ snprintf(a, 7, "%6d", (int) alink(n));
+ if (vlink(n) != null)
+ snprintf(v, 7, "%6d", (int) vlink(n));
+ snprintf(msg, 255, "<%s %s < %6d > %s : %s %d>", tag, a, (int) n, v, node_data[type(n)].name, subtype(n));
+ lua_pushstring(L, msg);
+ free(msg);
+ return ;
+}
+
+/* __tostring node.tostring */
+
+static int lua_nodelib_tostring(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ lua_nodelib_do_tostring(L, n, "node");
+ return 1;
+}
+
+/* node.direct.tostring */
+
+static int lua_nodelib_direct_tostring(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ if (n==0) {
+ lua_pushnil(L);
+ } else {
+ lua_nodelib_do_tostring(L, n, "direct");
+ }
+ return 1;
+}
+
+/* __eq */
+
+static int lua_nodelib_equal(lua_State * L)
+{
+ halfword n = *((halfword *) lua_touserdata(L, 1));
+ halfword m = *((halfword *) lua_touserdata(L, 2));
+ lua_pushboolean(L, (n == m));
+ return 1;
+}
+
+/* node.ligaturing */
+
+static int font_tex_ligaturing(lua_State * L)
+{
+ /* on the stack are two nodes and a direction */
+ /* we need to deal with prev nodes when a range starts with a ligature */
+ halfword tmp_head;
+ halfword h;
+ halfword t = null;
+ halfword p ;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ lua_pushboolean(L, 0);
+ return 2;
+ }
+ h = *check_isnode(L, 1);
+ if (lua_gettop(L) > 1) {
+ t = *check_isnode(L, 2);
+ }
+ tmp_head = new_node(nesting_node, 1);
+ p = alink(h);
+ couple_nodes(tmp_head, h);
+ tlink(tmp_head) = t;
+ t = handle_ligaturing(tmp_head, t);
+ if (p != null) {
+ vlink(p) = vlink(tmp_head) ;
+ }
+ alink(vlink(tmp_head)) = p ;
+ /*
+ lua_pushinteger(L, vlink(tmp_head));
+ lua_nodelib_push(L);
+ */
+ lua_nodelib_push_fast(L, vlink(tmp_head));
+ /*
+ lua_pushinteger(L, t);
+ lua_nodelib_push(L);
+ */
+ lua_nodelib_push_fast(L, t);
+ lua_pushboolean(L, 1);
+ flush_node(tmp_head);
+ return 3;
+}
+
+static int font_tex_direct_ligaturing(lua_State * L)
+{
+ /* on the stack are two nodes and a direction */
+ /* we need to deal with prev nodes when a range starts with a ligature */
+ halfword tmp_head;
+ halfword h;
+ halfword t = null;
+ halfword p ;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ lua_pushboolean(L, 0);
+ return 2;
+ }
+ h = lua_tointeger(L, 1);
+ if (lua_gettop(L) > 1) {
+ t = lua_tointeger(L, 2);
+ }
+ tmp_head = new_node(nesting_node, 1);
+ p = alink(h);
+ couple_nodes(tmp_head, h);
+ tlink(tmp_head) = t;
+ t = handle_ligaturing(tmp_head, t);
+ if (p != null) {
+ vlink(p) = vlink(tmp_head) ;
+ }
+ alink(vlink(tmp_head)) = p ;
+ lua_pushinteger(L, vlink(tmp_head));
+ lua_pushinteger(L, t);
+ lua_pushboolean(L, 1);
+ flush_node(tmp_head);
+ return 3;
+}
+
+/* node.kerning */
+
+static int font_tex_kerning(lua_State * L)
+{
+ /* on the stack are two nodes and a direction */
+
+ halfword tmp_head;
+ halfword h;
+ halfword t = null;
+ halfword p ;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ lua_pushboolean(L, 0);
+ return 2;
+ }
+ h = *check_isnode(L, 1);
+ if (lua_gettop(L) > 1) {
+ t = *check_isnode(L, 2);
+ }
+ tmp_head = new_node(nesting_node, 1);
+ p = alink(h);
+ couple_nodes(tmp_head, h);
+ tlink(tmp_head) = t;
+ t = handle_kerning(tmp_head, t);
+ if (p != null) {
+ vlink(p) = vlink(tmp_head) ;
+ }
+ alink(vlink(tmp_head)) = p ;
+ /*
+ lua_pushinteger(L, vlink(tmp_head));
+ lua_nodelib_push(L);
+ */
+ lua_nodelib_push_fast(L, vlink(tmp_head));
+ /*
+ lua_pushinteger(L, t);
+ lua_nodelib_push(L);
+ */
+ lua_nodelib_push_fast(L, t);
+ lua_pushboolean(L, 1);
+ flush_node(tmp_head);
+ return 3;
+}
+
+static int font_tex_direct_kerning(lua_State * L)
+{
+ /* on the stack are two nodes and a direction */
+
+ halfword tmp_head;
+ halfword h;
+ halfword t = null;
+ halfword p ;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ lua_pushboolean(L, 0);
+ return 2;
+ }
+ h = lua_tointeger(L, 1);
+ if (lua_gettop(L) > 1) {
+ t = lua_tointeger(L, 2);
+ }
+ tmp_head = new_node(nesting_node, 1);
+ p = alink(h);
+ couple_nodes(tmp_head, h);
+ tlink(tmp_head) = t;
+ t = handle_kerning(tmp_head, t);
+ if (p != null) {
+ vlink(p) = vlink(tmp_head) ;
+ }
+ alink(vlink(tmp_head)) = p ;
+ lua_pushinteger(L, vlink(tmp_head));
+ if (t == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, t);
+ }
+ lua_pushboolean(L, 1);
+ flush_node(tmp_head);
+ return 3;
+}
+
+/*tex
+ It's more consistent to have it here (so we will alias in lang later). Todo:
+ if no glyph then quit.
+*/
+
+static int lang_tex_hyphenating(lua_State * L)
+{
+ halfword t = null;
+ halfword h = *check_isnode(L, 1);
+ if (lua_isuserdata(L, 2)) {
+ t = *check_isnode(L, 2);
+ }
+ if (t == null) {
+ t = h;
+ while (vlink(t) != null) {
+ t = vlink(t);
+ }
+ }
+ hnj_hyphenation(h, t);
+ lua_nodelib_push_fast(L, h);
+ lua_nodelib_push_fast(L, t);
+ lua_pushboolean(L, 1);
+ return 3;
+}
+
+static int lang_tex_direct_hyphenating(lua_State * L)
+{
+ halfword t = null;
+ halfword h = lua_tointeger(L, 1);
+ if (lua_type(L,1) != LUA_TNUMBER) {
+ t = lua_tointeger(L, 2);
+ }
+ if (t == null) {
+ t = h;
+ while (vlink(t) != null) {
+ t = vlink(t);
+ }
+ }
+ hnj_hyphenation(h, t);
+ lua_pushinteger(L, h);
+ lua_pushinteger(L, t);
+ lua_pushboolean(L, 1);
+ return 3;
+}
+
+/* node.protect_glyphs (returns also boolean because that signals callback) */
+/* node.unprotect_glyphs (returns also boolean because that signals callback) */
+
+#define protect_one_indeed(n) \
+ if (n != null) { \
+ int s = subtype(n); \
+ if (s <= 256) { \
+ subtype(n) = (quarterword) (s == 1 ? 256 : 256 + s); \
+ } \
+ }
+
+#define protect_all_indeed(n) \
+ h = n ; \
+ if (h != null) { \
+ while (h != null) { \
+ if (type(h) == glyph_node) { \
+ int s = subtype(h); \
+ if (s <= 256) { \
+ subtype(h) = (quarterword) (s == 1 ? 256 : 256 + s); \
+ } \
+ } \
+ h = vlink(h); \
+ } \
+ }
+
+#define protect_node_indeed(n) \
+ if (type(n) == glyph_node) { \
+ protect_one_indeed(n); \
+ } else if (type(n) == disc_node) { \
+ protect_all_indeed(vlink(no_break(n))); \
+ protect_all_indeed(vlink(pre_break(n))); \
+ protect_all_indeed(vlink(post_break(n))); \
+ }
+
+#define unprotect_one_indeed(n) \
+ if (n != null) { \
+ int s = subtype(n); \
+ if (s > 256) { \
+ subtype(n) = (quarterword) (s - 256); \
+ } \
+ }
+
+#define unprotect_all_indeed(n) \
+ h = n ; \
+ if (h != null) { \
+ while (h != null) { \
+ if (type(h) == glyph_node) { \
+ int s = subtype(h); \
+ if (s <= 256) { \
+ subtype(h) = (quarterword) (s - 256); \
+ } \
+ } \
+ h = vlink(h); \
+ } \
+ }
+
+#define unprotect_node_indeed(n) \
+ if (type(n) == glyph_node) { \
+ unprotect_one_indeed(n); \
+ } else if (type(n) == disc_node) { \
+ unprotect_all_indeed(vlink(no_break(n))); \
+ unprotect_all_indeed(vlink(pre_break(n))); \
+ unprotect_all_indeed(vlink(post_break(n))); \
+ }
+
+static int lua_nodelib_protect_glyph(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ halfword h;
+ protect_node_indeed(n);
+ return 0;
+}
+
+static int lua_nodelib_unprotect_glyph(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ halfword h;
+ unprotect_node_indeed(n);
+ return 0;
+}
+
+static int lua_nodelib_protect_glyphs(lua_State * L)
+{
+ halfword head = *check_isnode(L, 1);
+ halfword tail = null;
+ halfword h;
+ if (lua_gettop(L) > 1) {
+ tail = *check_isnode(L, 2);
+ }
+ while (head != null) {
+ protect_node_indeed(head);
+ if (head == tail) {
+ break;
+ }
+ head = vlink(head);
+ }
+ return 0;
+}
+
+static int lua_nodelib_unprotect_glyphs(lua_State * L)
+{
+ halfword head = *check_isnode(L, 1);
+ halfword tail = null;
+ halfword h;
+ if (lua_gettop(L) > 1) {
+ tail = *check_isnode(L, 2);
+ }
+ while (head != null) {
+ unprotect_node_indeed(head);
+ if (head == tail) {
+ break;
+ }
+ head = vlink(head);
+ }
+ return 0;
+}
+
+/* node.direct.protect_glyphs */
+/* node.direct.unprotect_glyphs */
+
+static int lua_nodelib_direct_protect_glyph(lua_State * L)
+{
+ halfword n = (halfword) lua_tointeger(L,1);
+ halfword h;
+ protect_node_indeed(n);
+ return 0;
+}
+
+static int lua_nodelib_direct_unprotect_glyph(lua_State * L)
+{
+ halfword n = (halfword) lua_tointeger(L,1);
+ halfword h;
+ unprotect_node_indeed(n);
+ return 0;
+}
+
+static int lua_nodelib_direct_protect_glyphs(lua_State * L)
+{
+ halfword head = (halfword) lua_tointeger(L,1);
+ halfword tail = (halfword) lua_tointeger(L,2);
+ halfword h;
+ while (head != null) {
+ protect_node_indeed(head);
+ if (head == tail) {
+ break;
+ }
+ head = vlink(head);
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_unprotect_glyphs(lua_State * L)
+{
+ halfword head = (halfword) lua_tointeger(L,1);
+ halfword tail = (halfword) lua_tointeger(L,2);
+ halfword h;
+ while (head != null) {
+ unprotect_node_indeed(head);
+ if (head == tail) {
+ break;
+ }
+ head = vlink(head);
+ }
+ return 0;
+}
+
+/* node.first_glyph */
+
+static int lua_nodelib_first_glyph(lua_State * L)
+{
+ /* on the stack are two nodes and a direction */
+ halfword h, savetail = null, t = null;
+ if (lua_gettop(L) < 1) {
+ lua_pushnil(L);
+ lua_pushboolean(L, 0);
+ return 2;
+ }
+ h = *(check_isnode(L, 1));
+ if (lua_gettop(L) > 1) {
+ t = *(check_isnode(L, 2));
+ savetail = vlink(t);
+ vlink(t) = null;
+ }
+ while (h != null && (type(h) != glyph_node || !is_simple_character(h))) {
+ h = vlink(h);
+ }
+ if (savetail != null) {
+ vlink(t) = savetail;
+ }
+ lua_pushinteger(L, h);
+ lua_nodelib_push(L);
+ lua_pushboolean(L, (h == null ? 0 : 1));
+ return 2;
+}
+
+/* node.direct.first_glyph */
+
+static int lua_nodelib_direct_first_glyph(lua_State * L)
+{
+ halfword h,savetail,t;
+ savetail = null;
+ t = null;
+ h = (halfword) lua_tointeger(L,1);
+ if (h == null) {
+ lua_pushnil(L);
+ return 1;
+ }
+ t = (halfword) lua_tointeger(L,2);
+ if (t != null) {
+ savetail = vlink(t);
+ vlink(t) = null;
+ }
+ while (h != null && (type(h) != glyph_node || !is_simple_character(h)))
+ h = vlink(h);
+ if (savetail != null)
+ vlink(t) = savetail;
+ lua_pushinteger(L, h);
+ return 1; /* no need to also push a boolean if we have nil */
+}
+
+/* new, fast and dumb ones: only signals that something needs to be processed */
+
+/* node.has_glyph */
+
+static int lua_nodelib_has_glyph(lua_State * L)
+{
+ halfword *a;
+ halfword h = (halfword) *(check_isnode(L,1)) ;
+ while (h != null) {
+ if ( (type(h) == glyph_node) || (type(h) == disc_node)) {
+ fast_metatable(h);
+ return 1;
+ } else {
+ h = vlink(h);
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+/* node.direct.has_glyph */
+
+static int lua_nodelib_direct_has_glyph(lua_State * L)
+{
+ halfword h = (halfword) lua_tointeger(L,1) ;
+ while (h != null) {
+ if ((type(h) == glyph_node) || (type(h) == disc_node)) {
+ nodelib_pushdirect(h);
+ return 1;
+ } else {
+ h = vlink(h);
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+/* this is too simplistic, but it helps Hans to get going */
+
+/*
+
+static halfword do_ligature_n(halfword prev, halfword stop, halfword lig)
+{
+ vlink(lig) = vlink(stop);
+ vlink(stop) = null;
+ lig_ptr(lig) = vlink(prev);
+ vlink(prev) = lig;
+ return lig;
+}
+
+*/
+
+/* node.do_ligature_n(node prev, node last, node lig) */
+
+/*
+
+static int lua_nodelib_do_ligature_n(lua_State * L)
+{
+ halfword p;
+ halfword n = *check_isnode(L, 1);
+ halfword m = *check_isnode(L, 2);
+ halfword o = *check_isnode(L, 3);
+ if (alink(n) == null || vlink(alink(n)) != n) {
+ halfword tmp_head = new_node(temp_node, 0);
+ couple_nodes(tmp_head, n);
+ p = do_ligature_n(tmp_head, m, o);
+ flush_node(tmp_head);
+ } else {
+ p = do_ligature_n(alink(n), m, o);
+ }
+ lua_pushinteger(L, p);
+ lua_nodelib_push(L);
+ return 1;
+}
+
+*/
+
+/* node.direct.do_ligature_n(node prev, node last, node lig) */
+
+/*
+
+static int lua_nodelib_direct_do_ligature_n(lua_State * L)
+{
+ halfword p;
+ halfword n = (halfword) lua_tointeger(L, 1);
+ halfword m = (halfword) lua_tointeger(L, 2);
+ halfword o = (halfword) lua_tointeger(L, 3);
+ if ((n == null) || (m == null) || (o == null)) {
+ lua_pushnil(L);
+ } else {
+ if (alink(n) == null || vlink(alink(n)) != n) {
+ halfword tmp_head = new_node(temp_node, 0);
+ couple_nodes(tmp_head, n);
+ p = do_ligature_n(tmp_head, m, o);
+ flush_node(tmp_head);
+ } else {
+ p = do_ligature_n(alink(n), m, o);
+ }
+ lua_pushinteger(L, p);
+ }
+ return 1;
+}
+
+*/
+
+/* node.usedlist */
+
+static int lua_nodelib_usedlist(lua_State * L)
+{
+ lua_pushinteger(L, list_node_mem_usage());
+ lua_nodelib_push(L);
+ return 1;
+}
+
+/* node.direct.usedlist */
+
+static int lua_nodelib_direct_usedlist(lua_State * L)
+{
+ lua_pushinteger(L, list_node_mem_usage());
+ return 1;
+}
+
+/* node.protrusion_skipable(node m) */
+
+static int lua_nodelib_cp_skipable(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ lua_pushboolean(L, cp_skipable(n));
+ return 1;
+}
+
+/* node.direct.protrusion_skipable(node m) */
+
+static int lua_nodelib_direct_cp_skipable(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushboolean(L, cp_skipable(n));
+ }
+ return 1;
+}
+
+
+/* node.currentattr(node m) */
+
+static int lua_nodelib_currentattr(lua_State * L)
+{
+ int u = lua_gettop(L);
+ if (u == null) {
+ /* query */
+ halfword n ;
+ /* current_attribute_list() return attr_list_cache */
+ /* or null (attr_list_cache can also be null) */
+ n = current_attribute_list();
+ if (n) {
+ lua_pushinteger(L, n);
+ lua_nodelib_push(L);
+ }
+ else
+ lua_pushnil(L);
+ return 1;
+ } else {
+ /* assign */
+ normal_warning("node lib","assignment via node.current_attr(<list>) is not supported (yet)");
+ return 0;
+ }
+}
+
+
+/* node.direct.currentattr(node m) */
+
+static int lua_nodelib_direct_currentattr(lua_State * L)
+{
+ /* current_attribute_list() return attr_list_cache */
+ /* or null (attr_list_cache can also be null) */
+ halfword n = current_attribute_list();
+ if (n)
+ lua_pushinteger(L, n);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+
+/* node.direct.todirect */
+
+static int lua_nodelib_direct_todirect(lua_State * L)
+{
+ if (lua_type(L,1) != LUA_TNUMBER) {
+ /* assume node, no further testing, used in known situations */
+ void *n ;
+ n = lua_touserdata(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, *((halfword *)n) );
+ }
+ } /* else assume direct and returns argument */
+ return 1;
+}
+
+
+/* node.direct.tonode */
+
+static int lua_nodelib_direct_tonode(lua_State * L)
+{
+ halfword *a;
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ a = (halfword *) lua_newuserdata(L, sizeof(halfword));
+ *a=n;
+ lua_get_metatablelua(luatex_node);
+ lua_setmetatable(L,-2);
+ } /* else assume node and return argument */
+ return 1;
+}
+
+/* node.setfield */
+
+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) || 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) {
+ /*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) ;
+ late_lua_name(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ /* done */
+ } else if (t == user_defined_node) {
+ if (lua_key_eq(s, user_id)) {
+ user_node_id(n) = (halfword) lua_tointeger(L, 3);
+ } 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;
+ }
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_annot_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_annot_data(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_dest_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, dest_id)) {
+ if (pdf_dest_named_id(n) == 1) {
+ pdf_dest_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, dest_type)) {
+ pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, xyz_zoom)) {
+ pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_setmatrix_node) {
+ if (lua_key_eq(s, data)) {
+ set_pdf_setmatrix_direct_value(L,n,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_refobj_node) {
+ if (lua_key_eq(s, objnum)) {
+ pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_start_link_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, link_attr)) {
+ pdf_link_attr(n) = nodelib_gettoks(L, 3);
+ } else if (lua_key_eq(s, action)) {
+ pdf_link_action(n) = nodelib_getaction(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == write_node) {
+ if (lua_key_eq(s, stream)) {
+ write_stream(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ set_write_direct_value(L,n,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_colorstack_node) {
+ if (lua_key_eq(s, stack)) {
+ pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, command)) {
+ pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_action_node) {
+ if (lua_key_eq(s, action_type)) {
+ pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, action_id)) {
+ if (pdf_action_named_id(n) == 1) {
+ pdf_action_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, file)) {
+ pdf_action_file(n) = nodelib_gettoks(L, 3);
+ } else if (lua_key_eq(s, new_window)) {
+ pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_action_tokens(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, thread_id)) {
+ if (pdf_thread_named_id(n) == 1) {
+ pdf_thread_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, thread_attr)) {
+ pdf_thread_attr(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == special_node) {
+ if (lua_key_eq(s, data)) {
+ set_special_direct_value(L,n,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == open_node) {
+ if (lua_key_eq(s, stream)) {
+ write_stream(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, name)) {
+ open_name(n) = nodelib_getstring(L, 3);
+ } else if (lua_key_eq(s, area)) {
+ open_area(n) = nodelib_getstring(L, 3);
+ } else if (lua_key_eq(s, ext)) {
+ open_ext(n) = nodelib_getstring(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == close_node) {
+ if (lua_key_eq(s, stream)) {
+ write_stream(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_link_state_node) {
+ if (lua_key_eq(s, value)) {
+ pdf_link_state(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
+ (t == pdf_save_node) || (t == pdf_restore_node)) {
+ return nodelib_cantset(L, n, s);
+ } else {
+ /* do nothing */
+ }
+ return 0;
+}
+
+static int lua_nodelib_fast_setfield(lua_State * L)
+{
+ const char *s;
+ halfword n = *((halfword *) lua_touserdata(L, 1));
+ int t = type(n);
+
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ if (lua_gettop(L) == 3) {
+ int i = lua_tointeger(L, 2);
+ int val = lua_tointeger(L, 3);
+ if (val == UNUSED_ATTRIBUTE) {
+ (void) unset_attribute(n, i, val);
+ } else {
+ set_attribute(n, i, val);
+ }
+ } else {
+ luaL_error(L, "incorrect number of arguments");
+ }
+ return 0;
+ }
+
+ s = lua_tostring(L, 2);
+
+ /*if (lua_key_eq(s, id)) {
+ type(n) = (quarteword) lua_tointeger(L, 3);
+ }* else */
+ if (lua_key_eq(s, next)) {
+ halfword x = nodelib_getlist(L, 3);
+ if (x>0 && type(x) == glue_spec_node) {
+ return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
+ }
+ vlink(n) = x;
+ } else if (lua_key_eq(s, prev)) {
+ halfword x = nodelib_getlist(L, 3);
+ if (x>0 && type(x) == glue_spec_node) {
+ return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
+ }
+ alink(n) = x;
+ } else if (lua_key_eq(s, attr)) {
+ if (nodetype_has_attributes(type(n))) {
+ nodelib_setattr(L, 3, n);
+ }
+ } else if (t == glyph_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, font)) {
+ font(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, char)) {
+ character(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, xoffset)) {
+ 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, 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)) {
+ /* not yet */
+ } else if (lua_key_eq(s, depth)) {
+ /* not yet */
+ } else if (lua_key_eq(s, expansion_factor)) {
+ ex_glyph(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, components)) {
+ lig_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, lang)) {
+ set_char_lang(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, left)) {
+ set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, right)) {
+ set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, uchyph)) {
+ set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == hlist_node) || (t == vlist_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
+ list_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ glue_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_sign)) {
+ glue_sign(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_set)) {
+ glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == disc_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, pre)) {
+ set_disc_field(pre_break(n), nodelib_getlist(L, 3));
+ } else if (lua_key_eq(s, post)) {
+ set_disc_field(post_break(n), nodelib_getlist(L, 3));
+ } else if (lua_key_eq(s, replace)) {
+ set_disc_field(no_break(n), nodelib_getlist(L, 3));
+ } else if (lua_key_eq(s, penalty)) {
+ disc_penalty(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == glue_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, leader)) {
+ leader_ptr(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, kern)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, expansion_factor)) {
+ ex_kern(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == penalty_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, penalty)) {
+ penalty(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == rule_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ rule_transform(n) = (halfword) lua_roundnumber(L, 3); /* can also be user value */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == dir_node) {
+ 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 {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == local_par_node) {
+ if (lua_key_eq(s, pen_inter)) {
+ 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_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)) {
+ local_box_left_width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, box_right)) {
+ local_box_right(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, box_right_width)) {
+ local_box_right_width(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == whatsit_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ lua_nodelib_setfield_whatsit(L, n, s);
+ }
+ } else if (t == simple_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, options)) {
+ noadoptions(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, fam)) {
+ math_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, char)) {
+ math_character(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == mark_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, class)) {
+ mark_class(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, mark)) {
+ mark_ptr(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == ins_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, cost)) {
+ float_cost(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, depth)) {
+ depth(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ ins_ptr(n) = nodelib_getlist(L, 3);
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == math_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, surround)) {
+ surround(n) = (halfword) lua_roundnumber(L, 3);
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == fraction_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ thickness(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, num)) {
+ numerator(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, denom)) {
+ denominator(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, left)) {
+ left_delimiter(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, right)) {
+ 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 {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == style_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, style)) {
+ assign_math_style(L,3,subtype(n));
+ } else {
+ /* return nodelib_cantset(L, n, s); */
+ }
+ } else if (t == accent_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_getlist(L, 3);
+ } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
+ top_accent_chr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, bot_accent)) {
+ bot_accent_chr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, overlay_accent)) {
+ overlay_accent_chr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, fraction)) {
+ accentfraction(n) = (halfword) lua_roundnumber(L,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == fence_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, delim)) {
+ delimiter(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, italic)) {
+ delimiteritalic(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, height)) {
+ delimiterheight(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, depth)) {
+ delimiterdepth(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, options)) {
+ delimiteroptions(n) = (halfword) lua_tointeger(L,3);
+ } else if (lua_key_eq(s, class)) {
+ delimiterclass(n) = (halfword) lua_tointeger(L,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == delim_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, small_fam)) {
+ small_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, small_char)) {
+ small_char(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, large_fam)) {
+ large_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, large_char)) {
+ large_char(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ math_list(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == radical_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, left)) {
+ left_delimiter(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, degree)) {
+ degree(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ radicalwidth(n) = lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, options)) {
+ radicaloptions(n) = (halfword) lua_tointeger(L,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == margin_kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width) || lua_key_eq(s, kern)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, glyph)) {
+ margin_char(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == split_up_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ last_ins_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ best_ins_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, broken_ptr)) {
+ broken_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, broken_ins)) {
+ broken_ins(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == choice_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, display)) {
+ display_mlist(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, text)) {
+ text_mlist(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, script)) {
+ script_mlist(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, scriptscript)) {
+ script_script_mlist(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == inserting_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ last_ins_ptr(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ best_ins_ptr(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == attribute_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, number)) {
+ attribute_id(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, value)) {
+ attribute_value(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == adjust_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ adjust_ptr(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == unset_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ glue_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_sign)) {
+ glue_sign(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ glue_stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, count)) {
+ span_count(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ list_ptr(n) = nodelib_getlist(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == attribute_list_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == boundary_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, value)) {
+ boundary_value(n) = lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == glue_spec_node) {
+ if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else {
+ return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
+ }
+ return 0;
+}
+
+static int lua_nodelib_setfield(lua_State * L)
+{
+ /* [given-node] [...]*/
+ halfword *p = lua_touserdata(L, 1);
+ if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
+ return 0;
+ }
+ /* [given-node] [mt-given-node]*/
+ lua_get_metatablelua(luatex_node);
+ /* [given-node] [mt-given-node] [mt-node]*/
+ if ( (!lua_rawequal(L, -1, -2)) ) {
+ return 0;
+ }
+ /* prune stack and call getfield */
+ lua_settop(L,3);
+ return lua_nodelib_fast_setfield(L);
+}
+
+/* node.direct.setfield */
+
+static int lua_nodelib_direct_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) || 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) {
+ /*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) ;
+ late_lua_name(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == user_defined_node) {
+ if (lua_key_eq(s, user_id)) {
+ user_node_id(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, type)) {
+ user_node_type(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, value)) {
+ set_user_node_direct_value(L, n, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_annot_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_annot_data(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_dest_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, dest_id)) {
+ if (pdf_dest_named_id(n) == 1) {
+ pdf_dest_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, dest_type)) {
+ pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, xyz_zoom)) {
+ pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_setmatrix_node) {
+ if (lua_key_eq(s, data)) {
+ set_pdf_setmatrix_direct_value(L, n, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_refobj_node) {
+ if (lua_key_eq(s, objnum)) {
+ pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_start_link_node) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, objnum)) {
+ pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, link_attr)) {
+ pdf_link_attr(n) = nodelib_gettoks(L, 3);
+ } else if (lua_key_eq(s, action)) {
+ pdf_link_action(n) = nodelib_popdirect(n); /*nodelib_getaction(L, 3);*/
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == write_node) {
+ if (lua_key_eq(s, stream)) {
+ set_write_direct_value(L,n,3);
+ } else if (lua_key_eq(s, data)) {
+ set_write_direct_value(L,n,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_colorstack_node) {
+ if (lua_key_eq(s, stack)) {
+ pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, command)) {
+ pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == pdf_action_node) {
+ if (lua_key_eq(s, action_type)) {
+ pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, action_id)) {
+ if (pdf_action_named_id(n) == 1) {
+ pdf_action_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, file)) {
+ pdf_action_file(n) = nodelib_gettoks(L, 3);
+ } else if (lua_key_eq(s, new_window)) {
+ pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, data)) {
+ pdf_action_tokens(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
+ if (lua_key_eq(s, width)) {
+ width(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, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, named_id)) {
+ pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, thread_id)) {
+ if (pdf_thread_named_id(n) == 1) {
+ pdf_thread_id(n) = nodelib_gettoks(L, 3);
+ } else {
+ pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
+ }
+ } else if (lua_key_eq(s, thread_attr)) {
+ pdf_thread_attr(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == special_node) {
+ if (lua_key_eq(s, data)) {
+ set_special_direct_value(L, n, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == open_node) {
+ if (lua_key_eq(s, stream)) {
+ write_stream(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, name)) {
+ open_name(n) = nodelib_getstring(L, 3);
+ } else if (lua_key_eq(s, area)) {
+ open_area(n) = nodelib_getstring(L, 3);
+ } else if (lua_key_eq(s, ext)) {
+ open_ext(n) = nodelib_getstring(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == close_node) {
+ if (lua_key_eq(s, stream)) {
+ write_stream(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
+ (t == pdf_save_node) || (t == pdf_restore_node)) {
+ return nodelib_cantset(L, n, s);
+ } else {
+ /* do nothing */
+ }
+ return 0;
+}
+
+/* direct.is_char */
+/* direct.is_glyph */
+
+static int lua_nodelib_direct_is_char(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (type(n) != glyph_node) {
+ lua_pushnil(L); /* no glyph at all */
+ lua_pushinteger(L,type(n)); /* can save a lookup call */
+ return 2;
+ } else if (subtype(n) >= 256) {
+ lua_pushboolean(L,0); /* a done glyph */
+ } else if (lua_type(L,2) == LUA_TNUMBER) {
+ halfword f = lua_tointeger(L, 2);
+ if (f && f == font(n)) {
+ lua_pushinteger(L,character(n)); /* a todo glyph in the asked font */
+ } else {
+ lua_pushboolean(L,0); /* a todo glyph in another font */
+ }
+ } else {
+ lua_pushinteger(L,character(n)); /* a todo glyph */
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_is_glyph(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (type(n) != glyph_node) {
+ lua_pushboolean(L,0);
+ lua_pushinteger(L,type(n));
+ } else {
+ lua_pushinteger(L,character(n));
+ lua_pushinteger(L,font(n));
+ }
+ return 2;
+}
+
+/* uses_font */
+/* direct.uses_font */
+
+#define uses_font_disc(what,p,n) \
+p = vlink(what(n)); \
+while (p) { \
+ if ((type(p) == glyph_node) && (font(p) == f)) { \
+ lua_pushboolean(L,1); \
+ return 1; \
+ } \
+ p = vlink(p); \
+}
+
+
+static int lua_nodelib_direct_uses_font(lua_State * L)
+{
+ halfword n = lua_tointeger(L,1);
+ halfword f = lua_tointeger(L,2);
+ halfword p;
+ if (type(n) == glyph_node) {
+ lua_pushboolean(L,font(n) == f);
+ return 1;
+ } else if (type(n) == disc_node) {
+ uses_font_disc(pre_break,p,n);
+ uses_font_disc(post_break,p,n);
+ uses_font_disc(no_break,p,n);
+ }
+ /* todo: other node types */
+ lua_pushboolean(L,0);
+ return 1;
+}
+
+static int lua_nodelib_uses_font(lua_State * L)
+{
+ halfword n = *check_isnode(L, 1);
+ halfword f = lua_tointeger(L,2);
+ halfword p;
+ if (type(n) == glyph_node) {
+ lua_pushboolean(L,font(n) == f);
+ return 1;
+ } else if (type(n) == disc_node) {
+ uses_font_disc(pre_break,p,n);
+ uses_font_disc(post_break,p,n);
+ uses_font_disc(no_break,p,n);
+ }
+ /* todo: other node types */
+ lua_pushboolean(L,0);
+ return 1;
+}
+
+
+/* direct.setfield */
+
+static int lua_nodelib_direct_setfield(lua_State * L)
+{
+ const char *s;
+
+ halfword n = lua_tointeger(L, 1);
+ int t = type(n);
+
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ if (lua_gettop(L) == 3) {
+ int i = lua_tointeger(L, 2);
+ int val = lua_tointeger(L, 3);
+ if (val == UNUSED_ATTRIBUTE) {
+ (void) unset_attribute(n, i, val);
+ } else {
+ set_attribute(n, i, val);
+ }
+ } else {
+ luaL_error(L, "incorrect number of arguments");
+ }
+ return 0;
+ }
+
+ s = lua_tostring(L, 2);
+
+ /*if (lua_key_eq(s, id)) {
+ type(n) = (quarteword) lua_tointeger(L, 3);
+ } else*/
+ if (lua_key_eq(s, next)) {
+ halfword x = nodelib_popdirect(3);
+ if (x>0 && type(x) == glue_spec_node) {
+ return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
+ }
+ vlink(n) = x;
+ } else if (lua_key_eq(s, prev)) {
+ halfword x = nodelib_popdirect(3);
+ if (x>0 && type(x) == glue_spec_node) {
+ return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
+ }
+ alink(n) = x;
+ } else if (lua_key_eq(s, attr)) {
+ if (nodetype_has_attributes(type(n))) {
+ /* nodelib_setattr(L, 3, n); */
+ reassign_attribute(n,lua_tointeger(L, 3));
+ }
+ } else if (t == glyph_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, font)) {
+ font(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, char)) {
+ character(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, xoffset)) {
+ 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, 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)) {
+ lig_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, lang)) {
+ set_char_lang(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, left)) {
+ set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, right)) {
+ set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, uchyph)) {
+ set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
+ } else if (lua_key_eq(s, width)) {
+ /* not yet */
+ } else if (lua_key_eq(s, height)) {
+ /* not yet */
+ } else if (lua_key_eq(s, depth)) {
+ /* not yet */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == hlist_node) || (t == vlist_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
+ list_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ glue_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_sign)) {
+ glue_sign(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_set)) {
+ glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == disc_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, pre)) {
+ set_disc_field(pre_break(n), nodelib_popdirect(3));
+ } else if (lua_key_eq(s, post)) {
+ set_disc_field(post_break(n), nodelib_popdirect(3));
+ } else if (lua_key_eq(s, replace)) {
+ set_disc_field(no_break(n), nodelib_popdirect(3));
+ } else if (lua_key_eq(s, penalty)) {
+ disc_penalty(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == glue_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, leader)) {
+ leader_ptr(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, kern)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, expansion_factor)) {
+ ex_kern(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == penalty_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, penalty)) {
+ penalty(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == rule_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ rule_transform(n) = (halfword) lua_roundnumber(L, 3); /* can also be user value */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == dir_node) {
+ 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 {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == whatsit_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ lua_nodelib_direct_setfield_whatsit(L, n, s);
+ }
+ } else if (t == local_par_node) {
+ if (lua_key_eq(s, pen_inter)) {
+ 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_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)) {
+ local_box_left_width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, box_right)) {
+ local_box_right(n) = nodelib_getlist(L, 3);
+ } else if (lua_key_eq(s, box_right_width)) {
+ local_box_right_width(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == simple_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, options)) {
+ noadoptions(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == math_char_node) || (t == math_text_char_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, fam)) {
+ math_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, char)) {
+ math_character(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == mark_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, class)) {
+ mark_class(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, mark)) {
+ mark_ptr(n) = nodelib_gettoks(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == ins_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, cost)) {
+ float_cost(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, depth)) {
+ depth(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ height(n) = (halfword) lua_roundnumber(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ ins_ptr(n) = nodelib_popdirect(3);
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == math_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, surround)) {
+ surround(n) = (halfword) lua_roundnumber(L, 3);
+ /* glue */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == fraction_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width)) {
+ thickness(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, num)) {
+ numerator(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, denom)) {
+ denominator(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, left)) {
+ left_delimiter(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, right)) {
+ 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 {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == style_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, style)) {
+ assign_math_style(L,2,subtype(n));
+ } else {
+ /* return nodelib_cantset(L, n, s); */
+ }
+ } else if (t == accent_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_popdirect(3);
+ } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
+ top_accent_chr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, bot_accent)) {
+ bot_accent_chr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, overlay_accent)) {
+ overlay_accent_chr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, fraction)) {
+ accentfraction(n) = (halfword) lua_roundnumber(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == fence_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, delim)) {
+ delimiter(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, italic)) {
+ delimiteritalic(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, height)) {
+ delimiterheight(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, depth)) {
+ delimiterdepth(n) = (halfword) lua_roundnumber(L,3);
+ } else if (lua_key_eq(s, options)) {
+ delimiteroptions(n) = (halfword) lua_tointeger(L,3);
+ } else if (lua_key_eq(s, class)) {
+ delimiterclass(n) = (halfword) lua_tointeger(L,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == delim_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, small_fam)) {
+ small_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, small_char)) {
+ small_char(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, large_fam)) {
+ large_fam(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, large_char)) {
+ large_char(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ math_list(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == radical_noad) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, nucleus)) {
+ nucleus(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sub)) {
+ subscr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, sup)) {
+ supscr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, left)) {
+ left_delimiter(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, degree)) {
+ degree(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, width)) {
+ radicalwidth(n) = lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, options)) {
+ radicaloptions(n) = (halfword) lua_tointeger(L,3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == margin_kern_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, width) || lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, glyph)) {
+ margin_char(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == split_up_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ last_ins_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ best_ins_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, broken_ptr)) {
+ broken_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, broken_ins)) {
+ broken_ins(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == choice_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, display)) {
+ display_mlist(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, text)) {
+ text_mlist(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, script)) {
+ script_mlist(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, scriptscript)) {
+ script_script_mlist(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == inserting_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, last_ins_ptr)) {
+ last_ins_ptr(n) = nodelib_popdirect(3);
+ } else if (lua_key_eq(s, best_ins_ptr)) {
+ best_ins_ptr(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == attribute_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, number)) {
+ attribute_id(n) = (halfword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, value)) {
+ attribute_value(n) = (halfword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == adjust_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
+ adjust_ptr(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == unset_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, height)) {
+ 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_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)) {
+ glue_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, glue_sign)) {
+ glue_sign(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ glue_stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, count)) {
+ span_count(n) = (quarterword) lua_tointeger(L, 3);
+ } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
+ list_ptr(n) = nodelib_popdirect(3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == attribute_list_node) {
+ if (lua_key_eq(s, subtype)) {
+ /* dummy subtype */
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == boundary_node) {
+ if (lua_key_eq(s, subtype)) {
+ subtype(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, value)) {
+ boundary_value(n) = lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else if (t == glue_spec_node) {
+ if (lua_key_eq(s, width)) {
+ width(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch)) {
+ stretch(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, shrink)) {
+ shrink(n) = (halfword) lua_roundnumber(L, 3);
+ } else if (lua_key_eq(s, stretch_order)) {
+ stretch_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else if (lua_key_eq(s, shrink_order)) {
+ shrink_order(n) = (quarterword) lua_tointeger(L, 3);
+ } else {
+ return nodelib_cantset(L, n, s);
+ }
+ } else {
+ return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
+ }
+ return 0;
+}
+
+/* boxes */
+
+static int direct_get_box_id(lua_State * L, int i)
+{
+ const char *s;
+ int cur_cs1, cur_cmd1;
+ size_t k = 0;
+ int j = -1;
+ switch (lua_type(L, i)) {
+ case LUA_TSTRING:
+ s = lua_tolstring(L, i, &k);
+ cur_cs1 = string_lookup(s, k);
+ cur_cmd1 = eq_type(cur_cs1);
+ if (cur_cmd1 == char_given_cmd ||
+ cur_cmd1 == math_given_cmd) {
+ j = equiv(cur_cs1);
+ }
+ break;
+ case LUA_TNUMBER:
+ j = lua_tointeger(L, (i));
+ break;
+ default:
+ luaL_error(L, "argument must be a string or a number");
+ j = -1; /* not a valid box id */
+ }
+ return j;
+}
+
+/* node.getbox = tex.getbox */
+/* node.setbox = tex.setbox */
+
+/* node.direct.getbox */
+/* node.direct.setbox */
+
+static int lua_nodelib_direct_getbox(lua_State * L)
+{
+ int t;
+ int k = direct_get_box_id(L, -1);
+ direct_check_index_range(k, "getbox");
+ t = get_tex_box_register(k);
+ if (t == null) {
+ lua_pushnil(L);
+ } else {
+ lua_pushinteger(L, t);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_setbox(lua_State * L)
+{
+ int isglobal = 0;
+ int j, k, err, t;
+ int save_global_defs ;
+ int n = lua_gettop(L);
+ if (n == 3 && (lua_type(L, 1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s, global))
+ isglobal = 1;
+ }
+ t = lua_type(L, -1);
+ k = direct_get_box_id(L, -2);
+ direct_check_index_range(k, "setbox");
+ if (t == LUA_TBOOLEAN) {
+ j = lua_toboolean(L, -1);
+ if (j == 0) {
+ j = null;
+ } else {
+ return 0;
+ }
+ } else if (t == LUA_TNIL) {
+ j = null;
+ } else {
+ j = nodelib_popdirect(-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;
+ }
+ }
+ save_global_defs = global_defs_par;
+ if (isglobal) {
+ global_defs_par = 1;
+ }
+ err = set_tex_box_register(k, j);
+ global_defs_par = save_global_defs;
+ if (err) {
+ luaL_error(L, "incorrect value");
+ }
+ return 0;
+}
+
+/* node.is_node(n) */
+
+/*
+
+static int lua_nodelib_is_node(lua_State * L)
+{
+ if (maybe_isnode(L,1) == NULL)
+ lua_pushboolean(L,0);
+ else
+ lua_pushboolean(L,1);
+ 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)
+{ /*
+ quick and dirty and faster than not node.is_node, this helper
+ returns false or <direct>
+ */
+ /*
+ if (lua_type(L,1) == LUA_TNUMBER)
+ lua_pushboolean(L,1);
+ else
+ lua_pushboolean(L,0);
+ */
+ if (lua_type(L,1) != LUA_TNUMBER)
+ lua_pushboolean(L,0);
+ /* else return direct */
+ return 1;
+}
+
+/* node.direct.is_node(n) (handy for mixed usage testing) */
+
+static int lua_nodelib_direct_is_node(lua_State * L)
+{ /*
+ quick and dirty, only checks userdata, node.is_node is slower but
+ more exact, this helper returns false or <node>
+ */
+ /*
+ halfword *n = lua_touserdata(L, 1);
+ if (n != NULL) {
+ lua_pushboolean(L,1);
+ } else {
+ lua_pushboolean(L,0);
+ }
+ */
+ if (maybe_isnode(L,1) == NULL)
+ lua_pushboolean(L,0);
+ /* else assume and return node */
+ return 1;
+}
+
+ /*
+ Beware, enabling and disabling can result in an inconsistent properties table
+ but it might make sense sometimes. Of course by default we have disabled this
+ mechanism. And, one can always sweep the table empty.
+*/
+
+static int lua_nodelib_properties_set_mode(lua_State * L)
+{ /* <boolean> */
+ if (lua_isboolean(L,1)) {
+ lua_properties_enabled = lua_toboolean(L,1);
+ }
+ if (lua_isboolean(L,2)) {
+ lua_properties_use_metatable = lua_toboolean(L,2);
+ }
+ return 0;
+}
+
+/* We used to have variants in assigned defaults but they made no sense. */
+
+static int lua_nodelib_properties_flush_table(lua_State * L)
+{ /* <node|direct> <number> */
+ lua_get_metatablelua(node_properties);
+ lua_pushnil(L); /* initializes lua_next */
+ while (lua_next(L,-2) != 0) {
+ lua_pushvalue(L,-2);
+ lua_pushnil(L);
+ lua_settable(L,-5);
+ lua_pop(L,1);
+ }
+ return 1;
+}
+
+/* maybe we should allocate a proper index 0..var_mem_max but not now */
+
+static int lua_nodelib_get_property(lua_State * L)
+{ /* <node> */
+ halfword n = *((halfword *) lua_touserdata(L, 1));
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ lua_get_metatablelua(node_properties);
+ lua_rawgeti(L,-1,n);
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_get_property(lua_State * L)
+{ /* <direct> */
+ halfword n = lua_tointeger(L, 1);
+ if (n == null) {
+ lua_pushnil(L);
+ } else {
+ lua_get_metatablelua(node_properties);
+ lua_rawgeti(L,-1,n);
+ }
+ return 1;
+}
+
+static int lua_nodelib_set_property(lua_State * L)
+{
+ /* <node> <value> */
+ halfword n = *((halfword *) lua_touserdata(L, 1));
+ if (n != null) {
+ lua_settop(L,2);
+ lua_get_metatablelua(node_properties);
+ /* <node> <value> <propertytable> */
+ lua_replace(L,-3);
+ /* <propertytable> <value> */
+ lua_rawseti(L,-2,n);
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_set_property(lua_State * L)
+{
+ /* <direct> <value> */
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ lua_settop(L,2);
+ lua_get_metatablelua(node_properties);
+ /* <node> <value> <propertytable> */
+ lua_replace(L,1);
+ /* <propertytable> <value> */
+ lua_rawseti(L,1,n);
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_properties_get_table(lua_State * L)
+{ /* <node|direct> */
+ lua_get_metatablelua(node_properties);
+ return 1;
+}
+
+static int lua_nodelib_properties_get_table(lua_State * L)
+{ /* <node|direct> */
+ lua_get_metatablelua(node_properties_indirect);
+ return 1;
+}
+
+/* bonus */
+
+static int lua_nodelib_get_property_t(lua_State * L)
+{ /* <table> <node> */
+ halfword n = *((halfword *) lua_touserdata(L, 2));
+ if (n != null) {
+ lua_get_metatablelua(node_properties);
+ lua_rawgeti(L, -1, n);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nodelib_set_property_t(lua_State * L)
+{
+ /* <table> <node> <value> */
+ halfword n = *((halfword *) lua_touserdata(L, 2));
+ if (n != null) {
+ lua_get_metatablelua(node_properties);
+ lua_insert(L, -2);
+ lua_rawseti(L, -2, n);
+ }
+ return 0;
+}
+
+/* extra helpers */
+
+static int lua_nodelib_effective_glue(lua_State * L)
+{
+ halfword *glue;
+ halfword *parent;
+ glue = lua_touserdata(L, 1);
+ if ((glue == NULL) || (type(*glue) != glue_node)) {
+ lua_pushnil(L) ;
+ } else {
+ parent = lua_touserdata(L, 2);
+ if ((parent != NULL) && ((type(*parent) == hlist_node) || (type(*parent) == vlist_node))) {
+ double w = width(*glue) ;
+ if ((int) glue_sign(*parent) == 1) {
+ if (stretch_order(*glue) == glue_order(*parent)) {
+ w += stretch(*glue) * (double) glue_set(*parent);
+ }
+ } else if (glue_sign(*parent) == 2) {
+ if (shrink_order(*glue) == glue_order(*parent)) {
+ w -= shrink(*glue) * (double) glue_set(*parent);
+ }
+ }
+ if (lua_toboolean(L,3)) {
+ lua_pushinteger(L,round(w));
+ } else {
+ lua_pushnumber(L,w);
+ }
+ } else {
+ lua_pushinteger(L,width(*glue));
+ }
+ }
+ return 1;
+}
+
+static int lua_nodelib_direct_effective_glue(lua_State * L)
+{
+ halfword glue = lua_tointeger(L, 1);
+ if ((glue == null) || (type(glue) != glue_node)) {
+ lua_pushnil(L) ;
+ } else {
+ halfword parent = lua_tointeger(L, 2);
+ if ((parent != null) && ((type(parent) == hlist_node) || (type(parent) == vlist_node))) {
+ double w = (double) width(glue) ;
+ if ((int)glue_sign(parent) == 1) {
+ if (stretch_order(glue) == glue_order(parent)) {
+ w += stretch(glue) * (double) glue_set(parent);
+ }
+ } else if (glue_sign(parent) == 2) {
+ if (shrink_order(glue) == glue_order(parent)) {
+ w -= shrink(glue) * (double) glue_set(parent);
+ }
+ }
+ if (lua_toboolean(L,3)) {
+ lua_pushinteger(L,round(w));
+ } else {
+ lua_pushnumber(L,w);
+ }
+ } else {
+ lua_pushinteger(L,width(glue));
+ }
+ }
+ return 1;
+}
+
+/*
+ Disc nodes are kind of special in the sense that their head is not the head as we
+ see it, but a special node that has status info of which head and tail are part.
+ Normally when proper set/get functions are used this status node is all right but
+ if a macro package permits arbitrary messing around, then it can at some point
+ call the following cleaner, just before linebreaking kicks in. This one is not
+ called automatically because if significantly slows down the line break routing.
+
+*/
+
+#define check_disc(c) \
+ p = c ; \
+ if (p != null && vlink(p) != null) \
+ tlink(p) = tail_of_list(vlink(p));
+
+static int lua_nodelib_direct_check_discretionaries(lua_State * L) {
+ halfword c = lua_tointeger(L, 1);
+ halfword p ;
+ while (c != null) {
+ if (type(c) == disc_node) {
+ check_disc(no_break(c)) ;
+ check_disc(pre_break(c)) ;
+ check_disc(post_break(c)) ;
+ }
+ c = vlink(c) ;
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_check_discretionary(lua_State * L) {
+ halfword c = lua_tointeger(L, 1);
+ if (c != null && type(c) == disc_node) {
+ halfword p ;
+ check_disc(no_break(c)) ;
+ check_disc(pre_break(c)) ;
+ check_disc(post_break(c)) ;
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_flatten_discretionaries(lua_State * L)
+{
+ halfword head = lua_tointeger(L, 1);
+ halfword current = head;
+ halfword next;
+ halfword d, n, h, t;
+ int c = 0;
+ while (current != null) {
+ next = vlink(current);
+ if (type(current) == disc_node) {
+ ++c;
+ d = current;
+ n = no_break(d);
+ h = vlink(n);
+ t = tlink(n);
+ if (h != null) {
+ try_couple_nodes(t,next);
+ if (current == head) {
+ head = h;
+ } else {
+ try_couple_nodes(alink(current),h);
+ }
+ vlink(n) = null ;
+ /*tlink(n) = null; */
+ } else {
+ if (current == head) {
+ head = next;
+ } else {
+ try_couple_nodes(alink(current),next);
+ }
+ }
+ flush_node(d);
+ }
+ current = next;
+ }
+ nodelib_pushdirect_or_nil(head);
+ lua_pushinteger(L,c);
+ return 2;
+}
+
+static int lua_nodelib_check_discretionaries(lua_State * L) {
+ halfword c = *check_isnode(L, 1);
+ halfword p ;
+ while (c != null) {
+ if (type(c) == disc_node) {
+ check_disc(no_break(c)) ;
+ check_disc(pre_break(c)) ;
+ check_disc(post_break(c)) ;
+ }
+ c = vlink(c) ;
+ }
+ return 0;
+}
+
+static int lua_nodelib_check_discretionary(lua_State * L) {
+ halfword c = *check_isnode(L, 1);
+ if (c != null && type(c) == disc_node) {
+ halfword p ;
+ check_disc(no_break(c)) ;
+ check_disc(pre_break(c)) ;
+ check_disc(post_break(c)) ;
+ }
+ return 0;
+}
+
+static int lua_nodelib_flatten_discretionaries(lua_State * L)
+{
+ halfword head = *check_isnode(L, 1);
+ halfword current = head;
+ halfword next;
+ halfword d, n, h, t;
+ halfword *a;
+ int c = 0;
+ while (current != null) {
+ next = vlink(current);
+ if (type(current) == disc_node) {
+ ++c;
+ d = current;
+ n = no_break(d);
+ h = vlink(n);
+ t = tlink(n);
+ if (h != null) {
+ try_couple_nodes(t,next);
+ if (current == head) {
+ head = h;
+ } else {
+ try_couple_nodes(alink(current),h);
+ }
+ vlink(n) = null ;
+ /*tlink(n) = null; */
+ } else {
+ if (current == head) {
+ head = next;
+ } else {
+ try_couple_nodes(alink(current),next);
+ }
+ }
+ flush_node(d);
+ }
+ current = next;
+ }
+ fast_metatable_or_nil(head);
+ lua_pushinteger(L,c);
+ return 2;
+}
+
+/* synctex but not */
+
+static int lua_nodelib_direct_set_synctex_fields(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ halfword tag = lua_tointeger(L, 2);
+ halfword line = lua_tointeger(L, 3);
+ if (n != null) {
+ switch (type(n)) {
+ case glyph_node:
+ if (tag) synctex_tag_glyph(n) = tag;
+ if (line) synctex_line_glyph(n) = line;
+ break;
+ case glue_node:
+ if (tag) synctex_tag_glue(n) = tag;
+ if (line) synctex_line_glue(n) = line;
+ break;
+ case kern_node:
+ if (tag) synctex_tag_kern(n) = tag;
+ if (line) synctex_line_kern(n) = line;
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ if (tag) synctex_tag_box(n) = tag;
+ if (line) synctex_line_box(n) = line;
+ break;
+ case rule_node:
+ if (tag) synctex_tag_rule(n) = tag;
+ if (line) synctex_line_rule(n) = line;
+ break;
+ case math_node:
+ if (tag) synctex_tag_math(n) = tag;
+ if (line) synctex_line_math(n) = line;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int lua_nodelib_direct_get_synctex_fields(lua_State * L)
+{
+ halfword n = lua_tointeger(L, 1);
+ if (n != null) {
+ switch (type(n)) {
+ case glyph_node:
+ lua_pushinteger(L,synctex_tag_glyph(n));
+ lua_pushinteger(L,synctex_line_glyph(n));
+ break;
+ case glue_node:
+ lua_pushinteger(L,synctex_tag_glue(n));
+ lua_pushinteger(L,synctex_line_glue(n));
+ break;
+ case kern_node:
+ lua_pushinteger(L,synctex_tag_kern(n));
+ lua_pushinteger(L,synctex_line_kern(n));
+ break;
+ case hlist_node:
+ case vlist_node:
+ case unset_node:
+ lua_pushinteger(L,synctex_tag_box(n));
+ lua_pushinteger(L,synctex_line_box(n));
+ break;
+ case rule_node:
+ lua_pushinteger(L,synctex_tag_rule(n));
+ lua_pushinteger(L,synctex_line_rule(n));
+ break;
+ case math_node:
+ lua_pushinteger(L,synctex_tag_math(n));
+ lua_pushinteger(L,synctex_line_math(n));
+ break;
+ default:
+ return 0;
+ break;
+ }
+ return 2;
+ }
+ 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[] = {
+ {"__index", lua_nodelib_get_property_t},
+ {"__newindex", lua_nodelib_set_property_t},
+ {NULL, NULL} /* sentinel */
+};
+
+static void lua_new_properties_table(lua_State * L)
+{
+ lua_pushstring(L,"node.properties");
+ lua_newtable(L);
+ lua_settable(L,LUA_REGISTRYINDEX);
+
+ lua_pushstring(L,"node.properties.indirect");
+ lua_newtable(L);
+ luaL_newmetatable(L,"node.properties.indirect.meta");
+ luaL_openlib(L, NULL, nodelib_p, 0);
+ lua_setmetatable(L,-2);
+ lua_settable(L,LUA_REGISTRYINDEX);
+}
+
+/* node.direct.* */
+
+static const struct luaL_Reg direct_nodelib_f[] = {
+ {"copy", lua_nodelib_direct_copy},
+ {"copy_list", lua_nodelib_direct_copy_list},
+ {"count", lua_nodelib_direct_count},
+ {"current_attr", lua_nodelib_direct_currentattr},
+ {"dimensions", lua_nodelib_direct_dimensions},
+ {"rangedimensions", lua_nodelib_direct_rangedimensions},
+ /* {"do_ligature_n", lua_nodelib_direct_do_ligature_n}, */
+ {"end_of_math", lua_nodelib_direct_end_of_math},
+ /* {"family_font", lua_nodelib_mfont}, */ /* no node argument */
+ /* {"fields", lua_nodelib_fields}, */ /* no node argument */
+ {"first_glyph", lua_nodelib_direct_first_glyph},
+ {"flush_list", lua_nodelib_direct_flush_list},
+ {"flush_node", lua_nodelib_direct_flush_node},
+ {"free", lua_nodelib_direct_free},
+ {"getbox", lua_nodelib_direct_getbox},
+ {"getchar", lua_nodelib_direct_getchar},
+ {"getcomponents", lua_nodelib_direct_getcomponents},
+ {"getlang", lua_nodelib_direct_getlang},
+ {"getkern", lua_nodelib_direct_getkern},
+ {"getpenalty", lua_nodelib_direct_getpenalty},
+ {"getdir", lua_nodelib_direct_getdir},
+ {"getoffsets", lua_nodelib_direct_getoffsets},
+ {"getdisc", lua_nodelib_direct_getdisc},
+ {"getwhd", lua_nodelib_direct_getwhd},
+ {"getwidth", lua_nodelib_direct_getwidth},
+ {"getheight", lua_nodelib_direct_getheight},
+ {"getdepth", lua_nodelib_direct_getdepth},
+ {"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},
+ {"getprev", lua_nodelib_direct_getprev},
+ {"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},
+ {"find_attribute", lua_nodelib_direct_find_attribute},
+ {"has_field", lua_nodelib_direct_has_field},
+ {"is_char", lua_nodelib_direct_is_char},
+ {"is_glyph", lua_nodelib_direct_is_glyph},
+ {"uses_font", lua_nodelib_direct_uses_font},
+ {"hpack", lua_nodelib_direct_hpack},
+ {"hyphenating", lang_tex_direct_hyphenating},
+ /* {"id", lua_nodelib_id}, */ /* no node argument */
+ {"insert_after", lua_nodelib_direct_insert_after},
+ {"insert_before", lua_nodelib_direct_insert_before},
+ {"is_direct", lua_nodelib_direct_is_direct},
+ {"is_node", lua_nodelib_direct_is_node},
+ {"kerning", font_tex_direct_kerning},
+ {"last_node", lua_nodelib_direct_last_node},
+ {"length", lua_nodelib_direct_length},
+ {"ligaturing", font_tex_direct_ligaturing},
+ /* {"mlist_to_hlist", lua_nodelib_mlist_to_hset_properties_modelist}, */
+ {"new", lua_nodelib_direct_new},
+ {"tostring", lua_nodelib_direct_tostring},
+ {"protect_glyphs", lua_nodelib_direct_protect_glyphs},
+ {"protect_glyph", lua_nodelib_direct_protect_glyph},
+ {"protrusion_skippable", lua_nodelib_direct_cp_skipable},
+ {"remove", lua_nodelib_direct_remove},
+ {"set_attribute", lua_nodelib_direct_set_attribute},
+ {"setbox", lua_nodelib_direct_setbox},
+ {"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},
+ {"setwidth", lua_nodelib_direct_setwidth},
+ {"setheight", lua_nodelib_direct_setheight},
+ {"setdepth", lua_nodelib_direct_setdepth},
+ {"setshift", lua_nodelib_direct_setshift},
+ {"setnext", lua_nodelib_direct_setnext},
+ {"setprev", lua_nodelib_direct_setprev},
+ {"setboth", lua_nodelib_direct_setboth},
+ {"setlink", lua_nodelib_direct_setlink},
+ {"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},
+ {"setsub", lua_nodelib_direct_setsub},
+ {"setsup", lua_nodelib_direct_setsup},
+ {"slide", lua_nodelib_direct_slide},
+ /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
+ {"tail", lua_nodelib_direct_tail},
+ {"todirect", lua_nodelib_direct_todirect},
+ {"tonode", lua_nodelib_direct_tonode},
+ {"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},
+ {"unprotect_glyph", lua_nodelib_direct_unprotect_glyph},
+ {"unset_attribute", lua_nodelib_direct_unset_attribute},
+ {"setglue",lua_nodelib_direct_set_glue},
+ {"getglue",lua_nodelib_direct_get_glue},
+ {"is_zero_glue",lua_nodelib_direct_is_zero_glue},
+ {"usedlist", lua_nodelib_direct_usedlist},
+ {"vpack", lua_nodelib_direct_vpack},
+ /* {"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},
+ {"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},
+ /* done */
+ {NULL, NULL} /* sentinel */
+};
+
+/* node.* */
+
+static const struct luaL_Reg nodelib_f[] = {
+ {"copy", lua_nodelib_copy},
+ {"copy_list", lua_nodelib_copy_list},
+ {"count", lua_nodelib_count},
+ {"current_attr", lua_nodelib_currentattr},
+ {"dimensions", lua_nodelib_dimensions},
+ {"rangedimensions", lua_nodelib_rangedimensions},
+ /* {"do_ligature_n", lua_nodelib_do_ligature_n}, */
+ {"end_of_math", lua_nodelib_end_of_math},
+ {"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},
+ {"free", lua_nodelib_free},
+ /* {"getbox", lua_nodelib_getbox}, */ /* tex.getbox */
+ {"getnext", lua_nodelib_getnext},
+ {"getprev", lua_nodelib_getprev},
+ {"getboth", lua_nodelib_getboth},
+ {"getdisc", lua_nodelib_getdisc},
+ {"getwhd", lua_nodelib_getwhd},
+ {"getlist", lua_nodelib_getlist},
+ {"getleader", lua_nodelib_getleader},
+ {"getid", lua_nodelib_getid},
+ {"getsubtype", lua_nodelib_getsubtype},
+ {"getfont", lua_nodelib_getfont},
+ {"getchar", lua_nodelib_getchar},
+ {"getfield", lua_nodelib_getfield},
+ {"setfield", lua_nodelib_setfield},
+ {"has_glyph", lua_nodelib_has_glyph},
+ {"has_attribute", lua_nodelib_has_attribute},
+ {"get_attribute", lua_nodelib_get_attribute},
+ {"find_attribute", lua_nodelib_find_attribute},
+ {"has_field", lua_nodelib_has_field},
+ {"is_char", lua_nodelib_is_char},
+ {"is_glyph", lua_nodelib_is_glyph},
+ {"uses_font", lua_nodelib_uses_font},
+ {"hpack", lua_nodelib_hpack},
+ {"hyphenating", lang_tex_hyphenating},
+ {"id", lua_nodelib_id},
+ {"insert_after", lua_nodelib_insert_after},
+ {"insert_before", lua_nodelib_insert_before},
+ {"is_node", lua_nodelib_is_node},
+ {"kerning", font_tex_kerning},
+ {"last_node", lua_nodelib_last_node},
+ {"length", lua_nodelib_length},
+ {"ligaturing", font_tex_ligaturing},
+ {"mlist_to_hlist", lua_nodelib_mlist_to_hlist},
+ {"new", lua_nodelib_new},
+ {"next", lua_nodelib_next}, /* getnext is somewhat more efficient, and get* fits better in direct compatibility */
+ {"prev", lua_nodelib_prev}, /* getprev is somewhat more efficient, and get* fits better in direct compatibility */
+ {"tostring", lua_nodelib_tostring},
+ {"protect_glyphs", lua_nodelib_protect_glyphs},
+ {"protect_glyph", lua_nodelib_protect_glyph},
+ {"protrusion_skippable", lua_nodelib_cp_skipable},
+ {"remove", lua_nodelib_remove},
+ /* {"setbox", lua_nodelib_setbox}, */ /* tex.setbox */
+ {"set_attribute", lua_nodelib_set_attribute},
+ {"slide", lua_nodelib_slide},
+ {"subtype", lua_nodelib_subtype},
+ {"tail", lua_nodelib_tail},
+ {"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},
+ {"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}, */
+ /* 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},
+ {"prepend_prevdepth", lua_nodelib_prepend_prevdepth},
+ {"make_extensible", lua_nodelib_make_extensible},
+ /* done */
+ {"fix_node_lists", lua_nodelib_fix_node_lists},
+ {NULL, NULL} /* sentinel */
+};
+
+static const struct luaL_Reg nodelib_m[] = {
+ {"__index", lua_nodelib_fast_getfield},
+ {"__newindex", lua_nodelib_fast_setfield},
+ {"__tostring", lua_nodelib_tostring},
+ {"__eq", lua_nodelib_equal},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_node(lua_State * L)
+{
+
+ lua_new_properties_table(L);
+
+ /* the main metatable of node userdata */
+ luaL_newmetatable(L, NODE_METATABLE);
+ /* node.* */
+ luaL_openlib(L, NULL, nodelib_m, 0);
+ luaL_openlib(L, "node", nodelib_f, 0);
+ /* node.direct */
+ lua_pushstring(L,"direct");
+ lua_newtable(L);
+ luaL_openlib(L, NULL, direct_nodelib_f, 0);
+ lua_rawset(L,-3);
+ return 1;
+}
+
+void nodelist_to_lua(lua_State * L, int n)
+{
+ lua_pushinteger(L, n);
+ lua_nodelib_push(L);
+}
+
+int nodelist_from_lua(lua_State * L, int n)
+{
+ if (lua_isnil(L, n)) {
+ return null;
+ } else {
+ halfword list = *check_isnode(L, n);
+ return (list ? list : null);
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/loslibext.c b/Build/source/texk/web2c/luatexdir/lua/loslibext.c
new file mode 100644
index 00000000000..979f724720f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/loslibext.c
@@ -0,0 +1,1073 @@
+/* loslibext.c
+
+ Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+#include <kpathsea/c-stat.h>
+#include <kpathsea/c-dir.h>
+#include <time.h>
+
+
+#if defined(_WIN32) || defined(__NT__)
+# define MKDIR(a,b) mkdir(a)
+#else
+# define MKDIR(a,b) mkdir(a,b)
+#endif
+
+/* An attempt to figure out the basic platform, does not
+ care about niceties like version numbers yet,
+ and ignores platforms where luatex is unlikely to
+ successfully compile without major prorting effort
+ (amiga|mac|os2|vms) */
+
+#if defined(_WIN32) || defined(__NT__)
+# define OS_PLATTYPE "windows"
+# define OS_PLATNAME "windows"
+#elif defined(__GO32__) || defined(__DJGPP__) || defined(__DOS__)
+# define OS_PLATTYPE "msdos"
+# define OS_PLATNAME "msdos"
+#else /* assume everything else is unix-y */
+# include <sys/utsname.h>
+# define OS_PLATTYPE "unix"
+/* this is just a first guess */
+# if defined(__BSD__)
+# define OS_PLATNAME "bsd"
+# elif defined(__CYGWIN__)
+# define OS_PLATNAME "cygwin"
+# elif defined(__SYSV__)
+# define OS_PLATNAME "sysv"
+# else
+# define OS_PLATNAME "generic"
+# endif
+/* attempt to be more precise */
+# if defined(__LINUX__) || defined (__linux)
+# undef OS_PLATNAME
+# define OS_PLATNAME "linux"
+# elif defined(__FREEBSD__) || defined(__FreeBSD__) || defined(__FreeBSD)
+# undef OS_PLATNAME
+# define OS_PLATNAME "freebsd"
+# elif defined(__FreeBSD_kernel__)
+# undef OS_PLATNAME
+# define OS_PLATNAME "kfreebsd"
+# elif defined(__OPENBSD__) || defined(__OpenBSD)
+# undef OS_PLATNAME
+# define OS_PLATNAME "openbsd"
+# elif defined(__SOLARIS__)
+# undef OS_PLATNAME
+# define OS_PLATNAME "solaris"
+# elif defined(__SUNOS__) || defined(__SUN__) || defined(sun)
+# undef OS_PLATNAME
+# define OS_PLATNAME "sunos"
+# elif defined(HPUX) || defined(__hpux)
+# undef OS_PLATNAME
+# define OS_PLATNAME "hpux"
+# elif defined(__sgi)
+# undef OS_PLATNAME
+# define OS_PLATNAME "irix"
+# elif defined(__MACH__) && defined(__APPLE__)
+# undef OS_PLATNAME
+# define OS_PLATNAME "macosx"
+# elif defined(__GNU__)
+# undef OS_PLATNAME
+# define OS_PLATNAME "gnu"
+# endif
+#endif
+
+
+
+
+
+/* there could be more platforms that don't have these two,
+ * but win32 and sunos are for sure.
+ * gettimeofday() for win32 is using an alternative definition
+ */
+
+#if (! defined(_WIN32)) && (! defined(__SUNOS__))
+# include <sys/time.h> /* gettimeofday() */
+# include <sys/times.h> /* times() */
+# include <sys/wait.h>
+#endif
+
+/* set this to one for spawn instead of exec on windows */
+
+#define DONT_REALLY_EXIT 1
+
+/* Note: under WIN32, |environ| is nothing but a copy of the actual
+ environment as it was during program startup. That variable
+ can then be changed (which is a little odd), but such changes
+ do not survive in the actual environment *unless* they are
+ passed on down in e.g. |_execvpe|, when they would be inherited
+ by the child process.
+
+ This gives trouble because some parts of the texk code actually
+ change the contents of the |environ| variable as a side-effect
+ of other processing, and that explains why the current code does
+ not use |environ| at all for the moment.
+
+ The API is kept in place for now, just in case. Thanks to Tomek
+ for the patch and the persistence in tracking this down.
+*/
+
+#ifdef _WIN32
+# include <process.h>
+# define spawn_command(a,b,c) c ? \
+ _spawnvpe(_P_WAIT,(const char *)a,(const char* const*)b,(const char* const*)c) : \
+ _spawnvp(_P_WAIT,(const char *)a,(const char* const*)b)
+# if DONT_REALLY_EXIT
+# define exec_command(a,b,c) exit(spawn_command((a),(b),(c)))
+# else
+# define exec_command(a,b,c) c ? \
+ _execvpe((const char *)a,(const char* const*)b,(const char* const*)c) : \
+ _execvp((const char *)a,(const char* const*)b)
+# endif
+#else
+# include <unistd.h>
+# define DEFAULT_PATH "/bin:/usr/bin:."
+
+static int exec_command(const char *file, char *const *av, char *const *envp)
+{
+ char *path;
+ const char *searchpath, *esp;
+ size_t prefixlen, filelen, totallen;
+
+ if (strchr(file, '/')) /* Specific path */
+ return envp ? execve(file, av, envp) : execv(file, av);
+
+ filelen = strlen(file);
+ path = NULL;
+
+ searchpath = getenv("PATH");
+ if (!searchpath)
+ searchpath = DEFAULT_PATH;
+
+ errno = ENOENT; /* Default errno, if execve() doesn't change it */
+
+ do {
+ esp = strchr(searchpath, ':');
+ if (esp)
+ prefixlen = (size_t) (esp - searchpath);
+ else
+ prefixlen = strlen(searchpath);
+
+ if (prefixlen == 0 || searchpath[prefixlen - 1] == '/') {
+ totallen = prefixlen + filelen;
+# ifdef PATH_MAX
+ if (totallen >= PATH_MAX)
+ continue;
+# endif
+ path = malloc(totallen + 1);
+ memcpy(path, searchpath, prefixlen);
+ memcpy(path + prefixlen, file, filelen);
+ } else {
+ totallen = prefixlen + filelen + 1;
+# ifdef PATH_MAX
+ if (totallen >= PATH_MAX)
+ continue;
+# endif
+ path = malloc(totallen + 1);
+ memcpy(path, searchpath, prefixlen);
+ path[prefixlen] = '/';
+ memcpy(path + prefixlen + 1, file, filelen);
+ }
+ path[totallen] = '\0';
+
+ if (envp) {
+ execve(path, av, envp);
+ } else {
+ execv(path, av);
+ }
+ free(path);
+ path = NULL;
+ if (errno == E2BIG || errno == ENOEXEC ||
+ errno == ENOMEM || errno == ETXTBSY)
+ break; /* Report this as an error, no more search */
+
+ searchpath = esp + 1;
+ } while (esp);
+
+ return -1;
+}
+
+/*
+ It is not possible to mimic |spawnve()| completely. The main problem is
+ that the |fork|--|waitpid| combination cannot really do identical error
+ reporting to the parent process, because it has to pass all the possible
+ error conditions as well as the actual process return status through a
+ single 8-bit value.
+
+ The current implementation tries to give back meaningful results for |execve()|
+ errors in the child, for the cases that could also be returned by |spawnve()|,
+ and for |ETXTBSY|, because that can be triggered by our path searching routine.
+
+ This implementation does not differentiate abnormal status conditions reported
+ by |waitpid()|, but will simply return a single error indication value.
+
+ For all this, hyjacking a bunch of numbers in the range 1...255 is needed.
+ The chance of collisions is hopefully diminished by using a rather random
+ range in the 8-bit section.
+*/
+
+# define INVALID_RET_E2BIG 143
+# define INVALID_RET_ENOENT 144
+# define INVALID_RET_ENOEXEC 145
+# define INVALID_RET_ENOMEM 146
+# define INVALID_RET_ETXTBSY 147
+# define INVALID_RET_UNKNOWN 148
+# define INVALID_RET_INTR 149
+
+static int spawn_command(const char *file, char *const *av, char *const *envp)
+{
+ pid_t pid, wait_pid;
+ int status;
+ pid = fork();
+ if (pid < 0) {
+ return -1; /* fork failed */
+ }
+ if (pid > 0) { /* parent */
+ status = 0;
+ wait_pid = waitpid(pid, &status, 0);
+ if (wait_pid == pid) {
+ if (WIFEXITED(status))
+ return WEXITSTATUS(status);
+ else
+ return INVALID_RET_INTR;
+ } else {
+ return -1; /* some waitpid error */
+ }
+ } else {
+ int f;
+ /* somewhat random upper limit. ignore errors on purpose */
+ for (f = 0; f < 256; f++)
+ (void) fsync(f);
+
+ if (exec_command(file, av, envp)) {
+ /* let's hope no-one uses these values */
+ switch (errno) {
+ case E2BIG:
+ exit(INVALID_RET_E2BIG);
+ case ETXTBSY:
+ exit(INVALID_RET_ETXTBSY);
+ case ENOENT:
+ exit(INVALID_RET_ENOENT);
+ case ENOEXEC:
+ exit(INVALID_RET_ENOEXEC);
+ case ENOMEM:
+ exit(INVALID_RET_ENOMEM);
+ default:
+ exit(INVALID_RET_UNKNOWN);
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef _WIN32
+static char *get_command_name(char *maincmd)
+{
+ /* retrieve argv[0] part from the command string,
+ it will be truncated to MAX_PATH if it's too long */
+ char *cmdname = (char *) malloc(sizeof(char) * MAX_PATH);
+ int i, k, quoted;
+ quoted = k = 0;
+ for (i = 0; (i < MAX_PATH) && maincmd[i] &&
+ ((maincmd[i] != ' ' && maincmd[i] != '\t') || quoted); i++) {
+ if (maincmd[i] == '"') {
+ quoted = !quoted;
+ } else {
+ cmdname[k] = maincmd[i];
+ k++;
+ }
+ }
+ cmdname[k] = '\0';
+ return cmdname;
+}
+#endif
+
+static char **do_split_command(const char *maincmd, char **runcmd)
+{
+ char **cmdline = NULL;
+#ifdef _WIN32
+ /* On WIN32 don't split anything, because
+ _spawnvpe can't put it back together properly
+ if there are quoted arguments with spaces.
+ Instead, dump everything into one argument
+ and it will be passed through as is */
+ cmdline = malloc(sizeof(char *) * 2);
+ cmdline[0] = xstrdup(maincmd);
+ cmdline[1] = NULL;
+ *runcmd = get_command_name(cmdline[0]);
+#else
+ char *piece, *start_piece;
+ const char *cmd;
+ unsigned int i, j;
+ int ret = 0;
+ int in_string = 0;
+ int quoted = 0;
+ if (strlen(maincmd) == 0)
+ return NULL;
+ /* allocate the array of options first. it will probably be
+ be a little bit too big, but better too much than to little */
+ j = 2;
+ for (i = 0; i < strlen(maincmd); i++) {
+ if (maincmd[i] == ' ')
+ j++;
+ }
+ cmdline = malloc(sizeof(char *) * j);
+ for (i = 0; i < j; i++) {
+ cmdline[i] = NULL;
+ }
+ cmd = maincmd;
+ i = 0;
+ while (cmd[i] == ' ')
+ i++; /* skip leading spaces */
+ start_piece = malloc(strlen(cmd) + 1); /* a buffer */
+ piece = start_piece;
+ for (; i <= strlen(maincmd); i++) {
+ if (cmd[i] == '\\' &&
+ (cmd[i + 1] == '\\' || cmd[i + 1] == '\'' || cmd[i + 1] == '"')) {
+ quoted = 1;
+ continue;
+ }
+ if (in_string && cmd[i] == in_string && !quoted) {
+ in_string = 0;
+ continue;
+ }
+ if ((cmd[i] == '"' || cmd[i] == '\'') && !quoted) {
+ in_string = cmd[i];
+ continue;
+ }
+ if ((in_string == 0 && cmd[i] == ' ') || cmd[i] == 0) {
+ *piece = 0;
+ cmdline[ret++] = xstrdup(start_piece);
+ piece = start_piece;
+ while (i < strlen(maincmd) && cmd[(i + 1)] == ' ')
+ i++;
+ continue;
+ }
+ *piece++ = cmd[i];
+ quoted = 0;
+ }
+ xfree(start_piece);
+ *runcmd = cmdline[0];
+#endif
+ return cmdline;
+}
+
+static char **do_flatten_command(lua_State * L, char **runcmd)
+{
+ unsigned int i;
+ int j;
+ const char *s;
+ char **cmdline = NULL;
+ *runcmd = NULL;
+
+ for (j = 1;; j++) {
+ lua_rawgeti(L, -1, j);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ break;
+ }
+ lua_pop(L, 1);
+ }
+ if (j == 1)
+ return NULL;
+ cmdline = malloc(sizeof(char *) * (unsigned) (j + 1));
+ for (i = 1; i <= (unsigned) j; i++) {
+ cmdline[i] = NULL;
+ lua_rawgeti(L, -1, (int) i);
+ if (lua_isnil(L, -1) || (s = lua_tostring(L, -1)) == NULL) {
+ lua_pop(L, 1);
+ if (i == 1) {
+ xfree(cmdline);
+ return NULL;
+ } else {
+ break;
+ }
+ } else {
+ lua_pop(L, 1);
+ cmdline[(i - 1)] = xstrdup(s);
+ }
+ }
+ cmdline[i] = NULL;
+
+ lua_rawgeti(L, -1, 0);
+ if (lua_isnil(L, -1) || (s = lua_tostring(L, -1)) == NULL) {
+#ifdef _WIN32
+ *runcmd = get_command_name(cmdline[0]);
+#else
+ *runcmd = cmdline[0];
+#endif
+ } else {
+ *runcmd = xstrdup(s);
+ }
+ lua_pop(L, 1);
+
+ return cmdline;
+}
+
+
+static int os_exec(lua_State * L)
+{
+ int allow = 0;
+ const char *maincmd = NULL;
+ char *runcmd = NULL;
+ char *safecmd = NULL, *cmdname = NULL;
+ char **cmdline = NULL;
+ char **envblock = NULL;
+
+ if (lua_gettop(L) != 1) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "invalid arguments passed");
+ return 2;
+ }
+ if (shellenabledp <= 0) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "All command execution disabled.");
+ return 2;
+ }
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ maincmd = lua_tostring(L, 1);
+ cmdline = do_split_command(maincmd, &runcmd);
+ } else if (lua_type(L, 1) == LUA_TTABLE) {
+ cmdline = do_flatten_command(L, &runcmd);
+ }
+ /* If restrictedshell == 0, any command is allowed. */
+ /* this is a little different from \write18/ os.execute processing
+ * because it does not test for commands with fixed arguments,
+ * but I am not so eager to attempt to fix that. Just document
+ * that os.exec() checks only the command name.
+ */
+ if (restrictedshell == 0) {
+ allow = 1;
+ } else {
+ const char *theruncmd = runcmd;
+ allow = shell_cmd_is_allowed(theruncmd, &safecmd, &cmdname);
+ }
+
+ if (allow > 0 && cmdline != NULL && runcmd != NULL) {
+#if defined(_WIN32) && DONT_REALLY_EXIT
+ if (allow == 2)
+ exec_command(safecmd, cmdline, envblock);
+ else
+ exec_command(runcmd, cmdline, envblock);
+#else
+ {
+ int r;
+ if (allow == 2)
+ r = exec_command(safecmd, cmdline, envblock);
+ else
+ r = exec_command(runcmd, cmdline, envblock);
+ if (r == -1) {
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s: %s", runcmd, strerror(errno));
+ lua_pushinteger(L, errno);
+ return 3;
+ }
+ }
+#endif
+ }
+ if (safecmd)
+ free(safecmd);
+ if (cmdname)
+ free(cmdname);
+ if (allow == 0) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "Command execution disabled via shell_escape='p'");
+ return 2;
+ }
+ lua_pushnil(L);
+ lua_pushliteral(L, "invalid command line passed");
+ return 2;
+}
+
+#define do_error_return(A,B) do { \
+ lua_pushnil(L); \
+ lua_pushfstring(L,"%s: %s",runcmd,(A)); \
+ lua_pushinteger(L, B); \
+ return 3; \
+ } while (0)
+
+static int os_spawn(lua_State * L)
+{
+ int allow = 0;
+ const char *maincmd = NULL;
+ char *runcmd = NULL;
+ char *safecmd = NULL, *cmdname = NULL;
+ char **cmdline = NULL;
+ char **envblock = NULL;
+ int i;
+
+ if (lua_gettop(L) != 1) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "invalid arguments passed");
+ return 2;
+ }
+ if (shellenabledp <= 0) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "All command execution disabled.");
+ return 2;
+ }
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ maincmd = lua_tostring(L, 1);
+ cmdline = do_split_command(maincmd, &runcmd);
+ } else if (lua_type(L, 1) == LUA_TTABLE) {
+ cmdline = do_flatten_command(L, &runcmd);
+ }
+ /* If restrictedshell == 0, any command is allowed. */
+ /* this is a little different from \write18/ os.execute processing
+ * because it does not test for commands with fixed arguments,
+ * but I am not so eager to attempt to fix that. Just document
+ * that os.exec() checks only the command name.
+ */
+ if (restrictedshell == 0) {
+ allow = 1;
+ } else {
+ const char *theruncmd = runcmd;
+ allow = shell_cmd_is_allowed(theruncmd, &safecmd, &cmdname);
+ }
+ if (allow > 0 && cmdline != NULL && runcmd != NULL) {
+ if (allow == 2)
+ i = spawn_command(safecmd, cmdline, envblock);
+ else
+ i = spawn_command(runcmd, cmdline, envblock);
+ if (safecmd)
+ free(safecmd);
+ if (cmdname)
+ free(cmdname);
+ if (i == 0) {
+ lua_pushinteger(L, i);
+ return 1;
+ } else if (i == -1) {
+ /* this branch covers WIN32 as well as fork() and waitpid() errors */
+ do_error_return(strerror(errno), errno);
+#ifndef _WIN32
+ } else if (i == INVALID_RET_E2BIG) {
+ do_error_return(strerror(E2BIG), i);
+ } else if (i == INVALID_RET_ENOENT) {
+ do_error_return(strerror(ENOENT), i);
+ } else if (i == INVALID_RET_ENOEXEC) {
+ do_error_return(strerror(ENOEXEC), i);
+ } else if (i == INVALID_RET_ENOMEM) {
+ do_error_return(strerror(ENOMEM), i);
+ } else if (i == INVALID_RET_ETXTBSY) {
+ do_error_return(strerror(ETXTBSY), i);
+ } else if (i == INVALID_RET_UNKNOWN) {
+ do_error_return("execution failed", i);
+ } else if (i == INVALID_RET_INTR) {
+ do_error_return("execution interrupted", i);
+#endif
+ } else {
+ lua_pushinteger(L, i);
+ return 1;
+ }
+ }
+ if (safecmd)
+ free(safecmd);
+ if (cmdname)
+ free(cmdname);
+ if (allow == 0) {
+ lua_pushnil(L);
+ lua_pushliteral(L, "Command execution disabled via shell_escape='p'");
+ return 2;
+ }
+ lua_pushnil(L);
+ lua_pushliteral(L, "invalid command line passed");
+ return 2;
+}
+
+/* Hans wants to set env values */
+
+static int os_setenv(lua_State * L)
+{
+ const char *key, *val;
+ char *value;
+ key = luaL_optstring(L, 1, NULL);
+ val = luaL_optstring(L, 2, NULL);
+ if (key) {
+ if (val) {
+ value = xmalloc((unsigned) (strlen(key) + strlen(val) + 2));
+ sprintf(value, "%s=%s", key, val);
+ if (putenv(value)) {
+ return luaL_error(L, "unable to change environment");
+ }
+ } else {
+#if defined(_WIN32) || defined(__sun__) || defined(__sun) || defined(_AIX)
+ value = xmalloc(strlen(key) + 2);
+ sprintf(value, "%s=", key);
+ if (putenv(value)) {
+ return luaL_error(L, "unable to change environment");
+ }
+#else
+ (void) unsetenv(key);
+#endif
+ }
+ }
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
+
+static void find_env(lua_State * L)
+{
+ char *envitem, *envitem_orig;
+ char *envkey;
+ char **envpointer;
+ envpointer = environ;
+ lua_getglobal(L, "os");
+ if (envpointer != NULL && lua_istable(L, -1)) {
+ luaL_checkstack(L, 2, "out of stack space");
+ lua_pushstring(L, "env");
+ lua_newtable(L);
+ while (*envpointer) {
+ /* TODO: perhaps a memory leak here */
+ luaL_checkstack(L, 2, "out of stack space");
+ envitem = xstrdup(*envpointer);
+ envitem_orig = envitem;
+ envkey = envitem;
+ while (*envitem != '=') {
+ envitem++;
+ }
+ *envitem = 0;
+ envitem++;
+ lua_pushstring(L, envkey);
+ lua_pushstring(L, envitem);
+ lua_rawset(L, -3);
+ envpointer++;
+ free(envitem_orig);
+ }
+ lua_rawset(L, -3);
+ }
+ lua_pop(L, 1);
+}
+
+static int ex_sleep(lua_State * L)
+{
+ lua_Number interval = luaL_checknumber(L, 1);
+ lua_Number units = luaL_optnumber(L, 2, 1);
+#ifdef _WIN32
+ Sleep((DWORD) (1e3 * interval / units));
+#else /* assumes posix or bsd */
+ usleep((unsigned) (1e6 * interval / units));
+#endif
+ return 0;
+}
+
+
+
+#ifdef _WIN32
+# define _UTSNAME_LENGTH 65
+
+/* Structure describing the system and machine. */
+struct utsname {
+ char sysname[_UTSNAME_LENGTH];
+ char nodename[_UTSNAME_LENGTH];
+ char release[_UTSNAME_LENGTH];
+ char version[_UTSNAME_LENGTH];
+ char machine[_UTSNAME_LENGTH];
+};
+
+/*
+ * Get name and information about current kernel.
+ */
+static int uname(struct utsname *uts)
+{
+ enum { WinNT, Win95, Win98, WinUnknown };
+ OSVERSIONINFO osver;
+ SYSTEM_INFO sysinfo;
+ DWORD sLength;
+ DWORD os = WinUnknown;
+
+ memset(uts, 0, sizeof(*uts));
+
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ 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:
+ if (osver.dwMajorVersion == 4)
+ strcpy(uts->sysname, "Windows NT 4");
+ else if (osver.dwMajorVersion <= 3)
+ strcpy(uts->sysname, "Windows NT 3");
+ else if (osver.dwMajorVersion == 5) {
+ if (osver.dwMinorVersion == 0)
+ strcpy(uts->sysname, "Windows 2000");
+ else if (osver.dwMinorVersion == 1)
+ strcpy(uts->sysname, "Windows XP");
+ else if (osver.dwMinorVersion == 2)
+ strcpy(uts->sysname, "Windows XP 64-Bit");
+ } else if (osver.dwMajorVersion == 6) {
+ 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;
+
+ case VER_PLATFORM_WIN32_WINDOWS: /* Win95, Win98 or WinME */
+ if ((osver.dwMajorVersion > 4) ||
+ ((osver.dwMajorVersion == 4) && (osver.dwMinorVersion > 0))) {
+ if (osver.dwMinorVersion >= 90)
+ strcpy(uts->sysname, "Windows ME"); /* ME */
+ else
+ strcpy(uts->sysname, "Windows 98"); /* 98 */
+ os = Win98;
+ } else {
+ strcpy(uts->sysname, "Windows 95"); /* 95 */
+ os = Win95;
+ }
+ break;
+
+ case VER_PLATFORM_WIN32s: /* Windows 3.x */
+ strcpy(uts->sysname, "Windows");
+ break;
+
+ default: /* anything else */
+ strcpy(uts->sysname, "Windows");
+ break;
+ }
+
+ sprintf(uts->version, "%ld.%02ld",
+ osver.dwMajorVersion, osver.dwMinorVersion);
+
+ if (osver.szCSDVersion[0] != '\0' &&
+ (strlen(osver.szCSDVersion) + strlen(uts->version) + 1) <
+ sizeof(uts->version)) {
+ strcat(uts->version, " ");
+ strcat(uts->version, osver.szCSDVersion);
+ }
+
+ sprintf(uts->release, "build %ld", osver.dwBuildNumber & 0xFFFF);
+
+ switch (sysinfo.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_PPC:
+ strcpy(uts->machine, "ppc");
+ break;
+ case PROCESSOR_ARCHITECTURE_ALPHA:
+ strcpy(uts->machine, "alpha");
+ break;
+ case PROCESSOR_ARCHITECTURE_MIPS:
+ strcpy(uts->machine, "mips");
+ break;
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ /*
+ * dwProcessorType is only valid in Win95 and Win98 and WinME
+ * wProcessorLevel is only valid in WinNT
+ */
+ switch (os) {
+ case Win95:
+ case Win98:
+ switch (sysinfo.dwProcessorType) {
+ case PROCESSOR_INTEL_386:
+ case PROCESSOR_INTEL_486:
+ case PROCESSOR_INTEL_PENTIUM:
+ sprintf(uts->machine, "i%ld", sysinfo.dwProcessorType);
+ break;
+ default:
+ strcpy(uts->machine, "i386");
+ break;
+ }
+ break;
+ case WinNT:
+ sprintf(uts->machine, "i%d86", sysinfo.wProcessorLevel);
+ break;
+ default:
+ strcpy(uts->machine, "unknown");
+ break;
+ }
+ break;
+ default:
+ strcpy(uts->machine, "unknown");
+ break;
+ }
+
+ sLength = sizeof(uts->nodename) - 1;
+ GetComputerName(uts->nodename, &sLength);
+ return 0;
+}
+#endif
+
+
+static int ex_uname(lua_State * L)
+{
+ struct utsname uts;
+ if (uname(&uts) >= 0) {
+ lua_newtable(L);
+ lua_pushstring(L, uts.sysname);
+ lua_setfield(L, -2, "sysname");
+ lua_pushstring(L, uts.machine);
+ lua_setfield(L, -2, "machine");
+ lua_pushstring(L, uts.release);
+ lua_setfield(L, -2, "release");
+ lua_pushstring(L, uts.version);
+ lua_setfield(L, -2, "version");
+ lua_pushstring(L, uts.nodename);
+ lua_setfield(L, -2, "nodename");
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+
+#if (! defined (_WIN32)) && (! defined (__SUNOS__))
+static int os_times(lua_State * L)
+{
+ struct tms r;
+ (void) times(&r);
+ lua_newtable(L);
+ lua_pushnumber(L, /* float */
+ ((lua_Number) (r.tms_utime)) /
+ (lua_Number) sysconf(_SC_CLK_TCK));
+ lua_setfield(L, -2, "utime");
+ lua_pushnumber(L, /* float */
+ ((lua_Number) (r.tms_stime)) /
+ (lua_Number) sysconf(_SC_CLK_TCK));
+ lua_setfield(L, -2, "stime");
+ lua_pushnumber(L, /* float */
+ ((lua_Number) (r.tms_cutime)) /
+ (lua_Number) sysconf(_SC_CLK_TCK));
+ lua_setfield(L, -2, "cutime");
+ lua_pushnumber(L, /* float */
+ ((lua_Number) (r.tms_cstime)) /
+ (lua_Number) sysconf(_SC_CLK_TCK));
+ lua_setfield(L, -2, "cstime");
+ return 1;
+}
+#endif
+
+#if ! defined (__SUNOS__)
+
+# if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
+# define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
+# else
+# define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
+# endif
+
+static int os_gettimeofday(lua_State * L)
+{
+ double v;
+# ifndef _WIN32
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ v = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
+# else
+ FILETIME ft;
+ int64_t tmpres = 0;
+
+ GetSystemTimeAsFileTime(&ft);
+
+ tmpres |= ft.dwHighDateTime;
+ tmpres <<= 32;
+ tmpres |= ft.dwLowDateTime;
+ tmpres /= 10;
+ tmpres -= DELTA_EPOCH_IN_MICROSECS; /*converting file time to unix epoch */
+ v = (double) tmpres / 1000000.0;
+# endif
+ lua_pushnumber(L, v); /* float */
+ return 1;
+}
+#endif
+
+
+#define MAXTRIES 36*36*36
+
+#ifndef HAVE_MKDTEMP
+static const char repl[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+static int dirs_made = 0;
+
+static char *do_mkdtemp(char *tmpl)
+{
+ int count;
+ int value;
+ char *xes = &tmpl[strlen(tmpl) - 6];
+ /* this is not really all that random, but it will do */
+ if (dirs_made == 0) {
+ srand((unsigned) time(NULL));
+ }
+ value = rand();
+ for (count = 0; count < MAXTRIES; value += 8413, ++count) {
+ int v = value;
+ xes[0] = repl[v % 36];
+ v /= 36;
+ xes[1] = repl[v % 36];
+ v /= 36;
+ xes[2] = repl[v % 36];
+ v /= 36;
+ xes[3] = repl[v % 36];
+ v /= 36;
+ xes[4] = repl[v % 36];
+ v /= 36;
+ xes[5] = repl[v % 36];
+ if (MKDIR(tmpl, S_IRUSR | S_IWUSR | S_IXUSR) >= 0) {
+ dirs_made++;
+ return tmpl;
+ } else if (errno != EEXIST) {
+ return NULL;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static int os_tmpdir(lua_State * L)
+{
+ char *s, *tempdir;
+ const char *tmp = luaL_optstring(L, 1, "luatex.XXXXXX");
+ if (tmp == NULL ||
+ strlen(tmp) < 6 || (strcmp(tmp + strlen(tmp) - 6, "XXXXXX") != 0)) {
+ lua_pushnil(L);
+ lua_pushstring(L, "Invalid argument to os.tmpdir()");
+ return 2;
+ } else {
+ tempdir = xstrdup(tmp);
+ }
+#ifdef HAVE_MKDTEMP
+ s = mkdtemp(tempdir);
+#else
+ s = do_mkdtemp(tempdir);
+#endif
+ if (s == NULL) {
+ int en = errno; /* calls to Lua API may change this value */
+ lua_pushnil(L);
+ lua_pushfstring(L, "%s", strerror(en));
+ return 2;
+ } else {
+ lua_pushstring(L, s);
+ return 1;
+ }
+}
+
+
+static int os_execute(lua_State * L)
+{
+ int allow = 0;
+ int ret = 1;
+ char *safecmd = NULL;
+ char *cmdname = NULL;
+ const char *cmd = luaL_optstring(L, 1, NULL);
+
+ if (cmd == NULL) { /* pretend we are \.{\\pdfshellescape} */
+ if (shellenabledp <= 0) {
+ lua_pushinteger(L, 0);
+ } else if (restrictedshell == 0) {
+ lua_pushinteger(L, 1);
+ } else {
+ lua_pushinteger(L, 2);
+ }
+ return 1;
+ }
+ if (shellenabledp <= 0) {
+ lua_pushnil(L);
+ lua_pushstring(L, "All command execution disabled.");
+ return 2;
+ }
+ /* If restrictedshell == 0, any command is allowed. */
+ if (restrictedshell == 0)
+ allow = 1;
+ else
+ allow = shell_cmd_is_allowed(cmd, &safecmd, &cmdname);
+
+ if (allow == 1) {
+ lua_pushinteger(L, system(cmd));
+ } else if (allow == 2) {
+ lua_pushinteger(L, system(safecmd));
+ } else {
+ lua_pushnil(L);
+ ret = 2;
+ if (allow == 0)
+ lua_pushstring(L,
+ "Command execution disabled via shell_escape='p'");
+ else /* allow == -1 */
+ lua_pushstring(L, "Quoting error in system command line.");
+ }
+ if (safecmd)
+ free(safecmd);
+ if (cmdname)
+ free(cmdname);
+ return ret;
+}
+
+
+void open_oslibext(lua_State * L)
+{
+
+ find_env(L);
+
+ lua_getglobal(L, "os");
+ lua_pushcfunction(L, ex_sleep);
+ lua_setfield(L, -2, "sleep");
+ lua_pushliteral(L, OS_PLATTYPE);
+ lua_setfield(L, -2, "type");
+ lua_pushliteral(L, OS_PLATNAME);
+ lua_setfield(L, -2, "name");
+ lua_pushcfunction(L, ex_uname);
+ lua_setfield(L, -2, "uname");
+#if (! defined (_WIN32)) && (! defined (__SUNOS__))
+ lua_pushcfunction(L, os_times);
+ lua_setfield(L, -2, "times");
+#endif
+#if ! defined (__SUNOS__)
+ lua_pushcfunction(L, os_gettimeofday);
+ lua_setfield(L, -2, "gettimeofday");
+#endif
+
+ lua_pushcfunction(L, os_setenv);
+ lua_setfield(L, -2, "setenv");
+ lua_pushcfunction(L, os_exec);
+ lua_setfield(L, -2, "exec");
+ lua_pushcfunction(L, os_spawn);
+ lua_setfield(L, -2, "spawn");
+ lua_pushcfunction(L, os_execute);
+ lua_setfield(L, -2, "execute");
+ lua_pushcfunction(L, os_tmpdir);
+ lua_setfield(L, -2, "tmpdir");
+
+ lua_pop(L, 1); /* pop the table */
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c b/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
new file mode 100644
index 00000000000..030e3db7e6c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdfelib.c
@@ -0,0 +1,1759 @@
+/* loslibext.c
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+ This file hosts 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 "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;
+} pdfe_dictionary;
+
+typedef struct {
+ pparray *array;
+} pdfe_array;
+
+typedef struct {
+ ppstream *stream;
+ int decode;
+ int open;
+} pdfe_stream;
+
+typedef struct {
+ /* ppref *reference; */
+ ppxref *xref;
+ int onum;
+} pdfe_reference;
+
+/*tex
+
+ We need to check if we have the right userdata. A similar warning is issued
+ when encounter a problem. We don't exit.
+
+*/
+
+static void pdfe_invalid_object_warning(const char * detail)
+{
+ formatted_warning("pdfe lib","lua <pdfe %s> expected",detail);
+}
+
+static pdfe_document *check_isdocument(lua_State * L, int n)
+{
+ pdfe_document *p = (pdfe_document *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("document");
+ return NULL;
+}
+
+static pdfe_dictionary *check_isdictionary(lua_State * L, int n)
+{
+ pdfe_dictionary *p = (pdfe_dictionary *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_dictionary);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("dictionary");
+ return NULL;
+}
+
+static pdfe_array *check_isarray(lua_State * L, int n)
+{
+ pdfe_array *p = (pdfe_array *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_array);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("array");
+ return NULL;
+}
+
+static pdfe_stream *check_isstream(lua_State * L, int n)
+{
+ pdfe_stream *p = (pdfe_stream *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_stream);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("stream");
+ return NULL;
+}
+
+static pdfe_reference *check_isreference(lua_State * L, int n)
+{
+ pdfe_reference *p = (pdfe_reference *)lua_touserdata(L, n);
+ if (p != NULL && lua_getmetatable(L, n)) {
+ lua_get_metatablelua(luatex_pdfe_reference);
+ if (!lua_rawequal(L, -1, -2)) {
+ p = NULL;
+ }
+ lua_pop(L, 2);
+ if (p != NULL) {
+ return p;
+ }
+ }
+ pdfe_invalid_object_warning("reference");
+ return NULL;
+}
+
+/*tex
+
+ Reporting the type of a userdata is just a sequence of tests till we find the
+ right one. We return nothing is it is no pdfe type.
+
+ \starttyping
+ t = pdfe.type(<pdfe document|dictionary|array|reference|stream>)
+ \stoptyping
+
+*/
+
+# define check_type(field,meta,name) do { \
+ lua_get_metatablelua(luatex_##meta); \
+ if (lua_rawequal(L, -1, -2)) { \
+ lua_pushstring(L,name); \
+ return 1; \
+ } \
+ lua_pop(L, 1); \
+} while (0)
+
+static int pdfelib_type(lua_State * L)
+{
+ void *p = lua_touserdata(L, 1);
+ if (p != NULL && lua_getmetatable(L, 1)) {
+ check_type(document, pdfe, "pdfe");
+ check_type(dictionary,pdfe_dictionary,"pdfe.dictionary");
+ check_type(array, pdfe_array, "pdfe.array");
+ check_type(reference, pdfe_reference, "pdfe.reference");
+ check_type(stream, pdfe_stream, "pdfe.stream");
+ }
+ return 0;
+}
+
+/*tex
+
+ The \type {tostring} metamethods are similar and report a pdfe type plus a
+ pointer value, as is rather usual in \LUA.
+
+*/
+
+# define define_to_string(field,what) \
+static int pdfelib_tostring_##field(lua_State * L) { \
+ pdfe_##field *p = check_is##field(L, 1); \
+ if (p != NULL) { \
+ lua_pushfstring(L, "<" what " %p>", (ppdoc *) p->field); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+define_to_string(document, "pdfe")
+define_to_string(dictionary,"pdfe.dictionary")
+define_to_string(array, "pdfe.array")
+define_to_string(stream, "pdfe.stream")
+
+static int pdfelib_tostring_reference(lua_State * L) { \
+ pdfe_reference *p = check_isreference(L, 1); \
+ if (p != NULL) { \
+ lua_pushfstring(L, "<pdfe.reference " "%d>", p->onum); \
+ return 1; \
+ } \
+ return 0; \
+}
+
+/*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->xref = reference->xref; \
+ r->onum = reference->number; \
+ } while (0)
+
+static int pushreference(lua_State * L, ppref * reference)
+{
+ if (reference != NULL && reference->number != 0) {
+ 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:
+ {
+ ppname * n = ppname_decoded(object->name) ;
+ lua_pushlstring(L, ppname_data(n), ppname_size(n));
+ return 1;
+ }
+ break;
+ case PPSTRING:
+ lua_pushlstring(L, ppstring_data(object->string), ppstring_size(object->string));
+ lua_pushboolean(L, ppstring_hex(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);
+ if (object != NULL) {
+ 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);
+ if (object != NULL) {
+ ppname * key = ppname_decoded(ppdict_key(d->dictionary,index));
+ lua_pushlstring(L, ppname_data(key), ppname_size(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);
+ if (object != NULL) {
+ ppname * key = ppname_decoded(ppdict_key(d,index));
+ lua_pushlstring(L, ppname_data(key), ppname_size(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;
+ int j = 0;
+ lua_createtable(L,i,0);
+ /* table */
+ for (i=0;i<a->array->size;i++) {
+ ppobj *object = pparray_at(a->array,i);
+ if (object != NULL) {
+ pdfelib_totable(L,object,flat);
+ /* table { type, [value], [extra], [more] } */
+ lua_rawseti(L,-2,++j);
+ /* table[i] = { type, [value], [extra], [more] } */
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_dictionarytotable(lua_State * L)
+{
+ pdfe_dictionary *d = check_isdictionary(L, 1);
+ if (d != NULL) {
+ int flat = lua_isboolean(L,2);
+ int i = 0;
+ lua_createtable(L,0,i);
+ /* table */
+ for (i=0;i<d->dictionary->size;i++) {
+ ppobj *object = ppdict_at(d->dictionary,i);
+ if (object != NULL) {
+ ppname * key = ppname_decoded(ppdict_key(d->dictionary,i));
+ lua_pushlstring(L, ppname_data(key), ppname_size(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;
+ int j = 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);
+ if (ppref_obj(r) != NULL) {
+ 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,++j);
+ /* 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:
+
+ \starttyping
+ okay = openstream(streamobject,[decode])
+ string, n = readfromstream(streamobject)
+ closestream(streamobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_openstream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ if (s->open == 0) {
+ if (lua_gettop(L) > 1) {
+ s->decode = lua_isboolean(L, 2);
+ }
+ s->open = 1;
+ }
+ lua_pushboolean(L,1);
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_closestream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ if (s->open >0) {
+ ppstream_done(s->stream);
+ s->open = 0;
+ s->decode = 0;
+ }
+ }
+ return 0;
+}
+
+static int pdfelib_readfromstream(lua_State * L)
+{
+ pdfe_stream *s = check_isstream(L, 1);
+ if (s != NULL) {
+ size_t n = 0;
+ uint8_t *d = NULL;
+ if (s->open == 1) {
+ d = ppstream_first(s->stream,&n,s->decode);
+ s->open = 2;
+ } else if (s->open == 2) {
+ d = ppstream_next(s->stream,&n);
+ } else {
+ return 0;
+ }
+ lua_pushlstring(L, (const char *) d, n);
+ lua_pushinteger(L, (int) n);
+ return 2;
+ }
+ return 0;
+}
+
+/*tex
+
+ There are two methods for opening a document: files and strings.
+
+ \starttyping
+ documentobject = open(filename)
+ documentobject = new(string,length)
+ \stoptyping
+
+ Closing happens with:
+
+ \starttyping
+ close(documentobject)
+ \stoptyping
+
+ When the \type {new} function gets a peudo filename as third argument,
+ no user data will be created but the stream is accessible as image.
+
+*/
+
+static int pdfelib_open(lua_State * L)
+{
+ const char *filename = luaL_checkstring(L, 1);
+ ppdoc *d = ppdoc_load(filename);
+ if (d == NULL) {
+ formatted_warning("pdfe lib","no valid pdf file '%s'",filename);
+ } else {
+ pdfe_document *p = (pdfe_document *) lua_newuserdata(L, sizeof(pdfe_document));
+ luaL_getmetatable(L, PDFE_METATABLE);
+ lua_setmetatable(L, -2);
+ p->document = d;
+ p->open = true;
+ p->isfile = true;
+ p->memstream = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+static int pdfelib_new(lua_State * L)
+{
+ const char *docstream = NULL;
+ char *memstream = NULL ;
+ unsigned long long streamsize;
+ switch (lua_type(L, 1)) {
+ case LUA_TSTRING:
+ /* stream as Lua string */
+ docstream = luaL_checkstring(L, 1);
+ break;
+ case LUA_TLIGHTUSERDATA:
+ /* stream as sequence of bytes */
+ docstream = (const char *) lua_touserdata(L, 1);
+ break;
+ default:
+ luaL_error(L, "bad <pdfe> argument: string or lightuserdata expected");
+ break;
+ }
+ if (docstream == NULL) {
+ luaL_error(L, "bad <pdfe> document");
+ }
+ /* size of the stream */
+ streamsize = (unsigned long long) luaL_checkint(L, 2);
+ memstream = xmalloc((unsigned) (streamsize + 1));
+ if (! memstream) {
+ luaL_error(L, "no room for <pdfe> stream");
+ }
+ memcpy(memstream, docstream, streamsize);
+ memstream[streamsize]='\0';
+ if (lua_gettop(L) == 2) {
+ /* we stay at the lua end */
+ ppdoc *d = ppdoc_mem(memstream, streamsize);
+ if (d == NULL) {
+ normal_warning("pdfe lib","no valid pdf mem stream");
+ } else {
+ pdfe_document *p = (pdfe_document *) lua_newuserdata(L, sizeof(pdfe_document));
+ luaL_getmetatable(L, PDFE_METATABLE);
+ lua_setmetatable(L, -2);
+ p->document = d;
+ p->open = true;
+ p->isfile = false;
+ p->memstream = memstream;
+ return 1;
+ }
+ } else {
+ /* pseudo file name */
+ PdfDocument *pdf_doc;
+ const char *file_id = luaL_checkstring(L, 3);
+ if (file_id == NULL) {
+ luaL_error(L, "<pdfe> stream has an invalid id");
+ }
+ if (strlen(file_id) > STREAM_FILE_ID_LEN ) {
+ /* a limit to the length of the string */
+ luaL_error(L, "<pdfe> stream has a too long id");
+ }
+ pdf_doc = refMemStreamPdfDocument(memstream, streamsize, file_id);
+ if (pdf_doc != NULL) {
+ lua_pushstring(L,pdf_doc->file_path);
+ return 1;
+ } else {
+ /* pplib does this: xfree(memstream); */
+ }
+ }
+ return 0;
+}
+
+/*
+
+ There is no garbage collection needed as the library itself manages the
+ objects. Normally objects don't take much space. Streams use buffers so (I
+ assume) that they are not persistent. The only collector is in the parent
+ object (the document).
+
+*/
+
+static int pdfelib_free(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL && p->open) {
+ if (p->document != NULL) {
+ ppdoc_free(p->document);
+ p->document = NULL;
+ }
+ if (p->memstream != NULL) {
+ /* pplib does this: xfree(p->memstream); */
+ p->memstream = NULL;
+ }
+ p->open = false;
+ }
+ return 0;
+}
+
+static int pdfelib_close(lua_State * L)
+{
+ return pdfelib_free(L);
+}
+
+/*tex
+
+ A document is can be uncrypted with:
+
+ \starttyping
+ status = unencrypt(documentobject,user,owner)
+ \stoptyping
+
+ Instead of a password \type {nil} can be passed, so there are three possible
+ useful combinations.
+
+*/
+
+static int pdfelib_unencrypt(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL) {
+ size_t u = 0;
+ size_t o = 0;
+ const char* user = NULL;
+ const char* owner = NULL;
+ int top = lua_gettop(L);
+ if (top > 1) {
+ if (lua_type(L,2) == LUA_TSTRING) {
+ user = lua_tolstring(L, 2, &u);
+ } else {
+ /*tex we're not too picky but normally it will be nil or false */
+ }
+ if (top > 2) {
+ if (lua_type(L,3) == LUA_TSTRING) {
+ owner = lua_tolstring(L, 3, &o);
+ } else {
+ /*tex we're not too picky but normally it will be nil or false */
+ }
+ }
+ lua_pushinteger(L, (int) ppdoc_crypt_pass(p->document,user,u,owner,o));
+ return 1;
+ }
+ }
+ lua_pushinteger(L, (int) PPCRYPT_FAIL);
+ return 1;
+}
+
+/*tex
+
+ There are a couple of ways to get information about the document:
+
+ \starttyping
+ n = getsize (documentobject)
+ major, minor = getversion (documentobject)
+ status = getstatus (documentobject)
+ n = getnofobjects (documentobject)
+ n = getnofpages (documentobject)
+ bytes, waste = getmemoryusage(documentobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getsize(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_file_size(p->document));
+ return 1;
+}
+
+static int pdfelib_getversion(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ int minor;
+ int major = ppdoc_version_number(p->document, &minor);
+ lua_pushinteger(L,(int) major);
+ lua_pushinteger(L,(int) minor);
+ return 2;
+ }
+}
+
+static int pdfelib_getstatus(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_crypt_status(p->document));
+ return 1;
+}
+
+static int pdfelib_getnofobjects(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_objects(p->document));
+ return 1;
+}
+
+static int pdfelib_getnofpages(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL)
+ return 0;
+ lua_pushinteger(L,(int) ppdoc_page_count(p->document));
+ return 1;
+}
+
+static int pdfelib_getmemoryusage(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p != NULL) {
+ size_t w = 0;
+ size_t m = ppdoc_memory(p->document,&w);
+ lua_pushinteger(L,(int) m);
+ lua_pushinteger(L,(int) w);
+ return 2;
+ }
+ return 0;
+}
+
+/*
+ A specific page dictionary can be filtered with the next command. So, there
+ is no need to parse the document page tree (with these \type {kids} arrays).
+
+ \starttyping
+ dictionaryobject = getpage(documentobject,pagenumber)
+ \stoptyping
+
+*/
+
+static int pushpage(lua_State * L, ppdoc * d, int page)
+{
+ if (page <= 0 || page > ppdoc_page_count(d)) {
+ return 0;
+ } else {
+ ppref *pp = ppdoc_page(d,page);
+ return pushdictionaryonly(L, ppref_obj(pp)->dict);
+ }
+}
+
+static int pdfelib_getpage(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ return pushpage(L, p->document, luaL_checkint(L, 2));
+ }
+}
+
+static int pushpages(lua_State * L, ppdoc * d)
+{
+ int i = 0;
+ ppref *r;
+ lua_createtable(L,ppdoc_page_count(d),0);
+ /* pages[1..n] */
+ for (r = ppdoc_first_page(d), i = 1; r != NULL; r = ppdoc_next_page(d), ++i) {
+ pushdictionaryonly(L,ppref_obj(r)->dict);
+ lua_rawseti(L,-2,i);
+ }
+ return 1 ;
+}
+
+static int pdfelib_getpages(lua_State * L)
+{
+ pdfe_document *p = check_isdocument(L, 1);
+ if (p == NULL) {
+ return 0;
+ } else {
+ return pushpages(L, p->document);
+ }
+}
+
+/*tex
+
+ The boundingbox (\type {MediaBox) and similar boxes can be available in a
+ (page) doctionary but also in a parent object. Therefore a helper is
+ available that does the (backtracked) lookup.
+
+ \starttyping
+ { lx, ly, rx, ry } = getbox(dictionaryobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getbox(lua_State * L)
+{
+ if (lua_gettop(L) > 1 && lua_type(L,2) == LUA_TSTRING) {
+ pdfe_dictionary *p = check_isdictionary(L, 1);
+ if (p != NULL) {
+ const char *key = lua_tostring(L,2);
+ pprect box;
+ pprect *r;
+ box.lx = box.rx = box.ly = box.ry = 0;
+ r = ppdict_get_box(p->dictionary,key,&box);
+ if (r != NULL) {
+ lua_createtable(L,4,0);
+ lua_pushnumber(L,r->lx);
+ lua_rawseti(L,-2,1);
+ lua_pushnumber(L,r->ly);
+ lua_rawseti(L,-2,2);
+ lua_pushnumber(L,r->rx);
+ lua_rawseti(L,-2,3);
+ lua_pushnumber(L,r->ry);
+ lua_rawseti(L,-2,4);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ This one is needed when you use the detailed getters and run into an
+ object reference. The regular getters resolve this automatically.
+
+ \starttyping
+ [dictionary|array|stream]object = getfromreference(referenceobject)
+ \stoptyping
+
+*/
+
+static int pdfelib_getfromreference(lua_State * L)
+{
+ pdfe_reference *r = check_isreference(L, 1);
+ if (r != NULL && r->xref != NULL) {
+ ppref *rr = ppxref_find(r->xref, (ppuint) r->onum);
+ if (rr != NULL) {
+ ppobj *o = ppref_obj(rr);
+ if (o != NULL) {
+ lua_pushinteger(L,o->type);
+ return 1 + pushvalue(L,o);
+ }
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ Here are some convenient getters:
+
+ \starttyping
+ <string> = getstring (array|dict|ref,index|key)
+ <integer> = getinteger (array|dict|ref,index|key)
+ <number> = getnumber (array|dict|ref,index|key)
+ <boolan> = getboolean (array|dict|ref,index|key)
+ <string> = getname (array|dict|ref,index|key)
+ <dictionary> = getdictionary(array|dict|ref,index|key)
+ <array> = getarray (array|dict|ref,index|key)
+ <stream>, <dict> = getstream (array|dict|ref,index|key)
+ \stoptyping
+
+ We report issues when reasonable but are silent when it makes sense. We don't
+ error on this because we expect the user code to act reasonable on a return
+ value.
+
+*/
+
+# define pdfelib_get_value_check_1 do { \
+ if (p == NULL) { \
+ if (t == LUA_TSTRING) { \
+ normal_warning("pdfe lib","lua <pdfe dictionary> expected"); \
+ } else if (t == LUA_TNUMBER) { \
+ normal_warning("pdfe lib","lua <pdfe array> expected"); \
+ } else { \
+ normal_warning("pdfe lib","invalid arguments"); \
+ } \
+ return 0; \
+ } else if (! lua_getmetatable(L, 1)) { \
+ normal_warning("pdfe lib","first argument should be a <pde array> or <pde dictionary>"); \
+ } \
+} while (0)
+
+# define pdfelib_get_value_check_2 \
+ normal_warning("pdfe lib","second argument should be integer or string");
+
+/*tex
+
+ The direct fetcher returns the result or |NULL| when there is nothing
+ found.
+
+*/
+
+# define pdfelib_get_indirect_o(p) \
+ ppref *r = (((pdfe_reference *) p)->xref != NULL) ? ppxref_find(((pdfe_reference *) p)->xref, (ppuint) (((pdfe_reference *) p)->onum)) : NULL; \
+ ppobj *o = (r != NULL) ? ppref_obj(r) : NULL; \
+
+# define pdfelib_get_value_direct(get_d,get_a) do { \
+ int t = lua_type(L,2); \
+ void *p = lua_touserdata(L, 1); \
+ lua_settop(L,2); \
+ 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)) { \
+ pdfelib_get_indirect_o(p); \
+ 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)) { \
+ pdfelib_get_indirect_o(p); \
+ 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); \
+ lua_settop(L,2); \
+ 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)) { \
+ pdfelib_get_indirect_o(p); \
+ 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)) { \
+ pdfelib_get_indirect_o(p); \
+ if (o != NULL && o->type == PPARRAY) \
+ okay = get_a(o->array, index, &value); \
+ } \
+ } \
+ } else { \
+ pdfelib_get_value_check_2; \
+ } \
+} while (0)
+
+/* pre 1.13 version:
+
+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_pushlstring(L, ppstring_data(value), ppstring_size(value));
+ return 2;
+ }
+ }
+ return 0;
+}
+
+*/
+
+static int pdfelib_getstring(lua_State *L)
+{
+ if (lua_gettop(L) > 1) {
+ ppstring *value = NULL;
+ int how = 0;
+ if (lua_type(L, 3) == LUA_TBOOLEAN) {
+ if (lua_toboolean(L, 3)) {
+ how = 1;
+ } else {
+ how = 2;
+ }
+ }
+ pdfelib_get_value_direct(ppdict_rget_string,pparray_rget_string);
+ if (value != NULL) {
+ if (how == 1) {
+ value = ppstring_decoded(value);
+ }
+ lua_pushlstring(L,ppstring_data(value),ppstring_size(value));
+ if (how == 2) {
+ lua_pushboolean(L,ppstring_hex(value));
+ return 2;
+ } else {
+ 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) {
+ value = ppname_decoded(value) ;
+ lua_pushlstring(L, ppname_data(value), ppname_size(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:
+ {
+ ppname * n = ppname_decoded(object->name) ;
+ lua_pushlstring(L, ppname_data(n), ppname_size(n));
+ }
+ break;
+ case PPSTRING:
+ lua_pushlstring(L, ppstring_data(object->string), ppstring_size(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 add few more informational
+ helpers but this is it.
+
+*/
+
+static const struct luaL_Reg pdfelib[] = {
+ /* management */
+ { "type", pdfelib_type },
+ { "open", pdfelib_open },
+ { "new", pdfelib_new },
+ { "close", pdfelib_close },
+ { "unencrypt", pdfelib_unencrypt },
+ /* statistics */
+ { "getversion", pdfelib_getversion },
+ { "getstatus", pdfelib_getstatus },
+ { "getsize", pdfelib_getsize },
+ { "getnofobjects", pdfelib_getnofobjects },
+ { "getnofpages", pdfelib_getnofpages },
+ { "getmemoryusage", pdfelib_getmemoryusage },
+ /* getters */
+ { "getcatalog", pdfelib_getcatalog },
+ { "gettrailer", pdfelib_gettrailer },
+ { "getinfo", pdfelib_getinfo },
+ { "getpage", pdfelib_getpage },
+ { "getpages", pdfelib_getpages },
+ { "getbox", pdfelib_getbox },
+ { "getfromreference", pdfelib_getfromreference },
+ { "getfromdictionary", pdfelib_getfromdictionary },
+ { "getfromarray", pdfelib_getfromarray },
+ { "getfromstream", pdfelib_getfromstream },
+ /* collectors */
+ { "dictionarytotable", pdfelib_dictionarytotable },
+ { "arraytotable", pdfelib_arraytotable },
+ { "pagestotable", pdfelib_pagestotable },
+ /* more getters */
+ { "getstring", pdfelib_getstring },
+ { "getinteger", pdfelib_getinteger },
+ { "getnumber", pdfelib_getnumber },
+ { "getboolean", pdfelib_getboolean },
+ { "getname", pdfelib_getname },
+ { "getdictionary", pdfelib_getdictionary },
+ { "getarray", pdfelib_getarray },
+ { "getstream", pdfelib_getstream },
+ /* streams */
+ { "readwholestream", pdfelib_readwholestream },
+ /* not really needed */
+ { "openstream", pdfelib_openstream },
+ { "readfromstream", pdfelib_readfromstream },
+ { "closestream", pdfelib_closestream },
+ /* done */
+ { NULL, NULL}
+};
+
+/*tex
+
+ The user data metatables are defined as follows. Watch how only the
+ document needs a garbage collector.
+
+*/
+
+static const struct luaL_Reg pdfelib_m[] = {
+ { "__tostring", pdfelib_tostring_document },
+ { "__gc", pdfelib_free },
+ { "__index", pdfelib_access },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_dictionary[] = {
+ { "__tostring", pdfelib_tostring_dictionary },
+ { "__index", pdfelib_dictionary_access },
+ { "__len", pdfelib_dictionary_size },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_array[] = {
+ { "__tostring", pdfelib_tostring_array },
+ { "__index", pdfelib_array_access },
+ { "__len", pdfelib_array_size },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_stream[] = {
+ { "__tostring", pdfelib_tostring_stream },
+ { "__index", pdfelib_stream_access },
+ { "__len", pdfelib_stream_size },
+ { "__call", pdfelib_readwholestream },
+ { NULL, NULL}
+};
+
+static const struct luaL_Reg pdfelib_m_reference[] = {
+ { "__tostring", pdfelib_tostring_reference },
+ { NULL, NULL}
+};
+
+/*tex
+
+ Finally we hav earrived at the main initialiser that will be called as part
+ of \LUATEX's initializer.
+
+*/
+
+/*tex
+
+ Here we hook in the error handler.
+
+*/
+
+static void pdfelib_message(const char *message, void *alien)
+{
+ normal_warning("pdfe",message);
+}
+
+int luaopen_pdfe(lua_State * L)
+{
+ /*tex First the four userdata object get their metatables defined. */
+
+ luaL_newmetatable(L, PDFE_METATABLE_DICTIONARY);
+ luaL_openlib(L, NULL, pdfelib_m_dictionary, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_ARRAY);
+ luaL_openlib(L, NULL, pdfelib_m_array, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_STREAM);
+ luaL_openlib(L, NULL, pdfelib_m_stream, 0);
+
+ luaL_newmetatable(L, PDFE_METATABLE_REFERENCE);
+ luaL_openlib(L, NULL, pdfelib_m_reference, 0);
+
+ /*tex Then comes the main (document) metatable: */
+
+ luaL_newmetatable(L, PDFE_METATABLE);
+ luaL_openlib(L, NULL, pdfelib_m, 0);
+
+ /*tex Last the library opens up itself to the world. */
+
+ luaL_openlib(L, "pdfe", pdfelib, 0);
+
+ pplog_callback(pdfelib_message, stderr);
+
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdflib.c b/Build/source/texk/web2c/luatexdir/lua/lpdflib.c
new file mode 100644
index 00000000000..6396baa92cc
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdflib.c
@@ -0,0 +1,1398 @@
+/* lpdflib.c
+
+ Copyright 2006-2011 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#include "pdf/pdftables.h"
+
+int luapdfprint(lua_State * L)
+{
+ int n;
+ const_lstring st;
+ const char *modestr_s;
+ ctm_transform_modes literal_mode;
+ st.s = modestr_s = NULL;
+ n = lua_gettop(L);
+ if (!lua_isstring(L, -1)) { /* or number */
+ luaL_error(L, "no string to print");
+ }
+ literal_mode = set_origin;
+ if (n == 2) {
+ if (lua_type(L,-2) != LUA_TSTRING) {
+ luaL_error(L, "invalid first argument for print literal mode");
+ } else {
+ modestr_s = lua_tostring(L, -2);
+ if (lua_key_eq(modestr_s,direct))
+ literal_mode = direct_always;
+ else if (lua_key_eq(modestr_s,page))
+ literal_mode = direct_page;
+ else if (lua_key_eq(modestr_s,text))
+ literal_mode = direct_text;
+ else if (lua_key_eq(modestr_s,raw))
+ literal_mode = direct_raw;
+ else if (lua_key_eq(modestr_s,origin))
+ literal_mode = set_origin;
+ else {
+ luaL_error(L, "invalid first argument for print literal mode");
+ }
+ }
+ } else if (n != 1) {
+ luaL_error(L, "invalid number of arguments");
+ }
+ check_o_mode(static_pdf, "pdf.print()", 1 << OMODE_PDF, true);
+ switch (literal_mode) {
+ case (set_origin):
+ pdf_goto_pagemode(static_pdf);
+ pdf_set_pos(static_pdf, static_pdf->posstruct->pos);
+ (void) calc_pdfpos(static_pdf->pstruct, static_pdf->posstruct->pos);
+ break;
+ case (direct_page):
+ pdf_goto_pagemode(static_pdf);
+ (void) calc_pdfpos(static_pdf->pstruct, static_pdf->posstruct->pos);
+ break;
+ case (direct_text):
+ pdf_goto_textmode(static_pdf);
+ (void) calc_pdfpos(static_pdf->pstruct, static_pdf->posstruct->pos);
+ break;
+ case (direct_always):
+ pdf_end_string_nl(static_pdf);
+ break;
+ case (direct_raw):
+ pdf_end_string_nl(static_pdf);
+ break;
+ default:
+ assert(0);
+ }
+ st.s = lua_tolstring(L, n, &st.l);
+ pdf_out_block(static_pdf, st.s, st.l);
+/* pdf_out(pdf, '\n'); */
+ return 0;
+}
+
+static unsigned char *fread_to_buf(lua_State * L, const char *filename, size_t * len)
+{
+ int ilen = 0;
+ FILE *f;
+ unsigned char *buf = NULL;
+ if ((f = fopen(filename, "rb")) == NULL)
+ luaL_error(L, "pdf.immediateobj() cannot open input file");
+ if (readbinfile(f, &buf, &ilen) == 0)
+ luaL_error(L, "pdf.immediateobj() cannot read input file");
+ fclose(f);
+ *len = (size_t) ilen;
+ return buf;
+}
+
+static int l_immediateobj(lua_State * L)
+{
+ int n, first_arg = 1;
+ int k;
+ lstring buf;
+ const_lstring st1,st2, st3;
+ const char *st1_s = NULL;
+ st1.s = st2.s = st3.s = NULL;
+ check_o_mode(static_pdf, "immediateobj()", 1 << OMODE_PDF, true);
+ if (global_shipping_mode != NOT_SHIPPING)
+ luaL_error(L, "pdf.immediateobj() can not be used with \\latelua");
+ n = lua_gettop(L);
+ if ((n > 0) && (lua_type(L, 1) == LUA_TNUMBER)) {
+ first_arg++;
+ k = (int) lua_tointeger(L, 1);
+ check_obj_type(static_pdf, obj_type_obj, k);
+ if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
+ luaL_error(L, "pdf.immediateobj() object in use");
+ } else {
+ static_pdf->obj_count++;
+ k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
+ }
+ pdf_last_obj = k;
+ switch (n - first_arg + 1) {
+ case 0:
+ luaL_error(L, "pdf.immediateobj() needs at least one argument");
+ break;
+ case 1:
+ if (!lua_isstring(L, first_arg)) /* or number */
+ luaL_error(L, "pdf.immediateobj() 1st argument must be string");
+ pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
+ st1.s = lua_tolstring(L, first_arg, &st1.l);
+ pdf_out_block(static_pdf, st1.s, st1.l);
+ pdf_end_obj(static_pdf);
+ break;
+ case 2:
+ case 3:
+ if (lua_type(L,first_arg) != LUA_TSTRING)
+ luaL_error(L, "pdf.immediateobj() 1st argument must be string");
+ if (!lua_isstring(L, first_arg + 1)) /* or number */
+ luaL_error(L, "pdf.immediateobj() 2nd argument must be string");
+ st1_s = lua_tostring(L, first_arg);
+ st2.s = lua_tolstring(L, first_arg + 1, &st2.l);
+ if (lua_key_eq(st1_s, file)) {
+ if (n == first_arg + 2)
+ luaL_error(L, "pdf.immediateobj() 3rd argument forbidden in file mode");
+ pdf_begin_obj(static_pdf, k, OBJSTM_ALWAYS);
+ buf.s = fread_to_buf(L, st2.s, &buf.l);
+ pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
+ xfree(buf.s);
+ pdf_end_obj(static_pdf);
+ } else {
+ pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* not an object stream candidate! */
+ pdf_begin_dict(static_pdf);
+ if (n == first_arg + 2) { /* write attr text */
+ if (!lua_isstring(L, first_arg + 2)) /* or number (maybe only string as it's an attr) */
+ luaL_error(L, "pdf.immediateobj() 3rd argument must be string");
+ st3.s = lua_tolstring(L, first_arg + 2, &st3.l);
+ pdf_out_block(static_pdf, st3.s, st3.l);
+ if (st3.s[st3.l - 1] != '\n')
+ pdf_out(static_pdf, '\n');
+ }
+ pdf_dict_add_streaminfo(static_pdf);
+ pdf_end_dict(static_pdf);
+ pdf_begin_stream(static_pdf);
+ if (lua_key_eq(st1_s, stream)) {
+ pdf_out_block(static_pdf, st2.s, st2.l);
+ } else if (lua_key_eq(st1_s, streamfile)) {
+ buf.s = fread_to_buf(L, st2.s, &buf.l);
+ pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
+ xfree(buf.s);
+ } else
+ luaL_error(L, "pdf.immediateobj() invalid argument");
+ pdf_end_stream(static_pdf);
+ pdf_end_obj(static_pdf);
+ }
+ break;
+ default:
+ luaL_error(L, "pdf.immediateobj() allows max. 3 arguments");
+ }
+ lua_pushinteger(L, k);
+ return 1;
+}
+
+static int table_obj(lua_State * L)
+{
+ const char *type;
+ int k, obj_compression;
+ int compress_level = -1; /* unset */
+ int os_threshold = OBJSTM_ALWAYS; /* default: put non-stream objects into object streams */
+ int saved_compress_level = static_pdf->compress_level;
+ 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 */
+ lua_key_rawgeti(type);
+ if (lua_isnil(L, -1)) /* !vs t */
+ luaL_error(L, "pdf.obj(): object \"type\" missing");
+ if (lua_type(L,-1) != LUA_TSTRING) /* !vs t */
+ luaL_error(L, "pdf.obj(): object \"type\" must be string");
+ type = lua_tostring(L, -1);
+ if (! (lua_key_eq(type, raw) || lua_key_eq(type, stream))) {
+ luaL_error(L, "pdf.obj(): \"%s\" is not a valid object type", type); /* i vs t */
+ }
+ lua_pop(L, 1); /* t */
+ lua_key_rawgeti(immediate);
+ if (!lua_isnil(L, -1)) { /* b? t */
+ if (!lua_isboolean(L, -1)) /* !b t */
+ luaL_error(L, "pdf.obj(): \"immediate\" must be boolean");
+ 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"? */
+
+ lua_key_rawgeti(objnum);
+ if (!lua_isnil(L, -1)) { /* vi? t */
+ if (lua_type(L,-1) != LUA_TNUMBER) /* !vi t */
+ luaL_error(L, "pdf.obj(): \"objnum\" must be integer");
+ k = (int) lua_tointeger(L, -1); /* vi t */
+ check_obj_type(static_pdf, obj_type_obj, k);
+ if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
+ luaL_error(L, "pdf.obj() object in use");
+ } else {
+ static_pdf->obj_count++;
+ k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
+ }
+ pdf_last_obj = k;
+ if (immediate == 0) {
+ obj_data_ptr(static_pdf, k) = pdf_get_mem(static_pdf, pdfmem_obj_size);
+ init_obj_obj(static_pdf, k);
+ }
+ lua_pop(L, 1); /* t */
+
+ /* get optional "attr" (allowed only for stream case) */
+
+ lua_key_rawgeti(attr);
+ if (!lua_isnil(L, -1)) { /* attr-s? t */
+ if (! lua_key_eq(type, stream))
+ luaL_error(L, "pdf.obj(): \"attr\" key not allowed for non-stream object");
+ if (!lua_isstring(L, -1)) /* or number */ /* !attr-s t */
+ luaL_error(L, "pdf.obj(): object \"attr\" must be string");
+ if (immediate == 1) {
+ attr.s = lua_tolstring(L, -1, &attr.l); /* attr-s t */
+ lua_pop(L, 1); /* t */
+ } else
+ obj_obj_stream_attr(static_pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX); /* t */
+ } else {
+ lua_pop(L, 1); /* t */
+ }
+
+ /* get optional "compresslevel" (allowed only for stream case) */
+
+ lua_key_rawgeti(compresslevel);
+ if (!lua_isnil(L, -1)) { /* vi? t */
+ if (lua_key_eq(type, raw))
+ luaL_error(L, "pdf.obj(): \"compresslevel\" key not allowed for raw object");
+ if (lua_type(L, -1) != LUA_TNUMBER) /* !vi t */
+ luaL_error(L, "pdf.obj(): \"compresslevel\" must be integer");
+ compress_level = (int) lua_tointeger(L, -1); /* vi t */
+ if (compress_level > 9)
+ luaL_error(L, "pdf.obj(): \"compresslevel\" must be <= 9");
+ else if (compress_level < 0)
+ luaL_error(L, "pdf.obj(): \"compresslevel\" must be >= 0");
+ if (immediate == 0)
+ obj_obj_pdfcompresslevel(static_pdf, k) = compress_level;
+ }
+ lua_pop(L, 1); /* t */
+
+ /* get optional "objcompression" (allowed only for non-stream case) */
+
+ lua_key_rawgeti(objcompression);
+ if (!lua_isnil(L, -1)) { /* b? t */
+ if (lua_key_eq(type, stream))
+ luaL_error(L, "pdf.obj(): \"objcompression\" key not allowed for stream object");
+ if (!lua_isboolean(L, -1)) /* !b t */
+ luaL_error(L, "pdf.obj(): \"objcompression\" must be boolean");
+ obj_compression = lua_toboolean(L, -1); /* 0 or 1 */
+ /* OBJSTM_NEVER: never into object stream; OBJSTM_ALWAYS: depends then on \pdfobjcompresslevel */
+ if (obj_compression > 0)
+ os_threshold = OBJSTM_ALWAYS;
+ else
+ os_threshold = OBJSTM_NEVER;
+ if (immediate == 0)
+ obj_obj_objstm_threshold(static_pdf, k) = os_threshold;
+ }
+ lua_pop(L, 1); /* t */
+
+ /* now the object contents for all cases are handled */
+
+ lua_key_rawgeti(string);
+ lua_key_rawgeti_n(file,-2);
+
+ if (!lua_isnil(L, -1) && !lua_isnil(L, -2)) /* file-s? string-s? t */
+ luaL_error(L, "pdf.obj(): \"string\" and \"file\" must not be given together");
+ if (lua_isnil(L, -1) && lua_isnil(L, -2)) /* nil nil t */
+ luaL_error(L, "pdf.obj(): no \"string\" or \"file\" given");
+
+ if (lua_key_eq(type, raw)) {
+ if (immediate == 1)
+ pdf_begin_obj(static_pdf, k, os_threshold);
+ if (!lua_isnil(L, -2)) { /* file-s? string-s? t */
+ /* from string */
+ lua_pop(L, 1); /* string-s? t */
+ if (!lua_isstring(L, -1)) /* or number */ /* !string-s t */
+ luaL_error(L, "pdf.obj(): \"string\" must be string for raw object");
+ if (immediate == 1) {
+ st.s = lua_tolstring(L, -1, &st.l);
+ pdf_out_block(static_pdf, st.s, st.l);
+ } else
+ obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* t */
+ } else {
+ /* from file */
+ if (lua_type(L, -1) != LUA_TSTRING) /* !file-s nil t */
+ luaL_error(L, "pdf.obj(): \"file\" name must be string for raw object");
+ if (immediate == 1) {
+ st.s = lua_tolstring(L, -1, &st.l); /* file-s nil t */
+ buf.s = fread_to_buf(L, st.s, &buf.l);
+ pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
+ /* already in pdf_end_obj:
+ if (buf.s[buf.l - 1] != '\n')
+ pdf_out(static_pdf, '\n');
+ */
+ xfree(buf.s);
+ } else {
+ set_obj_obj_is_file(static_pdf, k);
+ obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* nil t */
+ }
+ }
+ if (immediate == 1)
+ pdf_end_obj(static_pdf);
+ } else {
+ if (immediate == 1) {
+ pdf_begin_obj(static_pdf, k, OBJSTM_NEVER); /* 0 = not an object stream candidate! */
+ 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);
+ 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);
+ }
+ 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;
+ }
+ if (!lua_isnil(L, -2)) { /* file-s? string-s? t */
+ /* from string */
+ lua_pop(L, 1); /* string-s? t */
+ if (!lua_isstring(L, -1)) /* or number */ /* !string-s t */
+ luaL_error(L, "pdf.obj(): \"string\" must be string for stream object");
+ if (immediate == 1) {
+ st.s = lua_tolstring(L, -1, &st.l); /* string-s t */
+ pdf_out_block(static_pdf, st.s, st.l);
+ } else
+ obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* t */
+ } else {
+ /* from file */
+ if (lua_type(L, -1) != LUA_TSTRING) /* !file-s nil t */
+ luaL_error(L, "pdf.obj(): \"file\" name must be string for stream object");
+ if (immediate == 1) {
+ st.s = lua_tolstring(L, -1, &st.l); /* file-s nil t */
+ buf.s = fread_to_buf(L, st.s, &buf.l);
+ pdf_out_block(static_pdf, (const char *) buf.s, buf.l);
+ xfree(buf.s);
+ } else {
+ set_obj_obj_is_file(static_pdf, k);
+ obj_obj_data(static_pdf, k) = luaL_ref(L, LUA_REGISTRYINDEX); /* nil t */
+ }
+ }
+ if (immediate == 1) {
+ pdf_end_stream(static_pdf);
+ pdf_end_obj(static_pdf);
+ }
+ }
+ static_pdf->compress_level = saved_compress_level;
+ return k;
+}
+
+static int orig_obj(lua_State * L)
+{
+ int n, first_arg = 1;
+ int k;
+ const char *st_s = NULL ;
+ n = lua_gettop(L);
+ if ((n > 0) && (lua_type(L, 1) == LUA_TNUMBER)) {
+ first_arg++;
+ k = (int) lua_tointeger(L, 1);
+ check_obj_type(static_pdf, obj_type_obj, k);
+ if (is_obj_scheduled(static_pdf, k) || obj_data_ptr(static_pdf, k) != 0)
+ luaL_error(L, "pdf.obj() object in use");
+ } else {
+ static_pdf->obj_count++;
+ k = pdf_create_obj(static_pdf, obj_type_obj, static_pdf->obj_ptr + 1);
+ }
+ pdf_last_obj = k;
+ 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);
+ 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;
+}
+
+static int l_obj(lua_State * L)
+{
+ int k, n;
+ ensure_output_state(static_pdf, ST_HEADER_WRITTEN);
+ n = lua_gettop(L);
+ if (n == 1 && lua_istable(L, 1))
+ k = table_obj(L); /* new */
+ else
+ k = orig_obj(L);
+ lua_pushinteger(L, k);
+ return 1;
+}
+
+static int l_refobj(lua_State * L)
+{
+ int k, n;
+ n = lua_gettop(L);
+ if (n != 1)
+ luaL_error(L, "pdf.refobj() needs exactly 1 argument");
+ k = (int) luaL_checkinteger(L, 1);
+ if (global_shipping_mode == NOT_SHIPPING)
+ scan_refobj_lua(static_pdf, k);
+ else
+ pdf_ref_obj_lua(static_pdf, k);
+ return 0;
+}
+
+static int l_reserveobj(lua_State * L)
+{
+ int n;
+ 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");
+ }
+ lua_pushinteger(L, static_pdf->obj_ptr);
+ return 1;
+}
+
+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");
+ }
+ return 0;
+}
+
+/*
+
+# define valid_pdf_key ( \
+ lua_key_eq(s,pageresources) \
+ lua_key_eq(s,pageattributes) || \
+ lua_key_eq(s,pagesattributes) || \
+ lua_key_eq(s,catalog) || \
+ lua_key_eq(s,info) || \
+ lua_key_eq(s,names) || \
+ lua_key_eq(s,trailer) || \
+ lua_key_eq(s,xformresources) || \
+ lua_key_eq(s,xformattributes) || \
+ lua_key_eq(s,trailerid) \
+)
+
+*/
+
+#define l_get_pdf_value(key) \
+ lua_get_metatablelua(pdf_data); \
+ lua_key_rawgeti(key); \
+ return 1;
+
+static int l_get_pageresources (lua_State * L) { l_get_pdf_value(pageresources); }
+static int l_get_pageattributes (lua_State * L) { l_get_pdf_value(pageattributes); }
+static int l_get_pagesattributes(lua_State * L) { l_get_pdf_value(pagesattributes); }
+static int l_get_catalog (lua_State * L) { l_get_pdf_value(catalog); }
+static int l_get_info (lua_State * L) { l_get_pdf_value(info); }
+static int l_get_names (lua_State * L) { l_get_pdf_value(names); }
+static int l_get_trailer (lua_State * L) { l_get_pdf_value(trailer); }
+static int l_get_xformresources (lua_State * L) { l_get_pdf_value(xformresources); }
+static int l_get_xformattributes(lua_State * L) { l_get_pdf_value(xformattributes); }
+static int l_get_trailerid (lua_State * L) { l_get_pdf_value(trailerid); }
+
+/*
+
+static int getpdf(lua_State * L)
+{
+ const char *s ;
+ if (lua_gettop(L) != 2) {
+ return 0;
+ }
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ s = lua_tostring(L, -1);
+ if (lua_key_eq(s,h)) {
+ lua_pushinteger(L, static_pdf->posstruct->pos.h);
+ return 1;
+ } else if (lua_key_eq(s,v)) {
+ lua_pushinteger(L, static_pdf->posstruct->pos.v);
+ return 1;
+ } else if (valid_pdf_key) {
+ lua_get_metatablelua(pdf_data);
+ lua_replace(L, -3);
+ lua_rawget(L, -2);
+ return 1;
+ }
+ }
+ return 0;
+}
+*/
+
+#define l_set_pdf_value(key) \
+ if (lua_type(L,-1) == LUA_TSTRING) { \
+ lua_get_metatablelua(pdf_data); \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(key)); \
+ lua_pushvalue(L, -3); \
+ lua_rawset(L,-3); \
+ } \
+ return 0;
+
+static int l_set_pageresources (lua_State * L) { l_set_pdf_value(pageresources); }
+static int l_set_pageattributes (lua_State * L) { l_set_pdf_value(pageattributes); }
+static int l_set_pagesattributes(lua_State * L) { l_set_pdf_value(pagesattributes); }
+static int l_set_catalog (lua_State * L) { l_set_pdf_value(catalog); }
+static int l_set_info (lua_State * L) { l_set_pdf_value(info); }
+static int l_set_names (lua_State * L) { l_set_pdf_value(names); }
+static int l_set_trailer (lua_State * L) { l_set_pdf_value(trailer); }
+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 getpdfobjtype(lua_State * L)
+{
+ 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_pushnil(L);
+ return 1;
+}
+
+static int getpdfmaxobjnum(lua_State * L)
+{
+ lua_pushinteger(L, static_pdf->obj_ptr);
+ return 1;
+}
+
+static int l_mapfile(lua_State * L)
+{
+ const char *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);
+ }
+ return 0;
+}
+
+static int l_mapline(lua_State * L)
+{
+ const char *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_getpos(lua_State * L)
+{
+ lua_pushinteger(L, static_pdf->posstruct->pos.h);
+ lua_pushinteger(L, static_pdf->posstruct->pos.v);
+ return 2;
+}
+
+static int l_gethpos(lua_State * L)
+{
+ lua_pushinteger(L, static_pdf->posstruct->pos.h);
+ return 1;
+}
+
+static int l_getvpos(lua_State * L)
+{
+ lua_pushinteger(L, static_pdf->posstruct->pos.v);
+ return 1;
+}
+
+static int l_getmatrix(lua_State * L)
+{
+ if (matrix_stack_used > 0) {
+ matrix_entry *m = &matrix_stack[matrix_stack_used - 1];
+ lua_pushnumber(L, m->a);
+ lua_pushnumber(L, m->b);
+ lua_pushnumber(L, m->c);
+ lua_pushnumber(L, m->d);
+ lua_pushnumber(L, m->e);
+ lua_pushnumber(L, m->f);
+ } else {
+ lua_pushinteger(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushinteger(L, 0);
+ lua_pushinteger(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushinteger(L, 0);
+ }
+ return 6 ;
+}
+
+static int l_hasmatrix(lua_State * L)
+{
+ lua_pushboolean(L, (matrix_stack_used > 0));
+ return 1 ;
+}
+
+static int l_get_lastlink(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_last_link));
+ return 1 ;
+}
+
+static int l_get_retval(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_retval));
+ return 1 ;
+}
+
+static int l_get_lastobj(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_last_obj));
+ return 1 ;
+}
+
+static int l_get_lastannot(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_last_annot));
+ return 1 ;
+}
+
+/* maybe:
+
+ get_fontname : set_ff(i) obj_info(static_pdf, pdf_font_num(ff))
+ get_fontobjnum : set_ff(i) pdf_font_num(ff)
+ get_fontsize : font_size(i)
+ get_xformname : obj_info(static_pdf, i)
+
+*/
+
+static int l_get_compress_level(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_compress_level));
+ return 1 ;
+}
+
+static int l_get_obj_compress_level(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_obj_compress_level));
+ 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) {
+ int c = (int) lua_tointeger(L, 1);
+ if (c<0)
+ c = 0 ;
+ else if (c>9)
+ c = 9 ;
+ set_pdf_compress_level(c);
+ }
+ return 0 ;
+}
+
+static int l_set_obj_compress_level(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_obj_compress_level(c);
+ }
+ 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)
+{
+ lua_pushinteger(L, (pdf_gen_tounicode));
+ return 1 ;
+}
+
+static int getpdfomitcidset(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_omit_cidset));
+ return 1 ;
+}
+
+static int getpdfomitcharset(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_omit_charset));
+ return 1 ;
+}
+
+static int setpdfgentounicode(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_pdf_gen_tounicode(lua_tointeger(L, 1));
+ }
+ return 0 ;
+}
+
+static int setpdfomitcidset(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_pdf_omit_cidset(lua_tointeger(L, 1));
+ }
+ return 0 ;
+}
+
+static int setpdfomitcharset(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_pdf_omit_charset(lua_tointeger(L, 1));
+ }
+ 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)
+{
+ lua_pushinteger(L, (pdf_decimal_digits));
+ return 1 ;
+}
+
+static int l_set_decimal_digits(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ if (c<0) {
+ c = 0 ;
+ }
+ set_pdf_decimal_digits(c);
+ }
+ return 0 ;
+}
+
+/* pk */
+
+static int l_get_pk_resolution(lua_State * L)
+{
+ lua_pushinteger(L, (pdf_pk_resolution));
+ lua_pushinteger(L, (pdf_pk_fixed_dpi));
+ return 2 ;
+}
+
+static int l_set_pk_resolution(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ if (c < 72) {
+ c = 72 ;
+ } else if (c > 8000) {
+ c = 8000 ;
+ }
+ set_pdf_pk_resolution(c);
+ }
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ set_pdf_pk_fixed_dpi(lua_tointeger(L, 1));
+ }
+ return 0 ;
+}
+
+/* pdf stuff */
+
+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_init_font(static_pdf,c);
+ }
+ set_ff(c);
+ lua_pushinteger(L, (obj_info(static_pdf, pdf_font_num(ff))));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1 ;
+}
+
+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_init_font(static_pdf,c);
+ }
+ set_ff(c);
+ lua_pushinteger(L, (pdf_font_num(ff)));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1 ;
+}
+
+static int getpdffontsize(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ lua_pushinteger(L, (font_size(c)));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1 ;
+}
+
+static int getpdfpageref(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ 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) {
+ int c = (int) lua_tointeger(L, 1);
+ check_obj_type(static_pdf, obj_type_xform, c);
+ lua_pushinteger(L, (obj_info(static_pdf, c)));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1 ;
+}
+
+static int getpdfcreationdate(lua_State * L)
+{
+ initialize_start_time(static_pdf);
+ lua_pushstring(L,static_pdf->start_time_str);
+ return 1 ;
+}
+
+static int getpdfmajorversion(lua_State * L)
+{
+ /* lua_pushinteger(L,static_pdf->major_version); */
+ lua_pushinteger(L,pdf_major_version);
+ return 1 ;
+}
+
+static int setpdfmajorversion(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ if ((c >= 1) && (c <= 2)) {
+ static_pdf->major_version = c;
+ set_pdf_major_version(c);
+ }
+ }
+ return 0 ;
+}
+
+static int getpdfminorversion(lua_State * L)
+{
+ /* lua_pushinteger(L,static_pdf->minor_version); */
+ lua_pushinteger(L,pdf_minor_version);
+ return 1 ;
+}
+
+static int setpdfminorversion(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ int c = (int) lua_tointeger(L, 1);
+ if ((c >= 0) && (c <= 9)) {
+ static_pdf->minor_version = c;
+ set_pdf_minor_version(c);
+ }
+ }
+ return 0 ;
+}
+
+static int setpdforigin(lua_State * L)
+{
+ int h = 0 ;
+ int v = 0 ;
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ h = (int) lua_roundnumber(L, 1);
+ if (lua_type(L, 2) == LUA_TNUMBER) {
+ v = (int) lua_roundnumber(L, 1);
+ } else {
+ v = h;
+ }
+ }
+ set_tex_extension_dimen_register(d_pdf_h_origin,h);
+ set_tex_extension_dimen_register(d_pdf_v_origin,v);
+ return 0 ;
+}
+
+static int getpdforigin(lua_State * L)
+{
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_h_origin));
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_v_origin));
+ return 2 ;
+}
+
+static int setpdfimageresolution(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_count_register(c_pdf_image_resolution,lua_tointeger(L, 1));
+ }
+ return 0;
+}
+
+static int getpdfimageresolution(lua_State * L)
+{
+ lua_pushinteger(L,get_tex_extension_count_register(c_pdf_image_resolution));
+ return 1 ;
+}
+
+static int setpdfthreadmargin(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_dimen_register(d_pdf_thread_margin,lua_roundnumber(L, 1));
+ }
+ return 0;
+}
+
+static int setpdfdestmargin(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_dimen_register(d_pdf_dest_margin,lua_roundnumber(L, 1));
+ }
+ return 0;
+}
+
+static int setpdflinkmargin(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_dimen_register(d_pdf_link_margin,lua_roundnumber(L, 1));
+ }
+ return 0;
+}
+
+static int setpdfxformmargin(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_dimen_register(d_pdf_xform_margin,lua_roundnumber(L, 1));
+ }
+ return 0;
+}
+
+static int getpdfthreadmargin(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_thread_margin));
+ return 1;
+}
+
+static int getpdfdestmargin(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_dest_margin));
+ return 1;
+}
+
+static int getpdflinkmargin(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_link_margin));
+ return 1;
+}
+
+static int getpdfxformmargin(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_dimen_register(d_pdf_xform_margin));
+ return 1;
+}
+
+static int setpdfinclusionerrorlevel(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_count_register(c_pdf_inclusion_errorlevel,lua_tointeger(L, 1));
+ }
+ return 0;
+}
+
+static int setpdfignoreunknownimages(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_count_register(c_pdf_ignore_unknown_images,lua_tointeger(L, 1));
+ }
+ return 0;
+}
+
+static int getpdfinclusionerrorlevel(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_count_register(c_pdf_inclusion_errorlevel));
+ return 1;
+}
+
+static int getpdfignoreunknownimages(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_count_register(c_pdf_ignore_unknown_images));
+ return 1;
+}
+
+ static int l_set_suppress_optional_info(lua_State * L) {
+ if (lua_type(L, 1) == LUA_TNUMBER) {
+ set_tex_extension_count_register(c_pdf_suppress_optional_info,lua_tointeger(L, 1));
+ }
+ return 0;
+}
+
+static int l_get_suppress_optional_info(lua_State * L) {
+ lua_pushinteger(L,get_tex_extension_count_register(c_pdf_suppress_optional_info));
+ return 1;
+}
+
+static int newpdfcolorstack(lua_State * L)
+{
+ const char *s = NULL;
+ const char *l = NULL;
+ int literal_mode = 0; /* set_origin */
+ boolean page_start = false;
+ int id ;
+ if (lua_type(L,1) != LUA_TSTRING) {
+ luaL_error(L, "pdf.newcolorstack() expects a string as first argument");
+ }
+ s = lua_tostring(L, 1);
+ if (lua_type(L,2) == LUA_TSTRING) {
+ l = lua_tostring(L, 2);
+ if (lua_key_eq(l,origin)) {
+ literal_mode = set_origin;
+ } else if (lua_key_eq(l,page)) {
+ literal_mode = direct_page;
+ } else if (lua_key_eq(l,text)) {
+ literal_mode = direct_text;
+ } else if (lua_key_eq(l,direct)) {
+ literal_mode = direct_always;
+ } else if (lua_key_eq(l,raw)) {
+ literal_mode = direct_raw;
+ } else {
+ luaL_error(L, "invalid literal mode in pdf.newcolorstack()");
+ }
+ }
+ if (lua_isboolean(L, 3)) {
+ page_start = lua_toboolean(L, 3);
+ }
+ id = newcolorstack(s, literal_mode, page_start);
+ lua_pushinteger(L, id);
+ return 1 ;
+}
+
+
+static int l_set_font_attributes(lua_State * L)
+{
+ int f = luaL_checkinteger(L, -2);
+ int i ;
+ /*char *s;*/
+ const char *st;
+ if ((lua_type(L,-1) == LUA_TSTRING) && (st = lua_tostring(L, -1)) != NULL) {
+ /* is this dup needed? */
+ /*s = xstrdup(st);*/
+ i = maketexstring(st); /* brrr */
+ set_pdf_font_attr(f, i);
+ /*free(s);*/
+ }
+ 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
+
+ The following option is not official and needs testing anyway. It's a
+ prelude a followup where the dependencies are limited.
+
+*/
+
+static int settypeonewidemode(lua_State * L)
+{
+ t1_wide_mode = lua_tointeger(L,1);
+ return 0;
+}
+
+/*tex For normal output see |pdflistout.c|: */
+
+static const struct luaL_Reg pdflib[] = {
+ { "gethpos", l_gethpos },
+ { "getvpos", l_getvpos },
+ { "obj", l_obj },
+ { "immediateobj", l_immediateobj },
+ { "refobj", l_refobj },
+ { "registerannot", l_registerannot },
+ { "reserveobj", l_reserveobj },
+ { "getpos", l_getpos },
+ { "getpageref", getpdfpageref },
+ { "getmaxobjnum", getpdfmaxobjnum },
+ { "print", luapdfprint },
+ { "getobjtype", getpdfobjtype },
+ { "getmatrix", l_getmatrix },
+ { "hasmatrix", l_hasmatrix },
+ { "setfontattributes", l_set_font_attributes },
+ { "setcatalog", l_set_catalog },
+ { "setinfo", l_set_info },
+ { "setnames", l_set_names },
+ { "settrailer", l_set_trailer },
+ { "setpageresources", l_set_pageresources },
+ { "setpageattributes", l_set_pageattributes },
+ { "setpagesattributes", l_set_pagesattributes },
+ { "setxformresources", l_set_xformresources },
+ { "setxformattributes", l_set_xformattributes },
+ { "settrailerid", l_set_trailerid },
+ { "getcatalog", l_get_catalog },
+ { "getinfo", l_get_info },
+ { "getnames", l_get_names },
+ { "gettrailer", l_get_trailer },
+ { "getpageresources", l_get_pageresources },
+ { "getpageattributes", l_get_pageattributes },
+ { "getpagesattributes", l_get_pagesattributes },
+ { "getxformresources", l_get_xformresources },
+ { "getxformattributes", l_get_xformattributes },
+ { "gettrailerid", l_get_trailerid },
+ { "getlastlink", l_get_lastlink },
+ { "getretval", l_get_retval },
+ { "getlastobj", l_get_lastobj },
+ { "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 },
+ { "getfontname", getpdffontname },
+ { "getfontobjnum", getpdffontobjnum },
+ { "getfontsize", getpdffontsize },
+ { "getxformname", getpdfxformname },
+ { "getcreationdate", getpdfcreationdate },
+ { "getmajorversion", getpdfmajorversion },
+ { "setmajorversion", setpdfmajorversion },
+ { "getminorversion", getpdfminorversion },
+ { "setminorversion", setpdfminorversion },
+ { "newcolorstack", newpdfcolorstack },
+ { "setorigin", setpdforigin },
+ { "getorigin", getpdforigin },
+ { "setimageresolution", setpdfimageresolution },
+ { "getimageresolution", getpdfimageresolution },
+ { "setthreadmargin", setpdfthreadmargin },
+ { "setdestmargin", setpdfdestmargin },
+ { "setlinkmargin", setpdflinkmargin },
+ { "setxformmargin", setpdfxformmargin },
+ { "getthreadmargin", getpdfthreadmargin },
+ { "getdestmargin", getpdfdestmargin },
+ { "getlinkmargin", getpdflinkmargin },
+ { "getxformmargin", getpdfxformmargin },
+ { "getinclusionerrorlevel", getpdfinclusionerrorlevel },
+ { "getignoreunknownimages", getpdfignoreunknownimages },
+ { "getgentounicode", getpdfgentounicode },
+ { "getomitcidset", getpdfomitcidset },
+ { "getomitcharset", getpdfomitcharset },
+ { "setinclusionerrorlevel", setpdfinclusionerrorlevel },
+ { "setignoreunknownimages", setpdfignoreunknownimages },
+ { "setgentounicode", setpdfgentounicode },
+ { "setomitcidset", setpdfomitcidset },
+ { "setomitcharset", setpdfomitcharset },
+ { "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 },
+ /* experimental */
+ { "settypeonewidemode", settypeonewidemode},
+ /* sentinel */
+ {NULL, NULL}
+};
+
+int luaopen_pdf(lua_State * L)
+{
+ lua_pushstring(L,"pdf.data");
+ lua_newtable(L);
+ lua_settable(L,LUA_REGISTRYINDEX);
+ /* */
+ luaL_openlib(L, "pdf", pdflib, 0);
+ /*
+ luaL_newmetatable(L, "pdf.meta");
+ lua_pushstring(L, "__index");
+ lua_pushcfunction(L, getpdf);
+ lua_settable(L, -3);
+ lua_pushstring(L, "__newindex");
+ lua_pushcfunction(L, setpdf);
+ lua_settable(L, -3);
+ lua_setmetatable(L, -2);
+ */
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
new file mode 100644
index 00000000000..90e7da58bf0
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lpdfscannerlib.c
@@ -0,0 +1,1110 @@
+/* lpdfscannerlib.c
+
+ Copyright 2013 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+ The scanner can read from a string or stream. Streams can be given directly as
+ |ppstream| object or as a |pparray| of streams. Here is an example of usage:
+
+ \starttyping
+ local operatortable = { }
+
+ operatortable.Do = function(scanner,info)
+ local resources = info.resources
+ if resources then
+ local val = scanner:pop()
+ local name = val[2]
+ local xobject = resources.XObject
+ print(info.space .. "Uses XObject " .. name)
+ local resources = xobject.Resources
+ if resources then
+ local newinfo = {
+ space = info.space .. " ",
+ resources = resources,
+ }
+ pdfscanner.scan(entry, operatortable, newinfo)
+ end
+ end
+ end
+
+ local function Analyze(filename)
+ local doc = pdfe.open(filename)
+ if doc then
+ local pages = doc.Pages
+ for i=1,#pages do
+ local page = pages[i]
+ local info = {
+ space = " " ,
+ resources = page.Resources,
+ }
+ print("Page " .. i)
+ pdfscanner.scan(page.Contents,operatortable,info)
+ pdfscanner.scan(page.Contents(),operatortable,info)
+ end
+ end
+ end
+
+ Analyze("foo.pdf")
+ \stoptyping
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#include "pplib.h"
+
+#include <lua/luatex-api.h>
+
+#define SCANNER "pdfscanner"
+
+#define MAXOPERANDS 1000
+
+typedef enum {
+ pdf_integer = 1,
+ pdf_real,
+ pdf_boolean,
+ pdf_name,
+ pdf_operator,
+ pdf_string,
+ pdf_startarray,
+ pdf_stoparray,
+ pdf_startdict,
+ pdf_stopdict,
+} pdf_token_type;
+
+typedef struct Token {
+ pdf_token_type type;
+ double value;
+ char *string;
+} Token;
+
+typedef struct ObjectList {
+ struct ObjectList *next;
+ ppstream *stream;
+} ObjectList;
+
+typedef struct scannerdata {
+ int _ininlineimage;
+ int _nextoperand;
+ Token **_operandstack;
+ ppstream *_stream;
+ ObjectList *_streams;
+ const char *buffer;
+ size_t position;
+ size_t size;
+ int uses_stream;
+} scannerdata;
+
+#define PDFE_METATABLE_ARRAY "luatex.pdfe.array"
+#define PDFE_METATABLE_STREAM "luatex.pdfe.stream"
+
+typedef struct {
+ void *d;
+ /*tex reference to |PdfDocument|, or |NULL| */
+ void *pd;
+ /*tex counter to detect |PDFDoc| change */
+ unsigned long pc;
+} udstruct;
+
+static void clear_operand_stack(scannerdata * self, int from);
+static Token *_parseToken(scannerdata * self, int c);
+static void push_token(lua_State * L, scannerdata * self);
+
+static void *priv_xmalloc(size_t size)
+{
+ void *new_mem = (void *) malloc(size);
+ if (new_mem == NULL) {
+ luaL_error(Luas, "no room for <pdfscanned> stream");
+ }
+ return new_mem;
+}
+
+static void *priv_xrealloc(void *old_ptr, size_t size)
+{
+ void *new_mem = (void *) realloc(old_ptr, size);
+ if (new_mem == NULL) {
+ luaL_error(Luas, "no room for <pdfscanned> stream");
+ }
+ return new_mem;
+}
+
+#define xreallocarray(ptr,type,size) ((type*)priv_xrealloc(ptr,(size+1)*sizeof(type)))
+
+#define INITBUFSIZE 64
+
+#define define_buffer(a) \
+ char *a = (char *)priv_xmalloc (INITBUFSIZE); \
+ int a##_size = INITBUFSIZE; \
+ int a##index = 0; \
+ memset (a,0,INITBUFSIZE)
+
+#define check_overflow(a, wsize) do { \
+ if (wsize >= a##_size) { \
+ int nsize = a##_size + a##_size / 4; \
+ a = (char *) xreallocarray(a, char, (unsigned) nsize); \
+ memset (a+a##_size, 0, a##_size / 4); \
+ a##_size = nsize; \
+ } \
+} while (0)
+
+
+static scannerdata *scanner_push(lua_State * L)
+{
+ scannerdata *a = (scannerdata *) lua_newuserdata(L, sizeof(scannerdata));
+ luaL_getmetatable(L, SCANNER);
+ lua_setmetatable(L, -2);
+ return a;
+}
+
+static scannerdata *scanner_check(lua_State * L, int index)
+{
+ scannerdata *bar;
+ luaL_checktype(L, index, LUA_TUSERDATA);
+ bar = (scannerdata *) luaL_checkudata(L, index, SCANNER);
+ if (bar == NULL)
+ luaL_argerror(L, index, SCANNER " expected");
+ return bar;
+}
+
+static void free_token(Token * token)
+{
+ if (token->string) {
+ free(token->string);
+ }
+ free(token);
+}
+
+static void clear_operand_stack(scannerdata * self, int from)
+{
+ int i = self->_nextoperand - 1;
+ while (i >= from) {
+ if (self->_operandstack[i]) {
+ free_token(self->_operandstack[i]);
+ self->_operandstack[i] = NULL;
+ }
+ i--;
+ }
+ self->_nextoperand = from;
+}
+
+static void push_operand(scannerdata * self, Token * token)
+{
+ if (self->_nextoperand + 1 > MAXOPERANDS) {
+ fprintf(stderr, "out of operand stack space");
+ exit(1);
+ }
+ self->_operandstack[self->_nextoperand++] = token;
+}
+
+static Token *new_operand(pdf_token_type c)
+{
+ Token *token = (Token *) priv_xmalloc(sizeof(Token));
+ memset(token, 0, sizeof(Token));
+ token->type = c;
+ return token;
+}
+
+static void _nextStream(scannerdata * self)
+{
+ ObjectList *rover = NULL;
+ if (self->uses_stream && self->buffer != NULL) {
+ if (self->uses_stream) {
+ ppstream_done(self->_stream);
+ } else {
+ free(self->_stream);
+ }
+ }
+ rover = self->_streams;
+ self->_stream = rover->stream;
+ if (self->uses_stream) {
+ self->buffer = (const char *) ppstream_all(self->_stream, &self->size, 1);
+ }
+ self->position = 0;
+ self->_streams = rover->next;
+ free(rover);
+}
+
+static int streamGetChar(scannerdata * self)
+{
+ int i = EOF;
+ if (self->position < self->size) {
+ const char c = self->buffer[self->position];
+ ++self->position;
+ i = (int) c;
+ }
+ if (i < 0 && self->_streams) {
+ _nextStream(self);
+ i = streamGetChar(self);
+ }
+ return i;
+}
+
+static int streamLookChar(scannerdata * self)
+{
+ int i = EOF;
+ if (self->position < self->size) {
+ const char c = self->buffer[self->position];
+ /*not |++self->position;| */
+ i = (int) c;
+ }
+ if (i < 0 && self->_streams) {
+ _nextStream(self);
+ i = streamGetChar(self);
+ }
+ return i;
+}
+
+static void streamReset(scannerdata * self)
+{
+ if (self->uses_stream) {
+ self->buffer = (const char *) ppstream_all(self->_stream, &self->size, 1);
+ }
+ self->position = 0;
+}
+
+static void streamClose(scannerdata * self)
+{
+ if (self->uses_stream) {
+ ppstream_done(self->_stream);
+ } else {
+ free(self->_stream);
+ }
+ self->buffer = NULL;
+ self->_stream = NULL;
+}
+
+/*tex end of stream interface */
+
+static Token *_parseSpace(scannerdata * self)
+{
+ return _parseToken(self, streamGetChar(self));
+}
+
+static Token *_parseString(scannerdata * self, int c)
+{
+ int level;
+ Token *token = NULL;
+ define_buffer(found);
+ level = 1;
+ while (1) {
+ c = streamGetChar(self);
+ if (c == '(') {
+ level = level + 1;
+ } else if (c == ')') {
+ level = level - 1;
+ if (level < 1)
+ break;
+ } else if (c == '\\') {
+ int next = streamGetChar(self);
+ if (next == '(' || next == ')' || next == '\\') {
+ c = next;
+ } else if (next == '\n' || next == '\r') {
+ c = '\0';
+ } else if (next == 'n') {
+ c = '\n';
+ } else if (next == 'r') {
+ c = '\r';
+ } else if (next == 't') {
+ c = '\t';
+ } else if (next == 'b') {
+ c = '\b';
+ } else if (next == 'f') {
+ c = '\f';
+ } else if (next >= '0' && next <= '7') {
+ int next2;
+ next = next - '0';
+ next2 = streamLookChar(self);
+ if (next2 >= '0' && next2 <= '7') {
+ int next3;
+ next2 = streamGetChar(self);
+ next2 = next2 - '0';
+ next3 = streamLookChar(self);
+ if (next3 >= '0' && next3 <= '7') {
+ next3 = streamGetChar(self);
+ next3 = next3 - '0';
+ c = (next * 64 + next2 * 8 + next3);
+ } else {
+ c = (next * 8 + next2);
+ }
+ } else {
+ c = next;
+ }
+ } else {
+ c = next;
+ }
+ }
+ check_overflow(found, foundindex);
+ if (c >= 0) {
+ found[foundindex++] = c;
+ }
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+static Token *_parseNumber(scannerdata * self, int c)
+{
+ double value = 0;
+ pdf_token_type type = pdf_integer;
+ int isfraction = 0;
+ int isnegative = 0;
+ int i = 0;
+ Token *token = NULL;
+ if (c == '-') {
+ isnegative = 1;
+ c = streamGetChar(self);
+ }
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ value = c - '0';
+ }
+ c = streamLookChar(self);
+ if ((c >= '0' && c <= '9') || c == '.') {
+ c = streamGetChar(self);
+ while (1) {
+ if (c == '.') {
+ type = pdf_real;
+ isfraction = 1;
+ } else {
+ i = c - '0';
+ if (isfraction > 0) {
+ value = value + (i / (pow(10.0, isfraction)));
+ isfraction = isfraction + 1;
+ } else {
+ value = (value * 10) + i;
+ }
+ }
+ c = streamLookChar(self);
+ if (!((c >= '0' && c <= '9') || c == '.'))
+ break;
+ c = streamGetChar(self);
+ }
+ }
+ if (isnegative) {
+ value = -value;
+ }
+ token = new_operand(type);
+ token->value = value;
+ return token;
+}
+
+static Token *_parseName(scannerdata * self, int c)
+{
+ Token *token = NULL;
+ define_buffer(found);
+ c = streamGetChar(self);
+ while (1) {
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<')
+ break;
+ c = streamGetChar(self);
+ }
+ token = new_operand(pdf_name);
+ token->string = found;
+ token->value = strlen(found);
+ return token;
+}
+
+#define hexdigit(c) \
+ (c>= '0' && c<= '9') ? (c - '0') : ((c>= 'A' && c<= 'F') ? (c - 'A' + 10) : (c - 'a' + 10))
+
+static Token *_parseHexstring(scannerdata * self, int c)
+{
+ int isodd = 1;
+ int hexval = 0;
+ Token *token = NULL;
+ define_buffer(found);
+ while (c != '>') {
+ if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
+ if (isodd == 1) {
+ int v = hexdigit(c);
+ hexval = 16 * v;
+ } else {
+ hexval += hexdigit(c);
+ check_overflow(found, foundindex);
+ found[foundindex++] = hexval;
+ }
+ isodd = (isodd == 1 ? 0 : 1);
+ }
+ c = streamGetChar(self);
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+#define pdf_isspace(a) (a == '\0' || a == ' ' || a == '\n' || a == '\r' || a == '\t' || a == '\v')
+
+/*tex this is rather horrible */
+
+static Token *_parseInlineImage(scannerdata * self, int c)
+{
+ Token *token = NULL;
+ define_buffer(found);
+ if (c == ' ') {
+ /*tex first space can be ignored */
+ c = streamGetChar(self);
+ }
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ while (1) {
+ c = streamLookChar(self);
+ if (c == 'E'
+ && (found[foundindex - 1] == '\n'
+ || found[foundindex - 1] == '\r')) {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (c == 'I') {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if (pdf_isspace(c)) {
+ /*tex |I| */
+ found[--foundindex] = '\0';
+ /*tex |E| */
+ found[--foundindex] = '\0';
+ /*tex remove end-of-line before |EI| */
+ if (found[foundindex - 1] == '\n') {
+ found[--foundindex] = '\0';
+ }
+ if (found[foundindex - 1] == '\r') {
+ found[--foundindex] = '\0';
+ }
+ break;
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ } else {
+ c = streamGetChar(self);
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ }
+ }
+ token = new_operand(pdf_string);
+ token->value = foundindex;
+ token->string = found;
+ return token;
+}
+
+static Token *_parseOperator(scannerdata * self, int c)
+{
+ define_buffer(found);
+ while (1) {
+ check_overflow(found, foundindex);
+ found[foundindex++] = c;
+ c = streamLookChar(self);
+ if ((c < 0) || (c == ' ' || c == '\n' || c == '\r' || c == '\t' ||
+ c == '/' || c == '[' || c == '(' || c == '<'))
+ break;
+ c = streamGetChar(self);
+ }
+ /*tex |print| (found) */
+ if (strcmp(found, "ID") == 0) {
+ self->_ininlineimage = 1;
+ }
+ if (strcmp(found, "false") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 0;
+ free(found);
+ return token;
+ } else if (strcmp(found, "true") == 0) {
+ Token *token = new_operand(pdf_boolean);
+ token->value = 1.0;
+ free(found);
+ return token;
+ } else {
+ Token *token = new_operand(pdf_operator);
+ token->string = found;
+ return token;
+ }
+}
+
+static Token *_parseComment(scannerdata * self, int c)
+{
+ do {
+ c = streamGetChar(self);
+ } while (c != '\n' && c != '\r' && c != -1);
+ return _parseToken(self, streamGetChar(self));
+}
+
+static Token *_parseLt(scannerdata * self, int c)
+{
+ c = streamGetChar(self);
+ if (c == '<') {
+ return new_operand(pdf_startdict);
+ } else {
+ return _parseHexstring(self, c);
+ }
+}
+
+static Token *_parseGt(scannerdata * self, int c)
+{
+ c = streamGetChar(self);
+ if (c == '>') {
+ return new_operand(pdf_stopdict);
+ } else {
+ fprintf(stderr, "stray > in stream");
+ return NULL;
+ }
+}
+
+static Token *_parseError(int c)
+{
+ fprintf(stderr, "stray %c [%d] in stream", c, c);
+ return NULL;
+}
+
+static Token *_parseStartarray(void)
+{
+ return new_operand(pdf_startarray);
+}
+
+static Token *_parseStoparray(void)
+{
+ return new_operand(pdf_stoparray);
+}
+
+static Token *_parseToken(scannerdata * self, int c)
+{
+ if (self->_ininlineimage == 1) {
+ self->_ininlineimage = 2;
+ return _parseInlineImage(self, c);
+ } else if (self->_ininlineimage == 2) {
+ Token *token = NULL;
+ self->_ininlineimage = 0;
+ token = new_operand(pdf_operator);
+ token->string = strdup("EI");
+ return token;
+ }
+ if (c < 0)
+ return NULL;
+ switch (c) {
+ case '(':
+ return _parseString(self, c);
+ break;
+ case ')':
+ return _parseError(c);
+ break;
+ case '[':
+ return _parseStartarray();
+ break;
+ case ']':
+ return _parseStoparray();
+ break;
+ case '/':
+ return _parseName(self, c);
+ break;
+ case '<':
+ return _parseLt(self, c);
+ break;
+ case '>':
+ return _parseGt(self, c);
+ break;
+ case '%':
+ return _parseComment(self, c);
+ break;
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ return _parseSpace(self);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ case '.':
+ return _parseNumber(self, c);
+ break;
+ default:
+ if (c <= 127) {
+ return _parseOperator(self, c);
+ } else {
+ return _parseError(c);
+ }
+ }
+}
+
+static int scanner_scan(lua_State * L)
+{
+ Token *token;
+ scannerdata *self;
+ if (lua_gettop(L) != 3) {
+ return 0;
+ }
+ luaL_checktype(L, 2, LUA_TTABLE);
+ luaL_checktype(L, 3, LUA_TTABLE);
+ self = scanner_push(L);
+ memset(self, 0, sizeof(scannerdata));
+ self->_operandstack = (Token **) priv_xmalloc(MAXOPERANDS * sizeof(Token));
+ memset(self->_operandstack, 0, (MAXOPERANDS * sizeof(Token)));
+ /*tex stack slot 4 = self */
+ self->uses_stream = 1;
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ /*tex
+ We could make a temporary copy on the stack (or in the registry)
+ which saves memory.
+ */
+ char *buf = NULL;
+ const char *s = lua_tolstring(L, 1, &self->size);
+ if (s==NULL){
+ fprintf(stderr,"fatal: cannot convert the token to string.");
+ exit(1);
+ }
+ buf = priv_xmalloc(self->size+1);
+ buf[self->size]='\0';
+ self->uses_stream = 0;
+ memcpy(buf,s,self->size);
+ self->buffer = buf;
+ } else if (lua_type(L, 1) == LUA_TTABLE) {
+ udstruct *uin;
+ void *ud;
+ int i = 1;
+ while (1) {
+ lua_rawgeti(L, 1, i);
+ if (lua_type(L, -1) == LUA_TUSERDATA) {
+ ud = luaL_checkudata(L, -1, PDFE_METATABLE_STREAM);
+ if (ud != NULL) {
+ ObjectList *rover = NULL;
+ ObjectList *item = NULL;
+ uin = (udstruct *) ud;
+ rover = self->_streams;
+ item = (ObjectList *) priv_xmalloc(sizeof(ObjectList));
+ item->stream = ((ppstream *) uin->d);
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ } else {
+ ObjectList *rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ free(rover);
+ lua_pop(L, 1);
+ break;
+ }
+ lua_pop(L, 1);
+ i++;
+ }
+ } else {
+ udstruct *uin;
+ void *ud;
+ luaL_checktype(L, 1, LUA_TUSERDATA);
+ ud = luaL_checkudata(L, 1, PDFE_METATABLE_STREAM);
+ if (ud != NULL) {
+ uin = (udstruct *) ud;
+ self->_stream = ((ppstream *) uin->d);
+ } else {
+ ud = luaL_checkudata(L, 1, PDFE_METATABLE_ARRAY);
+ if (ud != NULL) {
+ ObjectList *rover = NULL;
+ pparray *array = NULL;
+ int count;
+ int i;
+ uin = (udstruct *) ud;
+ array = (pparray *) uin->d;
+ count = array->size;
+ for (i = 0; i < count; i++) {
+ ppobj *obj = pparray_at(array, i);
+ if (obj->type == PPSTREAM) {
+ ObjectList *rover = self->_streams;
+ ObjectList *item =
+ (ObjectList *)
+ priv_xmalloc(sizeof(ObjectList));
+ item->stream = obj->stream;
+ item->next = NULL;
+ if (!rover) {
+ rover = item;
+ self->_streams = rover;
+ } else {
+ while (rover->next)
+ rover = rover->next;
+ rover->next = item;
+ }
+ }
+ }
+ rover = self->_streams;
+ self->_stream = rover->stream;
+ self->_streams = rover->next;
+ }
+ }
+ }
+ streamReset(self);
+ token = _parseToken(self, streamGetChar(self));
+ while (token) {
+ if (token->type == pdf_operator) {
+ lua_pushstring(L, token->string);
+ free_token(token);
+ /*tex fetch operator table */
+ lua_rawget(L, 2);
+ if (lua_isfunction(L, -1)) {
+ lua_pushvalue(L, 4);
+ lua_pushvalue(L, 3);
+ (void) lua_call(L, 2, 0);
+ } else {
+ /*tex nil */
+ lua_pop(L, 1);
+ }
+ clear_operand_stack(self, 0);
+ } else {
+ push_operand(self, token);
+ }
+ if (self->uses_stream) {
+ if (!self->_stream) {
+ break;
+ }
+ } else {
+ if (self->buffer == NULL) {
+ break;
+ }
+ }
+ token = _parseToken(self, streamGetChar(self));
+ }
+ /*tex wrap up */
+ if (self->_stream) {
+ streamClose(self);
+ }
+ clear_operand_stack(self, 0);
+ free(self->_operandstack);
+ return 0;
+}
+
+static int scanner_done(lua_State * L)
+{
+ int c;
+ scannerdata *self = scanner_check(L, 1);
+ while ((c = streamGetChar(self)) >= 0);
+ return 0;
+}
+
+/*tex here are the stack popping functions, and their helpers */
+
+static void operandstack_backup(scannerdata * self)
+{
+ int i = self->_nextoperand - 1;
+ int balance = 0;
+ int backupstart = 0;
+ int backupstop = self->_operandstack[i]->type;
+ if (backupstop == pdf_stopdict) {
+ backupstart = pdf_startdict;
+ } else if (backupstop == pdf_stoparray) {
+ backupstart = pdf_startarray;
+ } else {
+ return;
+ }
+ for (; i >= 0; i--) {
+ if (self->_operandstack[i]->type == backupstop) {
+ balance++;
+ } else if (self->_operandstack[i]->type == backupstart) {
+ balance--;
+ }
+ if (balance == 0) {
+ break;
+ }
+ }
+ self->_nextoperand = i + 1;
+}
+
+static void push_array(lua_State * L, scannerdata * self)
+{
+ /*tex nesting tracking */
+ int balance = 1;
+ /*tex \LUA\ array index */
+ int index = 1;
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stoparray)
+ balance--;
+ if (token->type == pdf_startarray)
+ balance++;
+ if (!balance) {
+ break;
+ } else {
+ push_token(L, self);
+ lua_rawseti(L, -2, index++);
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+
+static void push_dict(lua_State * L, scannerdata * self)
+{
+ /*tex nesting tracking */
+ int balance = 1;
+ /*tex toggle between \LUA\ value and \LUA\ key */
+ int needskey = 1;
+ Token *token = self->_operandstack[self->_nextoperand++];
+ lua_newtable(L);
+ while (token) {
+ if (token->type == pdf_stopdict)
+ balance--;
+ if (token->type == pdf_startdict)
+ balance++;
+ if (!balance) {
+ break;
+ } else if (needskey) {
+ lua_pushlstring(L, token->string, token->value);
+ needskey = 0;
+ } else {
+ push_token(L, self);
+ needskey = 1;
+ lua_rawset(L, -3);
+ }
+ token = self->_operandstack[self->_nextoperand++];
+ }
+}
+
+const char *typenames[pdf_stopdict + 1] = {
+ "unknown", "integer", "real", "boolean", "name", "operator",
+ "string", "array", "array", "dict", "dict"
+};
+
+static void push_token(lua_State * L, scannerdata * self)
+{
+ Token *token = self->_operandstack[self->_nextoperand - 1];
+ lua_createtable(L, 2, 0);
+ lua_pushstring(L, typenames[token->type]);
+ lua_rawseti(L, -2, 1);
+ if (token->type == pdf_string || token->type == pdf_name) {
+ lua_pushlstring(L, token->string, token->value);
+ } else if (token->type == pdf_real || token->type == pdf_integer) {
+ /*tex This is an integer or float. */
+ lua_pushnumber(L, token->value);
+ } else if (token->type == pdf_boolean) {
+ lua_pushboolean(L, (int) token->value);
+ } else if (token->type == pdf_startarray) {
+ push_array(L, self);
+ } else if (token->type == pdf_startdict) {
+ push_dict(L, self);
+ } else {
+ lua_pushnil(L);
+ }
+ lua_rawseti(L, -2, 2);
+}
+
+static int scanner_popsingular(lua_State * L, int token_type)
+{
+ Token *token = NULL;
+ /*tex this keeps track of how much of the operand stack needs deleting: */
+ int clear = 0;
+ scannerdata *self = scanner_check(L, 1);
+ if (self->_nextoperand == 0) {
+ return 0;
+ }
+ clear = self->_nextoperand - 1;
+ token = self->_operandstack[self->_nextoperand - 1];
+ if (token == NULL || (token->type != token_type)) {
+ return 0;
+ }
+ /*tex
+ The simple cases can be written out directly, but dicts and
+ arrays are better done via the recursive function.
+ */
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand - 1;
+ push_token(L, self);
+ lua_rawgeti(L, -1, 2);
+ } else if (token_type == pdf_real || token_type == pdf_integer) {
+ /*tex the number can be an integer or float */
+ lua_pushnumber(L, token->value);
+ } else if (token_type == pdf_boolean) {
+ lua_pushboolean(L, (int) token->value);
+ } else if (token_type == pdf_name || token_type == pdf_string) {
+ lua_pushlstring(L, token->string, token->value);
+ } else {
+ return 0;
+ }
+ clear_operand_stack(self, clear);
+ return 1;
+}
+
+static int scanner_popanything(lua_State * L)
+{
+ Token *token = NULL;
+ /*tex how much of the operand stack needs deleting: */
+ int clear = 0;
+ int token_type;
+ scannerdata *self = scanner_check(L, 1);
+ if (self->_nextoperand == 0) {
+ return 0;
+ }
+ clear = self->_nextoperand - 1;
+ token = self->_operandstack[self->_nextoperand - 1];
+ if (token == NULL) {
+ return 0;
+ }
+ token_type = token->type;
+ /*tex
+ The simple cases can be written out directly, but dicts and
+ arrays are better done via the recursive function.
+ */
+ if (token_type == pdf_stoparray || token_type == pdf_stopdict) {
+ operandstack_backup(self);
+ clear = self->_nextoperand - 1;
+ push_token(L, self);
+ } else {
+ push_token(L, self);
+ }
+ clear_operand_stack(self, clear);
+ return 1;
+}
+
+static int scanner_popnumber(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_real))
+ return 1;
+ if (scanner_popsingular(L, pdf_integer))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popboolean(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_boolean))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popstring(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_string))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popname(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_name))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_poparray(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_stoparray))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popdictionary(lua_State * L)
+{
+ if (scanner_popsingular(L, pdf_stopdict))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static int scanner_popany(lua_State * L)
+{
+ if (scanner_popanything(L))
+ return 1;
+ lua_pushnil(L);
+ return 1;
+}
+
+static const luaL_Reg scannerlib_meta[] = {
+ {0, 0}
+};
+
+static const struct luaL_Reg scannerlib_m[] = {
+ { "done", scanner_done },
+ { "pop", scanner_popany },
+ { "popnumber", scanner_popnumber },
+ { "popname", scanner_popname },
+ { "popstring", scanner_popstring },
+ { "poparray", scanner_poparray },
+ { "popdictionary", scanner_popdictionary },
+ { "popboolean", scanner_popboolean },
+ /*tex For old times sake: */
+ { "popNumber", scanner_popnumber },
+ { "popName", scanner_popname },
+ { "popString", scanner_popstring },
+ { "popArray", scanner_poparray },
+ { "popDict", scanner_popdictionary },
+ { "popBool", scanner_popboolean },
+ /*tex Sentinel: */
+ { NULL, NULL }
+};
+
+static const luaL_Reg scannerlib[] = {
+ { "scan", scanner_scan },
+ /*tex Sentinel: */
+ { NULL, NULL }
+};
+
+LUALIB_API int luaopen_pdfscanner(lua_State * L)
+{
+ luaL_newmetatable(L, SCANNER);
+ luaL_openlib(L, 0, scannerlib_meta, 0);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_openlib(L, NULL, scannerlib_m, 0);
+ luaL_openlib(L, "pdfscanner", scannerlib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lstatslib.c b/Build/source/texk/web2c/luatexdir/lua/lstatslib.c
new file mode 100644
index 00000000000..5f3b72262c6
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lstatslib.c
@@ -0,0 +1,527 @@
+/* lstatslib.c
+
+ Copyright 2006-2011 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#include "luatex_svnversion.h"
+
+typedef struct statistic {
+ const char *name;
+ char type;
+ void *value;
+} statistic;
+
+typedef const char *(*charfunc) (void);
+typedef lua_Number(*numfunc) (void);
+typedef int (*intfunc) (void);
+
+static const char *getbanner(void)
+{
+ return (const char *) luatex_banner;
+}
+
+static const char *getlogname(void)
+{
+ return (const char *) texmf_log_name;
+}
+
+static const char *get_output_file_name(void)
+{
+ if (static_pdf != NULL)
+ return (const char *) static_pdf->file_name;
+ return NULL;
+}
+
+/*
+static const char *getfilename(void)
+{
+ int t = 0;
+ int level = in_open;
+ while ((level > 0)) {
+ t = input_stack[level--].name_field;
+ if (t >= STRING_OFFSET) {
+ return (const char *) str_string(t);
+ }
+ }
+ return "";
+}
+*/
+
+static const char *getfilename(void)
+{
+ const char * s;
+ int level, t;
+ level = in_open;
+ while ((level > 0)) {
+ s = full_source_filename_stack[level--];
+ if (s != NULL) {
+ return s;
+ }
+ }
+ /* old method */
+ level = in_open;
+ while ((level > 0)) {
+ t = input_stack[level--].name_field;
+ if (t >= STRING_OFFSET) {
+ return (const char *) str_string(t);
+ }
+ }
+ return "";
+}
+
+
+static const char *getlasterror(void)
+{
+ return last_error;
+}
+
+static const char *getlastluaerror(void)
+{
+ return last_lua_error;
+}
+
+static const char *getlastwarningtag(void)
+{
+ return last_warning_tag;
+}
+
+static const char *getlastwarningstr(void)
+{
+ return last_warning_str;
+}
+
+static const char *getlasterrorcontext(void)
+{
+ return last_error_context;
+}
+
+static const char *luatexrevision(void)
+{
+ return (const char *) (strrchr(luatex_version_string, '.') + 1);
+}
+
+static const char *getenginename(void)
+{
+ return engine_name;
+}
+
+static const char * get_lc_ctype(void)
+{
+ return lc_ctype;
+}
+
+static const char * get_lc_collate(void)
+{
+ return lc_collate;
+}
+
+static const char * get_lc_numeric(void)
+{
+ return lc_numeric;
+}
+
+
+
+static lua_Number get_luatexhashchars(void)
+{
+ return (lua_Number) LUAI_HASHLIMIT;
+}
+
+static const char *get_luatexhashtype(void)
+{
+#ifdef LuajitTeX
+ 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)
+ return (lua_Number) static_pdf->gone;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_pdf_ptr(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) (static_pdf->buf->p - static_pdf->buf->data);
+ return (lua_Number) 0;
+}
+
+static lua_Number get_pdf_os_cntr(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->os->ostm_ctr;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_pdf_os_objidx(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->os->idx;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_pdf_mem_size(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->mem_size;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_pdf_mem_ptr(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->mem_ptr;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_obj_ptr(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->obj_ptr;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_obj_tab_size(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->obj_tab_size;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_dest_names_size(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->dest_names_size;
+ return (lua_Number) 0;
+}
+
+static lua_Number get_dest_names_ptr(void)
+{
+ if (static_pdf != NULL)
+ return (lua_Number) static_pdf->dest_names_ptr;
+ return (lua_Number) 0;
+}
+
+static int get_hash_size(void)
+{
+ return hash_size; /* is a #define */
+}
+
+static lua_Number shell_escape_state(void)
+{
+ if (shellenabledp <= 0) {
+ /* No shell at all. */
+ return (lua_Number) 0;
+ } else if (restrictedshell == 0) {
+ /* Shell has no restriction. */
+ return (lua_Number) 1;
+ } else {
+ /* Shell has restrictions, see cnf file. */
+ return (lua_Number) 2;
+ }
+}
+
+static lua_Number safer_option_state(void)
+{
+ if (safer_option == 0) {
+ return (lua_Number) 0;
+ } else {
+ return (lua_Number) 1;
+ }
+}
+
+static lua_Number kpse_used_state(void)
+{
+ if (kpse_init == 1) {
+ return (lua_Number) 1;
+ } else {
+ return (lua_Number) 0;
+ }
+}
+
+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[] = {
+
+ /* most likely accessed */
+
+ {"output_active", 'b', &output_active},
+ {"best_page_break", 'n', &best_page_break},
+
+ {"filename", 'S', (void *) &getfilename},
+ {"inputid", 'g', &(iname)},
+ {"linenumber", 'g', &line},
+
+ {"lasterrorstring", 'S', (void *) &getlasterror},
+ {"lastluaerrorstring", 'S', (void *) &getlastluaerror},
+ {"lastwarningtag", 'S', (void *) &getlastwarningtag},
+ {"lastwarningstring", 'S', (void *) &getlastwarningstr},
+ {"lasterrorcontext", 'S', (void *) &getlasterrorcontext},
+
+ /* seldom or never accessed */
+
+ {"pdf_gone", 'N', &get_pdf_gone},
+ {"pdf_ptr", 'N', &get_pdf_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},
+ {"banner", 'S', (void *) &getbanner},
+ {"luatex_version", 'G', &get_luatexversion},
+ {"luatex_revision", 'S', (void *) &luatexrevision},
+ {"development_id", 'N', &get_development_id},
+ {"luatex_hashtype", 'S', (void *) &get_luatexhashtype},
+ {"luatex_hashchars", 'N', &get_luatexhashchars},
+ {"luatex_engine", 'S', (void *) &getenginename},
+
+ {"ini_version", 'b', &ini_version},
+
+ {"shell_escape", 'N', &shell_escape_state},
+ {"safer_option", 'N', &safer_option_state},
+ {"kpse_used", 'N', &kpse_used_state},
+ /*
+ * mem stat
+ */
+ {"var_used", 'g', &var_used},
+ {"dyn_used", 'g', &dyn_used},
+ /*
+ * traditional tex stats
+ */
+ {"str_ptr", 'g', &str_ptr},
+ {"init_str_ptr", 'g', &init_str_ptr},
+ {"max_strings", 'g', &max_strings},
+ {"pool_ptr", 'g', &pool_size},
+ {"init_pool_ptr", 'g', &init_pool_ptr},
+ {"pool_size", 'g', &pool_size},
+ {"var_mem_max", 'g', &var_mem_max},
+ {"node_mem_usage", 'S', &sprint_node_mem_usage},
+ {"fix_mem_max", 'g', &fix_mem_max},
+ {"fix_mem_min", 'g', &fix_mem_min},
+ {"fix_mem_end", 'g', &fix_mem_end},
+ {"cs_count", 'g', &cs_count},
+ {"hash_size", 'G', &get_hash_size},
+ {"hash_extra", 'g', &hash_extra},
+ {"font_ptr", 'G', &max_font_id},
+ {"max_in_stack", 'g', &max_in_stack},
+ {"max_nest_stack", 'g', &max_nest_stack},
+ {"max_param_stack", 'g', &max_param_stack},
+ {"max_buf_stack", 'g', &max_buf_stack},
+ {"max_save_stack", 'g', &max_save_stack},
+ {"stack_size", 'g', &stack_size},
+ {"nest_size", 'g', &nest_size},
+ {"param_size", 'g', &param_size},
+ {"buf_size", 'g', &buf_size},
+ {"save_size", 'g', &save_size},
+ {"input_ptr", 'g', &input_ptr},
+ {"obj_ptr", 'N', &get_obj_ptr},
+ {"obj_tab_size", 'N', &get_obj_tab_size},
+ {"pdf_os_cntr", 'N', &get_pdf_os_cntr},
+ {"pdf_os_objidx", 'N', &get_pdf_os_objidx},
+ {"pdf_dest_names_ptr", 'N', &get_dest_names_ptr},
+ {"dest_names_size", 'N', &get_dest_names_size},
+ {"pdf_mem_ptr", 'N', &get_pdf_mem_ptr},
+ {"pdf_mem_size", 'N', &get_pdf_mem_size},
+ {"largest_used_mark", 'g', &biggest_used_mark},
+ {"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 */
+
+ {"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},
+ {"lc_numeric",'S', (void *) &get_lc_numeric},
+
+ {NULL, 0, 0}
+};
+
+static int stats_name_to_id(const char *name)
+{
+ int i;
+ for (i = 0; stats[i].name != NULL; i++) {
+ if (strcmp(stats[i].name, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+static int do_getstat(lua_State * L, int i)
+{
+ int t;
+ const char *st;
+ charfunc f;
+ intfunc g;
+ numfunc n;
+ int str;
+ t = stats[i].type;
+ switch (t) {
+ case 'S':
+ f = stats[i].value;
+ st = f();
+ lua_pushstring(L, st);
+ break;
+ case 's':
+ str = *(int *) (stats[i].value);
+ if (str) {
+ char *ss = makecstring(str);
+ lua_pushstring(L, ss);
+ free(ss);
+ } else {
+ lua_pushnil(L);
+ }
+ break;
+ case 'N':
+ n = stats[i].value;
+ lua_pushinteger(L, n());
+ break;
+ case 'G':
+ g = stats[i].value;
+ lua_pushinteger(L, g());
+ break;
+ case 'g':
+ lua_pushinteger(L, *(int *) (stats[i].value));
+ break;
+ case 'B':
+ g = stats[i].value;
+ lua_pushboolean(L, g());
+ break;
+ case 'n':
+ if (*(halfword *) (stats[i].value) != 0)
+ lua_nodelib_push_fast(L, *(halfword *) (stats[i].value));
+ else
+ lua_pushnil(L);
+ break;
+ case 'b':
+ lua_pushboolean(L, *(int *) (stats[i].value));
+ break;
+ default:
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int getstats(lua_State * L)
+{
+ const char *st;
+ int i;
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ st = lua_tostring(L, -1);
+ i = stats_name_to_id(st);
+ if (i >= 0) {
+ return do_getstat(L, i);
+ }
+ }
+ return 0;
+}
+
+static int setstats(lua_State * L)
+{
+ (void) L;
+ return 0;
+}
+
+static int statslist(lua_State * L)
+{
+ int i;
+ luaL_checkstack(L, 1, "out of stack space");
+ lua_newtable(L);
+ for (i = 0; stats[i].name != NULL; i++) {
+ luaL_checkstack(L, 2, "out of stack space");
+ lua_pushstring(L, stats[i].name);
+ do_getstat(L, i);
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
+static int resetmessages(lua_State * L)
+{
+ xfree(last_warning_str);
+ xfree(last_warning_tag);
+ xfree(last_error);
+ xfree(last_lua_error);
+ last_warning_str = NULL;
+ last_warning_tag = NULL;
+ last_error = NULL;
+ last_lua_error = NULL;
+ return 0;
+}
+
+static int setexitcode(lua_State * L) {
+ defaultexitcode = luaL_checkinteger(L,1);
+ return 0;
+}
+
+static const struct luaL_Reg statslib[] = {
+ {"list", statslist},
+ {"resetmessages", resetmessages},
+ {"setexitcode", setexitcode},
+ {NULL, NULL} /* sentinel */
+};
+
+int luaopen_stats(lua_State * L)
+{
+ luaL_openlib(L, "status", statslib, 0);
+ luaL_newmetatable(L, "tex.stats");
+ lua_pushstring(L, "__index");
+ lua_pushcfunction(L, getstats);
+ lua_settable(L, -3);
+ lua_pushstring(L, "__newindex");
+ lua_pushcfunction(L, setstats);
+ lua_settable(L, -3);
+ lua_setmetatable(L, -2); /* meta to itself */
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/lstrlibext.c b/Build/source/texk/web2c/luatexdir/lua/lstrlibext.c
new file mode 100644
index 00000000000..50c7235ee55
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/lstrlibext.c
@@ -0,0 +1,525 @@
+/* lstrlibext.c
+
+ Copyright 2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+/* The relative ordering of the header files is important here,
+ otherwise some of the defines that are needed for lua_sdump
+ come out wrong.
+ */
+#include "ptexlib.h"
+
+#define LUA_CORE
+#include "lua.h"
+#ifdef LuajitTeX
+#include "lauxlib.h"
+#include "lualib.h"
+#else
+#include "luaconf.h"
+#include "lapi.h"
+#include "lundump.h"
+#endif
+
+static int bytepairs_aux (lua_State *L) {
+ size_t ls;
+ unsigned char i;
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+ if (ind<(int)ls) {
+ if (ind+1<(int)ls) {
+ lua_pushinteger(L, (ind+2)); /* iterator */
+ } else {
+ lua_pushinteger(L, (ind+1)); /* iterator */
+ }
+ lua_replace(L, lua_upvalueindex(2));
+ i = (unsigned char)*(s+ind);
+ lua_pushinteger(L, i); /* byte one */
+ if (ind+1<(int)ls) {
+ i = (unsigned char)*(s+ind+1);
+ lua_pushinteger(L, i); /* byte two */
+ } else {
+ lua_pushnil(L); /* odd string length */
+ }
+ return 2;
+ }
+ return 0; /* string ended */
+}
+
+static int str_bytepairs (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, bytepairs_aux, 2);
+ return 1;
+}
+
+static int bytes_aux (lua_State *L) {
+ size_t ls;
+ unsigned char i;
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+ if (ind<(int)ls) {
+ lua_pushinteger(L, (ind+1)); /* iterator */
+ lua_replace(L, lua_upvalueindex(2));
+ i = (unsigned char)*(s+ind);
+ lua_pushinteger(L, i); /* byte */
+ return 1;
+ }
+ return 0; /* string ended */
+}
+
+static int str_bytes (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, bytes_aux, 2);
+ return 1;
+}
+
+static int utf_failed(lua_State *L, int new_ind) {
+ static char fffd [3] = {0xEF,0xBF,0xBD};
+ lua_pushinteger(L, new_ind); /* iterator */
+ lua_replace(L, lua_upvalueindex(2));
+ lua_pushlstring(L, fffd, 3);
+ return 1;
+}
+
+static int utfcharacters_aux (lua_State *L) {
+ static const unsigned char mask[4] = {0x80,0xE0,0xF0,0xF8};
+ static const unsigned char mequ[4] = {0x00,0xC0,0xE0,0xF0};
+ size_t ls;
+ unsigned char c;
+ int j;
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+ if (ind>=(int)ls) return 0; /* end of string */
+ c = (unsigned) s[ind];
+ for (j=0;j<4;j++) {
+ if ((c&mask[j])==mequ[j]) {
+ int k;
+ if (ind+1+j>(int)ls) return utf_failed(L,ls); /* will not fit */
+ for (k=1; k<=j; k++) {
+ c = (unsigned) s[ind+k];
+ if ((c&0xC0)!=0x80) return utf_failed(L,ind+k); /* bad follow */
+ }
+ lua_pushinteger(L, ind+1+j); /* iterator */
+ lua_replace(L, lua_upvalueindex(2));
+ lua_pushlstring(L, s+ind, 1+j);
+ return 1;
+ }
+ }
+ return utf_failed(L,ind+1); /* we found a follow byte! */
+}
+
+static int str_utfcharacters (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, utfcharacters_aux, 2);
+ return 1;
+}
+
+static int utfvalues_aux (lua_State *L) {
+ size_t ls;
+ unsigned char i = 0;
+ unsigned char j = 0;
+ unsigned char k = 0;
+ unsigned char l = 0;
+ unsigned int v = 0xFFFD;
+ int numbytes = 1;
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+
+ if (ind<(int)ls) {
+ i = *(s+ind);
+ if (i<0x80) {
+ v = i;
+ } else if (i>=0xF0) {
+ if ((ind+3)<(int)ls && ((unsigned)*(s+ind+1))>=0x80
+ && ((unsigned)*(s+ind+2))>=0x80 && ((unsigned)*(s+ind+3))>=0x80) {
+ numbytes = 4;
+ j = ((unsigned)*(s+ind+1))-128;
+ k = ((unsigned)*(s+ind+2))-128;
+ l = ((unsigned)*(s+ind+3))-128;
+ v = (((((i-0xF0)*64) + j)*64) + k)*64 + l;
+ }
+ } else if (i>=0xE0) {
+ if ((ind+2)<(int)ls && ((unsigned)*(s+ind+1))>=0x80 && ((unsigned)*(s+ind+2))>=0x80) {
+ numbytes = 3;
+ j = ((unsigned)*(s+ind+1))-128;
+ k = ((unsigned)*(s+ind+2))-128;
+ v = (((i-0xE0)*64) + j)*64 + k;
+ }
+
+ } else if (i>=0xC0) {
+ if ((ind+1)<(int)ls && ((unsigned)*(s+ind+1))>=0x80) {
+ numbytes = 2;
+ j = ((unsigned)*(s+ind+1))-128;
+ v = ((i-0xC0)*64) + j;
+ }
+ }
+ lua_pushinteger(L, (ind+numbytes)); /* iterator */
+ lua_replace(L, lua_upvalueindex(2));
+ lua_pushinteger(L, v);
+ return 1;
+ }
+ return 0; /* string ended */
+}
+
+static int str_utfvalues (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, utfvalues_aux, 2);
+ return 1;
+}
+
+static int characterpairs_aux (lua_State *L) {
+ size_t ls;
+ char b[2];
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+ if (ind<(int)ls) {
+ if (ind+1<(int)ls) {
+ lua_pushinteger(L, (ind+2)); /* iterator */
+ } else {
+ lua_pushinteger(L, (ind+1)); /* iterator */
+ }
+ lua_replace(L, lua_upvalueindex(2));
+ b[0] = *(s+ind); b[1] = 0;
+ lua_pushlstring(L, b, 1);
+ if (ind+1<(int)ls) {
+ b[0] = *(s+ind+1);
+ lua_pushlstring(L, b, 1);
+ } else {
+ lua_pushlstring(L, b+1, 0);
+ }
+ return 2;
+ }
+ return 0; /* string ended */
+}
+
+static int str_characterpairs (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, characterpairs_aux, 2);
+ return 1;
+}
+
+static int characters_aux (lua_State *L) {
+ size_t ls;
+ char b[2];
+ const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
+ int ind = lua_tointeger(L, lua_upvalueindex(2));
+ if (ind<(int)ls) {
+ lua_pushinteger(L, (ind+1)); /* iterator */
+ lua_replace(L, lua_upvalueindex(2));
+ b[0] = *(s+ind); b[1] = 0;
+ lua_pushlstring(L, b, 1);
+ return 1;
+ }
+ return 0; /* string ended */
+}
+
+static int str_characters (lua_State *L) {
+ luaL_checkstring(L, 1);
+ lua_settop(L, 1);
+ lua_pushinteger(L, 0);
+ lua_pushcclosure(L, characters_aux, 2);
+ return 1;
+}
+
+static int str_split (lua_State *L) {
+ size_t l;
+ size_t i;
+ int n;
+ char *q, *p, *orig;
+ int mult = 0;
+ const char *s = luaL_checklstring(L, 1, &l);
+ const char *joiner = luaL_optstring(L, 2, " +");
+ lua_newtable(L);
+ if (l == 0) {
+ lua_pushvalue(L,1);
+ lua_rawseti(L,-2,1);
+ return 1;
+ }
+ orig = p = malloc(l+1);
+ if (p==NULL) {
+ fprintf(stderr, "fatal: memory exhausted (malloc of %u bytes).\n",(int)(l+1));
+ exit(EXIT_FAILURE);
+ }
+ strcpy(p,s);
+ n = 1;
+ q = p;
+
+ if (*joiner == 0) {
+ for (i=0;i<l;i++) {
+ lua_pushlstring(L,q,1); q++;
+ lua_rawseti(L,-2,n); n++;
+ }
+ free(orig);
+ return 1;
+ }
+ if (*(joiner+1) == '+') {
+ mult = 1;
+ while(*p==*joiner) {
+ p++;
+ l--;
+ }
+ q = p;
+ }
+ for (i=0;i<l;i++) {
+ if (*(p+i)==*joiner) {
+ *(p+i) = 0;
+ lua_pushlstring(L,q,((p+i)-q));
+ lua_rawseti(L,-2,n); n++;
+ if (mult) {
+ while(*(p+i+1)==*joiner) {
+ i++;
+ }
+ }
+ q = p+i+1;
+ }
+ }
+ if (mult && q==(p+l)) {
+ free(orig);
+ return 1;
+ }
+ if(q<=(p+l)) {
+ lua_pushlstring(L,q,strlen(q));
+ lua_rawseti(L,-2,n);
+ }
+ free(orig);
+ return 1;
+}
+
+#ifdef LuajitTeX
+ /* dump is built in */
+#else
+#if (LUA_VERSION_NUM == 502)
+static int writer (lua_State *L, const void* b, size_t size, void* B) {
+ (void)L;
+ luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
+ return 0;
+}
+
+static int lua_sdump (lua_State *L, lua_Writer writer, void *data, int stripping) {
+ int status;
+ TValue *o;
+ lua_lock(L);
+ api_checknelems(L, 1);
+ o = L->top - 1;
+ if (isLfunction(o))
+ status = luaU_dump(L, getproto(o), writer, data, stripping);
+ else
+ status = 1;
+ lua_unlock(L);
+ return status;
+}
+
+
+static int str_dump (lua_State *L) {
+ luaL_Buffer b;
+ int stripping = 0;
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (lua_gettop(L)==2) {
+ stripping = lua_toboolean(L,2);
+ }
+ lua_settop(L, 1);
+ luaL_buffinit(L,&b);
+ if (lua_sdump(L, writer, &b, stripping) != 0)
+ return luaL_error(L, "unable to dump given function");
+ luaL_pushresult(&b);
+ return 1;
+}
+#endif
+#endif /*ifdef LuajitTeX*/
+
+static int str_bytetable (lua_State *L) {
+ size_t l;
+ int i;
+ const char *s = luaL_checklstring(L, 1, &l);
+ lua_createtable(L,l,0);
+ for (i=0;i<l;i++) {
+ lua_pushinteger(L,(unsigned char)*(s+i));
+ lua_rawseti(L,-2,i+1);
+ }
+ return 1;
+}
+
+/*
+ We provide a few helpers that we derived from the lua utf8 module
+ and slunicode. That way we're sort of covering a decent mix.
+
+*/
+
+#define MAXUNICODE 0x10FFFF
+
+/*
+ This is a combination of slunicode and utf8 converters but without mode
+ and a bit faster on the average than the utf8 one.
+*/
+
+static void utf8_enco (luaL_Buffer *b, unsigned c)
+{
+ if (c > MAXUNICODE) {
+ /* we silently ignore the bad character */
+ return;
+ }
+ if (0x80 > c) {
+ luaL_addchar(b, c);
+ return;
+ }
+ if (0x800 > c)
+ luaL_addchar(b, 0xC0|(c>>6));
+ else {
+ if (0x10000 > c)
+ luaL_addchar(b, 0xE0|(c>>12));
+ else {
+ luaL_addchar(b, 0xF0|(c>>18));
+ luaL_addchar(b, 0x80|(0x3F&(c>>12)));
+ }
+ luaL_addchar(b, 0x80|(0x3F&(c>>6)));
+ }
+ luaL_addchar(b, 0x80|(0x3F&c));
+}
+
+static int str_character (lua_State *L) {
+ int n = lua_gettop(L); /* number of arguments */
+ int i;
+ luaL_Buffer b;
+ luaL_buffinit(L,&b);
+ for (i = 1; i <= n; i++) {
+ utf8_enco (&b, (unsigned) lua_tointeger(L, i));
+ }
+ luaL_pushresult(&b);
+ return 1;
+}
+
+/*
+ The utf8 codepoint function takes two arguments, being positions in the
+ string, while slunicode byte takes two arguments representing the number of
+ utf characters. The variant below always returns all codepoints.
+
+*/
+
+static int str_utfvalue (lua_State *L) {
+ size_t ls;
+ int ind = 0;
+ int num = 0;
+ const char *s = lua_tolstring(L, 1, &ls);
+ while (ind<(int)ls) {
+ unsigned char i = (unsigned)*(s+ind);
+ if (i<0x80) {
+ lua_pushinteger(L, i);
+ num += 1;
+ ind += 1;
+ } else if (i>=0xF0) {
+ if ((ind+3)<(int)ls && ((unsigned)*(s+ind+1))>=0x80 && ((unsigned)*(s+ind+2))>=0x80 && ((unsigned)*(s+ind+3))>=0x80) {
+ unsigned char j = ((unsigned)*(s+ind+1))-128;
+ unsigned char k = ((unsigned)*(s+ind+2))-128;
+ unsigned char l = ((unsigned)*(s+ind+3))-128;
+ lua_pushinteger(L, (((((i-0xF0)*64) + j)*64) + k)*64 + l);
+ num += 1;
+ }
+ ind += 4;
+ } else if (i>=0xE0) {
+ if ((ind+2)<(int)ls && ((unsigned)*(s+ind+1))>=0x80 && ((unsigned)*(s+ind+2))>=0x80) {
+ unsigned char j = ((unsigned)*(s+ind+1))-128;
+ unsigned char k = ((unsigned)*(s+ind+2))-128;
+ lua_pushinteger(L, (((i-0xE0)*64) + j)*64 + k);
+ num += 1;
+ }
+ ind += 3;
+ } else if (i>=0xC0) {
+ if ((ind+1)<(int)ls && ((unsigned)*(s+ind+1))>=0x80) {
+ unsigned char j = ((unsigned)*(s+ind+1))-128;
+ lua_pushinteger(L, ((i-0xC0)*64) + j);
+ num += 1;
+ }
+ ind += 2;
+ } else {
+ ind += 1;
+ }
+ }
+ return num;
+}
+
+/* This is a simplified version of utf8.len but without range. */
+
+static int str_utflength (lua_State *L) {
+ size_t ls;
+ int ind = 0;
+ int num = 0;
+ const char *s = lua_tolstring(L, 1, &ls);
+ while (ind<(int)ls) {
+ unsigned char i = (unsigned)*(s+ind);
+ if (i<0x80) {
+ ind += 1;
+ } else if (i>=0xF0) {
+ ind += 4;
+ } else if (i>=0xE0) {
+ ind += 3;
+ } else if (i>=0xC0) {
+ ind += 2;
+ } else {
+ /* bad news, stupid recovery */
+ ind += 1;
+ }
+ num += 1;
+ }
+ lua_pushinteger(L, num);
+ return 1;
+}
+
+/* end of convenience inclusion */
+
+static const luaL_Reg strlibext[] = {
+ {"utfvalues", str_utfvalues},
+ {"utfcharacters", str_utfcharacters},
+ {"characters", str_characters},
+ {"characterpairs", str_characterpairs},
+ {"bytes", str_bytes},
+ {"bytepairs", str_bytepairs},
+ {"bytetable", str_bytetable},
+ {"explode", str_split},
+ {"utfcharacter", str_character},
+ {"utfvalue", str_utfvalue},
+ {"utflength", str_utflength},
+#ifdef LuajitTeX
+ /* luajit has dump built in */
+#else
+/* lua 5.3.4 doesn't need this patch */
+#if (LUA_VERSION_NUM == 502)
+ {"dump", str_dump},
+#endif
+
+#endif /* #ifdef LuajitTeX */
+ {NULL, NULL}
+};
+
+void open_strlibext(lua_State * L)
+{
+ const luaL_Reg *lib;
+ lua_getglobal(L, "string");
+ for (lib=strlibext;lib->name;lib++) {
+ lua_pushcfunction(L, lib->func);
+ lua_setfield(L, -2, lib->name);
+ }
+ lua_pop(L,1);
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/ltexiolib.c b/Build/source/texk/web2c/luatexdir/lua/ltexiolib.c
new file mode 100644
index 00000000000..5f1786c65c0
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/ltexiolib.c
@@ -0,0 +1,185 @@
+/* ltexiolib.c
+
+ Copyright 2006-2010 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+typedef void (*texio_printer) (const char *);
+
+static char *loggable_info = NULL;
+
+static boolean get_selector_value(lua_State * L, int i, int *l)
+{
+ boolean r = false;
+ int t = lua_type(L,i);
+ if (t == LUA_TSTRING) {
+ const char *s = lua_tostring(L, i);
+ if (lua_key_eq(s,term_and_log)) {
+ *l = term_and_log;
+ r = true;
+ } else if (lua_key_eq(s,log)) {
+ *l = log_only;
+ r = true;
+ } else if (lua_key_eq(s,term)) {
+ *l = term_only;
+ r = true;
+ } else {
+ *l = term_and_log;
+ r = true;
+ }
+ } else if (t == LUA_TNUMBER) {
+ int n = lua_tointeger(L,i);
+ if (file_can_be_written(n)) {
+ *l = n;
+ r = true;
+ } else {
+ *l = term_and_log;
+ r = true;
+ }
+ } else {
+ luaL_error(L, "first argument is not 'term and log', 'term', 'log' or a number");
+ }
+ return r;
+}
+
+static int do_texio_print(lua_State * L, texio_printer printfunction)
+{
+ const char *s;
+ int i = 1;
+ int save_selector = selector;
+ int n = lua_gettop(L);
+ if (n == 0 || !lua_isstring(L, -1)) { /* or number */
+ luaL_error(L, "no string to print"); /* or number */
+ }
+ if (n > 1) {
+ if (get_selector_value(L, i, &selector))
+ i++;
+ }
+ if (selector != term_and_log && selector != log_only && selector != term_only) {
+ if (! valid_write_file(selector)) {
+ normalize_selector(); /* sets selector */
+ }
+ }
+ for (; i <= n; i++) {
+ if (lua_isstring(L, i)) { /* or number */
+ s = lua_tostring(L, i);
+ printfunction(s);
+ } else {
+ luaL_error(L, "argument is not a string");
+ }
+ }
+ selector = save_selector;
+ return 0;
+}
+
+static void do_texio_ini_print(lua_State * L, const char *extra)
+{
+ const char *s;
+ int i = 1;
+ int l = term_and_log;
+ int n = lua_gettop(L);
+ if (n > 1) {
+ if (get_selector_value(L, i, &l))
+ i++;
+ }
+ for (; i <= n; i++) {
+ if (lua_isstring(L, i)) { /* or number */
+ s = lua_tostring(L, i);
+ if (l == term_and_log || l == term_only)
+ fprintf(stdout, "%s%s", extra, s);
+ if (l == log_only || l == term_and_log) {
+ if (loggable_info == NULL) {
+ loggable_info = strdup(s);
+ } else {
+ char *v = concat3(loggable_info, extra, s);
+ free(loggable_info);
+ loggable_info = v;
+ }
+ }
+ }
+ }
+}
+
+static int texio_print(lua_State * L)
+{
+ if (ready_already != 314159 || job_name == 0) {
+ do_texio_ini_print(L, "");
+ return 0;
+ }
+ return do_texio_print(L, tprint);
+}
+
+static int texio_printnl(lua_State * L)
+{
+ if (ready_already != 314159 || job_name == 0) {
+ do_texio_ini_print(L, "\n");
+ return 0;
+ }
+ return do_texio_print(L, tprint_nl);
+}
+
+/* at the point this function is called, the selector is log_only */
+
+void flush_loggable_info(void)
+{
+ if (loggable_info != NULL) {
+ fprintf(log_file, "%s\n", loggable_info);
+ free(loggable_info);
+ loggable_info = NULL;
+ }
+}
+
+static int texio_setescape(lua_State * L)
+{
+ if (lua_type(L, 1) == LUA_TBOOLEAN) {
+ escape_controls = lua_toboolean(L,1);
+ } else {
+ escape_controls = lua_tointeger(L,1);
+ }
+ 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}
+};
+
+int luaopen_texio(lua_State * L)
+{
+ luaL_openlib(L, "texio", texiolib, 0);
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/ltexlib.c b/Build/source/texk/web2c/luatexdir/lua/ltexlib.c
new file mode 100644
index 00000000000..6e19e0727bc
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/ltexlib.c
@@ -0,0 +1,3739 @@
+/* ltexlib.c
+
+ Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+/* hh-ls: Because the lists start with a temp node, we have to set the prev link
+to nil because otherwise at the lua end we expose temp which can create havoc. In the
+setter no prev link is created so we can presume that it's not used later on. */
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+/* tex random generators */
+extern int unif_rand(int );
+extern int norm_rand(void );
+extern void init_randoms(int );
+
+typedef struct {
+ char *text;
+ unsigned int tsize;
+ void *next;
+ boolean partial;
+ int cattable;
+ halfword tok;
+ halfword nod;
+} rope;
+
+typedef struct {
+ rope *head;
+ rope *tail;
+ char complete; /* currently still writing ? */
+} spindle;
+
+#define PARTIAL_LINE 1
+#define FULL_LINE 0
+
+#define write_spindle spindles[spindle_index]
+#define read_spindle spindles[(spindle_index-1)]
+
+static int spindle_size = 0;
+static spindle *spindles = NULL;
+static int spindle_index = 0;
+
+static int luac_store(lua_State * L, int i, int partial, int cattable)
+{
+ char *st = NULL;
+ size_t tsize = 0;
+ rope *rn = NULL;
+ 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 {
+ return 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)
+{
+ int cattable = deftable;
+ int startstrings = 1;
+ int n = lua_gettop(L);
+ if (cattable != NO_CAT_TABLE) {
+ if (lua_type(L, 1) == LUA_TNUMBER && n > 1) {
+ cattable = lua_tointeger(L, 1);
+ startstrings = 2;
+ if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
+ cattable = DEFAULT_CAT_TABLE;
+ }
+ }
+ }
+ if (lua_type(L, startstrings) == LUA_TTABLE) {
+ int i;
+ for (i = 1;; i++) {
+ lua_rawgeti(L, startstrings, i);
+ 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++) {
+ luac_store(L, i, partial, cattable);
+ }
+ }
+ 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 */
+ int cattable = lua_tointeger(L,1);
+ if (cattable < 0 || cattable > 15) {
+ cattable = - 12 - 0xFF ;
+ } else {
+ cattable = - cattable - 0xFF;
+ }
+ if (lua_type(L, 2) == LUA_TTABLE) {
+ int i;
+ for (i = 1;; i++) {
+ lua_rawgeti(L, 2, i);
+ if (luac_store(L, -1, PARTIAL_LINE, cattable)) {
+ lua_pop(L, 1);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ } else {
+ int i;
+ int n = lua_gettop(L);
+ for (i = 2; i <= n; i++) {
+ luac_store(L, i, PARTIAL_LINE, cattable);
+ }
+ }
+ return 0;
+}
+
+/* lua.tprint */
+
+static int luactprint(lua_State * L)
+{
+ int i, j;
+ int cattable, startstrings;
+ int n = lua_gettop(L);
+ for (i = 1; i <= n; i++) {
+ cattable = DEFAULT_CAT_TABLE;
+ startstrings = 1;
+ if (lua_type(L, i) != LUA_TTABLE) {
+ luaL_error(L, "no string to print");
+ }
+ lua_pushvalue(L, i); /* push the table */
+ lua_pushinteger(L, 1);
+ lua_gettable(L, -2);
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ cattable = lua_tointeger(L, -1);
+ startstrings = 2;
+ if (cattable != -1 && cattable != -2 && !valid_catcode_table(cattable)) {
+ cattable = DEFAULT_CAT_TABLE;
+ }
+ }
+ lua_pop(L, 1);
+ for (j = startstrings;; j++) {
+ lua_pushinteger(L, j);
+ lua_gettable(L, -2);
+ 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 */
+ }
+ return 0;
+}
+
+int luacstring_cattable(void)
+{
+ return (int) read_spindle.tail->cattable;
+}
+
+int luacstring_partial(void)
+{
+ return read_spindle.tail->partial;
+}
+
+int luacstring_final_line(void)
+{
+ return (read_spindle.tail->next == NULL);
+}
+
+int luacstring_input(halfword *n)
+{
+ rope *t = read_spindle.head;
+ int ret = 1 ;
+ if (!read_spindle.complete) {
+ read_spindle.complete = 1;
+ read_spindle.tail = NULL;
+ }
+ if (t == NULL) {
+ if (read_spindle.tail != NULL)
+ free(read_spindle.tail);
+ read_spindle.tail = NULL;
+ return 0;
+ }
+ if (t->text != NULL) {
+ /* put that thing in the buffer */
+ char *st = t->text;
+ int ret = first;
+ last = first;
+ check_buffer_overflow(last + (int) t->tsize);
+ while (t->tsize-- > 0)
+ buffer[last++] = (packed_ASCII_code) * st++;
+ if (!t->partial) {
+ while (last - 1 > ret && buffer[last - 1] == ' ')
+ last--;
+ }
+ free(t->text);
+ t->text = NULL;
+ } else if (t->tok > 0) {
+ *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;
+ read_spindle.head = t->next;
+ return ret;
+}
+
+/* open for reading, and make a new one for writing */
+
+void luacstring_start(int n)
+{
+ (void) n; /* for -W */
+ spindle_index++;
+ 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;
+ spindles[spindle_index].complete = 0;
+ spindle_size++;
+ }
+}
+
+/* close for reading */
+
+void luacstring_close(int n)
+{
+ rope *next, *t;
+ (void) n; /* for -W */
+ next = read_spindle.head;
+ while (next != NULL) {
+ if (next->text != NULL)
+ free(next->text);
+ t = next;
+ next = next->next;
+ if (t==read_spindle.tail) {
+ read_spindle.tail = NULL;
+ }
+ free(t);
+ }
+ read_spindle.head = NULL;
+ if (read_spindle.tail != NULL)
+ free(read_spindle.tail);
+ read_spindle.tail = NULL;
+ read_spindle.complete = 0;
+ spindle_index--;
+}
+
+/* local (static) versions */
+
+#define check_index_range(j,s) \
+ if (j<0 || j > 65535) { \
+ luaL_error(L, "incorrect index specification for tex.%s()", s); }
+
+#define check_register(base) do { \
+ int k = get_item_index(L, lua_gettop(L), base); \
+ if ((k>=0) && (k <= 65535)) { \
+ lua_pushinteger(L,k); \
+ } else { \
+ lua_pushboolean(L,false); \
+ } \
+ return 1; \
+} while (1)
+
+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 */
+ s = ss;
+ do {
+ do {
+ c = *s++;
+ } while (c && c == ' ');
+ if (c == '-') {
+ negative = !negative;
+ c = '+';
+ }
+ } while (c == '+');
+ if (c == '\'') {
+ radix1 = 8;
+ m = 02000000000;
+ c = *s++;
+ } else if (c == '"') {
+ radix1 = 16;
+ m = 01000000000;
+ c = *s++;
+ }
+ /* Accumulate the constant until |cur_tok| is not a suitable digit */
+ while (1) {
+ if ((c < '0' + radix1) && (c >= '0') && (c <= '0' + 9)) {
+ d = c - '0';
+ } else if (radix1 == 16) {
+ if ((c <= 'A' + 5) && (c >= 'A')) {
+ d = c - 'A' + 10;
+ } else if ((c <= 'a' + 5) && (c >= 'a')) {
+ d = c - 'a' + 10;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ vacuous = false;
+ if ((val >= m) && ((val > m) || (d > 7) || (radix1 != 10))) {
+ if (OK_so_far) {
+ luaL_error(L, "Number too big");
+ val = infinity;
+ OK_so_far = false;
+ }
+ } else {
+ val = val * radix1 + d;
+ }
+ c = *s++;
+ }
+ if (vacuous) {
+ /* Express astonishment that no number was here */
+ luaL_error(L, "Missing number, treated as zero");
+ }
+ if (negative)
+ val = -val;
+ *ret = val;
+ *radix_ret = radix1;
+ if (c != ' ' && s > ss)
+ s--;
+ return s;
+}
+
+#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)
+{
+ boolean negative = false; /* should the answer be negated? */
+ int f = 0; /* numerator of a fraction whose denominator is $2^{16}$ */
+ int num, denom; /* conversion ratio for the scanned units */
+ int k; /* number of digits in a decimal fraction */
+ scaled v; /* an internal dimension */
+ 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 rdig[18]; /* to save the |dig[]| array */
+ int saved_tex_remainder; /* to save |tex_remainder| */
+ int saved_arith_error; /* to save |arith_error| */
+ int saved_cur_val; /* to save the global |cur_val| */
+ saved_tex_remainder = tex_remainder;
+ saved_arith_error = arith_error;
+ saved_cur_val = cur_val;
+ /* get the next non-blank non-sign */
+ do {
+ /* get the next non-blank non-call token */
+ do {
+ c = *s++;
+ } while (c && c == ' ');
+ if (c == '-') {
+ negative = !negative;
+ c = '+';
+ }
+ } while (c == '+');
+ if (c == ',') {
+ c = '.';
+ }
+ if (c != '.') {
+ s = scan_integer_part(L, (s > ss ? (s - 1) : ss), &cur_val, &radix1);
+ c = *s;
+ } else {
+ radix1 = 10;
+ cur_val = 0;
+ c = *(--s);
+ }
+ if (c == ',')
+ c = '.';
+ if ((radix1 == 10) && (c == '.')) {
+ /* scan decimal fraction */
+ for (k = 0; k < 18; k++)
+ rdig[k] = dig[k];
+ k = 0;
+ 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 */
+ dig[k++] = c - '0';
+ }
+ }
+ f = round_decimals(k);
+ if (c != ' ')
+ c = *(--s);
+ for (k = 0; k < 18; k++)
+ dig[k] = rdig[k];
+ }
+ if (cur_val < 0) { /* in this case |f=0| */
+ negative = !negative;
+ cur_val = -cur_val;
+ }
+ /*
+ 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 {
+ c = *s++;
+ } while (c && c == ' ');
+ if (c != ' ')
+ c = *(--s);
+ if (strncmp(s, "em", 2) == 0) {
+ s += 2;
+ v = (quad(get_cur_font()));
+ } else if (strncmp(s, "ex", 2) == 0) {
+ s += 2;
+ v = (x_height(get_cur_font()));
+ } else if (strncmp(s, "px", 2) == 0) {
+ s += 2;
+ v = px_dimen_par;
+ } else {
+ goto NOT_FOUND;
+ }
+ c = *s++;
+ if (c != ' ') {
+ c = *(--s);
+ }
+ cur_val = nx_plus_y(save_cur_val, v, xn_over_d(v, f, 0200000));
+ goto ATTACH_SIGN;
+ NOT_FOUND:
+ /* Scan for (m)\.{mu} units and |goto attach_fraction| */
+ if (strncmp(s, "mu", 2) == 0) {
+ s += 2;
+ goto ATTACH_FRACTION;
+ }
+ if (strncmp(s, "true", 4) == 0) {
+ /* Adjust (f)for the magnification ratio */
+ s += 4;
+ 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;
+ }
+ }
+ do {
+ c = *s++;
+ } while (c && c == ' ');
+ c = *(--s);
+ }
+ if (strncmp(s, "pt", 2) == 0) {
+ 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
+ */
+ if (strncmp(s, "mm", 2) == 0) {
+ s += 2;
+ set_conversion(7227, 2540);
+ } else if (strncmp(s, "cm", 2) == 0) {
+ s += 2;
+ set_conversion(7227, 254);
+ } else if (strncmp(s, "sp", 2) == 0) {
+ s += 2;
+ goto DONE;
+ } else if (strncmp(s, "bp", 2) == 0) {
+ s += 2;
+ set_conversion(7227, 7200);
+ } else if (strncmp(s, "in", 2) == 0) {
+ s += 2;
+ set_conversion(7227, 100);
+ } else if (strncmp(s, "dd", 2) == 0) {
+ s += 2;
+ set_conversion(1238, 1157);
+ } else if (strncmp(s, "cc", 2) == 0) {
+ s += 2;
+ set_conversion(14856, 1157);
+ } else if (strncmp(s, "pc", 2) == 0) {
+ s += 2;
+ set_conversion(12, 1);
+ } else if (strncmp(s, "nd", 2) == 0) {
+ s += 2;
+ set_conversion(685, 642);
+ } else if (strncmp(s, "nc", 2) == 0) {
+ s += 2;
+ set_conversion(1370, 107);
+ } else {
+ /* Complain about unknown unit and |goto done2| */
+ luaL_error(L, "Illegal unit of measure (pt inserted)");
+ goto DONE2;
+ }
+ 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;
+ DONE2:
+ ATTACH_FRACTION:
+ if (cur_val >= 040000)
+ arith_error = true;
+ else
+ cur_val = cur_val * 65536 + f;
+ DONE:
+ /* Scan an optional space */
+ c = *s++;
+ if (c != ' ')
+ s--;
+ ATTACH_SIGN:
+ if (arith_error || (abs(cur_val) >= 010000000000)) {
+ /* Report that this dimension is out of range */
+ luaL_error(L, "Dimension too large");
+ cur_val = max_dimen;
+ }
+ if (negative)
+ cur_val = -cur_val;
+ *ret = cur_val;
+ tex_remainder = saved_tex_remainder;
+ arith_error = saved_arith_error;
+ cur_val = saved_cur_val;
+ return s;
+}
+
+int dimen_to_number(lua_State * L, const char *s)
+{
+ int j = 0;
+ const char *d = scan_dimen_part(L, s, &j);
+ if (*d) {
+ luaL_error(L, "conversion failed (trailing junk?)");
+ j = 0;
+ }
+ return j;
+}
+
+static int tex_scaledimen(lua_State * L)
+{
+ int sp;
+ int t = lua_type(L, 1);
+ if (t == LUA_TNUMBER) {
+ sp = lua_roundnumber(L, 1);
+ } else if (t == LUA_TSTRING) {
+ sp = dimen_to_number(L, lua_tostring(L, 1));
+ } else {
+ luaL_error(L, "argument must be a string or a number");
+ return 0;
+ }
+ lua_pushinteger(L, sp);
+ return 1;
+}
+
+static int texerror (lua_State * L)
+{
+ const char **errhlp = NULL;
+ const char *error = luaL_checkstring(L,1);
+ int n = lua_gettop(L);
+ if (n==2 && lua_type(L, n) == LUA_TTABLE) {
+ int i;
+ int l = 1; /* |errhlp| is terminated by a NULL entry */
+ for (i = 1;; i++) {
+ lua_rawgeti(L, n, i);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ l++;
+ lua_pop(L, 1);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ }
+ if (l>1) {
+ errhlp = xmalloc(l * sizeof(char *));
+ memset(errhlp,0,l * sizeof(char *));
+ for (i = 1;; i++) {
+ lua_rawgeti(L, n, i);
+ if (lua_type(L,-1) == LUA_TSTRING) {
+ errhlp[(i-1)] = lua_tostring(L,-1);
+ lua_pop(L, 1);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ deletions_allowed = false;
+ tex_error(error, errhlp);
+ if (errhlp)
+ xfree(errhlp);
+ deletions_allowed = true;
+ return 0;
+}
+
+static int get_item_index(lua_State * L, int i, int base)
+{
+ size_t kk;
+ int k;
+ int cur_cs1;
+ const char *s;
+ switch (lua_type(L, i)) {
+ case LUA_TSTRING:
+ 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 */
+ else
+ k = (equiv(cur_cs1) - base);
+ break;
+ case LUA_TNUMBER:
+ k = luaL_checkinteger(L, i);
+ break;
+ default:
+ luaL_error(L, "argument must be a string or a number");
+ k = -1; /* not a valid index */
+ }
+ return k;
+}
+
+#define check_item_global(L,top,isglobal) \
+ if (top == 3 && (lua_type(L,1) == LUA_TSTRING)) { \
+ const char *s = lua_tostring(L, 1); \
+ if (lua_key_eq(s,global)) { \
+ isglobal = 1; \
+ } \
+ }
+
+#define set_item_index_plus(L, where, base, what, value, is_global, is_assign, set_register, glue) { \
+ size_t len; \
+ const char *str; \
+ int key, err, cs; \
+ int save_global_defs = global_defs_par; \
+ if (is_global) { \
+ global_defs_par = 1; \
+ } \
+ switch (lua_type(L, where)) { \
+ case LUA_TSTRING: \
+ str = lua_tolstring(L, where, &len); \
+ cs = string_lookup(str, len); \
+ if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
+ luaL_error(L, "incorrect %s name", what); \
+ } else { \
+ key = equiv(cs) - base; \
+ if (key >= 0 && key <= 65535) { \
+ err = set_register(key, value); \
+ if (err) { \
+ luaL_error(L, "incorrect %s value", what); \
+ } \
+ } else if (is_assign(eq_type(cs))) { \
+ if (glue) { \
+ int a = is_global; \
+ define(equiv(cs), assign_glue_cmd, value); \
+ } else { \
+ assign_internal_value((is_global ? 4 : 0), equiv(cs), value); \
+ } \
+ } else { \
+ luaL_error(L, "incorrect %s name", what); \
+ } \
+ } \
+ break; \
+ case LUA_TNUMBER: \
+ key = luaL_checkinteger(L, where); \
+ if (key>=0 && key <= 65535) { \
+ err = set_register(key, value); \
+ if (err) { \
+ luaL_error(L, "incorrect %s value", what); \
+ } \
+ } else { \
+ luaL_error(L, "incorrect %s index", what); \
+ } \
+ break; \
+ default: \
+ luaL_error(L, "argument of 'set%s' must be a string or a number", what); \
+ } \
+ global_defs_par = save_global_defs; \
+}
+
+static int gettex(lua_State * L);
+
+#define get_item_index_plus(L, where, base, what, value, is_assign, get_register, texget) { \
+ size_t len; \
+ const char *str; \
+ int key, cs; \
+ switch (lua_type(L, where)) { \
+ case LUA_TSTRING: \
+ str = lua_tolstring(L, where, &len); \
+ cs = string_lookup(str, len); \
+ if (cs == undefined_control_sequence || cs == undefined_cs_cmd) { \
+ luaL_error(L, "incorrect %s name", what); \
+ } else { \
+ key = equiv(cs) - base; \
+ if (key >= 0 && key <= 65535) { \
+ value = get_register(key); \
+ } else if (is_assign(eq_type(cs))) { \
+ texget = gettex(L); /* lazy */ \
+ } else { \
+ luaL_error(L, "incorrect %s name", what); \
+ } \
+ } \
+ break; \
+ case LUA_TNUMBER: \
+ key = luaL_checkinteger(L, where); \
+ if (key>=0 && key <= 65535) { \
+ value = get_register(key); \
+ } else { \
+ luaL_error(L, "incorrect %s index", what); \
+ } \
+ break; \
+ default: \
+ luaL_error(L, "argument of 'get%s' must be a string or a number", what); \
+ } \
+}
+
+static int isdimen(lua_State * L)
+{
+ check_register(scaled_base);
+}
+
+static int setdimen(lua_State * L)
+{
+ int isglobal = 0;
+ int value = 0;
+ int top = lua_gettop(L);
+ int t = lua_type(L, top);
+ check_item_global(L,top,isglobal);
+ if (t == LUA_TNUMBER) {
+ value = lua_roundnumber(L, top);
+ } else if (t == LUA_TSTRING) {
+ value = dimen_to_number(L, lua_tostring(L, top));
+ } else {
+ luaL_error(L, "unsupported %s value type","dimen");
+ }
+ set_item_index_plus(L, top-1, scaled_base, "dimen", value, isglobal, is_dim_assign, set_tex_dimen_register, false);
+ return 0;
+}
+
+static int getdimen(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ get_item_index_plus(L, lua_gettop(L), scaled_base, "dimen", value, is_dim_assign, get_tex_dimen_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ lua_pushinteger(L, value);
+ return 1;
+}
+
+static int isskip(lua_State * L)
+{
+ check_register(skip_base);
+}
+
+static int setskip(lua_State * L)
+{
+ int isglobal = 0;
+ halfword *value = NULL;
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ value = check_isnode(L, top);
+ if (type(*value) == glue_spec_node) {
+ set_item_index_plus(L, top-1, skip_base, "skip", *value, isglobal, is_glue_assign, set_tex_skip_register, true);
+ } else {
+ luaL_error(L, "glue_spec expected");
+ }
+ return 0;
+}
+
+static int getskip(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ get_item_index_plus(L, lua_gettop(L), skip_base, "skip", value, is_glue_assign, get_tex_skip_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ if (value == null) {
+ lua_nodelib_push_fast(L, copy_node(zero_glue));
+ } else {
+ lua_nodelib_push_fast(L, copy_node(value));
+ }
+ return 1;
+}
+
+static int setglue(lua_State * L)
+{
+ int isglobal = 0;
+ int index = 1;
+ halfword value = copy_node(zero_glue);
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ if (isglobal) {
+ index = 2;
+ top -= 1;
+ }
+ /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
+ if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
+ if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
+ if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
+ if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
+ if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
+ set_item_index_plus(L, index, skip_base, "skip", value, isglobal, is_glue_assign, set_tex_skip_register, true);
+ return 0;
+}
+
+static int getglue(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ int top = lua_gettop(L);
+ int dim = -1;
+ if (top > 1 && lua_type(L,top) == LUA_TBOOLEAN) {
+ dim = lua_toboolean(L,top);
+ top = top - 1;
+ } else {
+ lua_pushboolean(L,1);
+ dim = 1 ;
+ /* no top adaption. somewhat messy, but the gettex fallback checks itself */
+ }
+ /* checks itself for the boolean */
+ get_item_index_plus(L, top, skip_base, "glue", value, is_glue_assign, get_tex_skip_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ if (dim == 0) {
+ /* false */
+ if (value == null) {
+ lua_pushinteger(L,0);
+ } else {
+ lua_pushinteger(L,width(value));
+ }
+ return 1;
+ } else {
+ /* true and nil */
+ if (value == null) {
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ } else {
+ lua_pushinteger(L,width(value));
+ lua_pushinteger(L,stretch(value));
+ lua_pushinteger(L,shrink(value));
+ lua_pushinteger(L,stretch_order(value));
+ lua_pushinteger(L,shrink_order(value));
+ }
+ return 5;
+ }
+}
+
+static int ismuskip(lua_State * L)
+{
+ check_register(mu_skip_base);
+}
+
+static int setmuskip(lua_State * L)
+{
+ int isglobal = 0;
+ halfword *value = NULL;
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ value = check_isnode(L, top);
+ set_item_index_plus(L, top-1, mu_skip_base, "muskip", *value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
+ return 0;
+}
+
+static int getmuskip(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ get_item_index_plus(L, lua_gettop(L), mu_skip_base, "muskip", value, is_mu_glue_assign, get_tex_mu_skip_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ lua_nodelib_push_fast(L, copy_node(value));
+ return 1;
+}
+
+static int setmuglue(lua_State * L)
+{
+ int isglobal = 0;
+ int index = 1;
+ halfword value = copy_node(zero_glue);
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ if (isglobal) {
+ index = 2;
+ top -= 1;
+ }
+ /* [global] slot [width] [stretch] [shrink] [stretch_order] [shrink_order] */
+ if (top > 1) { width(value) = lua_roundnumber(L,index+1); }
+ if (top > 2) { stretch(value) = lua_roundnumber(L,index+2); }
+ if (top > 3) { shrink(value) = lua_roundnumber(L,index+3); }
+ if (top > 4) { stretch_order(value) = lua_tointeger(L,index+4); }
+ if (top > 5) { shrink_order(value) = lua_tointeger(L,index+5); }
+ set_item_index_plus(L, index, mu_skip_base, "muskip", value, isglobal, is_mu_glue_assign, set_tex_mu_skip_register, true);
+ return 0;
+}
+
+static int getmuglue(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ int top = lua_gettop(L);
+ int dim = -1;
+ if (top > 1 && lua_type(L,top) == LUA_TBOOLEAN) {
+ dim = lua_toboolean(L,top);
+ top = top - 1;
+ } else {
+ lua_pushboolean(L,1);
+ dim = 1 ;
+ /* no top adaption. somewhat messy, but the gettex fallback checks itself */
+ }
+ /* checks itself for the boolean */
+ get_item_index_plus(L, top, mu_skip_base, "muskip", value, is_mu_glue_assign, get_tex_mu_skip_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ if (dim == 0) {
+ /* false */
+ if (value == null) {
+ lua_pushinteger(L,0);
+ } else {
+ lua_pushinteger(L,width(value));
+ }
+ return 1;
+ } else {
+ /* true and nil */
+ if (value == null) {
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ lua_pushinteger(L,0);
+ } else {
+ lua_pushinteger(L,width(value));
+ lua_pushinteger(L,stretch(value));
+ lua_pushinteger(L,shrink(value));
+ lua_pushinteger(L,stretch_order(value));
+ lua_pushinteger(L,shrink_order(value));
+ }
+ return 5;
+ }
+}
+
+static int iscount(lua_State * L)
+{
+ check_register(count_base);
+}
+
+static int setcount(lua_State * L)
+{
+ int t;
+ int isglobal = 0;
+ int value = 0;
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ t = lua_type(L,top);
+ if (t == LUA_TNUMBER) {
+ value = lua_tointeger(L, top);
+ } else {
+ luaL_error(L, "unsupported %s value type","count");
+ }
+ set_item_index_plus(L, top-1, count_base, "count", value, isglobal, is_int_assign, set_tex_count_register, false);
+ return 0;
+}
+
+static int getcount(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ get_item_index_plus(L, lua_gettop(L), count_base, "count", value, is_int_assign, get_tex_count_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ lua_pushinteger(L, value);
+ return 1;
+}
+
+static int isattribute(lua_State * L)
+{
+ check_register(attribute_base);
+}
+
+/* there are no system set attributes so this is a bit overkill */
+
+static int setattribute(lua_State * L)
+{
+ int t;
+ int isglobal = 0;
+ int value = 0;
+ int top = lua_gettop(L);
+ check_item_global(L,top,isglobal);
+ t = lua_type(L,top);
+ if (t == LUA_TNUMBER) {
+ value = lua_tointeger(L, top);
+ } else {
+ luaL_error(L, "unsupported %s value type","attribute");
+ }
+ set_item_index_plus(L, top-1, attribute_base, "attribute", value, isglobal, is_attr_assign, set_tex_attribute_register, false);
+ return 0;
+}
+
+static int getattribute(lua_State * L)
+{
+ int value = 0;
+ int texget = 0;
+ get_item_index_plus(L, lua_gettop(L), attribute_base, "attribute", value, is_attr_assign, get_tex_attribute_register, texget);
+ if (texget > 0) {
+ return texget;
+ }
+ lua_pushinteger(L, value);
+ return 1;
+}
+
+/* todo: we can avoid memcpy as there is no need to go through the pool */
+
+/* use string_to_toks */
+
+static int istoks(lua_State * L)
+{
+ check_register(toks_base);
+}
+
+static int settoks(lua_State * L)
+{
+ int i, err, k;
+ lstring str;
+ char *s;
+ const char *ss;
+ int is_global = 0;
+ int save_global_defs = global_defs_par;
+ int n = lua_gettop(L);
+ if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s,global))
+ is_global = 1;
+ }
+ if (is_global)
+ global_defs_par = 1;
+ i = lua_gettop(L);
+ if (lua_type(L,i) != LUA_TSTRING) {
+ luaL_error(L, "unsupported value type");
+ }
+ ss = lua_tolstring(L, i, &str.l);
+ s = xmalloc (str.l+1);
+ memcpy (s, ss, str.l+1);
+ str.s = (unsigned char *)s;
+ k = get_item_index(L, (i - 1), toks_base);
+ check_index_range(k, "settoks");
+ err = set_tex_toks_register(k, str);
+ xfree(str.s);
+ global_defs_par = save_global_defs;
+ if (err) {
+ luaL_error(L, "incorrect value");
+ }
+ return 0;
+}
+
+static int scantoks(lua_State * L)
+{
+ int i, err, k, c;
+ lstring str;
+ char *s;
+ const char *ss;
+ int is_global = 0;
+ int save_global_defs = global_defs_par;
+ int n = lua_gettop(L);
+ if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s,global))
+ is_global = 1;
+ }
+ /* action : vsettokscct(L, is_global); */
+ if (is_global)
+ global_defs_par = 1;
+ i = lua_gettop(L);
+ if (lua_type(L,i) != LUA_TSTRING) {
+ luaL_error(L, "unsupported value type");
+ }
+ ss = lua_tolstring(L, i, &str.l);
+ s = xmalloc (str.l+1);
+ memcpy (s, ss, str.l+1);
+ str.s = (unsigned char *)s;
+ k = get_item_index(L, (i - 2), toks_base);
+ c = luaL_checkinteger(L, i - 1);
+ check_index_range(k, "settoks");
+ err = scan_tex_toks_register(k, c, str);
+ xfree(str.s);
+ global_defs_par = save_global_defs;
+ if (err) {
+ luaL_error(L, "incorrect value");
+ }
+ return 0;
+}
+
+static int gettoks(lua_State * L)
+{
+ char *ss;
+ str_number t;
+ int k = get_item_index(L, lua_gettop(L), toks_base);
+ check_index_range(k, "gettoks");
+ t = get_tex_toks_register(k);
+ ss = makecstring(t);
+ lua_pushstring(L, ss);
+ free(ss);
+ flush_str(t);
+ return 1;
+}
+
+static int getmark(lua_State *L)
+{
+ if (lua_gettop(L) == 0) {
+ lua_pushinteger(L, biggest_used_mark);
+ return 1;
+ } else if (lua_type(L, 1) == LUA_TSTRING) {
+ int num = luaL_optinteger(L, 2, 0);
+ if (num >= 0 && num <= biggest_used_mark) {
+ int ptr = null;
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s, top)) {
+ ptr = top_marks_array[num];
+ } else if (lua_key_eq(s, first)) {
+ ptr = first_marks_array[num];
+ } else if (lua_key_eq(s, bottom)) {
+ ptr = bot_marks_array[num];
+ } else if (lua_key_eq(s, splitfirst)) {
+ ptr = split_first_marks_array[num];
+ } else if (lua_key_eq(s, splitbottom)) {
+ ptr = split_bot_marks_array[num];
+ }
+ if (ptr) {
+ char *str = tokenlist_to_cstring(ptr, 1, NULL);
+ lua_pushstring(L, str);
+ free(str);
+ return 1;
+ }
+ }
+ }
+ lua_pushnil(L);
+ return 1;
+}
+
+static int get_box_id(lua_State * L, int i, boolean report)
+{
+ const char *s;
+ int cur_cs1, cur_cmd1;
+ size_t k = 0;
+ int j = -1;
+ switch (lua_type(L, i)) {
+ case LUA_TSTRING:
+ s = lua_tolstring(L, i, &k);
+ cur_cs1 = string_lookup(s, k);
+ cur_cmd1 = eq_type(cur_cs1);
+ if (cur_cmd1 == char_given_cmd ||
+ cur_cmd1 == math_given_cmd) {
+ j = equiv(cur_cs1);
+ }
+ break;
+ case LUA_TNUMBER:
+ j = lua_tointeger(L, (i));
+ break;
+ default:
+ if (report) {
+ luaL_error(L, "argument must be a string or a number");
+ }
+ j = -1; /* not a valid box id */
+ }
+ return j;
+}
+
+static int getbox(lua_State * L)
+{
+ int t;
+ int k = get_box_id(L, -1, true);
+ check_index_range(k, "getbox");
+ t = get_tex_box_register(k);
+ nodelist_to_lua(L, t);
+ return 1;
+}
+
+static int splitbox(lua_State * L)
+{
+ const char *s;
+ int k = get_box_id(L, 1, true);
+ check_index_range(k, "splitbox");
+ if (lua_isnumber(L, 2)) {
+ int m = 1;
+ if (lua_type(L, 3) == LUA_TSTRING) {
+ s = lua_tostring(L, 3);
+ if (lua_key_eq(s, exactly)) {
+ m = 0;
+ } else if (lua_key_eq(s, additional)) {
+ m = 1;
+ }
+ } else if (lua_type(L, 3) == LUA_TNUMBER) {
+ m = (int) lua_tointeger(L, 3);
+ }
+ if ((m<0) || (m>1)) {
+ luaL_error(L, "wrong mode in splitbox");
+ }
+ nodelist_to_lua(L, vsplit(k,lua_roundnumber(L,2),m));
+ } else {
+ /* maybe a warning */
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int isbox(lua_State * L)
+{
+ int k = get_box_id(L, -1, false);
+ lua_pushboolean(L,(k>=0 && k<=65535));
+ return 1;
+}
+
+static int vsetbox(lua_State * L, int is_global)
+{
+ int j, k, err, t;
+ int save_global_defs;
+ k = get_box_id(L, -2, true);
+ check_index_range(k, "setbox");
+ t = lua_type(L, -1);
+ if (t == LUA_TBOOLEAN) {
+ j = lua_toboolean(L, -1);
+ if (j == 0) {
+ j = null;
+ } else {
+ return 0;
+ }
+ } else if (t == LUA_TNIL) {
+ j = null;
+ } else {
+ 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;
+ }
+ }
+ save_global_defs = global_defs_par;
+ if (is_global) {
+ global_defs_par = 1;
+ }
+ err = set_tex_box_register(k, j);
+ global_defs_par = save_global_defs;
+ if (err) {
+ luaL_error(L, "incorrect value");
+ }
+ return 0;
+}
+
+static int setbox(lua_State * L)
+{
+ int isglobal = 0;
+ int n = lua_gettop(L);
+ if (n == 3 && (lua_type(L,1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s,global))
+ isglobal = 1;
+ }
+ return vsetbox(L, isglobal);
+}
+
+#define check_char_range(j,s,lim) \
+ if (j<0 || j >= lim) { \
+ luaL_error(L, "incorrect character value %d for tex.%s()", (int) j, s); \
+ }
+
+static int setcode (lua_State *L, void (*setone)(int,halfword,quarterword),
+ void (*settwo)(int,halfword,quarterword), const char *name, int lim)
+{
+ int ch;
+ halfword val, ucval;
+ int level = cur_level;
+ int n = lua_gettop(L);
+ int f = 1;
+ if (n>1 && lua_type(L,1) == LUA_TTABLE)
+ f++;
+ if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, f);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f++;
+ }
+ }
+ ch = luaL_checkinteger(L, f);
+ check_char_range(ch, name, 65536*17);
+ val = (halfword) luaL_checkinteger(L, f+1);
+ check_char_range(val, name, lim);
+ (setone)(ch, val, level);
+ if (settwo != NULL && n-f == 2) {
+ ucval = (halfword) luaL_checkinteger(L, f+2);
+ check_char_range(ucval, name, lim);
+ (settwo)(ch, ucval, level);
+ }
+ return 0;
+}
+
+static int setlccode(lua_State * L)
+{
+ return setcode(L, &set_lc_code, &set_uc_code, "setlccode", 65536*17);
+}
+
+static int getlccode(lua_State * L)
+{
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getlccode", 65536*17);
+ lua_pushinteger(L, get_lc_code(ch));
+ return 1;
+}
+
+static int setuccode(lua_State * L)
+{
+ return setcode(L, &set_uc_code, &set_lc_code, "setuccode", 65536*17);
+}
+
+static int getuccode(lua_State * L)
+{
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getuccode", 65536*17);
+ lua_pushinteger(L, get_uc_code(ch));
+ return 1;
+}
+
+static int setsfcode(lua_State * L)
+{
+ return setcode(L, &set_sf_code, NULL, "setsfcode", 32768);
+}
+
+static int getsfcode(lua_State * L)
+{
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getsfcode", 65536*17);
+ lua_pushinteger(L, get_sf_code(ch));
+ return 1;
+}
+
+static int setcatcode(lua_State * L)
+{
+ int ch;
+ halfword val;
+ int level = cur_level;
+ int cattable = cat_code_table_par;
+ int n = lua_gettop(L);
+ int f = 1;
+ if (n>1 && lua_type(L,1) == LUA_TTABLE)
+ f++;
+ if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, f);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f++;
+ }
+ }
+ if (n-f == 2) {
+ cattable = luaL_checkinteger(L, -3);
+ }
+ ch = luaL_checkinteger(L, -2);
+ check_char_range(ch, "setcatcode", 65536*17);
+ val = (halfword) luaL_checkinteger(L, -1);
+ check_char_range(val, "setcatcode", 16);
+ set_cat_code(cattable, ch, val, level);
+ return 0;
+}
+
+static int getcatcode(lua_State * L)
+{
+ int cattable = cat_code_table_par;
+ int ch = luaL_checkinteger(L, -1);
+ if (lua_gettop(L)>=2 && lua_type(L,-2)==LUA_TNUMBER) {
+ cattable = luaL_checkinteger(L, -2);
+ }
+ check_char_range(ch, "getcatcode", 65536*17);
+ lua_pushinteger(L, get_cat_code(cattable, ch));
+ return 1;
+}
+
+/*
+
+static int setmathcode(lua_State * L)
+{
+ int ch;
+ halfword cval, fval, chval;
+ int level = cur_level;
+ int n = lua_gettop(L);
+ int f = 1;
+ if (n>1 && lua_type(L,1) == LUA_TTABLE)
+ f++;
+ if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, f);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f++;
+ }
+ }
+ if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
+ luaL_error(L, "Bad arguments for tex.setmathcode()");
+ }
+ ch = luaL_checkinteger(L, -2);
+ check_char_range(ch, "setmathcode", 65536*17);
+
+ lua_rawgeti(L, -1, 1);
+ cval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ fval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, -3, 3);
+ chval = (halfword) luaL_checkinteger(L, -1);
+ lua_pop(L,3);
+
+ check_char_range(cval, "setmathcode", 8);
+ check_char_range(fval, "setmathcode", 256);
+ check_char_range(chval, "setmathcode", 65536*17);
+ set_math_code(ch, cval,fval, chval, (quarterword) (level));
+ return 0;
+}
+
+*/
+
+/*
+ [global] code { c f ch }
+ [global] code c f ch (a bit easier on memory, counterpart of getter)
+*/
+
+static int setmathcode(lua_State * L)
+{
+ int ch;
+ halfword cval, fval, chval;
+ int level = cur_level;
+ int f = 1;
+ if (lua_type(L,1) == LUA_TSTRING) {
+ const char *s = lua_tostring(L,1);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f = 2;
+ }
+ }
+ ch = luaL_checkinteger(L, f);
+ check_char_range(ch, "setmathcode", 65536*17);
+ f += 1 ;
+ if (lua_type(L,f) == LUA_TNUMBER) {
+ cval = luaL_checkinteger(L, f);
+ fval = luaL_checkinteger(L, f+1);
+ chval = luaL_checkinteger(L, f+2);
+ } else if (lua_type(L,f) == LUA_TTABLE) {
+ lua_rawgeti(L, f, 1);
+ cval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, f, 2);
+ fval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, f, 3);
+ chval = (halfword) luaL_checkinteger(L, -1);
+ lua_pop(L,3);
+ } else {
+ luaL_error(L, "Bad arguments for tex.setmathcode()");
+ return 0;
+ }
+ check_char_range(cval, "setmathcode", 8);
+ check_char_range(fval, "setmathcode", 256);
+ check_char_range(chval, "setmathcode", 65536*17);
+ set_math_code(ch, cval,fval, chval, (quarterword) (level));
+ return 0;
+}
+
+static int getmathcode(lua_State * L)
+{
+ mathcodeval mval = { 0, 0, 0 };
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getmathcode", 65536*17);
+ mval = get_math_code(ch);
+ lua_newtable(L);
+ lua_pushinteger(L,mval.class_value);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L,mval.family_value);
+ lua_rawseti(L, -2, 2);
+ lua_pushinteger(L,mval.character_value);
+ lua_rawseti(L, -2, 3);
+ return 1;
+}
+
+static int getmathcodes(lua_State * L)
+{
+ mathcodeval mval = { 0, 0, 0 };
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getmathcodes", 65536*17);
+ mval = get_math_code(ch);
+ lua_pushinteger(L,mval.class_value);
+ lua_pushinteger(L,mval.family_value);
+ lua_pushinteger(L,mval.character_value);
+ return 3;
+}
+
+/*
+
+static int setdelcode(lua_State * L)
+{
+ int ch;
+ halfword sfval, scval, lfval, lcval;
+ int level = cur_level;
+ int n = lua_gettop(L);
+ int f = 1;
+ if (n>1 && lua_type(L,1) == LUA_TTABLE)
+ f++;
+ if (n>2 && (lua_type(L,f) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, f);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f++;
+ }
+ }
+ if (n-f!=1 || lua_type(L,f+1) != LUA_TTABLE) {
+ luaL_error(L, "Bad arguments for tex.setdelcode()");
+ }
+ ch = luaL_checkinteger(L, -2);
+ check_char_range(ch, "setdelcode", 65536*17);
+ lua_rawgeti(L, -1, 1);
+ sfval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ scval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, -3, 3);
+ lfval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, -4, 4);
+ lcval = (halfword) luaL_checkinteger(L, -1);
+ lua_pop(L,4);
+
+ check_char_range(sfval, "setdelcode", 256);
+ check_char_range(scval, "setdelcode", 65536*17);
+ check_char_range(lfval, "setdelcode", 256);
+ check_char_range(lcval, "setdelcode", 65536*17);
+ set_del_code(ch, sfval, scval, lfval, lcval, (quarterword) (level));
+
+ return 0;
+}
+
+*/
+
+/*
+ [global] code { c f ch }
+ [global] code c f ch (a bit easier on memory, counterpart of getter)
+*/
+
+static int setdelcode(lua_State * L)
+{
+ int ch;
+ halfword sfval, scval, lfval, lcval;
+ int level = cur_level;
+ int f = 1;
+ if (lua_type(L,1) == LUA_TSTRING) {
+ const char *s = lua_tostring(L,1);
+ if (lua_key_eq(s,global)) {
+ level = level_one;
+ f = 2;
+ }
+ }
+ ch = luaL_checkinteger(L, f);
+ check_char_range(ch, "setdelcode", 65536*17);
+ f += 1;
+ if (lua_type(L,f) == LUA_TNUMBER) {
+ sfval = luaL_checkinteger(L, f);
+ scval = luaL_checkinteger(L, f+1);
+ lfval = luaL_checkinteger(L, f+2);
+ lcval = luaL_checkinteger(L, f+3);
+ } else if (lua_type(L,f) == LUA_TTABLE) {
+ lua_rawgeti(L, f, 1);
+ sfval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, f, 2);
+ scval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, f, 3);
+ lfval = (halfword) luaL_checkinteger(L, -1);
+ lua_rawgeti(L, f, 4);
+ lcval = (halfword) luaL_checkinteger(L, -1);
+ lua_pop(L,4);
+ } else {
+ luaL_error(L, "Bad arguments for tex.setdelcode()");
+ return 0;
+ }
+ check_char_range(sfval, "setdelcode", 256);
+ check_char_range(scval, "setdelcode", 65536*17);
+ check_char_range(lfval, "setdelcode", 256);
+ check_char_range(lcval, "setdelcode", 65536*17);
+ set_del_code(ch, sfval, scval, lfval, lcval, (quarterword) (level));
+ return 0;
+}
+
+static int getdelcode(lua_State * L)
+{
+ delcodeval mval = { 0, 0, 0, 0, 0 };
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getdelcode", 65536*17);
+ mval = get_del_code(ch);
+ lua_newtable(L);
+ lua_pushinteger(L,mval.small_family_value);
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L,mval.small_character_value);
+ lua_rawseti(L, -2, 2);
+ lua_pushinteger(L,mval.large_family_value);
+ lua_rawseti(L, -2, 3);
+ lua_pushinteger(L,mval.large_character_value);
+ lua_rawseti(L, -2, 4);
+ return 1;
+}
+
+static int getdelcodes(lua_State * L)
+{
+ delcodeval mval = { 0, 0, 0, 0, 0 };
+ int ch = luaL_checkinteger(L, -1);
+ check_char_range(ch, "getdelcodes", 65536*17);
+ mval = get_del_code(ch);
+ lua_pushinteger(L,mval.small_family_value);
+ lua_pushinteger(L,mval.small_character_value);
+ lua_pushinteger(L,mval.large_family_value);
+ lua_pushinteger(L,mval.large_character_value);
+ return 4;
+}
+
+static int settex(lua_State * L)
+{
+ const char *st;
+ int texstr, isprim;
+ size_t k;
+ int cur_cs1, cur_cmd1;
+ int isglobal = 0;
+ int j = 0;
+ int i = lua_gettop(L);
+ if (lua_type(L,i-1) == LUA_TSTRING) {
+ st = lua_tolstring(L, (i - 1), &k);
+ if (lua_key_eq(st,prevdepth)) {
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ cur_list.prev_depth_field = lua_roundnumber(L, i);
+ } else if (lua_type(L, i) == LUA_TSTRING) {
+ cur_list.prev_depth_field = dimen_to_number(L, lua_tostring(L, i));
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+ return 0;
+ } else if (lua_key_eq(st,prevgraf)) {
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ cur_list.pg_field = lua_tointeger(L, i);
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+ return 0;
+ } else if (lua_key_eq(st,spacefactor)) {
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ cur_list.space_factor_field = lua_roundnumber(L, i);
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+ return 0;
+ }
+ texstr = maketexlstring(st, k);
+ isprim = is_primitive(texstr);
+ flush_str(texstr);
+ if (isprim) {
+ if (i == 3 && (lua_type(L,1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s,global))
+ isglobal = 1;
+ }
+ cur_cs1 = string_lookup(st, k);
+ flush_str(texstr);
+ cur_cmd1 = eq_type(cur_cs1);
+ if (is_int_assign(cur_cmd1)) {
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ int luai = lua_tointeger(L, i);
+ assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), luai);
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+ } else if (is_dim_assign(cur_cmd1)) {
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ j = lua_roundnumber(L, i);
+ } else if (lua_type(L, i) == LUA_TSTRING) {
+ j = dimen_to_number(L, lua_tostring(L, i));
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+ assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
+ } else if (is_glue_assign(cur_cmd1)) {
+ int a = isglobal;
+ if (lua_type(L, i) == LUA_TNUMBER) {
+ halfword value = copy_node(zero_glue);
+ width(value) = lua_roundnumber(L,i);
+ if (i > 1) { stretch(value) = lua_roundnumber(L,i+1); }
+ if (i > 3) { shrink(value) = lua_roundnumber(L,i+2); }
+ if (i > 4) { stretch_order(value) = lua_tointeger(L,i+3); }
+ if (i > 5) { shrink_order(value) = lua_tointeger(L,i+4); }
+ define(equiv(cur_cs1), assign_glue_cmd, value);
+ } else {
+ halfword *j1 = check_isnode(L, i); /* the value */
+ define(equiv(cur_cs1), assign_glue_cmd, *j1);
+ }
+ } else if (is_toks_assign(cur_cmd1)) {
+ if (lua_type(L,i) == LUA_TSTRING) {
+ j = tokenlist_from_lua(L); /* uses stack -1 */
+ assign_internal_value((isglobal ? 4 : 0), equiv(cur_cs1), j);
+
+ } else {
+ luaL_error(L, "unsupported value type");
+ }
+
+ } else if (lua_istable(L, (i - 2))) {
+ /*
+ people may want to add keys that are also primitives |tex.wd| for example)
+ so creating an error is not right here
+ */
+ lua_rawset(L, (i - 2));
+ }
+ } else if (lua_istable(L, (i - 2))) {
+ lua_rawset(L, (i - 2));
+ }
+ } else if (lua_istable(L, (i - 2))) {
+ lua_rawset(L, (i - 2));
+ }
+ return 0;
+}
+
+/* todo: some will to the pdf namespace .. ignore > 31 */
+
+static int do_convert(lua_State * L, int cur_code)
+{
+ int texstr;
+ int i = -1;
+ char *str = NULL;
+ switch (cur_code) {
+ /* ignored (yet) */
+
+ case insert_ht_code: /* arg <register int> */
+ case lua_code: /* arg complex */
+ case lua_escape_string_code: /* arg token list */
+ case left_margin_kern_code: /* arg box */
+ case right_margin_kern_code: /* arg box */
+ case string_code: /* arg token */
+ case cs_string_code: /* arg token */
+ case meaning_code: /* arg token */
+ break;
+
+ /* the next fall through, and come from 'official' indices! */
+
+ case font_name_code: /* arg fontid */
+ case font_identifier_code: /* arg fontid */
+ case uniform_deviate_code: /* arg int */
+ case number_code: /* arg int */
+ case roman_numeral_code: /* arg int */
+
+ if (lua_gettop(L) < 1) {
+ /* error */
+ }
+ i = lua_tointeger(L, 1);
+
+ /* these fall through! */
+
+ default:
+ /* no backend here */
+ if (cur_code < 32) {
+ texstr = the_convert_string(cur_code, i);
+ if (texstr) {
+ str = makecstring(texstr);
+ flush_str(texstr);
+ }
+ }
+ }
+ /* end */
+ if (str) {
+ lua_pushstring(L, str);
+ free(str);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int do_scan_internal(lua_State * L, int cur_cmd1, int cur_code, int values)
+{
+ int texstr;
+ int retval = 1 ;
+ char *str = NULL;
+ int save_cur_val, save_cur_val_level;
+ save_cur_val = cur_val;
+ save_cur_val_level = cur_val_level;
+ scan_something_simple(cur_cmd1, cur_code);
+ switch (cur_val_level) {
+ case int_val_level:
+ case dimen_val_level:
+ case attr_val_level:
+ lua_pushinteger(L, cur_val);
+ break;
+ case glue_val_level:
+ case mu_val_level:
+ if (values == 0) {
+ lua_pushinteger(L,width(cur_val));
+ flush_node(cur_val);
+ } else if (values == 1) {
+ lua_pushinteger(L,width(cur_val));
+ lua_pushinteger(L,stretch(cur_val));
+ lua_pushinteger(L,shrink(cur_val));
+ lua_pushinteger(L,stretch_order(cur_val));
+ lua_pushinteger(L,shrink_order(cur_val));
+ flush_node(cur_val);
+ retval = 5;
+ } else {
+ lua_nodelib_push_fast(L, cur_val);
+ }
+ break;
+ default:
+ texstr = the_scanned_result();
+ str = makecstring(texstr);
+ if (str) {
+ lua_pushstring(L, str);
+ free(str);
+ } else {
+ lua_pushnil(L);
+ }
+ flush_str(texstr);
+ break;
+ }
+ cur_val = save_cur_val;
+ cur_val_level = save_cur_val_level;
+ return retval;
+}
+
+static int do_lastitem(lua_State * L, int cur_code)
+{
+ int retval = 1;
+ switch (cur_code) {
+ /* the next two do not actually exist */
+ case lastattr_code:
+ case attrexpr_code:
+ lua_pushnil(L);
+ break;
+ /* the expressions do something complicated with arguments, yuck */
+ case numexpr_code:
+ case dimexpr_code:
+ case glueexpr_code:
+ case muexpr_code:
+ lua_pushnil(L);
+ break;
+ /* these read a glue or muglue, todo */
+ case mu_to_glue_code:
+ case glue_to_mu_code:
+ case glue_stretch_order_code:
+ case glue_shrink_order_code:
+ case glue_stretch_code:
+ case glue_shrink_code:
+ lua_pushnil(L);
+ break;
+ /* these read a fontid and a char, todo */
+ case font_char_wd_code:
+ case font_char_ht_code:
+ case font_char_dp_code:
+ case font_char_ic_code:
+ lua_pushnil(L);
+ break;
+ /* these read an integer, todo */
+ case par_shape_length_code:
+ case par_shape_indent_code:
+ case par_shape_dimen_code:
+ lua_pushnil(L);
+ break;
+ case lastpenalty_code:
+ case lastkern_code:
+ case lastskip_code:
+ case last_node_type_code:
+ case input_line_no_code:
+ case badness_code:
+ case last_saved_box_resource_index_code:
+ case last_saved_image_resource_index_code:
+ case last_saved_image_resource_pages_code:
+ case last_x_pos_code:
+ case last_y_pos_code:
+ case random_seed_code:
+ case luatex_version_code:
+ case eTeX_minor_version_code:
+ case eTeX_version_code:
+ case current_group_level_code:
+ case current_group_type_code:
+ case current_if_level_code:
+ case current_if_type_code:
+ case current_if_branch_code:
+ retval = do_scan_internal(L, last_item_cmd, cur_code, -1);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+ return retval;
+}
+
+static int tex_setmathparm(lua_State * L)
+{
+ int i, j;
+ int k;
+ int l = cur_level;
+ void *p;
+ int n = lua_gettop(L);
+ if ((n == 3) || (n == 4)) {
+ if (n == 4 && (lua_type(L,1) == LUA_TSTRING)) {
+ const char *s = lua_tostring(L, 1);
+ if (lua_key_eq(s,global))
+ l = 1;
+ }
+ i = luaL_checkoption(L, (n - 2), NULL, math_param_names);
+ j = luaL_checkoption(L, (n - 1), NULL, math_style_names);
+ if (i < 0 || j < 0) {
+ /* invalid spec, just ignore it */
+ } else if (i>=math_param_first_mu_glue) {
+ p = lua_touserdata(L, n);
+ k = *((halfword *)p);
+ def_math_param(i, j, (scaled) k, l);
+ } else if (lua_type(L, n) == LUA_TNUMBER) {
+ k = lua_roundnumber(L, n);
+ def_math_param(i, j, (scaled) k, l);
+ } else {
+ luaL_error(L, "argument must be a number");
+ }
+ }
+ return 0;
+}
+
+static int tex_getmathparm(lua_State * L)
+{
+ if (lua_gettop(L) == 2) {
+ int i = luaL_checkoption(L, 1, NULL, math_param_names);
+ int j = luaL_checkoption(L, 2, NULL, math_style_names);
+ if (i < 0 || j < 0) {
+ lua_pushnil(L);
+ } else {
+ scaled k = get_math_param(i, j);
+ if (i >= math_param_first_mu_glue) {
+ if (k <= thick_mu_skip_code) {
+ k = glue_par(k);
+ }
+ lua_nodelib_push_fast(L, k);
+ } else {
+ lua_pushinteger(L, k);
+ }
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int getfontname(lua_State * L)
+{
+ return do_convert(L, font_name_code);
+}
+
+static int getfontidentifier(lua_State * L)
+{
+ return do_convert(L, font_identifier_code);
+}
+
+static int getuniformdeviate(lua_State * L)
+{
+ return do_convert(L, uniform_deviate_code);
+}
+
+static int getnumber(lua_State * L)
+{
+ return do_convert(L, number_code);
+}
+
+static int getromannumeral(lua_State * L)
+{
+ return do_convert(L, roman_numeral_code);
+}
+
+static int get_parshape(lua_State * L)
+{
+ halfword ptr = par_shape_par_ptr;
+ if (ptr != null) {
+ int m = 1;
+ int n = vinfo(ptr + 1);
+ lua_createtable(L, n, 0);
+ while (m <= n) {
+ lua_createtable(L, 2, 0);
+ lua_pushinteger(L, vlink((ptr) + (2 * (m - 1)) + 2));
+ lua_rawseti(L, -2, 1);
+ lua_pushinteger(L, vlink((ptr) + (2 * (m - 1)) + 3));
+ lua_rawseti(L, -2, 2);
+ lua_rawseti(L, -2, m);
+ m++;
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int get_etex_parshape(lua_State * L, int code)
+{
+ halfword ptr = null;
+ switch (code) {
+ case inter_line_penalties_loc:
+ ptr = inter_line_penalties_par_ptr;
+ break;
+ case club_penalties_loc:
+ ptr = club_penalties_par_ptr;
+ break;
+ case widow_penalties_loc:
+ ptr = widow_penalties_par_ptr;
+ break;
+ case display_widow_penalties_loc:
+ ptr = display_widow_penalties_par_ptr;
+ break;
+ }
+ if (ptr != null) {
+ int m = 1;
+ int n = vinfo(ptr + 1) + 1;
+ lua_createtable(L, n, 0);
+ while (m <= n) {
+ lua_pushinteger(L, penalty(ptr + m));
+ lua_rawseti(L, -2, m);
+ m++;
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int gettex(lua_State * L)
+{
+ int cur_cs1 = -1;
+ int retval = 1; /* default is to return nil */
+ int t = lua_gettop(L);
+ int b = -1 ;
+ if (t > 1 && lua_type(L,t) == LUA_TBOOLEAN) {
+ /*
+ 0 == flush width only
+ 1 == flush all glue parameters
+ */
+ b = lua_toboolean(L,t);
+ t = t - 1;
+ }
+ if (lua_type(L,t) == LUA_TSTRING) {
+ /*
+ 1 == tex
+ 2 == boxmaxdepth
+ or
+ 1 == boxmaxdepth
+ */
+ int texstr;
+ size_t k;
+ const char *st = lua_tolstring(L, t, &k);
+ if (lua_key_eq(st,prevdepth)) {
+ lua_pushinteger(L, cur_list.prev_depth_field);
+ return 1;
+ } else if (lua_key_eq(st,prevgraf)) {
+ lua_pushinteger(L, cur_list.pg_field);
+ return 1;
+ } else if (lua_key_eq(st,spacefactor)) {
+ lua_pushinteger(L, cur_list.space_factor_field);
+ return 1;
+ }
+ texstr = maketexlstring(st, k);
+ cur_cs1 = prim_lookup(texstr); /* not found == relax == 0 */
+ flush_str(texstr);
+ }
+ if (cur_cs1 > 0) {
+ int cur_cmd1 = get_prim_eq_type(cur_cs1);
+ int cur_code = get_prim_equiv(cur_cs1);
+ switch (cur_cmd1) {
+ case last_item_cmd:
+ retval = do_lastitem(L, cur_code);
+ break;
+ case convert_cmd:
+ retval = do_convert(L, cur_code);
+ break;
+ case assign_toks_cmd:
+ 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:
+ case set_page_int_cmd:
+ case set_page_dimen_cmd:
+ case char_given_cmd:
+ case math_given_cmd:
+ retval = do_scan_internal(L, cur_cmd1, cur_code, -1);
+ break;
+ case assign_glue_cmd:
+ case assign_mu_glue_cmd:
+ retval = do_scan_internal(L, cur_cmd1, cur_code, b);
+ break;
+ case set_tex_shape_cmd:
+ retval = get_parshape(L);
+ break;
+ case set_etex_shape_cmd:
+ retval = get_etex_parshape(L, cur_code);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+ } else if ((t == 2) && (lua_type(L,2) == LUA_TSTRING)) {
+ lua_rawget(L, 1);
+ }
+ return retval;
+}
+
+static int getlist(lua_State * L)
+{
+ const char *str;
+ 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);
+ else
+ lua_pushinteger(L, vlink(page_ins_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,contrib_head)) {
+ alink(vlink(contrib_head)) = null ;
+ lua_pushinteger(L, vlink(contrib_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,page_discards_head)) {
+ alink(vlink(page_disc)) = null ;
+ lua_pushinteger(L, page_disc);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,split_discards_head)) {
+ alink(vlink(split_disc)) = null ;
+ lua_pushinteger(L, split_disc);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,page_head)) {
+ alink(vlink(page_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(page_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,temp_head)) {
+ alink(vlink(temp_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(temp_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,hold_head)) {
+ alink(vlink(hold_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(hold_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,adjust_head)) {
+ alink(vlink(adjust_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(adjust_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,best_page_break)) {
+ lua_pushinteger(L, best_page_break);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,least_page_cost)) {
+ lua_pushinteger(L, least_page_cost);
+ } else if (lua_key_eq(str,best_size)) {
+ lua_pushinteger(L, best_size);
+ } else if (lua_key_eq(str,pre_adjust_head)) {
+ alink(vlink(pre_adjust_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(pre_adjust_head));
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(str,align_head)) {
+ alink(vlink(align_head)) = null ;/*hh-ls */
+ lua_pushinteger(L, vlink(align_head));
+ lua_nodelib_push(L);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int setlist(lua_State * L)
+{
+ 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, top+1);
+ } else if (lua_key_eq(str,least_page_cost)) {
+ least_page_cost = (int) lua_tointeger(L, top+1);
+ } else {
+ halfword *n_ptr;
+ halfword n = 0;
+ if (!lua_isnil(L, top+1)) {
+ n_ptr = check_isnode(L, top+1);
+ n = *n_ptr;
+ }
+ if (lua_key_eq(str,page_ins_head)) {
+ if (n == 0) {
+ vlink(page_ins_head) = page_ins_head;
+ } else {
+ halfword m;
+ vlink(page_ins_head) = n;
+ m = tail_of_list(n);
+ vlink(m) = page_ins_head;
+ }
+ } else if (lua_key_eq(str,contrib_head)) {
+ vlink(contrib_head) = n;
+ if (n == 0) {
+ contrib_tail = contrib_head;
+ }
+ } else if (lua_key_eq(str,best_page_break)) {
+ best_page_break = n;
+ } else if (lua_key_eq(str,page_head)) {
+ vlink(page_head) = n;
+ page_tail = (n == 0 ? page_head : tail_of_list(n));
+ } else if (lua_key_eq(str,temp_head)) {
+ vlink(temp_head) = n;
+ } else if (lua_key_eq(str,page_discards_head)) {
+ page_disc = n;
+ } else if (lua_key_eq(str,split_discards_head)) {
+ split_disc = n;
+ } else if (lua_key_eq(str,hold_head)) {
+ vlink(hold_head) = n;
+ } else if (lua_key_eq(str,adjust_head)) {
+ vlink(adjust_head) = n;
+ adjust_tail = (n == 0 ? adjust_head : tail_of_list(n));
+ } else if (lua_key_eq(str,pre_adjust_head)) {
+ vlink(pre_adjust_head) = n;
+ pre_adjust_tail = (n == 0 ? pre_adjust_head : tail_of_list(n));
+ } else if (lua_key_eq(str,align_head)) {
+ vlink(align_head) = n;
+ }
+ }
+ }
+ return 0;
+}
+
+#define NEST_METATABLE "luatex.nest"
+
+static int lua_nest_getfield(lua_State * L)
+{
+ list_state_record *r, **rv = lua_touserdata(L, -2);
+ const char *field = lua_tostring(L, -1);
+ r = *rv;
+ if (lua_key_eq(field,mode)) {
+ lua_pushinteger(L, r->mode_field);
+ } else if (lua_key_eq(field,head)) {
+ lua_nodelib_push_fast(L, r->head_field);
+ } else if (lua_key_eq(field,tail)) {
+ lua_nodelib_push_fast(L, r->tail_field);
+ } else if (lua_key_eq(field,delimptr)) {
+ lua_pushinteger(L, r->eTeX_aux_field);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(field,prevgraf)) {
+ lua_pushinteger(L, r->pg_field);
+ } else if (lua_key_eq(field,modeline)) {
+ lua_pushinteger(L, r->ml_field);
+ } else if (lua_key_eq(field,prevdepth)) {
+ lua_pushinteger(L, r->prev_depth_field);
+ } else if (lua_key_eq(field,spacefactor)) {
+ lua_pushinteger(L, r->space_factor_field);
+ } else if (lua_key_eq(field,noad)) {
+ lua_pushinteger(L, r->incompleat_noad_field);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(field,dirs)) {
+ lua_pushinteger(L, r->dirs_field);
+ lua_nodelib_push(L);
+ } else if (lua_key_eq(field,mathdir)) {
+ lua_pushboolean(L, r->math_field);
+ } else if (lua_key_eq(field,mathstyle)) {
+ lua_pushinteger(L, r->math_style_field);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lua_nest_setfield(lua_State * L)
+{
+ halfword *n;
+ int i;
+ list_state_record *r, **rv = lua_touserdata(L, -3);
+ const char *field = lua_tostring(L, -2);
+ r = *rv;
+ if (lua_key_eq(field,mode)) {
+ i = lua_tointeger(L, -1);
+ r->mode_field = i;
+ } else if (lua_key_eq(field,head)) {
+ n = check_isnode(L, -1);
+ r->head_field = *n;
+ } else if (lua_key_eq(field,tail)) {
+ n = check_isnode(L, -1);
+ r->tail_field = *n;
+ } else if (lua_key_eq(field,delimptr)) {
+ n = check_isnode(L, -1);
+ r->eTeX_aux_field = *n;
+ } else if (lua_key_eq(field,prevgraf)) {
+ i = lua_tointeger(L, -1);
+ r->pg_field = i;
+ } else if (lua_key_eq(field,modeline)) {
+ i = lua_tointeger(L, -1);
+ r->ml_field = i;
+ } else if (lua_key_eq(field,prevdepth)) {
+ i = lua_roundnumber(L, -1);
+ r->prev_depth_field = i;
+ } else if (lua_key_eq(field,spacefactor)) {
+ i = lua_roundnumber(L, -1);
+ r->space_factor_field = i;
+ } else if (lua_key_eq(field,noad)) {
+ n = check_isnode(L, -1);
+ r->incompleat_noad_field = *n;
+ } else if (lua_key_eq(field,dirs)) {
+ n = check_isnode(L, -1);
+ r->dirs_field = *n;
+ } else if (lua_key_eq(field,mathdir)) {
+ r->math_field = lua_toboolean(L, -1);
+ } else if (lua_key_eq(field,mathstyle)) {
+ i = lua_tointeger(L, -1);
+ r->math_style_field = i;
+ }
+ return 0;
+}
+
+static const struct luaL_Reg nest_m[] = {
+ {"__index", lua_nest_getfield},
+ {"__newindex", lua_nest_setfield},
+ {NULL, NULL} /* sentinel */
+};
+
+static void init_nest_lib(lua_State * L)
+{
+ luaL_newmetatable(L, NEST_METATABLE);
+ luaL_openlib(L, NULL, nest_m, 0);
+ lua_pop(L, 1);
+}
+
+static int getnest(lua_State * L)
+{
+ list_state_record **nestitem;
+ 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);
+ }
+ return 1;
+}
+
+static int setnest(lua_State * L)
+{
+ luaL_error(L, "You can't modify the semantic nest array directly");
+ return 0;
+}
+
+static int do_integer_error(double m)
+{
+ const char *help[] = {
+ "I can only go up to 2147483647='17777777777=" "7FFFFFFF,",
+ "so I'm using that number instead of yours.",
+ NULL
+ };
+ tex_error("Number too big", help);
+ return (m > 0.0 ? infinity : -infinity);
+}
+
+static int tex_roundnumber(lua_State * L)
+{
+ double m = (double) lua_tonumber(L, 1) + 0.5; /* integer or float */
+ if (abs(m) > (double) infinity)
+ lua_pushinteger(L, do_integer_error(m));
+ else
+ lua_pushinteger(L, floor(m));
+ return 1;
+}
+
+static int tex_scaletable(lua_State * L)
+{
+ double delta = luaL_checknumber(L, 2);
+ if (lua_istable(L, 1)) {
+ lua_newtable(L); /* the new table is at index 3 */
+ lua_pushnil(L);
+ while (lua_next(L, 1) != 0) { /* numeric value */
+ lua_pushvalue(L, -2);
+ lua_insert(L, -2);
+ if (lua_type(L,-2) == LUA_TNUMBER) {
+ double m = (double) lua_tonumber(L, -1) * delta + 0.5; /* integer or float */
+ lua_pop(L, 1);
+ if (abs(m) > (double) infinity)
+ lua_pushinteger(L, do_integer_error(m));
+ else
+ lua_pushinteger(L, floor(m));
+ }
+ lua_rawset(L, 3);
+ }
+ } else if (lua_type(L,1) == LUA_TNUMBER) {
+ double m = (double) lua_tonumber(L, 1) * delta + 0.5; /* integer or float */
+ if (abs(m) > (double) infinity)
+ lua_pushinteger(L, do_integer_error(m));
+ else
+ lua_pushinteger(L, floor(m));
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+#define hash_text(A) hash[(A)].rh
+
+static int tex_definefont(lua_State * L)
+{
+ const char *csname;
+ int f, u;
+ str_number t, d;
+ size_t l;
+ int i = 1;
+ int a = 0;
+ if (!no_new_control_sequence) {
+ const char *help[] = { "You can't create a new font inside a \\csname\\endcsname pair", NULL };
+ tex_error("Definition active", help);
+ }
+ if ((lua_gettop(L) == 3) && lua_isboolean(L, 1)) {
+ a = lua_toboolean(L, 1);
+ i = 2;
+ }
+ csname = luaL_checklstring(L, i, &l);
+ f = luaL_checkinteger(L, (i + 1));
+ no_new_control_sequence = 0;
+ u = string_lookup(csname, l);
+ no_new_control_sequence = 1;
+ if (a)
+ geq_define(u, set_font_cmd, f);
+ else
+ eq_define(u, set_font_cmd, f);
+ eqtb[font_id_base + f] = eqtb[u];
+ /*tex
+
+ This is tricky: when we redefine a string we loose the old one. So this
+ will change as it's only used to display the |\fontname| so we can store
+ that with the font.
+
+ */
+ d = cs_text(font_id_base + f);
+ t = maketexlstring(csname, l); /* the csname */
+ if (!d) {
+ /*tex We have a new string. */
+ cs_text(font_id_base + f) = t;
+ } else if ((d!=t) && str_eq_str(d,t)){
+ /*tex We have a duplicate string. */
+ flush_str(t);
+ } else if(d!=t){
+ d = search_string(t);
+ if (d) {
+ /*tex We have already such a string. */
+ cs_text(font_id_base + f) = d;
+ flush_str(t);
+ } else {
+ /*tex The old value is lost but still in the pool. */
+ cs_text(font_id_base + f) = t;
+ }
+ }
+ return 0;
+}
+
+/*
+static int tex_hashpairs(lua_State * L)
+{
+ int cmd, chr;
+ str_number s = 0;
+ int cs = 1;
+ lua_newtable(L);
+ while (cs < hash_size) {
+ s = hash_text(cs);
+ if (s > 0) {
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ cmd = eq_type(cs);
+ chr = equiv(cs);
+ make_token_table(L, cmd, chr, cs);
+ lua_rawset(L, -3);
+ cs++;
+ }
+ }
+ return 1;
+}
+
+static int tex_primitives(lua_State * L)
+{
+ int cmd, chr;
+ str_number s = 0;
+ int cs = 0;
+ lua_newtable(L);
+ while (cs < prim_size) {
+ s = get_prim_text(cs);
+ if (s > 0) {
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ cmd = get_prim_eq_type(cs);
+ chr = get_prim_equiv(cs);
+ make_token_table(L, cmd, chr, 0);
+ lua_rawset(L, -3);
+ }
+ cs++;
+ }
+ return 1;
+}
+
+static int tex_extraprimitives(lua_State * L)
+{
+ int n, i;
+ int mask = 0;
+ int cs = 0;
+ n = lua_gettop(L);
+ if (n == 0) {
+ mask = etex_command + luatex_command;
+ } else {
+ for (i = 1; i <= n; i++) {
+ if (lua_type(L,i) == LUA_TSTRING) {
+ const char *s = lua_tostring(L, i);
+ if (lua_key_eq(s,etex)) {
+ mask |= etex_command;
+ } else if (lua_key_eq(s,tex)) {
+ mask |= tex_command;
+ } else if (lua_key_eq(s,core)) {
+ mask |= core_command;
+ } else if (lua_key_eq(s,luatex)) {
+ mask |= luatex_command;
+ }
+ }
+ }
+ }
+ lua_newtable(L);
+ i = 1;
+ while (cs < prim_size) {
+ str_number s = 0;
+ s = get_prim_text(cs);
+ if (s > 0) {
+ if (get_prim_origin(cs) & mask) {
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ lua_rawseti(L, -2, i++);
+ }
+ }
+ cs++;
+ }
+ return 1;
+}
+
+*/
+
+static int tex_hashpairs(lua_State * L)
+{
+ str_number s = 0;
+ int cs = 1;
+ int nt = 0;
+ lua_newtable(L);
+ while (cs < hash_size) {
+ s = hash_text(cs);
+ if (s > 0) {
+ halfword n = cs_next(cs);
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ lua_rawseti(L, -2, ++nt);
+ while (n) {
+ s = cs_text(n);
+ if (s) {
+ ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ lua_rawseti(L, -2, ++nt);
+ }
+ n = cs_next(n);
+ }
+ }
+ cs++;
+ }
+ return 1;
+}
+
+static int tex_primitives(lua_State * L)
+{
+ str_number s = 0;
+ int cs = 0;
+ int nt = 0;
+ lua_newtable(L);
+ while (cs < prim_size) {
+ s = get_prim_text(cs);
+ if (s > 0) {
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ lua_rawseti(L, -2, ++nt);
+ }
+ cs++;
+ }
+ return 1;
+}
+
+static int tex_extraprimitives(lua_State * L)
+{
+ int n, i;
+ int mask = 0;
+ int cs = 0;
+ int nt = 0;
+ n = lua_gettop(L);
+ if (n == 0) {
+ mask = etex_command + luatex_command;
+ } else {
+ for (i = 1; i <= n; i++) {
+ if (lua_type(L,i) == LUA_TSTRING) {
+ const char *s = lua_tostring(L, i);
+ if (lua_key_eq(s,etex)) {
+ mask |= etex_command;
+ } else if (lua_key_eq(s,tex)) {
+ mask |= tex_command;
+ } else if (lua_key_eq(s,core)) {
+ mask |= core_command;
+ } else if (lua_key_eq(s,luatex)) {
+ mask |= luatex_command;
+ }
+ }
+ }
+ }
+ lua_newtable(L);
+ while (cs < prim_size) {
+ str_number s = 0;
+ s = get_prim_text(cs);
+ if (s > 0) {
+ if (get_prim_origin(cs) & mask) {
+ char *ss = makecstring(s);
+ lua_pushstring(L, ss);
+ free(ss);
+ lua_rawseti(L, -2, ++nt);
+ }
+ }
+ cs++;
+ }
+ return 1;
+}
+
+static int tex_enableprimitives(lua_State * L)
+{
+ int n = lua_gettop(L);
+ if (n != 2) {
+ luaL_error(L, "wrong number of arguments");
+ } else {
+ size_t l;
+ int i;
+ const char *pre = luaL_checklstring(L, 1, &l);
+ if (lua_istable(L, 2)) {
+ int nncs = no_new_control_sequence;
+ no_new_control_sequence = true;
+ i = 1;
+ while (1) {
+ lua_rawgeti(L, 2, i);
+ if (lua_type(L,3) == LUA_TSTRING) {
+ const char *prim = lua_tostring(L, 3);
+ str_number s = maketexstring(prim);
+ halfword prim_val = prim_lookup(s);
+ if (prim_val != undefined_primitive) {
+ char *newprim;
+ int val;
+ size_t newl;
+ halfword cur_cmd1 = get_prim_eq_type(prim_val);
+ halfword cur_chr1 = get_prim_equiv(prim_val);
+ if (strncmp(pre, prim, l) != 0) { /* not a prefix */
+ newl = strlen(prim) + l;
+ newprim = (char *) xmalloc((unsigned) (newl + 1));
+ strcpy(newprim, pre);
+ strcat(newprim + l, prim);
+ } else {
+ newl = strlen(prim);
+ newprim = (char *) xmalloc((unsigned) (newl + 1));
+ strcpy(newprim, prim);
+ }
+ val = string_lookup(newprim, newl);
+ if (val == undefined_control_sequence ||
+ eq_type(val) == undefined_cs_cmd) {
+ primitive_def(newprim, newl, (quarterword) cur_cmd1, cur_chr1);
+ }
+ free(newprim);
+ }
+ flush_str(s);
+ } else {
+ lua_pop(L, 1);
+ break;
+ }
+ lua_pop(L, 1);
+ i++;
+ }
+ lua_pop(L, 1); /* the table */
+ no_new_control_sequence = nncs;
+ } else {
+ luaL_error(L, "Expected an array of names as second argument");
+ }
+ }
+ return 0;
+}
+
+#define get_int_par(A,B) do { \
+ lua_key_rawgeti(A); \
+ if (lua_type(L, -1) == LUA_TNUMBER) { \
+ A = (int) lua_tointeger(L, -1); \
+ } else { \
+ A = (B); \
+ } \
+ lua_pop(L,1); \
+} while (0)
+
+#define get_intx_par(A,B,C,D) do { \
+ lua_key_rawgeti(A); \
+ if (lua_type(L, -1) == LUA_TNUMBER) { \
+ A = (int) lua_tointeger(L, -1); \
+ C = null; \
+ } else if (lua_type(L, -1) == LUA_TTABLE){ \
+ A = 0; \
+ C = nodelib_topenalties(L, lua_gettop(L)); \
+ } else { \
+ A = (B); \
+ C = (D); \
+ } \
+ lua_pop(L,1); \
+} while (0)
+
+#define get_dimen_par(A,B) do { \
+ lua_key_rawgeti(A); \
+ if (lua_type(L, -1) == LUA_TNUMBER) { \
+ A = (int) lua_roundnumber(L, -1); \
+ } else { \
+ A = (B); \
+ } \
+ lua_pop(L,1); \
+} while (0)
+
+#define get_glue_par(A,B) do { \
+ lua_key_rawgeti(A); \
+ if (lua_type(L, -1) != LUA_TNIL) { \
+ A = *check_isnode(L, -1); \
+ } else { \
+ A = (B); \
+ } \
+ lua_pop(L,1); \
+} while (0)
+
+static halfword nodelib_toparshape(lua_State * L, int i)
+{
+ halfword p;
+ int n = 0;
+ int width, indent, j;
+ /* find |n| */
+ lua_pushnil(L);
+ while (lua_next(L, i) != 0) {
+ n++;
+ lua_pop(L, 1);
+ }
+ if (n == 0)
+ return null;
+ p = new_node(shape_node, 2 * (n + 1) + 1);
+ vinfo(p + 1) = n;
+ /* fill |p| */
+ lua_pushnil(L);
+ j = 0;
+ while (lua_next(L, i) != 0) {
+ /* don't give an error for non-tables, we may add special syntaxes at some point */
+ j++;
+ if (lua_type(L, i) == LUA_TTABLE) {
+ lua_rawgeti(L, -1, 1); /* indent */
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ indent = lua_roundnumber(L, -1);
+ lua_pop(L, 1);
+ lua_rawgeti(L, -1, 2); /* width */
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ width = lua_roundnumber(L, -1);
+ lua_pop(L, 1);
+ varmem[p + 2 * j].cint = indent;
+ varmem[p + 2 * j + 1].cint = width;
+ }
+ }
+ }
+ lua_pop(L, 1);
+ }
+ return p;
+}
+
+/* penalties */
+
+static halfword nodelib_topenalties(lua_State * L, int i)
+{
+ halfword p;
+ int n = 0;
+ int j;
+ /* find |n| */
+ lua_pushnil(L);
+ while (lua_next(L, i) != 0) {
+ n++;
+ lua_pop(L, 1);
+ }
+ if (n == 0)
+ return null;
+ p = new_node(shape_node, 2 * ((n / 2) + 1) + 1 + 1);
+ vinfo(p + 1) = (n / 2) + 1;
+ varmem[p + 2].cint = n;
+ lua_pushnil(L);
+ j = 2;
+ while (lua_next(L, i) != 0) {
+ j++;
+ if (lua_type(L, -1) == LUA_TNUMBER) {
+ int pen = lua_tointeger(L, -1);
+ varmem[p+j].cint = pen;
+ }
+ lua_pop(L, 1);
+ }
+ if (!odd(n))
+ varmem[p+j+1].cint = 0;
+ return p;
+}
+
+static int tex_run_linebreak(lua_State * L)
+{
+
+ halfword *j;
+ halfword p;
+ halfword final_par_glue;
+ int paragraph_dir = 0;
+ /* locally initialized parameters for line breaking */
+ int pretolerance, tracingparagraphs, tolerance, looseness,
+ adjustspacing, adjdemerits, protrudechars,
+ linepenalty, lastlinefit, doublehyphendemerits, finalhyphendemerits,
+ hangafter, interlinepenalty, widowpenalty, clubpenalty, brokenpenalty;
+ halfword emergencystretch, hangindent, hsize, leftskip, rightskip,parshape;
+ int fewest_demerits = 0, actual_looseness = 0;
+ halfword clubpenalties, interlinepenalties, widowpenalties;
+ int save_vlink_tmp_head;
+ /* push a new nest level */
+ push_nest();
+ save_vlink_tmp_head = vlink(temp_head);
+
+ j = check_isnode(L, 1); /* the value */
+ vlink(temp_head) = *j;
+ p = *j;
+ if ((!is_char_node(vlink(*j))) && ((type(vlink(*j)) == local_par_node))) {
+ paragraph_dir = local_par_dir(vlink(*j));
+ }
+
+ while (vlink(p) != null)
+ p = vlink(p);
+ final_par_glue = p;
+
+ /* initialize local parameters */
+
+ if (lua_gettop(L) != 2 || lua_type(L, 2) != LUA_TTABLE) {
+ lua_checkstack(L, 3);
+ lua_newtable(L);
+ }
+ lua_key_rawgeti(pardir);
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ paragraph_dir = nodelib_getdir(L, -1);
+ }
+ lua_pop(L, 1);
+
+ lua_key_rawgeti(parshape);
+ if (lua_type(L, -1) == LUA_TTABLE) {
+ parshape = nodelib_toparshape(L, lua_gettop(L));
+ } else {
+ parshape = equiv(par_shape_loc);
+ }
+ lua_pop(L, 1);
+
+ get_int_par (pretolerance, pretolerance_par);
+ get_int_par (tracingparagraphs, tracing_paragraphs_par);
+ get_int_par (tolerance, tolerance_par);
+ get_int_par (looseness, looseness_par);
+ get_int_par (adjustspacing, adjust_spacing_par);
+ get_int_par (adjdemerits, adj_demerits_par);
+ get_int_par (protrudechars, protrude_chars_par);
+ get_int_par (linepenalty, line_penalty_par);
+ get_int_par (lastlinefit, last_line_fit_par);
+ get_int_par (doublehyphendemerits, double_hyphen_demerits_par);
+ get_int_par (finalhyphendemerits, final_hyphen_demerits_par);
+ get_int_par (hangafter, hang_after_par);
+ get_intx_par (interlinepenalty,inter_line_penalty_par, interlinepenalties, equiv(inter_line_penalties_loc));
+ get_intx_par (clubpenalty, club_penalty_par, clubpenalties, equiv(club_penalties_loc));
+ get_intx_par (widowpenalty, widow_penalty_par, widowpenalties, equiv(widow_penalties_loc));
+ get_int_par (brokenpenalty, broken_penalty_par);
+ get_dimen_par(emergencystretch, emergency_stretch_par);
+ get_dimen_par(hangindent, hang_indent_par);
+ get_dimen_par(hsize, hsize_par);
+ get_glue_par (leftskip, left_skip_par);
+ get_glue_par (rightskip, right_skip_par);
+ ext_do_line_break(paragraph_dir,
+ pretolerance,
+ tracingparagraphs,
+ tolerance,
+ emergencystretch,
+ looseness,
+ adjustspacing,
+ parshape,
+ adjdemerits,
+ protrudechars,
+ linepenalty,
+ lastlinefit,
+ doublehyphendemerits,
+ finalhyphendemerits,
+ hangindent,
+ hsize,
+ hangafter,
+ leftskip,
+ rightskip,
+ interlinepenalties,
+ interlinepenalty,
+ clubpenalty,
+ clubpenalties,
+ widowpenalties,
+ widowpenalty,
+ brokenpenalty,
+ final_par_glue);
+
+ /* return the generated list, and its prevdepth */
+ get_linebreak_info (&fewest_demerits, &actual_looseness) ;
+ lua_nodelib_push_fast(L, vlink(cur_list.head_field));
+ lua_newtable(L);
+ lua_push_key(demerits);
+ lua_pushinteger(L, fewest_demerits);
+ lua_settable(L, -3);
+ lua_push_key(looseness);
+ lua_pushinteger(L, actual_looseness);
+ lua_settable(L, -3);
+ lua_push_key(prevdepth);
+ lua_pushinteger(L, cur_list.prev_depth_field);
+ lua_settable(L, -3);
+ lua_push_key(prevgraf);
+ lua_pushinteger(L, cur_list.pg_field);
+ lua_settable(L, -3);
+
+ /* restore nest stack */
+ vlink(temp_head) = save_vlink_tmp_head;
+ pop_nest();
+ if (parshape != equiv(par_shape_loc))
+ flush_node(parshape);
+ return 2;
+}
+
+static int tex_reset_paragraph(lua_State * L)
+{
+ (void) L;
+ normal_paragraph();
+ return 0;
+}
+
+static int tex_shipout(lua_State * L)
+{
+ int boxnum = get_box_id(L, 1, true);
+ ship_out(static_pdf, box(boxnum), SHIPPING_PAGE);
+ box(boxnum) = null;
+ return 0;
+}
+
+static int tex_badness(lua_State * L)
+{
+ scaled t = lua_tointeger(L,1);
+ scaled s = lua_tointeger(L,2);
+ lua_pushinteger(L, badness(t,s));
+ return 1;
+}
+
+static int tex_run_boot(lua_State * L)
+{
+ int n = lua_gettop(L);
+ const char *format = NULL;
+ if (n >= 1) {
+ ini_version = 0;
+ format = luaL_checkstring(L, 1);
+ } else {
+ ini_version = 1;
+ }
+ if (main_initialize()) { /* > 0 = failure */
+ lua_pushboolean(L, 0); /* false */
+ return 1;
+ }
+ if (format) {
+ if (!zopen_w_input(&fmt_file, format, DUMP_FORMAT, FOPEN_RBIN_MODE)) {
+ lua_pushboolean(L, 0); /* false */
+ return 1;
+ }
+ if (!load_fmt_file(format)) {
+ zwclose(fmt_file);
+ lua_pushboolean(L, 0); /* false */
+ return 1;
+ }
+ zwclose(fmt_file);
+ }
+ pdf_init_map_file("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();
+ text_dir_ptr = new_dir(0);
+ history = spotless; /* ready to go! */
+ /* Initialize synctex primitive */
+ synctexinitcommand();
+ /* tex is ready to go, now */
+ /*
+ unhide_lua_table(Luas, "tex", tex_table_id);
+ unhide_lua_table(Luas, "pdf", pdf_table_id);
+ unhide_lua_table(Luas, "token", token_table_id);
+ unhide_lua_table(Luas, "node", node_table_id);
+ */
+ lua_pushboolean(L, 1); /* true */
+ return 1;
+}
+
+/* tex random generators */
+
+static int tex_init_rand(lua_State * L)
+{
+ int sp;
+ if (lua_type(L, 1) != LUA_TNUMBER) {
+ luaL_error(L, "argument must be a number");
+ return 0;
+ }
+ sp = lua_roundnumber(L, 1);
+ init_randoms(sp);
+ return 0;
+}
+
+static int tex_unif_rand(lua_State * L)
+{
+ int sp;
+ if (lua_type(L, 1) != LUA_TNUMBER) {
+ luaL_error(L, "argument must be a number");
+ return 0;
+ }
+ sp = lua_roundnumber(L, 1);
+ lua_pushinteger(L, unif_rand(sp));
+ return 1;
+}
+
+static int tex_norm_rand(lua_State * L)
+{
+ lua_pushinteger(L, norm_rand());
+ return 1;
+}
+
+/* Same as lua but with tex rng */
+
+static int lua_math_random (lua_State *L)
+{
+ lua_Number rand_max = 0x7fffffff ;
+ lua_Number r = unif_rand(rand_max) ;
+ r = (r>=0 ? 0+r : 0-r) ;
+ r = r / rand_max;
+ switch (lua_gettop(L)) { /* check number of arguments */
+ case 0: { /* no arguments */
+ lua_pushnumber(L, r); /* float: [0, 1] */
+ break;
+ }
+ case 1: { /* only upper limit */
+ lua_Number u = luaL_checknumber(L, 1);
+ luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
+ lua_pushnumber(L, floor(r*u) + (lua_Number)(1.0)); /* float: [1, u] */
+ break;
+ }
+ case 2: { /* lower and upper limits */
+ lua_Number l = luaL_checknumber(L, 1);
+ lua_Number u = luaL_checknumber(L, 2);
+ luaL_argcheck(L, l <= u, 2, "interval is empty");
+ lua_pushnumber(L, floor(r*(u-l+1)) + l); /* float: [l, u] */
+ break;
+ }
+ default:
+ return luaL_error(L, "wrong number of arguments");
+ }
+ return 1;
+}
+
+static int tex_run_main(lua_State * L)
+{
+ (void) L;
+ main_control();
+ return 0;
+}
+
+static int tex_run_end(lua_State * L)
+{
+ (void) L;
+ final_cleanup(); /* prepare for death */
+ close_files_and_terminate();
+ do_final_end();
+ return 0;
+}
+
+static int tex_show_context(lua_State * L)
+{
+ (void) L;
+ show_context();
+ return 0;
+}
+
+static int tex_save_box_resource(lua_State * L)
+{
+ halfword boxdata;
+ int index = null;
+ int attributes = null;
+ int resources = null;
+ 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 */
+ if (lua_type(L,2) == LUA_TSTRING) {
+ lua_pushvalue(L, 2);
+ attributes = luaL_ref(L, LUA_REGISTRYINDEX);
+ }
+ if (lua_type(L,3) == LUA_TSTRING) {
+ lua_pushvalue(L, 3);
+ resources = luaL_ref(L, LUA_REGISTRYINDEX);
+ }
+ if (lua_type(L,4) == LUA_TBOOLEAN) {
+ immediate = lua_toboolean(L, 4);
+ }
+ if (lua_type(L,5) == LUA_TNUMBER) {
+ type = lua_tointeger(L, 5);
+ }
+ if (lua_type(L,6) == LUA_TNUMBER) {
+ margin = lua_tointeger(L, 6);
+ }
+ 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));
+ set_obj_xform_attr(static_pdf, index, null);
+ set_obj_xform_attr_str(static_pdf, index, attributes);
+ set_obj_xform_resources(static_pdf, index, null);
+ set_obj_xform_resources_str(static_pdf, index, resources);
+ set_obj_xform_box(static_pdf, index, (int) boxdata);
+ set_obj_xform_width(static_pdf, index, width(boxdata));
+ set_obj_xform_height(static_pdf, index, height(boxdata));
+ 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);
+ last_saved_box_index = index;
+ lua_pushinteger(L, index);
+ if (immediate) {
+ pdf_cur_form = last_saved_box_index;
+ ship_out(static_pdf, obj_xform_box(static_pdf, last_saved_box_index), SHIPPING_FORM);
+ }
+ return 1;
+}
+
+static int tex_use_box_resource(lua_State * L)
+{
+ halfword rule;
+ int index = 0;
+ scaled_whd alt, nat, dim;
+ if (lua_type(L,1) != LUA_TNUMBER) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ lua_pushnil(L);
+ lua_pushnil(L);
+ } else {
+ index = lua_tointeger(L,1);
+ alt.wd = null_flag;
+ alt.ht = null_flag;
+ alt.dp = null_flag;
+ if (lua_type(L,2) == LUA_TNUMBER) {
+ alt.wd = (scaled) lua_roundnumber(L,2);
+ }
+ if (lua_type(L,3) == LUA_TNUMBER) {
+ alt.ht = (scaled) lua_roundnumber(L,3);
+ }
+ if (lua_type(L,4) == LUA_TNUMBER) {
+ alt.dp = (scaled) lua_roundnumber(L,4);
+ }
+ /* sort of the same as backend */
+ check_obj_type(static_pdf, obj_type_xform, index);
+ nat.wd = obj_xform_width(static_pdf, index);
+ nat.ht = obj_xform_height(static_pdf, index);
+ nat.dp = obj_xform_depth(static_pdf, index);
+ if (alt.wd != null_flag || alt.ht != null_flag || alt.dp != null_flag) {
+ dim = tex_scale(nat, alt);
+ } else {
+ dim = nat;
+ }
+ rule = new_rule(box_rule);
+ rule_index(rule) = index;
+ width(rule) = dim.wd;
+ height(rule) = dim.ht;
+ depth(rule) = dim.dp;
+ nodelist_to_lua(L, rule);
+ lua_pushinteger(L, (int) dim.wd);
+ lua_pushinteger(L, (int) dim.ht);
+ lua_pushinteger(L, (int) dim.dp);
+ }
+ return 4;
+}
+
+static int tex_get_box_resource_dimensions(lua_State * L)
+{
+ int index = 0;
+ if (lua_type(L,1) != LUA_TNUMBER) {
+ lua_pushnil(L);
+ lua_pushnil(L);
+ lua_pushnil(L);
+ lua_pushnil(L);
+ } else {
+ index = lua_tointeger(L,1);
+ check_obj_type(static_pdf, obj_type_xform, index);
+ lua_pushinteger(L, (int) obj_xform_width(static_pdf, index));
+ lua_pushinteger(L, (int) obj_xform_height(static_pdf, index));
+ lua_pushinteger(L, (int) obj_xform_depth(static_pdf, index));
+ lua_pushinteger(L, (int) obj_xform_margin(static_pdf, index));
+ }
+ 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)
+{
+ halfword mode = lua_tointeger(L, 1);
+ synctex_set_mode(mode);
+ return 0;
+}
+static int lua_get_synctex_mode(lua_State * L)
+{
+ lua_pushinteger(L,synctex_get_mode());
+ return 1;
+}
+
+static int lua_set_synctex_tag(lua_State * L)
+{
+ halfword tag = lua_tointeger(L, 1);
+ synctex_set_tag(tag);
+ return 0;
+}
+
+static int lua_get_synctex_tag(lua_State * L)
+{
+ lua_pushinteger(L,synctex_get_tag());
+ return 1;
+}
+
+static int lua_force_synctex_tag(lua_State * L)
+{
+ halfword tag = lua_tointeger(L, 1);
+ synctex_force_tag(tag);
+ return 0;
+}
+
+static int lua_force_synctex_line(lua_State * L)
+{
+ halfword line = lua_tointeger(L, 1);
+ synctex_force_line(line);
+ return 0;
+}
+
+static int lua_set_synctex_line(lua_State * L)
+{
+ halfword line = lua_tointeger(L, 1);
+ synctex_set_line(line);
+ return 0;
+}
+
+static int lua_get_synctex_line(lua_State * L)
+{
+ lua_pushinteger(L,synctex_get_line());
+ return 1;
+}
+
+static int lua_set_synctex_no_files(lua_State * L)
+{
+ halfword flag = lua_tointeger(L, 1);
+ synctex_set_no_files(flag);
+ 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;
+ halfword r = get_avail();
+ halfword 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 {
+ halfword t;
+ int k = get_item_index(L, 1, toks_base);
+ check_index_range(k, "gettoks");
+ t = toks(k);
+ if (! t) {
+ /* nothing to do */
+ } else if ((scanner_status != defining) || (lua_toboolean(L,2))) {
+ int grouped = lua_toboolean(L,3);
+ int old_mode = mode;
+ if (grouped) {
+ halfword r = get_avail();
+ token_info(r) = token_val(right_brace_cmd,0);
+ begin_token_list(r,inserted);
+ }
+ {
+ halfword r = get_avail();
+ token_info(r) = token_val(extension_cmd,end_local_code);
+ begin_token_list(r,inserted);
+ }
+ begin_token_list(t,local_text);
+ if (grouped) {
+ halfword r = get_avail();
+ token_info(r) = token_val(left_brace_cmd,0);
+ begin_token_list(r,inserted);
+ }
+ 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(); */
+ } else {
+ halfword q;
+ halfword p = temp_token_head;
+ halfword r = token_link(t);
+ set_token_link(p, null);
+ while (r) {
+ fast_store_new_token(token_info(r));
+ r = token_link(r);
+ }
+ ins_list(token_link(temp_token_head));
+ }
+ }
+ return 0;
+}
+
+static int quittoks(lua_State * L)
+{
+ (void) L;
+ if (tracing_nesting_par > 2) {
+ local_control_message("quitting token scanner");
+ }
+ end_local_control();
+ return 0;
+}
+
+/*tex Negative values are internal and inline. */
+
+static int tex_getmodevalues(lua_State * L)
+{
+ lua_newtable(L);
+ lua_pushinteger(L,0);
+ lua_push_string_by_name(L,unset); /* 0 */
+ lua_rawset(L, -3);
+ lua_pushinteger(L,vmode);
+ lua_push_string_by_name(L,vertical); /* 1 */
+ lua_rawset(L, -3);
+ lua_pushinteger(L,hmode);
+ lua_push_string_by_name(L,horizontal); /* 127 */
+ lua_rawset(L, -3);
+ lua_pushinteger(L,mmode);
+ lua_push_string_by_name(L,math); /* 253 */
+ lua_rawset(L, -3);
+ return 1;
+}
+
+/* till here */
+
+void init_tex_table(lua_State * L)
+{
+ lua_createtable(L, 0, 3);
+ lua_pushcfunction(L, tex_run_boot);
+ lua_setfield(L, -2, "initialize");
+ lua_pushcfunction(L, tex_run_main);
+ lua_setfield(L, -2, "run");
+ lua_pushcfunction(L, tex_run_end);
+ lua_setfield(L, -2, "finish");
+ lua_setglobal(L, "tex");
+}
+
+static const struct luaL_Reg texlib[] = {
+ { "run", tex_run_main }, /* may be needed */
+ { "finish", tex_run_end }, /* may be needed */
+ { "write", luacwrite },
+ { "print", luacprint },
+ { "sprint", luacsprint },
+ { "tprint", luactprint },
+ { "cprint", luaccprint },
+ { "error", texerror },
+ { "set", settex },
+ { "get", gettex },
+ { "isdimen", isdimen },
+ { "setdimen", setdimen },
+ { "getdimen", getdimen },
+ { "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 },
+ { "setattribute", setattribute },
+ { "getattribute", getattribute },
+ { "iscount", iscount },
+ { "setcount", setcount },
+ { "getcount", getcount },
+ { "istoks", istoks },
+ { "settoks", settoks },
+ { "scantoks", scantoks },
+ { "gettoks", gettoks },
+ { "getmark", getmark },
+ { "isbox", isbox },
+ { "setbox", setbox },
+ { "getbox", getbox },
+ { "splitbox", splitbox },
+ { "setlist", setlist },
+ { "getlist", getlist },
+ { "setnest", setnest }, /* only a message */
+ { "getnest", getnest },
+ { "setcatcode", setcatcode },
+ { "getcatcode", getcatcode },
+ { "setdelcode", setdelcode },
+ { "getdelcode", getdelcode },
+ { "getdelcodes", getdelcodes },
+ { "setlccode", setlccode },
+ { "getlccode", getlccode },
+ { "setmathcode", setmathcode },
+ { "getmathcode", getmathcode },
+ { "getmathcodes", getmathcodes },
+ { "setsfcode", setsfcode },
+ { "getsfcode", getsfcode },
+ { "setuccode", setuccode },
+ { "getuccode", getuccode },
+ { "round", tex_roundnumber },
+ { "scale", tex_scaletable },
+ { "sp", tex_scaledimen },
+ { "fontname", getfontname },
+ { "fontidentifier", getfontidentifier },
+ { "uniformdeviate", getuniformdeviate },
+ { "number", getnumber },
+ { "romannumeral", getromannumeral },
+ { "definefont", tex_definefont },
+ { "hashtokens", tex_hashpairs },
+ { "primitives", tex_primitives },
+ { "extraprimitives", tex_extraprimitives },
+ { "enableprimitives", tex_enableprimitives },
+ { "shipout", tex_shipout },
+ { "badness", tex_badness },
+ { "setmath", tex_setmathparm },
+ { "getmath", tex_getmathparm },
+ { "linebreak", tex_run_linebreak },
+ { "resetparagraph", tex_reset_paragraph },
+ /* tex random generators */
+ { "init_rand", tex_init_rand },
+ { "uniform_rand",tex_unif_rand },
+ { "normal_rand", tex_norm_rand },
+ { "lua_math_randomseed", tex_init_rand }, /* syntactic sugar */
+ { "lua_math_random", lua_math_random },
+ { "show_context", tex_show_context },
+ { "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 },
+ { "set_synctex_tag", lua_set_synctex_tag },
+ { "get_synctex_tag", lua_get_synctex_tag },
+ { "set_synctex_no_files", lua_set_synctex_no_files },
+ { "force_synctex_tag", lua_force_synctex_tag },
+ { "force_synctex_line", lua_force_synctex_line },
+ { "set_synctex_line", lua_set_synctex_line },
+ { "get_synctex_line", lua_get_synctex_line },
+ /* test */
+ { "runtoks", runtoks },
+ { "quittoks", quittoks },
+ { "forcehmode", forcehmode },
+ { "getmodevalues", tex_getmodevalues },
+ /* sentinel */
+ { NULL, NULL }
+};
+
+int luaopen_tex(lua_State * L)
+{
+ luaL_openlib(L, "tex", texlib, 0);
+ /* *INDENT-OFF* */
+ make_table(L, "attribute", "tex.attribute", "getattribute", "setattribute");
+ make_table(L, "skip", "tex.skip", "getskip", "setskip");
+ make_table(L, "glue", "tex.glue", "getglue", "setglue");
+ make_table(L, "muskip", "tex.muskip", "getmuskip", "setmuskip");
+ make_table(L, "muglue", "tex.muglue", "getmuglue", "setmuglue");
+ make_table(L, "dimen", "tex.dimen", "getdimen", "setdimen");
+ make_table(L, "count", "tex.count", "getcount", "setcount");
+ make_table(L, "toks", "tex.toks", "gettoks", "settoks");
+ make_table(L, "box", "tex.box", "getbox", "setbox");
+ make_table(L, "sfcode", "tex.sfcode", "getsfcode", "setsfcode");
+ make_table(L, "lccode", "tex.lccode", "getlccode", "setlccode");
+ make_table(L, "uccode", "tex.uccode", "getuccode", "setuccode");
+ make_table(L, "catcode", "tex.catcode", "getcatcode", "setcatcode");
+ make_table(L, "mathcode", "tex.mathcode", "getmathcode", "setmathcode");
+ make_table(L, "delcode", "tex.delcode", "getdelcode", "setdelcode");
+ make_table(L, "lists", "tex.lists", "getlist", "setlist");
+ make_table(L, "nest", "tex.nest", "getnest", "setnest");
+ /* *INDENT-ON* */
+ init_nest_lib(L);
+ /* make the meta entries */
+ /* fetch it back */
+ luaL_newmetatable(L, "tex.meta");
+ lua_pushstring(L, "__index");
+ lua_pushcfunction(L, gettex);
+ lua_settable(L, -3);
+ lua_pushstring(L, "__newindex");
+ lua_pushcfunction(L, settex);
+ lua_settable(L, -3);
+ lua_setmetatable(L, -2); /* meta to itself */
+ /* initialize the I/O stack: */
+ spindles = xmalloc(sizeof(spindle));
+ spindle_index = 0;
+ spindles[0].head = NULL;
+ spindles[0].tail = NULL;
+ spindle_size = 1;
+ /* a somewhat odd place for this assert, maybe */
+ if (command_names[data_cmd].id != data_cmd) {
+ fatal_error("mismatch between tex and lua command name tables");
+ };
+ return 1;
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luainit.c b/Build/source/texk/web2c/luatexdir/lua/luainit.c
new file mode 100644
index 00000000000..c88ebb09656
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luainit.c
@@ -0,0 +1,1212 @@
+/*
+
+luainit.w
+
+Copyright 2006-2021 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+
+#include <kpathsea/c-stat.h>
+#include <kpathsea/cnf.h>
+
+#include "lua/luatex-api.h"
+
+#include <locale.h>
+
+extern int load_luatex_core_lua (lua_State * L);
+
+/*tex internalized strings: see luatex-api.h */
+
+set_make_keys;
+
+/*tex
+
+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|
+
+and five environment variables:
+
+ |SELFAUTOLOC| |SELFAUTODIR| |SELFAUTOPARENT| |SELFAUTOGRANDPARENT| |progname|
+
+*/
+
+const_string LUATEX_IHELP[] = {
+ "Usage: " my_name " --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS]",
+ " or: " my_name " --lua=FILE [OPTION]... \\FIRST-LINE",
+ " or: " my_name " --lua=FILE [OPTION]... &FMT ARGS",
+ " Run " MyName " on TEXNAME, usually creating TEXNAME.pdf.",
+ " Any remaining COMMANDS are processed as luatex input, after TEXNAME is read.",
+ "",
+ " Alternatively, if the first non-option argument begins with a backslash,",
+ " " my_name " interprets all non-option arguments as an input line.",
+ "",
+ " Alternatively, if the first non-option argument begins with a &, the",
+ " next word is taken as the FMT to read, overriding all else. Any",
+ " remaining arguments are processed as above.",
+ "",
+ " If no arguments or options are specified, prompt for input.",
+ "",
+ " The following regular options are understood: ",
+ "",
+ " --cnf-line =STRING parse STRING as a configuration file line",
+ " --credits display credits and exit",
+ " --debug-format enable format debugging",
+ " --draftmode switch on draft mode (generates no output PDF)",
+ " --[no-]file-line-error disable/enable file:line:error style messages",
+ " --[no-]file-line-error-style aliases of --[no-]file-line-error",
+ " --fmt=FORMAT load the format file FORMAT",
+ " --halt-on-error stop processing at the first error",
+ " --help display help and exit",
+ " --ini be ini" my_name ", for dumping formats",
+ " --interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode)",
+ " --jobname=STRING set the job name to STRING",
+ " --kpathsea-debug=NUMBER set path searching debugging flags according to the bits of NUMBER",
+ " --lua=FILE load and execute a lua initialization script",
+ " --[no-]mktex=FMT disable/enable mktexFMT generation (FMT=tex/tfm)",
+ " --nosocket disable the lua socket library",
+ " --output-comment=STRING use STRING for DVI file comment instead of date (no effect for PDF)",
+ " --output-directory=DIR use existing DIR as the directory to write files in",
+ " --output-format=FORMAT use FORMAT for job output; FORMAT is 'dvi' or 'pdf'",
+ " --progname=STRING set the program name to STRING",
+ " --recorder enable filename recorder",
+ " --safer disable easily exploitable lua commands",
+ " --[no-]shell-escape disable/enable system commands",
+ " --shell-restricted restrict system commands to a list of commands given in texmf.cnf",
+ " --synctex=NUMBER enable synctex (see man synctex)",
+ " --utc init time to UTC",
+ " --version display version and exit",
+ "",
+ "Alternate behaviour models can be obtained by special switches",
+ "",
+ " --luaonly run a lua file, then exit",
+ " --luaconly byte-compile a lua file, then exit",
+ " --luahashchars the bits used by current Lua interpreter for strings hashing",
+#ifdef LuajitTeX
+ " --jiton turns the JIT compiler on (default off)",
+ " --jithash=STRING choose the hash function for the lua strings (lua51|luajit20: default lua51)",
+#endif
+ "",
+ "See the reference manual for more information about the startup process.",
+ NULL
+};
+
+/*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;
+
+/*
+ " --8bit ignored, input is assumed to be in UTF-8 encoding",
+ " --default-translate-file=FILE ignored, input is assumed to be in UTF-8 encoding",
+ " --etex ignored, the etex extensions are always active",
+ " --disable-write18 disable \\write18{SHELL COMMAND}",
+ " --enable-write18 enable \\write18{SHELL COMMAND}",
+ " --[no-]parse-first-line ignored",
+ " --translate-file=FILE ignored, input is assumed to be in UTF-8 encoding",
+*/
+
+/*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;
+ /*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);
+ /*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;
+ /*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) {
+ FATAL1("This path points to an invalid file : %s\n", short_path);
+ }
+#endif /* __MINGW32__ */
+ return xdirname(path);
+#else /* WIN32 */
+ return kpse_selfdir(argv0);
+#endif
+}
+
+static void prepare_cmdline(lua_State * L, char **av, int ac, int zero_offset)
+{
+ int i;
+ char *s;
+ luaL_checkstack(L, ac + 3, "too many arguments to script");
+ lua_createtable(L, 0, 0);
+ for (i = 0; i < ac; i++) {
+ lua_pushstring(L, av[i]);
+ lua_rawseti(L, -2, (i - zero_offset));
+ }
+ lua_setglobal(L, "arg");
+ lua_getglobal(L, "os");
+ s = ex_selfdir(argv[0]);
+ lua_pushstring(L, s);
+ xfree(s);
+ lua_setfield(L, -2, "selfdir");
+ return;
+}
+
+int kpse_init = -1;
+
+/*tex
+
+Array and count of values given with --cnf-line.
+
+*/
+static string *user_cnf_lines = NULL;
+static unsigned user_cnf_nlines = 0;
+
+
+
+string input_name = NULL;
+
+static string user_progname = NULL;
+
+char *startup_filename = NULL;
+int lua_only = 0;
+int lua_offset = 0;
+unsigned char show_luahashchars = 0;
+
+#ifdef LuajitTeX
+int luajiton = 0;
+char *jithash_hashname = NULL;
+#endif
+
+int safer_option = 0;
+int nosocket_option = 0;
+int utc_option = 0;
+
+/*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|.
+
+*/
+
+#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[] = {
+ {"fmt", 1, 0, 0},
+ {"lua", 1, 0, 0},
+ {"luaonly", 0, 0, 0},
+ {"luahashchars", 0, 0, 0},
+#ifdef LuajitTeX
+ {"jiton", 0, 0, 0},
+ {"jithash", 1, 0, 0},
+#endif
+ {"safer", 0, &safer_option, 1},
+ {"utc", 0, &utc_option, 1},
+ {"nosocket", 0, &nosocket_option, 1},
+ {"help", 0, 0, 0},
+ {"ini", 0, &ini_version, 1},
+ {"interaction", 1, 0, 0},
+ {"halt-on-error", 0, &haltonerrorp, 1},
+ {"kpathsea-debug", 1, 0, 0},
+ {"cnf-line", 1,0 ,0},
+ {"progname", 1, 0, 0},
+ {"version", 0, 0, 0},
+ {"credits", 0, 0, 0},
+ {"recorder", 0, 0, 0},
+ {"etex", 0, 0, 0},
+ {"output-comment", 1, 0, 0},
+ {"output-directory", 1, 0, 0},
+ {"draftmode", 0, 0, 0},
+ {"output-format", 1, 0, 0},
+ {"shell-escape", 0, &shellenabledp, 1},
+ {"no-shell-escape", 0, &shellenabledp, -1},
+ {"enable-write18", 0, &shellenabledp, 1},
+ {"disable-write18", 0, &shellenabledp, -1},
+ {"shell-restricted", 0, 0, 0},
+ {"debug-format", 0, &debug_format_file, 1},
+ {"file-line-error-style", 0, &filelineerrorstylep, 1},
+ {"no-file-line-error-style", 0, &filelineerrorstylep, -1},
+ /*tex Shorter option names for the above. */
+ {"file-line-error", 0, &filelineerrorstylep, 1},
+ {"no-file-line-error", 0, &filelineerrorstylep, -1},
+ {"jobname", 1, 0, 0},
+ {"parse-first-line", 0, &parsefirstlinep, 1},
+ {"no-parse-first-line", 0, &parsefirstlinep, -1},
+ {"translate-file", 1, 0, 0},
+ {"default-translate-file", 1, 0, 0},
+ {"8bit", 0, 0, 0},
+ {"mktex", 1, 0, 0},
+ {"no-mktex", 1, 0, 0},
+ /*tex Synchronization: just like ``interaction'' above */
+ {"synctex", 1, 0, 0},
+ {0, 0, 0, 0}
+};
+
+int lua_numeric_field_by_index(lua_State * L, int name_index, int dflt)
+{
+ register int i = dflt;
+ /*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);
+ }
+ lua_pop(L, 1);
+ return i;
+}
+
+unsigned int lua_unsigned_numeric_field_by_index(lua_State * L, int name_index, int dflt)
+{
+ register unsigned int i = dflt;
+ /*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);
+ }
+ lua_pop(L, 1);
+ return i;
+}
+
+static int recorderoption = 0;
+
+static void parse_options(int ac, char **av)
+{
+#ifdef WIN32
+ /*tex We save |argc| and |argv|. */
+ int sargc = argc;
+ char **sargv = argv;
+#endif
+ /*tex The `getopt' return code. */
+ int g;
+ int option_index;
+ char *firstfile = NULL;
+ /*tex Dont whine. */
+ opterr = 0;
+#ifdef LuajitTeX
+ if ((strstr(argv[0], "luajittexlua") != NULL) ||
+ (strstr(argv[0], "texluajit") != NULL) ||
+ (strstr(argv[0], "texluahbjit") != NULL) ) {
+#else
+ if ((strstr(argv[0], "luatexlua") != NULL) ||
+ (strstr(argv[0], "texlua") != NULL) ||
+ (strstr(argv[0], "texluahb") != NULL)) {
+#endif
+ lua_only = 1;
+ luainit = 1;
+ }
+
+ for (;;) {
+ g = getopt_long_only(ac, av, "+", long_options, &option_index);
+ if (g == -1) {
+ /*tex End of arguments, exit the loop. */
+ break;
+ }
+ 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 = 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;
+ }
+#endif
+ } else if (ARGUMENT_IS("luahashchars")) {
+ show_luahashchars = 1;
+ } else if (ARGUMENT_IS("kpathsea-debug")) {
+ kpathsea_debug |= atoi(optarg);
+ } else if (ARGUMENT_IS ("cnf-line")) {
+ if (user_cnf_lines == NULL) {
+ user_cnf_nlines = 1;
+ user_cnf_lines = xmalloc (sizeof (const_string));
+ } else {
+ user_cnf_nlines++;
+ user_cnf_lines = xrealloc (user_cnf_lines,
+ user_cnf_nlines * sizeof (const_string));
+ }
+ user_cnf_lines[user_cnf_nlines-1] = xstrdup (optarg);
+ } else if (ARGUMENT_IS("progname")) {
+ user_progname = optarg;
+ } else if (ARGUMENT_IS("jobname")) {
+ c_job_name = optarg;
+ } else if (ARGUMENT_IS("fmt")) {
+ dump_name = optarg;
+ } else if (ARGUMENT_IS("output-directory")) {
+ output_directory = optarg;
+ } else if (ARGUMENT_IS("output-comment")) {
+ size_t len = strlen(optarg);
+ if (len < 256) {
+ output_comment = optarg;
+ } else {
+ WARNING2("Comment truncated to 255 characters from %d. (%s)", (int) len, optarg);
+ output_comment = (string) xmalloc(256);
+ strncpy(output_comment, optarg, 255);
+ output_comment[255] = 0;
+ }
+ } else if (ARGUMENT_IS("shell-restricted")) {
+ shellenabledp = 1;
+ restrictedshell = 1;
+ } else if (ARGUMENT_IS("output-format")) {
+ output_mode_option = 1;
+ if (strcmp(optarg, "dvi") == 0) {
+ output_mode_value = 0;
+ } else if (strcmp(optarg, "pdf") == 0) {
+ output_mode_value = 1;
+ } else {
+ WARNING1("Ignoring unknown value `%s' for --output-format",optarg);
+ output_mode_option = 0;
+ }
+ } else if (ARGUMENT_IS("draftmode")) {
+ draft_mode_option = 1;
+ draft_mode_value = 1;
+ } else if (ARGUMENT_IS("mktex")) {
+ kpse_maketex_option(optarg, true);
+ } else if (ARGUMENT_IS("no-mktex")) {
+ kpse_maketex_option(optarg, false);
+ } else if (ARGUMENT_IS("interaction")) {
+ /* These numbers match CPP defines */
+ if (STREQ(optarg, "batchmode")) {
+ interactionoption = 0;
+ } else if (STREQ(optarg, "nonstopmode")) {
+ interactionoption = 1;
+ } else if (STREQ(optarg, "scrollmode")) {
+ interactionoption = 2;
+ } else if (STREQ(optarg, "errorstopmode")) {
+ interactionoption = 3;
+ } else {
+ WARNING1("Ignoring unknown argument `%s' to --interaction", optarg);
+ }
+ } else if (ARGUMENT_IS("synctex")) {
+ /*tex Synchronize TeXnology: catching the command line option as a long */
+ synctexoption = (int) strtol(optarg, NULL, 0);
+ } else if (ARGUMENT_IS("recorder")) {
+ recorderoption = 1 ;
+ } else if (ARGUMENT_IS("help")) {
+ usagehelp(LUATEX_IHELP, BUG_ADDRESS);
+ } else if (ARGUMENT_IS("version")) {
+ print_version_banner();
+ /* *INDENT-OFF* */
+ puts("\n\nExecute '" my_name " --credits' for credits and version details.\n\n"
+ "There is NO warranty. Redistribution of this software is covered by\n"
+ "the terms of the GNU General Public License, version 2 or (at your option)\n"
+ "any later version. For more information about these matters, see the file\n"
+ "named COPYING and the LuaTeX source.\n\n"
+ "LuaTeX is Copyright 2021 Taco Hoekwater and the LuaTeX Team.\n");
+ /* *INDENT-ON* */
+ uexit(0);
+ } else if (ARGUMENT_IS("credits")) {
+ char *versions;
+ initversionstring(&versions);
+ print_version_banner();
+ /* *INDENT-OFF* */
+ puts("\n\nThe LuaTeX team is Hans Hagen, Hartmut Henkel, Taco Hoekwater, Luigi Scarso.\n\n"
+ MyName " merges and builds upon (parts of) the code from these projects:\n\n"
+ "tex : Donald Knuth\n"
+ "etex : Peter Breitenlohner, Phil Taylor and friends\n"
+ "omega : John Plaice and Yannis Haralambous\n"
+ "aleph : Giuseppe Bilotta\n"
+ "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, 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* */
+ puts(versions);
+ uexit(0);
+ }
+ }
+ /*tex attempt to find |input_name| and |dump_name| */
+ if (lua_only) {
+ if (argv[optind]) {
+ startup_filename = xstrdup(argv[optind]);
+ lua_offset = optind;
+ }
+ } else if (argv[optind] && argv[optind][0] == '&') {
+ dump_name = xstrdup(argv[optind] + 1);
+ } else if (argv[optind] && argv[optind][0] != '\\') {
+ if (argv[optind][0] == '*') {
+ input_name = xstrdup(argv[optind] + 1);
+ } else {
+ firstfile = xstrdup(argv[optind]);
+ if ((strstr(firstfile, ".lua") ==
+ firstfile + strlen(firstfile) - 4)
+ || (strstr(firstfile, ".luc") ==
+ firstfile + strlen(firstfile) - 4)
+ || (strstr(firstfile, ".LUA") ==
+ firstfile + strlen(firstfile) - 4)
+ || (strstr(firstfile, ".LUC") ==
+ firstfile + strlen(firstfile) - 4)) {
+ if (startup_filename == NULL) {
+ startup_filename = firstfile;
+ lua_offset = optind;
+ lua_only = 1;
+ luainit = 1;
+ }
+ } else {
+ input_name = firstfile;
+ }
+ }
+#ifdef WIN32
+ } else if (sargc > 1 && sargv[sargc-1] && sargv[sargc-1][0] != '-' &&
+ sargv[sargc-1][0] != '\\') {
+ if (sargv[sargc-1][0] == '&')
+ dump_name = xstrdup(sargv[sargc-1] + 1);
+ else {
+ if (sargv[sargc-1][0] == '*')
+ input_name = xstrdup(sargv[sargc-1] + 1);
+ else
+ input_name = xstrdup(sargv[sargc-1]);
+ sargv[sargc-1] = normalize_quotes(input_name, "argument");
+ }
+ if (safer_option) /* --safer implies --nosocket */
+ nosocket_option = 1;
+ return;
+#endif
+ }
+ /*tex |--safer| implies |--nosocket| */
+ if (safer_option)
+ nosocket_option = 1;
+ /*tex Finalize the input filename. */
+ if (input_name != NULL) {
+ argv[optind] = normalize_quotes(input_name, "argument");
+ }
+}
+
+/*tex
+ Test for readability.
+*/
+
+#define is_readable(a) (stat(a,&finfo)==0) \
+ && S_ISREG(finfo.st_mode) \
+ && (f=fopen(a,"r")) != NULL && !fclose(f)
+
+static char *find_filename(char *name, const char *envkey)
+{
+ struct stat finfo;
+ char *dirname = NULL;
+ char *filename = NULL;
+ FILE *f;
+ if (is_readable(name)) {
+ return name;
+ } else {
+ dirname = getenv(envkey);
+ if ((dirname != NULL) && strlen(dirname)) {
+ dirname = xstrdup(getenv(envkey));
+ if (*(dirname + strlen(dirname) - 1) == '/') {
+ *(dirname + strlen(dirname) - 1) = 0;
+ }
+ filename = xmalloc((unsigned) (strlen(dirname) + strlen(name) + 2));
+ filename = concat3(dirname, "/", name);
+ xfree(dirname);
+ if (is_readable(filename)) {
+ return filename;
+ }
+ xfree(filename);
+ }
+ }
+ return NULL;
+}
+
+static void init_kpse(void)
+{
+ if (!user_progname) {
+ user_progname = dump_name;
+ } else if (!dump_name) {
+ dump_name = user_progname;
+ }
+ if (!user_progname) {
+ if (ini_version) {
+ if (input_name) {
+ char *p = input_name + strlen(input_name) - 1;
+ while (p >= input_name) {
+ if (IS_DIR_SEP (*p)) {
+ p++;
+ input_name = p;
+ break;
+ }
+ p--;
+ }
+ user_progname = remove_suffix (input_name);
+ }
+ if (!user_progname) {
+ user_progname = kpse_program_basename(argv[0]);
+ }
+ } else {
+ if (!dump_name) {
+ dump_name = kpse_program_basename(argv[0]);
+ }
+ user_progname = dump_name;
+ }
+ }
+ kpse_set_program_enabled(kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT, kpse_src_compile);
+ kpse_set_program_name(argv[0], user_progname);
+ /*tex set up 'restrictedshell' */
+ init_shell_escape();
+ init_start_time();
+ program_name_set = 1 ;
+ if (recorderoption) {
+ recorder_enabled = 1;
+ }
+}
+
+static void fix_dumpname(void)
+{
+ int dist;
+ if (dump_name) {
+ /*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 {
+ /*tex For |dump_name| to be NULL is a bug. */
+ if (!ini_version) {
+ fprintf(stdout, "no format given, quitting\n");
+ exit(1);
+ }
+ }
+}
+
+/*tex
+ Auxiliary function for kpse search.
+*/
+
+static const char *luatex_kpse_find_aux(lua_State *L, const char *name,
+ kpse_file_format_type format, const char *errname)
+{
+ const char *filename;
+ const char *altname;
+ /*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);
+ }
+ if (filename == NULL) {
+ lua_pushfstring(L, "\n\t[kpse %s searcher] file not found: " LUA_QS, errname, name);
+ }
+ return filename;
+}
+
+/*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.
+
+ Two registry ref variables are needed: one for the actual \LUA\ function, the
+ other for its environment .
+
+*/
+
+static int lua_loader_function = 0;
+
+static int luatex_kpse_lua_find(lua_State * L)
+{
+ const char *filename;
+ const char *name;
+ name = luaL_checkstring(L, 1);
+ if (program_name_set == 0) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, lua_loader_function);
+ lua_pushvalue(L, -2);
+ lua_call(L, 1, 1);
+ return 1;
+ }
+ filename = luatex_kpse_find_aux(L, name, kpse_lua_format, "lua");
+ if (filename == NULL) {
+ /*tex library not found in this path */
+ return 1;
+ }
+ recorder_record_input(filename);
+ 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));
+ }
+ /*tex library loaded successfully */
+ return 1;
+}
+
+static int clua_loader_function = 0;
+extern int searcher_C_luatex (lua_State *L, const char *name, const char *filename);
+
+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;
+ }
+ name = luaL_checkstring(L, 1);
+ if (program_name_set == 0) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, clua_loader_function);
+ lua_pushvalue(L, -2);
+ lua_call(L, 1, 1);
+ return 1;
+ } else {
+ const char *path_saved;
+ char *prefix, *postfix, *p, *total;
+ char *extensionless;
+ char *temp_name;
+ int j;
+ filename = luatex_kpse_find_aux(L, name, kpse_clua_format, "C");
+ if (filename == NULL) {
+ /*tex library not found in this path */
+ return 1;
+ }
+ recorder_record_input(filename);
+ extensionless = strdup(filename);
+ 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') {
+ break;
+ }
+ if ((unsigned char)temp_name[j]=='.'){
+ temp_name[j]=LUA_DIRSEP[0];
+ }
+ }
+ p = strstr(extensionless, temp_name);
+ if (!p) {
+ /*tex this would be exceedingly weird */
+ return 1;
+ }
+ *p = '\0';
+ prefix = strdup(extensionless);
+ if (!prefix) {
+ /*tex allocation failure */
+ return 1;
+ }
+ postfix = strdup(p+strlen(name));
+ 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);
+ /*tex save package.path */
+ lua_getglobal(L,"package");
+ lua_getfield(L,-1,"cpath");
+ path_saved = lua_tostring(L,-1);
+ lua_pop(L,1);
+ /*tex set package.path = "?" */
+ lua_pushstring(L,total);
+ lua_setfield(L,-2,"cpath");
+ /*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);
+ /*tex restore package.path */
+ lua_getglobal(L,"package");
+ lua_pushstring(L,path_saved);
+ lua_setfield(L,-2,"cpath");
+ /*tex pop ``package'' */
+ lua_pop(L,1);
+ free(extensionless);
+ free(total);
+ free(temp_name);
+ return 1;
+ }
+}
+
+/*tex
+
+ Setting up the new search functions. This replaces package.searchers[2] and
+ package.searchers[3] with the functions defined above.
+
+*/
+
+static void setup_lua_path(lua_State * L)
+{
+ lua_getglobal(L, "package");
+#ifdef LuajitTeX
+ lua_getfield(L, -1, "loaders");
+#else
+ lua_getfield(L, -1, "searchers");
+#endif
+ /*tex package.searchers[2] */
+ lua_rawgeti(L, -1, 2);
+ lua_loader_function = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pushcfunction(L, luatex_kpse_lua_find);
+ /*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);
+ /*tex replace the normal lua lib loader */
+ lua_rawseti(L, -2, 3);
+ /*tex pop the array and table */
+ lua_pop(L, 2);
+}
+
+/*tex
+
+ Helper variables for the safe keeping of table ids.
+
+*/
+
+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_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 offset, int max)
+{
+ int i;
+ lua_newtable(L);
+ for (i = 0; i < max; i++) {
+ lua_pushinteger(L,i+offset);
+ lua_pushstring(L, list[i]);
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+int lua_show_valid_keys(lua_State *L, int *list, int max)
+{
+ int i;
+ lua_newtable(L);
+ for (i = 0; i < max; i++) {
+ lua_pushinteger(L,i+1);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, list[i]);
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
+char **suffixlist;
+
+/* 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"
+
+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");
+ /*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++;
+ q = r;
+ }
+ if (*q)
+ n++;
+ suffixlist = (char **) xmalloc((n + 2) * sizeof(char *));
+ p = suffixlist;
+ *p = xstrdup(".dll");
+ p++;
+ q = v;
+ while ((r = strchr(q, ';')) != NULL) {
+ *r = '\0';
+ *p = xstrdup(q);
+ p++;
+ r++;
+ q = r;
+ }
+ if (*q) {
+ *p = xstrdup(q);
+ p++;
+ }
+ *p = NULL;
+ free(v);
+}
+#endif
+
+void lua_initialize(int ac, char **av)
+{
+ char *given_file = NULL;
+ char *banner;
+ size_t len;
+ int starttime;
+ int utc;
+ static char LC_CTYPE_C[] = "LC_CTYPE=C";
+ static char LC_COLLATE_C[] = "LC_COLLATE=C";
+ static char LC_NUMERIC_C[] = "LC_NUMERIC=C";
+ static char engine_luatex[] = "engine=" my_name;
+ char *old_locale = NULL;
+ char *env_locale = NULL;
+ char *tmp = NULL;
+ /*tex Save to pass along to topenin. */
+ const char *fmt = "This is " MyName ", Version %s" WEB2CVERSION;
+ argc = ac;
+ argv = av;
+ len = strlen(fmt) + strlen(luatex_version_string) ;
+ banner = xmalloc(len);
+ sprintf(banner, fmt, luatex_version_string);
+ luatex_banner = banner;
+ kpse_invocation_name = kpse_program_basename(argv[0]);
+ /*tex be `luac' */
+ if (argc >1) {
+#ifdef LuajitTeX
+ if (FILESTRCASEEQ(kpse_invocation_name, "texluajitc"))
+ exit(luac_main(ac, av));
+ if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
+ char *argv1 = xmalloc (strlen ("luajittex") + 1);
+ av[1] = argv1;
+ strcpy (av[1], "luajittex");
+ exit(luac_main(--ac, ++av));
+ }
+#else
+ if (FILESTRCASEEQ(kpse_invocation_name, "texluac"))
+ exit(luac_main(ac, av));
+ if (STREQ(argv[1], "--luaconly") || STREQ(argv[1], "--luac")) {
+ strcpy(av[1], "luatex");
+ exit(luac_main(--ac, ++av));
+ }
+#endif
+ }
+#if defined(WIN32) || defined(__MINGW32__) || defined(__CYGWIN__)
+ mk_suffixlist();
+#endif
+ /*tex Must be initialized before options are parsed and might get adapted by config table. */
+ interactionoption = 4;
+ filelineerrorstylep = false;
+ haltonerrorp = false;
+ tracefilenames = 1;
+ dump_name = NULL;
+ /*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;
+ /*tex parse commandline */
+ parse_options(ac, av);
+ if (lua_only) {
+ /*tex Shell has no restrictions. */
+ shellenabledp = true;
+ restrictedshell = false;
+ safer_option = 0;
+ }
+ /*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) {
+ /*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);
+ }
+ tmp = setlocale (LC_CTYPE, NULL);
+ if (tmp) {
+ lc_ctype = xstrdup(tmp);
+ }
+ tmp = setlocale (LC_COLLATE, NULL);
+ if (tmp) {
+ lc_collate = 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);
+ }
+ xfree(old_locale);
+ } else {
+ fprintf(stderr,"Unable to store environment locale.\n");
+ }
+ /*tex make sure that the locale is 'sane' (for lua) */
+ putenv(LC_CTYPE_C);
+ putenv(LC_COLLATE_C);
+ putenv(LC_NUMERIC_C);
+ /*tex this is sometimes needed */
+ putenv(engine_luatex);
+ /*tex add user's cnf values*/
+ if (user_cnf_lines) {
+ unsigned i;
+ for (i = 0; i < user_cnf_nlines; i++) {
+ /* debug printf ("ucnf%d: %s\n", i, user_cnf_lines[i]); */
+ kpathsea_cnf_line_env_progname (kpse_def, user_cnf_lines[i]);
+ free (user_cnf_lines[i]);
+ }
+ }
+ luainterpreter();
+ /*tex init internalized strings */
+ set_init_keys;
+ lua_pushstring(Luas,"lua.functions");
+ lua_newtable(Luas);
+ lua_settable(Luas,LUA_REGISTRYINDEX);
+ /*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;
+ /*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);
+ }
+ startup_filename = find_filename(given_file, "LUATEXDIR");
+ }
+ /*tex now run the file */
+ if (startup_filename != NULL) {
+ char *v1;
+ int tex_table_id = hide_lua_table(Luas, "tex");
+ int token_table_id = hide_lua_table(Luas, "token");
+ int node_table_id = hide_lua_table(Luas, "node");
+ int pdf_table_id = hide_lua_table(Luas, "pdf");
+ if (lua_only) {
+ /*tex hide the 'tex' and 'pdf' table */
+ if (load_luatex_core_lua(Luas)) {
+ fprintf(stderr, "Error in execution of luatex-core.lua .\n");
+ }
+ if (luaL_loadfile(Luas, startup_filename)) {
+ fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+ exit(1);
+ }
+ init_tex_table(Luas);
+ if (lua_pcall(Luas, 0, 0, 0)) {
+ fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+ lua_traceback(Luas);
+ /*tex lua_close(Luas); */
+ exit(1);
+ } else {
+ if (given_file)
+ free(given_file);
+ /*tex lua_close(Luas); */
+ exit(0);
+ }
+ }
+ /*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);
+ unhide_lua_table(Luas, "token", token_table_id);
+ unhide_lua_table(Luas, "node", node_table_id);
+ if (luaL_loadfile(Luas, startup_filename)) {
+ fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+ exit(1);
+ }
+ if (lua_pcall(Luas, 0, 0, 0)) {
+ fprintf(stdout, "%s\n", lua_tostring(Luas, -1));
+ lua_traceback(Luas);
+ exit(1);
+ }
+ if (!input_name) {
+ get_lua_string("texconfig", "jobname", &input_name);
+ }
+ if (!dump_name) {
+ get_lua_string("texconfig", "formatname", &dump_name);
+ }
+ kpse_init = -1;
+ get_lua_boolean("texconfig", "kpse_init", &kpse_init);
+ if (kpse_init != 0) {
+ /*tex re-enable loading of texmf.cnf values, see luatex.ch */
+ luainit = 0;
+ init_kpse();
+ kpse_init = 1;
+ }
+ /*tex |prohibit_file_trace| (boolean) */
+ get_lua_boolean("texconfig", "trace_file_names", &tracefilenames);
+ /*tex |file_line_error| */
+ get_lua_boolean("texconfig", "file_line_error", &filelineerrorstylep);
+ /*tex |halt_on_error| */
+ get_lua_boolean("texconfig", "halt_on_error", &haltonerrorp);
+ /*tex |interactionoption| */
+ get_lua_number("texconfig", "interaction", &interactionoption);
+ if ((interactionoption < 0) || (interactionoption > 4)) {
+ interactionoption = 4;
+ }
+ /*tex |restrictedshell| */
+ v1 = NULL;
+ get_lua_string("texconfig", "shell_escape", &v1);
+ if (v1) {
+ if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
+ shellenabledp = 1;
+ } else if (*v1 == 'p') {
+ shellenabledp = 1;
+ restrictedshell = 1;
+ }
+ free(v1);
+ }
+ /*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);
+ if (v1) {
+ mk_shellcmdlist(v1);
+ 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.
+ */
+ get_lua_number("texconfig", "SOURCE_DATE_EPOCH", &starttime);
+ }
+ 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 {
+ /* 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");
+ }
+}
+
+void check_texconfig_init(void)
+{
+ if (Luas != NULL) {
+ lua_getglobal(Luas, "texconfig");
+ if (lua_istable(Luas, -1)) {
+ lua_getfield(Luas, -1, "init");
+ if (lua_isfunction(Luas, -1)) {
+ int i = lua_pcall(Luas, 0, 0, 0);
+ if (i != 0) {
+ /*tex
+ We can't be more precise hereas it's called before \TEX\
+ initialization happens.
+ */
+ fprintf(stderr, "This went wrong: %s\n", lua_tostring(Luas, -1));
+ error();
+ }
+ }
+ }
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luanode.c b/Build/source/texk/web2c/luatexdir/lua/luanode.c
new file mode 100644
index 00000000000..502c407079e
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luanode.c
@@ -0,0 +1,467 @@
+/*
+
+luanode.w
+
+Copyright 2006-2008 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+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) {
+ lua_settop(Luas, s_top);
+ return;
+ }
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, s_top);
+ return;
+ }
+ 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);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return;
+ }
+ lua_settop(Luas, s_top);
+ return;
+}
+
+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);
+ if (head_node == null || callback_id <= 0) {
+ lua_settop(Luas, s_top);
+ return;
+ }
+ /*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;
+ }
+ /*tex We make sure we have no prev */
+ alink(start_node) = null ;
+ /*tex the action */
+ nodelist_to_lua(Luas, start_node);
+ lua_push_group_code(Luas,extrainfo);
+ 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);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return;
+ }
+ /*tex the result */
+ if (lua_isboolean(Luas, -1)) {
+ if (lua_toboolean(Luas, -1) != 1) {
+ /*tex discard */
+ flush_node_list(start_node);
+ vlink(head_node) = null;
+ } else {
+ /*tex keep */
+ }
+ } else {
+ /*tex append to old head */
+ start_done = nodelist_from_lua(Luas,-1);
+ try_couple_nodes(head_node,start_done);
+ }
+ /*tex redundant as we set top anyway */
+ lua_pop(Luas, 2);
+ /*tex find tail in order to update tail */
+ start_node = vlink(head_node);
+ if (start_node != null) {
+ /*tex maybe just always slide (harmless and fast) */
+ if (fix_node_lists) {
+ /*tex slides and returns last node */
+ *tail_node = fix_node_list(start_node);
+ } else {
+ last_node = vlink(start_node);
+ while (last_node != null) {
+ start_node = last_node;
+ last_node = vlink(start_node);
+ }
+ /*tex we're at the end now */
+ *tail_node = start_node;
+ }
+ } else {
+ /*tex we're already at the end */
+ *tail_node = head_node;
+ }
+ /*tex clean up */
+ lua_settop(Luas, s_top);
+ return;
+}
+
+int lua_linebreak_callback(int is_broken, halfword head_node, halfword * new_head)
+{
+ int a, i;
+ register halfword *p;
+ 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) {
+ lua_settop(Luas, s_top);
+ return ret;
+ }
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, s_top);
+ return ret;
+ }
+ 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);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return ret;
+ }
+ /*tex This should prevent a stack overflow (see r6689), */
+ /*tex but as side effect it discards the ouput */
+ /*tex of the linebreak_filter, see [Dev-luatex] linebreak_filter */
+ /*tex lua_settop(Luas, s_top);*/
+ p = lua_touserdata(Luas, -1);
+ if (p != NULL) {
+ a = nodelist_from_lua(Luas,-1);
+ try_couple_nodes(*new_head,a);
+ ret = 1;
+ }
+ /*tex re-inserted this line */
+ lua_settop(Luas, s_top);
+ return ret;
+}
+
+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) {
+ lua_settop(Luas, s_top);
+ return 0;
+ }
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, s_top);
+ return 0;
+ }
+ nodelist_to_lua(Luas, box);
+ lua_push_string_by_index(Luas,location);
+ lua_pushinteger(Luas, (int) prev_depth);
+ lua_pushboolean(Luas, is_mirrored);
+ 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);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return 0;
+ }
+ if (lua_type(Luas, -2) == LUA_TUSERDATA) {
+ p = check_isnode(Luas, -2);
+ *result = *p;
+ } else if (lua_type(Luas, -2) == LUA_TNIL) {
+ *result = null;
+ } else {
+ normal_warning("append to vlist","error: node or nil expected");
+ }
+ if (lua_type(Luas, -1) == LUA_TNUMBER) {
+ *next_depth = lua_roundnumber(Luas, -1);
+ *prev_set = 1;
+ }
+ return 1;
+}
+
+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);
+ if (head_node == null || callback_id <= 0) {
+ lua_settop(Luas, s_top);
+ return head_node;
+ }
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, s_top);
+ return head_node;
+ }
+ alink(head_node) = null ;
+ nodelist_to_lua(Luas, head_node);
+ lua_push_group_code(Luas,extrainfo);
+ lua_pushinteger(Luas, size);
+ lua_push_pack_type(Luas, pack_type);
+ if (pack_direction >= 0) {
+ lua_push_dir_par(Luas, pack_direction);
+ } else {
+ lua_pushnil(Luas);
+ }
+ if (attr != null) {
+ nodelist_to_lua(Luas, attr);
+ } else {
+ lua_pushnil(Luas);
+ }
+ 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);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return head_node;
+ }
+ ret = head_node;
+ if (lua_isboolean(Luas, -1)) {
+ if (lua_toboolean(Luas, -1) != 1) {
+ flush_node_list(head_node);
+ ret = null;
+ }
+ } else {
+ ret = nodelist_from_lua(Luas,-1);
+ }
+ lua_settop(Luas, s_top);
+ if (fix_node_lists)
+ fix_node_list(ret);
+ return ret;
+}
+
+halfword lua_vpack_filter(halfword head_node, scaled size, int pack_type, scaled maxd,
+ 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) {
+ callback_id = callback_defined(pre_output_filter_callback);
+ } else {
+ callback_id = callback_defined(vpack_filter_callback);
+ }
+ if (callback_id <= 0) {
+ lua_settop(Luas, s_top);
+ return head_node;
+ }
+ if (!get_callback(Luas, callback_id)) {
+ lua_settop(Luas, s_top);
+ return head_node;
+ }
+ alink(head_node) = null ;
+ nodelist_to_lua(Luas, head_node);
+ lua_push_group_code(Luas, extrainfo);
+ lua_pushinteger(Luas, size);
+ lua_push_pack_type(Luas, pack_type);
+ lua_pushinteger(Luas, maxd);
+ if (pack_direction >= 0) {
+ lua_push_dir_par(Luas, pack_direction);
+ } else {
+ lua_pushnil(Luas);
+ }
+ if (attr != null) {
+ nodelist_to_lua(Luas, attr);
+ } else {
+ lua_pushnil(Luas);
+ }
+ if ((i=lua_pcall(Luas, 7, 1, 0)) != 0) {
+ formatted_warning("vpack filter", "error: %s", lua_tostring(Luas, -1));
+ lua_settop(Luas, s_top);
+ luatex_error(Luas, (i == LUA_ERRRUN ? 0 : 1));
+ return head_node;
+ }
+ ret = head_node;
+ if (lua_isboolean(Luas, -1)) {
+ if (lua_toboolean(Luas, -1) != 1) {
+ flush_node_list(head_node);
+ ret = null;
+ }
+ } else {
+ ret = nodelist_from_lua(Luas,-1);
+ }
+ lua_settop(Luas, s_top);
+ if (fix_node_lists)
+ fix_node_list(ret);
+ return ret;
+}
+
+/*tex
+
+ This is a quick hack to fix \ETEX's \.{\\lastnodetype} now that there are many
+ more visible node types.
+
+*/
+
+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)) {
+ /*tex old ligature value */
+ return 7;
+ } else {
+ /*tex old character value */
+ return 0;
+ }
+}
+
+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);
+ 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);
+}
+
+void copy_pdf_literal(pointer r, pointer p)
+{
+ int t = pdf_literal_type(p);
+ pdf_literal_type(r) = t;
+ pdf_literal_mode(r) = pdf_literal_mode(p);
+ if (t == normal) {
+ pdf_literal_data(r) = pdf_literal_data(p);
+ add_token_ref(pdf_literal_data(p));
+ } 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);
+ }
+}
+
+void copy_late_lua(pointer r, pointer 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 (t == normal) {
+ late_lua_data(r) = late_lua_data(p);
+ add_token_ref(late_lua_data(p));
+ } else if (t == lua_refid_literal) {
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, late_lua_data(p));
+ late_lua_data(r) = luaL_ref(Luas, LUA_REGISTRYINDEX);
+ }
+}
+
+void copy_user_lua(pointer r, pointer p)
+{
+ if (user_node_value(p) != 0) {
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, user_node_value(p));
+ user_node_value(r) = luaL_ref(Luas, LUA_REGISTRYINDEX);
+ }
+}
+
+void free_pdf_literal(pointer p)
+{
+ int t = pdf_literal_type(p);
+ if (t == normal) {
+ delete_token_ref(pdf_literal_data(p));
+ } 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 (t == normal) {
+ delete_token_ref(late_lua_data(p));
+ } else if (t == lua_refid_literal) {
+ luaL_unref(Luas, LUA_REGISTRYINDEX, late_lua_data(p));
+ }
+}
+
+void free_user_lua(pointer p)
+{
+ if (user_node_value(p) != 0) {
+ luaL_unref(Luas, LUA_REGISTRYINDEX, user_node_value(p));
+ }
+}
+
+void show_pdf_literal(pointer p)
+{
+ int t = pdf_literal_type(p);
+ tprint_esc("pdfliteral");
+ switch (pdf_literal_mode(p)) {
+ case set_origin:
+ tprint(" origin");
+ break;
+ case direct_page:
+ tprint(" page");
+ break;
+ case direct_always:
+ tprint(" direct");
+ break;
+ case direct_raw:
+ tprint(" raw");
+ break;
+ default:
+ tprint(" <invalid mode>");
+ break;
+ }
+ if (t == normal) {
+ print_mark(pdf_literal_data(p));
+ } else if (t == lua_refid_literal) {
+ tprint(" <lua data reference ");
+ print_int(pdf_literal_data(p));
+ tprint(">");
+ } else {
+ tprint(" <invalid data>");
+ }
+}
+
+void show_late_lua(pointer p)
+{
+ int t = late_lua_type(p);
+ tprint_esc("latelua");
+ print_int(late_lua_reg(p));
+ if (t == normal) {
+ print_mark(late_lua_data(p));
+ } else if (t == lua_refid_literal) {
+ tprint(" <function reference ");
+ print_int(late_lua_data(p));
+ tprint(">");
+ } else if (t == lua_refid_call) {
+ tprint(" <functioncall reference ");
+ print_int(late_lua_data(p));
+ tprint(">");
+ } else {
+ tprint(" <invalid data>");
+ }
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/luastuff.c b/Build/source/texk/web2c/luatexdir/lua/luastuff.c
new file mode 100644
index 00000000000..fb05c60dd1f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luastuff.c
@@ -0,0 +1,760 @@
+/*
+
+luastuff.w
+
+Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+#ifdef LuajitTeX
+#include "lua/lauxlib_bridge.h"
+#endif
+
+lua_State *Luas = NULL;
+
+int luastate_bytes = 0;
+int lua_active = 0;
+
+#ifdef LuajitTeX
+#define Luas_load(Luas,getS,ls,lua_id) \
+ lua_load(Luas,getS,ls,lua_id);
+#define Luas_open(name,luaopen_lib) \
+ lua_pushcfunction(L, luaopen_lib); \
+ lua_pushstring(L, name); \
+ lua_call(L, 1, 0);
+#else
+#define Luas_load(Luas,getS,ls,lua_id) \
+ lua_load(Luas,getS,ls,lua_id,NULL);
+#define Luas_open(name,luaopen_lib) \
+ luaL_requiref(L, name, luaopen_lib, 1); \
+ lua_pop(L, 1);
+#endif
+
+void make_table(lua_State * L, const char *tab, const char *mttab, const char *getfunc, const char *setfunc)
+{
+ /*tex make the table *//* |[{<tex>}]| */
+ /*tex |[{<tex>},"dimen"]| */
+ lua_pushstring(L, tab);
+ /*tex |[{<tex>},"dimen",{}]| */
+ lua_newtable(L);
+ /*tex |[{<tex>}]| */
+ lua_settable(L, -3);
+ /*tex fetch it back */
+ /*tex |[{<tex>},"dimen"]| */
+ lua_pushstring(L, tab);
+ /*tex |[{<tex>},{<dimen>}]| */
+ lua_gettable(L, -2);
+ /*tex make the meta entries */
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ luaL_newmetatable(L, mttab);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index"]| */
+ lua_pushstring(L, "__index");
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index","getdimen"]| */
+ lua_pushstring(L, getfunc);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__index",<tex.getdimen>]| */
+ lua_gettable(L, -5);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ lua_settable(L, -3);
+ lua_pushstring(L, "__newindex"); /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex"]| */
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex","setdimen"]| */
+ lua_pushstring(L, setfunc);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>},"__newindex",<tex.setdimen>]| */
+ lua_gettable(L, -5);
+ /*tex |[{<tex>},{<dimen>},{<dimen_m>}]| */
+ lua_settable(L, -3);
+ /*tex |[{<tex>},{<dimen>}]| : assign the metatable */
+ lua_setmetatable(L, -2);
+ /*tex |[{<tex>}]| : clean the stack */
+ lua_pop(L, 1);
+}
+
+static const char *getS(lua_State * L, void *ud, size_t * size)
+{
+ LoadS *ls = (LoadS *) ud;
+ (void) L;
+ if (ls->size == 0)
+ return NULL;
+ *size = ls->size;
+ ls->size = 0;
+ return ls->s;
+}
+
+#ifdef LuajitTeX
+ /*
+ \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;
+ /*tex define |ud| for -Wunused */
+ (void) ud;
+ if (nsize == 0)
+ free(ptr);
+ else
+ ret = realloc(ptr, nsize);
+ luastate_bytes += (int) (nsize - osize);
+ return ret;
+}
+#endif
+
+static int my_luapanic(lua_State * L)
+{
+ /*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;
+}
+
+void luafunctioncall(int slot)
+{
+ int i ;
+ int stacktop = lua_gettop(Luas);
+ lua_active++;
+ lua_rawgeti(Luas, LUA_REGISTRYINDEX, lua_key_index(lua_functions));
+ lua_gettable(Luas, LUA_REGISTRYINDEX);
+ lua_rawgeti(Luas, -1,slot);
+ if (lua_isfunction(Luas,-1)) {
+ /*tex function index */
+ int base = lua_gettop(Luas);
+ lua_pushinteger(Luas, slot);
+ /* 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);
+ /*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--;
+}
+
+static const luaL_Reg lualibs[] = {
+ /*tex standard \LUA\ libraries */
+ { "_G", luaopen_base },
+ { "package", luaopen_package },
+ { "table", luaopen_table },
+ { "io", luaopen_io },
+ { "os", luaopen_os },
+ { "string", luaopen_string },
+ { "math", luaopen_math },
+ { "debug", luaopen_debug },
+ { "lpeg", luaopen_lpeg },
+ { "bit32", luaopen_bit32 },
+#ifdef LuajitTeX
+ /*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
+ /*tex additional (public) libraries */
+ { "unicode", luaopen_unicode },
+ { "zip", luaopen_zip },
+ { "md5", luaopen_md5 },
+ { "sha2", luaopen_sha2 },
+ { "lfs", luaopen_lfs },
+ /*tex extra standard lua libraries */
+#ifdef LuajitTeX
+ { "jit", luaopen_jit },
+#endif
+ { "ffi", luaopen_ffi },
+ /*tex more libraries will be loaded later */
+#ifdef LUATEX_HARFBUZZ_ENABLED
+ { "luaharfbuzz", luaopen_luaharfbuzz },
+#endif
+ { NULL, NULL }
+};
+
+static void do_openlibs(lua_State * L)
+{
+ const luaL_Reg *lib = lualibs;
+ for (; lib->func; lib++) {
+ Luas_open(lib->name,lib->func);
+ }
+}
+
+#ifdef LuajitTeX
+ /*tex in \LUAJIT\ |load_aux| is not used.*/
+#else
+static int load_aux (lua_State *L, int status) {
+ if (status == 0)
+ /*tex okay */
+ return 1;
+ else {
+ /*tex return nil plus error message */
+ lua_pushnil(L);
+ /*tex put before error message */
+ lua_insert(L, -2);
+ return 2;
+ }
+}
+#endif
+
+static int luatex_loadfile (lua_State *L) {
+ int status = 0;
+ const char *fname = luaL_optstring(L, 1, NULL);
+ const char *mode = luaL_optstring(L, 2, NULL);
+#ifdef LuajitTeX
+ /* 5.1 */
+#else
+ /*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;
+ }
+ status = luaL_loadfilex(L, fname, mode);
+ if (status == LUA_OK) {
+ recorder_record_input(fname);
+#ifdef LuajitTeX
+ /* 5.1 */
+#else
+ if (env) {
+ /*tex the |env| parameter */
+ lua_pushvalue(L, 3);
+ /*tex set it as first upvalue of loaded chunk */
+ lua_setupvalue(L, -2, 1);
+ }
+#endif
+ }
+#ifdef LuajitTeX
+ return RESERVED_load_aux_JIT(L, status,3);
+#else
+ return load_aux(L, status);
+#endif
+}
+
+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;
+ } else {
+ tprint_nl("lua> ");
+ }
+ }
+ if (luaL_loadfile(L, fname) != 0)
+ lua_error(L);
+ recorder_record_input(fname);
+ lua_call(L, 0, LUA_MULTRET);
+ return lua_gettop(L) - n;
+}
+
+void luainterpreter(void)
+{
+ lua_State *L;
+#ifdef LuajitTeX
+ if (jithash_hashname == NULL) {
+ /*tex default lua51 */
+ luajittex_choose_hash_function = 0;
+ jithash_hashname = (char *) xmalloc(strlen("lua51") + 1);
+ jithash_hashname = strcpy ( jithash_hashname, "lua51");
+ } else if (strcmp((const char*)jithash_hashname,"lua51") == 0) {
+ luajittex_choose_hash_function = 0;
+ } else if (strcmp((const char*)jithash_hashname,"luajit20") == 0) {
+ luajittex_choose_hash_function = 1;
+ } else {
+ /*tex default lua51 */
+ luajittex_choose_hash_function = 0;
+ jithash_hashname = strcpy ( jithash_hashname, "lua51");
+ }
+ L = luaL_newstate() ;
+#else
+ L = lua_newstate(my_luaalloc, NULL);
+#endif
+ if (L == NULL) {
+ fprintf(stderr, "Can't create the Lua state.\n");
+ return;
+ }
+ lua_atpanic(L, &my_luapanic);
+ /*tex This initializes all the `simple' libraries: */
+ do_openlibs(L);
+#ifdef LuajitTeX
+ if (luajiton){
+ luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE|LUAJIT_MODE_ON);
+ }
+ else {
+ 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);
+ /*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");
+ lua_getfield(L, -1, "loaded");
+ if (!lua_istable(L, -1)) {
+ lua_newtable(L);
+ 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");
+ /*tex |package.loaded.mime = nil| */
+ luaopen_mime_core(L);
+ lua_setfield(L, -2, "mime.core");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "mime");
+ /*tex pop the tables */
+ lua_pop(L, 2);
+ /*tex preload the pure \LUA\ modules */
+ luatex_socketlua_open(L);
+ }
+ luaopen_zlib(L);
+ luaopen_gzip(L);
+ /*tex our own libraries register themselves */
+ luaopen_fio(L);
+ luaopen_ff(L);
+ luaopen_tex(L);
+ luaopen_token(L);
+ luaopen_node(L);
+ 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_pdfe(L);
+ luaopen_pdfscanner(L);
+ if (!lua_only) {
+ luaopen_img(L);
+ }
+ lua_createtable(L, 0, 0);
+ lua_setglobal(L, "texconfig");
+ Luas = L;
+}
+
+int hide_lua_table(lua_State * L, const char *name)
+{
+ int r = 0;
+ lua_getglobal(L, name);
+ if (lua_istable(L, -1)) {
+ r = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pushnil(L);
+ lua_setglobal(L, name);
+ }
+ return r;
+}
+
+void unhide_lua_table(lua_State * L, const char *name, int r)
+{
+ lua_rawgeti(L, LUA_REGISTRYINDEX, r);
+ lua_setglobal(L, name);
+ luaL_unref(L, LUA_REGISTRYINDEX, r);
+}
+
+int hide_lua_value(lua_State * L, const char *name, const char *item)
+{
+ int r = 0;
+ lua_getglobal(L, name);
+ if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, item);
+ r = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pushnil(L);
+ lua_setfield(L, -2, item);
+ }
+ return r;
+}
+
+void unhide_lua_value(lua_State * L, const char *name, const char *item, int r)
+{
+ lua_getglobal(L, name);
+ if (lua_istable(L, -1)) {
+ lua_rawgeti(L, LUA_REGISTRYINDEX, r);
+ lua_setfield(L, -2, item);
+ luaL_unref(L, LUA_REGISTRYINDEX, r);
+ }
+}
+
+int lua_traceback(lua_State * L)
+{
+ lua_getglobal(L, "debug");
+ if (!lua_istable(L, -1)) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ lua_getfield(L, -1, "traceback");
+ if (!lua_isfunction(L, -1)) {
+ lua_pop(L, 2);
+ return 1;
+ }
+ /*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;
+}
+
+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();
+ }
+ lua_active++;
+ if (is_string) {
+ const char *ss = NULL;
+ 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);
+ ++late_callback_count;
+ i = lua_pcall(Luas, 0, 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));
+ }
+ lua_settop(Luas,stacktop);
+ lua_active--;
+ return ;
+ }
+ ss = lua_tolstring(Luas, -1, &ll);
+ s = xmalloc(ll+1);
+ memcpy(s,ss,ll+1);
+ lua_pop(Luas,1);
+ } else {
+ int l = 0;
+ s = tokenlist_to_cstring(p, 1, &l);
+ ll = (size_t)l;
+ }
+ ls.s = s;
+ ls.size = ll;
+ if (ls.size > 0) {
+ if (nameptr > 0) {
+ /*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);
+ } else if (nameptr < 0) {
+ lua_id = get_lua_name((nameptr + 65536));
+ if (lua_id != NULL) {
+ i = Luas_load(Luas, getS, &ls, lua_id);
+ } else {
+ i = Luas_load(Luas, getS, &ls, "=[\\latelua]");
+ }
+ } else {
+ i = Luas_load(Luas, getS, &ls, "=[\\latelua]");
+ }
+ if (i != 0) {
+ Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
+ } else {
+ /*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);
+ ++late_callback_count;
+ i = lua_pcall(Luas, 0, 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));
+ }
+ }
+ 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--;
+}
+
+void late_lua(PDF pdf, halfword p)
+{
+ halfword t;
+ (void) pdf;
+ 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 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. */
+ }
+}
+
+void luatokencall(int p, int nameptr)
+{
+ LoadS ls;
+ int i;
+ int l = 0;
+ char *s = NULL;
+ char *lua_id;
+ int stacktop = lua_gettop(Luas);
+ lua_active++;
+ s = tokenlist_to_cstring(p, 1, &l);
+ ls.s = s;
+ ls.size = (size_t) l;
+ if (ls.size > 0) {
+ if (nameptr > 0) {
+ lua_id = tokenlist_to_cstring(nameptr, 1, &l);
+ i = Luas_load(Luas, getS, &ls, lua_id);
+ xfree(lua_id);
+ } else if (nameptr < 0) {
+ lua_id = get_lua_name((nameptr + 65536));
+ if (lua_id != NULL) {
+ i = Luas_load(Luas, getS, &ls, lua_id);
+ } else {
+ i = Luas_load(Luas, getS, &ls, "=[\\directlua]");
+ }
+ } else {
+ i = Luas_load(Luas, getS, &ls, "=[\\directlua]");
+ }
+ xfree(s);
+ if (i != 0) {
+ Luas = luatex_error(Luas, (i == LUA_ERRSYNTAX ? 0 : 1));
+ } else {
+ /*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);
+ ++direct_callback_count;
+ i = lua_pcall(Luas, 0, 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));
+ }
+ }
+ }
+ lua_settop(Luas,stacktop);
+ lua_active--;
+}
+
+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);
+ /*tex
+ Free the last one.
+ */
+ err = (char *) xmalloc((unsigned) (luaerr.l + 1));
+ snprintf(err, (luaerr.l + 1), "%s", luaerr.s);
+ /*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
+ */
+ normal_error("lua",err);
+ /*tex
+ This is never reached.
+ */
+ lua_close(L);
+ return (lua_State *) NULL;
+ } else {
+ normal_warning("lua",err);
+ return L;
+ }
+}
+
+void preset_environment(lua_State * L, const parm_struct * p, const char *s)
+{
+ int i;
+ assert(L != NULL);
+ /*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);
+ /*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);
+ /*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);
+ /* tex state: - */
+}
+
+/*tex
+ Here comes a \LUAJIT\ compatibility layer for \LUATEX\ \LUA5.2:
+*/
+
+#ifdef LuajitTeX
+
+LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
+ lua_State *L = B->L;
+ if (sz > LUAL_BUFFERSIZE )
+ luaL_error(L, "buffer too large");
+ return luaL_prepbuffer(B) ;
+}
+
+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)) {*/
+ 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;
+}
+
+#endif
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatex-api.h b/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
new file mode 100644
index 00000000000..5f42bd5895c
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luatex-api.h
@@ -0,0 +1,2727 @@
+/* luatex-api.h
+
+ Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
+
+ This file is part of LuaTeX.
+
+ LuaTeX is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LUATEX_API_H
+# define LUATEX_API_H 1
+
+/* output modes, a bad place but this compiles at least */
+
+typedef enum { OMODE_NONE, OMODE_DVI, OMODE_PDF } output_mode ;
+
+# define MAX_OMODE 2 /* largest index in enum output_mode */
+
+extern int output_mode_used;
+extern int output_mode_option;
+extern int output_mode_value;
+extern int draft_mode_option;
+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 */
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <stdarg.h>
+# include "lua.h"
+# include "lauxlib.h"
+# include "lualib.h"
+#ifdef LuajitTeX
+# include "luajit.h"
+#endif
+
+/* Names */
+#ifndef LUATEX_HARFBUZZ_ENABLED
+#ifdef LuajitTeX
+# define MyName "LuajitTeX"
+# define my_name "luajittex"
+#else
+# define MyName "LuaTeX"
+# define my_name "luatex"
+#endif
+#endif
+
+#ifdef LUATEX_HARFBUZZ_ENABLED
+#ifdef LuajitTeX
+# define MyName "LuajitHBTeX"
+# define my_name "luajithbtex"
+#else
+# define MyName "LuaHBTeX"
+# define my_name "luahbtex"
+#endif
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct LoadS {
+ char *s;
+ size_t size;
+} 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 int luac_main(int argc, char *argv[]);
+
+extern int luaopen_tex(lua_State * L);
+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);
+
+extern int luaopen_unicode(lua_State * L);
+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);
+#endif
+
+#ifdef LUATEX_HARFBUZZ_ENABLED
+extern int luaopen_luaharfbuzz(lua_State * L);
+#endif
+
+extern int luaopen_zlib(lua_State * L);
+extern int luaopen_gzip(lua_State * L);
+extern int luaopen_ff(lua_State * L);
+extern int luaopen_profiler(lua_State * L);
+
+extern int luaopen_socket_core(lua_State * L);
+extern int luaopen_mime_core(lua_State * L);
+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_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 initfilecallbackids(int max);
+extern void setinputfilecallbackid(int n, int i);
+extern void setreadfilecallbackid(int n, int i);
+extern int getinputfilecallbackid(int n);
+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);
+
+extern int luaopen_lua(lua_State * L, char *fname);
+
+extern int luaopen_stats(lua_State * L);
+
+extern int luaopen_font(lua_State * L);
+extern int luaopen_vf(lua_State * L);
+extern int font_parameters_to_lua(lua_State * L, int f);
+extern int font_to_lua(lua_State * L, int f, int usecache);
+extern int font_from_lua(lua_State * L, int f); /* return is boolean */
+extern int characters_from_lua(lua_State * L, int f); /* return is boolean */
+
+extern int luaopen_token(lua_State * L);
+extern void tokenlist_to_lua(lua_State * L, int p);
+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);
+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, int n);
+
+extern int dimen_to_number(lua_State * L, const char *s);
+
+extern int get_command_id(const char *s);
+
+extern void dump_luac_registers(void);
+
+extern void undump_luac_registers(void);
+
+extern int lua_only;
+extern const char *lc_ctype;
+extern const char *lc_collate;
+extern const char *lc_numeric;
+
+#ifdef LuajitTeX
+extern int luajiton;
+extern char *jithash_hashname ;
+#endif
+
+#if !defined(LUAI_HASHLIMIT)
+#define LUAI_HASHLIMIT 5
+#endif
+extern unsigned char show_luahashchars ;
+
+extern void unhide_lua_table(lua_State * lua, const char *name, int r);
+extern int hide_lua_table(lua_State * lua, const char *name);
+
+extern void unhide_lua_value(lua_State * lua, const char *name, const char *item, int r);
+extern int hide_lua_value(lua_State * lua, const char *name, const char *item);
+
+typedef struct command_item_ {
+ int id;
+ const char *name;
+ int lua;
+} command_item;
+
+extern command_item command_names[];
+extern int callback_callbacks_id;
+
+extern void luainterpreter(void);
+
+extern int luabytecode_max;
+extern unsigned int luabytecode_bytes;
+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;
+
+/* luastuff.h */
+
+typedef struct {
+ const char *name; /* parameter name */
+ int idx; /* index within img_parms array */
+} parm_struct;
+
+extern void preset_environment(lua_State * L, const parm_struct * p, const char *s);
+
+extern char *startup_filename;
+extern int safer_option;
+extern int nosocket_option;
+extern int utc_option;
+
+extern char *last_source_name;
+extern int last_lineno;
+
+extern int program_name_set; /* in lkpselib.c */
+
+/* for topenin() */
+extern char **argv;
+extern int argc;
+
+extern int loader_C_luatex(lua_State * L, const char *name, const char *filename);
+extern int loader_Call_luatex(lua_State * L, const char *name, const char *filename);
+
+extern void init_tex_table(lua_State * L);
+
+/*
+extern int tex_table_id;
+extern int pdf_table_id;
+extern int token_table_id;
+extern int node_table_id;
+*/
+
+extern int main_initialize(void);
+
+extern int do_run_callback(int special, const char *values, va_list vl);
+extern int lua_traceback(lua_State * L);
+
+extern int luainit;
+
+extern char *luanames[];
+
+extern int ff_get_ttc_index(char *ffname, char *psname); /* luafontloader/src/luafflib.c */
+extern int ff_createcff(char *, unsigned char **, int *); /* luafontloader/src/luafflib.c */
+
+extern char *FindResourceTtfFont(char *filename, char *fontname); /* luafontloader/fontforge/fontforge/macbinary.c */
+
+extern char charsetstr[]; /* from mpdir/psout.w */
+
+#ifndef WIN32
+extern char **environ;
+#endif
+
+#ifdef __cplusplus
+}
+#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.
+ These macros create and access pointers (indices) to keys which is faster. The
+ shortcuts are created as part of the initialization.
+
+*/
+
+#define init_lua_key(a) do { \
+ lua_pushliteral(Luas,#a); \
+ luaS_##a##_ptr = lua_tostring(Luas,-1); \
+ luaS_##a##_index = luaL_ref (Luas,LUA_REGISTRYINDEX); \
+} while (0)
+
+#define init_lua_key_alias(a,b) do { \
+ lua_pushliteral(Luas,b); \
+ luaS_##a##_ptr = lua_tostring(Luas,-1); \
+ luaS_##a##_index = luaL_ref (Luas,LUA_REGISTRYINDEX); \
+} while (0)
+
+#define make_lua_key(a) \
+ int luaS_##a##_index = 0; \
+ const char * luaS_##a##_ptr = NULL
+
+#define lua_key_eq(a,b) (a==luaS_##b##_ptr)
+
+#define lua_key_index(a) luaS_##a##_index
+#define lua_key(a) luaS_##a##_ptr
+#define lua_key_plus(a) luaS_p##a##_ptr
+#define lua_key_minus(a) luaS_m##a##_ptr
+#define use_lua_key(a) \
+ extern int luaS_##a##_index ; \
+ extern const char * luaS_##a##_ptr
+
+#define lua_key_rawgeti(a) \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_##a##_index);\
+ lua_rawget(L, -2)
+
+#define lua_key_direct_rawgeti(i) \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, i);\
+ lua_rawget(L, -2)
+
+#define lua_key_rawgeti_n(a,n) \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_##a##_index);\
+ lua_rawget(L, -1+n)
+
+#define lua_key_direct_rawget_n(i,n) \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, i);\
+ lua_rawget(L, -1+n)
+
+#define lua_push_key(a) \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_##a##_index);
+
+#define lua_get_metatablelua_l(L,a) do { \
+ lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_##a##_index); \
+ lua_gettable(L, LUA_REGISTRYINDEX); \
+} while (0)
+
+#define lua_get_metatablelua(a) lua_get_metatablelua_l(L,a)
+
+/*
+Unfortunately floor is already redefined as
+#define floor ((integer)floor((double)(a)))
+so
+#define lua_uroundnumber(a,b) (unsigned int)floor((double)(lua_tonumber(a,b)+0.5))
+is useless.
+*/
+
+#define lua_roundnumber(a,b) (int)floor((double)lua_tonumber(a,b)+0.5)
+#define lua_uroundnumber(a,b) (unsigned int)((double)(lua_tonumber(a,b)+0.5))
+extern int lua_numeric_field_by_index(lua_State *, int , int);
+extern unsigned int lua_unsigned_numeric_field_by_index(lua_State *, int , int);
+
+/* Currently we sometimes use numbers and sometimes strings in node properties. We can
+make that consistent by having a check on number and if not then assign a string. The
+strings are prehashed and we make a bunch of lua tables that have these values. We can
+preassign these at startup time. */
+
+/* no need for L state argument */
+
+#define PACK_TYPE_SIZE 4
+#define GROUP_CODE_SIZE 23
+#define LOCAL_PAR_SIZE 5
+#define MATH_STYLE_NAME_SIZE 8
+#define APPEND_LIST_SIZE 5
+#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_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_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))
+
+#define set_l_pack_type_index \
+l_pack_type_index[exactly] = lua_key_index(exactly); \
+l_pack_type_index[additional] = lua_key_index(additional); \
+l_pack_type_index[cal_expand_ratio] = lua_key_index(cal_expand_ratio);\
+l_pack_type_index[subst_ex_font] = lua_key_index(subst_ex_font);
+
+#define set_l_group_code_index \
+l_group_code_index[bottom_level] = lua_key_index(empty_string);\
+l_group_code_index[simple_group] = lua_key_index(simple);\
+l_group_code_index[hbox_group] = lua_key_index(hbox);\
+l_group_code_index[adjusted_hbox_group] = lua_key_index(adjusted_hbox);\
+l_group_code_index[vbox_group] = lua_key_index(vbox);\
+l_group_code_index[vtop_group] = lua_key_index(vtop);\
+l_group_code_index[align_group] = lua_key_index(align);\
+l_group_code_index[no_align_group] = lua_key_index(no_align);\
+l_group_code_index[output_group] = lua_key_index(output);\
+l_group_code_index[math_group] = lua_key_index(math);\
+l_group_code_index[disc_group] = lua_key_index(disc);\
+l_group_code_index[insert_group] = lua_key_index(insert);\
+l_group_code_index[vcenter_group] = lua_key_index(vcenter);\
+l_group_code_index[math_choice_group] = lua_key_index(math_choice);\
+l_group_code_index[semi_simple_group] = lua_key_index(semi_simple);\
+l_group_code_index[math_shift_group] = lua_key_index(math_shift);\
+l_group_code_index[math_left_group] = lua_key_index(math_left);\
+l_group_code_index[local_box_group] = lua_key_index(local_box);\
+l_group_code_index[split_off_group] = lua_key_index(split_off);\
+l_group_code_index[split_keep_group] = lua_key_index(split_keep);\
+l_group_code_index[preamble_group] = lua_key_index(preamble);\
+l_group_code_index[align_set_group] = lua_key_index(align_set);\
+l_group_code_index[fin_row_group] = lua_key_index(fin_row)
+
+#define set_l_local_par_index \
+l_local_par_index[new_graf_par_code] = lua_key_index(new_graf);\
+l_local_par_index[local_box_par_code] = lua_key_index(local_box);\
+l_local_par_index[hmode_par_par_code] = lua_key_index(hmode_par);\
+l_local_par_index[penalty_par_code] = lua_key_index(penalty);\
+l_local_par_index[math_par_code] = lua_key_index(math);
+
+#define set_l_math_style_name_index \
+l_math_style_name_index[display_style] = lua_key_index(display);\
+l_math_style_name_index[cramped_display_style] = lua_key_index(crampeddisplay);\
+l_math_style_name_index[text_style] = lua_key_index(text);\
+l_math_style_name_index[cramped_text_style] = lua_key_index(crampedtext);\
+l_math_style_name_index[script_style] = lua_key_index(script);\
+l_math_style_name_index[cramped_script_style] = lua_key_index(crampedscript);\
+l_math_style_name_index[script_script_style] = lua_key_index(scriptscript);\
+l_math_style_name_index[cramped_script_script_style] = lua_key_index(crampedscriptscript)
+
+#define set_l_dir_par_index \
+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);
+
+#define set_l_dir_text_index \
+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
+
+extern int img_parms [img_parms_max];
+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); \
+img_parms[ 4] = lua_key_index(depth); \
+img_parms[ 5] = lua_key_index(filename); \
+img_parms[ 6] = lua_key_index(filepath); \
+img_parms[ 7] = lua_key_index(height); \
+img_parms[ 8] = lua_key_index(imagetype); \
+img_parms[ 9] = lua_key_index(index); \
+img_parms[10] = lua_key_index(keepopen); \
+img_parms[11] = lua_key_index(objnum); \
+img_parms[12] = lua_key_index(pagebox); \
+img_parms[13] = lua_key_index(page); \
+img_parms[14] = lua_key_index(pages); \
+img_parms[15] = lua_key_index(ref_count); \
+img_parms[16] = lua_key_index(rotation); \
+img_parms[17] = lua_key_index(stream); \
+img_parms[18] = lua_key_index(transform); \
+img_parms[19] = lua_key_index(visiblefilename); \
+img_parms[20] = lua_key_index(width); \
+img_parms[21] = lua_key_index(xres); \
+img_parms[22] = lua_key_index(xsize); \
+img_parms[23] = lua_key_index(yres); \
+img_parms[24] = lua_key_index(ysize); \
+
+# define set_l_img_pageboxes_index \
+img_pageboxes[0] = lua_key_index(none); \
+img_pageboxes[1] = lua_key_index(media); \
+img_pageboxes[2] = lua_key_index(crop); \
+img_pageboxes[3] = lua_key_index(bleed); \
+img_pageboxes[4] = lua_key_index(trim); \
+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 offset, int max);
+extern int lua_show_valid_keys(lua_State *L, int *list, int max);
+
+#define set_make_keys \
+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);\
+make_lua_key(active);\
+make_lua_key(additional);\
+make_lua_key(adjdemerits);\
+make_lua_key(adjust);\
+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(bottom);\
+make_lua_key(splitbottom);\
+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);\
+make_lua_key(crampeddisplay);\
+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(delimiter);\
+make_lua_key(hdelimiter);\
+make_lua_key(vdelimiter);\
+make_lua_key(delim_num);\
+make_lua_key(delimptr);\
+make_lua_key(delta);\
+make_lua_key(demerits);\
+make_lua_key(denom);\
+make_lua_key(denominator);\
+make_lua_key(depth);\
+make_lua_key(designsize);\
+make_lua_key(dest_id);\
+make_lua_key(dest_type);\
+make_lua_key(dir);\
+make_lua_key(dir_h);\
+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(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(hextensible);\
+make_lua_key(vextensible);\
+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(splitfirst);\
+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);\
+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(horizontal);\
+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);\
+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(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(mathchar);\
+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(nobbox);\
+make_lua_key(nolength);\
+make_lua_key(notype);\
+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(numerator);\
+make_lua_key(number);\
+make_lua_key(objcompression);\
+make_lua_key(objnum);\
+make_lua_key(oldmath);\
+make_lua_key(omit);\
+make_lua_key(limits);\
+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(overdelimiter);\
+make_lua_key(overlay_accent);\
+make_lua_key(ownerpassword);\
+make_lua_key(page);\
+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_link_state);\
+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);\
+make_lua_key(pre);\
+make_lua_key(pre_adjust);\
+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(scripts);\
+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);\
+make_lua_key(size);\
+make_lua_key(skewchar);\
+make_lua_key(slant);\
+make_lua_key(slot);\
+make_lua_key(small_char);\
+make_lua_key(small_fam);\
+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);\
+make_lua_key(stretch);\
+make_lua_key(stretch_order);\
+make_lua_key(string);\
+make_lua_key(style);\
+make_lua_key(sub);\
+make_lua_key(subfont);\
+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(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(underdelimiter);\
+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(vertical);\
+make_lua_key(vert_italic);\
+make_lua_key(vert_variants);\
+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(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);
+
+#define set_init_keys \
+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);\
+init_lua_key(active);\
+init_lua_key(additional);\
+init_lua_key(adjdemerits);\
+init_lua_key(adjust);\
+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(bottom);\
+init_lua_key(splitbottom);\
+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);\
+init_lua_key(crampeddisplay);\
+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(delimiter);\
+init_lua_key(hdelimiter);\
+init_lua_key(vdelimiter);\
+init_lua_key(delim_num);\
+init_lua_key(delimptr);\
+init_lua_key(delta);\
+init_lua_key(demerits);\
+init_lua_key(denom);\
+init_lua_key(denominator);\
+init_lua_key(depth);\
+init_lua_key(designsize);\
+init_lua_key(dest_id);\
+init_lua_key(dest_type);\
+init_lua_key(dir);\
+init_lua_key(dir_h);\
+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(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(hextensible);\
+init_lua_key(vextensible);\
+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(splitfirst);\
+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);\
+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(horizontal);\
+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);\
+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(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(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(mathchar);\
+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(nobbox);\
+init_lua_key(nolength);\
+init_lua_key(notype);\
+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(numerator);\
+init_lua_key(number);\
+init_lua_key(objcompression);\
+init_lua_key(objnum);\
+init_lua_key(oldmath);\
+init_lua_key(omit);\
+init_lua_key(limits);\
+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(other_char);\
+init_lua_key(outer_call);\
+init_lua_key(outline);\
+init_lua_key(output);\
+init_lua_key(over);\
+init_lua_key(overdelimiter);\
+init_lua_key(overlay_accent);\
+init_lua_key(ownerpassword);\
+init_lua_key(page);\
+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_link_state);\
+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);\
+init_lua_key(pop);\
+init_lua_key(post);\
+init_lua_key(post_linebreak);\
+init_lua_key(pre);\
+init_lua_key(pre_adjust);\
+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(scripts);\
+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);\
+init_lua_key(size);\
+init_lua_key(skewchar);\
+init_lua_key(slant);\
+init_lua_key(slot);\
+init_lua_key(small_char);\
+init_lua_key(small_fam);\
+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);\
+init_lua_key(stretch);\
+init_lua_key(stretch_order);\
+init_lua_key(string);\
+init_lua_key(style);\
+init_lua_key(sub);\
+init_lua_key(subfont);\
+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(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(underdelimiter);\
+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(vertical);\
+init_lua_key(vert_italic);\
+init_lua_key(vert_variants);\
+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(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_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");\
+init_lua_key_alias(mTRT,"-TRT");\
+init_lua_key_alias(node_properties,"node.properties");\
+init_lua_key_alias(node_properties_indirect,"node.properties.indirect");\
+init_lua_key_alias(pLTL,"+LTL");\
+init_lua_key_alias(pRTT,"+RTT");\
+init_lua_key_alias(pTLT,"+TLT");\
+init_lua_key_alias(pTRT,"+TRT");\
+init_lua_key_alias(pdf,"pdf");\
+init_lua_key_alias(pdf_data,"pdf.data");\
+init_lua_key_alias(term_and_log,"term and log")
+
+#define assign_math_style(L,n,target) do { \
+ if (lua_type(L,n) == LUA_TNUMBER) { \
+ /* new, often same as subtype anyway */ \
+ target = lua_tointeger(L,n); \
+ } else if (lua_type(L,n) == LUA_TSTRING) { \
+ const char *s = lua_tostring(L, n); \
+ if (lua_key_eq(s,display)) { \
+ target = 0; \
+ } else if (lua_key_eq(s,crampeddisplay)) { \
+ target = 1; \
+ } else if (lua_key_eq(s,text)) { \
+ target = 2; \
+ } else if (lua_key_eq(s,crampedtext)) { \
+ target = 3; \
+ } else if (lua_key_eq(s,script)) { \
+ target = 4; \
+ } else if (lua_key_eq(s,crampedscript)) { \
+ target = 5; \
+ } else if (lua_key_eq(s,scriptscript)) { \
+ target = 6; \
+ } else if (lua_key_eq(s,crampedscriptscript)) { \
+ target = 7; \
+ } else { \
+ target = 2; \
+ } \
+ } else { \
+ target = 2; /* text by default */ \
+ } \
+} while(0)
+
+#ifdef _WIN32
+extern FILE *_cairo_win_tmpfile( void );
+#define tmpfile() _cairo_win_tmpfile()
+#endif /* _WIN32 */
+
+#endif /* LUATEX_API_H */
+
+/* */
+/* These keys have to available to different files */
+/* */
+
+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);
+use_lua_key(active);
+use_lua_key(additional);
+use_lua_key(adjdemerits);
+use_lua_key(adjust);
+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(bottom);
+use_lua_key(splitbottom);
+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);
+use_lua_key(crampeddisplay);
+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(delimiter);
+use_lua_key(hdelimiter);
+use_lua_key(vdelimiter);
+use_lua_key(delim_num);
+use_lua_key(delimptr);
+use_lua_key(delta);
+use_lua_key(demerits);
+use_lua_key(denom);
+use_lua_key(denominator);
+use_lua_key(depth);
+use_lua_key(designsize);
+use_lua_key(dest_id);
+use_lua_key(dest_type);
+use_lua_key(dir);
+use_lua_key(dir_h);
+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(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(hextensible);
+use_lua_key(vextensible);
+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(splitfirst);
+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);
+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(horizontal);
+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);
+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(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(mathchar);
+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(nobbox);
+use_lua_key(nolength);
+use_lua_key(notype);
+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(numerator);
+use_lua_key(number);
+use_lua_key(objcompression);
+use_lua_key(objnum);
+use_lua_key(oldmath);
+use_lua_key(omit);
+use_lua_key(limits);
+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(other_char);
+use_lua_key(outer_call);
+use_lua_key(outline);
+use_lua_key(output);
+use_lua_key(over);
+use_lua_key(overdelimiter);
+use_lua_key(overlay_accent);
+use_lua_key(ownerpassword);
+use_lua_key(page);
+use_lua_key(page_discards_head);
+use_lua_key(page_head);
+use_lua_key(page_ins_head);
+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_link_state);
+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);
+use_lua_key(pre);
+use_lua_key(pre_adjust);
+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(scripts);
+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);
+use_lua_key(size);
+use_lua_key(skewchar);
+use_lua_key(slant);
+use_lua_key(slot);
+use_lua_key(small_char);
+use_lua_key(small_fam);
+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);
+use_lua_key(stretch);
+use_lua_key(stretch_order);
+use_lua_key(string);
+use_lua_key(style);
+use_lua_key(sub);
+use_lua_key(subfont);
+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(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(underdelimiter);
+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(vertical);
+use_lua_key(vert_italic);
+use_lua_key(vert_variants);
+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(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);
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatex-core.c b/Build/source/texk/web2c/luatexdir/lua/luatex-core.c
new file mode 100644
index 00000000000..95396765c0f
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luatex-core.c
@@ -0,0 +1,676 @@
+/* generated from and by luatex-core.lua */
+
+#include "lua.h"
+#include "lauxlib.h"
+
+int load_luatex_core_lua (lua_State * L);
+
+int load_luatex_core_lua (lua_State * L)
+{
+ static unsigned char luatex_core_lua[] = {
+ 0x2d, 0x2d, 0x20, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x78, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x20, 0x73,
+ 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x6f, 0x20, 0x6f,
+ 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x20, 0x2e, 0x2e, 0x0a, 0x0a, 0x2d, 0x2d, 0x20,
+ 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x74,
+ 0x68, 0x65, 0x6e, 0x20, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x20,
+ 0x7d, 0x20, 0x65, 0x6e, 0x64, 0x20, 0x6d, 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, 0x31, 0x31, 0x32, 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, 0x3d, 0x20, 0x27, 0x48, 0x61, 0x6e, 0x73, 0x20, 0x48,
+ 0x61, 0x67, 0x65, 0x6e, 0x20, 0x26, 0x20, 0x4c, 0x75, 0x69, 0x67, 0x69, 0x20, 0x53, 0x63, 0x61,
+ 0x72, 0x73, 0x6f, 0x27, 0x2c, 0x0a, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x63, 0x6f, 0x70,
+ 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 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,
+ 0x31, 0x32, 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,
+ 0x73, 0x61, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 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, 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, 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, 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, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x74, 0x79,
+ 0x70, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x67, 0x73, 0x75,
+ 0x62, 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, 0x69, 0x6e, 0x64, 0x20, 0x3d,
+ 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 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, 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, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x3d, 0x20, 0x6d, 0x74, 0x2e, 0x6c, 0x69, 0x6e,
+ 0x65, 0x73, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6b, 0x70,
+ 0x73, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69,
+ 0x6f, 0x6e, 0x20, 0x20, 0x3d, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x2e, 0x63, 0x68, 0x65, 0x63, 0x6b,
+ 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72,
+ 0x64, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x20, 0x3d, 0x20, 0x6b, 0x70,
+ 0x73, 0x65, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f,
+ 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6b,
+ 0x70, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
+ 0x66, 0x69, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x2e, 0x72, 0x65, 0x63, 0x6f,
+ 0x72, 0x64, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x0a, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20,
+ 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x70,
+ 0x6f, 0x70, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x3d, 0x20, 0x69, 0x6f, 0x2e, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x0a,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20,
+ 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6f, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x0a,
+ 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20,
+ 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6e,
+ 0x6c, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 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, 0x20, 0x20, 0x20, 0x20, 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, 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,
+ 0x20, 0x20, 0x20, 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, 0x6f, 0x70, 0x65,
+ 0x6e, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x68, 0x6f, 0x77, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20,
+ 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, 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, 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, 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, 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, 0x20, 0x20, 0x20, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x63,
+ 0x6f, 0x72, 0x64, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x28, 0x6e, 0x61,
+ 0x6d, 0x65, 0x2c, 0x27, 0x77, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x5f, 0x72, 0x65,
+ 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x66, 0x69, 0x6c, 0x65, 0x28, 0x6e, 0x61,
+ 0x6d, 0x65, 0x2c, 0x27, 0x72, 0x27, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x66, 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, 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, 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, 0x20, 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27,
+ 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, 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, 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, 0x20,
+ 0x20, 0x20, 0x20, 0x68, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x27, 0x72, 0x27, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 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, 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, 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, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75,
+ 0x72, 0x6e, 0x20, 0x66, 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, 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, 0x20,
+ 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x6b, 0x61, 0x79, 0x2c, 0x20, 0x66,
+ 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x6b, 0x70, 0x73, 0x65, 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, 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, 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, 0x20, 0x20, 0x20, 0x20,
+ 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 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, 0x20, 0x20, 0x20,
+ 0x20, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20,
+ 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+ 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 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, 0x20, 0x20,
+ 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20,
+ 0x20, 0x2d, 0x2d, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 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,
+ 0x63, 0x69, 0x74, 0x6c, 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 0x20, 0x20, 0x20,
+ 0x20, 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, 0x20, 0x20, 0x20, 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, 0x20,
+ 0x20, 0x20, 0x20, 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, 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, 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, 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, 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, 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, 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, 0x20,
+ 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72,
+ 0x6e, 0x20, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 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, 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, 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, 0x72, 0x65, 0x74,
+ 0x75, 0x72, 0x6e, 0x20, 0x69, 0x6f, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x28, 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, 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, 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, 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, 0x20, 0x20,
+ 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 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, 0x20, 0x20,
+ 0x20, 0x20, 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, 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,
+ 0x6c, 0x73, 0x65, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x65, 0x20, 0x61,
+ 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
+ 0x20, 0x65, 0x6c, 0x73, 0x65, 0x77, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x0a, 0x65, 0x6e, 0x64, 0x0a,
+ 0x0a, 0x2d, 0x2d, 0x20, 0x6d, 0x61, 0x79, 0x62, 0x65, 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6f,
+ 0x6e, 0x6c, 0x79, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x6b, 0x70, 0x73, 0x65,
+ 0x20, 0x6d, 0x6f, 0x64, 0x65, 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, 0x77, 0x72, 0x69, 0x74, 0x65,
+ 0x5f, 0x6e, 0x6c, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x69, 0x6f, 0x2e, 0x77, 0x72, 0x69, 0x74,
+ 0x65, 0x5f, 0x6e, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66,
+ 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+ 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 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, 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, 0x20, 0x20, 0x20,
+ 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x20, 0x20,
+ 0x20, 0x20, 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, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x2d, 0x2d, 0x20, 0x6d, 0x61, 0x79, 0x62, 0x65,
+ 0x20, 0x61, 0x6c, 0x73, 0x6f, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20,
+ 0x69, 0x6e, 0x20, 0x6b, 0x70, 0x73, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x65, 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,
+ 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x6c, 0x69, 0x62, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28,
+ 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
+ 0x65, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x5b, 0x34, 0x5d, 0x20, 0x3d,
+ 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+ 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x65, 0x72, 0x73, 0x5b, 0x33, 0x5d, 0x20, 0x3d, 0x20,
+ 0x6e, 0x69, 0x6c, 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, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x66, 0x66, 0x69, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20,
+ 0x20, 0x20, 0x20, 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, 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, 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, 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, 0x66, 0x66, 0x69, 0x20, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, 0x0a, 0x65,
+ 0x6e, 0x64, 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, 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, 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, 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, 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, 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, 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, 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, 0x20, 0x20, 0x20, 0x20, 0x69,
+ 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6c, 0x66, 0x73,
+ 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x2e, 0x6c, 0x66, 0x73,
+ 0x20, 0x3d, 0x20, 0x6c, 0x66, 0x73, 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, 0x00
+ };
+ return luaL_dostring(L, (const char*) luatex_core_lua);
+} \ No newline at end of file
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatex-core.lua b/Build/source/texk/web2c/luatexdir/lua/luatex-core.lua
new file mode 100644
index 00000000000..538d8f903ac
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luatex-core.lua
@@ -0,0 +1,490 @@
+-- luatex-core security and io overloads ..
+
+-- if not modules then modules = { } end modules ['luatex-core'] = {
+-- version = 1.112,
+-- comment = 'companion to luatex',
+-- author = 'Hans Hagen & Luigi Scarso',
+-- copyright = 'LuaTeX Development Team',
+-- }
+
+LUATEXCOREVERSION = 1.120 -- 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 saferoption = status.safer_option
+local shellescape = status.shell_escape -- 0 (disabled) 1 (anything) 2 (restricted)
+local kpseused = status.kpse_used -- 0 1
+
+if kpseused == 1 then
+
+ local type = type
+ local gsub = string.gsub
+ local find = string.find
+
+ local mt = getmetatable(io.stderr)
+ local mt_lines = mt.lines
+
+ local kpse_checkpermission = kpse.check_permission
+ local kpse_recordinputfile = kpse.record_input_file
+ local kpse_recordoutputfile = kpse.record_output_file
+
+ local io_open = io.open
+ local io_popen = io.popen
+ local io_lines = io.lines
+
+ local fio_readline = fio.readline
+
+ 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
+ kpse_recordoutputfile(name,'w')
+ else
+ kpse_recordinputfile(name,'r')
+ end
+ end
+ return f
+ end
+
+ local function luatex_io_open_readonly(name,how)
+ if not 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 = kpse_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 explicitly
+ -- 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
+
+ io.open = luatex_io_open
+ io.popen = luatex_io_popen
+
+else
+
+ -- we assume management elsewhere
+
+end
+
+-- maybe also only when in kpse mode
+
+if saferoption == 1 then
+
+ local write_nl = texio.write_nl
+ local format = string.format
+
+ 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")
+
+ debug = nil
+
+ -- os.[execute|os.spawn|os.exec] already are shellescape aware)
+
+end
+
+-- maybe also only when in kpse mode
+
+if saferoption == 1 or shellescape ~= 1 then
+
+ package.loadlib = function() end
+ package.searchers[4] = nil
+ package.searchers[3] = nil
+
+ ffi = require('ffi')
+
+ if ffi then
+ for k, v in next, ffi do
+ if k ~= 'gc' then
+ ffi[k] = nil
+ end
+ end
+ end
+
+ ffi = nil
+
+end
+
+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
+
+ if not loaded.lfs then loaded.lfs = lfs 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
+
+-- start omit
+
+if utilities and utilities.merger and utilities.merger.compact then
+
+ local byte, format, gmatch, gsub = string.byte, string.format, string.gmatch, string.gsub
+ local concat = table.concat
+
+ local data = io.loaddata('luatex-core.lua')
+
+ data = gsub(data,'%-%-%s*start%s*omit.-%-%-%s*stop%s*omit%s*','')
+ data = gsub(data,'\r\n','\n')
+
+ local t = { }
+ local r = { }
+ local n = 0
+ local s = utilities.merger.compact(data) -- no comments and less spaces
+
+ t[#t+1] = '/* generated from and by luatex-core.lua */'
+ 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(data,'.') 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
+
+-- stop omit
diff --git a/Build/source/texk/web2c/luatexdir/lua/luatoken.c b/Build/source/texk/web2c/luatexdir/lua/luatoken.c
new file mode 100644
index 00000000000..874fbc99a5d
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/luatoken.c
@@ -0,0 +1,585 @@
+/*
+
+luatoken.w
+
+Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ptexlib.h"
+#include "lua/luatex-api.h"
+
+command_item command_names[] = {
+ { relax_cmd, NULL, 0},
+ { left_brace_cmd, NULL, 0},
+ { right_brace_cmd, NULL, 0},
+ { math_shift_cmd, NULL, 0},
+ { tab_mark_cmd, NULL, 0},
+ { car_ret_cmd, NULL, 0},
+ { mac_param_cmd, NULL, 0},
+ { sup_mark_cmd, NULL, 0},
+ { sub_mark_cmd, NULL, 0},
+ { endv_cmd, NULL, 0},
+ { spacer_cmd, NULL, 0},
+ { letter_cmd, NULL, 0},
+ { other_char_cmd, NULL, 0},
+ { par_end_cmd, NULL, 0},
+ { stop_cmd, NULL, 0},
+ { delim_num_cmd, NULL, 0},
+ { char_num_cmd, NULL, 0},
+ { math_char_num_cmd, NULL, 0},
+ { mark_cmd, NULL, 0},
+ { node_cmd, NULL, 0},
+ { xray_cmd, NULL, 0},
+ { make_box_cmd, NULL, 0},
+ { hmove_cmd, NULL, 0},
+ { vmove_cmd, NULL, 0},
+ { un_hbox_cmd, NULL, 0},
+ { un_vbox_cmd, NULL, 0},
+ { remove_item_cmd, NULL, 0},
+ { hskip_cmd, NULL, 0},
+ { vskip_cmd, NULL, 0},
+ { mskip_cmd, NULL, 0},
+ { kern_cmd, NULL, 0},
+ { mkern_cmd, NULL, 0},
+ { leader_ship_cmd, NULL, 0},
+ { halign_cmd, NULL, 0},
+ { valign_cmd, NULL, 0},
+ { no_align_cmd, NULL, 0},
+ { no_vrule_cmd, NULL, 0},
+ { no_hrule_cmd, NULL, 0},
+ { vrule_cmd, NULL, 0},
+ { hrule_cmd, NULL, 0},
+ { insert_cmd, NULL, 0},
+ { vadjust_cmd, NULL, 0},
+ { ignore_spaces_cmd, NULL, 0},
+ { after_assignment_cmd, NULL, 0},
+ { after_group_cmd, NULL, 0},
+ { break_penalty_cmd, NULL, 0},
+ { start_par_cmd, NULL, 0},
+ { ital_corr_cmd, NULL, 0},
+ { accent_cmd, NULL, 0},
+ { math_accent_cmd, NULL, 0},
+ { discretionary_cmd, NULL, 0},
+ { eq_no_cmd, NULL, 0},
+ { left_right_cmd, NULL, 0},
+ { math_comp_cmd, NULL, 0},
+ { limit_switch_cmd, NULL, 0},
+ { above_cmd, NULL, 0},
+ { math_style_cmd, NULL, 0},
+ { math_choice_cmd, NULL, 0},
+ { non_script_cmd, NULL, 0},
+ { vcenter_cmd, NULL, 0},
+ { case_shift_cmd, NULL, 0},
+ { message_cmd, NULL, 0},
+ { normal_cmd, NULL, 0},
+ { extension_cmd, NULL, 0},
+ { option_cmd, NULL, 0},
+ { lua_function_call_cmd, NULL, 0},
+ { lua_bytecode_call_cmd, NULL, 0},
+ { lua_call_cmd, NULL, 0},
+ { in_stream_cmd, NULL, 0},
+ { begin_group_cmd, NULL, 0},
+ { end_group_cmd, NULL, 0},
+ { omit_cmd, NULL, 0},
+ { ex_space_cmd, NULL, 0},
+ { boundary_cmd, NULL, 0},
+ { radical_cmd, NULL, 0},
+ { super_sub_script_cmd, NULL, 0},
+ { no_super_sub_script_cmd, NULL, 0},
+ { math_shift_cs_cmd, NULL, 0},
+ { end_cs_name_cmd, NULL, 0},
+ { char_ghost_cmd, NULL, 0},
+ { assign_local_box_cmd, NULL, 0},
+ { char_given_cmd, NULL, 0},
+ { math_given_cmd, NULL, 0},
+ { xmath_given_cmd, NULL, 0},
+ { last_item_cmd, NULL, 0},
+ { toks_register_cmd, NULL, 0},
+ { assign_toks_cmd, NULL, 0},
+ { assign_int_cmd, NULL, 0},
+ { assign_attr_cmd, NULL, 0},
+ { assign_dimen_cmd, NULL, 0},
+ { assign_glue_cmd, NULL, 0},
+ { assign_mu_glue_cmd, NULL, 0},
+ { assign_font_dimen_cmd, NULL, 0},
+ { assign_font_int_cmd, NULL, 0},
+ { assign_hang_indent_cmd, NULL, 0},
+ { set_aux_cmd, NULL, 0},
+ { set_prev_graf_cmd, NULL, 0},
+ { set_page_dimen_cmd, NULL, 0},
+ { set_page_int_cmd, NULL, 0},
+ { set_box_dimen_cmd, NULL, 0},
+ { set_tex_shape_cmd, NULL, 0},
+ { set_etex_shape_cmd, NULL, 0},
+ { def_char_code_cmd, NULL, 0},
+ { def_del_code_cmd, NULL, 0},
+ { extdef_math_code_cmd, NULL, 0},
+ { extdef_del_code_cmd, NULL, 0},
+ { def_family_cmd, NULL, 0},
+ { set_math_param_cmd, NULL, 0},
+ { set_font_cmd, NULL, 0},
+ { def_font_cmd, NULL, 0},
+ { register_cmd, NULL, 0},
+ { assign_box_direction_cmd, NULL, 0},
+ { assign_box_dir_cmd, NULL, 0},
+ { assign_direction_cmd, NULL, 0},
+ { assign_dir_cmd, NULL, 0},
+ { combine_toks_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},
+ { 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, combine_toks_cmd, combinetoks);
+ 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, top_bot_mark_cmd, top_bot_mark);
+ init_token_key(command_names, call_cmd, call);
+ init_token_key(command_names, long_call_cmd, long_call);
+ init_token_key(command_names, outer_call_cmd, outer_call);
+ init_token_key(command_names, long_outer_call_cmd, long_outer_call);
+ init_token_key(command_names, end_template_cmd, end_template);
+ init_token_key(command_names, dont_expand_cmd, dont_expand);
+ init_token_key(command_names, glue_ref_cmd, glue_ref);
+ init_token_key(command_names, shape_ref_cmd, shape_ref);
+ init_token_key(command_names, box_ref_cmd, box_ref);
+ init_token_key(command_names, data_cmd, data);
+}
+
+int get_command_id(const char *s)
+{
+ int i;
+ for (i = 0; command_names[i].id != -1; i++) {
+ if (s == command_names[i].name)
+ return i;
+ }
+ return -1;
+}
+
+/*
+static int get_cur_cmd(lua_State * L)
+{
+ int r = 0;
+ size_t len = lua_rawlen(L, -1);
+ cur_cs = 0;
+ if (len == 3 || len == 2) {
+ r = 1;
+ lua_rawgeti(L, -1, 1);
+ cur_cmd = (int) lua_tointeger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ cur_chr = (halfword) lua_tointeger(L, -1);
+ if (len == 3) {
+ lua_rawgeti(L, -3, 3);
+ cur_cs = (halfword) lua_tointeger(L, -1);
+ }
+ lua_pop(L, (int) len);
+ if (cur_cs == 0)
+ cur_tok = token_val(cur_cmd, cur_chr);
+ else
+ cur_tok = cs_token_flag + cur_cs;
+ }
+ return r;
+}
+*/
+
+static int token_from_lua(lua_State * L)
+{
+ int cmd, chr;
+ int cs = 0;
+ size_t len = lua_rawlen(L, -1);
+ if (len == 3 || len == 2) {
+ lua_rawgeti(L, -1, 1);
+ cmd = (int) lua_tointeger(L, -1);
+ lua_rawgeti(L, -2, 2);
+ chr = (int) lua_tointeger(L, -1);
+ if (len == 3) {
+ lua_rawgeti(L, -3, 3);
+ cs = (int) lua_tointeger(L, -1);
+ }
+ lua_pop(L, (int) len);
+ if (cs == 0) {
+ return token_val(cmd, chr);
+ } else {
+ return cs_token_flag + cs;
+ }
+ }
+ return -1;
+}
+
+/*
+static int get_cur_cs(lua_State * L)
+{
+ const char *s;
+ unsigned j;
+ size_t l;
+ int cs;
+ int save_nncs;
+ int ret;
+ ret = 0;
+ cur_cs = 0;
+ lua_getfield(L, -1, "name");
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ s = lua_tolstring(L, -1, &l);
+ if (l > 0) {
+ if ((last + (int) l) > buf_size)
+ check_buffer_overflow((last + (int) l));
+ for (j = 0; j < l; j++) {
+ buffer[(unsigned) last + 1 + j] = (packed_ASCII_code) * s++;
+ }
+ save_nncs = no_new_control_sequence;
+ no_new_control_sequence = false;
+ cs = id_lookup((last + 1), (int) l);
+ cur_tok = cs_token_flag + cs;
+ cur_cmd = eq_type(cs);
+ cur_chr = equiv(cs);
+ no_new_control_sequence = save_nncs;
+ ret = 1;
+ }
+ }
+ lua_pop(L, 1);
+ return ret;
+}
+*/
+
+void tokenlist_to_lua(lua_State * L, int p)
+{
+ int cmd, chr, cs;
+ int v;
+ int i = 1;
+ v = p;
+ while (v != null && v < (int) fix_mem_end) {
+ i++;
+ v = token_link(v);
+ }
+ i = 1;
+ lua_createtable(L, i, 0);
+ while (p != null && p < (int) fix_mem_end) {
+ if (token_info(p) >= cs_token_flag) {
+ cs = token_info(p) - cs_token_flag;
+ cmd = eq_type(cs);
+ chr = equiv(cs);
+ make_token_table(L, cmd, chr, cs);
+ } else {
+ cmd = token_cmd(token_info(p));
+ chr = token_chr(token_info(p));
+ make_token_table(L, cmd, chr, 0);
+ }
+ lua_rawseti(L, -2, i++);
+ p = token_link(p);
+ }
+}
+
+void tokenlist_to_luastring(lua_State * L, int p)
+{
+ int l;
+ char *s;
+ s = tokenlist_to_cstring(p, 1, &l);
+ lua_pushlstring(L, s, (size_t) l);
+ free(s);
+}
+
+int tokenlist_from_lua(lua_State * L)
+{
+ const char *s;
+ int tok, t;
+ size_t i, j;
+ halfword p, q, r;
+ r = get_avail();
+ token_info(r) = 0;
+ token_link(r) = null;
+ p = r;
+ t = lua_type(L, -1);
+ if (t == LUA_TTABLE) {
+ j = lua_rawlen(L, -1);
+ if (j > 0) {
+ for (i = 1; i <= j; i++) {
+ lua_rawgeti(L, -1, (int) i);
+ tok = token_from_lua(L);
+ if (tok >= 0) {
+ store_new_token(tok);
+ }
+ lua_pop(L, 1);
+ };
+ }
+ return r;
+ } else if (t == LUA_TSTRING) {
+ s = lua_tolstring(L, -1, &j);
+ for (i = 0; i < j; i++) {
+ if (s[i] == 32) {
+ tok = token_val(10, s[i]);
+ } else {
+ int j1 = (int) str2uni((const unsigned char *) (s + i));
+ i = i + (size_t) (utf8_size(j1) - 1);
+ tok = token_val(12, j1);
+ }
+ store_new_token(tok);
+ }
+ return r;
+ } else {
+ free_avail(r);
+ return null;
+ }
+}
+
+/*
+static void do_get_token_lua(int callback_id)
+{
+ while (1) {
+ if (!get_callback(Luas, callback_id)) {
+ get_next();
+ lua_pop(Luas, 2);
+ break;
+ }
+ if (lua_pcall(Luas, 0, 1, 0) != 0) {
+ tex_error(lua_tostring(Luas, -1), NULL);
+ lua_pop(Luas, 2);
+ break;
+ }
+ if (lua_istable(Luas, -1)) {
+ lua_rawgeti(Luas, -1, 1);
+ if (lua_istable(Luas, -1)) {
+ int p, q, r;
+ size_t i, j;
+ lua_pop(Luas, 1);
+ r = get_avail();
+ p = r;
+ j = lua_rawlen(Luas, -1);
+ if (j > 0) {
+ for (i = 1; i <= j; i++) {
+ lua_rawgeti(Luas, -1, (int) i);
+ if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
+ store_new_token(cur_tok);
+ }
+ lua_pop(Luas, 1);
+ }
+ }
+ if (p != r) {
+ p = token_link(r);
+ free_avail(r);
+ begin_token_list(p, inserted);
+ cur_input.nofilter_field = true;
+ get_next();
+ } else {
+ tex_error("error: illegal or empty token list returned", NULL);
+ }
+ lua_pop(Luas, 2);
+ break;
+ } else {
+ lua_pop(Luas, 1);
+ if (get_cur_cmd(Luas) || get_cur_cs(Luas)) {
+ lua_pop(Luas, 2);
+ break;
+ } else {
+ lua_pop(Luas, 2);
+ continue;
+ }
+ }
+ } else {
+ lua_pop(Luas, 2);
+ }
+ }
+ return;
+}
+*/
diff --git a/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c b/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
new file mode 100644
index 00000000000..f4845c0a4f4
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/mplibstuff.c
@@ -0,0 +1,115 @@
+/*
+
+mplibstuff.w
+
+Copyright 2021 LuaTeX team <bugs@@luatex.org>
+
+This file is part of LuaTeX.
+
+LuaTeX is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+LuaTeX is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License along
+with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*tex
+
+The \PNG\ and \SVG\ backends are not available in \LUATEX, because it's complex
+to manage the math formulas at run time. In this respect \POSTSCRIPT\ and the
+highlevel |objects| are better, and they are the standard way. Another problem is
+how to emit the warning: the |normal_warning| function is not available when
+\LUATEX\ is called as \LUA\ only.
+
+*/
+
+#include <stdio.h>
+
+extern void normal_warning(const char *t, const char *p);
+
+extern int lua_only;
+
+#define mplibstuff_message(MSG) do { \
+ if (lua_only) { \
+ fprintf(stdout,"mplib: " #MSG " not available.\n"); \
+ } else { \
+ normal_warning("mplib", #MSG " not available."); \
+ } \
+} while (0)
+
+void mp_png_backend_initialize (void *mp);
+void mp_png_backend_free (void *mp);
+int mp_png_gr_ship_out (void *hh, void *options, int standalone);
+int mp_png_ship_out (void *hh, const char *options);
+
+void mp_svg_backend_initialize (void *mp);
+void mp_svg_backend_free (void *mp);
+int mp_svg_ship_out (void *hh, int prologues);
+int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone);
+
+void *mp_initialize_binary_math(void *mp);
+
+
+void mp_png_backend_initialize (void *mp) { return; }
+void mp_png_backend_free (void *mp) { return; }
+int mp_png_gr_ship_out (void *hh, void *options, int standalone) { mplibstuff_message(png backend); return 1; }
+int mp_png_ship_out (void *hh, const char *options) { mplibstuff_message(png backend); return 1; }
+
+void mp_svg_backend_initialize (void *mp) { return; }
+void mp_svg_backend_free (void *mp) { return; }
+int mp_svg_ship_out (void *hh, int prologues) { mplibstuff_message(svg bakend); return 1; }
+int mp_svg_gr_ship_out (void *hh, int qprologues, int standalone) { mplibstuff_message(svg backend); return 1; }
+
+
+void *mp_initialize_binary_math(void *mp) {mplibstuff_message(math binary);return NULL; }
+
+const char* cairo_version_string (void);
+const char* mpfr_get_version(void);
+const char* pixman_version_string (void);
+
+
+#define CAIRO_VERSION_STRING "CAIRO NOT AVAILABLE"
+const char *COMPILED_CAIRO_VERSION_STRING = CAIRO_VERSION_STRING;
+
+#define MPFR_VERSION_STRING "MPFR NOT AVAILABLE"
+const char *COMPILED_MPFR_VERSION_STRING = MPFR_VERSION_STRING;
+
+
+#define __GNU_MP_VERSION -1
+#define __GNU_MP_VERSION_MINOR -1
+#define __GNU_MP_VERSION_PATCHLEVEL -1
+int COMPILED__GNU_MP_VERSION = __GNU_MP_VERSION ;
+int COMPILED__GNU_MP_VERSION_MINOR = __GNU_MP_VERSION_MINOR ;
+int COMPILED__GNU_MP_VERSION_PATCHLEVEL = __GNU_MP_VERSION_PATCHLEVEL ;
+const char * const COMPILED_gmp_version="GMP NOT AVAILABLE";
+
+#define PIXMAN_VERSION_STRING "PIXMAN NOT AVAILABLE"
+const char *COMPILED_PIXMAN_VERSION_STRING = PIXMAN_VERSION_STRING;
+
+const char* cairo_version_string (void)
+{
+ return CAIRO_VERSION_STRING;
+}
+
+const char* mpfr_get_version(void)
+{
+ return MPFR_VERSION_STRING;
+}
+
+const char* pixman_version_string (void)
+{
+ return PIXMAN_VERSION_STRING;
+}
+
+char png_libpng_ver[] = "PNG NOT AVAILABLE";
+
+
+
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluac.c b/Build/source/texk/web2c/luatexdir/lua/texluac.c
new file mode 100644
index 00000000000..984a854c036
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/texluac.c
@@ -0,0 +1,537 @@
+/*
+
+texluac.w
+
+Copyright (C) 1994-2007 Lua.org, PUC-Rio. All rights reserved.
+Copyright 2006-2013 Taco Hoekwater <taco@@luatex.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+This file is part of LuaTeX.
+
+*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define luac_c
+#define LUA_CORE
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lobject.h"
+#include "lopcodes.h"
+#include "lstring.h"
+#include "lundump.h"
+
+#include "lua/luatex-api.h"
+
+static void PrintFunction(const Proto* f, int full);
+
+#define luaU_print PrintFunction
+
+/*tex A fix for non-gcc compilation: */
+
+#if !defined(__GNUC__) || (__GNUC__ < 2)
+# define __attribute__(x)
+#endif
+
+/*tex default program name */
+
+#define PROGNAME "texluac"
+
+/*tex default output file */
+
+#define OUTPUT PROGNAME ".out"
+
+/*tex list bytecodes? */
+
+static int listing = 0;
+
+/*tex dump bytecodes? */
+
+static int dumping = 1;
+
+/*tex strip debug information? */
+
+static int stripping = 0;
+
+/*tex default output file name */
+
+static char Output[] = { OUTPUT };
+
+/*tex actual output file name */
+
+static const char *output = Output;
+
+/*tex actual program name */
+
+static const char *progname = PROGNAME;
+
+__attribute__ ((noreturn))
+static void fatal(const char *message) {
+ fprintf(stderr,"%s: %s\n",progname,message);
+ exit(EXIT_FAILURE);
+}
+
+__attribute__ ((noreturn))
+static void cannot(const char *what) {
+ fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
+ exit(EXIT_FAILURE);
+}
+
+__attribute__ ((noreturn))
+static void usage(const char* message)
+{
+ if (*message=='-')
+ fprintf(stderr,"%s: unrecognized option " LUA_QS "\n",progname,message);
+ else
+ fprintf(stderr,"%s: %s\n",progname,message);
+ fprintf(stderr,
+ "usage: %s [options] [filenames]\n"
+ "Available options are:\n"
+ " -l list (use -l -l for full listing)\n"
+ " -o name output to file " LUA_QL("name") " (default is \"%s\")\n"
+ " -p parse only\n"
+ " -s strip debug information\n"
+ " -v show version information\n"
+ " -- stop handling options\n"
+ " - stop handling options and process stdin\n"
+ ,progname,Output);
+ exit(EXIT_FAILURE);
+}
+
+#define IS(s) (strcmp(argv[i],s)==0)
+
+static int doargs(int argc, char* argv[])
+{
+ int i;
+ int version=0;
+ if (argv[0]!=NULL && *argv[0]!=0)
+ progname=argv[0];
+ for (i=1; i<argc; i++) {
+ if (*argv[i]!='-') {
+ /* end of options; keep it */
+ break;
+ } else if (IS("--")) {
+ /* end of options; skip it */
+ ++i;
+ if (version) ++version;
+ break;
+ } else if (IS("-")) {
+ /* end of options; use stdin */
+ break;
+ } else if (IS("-l")) {
+ /* list */
+ ++listing;
+ } else if (IS("-o")) {
+ /* output file */
+ output=argv[++i];
+ if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
+ usage(LUA_QL("-o") " needs argument");
+ if (IS("-"))
+ output=NULL;
+ } else if (IS("-p")) {
+ /* parse only */
+ dumping=0;
+ } else if (IS("-s")) {
+ /* strip debug information */
+ stripping=1;
+ } else if (IS("-v")) {
+ /* show version */
+ ++version;
+ } else {
+ /* unknown option */
+ usage(argv[i]);
+ }
+ }
+ if (i==argc && (listing || !dumping)) {
+ dumping=0;
+ argv[--i]=Output;
+ }
+ if (version) {
+ printf("%s\n",LUA_COPYRIGHT);
+ if (version==argc-1)
+ exit(EXIT_SUCCESS);
+ }
+ return i;
+}
+
+#define FUNCTION "(function()end)();"
+
+static const char* reader(lua_State *L, void *ud, size_t *size)
+{
+ UNUSED(L);
+ if ((*(int*)ud)--) {
+ *size=sizeof(FUNCTION)-1;
+ return FUNCTION;
+ } else {
+ *size=0;
+ return NULL;
+ }
+}
+
+#define toproto(L,i) getproto(L->top+(i))
+
+static const Proto* combine(lua_State* L, int n)
+{
+ if (n==1) {
+ return toproto(L,-1);
+ } else {
+ Proto* f;
+ int i=n;
+ if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ f=toproto(L,-1);
+ for (i=0; i<n; i++) {
+ f->p[i]=toproto(L,i-n-1);
+ if (f->p[i]->sizeupvalues>0)
+ f->p[i]->upvalues[0].instack=0;
+ }
+ f->sizelineinfo=0;
+ return f;
+ }
+}
+
+static int writer(lua_State* L, const void* p, size_t size, void* u)
+{
+ UNUSED(L);
+ return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
+}
+
+static int pmain(lua_State* L)
+{
+ int argc=(int)lua_tointeger(L,1);
+ char** argv=(char**)lua_touserdata(L,2);
+ const Proto* f;
+ int i;
+ if (!lua_checkstack(L,argc))
+ fatal("too many input files");
+ /*tex
+ Open standard libraries: we need to to this to keep the symbol
+ |luaL_openlibs|.
+ */
+ luaL_checkversion(L);
+ /*tex stop collector during initialization */
+ lua_gc(L, LUA_GCSTOP, 0);
+ /*tex open libraries */
+ luaL_openlibs(L);
+ lua_gc(L, LUA_GCRESTART, 0);
+ for (i=0; i<argc; i++) {
+ const char* filename=IS("-") ? NULL : argv[i];
+ if (luaL_loadfile(L,filename)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ }
+ f=combine(L,argc);
+ if (listing)
+ luaU_print(f,listing>1);
+ if (dumping) {
+ FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
+ if (D==NULL)
+ cannot("open");
+ lua_lock(L);
+ luaU_dump(L,f,writer,D,stripping);
+ lua_unlock(L);
+ if (ferror(D))
+ cannot("write");
+ if (fclose(D))
+ cannot("close");
+ }
+ return 0;
+}
+
+int luac_main(int ac, char *av[])
+{
+ lua_State *L;
+ int i = doargs(ac, av);
+ ac -= i;
+ av += i;
+ if (ac <= 0)
+ usage("no input files given");
+ L=luaL_newstate();
+ if (L == NULL)
+ fatal("not enough memory for state");
+ lua_pushcfunction(L,&pmain);
+ lua_pushinteger(L,ac);
+ lua_pushlightuserdata(L,av);
+ if (lua_pcall(L,2,0,0)!=LUA_OK)
+ fatal(lua_tostring(L,-1));
+ lua_close(L);
+ return EXIT_SUCCESS;
+}
+
+/*
+ See Copyright Notice in |lua.h|.
+*/
+
+#define VOID(p) ((const void*)(p))
+
+#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
+#define TSVALUE(o) rawtsvalue(o)
+#endif
+#if (LUA_VERSION_NUM == 503)
+#define TSVALUE(o) tsvalue(o)
+#endif
+
+/* if ts is a const pointer, using Lua's getstr(ts) is not correct */
+#define getconststr(ts) \
+ check_exp(sizeof((ts)->extra), cast(const char *, (ts)) + sizeof(UTString))
+
+
+static void PrintString(const TString* ts)
+{
+ const char* s=getconststr(ts);
+ size_t i,n;
+#if (defined(LuajitTeX)) || (LUA_VERSION_NUM == 502)
+ n=ts->tsv.len;
+#endif
+#if (LUA_VERSION_NUM == 503)
+ n=(ts->tt == LUA_TSHRSTR ? ts->shrlen : ts->u.lnglen);
+#endif
+ printf("%c",'"');
+ for (i=0; i<n; i++) {
+ int c=(int)(unsigned char)s[i];
+ switch (c) {
+ case '"':
+ printf("\\\"");
+ break;
+ case '\\':
+ printf("\\\\");
+ break;
+ case '\a':
+ printf("\\a");
+ break;
+ case '\b':
+ printf("\\b");
+ break;
+ case '\f':
+ printf("\\f");
+ break;
+ case '\n':
+ printf("\\n");
+ break;
+ case '\r':
+ printf("\\r");
+ break;
+ case '\t':
+ printf("\\t");
+ break;
+ case '\v':
+ printf("\\v");
+ break;
+ default :
+ if (isprint(c))
+ printf("%c",c);
+ else
+ printf("\\%03d",c);
+ break;
+ }
+ }
+ printf("%c",'"');
+}
+
+static void PrintConstant(const Proto* f, int i)
+{
+ const TValue* o=&f->k[i];
+ switch (ttype(o)) {
+ case LUA_TNIL:
+ printf("nil");
+ break;
+ case LUA_TBOOLEAN:
+ printf(bvalue(o) ? "true" : "false");
+ break;
+ case LUA_TNUMBER:
+ printf(LUA_NUMBER_FMT,nvalue(o));
+ break;
+ case LUA_TSTRING:
+ PrintString(TSVALUE(o));
+ break;
+ default:
+ /*tex This cannot happen. */
+ printf("? type=%d",ttype(o));
+ break;
+ }
+}
+
+#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
+#define MYK(x) (-1-(x))
+
+static void PrintCode(const Proto* f)
+{
+ const Instruction* code=f->code;
+ int pc,n=f->sizecode;
+ for (pc=0; pc<n; pc++) {
+ Instruction i=code[pc];
+ OpCode o=GET_OPCODE(i);
+ int a=GETARG_A(i);
+ int b=GETARG_B(i);
+ int c=GETARG_C(i);
+ int ax=GETARG_Ax(i);
+ int bx=GETARG_Bx(i);
+ int sbx=GETARG_sBx(i);
+ int line=getfuncline(f,pc);
+ printf("\t%d\t",pc+1);
+ if (line>0)
+ printf("[%d]\t",line);
+ else
+ printf("[-]\t");
+ printf("%-9s\t",luaP_opnames[o]);
+ switch (getOpMode(o)) {
+ case iABC:
+ printf("%d",a);
+ if (getBMode(o)!=OpArgN) printf(" %d",ISK(b) ? (MYK(INDEXK(b))) : b);
+ if (getCMode(o)!=OpArgN) printf(" %d",ISK(c) ? (MYK(INDEXK(c))) : c);
+ break;
+ case iABx:
+ printf("%d",a);
+ if (getBMode(o)==OpArgK) printf(" %d",MYK(bx));
+ if (getBMode(o)==OpArgU) printf(" %d",bx);
+ break;
+ case iAsBx:
+ printf("%d %d",a,sbx);
+ break;
+ case iAx:
+ printf("%d",MYK(ax));
+ break;
+ }
+ switch (o) {
+ case OP_LOADK:
+ printf("\t; "); PrintConstant(f,bx);
+ break;
+ case OP_GETUPVAL:
+ case OP_SETUPVAL:
+ printf("\t; %s",UPVALNAME(b));
+ break;
+ case OP_GETTABUP:
+ printf("\t; %s",UPVALNAME(b));
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABUP:
+ printf("\t; %s",UPVALNAME(a));
+ if (ISK(b)) { printf(" "); PrintConstant(f,INDEXK(b)); }
+ if (ISK(c)) { printf(" "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_GETTABLE:
+ case OP_SELF:
+ if (ISK(c)) { printf("\t; "); PrintConstant(f,INDEXK(c)); }
+ break;
+ case OP_SETTABLE:
+ case OP_ADD:
+ case OP_SUB:
+ case OP_MUL:
+ case OP_DIV:
+ case OP_POW:
+ case OP_EQ:
+ case OP_LT:
+ case OP_LE:
+ if (ISK(b) || ISK(c)) {
+ printf("\t; ");
+ if (ISK(b)) PrintConstant(f,INDEXK(b)); else printf("-");
+ printf(" ");
+ if (ISK(c)) PrintConstant(f,INDEXK(c)); else printf("-");
+ }
+ break;
+ case OP_JMP:
+ case OP_FORLOOP:
+ case OP_FORPREP:
+ case OP_TFORLOOP:
+ printf("\t; to %d",sbx+pc+2);
+ break;
+ case OP_CLOSURE:
+ printf("\t; %p",VOID(f->p[bx]));
+ break;
+ case OP_SETLIST:
+ if (c==0) printf("\t; %d",(int)code[++pc]); else printf("\t; %d",c);
+ break;
+ case OP_EXTRAARG:
+ printf("\t; "); PrintConstant(f,ax);
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+}
+
+#define SS(x) ((x==1)?"":"s")
+#define S(x) (int)(x),SS(x)
+
+static void PrintHeader(const Proto* f)
+{
+ const char* s=f->source ? getstr(f->source) : "=?";
+ if (*s=='@' || *s=='=')
+ s++;
+ else if (*s==LUA_SIGNATURE[0])
+ s="(bstring)";
+ else
+ s="(string)";
+ printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
+ (f->linedefined==0)?"main":"function",s,
+ f->linedefined,f->lastlinedefined,
+ S(f->sizecode),VOID(f));
+ printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
+ (int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
+ S(f->maxstacksize),S(f->sizeupvalues));
+ printf("%d local%s, %d constant%s, %d function%s\n",
+ S(f->sizelocvars),S(f->sizek),S(f->sizep));
+}
+
+static void PrintDebug(const Proto* f)
+{
+ int i,n;
+ n=f->sizek;
+ printf("constants (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t",i+1);
+ PrintConstant(f,i);
+ printf("\n");
+ }
+ n=f->sizelocvars;
+ printf("locals (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
+ }
+ n=f->sizeupvalues;
+ printf("upvalues (%d) for %p:\n",n,VOID(f));
+ for (i=0; i<n; i++) {
+ printf("\t%d\t%s\t%d\t%d\n",
+ i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
+ }
+}
+
+static void PrintFunction(const Proto* f, int full)
+{
+ int i,n=f->sizep;
+ PrintHeader(f);
+ PrintCode(f);
+ if (full)
+ PrintDebug(f);
+ for (i=0; i<n; i++)
+ PrintFunction(f->p[i],full);
+}
diff --git a/Build/source/texk/web2c/luatexdir/lua/texluajitc.c b/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
new file mode 100644
index 00000000000..5cac5d65ab1
--- /dev/null
+++ b/Build/source/texk/web2c/luatexdir/lua/texluajitc.c
@@ -0,0 +1,650 @@
+/*
+
+ LuaJIT frontend. Runs commands, scripts, read-eval-print (REPL) etc.
+ Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
+
+ Major portions taken verbatim or adapted from the Lua interpreter.
+ Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define luajit_c
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "luajit.h"
+
+#include "lj_arch.h"
+
+#if LJ_TARGET_POSIX
+#include <unistd.h>
+#define lua_stdin_is_tty() isatty(0)
+#elif LJ_TARGET_WINDOWS
+#include <io.h>
+#ifdef __BORLANDC__
+#define lua_stdin_is_tty() isatty(_fileno(stdin))
+#else
+#define lua_stdin_is_tty() _isatty(_fileno(stdin))
+#endif
+#else
+#define lua_stdin_is_tty() 1
+#endif
+
+#if !LJ_TARGET_CONSOLE
+#include <signal.h>
+#endif
+
+#include "lua/luatex-api.h"
+
+static lua_State *globalL = NULL;
+static const char *progname = LUA_PROGNAME;
+
+#if !LJ_TARGET_CONSOLE
+
+static void lstop(lua_State *L, lua_Debug *ar)
+{
+ /*tex Unused arg. */
+ (void)ar;
+ lua_sethook(L, NULL, 0, 0);
+ /*tex Avoid luaL_error -- a C hook doesn't add an extra frame. */
+ luaL_where(L, 0);
+ lua_pushfstring(L, "%sinterrupted!", lua_tostring(L, -1));
+ lua_error(L);
+}
+
+/*tex if another SIGINT happens before lstop, terminate process (default action) */
+
+static void laction(int i)
+{
+ signal(i, SIG_DFL);
+ lua_sethook(globalL, lstop, LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT, 1);
+}
+
+#endif
+
+static void print_usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [options]... [script [args]...].\n"
+ "Available options are:\n"
+ " -e chunk Execute string " LUA_QL("chunk") ".\n"
+ " -l name Require library " LUA_QL("name") ".\n"
+ " -b ... Save or list bytecode.\n"
+ " -j cmd Perform LuaJIT control command.\n"
+ " -O[opt] Control LuaJIT optimizations.\n"
+ " -i Enter interactive mode after executing " LUA_QL("script") ".\n"
+ " -v Show version information.\n"
+ " -E Ignore environment variables.\n"
+ " -- Stop handling options.\n"
+ " - Execute stdin and stop handling options.\n"
+ ,
+ progname);
+ fflush(stderr);
+}
+
+static void l_message(const char *pname, const char *msg)
+{
+ if (pname) fprintf(stderr, "%s: ", pname);
+ fprintf(stderr, "%s\n", msg);
+ fflush(stderr);
+}
+
+static int report(lua_State *L, int status)
+{
+ if (status && !lua_isnil(L, -1)) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg == NULL)
+ msg = "(error object is not a string)";
+ l_message(progname, msg);
+ lua_pop(L, 1);
+ }
+ return status;
+}
+
+static int traceback(lua_State *L)
+{
+ if (!lua_isstring(L, 1)) {
+ /*tex Non-string error object? Try metamethod. */
+ if (lua_isnoneornil(L, 1) || !luaL_callmeta(L, 1, "__tostring") || !lua_isstring(L, -1)) {
+ /*tex Return non-string error object. */
+ return 1;
+ }
+ /*tex Replace object by result of __tostring metamethod. */
+ lua_remove(L, 1);
+ }
+ luaL_traceback(L, L, lua_tostring(L, 1), 1);
+ return 1;
+}
+
+static int docall(lua_State *L, int narg, int clear)
+{
+ int status;
+ /*tex function index */
+ int base = lua_gettop(L) - narg;
+ /*tex push traceback function */
+ lua_pushcfunction(L, traceback);
+ /*tex put it under chunk and args */
+ lua_insert(L, base);
+#if !LJ_TARGET_CONSOLE
+ signal(SIGINT, laction);
+#endif
+ status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
+#if !LJ_TARGET_CONSOLE
+ signal(SIGINT, SIG_DFL);
+#endif
+ /*tex remove traceback function */
+ lua_remove(L, base);
+ /*tex force a complete garbage collection in case of errors */
+ if (status != 0)
+ lua_gc(L, LUA_GCCOLLECT, 0);
+ return status;
+}
+
+static void print_version(void)
+{
+ fputs(LUAJIT_VERSION " -- " LUAJIT_COPYRIGHT ". " LUAJIT_URL "\n", stdout);
+}
+
+static void print_jit_status(lua_State *L)
+{
+ int n;
+ const char *s;
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ /*tex Get jit.* module table. */
+ lua_getfield(L, -1, "jit");
+ lua_remove(L, -2);
+ lua_getfield(L, -1, "status");
+ lua_remove(L, -2);
+ n = lua_gettop(L);
+ lua_call(L, 0, LUA_MULTRET);
+ fputs(lua_toboolean(L, n) ? "JIT: ON" : "JIT: OFF", stdout);
+ for (n++; (s = lua_tostring(L, n)); n++) {
+ putc(' ', stdout);
+ fputs(s, stdout);
+ }
+ putc('\n', stdout);
+}
+
+static int getargs(lua_State *L, char **argv, int n)
+{
+ int narg = 0;
+ int i;
+ /*tex count total number of arguments */
+ while (argv[argc]) argc++;
+ /*tex number of arguments to the script */
+ narg = argc - (n + 1);
+ luaL_checkstack(L, narg + 3, "too many arguments to script");
+ for (i = n+1; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ }
+ lua_createtable(L, narg, n + 1);
+ for (i = 0; i < argc; i++) {
+ lua_pushstring(L, argv[i]);
+ lua_rawseti(L, -2, i - n);
+ }
+ return narg;
+}
+
+static int dofile(lua_State *L, const char *name)
+{
+ int status = luaL_loadfile(L, name) || docall(L, 0, 1);
+ return report(L, status);
+}
+
+static int dostring(lua_State *L, const char *s, const char *name)
+{
+ int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
+ return report(L, status);
+}
+
+static int dolibrary(lua_State *L, const char *name)
+{
+ lua_getglobal(L, "require");
+ lua_pushstring(L, name);
+ return report(L, docall(L, 1, 1));
+}
+
+static void write_prompt(lua_State *L, int firstline)
+{
+ const char *p;
+ lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
+ p = lua_tostring(L, -1);
+ if (p == NULL) p = firstline ? LUA_PROMPT : LUA_PROMPT2;
+ fputs(p, stdout);
+ fflush(stdout);
+ /*tex remove global */
+ lua_pop(L, 1);
+}
+
+static int incomplete(lua_State *L, int status)
+{
+ if (status == LUA_ERRSYNTAX) {
+ size_t lmsg;
+ const char *msg = lua_tolstring(L, -1, &lmsg);
+ const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
+ if (strstr(msg, LUA_QL("<eof>")) == tp) {
+ lua_pop(L, 1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int pushline(lua_State *L, int firstline)
+{
+ char buf[LUA_MAXINPUT];
+ write_prompt(L, firstline);
+ if (fgets(buf, LUA_MAXINPUT, stdin)) {
+ size_t len = strlen(buf);
+ if (len > 0 && buf[len-1] == '\n')
+ buf[len-1] = '\0';
+ if (firstline && buf[0] == '=')
+ lua_pushfstring(L, "return %s", buf+1);
+ else
+ lua_pushstring(L, buf);
+ return 1;
+ }
+ return 0;
+}
+
+static int loadline(lua_State *L)
+{
+ int status;
+ lua_settop(L, 0);
+ if (!pushline(L, 1)) {
+ /*tex no input */
+ return -1;
+ }
+ for (;;) {
+ /*tex repeat until gets a complete line */
+ status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
+ /*tex cannot try to add lines? */
+ if (!incomplete(L, status))
+ break;
+ /*tex no more input? */
+ if (!pushline(L, 0))
+ return -1;
+ /*tex add a new line... */
+ lua_pushliteral(L, "\n");
+ /*tex ...between the two lines */
+ lua_insert(L, -2);
+ /*tex join them */
+ lua_concat(L, 3);
+ }
+ /*tex remove line */
+ lua_remove(L, 1);
+ return status;
+}
+
+static void dotty(lua_State *L)
+{
+ int status;
+ const char *oldprogname = progname;
+ progname = NULL;
+ while ((status = loadline(L)) != -1) {
+ if (status == 0)
+ status = docall(L, 0, 0);
+ report(L, status);
+ if (status == 0 && lua_gettop(L) > 0) {
+ /*tex any result to print? */
+ lua_getglobal(L, "print");
+ lua_insert(L, 1);
+ if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
+ l_message(progname,
+ lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)",
+ lua_tostring(L, -1)));
+ }
+ }
+ /*tex clear stack */
+ lua_settop(L, 0);
+ fputs("\n", stdout);
+ fflush(stdout);
+ progname = oldprogname;
+}
+
+static int handle_script(lua_State *L, char **argv, int n)
+{
+ int status;
+ const char *fname;
+ /*tex collect arguments */
+ int narg = getargs(L, argv, n);
+ lua_setglobal(L, "arg");
+ fname = argv[n];
+ if (strcmp(fname, "-") == 0 && strcmp(argv[n-1], "--") != 0) {
+ /*tex use stdin */
+ fname = NULL;
+ }
+ status = luaL_loadfile(L, fname);
+ lua_insert(L, -(narg+1));
+ if (status == 0)
+ status = docall(L, narg, 0);
+ else
+ lua_pop(L, narg);
+ return report(L, status);
+}
+
+/*tex Load add-on module. */
+
+static int loadjitmodule(lua_State *L)
+{
+ lua_getglobal(L, "require");
+ lua_pushliteral(L, "jit.");
+ lua_pushvalue(L, -3);
+ lua_concat(L, 2);
+ if (lua_pcall(L, 1, 1, 0)) {
+ const char *msg = lua_tostring(L, -1);
+ if (msg && !strncmp(msg, "module ", 7)) {
+ err:
+ l_message(progname,
+ "unknown luaJIT command or jit.* modules not installed");
+ return 1;
+ } else {
+ return report(L, 1);
+ }
+ }
+ lua_getfield(L, -1, "start");
+ if (lua_isnil(L, -1))
+ goto err;
+ /*tex Drop module table. */
+ lua_remove(L, -2);
+ return 0;
+}
+
+/*tex Run command with options. */
+
+static int runcmdopt(lua_State *L, const char *opt)
+{
+ int narg = 0;
+ if (opt && *opt) {
+ /*tex Split arguments. */
+ for (;;) {
+ const char *p = strchr(opt, ',');
+ narg++;
+ if (!p)
+ break;
+ if (p == opt)
+ lua_pushnil(L);
+ else
+ lua_pushlstring(L, opt, (size_t)(p - opt));
+ opt = p + 1;
+ }
+ if (*opt)
+ lua_pushstring(L, opt);
+ else
+ lua_pushnil(L);
+ }
+ return report(L, lua_pcall(L, narg, 0, 0));
+}
+
+/*tex JIT engine control command: try jit library first or load add-on module. */
+
+static int dojitcmd(lua_State *L, const char *cmd)
+{
+ const char *opt = strchr(cmd, '=');
+ lua_pushlstring(L, cmd, opt ? (size_t)(opt - cmd) : strlen(cmd));
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ /*tex Get jit.* module table. */
+ lua_getfield(L, -1, "jit");
+ lua_remove(L, -2);
+ /*tex Lookup library function. */
+ lua_pushvalue(L, -2);
+ lua_gettable(L, -2);
+ if (!lua_isfunction(L, -1)) {
+ /*tex Drop non-function and jit.* table, keep module name. */
+ lua_pop(L, 2);
+ if (loadjitmodule(L))
+ return 1;
+ } else {
+ /*tex Drop jit.* table. */
+ lua_remove(L, -2);
+ }
+ /*tex Drop module name. */
+ lua_remove(L, -2);
+ return runcmdopt(L, opt ? opt+1 : opt);
+}
+
+/*tex Optimization flags. */
+
+static int dojitopt(lua_State *L, const char *opt)
+{
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, -1, "jit.opt");
+ lua_remove(L, -2);
+ lua_getfield(L, -1, "start");
+ lua_remove(L, -2);
+ return runcmdopt(L, opt);
+}
+
+/*tex Save or list bytecode. */
+
+static int dobytecode(lua_State *L, char **argv)
+{
+ int narg = 0;
+ lua_pushliteral(L, "bcsave");
+ if (loadjitmodule(L))
+ return 1;
+ if (argv[0][2]) {
+ narg++;
+ argv[0][1] = '-';
+ lua_pushstring(L, argv[0]+1);
+ }
+ for (argv++; *argv != NULL; narg++, argv++)
+ lua_pushstring(L, *argv);
+ return report(L, lua_pcall(L, narg, 0, 0));
+}
+
+/*tex Check that argument has no extra characters at the end */
+
+#define notail(x) {if ((x)[2] != '\0') return -1;}
+
+#define FLAGS_INTERACTIVE 1
+#define FLAGS_VERSION 2
+#define FLAGS_EXEC 4
+#define FLAGS_OPTION 8
+#define FLAGS_NOENV 16
+
+static int collectargs(char **argv, int *flags)
+{
+ int i;
+ for (i = 1; argv[i] != NULL; i++) {
+ /*tex Not an option? */
+ if (argv[i][0] != '-')
+ return i;
+ /*tex Check option. */
+ switch (argv[i][1]) {
+ case '-':
+ notail(argv[i]);
+ return (argv[i+1] != NULL ? i+1 : 0);
+ case '\0':
+ return i;
+ case 'i':
+ notail(argv[i]);
+ *flags |= FLAGS_INTERACTIVE;
+ /*tex fallthrough */
+ case 'v':
+ notail(argv[i]);
+ *flags |= FLAGS_VERSION;
+ break;
+ case 'e':
+ *flags |= FLAGS_EXEC;
+ case 'j':
+ /*tex LuaJIT extension */
+ case 'l':
+ *flags |= FLAGS_OPTION;
+ if (argv[i][2] == '\0') {
+ i++;
+ if (argv[i] == NULL)
+ return -1;
+ }
+ break;
+ case 'O':
+ /*tex LuaJIT extension */
+ break;
+ case 'b':
+ /*tex LuaJIT extension */
+ if (*flags) return -1;
+ *flags |= FLAGS_EXEC;
+ return 0;
+ case 'E':
+ *flags |= FLAGS_NOENV;
+ break;
+ default:
+ /*tex invalid option */
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int runargs(lua_State *L, char **argv, int n)
+{
+ int i;
+ for (i = 1; i < n; i++) {
+ if (argv[i] == NULL)
+ continue;
+ lua_assert(argv[i][0] == '-');
+ switch (argv[i][1]) {
+ /*tex Options */
+ case 'e': {
+ const char *chunk = argv[i] + 2;
+ if (*chunk == '\0')
+ chunk = argv[++i];
+ lua_assert(chunk != NULL);
+ if (dostring(L, chunk, "=(command line)") != 0)
+ return 1;
+ break;
+ }
+ case 'l': {
+ const char *filename = argv[i] + 2;
+ if (*filename == '\0')
+ filename = argv[++i];
+ lua_assert(filename != NULL);
+ if (dolibrary(L, filename)) {
+ /*tex stop if file fails */
+ return 1;
+ }
+ break;
+ }
+ case 'j': {
+ /*tex LuaJIT extension */
+ const char *cmd = argv[i] + 2;
+ if (*cmd == '\0')
+ cmd = argv[++i];
+ lua_assert(cmd != NULL);
+ if (dojitcmd(L, cmd))
+ return 1;
+ break;
+ }
+ case 'O':
+ /*tex LuaJIT extension */
+ if (dojitopt(L, argv[i] + 2))
+ return 1;
+ break;
+ case 'b':
+ /*tex LuaJIT extension */
+ return dobytecode(L, argv+i);
+ default: break;
+ }
+ }
+ return 0;
+}
+
+static int handle_luainit(lua_State *L)
+{
+#if LJ_TARGET_CONSOLE
+ const char *init = NULL;
+#else
+ const char *init = getenv(LUA_INIT);
+#endif
+ if (init == NULL) {
+ /*tex status OK */
+ return 0;
+ } else if (init[0] == 64) {
+ return dofile(L, init+1);
+ } else {
+ return dostring(L, init, "=" LUA_INIT);
+ }
+}
+
+struct Smain {
+ char **argv;
+ int argc;
+ int status;
+};
+
+static int pmain(lua_State *L)
+{
+ struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
+ char **argv = s->argv;
+ int script;
+ int flags = 0;
+ globalL = L;
+ if (argv[0] && argv[0][0])
+ progname = argv[0];
+ /*tex linker-enforced version check */
+ LUAJIT_VERSION_SYM();
+ script = collectargs(argv, &flags);
+ if (script < 0) {
+ /*tex invalid args? */
+ print_usage();
+ s->status = 1;
+ return 0;
+ }
+ if ((flags & FLAGS_NOENV)) {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ }
+ /*tex stop collector during initialization */
+ lua_gc(L, LUA_GCSTOP, 0);
+ /*tex open libraries */
+ luaL_openlibs(L);
+ lua_gc(L, LUA_GCRESTART, -1);
+ if (!(flags & FLAGS_NOENV)) {
+ s->status = handle_luainit(L);
+ if (s->status != 0) return 0;
+ }
+ if ((flags & FLAGS_VERSION)) print_version();
+ s->status = runargs(L, argv, (script > 0) ? script : s->argc);
+ if (s->status != 0) return 0;
+ if (script) {
+ s->status = handle_script(L, argv, script);
+ if (s->status != 0) return 0;
+ }
+ if ((flags & FLAGS_INTERACTIVE)) {
+ print_jit_status(L);
+ dotty(L);
+ } else if (script == 0 && !(flags & (FLAGS_EXEC|FLAGS_VERSION))) {
+ if (lua_stdin_is_tty()) {
+ print_version();
+ print_jit_status(L);
+ dotty(L);
+ } else {
+ /*tex executes stdin as a file */
+ dofile(L, NULL);
+ }
+ }
+ return 0;
+}
+
+int luac_main(int argc, char **argv)
+{
+ int status;
+ struct Smain s;
+ lua_State *L = lua_open(); /* create state */
+ if (L == NULL) {
+ l_message(argv[0], "cannot create state: not enough memory");
+ return EXIT_FAILURE;
+ }
+ s.argc = argc;
+ s.argv = argv;
+ status = lua_cpcall(L, pmain, &s);
+ report(L, status);
+ lua_close(L);
+ return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+