diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/lua/lnodelib.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/lua/lnodelib.c | 9141 |
1 files changed, 9141 insertions, 0 deletions
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); + } +} |