diff options
author | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
commit | ad547a6b5986815fda458221149728d9d9ab1d87 (patch) | |
tree | 16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/luatexdir/lua | |
parent | 947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (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')
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', ¶m_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; +} + |