sync with experimental
[luatex.git] / source / texk / web2c / luatexdir / lua / lnodelib.c
blob06503800b4d6368b204b513780e7cea3d3c5e39c
1 /* lnodelib.c
3 Copyright 2006-2013 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
7 LuaTeX is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License along
18 with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
24 The node getter and setter are adapted a bit by Hans and Luigi so blame
25 them! On the agenda: check all keys, maybe hide some fields that are not
26 supposed to be seen and set (scratch fields for the backend and par
27 builder).
29 After doing lots of tests with luatex and luajittex, with and without jit,
30 and with and without ffi, we came to the conclusion that userdata prevents
31 a speedup. We also found that the checking of metatables as well as assignment
32 comes with overhead that can't be neglected. This is normally not really a
33 problem but when processing fonts for more complex scripts it's quite some
34 overhead.
36 Because the userdata approach has some benefits, we stick to this. We did
37 some experiments with fast access (assuming nodes) and kept some of the code
38 commented here, but eventually settled for the direct approach. For code that
39 is proven to be okay, one can use the direct variants and operate on nodes
40 more directly. Currently these are numbers, but that might become light
41 userdata at one point, so *never* rely on that property. An important aspect
42 is that one cannot mix both methods, although with node.direct.tonode and
43 node.direct.todirect one can cast both representations.
45 So the advice is: use the indexed approach when possible and investigate the
46 direct one when speed might be an issue. For that reason we also provide the
47 get* and set* functions in the top level node namespace. There is a limited set
48 of getters.
50 getnext : parsing nodelist always involves this one
51 getprev : used less but is logical companion to getnext
52 getid : consulted a lot
53 getsubtype : consulted less but also a topper
54 getfont : used a lot in otf handling (glyph nodes are consulted a lot)
55 getchar : idem and also in other places
56 getlist : we often parse nested lists so this is a convenient one too (only hlist/vlist !)
57 getleader : comparable to list, seldom used in tex (but needs consulting
58 like lists)
59 getfield : generic getter, sufficient for the rest (other field names are
60 often shared so a specific getter makes no sense then)
62 Keep in mind that these only make sense when we're calling them millions of
63 times (which happens in font processing for instance). Setters are less important
64 as documents have not that many content related nodes (and setting many thousands
65 of properties is hardly a burden contrary to millions of consultations.)
67 Another change is that __index and __newindex are (as expected) exposed to
68 users but do no checking. The getfield and setfield functions do check. In
69 fact, fast mode can be simulated by fast_getfield = __index but the (measured)
70 benefit on average runs is not that large (some 5% when we also use the other
71 fast ones) which is easily nilled by inefficient coding. The direct variants
72 on the other hand can be significantly faster but with the drawback of lack
73 of userdata features. With respect to speed: keep in mind that measuring
74 a speedup on these functions is not representative for a normal run, where
75 much more happens.
77 maybe : setnext setprev setfont setchar (only makes sense for some scripts)
79 todo : check and optimize the direct function when possible
81 todo : once the direct ones are proven we can redefine some of the less
82 critical normal ones to call the direct ones after checking for
83 a first argument being a node (like protect/unprotect)
85 The code below has quite some duplicated code but this is also a prelude
86 to light userdata for diretc nodes so we prefer this method. Some userdata
87 variants could call the direct functions but not now (also because we don't
88 want to touch the originals too much). As usual: blame Luigi and Hans for
89 issues with this code. You can blame HH for weird or inaccurate comments.
91 Todo: as a prelude to lua 5.3 we should use integer instead of number when
92 possible. A boring job. We can use the direct variants for testing this.
94 Hans Hagen, Luigi Scarso (2011-2013)
98 static const char _svn_version[] =
99 "$Id$ "
100 "$URL$";
102 #include "ptexlib.h"
103 #include "lua/luatex-api.h"
104 #include "lua/lauxlib_bridge.h"
108 These macros create and access pointers (indices) to keys which is faster. The
109 shortcuts are created as part of the initialization.
116 When the first argument to an accessor is a node, we can use it's metatable
117 entry when we are returning nodes, which saves a lookup.
121 #define fast_metatable(n) do { \
122 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
123 *a = n; \
124 lua_getmetatable(L,1); \
125 lua_setmetatable(L,-2); \
126 } while (0)
128 #define fast_metatable_or_nil(n) do { \
129 if (n) { \
130 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
131 *a = n; \
132 lua_getmetatable(L,1); \
133 lua_setmetatable(L,-2); \
134 } else { \
135 lua_pushnil(L); \
137 } while (0)
139 #define fast_metatable_or_nil_alink(n) do { \
140 if (n) { \
141 alink(n) = null; \
142 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
143 *a = n; \
144 lua_getmetatable(L,1); \
145 lua_setmetatable(L,-2); \
146 } else { \
147 lua_pushnil(L); \
149 } while (0)
151 #define fast_metatable_top(n) do { \
152 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
153 *a = n; \
154 lua_getmetatable(L,-2); \
155 lua_setmetatable(L,-2); \
156 } while (0)
158 #define lua_push_node_metatablelua do { \
159 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node)); \
160 lua_gettable(L, LUA_REGISTRYINDEX); \
161 } while (0)
165 This is a first step towards abstract direct nodes. When we have Lua 5.3 we
166 need to check all returned values for being integers. This might be another
167 level of abtraction.
171 #define nodelib_pushdirect(n) lua_pushnumber(L,n)
172 #define nodelib_popdirect(n) lua_tointeger(L,n)
174 #define nodelib_pushdirect_or_nil(n) do { \
175 if (n==null) { \
176 lua_pushnil(L); \
177 } else { \
178 lua_pushnumber(L,n); \
180 } while (0)
182 #define nodelib_pushdirect_or_nil_alink(n) do { \
183 if (n==null) { \
184 lua_pushnil(L); \
185 } else { \
186 alink(n) = null; \
187 lua_pushnumber(L,n); \
189 } while (0)
191 /* handy sometimes: */
193 /* static void stackDump (lua_State * L) { */
194 /* int i; */
195 /* int top = lua_gettop(L); */
196 /* for (i = top; i >= 1; i--) { */
197 /* int t = lua_type(L, i); */
198 /* switch (t) { */
199 /* case LUA_TSTRING: */
200 /* printf("[%d] '%s'\n", i, lua_tostring(L, i)); */
201 /* break; */
202 /* case LUA_TBOOLEAN: */
203 /* printf("[%d] %s\n",i, lua_toboolean(L, i) ? "true" : "false"); */
204 /* break; */
205 /* case LUA_TNUMBER: */
206 /* printf("[%d] %g\n", i, lua_tonumber(L, i)); */
207 /* break; */
208 /* default: */
209 /* printf("[%d][%d] %s &d=0x%x *d=%d\n",i-top-1, i, lua_typename(L, t), lua_touserdata(L,i), *((int *)lua_touserdata(L,i))); */
210 /* break; */
211 /* } */
212 /* } */
213 /* } */
216 #define nodelib_gettoks(L,a) tokenlist_from_lua(L)
218 #define nodelib_getspec nodelib_getlist
219 #define nodelib_getaction nodelib_getlist
221 /* a quick helper for dir nodes; there is only a small set of possible values */
223 #define RETURN_DIR_VALUES(a) \
224 if (s==luaS_##a##_ptr) { \
225 return (dir_##a); \
226 } else if (!absolute_only) { \
227 if (s==luaS_p##a##_ptr) \
228 return (dir_##a); \
229 else if (s==luaS_m##a##_ptr) \
230 return ((dir_##a)-64); \
233 /* fetching a field from a node .. we can often use the reuse bot-of-stack metatable */
235 #define nodelib_pushlist(L,n) { lua_pushnumber(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
236 #define nodelib_pushattr(L,n) { lua_pushnumber(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
237 #define nodelib_pushspec(L,n) { lua_pushnumber(L,n); lua_nodelib_push_spec(L); } /* can be: fast_metatable_or_nil(n) - different criterium? */
238 #define nodelib_pushaction(L,n) { lua_pushnumber(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
239 #define nodelib_pushstring(L,n) { char *ss=makecstring(n); lua_pushstring(L,ss); free(ss); }
241 /* find prev, and fix backlinks .. can be a macro instead (only used a few times) */
243 #define set_t_to_prev(head,current) \
244 t = head; \
245 while (vlink(t)!=current && t != null) { \
246 if (vlink(t)!=null) \
247 alink(vlink(t)) = t; \
248 t = vlink(t); \
251 #define get_node_type_id(L,n) do_get_node_type_id(L,n,node_data)
252 #define get_node_subtype_id(L,n) do_get_node_type_id(L,n,whatsit_node_data)
254 #define box(A) eqtb[box_base+(A)].hh.rh
255 #define direct_check_index_range(j,s) \
256 if (j<0 || j > 65535) { \
257 luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s); \
260 #define NODE_METATABLE "luatex.node"
262 #define DEBUG 0
263 #define DEBUG_OUT stdout
265 /* maybe these qualify as macros, not functions */
267 static halfword *maybe_isnode(lua_State * L, int ud)
269 halfword *p = lua_touserdata(L, ud);
270 if (p != NULL) {
271 if (lua_getmetatable(L, ud)) {
272 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
273 lua_gettable(L, LUA_REGISTRYINDEX);
274 if (!lua_rawequal(L, -1, -2))
275 p = NULL;
276 lua_pop(L, 2);
279 return p;
282 /* we could make the message a function and just inline the rest (via a macro) */
284 halfword *check_isnode(lua_State * L, int ud)
286 halfword *p = maybe_isnode(L, ud);
287 if (p != NULL)
288 return p;
289 luatex_fail("There should have been a lua <node> here, not an object with type %s!", luaL_typename(L, ud));
290 return NULL;
295 This routine finds the numerical value of a string (or number) at
296 lua stack index |n|. If it is not a valid node type, returns -1
298 Todo: create a lua table instead at initialization time and then
299 use that hash, so that we don't need to loop for each lookup.
301 HH: can crash on noad 9
305 static int do_get_node_type_id(lua_State * L, int n, node_info * data)
307 int j;
308 /* switch (lua_type(L, n)) { */
309 /* case LUA_TNIL: */
310 /* printf("LUA_TNIL\n"); */
311 /* break; */
312 /* case LUA_TNUMBER: */
313 /* printf("LUA_TNUMBER\n"); */
314 /* break; */
315 /* case LUA_TBOOLEAN: */
316 /* printf("LUA_TBOOLEAN\n"); */
317 /* break; */
318 /* case LUA_TSTRING: */
319 /* printf("LUA_TSTRING\n"); */
320 /* break; */
321 /* case LUA_TTABLE: */
322 /* printf("LUA_TTABLE\n"); */
323 /* break; */
324 /* case LUA_TFUNCTION: */
325 /* printf("LUA_TFUNCTION\n"); */
326 /* break; */
327 /* case LUA_TUSERDATA: */
328 /* printf("LUA_TUSERDATA\n"); */
329 /* break; */
330 /* case LUA_TTHREAD: */
331 /* printf("LUA_TTHREAD\n"); */
332 /* break; */
333 /* case LUA_TLIGHTUSERDATA: */
334 /* printf("LUA_TLIGHTUSERDATA\n"); */
335 /* break; */
336 /* } */
337 if (lua_type(L, n) == LUA_TSTRING) {
338 const char *s = lua_tostring(L, n);
339 for (j = 0; data[j].id != -1; j++) {
340 if (strcmp(s, data[j].name) == 0)
341 return j;
343 } else if (lua_type(L, n) == LUA_TNUMBER) {
344 int i = (int) lua_tointeger(L, n);
345 for (j = 0; data[j].id != -1; j++) {
346 if (data[j].id == i)
347 return j;
350 return -1;
353 static int get_valid_node_type_id(lua_State * L, int n)
355 int i = get_node_type_id(L, n);
356 if (i == -1) {
357 if (lua_type(L, n) == LUA_TSTRING) {
358 luaL_error(L, "Invalid node type id: %s", lua_tostring(L, n));
359 } else {
360 luaL_error(L, "Invalid node type id: %d", lua_tonumber(L, n));
363 return i;
366 static int get_valid_node_subtype_id(lua_State * L, int n)
368 int i = get_node_subtype_id(L, n);
369 if (i == -1) {
370 if (lua_type(L, n) == LUA_TSTRING) {
371 luaL_error(L, "Invalid whatsit node id: %s", lua_tostring(L, n));
372 } else {
373 luaL_error(L, "Invalid whatsit node id: %d", lua_tonumber(L, n));
376 return i;
379 /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
381 static int lua_nodelib_next(lua_State * L)
383 halfword *p = maybe_isnode(L,1);
384 if (p != NULL && *p && vlink(*p)) {
385 lua_nodelib_push_fast(L,vlink(*p));
386 } else {
387 lua_pushnil(L);
389 return 1;
392 static int lua_nodelib_prev(lua_State * L)
394 halfword *p = maybe_isnode(L,1);
395 if (p != NULL && *p && alink(*p)) {
396 lua_nodelib_push_fast(L,alink(*p));
397 } else {
398 lua_pushnil(L);
400 return 1;
405 static void lua_nodelib_push_simple(lua_State * L, halfword p)
407 halfword *a;
408 a = (halfword *) lua_newuserdata(L, sizeof(halfword));
409 *a = p;
410 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
411 lua_gettable(L, LUA_REGISTRYINDEX);
412 lua_setmetatable(L, -2);
419 Creates a userdata object for a number found at the stack top, if it is
420 representing a node (i.e. an pointer into |varmem|). It replaces the
421 stack entry with the new userdata, or pushes |nil| if the number is |null|,
422 or if the index is definately out of range. This test could be improved.
426 void lua_nodelib_push(lua_State * L)
428 halfword n;
429 halfword *a;
430 n = -1;
431 if (lua_isnumber(L, -1))
432 n = (int) lua_tointeger(L, -1);
433 lua_pop(L, 1);
434 if ((n == null) || (n < 0) || (n > var_mem_max)) {
435 lua_pushnil(L);
436 } else {
437 a = lua_newuserdata(L, sizeof(halfword));
438 *a = n;
439 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
440 lua_gettable(L, LUA_REGISTRYINDEX);
441 lua_setmetatable(L, -2);
443 return;
446 /* |spec_ptr| fields can legally be zero, which is why there is a special function. */
448 static void lua_nodelib_push_spec(lua_State * L)
450 halfword n;
451 halfword *a;
452 n = -1;
453 if (lua_isnumber(L, -1))
454 n = (halfword) lua_tointeger(L, -1);
455 lua_pop(L, 1);
456 if ((n < 0) || (n > var_mem_max)) {
457 lua_pushnil(L);
458 } else {
459 a = lua_newuserdata(L, sizeof(halfword));
460 *a = n;
461 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
462 lua_gettable(L, LUA_REGISTRYINDEX);
463 lua_setmetatable(L, -2);
465 return;
468 void lua_nodelib_push_fast(lua_State * L, halfword n)
470 halfword *a;
471 a = lua_newuserdata(L, sizeof(halfword));
472 *a = n;
473 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
474 lua_gettable(L, LUA_REGISTRYINDEX);
475 lua_setmetatable(L, -2);
476 return;
479 /* converts type strings to type ids */
481 static int lua_nodelib_id(lua_State * L)
483 int i = get_node_type_id(L, 1);
484 if (i >= 0) {
485 lua_pushnumber(L, i);
486 } else {
487 lua_pushnil(L);
489 return 1;
492 /* node.getid */
494 static int lua_nodelib_getid(lua_State * L)
496 /* [given-node] [...] */
497 halfword *p = lua_touserdata(L, 1);
498 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
499 lua_pushnil(L);
500 return 1;
502 /* [given-node] [mt-given-node] */
503 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
504 lua_gettable(L, LUA_REGISTRYINDEX);
505 /* [given-node] [mt-given-node] [mt-node] */
506 if (!lua_rawequal(L, -1, -2)) {
507 lua_pushnil(L);
508 } else {
509 lua_pushnumber(L, type(*p));
511 return 1;
514 /* node.fast.getid
516 static int lua_nodelib_fast_getid(lua_State * L)
518 halfword *n;
519 n = (halfword *) lua_touserdata(L, 1);
520 lua_pushnumber(L, type(*n));
521 return 1;
526 /* node.direct.getid */
528 static int lua_nodelib_direct_getid(lua_State * L)
530 halfword n;
531 n = (halfword) lua_tonumber(L, 1);
532 if (n == null) {
533 lua_pushnil(L);
534 } else {
535 lua_pushnumber(L, type(n));
537 return 1;
540 /* node.getsubtype */
542 static int lua_nodelib_getsubtype(lua_State * L)
544 halfword *p = lua_touserdata(L, 1);
545 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
546 lua_pushnil(L);
547 } else {
548 lua_push_node_metatablelua;
549 if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
550 lua_pushnil(L);
551 } else {
552 lua_pushnumber(L, subtype(*p));
555 return 1;
558 /* node.fast.getsubtype
560 static int lua_nodelib_fast_getsubtype(lua_State * L)
562 halfword *n;
563 n = (halfword *) lua_touserdata(L, 1);
564 lua_pushnumber(L, subtype(*n));
565 return 1;
570 /* node.direct.getsubtype */
572 static int lua_nodelib_direct_getsubtype(lua_State * L)
574 halfword n;
575 n = (halfword) lua_tonumber(L, 1);
576 if (n == null) { /* no check, we assume sane use */
577 lua_pushnil(L);
578 } else {
579 lua_pushnumber(L, subtype(n));
581 return 1;
584 /* node.getfont */
586 static int lua_nodelib_getfont(lua_State * L)
588 halfword *p = lua_touserdata(L, 1);
589 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
590 lua_pushnil(L);
591 } else {
592 lua_push_node_metatablelua;
593 if ( (!lua_rawequal(L, -1, -2)) || (type(*p) != glyph_node) ) {
594 lua_pushnil(L);
595 } else {
596 lua_pushnumber(L, font(*p));
599 return 1;
602 /* node.fast.getfont
604 static int lua_nodelib_fast_getfont(lua_State * L)
606 halfword *n;
607 n = (halfword *) lua_touserdata(L, 1);
608 if (type(*n) != glyph_node) {
609 lua_pushnil(L);
610 } else {
611 lua_pushnumber(L, font(*n));
613 return 1;
618 /* node.direct.getfont */
620 static int lua_nodelib_direct_getfont(lua_State * L)
622 halfword n;
623 n = (halfword) lua_tonumber(L, 1);
624 if ((n == null) || (type(n) != glyph_node)) {
625 lua_pushnil(L);
626 } else {
627 lua_pushnumber(L, font(n));
629 return 1;
632 /* node.getchar */
634 static int lua_nodelib_getcharacter(lua_State * L)
636 halfword *n = lua_touserdata(L, 1);
637 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
638 lua_pushnil(L);
639 } else if (type(*n) == glyph_node) {
640 lua_pushnumber(L, character(*n));
641 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
642 lua_pushnumber(L, math_character(*n));
644 return 1;
647 /* node.fast.getchar
649 static int lua_nodelib_fast_getcharacter(lua_State * L)
651 halfword *n;
652 n = (halfword *) lua_touserdata(L, 1);
653 if (type(*n) == glyph_node) {
654 lua_pushnumber(L, character(*n));
655 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
656 lua_pushnumber(L, math_character(*n));
657 } else {
658 lua_pushnil(L);
660 return 1;
665 /* node.direct.getchar */
667 static int lua_nodelib_direct_getcharacter(lua_State * L)
669 halfword n;
670 n = (halfword) lua_tonumber(L, 1);
671 if (n == null) {
672 lua_pushnil(L);
673 } else if (type(n) == glyph_node) {
674 lua_pushnumber(L, character(n));
675 } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
676 lua_pushnumber(L, math_character(n));
677 } else {
678 lua_pushnil(L);
680 return 1;
683 /* node.getlist */
685 static int lua_nodelib_getlist(lua_State * L)
687 halfword *a;
688 halfword *n = lua_touserdata(L, 1);
689 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
690 lua_pushnil(L);
691 } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
692 fast_metatable_or_nil_alink(list_ptr(*n));
693 } else {
694 lua_pushnil(L);
696 return 1;
699 /* node.direct.getlist */
701 static int lua_nodelib_direct_getlist(lua_State * L)
703 halfword n;
704 n = (halfword) lua_tonumber(L, 1);
705 if ( n == null) {
706 lua_pushnil(L);
707 } else if ((type(n) == hlist_node) || (type(n) == vlist_node)) {
708 nodelib_pushdirect_or_nil_alink(list_ptr(n));
709 } else {
710 lua_pushnil(L);
712 return 1;
715 /* node.getleader */
717 static int lua_nodelib_getleader(lua_State * L)
719 halfword *a;
720 halfword *n = lua_touserdata(L, 1);
721 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
722 lua_pushnil(L);
723 } else if (type(*n) == glue_node) {
724 fast_metatable_or_nil(leader_ptr(*n));
725 } else {
726 lua_pushnil(L);
728 return 1;
731 /* node.direct.getleader */
733 static int lua_nodelib_direct_getleader(lua_State * L)
735 halfword n;
736 n = (halfword) lua_tonumber(L, 1);
737 if ( n == null) {
738 lua_pushnil(L);
739 } else if (type(n) == glue_node) {
740 nodelib_pushdirect_or_nil(leader_ptr(n));
741 } else {
742 lua_pushnil(L);
744 return 1;
747 /* node.getnext */
749 static int lua_nodelib_getnext(lua_State * L)
751 halfword *a;
752 /* [given-node] [...]*/
753 halfword *p = lua_touserdata(L, 1);
754 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
755 lua_pushnil(L);
756 } else {
757 /* [given-node] [mt-given-node]*/
758 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
759 lua_gettable(L, LUA_REGISTRYINDEX);
760 /* [given-node] [mt-given-node] [mt-node]*/
761 if (!lua_rawequal(L, -1, -2)) {
762 lua_pushnil(L);
763 } else {
764 fast_metatable_or_nil(vlink(*p));
767 return 1; /* just one*/
770 /* node.fast.getnext
772 static int lua_nodelib_fast_getnext(lua_State * L)
774 halfword *a;
775 // [given-node] [...]
776 halfword *p = lua_touserdata(L, 1);
777 if ((p == NULL) || (!vlink(*p))){
778 lua_pushnil(L);
779 } else {
780 lua_settop(L,1);
781 // [given-node]
782 lua_getmetatable(L,1);
783 // [given-node] [mt-node]
784 a = lua_newuserdata(L, sizeof(halfword));
785 // [given-node] [mt-node] [next-node]
786 *a = vlink(*p);
787 lua_replace(L,1);
788 // [next-node] [mt-node]
789 lua_setmetatable(L,1);
790 // [next-node-with-mt]
792 return 1;
797 /* node.direct.getnext */
799 static int lua_nodelib_direct_getnext(lua_State * L)
801 halfword p;
802 p = (halfword) lua_tonumber(L, 1);
803 if (p == null) {
804 lua_pushnil(L);
805 } else {
806 nodelib_pushdirect_or_nil(vlink(p));
808 return 1;
811 /* node.getprev */
813 static int lua_nodelib_getprev(lua_State * L)
815 halfword *a;
816 halfword *p = lua_touserdata(L, 1);
817 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
818 lua_pushnil(L);
819 } else {
820 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
821 lua_gettable(L, LUA_REGISTRYINDEX);
822 if (!lua_rawequal(L, -1, -2)) {
823 lua_pushnil(L);
824 } else {
825 fast_metatable_or_nil(alink(*p));
828 return 1;
832 /* node.fast.getprev
834 static int lua_nodelib_fast_getprev(lua_State * L)
836 halfword *a;
837 // [given-node] [...]
838 halfword *p = lua_touserdata(L, 1);
839 if ((p == NULL) || (!alink(*p))) {
840 lua_pushnil(L);
841 } else {
842 lua_settop(L,1);
843 // [given-node]
844 lua_getmetatable(L,1);
845 // [given-node] [mt-node]
846 a = lua_newuserdata(L, sizeof(halfword));
847 // [given-node] [mt-node] [next-node]
848 *a = alink(*p);
849 lua_replace(L,1);
850 // [next-node] [mt-node]
851 lua_setmetatable(L,1);
852 // [next-node-with-mt]
854 return 1;
859 /* node.direct.getprev */
861 static int lua_nodelib_direct_getprev(lua_State * L)
863 halfword p;
864 p = (halfword) lua_tonumber(L, 1);
865 if (p == null) {
866 lua_pushnil(L);
867 } else {
868 nodelib_pushdirect_or_nil(alink(p));
870 return 1;
873 /* node.subtype */
875 static int lua_nodelib_subtype(lua_State * L)
877 int i = get_node_subtype_id(L, 1);
878 if (i >= 0) {
879 lua_pushnumber(L, i);
880 } else {
881 lua_pushnil(L); /* return 0; */
883 return 1;
886 /* node.type (converts id numbers to type names) */
888 static int lua_nodelib_type(lua_State * L)
890 if (lua_type(L,1) == LUA_TNUMBER) {
891 int i = get_node_type_id(L, 1);
892 if (i >= 0) {
893 lua_pushstring(L, node_data[i].name);
894 return 1;
896 } else if (maybe_isnode(L, 1) != NULL) {
897 lua_pushstring(L,"node");
898 return 1;
900 lua_pushnil(L);
901 return 1;
904 /* node.new (allocate a new node) */
906 static int lua_nodelib_new(lua_State * L)
908 int i, j;
909 halfword n = null;
910 i = get_valid_node_type_id(L, 1);
911 if (i == whatsit_node) {
912 j = -1;
913 if (lua_gettop(L) > 1)
914 j = get_valid_node_subtype_id(L, 2);
915 if (j < 0)
916 luaL_error(L, "Creating a whatsit requires the subtype number as a second argument");
917 } else {
918 j = 0;
919 if (lua_gettop(L) > 1)
920 j = (int) lua_tointeger(L, 2);
922 n = new_node(i, j);
923 lua_nodelib_push_fast(L, n);
924 return 1;
927 /* node.direct.new (still with checking) */
929 static int lua_nodelib_direct_new(lua_State * L)
931 int i, j;
932 halfword n ;
933 i = get_valid_node_type_id(L, 1);
934 if (i == whatsit_node) {
935 j = -1;
936 if (lua_gettop(L) > 1)
937 j = get_valid_node_subtype_id(L, 2);
938 if (j < 0)
939 luaL_error(L, "Creating a whatsit requires the subtype number as a second argument");
940 } else {
941 j = 0;
942 if (lua_gettop(L) > 1)
943 j = (int) lua_tointeger(L, 2);
945 n = new_node(i, j);
946 lua_pushnumber(L,n);
947 return 1;
950 /* node.free (this function returns the 'next' node, because that may be helpful) */
952 static int lua_nodelib_free(lua_State * L)
954 halfword *n;
955 halfword p;
956 if (lua_gettop(L) < 1) {
957 lua_pushnil(L);
958 return 1;
959 } else if (lua_isnil(L, 1)) {
960 return 1; /* the nil itself */
962 n = check_isnode(L, 1);
963 p = vlink(*n);
964 flush_node(*n);
965 /* can be: lua_nodelib_push_fast(L, p); */
966 lua_pushnumber(L, p);
967 lua_nodelib_push(L);
968 return 1;
971 /* node.direct.free */
973 static int lua_nodelib_direct_free(lua_State * L)
975 halfword n;
976 halfword p;
977 n = (halfword) lua_tonumber(L,1);
978 if (n == null) {
979 lua_pushnil(L);
980 } else {
981 p = vlink(n);
982 flush_node(n);
983 if (p == 0) {
984 lua_pushnil(L);
985 } else {
986 lua_pushnumber(L,p);
989 return 1;
992 /* node.flush_node (no next returned) */
994 static int lua_nodelib_flush_node(lua_State * L)
996 halfword *n;
997 if ((lua_gettop(L) < 1) || lua_isnil(L, 1))
998 return 0;
999 n = check_isnode(L, 1);
1000 // no check if n?
1001 flush_node(*n);
1002 return 0;
1005 /* node.direct.flush_node */
1007 static int lua_nodelib_direct_flush_node(lua_State * L)
1009 halfword n;
1010 n = (halfword) lua_tonumber(L,1);
1011 if (n == null)
1012 return 0;
1013 flush_node(n);
1014 return 0;
1017 /* node.flush_list */
1019 static int lua_nodelib_flush_list(lua_State * L)
1021 halfword *n_ptr;
1022 if ((lua_gettop(L) < 1) || lua_isnil(L, 1))
1023 return 0;
1024 n_ptr = check_isnode(L, 1);
1025 flush_node_list(*n_ptr);
1026 return 0;
1029 /* node.direct.flush_list */
1031 static int lua_nodelib_direct_flush_list(lua_State * L)
1033 halfword n;
1034 n = (halfword) lua_tonumber(L,1);
1035 if (n == null)
1036 return 0;
1037 flush_node_list(n);
1038 return 0;
1041 /* remove a node from a list */
1043 #if DEBUG
1045 static void show_node_links (halfword l, const char * p)
1047 halfword t = l;
1048 while (t) {
1049 fprintf(DEBUG_OUT, "%s t = %d, prev = %d, next = %d\n", p, (int)t, (int)alink(t), (int)vlink(t));
1050 t = vlink(t);
1054 #endif
1056 /* node.remove */
1058 static int lua_nodelib_remove(lua_State * L)
1060 halfword head, current, t;
1061 if (lua_gettop(L) < 2)
1062 luaL_error(L, "Not enough arguments for node.remove()");
1063 head = *(check_isnode(L, 1));
1064 #if DEBUG
1065 show_node_links(head, "before");
1066 #endif
1067 if (lua_isnil(L, 2))
1068 return 2; /* the arguments, as they are */
1069 current = *(check_isnode(L, 2));
1070 if (head == current) {
1071 if (alink(current)){
1072 vlink(alink(current)) = vlink(current); // vlink(prev) = next
1074 if (vlink(current)){
1075 alink( vlink(current)) = alink(current); // alink(next) = prev
1078 head = vlink(current); //head = next
1079 current = vlink(current); //current = next
1080 } else { /* head != current */
1081 t = alink(current);
1082 if (t == null || vlink(t) != current) {
1083 set_t_to_prev(head, current);
1084 if (t == null) /* error! */
1085 luaL_error(L,"Attempt to node.remove() a non-existing node");
1087 /* t is now the previous node */
1088 vlink(t) = vlink(current);
1089 if (vlink(current) != null)
1090 alink(vlink(current)) = t;
1091 current = vlink(current);
1093 #if DEBUG
1094 show_node_links(head, "after");
1095 #endif
1096 /* can be: lua_nodelib_push_fast(L, head); */
1097 lua_pushnumber(L, head);
1098 lua_nodelib_push(L);
1099 /* can be: lua_nodelib_push_fast(L, current); */
1100 lua_pushnumber(L, current);
1101 lua_nodelib_push(L);
1102 return 2;
1105 /* node.direct.remove */
1107 static int lua_nodelib_direct_remove(lua_State * L)
1109 halfword head, current , t;
1110 head = (halfword) lua_tonumber(L,1);
1111 if (head == null) {
1112 lua_pushnil(L);
1113 lua_pushnil(L);
1114 return 2 ;
1116 current = (halfword) lua_tonumber(L,2);
1117 if (current == null) {
1118 lua_pushnumber(L, head);
1119 lua_pushnil(L);
1120 return 2 ;
1122 if (head == current) {
1123 if (alink(current)){
1124 vlink( alink(current) ) = vlink(current); // vlink(prev) = next
1126 if (vlink(current)){
1127 alink( vlink(current) ) = alink(current); // alink(next) = prev
1129 head = vlink(current); //head = next
1130 current = vlink(current); //current = next
1131 } else {
1132 t = alink(current);
1133 if (t == null || vlink(t) != current) {
1134 set_t_to_prev(head, current);
1135 if (t == null) {
1136 luaL_error(L,"Attempt to node.direct.remove() a non-existing node");
1139 vlink(t) = vlink(current);
1140 if (vlink(current) != null)
1141 alink(vlink(current)) = t;
1142 current = vlink(current);
1144 if (head == null) {
1145 lua_pushnil(L);
1146 } else {
1147 lua_pushnumber(L, head);
1149 if (current == null) {
1150 lua_pushnil(L);
1151 } else {
1152 lua_pushnumber(L, current);
1154 return 2;
1157 /* node.insert_before (insert a node in a list) */
1159 static int lua_nodelib_insert_before(lua_State * L)
1161 halfword head, current, n, t;
1162 if (lua_gettop(L) < 3) {
1163 luaL_error(L, "Not enough arguments for node.insert_before()");
1165 if (lua_isnil(L, 3)) {
1166 lua_pop(L, 1);
1167 return 2;
1168 } else {
1169 n = *(check_isnode(L, 3));
1171 if (lua_isnil(L, 1)) { /* no head */
1172 vlink(n) = null;
1173 alink(n) = null;
1174 lua_nodelib_push_fast(L, n);
1175 lua_pushvalue(L, -1);
1176 return 2;
1177 } else {
1178 head = *(check_isnode(L, 1));
1180 if (lua_isnil(L, 2)) {
1181 current = tail_of_list(head);
1182 } else {
1183 current = *(check_isnode(L, 2));
1185 if (head != current) {
1186 t = alink(current);
1187 if (t == null || vlink(t) != current) {
1188 set_t_to_prev(head, current);
1189 if (t == null) { /* error! */
1190 luaL_error(L, "Attempt to node.insert_before() a non-existing node");
1193 couple_nodes(t, n);
1195 couple_nodes(n, current);
1196 if (head == current) {
1197 lua_nodelib_push_fast(L, n);
1198 } else {
1199 lua_nodelib_push_fast(L, head);
1201 lua_nodelib_push_fast(L, n);
1202 return 2;
1205 /* node.direct.insert_before */
1207 static int lua_nodelib_direct_insert_before(lua_State * L)
1209 halfword head, current, n, t;
1210 n = (halfword) lua_tonumber(L,3);
1211 if (n == null){
1212 /* no node */
1213 lua_pop(L, 1);
1214 return 2 ;
1216 head = (halfword) lua_tonumber(L,1);
1217 current = (halfword) lua_tonumber(L,2);
1218 /* no head, ignore current */
1219 if (head == null) {
1220 vlink(n) = null;
1221 alink(n) = null;
1222 lua_pushnumber(L, n);
1223 lua_pushvalue(L, -1);
1224 /* n, n */
1225 return 2;
1227 /* no current */
1228 if (current == null)
1229 current = tail_of_list(head);
1230 if (head != current) {
1231 t = alink(current);
1232 if (t == null || vlink(t) != current)
1233 set_t_to_prev(head, current);
1234 couple_nodes(t, n);
1236 couple_nodes(n, current);
1237 if (head == current) {
1238 lua_pushnumber(L, n);
1239 } else {
1240 lua_pushnumber(L, head);
1242 lua_pushnumber(L, n);
1243 return 2;
1246 /* node.insert_after */
1248 static int lua_nodelib_insert_after(lua_State * L)
1250 halfword head, current, n;
1251 if (lua_gettop(L) < 3) {
1252 luaL_error(L, "Not enough arguments for node.insert_after()");
1254 if (lua_isnil(L, 3)) {
1255 lua_pop(L, 1);
1256 return 2;
1257 } else {
1258 n = *(check_isnode(L, 3));
1260 if (lua_isnil(L, 1)) { /* no head */
1261 vlink(n) = null;
1262 alink(n) = null;
1263 lua_nodelib_push_fast(L, n);
1264 lua_pushvalue(L, -1);
1265 return 2;
1266 } else {
1267 head = *(check_isnode(L, 1));
1269 if (lua_isnil(L, 2)) {
1270 current = head;
1271 while (vlink(current) != null)
1272 current = vlink(current);
1273 } else {
1274 current = *(check_isnode(L, 2));
1276 try_couple_nodes(n, vlink(current));
1277 couple_nodes(current, n);
1279 lua_pop(L, 2);
1280 lua_nodelib_push_fast(L, n);
1281 return 2;
1284 /* node.direct.insert_after */
1286 static int lua_nodelib_direct_insert_after(lua_State * L)
1288 halfword head, current, n;
1289 /*[head][current][new]*/
1290 n = (halfword) lua_tonumber(L,3);
1291 if (n == null) {
1292 /* no node */
1293 return 2 ;
1295 head = (halfword) lua_tonumber(L,1);
1296 current = (halfword) lua_tonumber(L,2);
1297 if (head == null) {
1298 /* no head, ignore current */
1299 vlink(n) = null;
1300 alink(n) = null;
1301 lua_pushnumber(L,n);
1302 lua_pushvalue(L, -1);
1303 /* n, n */
1304 return 2;
1306 if (current == null) {
1307 /* no current */
1308 current = head;
1309 while (vlink(current) != null)
1310 current = vlink(current);
1312 try_couple_nodes(n, vlink(current));
1313 couple_nodes(current, n);
1314 lua_pop(L, 2);
1315 lua_pushnumber(L, n);
1316 return 2;
1319 /* node.copy_list */
1320 /* hh-ls: we need to use an intermediate variable as otherwise target is used in the loop
1321 and subfields get overwritten (or something like that) which results in crashes and
1322 unexpected side effects */
1323 static int lua_nodelib_copy_list(lua_State * L)
1325 halfword n, s = null;
1326 halfword m;
1327 if (lua_isnil(L, 1))
1328 return 1; /* the nil itself */
1329 n = *check_isnode(L, 1);
1330 if ((lua_gettop(L) > 1) && (!lua_isnil(L,2)))
1331 s = *check_isnode(L, 2);
1332 m = do_copy_node_list(n, s);
1333 // lua_pushnumber(L, m);
1334 // lua_nodelib_push(L);
1335 lua_nodelib_push_fast(L,m);
1336 return 1;
1341 /* node.direct.copy_list */
1343 static int lua_nodelib_direct_copy_list(lua_State * L)
1345 halfword n, s, m;
1346 n = (halfword) lua_tonumber(L,1);
1347 if (n == null) {
1348 lua_pushnil(L);
1349 } else {
1350 s = (halfword) lua_tonumber(L,2);
1351 if (s == null) {
1352 m = do_copy_node_list(n,null);
1353 } else {
1354 m = do_copy_node_list(n,s);
1356 lua_pushnumber(L,m);
1358 return 1;
1361 /* node.copy (deep copy) */
1363 static int lua_nodelib_copy(lua_State * L)
1365 halfword *n;
1366 halfword m;
1367 if (lua_isnil(L, 1))
1368 return 1; /* the nil itself */
1369 n = check_isnode(L, 1);
1370 m = copy_node(*n);
1371 lua_nodelib_push_fast(L, m);
1372 return 1;
1375 /* node.direct.copy (deep copy) */
1377 static int lua_nodelib_direct_copy(lua_State * L)
1379 halfword n;
1380 halfword m;
1381 if (lua_isnil(L, 1))
1382 return 1; /* the nil itself */
1383 /* beware, a glue node can have number 0 (zeropt) so we cannot test for null) */
1384 n = (halfword) lua_tonumber(L, 1);
1385 m = copy_node(n);
1386 lua_pushnumber(L, m);
1387 return 1;
1391 /* node.write (output a node to tex's processor) */
1393 static int lua_nodelib_append(lua_State * L)
1395 halfword *n;
1396 halfword m;
1397 int i, j;
1398 j = lua_gettop(L);
1399 for (i = 1; i <= j; i++) {
1400 n = check_isnode(L, i);
1401 m = *n;
1402 tail_append(m);
1403 while (vlink(m) != null) {
1404 m = vlink(m);
1405 tail_append(m);
1408 return 0;
1411 /* node.direct.write */
1413 static int lua_nodelib_direct_append(lua_State * L)
1415 halfword n;
1416 halfword m;
1417 int i, j;
1418 j = lua_gettop(L);
1419 for (i = 1; i <= j; i++) {
1420 n = (halfword) lua_tonumber(L,i); /*lua_getnumber(L, i);*/
1421 if (n != null) {
1422 m = n ;
1423 tail_append(m);
1424 while (vlink(m) != null) {
1425 m = vlink(m);
1426 tail_append(m);
1430 return 0;
1433 /* node.last */
1435 static int lua_nodelib_last_node(lua_State * L)
1437 halfword m;
1438 m = pop_tail();
1439 /* can be: lua_nodelib_push_fast(L, m); */
1440 lua_pushnumber(L, m);
1441 lua_nodelib_push(L);
1442 return 1;
1445 /* node.direct.last */
1447 static int lua_nodelib_direct_last_node(lua_State * L)
1449 halfword m;
1450 m = pop_tail();
1451 lua_pushnumber(L, m);
1452 return 1;
1455 /* node.hpack (build a hbox) */
1457 static int lua_nodelib_hpack(lua_State * L)
1459 halfword n, p;
1460 const char *s;
1461 int w = 0;
1462 int m = 1;
1463 int d = -1;
1464 n = *(check_isnode(L, 1));
1465 if (lua_gettop(L) > 1) {
1466 w = (int) lua_tointeger(L, 2);
1467 if (lua_gettop(L) > 2) {
1468 if (lua_type(L, 3) == LUA_TSTRING) {
1469 s = lua_tostring(L, 3);
1470 if (lua_key_eq(s, exactly)) {
1471 m = 0;
1472 } else if (lua_key_eq(s, additional)) {
1473 m = 1;
1474 } else if (lua_key_eq(s, cal_expand_ratio)) {
1475 m = 2;
1476 } else if (lua_key_eq(s, subst_ex_font)) {
1477 m = 3;
1478 } else {
1479 luaL_error(L, "3rd argument should be either additional or exactly");
1481 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1482 m=(int)lua_tonumber(L, 3);
1483 } else {
1484 lua_pushstring(L, "incorrect 3rd argument");
1486 if (lua_gettop(L) > 3) {
1487 if (lua_type(L, 4) == LUA_TSTRING) {
1488 d = nodelib_getdir(L, 4, 1);
1489 } else {
1490 lua_pushstring(L, "incorrect 4th argument");
1495 p = hpack(n, w, m, d);
1496 lua_nodelib_push_fast(L, p);
1497 lua_pushnumber(L, last_badness);
1498 return 2;
1501 /* node.direct.hpack */
1503 static int lua_nodelib_direct_hpack(lua_State * L)
1505 halfword n, p;
1506 const char *s;
1507 int w = 0;
1508 int m = 1;
1509 int d = -1;
1510 n = (halfword) lua_tonumber(L,1);
1511 /* could be macro */
1512 if (lua_gettop(L) > 1) {
1513 w = (int) lua_tointeger(L, 2);
1514 if (lua_gettop(L) > 2) {
1515 if (lua_type(L, 3) == LUA_TSTRING) {
1516 s = lua_tostring(L, 3);
1517 if (lua_key_eq(s, additional)) {
1518 m = 1;
1519 } else if (lua_key_eq(s, exactly)) {
1520 m = 0;
1521 } else if (lua_key_eq(s, cal_expand_ratio)) {
1522 m = 2;
1523 } else if (lua_key_eq(s, subst_ex_font)) {
1524 m = 3;
1525 } else {
1526 luaL_error(L, "3rd argument should be either additional or exactly");
1528 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1529 m=(int)lua_tonumber(L, 3);
1530 } else {
1531 lua_pushstring(L, "incorrect 3rd argument");
1533 if (lua_gettop(L) > 3) {
1534 if (lua_type(L, 4) == LUA_TSTRING) {
1535 d = nodelib_getdir(L, 4, 1);
1536 } else {
1537 lua_pushstring(L, "incorrect 4th argument");
1542 /* till here */
1543 p = hpack(n, w, m, d);
1544 lua_pushnumber(L, p);
1545 lua_pushnumber(L, last_badness);
1546 return 2;
1549 /* node.vpack (build a vbox) */
1551 static int lua_nodelib_vpack(lua_State * L)
1553 halfword n, p;
1554 const char *s;
1555 int w = 0;
1556 int m = 1;
1557 int d = -1;
1558 n = *(check_isnode(L, 1));
1559 if (lua_gettop(L) > 1) {
1560 w = (int) lua_tointeger(L, 2);
1561 if (lua_gettop(L) > 2) {
1562 if (lua_type(L, 3) == LUA_TSTRING) {
1563 s = lua_tostring(L, 3);
1564 if (lua_key_eq(s, additional)) {
1565 m = 1;
1566 } else if (lua_key_eq(s, exactly)) {
1567 m = 0;
1568 } else {
1569 luaL_error(L, "3rd argument should be either additional or exactly");
1572 if (lua_gettop(L) > 3) {
1573 if (lua_type(L, 4) == LUA_TSTRING) {
1574 d = nodelib_getdir(L, 4, 1);
1575 } else {
1576 lua_pushstring(L, "incorrect 4th argument");
1581 else if (lua_type(L, 3) == LUA_TNUMBER) {
1582 m=(int)lua_tonumber(L, 3);
1583 } else {
1584 lua_pushstring(L, "incorrect 3rd argument");
1588 p = vpackage(n, w, m, max_dimen, d);
1589 lua_nodelib_push_fast(L, p);
1590 lua_pushnumber(L, last_badness);
1591 return 2;
1594 /* node.direct.vpack */
1596 static int lua_nodelib_direct_vpack(lua_State * L)
1598 halfword n, p;
1599 const char *s;
1600 int w = 0;
1601 int m = 1;
1602 int d = -1;
1603 n = (halfword) lua_tonumber(L,1);
1604 if (lua_gettop(L) > 1) {
1605 w = (int) lua_tointeger(L, 2);
1606 if (lua_gettop(L) > 2) {
1607 if (lua_type(L, 3) == LUA_TSTRING) {
1608 s = lua_tostring(L, 3);
1609 if (lua_key_eq(s, additional)) {
1610 m = 1;
1611 } else if (lua_key_eq(s, exactly)) {
1612 m = 0;
1613 } else {
1614 luaL_error(L, "3rd argument should be either additional or exactly");
1617 if (lua_gettop(L) > 3) {
1618 if (lua_type(L, 4) == LUA_TSTRING) {
1619 d = nodelib_getdir(L, 4, 1);
1620 } else {
1621 lua_pushstring(L, "incorrect 4th argument");
1626 else if (lua_type(L, 3) == LUA_TNUMBER) {
1627 m=(int)lua_tonumber(L, 3);
1628 } else {
1629 lua_pushstring(L, "incorrect 3rd argument");
1633 p = vpackage(n, w, m, max_dimen, d);
1634 lua_pushnumber(L, p);
1635 lua_pushnumber(L, last_badness);
1636 return 2;
1639 /* node.dimensions (of a hlist or vlist) */
1641 static int lua_nodelib_dimensions(lua_State * L)
1643 int top;
1644 top = lua_gettop(L);
1645 if (top > 0) {
1646 scaled_whd siz;
1647 glue_ratio g_mult = 1.0;
1648 int g_sign = normal;
1649 int g_order = normal;
1650 int i = 1;
1651 int d = -1;
1652 halfword n = null, p = null;
1653 /* maybe be more restrictive: LUA_TNUMBER i.e. it's not good to mix numbers and strings with digits */
1654 if (lua_isnumber(L, 1)) {
1655 if (top < 4) {
1656 lua_pushnil(L);
1657 return 1;
1659 i += 3;
1660 g_mult = (glue_ratio) lua_tonumber(L, 1);
1661 g_sign=(int)lua_tonumber(L, 2);
1662 g_order=(int)lua_tonumber(L, 3);
1664 n = *(check_isnode(L, i));
1665 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1666 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1667 d = nodelib_getdir(L, (i + 1), 1);
1668 } else {
1669 p = *(check_isnode(L, (i + 1)));
1672 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING) {
1673 d = nodelib_getdir(L, (i + 2), 1);
1675 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1676 lua_pushnumber(L, siz.wd);
1677 lua_pushnumber(L, siz.ht);
1678 lua_pushnumber(L, siz.dp);
1679 return 3;
1680 } else {
1681 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1683 return 0; /* not reached */
1686 /* node.direct.dimensions*/
1688 static int lua_nodelib_direct_dimensions(lua_State * L)
1690 int top;
1691 top = lua_gettop(L);
1692 if (top > 0) {
1693 scaled_whd siz;
1694 glue_ratio g_mult = 1.0;
1695 int g_sign = normal;
1696 int g_order = normal;
1697 int i = 1;
1698 int d = -1;
1699 halfword n = null, p = null;
1700 if (top > 3) {
1701 i += 3;
1702 g_mult = (glue_ratio) lua_tonumber(L, 1);
1703 g_sign=(int)lua_tonumber(L, 2);
1704 g_order=(int)lua_tonumber(L, 3);
1706 n = (halfword) lua_tonumber(L,i);
1707 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1708 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1709 d = nodelib_getdir(L, (i + 1), 1);
1710 } else {
1711 p = (halfword) lua_tonumber(L,i+1);
1714 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING)
1715 d = nodelib_getdir(L, (i + 2), 1);
1716 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1717 lua_pushnumber(L, siz.wd);
1718 lua_pushnumber(L, siz.ht);
1719 lua_pushnumber(L, siz.dp);
1720 return 3;
1721 } else {
1722 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1724 return 0; /* not reached */
1727 /* node.mlist_to_hlist (create a hlist from a formula) */
1729 static int lua_nodelib_mlist_to_hlist(lua_State * L)
1731 halfword n;
1732 int w;
1733 boolean m;
1734 n = *(check_isnode(L, 1));
1735 //w = luaL_checkoption(L, 2, "text", math_style_names);
1736 assign_math_style(L,2,w);
1737 luaL_checkany(L, 3);
1738 m = lua_toboolean(L, 3);
1739 mlist_to_hlist_args(n, w, m);
1740 alink(vlink(temp_head)) = null; /*hh-ls */
1741 lua_nodelib_push_fast(L, vlink(temp_head));
1742 return 1;
1745 /* node.family_font */
1747 static int lua_nodelib_mfont(lua_State * L)
1749 int f, s;
1750 f = (int) luaL_checkinteger(L, 1);
1751 if (lua_gettop(L) == 2)
1752 s = (int) lua_tointeger(L, 2); /* this should be a multiple of 256 ! */
1753 else
1754 s = 0;
1755 lua_pushnumber(L, fam_fnt(f, s));
1756 return 1;
1760 This function is similar to |get_node_type_id|, for field
1761 identifiers. It has to do some more work, because not all
1762 identifiers are valid for all types of nodes.
1764 If really needed we can optimize this one using a big if ..
1765 .. else like with the getter and setter.
1769 static int get_node_field_id(lua_State * L, int n, int node)
1771 int t = type(node);
1772 const char *s = lua_tostring(L, n);
1774 if (s == NULL)
1775 return -2;
1777 if (lua_key_eq(s, next)) {
1778 return 0;
1779 } else if (lua_key_eq(s, id)) {
1780 return 1;
1781 } else if (lua_key_eq(s, subtype)) {
1782 if (nodetype_has_subtype(t)) {
1783 return 2;
1785 } else if (lua_key_eq(s, attr)) {
1786 if (nodetype_has_attributes(t)) {
1787 return 3;
1789 } else if (lua_key_eq(s, prev)) {
1790 if (nodetype_has_prev(t)) {
1791 return -1;
1793 } else {
1794 int j;
1795 const char **fields = node_data[t].fields;
1796 if (t == whatsit_node) {
1797 fields = whatsit_node_data[subtype(node)].fields;
1799 if (lua_key_eq(s, list)) {
1800 /* head and list are equivalent; we don't catch extra virtual fields */
1801 s = luaS_head_ptr;
1803 if (fields != NULL) {
1804 for (j = 0; fields[j] != NULL; j++) {
1805 if (strcmp(s, fields[j]) == 0) {
1806 return j + 3;
1811 return -2;
1814 /* node.has_field */
1816 static int lua_nodelib_has_field(lua_State * L)
1818 int i = -2;
1819 if (!lua_isnil(L, 1))
1820 i = get_node_field_id(L, 2, *(check_isnode(L, 1)));
1821 lua_pushboolean(L, (i != -2));
1822 return 1;
1825 /* node.direct.has_field */
1827 static int lua_nodelib_direct_has_field(lua_State * L)
1829 int i = -2;
1830 halfword n;
1831 n = (halfword) lua_tonumber(L, 1);
1832 if (n != null)
1833 i = get_node_field_id(L, 2, n);
1834 lua_pushboolean(L, (i != -2));
1835 return 1;
1838 /* fetch the list of valid node types */
1840 static int do_lua_nodelib_types(lua_State * L, node_info * data)
1842 int i;
1843 lua_newtable(L);
1844 for (i = 0; data[i].id != -1; i++) {
1845 lua_pushstring(L, data[i].name);
1846 lua_rawseti(L, -2, data[i].id);
1848 return 1;
1851 /* node.types */
1853 static int lua_nodelib_types(lua_State * L)
1855 return do_lua_nodelib_types(L, node_data);
1858 /* node.whatsits */
1860 static int lua_nodelib_whatsits(lua_State * L)
1862 return do_lua_nodelib_types(L, whatsit_node_data);
1865 /* node.fields (fetch the list of valid fields) */
1867 static int lua_nodelib_fields(lua_State * L)
1869 int i = -1;
1870 int offset = 2;
1871 const char **fields;
1872 int t = get_valid_node_type_id(L, 1);
1873 if (t == whatsit_node) {
1874 t = get_valid_node_subtype_id(L, 2);
1875 fields = whatsit_node_data[t].fields;
1876 } else {
1877 fields = node_data[t].fields;
1879 lua_checkstack(L, 2);
1880 lua_newtable(L);
1881 // lua_pushstring(L, "next");
1882 lua_push_string_by_name(L,next);
1883 lua_rawseti(L, -2, 0);
1884 // lua_pushstring(L, "id");
1885 lua_push_string_by_name(L,id);
1886 lua_rawseti(L, -2, 1);
1887 if (nodetype_has_subtype(t)) {
1888 // lua_pushstring(L, "subtype");
1889 lua_push_string_by_name(L,subtype);
1890 lua_rawseti(L, -2, 2);
1891 offset++;
1893 if (fields != NULL) {
1894 if (nodetype_has_prev(t)) {
1895 // lua_pushstring(L, "prev");
1896 lua_push_string_by_name(L,prev);
1897 lua_rawseti(L, -2, -1);
1899 for (i = 0; fields[i] != NULL; i++) {
1900 lua_pushstring(L, fields[i]); /* todo */
1901 lua_rawseti(L, -2, (i + offset));
1904 return 1;
1907 /* node.slide (find the end of a list and add prev links) */
1909 static int lua_nodelib_slide(lua_State * L)
1911 halfword *n;
1912 halfword t;
1913 if (lua_isnil(L, 1))
1914 return 1; /* the nil itself */
1915 n = check_isnode(L, 1);
1916 t = *n;
1917 if (t == null)
1918 return 1; /* the old userdata */
1919 /* alink(t) = null; */ /* don't do this, |t|'s |alink| may be a valid pointer */
1920 while (vlink(t) != null) {
1921 alink(vlink(t)) = t;
1922 t = vlink(t);
1924 lua_nodelib_push_fast(L, t);
1925 return 1;
1928 /* node.direct.slide */
1930 static int lua_nodelib_direct_slide(lua_State * L)
1932 halfword n;
1933 n = (halfword) lua_tonumber(L, 1);
1934 if (n == null) {
1935 lua_pushnil(L);
1936 } else {
1937 while (vlink(n) != null) {
1938 alink(vlink(n)) = n;
1939 n = vlink(n);
1941 lua_pushnumber(L, n);
1943 return 1;
1946 /* node.tail (find the end of a list) */
1948 static int lua_nodelib_tail(lua_State * L)
1950 halfword *n;
1951 halfword t;
1952 if (lua_isnil(L, 1))
1953 return 1; /* the nil itself */
1954 n = check_isnode(L, 1);
1955 t = *n;
1956 if (t == null)
1957 return 1; /* the old userdata */
1958 while (vlink(t) != null)
1959 t = vlink(t);
1960 lua_nodelib_push_fast(L, t);
1961 return 1;
1964 /* node.direct.tail */
1966 static int lua_nodelib_direct_tail(lua_State * L)
1968 halfword n;
1969 n = (halfword) lua_tonumber(L, 1);
1970 if (n == null) {
1971 lua_pushnil(L);
1972 } else {
1973 while (vlink(n) != null)
1974 n = vlink(n);
1975 lua_pushnumber(L, n);
1977 return 1;
1980 /* node.end_of_math (skip over math and return last) */
1982 static int lua_nodelib_end_of_math(lua_State * L)
1984 halfword *n;
1985 halfword t;
1986 if (lua_isnil(L, 1))
1987 return 1; /* the nil itself */
1988 n = check_isnode(L, 1);
1989 t = *n;
1990 if (t == null)
1991 return 1; /* the old userdata */
1992 while (vlink(t) != null) {
1993 t = vlink(t); /* skip first node */
1994 if (t && type(t)==math_node) {
1995 lua_nodelib_push_fast(L, t);
1996 return 1;
1999 return 0;
2002 /* node.direct.end_of_math */
2004 static int lua_nodelib_direct_end_of_math(lua_State * L)
2006 halfword n;
2007 n = (halfword) lua_tonumber(L, 1);
2008 if (n != null) {
2009 while (vlink(n) != null) {
2010 n = vlink(n); /* skip first node */
2011 if (n && type(n)==math_node) {
2012 lua_pushnumber(L, n);
2013 return 1;
2017 lua_pushnil(L);
2018 return 0;
2021 /* node.has_attribute (gets attribute) */
2023 static int lua_nodelib_has_attribute(lua_State * L)
2025 halfword *n;
2026 int i, val;
2027 n = check_isnode(L, 1);
2028 if (n != NULL) {
2029 i = (int) lua_tointeger(L, 2);
2030 val = (int) luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2031 if ((val = has_attribute(*n, i, val)) > UNUSED_ATTRIBUTE) {
2032 lua_pushnumber(L, val);
2033 return 1;
2036 lua_pushnil(L);
2037 return 1;
2040 /* node.direct.has_attribute */
2042 static int lua_nodelib_direct_has_attribute(lua_State * L)
2044 halfword n;
2045 int i, val;
2046 n = (halfword) lua_tonumber(L, 1);
2047 if (n != null) {
2048 i = (int) lua_tointeger(L, 2);
2049 val = (int) luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2050 if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
2051 lua_pushnumber(L, val);
2052 return 1;
2055 lua_pushnil(L);
2056 return 1;
2059 /* node.set_attribute */
2061 static int lua_nodelib_set_attribute(lua_State * L)
2063 halfword *n;
2064 int i, val;
2065 if (lua_gettop(L) == 3) {
2066 i = (int) lua_tointeger(L, 2);
2067 val = (int) lua_tointeger(L, 3);
2068 n = check_isnode(L, 1);
2069 if (val == UNUSED_ATTRIBUTE) {
2070 (void) unset_attribute(*n, i, val);
2071 } else {
2072 set_attribute(*n, i, val);
2074 } else {
2075 luaL_error(L, "incorrect number of arguments");
2077 return 0;
2080 /* node.direct.set_attribute */
2082 static int lua_nodelib_direct_set_attribute(lua_State * L)
2084 halfword n;
2085 int i, val;
2086 n = (halfword) lua_tonumber(L, 1);
2087 if (n == null)
2088 return 0;
2089 if (lua_gettop(L) == 3) {
2090 i = (int) lua_tointeger(L, 2);
2091 val = (int) lua_tointeger(L, 3);
2092 if (val == UNUSED_ATTRIBUTE) {
2093 (void) unset_attribute(n, i, val);
2094 } else {
2095 set_attribute(n, i, val);
2097 } else {
2098 luaL_error(L, "incorrect number of arguments");
2100 return 0;
2103 /* node.unset_attribute */
2105 static int lua_nodelib_unset_attribute(lua_State * L)
2107 halfword *n;
2108 int i, val, ret;
2109 if (lua_gettop(L) <= 3) {
2110 i=(int)luaL_checknumber(L, 2);
2111 val=(int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2112 n = check_isnode(L, 1);
2113 ret = unset_attribute(*n, i, val);
2114 if (ret > UNUSED_ATTRIBUTE) {
2115 lua_pushnumber(L, ret);
2116 } else {
2117 lua_pushnil(L);
2119 return 1;
2120 } else {
2121 return luaL_error(L, "incorrect number of arguments");
2125 /* node.direct.unset_attribute */
2127 static int lua_nodelib_direct_unset_attribute(lua_State * L)
2129 halfword n;
2130 int i, val, ret;
2131 n = (halfword) lua_tonumber(L, 1);
2132 if (n == null) {
2133 lua_pushnil(L);
2134 } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
2135 i=(int)luaL_checknumber(L, 2);
2136 val=(int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2137 ret = unset_attribute(n, i, val);
2138 if (ret > UNUSED_ATTRIBUTE) {
2139 lua_pushnumber(L, ret);
2140 } else {
2141 lua_pushnil(L);
2143 } else { /* can go */
2144 return luaL_error(L, "incorrect number of arguments");
2146 return 1;
2149 /* iteration */
2151 static int nodelib_aux_nil(lua_State * L)
2153 lua_pushnil(L);
2154 return 1;
2157 /* node.traverse_id */
2159 static int nodelib_aux_next_filtered(lua_State * L)
2161 halfword t; /* traverser */
2162 halfword *a;
2163 int i = (int) lua_tointeger(L, lua_upvalueindex(1));
2164 if (lua_isnil(L, 2)) { /* first call */
2165 t = *check_isnode(L, 1);
2166 lua_settop(L,1);
2167 } else {
2168 t = *check_isnode(L, 2);
2169 t = vlink(t);
2170 lua_settop(L,2);
2172 while (t != null && type(t) != i) {
2173 t = vlink(t);
2175 if (t == null) {
2176 lua_pushnil(L);
2177 } else {
2178 fast_metatable_top(t);
2180 return 1;
2183 static int lua_nodelib_traverse_filtered(lua_State * L)
2185 halfword n;
2186 if (lua_isnil(L, 2)) {
2187 lua_pushcclosure(L, nodelib_aux_nil, 0);
2188 return 1;
2190 n = *(check_isnode(L, 2));
2191 lua_pop(L, 1); /* the node, integer remains */
2192 lua_pushcclosure(L, nodelib_aux_next_filtered, 1);
2193 lua_nodelib_push_fast(L, n);
2194 lua_pushnil(L);
2195 return 3;
2198 /* node.direct.traverse_id */
2200 static int nodelib_direct_aux_next_filtered(lua_State * L)
2202 halfword t; /* traverser */
2203 int i = (int) lua_tointeger(L, lua_upvalueindex(1));
2204 if (lua_isnil(L, 2)) { /* first call */
2205 t = lua_tonumber(L,1) ;
2206 lua_settop(L,1);
2207 } else {
2208 t = lua_tonumber(L,2) ;
2209 t = vlink(t);
2210 lua_settop(L,2);
2212 while (t != null && type(t) != i) {
2213 t = vlink(t);
2215 if (t == null) {
2216 lua_pushnil(L);
2217 } else {
2218 lua_pushnumber(L,t);
2220 return 1;
2223 static int lua_nodelib_direct_traverse_filtered(lua_State * L)
2225 halfword n;
2226 if (lua_isnil(L, 2)) {
2227 lua_pushcclosure(L, nodelib_aux_nil, 0);
2228 return 1;
2230 n = (halfword) lua_tonumber(L, 2);
2231 if (n == null)
2232 return 0;
2233 n = (halfword) lua_tonumber(L, 2);
2234 lua_pop(L, 1);
2235 lua_pushcclosure(L, nodelib_direct_aux_next_filtered, 1);
2236 lua_pushnumber(L,n);
2237 lua_pushnil(L);
2238 return 3;
2241 /* node.traverse */
2243 static int nodelib_aux_next(lua_State * L)
2245 halfword t; /* traverser */
2246 halfword *a; /* a or *a */
2247 if (lua_isnil(L, 2)) { /* first call */
2248 t = *check_isnode(L, 1);
2249 lua_settop(L,1);
2250 } else {
2251 t = *check_isnode(L, 2);
2252 t = vlink(t);
2253 lua_settop(L,2);
2255 if (t == null) {
2256 lua_pushnil(L);
2257 } else {
2258 fast_metatable_top(t);
2260 return 1;
2263 static int lua_nodelib_traverse(lua_State * L)
2265 halfword n;
2266 if (lua_isnil(L, 1)) {
2267 lua_pushcclosure(L, nodelib_aux_nil, 0);
2268 return 1;
2270 n = *(check_isnode(L, 1));
2271 lua_pushcclosure(L, nodelib_aux_next, 0);
2272 lua_nodelib_push_fast(L, n);
2273 lua_pushnil(L);
2274 return 3;
2277 /* node.direct.traverse */
2279 static int nodelib_direct_aux_next(lua_State * L)
2281 halfword t; /* traverser */
2282 /*int i = (int) lua_tointeger(L, lua_upvalueindex(1));*/
2283 if (lua_isnil(L, 2)) { /* first call */
2284 t = lua_tonumber(L,1) ;
2285 lua_settop(L,1);
2286 } else {
2287 t = lua_tonumber(L,2) ;
2288 t = vlink(t);
2289 lua_settop(L,2);
2291 if (t == null) {
2292 lua_pushnil(L);
2293 } else {
2294 lua_pushnumber(L,t);
2296 return 1;
2299 static int lua_nodelib_direct_traverse(lua_State * L)
2301 halfword n;
2302 if (lua_isnil(L, 1)) {
2303 lua_pushcclosure(L, nodelib_aux_nil, 0);
2304 return 1;
2306 n = (halfword) lua_tonumber(L, 1);
2307 if (n == null) {
2308 lua_pushcclosure(L, nodelib_aux_nil, 0);
2309 return 1;
2311 lua_pushcclosure(L, nodelib_direct_aux_next, 0);
2312 lua_pushnumber(L,n);
2313 lua_pushnil(L);
2314 return 3;
2318 /* counting */
2320 static int do_lua_nodelib_count(lua_State * L, halfword match, int i, halfword first1)
2322 int count = 0;
2323 int t = first1;
2324 while (t != match) {
2325 if (i < 0 || type(t) == i)
2326 count++;
2327 t = vlink(t);
2329 lua_pushnumber(L, count);
2330 return 1;
2333 /* node.length */
2335 static int lua_nodelib_length(lua_State * L)
2337 halfword n;
2338 halfword m = null;
2339 if (lua_isnil(L, 1)) {
2340 lua_pushnumber(L, 0);
2341 return 1;
2343 n = *(check_isnode(L, 1));
2344 if (lua_gettop(L) == 2)
2345 m = *(check_isnode(L, 2));
2346 return do_lua_nodelib_count(L, m, -1, n);
2349 /* node.direct.length */
2351 static int lua_nodelib_direct_length(lua_State * L)
2353 halfword n, m;
2354 n = (halfword) lua_tonumber(L, 1);
2355 if (n == 0) {
2356 lua_pushnumber(L, 0);
2357 return 1;
2359 m = (halfword) lua_tonumber(L, 2);
2360 return do_lua_nodelib_count(L, m, -1, n);
2363 /* node.count */
2365 static int lua_nodelib_count(lua_State * L)
2367 halfword n;
2368 halfword m = null;
2369 int i = -1;
2370 i = (int) lua_tointeger(L, 1);
2371 if (lua_isnil(L, 2)) {
2372 lua_pushnumber(L, 0);
2373 return 1;
2375 n = *(check_isnode(L, 2));
2376 if (lua_gettop(L) == 3)
2377 m = *(check_isnode(L, 3));
2378 return do_lua_nodelib_count(L, m, i, n);
2381 /* node.direct.count */
2383 static int lua_nodelib_direct_count(lua_State * L)
2385 return do_lua_nodelib_count(L,
2386 (halfword) lua_tonumber(L, 3), /* m */
2387 (int) lua_tointeger(L, 1), /* i */
2388 (halfword) lua_tonumber(L, 2) /* n */
2392 /* directions (could be a macro) */
2394 // static void nodelib_pushdir(lua_State * L, int n, boolean dirnode)
2395 // {
2396 // if (dirnode) {
2397 // lua_pushstring(L, dir_strings[n+64]);
2398 // } else {
2399 // lua_pushstring(L, dir_strings[n+64]+1);
2400 // }
2401 // }
2403 /* getting and setting fields (helpers) */
2405 static int nodelib_getlist(lua_State * L, int n)
2407 halfword *m;
2408 if (lua_isuserdata(L, n)) {
2409 m = check_isnode(L, n);
2410 return *m;
2411 } else {
2412 return null;
2416 int nodelib_getdir(lua_State * L, int n, int absolute_only)
2418 if (lua_type(L, n) == LUA_TSTRING) {
2419 const char *s = lua_tostring(L, n);
2420 RETURN_DIR_VALUES(TLT);
2421 RETURN_DIR_VALUES(TRT);
2422 RETURN_DIR_VALUES(LTL);
2423 RETURN_DIR_VALUES(RTT);
2424 luaL_error(L, "Bad direction specifier %s", s);
2425 } else {
2426 luaL_error(L, "Direction specifiers have to be strings");
2428 return 0;
2431 static str_number nodelib_getstring(lua_State * L, int a)
2433 size_t k;
2434 const char *s = lua_tolstring(L, a, &k);
2435 return maketexlstring(s, k);
2438 static void nodelib_setattr(lua_State * L, int stackindex, halfword n)
2440 halfword p;
2441 p = nodelib_getlist(L, stackindex);
2442 if (node_attr(n) != p) {
2443 if (node_attr(n) != null)
2444 delete_attribute_ref(node_attr(n));
2445 node_attr(n) = p;
2446 if (p != null)
2447 attr_list_ref(p)++;
2451 static int nodelib_cantset(lua_State * L, int n, const char *s)
2453 luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name);
2454 return 0;
2457 /* node.direct.getfield */
2459 static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s)
2461 int t ;
2462 t = subtype(n);
2464 if (t == dir_node) {
2465 if (lua_key_eq(s, dir)) {
2466 // nodelib_pushdir(L, dir_dir(n), true);
2467 lua_push_dir_text(L, dir_dir(n));
2468 } else if (lua_key_eq(s, level)) {
2469 lua_pushnumber(L, dir_level(n));
2470 } else if (lua_key_eq(s, dvi_ptr)) {
2471 lua_pushnumber(L, dir_dvi_ptr(n));
2472 } else if (lua_key_eq(s, dir_h)) {
2473 lua_pushnumber(L, dir_dvi_h(n));
2474 } else {
2475 lua_pushnil(L);
2477 } else if (t == user_defined_node) {
2478 if (lua_key_eq(s, user_id)) {
2479 lua_pushnumber(L, user_node_id(n));
2480 } else if (lua_key_eq(s, type)) {
2481 lua_pushnumber(L, user_node_type(n));
2482 } else if (lua_key_eq(s, value)) {
2483 switch (user_node_type(n)) {
2484 case 'a':
2485 nodelib_pushlist(L, user_node_value(n));
2486 break;
2487 case 'd':
2488 lua_pushnumber(L, user_node_value(n));
2489 break;
2490 case 'l':
2491 if (user_node_value(n) != 0) {
2492 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
2493 } else {
2494 lua_pushnil(L);
2496 break;
2497 case 'n':
2498 nodelib_pushlist(L, user_node_value(n));
2499 break;
2500 case 's':
2501 nodelib_pushstring(L, user_node_value(n));
2502 break;
2503 case 't':
2504 tokenlist_to_lua(L, user_node_value(n));
2505 break;
2506 default:
2507 lua_pushnumber(L, user_node_value(n));
2508 break;
2510 } else {
2511 lua_pushnil(L);
2513 } else if (t == local_par_node) {
2514 if (lua_key_eq(s, pen_inter)) {
2515 lua_pushnumber(L, local_pen_inter(n));
2516 } else if (lua_key_eq(s, pen_broken)) {
2517 lua_pushnumber(L, local_pen_broken(n));
2518 } else if (lua_key_eq(s, dir)) {
2519 // nodelib_pushdir(L, local_par_dir(n), false);
2520 lua_push_dir_par(L, local_par_dir(n));
2521 } else if (lua_key_eq(s, box_left)) {
2522 /* can be: fast_metatable_or_nil(local_box_left(n)) */
2523 nodelib_pushlist(L, local_box_left(n));
2524 } else if (lua_key_eq(s, box_left_width)) {
2525 lua_pushnumber(L, local_box_left_width(n));
2526 } else if (lua_key_eq(s, box_right)) {
2527 /* can be: fast_metatable_or_nil(local_box_right(n)) */
2528 nodelib_pushlist(L, local_box_right(n));
2529 } else if (lua_key_eq(s, box_right_width)) {
2530 lua_pushnumber(L, local_box_right_width(n));
2531 } else {
2532 lua_pushnil(L);
2534 } else if (t == pdf_literal_node) {
2535 if (lua_key_eq(s, mode)) {
2536 lua_pushnumber(L, pdf_literal_mode(n));
2537 } else if (lua_key_eq(s, data)) {
2538 if (pdf_literal_type(n) == lua_refid_literal) {
2539 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
2540 } else {
2541 tokenlist_to_luastring(L, pdf_literal_data(n));
2543 } else {
2544 lua_pushnil(L);
2546 } else if (t == late_lua_node) {
2547 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
2548 if (late_lua_type(n) == lua_refid_literal) {
2549 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
2550 } else {
2551 tokenlist_to_luastring(L, late_lua_data(n));
2553 } else if (lua_key_eq(s, name)) {
2554 tokenlist_to_luastring(L, late_lua_name(n));
2555 } else {
2556 lua_pushnil(L);
2558 } else if (t == pdf_annot_node) {
2559 if (lua_key_eq(s, width)) {
2560 lua_pushnumber(L, width(n));
2561 } else if (lua_key_eq(s, depth)) {
2562 lua_pushnumber(L, depth(n));
2563 } else if (lua_key_eq(s, height)) {
2564 lua_pushnumber(L, height(n));
2565 } else if (lua_key_eq(s, objnum)) {
2566 lua_pushnumber(L, pdf_annot_objnum(n));
2567 } else if (lua_key_eq(s, data)) {
2568 tokenlist_to_luastring(L, pdf_annot_data(n));
2569 } else {
2570 lua_pushnil(L);
2572 } else if (t == pdf_dest_node) {
2573 if (lua_key_eq(s, width)) {
2574 lua_pushnumber(L, width(n));
2575 } else if (lua_key_eq(s, depth)) {
2576 lua_pushnumber(L, depth(n));
2577 } else if (lua_key_eq(s, height)) {
2578 lua_pushnumber(L, height(n));
2579 } else if (lua_key_eq(s, named_id)) {
2580 lua_pushnumber(L, pdf_dest_named_id(n));
2581 } else if (lua_key_eq(s, dest_id)) {
2582 if (pdf_dest_named_id(n) == 1)
2583 tokenlist_to_luastring(L, pdf_dest_id(n));
2584 else
2585 lua_pushnumber(L, pdf_dest_id(n));
2586 } else if (lua_key_eq(s, dest_type)) {
2587 lua_pushnumber(L, pdf_dest_type(n));
2588 } else if (lua_key_eq(s, xyz_zoom)) {
2589 lua_pushnumber(L, pdf_dest_xyz_zoom(n));
2590 } else if (lua_key_eq(s, objnum)) {
2591 lua_pushnumber(L, pdf_dest_objnum(n));
2592 } else {
2593 lua_pushnil(L);
2595 } else if (t == pdf_setmatrix_node) {
2596 if (lua_key_eq(s, data)) {
2597 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
2598 } else {
2599 lua_pushnil(L);
2601 } else if (t == pdf_colorstack_node) {
2602 if (lua_key_eq(s, stack)) {
2603 lua_pushnumber(L, pdf_colorstack_stack(n));
2604 } else if (lua_key_eq(s, command)) {
2605 lua_pushnumber(L, pdf_colorstack_cmd(n));
2606 } else if (lua_key_eq(s, data)) {
2607 tokenlist_to_luastring(L, pdf_colorstack_data(n));
2608 } else {
2609 lua_pushnil(L);
2611 } else if (t == pdf_refobj_node) {
2612 if (lua_key_eq(s, objnum)) {
2613 lua_pushnumber(L, pdf_obj_objnum(n));
2614 } else {
2615 lua_pushnil(L);
2617 } else if (t == pdf_refxform_node) {
2618 if (lua_key_eq(s, width)) {
2619 lua_pushnumber(L, width(n));
2620 } else if (lua_key_eq(s, depth)) {
2621 lua_pushnumber(L, depth(n));
2622 } else if (lua_key_eq(s, height)) {
2623 lua_pushnumber(L, height(n));
2624 } else if (lua_key_eq(s, objnum)) {
2625 lua_pushnumber(L, pdf_xform_objnum(n));
2626 } else {
2627 lua_pushnil(L);
2629 } else if (t == pdf_refximage_node) {
2630 if (lua_key_eq(s, width)) {
2631 lua_pushnumber(L, width(n));
2632 } else if (lua_key_eq(s, depth)) {
2633 lua_pushnumber(L, depth(n));
2634 } else if (lua_key_eq(s, height)) {
2635 lua_pushnumber(L, height(n));
2636 } else if (lua_key_eq(s, transform)) {
2637 lua_pushnumber(L, pdf_ximage_transform(n));
2638 } else if (lua_key_eq(s, index)) {
2639 lua_pushnumber(L, pdf_ximage_index(n));
2640 } else {
2641 lua_pushnil(L);
2643 } else if (t == write_node) {
2644 if (lua_key_eq(s, stream)) {
2645 lua_pushnumber(L, write_stream(n));
2646 } else if (lua_key_eq(s, data)) {
2647 tokenlist_to_lua(L, write_tokens(n));
2648 } else {
2649 lua_pushnil(L);
2651 } else if (t == special_node) {
2652 if (lua_key_eq(s, data)) {
2653 tokenlist_to_luastring(L, write_tokens(n));
2654 } else {
2655 lua_pushnil(L);
2657 } else if (t == pdf_start_link_node) {
2658 if (lua_key_eq(s, width)) {
2659 lua_pushnumber(L, width(n));
2660 } else if (lua_key_eq(s, depth)) {
2661 lua_pushnumber(L, depth(n));
2662 } else if (lua_key_eq(s, height)) {
2663 lua_pushnumber(L, height(n));
2664 } else if (lua_key_eq(s, objnum)) {
2665 lua_pushnumber(L, pdf_link_objnum(n));
2666 } else if (lua_key_eq(s, link_attr)) {
2667 tokenlist_to_luastring(L, pdf_link_attr(n));
2668 } else if (lua_key_eq(s, action)) {
2669 nodelib_pushaction(L, pdf_link_action(n));
2670 } else {
2671 lua_pushnil(L);
2673 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
2674 if (lua_key_eq(s, width)) {
2675 lua_pushnumber(L, width(n));
2676 } else if (lua_key_eq(s, depth)) {
2677 lua_pushnumber(L, depth(n));
2678 } else if (lua_key_eq(s, height)) {
2679 lua_pushnumber(L, height(n));
2680 } else if (lua_key_eq(s, named_id)) {
2681 lua_pushnumber(L, pdf_thread_named_id(n));
2682 } else if (lua_key_eq(s, thread_id)) {
2683 if (pdf_thread_named_id(n) == 1) {
2684 tokenlist_to_luastring(L, pdf_thread_id(n));
2685 } else {
2686 lua_pushnumber(L, pdf_thread_id(n));
2688 } else if (lua_key_eq(s, thread_attr)) {
2689 tokenlist_to_luastring(L, pdf_thread_attr(n));
2690 } else {
2691 lua_pushnil(L);
2693 } else if (t == open_node) {
2694 if (lua_key_eq(s, stream)) {
2695 lua_pushnumber(L, write_stream(n));
2696 } else if (lua_key_eq(s, name)) {
2697 nodelib_pushstring(L, open_name(n));
2698 } else if (lua_key_eq(s, area)) {
2699 nodelib_pushstring(L, open_area(n));
2700 } else if (lua_key_eq(s, ext)) {
2701 nodelib_pushstring(L, open_ext(n));
2702 } else {
2703 lua_pushnil(L);
2705 } else if (t == close_node) {
2706 if (lua_key_eq(s, stream)) {
2707 lua_pushnumber(L, write_stream(n));
2708 } else {
2709 lua_pushnil(L);
2711 } else {
2712 lua_pushnil(L);
2716 static int lua_nodelib_fast_getfield(lua_State * L)
2719 the order is somewhat determined by the occurance of nodes and
2720 importance of fields
2723 halfword n;
2724 halfword *a;
2725 const char *s;
2726 int t ;
2728 n = *((halfword *) lua_touserdata(L, 1));
2729 t = type(n);
2733 somenode[9] as interface to attributes ... 30% faster than has_attribute
2734 (1) because there is no lua function overhead, and (2) because we already
2735 know that we deal with a node so no checking is needed. The fast typecheck
2736 is needed (lua_check... is a slow down actually).
2740 if (lua_type(L, 2) == LUA_TNUMBER) {
2742 halfword p;
2743 int i;
2745 if (! nodetype_has_attributes(t)) {
2746 lua_pushnil(L);
2747 return 1;
2750 p = node_attr(n);
2751 if (p == null || vlink(p) == null) {
2752 lua_pushnil(L);
2753 return 1;
2755 i = (int) lua_tointeger(L, 2);
2756 p = vlink(p);
2757 while (p != null) {
2758 if (attribute_id(p) == i) {
2759 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
2760 lua_pushnumber(L, (int) attribute_value(p));
2761 } else {
2762 lua_pushnil(L);
2764 return 1;
2765 } else if (attribute_id(p) > i) {
2766 lua_pushnil(L);
2767 return 1;
2769 p = vlink(p);
2771 lua_pushnil(L);
2772 return 1;
2775 s = lua_tostring(L, 2);
2777 if (lua_key_eq(s, id)) {
2778 lua_pushnumber(L, t);
2779 } else if (lua_key_eq(s, next)) {
2780 fast_metatable_or_nil(vlink(n));
2781 } else if (lua_key_eq(s, prev)) {
2782 fast_metatable_or_nil(alink(n));
2783 } else if (lua_key_eq(s, attr)) {
2784 if (! nodetype_has_attributes(t)) {
2785 lua_pushnil(L);
2786 } else {
2787 nodelib_pushattr(L, node_attr(n));
2789 } else if (t == glyph_node) {
2790 /* candidates: fontchar (font,char) whd (width,height,depth) */
2791 if (lua_key_eq(s, subtype)) {
2792 lua_pushnumber(L, subtype(n));
2793 } else if (lua_key_eq(s, font)) {
2794 lua_pushnumber(L, font(n));
2795 } else if (lua_key_eq(s, char)) {
2796 lua_pushnumber(L, character(n));
2797 } else if (lua_key_eq(s, xoffset)) {
2798 lua_pushnumber(L, x_displace(n));
2799 } else if (lua_key_eq(s, yoffset)) {
2800 lua_pushnumber(L, y_displace(n));
2801 } else if (lua_key_eq(s, width)) {
2802 lua_pushnumber(L, char_width(font(n),character(n)));
2803 } else if (lua_key_eq(s, height)) {
2804 lua_pushnumber(L, char_height(font(n),character(n)));
2805 } else if (lua_key_eq(s, depth)) {
2806 lua_pushnumber(L, char_depth(font(n),character(n)));
2807 } else if (lua_key_eq(s, expansion_factor)) {
2808 lua_pushnumber(L, ex_glyph(n));
2809 } else if (lua_key_eq(s, components)) {
2810 fast_metatable_or_nil(lig_ptr(n));
2811 } else if (lua_key_eq(s, lang)) {
2812 lua_pushnumber(L, char_lang(n));
2813 } else if (lua_key_eq(s, left)) {
2814 lua_pushnumber(L, char_lhmin(n));
2815 } else if (lua_key_eq(s, right)) {
2816 lua_pushnumber(L, char_rhmin(n));
2817 } else if (lua_key_eq(s, uchyph)) {
2818 lua_pushnumber(L, char_uchyph(n));
2819 } else {
2820 lua_pushnil(L);
2822 } else if ((t == hlist_node) || (t == vlist_node)) {
2823 /* candidates: whd (width,height,depth) */
2824 if (lua_key_eq(s, subtype)) {
2825 lua_pushnumber(L, subtype(n));
2826 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
2827 fast_metatable_or_nil_alink(list_ptr(n));
2828 } else if (lua_key_eq(s, width)) {
2829 lua_pushnumber(L, width(n));
2830 } else if (lua_key_eq(s, height)) {
2831 lua_pushnumber(L, height(n));
2832 } else if (lua_key_eq(s, depth)) {
2833 lua_pushnumber(L, depth(n));
2834 } else if (lua_key_eq(s, dir)) {
2835 // nodelib_pushdir(L, box_dir(n), false);
2836 lua_push_dir_par(L, box_dir(n));
2837 } else if (lua_key_eq(s, shift)) {
2838 lua_pushnumber(L, shift_amount(n));
2839 } else if (lua_key_eq(s, glue_order)) {
2840 lua_pushnumber(L, glue_order(n));
2841 } else if (lua_key_eq(s, glue_sign)) {
2842 lua_pushnumber(L, glue_sign(n));
2843 } else if (lua_key_eq(s, glue_set)) {
2844 lua_pushnumber(L, (double) glue_set(n));
2845 } else {
2846 lua_pushnil(L);
2848 } else if (t == disc_node) {
2849 if (lua_key_eq(s, subtype)) {
2850 lua_pushnumber(L, subtype(n));
2851 } else if (lua_key_eq(s, pre)) {
2852 fast_metatable_or_nil(vlink(pre_break(n)));
2853 } else if (lua_key_eq(s, post)) {
2854 fast_metatable_or_nil(vlink(post_break(n)));
2855 } else if (lua_key_eq(s, replace)) {
2856 fast_metatable_or_nil(vlink(no_break(n)));
2857 } else {
2858 lua_pushnil(L);
2860 } else if (t == glue_node) {
2861 if (lua_key_eq(s, subtype)) {
2862 lua_pushnumber(L, subtype(n));
2863 } else if (lua_key_eq(s, spec)) {
2864 nodelib_pushspec(L, glue_ptr(n));
2865 } else if (lua_key_eq(s, leader)) {
2866 fast_metatable_or_nil(leader_ptr(n));
2867 } else {
2868 lua_pushnil(L);
2870 } else if (t == glue_spec_node) {
2871 if (lua_key_eq(s, subtype)) {
2872 lua_pushnumber(L, 0); /* dummy, the only one that prevents move up */
2873 } else if (lua_key_eq(s, width)) {
2874 lua_pushnumber(L, width(n));
2875 } else if (lua_key_eq(s, stretch)) {
2876 lua_pushnumber(L, stretch(n));
2877 } else if (lua_key_eq(s, shrink)) {
2878 lua_pushnumber(L, shrink(n));
2879 } else if (lua_key_eq(s, stretch_order)) {
2880 lua_pushnumber(L, stretch_order(n));
2881 } else if (lua_key_eq(s, shrink_order)) {
2882 lua_pushnumber(L, shrink_order(n));
2883 } else if (lua_key_eq(s, ref_count)) {
2884 lua_pushnumber(L, glue_ref_count(n));
2885 } else if (lua_key_eq(s, writable)) {
2886 lua_pushboolean(L, valid_node(n));
2887 } else {
2888 lua_pushnil(L);
2890 } else if (t == kern_node) {
2891 if (lua_key_eq(s, subtype)) {
2892 lua_pushnumber(L, subtype(n));
2893 } else if (lua_key_eq(s, kern)) {
2894 lua_pushnumber(L, width(n));
2895 } else if (lua_key_eq(s, expansion_factor)) {
2896 lua_pushnumber(L, ex_kern(n));
2897 } else {
2898 lua_pushnil(L);
2900 } else if (t == penalty_node) {
2901 if (lua_key_eq(s, subtype)) {
2902 lua_pushnumber(L, subtype(n));
2903 } else if (lua_key_eq(s, penalty)) {
2904 lua_pushnumber(L, penalty(n));
2905 } else {
2906 lua_pushnil(L);
2908 } else if (t == rule_node) {
2909 /* candidates: whd (width,height,depth) */
2910 if (lua_key_eq(s, subtype)) {
2911 lua_pushnumber(L, subtype(n));
2912 } else if (lua_key_eq(s, width)) {
2913 lua_pushnumber(L, width(n));
2914 } else if (lua_key_eq(s, height)) {
2915 lua_pushnumber(L, height(n));
2916 } else if (lua_key_eq(s, depth)) {
2917 lua_pushnumber(L, depth(n));
2918 } else if (lua_key_eq(s, dir)) {
2919 // nodelib_pushdir(L, rule_dir(n), false);
2920 lua_push_dir_par(L, rule_dir(n));
2921 } else {
2922 lua_pushnil(L);
2924 } else if (t == whatsit_node) {
2925 if (lua_key_eq(s, subtype)) {
2926 lua_pushnumber(L, subtype(n));
2927 } else {
2928 lua_nodelib_getfield_whatsit(L, n, s);
2930 } else if (t == simple_noad) {
2931 if (lua_key_eq(s, subtype)) {
2932 lua_pushnumber(L, subtype(n));
2933 } else if (lua_key_eq(s, nucleus)) {
2934 fast_metatable_or_nil(nucleus(n));
2935 } else if (lua_key_eq(s, sub)) {
2936 fast_metatable_or_nil(subscr(n));
2937 } else if (lua_key_eq(s, sup)) {
2938 fast_metatable_or_nil(supscr(n));
2939 } else {
2940 lua_pushnil(L);
2942 } else if ((t == math_char_node) || (t == math_text_char_node)) {
2943 /* candidates: famchar (fam,char) */
2944 if (lua_key_eq(s, subtype)) {
2945 lua_pushnumber(L, subtype(n));
2946 } else if (lua_key_eq(s, fam)) {
2947 lua_pushnumber(L, math_fam(n));
2948 } else if (lua_key_eq(s, char)) {
2949 lua_pushnumber(L, math_character(n));
2950 } else {
2951 lua_pushnil(L);
2953 } else if (t == mark_node) {
2954 if (lua_key_eq(s, subtype)) {
2955 lua_pushnumber(L, subtype(n));
2956 } else if (lua_key_eq(s, class)) {
2957 lua_pushnumber(L, mark_class(n));
2958 } else if (lua_key_eq(s, mark)) {
2959 tokenlist_to_lua(L, mark_ptr(n));
2960 } else {
2961 lua_pushnil(L);
2963 } else if (t == ins_node) {
2964 if (lua_key_eq(s, subtype)) {
2965 lua_pushnumber(L, subtype(n));
2966 } else if (lua_key_eq(s, cost)) {
2967 lua_pushnumber(L, float_cost(n));
2968 } else if (lua_key_eq(s, depth)) {
2969 lua_pushnumber(L, depth(n));
2970 } else if (lua_key_eq(s, height)) {
2971 lua_pushnumber(L, height(n));
2972 } else if (lua_key_eq(s, spec)) {
2973 nodelib_pushspec(L, split_top_ptr(n));
2974 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
2975 fast_metatable_or_nil_alink(ins_ptr(n));
2976 } else {
2977 lua_pushnil(L);
2979 } else if (t == math_node) {
2980 if (lua_key_eq(s, subtype)) {
2981 lua_pushnumber(L, subtype(n));
2982 } else if (lua_key_eq(s, surround)) {
2983 lua_pushnumber(L, surround(n));
2984 } else {
2985 lua_pushnil(L);
2987 } else if (t == fraction_noad) {
2988 if (lua_key_eq(s, subtype)) {
2989 lua_pushnumber(L, subtype(n));
2990 } else if (lua_key_eq(s, width)) {
2991 lua_pushnumber(L, thickness(n));
2992 } else if (lua_key_eq(s, num)) {
2993 fast_metatable_or_nil(numerator(n));
2994 } else if (lua_key_eq(s, denom)) {
2995 fast_metatable_or_nil(denominator(n));
2996 } else if (lua_key_eq(s, left)) {
2997 fast_metatable_or_nil(left_delimiter(n));
2998 } else if (lua_key_eq(s, right)) {
2999 fast_metatable_or_nil(right_delimiter(n));
3000 } else {
3001 lua_pushnil(L);
3003 } else if (t == style_node) {
3004 if (lua_key_eq(s, subtype)) {
3005 lua_pushnumber(L, subtype(n));
3006 } else if (lua_key_eq(s, style)) {
3007 lua_push_math_style_name(L,subtype(n));
3008 } else {
3009 lua_pushnil(L);
3011 } else if (t == accent_noad) {
3012 if (lua_key_eq(s, subtype)) {
3013 lua_pushnumber(L, subtype(n));
3014 } else if (lua_key_eq(s, nucleus)) {
3015 fast_metatable_or_nil(nucleus(n));
3016 } else if (lua_key_eq(s, sub)) {
3017 fast_metatable_or_nil(subscr(n));
3018 } else if (lua_key_eq(s, sup)) {
3019 fast_metatable_or_nil(supscr(n));
3020 } else if (lua_key_eq(s, accent)) {
3021 fast_metatable_or_nil(accent_chr(n));
3022 } else if (lua_key_eq(s, bot_accent)) {
3023 fast_metatable_or_nil(bot_accent_chr(n));
3024 } else {
3025 lua_pushnil(L);
3027 } else if (t == fence_noad) {
3028 if (lua_key_eq(s, subtype)) {
3029 lua_pushnumber(L, subtype(n));
3030 } else if (lua_key_eq(s, delim)) {
3031 fast_metatable_or_nil(delimiter(n));
3032 } else {
3033 lua_pushnil(L);
3035 } else if (t == delim_node) {
3036 if (lua_key_eq(s, subtype)) {
3037 lua_pushnumber(L, subtype(n));
3038 } else if (lua_key_eq(s, small_fam)) {
3039 lua_pushnumber(L, small_fam(n));
3040 } else if (lua_key_eq(s, small_char)) {
3041 lua_pushnumber(L, small_char(n));
3042 } else if (lua_key_eq(s, large_fam)) {
3043 lua_pushnumber(L, large_fam(n));
3044 } else if (lua_key_eq(s, large_char)) {
3045 lua_pushnumber(L, large_char(n));
3046 } else {
3047 lua_pushnil(L);
3049 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
3050 if (lua_key_eq(s, subtype)) {
3051 lua_pushnumber(L, subtype(n));
3052 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3053 fast_metatable_or_nil_alink(math_list(n));
3054 } else {
3055 lua_pushnil(L);
3057 } else if (t == radical_noad) {
3058 if (lua_key_eq(s, subtype)) {
3059 lua_pushnumber(L, subtype(n));
3060 } else if (lua_key_eq(s, nucleus)) {
3061 fast_metatable_or_nil(nucleus(n));
3062 } else if (lua_key_eq(s, sub)) {
3063 fast_metatable_or_nil(subscr(n));
3064 } else if (lua_key_eq(s, sup)) {
3065 fast_metatable_or_nil(supscr(n));
3066 } else if (lua_key_eq(s, left)) {
3067 fast_metatable_or_nil(left_delimiter(n));
3068 } else if (lua_key_eq(s, degree)) {
3069 fast_metatable_or_nil(degree(n));
3070 } else {
3071 lua_pushnil(L);
3073 } else if (t == margin_kern_node) {
3074 if (lua_key_eq(s, subtype)) {
3075 lua_pushnumber(L, subtype(n));
3076 } else if (lua_key_eq(s, width)) {
3077 lua_pushnumber(L, width(n));
3078 } else if (lua_key_eq(s, glyph)) {
3079 fast_metatable_or_nil(margin_char(n));
3080 } else {
3081 lua_pushnil(L);
3083 } else if (t == split_up_node) {
3084 if (lua_key_eq(s, subtype)) {
3085 lua_pushnumber(L, subtype(n));
3086 } else if (lua_key_eq(s, last_ins_ptr)) {
3087 fast_metatable_or_nil(last_ins_ptr(n));
3088 } else if (lua_key_eq(s, best_ins_ptr)) {
3089 fast_metatable_or_nil(best_ins_ptr(n));
3090 } else if (lua_key_eq(s, broken_ptr)) {
3091 fast_metatable_or_nil(broken_ptr(n));
3092 } else if (lua_key_eq(s, broken_ins)) {
3093 fast_metatable_or_nil(broken_ins(n));
3094 } else {
3095 lua_pushnil(L);
3097 } else if (t == choice_node) {
3098 if (lua_key_eq(s, subtype)) {
3099 lua_pushnumber(L, subtype(n));
3100 } else if (lua_key_eq(s, display)) {
3101 fast_metatable_or_nil(display_mlist(n));
3102 } else if (lua_key_eq(s, text)) {
3103 fast_metatable_or_nil(text_mlist(n));
3104 } else if (lua_key_eq(s, script)) {
3105 fast_metatable_or_nil(script_mlist(n));
3106 } else if (lua_key_eq(s, scriptscript)) {
3107 fast_metatable_or_nil(script_script_mlist(n));
3108 } else {
3109 lua_pushnil(L);
3111 } else if (t == inserting_node) {
3112 if (lua_key_eq(s, subtype)) {
3113 lua_pushnumber(L, subtype(n));
3114 } else if (lua_key_eq(s, last_ins_ptr)) {
3115 fast_metatable_or_nil(last_ins_ptr(n));
3116 } else if (lua_key_eq(s, best_ins_ptr)) {
3117 fast_metatable_or_nil(best_ins_ptr(n));
3118 } else {
3119 lua_pushnil(L);
3121 } else if (t == attribute_node) {
3122 if (lua_key_eq(s, subtype)) {
3123 lua_pushnumber(L, subtype(n));
3124 } else if (lua_key_eq(s, number)) {
3125 lua_pushnumber(L, attribute_id(n));
3126 } else if (lua_key_eq(s, value)) {
3127 lua_pushnumber(L, attribute_value(n));
3128 } else {
3129 lua_pushnil(L);
3131 } else if (t == adjust_node) {
3132 if (lua_key_eq(s, subtype)) {
3133 lua_pushnumber(L, subtype(n));
3134 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3135 fast_metatable_or_nil_alink(adjust_ptr(n));
3136 } else {
3137 lua_pushnil(L);
3139 } else if (t == action_node) {
3140 if (lua_key_eq(s, subtype)) {
3141 lua_pushnumber(L, subtype(n));/* dummy subtype */
3142 } else if (lua_key_eq(s, action_type)) {
3143 lua_pushnumber(L, pdf_action_type(n));
3144 } else if (lua_key_eq(s, named_id)) {
3145 lua_pushnumber(L, pdf_action_named_id(n));
3146 } else if (lua_key_eq(s, action_id)) {
3147 if (pdf_action_named_id(n) == 1) {
3148 tokenlist_to_luastring(L, pdf_action_id(n));
3149 } else {
3150 lua_pushnumber(L, pdf_action_id(n));
3152 } else if (lua_key_eq(s, file)) {
3153 tokenlist_to_luastring(L, pdf_action_file(n));
3154 } else if (lua_key_eq(s, new_window)) {
3155 lua_pushnumber(L, pdf_action_new_window(n));
3156 } else if (lua_key_eq(s, data)) {
3157 tokenlist_to_luastring(L, pdf_action_tokens(n));
3158 } else if (lua_key_eq(s, ref_count)) {
3159 lua_pushnumber(L, pdf_action_refcount(n));
3160 } else {
3161 lua_pushnil(L);
3163 } else if (t == unset_node) {
3164 if (lua_key_eq(s, subtype)) {
3165 lua_pushnumber(L, subtype(n));
3166 } else if (lua_key_eq(s, width)) {
3167 lua_pushnumber(L, width(n));
3168 } else if (lua_key_eq(s, height)) {
3169 lua_pushnumber(L, height(n));
3170 } else if (lua_key_eq(s, depth)) {
3171 lua_pushnumber(L, depth(n));
3172 } else if (lua_key_eq(s, dir)) {
3173 // nodelib_pushdir(L, box_dir(n), false);
3174 lua_push_dir_par(L, box_dir(n));
3175 } else if (lua_key_eq(s, shrink)) {
3176 lua_pushnumber(L, glue_shrink(n));
3177 } else if (lua_key_eq(s, glue_order)) {
3178 lua_pushnumber(L, glue_order(n));
3179 } else if (lua_key_eq(s, glue_sign)) {
3180 lua_pushnumber(L, glue_sign(n));
3181 } else if (lua_key_eq(s, stretch)) {
3182 lua_pushnumber(L, glue_stretch(n));
3183 } else if (lua_key_eq(s, count)) {
3184 lua_pushnumber(L, span_count(n));
3185 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3186 fast_metatable_or_nil_alink(list_ptr(n));
3187 } else {
3188 lua_pushnil(L);
3190 } else if (t == attribute_list_node) {
3191 if (lua_key_eq(s, subtype)) {
3192 lua_pushnumber(L, subtype(n));
3193 } else {
3194 lua_pushnil(L);
3196 } else {
3197 lua_pushnil(L);
3199 return 1;
3202 static int lua_nodelib_getfield(lua_State * L)
3204 /* [given-node] [...]*/
3205 halfword *p = lua_touserdata(L, 1);
3206 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
3207 lua_pushnil(L) ;
3208 return 1;
3210 /* [given-node] [mt-given-node]*/
3211 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
3212 lua_gettable(L, LUA_REGISTRYINDEX);
3213 /* [given-node] [mt-given-node] [mt-node]*/
3214 if (!lua_rawequal(L, -1, -2)) {
3215 lua_pushnil(L) ;
3216 return 1;
3218 /* prune stack and call getfield */
3219 lua_settop(L,2);
3220 return lua_nodelib_fast_getfield(L);
3223 /* node.direct.getfield */
3225 static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char *s)
3227 int t ;
3228 t = subtype(n);
3230 if (t == dir_node) {
3231 if (lua_key_eq(s, dir)) {
3232 // nodelib_pushdir(L, dir_dir(n), true);
3233 lua_push_dir_text(L, dir_dir(n));
3234 } else if (lua_key_eq(s, level)) {
3235 lua_pushnumber(L, dir_level(n));
3236 } else if (lua_key_eq(s, dvi_ptr)) {
3237 lua_pushnumber(L, dir_dvi_ptr(n));
3238 } else if (lua_key_eq(s, dir_h)) {
3239 lua_pushnumber(L, dir_dvi_h(n));
3240 } else {
3241 lua_pushnil(L);
3243 } else if (t == user_defined_node) {
3244 if (lua_key_eq(s, user_id)) {
3245 lua_pushnumber(L, user_node_id(n));
3246 } else if (lua_key_eq(s, type)) {
3247 lua_pushnumber(L, user_node_type(n));
3248 } else if (lua_key_eq(s, value)) {
3249 switch (user_node_type(n)) {
3250 case 'a':
3251 nodelib_pushdirect(user_node_value(n));
3252 break;
3253 case 'd':
3254 lua_pushnumber(L, user_node_value(n));
3255 break;
3256 case 'l':
3257 if (user_node_value(n) != 0) {
3258 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
3259 } else {
3260 lua_pushnil(L);
3262 break;
3263 case 'n':
3264 nodelib_pushdirect(user_node_value(n));
3265 break;
3266 case 's':
3267 nodelib_pushstring(L, user_node_value(n));
3268 break;
3269 case 't':
3270 tokenlist_to_lua(L, user_node_value(n));
3271 break;
3272 default:
3273 lua_pushnumber(L, user_node_value(n));
3274 break;
3276 } else {
3277 lua_pushnil(L);
3279 } else if (t == local_par_node) {
3280 if (lua_key_eq(s, pen_inter)) {
3281 lua_pushnumber(L, local_pen_inter(n));
3282 } else if (lua_key_eq(s, pen_broken)) {
3283 lua_pushnumber(L, local_pen_broken(n));
3284 } else if (lua_key_eq(s, dir)) {
3285 // nodelib_pushdir(L, local_par_dir(n), false);
3286 lua_push_dir_par(L, local_par_dir(n));
3287 } else if (lua_key_eq(s, box_left)) {
3288 nodelib_pushdirect_or_nil(local_box_left(n));
3289 } else if (lua_key_eq(s, box_left_width)) {
3290 lua_pushnumber(L, local_box_left_width(n));
3291 } else if (lua_key_eq(s, box_right)) {
3292 nodelib_pushdirect_or_nil(local_box_right(n));
3293 } else if (lua_key_eq(s, box_right_width)) {
3294 lua_pushnumber(L, local_box_right_width(n));
3295 } else {
3296 lua_pushnil(L);
3298 } else if (t == pdf_literal_node) {
3299 if (lua_key_eq(s, mode)) {
3300 lua_pushnumber(L, pdf_literal_mode(n));
3301 } else if (lua_key_eq(s, data)) {
3302 if (pdf_literal_type(n) == lua_refid_literal) {
3303 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
3304 } else {
3305 tokenlist_to_luastring(L, pdf_literal_data(n));
3307 } else {
3308 lua_pushnil(L);
3310 } else if (t == late_lua_node) {
3311 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
3312 if (late_lua_type(n) == lua_refid_literal) {
3313 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
3314 } else {
3315 tokenlist_to_luastring(L, late_lua_data(n));
3317 } else if (lua_key_eq(s, name)) {
3318 tokenlist_to_luastring(L, late_lua_name(n));
3319 } else {
3320 lua_pushnil(L);
3322 } else if (t == pdf_annot_node) {
3323 if (lua_key_eq(s, width)) {
3324 lua_pushnumber(L, width(n));
3325 } else if (lua_key_eq(s, depth)) {
3326 lua_pushnumber(L, depth(n));
3327 } else if (lua_key_eq(s, height)) {
3328 lua_pushnumber(L, height(n));
3329 } else if (lua_key_eq(s, objnum)) {
3330 lua_pushnumber(L, pdf_annot_objnum(n));
3331 } else if (lua_key_eq(s, data)) {
3332 tokenlist_to_luastring(L, pdf_annot_data(n));
3333 } else {
3334 lua_pushnil(L);
3336 } else if (t == pdf_dest_node) {
3337 if (lua_key_eq(s, width)) {
3338 lua_pushnumber(L, width(n));
3339 } else if (lua_key_eq(s, depth)) {
3340 lua_pushnumber(L, depth(n));
3341 } else if (lua_key_eq(s, height)) {
3342 lua_pushnumber(L, height(n));
3343 } else if (lua_key_eq(s, named_id)) {
3344 lua_pushnumber(L, pdf_dest_named_id(n));
3345 } else if (lua_key_eq(s, dest_id)) {
3346 if (pdf_dest_named_id(n) == 1)
3347 tokenlist_to_luastring(L, pdf_dest_id(n));
3348 else
3349 lua_pushnumber(L, pdf_dest_id(n));
3350 } else if (lua_key_eq(s, dest_type)) {
3351 lua_pushnumber(L, pdf_dest_type(n));
3352 } else if (lua_key_eq(s, xyz_zoom)) {
3353 lua_pushnumber(L, pdf_dest_xyz_zoom(n));
3354 } else if (lua_key_eq(s, objnum)) {
3355 lua_pushnumber(L, pdf_dest_objnum(n));
3356 } else {
3357 lua_pushnil(L);
3359 } else if (t == pdf_setmatrix_node) {
3360 if (lua_key_eq(s, data)) {
3361 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
3362 } else {
3363 lua_pushnil(L);
3365 } else if (t == pdf_colorstack_node) {
3366 if (lua_key_eq(s, stack)) {
3367 lua_pushnumber(L, pdf_colorstack_stack(n));
3368 } else if (lua_key_eq(s, command)) {
3369 lua_pushnumber(L, pdf_colorstack_cmd(n));
3370 } else if (lua_key_eq(s, data)) {
3371 tokenlist_to_luastring(L, pdf_colorstack_data(n));
3372 } else {
3373 lua_pushnil(L);
3375 } else if (t == pdf_refobj_node) {
3376 if (lua_key_eq(s, objnum)) {
3377 lua_pushnumber(L, pdf_obj_objnum(n));
3378 } else {
3379 lua_pushnil(L);
3381 } else if (t == pdf_refxform_node) {
3382 if (lua_key_eq(s, width)) {
3383 lua_pushnumber(L, width(n));
3384 } else if (lua_key_eq(s, depth)) {
3385 lua_pushnumber(L, depth(n));
3386 } else if (lua_key_eq(s, height)) {
3387 lua_pushnumber(L, height(n));
3388 } else if (lua_key_eq(s, objnum)) {
3389 lua_pushnumber(L, pdf_xform_objnum(n));
3390 } else {
3391 lua_pushnil(L);
3393 } else if (t == pdf_refximage_node) {
3394 if (lua_key_eq(s, width)) {
3395 lua_pushnumber(L, width(n));
3396 } else if (lua_key_eq(s, depth)) {
3397 lua_pushnumber(L, depth(n));
3398 } else if (lua_key_eq(s, height)) {
3399 lua_pushnumber(L, height(n));
3400 } else if (lua_key_eq(s, transform)) {
3401 lua_pushnumber(L, pdf_ximage_transform(n));
3402 } else if (lua_key_eq(s, index)) {
3403 lua_pushnumber(L, pdf_ximage_index(n));
3404 } else {
3405 lua_pushnil(L);
3407 } else if (t == write_node) {
3408 if (lua_key_eq(s, stream)) {
3409 lua_pushnumber(L, write_stream(n));
3410 } else if (lua_key_eq(s, data)) {
3411 tokenlist_to_lua(L, write_tokens(n));
3412 } else {
3413 lua_pushnil(L);
3415 } else if (t == special_node) {
3416 if (lua_key_eq(s, data)) {
3417 tokenlist_to_luastring(L, write_tokens(n));
3418 } else {
3419 lua_pushnil(L);
3421 } else if (t == pdf_start_link_node) {
3422 if (lua_key_eq(s, width)) {
3423 lua_pushnumber(L, width(n));
3424 } else if (lua_key_eq(s, depth)) {
3425 lua_pushnumber(L, depth(n));
3426 } else if (lua_key_eq(s, height)) {
3427 lua_pushnumber(L, height(n));
3428 } else if (lua_key_eq(s, objnum)) {
3429 lua_pushnumber(L, pdf_link_objnum(n));
3430 } else if (lua_key_eq(s, link_attr)) {
3431 tokenlist_to_luastring(L, pdf_link_attr(n));
3432 } else if (lua_key_eq(s, action)) {
3433 nodelib_pushaction(L, pdf_link_action(n));
3434 } else {
3435 lua_pushnil(L);
3437 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
3438 if (lua_key_eq(s, width)) {
3439 lua_pushnumber(L, width(n));
3440 } else if (lua_key_eq(s, depth)) {
3441 lua_pushnumber(L, depth(n));
3442 } else if (lua_key_eq(s, height)) {
3443 lua_pushnumber(L, height(n));
3444 } else if (lua_key_eq(s, named_id)) {
3445 lua_pushnumber(L, pdf_thread_named_id(n));
3446 } else if (lua_key_eq(s, thread_id)) {
3447 if (pdf_thread_named_id(n) == 1) {
3448 tokenlist_to_luastring(L, pdf_thread_id(n));
3449 } else {
3450 lua_pushnumber(L, pdf_thread_id(n));
3452 } else if (lua_key_eq(s, thread_attr)) {
3453 tokenlist_to_luastring(L, pdf_thread_attr(n));
3454 } else {
3455 lua_pushnil(L);
3457 } else if (t == open_node) {
3458 if (lua_key_eq(s, stream)) {
3459 lua_pushnumber(L, write_stream(n));
3460 } else if (lua_key_eq(s, name)) {
3461 nodelib_pushstring(L, open_name(n));
3462 } else if (lua_key_eq(s, area)) {
3463 nodelib_pushstring(L, open_area(n));
3464 } else if (lua_key_eq(s, ext)) {
3465 nodelib_pushstring(L, open_ext(n));
3466 } else {
3467 lua_pushnil(L);
3469 } else if (t == close_node) {
3470 if (lua_key_eq(s, stream)) {
3471 lua_pushnumber(L, write_stream(n));
3472 } else {
3473 lua_pushnil(L);
3475 } else {
3476 lua_pushnil(L);
3480 static int lua_nodelib_direct_getfield(lua_State * L)
3483 halfword n;
3484 const char *s;
3485 int t ;
3487 n = (halfword) lua_tonumber(L, 1);
3489 t = type(n);
3491 if (lua_type(L, 2) == LUA_TNUMBER) {
3493 halfword p;
3494 int i;
3496 if (! nodetype_has_attributes(t)) {
3497 lua_pushnil(L) ;
3498 return 1;
3501 p = node_attr(n);
3502 if (p == null || vlink(p) == null) {
3503 lua_pushnil(L) ;
3504 return 1;
3506 i = (int) lua_tointeger(L, 2);
3507 p = vlink(p);
3508 while (p != null) {
3509 if (attribute_id(p) == i) {
3510 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
3511 lua_pushnumber(L, (int) attribute_value(p));
3512 } else {
3513 lua_pushnil(L);
3515 return 1;
3516 } else if (attribute_id(p) > i) {
3517 lua_pushnil(L) ;
3518 return 1;
3520 p = vlink(p);
3522 lua_pushnil(L) ;
3523 return 1;
3526 s = lua_tostring(L, 2);
3528 if (lua_key_eq(s, id)) {
3529 lua_pushnumber(L, t);
3530 } else if (lua_key_eq(s, next)) {
3531 nodelib_pushdirect_or_nil(vlink(n));
3532 } else if (lua_key_eq(s, prev)) {
3533 nodelib_pushdirect_or_nil(alink(n));
3534 } else if (lua_key_eq(s, attr)) {
3535 if (! nodetype_has_attributes(t)) {
3536 lua_pushnil(L);
3537 } else {
3538 nodelib_pushattr(L, node_attr(n));
3540 } else if (lua_key_eq(s, subtype)) {
3541 if (t == glue_spec_node) {
3542 lua_pushnumber(L, 0); /* dummy, the only one */
3543 } else {
3544 lua_pushnumber(L, subtype(n));
3546 } else if (t == glyph_node) {
3547 if (lua_key_eq(s, font)) {
3548 lua_pushnumber(L, font(n));
3549 } else if (lua_key_eq(s, char)) {
3550 lua_pushnumber(L, character(n));
3551 } else if (lua_key_eq(s, xoffset)) {
3552 lua_pushnumber(L, x_displace(n));
3553 } else if (lua_key_eq(s, yoffset)) {
3554 lua_pushnumber(L, y_displace(n));
3555 } else if (lua_key_eq(s, width)) {
3556 lua_pushnumber(L, char_width(font(n),character(n)));
3557 } else if (lua_key_eq(s, height)) {
3558 lua_pushnumber(L, char_height(font(n),character(n)));
3559 } else if (lua_key_eq(s, depth)) {
3560 lua_pushnumber(L, char_depth(font(n),character(n)));
3561 } else if (lua_key_eq(s, expansion_factor)) {
3562 lua_pushnumber(L, ex_glyph(n));
3563 } else if (lua_key_eq(s, components)) {
3564 nodelib_pushdirect_or_nil(lig_ptr(n));
3565 } else if (lua_key_eq(s, lang)) {
3566 lua_pushnumber(L, char_lang(n));
3567 } else if (lua_key_eq(s, left)) {
3568 lua_pushnumber(L, char_lhmin(n));
3569 } else if (lua_key_eq(s, right)) {
3570 lua_pushnumber(L, char_rhmin(n));
3571 } else if (lua_key_eq(s, uchyph)) {
3572 lua_pushnumber(L, char_uchyph(n));
3573 } else {
3574 lua_pushnil(L);
3576 } else if ((t == hlist_node) || (t == vlist_node)) {
3577 /* candidates: whd (width,height,depth) */
3578 if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
3579 nodelib_pushdirect_or_nil_alink(list_ptr(n));
3580 } else if (lua_key_eq(s, width)) {
3581 lua_pushnumber(L, width(n));
3582 } else if (lua_key_eq(s, height)) {
3583 lua_pushnumber(L, height(n));
3584 } else if (lua_key_eq(s, depth)) {
3585 lua_pushnumber(L, depth(n));
3586 } else if (lua_key_eq(s, dir)) {
3587 // nodelib_pushdir(L, box_dir(n), false);
3588 lua_push_dir_par(L, box_dir(n));
3589 } else if (lua_key_eq(s, shift)) {
3590 lua_pushnumber(L, shift_amount(n));
3591 } else if (lua_key_eq(s, glue_order)) {
3592 lua_pushnumber(L, glue_order(n));
3593 } else if (lua_key_eq(s, glue_sign)) {
3594 lua_pushnumber(L, glue_sign(n));
3595 } else if (lua_key_eq(s, glue_set)) {
3596 lua_pushnumber(L, (double) glue_set(n));
3597 } else {
3598 lua_pushnil(L);
3600 } else if (t == disc_node) {
3601 if (lua_key_eq(s, pre)) {
3602 nodelib_pushdirect_or_nil(vlink(pre_break(n)));
3603 } else if (lua_key_eq(s, post)) {
3604 nodelib_pushdirect_or_nil(vlink(post_break(n)));
3605 } else if (lua_key_eq(s, replace)) {
3606 nodelib_pushdirect_or_nil(vlink(no_break(n)));
3607 } else {
3608 lua_pushnil(L);
3610 } else if (t == glue_node) {
3611 if (lua_key_eq(s, spec)) {
3612 nodelib_pushdirect(glue_ptr(n));
3613 } else if (lua_key_eq(s, leader)) {
3614 nodelib_pushdirect_or_nil(leader_ptr(n));
3615 } else {
3616 lua_pushnil(L);
3618 } else if (t == glue_spec_node) {
3619 if (lua_key_eq(s, width)) {
3620 lua_pushnumber(L, width(n));
3621 } else if (lua_key_eq(s, stretch)) {
3622 lua_pushnumber(L, stretch(n));
3623 } else if (lua_key_eq(s, shrink)) {
3624 lua_pushnumber(L, shrink(n));
3625 } else if (lua_key_eq(s, stretch_order)) {
3626 lua_pushnumber(L, stretch_order(n));
3627 } else if (lua_key_eq(s, shrink_order)) {
3628 lua_pushnumber(L, shrink_order(n));
3629 } else if (lua_key_eq(s, ref_count)) {
3630 lua_pushnumber(L, glue_ref_count(n));
3631 } else if (lua_key_eq(s, writable)) {
3632 lua_pushboolean(L, valid_node(n));
3633 } else {
3634 lua_pushnil(L);
3636 } else if (t == kern_node) {
3637 if (lua_key_eq(s, kern)) {
3638 lua_pushnumber(L, width(n));
3639 } else if (lua_key_eq(s, expansion_factor)) {
3640 lua_pushnumber(L, ex_kern(n));
3641 } else {
3642 lua_pushnil(L);
3644 } else if (t == penalty_node) {
3645 if (lua_key_eq(s, penalty)) {
3646 lua_pushnumber(L, penalty(n));
3647 } else {
3648 lua_pushnil(L);
3650 } else if (t == rule_node) {
3651 /* candidates: whd (width,height,depth) */
3652 if (lua_key_eq(s, width)) {
3653 lua_pushnumber(L, width(n));
3654 } else if (lua_key_eq(s, height)) {
3655 lua_pushnumber(L, height(n));
3656 } else if (lua_key_eq(s, depth)) {
3657 lua_pushnumber(L, depth(n));
3658 } else if (lua_key_eq(s, dir)) {
3659 // nodelib_pushdir(L, rule_dir(n), false);
3660 lua_push_dir_par(L, rule_dir(n));
3661 } else {
3662 lua_pushnil(L);
3664 } else if (t == whatsit_node) {
3665 lua_nodelib_direct_getfield_whatsit(L, n, s);
3666 } else if (t == simple_noad) {
3667 if (lua_key_eq(s, nucleus)) {
3668 nodelib_pushdirect_or_nil(nucleus(n));
3669 } else if (lua_key_eq(s, sub)) {
3670 nodelib_pushdirect_or_nil(subscr(n));
3671 } else if (lua_key_eq(s, sup)) {
3672 nodelib_pushdirect_or_nil(supscr(n));
3673 } else {
3674 lua_pushnil(L);
3676 } else if ((t == math_char_node) || (t == math_text_char_node)) {
3677 if (lua_key_eq(s, fam)) {
3678 lua_pushnumber(L, math_fam(n));
3679 } else if (lua_key_eq(s, char)) {
3680 lua_pushnumber(L, math_character(n));
3681 } else {
3682 lua_pushnil(L);
3684 } else if (t == mark_node) {
3685 if (lua_key_eq(s, class)) {
3686 lua_pushnumber(L, mark_class(n));
3687 } else if (lua_key_eq(s, mark)) {
3688 tokenlist_to_lua(L, mark_ptr(n));
3689 } else {
3690 lua_pushnil(L);
3692 } else if (t == ins_node) {
3693 if (lua_key_eq(s, cost)) {
3694 lua_pushnumber(L, float_cost(n));
3695 } else if (lua_key_eq(s, depth)) {
3696 lua_pushnumber(L, depth(n));
3697 } else if (lua_key_eq(s, height)) {
3698 lua_pushnumber(L, height(n));
3699 } else if (lua_key_eq(s, spec)) {
3700 nodelib_pushdirect_or_nil(split_top_ptr(n));
3701 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3702 nodelib_pushdirect_or_nil_alink(ins_ptr(n));
3703 } else {
3704 lua_pushnil(L);
3706 } else if (t == math_node) {
3707 if (lua_key_eq(s, surround)) {
3708 lua_pushnumber(L, surround(n));
3709 } else {
3710 lua_pushnil(L);
3712 } else if (t == fraction_noad) {
3713 if (lua_key_eq(s, width)) {
3714 lua_pushnumber(L, thickness(n));
3715 } else if (lua_key_eq(s, num)) {
3716 nodelib_pushdirect_or_nil(numerator(n));
3717 } else if (lua_key_eq(s, denom)) {
3718 nodelib_pushdirect_or_nil(denominator(n));
3719 } else if (lua_key_eq(s, left)) {
3720 nodelib_pushdirect_or_nil(left_delimiter(n));
3721 } else if (lua_key_eq(s, right)) {
3722 nodelib_pushdirect_or_nil(right_delimiter(n));
3723 } else {
3724 lua_pushnil(L);
3726 } else if (t == style_node) {
3727 if (lua_key_eq(s, style)) {
3728 lua_push_math_style_name(L,subtype(n));
3729 } else {
3730 lua_pushnil(L);
3732 } else if (t == accent_noad) {
3733 if (lua_key_eq(s, nucleus)) {
3734 nodelib_pushdirect_or_nil(nucleus(n));
3735 } else if (lua_key_eq(s, sub)) {
3736 nodelib_pushdirect_or_nil(subscr(n));
3737 } else if (lua_key_eq(s, sup)) {
3738 nodelib_pushdirect_or_nil(supscr(n));
3739 } else if (lua_key_eq(s, accent)) {
3740 nodelib_pushdirect_or_nil(accent_chr(n));
3741 } else if (lua_key_eq(s, bot_accent)) {
3742 nodelib_pushdirect_or_nil(bot_accent_chr(n));
3743 } else {
3744 lua_pushnil(L);
3746 } else if (t == fence_noad) {
3747 if (lua_key_eq(s, delim)) {
3748 nodelib_pushdirect_or_nil(delimiter(n));
3749 } else {
3750 lua_pushnil(L);
3752 } else if (t == delim_node) {
3753 if (lua_key_eq(s, small_fam)) {
3754 lua_pushnumber(L, small_fam(n));
3755 } else if (lua_key_eq(s, small_char)) {
3756 lua_pushnumber(L, small_char(n));
3757 } else if (lua_key_eq(s, large_fam)) {
3758 lua_pushnumber(L, large_fam(n));
3759 } else if (lua_key_eq(s, large_char)) {
3760 lua_pushnumber(L, large_char(n));
3761 } else {
3762 lua_pushnil(L);
3764 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
3765 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3766 nodelib_pushdirect_or_nil_alink(math_list(n));
3767 } else {
3768 lua_pushnil(L);
3770 } else if (t == radical_noad) {
3771 if (lua_key_eq(s, nucleus)) {
3772 nodelib_pushdirect_or_nil(nucleus(n));
3773 } else if (lua_key_eq(s, sub)) {
3774 nodelib_pushdirect_or_nil(subscr(n));
3775 } else if (lua_key_eq(s, sup)) {
3776 nodelib_pushdirect_or_nil(supscr(n));
3777 } else if (lua_key_eq(s, left)) {
3778 nodelib_pushdirect_or_nil(left_delimiter(n));
3779 } else if (lua_key_eq(s, degree)) {
3780 nodelib_pushdirect_or_nil(degree(n));
3781 } else {
3782 lua_pushnil(L);
3784 } else if (t == margin_kern_node) {
3785 if (lua_key_eq(s, width)) {
3786 lua_pushnumber(L, width(n));
3787 } else if (lua_key_eq(s, glyph)) {
3788 nodelib_pushdirect_or_nil(margin_char(n));
3789 } else {
3790 lua_pushnil(L);
3792 } else if (t == split_up_node) {
3793 if (lua_key_eq(s, last_ins_ptr)) {
3794 nodelib_pushdirect_or_nil(last_ins_ptr(n));
3795 } else if (lua_key_eq(s, best_ins_ptr)) {
3796 nodelib_pushdirect_or_nil(best_ins_ptr(n));
3797 } else if (lua_key_eq(s, broken_ptr)) {
3798 nodelib_pushdirect_or_nil(broken_ptr(n));
3799 } else if (lua_key_eq(s, broken_ins)) {
3800 nodelib_pushdirect_or_nil(broken_ins(n));
3801 } else {
3802 lua_pushnil(L);
3804 } else if (t == choice_node) {
3805 if (lua_key_eq(s, display)) {
3806 nodelib_pushdirect_or_nil(display_mlist(n));
3807 } else if (lua_key_eq(s, text)) {
3808 nodelib_pushdirect_or_nil(text_mlist(n));
3809 } else if (lua_key_eq(s, script)) {
3810 nodelib_pushdirect_or_nil(script_mlist(n));
3811 } else if (lua_key_eq(s, scriptscript)) {
3812 nodelib_pushdirect_or_nil(script_script_mlist(n));
3813 } else {
3814 lua_pushnil(L);
3816 } else if (t == inserting_node) {
3817 if (lua_key_eq(s, last_ins_ptr)) {
3818 nodelib_pushdirect_or_nil(last_ins_ptr(n));
3819 } else if (lua_key_eq(s, best_ins_ptr)) {
3820 nodelib_pushdirect_or_nil(best_ins_ptr(n));
3821 } else {
3822 lua_pushnil(L);
3824 } else if (t == attribute_node) {
3825 if (lua_key_eq(s, number)) {
3826 lua_pushnumber(L, attribute_id(n));
3827 } else if (lua_key_eq(s, value)) {
3828 lua_pushnumber(L, attribute_value(n));
3829 } else {
3830 lua_pushnil(L);
3832 } else if (t == adjust_node) {
3833 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3834 nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
3835 } else {
3836 lua_pushnil(L);
3838 } else if (t == action_node) {
3839 if (lua_key_eq(s, action_type)) {
3840 lua_pushnumber(L, pdf_action_type(n));
3841 } else if (lua_key_eq(s, named_id)) {
3842 lua_pushnumber(L, pdf_action_named_id(n));
3843 } else if (lua_key_eq(s, action_id)) {
3844 if (pdf_action_named_id(n) == 1) {
3845 tokenlist_to_luastring(L, pdf_action_id(n));
3846 } else {
3847 lua_pushnumber(L, pdf_action_id(n));
3849 } else if (lua_key_eq(s, file)) {
3850 tokenlist_to_luastring(L, pdf_action_file(n));
3851 } else if (lua_key_eq(s, new_window)) {
3852 lua_pushnumber(L, pdf_action_new_window(n));
3853 } else if (lua_key_eq(s, data)) {
3854 tokenlist_to_luastring(L, pdf_action_tokens(n));
3855 } else if (lua_key_eq(s, ref_count)) {
3856 lua_pushnumber(L, pdf_action_refcount(n));
3857 } else {
3858 lua_pushnil(L);
3860 } else if (t == unset_node) {
3861 if (lua_key_eq(s, width)) {
3862 lua_pushnumber(L, width(n));
3863 } else if (lua_key_eq(s, height)) {
3864 lua_pushnumber(L, height(n));
3865 } else if (lua_key_eq(s, depth)) {
3866 lua_pushnumber(L, depth(n));
3867 } else if (lua_key_eq(s, dir)) {
3868 // nodelib_pushdir(L, box_dir(n), false);
3869 lua_push_dir_par(L, box_dir(n));
3870 } else if (lua_key_eq(s, shrink)) {
3871 lua_pushnumber(L, glue_shrink(n));
3872 } else if (lua_key_eq(s, glue_order)) {
3873 lua_pushnumber(L, glue_order(n));
3874 } else if (lua_key_eq(s, glue_sign)) {
3875 lua_pushnumber(L, glue_sign(n));
3876 } else if (lua_key_eq(s, stretch)) {
3877 lua_pushnumber(L, glue_stretch(n));
3878 } else if (lua_key_eq(s, count)) {
3879 lua_pushnumber(L, span_count(n));
3880 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3881 nodelib_pushdirect_or_nil_alink(list_ptr(n));
3882 } else {
3883 lua_pushnil(L);
3885 /* } else if (t == attribute_list_node) { */
3886 /* lua_pushnil(L); */
3887 } else {
3888 lua_pushnil(L);
3890 return 1;
3893 /* msg could be preallocated and shared */
3895 static void lua_nodelib_do_tostring(lua_State * L, halfword n, const char *tag)
3897 char *msg;
3898 char a[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
3899 char v[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
3900 msg = xmalloc(256);
3901 if (alink(n) != null)
3902 snprintf(a, 7, "%6d", (int) alink(n));
3903 if (vlink(n) != null)
3904 snprintf(v, 7, "%6d", (int) vlink(n));
3905 snprintf(msg, 255, "<%s %s < %6d > %s : %s %d>", tag, a, (int) n, v, node_data[type(n)].name, subtype(n));
3906 lua_pushstring(L, msg);
3907 free(msg);
3908 return ;
3911 /* __tostring node.tostring */
3913 static int lua_nodelib_tostring(lua_State * L)
3915 halfword *n;
3916 n = check_isnode(L, 1);
3917 lua_nodelib_do_tostring(L, *n, "node");
3918 return 1;
3921 /* node.direct.tostring */
3923 static int lua_nodelib_direct_tostring(lua_State * L)
3925 halfword n = (halfword) lua_tonumber(L,1);
3926 if (n==0) {
3927 lua_pushnil(L);
3928 } else {
3929 lua_nodelib_do_tostring(L, n, "direct");
3931 return 1;
3934 /* __eq */
3936 static int lua_nodelib_equal(lua_State * L)
3938 halfword n, m;
3939 n = *((halfword *) lua_touserdata(L, 1));
3940 m = *((halfword *) lua_touserdata(L, 2));
3941 lua_pushboolean(L, (n == m));
3942 return 1;
3945 /* node.ligaturing */
3947 static int font_tex_ligaturing(lua_State * L)
3949 /* on the stack are two nodes and a direction */
3950 halfword tmp_head;
3951 halfword *h;
3952 halfword t = null;
3953 if (lua_gettop(L) < 1) {
3954 lua_pushnil(L);
3955 lua_pushboolean(L, 0);
3956 return 2;
3958 h = check_isnode(L, 1);
3959 if (lua_gettop(L) > 1) {
3960 t = *(check_isnode(L, 2));
3962 tmp_head = new_node(nesting_node, 1);
3963 couple_nodes(tmp_head, *h);
3964 tlink(tmp_head) = t;
3965 t = handle_ligaturing(tmp_head, t);
3966 alink(vlink(tmp_head)) = null ; /* hh-ls */
3967 lua_pushnumber(L, vlink(tmp_head));
3968 /* can be: lua_nodelib_push_fast(L, head); */
3969 flush_node(tmp_head);
3970 lua_nodelib_push(L);
3971 /* can be: lua_nodelib_push_fast(L, t); */
3972 lua_pushnumber(L, t);
3973 lua_nodelib_push(L);
3974 lua_pushboolean(L, 1);
3975 return 3;
3978 /* node.kerning */
3980 static int font_tex_kerning(lua_State * L)
3982 /* on the stack are two nodes and a direction */
3984 halfword tmp_head;
3985 halfword *h;
3986 halfword t = null;
3987 if (lua_gettop(L) < 1) {
3988 lua_pushnil(L);
3989 lua_pushboolean(L, 0);
3990 return 2;
3992 h = check_isnode(L, 1);
3993 if (lua_gettop(L) > 1) {
3994 t = *(check_isnode(L, 2));
3996 tmp_head = new_node(nesting_node, 1);
3997 couple_nodes(tmp_head, *h);
3998 tlink(tmp_head) = t;
3999 t = handle_kerning(tmp_head, t);
4000 alink(vlink(tmp_head)) = null ; /* hh-ls */
4001 lua_pushnumber(L, vlink(tmp_head));
4002 /* can be: lua_nodelib_push_fast(L, head); */
4003 flush_node(tmp_head);
4004 lua_nodelib_push(L);
4005 /* can be: lua_nodelib_push_fast(L, t); */
4006 lua_pushnumber(L, t);
4007 lua_nodelib_push(L);
4008 lua_pushboolean(L, 1);
4009 return 3;
4013 /* node.protect_glyphs (returns also boolean because that signals callback) */
4015 static int lua_nodelib_protect_glyphs(lua_State * L)
4017 int t = 0;
4018 halfword head = *(check_isnode(L, 1));
4019 while (head != null) {
4020 if (type(head) == glyph_node) {
4021 int s = subtype(head);
4022 if (s <= 256) {
4023 t = 1;
4024 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4027 head = vlink(head);
4029 lua_pushboolean(L, t);
4030 lua_pushvalue(L, 1);
4031 return 2;
4034 /* node.direct.protect_glyphs */
4036 static int lua_nodelib_direct_protect_glyphs(lua_State * L)
4038 int t = 0;
4039 halfword head = (halfword) lua_tonumber(L,1);
4040 while (head != null) {
4041 if (type(head) == glyph_node) {
4042 int s = subtype(head);
4043 if (s <= 256) {
4044 t = 1;
4045 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4048 head = vlink(head);
4050 lua_pushboolean(L, t);
4051 lua_pushvalue(L, 1);
4052 return 2;
4055 /* node.unprotect_glyphs (returns also boolean because that signals callback) */
4057 static int lua_nodelib_unprotect_glyphs(lua_State * L)
4059 int t = 0;
4060 halfword head = *(check_isnode(L, 1));
4061 while (head != null) {
4062 if (type(head) == glyph_node) {
4063 int s = subtype(head);
4064 if (s > 256) {
4065 t = 1;
4066 subtype(head) = (quarterword) (s - 256);
4069 head = vlink(head);
4071 lua_pushboolean(L, t);
4072 lua_pushvalue(L, 1);
4073 return 2;
4076 /* node.direct.unprotect_glyphs */
4078 static int lua_nodelib_direct_unprotect_glyphs(lua_State * L)
4080 int t = 0;
4081 halfword head = (halfword) lua_tonumber(L,1);
4082 while (head != null) {
4083 if (type(head) == glyph_node) {
4084 int s = subtype(head);
4085 if (s > 256) {
4086 t = 1;
4087 subtype(head) = (quarterword) (s - 256);
4090 head = vlink(head);
4092 lua_pushboolean(L, t);
4093 lua_pushvalue(L, 1);
4094 return 2;
4097 /* node.first_glyph */
4099 static int lua_nodelib_first_glyph(lua_State * L)
4101 /* on the stack are two nodes and a direction */
4102 halfword h, savetail = null, t = null;
4103 if (lua_gettop(L) < 1) {
4104 lua_pushnil(L);
4105 lua_pushboolean(L, 0);
4106 return 2;
4108 h = *(check_isnode(L, 1));
4109 if (lua_gettop(L) > 1) {
4110 t = *(check_isnode(L, 2));
4111 savetail = vlink(t);
4112 vlink(t) = null;
4114 while (h != null && (type(h) != glyph_node || !is_simple_character(h))) {
4115 h = vlink(h);
4117 if (savetail != null) {
4118 vlink(t) = savetail;
4120 lua_pushnumber(L, h);
4121 lua_nodelib_push(L);
4122 lua_pushboolean(L, (h == null ? 0 : 1));
4123 return 2;
4126 /* node.direct.first_glyph */
4128 static int lua_nodelib_direct_first_glyph(lua_State * L)
4130 halfword h,savetail,t;
4131 savetail = null;
4132 t = null;
4133 h = (halfword) lua_tonumber(L,1);
4134 if (h == null) {
4135 lua_pushnil(L);
4136 return 1;
4138 t = (halfword) lua_tonumber(L,2);
4139 if (t != null) {
4140 savetail = vlink(t);
4141 vlink(t) = null;
4143 while (h != null && (type(h) != glyph_node || !is_simple_character(h)))
4144 h = vlink(h);
4145 if (savetail != null)
4146 vlink(t) = savetail;
4147 lua_pushnumber(L, h);
4148 return 1; /* no need to also push a boolean if we have nil */
4151 /* new, fast and dumb ones: only signals that something needs to be processed */
4153 /* #define do_has_glyph(h) do { \ */
4154 /* while (h != null) { \ */
4155 /* if (type(h) == glyph_node) { \ */
4156 /* return h; \ */
4157 /* } else { \ */
4158 /* h = vlink(h); \ */
4159 /* } \ */
4160 /* } \ */
4161 /* return null; \ */
4162 /* } while (0) */
4167 /* node.has_glyph */
4169 static int lua_nodelib_has_glyph(lua_State * L)
4171 halfword *a;
4172 halfword h = (halfword) *(check_isnode(L,1)) ;
4173 while (h != null) {
4174 if (type(h) == glyph_node) {
4175 fast_metatable(h);
4176 return 1;
4177 } else {
4178 h = vlink(h);
4181 lua_pushnil(L);
4182 return 1;
4185 /* node.direct.has_glyph */
4187 static int lua_nodelib_direct_has_glyph(lua_State * L)
4189 halfword h = (halfword) lua_tonumber(L,1) ;
4190 while (h != null) {
4191 if (type(h) == glyph_node) {
4192 nodelib_pushdirect(h);
4193 return 1;
4194 } else {
4195 h = vlink(h);
4198 lua_pushnil(L);
4199 return 1;
4203 /* depricated */
4205 static int lua_nodelib_first_character(lua_State * L)
4207 luatex_warn("node.first_character() is deprecated, please update to node.first_glyph()");
4208 return lua_nodelib_first_glyph(L);
4211 /* this is too simplistic, but it helps Hans to get going */
4213 static halfword do_ligature_n(halfword prev, halfword stop, halfword lig)
4215 vlink(lig) = vlink(stop);
4216 vlink(stop) = null;
4217 lig_ptr(lig) = vlink(prev);
4218 vlink(prev) = lig;
4219 return lig;
4222 /* node.do_ligature_n(node prev, node last, node lig) */
4224 static int lua_nodelib_do_ligature_n(lua_State * L)
4226 halfword n, m, o, p, tmp_head;
4227 n = *(check_isnode(L, 1));
4228 m = *(check_isnode(L, 2));
4229 o = *(check_isnode(L, 3));
4230 if (alink(n) == null || vlink(alink(n)) != n) {
4231 tmp_head = new_node(temp_node, 0);
4232 couple_nodes(tmp_head, n);
4233 p = do_ligature_n(tmp_head, m, o);
4234 flush_node(tmp_head);
4235 } else {
4236 p = do_ligature_n(alink(n), m, o);
4238 lua_pushnumber(L, p);
4239 lua_nodelib_push(L);
4240 return 1;
4243 /* node.direct.do_ligature_n(node prev, node last, node lig) */
4245 static int lua_nodelib_direct_do_ligature_n(lua_State * L)
4247 halfword n, m, o, p, tmp_head;
4248 n = (halfword) lua_tonumber(L, 1);
4249 m = (halfword) lua_tonumber(L, 2);
4250 o = (halfword) lua_tonumber(L, 3);
4251 if ((n == null) || (m == null) || (o == null)) {
4252 lua_pushnil(L);
4253 } else {
4254 if (alink(n) == null || vlink(alink(n)) != n) {
4255 tmp_head = new_node(temp_node, 0);
4256 couple_nodes(tmp_head, n);
4257 p = do_ligature_n(tmp_head, m, o);
4258 flush_node(tmp_head);
4259 } else {
4260 p = do_ligature_n(alink(n), m, o);
4262 lua_pushnumber(L, p);
4264 return 1;
4267 /* node.usedlist */
4269 static int lua_nodelib_usedlist(lua_State * L)
4271 lua_pushnumber(L, list_node_mem_usage());
4272 lua_nodelib_push(L);
4273 return 1;
4276 /* node.direct.usedlist */
4278 static int lua_nodelib_direct_usedlist(lua_State * L)
4280 lua_pushnumber(L, list_node_mem_usage());
4281 return 1;
4284 /* node.protrusion_skipable(node m) */
4286 static int lua_nodelib_cp_skipable(lua_State * L)
4288 halfword n;
4289 n = *(check_isnode(L, 1));
4290 lua_pushboolean(L, cp_skipable(n));
4291 return 1;
4294 /* node.direct.protrusion_skipable(node m) */
4296 static int lua_nodelib_direct_cp_skipable(lua_State * L)
4298 halfword n;
4299 n = (halfword) lua_tonumber(L, 1);
4300 if (n == null) {
4301 lua_pushnil(L);
4302 } else {
4303 lua_pushboolean(L, cp_skipable(n));
4305 return 1;
4308 /* node.currentattr(node m) */
4310 static int lua_nodelib_currentattr(lua_State * L)
4312 int n = lua_gettop(L);
4313 if (n == null) {
4314 /* query */
4315 if (max_used_attr >= 0) {
4316 if (attr_list_cache == cache_disabled) {
4317 update_attribute_cache();
4318 if (attr_list_cache == null) {
4319 lua_pushnil (L);
4320 return 1;
4323 attr_list_ref(attr_list_cache)++;
4324 lua_pushnumber(L, attr_list_cache);
4325 lua_nodelib_push(L);
4326 } else {
4327 lua_pushnil(L);
4329 return 1;
4330 } else {
4331 /* assign */
4332 luatex_warn("Assignment via node.current_attr(<list>) is not supported (yet)");
4333 return 0;
4337 /* node.direct.currentattr(node m) */
4339 static int lua_nodelib_direct_currentattr(lua_State * L)
4341 if (max_used_attr >= 0) {
4342 if (attr_list_cache == cache_disabled) {
4343 update_attribute_cache();
4344 if (attr_list_cache == null) {
4345 lua_pushnil (L);
4346 return 1;
4349 attr_list_ref(attr_list_cache)++;
4350 lua_pushnumber(L, attr_list_cache);
4351 } else {
4352 lua_pushnil(L);
4354 return 1;
4357 /* node.direct.todirect */
4359 static int lua_nodelib_direct_todirect(lua_State * L)
4361 if (lua_type(L,1) != LUA_TNUMBER) {
4362 /* assume node, no further testing, used in known situations */
4363 void *n ;
4364 n = lua_touserdata(L, 1);
4365 if (n == null) {
4366 lua_pushnil(L);
4367 } else {
4368 lua_pushnumber(L, *((halfword *)n) );
4370 } /* else assume direct and returns argument */
4371 return 1;
4375 /* node.direct.tonode */
4377 static int lua_nodelib_direct_tonode(lua_State * L)
4379 halfword *a;
4380 halfword n;
4381 n = (halfword) lua_tonumber(L, 1);
4382 if (n != null) {
4383 a = (halfword *) lua_newuserdata(L, sizeof(halfword));
4384 *a=n;
4385 lua_push_node_metatablelua;
4386 lua_setmetatable(L,-2);
4387 } /* else assume node and return argument */
4388 return 1;
4391 /* node.setfield */
4393 /* ls-hh: normally a value will not be reassigned */
4395 #define cleanup_late_lua(n) do { \
4396 if (late_lua_data(n) != 0) { \
4397 if (late_lua_type(n) == normal) { \
4398 delete_token_ref(late_lua_data(n)); \
4399 } else if (late_lua_type(n) == lua_refid_literal) { \
4400 luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \
4403 } while (0)
4405 #define cleanup_late_lua_name(n) do { \
4406 if (late_lua_name(n) != 0) { \
4407 delete_token_ref(late_lua_name(n)); \
4409 } while (0)
4411 static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s)
4413 int t ;
4414 t = subtype(n);
4416 if (t == dir_node) {
4417 if (lua_key_eq(s, dir)) {
4418 dir_dir(n) = nodelib_getdir(L, 3, 0);
4419 } else if (lua_key_eq(s, level)) {
4420 dir_level(n) = (halfword) lua_tointeger(L, 3);
4421 } else if (lua_key_eq(s, dvi_ptr)) {
4422 dir_dvi_ptr(n) = (halfword) lua_tointeger(L, 3);
4423 } else if (lua_key_eq(s, dir_h)) {
4424 dir_dvi_h(n) = (halfword) lua_tointeger(L, 3);
4425 } else {
4426 return nodelib_cantset(L, n, s);
4428 } else if (t == pdf_literal_node) {
4429 if (lua_key_eq(s, mode)) {
4430 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
4431 } else if (lua_key_eq(s, data)) {
4432 if (ini_version) {
4433 pdf_literal_data(n) = nodelib_gettoks(L, 3);
4434 } else {
4435 lua_pushvalue(L, 3);
4436 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4437 pdf_literal_type(n) = lua_refid_literal;
4439 } else {
4440 return nodelib_cantset(L, n, s);
4442 } else if (t == late_lua_node) {
4443 if (lua_key_eq(s, string)) {
4444 cleanup_late_lua(n) ; /* ls-hh */
4445 if (ini_version) {
4446 late_lua_data(n) = nodelib_gettoks(L, 3);
4447 late_lua_type(n) = normal;
4448 } else {
4449 lua_pushvalue(L, 3);
4450 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4451 late_lua_type(n) = lua_refid_literal;
4453 } else if (lua_key_eq(s, data)) {
4454 cleanup_late_lua(n) ; /* ls-hh */
4455 late_lua_data(n) = nodelib_gettoks(L, 3);
4456 late_lua_type(n) = normal;
4457 } else if (lua_key_eq(s, name)) {
4458 cleanup_late_lua_name(n) ; /* ls-hh */
4459 late_lua_name(n) = nodelib_gettoks(L, 3);
4460 } else {
4461 return nodelib_cantset(L, n, s);
4463 /* done */
4464 } else if (t == user_defined_node) {
4465 if (lua_key_eq(s, user_id)) {
4466 user_node_id(n) = (halfword) lua_tointeger(L, 3);
4467 } else if (lua_key_eq(s, type)) {
4468 user_node_type(n) = (halfword) lua_tointeger(L, 3);
4469 } else if (lua_key_eq(s, value)) {
4470 switch (user_node_type(n)) {
4471 case 'a':
4472 user_node_value(n) = nodelib_getlist(L, 3);
4473 break;
4474 case 'd':
4475 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4476 break;
4477 case 'l':
4478 lua_pushvalue(L, 3);
4479 if (user_node_value(n) != 0) {
4480 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
4482 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4483 break;
4484 case 'n':
4485 user_node_value(n) = nodelib_getlist(L, 3);
4486 break;
4487 case 's':
4488 user_node_value(n) = nodelib_getstring(L, 3);
4489 break;
4490 case 't':
4491 user_node_value(n) = nodelib_gettoks(L, 3);
4492 break;
4493 default:
4494 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4495 break;
4497 } else {
4498 return nodelib_cantset(L, n, s);
4500 } else if (t == pdf_annot_node) {
4501 if (lua_key_eq(s, width)) {
4502 width(n) = (halfword) lua_tointeger(L, 3);
4503 } else if (lua_key_eq(s, depth)) {
4504 depth(n) = (halfword) lua_tointeger(L, 3);
4505 } else if (lua_key_eq(s, height)) {
4506 height(n) = (halfword) lua_tointeger(L, 3);
4507 } else if (lua_key_eq(s, objnum)) {
4508 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
4509 } else if (lua_key_eq(s, data)) {
4510 pdf_annot_data(n) = nodelib_gettoks(L, 3);
4511 } else {
4512 return nodelib_cantset(L, n, s);
4514 } else if (t == pdf_dest_node) {
4515 if (lua_key_eq(s, width)) {
4516 width(n) = (halfword) lua_tointeger(L, 3);
4517 } else if (lua_key_eq(s, depth)) {
4518 depth(n) = (halfword) lua_tointeger(L, 3);
4519 } else if (lua_key_eq(s, height)) {
4520 height(n) = (halfword) lua_tointeger(L, 3);
4521 } else if (lua_key_eq(s, named_id)) {
4522 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
4523 } else if (lua_key_eq(s, dest_id)) {
4524 if (pdf_dest_named_id(n) == 1) {
4525 pdf_dest_id(n) = nodelib_gettoks(L, 3);
4526 } else {
4527 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
4529 } else if (lua_key_eq(s, dest_type)) {
4530 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
4531 } else if (lua_key_eq(s, xyz_zoom)) {
4532 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
4533 } else if (lua_key_eq(s, objnum)) {
4534 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
4535 } else {
4536 return nodelib_cantset(L, n, s);
4538 } else if (t == pdf_setmatrix_node) {
4539 if (lua_key_eq(s, data)) {
4540 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
4541 } else {
4542 return nodelib_cantset(L, n, s);
4544 } else if (t == pdf_refobj_node) {
4545 if (lua_key_eq(s, objnum)) {
4546 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
4547 } else {
4548 return nodelib_cantset(L, n, s);
4550 } else if (t == pdf_refxform_node) {
4551 if (lua_key_eq(s, width)) {
4552 width(n) = (halfword) lua_tointeger(L, 3);
4553 } else if (lua_key_eq(s, depth)) {
4554 depth(n) = (halfword) lua_tointeger(L, 3);
4555 } else if (lua_key_eq(s, height)) {
4556 height(n) = (halfword) lua_tointeger(L, 3);
4557 } else if (lua_key_eq(s, objnum)) {
4558 pdf_xform_objnum(n) = (halfword) lua_tointeger(L, 3);
4559 } else {
4560 return nodelib_cantset(L, n, s);
4562 } else if (t == pdf_refximage_node) {
4563 if (lua_key_eq(s, width)) {
4564 width(n) = (halfword) lua_tointeger(L, 3);
4565 } else if (lua_key_eq(s, depth)) {
4566 depth(n) = (halfword) lua_tointeger(L, 3);
4567 } else if (lua_key_eq(s, height)) {
4568 height(n) = (halfword) lua_tointeger(L, 3);
4569 } else if (lua_key_eq(s, transform)) {
4570 pdf_ximage_transform(n) = (halfword) lua_tointeger(L, 3);
4571 } else if (lua_key_eq(s, index)) {
4572 pdf_ximage_index(n) = (halfword) lua_tointeger(L, 3);
4573 } else {
4574 return nodelib_cantset(L, n, s);
4576 } else if (t == local_par_node) {
4577 if (lua_key_eq(s, pen_inter)) {
4578 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
4579 } else if (lua_key_eq(s, pen_broken)) {
4580 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
4581 } else if (lua_key_eq(s, dir)) {
4582 local_par_dir(n) = nodelib_getdir(L, 3, 1);
4583 } else if (lua_key_eq(s, box_left)) {
4584 local_box_left(n) = nodelib_getlist(L, 3);
4585 } else if (lua_key_eq(s, box_left_width)) {
4586 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
4587 } else if (lua_key_eq(s, box_right)) {
4588 local_box_right(n) = nodelib_getlist(L, 3);
4589 } else if (lua_key_eq(s, box_right_width)) {
4590 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
4591 } else {
4592 return nodelib_cantset(L, n, s);
4594 } else if (t == pdf_start_link_node) {
4595 if (lua_key_eq(s, width)) {
4596 width(n) = (halfword) lua_tointeger(L, 3);
4597 } else if (lua_key_eq(s, depth)) {
4598 depth(n) = (halfword) lua_tointeger(L, 3);
4599 } else if (lua_key_eq(s, height)) {
4600 height(n) = (halfword) lua_tointeger(L, 3);
4601 } else if (lua_key_eq(s, objnum)) {
4602 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
4603 } else if (lua_key_eq(s, link_attr)) {
4604 pdf_link_attr(n) = nodelib_gettoks(L, 3);
4605 } else if (lua_key_eq(s, action)) {
4606 pdf_link_action(n) = nodelib_getaction(L, 3);
4607 } else {
4608 return nodelib_cantset(L, n, s);
4610 } else if (t == write_node) {
4611 if (lua_key_eq(s, stream)) {
4612 write_stream(n) = (halfword) lua_tointeger(L, 3);
4613 } else if (lua_key_eq(s, data)) {
4614 write_tokens(n) = nodelib_gettoks(L, 3);
4615 } else {
4616 return nodelib_cantset(L, n, s);
4618 } else if (t == pdf_colorstack_node) {
4619 if (lua_key_eq(s, stack)) {
4620 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
4621 } else if (lua_key_eq(s, command)) {
4622 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
4623 } else if (lua_key_eq(s, data)) {
4624 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
4625 } else {
4626 return nodelib_cantset(L, n, s);
4628 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
4629 if (lua_key_eq(s, width)) {
4630 width(n) = (halfword) lua_tointeger(L, 3);
4631 } else if (lua_key_eq(s, depth)) {
4632 depth(n) = (halfword) lua_tointeger(L, 3);
4633 } else if (lua_key_eq(s, height)) {
4634 height(n) = (halfword) lua_tointeger(L, 3);
4635 } else if (lua_key_eq(s, named_id)) {
4636 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
4637 } else if (lua_key_eq(s, thread_id)) {
4638 if (pdf_thread_named_id(n) == 1) {
4639 pdf_thread_id(n) = nodelib_gettoks(L, 3);
4640 } else {
4641 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
4643 } else if (lua_key_eq(s, thread_attr)) {
4644 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
4645 } else {
4646 return nodelib_cantset(L, n, s);
4648 } else if (t == special_node) {
4649 if (lua_key_eq(s, data)) {
4650 write_tokens(n) = nodelib_gettoks(L, 3);
4651 } else {
4652 return nodelib_cantset(L, n, s);
4654 } else if (t == open_node) {
4655 if (lua_key_eq(s, stream)) {
4656 write_stream(n) = (halfword) lua_tointeger(L, 3);
4657 } else if (lua_key_eq(s, name)) {
4658 open_name(n) = nodelib_getstring(L, 3);
4659 } else if (lua_key_eq(s, area)) {
4660 open_area(n) = nodelib_getstring(L, 3);
4661 } else if (lua_key_eq(s, ext)) {
4662 open_ext(n) = nodelib_getstring(L, 3);
4663 } else {
4664 return nodelib_cantset(L, n, s);
4666 } else if (t == close_node) {
4667 if (lua_key_eq(s, stream)) {
4668 write_stream(n) = (halfword) lua_tointeger(L, 3);
4669 } else {
4670 return nodelib_cantset(L, n, s);
4672 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == pdf_save_pos_node) ||
4673 (t == pdf_save_node) || (t == pdf_restore_node) || (t == cancel_boundary_node)) {
4674 return nodelib_cantset(L, n, s);
4675 } else {
4676 /* do nothing */
4678 return 0;
4681 static int lua_nodelib_fast_setfield(lua_State * L)
4683 halfword n;
4684 const char *s;
4685 int t ;
4687 n = *((halfword *) lua_touserdata(L, 1));
4688 t = type(n);
4690 if (lua_type(L, 2) == LUA_TNUMBER) {
4692 int i, val;
4694 if (lua_gettop(L) == 3) {
4695 i = (int) lua_tointeger(L, 2);
4696 val = (int) lua_tointeger(L, 3);
4697 if (val == UNUSED_ATTRIBUTE) {
4698 (void) unset_attribute(n, i, val);
4699 } else {
4700 set_attribute(n, i, val);
4702 } else {
4703 luaL_error(L, "incorrect number of arguments");
4705 return 0;
4708 s = lua_tostring(L, 2);
4710 /*if (lua_key_eq(s, id)) {
4711 type(n) = (quarteword) lua_tointeger(L, 3);
4712 }* else */
4713 if (lua_key_eq(s, next)) {
4714 halfword x = nodelib_getlist(L, 3);
4715 if (x>0 && type(x) == glue_spec_node) {
4716 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
4718 vlink(n) = x;
4719 } else if (lua_key_eq(s, prev)) {
4720 halfword x = nodelib_getlist(L, 3);
4721 if (x>0 && type(x) == glue_spec_node) {
4722 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
4724 alink(n) = x;
4725 } else if (lua_key_eq(s, attr)) {
4726 if (nodetype_has_attributes(type(n))) {
4727 nodelib_setattr(L, 3, n);
4729 } else if (t == glyph_node) {
4730 if (lua_key_eq(s, subtype)) {
4731 subtype(n) = (quarterword) lua_tointeger(L, 3);
4732 } else if (lua_key_eq(s, font)) {
4733 font(n) = (halfword) lua_tointeger(L, 3);
4734 } else if (lua_key_eq(s, char)) {
4735 character(n) = (halfword) lua_tointeger(L, 3);
4736 } else if (lua_key_eq(s, xoffset)) {
4737 x_displace(n) = (halfword) lua_tointeger(L, 3);
4738 } else if (lua_key_eq(s, yoffset)) {
4739 y_displace(n) = (halfword) lua_tointeger(L, 3);
4740 } else if (lua_key_eq(s, width)) {
4741 /* not yet */
4742 } else if (lua_key_eq(s, height)) {
4743 /* not yet */
4744 } else if (lua_key_eq(s, depth)) {
4745 /* not yet */
4746 } else if (lua_key_eq(s, expansion_factor)) {
4747 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
4748 } else if (lua_key_eq(s, components)) {
4749 lig_ptr(n) = nodelib_getlist(L, 3);
4750 } else if (lua_key_eq(s, lang)) {
4751 set_char_lang(n, (halfword) lua_tointeger(L, 3));
4752 } else if (lua_key_eq(s, left)) {
4753 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
4754 } else if (lua_key_eq(s, right)) {
4755 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
4756 } else if (lua_key_eq(s, uchyph)) {
4757 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
4758 } else {
4759 return nodelib_cantset(L, n, s);
4761 } else if ((t == hlist_node) || (t == vlist_node)) {
4762 if (lua_key_eq(s, subtype)) {
4763 subtype(n) = (quarterword) lua_tointeger(L, 3);
4764 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
4765 list_ptr(n) = nodelib_getlist(L, 3);
4766 } else if (lua_key_eq(s, width)) {
4767 width(n) = (halfword) lua_tointeger(L, 3);
4768 } else if (lua_key_eq(s, height)) {
4769 height(n) = (halfword) lua_tointeger(L, 3);
4770 } else if (lua_key_eq(s, depth)) {
4771 depth(n) = (halfword) lua_tointeger(L, 3);
4772 } else if (lua_key_eq(s, dir)) {
4773 box_dir(n) = nodelib_getdir(L, 3, 1);
4774 } else if (lua_key_eq(s, shift)) {
4775 shift_amount(n) = (halfword) lua_tointeger(L, 3);
4776 } else if (lua_key_eq(s, glue_order)) {
4777 glue_order(n) = (quarterword) lua_tointeger(L, 3);
4778 } else if (lua_key_eq(s, glue_sign)) {
4779 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
4780 } else if (lua_key_eq(s, glue_set)) {
4781 glue_set(n) = (glue_ratio) lua_tonumber(L, 3);
4782 } else {
4783 return nodelib_cantset(L, n, s);
4785 } else if (t == disc_node) {
4786 if (lua_key_eq(s, subtype)) {
4787 subtype(n) = (quarterword) lua_tointeger(L, 3);
4788 } else if (lua_key_eq(s, pre)) {
4789 set_disc_field(pre_break(n), nodelib_getlist(L, 3));
4790 } else if (lua_key_eq(s, post)) {
4791 set_disc_field(post_break(n), nodelib_getlist(L, 3));
4792 } else if (lua_key_eq(s, replace)) {
4793 set_disc_field(no_break(n), nodelib_getlist(L, 3));
4794 } else {
4795 return nodelib_cantset(L, n, s);
4797 } else if (t == glue_node) {
4798 if (lua_key_eq(s, subtype)) {
4799 subtype(n) = (quarterword) lua_tointeger(L, 3);
4800 } else if (lua_key_eq(s, spec)) {
4801 glue_ptr(n) = nodelib_getspec(L, 3);
4802 } else if (lua_key_eq(s, leader)) {
4803 leader_ptr(n) = nodelib_getlist(L, 3);
4804 } else {
4805 return nodelib_cantset(L, n, s);
4807 } else if (t == glue_spec_node) {
4808 if (lua_key_eq(s, subtype)) {
4809 subtype(n) = (quarterword) lua_tointeger(L, 3); /* dummy, the only one that prevents move up */
4810 } else if (lua_key_eq(s, width)) {
4811 width(n) = (halfword) lua_tointeger(L, 3);
4812 } else if (lua_key_eq(s, stretch)) {
4813 stretch(n) = (halfword) lua_tointeger(L, 3);
4814 } else if (lua_key_eq(s, shrink)) {
4815 shrink(n) = (halfword) lua_tointeger(L, 3);
4816 } else if (lua_key_eq(s, stretch_order)) {
4817 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
4818 } else if (lua_key_eq(s, shrink_order)) {
4819 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
4820 /* } else if (lua_key_eq(s, ref_count)) {
4821 glue_ref_count(n) = (halfword) lua_tointeger(L, 3);
4822 } else if (lua_key_eq(s, writable)) {
4824 /* can't be set */
4825 } else {
4826 return nodelib_cantset(L, n, s);
4828 } else if (t == kern_node) {
4829 if (lua_key_eq(s, subtype)) {
4830 subtype(n) = (quarterword) lua_tointeger(L, 3);
4831 } else if (lua_key_eq(s, kern)) {
4832 width(n) = (halfword) lua_tointeger(L, 3);
4833 } else if (lua_key_eq(s, expansion_factor)) {
4834 ex_kern(n) = (halfword) lua_tointeger(L, 3);
4835 } else {
4836 return nodelib_cantset(L, n, s);
4838 } else if (t == penalty_node) {
4839 if (lua_key_eq(s, subtype)) {
4840 /* dummy subtype */
4841 } else if (lua_key_eq(s, penalty)) {
4842 penalty(n) = (halfword) lua_tointeger(L, 3);
4843 } else {
4844 return nodelib_cantset(L, n, s);
4846 } else if (t == rule_node) {
4847 if (lua_key_eq(s, subtype)) {
4848 subtype(n) = (quarterword) lua_tointeger(L, 3);
4849 } else if (lua_key_eq(s, width)) {
4850 width(n) = (halfword) lua_tointeger(L, 3);
4851 } else if (lua_key_eq(s, height)) {
4852 height(n) = (halfword) lua_tointeger(L, 3);
4853 } else if (lua_key_eq(s, depth)) {
4854 depth(n) = (halfword) lua_tointeger(L, 3);
4855 } else if (lua_key_eq(s, dir)) {
4856 rule_dir(n) = nodelib_getdir(L, 3, 1);
4857 } else {
4858 return nodelib_cantset(L, n, s);
4860 } else if (t == whatsit_node) {
4861 if (lua_key_eq(s, subtype)) {
4862 subtype(n) = (quarterword) lua_tointeger(L, 3);
4863 } else {
4864 lua_nodelib_setfield_whatsit(L, n, s);
4866 } else if (t == simple_noad) {
4867 if (lua_key_eq(s, subtype)) {
4868 subtype(n) = (quarterword) lua_tointeger(L, 3);
4869 } else if (lua_key_eq(s, nucleus)) {
4870 nucleus(n) = nodelib_getlist(L, 3);
4871 } else if (lua_key_eq(s, sub)) {
4872 subscr(n) = nodelib_getlist(L, 3);
4873 } else if (lua_key_eq(s, sup)) {
4874 supscr(n) = nodelib_getlist(L, 3);
4875 } else {
4876 return nodelib_cantset(L, n, s);
4878 } else if ((t == math_char_node) || (t == math_text_char_node)) {
4879 if (lua_key_eq(s, subtype)) {
4880 subtype(n) = (quarterword) lua_tointeger(L, 3);
4881 } else if (lua_key_eq(s, fam)) {
4882 math_fam(n) = (halfword) lua_tointeger(L, 3);
4883 } else if (lua_key_eq(s, char)) {
4884 math_character(n) = (halfword) lua_tointeger(L, 3);
4885 } else {
4886 return nodelib_cantset(L, n, s);
4888 } else if (t == mark_node) {
4889 if (lua_key_eq(s, subtype)) {
4890 subtype(n) = (quarterword) lua_tointeger(L, 3);
4891 } else if (lua_key_eq(s, class)) {
4892 mark_class(n) = (halfword) lua_tointeger(L, 3);
4893 } else if (lua_key_eq(s, mark)) {
4894 mark_ptr(n) = nodelib_gettoks(L, 3);
4895 } else {
4896 return nodelib_cantset(L, n, s);
4898 } else if (t == ins_node) {
4899 if (lua_key_eq(s, subtype)) {
4900 subtype(n) = (quarterword) lua_tointeger(L, 3);
4901 } else if (lua_key_eq(s, cost)) {
4902 float_cost(n) = (halfword) lua_tointeger(L, 3);
4903 } else if (lua_key_eq(s, depth)) {
4904 depth(n) = (halfword) lua_tointeger(L, 3);
4905 } else if (lua_key_eq(s, height)) {
4906 height(n) = (halfword) lua_tointeger(L, 3);
4907 } else if (lua_key_eq(s, spec)) {
4908 split_top_ptr(n) = nodelib_getspec(L, 3);
4909 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
4910 ins_ptr(n) = nodelib_getlist(L, 3);
4911 } else {
4912 return nodelib_cantset(L, n, s);
4914 } else if (t == math_node) {
4915 if (lua_key_eq(s, subtype)) {
4916 subtype(n) = (quarterword) lua_tointeger(L, 3);
4917 } else if (lua_key_eq(s, surround)) {
4918 surround(n) = (halfword) lua_tointeger(L, 3);
4919 } else {
4920 return nodelib_cantset(L, n, s);
4922 } else if (t == fraction_noad) {
4923 if (lua_key_eq(s, subtype)) {
4924 subtype(n) = (quarterword) lua_tointeger(L, 3);
4925 } else if (lua_key_eq(s, width)) {
4926 thickness(n) = (halfword) lua_tointeger(L, 3);
4927 } else if (lua_key_eq(s, num)) {
4928 numerator(n) = nodelib_getlist(L, 3);
4929 } else if (lua_key_eq(s, denom)) {
4930 denominator(n) = nodelib_getlist(L, 3);
4931 } else if (lua_key_eq(s, left)) {
4932 left_delimiter(n) = nodelib_getlist(L, 3);
4933 } else if (lua_key_eq(s, right)) {
4934 right_delimiter(n) = nodelib_getlist(L, 3);
4935 } else {
4936 return nodelib_cantset(L, n, s);
4938 } else if (t == style_node) {
4939 if (lua_key_eq(s, subtype)) {
4940 /* dummy subtype */
4941 } else if (lua_key_eq(s, style)) {
4942 assign_math_style(L,3,subtype(n));
4943 //subtype(n) = (quarterword) luaL_checkoption(L, 3, "text", math_style_names); /* not 2? */
4944 } else {
4945 /* return nodelib_cantset(L, n, s); */
4947 } else if (t == accent_noad) {
4948 if (lua_key_eq(s, subtype)) {
4949 subtype(n) = (quarterword) lua_tointeger(L, 3);
4950 } else if (lua_key_eq(s, nucleus)) {
4951 nucleus(n) = nodelib_getlist(L, 3);
4952 } else if (lua_key_eq(s, sub)) {
4953 subscr(n) = nodelib_getlist(L, 3);
4954 } else if (lua_key_eq(s, sup)) {
4955 supscr(n) = nodelib_getlist(L, 3);
4956 } else if (lua_key_eq(s, accent)) {
4957 accent_chr(n) = nodelib_getlist(L, 3);
4958 } else if (lua_key_eq(s, bot_accent)) {
4959 bot_accent_chr(n) = nodelib_getlist(L, 3);
4960 } else {
4961 return nodelib_cantset(L, n, s);
4963 } else if (t == fence_noad) {
4964 if (lua_key_eq(s, subtype)) {
4965 subtype(n) = (quarterword) lua_tointeger(L, 3);
4966 } else if (lua_key_eq(s, delim)) {
4967 delimiter(n) = nodelib_getlist(L, 3);
4968 } else {
4969 return nodelib_cantset(L, n, s);
4971 } else if (t == delim_node) {
4972 if (lua_key_eq(s, subtype)) {
4973 subtype(n) = (quarterword) lua_tointeger(L, 3);
4974 } else if (lua_key_eq(s, small_fam)) {
4975 small_fam(n) = (halfword) lua_tointeger(L, 3);
4976 } else if (lua_key_eq(s, small_char)) {
4977 small_char(n) = (halfword) lua_tointeger(L, 3);
4978 } else if (lua_key_eq(s, large_fam)) {
4979 large_fam(n) = (halfword) lua_tointeger(L, 3);
4980 } else if (lua_key_eq(s, large_char)) {
4981 large_char(n) = (halfword) lua_tointeger(L, 3);
4982 } else {
4983 return nodelib_cantset(L, n, s);
4985 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
4986 if (lua_key_eq(s, subtype)) {
4987 subtype(n) = (quarterword) lua_tointeger(L, 3);
4988 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
4989 math_list(n) = nodelib_getlist(L, 3);
4990 } else {
4991 return nodelib_cantset(L, n, s);
4993 } else if (t == radical_noad) {
4994 if (lua_key_eq(s, subtype)) {
4995 subtype(n) = (quarterword) lua_tointeger(L, 3);
4996 } else if (lua_key_eq(s, nucleus)) {
4997 nucleus(n) = nodelib_getlist(L, 3);
4998 } else if (lua_key_eq(s, sub)) {
4999 subscr(n) = nodelib_getlist(L, 3);
5000 } else if (lua_key_eq(s, sup)) {
5001 supscr(n) = nodelib_getlist(L, 3);
5002 } else if (lua_key_eq(s, left)) {
5003 left_delimiter(n) = nodelib_getlist(L, 3);
5004 } else if (lua_key_eq(s, degree)) {
5005 degree(n) = nodelib_getlist(L, 3);
5006 } else {
5007 return nodelib_cantset(L, n, s);
5009 } else if (t == margin_kern_node) {
5010 if (lua_key_eq(s, subtype)) {
5011 subtype(n) = (quarterword) lua_tointeger(L, 3);
5012 } else if (lua_key_eq(s, width)) {
5013 width(n) = (halfword) lua_tointeger(L, 3);
5014 } else if (lua_key_eq(s, glyph)) {
5015 margin_char(n) = nodelib_getlist(L, 3);
5016 } else {
5017 return nodelib_cantset(L, n, s);
5019 } else if (t == split_up_node) {
5020 if (lua_key_eq(s, subtype)) {
5021 subtype(n) = (quarterword) lua_tointeger(L, 3);
5022 } else if (lua_key_eq(s, last_ins_ptr)) {
5023 last_ins_ptr(n) = nodelib_getlist(L, 3);
5024 } else if (lua_key_eq(s, best_ins_ptr)) {
5025 best_ins_ptr(n) = nodelib_getlist(L, 3);
5026 } else if (lua_key_eq(s, broken_ptr)) {
5027 broken_ptr(n) = nodelib_getlist(L, 3);
5028 } else if (lua_key_eq(s, broken_ins)) {
5029 broken_ins(n) = nodelib_getlist(L, 3);
5030 } else {
5031 return nodelib_cantset(L, n, s);
5033 } else if (t == choice_node) {
5034 if (lua_key_eq(s, subtype)) {
5035 subtype(n) = (quarterword) lua_tointeger(L, 3);
5036 } else if (lua_key_eq(s, display)) {
5037 display_mlist(n) = nodelib_getlist(L, 3);
5038 } else if (lua_key_eq(s, text)) {
5039 text_mlist(n) = nodelib_getlist(L, 3);
5040 } else if (lua_key_eq(s, script)) {
5041 script_mlist(n) = nodelib_getlist(L, 3);
5042 } else if (lua_key_eq(s, scriptscript)) {
5043 script_script_mlist(n) = nodelib_getlist(L, 3);
5044 } else {
5045 return nodelib_cantset(L, n, s);
5047 } else if (t == inserting_node) {
5048 if (lua_key_eq(s, subtype)) {
5049 subtype(n) = (quarterword) lua_tointeger(L, 3);
5050 } else if (lua_key_eq(s, last_ins_ptr)) {
5051 last_ins_ptr(n) = nodelib_getlist(L, 3);
5052 } else if (lua_key_eq(s, best_ins_ptr)) {
5053 best_ins_ptr(n) = nodelib_getlist(L, 3);
5054 } else {
5055 return nodelib_cantset(L, n, s);
5057 } else if (t == attribute_node) {
5058 if (lua_key_eq(s, subtype)) {
5059 /* dummy subtype */
5060 } else if (lua_key_eq(s, number)) {
5061 attribute_id(n) = (halfword) lua_tointeger(L, 3);
5062 } else if (lua_key_eq(s, value)) {
5063 attribute_value(n) = (halfword) lua_tointeger(L, 3);
5064 } else {
5065 return nodelib_cantset(L, n, s);
5067 } else if (t == adjust_node) {
5068 if (lua_key_eq(s, subtype)) {
5069 subtype(n) = (quarterword) lua_tointeger(L, 3);
5070 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5071 adjust_ptr(n) = nodelib_getlist(L, 3);
5072 } else {
5073 return nodelib_cantset(L, n, s);
5075 } else if (t == action_node) {
5076 if (lua_key_eq(s, subtype)) {
5077 /* dummy subtype */
5078 } else if (lua_key_eq(s, action_type)) {
5079 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
5080 } else if (lua_key_eq(s, named_id)) {
5081 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
5082 } else if (lua_key_eq(s, action_id)) {
5083 if (pdf_action_named_id(n) == 1) {
5084 pdf_action_id(n) = nodelib_gettoks(L, 3);
5085 } else {
5086 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
5088 } else if (lua_key_eq(s, file)) {
5089 pdf_action_file(n) = nodelib_gettoks(L, 3);
5090 } else if (lua_key_eq(s, new_window)) {
5091 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
5092 } else if (lua_key_eq(s, data)) {
5093 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
5094 /* } else if (lua_key_eq(s, ref_count)) {
5095 pdf_action_refcount(n) = (halfword) lua_tointeger(L, 3); */
5096 } else {
5097 return nodelib_cantset(L, n, s);
5099 } else if (t == unset_node) {
5100 if (lua_key_eq(s, subtype)) {
5101 /* dummy subtype */
5102 } else if (lua_key_eq(s, width)) {
5103 width(n) = (halfword) lua_tointeger(L, 3);
5104 } else if (lua_key_eq(s, height)) {
5105 height(n) = (halfword) lua_tointeger(L, 3);
5106 } else if (lua_key_eq(s, depth)) {
5107 depth(n) = (halfword) lua_tointeger(L, 3);
5108 } else if (lua_key_eq(s, dir)) {
5109 box_dir(n) = nodelib_getdir(L, 3, 1);
5110 } else if (lua_key_eq(s, shrink)) {
5111 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
5112 } else if (lua_key_eq(s, glue_order)) {
5113 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5114 } else if (lua_key_eq(s, glue_sign)) {
5115 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5116 } else if (lua_key_eq(s, stretch)) {
5117 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
5118 } else if (lua_key_eq(s, count)) {
5119 span_count(n) = (quarterword) lua_tointeger(L, 3);
5120 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5121 list_ptr(n) = nodelib_getlist(L, 3);
5122 } else {
5123 return nodelib_cantset(L, n, s);
5125 } else if (t == attribute_list_node) {
5126 if (lua_key_eq(s, subtype)) {
5127 /* dummy subtype */
5128 } else {
5129 return nodelib_cantset(L, n, s);
5131 } else {
5132 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
5134 return 0;
5137 static int lua_nodelib_setfield(lua_State * L)
5139 /* [given-node] [...]*/
5140 halfword *p = lua_touserdata(L, 1);
5141 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
5142 return 0;
5144 /* [given-node] [mt-given-node]*/
5145 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
5146 lua_gettable(L, LUA_REGISTRYINDEX);
5147 /* [given-node] [mt-given-node] [mt-node]*/
5148 if ( (!lua_rawequal(L, -1, -2)) ) {
5149 return 0;
5151 /* prune stack and call getfield */
5152 lua_settop(L,3);
5153 return lua_nodelib_fast_setfield(L);
5156 /* node.direct.setfield */
5158 static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char *s)
5160 int t ;
5161 t = subtype(n);
5163 if (t == dir_node) {
5164 if (lua_key_eq(s, dir)) {
5165 dir_dir(n) = nodelib_getdir(L, 3, 0);
5166 } else if (lua_key_eq(s, level)) {
5167 dir_level(n) = (halfword) lua_tointeger(L, 3);
5168 } else if (lua_key_eq(s, dvi_ptr)) {
5169 dir_dvi_ptr(n) = (halfword) lua_tointeger(L, 3);
5170 } else if (lua_key_eq(s, dir_h)) {
5171 dir_dvi_h(n) = (halfword) lua_tointeger(L, 3);
5172 } else {
5173 return nodelib_cantset(L, n, s);
5175 } else if (t == pdf_literal_node) {
5176 if (lua_key_eq(s, mode)) {
5177 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
5178 } else if (lua_key_eq(s, data)) {
5179 if (ini_version) {
5180 pdf_literal_data(n) = nodelib_gettoks(L, 3);
5181 } else {
5182 lua_pushvalue(L, 3);
5183 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5184 pdf_literal_type(n) = lua_refid_literal;
5186 } else {
5187 return nodelib_cantset(L, n, s);
5189 } else if (t == late_lua_node) {
5190 if (lua_key_eq(s, string)) {
5191 cleanup_late_lua(n) ; /* ls-hh */
5192 if (ini_version) {
5193 late_lua_data(n) = nodelib_gettoks(L, 3);
5194 late_lua_type(n) = normal;
5195 } else {
5196 lua_pushvalue(L, 3);
5197 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5198 late_lua_type(n) = lua_refid_literal;
5200 } else if (lua_key_eq(s, data)) {
5201 cleanup_late_lua(n) ; /* ls-hh */
5202 late_lua_data(n) = nodelib_gettoks(L, 3);
5203 late_lua_type(n) = normal;
5204 } else if (lua_key_eq(s, name)) {
5205 cleanup_late_lua_name(n) ; /* ls-hh */
5206 late_lua_name(n) = nodelib_gettoks(L, 3);
5207 } else {
5208 return nodelib_cantset(L, n, s);
5210 } else if (t == user_defined_node) {
5211 if (lua_key_eq(s, user_id)) {
5212 user_node_id(n) = (halfword) lua_tointeger(L, 3);
5213 } else if (lua_key_eq(s, type)) {
5214 user_node_type(n) = (halfword) lua_tointeger(L, 3);
5215 } else if (lua_key_eq(s, value)) {
5216 switch (user_node_type(n)) {
5217 case 'a':
5218 user_node_value(n) = nodelib_getlist(L, 3);
5219 break;
5220 case 'd':
5221 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5222 break;
5223 case 'l':
5224 lua_pushvalue(L, 3);
5225 if (user_node_value(n) != 0) {
5226 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
5228 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5229 break;
5230 case 'n':
5231 user_node_value(n) = nodelib_getlist(L, 3);
5232 break;
5233 case 's':
5234 user_node_value(n) = nodelib_getstring(L, 3);
5235 break;
5236 case 't':
5237 user_node_value(n) = nodelib_gettoks(L, 3);
5238 break;
5239 default:
5240 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5241 break;
5243 } else {
5244 return nodelib_cantset(L, n, s);
5246 } else if (t == pdf_annot_node) {
5247 if (lua_key_eq(s, width)) {
5248 width(n) = (halfword) lua_tointeger(L, 3);
5249 } else if (lua_key_eq(s, depth)) {
5250 depth(n) = (halfword) lua_tointeger(L, 3);
5251 } else if (lua_key_eq(s, height)) {
5252 height(n) = (halfword) lua_tointeger(L, 3);
5253 } else if (lua_key_eq(s, objnum)) {
5254 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
5255 } else if (lua_key_eq(s, data)) {
5256 pdf_annot_data(n) = nodelib_gettoks(L, 3);
5257 } else {
5258 return nodelib_cantset(L, n, s);
5260 } else if (t == pdf_dest_node) {
5261 if (lua_key_eq(s, width)) {
5262 width(n) = (halfword) lua_tointeger(L, 3);
5263 } else if (lua_key_eq(s, depth)) {
5264 depth(n) = (halfword) lua_tointeger(L, 3);
5265 } else if (lua_key_eq(s, height)) {
5266 height(n) = (halfword) lua_tointeger(L, 3);
5267 } else if (lua_key_eq(s, named_id)) {
5268 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
5269 } else if (lua_key_eq(s, dest_id)) {
5270 if (pdf_dest_named_id(n) == 1) {
5271 pdf_dest_id(n) = nodelib_gettoks(L, 3);
5272 } else {
5273 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
5275 } else if (lua_key_eq(s, dest_type)) {
5276 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
5277 } else if (lua_key_eq(s, xyz_zoom)) {
5278 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
5279 } else if (lua_key_eq(s, objnum)) {
5280 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
5281 } else {
5282 return nodelib_cantset(L, n, s);
5284 } else if (t == pdf_setmatrix_node) {
5285 if (lua_key_eq(s, data)) {
5286 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
5287 } else {
5288 return nodelib_cantset(L, n, s);
5290 } else if (t == pdf_refobj_node) {
5291 if (lua_key_eq(s, objnum)) {
5292 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
5293 } else {
5294 return nodelib_cantset(L, n, s);
5296 } else if (t == pdf_refxform_node) {
5297 if (lua_key_eq(s, width)) {
5298 width(n) = (halfword) lua_tointeger(L, 3);
5299 } else if (lua_key_eq(s, depth)) {
5300 depth(n) = (halfword) lua_tointeger(L, 3);
5301 } else if (lua_key_eq(s, height)) {
5302 height(n) = (halfword) lua_tointeger(L, 3);
5303 } else if (lua_key_eq(s, objnum)) {
5304 pdf_xform_objnum(n) = (halfword) lua_tointeger(L, 3);
5305 } else {
5306 return nodelib_cantset(L, n, s);
5308 } else if (t == pdf_refximage_node) {
5309 if (lua_key_eq(s, width)) {
5310 width(n) = (halfword) lua_tointeger(L, 3);
5311 } else if (lua_key_eq(s, depth)) {
5312 depth(n) = (halfword) lua_tointeger(L, 3);
5313 } else if (lua_key_eq(s, height)) {
5314 height(n) = (halfword) lua_tointeger(L, 3);
5315 } else if (lua_key_eq(s, transform)) {
5316 pdf_ximage_transform(n) = (halfword) lua_tointeger(L, 3);
5317 } else if (lua_key_eq(s, index)) {
5318 pdf_ximage_index(n) = (halfword) lua_tointeger(L, 3);
5319 } else {
5320 return nodelib_cantset(L, n, s);
5322 } else if (t == local_par_node) {
5323 if (lua_key_eq(s, pen_inter)) {
5324 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
5325 } else if (lua_key_eq(s, pen_broken)) {
5326 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
5327 } else if (lua_key_eq(s, dir)) {
5328 local_par_dir(n) = nodelib_getdir(L, 3, 1);
5329 } else if (lua_key_eq(s, box_left)) {
5330 local_box_left(n) = nodelib_getlist(L, 3);
5331 } else if (lua_key_eq(s, box_left_width)) {
5332 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
5333 } else if (lua_key_eq(s, box_right)) {
5334 local_box_right(n) = nodelib_getlist(L, 3);
5335 } else if (lua_key_eq(s, box_right_width)) {
5336 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
5337 } else {
5338 return nodelib_cantset(L, n, s);
5340 } else if (t == pdf_start_link_node) {
5341 if (lua_key_eq(s, width)) {
5342 width(n) = (halfword) lua_tointeger(L, 3);
5343 } else if (lua_key_eq(s, depth)) {
5344 depth(n) = (halfword) lua_tointeger(L, 3);
5345 } else if (lua_key_eq(s, height)) {
5346 height(n) = (halfword) lua_tointeger(L, 3);
5347 } else if (lua_key_eq(s, objnum)) {
5348 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
5349 } else if (lua_key_eq(s, link_attr)) {
5350 pdf_link_attr(n) = nodelib_gettoks(L, 3);
5351 } else if (lua_key_eq(s, action)) {
5352 pdf_link_action(n) = nodelib_popdirect(n); /*nodelib_getaction(L, 3);*/
5353 } else {
5354 return nodelib_cantset(L, n, s);
5356 } else if (t == write_node) {
5357 if (lua_key_eq(s, stream)) {
5358 write_stream(n) = (halfword) lua_tointeger(L, 3);
5359 } else if (lua_key_eq(s, data)) {
5360 write_tokens(n) = nodelib_gettoks(L, 3);
5361 } else {
5362 return nodelib_cantset(L, n, s);
5364 } else if (t == pdf_colorstack_node) {
5365 if (lua_key_eq(s, stack)) {
5366 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
5367 } else if (lua_key_eq(s, command)) {
5368 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
5369 } else if (lua_key_eq(s, data)) {
5370 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
5371 } else {
5372 return nodelib_cantset(L, n, s);
5374 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
5375 if (lua_key_eq(s, width)) {
5376 width(n) = (halfword) lua_tointeger(L, 3);
5377 } else if (lua_key_eq(s, depth)) {
5378 depth(n) = (halfword) lua_tointeger(L, 3);
5379 } else if (lua_key_eq(s, height)) {
5380 height(n) = (halfword) lua_tointeger(L, 3);
5381 } else if (lua_key_eq(s, named_id)) {
5382 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
5383 } else if (lua_key_eq(s, thread_id)) {
5384 if (pdf_thread_named_id(n) == 1) {
5385 pdf_thread_id(n) = nodelib_gettoks(L, 3);
5386 } else {
5387 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
5389 } else if (lua_key_eq(s, thread_attr)) {
5390 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
5391 } else {
5392 return nodelib_cantset(L, n, s);
5394 } else if (t == special_node) {
5395 if (lua_key_eq(s, data)) {
5396 write_tokens(n) = nodelib_gettoks(L, 3);
5397 } else {
5398 return nodelib_cantset(L, n, s);
5400 } else if (t == open_node) {
5401 if (lua_key_eq(s, stream)) {
5402 write_stream(n) = (halfword) lua_tointeger(L, 3);
5403 } else if (lua_key_eq(s, name)) {
5404 open_name(n) = nodelib_getstring(L, 3);
5405 } else if (lua_key_eq(s, area)) {
5406 open_area(n) = nodelib_getstring(L, 3);
5407 } else if (lua_key_eq(s, ext)) {
5408 open_ext(n) = nodelib_getstring(L, 3);
5409 } else {
5410 return nodelib_cantset(L, n, s);
5412 } else if (t == close_node) {
5413 if (lua_key_eq(s, stream)) {
5414 write_stream(n) = (halfword) lua_tointeger(L, 3);
5415 } else {
5416 return nodelib_cantset(L, n, s);
5418 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == pdf_save_pos_node) ||
5419 (t == pdf_save_node) || (t == pdf_restore_node) || (t == cancel_boundary_node)) {
5420 return nodelib_cantset(L, n, s);
5421 } else {
5422 /* do nothing */
5424 return 0;
5427 static int lua_nodelib_direct_setfield(lua_State * L)
5429 halfword n;
5430 const char *s;
5431 int t ;
5433 n = (halfword ) lua_tonumber(L, 1);
5434 t = type(n);
5436 if (lua_type(L, 2) == LUA_TNUMBER) {
5438 int i, val;
5440 if (lua_gettop(L) == 3) {
5441 i = (int) lua_tointeger(L, 2);
5442 val = (int) lua_tointeger(L, 3);
5443 if (val == UNUSED_ATTRIBUTE) {
5444 (void) unset_attribute(n, i, val);
5445 } else {
5446 set_attribute(n, i, val);
5448 } else {
5449 luaL_error(L, "incorrect number of arguments");
5451 return 0;
5454 s = lua_tostring(L, 2);
5456 /*if (lua_key_eq(s, id)) {
5457 type(n) = (quarteword) lua_tointeger(L, 3);
5458 } else*/
5459 if (lua_key_eq(s, next)) {
5460 halfword x = nodelib_popdirect(3);
5461 if (x>0 && type(x) == glue_spec_node) {
5462 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
5464 vlink(n) = x;
5465 } else if (lua_key_eq(s, prev)) {
5466 halfword x = nodelib_popdirect(3);
5467 if (x>0 && type(x) == glue_spec_node) {
5468 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
5470 alink(n) = x;
5471 } else if (lua_key_eq(s, attr)) {
5472 if (nodetype_has_attributes(type(n))) {
5473 nodelib_setattr(L, 3, n);
5475 } else if (t == glyph_node) {
5476 if (lua_key_eq(s, subtype)) {
5477 subtype(n) = (quarterword) lua_tointeger(L, 3);
5478 } else if (lua_key_eq(s, font)) {
5479 font(n) = (halfword) lua_tointeger(L, 3);
5480 } else if (lua_key_eq(s, char)) {
5481 character(n) = (halfword) lua_tointeger(L, 3);
5482 } else if (lua_key_eq(s, xoffset)) {
5483 x_displace(n) = (halfword) lua_tointeger(L, 3);
5484 } else if (lua_key_eq(s, yoffset)) {
5485 y_displace(n) = (halfword) lua_tointeger(L, 3);
5486 } else if (lua_key_eq(s, width)) {
5487 /* not yet */
5488 } else if (lua_key_eq(s, height)) {
5489 /* not yet */
5490 } else if (lua_key_eq(s, depth)) {
5491 /* not yet */
5492 } else if (lua_key_eq(s, expansion_factor)) {
5493 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
5494 } else if (lua_key_eq(s, components)) {
5495 lig_ptr(n) = nodelib_popdirect(3);
5496 } else if (lua_key_eq(s, lang)) {
5497 set_char_lang(n, (halfword) lua_tointeger(L, 3));
5498 } else if (lua_key_eq(s, left)) {
5499 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
5500 } else if (lua_key_eq(s, right)) {
5501 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
5502 } else if (lua_key_eq(s, uchyph)) {
5503 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
5504 } else {
5505 return nodelib_cantset(L, n, s);
5507 } else if ((t == hlist_node) || (t == vlist_node)) {
5508 if (lua_key_eq(s, subtype)) {
5509 subtype(n) = (quarterword) lua_tointeger(L, 3);
5510 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
5511 list_ptr(n) = nodelib_popdirect(3);
5512 } else if (lua_key_eq(s, width)) {
5513 width(n) = (halfword) lua_tointeger(L, 3);
5514 } else if (lua_key_eq(s, height)) {
5515 height(n) = (halfword) lua_tointeger(L, 3);
5516 } else if (lua_key_eq(s, depth)) {
5517 depth(n) = (halfword) lua_tointeger(L, 3);
5518 } else if (lua_key_eq(s, dir)) {
5519 box_dir(n) = nodelib_getdir(L, 3, 1);
5520 } else if (lua_key_eq(s, shift)) {
5521 shift_amount(n) = (halfword) lua_tointeger(L, 3);
5522 } else if (lua_key_eq(s, glue_order)) {
5523 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5524 } else if (lua_key_eq(s, glue_sign)) {
5525 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5526 } else if (lua_key_eq(s, glue_set)) {
5527 glue_set(n) = (glue_ratio) lua_tonumber(L, 3);
5528 } else {
5529 return nodelib_cantset(L, n, s);
5531 } else if (t == disc_node) {
5532 if (lua_key_eq(s, subtype)) {
5533 subtype(n) = (quarterword) lua_tointeger(L, 3);
5534 } else if (lua_key_eq(s, pre)) {
5535 set_disc_field(pre_break(n), nodelib_popdirect(3));
5536 } else if (lua_key_eq(s, post)) {
5537 set_disc_field(post_break(n), nodelib_popdirect(3));
5538 } else if (lua_key_eq(s, replace)) {
5539 set_disc_field(no_break(n), nodelib_popdirect(3));
5540 } else {
5541 return nodelib_cantset(L, n, s);
5543 } else if (t == glue_node) {
5544 if (lua_key_eq(s, subtype)) {
5545 subtype(n) = (quarterword) lua_tointeger(L, 3);
5546 } else if (lua_key_eq(s, spec)) {
5547 glue_ptr(n) = nodelib_popdirect(3);
5548 } else if (lua_key_eq(s, leader)) {
5549 leader_ptr(n) = nodelib_popdirect(3);
5550 } else {
5551 return nodelib_cantset(L, n, s);
5553 } else if (t == glue_spec_node) {
5554 if (lua_key_eq(s, subtype)) {
5555 subtype(n) = (quarterword) lua_tointeger(L, 3); /* dummy, the only one that prevents move up */
5556 } else if (lua_key_eq(s, width)) {
5557 width(n) = (halfword) lua_tointeger(L, 3);
5558 } else if (lua_key_eq(s, stretch)) {
5559 stretch(n) = (halfword) lua_tointeger(L, 3);
5560 } else if (lua_key_eq(s, shrink)) {
5561 shrink(n) = (halfword) lua_tointeger(L, 3);
5562 } else if (lua_key_eq(s, stretch_order)) {
5563 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5564 } else if (lua_key_eq(s, shrink_order)) {
5565 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5566 /* } else if (lua_key_eq(s, ref_count)) {
5567 glue_ref_count(n) = (halfword) lua_tointeger(L, 3);
5568 } else if (lua_key_eq(s, writable)) {
5570 } else {
5571 return nodelib_cantset(L, n, s);
5573 } else if (t == kern_node) {
5574 if (lua_key_eq(s, subtype)) {
5575 subtype(n) = (quarterword) lua_tointeger(L, 3);
5576 } else if (lua_key_eq(s, kern)) {
5577 width(n) = (halfword) lua_tointeger(L, 3);
5578 } else if (lua_key_eq(s, expansion_factor)) {
5579 ex_kern(n) = (halfword) lua_tointeger(L, 3);
5580 } else {
5581 return nodelib_cantset(L, n, s);
5583 } else if (t == penalty_node) {
5584 if (lua_key_eq(s, subtype)) {
5585 /* dummy subtype */
5586 } else if (lua_key_eq(s, penalty)) {
5587 penalty(n) = (halfword) lua_tointeger(L, 3);
5588 } else {
5589 return nodelib_cantset(L, n, s);
5591 } else if (t == rule_node) {
5592 if (lua_key_eq(s, subtype)) {
5593 subtype(n) = (quarterword) lua_tointeger(L, 3);
5594 } else if (lua_key_eq(s, width)) {
5595 width(n) = (halfword) lua_tointeger(L, 3);
5596 } else if (lua_key_eq(s, height)) {
5597 height(n) = (halfword) lua_tointeger(L, 3);
5598 } else if (lua_key_eq(s, depth)) {
5599 depth(n) = (halfword) lua_tointeger(L, 3);
5600 } else if (lua_key_eq(s, dir)) {
5601 rule_dir(n) = nodelib_getdir(L, 3, 1);
5602 } else {
5603 return nodelib_cantset(L, n, s);
5605 } else if (t == whatsit_node) {
5606 if (lua_key_eq(s, subtype)) {
5607 subtype(n) = (quarterword) lua_tointeger(L, 3);
5608 } else {
5609 lua_nodelib_direct_setfield_whatsit(L, n, s);
5611 } else if (t == simple_noad) {
5612 if (lua_key_eq(s, subtype)) {
5613 subtype(n) = (quarterword) lua_tointeger(L, 3);
5614 } else if (lua_key_eq(s, nucleus)) {
5615 nucleus(n) = nodelib_popdirect(3);
5616 } else if (lua_key_eq(s, sub)) {
5617 subscr(n) = nodelib_popdirect(3);
5618 } else if (lua_key_eq(s, sup)) {
5619 supscr(n) = nodelib_popdirect(3);
5620 } else {
5621 return nodelib_cantset(L, n, s);
5623 } else if ((t == math_char_node) || (t == math_text_char_node)) {
5624 if (lua_key_eq(s, subtype)) {
5625 subtype(n) = (quarterword) lua_tointeger(L, 3);
5626 } else if (lua_key_eq(s, fam)) {
5627 math_fam(n) = (halfword) lua_tointeger(L, 3);
5628 } else if (lua_key_eq(s, char)) {
5629 math_character(n) = (halfword) lua_tointeger(L, 3);
5630 } else {
5631 return nodelib_cantset(L, n, s);
5633 } else if (t == mark_node) {
5634 if (lua_key_eq(s, subtype)) {
5635 subtype(n) = (quarterword) lua_tointeger(L, 3);
5636 } else if (lua_key_eq(s, class)) {
5637 mark_class(n) = (halfword) lua_tointeger(L, 3);
5638 } else if (lua_key_eq(s, mark)) {
5639 mark_ptr(n) = nodelib_gettoks(L, 3);
5640 } else {
5641 return nodelib_cantset(L, n, s);
5643 } else if (t == ins_node) {
5644 if (lua_key_eq(s, subtype)) {
5645 subtype(n) = (quarterword) lua_tointeger(L, 3);
5646 } else if (lua_key_eq(s, cost)) {
5647 float_cost(n) = (halfword) lua_tointeger(L, 3);
5648 } else if (lua_key_eq(s, depth)) {
5649 depth(n) = (halfword) lua_tointeger(L, 3);
5650 } else if (lua_key_eq(s, height)) {
5651 height(n) = (halfword) lua_tointeger(L, 3);
5652 } else if (lua_key_eq(s, spec)) {
5653 split_top_ptr(n) = nodelib_popdirect(3);
5654 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5655 ins_ptr(n) = nodelib_popdirect(3);
5656 } else {
5657 return nodelib_cantset(L, n, s);
5659 } else if (t == math_node) {
5660 if (lua_key_eq(s, subtype)) {
5661 subtype(n) = (quarterword) lua_tointeger(L, 3);
5662 } else if (lua_key_eq(s, surround)) {
5663 surround(n) = (halfword) lua_tointeger(L, 3);
5664 } else {
5665 return nodelib_cantset(L, n, s);
5667 } else if (t == fraction_noad) {
5668 if (lua_key_eq(s, subtype)) {
5669 subtype(n) = (quarterword) lua_tointeger(L, 3);
5670 } else if (lua_key_eq(s, width)) {
5671 thickness(n) = (halfword) lua_tointeger(L, 3);
5672 } else if (lua_key_eq(s, num)) {
5673 numerator(n) = nodelib_popdirect(3);
5674 } else if (lua_key_eq(s, denom)) {
5675 denominator(n) = nodelib_popdirect(3);
5676 } else if (lua_key_eq(s, left)) {
5677 left_delimiter(n) = nodelib_popdirect(3);
5678 } else if (lua_key_eq(s, right)) {
5679 right_delimiter(n) = nodelib_popdirect(3);
5680 } else {
5681 return nodelib_cantset(L, n, s);
5683 } else if (t == style_node) {
5684 if (lua_key_eq(s, subtype)) {
5685 /* dummy subtype */
5686 } else if (lua_key_eq(s, style)) {
5687 assign_math_style(L,2,subtype(n));
5688 //subtype(n) = (quarterword) luaL_checkoption(L, 2, "text", math_style_names); /* was 3 */
5689 } else {
5690 /* return nodelib_cantset(L, n, s); */
5692 } else if (t == accent_noad) {
5693 if (lua_key_eq(s, subtype)) {
5694 subtype(n) = (quarterword) lua_tointeger(L, 3);
5695 } else if (lua_key_eq(s, nucleus)) {
5696 nucleus(n) = nodelib_popdirect(3);
5697 } else if (lua_key_eq(s, sub)) {
5698 subscr(n) = nodelib_popdirect(3);
5699 } else if (lua_key_eq(s, sup)) {
5700 supscr(n) = nodelib_popdirect(3);
5701 } else if (lua_key_eq(s, accent)) {
5702 accent_chr(n) = nodelib_popdirect(3);
5703 } else if (lua_key_eq(s, bot_accent)) {
5704 bot_accent_chr(n) = nodelib_popdirect(3);
5705 } else {
5706 return nodelib_cantset(L, n, s);
5708 } else if (t == fence_noad) {
5709 if (lua_key_eq(s, subtype)) {
5710 subtype(n) = (quarterword) lua_tointeger(L, 3);
5711 } else if (lua_key_eq(s, delim)) {
5712 delimiter(n) = nodelib_popdirect(3);
5713 } else {
5714 return nodelib_cantset(L, n, s);
5716 } else if (t == delim_node) {
5717 if (lua_key_eq(s, subtype)) {
5718 subtype(n) = (quarterword) lua_tointeger(L, 3);
5719 } else if (lua_key_eq(s, small_fam)) {
5720 small_fam(n) = (halfword) lua_tointeger(L, 3);
5721 } else if (lua_key_eq(s, small_char)) {
5722 small_char(n) = (halfword) lua_tointeger(L, 3);
5723 } else if (lua_key_eq(s, large_fam)) {
5724 large_fam(n) = (halfword) lua_tointeger(L, 3);
5725 } else if (lua_key_eq(s, large_char)) {
5726 large_char(n) = (halfword) lua_tointeger(L, 3);
5727 } else {
5728 return nodelib_cantset(L, n, s);
5730 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
5731 if (lua_key_eq(s, subtype)) {
5732 subtype(n) = (quarterword) lua_tointeger(L, 3);
5733 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5734 math_list(n) = nodelib_popdirect(3);
5735 } else {
5736 return nodelib_cantset(L, n, s);
5738 } else if (t == radical_noad) {
5739 if (lua_key_eq(s, subtype)) {
5740 subtype(n) = (quarterword) lua_tointeger(L, 3);
5741 } else if (lua_key_eq(s, nucleus)) {
5742 nucleus(n) = nodelib_popdirect(3);
5743 } else if (lua_key_eq(s, sub)) {
5744 subscr(n) = nodelib_popdirect(3);
5745 } else if (lua_key_eq(s, sup)) {
5746 supscr(n) = nodelib_popdirect(3);
5747 } else if (lua_key_eq(s, left)) {
5748 left_delimiter(n) = nodelib_popdirect(3);
5749 } else if (lua_key_eq(s, degree)) {
5750 degree(n) = nodelib_popdirect(3);
5751 } else {
5752 return nodelib_cantset(L, n, s);
5754 } else if (t == margin_kern_node) {
5755 if (lua_key_eq(s, subtype)) {
5756 subtype(n) = (quarterword) lua_tointeger(L, 3);
5757 } else if (lua_key_eq(s, width)) {
5758 width(n) = (halfword) lua_tointeger(L, 3);
5759 } else if (lua_key_eq(s, glyph)) {
5760 margin_char(n) = nodelib_popdirect(3);
5761 } else {
5762 return nodelib_cantset(L, n, s);
5764 } else if (t == split_up_node) {
5765 if (lua_key_eq(s, subtype)) {
5766 subtype(n) = (quarterword) lua_tointeger(L, 3);
5767 } else if (lua_key_eq(s, last_ins_ptr)) {
5768 last_ins_ptr(n) = nodelib_popdirect(3);
5769 } else if (lua_key_eq(s, best_ins_ptr)) {
5770 best_ins_ptr(n) = nodelib_popdirect(3);
5771 } else if (lua_key_eq(s, broken_ptr)) {
5772 broken_ptr(n) = nodelib_popdirect(3);
5773 } else if (lua_key_eq(s, broken_ins)) {
5774 broken_ins(n) = nodelib_popdirect(3);
5775 } else {
5776 return nodelib_cantset(L, n, s);
5778 } else if (t == choice_node) {
5779 if (lua_key_eq(s, subtype)) {
5780 subtype(n) = (quarterword) lua_tointeger(L, 3);
5781 } else if (lua_key_eq(s, display)) {
5782 display_mlist(n) = nodelib_popdirect(3);
5783 } else if (lua_key_eq(s, text)) {
5784 text_mlist(n) = nodelib_popdirect(3);
5785 } else if (lua_key_eq(s, script)) {
5786 script_mlist(n) = nodelib_popdirect(3);
5787 } else if (lua_key_eq(s, scriptscript)) {
5788 script_script_mlist(n) = nodelib_popdirect(3);
5789 } else {
5790 return nodelib_cantset(L, n, s);
5792 } else if (t == inserting_node) {
5793 if (lua_key_eq(s, subtype)) {
5794 subtype(n) = (quarterword) lua_tointeger(L, 3);
5795 } else if (lua_key_eq(s, last_ins_ptr)) {
5796 last_ins_ptr(n) = nodelib_popdirect(3);
5797 } else if (lua_key_eq(s, best_ins_ptr)) {
5798 best_ins_ptr(n) = nodelib_popdirect(3);
5799 } else {
5800 return nodelib_cantset(L, n, s);
5802 } else if (t == attribute_node) {
5803 if (lua_key_eq(s, subtype)) {
5804 /* dummy subtype */
5805 } else if (lua_key_eq(s, number)) {
5806 attribute_id(n) = (halfword) lua_tointeger(L, 3);
5807 } else if (lua_key_eq(s, value)) {
5808 attribute_value(n) = (halfword) lua_tointeger(L, 3);
5809 } else {
5810 return nodelib_cantset(L, n, s);
5812 } else if (t == adjust_node) {
5813 if (lua_key_eq(s, subtype)) {
5814 subtype(n) = (quarterword) lua_tointeger(L, 3);
5815 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5816 adjust_ptr(n) = nodelib_popdirect(3);
5817 } else {
5818 return nodelib_cantset(L, n, s);
5820 } else if (t == action_node) {
5821 if (lua_key_eq(s, subtype)) {
5822 /* dummy subtype */
5823 } else if (lua_key_eq(s, action_type)) {
5824 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
5825 } else if (lua_key_eq(s, named_id)) {
5826 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
5827 } else if (lua_key_eq(s, action_id)) {
5828 if (pdf_action_named_id(n) == 1) {
5829 pdf_action_id(n) = nodelib_gettoks(L, 3);
5830 } else {
5831 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
5833 } else if (lua_key_eq(s, file)) {
5834 pdf_action_file(n) = nodelib_gettoks(L, 3);
5835 } else if (lua_key_eq(s, new_window)) {
5836 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
5837 } else if (lua_key_eq(s, data)) {
5838 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
5839 /* } else if (lua_key_eq(s, ref_count)) {
5840 pdf_action_refcount(n) = (halfword) lua_tointeger(L, 3); */
5841 } else {
5842 return nodelib_cantset(L, n, s);
5844 } else if (t == unset_node) {
5845 if (lua_key_eq(s, subtype)) {
5846 /* dummy subtype */
5847 } else if (lua_key_eq(s, width)) {
5848 width(n) = (halfword) lua_tointeger(L, 3);
5849 } else if (lua_key_eq(s, height)) {
5850 height(n) = (halfword) lua_tointeger(L, 3);
5851 } else if (lua_key_eq(s, depth)) {
5852 depth(n) = (halfword) lua_tointeger(L, 3);
5853 } else if (lua_key_eq(s, dir)) {
5854 box_dir(n) = nodelib_getdir(L, 3, 1);
5855 } else if (lua_key_eq(s, shrink)) {
5856 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
5857 } else if (lua_key_eq(s, glue_order)) {
5858 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5859 } else if (lua_key_eq(s, glue_sign)) {
5860 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5861 } else if (lua_key_eq(s, stretch)) {
5862 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
5863 } else if (lua_key_eq(s, count)) {
5864 span_count(n) = (quarterword) lua_tointeger(L, 3);
5865 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5866 list_ptr(n) = nodelib_popdirect(3);
5867 } else {
5868 return nodelib_cantset(L, n, s);
5870 } else if (t == attribute_list_node) {
5871 if (lua_key_eq(s, subtype)) {
5872 /* dummy subtype */
5873 } else {
5874 return nodelib_cantset(L, n, s);
5876 } else {
5877 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
5879 return 0;
5882 /* boxes */
5884 static int direct_get_box_id(lua_State * L, int i)
5886 const char *s;
5887 int cur_cs1, cur_cmd1;
5888 size_t k = 0;
5889 int j = -1;
5890 switch (lua_type(L, i)) {
5891 case LUA_TSTRING:
5892 s = lua_tolstring(L, i, &k);
5893 cur_cs1 = string_lookup(s, k);
5894 cur_cmd1 = eq_type(cur_cs1);
5895 if (cur_cmd1 == char_given_cmd ||
5896 cur_cmd1 == math_given_cmd) {
5897 j = equiv(cur_cs1);
5899 break;
5900 case LUA_TNUMBER:
5901 j=(int)lua_tonumber(L, (i));
5902 break;
5903 default:
5904 luaL_error(L, "argument must be a string or a number");
5905 j = -1; /* not a valid box id */
5907 return j;
5910 /* node.getbox = tex.getbox */
5912 /* node.direct.getbox */
5914 static int lua_nodelib_direct_getbox(lua_State * L)
5916 int k, t;
5917 k = direct_get_box_id(L, -1);
5918 direct_check_index_range(k, "getbox");
5919 t = get_tex_box_register(k);
5920 lua_pushnumber(L, t);
5921 return 1;
5924 static int direct_vsetbox(lua_State * L, int is_global)
5926 int j, k, err;
5927 int save_global_defs = int_par(global_defs_code);
5928 if (is_global)
5929 int_par(global_defs_code) = 1;
5930 k = direct_get_box_id(L, -2);
5931 direct_check_index_range(k, "setbox");
5932 if (lua_isboolean(L, -1)) {
5933 j = lua_toboolean(L, -1);
5934 if (j == 0)
5935 j = null;
5936 else
5937 return 0;
5938 } else {
5939 j=nodelib_popdirect(-1);
5940 if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
5941 luaL_error(L, "setbox: incompatible node type (%s)\n",get_node_name(type(j), subtype(j)));
5942 return 0;
5946 err = set_tex_box_register(k, j);
5947 int_par(global_defs_code) = save_global_defs;
5948 if (err) {
5949 luaL_error(L, "incorrect value");
5951 return 0;
5954 /* node.setbox = tex.setbox */
5955 /* node.setbox */
5957 static int lua_nodelib_direct_setbox(lua_State * L)
5959 int isglobal = 0;
5960 int n = lua_gettop(L);
5961 if (n == 3 && lua_isstring(L, 1)) {
5962 const char *s = lua_tostring(L, 1);
5963 if (lua_key_eq(s, global))
5964 isglobal = 1;
5966 return direct_vsetbox(L, isglobal);
5969 /* node.is_node(n) */
5971 static int lua_nodelib_is_node(lua_State * L)
5973 if (maybe_isnode(L,1) == NULL)
5974 lua_pushboolean(L,0);
5975 else
5976 lua_pushboolean(L,1);
5977 return 1;
5980 /* node.direct.is_direct(n) (handy for mixed usage testing) */
5982 static int lua_nodelib_direct_is_direct(lua_State * L)
5983 { /*
5984 quick and dirty and faster than not node.is_node, this helper
5985 returns false or <direct>
5988 if (lua_type(L,1) == LUA_TNUMBER)
5989 lua_pushboolean(L,1);
5990 else
5991 lua_pushboolean(L,0);
5993 if (lua_type(L,1) != LUA_TNUMBER)
5994 lua_pushboolean(L,0);
5995 /* else return direct */
5996 return 1;
5999 /* node.direct.is_node(n) (handy for mixed usage testing) */
6001 static int lua_nodelib_direct_is_node(lua_State * L)
6002 { /*
6003 quick and dirty, only checks userdata, node.is_node is slower but
6004 more exact, this helper returns false or <node>
6007 halfword *n = lua_touserdata(L, 1);
6008 if (n != NULL) {
6009 lua_pushboolean(L,1);
6010 } else {
6011 lua_pushboolean(L,0);
6014 if (maybe_isnode(L,1) == NULL)
6015 lua_pushboolean(L,0);
6016 /* else assume and return node */
6017 return 1;
6020 /* node.fast.*
6022 static const struct luaL_Reg fast_nodelib_f[] = {
6023 {"getid", lua_nodelib_fast_getid},
6024 {"getsubtype", lua_nodelib_fast_getsubtype},
6025 {"getfont", lua_nodelib_fast_getfont},
6026 {"getchar", lua_nodelib_fast_getcharacter},
6027 {"getnext", lua_nodelib_fast_getnext},
6028 {"getprev", lua_nodelib_fast_getprev},
6029 {"getfield", lua_nodelib_fast_getfield},
6030 {"setfield", lua_nodelib_fast_setfield},
6031 {NULL, NULL}
6036 /* if really needed we can provide this:
6038 static int lua_nodelib_attributes_to_table(lua_State * L) // hh
6039 { // <node|direct>
6040 halfword n;
6041 register halfword attribute;
6042 if (lua_isnumber(L,1)) {
6043 n = lua_tonumber(L,1);
6044 } else {
6045 n = *((halfword *) lua_touserdata(L, 1));
6047 if ((n == null) || (! nodetype_has_attributes(type(n)))) {
6048 lua_pushnil(L);
6049 } else {
6050 attribute = node_attr(n);
6051 if (attribute == null || (attribute == cache_disabled)) {
6052 lua_pushnil(L);
6053 } else {
6054 if (! lua_istable(L,2)) {
6055 lua_newtable(L);
6057 while (attribute != null) {
6058 lua_pushnumber(L,(int)attribute_id(attribute));
6059 lua_pushnumber(L,(int)attribute_value(attribute));
6060 lua_rawset(L,-3);
6061 attribute = vlink(attribute) ;
6065 return 1 ;
6070 /* There is no gain here but let's keep it around:
6072 static int lua_nodelib_attributes_to_properties(lua_State * L)
6073 { // <node|direct>
6074 halfword n;
6075 register halfword attribute;
6076 if (lua_isnumber(L,1)) {
6077 n = lua_tonumber(L,1);
6078 } else {
6079 n = *((halfword *) lua_touserdata(L, 1));
6081 if (n == null) {
6082 lua_pushnil(L);
6083 return 1;
6085 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(node_properties));
6086 lua_gettable(L, LUA_REGISTRYINDEX);
6087 while (n != null) {
6088 lua_rawseti(L, -1, luaS_index(attributes));
6089 lua_newtable(L);
6090 if (! nodetype_has_attributes(type(n))) {
6091 lua_pushnil(L);
6092 } else {
6093 attribute = node_attr(n);
6094 if (attribute == null || (attribute == cache_disabled)) {
6095 lua_pushnil(L);
6096 } else {
6097 while (attribute != null) {
6098 lua_pushnumber(L,(int)attribute_id(attribute));
6099 lua_pushnumber(L,(int)attribute_value(attribute));
6100 lua_rawset(L,-3);
6101 attribute = vlink(attribute) ;
6105 lua_rawset(L,-3);
6106 n = vlink(n);
6108 return 1 ;
6113 /* Beware, enabling and disabling can result in an inconsistent properties table
6114 but it might make sense sometimes. Of course by default we have disabled this
6115 mechanism. And, one can always sweep the table empty. */
6117 static int lua_nodelib_properties_set_mode(lua_State * L) /* hh */
6118 { /* <boolean> */
6119 if (lua_isboolean(L,1)) {
6120 lua_properties_enabled = lua_toboolean(L,1);
6122 if (lua_isboolean(L,2)) {
6123 lua_properties_use_metatable = lua_toboolean(L,2);
6125 return 0;
6128 /* We used to have variants in assigned defaults but they made no sense. */
6130 static int lua_nodelib_properties_flush_table(lua_State * L) /* hh */
6131 { /* <node|direct> <number> */
6132 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6133 lua_gettable(L, LUA_REGISTRYINDEX);
6134 lua_pushnil(L); /* initializes lua_next */
6135 while (lua_next(L,-2) != 0) {
6136 lua_pushvalue(L,-2);
6137 lua_pushnil(L);
6138 lua_settable(L,-5);
6139 lua_pop(L,1);
6141 return 1;
6144 /* maybe we should allocate a proper index 0..var_mem_max but not now */
6146 static int lua_nodelib_get_property(lua_State * L) /* hh */
6147 { /* <node> */
6148 halfword n;
6149 n = *((halfword *) lua_touserdata(L, 1));
6150 if (n == null) {
6151 lua_pushnil(L);
6152 } else {
6153 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6154 lua_gettable(L, LUA_REGISTRYINDEX);
6155 lua_rawgeti(L,-1,n);
6157 return 1;
6160 static int lua_nodelib_direct_get_property(lua_State * L) /* hh */
6161 { /* <direct> */
6162 halfword n = lua_tonumber(L, 1);
6163 if (n == null) {
6164 lua_pushnil(L);
6165 } else {
6166 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6167 lua_gettable(L, LUA_REGISTRYINDEX);
6168 lua_rawgeti(L,-1,n);
6170 return 1;
6173 static int lua_nodelib_set_property(lua_State * L) /* hh */
6175 /* <node> <value> */
6176 halfword n;
6177 n = *((halfword *) lua_touserdata(L, 1));
6178 if (n != null) {
6179 lua_settop(L,2);
6180 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6181 lua_gettable(L, LUA_REGISTRYINDEX);
6182 /* <node> <value> <propertytable> */
6183 lua_replace(L,-3);
6184 /* <propertytable> <value> */
6185 lua_rawseti(L,-2,n);
6187 return 0;
6190 static int lua_nodelib_direct_set_property(lua_State * L) /* hh */
6192 /* <direct> <value> */
6193 halfword n = lua_tonumber(L, 1);
6194 if (n != null) { // we could store in node instead */
6195 lua_settop(L,2);
6196 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6197 lua_gettable(L, LUA_REGISTRYINDEX);
6198 /* <node> <value> <propertytable> */
6199 lua_replace(L,1);
6200 /* <propertytable> <value> */
6201 lua_rawseti(L,1,n);
6203 return 0;
6206 static int lua_nodelib_direct_properties_get_table(lua_State * L) /* hh */
6207 { /* <node|direct> */
6208 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6209 lua_gettable(L, LUA_REGISTRYINDEX);
6210 return 1;
6213 static int lua_nodelib_properties_get_table(lua_State * L) /* hh */
6214 { /* <node|direct> */
6215 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties_indirect));
6216 lua_gettable(L, LUA_REGISTRYINDEX);
6217 return 1;
6220 /* bonus */
6222 static int lua_nodelib_get_property_t(lua_State * L) /* hh */
6223 { /* <table> <node> */
6224 halfword n;
6225 n = *((halfword *) lua_touserdata(L, 2));
6226 if (n == null) {
6227 lua_pushnil(L);
6228 } else {
6229 lua_rawgeti(L,1,n);
6231 return 1;
6234 static int lua_nodelib_set_property_t(lua_State * L) /* hh */
6236 /* <table> <node> <value> */
6237 halfword n;
6238 n = *((halfword *) lua_touserdata(L, 2));
6239 if (n != null) {
6240 lua_settop(L,3);
6241 lua_rawseti(L,1,n);
6243 return 0;
6246 static const struct luaL_Reg nodelib_p[] = {
6247 {"__index", lua_nodelib_get_property_t},
6248 {"__newindex", lua_nodelib_set_property_t},
6249 {NULL, NULL} /* sentinel */
6252 static void lua_new_properties_table(lua_State * L) /* hh */
6254 lua_pushstring(L,"node.properties");
6255 lua_newtable(L);
6256 lua_settable(L,LUA_REGISTRYINDEX);
6258 lua_pushstring(L,"node.properties.indirect");
6259 lua_newtable(L);
6260 luaL_newmetatable(L,"node.properties.indirect.meta");
6261 luaL_register(L, NULL, nodelib_p);
6262 lua_setmetatable(L,-2);
6263 lua_settable(L,LUA_REGISTRYINDEX);
6266 /* end of properties experiment */
6268 /* node.direct.* */
6270 static const struct luaL_Reg direct_nodelib_f[] = {
6271 {"copy", lua_nodelib_direct_copy},
6272 {"copy_list", lua_nodelib_direct_copy_list},
6273 {"count", lua_nodelib_direct_count},
6274 {"current_attr", lua_nodelib_direct_currentattr},
6275 {"dimensions", lua_nodelib_direct_dimensions},
6276 {"do_ligature_n", lua_nodelib_direct_do_ligature_n},
6277 {"end_of_math", lua_nodelib_direct_end_of_math},
6278 /* {"family_font", lua_nodelib_mfont}, */ /* no node argument */
6279 /* {"fields", lua_nodelib_fields}, */ /* no node argument */
6280 /* {"first_character", lua_nodelib_first_character}, */ /* obsolete */
6281 {"first_glyph", lua_nodelib_direct_first_glyph},
6282 {"flush_list", lua_nodelib_direct_flush_list},
6283 {"flush_node", lua_nodelib_direct_flush_node},
6284 {"free", lua_nodelib_direct_free},
6285 {"getbox", lua_nodelib_direct_getbox},
6286 {"getchar", lua_nodelib_direct_getcharacter},
6287 {"getfield", lua_nodelib_direct_getfield},
6288 {"getfont", lua_nodelib_direct_getfont},
6289 {"getid", lua_nodelib_direct_getid},
6290 {"getnext", lua_nodelib_direct_getnext},
6291 {"getprev", lua_nodelib_direct_getprev},
6292 {"getlist", lua_nodelib_direct_getlist},
6293 {"getleader", lua_nodelib_direct_getleader},
6294 {"getsubtype", lua_nodelib_direct_getsubtype},
6295 {"has_glyph", lua_nodelib_direct_has_glyph},
6296 {"has_attribute", lua_nodelib_direct_has_attribute},
6297 {"has_field", lua_nodelib_direct_has_field},
6298 {"hpack", lua_nodelib_direct_hpack},
6299 /* {"id", lua_nodelib_id}, */ /* no node argument */
6300 {"insert_after", lua_nodelib_direct_insert_after},
6301 {"insert_before", lua_nodelib_direct_insert_before},
6302 {"is_direct", lua_nodelib_direct_is_direct},
6303 {"is_node", lua_nodelib_direct_is_node},
6304 /* {"kerning", font_tex_kerning}, */ /* maybe direct too (rather basic callback exposure) */
6305 {"last_node", lua_nodelib_direct_last_node},
6306 {"length", lua_nodelib_direct_length},
6307 /* {"ligaturing", font_tex_ligaturing}, */ /* maybe direct too (rather basic callback exposure) */
6308 /* {"mlist_to_hlist", lua_nodelib_mlist_to_hset_properties_modelist}, */ /* maybe direct too (rather basic callback exposure) */
6309 {"new", lua_nodelib_direct_new},
6310 /* {"next", lua_nodelib_next}, */ /* replaced by getnext */
6311 /* {"prev", lua_nodelib_prev}, */ /* replaced by getprev */
6312 {"tostring", lua_nodelib_direct_tostring},
6313 {"protect_glyphs", lua_nodelib_direct_protect_glyphs},
6314 {"protrusion_skippable", lua_nodelib_direct_cp_skipable},
6315 {"remove", lua_nodelib_direct_remove},
6316 {"set_attribute", lua_nodelib_direct_set_attribute},
6317 {"setbox", lua_nodelib_direct_setbox},
6318 {"setfield", lua_nodelib_direct_setfield},
6319 {"slide", lua_nodelib_direct_slide},
6320 /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
6321 {"tail", lua_nodelib_direct_tail},
6322 {"todirect", lua_nodelib_direct_todirect}, /* not in node.* */
6323 {"tonode", lua_nodelib_direct_tonode}, /* similar to node.* */
6324 {"traverse", lua_nodelib_direct_traverse},
6325 {"traverse_id", lua_nodelib_direct_traverse_filtered},
6326 /* {"type", lua_nodelib_type}, */ /* no node argument */
6327 /* {"types", lua_nodelib_types}, */ /* no node argument */
6328 {"unprotect_glyphs", lua_nodelib_direct_unprotect_glyphs},
6329 {"unset_attribute", lua_nodelib_direct_unset_attribute},
6330 {"usedlist", lua_nodelib_direct_usedlist},
6331 {"vpack", lua_nodelib_direct_vpack},
6332 /* {"whatsits", lua_nodelib_whatsits}, */ /* no node argument */
6333 {"write", lua_nodelib_direct_append},
6334 /* an experiment */
6335 /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ /* hh experiment */
6336 /* an experiment */
6337 {"set_properties_mode",lua_nodelib_properties_set_mode}, /* hh experiment */
6338 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6339 {"get_properties_table",lua_nodelib_direct_properties_get_table}, /* hh experiment */
6340 {"getproperty", lua_nodelib_direct_get_property}, /* bonus */ /* hh experiment */
6341 {"setproperty", lua_nodelib_direct_set_property}, /* bonus */ /* hh experiment */
6342 /* done */
6343 {NULL, NULL} /* sentinel */
6346 /* node.* */
6348 static const struct luaL_Reg nodelib_f[] = {
6349 {"copy", lua_nodelib_copy},
6350 {"copy_list", lua_nodelib_copy_list},
6351 {"count", lua_nodelib_count},
6352 {"current_attr", lua_nodelib_currentattr},
6353 {"dimensions", lua_nodelib_dimensions},
6354 {"do_ligature_n", lua_nodelib_do_ligature_n},
6355 {"end_of_math", lua_nodelib_end_of_math},
6356 {"family_font", lua_nodelib_mfont},
6357 {"fields", lua_nodelib_fields},
6358 {"first_character", lua_nodelib_first_character},
6359 {"first_glyph", lua_nodelib_first_glyph},
6360 {"flush_list", lua_nodelib_flush_list},
6361 {"flush_node", lua_nodelib_flush_node},
6362 {"free", lua_nodelib_free},
6363 /* {"getbox", lua_nodelib_getbox}, */ /* tex.getbox */
6364 {"getnext", lua_nodelib_getnext},
6365 {"getprev", lua_nodelib_getprev},
6366 {"getlist", lua_nodelib_getlist},
6367 {"getleader", lua_nodelib_getleader},
6368 {"getid", lua_nodelib_getid},
6369 {"getfield", lua_nodelib_getfield},
6370 {"setfield", lua_nodelib_setfield},
6371 {"getsubtype", lua_nodelib_getsubtype},
6372 {"getfont", lua_nodelib_getfont},
6373 {"getchar", lua_nodelib_getcharacter},
6374 {"has_glyph", lua_nodelib_has_glyph},
6375 {"has_attribute", lua_nodelib_has_attribute},
6376 {"has_field", lua_nodelib_has_field},
6377 {"hpack", lua_nodelib_hpack},
6378 {"id", lua_nodelib_id},
6379 {"insert_after", lua_nodelib_insert_after},
6380 {"insert_before", lua_nodelib_insert_before},
6381 {"is_node", lua_nodelib_is_node},
6382 {"kerning", font_tex_kerning},
6383 {"last_node", lua_nodelib_last_node},
6384 {"length", lua_nodelib_length},
6385 {"ligaturing", font_tex_ligaturing},
6386 {"mlist_to_hlist", lua_nodelib_mlist_to_hlist},
6387 {"new", lua_nodelib_new},
6388 {"next", lua_nodelib_next}, /* getnext is somewhat more efficient, and get* fits better in direct compatibility */
6389 {"prev", lua_nodelib_prev}, /* getprev is somewhat more efficient, and get* fits better in direct compatibility */
6390 {"tostring", lua_nodelib_tostring},
6391 {"protect_glyphs", lua_nodelib_protect_glyphs},
6392 {"protrusion_skippable", lua_nodelib_cp_skipable},
6393 {"remove", lua_nodelib_remove},
6394 /* {"setbox", lua_nodelib_setbox}, */ /* tex.setbox */
6395 {"set_attribute", lua_nodelib_set_attribute},
6396 {"slide", lua_nodelib_slide},
6397 {"subtype", lua_nodelib_subtype},
6398 {"tail", lua_nodelib_tail},
6399 {"traverse", lua_nodelib_traverse},
6400 {"traverse_id", lua_nodelib_traverse_filtered},
6401 {"type", lua_nodelib_type},
6402 {"types", lua_nodelib_types},
6403 {"unprotect_glyphs", lua_nodelib_unprotect_glyphs},
6404 {"unset_attribute", lua_nodelib_unset_attribute},
6405 {"usedlist", lua_nodelib_usedlist},
6406 {"vpack", lua_nodelib_vpack},
6407 {"whatsits", lua_nodelib_whatsits},
6408 {"write", lua_nodelib_append},
6409 /* experiment */
6410 /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ /* hh experiment */
6411 /* experiment */
6412 {"set_properties_mode",lua_nodelib_properties_set_mode}, /* hh experiment */
6413 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6414 {"get_properties_table",lua_nodelib_properties_get_table}, /* bonus */ /* hh experiment */
6415 {"getproperty", lua_nodelib_get_property}, /* hh experiment */
6416 {"setproperty", lua_nodelib_set_property}, /* hh experiment */
6417 /* done */
6418 {NULL, NULL} /* sentinel */
6421 static const struct luaL_Reg nodelib_m[] = {
6422 {"__index", lua_nodelib_fast_getfield},
6423 {"__newindex", lua_nodelib_fast_setfield},
6424 {"__tostring", lua_nodelib_tostring},
6425 {"__eq", lua_nodelib_equal},
6426 {NULL, NULL} /* sentinel */
6429 int luaopen_node(lua_State * L)
6432 lua_new_properties_table(L);
6434 /* the main metatable of node userdata */
6435 luaL_newmetatable(L, NODE_METATABLE);
6436 /* node.* */
6437 luaL_register(L, NULL, nodelib_m);
6438 luaL_register(L, "node", nodelib_f);
6439 /* node.fast (experimental code)
6440 lua_pushstring(L,"fast");
6441 lua_newtable(L);
6442 luaL_register(L, NULL, fast_nodelib_f);
6443 lua_rawset(L,-3);
6445 /* node.direct */
6446 lua_pushstring(L,"direct");
6447 lua_newtable(L);
6448 luaL_register(L, NULL, direct_nodelib_f);
6449 lua_rawset(L,-3);
6450 /* initialization of keywords */
6451 /*initialize_luaS_indexes(L);*/
6452 return 1;
6455 void nodelist_to_lua(lua_State * L, int n)
6457 lua_pushnumber(L, n);
6458 lua_nodelib_push(L);
6461 int nodelist_from_lua(lua_State * L)
6463 halfword *n;
6464 if (lua_isnil(L, -1))
6465 return null;
6466 n = check_isnode(L, -1);
6467 return (n ? *n : null);