boundary nodes made consistent (cleanup and document): WARNING: bump the format numbe...
[luatex.git] / source / texk / web2c / luatexdir / lua / lnodelib.c
blob7ff2eb7c3bde0133fe26a8fa0dae4453cbead022
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 After doing lots of tests with luatex and luajittex, with and without jit,
25 and with and without ffi, we came to the conclusion that userdata prevents
26 a speedup. We also found that the checking of metatables as well as assignment
27 comes with overhead that can't be neglected. This is normally not really a
28 problem but when processing fonts for more complex scripts it's quite some
29 overhead.
31 Because the userdata approach has some benefits, we stick to this. We did
32 some experiments with fast access (assuming nodes) and kept some of the code
33 commented here, but eventually settled for the direct approach. For code that
34 is proven to be okay, one can use the direct variants and operate on nodes
35 more directly. Currently these are numbers, but that might become light
36 userdata at one point, so *never* rely on that property. An important aspect
37 is that one cannot mix both methods, although with node.direct.tonode and
38 node.direct.todirect one can cast both representations.
40 So the advice is: use the indexed approach when possible and investigate the
41 direct one when speed might be an issue. For that reason we also provide the
42 get* and set* functions in the top level node namespace. There is a limited set
43 of getters and a generic getfield to complement them.
45 Keep in mind that these only make sense when we're calling them millions of
46 times (which happens in font processing for instance). Setters are less important
47 as documents have not that many content related nodes (and setting many thousands
48 of properties is hardly a burden contrary to millions of consultations.)
50 Another change is that __index and __newindex are (as expected) exposed to
51 users but do no checking. The getfield and setfield functions do check. In
52 fact, a fast mode can be simulated by fast_getfield = __index but the (measured)
53 benefit on average runs is not that large (some 5% when we also use the other
54 fast ones) which is easily nilled by inefficient coding. The direct variants
55 on the other hand can be significantly faster but with the drawback of lack
56 of userdata features. With respect to speed: keep in mind that measuring
57 a speedup on these functions is not representative for a normal run, where
58 much more happens.
62 #include "ptexlib.h"
63 #include "lua/luatex-api.h"
64 #ifdef LuajitTeX
65 #include "lua/lauxlib_bridge.h"
66 #else
67 #include "lauxlib.h"
68 #endif
72 These macros create and access pointers (indices) to keys which is faster. The
73 shortcuts are created as part of the initialization.
79 When the first argument to an accessor is a node, we can use it's metatable
80 entry when we are returning nodes, which saves a lookup.
84 #define fast_metatable(n) do { \
85 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
86 *a = n; \
87 lua_getmetatable(L,1); \
88 lua_setmetatable(L,-2); \
89 } while (0)
91 #define fast_metatable_or_nil(n) do { \
92 if (n) { \
93 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
94 *a = n; \
95 lua_getmetatable(L,1); \
96 lua_setmetatable(L,-2); \
97 } else { \
98 lua_pushnil(L); \
99 } \
100 } while (0)
102 #define fast_metatable_or_nil_alink(n) do { \
103 if (n) { \
104 alink(n) = null; \
105 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
106 *a = n; \
107 lua_getmetatable(L,1); \
108 lua_setmetatable(L,-2); \
109 } else { \
110 lua_pushnil(L); \
112 } while (0)
114 #define fast_metatable_top(n) do { \
115 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
116 *a = n; \
117 lua_getmetatable(L,-2); \
118 lua_setmetatable(L,-2); \
119 } while (0)
123 This is a first step towards abstract direct nodes. When we have Lua 5.3 we
124 need to check all returned values for being integers. This might be another
125 level of abtraction.
129 #define nodelib_pushdirect(n) lua_pushinteger(L,n)
130 #define nodelib_popdirect(n) lua_tointeger(L,n)
132 #define nodelib_pushdirect_or_nil(n) do { \
133 if (n==null) { \
134 lua_pushnil(L); \
135 } else { \
136 lua_pushinteger(L,n); \
138 } while (0)
140 #define nodelib_pushdirect_or_nil_alink(n) do { \
141 if (n==null) { \
142 lua_pushnil(L); \
143 } else { \
144 alink(n) = null; \
145 lua_pushinteger(L,n); \
147 } while (0)
149 #define nodelib_setattr(L, s, n) reassign_attribute(n,nodelib_getlist(L,s))
151 #define nodelib_gettoks(L,a) tokenlist_from_lua(L)
153 #define nodelib_getspec nodelib_getlist
154 #define nodelib_getaction nodelib_getlist
156 /* fetching a field from a node .. we can often use the reuse bot-of-stack metatable */
158 #define nodelib_pushlist(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
159 #define nodelib_pushattr(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
160 #define nodelib_pushaction(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
161 #define nodelib_pushstring(L,n) { char *ss=makecstring(n); lua_pushstring(L,ss); free(ss); }
163 /* find prev, and fix backlinks .. can be a macro instead (only used a few times) */
165 #define set_t_to_prev(head,current) \
166 t = head; \
167 while (vlink(t)!=current && t != null) { \
168 if (vlink(t)!=null) \
169 alink(vlink(t)) = t; \
170 t = vlink(t); \
173 #define box(A) eqtb[box_base+(A)].hh.rh
174 #define direct_check_index_range(j,s) \
175 if (j<0 || j > 65535) { \
176 luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s); \
179 #define NODE_METATABLE "luatex.node"
181 #define DEBUG 0
182 #define DEBUG_OUT stdout
184 /* maybe these qualify as macros, not functions */
186 static halfword *maybe_isnode(lua_State * L, int i)
188 halfword *p = lua_touserdata(L, i);
189 if (p != NULL) {
190 if (lua_getmetatable(L, i)) {
191 lua_get_metatablelua(luatex_node);
192 if (!lua_rawequal(L, -1, -2))
193 p = NULL;
194 lua_pop(L, 2);
197 return p;
200 /* we could make the message a function and just inline the rest (via a macro) */
202 halfword *check_isnode(lua_State * L, int i)
204 halfword *p = maybe_isnode(L, i);
205 if (p != NULL)
206 return p;
207 formatted_error("node lib","lua <node> expected, not an object with type %s", luaL_typename(L, i));
208 return NULL;
213 This routine finds the numerical value of a string (or number) at
214 lua stack index |n|. If it is not a valid node type, returns -1
218 static int get_node_type_id_from_name(lua_State * L, int n, node_info * data)
220 int j;
221 const char *s = lua_tostring(L, n);
222 for (j = 0; data[j].id != -1; j++) {
223 if (strcmp(s, data[j].name) == 0) {
224 return j;
227 return -1;
230 static int get_valid_node_type_id(lua_State * L, int n)
232 int i = -1;
233 int t = lua_type(L, n);
234 if (t == LUA_TSTRING) {
235 i = get_node_type_id_from_name(L,n,node_data);
236 if (i<0) {
237 luaL_error(L, "invalid node type id: %s", lua_tostring(L, n));
239 } else if (t == LUA_TNUMBER) {
240 i = lua_tointeger(L,n);
241 if (! known_node_type(i)) {
242 luaL_error(L, "invalid node type id: %d", i);
244 } else {
245 luaL_error(L, "invalid node type id");
247 return i;
250 static int get_valid_node_subtype_id(lua_State * L, int n)
252 int i = -1;
253 int t = lua_type(L, n);
254 if (t == LUA_TSTRING) {
255 i = get_node_type_id_from_name(L,n,whatsit_node_data);
256 if (i<0) {
257 luaL_error(L, "invalid whatsit type id: %s", lua_tostring(L, n));
259 } else if (t == LUA_TNUMBER) {
260 i = lua_tointeger(L,n);
261 if (! known_whatsit_type(i)) {
262 luaL_error(L, "invalid whatsit type id: %d", i);
264 } else {
265 luaL_error(L, "invalid whatsit type id");
267 return i;
270 /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
272 static int lua_nodelib_next(lua_State * L)
274 halfword *p = maybe_isnode(L,1);
275 if (p != NULL && *p && vlink(*p)) {
276 lua_nodelib_push_fast(L,vlink(*p));
277 } else {
278 lua_pushnil(L);
280 return 1;
283 static int lua_nodelib_prev(lua_State * L)
285 halfword *p = maybe_isnode(L,1);
286 if (p != NULL && *p && alink(*p)) {
287 lua_nodelib_push_fast(L,alink(*p));
288 } else {
289 lua_pushnil(L);
291 return 1;
296 Creates a userdata object for a number found at the stack top, if it is
297 representing a node (i.e. an pointer into |varmem|). It replaces the
298 stack entry with the new userdata, or pushes |nil| if the number is |null|,
299 or if the index is definately out of range. This test could be improved.
303 void lua_nodelib_push(lua_State * L)
305 halfword n;
306 halfword *a;
307 n = -1;
308 if (lua_type(L, -1) == LUA_TNUMBER)
309 n = (int) lua_tointeger(L, -1);
310 lua_pop(L, 1);
311 if ((n == null) || (n < 0) || (n > var_mem_max)) {
312 lua_pushnil(L);
313 } else {
314 a = lua_newuserdata(L, sizeof(halfword));
315 *a = n;
316 lua_get_metatablelua(luatex_node);
317 lua_setmetatable(L, -2);
319 return;
322 void lua_nodelib_push_fast(lua_State * L, halfword n)
324 halfword *a;
325 if (n) {
326 a = lua_newuserdata(L, sizeof(halfword));
327 *a = n;
328 lua_get_metatablelua(luatex_node);
329 lua_setmetatable(L, -2);
330 } else {
331 lua_pushnil(L);
333 return;
336 /* converts type strings to type ids */
338 static int lua_nodelib_id(lua_State * L)
340 if (lua_type(L,1) == LUA_TSTRING) {
341 int i = get_node_type_id_from_name(L, 1, node_data);
342 if (i >= 0) {
343 lua_pushinteger(L, i);
344 } else {
345 lua_pushnil(L);
347 } else {
348 lua_pushnil(L);
350 return 1;
353 /* node.getid */
355 static int lua_nodelib_getid(lua_State * L)
357 /* [given-node] [...] */
358 halfword *p = lua_touserdata(L, 1);
359 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
360 lua_pushnil(L);
361 return 1;
363 /* [given-node] [mt-given-node] */
364 lua_get_metatablelua(luatex_node);
365 /* [given-node] [mt-given-node] [mt-node] */
366 if (!lua_rawequal(L, -1, -2)) {
367 lua_pushnil(L);
368 } else {
369 lua_pushinteger(L, type(*p));
371 return 1;
374 /* node.fast.getid
376 static int lua_nodelib_fast_getid(lua_State * L)
378 halfword *n;
379 n = (halfword *) lua_touserdata(L, 1);
380 lua_pushinteger(L, type(*n));
381 return 1;
386 /* node.direct.getid */
388 static int lua_nodelib_direct_getid(lua_State * L)
390 halfword n = lua_tointeger(L, 1);
391 if (n == null) {
392 lua_pushnil(L);
393 } else {
394 lua_pushinteger(L, type(n));
396 return 1;
399 /* node.getsubtype */
401 static int lua_nodelib_getsubtype(lua_State * L)
403 halfword *p = lua_touserdata(L, 1);
404 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
405 lua_pushnil(L);
406 } else {
407 lua_get_metatablelua(luatex_node);
408 if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
409 lua_pushnil(L);
410 } else {
411 lua_pushinteger(L, subtype(*p));
414 return 1;
417 /* node.fast.getsubtype
419 static int lua_nodelib_fast_getsubtype(lua_State * L)
421 halfword *n;
422 n = (halfword *) lua_touserdata(L, 1);
423 lua_pushinteger(L, subtype(*n));
424 return 1;
429 /* node.direct.getsubtype */
431 static int lua_nodelib_direct_getsubtype(lua_State * L)
433 halfword n = lua_tointeger(L, 1);
434 if (n == null) { /* no check, we assume sane use */
435 lua_pushnil(L);
436 } else {
437 lua_pushinteger(L, subtype(n));
439 return 1;
442 static int lua_nodelib_direct_setsubtype(lua_State * L)
444 halfword n = lua_tointeger(L, 1);
445 if ((n != null) && (lua_type(L,2) == LUA_TNUMBER)) {
446 subtype(n) = (halfword) lua_tointeger(L, 2);
448 return 0;
451 /* node.getfont */
453 static int lua_nodelib_getfont(lua_State * L)
455 halfword *n = lua_touserdata(L, 1);
456 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
457 lua_pushnil(L);
458 } else {
459 halfword t = type(*n);
460 if (t == glyph_node) {
461 lua_pushinteger(L, font(*n));
462 } else if ((t == math_char_node) || (t == math_text_char_node)) {
463 lua_pushinteger(L, fam_fnt(math_fam(*n), 0));
464 } else {
465 lua_pushnil(L);
468 return 1;
471 /* node.fast.getfont
473 static int lua_nodelib_fast_getfont(lua_State * L)
475 halfword *n;
476 n = (halfword *) lua_touserdata(L, 1);
477 if (type(*n) != glyph_node) {
478 lua_pushnil(L);
479 } else {
480 lua_pushinteger(L, font(*n));
482 return 1;
487 /* node.direct.getfont */
491 static int lua_nodelib_direct_getfont(lua_State * L)
493 halfword n;
494 n = (halfword) lua_tointeger(L, 1);
495 if ((n == null) || (type(n) != glyph_node)) {
496 lua_pushnil(L);
497 } else {
498 lua_pushinteger(L, font(n));
500 return 1;
505 static int lua_nodelib_direct_getfont(lua_State * L) /* family_font is not yet in manual, what does arg 2 do */
507 halfword n = lua_tointeger(L, 1);
508 if (n != null) {
509 halfword t = type(n);
510 if (t == glyph_node) {
511 lua_pushinteger(L, font(n));
512 } else if ((t == math_char_node) || (t == math_text_char_node)) {
513 lua_pushinteger(L, fam_fnt(math_fam(n), 0));
514 } else {
515 lua_pushnil(L);
517 } else {
518 lua_pushnil(L);
520 return 1;
523 /* node.getchar */
525 static int lua_nodelib_getcharacter(lua_State * L)
527 halfword *n = lua_touserdata(L, 1);
528 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
529 lua_pushnil(L);
530 } else if (type(*n) == glyph_node) {
531 lua_pushinteger(L, character(*n));
532 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
533 lua_pushinteger(L, math_character(*n));
535 return 1;
538 /* node.fast.getchar
540 static int lua_nodelib_fast_getcharacter(lua_State * L)
542 halfword *n;
543 n = (halfword *) lua_touserdata(L, 1);
544 if (type(*n) == glyph_node) {
545 lua_pushinteger(L, character(*n));
546 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
547 lua_pushinteger(L, math_character(*n));
548 } else {
549 lua_pushnil(L);
551 return 1;
556 /* node.direct.getchar */
558 static int lua_nodelib_direct_getcharacter(lua_State * L)
560 halfword n = lua_tointeger(L, 1);
561 if (n == null) {
562 lua_pushnil(L);
563 } else if (type(n) == glyph_node) {
564 lua_pushinteger(L, character(n));
565 } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
566 lua_pushinteger(L, math_character(n));
567 } else {
568 lua_pushnil(L);
570 return 1;
573 /* node.getdisc */
575 static int lua_nodelib_direct_getdiscretionary(lua_State * L)
577 halfword n = lua_tointeger(L, 1);
578 if (n != null) {
579 if (type(n) == disc_node) {
580 nodelib_pushdirect_or_nil(vlink(pre_break(n)));
581 nodelib_pushdirect_or_nil(vlink(post_break(n)));
582 nodelib_pushdirect_or_nil(vlink(no_break(n)));
583 if (lua_isboolean(L, 2)) {
584 if (lua_toboolean(L, 2)) {
585 nodelib_pushdirect_or_nil(tlink(pre_break(n)));
586 nodelib_pushdirect_or_nil(tlink(post_break(n)));
587 nodelib_pushdirect_or_nil(tlink(no_break(n)));
588 return 6;
591 return 3;
594 lua_pushnil(L);
595 return 1;
598 static int lua_nodelib_getdiscretionary(lua_State * L)
600 halfword *a;
601 halfword *n = lua_touserdata(L, 1);
602 if (n != NULL) {
603 if (type(*n) == disc_node) {
604 fast_metatable_or_nil(vlink(pre_break(*n)));
605 fast_metatable_or_nil(vlink(post_break(*n)));
606 fast_metatable_or_nil(vlink(no_break(*n)));
607 if (lua_isboolean(L, 2)) {
608 if (lua_toboolean(L, 2)) {
609 fast_metatable_or_nil(tlink(pre_break(*n)));
610 fast_metatable_or_nil(tlink(post_break(*n)));
611 fast_metatable_or_nil(tlink(no_break(*n)));
612 return 6;
615 return 3;
618 lua_pushnil(L);
619 return 1;
623 /* node.getlist */
625 static int lua_nodelib_getlist(lua_State * L)
627 halfword *a;
628 halfword *n = lua_touserdata(L, 1);
629 if ((n == NULL) || (! lua_getmetatable(L,1))) {
630 lua_pushnil(L);
631 } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
632 fast_metatable_or_nil_alink(list_ptr(*n));
633 } else {
634 lua_pushnil(L);
636 return 1;
641 static int lua_nodelib_setlist(lua_State * L)
643 halfword *n = lua_touserdata(L, 1);
644 if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
645 if (lua_type(L,2) == LUA_TNIL) {
646 list_ptr(n) = null;
647 } else {
648 halfword *l = lua_touserdata(L, 2);
649 list_ptr(n) = l;
652 return 0;
657 /* node.direct.getlist */
659 static int lua_nodelib_direct_getlist(lua_State * L)
661 halfword n = lua_tointeger(L, 1);
662 if (n == null) {
663 lua_pushnil(L);
664 } else if ((type(n) == hlist_node) || (type(n) == vlist_node)) {
665 nodelib_pushdirect_or_nil_alink(list_ptr(n));
666 } else {
667 lua_pushnil(L);
669 return 1;
672 static int lua_nodelib_direct_setlist(lua_State * L)
674 halfword n = lua_tointeger(L, 1);
675 if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
676 if (lua_type(L,2) == LUA_TNUMBER) {
677 list_ptr(n) = (halfword) lua_tointeger(L, 2);
678 } else {
679 list_ptr(n) = null;
682 return 0;
685 /* node.getleader */
687 static int lua_nodelib_getleader(lua_State * L)
689 halfword *a;
690 halfword *n = lua_touserdata(L, 1);
691 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
692 lua_pushnil(L);
693 } else if (type(*n) == glue_node) {
694 fast_metatable_or_nil(leader_ptr(*n));
695 } else {
696 lua_pushnil(L);
698 return 1;
701 /* node.direct.getleader */
703 static int lua_nodelib_direct_getleader(lua_State * L)
705 halfword n = lua_tointeger(L, 1);
706 if (n == null) {
707 lua_pushnil(L);
708 } else if (type(n) == glue_node) {
709 nodelib_pushdirect_or_nil(leader_ptr(n));
710 } else {
711 lua_pushnil(L);
713 return 1;
716 static int lua_nodelib_direct_setleader(lua_State * L)
718 halfword n = lua_tointeger(L, 1);
719 if ((n != null) && (type(n) == glue_node)) {
720 if (lua_type(L,2) == LUA_TNUMBER) {
721 leader_ptr(n) = (halfword) lua_tointeger(L, 2);
722 } else {
723 leader_ptr(n) = null;
726 return 0;
729 /* node.getnext */
731 static int lua_nodelib_getnext(lua_State * L)
733 halfword *a;
734 /* [given-node] [...]*/
735 halfword *p = lua_touserdata(L, 1);
736 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
737 lua_pushnil(L);
738 } else {
739 /* [given-node] [mt-given-node]*/
740 lua_get_metatablelua(luatex_node);
741 /* [given-node] [mt-given-node] [mt-node]*/
742 if (!lua_rawequal(L, -1, -2)) {
743 lua_pushnil(L);
744 } else {
745 fast_metatable_or_nil(vlink(*p));
748 return 1; /* just one*/
751 /* node.fast.getnext
753 static int lua_nodelib_fast_getnext(lua_State * L)
755 halfword *a;
756 halfword *p = lua_touserdata(L, 1);
757 if ((p == NULL) || (!vlink(*p))){
758 lua_pushnil(L);
759 } else {
760 lua_settop(L,1);
761 lua_getmetatable(L,1);
762 a = lua_newuserdata(L, sizeof(halfword));
763 *a = vlink(*p);
764 lua_replace(L,1);
765 lua_setmetatable(L,1);
767 return 1;
772 /* node.direct.getnext */
774 static int lua_nodelib_direct_getnext(lua_State * L)
776 halfword p = lua_tointeger(L, 1);
777 if (p == null) {
778 lua_pushnil(L);
779 } else {
780 nodelib_pushdirect_or_nil(vlink(p));
782 return 1;
785 /* node.getprev */
787 static int lua_nodelib_getprev(lua_State * L)
789 halfword *a;
790 halfword *p = lua_touserdata(L, 1);
791 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
792 lua_pushnil(L);
793 } else {
794 lua_get_metatablelua(luatex_node);
795 if (!lua_rawequal(L, -1, -2)) {
796 lua_pushnil(L);
797 } else {
798 fast_metatable_or_nil(alink(*p));
801 return 1;
804 static int lua_nodelib_getboth(lua_State * L)
806 halfword *a;
807 halfword *p = lua_touserdata(L, 1);
808 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
809 lua_pushnil(L);
810 lua_pushnil(L);
811 } else {
812 lua_get_metatablelua(luatex_node);
813 if (!lua_rawequal(L, -1, -2)) {
814 lua_pushnil(L);
815 lua_pushnil(L);
816 } else {
817 fast_metatable_or_nil(alink(*p));
818 fast_metatable_or_nil(vlink(*p));
821 return 2;
824 /* node.fast.getprev
826 static int lua_nodelib_fast_getprev(lua_State * L)
828 halfword *a;
829 halfword *p = lua_touserdata(L, 1);
830 if ((p == NULL) || (!alink(*p))) {
831 lua_pushnil(L);
832 } else {
833 lua_settop(L,1);
834 lua_getmetatable(L,1);
835 a = lua_newuserdata(L, sizeof(halfword));
836 *a = alink(*p);
837 lua_replace(L,1);
838 lua_setmetatable(L,1);
840 return 1;
845 /* node.direct.getprev */
847 static int lua_nodelib_direct_getprev(lua_State * L)
849 halfword p = lua_tointeger(L, 1);
850 if (p == null) {
851 lua_pushnil(L);
852 } else {
853 nodelib_pushdirect_or_nil(alink(p));
855 return 1;
858 /* node.direct.getboth */
860 static int lua_nodelib_direct_getboth(lua_State * L)
862 halfword p = lua_tointeger(L, 1);
863 if (p == null) {
864 lua_pushnil(L);
865 lua_pushnil(L);
866 } else {
867 nodelib_pushdirect_or_nil(alink(p));
868 nodelib_pushdirect_or_nil(vlink(p));
870 return 2;
873 /* node.subtype (maybe also return them for other node types now) */
875 static int lua_nodelib_subtype(lua_State * L)
877 if (lua_type(L,1) == LUA_TSTRING) {
878 int i = get_node_type_id_from_name(L,1,whatsit_node_data);
879 if (i >= 0) {
880 lua_pushinteger(L, i);
881 } else {
882 lua_pushnil(L);
884 } else {
885 lua_pushnil(L);
887 return 1;
890 /* node.type (converts id numbers to type names) */
892 static int lua_nodelib_type(lua_State * L)
894 if (lua_type(L,1) == LUA_TNUMBER) {
895 int i = lua_tointeger(L, 1);
896 if (known_node_type(i)) {
897 lua_pushstring(L, node_data[i].name);
898 return 1;
900 } else if (maybe_isnode(L, 1) != NULL) {
901 lua_pushstring(L,"node");
902 return 1;
904 lua_pushnil(L);
905 return 1;
908 /* node.new (allocate a new node) */
910 static int lua_nodelib_new(lua_State * L)
912 int i, j;
913 halfword n = null;
914 int t = lua_type(L, 1);
915 if (t == LUA_TNUMBER) {
916 i = lua_tointeger(L,1);
917 if (! known_node_type(i)) {
918 i = -1;
920 } else if (t == LUA_TSTRING) {
921 i = get_node_type_id_from_name(L,1,node_data);
922 } else {
923 i = -1;
925 if (i < 0) {
926 luaL_error(L, "invalid node id for creating new node");
928 t = lua_type(L, 2);
929 if (i == whatsit_node) {
930 if (t == LUA_TNUMBER) {
931 j = lua_tointeger(L,2);
932 if (! known_whatsit_type(j)) {
933 j = -1;
935 } else if (t == LUA_TSTRING) {
936 j = get_node_type_id_from_name(L,2,whatsit_node_data);
937 } else {
938 j = -1;
940 if (j < 0) {
941 luaL_error(L, "creating a whatsit requires the subtype number as a second argument");
943 } else if (t == LUA_TNUMBER) {
944 j = (int) lua_tointeger(L, 2);
945 } else {
946 j = 0;
948 n = new_node(i, j);
949 lua_nodelib_push_fast(L, n);
950 return 1;
953 /* node.direct.new (still with checking) */
955 static int lua_nodelib_direct_new(lua_State * L)
957 int j;
958 halfword n ;
959 int i = get_valid_node_type_id(L, 1);
960 if (i == whatsit_node) {
961 j = -1;
962 if (lua_gettop(L) > 1)
963 j = get_valid_node_subtype_id(L, 2);
964 if (j < 0)
965 luaL_error(L, "Creating a whatsit requires the subtype number as a second argument");
966 } else {
967 j = 0;
968 if (lua_gettop(L) > 1)
969 j = (int) lua_tointeger(L, 2);
971 n = new_node(i, j);
972 lua_pushinteger(L,n);
973 return 1;
976 /* node.free (this function returns the 'next' node, because that may be helpful) */
978 static int lua_nodelib_free(lua_State * L)
980 halfword n;
981 halfword p;
982 if (lua_gettop(L) < 1) {
983 lua_pushnil(L);
984 return 1;
985 } else if (lua_isnil(L, 1)) {
986 return 1; /* the nil itself */
988 n = *(check_isnode(L, 1));
989 p = vlink(n);
990 flush_node(n);
991 /* can be: lua_nodelib_push_fast(L, p); */
992 lua_pushinteger(L, p);
993 lua_nodelib_push(L);
994 return 1;
997 /* node.direct.free */
999 static int lua_nodelib_direct_free(lua_State * L)
1001 halfword n = lua_tointeger(L,1);
1002 if (n == null) {
1003 lua_pushnil(L);
1004 } else {
1005 halfword p = vlink(n);
1006 flush_node(n);
1007 if (p == 0) {
1008 lua_pushnil(L);
1009 } else {
1010 lua_pushinteger(L,p);
1013 return 1;
1016 /* node.flush_node (no next returned) */
1018 static int lua_nodelib_flush_node(lua_State * L)
1020 if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
1021 return 0;
1022 } else {
1023 halfword n = *(check_isnode(L, 1));
1024 flush_node(n);
1025 return 0;
1029 /* node.direct.flush_node */
1031 static int lua_nodelib_direct_flush_node(lua_State * L)
1033 halfword n = lua_tointeger(L,1);
1034 if (n == null)
1035 return 0;
1036 flush_node(n);
1037 return 0;
1040 /* node.flush_list */
1042 static int lua_nodelib_flush_list(lua_State * L)
1044 if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
1045 return 0;
1046 } else {
1047 halfword n_ptr = *check_isnode(L, 1);
1048 flush_node_list(n_ptr);
1049 return 0;
1053 /* node.direct.flush_list */
1055 static int lua_nodelib_direct_flush_list(lua_State * L)
1057 halfword n = lua_tointeger(L,1);
1058 if (n == null)
1059 return 0;
1060 flush_node_list(n);
1061 return 0;
1064 /* remove a node from a list */
1066 #if DEBUG
1068 static void show_node_links (halfword l, const char * p)
1070 halfword t = l;
1071 while (t) {
1072 fprintf(DEBUG_OUT, "%s t = %d, prev = %d, next = %d\n", p, (int)t, (int)alink(t), (int)vlink(t));
1073 t = vlink(t);
1077 #endif
1079 /* node.remove */
1081 static int lua_nodelib_remove(lua_State * L)
1083 halfword head, current, t;
1084 if (lua_gettop(L) < 2)
1085 luaL_error(L, "Not enough arguments for node.remove()");
1086 head = *(check_isnode(L, 1));
1087 if (lua_isnil(L, 2))
1088 return 2; /* the arguments, as they are */
1089 current = *(check_isnode(L, 2));
1090 if (head == current) {
1091 if (alink(current)){
1092 vlink(alink(current)) = vlink(current);
1094 if (vlink(current)){
1095 alink( vlink(current)) = alink(current);
1098 head = vlink(current);
1099 current = vlink(current);
1100 } else {
1101 t = alink(current);
1102 if (t == null || vlink(t) != current) {
1103 set_t_to_prev(head, current);
1104 if (t == null) /* error! */
1105 luaL_error(L,"Attempt to node.remove() a non-existing node");
1107 /* t is now the previous node */
1108 vlink(t) = vlink(current);
1109 if (vlink(current) != null)
1110 alink(vlink(current)) = t;
1111 current = vlink(current);
1113 #if DEBUG
1114 show_node_links(head, "after");
1115 #endif
1116 /* can be: lua_nodelib_push_fast(L, head); */
1117 lua_pushinteger(L, head);
1118 lua_nodelib_push(L);
1119 /* can be: lua_nodelib_push_fast(L, current); */
1120 lua_pushinteger(L, current);
1121 lua_nodelib_push(L);
1122 return 2;
1125 /* node.direct.remove */
1127 static int lua_nodelib_direct_remove(lua_State * L)
1129 halfword current, t;
1130 halfword head = lua_tointeger(L,1);
1131 if (head == null) {
1132 lua_pushnil(L);
1133 lua_pushnil(L);
1134 return 2 ;
1136 current = (halfword) lua_tointeger(L,2);
1137 if (current == null) {
1138 lua_pushinteger(L, head);
1139 lua_pushnil(L);
1140 return 2 ;
1142 if (head == current) {
1143 if (alink(current)){
1144 vlink( alink(current) ) = vlink(current);
1146 if (vlink(current)){
1147 alink( vlink(current) ) = alink(current);
1149 head = vlink(current);
1150 current = vlink(current);
1151 } else {
1152 t = alink(current);
1153 if (t == null || vlink(t) != current) {
1154 set_t_to_prev(head, current);
1155 if (t == null) {
1156 luaL_error(L,"Attempt to node.direct.remove() a non-existing node");
1159 vlink(t) = vlink(current);
1160 if (vlink(current) != null)
1161 alink(vlink(current)) = t;
1162 current = vlink(current);
1164 if (head == null) {
1165 lua_pushnil(L);
1166 } else {
1167 lua_pushinteger(L, head);
1169 if (current == null) {
1170 lua_pushnil(L);
1171 } else {
1172 lua_pushinteger(L, current);
1174 return 2;
1177 /* node.insert_before (insert a node in a list) */
1179 static int lua_nodelib_insert_before(lua_State * L)
1181 halfword head, current, n, t;
1182 if (lua_gettop(L) < 3) {
1183 luaL_error(L, "Not enough arguments for node.insert_before()");
1185 if (lua_isnil(L, 3)) {
1186 lua_pop(L, 1);
1187 return 2;
1188 } else {
1189 n = *(check_isnode(L, 3));
1191 if (lua_isnil(L, 1)) { /* no head */
1192 vlink(n) = null;
1193 alink(n) = null;
1194 lua_nodelib_push_fast(L, n);
1195 lua_pushvalue(L, -1);
1196 return 2;
1197 } else {
1198 head = *(check_isnode(L, 1));
1200 if (lua_isnil(L, 2)) {
1201 current = tail_of_list(head);
1202 } else {
1203 current = *(check_isnode(L, 2));
1205 if (head != current) {
1206 t = alink(current);
1207 if (t == null || vlink(t) != current) {
1208 set_t_to_prev(head, current);
1209 if (t == null) { /* error! */
1210 luaL_error(L, "Attempt to node.insert_before() a non-existing node");
1213 couple_nodes(t, n);
1215 couple_nodes(n, current);
1216 if (head == current) {
1217 lua_nodelib_push_fast(L, n);
1218 } else {
1219 lua_nodelib_push_fast(L, head);
1221 lua_nodelib_push_fast(L, n);
1222 return 2;
1225 /* node.direct.insert_before */
1227 static int lua_nodelib_direct_insert_before(lua_State * L)
1229 halfword head, current;
1230 halfword n = lua_tointeger(L,3);
1231 if (n == null){
1232 /* no node */
1233 lua_pop(L, 1);
1234 return 2 ;
1236 head = (halfword) lua_tointeger(L,1);
1237 current = (halfword) lua_tointeger(L,2);
1238 /* no head, ignore current */
1239 if (head == null) {
1240 vlink(n) = null;
1241 alink(n) = null;
1242 lua_pushinteger(L, n);
1243 lua_pushvalue(L, -1);
1244 /* n, n */
1245 return 2;
1247 /* no current */
1248 if (current == null)
1249 current = tail_of_list(head);
1250 if (head != current) {
1251 halfword t = alink(current);
1252 if (t == null || vlink(t) != current)
1253 set_t_to_prev(head, current);
1254 couple_nodes(t, n);
1256 couple_nodes(n, current);
1257 if (head == current) {
1258 lua_pushinteger(L, n);
1259 } else {
1260 lua_pushinteger(L, head);
1262 lua_pushinteger(L, n);
1263 return 2;
1266 /* node.insert_after */
1268 static int lua_nodelib_insert_after(lua_State * L)
1270 halfword head, current, n;
1271 if (lua_gettop(L) < 3) {
1272 luaL_error(L, "Not enough arguments for node.insert_after()");
1274 if (lua_isnil(L, 3)) {
1275 lua_pop(L, 1);
1276 return 2;
1277 } else {
1278 n = *(check_isnode(L, 3));
1280 if (lua_isnil(L, 1)) { /* no head */
1281 vlink(n) = null;
1282 alink(n) = null;
1283 lua_nodelib_push_fast(L, n);
1284 lua_pushvalue(L, -1);
1285 return 2;
1286 } else {
1287 head = *(check_isnode(L, 1));
1289 if (lua_isnil(L, 2)) {
1290 current = head;
1291 while (vlink(current) != null)
1292 current = vlink(current);
1293 } else {
1294 current = *(check_isnode(L, 2));
1296 try_couple_nodes(n, vlink(current));
1297 couple_nodes(current, n);
1299 lua_pop(L, 2);
1300 lua_nodelib_push_fast(L, n);
1301 return 2;
1304 /* node.direct.insert_after */
1306 static int lua_nodelib_direct_insert_after(lua_State * L)
1308 halfword head, current;
1309 /*[head][current][new]*/
1310 halfword n = lua_tointeger(L,3);
1311 if (n == null) {
1312 /* no node */
1313 return 2 ;
1315 head = (halfword) lua_tointeger(L,1);
1316 current = (halfword) lua_tointeger(L,2);
1317 if (head == null) {
1318 /* no head, ignore current */
1319 vlink(n) = null;
1320 alink(n) = null;
1321 lua_pushinteger(L,n);
1322 lua_pushvalue(L, -1);
1323 /* n, n */
1324 return 2;
1326 if (current == null) {
1327 /* no current */
1328 current = head;
1329 while (vlink(current) != null)
1330 current = vlink(current);
1332 try_couple_nodes(n, vlink(current));
1333 couple_nodes(current, n);
1334 lua_pop(L, 2);
1335 lua_pushinteger(L, n);
1336 return 2;
1339 /* node.copy_list */
1342 we need to use an intermediate variable as otherwise target is used in the loop
1343 and subfields get overwritten (or something like that) which results in crashes
1344 and unexpected side effects
1347 static int lua_nodelib_copy_list(lua_State * L)
1349 halfword n, s = null;
1350 halfword m;
1351 if (lua_isnil(L, 1))
1352 return 1; /* the nil itself */
1353 n = *check_isnode(L, 1);
1354 if ((lua_gettop(L) > 1) && (!lua_isnil(L,2)))
1355 s = *check_isnode(L, 2);
1356 m = do_copy_node_list(n, s);
1357 lua_nodelib_push_fast(L,m);
1358 return 1;
1362 /* node.direct.copy_list */
1364 static int lua_nodelib_direct_copy_list(lua_State * L)
1366 halfword n = lua_tointeger(L,1);
1367 if (n == null) {
1368 lua_pushnil(L);
1369 } else {
1370 halfword s = lua_tointeger(L,2);
1371 halfword m;
1372 if (s == null) {
1373 m = do_copy_node_list(n,null);
1374 } else {
1375 m = do_copy_node_list(n,s);
1377 lua_pushinteger(L,m);
1379 return 1;
1382 /* node.copy (deep copy) */
1384 static int lua_nodelib_copy(lua_State * L)
1386 halfword n;
1387 if (lua_isnil(L, 1))
1388 return 1; /* the nil itself */
1389 n = *check_isnode(L, 1);
1390 n = copy_node(n);
1391 lua_nodelib_push_fast(L, n);
1392 return 1;
1395 /* node.direct.copy (deep copy) */
1397 static int lua_nodelib_direct_copy(lua_State * L)
1399 if (lua_isnil(L, 1)) {
1400 return 1; /* the nil itself */
1401 } else {
1402 /* beware, a glue node can have number 0 (zeropt) so we cannot test for null) */
1403 halfword n = lua_tointeger(L, 1);
1404 n = copy_node(n);
1405 lua_pushinteger(L, n);
1406 return 1;
1411 /* node.write (output a node to tex's processor) */
1413 static int lua_nodelib_append(lua_State * L)
1415 halfword n;
1416 int i;
1417 int j = lua_gettop(L);
1418 for (i = 1; i <= j; i++) {
1419 n = *check_isnode(L, i);
1420 tail_append(n);
1421 while (vlink(n) != null) {
1422 n = vlink(n);
1423 tail_append(n);
1426 return 0;
1429 /* node.direct.write */
1431 static int lua_nodelib_direct_append(lua_State * L)
1433 halfword m;
1434 int i;
1435 int j = lua_gettop(L);
1436 for (i = 1; i <= j; i++) {
1437 halfword n = lua_tointeger(L,i); /*lua_getnumber(L, i);*/
1438 if (n != null) {
1439 m = n ;
1440 tail_append(m);
1441 while (vlink(m) != null) {
1442 m = vlink(m);
1443 tail_append(m);
1447 return 0;
1450 /* node.last */
1452 static int lua_nodelib_last_node(lua_State * L)
1454 halfword m = pop_tail();
1455 /* can be: lua_nodelib_push_fast(L, m); */
1456 lua_pushinteger(L, m);
1457 lua_nodelib_push(L);
1458 return 1;
1461 /* node.direct.last */
1463 static int lua_nodelib_direct_last_node(lua_State * L)
1465 halfword m = pop_tail();
1466 lua_pushinteger(L, m);
1467 return 1;
1470 /* node.hpack (build a hbox) */
1472 static int lua_nodelib_hpack(lua_State * L)
1474 halfword p;
1475 const char *s;
1476 int w = 0;
1477 int m = 1;
1478 int d = -1;
1479 halfword n = *(check_isnode(L, 1));
1480 if (lua_gettop(L) > 1) {
1481 w = (int) lua_tointeger(L, 2);
1482 if (lua_gettop(L) > 2) {
1483 if (lua_type(L, 3) == LUA_TSTRING) {
1484 s = lua_tostring(L, 3);
1485 if (lua_key_eq(s, exactly)) {
1486 m = 0;
1487 } else if (lua_key_eq(s, additional)) {
1488 m = 1;
1489 } else if (lua_key_eq(s, cal_expand_ratio)) {
1490 m = 2;
1491 } else if (lua_key_eq(s, subst_ex_font)) {
1492 m = 3;
1494 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1495 m = (int) lua_tointeger(L, 3);
1497 if ((m<0) || (m>3)) {
1498 luaL_error(L, "wrong mode in hpack");
1500 if (lua_gettop(L) > 3) {
1501 if (lua_type(L, 4) == LUA_TSTRING) {
1502 d = nodelib_getdir(L, 4, 1);
1503 } else {
1504 lua_pushstring(L, "incorrect 4th argument");
1509 p = hpack(n, w, m, d);
1510 lua_nodelib_push_fast(L, p);
1511 lua_pushinteger(L, last_badness);
1512 return 2;
1515 /* node.direct.hpack */
1517 static int lua_nodelib_direct_hpack(lua_State * L)
1519 halfword p;
1520 const char *s;
1521 int w = 0;
1522 int m = 1;
1523 int d = -1;
1524 halfword n = lua_tointeger(L,1);
1525 /* could be macro */
1526 if (lua_gettop(L) > 1) {
1527 w = (int) lua_tointeger(L, 2);
1528 if (lua_gettop(L) > 2) {
1529 if (lua_type(L, 3) == LUA_TSTRING) {
1530 s = lua_tostring(L, 3);
1531 if (lua_key_eq(s, additional)) {
1532 m = 1;
1533 } else if (lua_key_eq(s, exactly)) {
1534 m = 0;
1535 } else if (lua_key_eq(s, cal_expand_ratio)) {
1536 m = 2;
1537 } else if (lua_key_eq(s, subst_ex_font)) {
1538 m = 3;
1539 } else {
1540 luaL_error(L, "3rd argument should be either additional or exactly");
1542 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1543 m = (int) lua_tointeger(L, 3);
1544 } else {
1545 lua_pushstring(L, "incorrect 3rd argument");
1547 if (lua_gettop(L) > 3) {
1548 if (lua_type(L, 4) == LUA_TSTRING) {
1549 d = nodelib_getdir(L, 4, 1);
1550 } else {
1551 lua_pushstring(L, "incorrect 4th argument");
1556 /* till here */
1557 p = hpack(n, w, m, d);
1558 lua_pushinteger(L, p);
1559 lua_pushinteger(L, last_badness);
1560 return 2;
1563 /* node.vpack (build a vbox) */
1565 static int lua_nodelib_vpack(lua_State * L)
1567 halfword p;
1568 const char *s;
1569 int w = 0;
1570 int m = 1;
1571 int d = -1;
1572 halfword n = *(check_isnode(L, 1));
1573 if (lua_gettop(L) > 1) {
1574 w = (int) lua_tointeger(L, 2);
1575 if (lua_gettop(L) > 2) {
1576 if (lua_type(L, 3) == LUA_TSTRING) {
1577 s = lua_tostring(L, 3);
1578 if (lua_key_eq(s, additional)) {
1579 m = 1;
1580 } else if (lua_key_eq(s, exactly)) {
1581 m = 0;
1582 } else {
1583 luaL_error(L, "3rd argument should be either additional or exactly");
1586 if (lua_gettop(L) > 3) {
1587 if (lua_type(L, 4) == LUA_TSTRING) {
1588 d = nodelib_getdir(L, 4, 1);
1589 } else {
1590 lua_pushstring(L, "incorrect 4th argument");
1595 else if (lua_type(L, 3) == LUA_TNUMBER) {
1596 m= (int) lua_tointeger(L, 3);
1597 } else {
1598 lua_pushstring(L, "incorrect 3rd argument");
1602 p = vpackage(n, w, m, max_dimen, d);
1603 lua_nodelib_push_fast(L, p);
1604 lua_pushinteger(L, last_badness);
1605 return 2;
1608 /* node.direct.vpack */
1610 static int lua_nodelib_direct_vpack(lua_State * L)
1612 halfword p;
1613 const char *s;
1614 int w = 0;
1615 int m = 1;
1616 int d = -1;
1617 halfword n = (halfword) lua_tointeger(L,1);
1618 if (lua_gettop(L) > 1) {
1619 w = (int) lua_tointeger(L, 2);
1620 if (lua_gettop(L) > 2) {
1621 if (lua_type(L, 3) == LUA_TSTRING) {
1622 s = lua_tostring(L, 3);
1623 if (lua_key_eq(s, additional)) {
1624 m = 1;
1625 } else if (lua_key_eq(s, exactly)) {
1626 m = 0;
1627 } else {
1628 luaL_error(L, "3rd argument should be either additional or exactly");
1631 if (lua_gettop(L) > 3) {
1632 if (lua_type(L, 4) == LUA_TSTRING) {
1633 d = nodelib_getdir(L, 4, 1);
1634 } else {
1635 lua_pushstring(L, "incorrect 4th argument");
1640 else if (lua_type(L, 3) == LUA_TNUMBER) {
1641 m= (int) lua_tointeger(L, 3);
1642 } else {
1643 lua_pushstring(L, "incorrect 3rd argument");
1647 p = vpackage(n, w, m, max_dimen, d);
1648 lua_pushinteger(L, p);
1649 lua_pushinteger(L, last_badness);
1650 return 2;
1653 /* node.dimensions (of a hlist or vlist) */
1655 static int lua_nodelib_dimensions(lua_State * L)
1657 int top = lua_gettop(L);
1658 if (top > 0) {
1659 scaled_whd siz;
1660 glue_ratio g_mult = 1.0;
1661 int g_sign = normal;
1662 int g_order = normal;
1663 int i = 1;
1664 int d = -1;
1665 halfword n = null, p = null;
1666 if (lua_type(L, 1) == LUA_TNUMBER) {
1667 if (top < 4) {
1668 lua_pushnil(L);
1669 return 1;
1671 i += 3;
1672 g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
1673 g_sign = (int) lua_tointeger(L, 2);
1674 g_order = (int) lua_tointeger(L, 3);
1676 n = *(check_isnode(L, i));
1677 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1678 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1679 d = nodelib_getdir(L, (i + 1), 1);
1680 } else {
1681 p = *(check_isnode(L, (i + 1)));
1684 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING) {
1685 d = nodelib_getdir(L, (i + 2), 1);
1687 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1688 lua_pushinteger(L, siz.wd);
1689 lua_pushinteger(L, siz.ht);
1690 lua_pushinteger(L, siz.dp);
1691 return 3;
1692 } else {
1693 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1695 return 0; /* not reached */
1698 /* node.direct.dimensions*/
1700 static int lua_nodelib_direct_dimensions(lua_State * L)
1702 int top = lua_gettop(L);
1703 if (top > 0) {
1704 scaled_whd siz;
1705 glue_ratio g_mult = 1.0;
1706 int g_sign = normal;
1707 int g_order = normal;
1708 int i = 1;
1709 int d = -1;
1710 halfword n = null, p = null;
1711 if (top > 3) {
1712 i += 3;
1713 g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
1714 g_sign = (int) lua_tointeger(L, 2);
1715 g_order = (int) lua_tointeger(L, 3);
1717 n = (halfword) lua_tointeger(L,i);
1718 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1719 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1720 d = nodelib_getdir(L, (i + 1), 1);
1721 } else {
1722 p = (halfword) lua_tointeger(L,i+1);
1725 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING)
1726 d = nodelib_getdir(L, (i + 2), 1);
1727 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1728 lua_pushinteger(L, siz.wd);
1729 lua_pushinteger(L, siz.ht);
1730 lua_pushinteger(L, siz.dp);
1731 return 3;
1732 } else {
1733 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1735 return 0; /* not reached */
1738 /* node.mlist_to_hlist (create a hlist from a formula) */
1740 static int lua_nodelib_mlist_to_hlist(lua_State * L)
1742 int w;
1743 boolean m;
1744 halfword n = *(check_isnode(L, 1));
1745 assign_math_style(L,2,w);
1746 luaL_checkany(L, 3);
1747 m = lua_toboolean(L, 3);
1748 mlist_to_hlist(n, m, w);
1749 alink(vlink(temp_head)) = null; /*hh-ls */
1750 lua_nodelib_push_fast(L, vlink(temp_head));
1751 return 1;
1754 /* node.family_font */
1756 static int lua_nodelib_mfont(lua_State * L)
1758 int s;
1759 int f = luaL_checkinteger(L, 1);
1760 if (lua_gettop(L) == 2)
1761 s = lua_tointeger(L, 2); /* this should be a multiple of 256 ! */
1762 else
1763 s = 0;
1764 lua_pushinteger(L, fam_fnt(f,s));
1765 return 1;
1769 This function is similar to |get_node_type_id|, for field
1770 identifiers. It has to do some more work, because not all
1771 identifiers are valid for all types of nodes.
1773 If really needed we can optimize this one using a big if ..
1774 .. else like with the getter and setter.
1778 static int get_node_field_id(lua_State * L, int n, int node)
1780 int t = type(node);
1781 const char *s = lua_tostring(L, n);
1783 if (s == NULL)
1784 return -2;
1786 if (lua_key_eq(s, next)) {
1787 return 0;
1788 } else if (lua_key_eq(s, id)) {
1789 return 1;
1790 } else if (lua_key_eq(s, subtype)) {
1791 if (nodetype_has_subtype(t)) {
1792 return 2;
1794 } else if (lua_key_eq(s, attr)) {
1795 if (nodetype_has_attributes(t)) {
1796 return 3;
1798 } else if (lua_key_eq(s, prev)) {
1799 if (nodetype_has_prev(t)) {
1800 return -1;
1802 } else {
1803 int j;
1804 const char **fields = node_data[t].fields;
1805 if (t == whatsit_node) {
1806 fields = whatsit_node_data[subtype(node)].fields;
1808 if (lua_key_eq(s, list)) {
1809 s = lua_key(head);
1811 if (fields != NULL) {
1812 for (j = 0; fields[j] != NULL; j++) {
1813 if (strcmp(s, fields[j]) == 0) {
1814 return j + 3;
1819 return -2;
1822 /* node.has_field */
1824 static int lua_nodelib_has_field(lua_State * L)
1826 int i = -2;
1827 if (!lua_isnil(L, 1))
1828 i = get_node_field_id(L, 2, *(check_isnode(L, 1)));
1829 lua_pushboolean(L, (i != -2));
1830 return 1;
1833 /* node.is_char (node[,font]) */
1835 static int lua_nodelib_is_char(lua_State * L)
1837 halfword n = *(check_isnode(L, 1));
1838 if (type(n) != glyph_node) {
1839 lua_pushnil(L); /* no glyph at all */
1840 lua_pushinteger(L,type(n)); /* can save a lookup call */
1841 return 2;
1842 } else if (subtype(n) >= 256) {
1843 lua_pushboolean(L,0); /* a done glyph */
1844 } else if (lua_type(L,2) == LUA_TNUMBER) {
1845 halfword f = lua_tointeger(L, 2);
1846 if (f && f == font(n)) {
1847 lua_pushinteger(L,character(n)); /* a todo glyph in the asked font */
1848 } else {
1849 lua_pushboolean(L,0); /* a todo glyph in another font */
1851 } else {
1852 lua_pushinteger(L,character(n)); /* a todo glyph */
1854 return 1;
1857 static int lua_nodelib_is_glyph(lua_State * L)
1859 halfword n = *(check_isnode(L, 1));
1860 if (type(n) != glyph_node) {
1861 lua_pushboolean(L,0);
1862 lua_pushinteger(L,type(n));
1863 } else {
1864 lua_pushinteger(L,character(n));
1865 lua_pushinteger(L,font(n));
1867 return 2;
1870 /* node.direct.has_field */
1872 static int lua_nodelib_direct_has_field(lua_State * L)
1874 int i = -2;
1875 halfword n = lua_tointeger(L, 1);
1876 if (n != null)
1877 i = get_node_field_id(L, 2, n);
1878 lua_pushboolean(L, (i != -2));
1879 return 1;
1882 /* fetch the list of valid node types */
1884 static int do_lua_nodelib_types(lua_State * L, node_info * data)
1886 int i;
1887 lua_newtable(L);
1888 for (i = 0; data[i].id != -1; i++) {
1889 lua_pushstring(L, data[i].name);
1890 lua_rawseti(L, -2, data[i].id);
1892 return 1;
1895 /* node.types */
1897 static int lua_nodelib_types(lua_State * L)
1899 return do_lua_nodelib_types(L, node_data);
1902 /* node.whatsits */
1904 static int lua_nodelib_whatsits(lua_State * L)
1906 return do_lua_nodelib_types(L, whatsit_node_data);
1909 /* node.fields (fetch the list of valid fields) */
1911 static int lua_nodelib_fields(lua_State * L)
1913 int i = -1;
1914 int offset = 2;
1915 const char **fields;
1916 int t = get_valid_node_type_id(L, 1);
1917 if (t == whatsit_node) {
1918 t = get_valid_node_subtype_id(L, 2);
1919 fields = whatsit_node_data[t].fields;
1920 } else {
1921 fields = node_data[t].fields;
1923 lua_checkstack(L, 2);
1924 lua_newtable(L);
1925 lua_push_string_by_name(L,next);
1926 lua_rawseti(L, -2, 0);
1927 lua_push_string_by_name(L,id);
1928 lua_rawseti(L, -2, 1);
1929 if (nodetype_has_subtype(t)) {
1930 lua_push_string_by_name(L,subtype);
1931 lua_rawseti(L, -2, 2);
1932 offset++;
1934 if (nodetype_has_prev(t)) {
1935 lua_push_string_by_name(L,prev);
1936 lua_rawseti(L, -2, -1);
1938 if (fields != NULL) {
1939 for (i = 0; fields[i] != NULL; i++) {
1940 lua_pushstring(L, fields[i]); /* todo */
1941 lua_rawseti(L, -2, (i + offset));
1944 return 1;
1947 static int lua_nodelib_subtypes(lua_State * L)
1949 int i = -1;
1950 int l = 0;
1951 const char **subtypes = NULL;
1952 const char *s ;
1953 int t = lua_type(L,1);
1954 if (t == LUA_TSTRING) {
1955 /* official accessors */
1956 s = lua_tostring(L,1);
1957 if (lua_key_eq(s,glyph)) subtypes = node_subtypes_glyph;
1958 else if (lua_key_eq(s,glue)) { subtypes = node_subtypes_glue; l = 1; }
1959 else if (lua_key_eq(s,boundary)) subtypes = node_subtypes_boundary;
1960 else if (lua_key_eq(s,penalty)) subtypes = node_subtypes_penalty;
1961 else if (lua_key_eq(s,kern)) subtypes = node_subtypes_kern;
1962 else if (lua_key_eq(s,rule)) subtypes = node_subtypes_rule;
1963 else if (lua_key_eq(s,list)
1964 || lua_key_eq(s,hlist)
1965 || lua_key_eq(s,vlist)) subtypes = node_subtypes_list; /* too many but ok as reserved */
1966 else if (lua_key_eq(s,adjust)) subtypes = node_subtypes_adjust;
1967 else if (lua_key_eq(s,disc)) subtypes = node_subtypes_disc;
1968 else if (lua_key_eq(s,fill)) subtypes = node_subtypes_fill;
1969 else if (lua_key_eq(s,leader)) { subtypes = node_subtypes_leader; l = 2; }
1970 else if (lua_key_eq(s,marginkern)) subtypes = node_subtypes_marginkern;
1971 else if (lua_key_eq(s,math)) subtypes = node_subtypes_math;
1972 else if (lua_key_eq(s,noad)) subtypes = node_subtypes_noad;
1973 else if (lua_key_eq(s,radical)) subtypes = node_subtypes_radical;
1974 else if (lua_key_eq(s,accent)) subtypes = node_subtypes_accent;
1975 else if (lua_key_eq(s,fence)) subtypes = node_subtypes_fence;
1976 /* backend */
1977 else if (lua_key_eq(s,pdf_destination)) subtypes = node_subtypes_pdf_destination;
1978 else if (lua_key_eq(s,pdf_literal)) subtypes = node_subtypes_pdf_literal;
1979 } else if (t == LUA_TNUMBER) {
1980 /* maybe */
1981 t = lua_tointeger(L,1);
1982 if (t == glyph_node) subtypes = node_subtypes_glyph;
1983 else if (t == glue_node) { subtypes = node_subtypes_glue; l = 1; }
1984 else if (t == boundary_node) subtypes = node_subtypes_boundary;
1985 else if (t == penalty_node) subtypes = node_subtypes_penalty;
1986 else if (t == kern_node) subtypes = node_subtypes_kern;
1987 else if (t == rule_node) subtypes = node_subtypes_rule;
1988 else if((t == hlist_node)
1989 || (t == vlist_node)) subtypes = node_subtypes_list;
1990 else if (t == adjust_node) subtypes = node_subtypes_adjust;
1991 else if (t == disc_node) subtypes = node_subtypes_disc;
1992 else if (t == glue_spec_node) subtypes = node_subtypes_fill;
1993 else if (t == margin_kern_node) subtypes = node_subtypes_marginkern;
1994 else if (t == math_node) subtypes = node_subtypes_math;
1995 else if (t == simple_noad) subtypes = node_subtypes_noad;
1996 else if (t == radical_noad) subtypes = node_subtypes_radical;
1997 else if (t == accent_noad) subtypes = node_subtypes_accent;
1998 else if (t == fence_noad) subtypes = node_subtypes_fence;
1999 /* backend */
2000 else if (t == pdf_dest_node) subtypes = node_subtypes_pdf_destination;
2001 else if (t == pdf_literal_node) subtypes = node_subtypes_pdf_literal;
2003 if (subtypes != NULL) {
2004 lua_checkstack(L, 2);
2005 lua_newtable(L);
2006 if (l < 2) {
2007 for (i = 0; subtypes[i] != NULL; i++) {
2008 lua_pushstring(L, subtypes[i]); /* todo */
2009 lua_rawseti(L, -2, i);
2012 if (l > 0) {
2013 /* add math states */
2014 for (i = 0; node_subtypes_mathglue[i] != NULL; i++) {
2015 lua_pushstring(L, node_subtypes_mathglue[i]); /* todo */
2016 lua_rawseti(L, -2, 98 + i);
2018 /* add leaders */
2019 for (i = 0; node_subtypes_leader[i] != NULL; i++) {
2020 lua_pushstring(L, node_subtypes_leader[i]); /* todo */
2021 lua_rawseti(L, -2, 100 + i);
2024 } else {
2025 lua_pushnil(L);
2027 return 1;
2030 /* node.slide (find the end of a list and add prev links) */
2032 static int lua_nodelib_slide(lua_State * L)
2034 halfword n;
2035 if (lua_isnil(L, 1))
2036 return 1; /* the nil itself */
2037 n = *check_isnode(L, 1);
2038 if (n == null)
2039 return 1; /* the old userdata */
2040 /* alink(t) = null; */ /* don't do this, |t|'s |alink| may be a valid pointer */
2041 while (vlink(n) != null) {
2042 alink(vlink(n)) = n;
2043 n = vlink(n);
2045 lua_nodelib_push_fast(L, n);
2046 return 1;
2049 /* node.direct.slide */
2051 static int lua_nodelib_direct_slide(lua_State * L)
2053 halfword n = lua_tointeger(L, 1);
2054 if (n == null) {
2055 lua_pushnil(L);
2056 } else {
2057 while (vlink(n) != null) {
2058 alink(vlink(n)) = n;
2059 n = vlink(n);
2061 lua_pushinteger(L, n);
2063 return 1;
2066 /* node.tail (find the end of a list) */
2068 static int lua_nodelib_tail(lua_State * L)
2070 halfword n;
2071 if (lua_isnil(L, 1))
2072 return 1; /* the nil itself */
2073 n = *check_isnode(L, 1);
2074 if (n == null)
2075 return 1; /* the old userdata */
2076 while (vlink(n) != null)
2077 n = vlink(n);
2078 lua_nodelib_push_fast(L, n);
2079 return 1;
2082 /* node.direct.tail */
2084 static int lua_nodelib_direct_tail(lua_State * L)
2086 halfword n = lua_tointeger(L, 1);
2087 if (n == null) {
2088 lua_pushnil(L);
2089 } else {
2090 while (vlink(n) != null)
2091 n = vlink(n);
2092 lua_pushinteger(L, n);
2094 return 1;
2097 /* node.end_of_math (skip over math and return last) */
2099 static int lua_nodelib_end_of_math(lua_State * L)
2101 halfword n;
2102 if (lua_isnil(L, 1))
2103 return 0;
2104 n = *check_isnode(L, 1);
2105 if (n == null)
2106 return 0;
2107 if (type(n) == math_node && (subtype(n) == 1)) {
2108 lua_nodelib_push_fast(L, n);
2109 return 1;
2111 while (vlink(n) != null) {
2112 n = vlink(n);
2113 if (n && (type(n) == math_node) && (subtype(n) == 1)) {
2114 lua_nodelib_push_fast(L, n);
2115 return 1;
2118 return 0;
2121 /* node.direct.end_of_math */
2123 static int lua_nodelib_direct_end_of_math(lua_State * L)
2125 halfword n = lua_tointeger(L, 1);
2126 if (n == null)
2127 return 0;
2128 if ((type(n)==math_node && (subtype(n)==1))) {
2129 lua_pushinteger(L, n);
2130 return 1;
2132 while (vlink(n) != null) {
2133 n = vlink(n);
2134 if (n && (type(n)==math_node) && (subtype(n)==1)) {
2135 lua_pushinteger(L, n);
2136 return 1;
2139 return 0;
2143 /* node.has_attribute (gets attribute) */
2145 static int lua_nodelib_has_attribute(lua_State * L)
2147 int i, val;
2148 halfword n = *check_isnode(L, 1);
2149 if (n != null) {
2150 i = lua_tointeger(L, 2);
2151 val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2152 if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
2153 lua_pushinteger(L, val);
2154 return 1;
2157 lua_pushnil(L);
2158 return 1;
2161 /* node.direct.has_attribute */
2163 static int lua_nodelib_direct_has_attribute(lua_State * L)
2165 int i, val;
2166 halfword n = lua_tointeger(L, 1);
2167 if (n != null) {
2168 i = lua_tointeger(L, 2);
2169 val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2170 if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
2171 lua_pushinteger(L, val);
2172 return 1;
2175 lua_pushnil(L);
2176 return 1;
2179 /* node.get_attribute */
2181 static int lua_nodelib_get_attribute(lua_State * L)
2183 halfword p;
2184 p = *check_isnode(L, 1);
2185 if (nodetype_has_attributes(type(p))) {
2186 p = node_attr(p);
2187 if (p != null) {
2188 p = vlink(p);
2189 if (p != null) {
2190 int i = lua_tointeger(L, 2);
2191 while (p != null) {
2192 if (attribute_id(p) == i) {
2193 int ret = attribute_value(p);
2194 if (ret == UNUSED_ATTRIBUTE) {
2195 break;
2196 } else {
2197 lua_pushinteger(L,ret);
2198 return 1;
2200 } else if (attribute_id(p) > i) {
2201 break;
2203 p = vlink(p);
2208 lua_pushnil(L);
2209 return 1;
2212 /* node.direct.get_attribute */
2214 static int lua_nodelib_direct_get_attribute(lua_State * L)
2216 register halfword p = lua_tointeger(L, 1);
2217 if (nodetype_has_attributes(type(p))) {
2218 p = node_attr(p);
2219 if (p != null) {
2220 p = vlink(p);
2221 if (p != null) {
2222 int i = lua_tointeger(L, 2);
2223 while (p != null) {
2224 if (attribute_id(p) == i) {
2225 int ret = attribute_value(p);
2226 if (ret == UNUSED_ATTRIBUTE) {
2227 break;
2228 } else {
2229 lua_pushinteger(L,ret);
2230 return 1;
2232 } else if (attribute_id(p) > i) {
2233 break;
2235 p = vlink(p);
2240 lua_pushnil(L);
2241 return 1;
2244 /* node.set_attribute */
2246 static int lua_nodelib_set_attribute(lua_State * L)
2248 if (lua_gettop(L) == 3) {
2249 int i = lua_tointeger(L, 2);
2250 int val = lua_tointeger(L, 3);
2251 halfword n = *check_isnode(L, 1);
2252 if (val == UNUSED_ATTRIBUTE) {
2253 (void) unset_attribute(n, i, val);
2254 } else {
2255 set_attribute(n, i, val);
2257 } else {
2258 luaL_error(L, "incorrect number of arguments");
2260 return 0;
2263 /* node.direct.set_attribute */
2265 static int lua_nodelib_direct_set_attribute(lua_State * L)
2267 int i, val;
2268 halfword n = lua_tointeger(L, 1);
2269 if (n == null)
2270 return 0;
2271 if (lua_gettop(L) == 3) {
2272 i = (int) lua_tointeger(L, 2);
2273 val = (int) lua_tointeger(L, 3);
2274 if (val == UNUSED_ATTRIBUTE) {
2275 (void) unset_attribute(n, i, val);
2276 } else {
2277 set_attribute(n, i, val);
2279 } else {
2280 luaL_error(L, "incorrect number of arguments");
2282 return 0;
2285 /* node.unset_attribute */
2287 static int lua_nodelib_unset_attribute(lua_State * L)
2289 if (lua_gettop(L) <= 3) {
2290 int i = luaL_checknumber(L, 2);
2291 int val = luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2292 halfword n = *check_isnode(L, 1);
2293 int ret = unset_attribute(n, i, val);
2294 if (ret > UNUSED_ATTRIBUTE) {
2295 lua_pushinteger(L, ret);
2296 } else {
2297 lua_pushnil(L);
2299 return 1;
2300 } else {
2301 return luaL_error(L, "incorrect number of arguments");
2305 /* node.direct.unset_attribute */
2307 static int lua_nodelib_direct_unset_attribute(lua_State * L)
2309 halfword n = lua_tointeger(L, 1);
2310 if (n == null) {
2311 lua_pushnil(L);
2312 } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
2313 int i = (int)luaL_checknumber(L, 2);
2314 int val = (int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2315 int ret = unset_attribute(n, i, val);
2316 if (ret > UNUSED_ATTRIBUTE) {
2317 lua_pushinteger(L, ret);
2318 } else {
2319 lua_pushnil(L);
2321 } else { /* can go */
2322 return luaL_error(L, "incorrect number of arguments");
2324 return 1;
2327 /* glue */
2329 static int lua_nodelib_set_glue(lua_State * L)
2331 halfword n = *check_isnode(L, 1);
2332 int top = lua_gettop(L) ;
2333 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2334 width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_tointeger(L,2) : 0;
2335 stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
2336 shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
2337 stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
2338 shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
2339 return 0;
2340 } else {
2341 return luaL_error(L, "glue (spec) expected");
2345 static int lua_nodelib_direct_set_glue(lua_State * L)
2347 halfword n = lua_tointeger(L, 1);
2348 int top = lua_gettop(L) ;
2349 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2350 width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_tointeger(L,2) : 0;
2351 stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
2352 shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
2353 stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
2354 shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
2355 return 0;
2356 } else {
2357 return luaL_error(L, "glue (spec) expected");
2361 static int lua_nodelib_get_glue(lua_State * L)
2363 halfword n = *check_isnode(L, 1);
2364 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2365 lua_pushinteger(L,width(n));
2366 lua_pushinteger(L,stretch(n));
2367 lua_pushinteger(L,shrink(n));
2368 lua_pushinteger(L,stretch_order(n));
2369 lua_pushinteger(L,shrink_order(n));
2370 return 5;
2371 } else {
2372 return luaL_error(L, "glue (spec) expected");
2376 static int lua_nodelib_direct_get_glue(lua_State * L)
2378 halfword n = lua_tointeger(L, 1);
2379 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2380 lua_pushinteger(L,width(n));
2381 lua_pushinteger(L,stretch(n));
2382 lua_pushinteger(L,shrink(n));
2383 lua_pushinteger(L,stretch_order(n));
2384 lua_pushinteger(L,shrink_order(n));
2385 return 5;
2386 } else {
2387 return luaL_error(L, "glue (spec) expected");
2391 static int lua_nodelib_is_zero_glue(lua_State * L)
2393 halfword n = *check_isnode(L, 1);
2394 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2395 lua_toboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
2396 return 1;
2397 } else {
2398 return luaL_error(L, "glue (spec) expected");
2402 static int lua_nodelib_direct_is_zero_glue(lua_State * L)
2404 halfword n = lua_tointeger(L, 1);
2405 if ((n != null) && (type(n) == glue_node || type(n) == glue_spec_node)) {
2406 lua_toboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
2407 return 1;
2408 } else {
2409 return luaL_error(L, "glue (spec) expected");
2413 /* iteration */
2415 static int nodelib_aux_nil(lua_State * L)
2417 lua_pushnil(L);
2418 return 1;
2421 /* node.traverse_id */
2423 static int nodelib_aux_next_filtered(lua_State * L)
2425 halfword t; /* traverser */
2426 halfword *a;
2427 int i = (int) lua_tointeger(L, lua_upvalueindex(1));
2428 if (lua_isnil(L, 2)) { /* first call */
2429 t = *check_isnode(L, 1);
2430 lua_settop(L,1);
2431 } else {
2432 t = *check_isnode(L, 2);
2433 t = vlink(t);
2434 lua_settop(L,2);
2436 while (t != null && type(t) != i) {
2437 t = vlink(t);
2439 if (t == null) {
2440 lua_pushnil(L);
2441 } else {
2442 fast_metatable_top(t);
2444 return 1;
2447 static int lua_nodelib_traverse_filtered(lua_State * L)
2449 halfword n;
2450 if (lua_isnil(L, 2)) {
2451 lua_pushcclosure(L, nodelib_aux_nil, 0);
2452 return 1;
2454 n = *check_isnode(L, 2);
2455 lua_pop(L, 1); /* the node, integer remains */
2456 lua_pushcclosure(L, nodelib_aux_next_filtered, 1);
2457 lua_nodelib_push_fast(L, n);
2458 lua_pushnil(L);
2459 return 3;
2462 /* node.direct.traverse_id */
2464 static int nodelib_direct_aux_next_filtered(lua_State * L)
2466 halfword t; /* traverser */
2467 int i = (int) lua_tointeger(L, lua_upvalueindex(1));
2468 if (lua_isnil(L, 2)) { /* first call */
2469 t = lua_tointeger(L,1) ;
2470 lua_settop(L,1);
2471 } else {
2472 t = lua_tointeger(L,2) ;
2473 t = vlink(t);
2474 lua_settop(L,2);
2476 while (1) {
2477 if (t == null) {
2478 break;
2479 } else if (type(t) == i) {
2480 lua_pushinteger(L,t);
2481 return 1;
2482 } else {
2483 t = vlink(t);
2486 lua_pushnil(L);
2487 return 1;
2490 static int lua_nodelib_direct_traverse_filtered(lua_State * L)
2492 halfword n;
2493 if (lua_isnil(L, 2)) {
2494 lua_pushcclosure(L, nodelib_aux_nil, 0);
2495 return 1;
2497 n = (halfword) lua_tointeger(L, 2);
2498 if (n == null)
2499 return 0;
2500 lua_pop(L, 1);
2501 lua_pushcclosure(L, nodelib_direct_aux_next_filtered, 1);
2502 lua_pushinteger(L,n);
2503 lua_pushnil(L);
2504 return 3;
2507 /* node.direct.traverse_char */
2509 static int nodelib_direct_aux_next_char(lua_State * L)
2511 halfword t; /* traverser */
2512 if (lua_isnil(L, 2)) { /* first call */
2513 t = lua_tointeger(L,1) ;
2514 lua_settop(L,1);
2515 } else {
2516 t = lua_tointeger(L,2) ;
2517 t = vlink(t);
2518 lua_settop(L,2);
2520 while (1) {
2521 if (t == null) {
2522 break;
2523 } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
2524 lua_pushinteger(L,t);
2525 return 1;
2526 } else {
2527 t = vlink(t);
2530 lua_pushnil(L);
2531 return 1;
2534 static int lua_nodelib_direct_traverse_char(lua_State * L)
2536 halfword n;
2537 if (lua_isnil(L, 1)) {
2538 lua_pushcclosure(L, nodelib_aux_nil, 0);
2539 return 1;
2541 n = (halfword) lua_tointeger(L, 1);
2542 if (n == null) {
2543 lua_pushcclosure(L, nodelib_aux_nil, 0);
2544 return 1;
2546 lua_pushcclosure(L, nodelib_direct_aux_next_char, 0);
2547 lua_pushinteger(L,n);
2548 lua_pushnil(L);
2549 return 3;
2552 /* node.traverse */
2554 static int nodelib_aux_next(lua_State * L)
2556 halfword t; /* traverser */
2557 halfword *a; /* a or *a */
2558 if (lua_isnil(L, 2)) { /* first call */
2559 t = *check_isnode(L, 1);
2560 lua_settop(L,1);
2561 } else {
2562 t = *check_isnode(L, 2);
2563 t = vlink(t);
2564 lua_settop(L,2);
2566 if (t == null) {
2567 lua_pushnil(L);
2568 } else {
2569 fast_metatable_top(t);
2571 return 1;
2574 static int lua_nodelib_traverse(lua_State * L)
2576 halfword n;
2577 if (lua_isnil(L, 1)) {
2578 lua_pushcclosure(L, nodelib_aux_nil, 0);
2579 return 1;
2581 n = *check_isnode(L, 1);
2582 lua_pushcclosure(L, nodelib_aux_next, 0);
2583 lua_nodelib_push_fast(L, n);
2584 lua_pushnil(L);
2585 return 3;
2588 /* node.traverse_char */
2590 static int nodelib_aux_next_char(lua_State * L)
2592 halfword t; /* traverser */
2593 halfword *a;
2594 if (lua_isnil(L, 2)) { /* first call */
2595 t = *check_isnode(L, 1);
2596 lua_settop(L,1);
2597 } else {
2598 t = *check_isnode(L, 2);
2599 t = vlink(t);
2600 lua_settop(L,2);
2602 while (1) {
2603 if (t == null) {
2604 break;
2605 } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
2606 fast_metatable_top(t);
2607 return 1;
2608 } else {
2609 t = vlink(t);
2612 return 1;
2615 static int lua_nodelib_traverse_char(lua_State * L)
2617 halfword n;
2618 if (lua_isnil(L, 1)) {
2619 lua_pushcclosure(L, nodelib_aux_nil, 0);
2620 return 1;
2622 n = *check_isnode(L, 1);
2623 lua_pushcclosure(L, nodelib_aux_next_char, 0);
2624 lua_nodelib_push_fast(L, n);
2625 lua_pushnil(L);
2626 return 3;
2629 /* node.direct.traverse */
2631 static int nodelib_direct_aux_next(lua_State * L)
2633 halfword t; /* traverser */
2634 if (lua_isnil(L, 2)) { /* first call */
2635 t = lua_tointeger(L,1) ;
2636 lua_settop(L,1);
2637 } else {
2638 t = lua_tointeger(L,2) ;
2639 t = vlink(t);
2640 lua_settop(L,2);
2642 if (t == null) {
2643 lua_pushnil(L);
2644 } else {
2645 lua_pushinteger(L,t);
2647 return 1;
2650 static int lua_nodelib_direct_traverse(lua_State * L)
2652 halfword n;
2653 if (lua_isnil(L, 1)) {
2654 lua_pushcclosure(L, nodelib_aux_nil, 0);
2655 return 1;
2657 n = (halfword) lua_tointeger(L, 1);
2658 if (n == null) {
2659 lua_pushcclosure(L, nodelib_aux_nil, 0);
2660 return 1;
2662 lua_pushcclosure(L, nodelib_direct_aux_next, 0);
2663 lua_pushinteger(L,n);
2664 lua_pushnil(L);
2665 return 3;
2668 /* counting */
2670 static int do_lua_nodelib_count(lua_State * L, halfword match, int i, halfword first1)
2672 int count = 0;
2673 int t = first1;
2674 while (t != match) {
2675 if (i < 0 || type(t) == i)
2676 count++;
2677 t = vlink(t);
2679 lua_pushinteger(L, count);
2680 return 1;
2683 /* node.length */
2685 static int lua_nodelib_length(lua_State * L)
2687 halfword n;
2688 halfword m = null;
2689 if (lua_isnil(L, 1)) {
2690 lua_pushinteger(L, 0);
2691 return 1;
2693 n = *check_isnode(L, 1);
2694 if (lua_gettop(L) == 2)
2695 m = *check_isnode(L, 2);
2696 return do_lua_nodelib_count(L, m, -1, n);
2699 /* node.direct.length */
2701 static int lua_nodelib_direct_length(lua_State * L)
2703 halfword m;
2704 halfword n = lua_tointeger(L, 1);
2705 if (n == 0) {
2706 lua_pushinteger(L, 0);
2707 return 1;
2709 m = (halfword) lua_tointeger(L, 2);
2710 return do_lua_nodelib_count(L, m, -1, n);
2713 /* node.count */
2715 static int lua_nodelib_count(lua_State * L)
2717 halfword n;
2718 halfword m = null;
2719 int i = lua_tointeger(L, 1);
2720 if (lua_isnil(L, 2)) {
2721 lua_pushinteger(L, 0);
2722 return 1;
2724 n = *check_isnode(L, 2);
2725 if (lua_gettop(L) == 3)
2726 m = *check_isnode(L, 3);
2727 return do_lua_nodelib_count(L, m, i, n);
2730 /* node.direct.count */
2732 static int lua_nodelib_direct_count(lua_State * L)
2734 return do_lua_nodelib_count(L,
2735 (halfword) lua_tointeger(L, 3), /* m */
2736 (int) lua_tointeger(L, 1), /* i */
2737 (halfword) lua_tointeger(L, 2) /* n */
2741 /* getting and setting fields (helpers) */
2743 int nodelib_getlist(lua_State * L, int n)
2745 if (lua_isuserdata(L, n)) {
2746 halfword m = *check_isnode(L, n);
2747 return m;
2748 } else {
2749 return null;
2753 int nodelib_getdir(lua_State * L, int n, int absolute_only)
2755 if (lua_type(L, n) == LUA_TSTRING) {
2756 const char *s = lua_tostring(L, n);
2757 RETURN_DIR_VALUES(TLT);
2758 RETURN_DIR_VALUES(TRT);
2759 RETURN_DIR_VALUES(LTL);
2760 RETURN_DIR_VALUES(RTT);
2761 luaL_error(L, "Bad direction specifier %s", s);
2762 } else {
2763 luaL_error(L, "Direction specifiers have to be strings");
2765 return 0;
2768 static str_number nodelib_getstring(lua_State * L, int a)
2770 size_t k;
2771 const char *s = lua_tolstring(L, a, &k);
2772 return maketexlstring(s, k);
2775 static int nodelib_cantset(lua_State * L, int n, const char *s)
2777 luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name);
2778 return 0;
2781 /* node.direct.getfield */
2783 static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s)
2785 int t = subtype(n);
2786 if (t == user_defined_node) {
2787 if (lua_key_eq(s, user_id)) {
2788 lua_pushinteger(L, user_node_id(n));
2789 } else if (lua_key_eq(s, type)) {
2790 lua_pushinteger(L, user_node_type(n));
2791 } else if (lua_key_eq(s, value)) {
2792 switch (user_node_type(n)) {
2793 case 'a':
2794 nodelib_pushlist(L, user_node_value(n));
2795 break;
2796 case 'd':
2797 lua_pushinteger(L, user_node_value(n));
2798 break;
2799 case 'l':
2800 if (user_node_value(n) != 0) {
2801 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
2802 } else {
2803 lua_pushnil(L);
2805 break;
2806 case 'n':
2807 nodelib_pushlist(L, user_node_value(n));
2808 break;
2809 case 's':
2810 nodelib_pushstring(L, user_node_value(n));
2811 break;
2812 case 't':
2813 tokenlist_to_lua(L, user_node_value(n));
2814 break;
2815 default:
2816 lua_pushinteger(L, user_node_value(n));
2817 break;
2819 } else {
2820 lua_pushnil(L);
2822 } else if (t == pdf_literal_node) {
2823 if (lua_key_eq(s, mode)) {
2824 lua_pushinteger(L, pdf_literal_mode(n));
2825 } else if (lua_key_eq(s, data)) {
2826 if (pdf_literal_type(n) == lua_refid_literal) {
2827 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
2828 } else {
2829 tokenlist_to_luastring(L, pdf_literal_data(n));
2831 } else {
2832 lua_pushnil(L);
2834 } else if (t == late_lua_node) {
2835 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
2836 if (late_lua_type(n) == lua_refid_literal) {
2837 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
2838 } else {
2839 tokenlist_to_luastring(L, late_lua_data(n));
2841 } else if (lua_key_eq(s, name)) {
2842 tokenlist_to_luastring(L, late_lua_name(n));
2843 } else {
2844 lua_pushnil(L);
2846 } else if (t == pdf_annot_node) {
2847 if (lua_key_eq(s, width)) {
2848 lua_pushinteger(L, width(n));
2849 } else if (lua_key_eq(s, depth)) {
2850 lua_pushinteger(L, depth(n));
2851 } else if (lua_key_eq(s, height)) {
2852 lua_pushinteger(L, height(n));
2853 } else if (lua_key_eq(s, objnum)) {
2854 lua_pushinteger(L, pdf_annot_objnum(n));
2855 } else if (lua_key_eq(s, data)) {
2856 tokenlist_to_luastring(L, pdf_annot_data(n));
2857 } else {
2858 lua_pushnil(L);
2860 } else if (t == pdf_dest_node) {
2861 if (lua_key_eq(s, width)) {
2862 lua_pushinteger(L, width(n));
2863 } else if (lua_key_eq(s, depth)) {
2864 lua_pushinteger(L, depth(n));
2865 } else if (lua_key_eq(s, height)) {
2866 lua_pushinteger(L, height(n));
2867 } else if (lua_key_eq(s, named_id)) {
2868 lua_pushinteger(L, pdf_dest_named_id(n));
2869 } else if (lua_key_eq(s, dest_id)) {
2870 if (pdf_dest_named_id(n) == 1)
2871 tokenlist_to_luastring(L, pdf_dest_id(n));
2872 else
2873 lua_pushinteger(L, pdf_dest_id(n));
2874 } else if (lua_key_eq(s, dest_type)) {
2875 lua_pushinteger(L, pdf_dest_type(n));
2876 } else if (lua_key_eq(s, xyz_zoom)) {
2877 lua_pushinteger(L, pdf_dest_xyz_zoom(n));
2878 } else if (lua_key_eq(s, objnum)) {
2879 lua_pushinteger(L, pdf_dest_objnum(n));
2880 } else {
2881 lua_pushnil(L);
2883 } else if (t == pdf_setmatrix_node) {
2884 if (lua_key_eq(s, data)) {
2885 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
2886 } else {
2887 lua_pushnil(L);
2889 } else if (t == pdf_colorstack_node) {
2890 if (lua_key_eq(s, stack)) {
2891 lua_pushinteger(L, pdf_colorstack_stack(n));
2892 } else if (lua_key_eq(s, command)) {
2893 lua_pushinteger(L, pdf_colorstack_cmd(n));
2894 } else if (lua_key_eq(s, data)) {
2895 tokenlist_to_luastring(L, pdf_colorstack_data(n));
2896 } else {
2897 lua_pushnil(L);
2899 } else if (t == pdf_refobj_node) {
2900 if (lua_key_eq(s, objnum)) {
2901 lua_pushinteger(L, pdf_obj_objnum(n));
2902 } else {
2903 lua_pushnil(L);
2905 } else if (t == write_node) {
2906 if (lua_key_eq(s, stream)) {
2907 lua_pushinteger(L, write_stream(n));
2908 } else if (lua_key_eq(s, data)) {
2909 tokenlist_to_lua(L, write_tokens(n));
2910 } else {
2911 lua_pushnil(L);
2913 } else if (t == special_node) {
2914 if (lua_key_eq(s, data)) {
2915 tokenlist_to_luastring(L, write_tokens(n));
2916 } else {
2917 lua_pushnil(L);
2919 } else if (t == pdf_start_link_node) {
2920 if (lua_key_eq(s, width)) {
2921 lua_pushinteger(L, width(n));
2922 } else if (lua_key_eq(s, depth)) {
2923 lua_pushinteger(L, depth(n));
2924 } else if (lua_key_eq(s, height)) {
2925 lua_pushinteger(L, height(n));
2926 } else if (lua_key_eq(s, objnum)) {
2927 lua_pushinteger(L, pdf_link_objnum(n));
2928 } else if (lua_key_eq(s, link_attr)) {
2929 tokenlist_to_luastring(L, pdf_link_attr(n));
2930 } else if (lua_key_eq(s, action)) {
2931 nodelib_pushaction(L, pdf_link_action(n));
2932 } else {
2933 lua_pushnil(L);
2935 } else if (t == pdf_action_node) {
2936 if (lua_key_eq(s, action_type)) {
2937 lua_pushinteger(L, pdf_action_type(n));
2938 } else if (lua_key_eq(s, named_id)) {
2939 lua_pushinteger(L, pdf_action_named_id(n));
2940 } else if (lua_key_eq(s, action_id)) {
2941 if (pdf_action_named_id(n) == 1) {
2942 tokenlist_to_luastring(L, pdf_action_id(n));
2943 } else {
2944 lua_pushinteger(L, pdf_action_id(n));
2946 } else if (lua_key_eq(s, file)) {
2947 tokenlist_to_luastring(L, pdf_action_file(n));
2948 } else if (lua_key_eq(s, new_window)) {
2949 lua_pushinteger(L, pdf_action_new_window(n));
2950 } else if (lua_key_eq(s, data)) {
2951 tokenlist_to_luastring(L, pdf_action_tokens(n));
2952 } else {
2953 lua_pushnil(L);
2955 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
2956 if (lua_key_eq(s, width)) {
2957 lua_pushinteger(L, width(n));
2958 } else if (lua_key_eq(s, depth)) {
2959 lua_pushinteger(L, depth(n));
2960 } else if (lua_key_eq(s, height)) {
2961 lua_pushinteger(L, height(n));
2962 } else if (lua_key_eq(s, named_id)) {
2963 lua_pushinteger(L, pdf_thread_named_id(n));
2964 } else if (lua_key_eq(s, thread_id)) {
2965 if (pdf_thread_named_id(n) == 1) {
2966 tokenlist_to_luastring(L, pdf_thread_id(n));
2967 } else {
2968 lua_pushinteger(L, pdf_thread_id(n));
2970 } else if (lua_key_eq(s, thread_attr)) {
2971 tokenlist_to_luastring(L, pdf_thread_attr(n));
2972 } else {
2973 lua_pushnil(L);
2975 } else if (t == open_node) {
2976 if (lua_key_eq(s, stream)) {
2977 lua_pushinteger(L, write_stream(n));
2978 } else if (lua_key_eq(s, name)) {
2979 nodelib_pushstring(L, open_name(n));
2980 } else if (lua_key_eq(s, area)) {
2981 nodelib_pushstring(L, open_area(n));
2982 } else if (lua_key_eq(s, ext)) {
2983 nodelib_pushstring(L, open_ext(n));
2984 } else {
2985 lua_pushnil(L);
2987 } else if (t == close_node) {
2988 if (lua_key_eq(s, stream)) {
2989 lua_pushinteger(L, write_stream(n));
2990 } else {
2991 lua_pushnil(L);
2993 } else {
2994 lua_pushnil(L);
2998 static int lua_nodelib_fast_getfield(lua_State * L)
3001 the order is somewhat determined by the occurance of nodes and
3002 importance of fields
3005 halfword *a;
3006 const char *s;
3008 halfword n = *((halfword *) lua_touserdata(L, 1));
3009 int t = type(n);
3013 somenode[9] as interface to attributes ... 30% faster than has_attribute
3014 (1) because there is no lua function overhead, and (2) because we already
3015 know that we deal with a node so no checking is needed. The fast typecheck
3016 is needed (lua_check... is a slow down actually).
3020 if (lua_type(L, 2) == LUA_TNUMBER) {
3022 halfword p;
3023 int i;
3025 if (! nodetype_has_attributes(t)) {
3026 lua_pushnil(L);
3027 return 1;
3030 p = node_attr(n);
3031 if (p == null || vlink(p) == null) {
3032 lua_pushnil(L);
3033 return 1;
3035 i = (int) lua_tointeger(L, 2);
3036 p = vlink(p);
3037 while (p != null) {
3038 if (attribute_id(p) == i) {
3039 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
3040 lua_pushinteger(L, (int) attribute_value(p));
3041 } else {
3042 lua_pushnil(L);
3044 return 1;
3045 } else if (attribute_id(p) > i) {
3046 lua_pushnil(L);
3047 return 1;
3049 p = vlink(p);
3051 lua_pushnil(L);
3052 return 1;
3055 s = lua_tostring(L, 2);
3057 if (lua_key_eq(s, id)) {
3058 lua_pushinteger(L, t);
3059 } else if (lua_key_eq(s, next)) {
3060 fast_metatable_or_nil(vlink(n));
3061 } else if (lua_key_eq(s, prev)) {
3062 fast_metatable_or_nil(alink(n));
3063 } else if (lua_key_eq(s, attr)) {
3064 if (! nodetype_has_attributes(t)) {
3065 lua_pushnil(L);
3066 } else {
3067 nodelib_pushattr(L, node_attr(n));
3069 } else if (t == glyph_node) {
3070 /* candidates: fontchar (font,char) whd (width,height,depth) */
3071 if (lua_key_eq(s, subtype)) {
3072 lua_pushinteger(L, subtype(n));
3073 } else if (lua_key_eq(s, font)) {
3074 lua_pushinteger(L, font(n));
3075 } else if (lua_key_eq(s, char)) {
3076 lua_pushinteger(L, character(n));
3077 } else if (lua_key_eq(s, xoffset)) {
3078 lua_pushinteger(L, x_displace(n));
3079 } else if (lua_key_eq(s, yoffset)) {
3080 lua_pushinteger(L, y_displace(n));
3081 } else if (lua_key_eq(s, xadvance)) {
3082 lua_pushinteger(L, x_advance(n));
3083 } else if (lua_key_eq(s, width)) {
3084 lua_pushinteger(L, char_width(font(n),character(n)));
3085 } else if (lua_key_eq(s, height)) {
3086 lua_pushinteger(L, char_height(font(n),character(n)));
3087 } else if (lua_key_eq(s, depth)) {
3088 lua_pushinteger(L, char_depth(font(n),character(n)));
3089 } else if (lua_key_eq(s, expansion_factor)) {
3090 lua_pushinteger(L, ex_glyph(n));
3091 } else if (lua_key_eq(s, components)) {
3092 fast_metatable_or_nil(lig_ptr(n));
3093 } else if (lua_key_eq(s, lang)) {
3094 lua_pushinteger(L, char_lang(n));
3095 } else if (lua_key_eq(s, left)) {
3096 lua_pushinteger(L, char_lhmin(n));
3097 } else if (lua_key_eq(s, right)) {
3098 lua_pushinteger(L, char_rhmin(n));
3099 } else if (lua_key_eq(s, uchyph)) {
3100 lua_pushinteger(L, char_uchyph(n));
3101 } else {
3102 lua_pushnil(L);
3104 } else if ((t == hlist_node) || (t == vlist_node)) {
3105 /* candidates: whd (width,height,depth) */
3106 if (lua_key_eq(s, subtype)) {
3107 lua_pushinteger(L, subtype(n));
3108 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
3109 fast_metatable_or_nil_alink(list_ptr(n));
3110 } else if (lua_key_eq(s, width)) {
3111 lua_pushinteger(L, width(n));
3112 } else if (lua_key_eq(s, height)) {
3113 lua_pushinteger(L, height(n));
3114 } else if (lua_key_eq(s, depth)) {
3115 lua_pushinteger(L, depth(n));
3116 } else if (lua_key_eq(s, dir)) {
3117 lua_push_dir_par(L, box_dir(n));
3118 } else if (lua_key_eq(s, shift)) {
3119 lua_pushinteger(L, shift_amount(n));
3120 } else if (lua_key_eq(s, glue_order)) {
3121 lua_pushinteger(L, glue_order(n));
3122 } else if (lua_key_eq(s, glue_sign)) {
3123 lua_pushinteger(L, glue_sign(n));
3124 } else if (lua_key_eq(s, glue_set)) {
3125 lua_pushnumber(L, (double) glue_set(n)); /* float */
3126 } else {
3127 lua_pushnil(L);
3129 } else if (t == disc_node) {
3130 if (lua_key_eq(s, subtype)) {
3131 lua_pushinteger(L, subtype(n));
3132 } else if (lua_key_eq(s, pre)) {
3133 fast_metatable_or_nil(vlink(pre_break(n)));
3134 } else if (lua_key_eq(s, post)) {
3135 fast_metatable_or_nil(vlink(post_break(n)));
3136 } else if (lua_key_eq(s, replace)) {
3137 fast_metatable_or_nil(vlink(no_break(n)));
3138 } else if (lua_key_eq(s, penalty)) {
3139 lua_pushinteger(L, disc_penalty(n));
3140 } else {
3141 lua_pushnil(L);
3143 } else if (t == glue_node) {
3144 if (lua_key_eq(s, subtype)) {
3145 lua_pushinteger(L, subtype(n));
3146 } else if (lua_key_eq(s, width)) {
3147 lua_pushinteger(L, width(n));
3148 } else if (lua_key_eq(s, stretch)) {
3149 lua_pushinteger(L, stretch(n));
3150 } else if (lua_key_eq(s, shrink)) {
3151 lua_pushinteger(L, shrink(n));
3152 } else if (lua_key_eq(s, stretch_order)) {
3153 lua_pushinteger(L, stretch_order(n));
3154 } else if (lua_key_eq(s, shrink_order)) {
3155 lua_pushinteger(L, shrink_order(n));
3156 } else if (lua_key_eq(s, leader)) {
3157 fast_metatable_or_nil(leader_ptr(n));
3158 } else {
3159 lua_pushnil(L);
3161 } else if (t == kern_node) {
3162 if (lua_key_eq(s, subtype)) {
3163 lua_pushinteger(L, subtype(n));
3164 } else if (lua_key_eq(s, kern)) {
3165 lua_pushinteger(L, width(n));
3166 } else if (lua_key_eq(s, expansion_factor)) {
3167 lua_pushinteger(L, ex_kern(n));
3168 } else {
3169 lua_pushnil(L);
3171 } else if (t == penalty_node) {
3172 if (lua_key_eq(s, subtype)) {
3173 lua_pushinteger(L, subtype(n));
3174 } else if (lua_key_eq(s, penalty)) {
3175 lua_pushinteger(L, penalty(n));
3176 } else {
3177 lua_pushnil(L);
3179 } else if (t == rule_node) {
3180 /* candidates: whd (width,height,depth) */
3181 if (lua_key_eq(s, subtype)) {
3182 lua_pushinteger(L, subtype(n));
3183 } else if (lua_key_eq(s, width)) {
3184 lua_pushinteger(L, width(n));
3185 } else if (lua_key_eq(s, height)) {
3186 lua_pushinteger(L, height(n));
3187 } else if (lua_key_eq(s, depth)) {
3188 lua_pushinteger(L, depth(n));
3189 } else if (lua_key_eq(s, dir)) {
3190 lua_push_dir_par(L, rule_dir(n));
3191 } else if (lua_key_eq(s, index)) {
3192 lua_pushinteger(L, rule_index(n));
3193 } else if (lua_key_eq(s, transform)) {
3194 lua_pushinteger(L,rule_transform(n));
3195 } else {
3196 lua_pushnil(L);
3198 } else if (t == dir_node) {
3199 if (lua_key_eq(s, dir)) {
3200 lua_push_dir_text(L, dir_dir(n));
3201 } else if (lua_key_eq(s, level)) {
3202 lua_pushinteger(L, dir_level(n));
3203 } else if (lua_key_eq(s, subtype)) { /* can be used for anything */
3204 lua_pushinteger(L, subtype(n));
3205 } else {
3206 lua_pushnil(L);
3208 } else if (t == local_par_node) {
3209 if (lua_key_eq(s, pen_inter)) {
3210 lua_pushinteger(L, local_pen_inter(n));
3211 } else if (lua_key_eq(s, pen_broken)) {
3212 lua_pushinteger(L, local_pen_broken(n));
3213 } else if (lua_key_eq(s, dir)) {
3214 lua_push_dir_par(L, local_par_dir(n));
3215 } else if (lua_key_eq(s, box_left)) {
3216 /* can be: fast_metatable_or_nil(local_box_left(n)) */
3217 nodelib_pushlist(L, local_box_left(n));
3218 } else if (lua_key_eq(s, box_left_width)) {
3219 lua_pushinteger(L, local_box_left_width(n));
3220 } else if (lua_key_eq(s, box_right)) {
3221 /* can be: fast_metatable_or_nil(local_box_right(n)) */
3222 nodelib_pushlist(L, local_box_right(n));
3223 } else if (lua_key_eq(s, box_right_width)) {
3224 lua_pushinteger(L, local_box_right_width(n));
3225 } else {
3226 lua_pushnil(L);
3228 } else if (t == glue_spec_node) {
3229 if (lua_key_eq(s, width)) {
3230 lua_pushinteger(L, width(n));
3231 } else if (lua_key_eq(s, stretch)) {
3232 lua_pushinteger(L, stretch(n));
3233 } else if (lua_key_eq(s, shrink)) {
3234 lua_pushinteger(L, shrink(n));
3235 } else if (lua_key_eq(s, stretch_order)) {
3236 lua_pushinteger(L, stretch_order(n));
3237 } else if (lua_key_eq(s, shrink_order)) {
3238 lua_pushinteger(L, shrink_order(n));
3239 } else {
3240 lua_pushnil(L);
3242 } else if (t == whatsit_node) {
3243 if (lua_key_eq(s, subtype)) {
3244 lua_pushinteger(L, subtype(n));
3245 } else {
3246 lua_nodelib_getfield_whatsit(L, n, s);
3248 } else if (t == simple_noad) {
3249 if (lua_key_eq(s, subtype)) {
3250 lua_pushinteger(L, subtype(n));
3251 } else if (lua_key_eq(s, nucleus)) {
3252 fast_metatable_or_nil(nucleus(n));
3253 } else if (lua_key_eq(s, sub)) {
3254 fast_metatable_or_nil(subscr(n));
3255 } else if (lua_key_eq(s, sup)) {
3256 fast_metatable_or_nil(supscr(n));
3257 } else {
3258 lua_pushnil(L);
3260 } else if ((t == math_char_node) || (t == math_text_char_node)) {
3261 /* candidates: famchar (fam,char) */
3262 if (lua_key_eq(s, subtype)) {
3263 lua_pushinteger(L, subtype(n));
3264 } else if (lua_key_eq(s, fam)) {
3265 lua_pushinteger(L, math_fam(n));
3266 } else if (lua_key_eq(s, char)) {
3267 lua_pushinteger(L, math_character(n));
3268 } else if (lua_key_eq(s, font)) {
3269 lua_pushinteger(L, fam_fnt(math_fam(n), 0));
3270 } else {
3271 lua_pushnil(L);
3273 } else if (t == mark_node) {
3274 if (lua_key_eq(s, subtype)) {
3275 lua_pushinteger(L, subtype(n));
3276 } else if (lua_key_eq(s, class)) {
3277 lua_pushinteger(L, mark_class(n));
3278 } else if (lua_key_eq(s, mark)) {
3279 tokenlist_to_lua(L, mark_ptr(n));
3280 } else {
3281 lua_pushnil(L);
3283 } else if (t == ins_node) {
3284 if (lua_key_eq(s, subtype)) {
3285 lua_pushinteger(L, subtype(n));
3286 } else if (lua_key_eq(s, cost)) {
3287 lua_pushinteger(L, float_cost(n));
3288 } else if (lua_key_eq(s, depth)) {
3289 lua_pushinteger(L, depth(n));
3290 } else if (lua_key_eq(s, height)) {
3291 lua_pushinteger(L, height(n));
3292 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) { /* already mapped */
3293 fast_metatable_or_nil_alink(ins_ptr(n));
3294 /* glue parameters */
3295 } else if (lua_key_eq(s, width)) {
3296 lua_pushinteger(L, width(n));
3297 } else if (lua_key_eq(s, stretch)) {
3298 lua_pushinteger(L, stretch(n));
3299 } else if (lua_key_eq(s, shrink)) {
3300 lua_pushinteger(L, shrink(n));
3301 } else if (lua_key_eq(s, stretch_order)) {
3302 lua_pushinteger(L, stretch_order(n));
3303 } else if (lua_key_eq(s, shrink_order)) {
3304 lua_pushinteger(L, shrink_order(n));
3305 } else {
3306 lua_pushnil(L);
3308 } else if (t == math_node) {
3309 if (lua_key_eq(s, subtype)) {
3310 lua_pushinteger(L, subtype(n));
3311 } else if (lua_key_eq(s, surround)) {
3312 lua_pushinteger(L, surround(n));
3313 /* glue parameters */
3314 } else if (lua_key_eq(s, width)) {
3315 lua_pushinteger(L, width(n));
3316 } else if (lua_key_eq(s, stretch)) {
3317 lua_pushinteger(L, stretch(n));
3318 } else if (lua_key_eq(s, shrink)) {
3319 lua_pushinteger(L, shrink(n));
3320 } else if (lua_key_eq(s, stretch_order)) {
3321 lua_pushinteger(L, stretch_order(n));
3322 } else if (lua_key_eq(s, shrink_order)) {
3323 lua_pushinteger(L, shrink_order(n));
3324 } else {
3325 lua_pushnil(L);
3327 } else if (t == fraction_noad) {
3328 if (lua_key_eq(s, subtype)) {
3329 lua_pushinteger(L, subtype(n));
3330 } else if (lua_key_eq(s, width)) {
3331 lua_pushinteger(L, thickness(n));
3332 } else if (lua_key_eq(s, num)) {
3333 fast_metatable_or_nil(numerator(n));
3334 } else if (lua_key_eq(s, denom)) {
3335 fast_metatable_or_nil(denominator(n));
3336 } else if (lua_key_eq(s, left)) {
3337 fast_metatable_or_nil(left_delimiter(n));
3338 } else if (lua_key_eq(s, right)) {
3339 fast_metatable_or_nil(right_delimiter(n));
3340 } else {
3341 lua_pushnil(L);
3343 } else if (t == style_node) {
3344 if (lua_key_eq(s, subtype)) {
3345 lua_pushinteger(L, subtype(n));
3346 } else if (lua_key_eq(s, style)) {
3347 lua_push_math_style_name(L,subtype(n));
3348 } else {
3349 lua_pushnil(L);
3351 } else if (t == accent_noad) {
3352 if (lua_key_eq(s, subtype)) {
3353 lua_pushinteger(L, subtype(n));
3354 } else if (lua_key_eq(s, nucleus)) {
3355 fast_metatable_or_nil(nucleus(n));
3356 } else if (lua_key_eq(s, sub)) {
3357 fast_metatable_or_nil(subscr(n));
3358 } else if (lua_key_eq(s, sup)) {
3359 fast_metatable_or_nil(supscr(n));
3360 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
3361 fast_metatable_or_nil(top_accent_chr(n));
3362 } else if (lua_key_eq(s, bot_accent)) {
3363 fast_metatable_or_nil(bot_accent_chr(n));
3364 } else if (lua_key_eq(s, overlay_accent)) {
3365 fast_metatable_or_nil(overlay_accent_chr(n));
3366 } else {
3367 lua_pushnil(L);
3369 } else if (t == fence_noad) {
3370 if (lua_key_eq(s, subtype)) {
3371 lua_pushinteger(L, subtype(n));
3372 } else if (lua_key_eq(s, delim)) {
3373 fast_metatable_or_nil(delimiter(n));
3374 } else {
3375 lua_pushnil(L);
3377 } else if (t == delim_node) {
3378 if (lua_key_eq(s, subtype)) {
3379 lua_pushinteger(L, subtype(n));
3380 } else if (lua_key_eq(s, small_fam)) {
3381 lua_pushinteger(L, small_fam(n));
3382 } else if (lua_key_eq(s, small_char)) {
3383 lua_pushinteger(L, small_char(n));
3384 } else if (lua_key_eq(s, large_fam)) {
3385 lua_pushinteger(L, large_fam(n));
3386 } else if (lua_key_eq(s, large_char)) {
3387 lua_pushinteger(L, large_char(n));
3388 } else {
3389 lua_pushnil(L);
3391 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
3392 if (lua_key_eq(s, subtype)) {
3393 lua_pushinteger(L, subtype(n));
3394 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3395 fast_metatable_or_nil_alink(math_list(n));
3396 } else {
3397 lua_pushnil(L);
3399 } else if (t == radical_noad) {
3400 if (lua_key_eq(s, subtype)) {
3401 lua_pushinteger(L, subtype(n));
3402 } else if (lua_key_eq(s, nucleus)) {
3403 fast_metatable_or_nil(nucleus(n));
3404 } else if (lua_key_eq(s, sub)) {
3405 fast_metatable_or_nil(subscr(n));
3406 } else if (lua_key_eq(s, sup)) {
3407 fast_metatable_or_nil(supscr(n));
3408 } else if (lua_key_eq(s, left)) {
3409 fast_metatable_or_nil(left_delimiter(n));
3410 } else if (lua_key_eq(s, degree)) {
3411 fast_metatable_or_nil(degree(n));
3412 } else {
3413 lua_pushnil(L);
3415 } else if (t == margin_kern_node) {
3416 if (lua_key_eq(s, subtype)) {
3417 lua_pushinteger(L, subtype(n));
3418 } else if (lua_key_eq(s, width)) {
3419 lua_pushinteger(L, width(n));
3420 } else if (lua_key_eq(s, glyph)) {
3421 fast_metatable_or_nil(margin_char(n));
3422 } else {
3423 lua_pushnil(L);
3425 } else if (t == split_up_node) {
3426 if (lua_key_eq(s, subtype)) {
3427 lua_pushinteger(L, subtype(n));
3428 } else if (lua_key_eq(s, last_ins_ptr)) {
3429 fast_metatable_or_nil(last_ins_ptr(n));
3430 } else if (lua_key_eq(s, best_ins_ptr)) {
3431 fast_metatable_or_nil(best_ins_ptr(n));
3432 } else if (lua_key_eq(s, broken_ptr)) {
3433 fast_metatable_or_nil(broken_ptr(n));
3434 } else if (lua_key_eq(s, broken_ins)) {
3435 fast_metatable_or_nil(broken_ins(n));
3436 } else {
3437 lua_pushnil(L);
3439 } else if (t == choice_node) {
3440 if (lua_key_eq(s, subtype)) {
3441 lua_pushinteger(L, subtype(n));
3442 } else if (lua_key_eq(s, display)) {
3443 fast_metatable_or_nil(display_mlist(n));
3444 } else if (lua_key_eq(s, text)) {
3445 fast_metatable_or_nil(text_mlist(n));
3446 } else if (lua_key_eq(s, script)) {
3447 fast_metatable_or_nil(script_mlist(n));
3448 } else if (lua_key_eq(s, scriptscript)) {
3449 fast_metatable_or_nil(script_script_mlist(n));
3450 } else {
3451 lua_pushnil(L);
3453 } else if (t == inserting_node) {
3454 if (lua_key_eq(s, subtype)) {
3455 lua_pushinteger(L, subtype(n));
3456 } else if (lua_key_eq(s, last_ins_ptr)) {
3457 fast_metatable_or_nil(last_ins_ptr(n));
3458 } else if (lua_key_eq(s, best_ins_ptr)) {
3459 fast_metatable_or_nil(best_ins_ptr(n));
3460 } else {
3461 lua_pushnil(L);
3463 } else if (t == attribute_node) {
3464 if (lua_key_eq(s, subtype)) {
3465 lua_pushinteger(L, subtype(n));
3466 } else if (lua_key_eq(s, number)) {
3467 lua_pushinteger(L, attribute_id(n));
3468 } else if (lua_key_eq(s, value)) {
3469 lua_pushinteger(L, attribute_value(n));
3470 } else {
3471 lua_pushnil(L);
3473 } else if (t == adjust_node) {
3474 if (lua_key_eq(s, subtype)) {
3475 lua_pushinteger(L, subtype(n));
3476 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3477 fast_metatable_or_nil_alink(adjust_ptr(n));
3478 } else {
3479 lua_pushnil(L);
3481 } else if (t == unset_node) {
3482 if (lua_key_eq(s, subtype)) {
3483 lua_pushinteger(L, subtype(n));
3484 } else if (lua_key_eq(s, width)) {
3485 lua_pushinteger(L, width(n));
3486 } else if (lua_key_eq(s, height)) {
3487 lua_pushinteger(L, height(n));
3488 } else if (lua_key_eq(s, depth)) {
3489 lua_pushinteger(L, depth(n));
3490 } else if (lua_key_eq(s, dir)) {
3491 lua_push_dir_par(L, box_dir(n));
3492 } else if (lua_key_eq(s, shrink)) {
3493 lua_pushinteger(L, glue_shrink(n));
3494 } else if (lua_key_eq(s, glue_order)) {
3495 lua_pushinteger(L, glue_order(n));
3496 } else if (lua_key_eq(s, glue_sign)) {
3497 lua_pushinteger(L, glue_sign(n));
3498 } else if (lua_key_eq(s, stretch)) {
3499 lua_pushinteger(L, glue_stretch(n));
3500 } else if (lua_key_eq(s, count)) {
3501 lua_pushinteger(L, span_count(n));
3502 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3503 fast_metatable_or_nil_alink(list_ptr(n));
3504 } else {
3505 lua_pushnil(L);
3507 } else if (t == attribute_list_node) {
3508 if (lua_key_eq(s, subtype)) {
3509 lua_pushinteger(L, subtype(n));
3510 } else {
3511 lua_pushnil(L);
3513 } else if (t == boundary_node) {
3514 if (lua_key_eq(s, subtype)) {
3515 lua_pushinteger(L, subtype(n));
3516 } else if (lua_key_eq(s, value)) {
3517 lua_pushinteger(L, boundary_value(n));
3518 } else {
3519 lua_pushnil(L);
3521 } else {
3522 lua_pushnil(L);
3524 return 1;
3527 static int lua_nodelib_getfield(lua_State * L)
3529 /* [given-node] [...]*/
3530 halfword *p = lua_touserdata(L, 1);
3531 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
3532 lua_pushnil(L) ;
3533 return 1;
3535 /* [given-node] [mt-given-node]*/
3536 lua_get_metatablelua(luatex_node);
3537 /* [given-node] [mt-given-node] [mt-node]*/
3538 if (!lua_rawequal(L, -1, -2)) {
3539 lua_pushnil(L) ;
3540 return 1;
3542 /* prune stack and call getfield */
3543 lua_settop(L,2);
3544 return lua_nodelib_fast_getfield(L);
3547 /* node.direct.getfield */
3549 static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char *s)
3551 int t = subtype(n);
3552 if (t == user_defined_node) {
3553 if (lua_key_eq(s, user_id)) {
3554 lua_pushinteger(L, user_node_id(n));
3555 } else if (lua_key_eq(s, type)) {
3556 lua_pushinteger(L, user_node_type(n));
3557 } else if (lua_key_eq(s, value)) {
3558 switch (user_node_type(n)) {
3559 case 'a':
3560 nodelib_pushdirect(user_node_value(n));
3561 break;
3562 case 'd':
3563 lua_pushinteger(L, user_node_value(n));
3564 break;
3565 case 'l':
3566 if (user_node_value(n) != 0) {
3567 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
3568 } else {
3569 lua_pushnil(L);
3571 break;
3572 case 'n':
3573 nodelib_pushdirect(user_node_value(n));
3574 break;
3575 case 's':
3576 nodelib_pushstring(L, user_node_value(n));
3577 break;
3578 case 't':
3579 tokenlist_to_lua(L, user_node_value(n));
3580 break;
3581 default:
3582 lua_pushinteger(L, user_node_value(n));
3583 break;
3585 } else {
3586 lua_pushnil(L);
3588 } else if (t == pdf_literal_node) {
3589 if (lua_key_eq(s, mode)) {
3590 lua_pushinteger(L, pdf_literal_mode(n));
3591 } else if (lua_key_eq(s, data)) {
3592 if (pdf_literal_type(n) == lua_refid_literal) {
3593 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
3594 } else {
3595 tokenlist_to_luastring(L, pdf_literal_data(n));
3597 } else {
3598 lua_pushnil(L);
3600 } else if (t == late_lua_node) {
3601 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
3602 if (late_lua_type(n) == lua_refid_literal) {
3603 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
3604 } else {
3605 tokenlist_to_luastring(L, late_lua_data(n));
3607 } else if (lua_key_eq(s, name)) {
3608 tokenlist_to_luastring(L, late_lua_name(n));
3609 } else {
3610 lua_pushnil(L);
3612 } else if (t == pdf_annot_node) {
3613 if (lua_key_eq(s, width)) {
3614 lua_pushinteger(L, width(n));
3615 } else if (lua_key_eq(s, depth)) {
3616 lua_pushinteger(L, depth(n));
3617 } else if (lua_key_eq(s, height)) {
3618 lua_pushinteger(L, height(n));
3619 } else if (lua_key_eq(s, objnum)) {
3620 lua_pushinteger(L, pdf_annot_objnum(n));
3621 } else if (lua_key_eq(s, data)) {
3622 tokenlist_to_luastring(L, pdf_annot_data(n));
3623 } else {
3624 lua_pushnil(L);
3626 } else if (t == pdf_dest_node) {
3627 if (lua_key_eq(s, width)) {
3628 lua_pushinteger(L, width(n));
3629 } else if (lua_key_eq(s, depth)) {
3630 lua_pushinteger(L, depth(n));
3631 } else if (lua_key_eq(s, height)) {
3632 lua_pushinteger(L, height(n));
3633 } else if (lua_key_eq(s, named_id)) {
3634 lua_pushinteger(L, pdf_dest_named_id(n));
3635 } else if (lua_key_eq(s, dest_id)) {
3636 if (pdf_dest_named_id(n) == 1)
3637 tokenlist_to_luastring(L, pdf_dest_id(n));
3638 else
3639 lua_pushinteger(L, pdf_dest_id(n));
3640 } else if (lua_key_eq(s, dest_type)) {
3641 lua_pushinteger(L, pdf_dest_type(n));
3642 } else if (lua_key_eq(s, xyz_zoom)) {
3643 lua_pushinteger(L, pdf_dest_xyz_zoom(n));
3644 } else if (lua_key_eq(s, objnum)) {
3645 lua_pushinteger(L, pdf_dest_objnum(n));
3646 } else {
3647 lua_pushnil(L);
3649 } else if (t == pdf_setmatrix_node) {
3650 if (lua_key_eq(s, data)) {
3651 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
3652 } else {
3653 lua_pushnil(L);
3655 } else if (t == pdf_colorstack_node) {
3656 if (lua_key_eq(s, stack)) {
3657 lua_pushinteger(L, pdf_colorstack_stack(n));
3658 } else if (lua_key_eq(s, command)) {
3659 lua_pushinteger(L, pdf_colorstack_cmd(n));
3660 } else if (lua_key_eq(s, data)) {
3661 tokenlist_to_luastring(L, pdf_colorstack_data(n));
3662 } else {
3663 lua_pushnil(L);
3665 } else if (t == pdf_refobj_node) {
3666 if (lua_key_eq(s, objnum)) {
3667 lua_pushinteger(L, pdf_obj_objnum(n));
3668 } else {
3669 lua_pushnil(L);
3671 } else if (t == write_node) {
3672 if (lua_key_eq(s, stream)) {
3673 lua_pushinteger(L, write_stream(n));
3674 } else if (lua_key_eq(s, data)) {
3675 tokenlist_to_lua(L, write_tokens(n));
3676 } else {
3677 lua_pushnil(L);
3679 } else if (t == special_node) {
3680 if (lua_key_eq(s, data)) {
3681 tokenlist_to_luastring(L, write_tokens(n));
3682 } else {
3683 lua_pushnil(L);
3685 } else if (t == pdf_start_link_node) {
3686 if (lua_key_eq(s, width)) {
3687 lua_pushinteger(L, width(n));
3688 } else if (lua_key_eq(s, depth)) {
3689 lua_pushinteger(L, depth(n));
3690 } else if (lua_key_eq(s, height)) {
3691 lua_pushinteger(L, height(n));
3692 } else if (lua_key_eq(s, objnum)) {
3693 lua_pushinteger(L, pdf_link_objnum(n));
3694 } else if (lua_key_eq(s, link_attr)) {
3695 tokenlist_to_luastring(L, pdf_link_attr(n));
3696 } else if (lua_key_eq(s, action)) {
3697 nodelib_pushaction(L, pdf_link_action(n));
3698 } else {
3699 lua_pushnil(L);
3701 } else if (t == pdf_action_node) {
3702 if (lua_key_eq(s, action_type)) {
3703 lua_pushinteger(L, pdf_action_type(n));
3704 } else if (lua_key_eq(s, named_id)) {
3705 lua_pushinteger(L, pdf_action_named_id(n));
3706 } else if (lua_key_eq(s, action_id)) {
3707 if (pdf_action_named_id(n) == 1) {
3708 tokenlist_to_luastring(L, pdf_action_id(n));
3709 } else {
3710 lua_pushinteger(L, pdf_action_id(n));
3712 } else if (lua_key_eq(s, file)) {
3713 tokenlist_to_luastring(L, pdf_action_file(n));
3714 } else if (lua_key_eq(s, new_window)) {
3715 lua_pushinteger(L, pdf_action_new_window(n));
3716 } else if (lua_key_eq(s, data)) {
3717 tokenlist_to_luastring(L, pdf_action_tokens(n));
3718 } else {
3719 lua_pushnil(L);
3721 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
3722 if (lua_key_eq(s, width)) {
3723 lua_pushinteger(L, width(n));
3724 } else if (lua_key_eq(s, depth)) {
3725 lua_pushinteger(L, depth(n));
3726 } else if (lua_key_eq(s, height)) {
3727 lua_pushinteger(L, height(n));
3728 } else if (lua_key_eq(s, named_id)) {
3729 lua_pushinteger(L, pdf_thread_named_id(n));
3730 } else if (lua_key_eq(s, thread_id)) {
3731 if (pdf_thread_named_id(n) == 1) {
3732 tokenlist_to_luastring(L, pdf_thread_id(n));
3733 } else {
3734 lua_pushinteger(L, pdf_thread_id(n));
3736 } else if (lua_key_eq(s, thread_attr)) {
3737 tokenlist_to_luastring(L, pdf_thread_attr(n));
3738 } else {
3739 lua_pushnil(L);
3741 } else if (t == open_node) {
3742 if (lua_key_eq(s, stream)) {
3743 lua_pushinteger(L, write_stream(n));
3744 } else if (lua_key_eq(s, name)) {
3745 nodelib_pushstring(L, open_name(n));
3746 } else if (lua_key_eq(s, area)) {
3747 nodelib_pushstring(L, open_area(n));
3748 } else if (lua_key_eq(s, ext)) {
3749 nodelib_pushstring(L, open_ext(n));
3750 } else {
3751 lua_pushnil(L);
3753 } else if (t == close_node) {
3754 if (lua_key_eq(s, stream)) {
3755 lua_pushinteger(L, write_stream(n));
3756 } else {
3757 lua_pushnil(L);
3759 } else {
3760 lua_pushnil(L);
3764 static int lua_nodelib_direct_getfield(lua_State * L)
3767 const char *s;
3768 halfword n = lua_tointeger(L, 1);
3769 int t = type(n);
3770 if (lua_type(L, 2) == LUA_TNUMBER) {
3771 halfword p;
3772 int i;
3773 if (! nodetype_has_attributes(t)) {
3774 lua_pushnil(L) ;
3775 return 1;
3777 p = node_attr(n);
3778 if (p == null || vlink(p) == null) {
3779 lua_pushnil(L) ;
3780 return 1;
3782 i = (int) lua_tointeger(L, 2);
3783 p = vlink(p);
3784 while (p != null) {
3785 if (attribute_id(p) == i) {
3786 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
3787 lua_pushinteger(L, (int) attribute_value(p));
3788 } else {
3789 lua_pushnil(L);
3791 return 1;
3792 } else if (attribute_id(p) > i) {
3793 lua_pushnil(L) ;
3794 return 1;
3796 p = vlink(p);
3798 lua_pushnil(L) ;
3799 return 1;
3802 s = lua_tostring(L, 2);
3804 if (lua_key_eq(s, id)) {
3805 lua_pushinteger(L, t);
3806 } else if (lua_key_eq(s, next)) {
3807 nodelib_pushdirect_or_nil(vlink(n));
3808 } else if (lua_key_eq(s, prev)) {
3809 nodelib_pushdirect_or_nil(alink(n));
3810 } else if (lua_key_eq(s, subtype)) {
3811 if (t == glue_spec_node) {
3812 lua_pushinteger(L, 0); /* dummy, the only one */
3813 } else {
3814 lua_pushinteger(L, subtype(n));
3816 } else if (lua_key_eq(s, attr)) {
3817 if (! nodetype_has_attributes(t)) {
3818 lua_pushnil(L);
3819 } else {
3820 nodelib_pushattr(L, node_attr(n));
3822 } else if (t == glyph_node) {
3823 if (lua_key_eq(s, font)) {
3824 lua_pushinteger(L, font(n));
3825 } else if (lua_key_eq(s, char)) {
3826 lua_pushinteger(L, character(n));
3827 } else if (lua_key_eq(s, xoffset)) {
3828 lua_pushinteger(L, x_displace(n));
3829 } else if (lua_key_eq(s, yoffset)) {
3830 lua_pushinteger(L, y_displace(n));
3831 } else if (lua_key_eq(s, xadvance)) {
3832 lua_pushinteger(L, x_advance(n));
3833 } else if (lua_key_eq(s, width)) {
3834 lua_pushinteger(L, char_width(font(n),character(n)));
3835 } else if (lua_key_eq(s, height)) {
3836 lua_pushinteger(L, char_height(font(n),character(n)));
3837 } else if (lua_key_eq(s, depth)) {
3838 lua_pushinteger(L, char_depth(font(n),character(n)));
3839 } else if (lua_key_eq(s, expansion_factor)) {
3840 lua_pushinteger(L, ex_glyph(n));
3841 } else if (lua_key_eq(s, components)) {
3842 nodelib_pushdirect_or_nil(lig_ptr(n));
3843 } else if (lua_key_eq(s, lang)) {
3844 lua_pushinteger(L, char_lang(n));
3845 } else if (lua_key_eq(s, left)) {
3846 lua_pushinteger(L, char_lhmin(n));
3847 } else if (lua_key_eq(s, right)) {
3848 lua_pushinteger(L, char_rhmin(n));
3849 } else if (lua_key_eq(s, uchyph)) {
3850 lua_pushinteger(L, char_uchyph(n));
3851 } else {
3852 lua_pushnil(L);
3854 } else if ((t == hlist_node) || (t == vlist_node)) {
3855 /* candidates: whd (width,height,depth) */
3856 if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
3857 nodelib_pushdirect_or_nil_alink(list_ptr(n));
3858 } else if (lua_key_eq(s, width)) {
3859 lua_pushinteger(L, width(n));
3860 } else if (lua_key_eq(s, height)) {
3861 lua_pushinteger(L, height(n));
3862 } else if (lua_key_eq(s, depth)) {
3863 lua_pushinteger(L, depth(n));
3864 } else if (lua_key_eq(s, dir)) {
3865 lua_push_dir_par(L, box_dir(n));
3866 } else if (lua_key_eq(s, shift)) {
3867 lua_pushinteger(L, shift_amount(n));
3868 } else if (lua_key_eq(s, glue_order)) {
3869 lua_pushinteger(L, glue_order(n));
3870 } else if (lua_key_eq(s, glue_sign)) {
3871 lua_pushinteger(L, glue_sign(n));
3872 } else if (lua_key_eq(s, glue_set)) {
3873 lua_pushnumber(L, (double) glue_set(n)); /* float */
3874 } else {
3875 lua_pushnil(L);
3877 } else if (t == disc_node) {
3878 if (lua_key_eq(s, pre)) {
3879 nodelib_pushdirect_or_nil(vlink(pre_break(n)));
3880 } else if (lua_key_eq(s, post)) {
3881 nodelib_pushdirect_or_nil(vlink(post_break(n)));
3882 } else if (lua_key_eq(s, replace)) {
3883 nodelib_pushdirect_or_nil(vlink(no_break(n)));
3884 } else if (lua_key_eq(s, penalty)) {
3885 lua_pushinteger(L, disc_penalty(n));
3886 } else {
3887 lua_pushnil(L);
3889 } else if (t == glue_node) {
3890 if (lua_key_eq(s, width)) {
3891 lua_pushinteger(L, width(n));
3892 } else if (lua_key_eq(s, stretch)) {
3893 lua_pushinteger(L, stretch(n));
3894 } else if (lua_key_eq(s, shrink)) {
3895 lua_pushinteger(L, shrink(n));
3896 } else if (lua_key_eq(s, stretch_order)) {
3897 lua_pushinteger(L, stretch_order(n));
3898 } else if (lua_key_eq(s, shrink_order)) {
3899 lua_pushinteger(L, shrink_order(n));
3900 } else if (lua_key_eq(s, leader)) {
3901 nodelib_pushdirect_or_nil(leader_ptr(n));
3902 } else {
3903 lua_pushnil(L);
3905 } else if (t == kern_node) {
3906 if (lua_key_eq(s, kern)) {
3907 lua_pushinteger(L, width(n));
3908 } else if (lua_key_eq(s, expansion_factor)) {
3909 lua_pushinteger(L, ex_kern(n));
3910 } else {
3911 lua_pushnil(L);
3913 } else if (t == penalty_node) {
3914 if (lua_key_eq(s, penalty)) {
3915 lua_pushinteger(L, penalty(n));
3916 } else {
3917 lua_pushnil(L);
3919 } else if (t == rule_node) {
3920 /* candidates: whd (width,height,depth) */
3921 if (lua_key_eq(s, width)) {
3922 lua_pushinteger(L, width(n));
3923 } else if (lua_key_eq(s, height)) {
3924 lua_pushinteger(L, height(n));
3925 } else if (lua_key_eq(s, depth)) {
3926 lua_pushinteger(L, depth(n));
3927 } else if (lua_key_eq(s, dir)) {
3928 lua_push_dir_par(L, rule_dir(n));
3929 } else if (lua_key_eq(s, index)) {
3930 lua_pushinteger(L, rule_index(n));
3931 } else if (lua_key_eq(s, transform)) {
3932 lua_pushinteger(L,rule_transform(n));
3933 } else {
3934 lua_pushnil(L);
3936 } else if (t == dir_node) {
3937 if (lua_key_eq(s, dir)) {
3938 lua_push_dir_text(L, dir_dir(n));
3939 } else if (lua_key_eq(s, level)) {
3940 lua_pushinteger(L, dir_level(n));
3941 } else if (lua_key_eq(s, subtype)) { /* can be used for anything */
3942 lua_pushinteger(L, subtype(n));
3943 } else {
3944 lua_pushnil(L);
3946 } else if (t == local_par_node) {
3947 if (lua_key_eq(s, pen_inter)) {
3948 lua_pushinteger(L, local_pen_inter(n));
3949 } else if (lua_key_eq(s, pen_broken)) {
3950 lua_pushinteger(L, local_pen_broken(n));
3951 } else if (lua_key_eq(s, dir)) {
3952 lua_push_dir_par(L, local_par_dir(n));
3953 } else if (lua_key_eq(s, box_left)) {
3954 nodelib_pushdirect_or_nil(local_box_left(n));
3955 } else if (lua_key_eq(s, box_left_width)) {
3956 lua_pushinteger(L, local_box_left_width(n));
3957 } else if (lua_key_eq(s, box_right)) {
3958 nodelib_pushdirect_or_nil(local_box_right(n));
3959 } else if (lua_key_eq(s, box_right_width)) {
3960 lua_pushinteger(L, local_box_right_width(n));
3961 } else {
3962 lua_pushnil(L);
3964 } else if (t == whatsit_node) {
3965 lua_nodelib_direct_getfield_whatsit(L, n, s);
3966 } else if (t == simple_noad) {
3967 if (lua_key_eq(s, nucleus)) {
3968 nodelib_pushdirect_or_nil(nucleus(n));
3969 } else if (lua_key_eq(s, sub)) {
3970 nodelib_pushdirect_or_nil(subscr(n));
3971 } else if (lua_key_eq(s, sup)) {
3972 nodelib_pushdirect_or_nil(supscr(n));
3973 } else {
3974 lua_pushnil(L);
3976 } else if ((t == math_char_node) || (t == math_text_char_node)) {
3977 if (lua_key_eq(s, fam)) {
3978 lua_pushinteger(L, math_fam(n));
3979 } else if (lua_key_eq(s, char)) {
3980 lua_pushinteger(L, math_character(n));
3981 } else if (lua_key_eq(s, font)) {
3982 lua_pushinteger(L, fam_fnt(math_fam(n), 0));
3983 } else {
3984 lua_pushnil(L);
3986 } else if (t == mark_node) {
3987 if (lua_key_eq(s, class)) {
3988 lua_pushinteger(L, mark_class(n));
3989 } else if (lua_key_eq(s, mark)) {
3990 tokenlist_to_lua(L, mark_ptr(n));
3991 } else {
3992 lua_pushnil(L);
3994 } else if (t == ins_node) {
3995 if (lua_key_eq(s, cost)) {
3996 lua_pushinteger(L, float_cost(n));
3997 } else if (lua_key_eq(s, depth)) {
3998 lua_pushinteger(L, depth(n));
3999 } else if (lua_key_eq(s, height)) {
4000 lua_pushinteger(L, height(n));
4001 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
4002 nodelib_pushdirect_or_nil_alink(ins_ptr(n));
4003 /* glue */
4004 } else if (lua_key_eq(s, width)) {
4005 lua_pushinteger(L, width(n));
4006 } else if (lua_key_eq(s, stretch)) {
4007 lua_pushinteger(L, stretch(n));
4008 } else if (lua_key_eq(s, shrink)) {
4009 lua_pushinteger(L, shrink(n));
4010 } else if (lua_key_eq(s, stretch_order)) {
4011 lua_pushinteger(L, stretch_order(n));
4012 } else if (lua_key_eq(s, shrink_order)) {
4013 lua_pushinteger(L, shrink_order(n));
4014 } else {
4015 lua_pushnil(L);
4017 } else if (t == math_node) {
4018 if (lua_key_eq(s, surround)) {
4019 lua_pushinteger(L, surround(n));
4020 /* glue */
4021 } else if (lua_key_eq(s, width)) {
4022 lua_pushinteger(L, width(n));
4023 } else if (lua_key_eq(s, stretch)) {
4024 lua_pushinteger(L, stretch(n));
4025 } else if (lua_key_eq(s, shrink)) {
4026 lua_pushinteger(L, shrink(n));
4027 } else if (lua_key_eq(s, stretch_order)) {
4028 lua_pushinteger(L, stretch_order(n));
4029 } else if (lua_key_eq(s, shrink_order)) {
4030 lua_pushinteger(L, shrink_order(n));
4031 } else {
4032 lua_pushnil(L);
4034 } else if (t == fraction_noad) {
4035 if (lua_key_eq(s, width)) {
4036 lua_pushinteger(L, thickness(n));
4037 } else if (lua_key_eq(s, num)) {
4038 nodelib_pushdirect_or_nil(numerator(n));
4039 } else if (lua_key_eq(s, denom)) {
4040 nodelib_pushdirect_or_nil(denominator(n));
4041 } else if (lua_key_eq(s, left)) {
4042 nodelib_pushdirect_or_nil(left_delimiter(n));
4043 } else if (lua_key_eq(s, right)) {
4044 nodelib_pushdirect_or_nil(right_delimiter(n));
4045 } else {
4046 lua_pushnil(L);
4048 } else if (t == style_node) {
4049 if (lua_key_eq(s, style)) {
4050 lua_push_math_style_name(L,subtype(n));
4051 } else {
4052 lua_pushnil(L);
4054 } else if (t == accent_noad) {
4055 if (lua_key_eq(s, nucleus)) {
4056 nodelib_pushdirect_or_nil(nucleus(n));
4057 } else if (lua_key_eq(s, sub)) {
4058 nodelib_pushdirect_or_nil(subscr(n));
4059 } else if (lua_key_eq(s, sup)) {
4060 nodelib_pushdirect_or_nil(supscr(n));
4061 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
4062 nodelib_pushdirect_or_nil(top_accent_chr(n));
4063 } else if (lua_key_eq(s, bot_accent)) {
4064 nodelib_pushdirect_or_nil(bot_accent_chr(n));
4065 } else if (lua_key_eq(s, overlay_accent)) {
4066 nodelib_pushdirect_or_nil(overlay_accent_chr(n));
4067 } else {
4068 lua_pushnil(L);
4070 } else if (t == fence_noad) {
4071 if (lua_key_eq(s, delim)) {
4072 nodelib_pushdirect_or_nil(delimiter(n));
4073 } else {
4074 lua_pushnil(L);
4076 } else if (t == delim_node) {
4077 if (lua_key_eq(s, small_fam)) {
4078 lua_pushinteger(L, small_fam(n));
4079 } else if (lua_key_eq(s, small_char)) {
4080 lua_pushinteger(L, small_char(n));
4081 } else if (lua_key_eq(s, large_fam)) {
4082 lua_pushinteger(L, large_fam(n));
4083 } else if (lua_key_eq(s, large_char)) {
4084 lua_pushinteger(L, large_char(n));
4085 } else {
4086 lua_pushnil(L);
4088 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
4089 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
4090 nodelib_pushdirect_or_nil_alink(math_list(n));
4091 } else {
4092 lua_pushnil(L);
4094 } else if (t == radical_noad) {
4095 if (lua_key_eq(s, nucleus)) {
4096 nodelib_pushdirect_or_nil(nucleus(n));
4097 } else if (lua_key_eq(s, sub)) {
4098 nodelib_pushdirect_or_nil(subscr(n));
4099 } else if (lua_key_eq(s, sup)) {
4100 nodelib_pushdirect_or_nil(supscr(n));
4101 } else if (lua_key_eq(s, left)) {
4102 nodelib_pushdirect_or_nil(left_delimiter(n));
4103 } else if (lua_key_eq(s, degree)) {
4104 nodelib_pushdirect_or_nil(degree(n));
4105 } else {
4106 lua_pushnil(L);
4108 } else if (t == margin_kern_node) {
4109 if (lua_key_eq(s, width)) {
4110 lua_pushinteger(L, width(n));
4111 } else if (lua_key_eq(s, glyph)) {
4112 nodelib_pushdirect_or_nil(margin_char(n));
4113 } else {
4114 lua_pushnil(L);
4116 } else if (t == split_up_node) {
4117 if (lua_key_eq(s, last_ins_ptr)) {
4118 nodelib_pushdirect_or_nil(last_ins_ptr(n));
4119 } else if (lua_key_eq(s, best_ins_ptr)) {
4120 nodelib_pushdirect_or_nil(best_ins_ptr(n));
4121 } else if (lua_key_eq(s, broken_ptr)) {
4122 nodelib_pushdirect_or_nil(broken_ptr(n));
4123 } else if (lua_key_eq(s, broken_ins)) {
4124 nodelib_pushdirect_or_nil(broken_ins(n));
4125 } else {
4126 lua_pushnil(L);
4128 } else if (t == choice_node) {
4129 if (lua_key_eq(s, display)) {
4130 nodelib_pushdirect_or_nil(display_mlist(n));
4131 } else if (lua_key_eq(s, text)) {
4132 nodelib_pushdirect_or_nil(text_mlist(n));
4133 } else if (lua_key_eq(s, script)) {
4134 nodelib_pushdirect_or_nil(script_mlist(n));
4135 } else if (lua_key_eq(s, scriptscript)) {
4136 nodelib_pushdirect_or_nil(script_script_mlist(n));
4137 } else {
4138 lua_pushnil(L);
4140 } else if (t == inserting_node) {
4141 if (lua_key_eq(s, last_ins_ptr)) {
4142 nodelib_pushdirect_or_nil(last_ins_ptr(n));
4143 } else if (lua_key_eq(s, best_ins_ptr)) {
4144 nodelib_pushdirect_or_nil(best_ins_ptr(n));
4145 } else {
4146 lua_pushnil(L);
4148 } else if (t == attribute_node) {
4149 if (lua_key_eq(s, number)) {
4150 lua_pushinteger(L, attribute_id(n));
4151 } else if (lua_key_eq(s, value)) {
4152 lua_pushinteger(L, attribute_value(n));
4153 } else {
4154 lua_pushnil(L);
4156 } else if (t == adjust_node) {
4157 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
4158 nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
4159 } else {
4160 lua_pushnil(L);
4162 } else if (t == unset_node) {
4163 if (lua_key_eq(s, width)) {
4164 lua_pushinteger(L, width(n));
4165 } else if (lua_key_eq(s, height)) {
4166 lua_pushinteger(L, height(n));
4167 } else if (lua_key_eq(s, depth)) {
4168 lua_pushinteger(L, depth(n));
4169 } else if (lua_key_eq(s, dir)) {
4170 lua_push_dir_par(L, box_dir(n));
4171 } else if (lua_key_eq(s, shrink)) {
4172 lua_pushinteger(L, glue_shrink(n));
4173 } else if (lua_key_eq(s, glue_order)) {
4174 lua_pushinteger(L, glue_order(n));
4175 } else if (lua_key_eq(s, glue_sign)) {
4176 lua_pushinteger(L, glue_sign(n));
4177 } else if (lua_key_eq(s, stretch)) {
4178 lua_pushinteger(L, glue_stretch(n));
4179 } else if (lua_key_eq(s, count)) {
4180 lua_pushinteger(L, span_count(n));
4181 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
4182 nodelib_pushdirect_or_nil_alink(list_ptr(n));
4183 } else {
4184 lua_pushnil(L);
4186 /* } else if (t == attribute_list_node) { */
4187 /* lua_pushnil(L); */
4188 } else if (t == boundary_node) {
4189 if (lua_key_eq(s, subtype)) {
4190 lua_pushinteger(L, subtype(n));
4191 } else if (lua_key_eq(s, value)) {
4192 lua_pushinteger(L, boundary_value(n));
4193 } else {
4194 lua_pushnil(L);
4196 } else if (t == glue_spec_node) {
4197 if (lua_key_eq(s, width)) {
4198 lua_pushinteger(L, width(n));
4199 } else if (lua_key_eq(s, stretch)) {
4200 lua_pushinteger(L, stretch(n));
4201 } else if (lua_key_eq(s, shrink)) {
4202 lua_pushinteger(L, shrink(n));
4203 } else if (lua_key_eq(s, stretch_order)) {
4204 lua_pushinteger(L, stretch_order(n));
4205 } else if (lua_key_eq(s, shrink_order)) {
4206 lua_pushinteger(L, shrink_order(n));
4207 } else {
4208 lua_pushnil(L);
4210 } else {
4211 lua_pushnil(L);
4213 return 1;
4216 /* msg could be preallocated and shared */
4218 static void lua_nodelib_do_tostring(lua_State * L, halfword n, const char *tag)
4220 char *msg;
4221 char a[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
4222 char v[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
4223 msg = xmalloc(256);
4224 if ((alink(n) != null) && (type(n) != attribute_node))
4225 snprintf(a, 7, "%6d", (int) alink(n));
4226 if (vlink(n) != null)
4227 snprintf(v, 7, "%6d", (int) vlink(n));
4228 snprintf(msg, 255, "<%s %s < %6d > %s : %s %d>", tag, a, (int) n, v, node_data[type(n)].name, subtype(n));
4229 lua_pushstring(L, msg);
4230 free(msg);
4231 return ;
4234 /* __tostring node.tostring */
4236 static int lua_nodelib_tostring(lua_State * L)
4238 halfword n = *check_isnode(L, 1);
4239 lua_nodelib_do_tostring(L, n, "node");
4240 return 1;
4243 /* node.direct.tostring */
4245 static int lua_nodelib_direct_tostring(lua_State * L)
4247 halfword n = lua_tointeger(L,1);
4248 if (n==0) {
4249 lua_pushnil(L);
4250 } else {
4251 lua_nodelib_do_tostring(L, n, "direct");
4253 return 1;
4256 /* __eq */
4258 static int lua_nodelib_equal(lua_State * L)
4260 halfword n = *((halfword *) lua_touserdata(L, 1));
4261 halfword m = *((halfword *) lua_touserdata(L, 2));
4262 lua_pushboolean(L, (n == m));
4263 return 1;
4266 /* node.ligaturing */
4268 static int font_tex_ligaturing(lua_State * L)
4270 /* on the stack are two nodes and a direction */
4271 /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */
4272 halfword tmp_head;
4273 halfword h;
4274 halfword t = null;
4275 halfword p ;
4276 if (lua_gettop(L) < 1) {
4277 lua_pushnil(L);
4278 lua_pushboolean(L, 0);
4279 return 2;
4281 h = *check_isnode(L, 1);
4282 if (lua_gettop(L) > 1) {
4283 t = *check_isnode(L, 2);
4285 tmp_head = new_node(nesting_node, 1);
4286 p = alink(h);
4287 couple_nodes(tmp_head, h);
4288 tlink(tmp_head) = t;
4289 t = handle_ligaturing(tmp_head, t);
4290 if (p != null) {
4291 vlink(p) = vlink(tmp_head) ;
4293 alink(vlink(tmp_head)) = p ;
4295 lua_pushinteger(L, vlink(tmp_head));
4296 lua_nodelib_push(L);
4298 lua_nodelib_push_fast(L, vlink(tmp_head));
4300 lua_pushinteger(L, t);
4301 lua_nodelib_push(L);
4303 lua_nodelib_push_fast(L, t);
4304 lua_pushboolean(L, 1);
4305 flush_node(tmp_head);
4306 return 3;
4309 static int font_tex_direct_ligaturing(lua_State * L)
4311 /* on the stack are two nodes and a direction */
4312 /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */
4313 halfword tmp_head;
4314 halfword h;
4315 halfword t = null;
4316 halfword p ;
4317 if (lua_gettop(L) < 1) {
4318 lua_pushnil(L);
4319 lua_pushboolean(L, 0);
4320 return 2;
4322 h = lua_tointeger(L, 1);
4323 if (lua_gettop(L) > 1) {
4324 t = lua_tointeger(L, 2);
4326 tmp_head = new_node(nesting_node, 1);
4327 p = alink(h);
4328 couple_nodes(tmp_head, h);
4329 tlink(tmp_head) = t;
4330 t = handle_ligaturing(tmp_head, t);
4331 if (p != null) {
4332 vlink(p) = vlink(tmp_head) ;
4334 alink(vlink(tmp_head)) = p ;
4335 lua_pushinteger(L, vlink(tmp_head));
4336 lua_pushinteger(L, t);
4337 lua_pushboolean(L, 1);
4338 flush_node(tmp_head);
4339 return 3;
4342 /* node.kerning */
4344 static int font_tex_kerning(lua_State * L)
4346 /* on the stack are two nodes and a direction */
4348 halfword tmp_head;
4349 halfword h;
4350 halfword t = null;
4351 halfword p ;
4352 if (lua_gettop(L) < 1) {
4353 lua_pushnil(L);
4354 lua_pushboolean(L, 0);
4355 return 2;
4357 h = *check_isnode(L, 1);
4358 if (lua_gettop(L) > 1) {
4359 t = *check_isnode(L, 2);
4361 tmp_head = new_node(nesting_node, 1);
4362 p = alink(h);
4363 couple_nodes(tmp_head, h);
4364 tlink(tmp_head) = t;
4365 t = handle_kerning(tmp_head, t);
4366 if (p != null) {
4367 vlink(p) = vlink(tmp_head) ;
4369 alink(vlink(tmp_head)) = p ;
4371 lua_pushinteger(L, vlink(tmp_head));
4372 lua_nodelib_push(L);
4374 lua_nodelib_push_fast(L, vlink(tmp_head));
4376 lua_pushinteger(L, t);
4377 lua_nodelib_push(L);
4379 lua_nodelib_push_fast(L, t);
4380 lua_pushboolean(L, 1);
4381 flush_node(tmp_head);
4382 return 3;
4385 static int font_tex_direct_kerning(lua_State * L)
4387 /* on the stack are two nodes and a direction */
4389 halfword tmp_head;
4390 halfword h;
4391 halfword t = null;
4392 halfword p ;
4393 if (lua_gettop(L) < 1) {
4394 lua_pushnil(L);
4395 lua_pushboolean(L, 0);
4396 return 2;
4398 h = lua_tointeger(L, 1);
4399 if (lua_gettop(L) > 1) {
4400 t = lua_tointeger(L, 2);
4402 tmp_head = new_node(nesting_node, 1);
4403 p = alink(h);
4404 couple_nodes(tmp_head, h);
4405 tlink(tmp_head) = t;
4406 t = handle_kerning(tmp_head, t);
4407 if (p != null) {
4408 vlink(p) = vlink(tmp_head) ;
4410 alink(vlink(tmp_head)) = p ;
4411 lua_pushinteger(L, vlink(tmp_head));
4412 lua_pushinteger(L, t);
4413 lua_pushboolean(L, 1);
4414 flush_node(tmp_head);
4415 return 3;
4418 /* node.protect_glyphs (returns also boolean because that signals callback) */
4420 static int lua_nodelib_protect_glyphs(lua_State * L)
4422 int t = 0;
4423 halfword head = *check_isnode(L, 1);
4424 while (head != null) {
4425 if (type(head) == glyph_node) {
4426 int s = subtype(head);
4427 if (s <= 256) {
4428 t = 1;
4429 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4432 head = vlink(head);
4434 lua_pushboolean(L, t);
4435 lua_pushvalue(L, 1);
4436 return 2;
4439 static int lua_nodelib_protect_glyph(lua_State * L)
4441 halfword n = *check_isnode(L, 1);
4442 if (type(n) == glyph_node) {
4443 int s = subtype(n);
4444 if (s <= 256) {
4445 subtype(n) = (quarterword) (s == 1 ? 256 : 256 + s);
4448 return 0;
4451 /* node.direct.protect_glyphs */
4453 static int lua_nodelib_direct_protect_glyphs(lua_State * L)
4455 int t = 0;
4456 halfword head = (halfword) lua_tointeger(L,1);
4457 while (head != null) {
4458 if (type(head) == glyph_node) {
4459 int s = subtype(head);
4460 if (s <= 256) {
4461 t = 1;
4462 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4465 head = vlink(head);
4467 lua_pushboolean(L, t);
4468 lua_pushvalue(L, 1);
4469 return 2;
4472 static int lua_nodelib_direct_protect_glyph(lua_State * L)
4474 halfword n = (halfword) lua_tointeger(L,1);
4475 if ((n != null) && (type(n) == glyph_node)) {
4476 int s = subtype(n);
4477 if (s <= 256) {
4478 subtype(n) = (quarterword) (s == 1 ? 256 : 256 + s);
4481 return 0;
4484 /* node.unprotect_glyphs (returns also boolean because that signals callback) */
4486 static int lua_nodelib_unprotect_glyphs(lua_State * L)
4488 int t = 0;
4489 halfword head = *(check_isnode(L, 1));
4490 while (head != null) {
4491 if (type(head) == glyph_node) {
4492 int s = subtype(head);
4493 if (s > 256) {
4494 t = 1;
4495 subtype(head) = (quarterword) (s - 256);
4498 head = vlink(head);
4500 lua_pushboolean(L, t);
4501 lua_pushvalue(L, 1);
4502 return 2;
4505 /* node.direct.unprotect_glyphs */
4507 static int lua_nodelib_direct_unprotect_glyphs(lua_State * L)
4509 int t = 0;
4510 halfword head = (halfword) lua_tointeger(L,1);
4511 while (head != null) {
4512 if (type(head) == glyph_node) {
4513 int s = subtype(head);
4514 if (s > 256) {
4515 t = 1;
4516 subtype(head) = (quarterword) (s - 256);
4519 head = vlink(head);
4521 lua_pushboolean(L, t);
4522 lua_pushvalue(L, 1);
4523 return 2;
4526 /* node.first_glyph */
4528 static int lua_nodelib_first_glyph(lua_State * L)
4530 /* on the stack are two nodes and a direction */
4531 halfword h, savetail = null, t = null;
4532 if (lua_gettop(L) < 1) {
4533 lua_pushnil(L);
4534 lua_pushboolean(L, 0);
4535 return 2;
4537 h = *(check_isnode(L, 1));
4538 if (lua_gettop(L) > 1) {
4539 t = *(check_isnode(L, 2));
4540 savetail = vlink(t);
4541 vlink(t) = null;
4543 while (h != null && (type(h) != glyph_node || !is_simple_character(h))) {
4544 h = vlink(h);
4546 if (savetail != null) {
4547 vlink(t) = savetail;
4549 lua_pushinteger(L, h);
4550 lua_nodelib_push(L);
4551 lua_pushboolean(L, (h == null ? 0 : 1));
4552 return 2;
4555 /* node.direct.first_glyph */
4557 static int lua_nodelib_direct_first_glyph(lua_State * L)
4559 halfword h,savetail,t;
4560 savetail = null;
4561 t = null;
4562 h = (halfword) lua_tointeger(L,1);
4563 if (h == null) {
4564 lua_pushnil(L);
4565 return 1;
4567 t = (halfword) lua_tointeger(L,2);
4568 if (t != null) {
4569 savetail = vlink(t);
4570 vlink(t) = null;
4572 while (h != null && (type(h) != glyph_node || !is_simple_character(h)))
4573 h = vlink(h);
4574 if (savetail != null)
4575 vlink(t) = savetail;
4576 lua_pushinteger(L, h);
4577 return 1; /* no need to also push a boolean if we have nil */
4580 /* new, fast and dumb ones: only signals that something needs to be processed */
4582 /* node.has_glyph */
4584 static int lua_nodelib_has_glyph(lua_State * L)
4586 halfword *a;
4587 halfword h = (halfword) *(check_isnode(L,1)) ;
4588 while (h != null) {
4589 if ( (type(h) == glyph_node) || (type(h) == disc_node)) {
4590 fast_metatable(h);
4591 return 1;
4592 } else {
4593 h = vlink(h);
4596 lua_pushnil(L);
4597 return 1;
4600 /* node.direct.has_glyph */
4602 static int lua_nodelib_direct_has_glyph(lua_State * L)
4604 halfword h = (halfword) lua_tointeger(L,1) ;
4605 while (h != null) {
4606 if ((type(h) == glyph_node) || (type(h) == disc_node)) {
4607 nodelib_pushdirect(h);
4608 return 1;
4609 } else {
4610 h = vlink(h);
4613 lua_pushnil(L);
4614 return 1;
4617 /* this is too simplistic, but it helps Hans to get going */
4619 static halfword do_ligature_n(halfword prev, halfword stop, halfword lig)
4621 vlink(lig) = vlink(stop);
4622 vlink(stop) = null;
4623 lig_ptr(lig) = vlink(prev);
4624 vlink(prev) = lig;
4625 return lig;
4628 /* node.do_ligature_n(node prev, node last, node lig) */
4630 static int lua_nodelib_do_ligature_n(lua_State * L)
4632 halfword p;
4633 halfword n = *check_isnode(L, 1);
4634 halfword m = *check_isnode(L, 2);
4635 halfword o = *check_isnode(L, 3);
4636 if (alink(n) == null || vlink(alink(n)) != n) {
4637 halfword tmp_head = new_node(temp_node, 0);
4638 couple_nodes(tmp_head, n);
4639 p = do_ligature_n(tmp_head, m, o);
4640 flush_node(tmp_head);
4641 } else {
4642 p = do_ligature_n(alink(n), m, o);
4644 lua_pushinteger(L, p);
4645 lua_nodelib_push(L);
4646 return 1;
4649 /* node.direct.do_ligature_n(node prev, node last, node lig) */
4651 static int lua_nodelib_direct_do_ligature_n(lua_State * L)
4653 halfword p;
4654 halfword n = (halfword) lua_tointeger(L, 1);
4655 halfword m = (halfword) lua_tointeger(L, 2);
4656 halfword o = (halfword) lua_tointeger(L, 3);
4657 if ((n == null) || (m == null) || (o == null)) {
4658 lua_pushnil(L);
4659 } else {
4660 if (alink(n) == null || vlink(alink(n)) != n) {
4661 halfword tmp_head = new_node(temp_node, 0);
4662 couple_nodes(tmp_head, n);
4663 p = do_ligature_n(tmp_head, m, o);
4664 flush_node(tmp_head);
4665 } else {
4666 p = do_ligature_n(alink(n), m, o);
4668 lua_pushinteger(L, p);
4670 return 1;
4673 /* node.usedlist */
4675 static int lua_nodelib_usedlist(lua_State * L)
4677 lua_pushinteger(L, list_node_mem_usage());
4678 lua_nodelib_push(L);
4679 return 1;
4682 /* node.direct.usedlist */
4684 static int lua_nodelib_direct_usedlist(lua_State * L)
4686 lua_pushinteger(L, list_node_mem_usage());
4687 return 1;
4690 /* node.protrusion_skipable(node m) */
4692 static int lua_nodelib_cp_skipable(lua_State * L)
4694 halfword n = *check_isnode(L, 1);
4695 lua_pushboolean(L, cp_skipable(n));
4696 return 1;
4699 /* node.direct.protrusion_skipable(node m) */
4701 static int lua_nodelib_direct_cp_skipable(lua_State * L)
4703 halfword n = lua_tointeger(L, 1);
4704 if (n == null) {
4705 lua_pushnil(L);
4706 } else {
4707 lua_pushboolean(L, cp_skipable(n));
4709 return 1;
4713 /* node.currentattr(node m) */
4715 static int lua_nodelib_currentattr(lua_State * L)
4717 int u = lua_gettop(L);
4718 if (u == null) {
4719 /* query */
4720 halfword n ;
4721 /* current_attribute_list() return attr_list_cache */
4722 /* or null (attr_list_cache can also be null) */
4723 n = current_attribute_list();
4724 if (n) {
4725 lua_pushinteger(L, n);
4726 lua_nodelib_push(L);
4728 else
4729 lua_pushnil(L);
4730 return 1;
4731 } else {
4732 /* assign */
4733 normal_warning("node lib","assignment via node.current_attr(<list>) is not supported (yet)");
4734 return 0;
4739 /* node.direct.currentattr(node m) */
4741 static int lua_nodelib_direct_currentattr(lua_State * L)
4743 /* current_attribute_list() return attr_list_cache */
4744 /* or null (attr_list_cache can also be null) */
4745 halfword n = current_attribute_list();
4746 if (n)
4747 lua_pushinteger(L, n);
4748 else
4749 lua_pushnil(L);
4750 return 1;
4754 /* node.direct.todirect */
4756 static int lua_nodelib_direct_todirect(lua_State * L)
4758 if (lua_type(L,1) != LUA_TNUMBER) {
4759 /* assume node, no further testing, used in known situations */
4760 void *n ;
4761 n = lua_touserdata(L, 1);
4762 if (n == null) {
4763 lua_pushnil(L);
4764 } else {
4765 lua_pushinteger(L, *((halfword *)n) );
4767 } /* else assume direct and returns argument */
4768 return 1;
4772 /* node.direct.tonode */
4774 static int lua_nodelib_direct_tonode(lua_State * L)
4776 halfword *a;
4777 halfword n = lua_tointeger(L, 1);
4778 if (n != null) {
4779 a = (halfword *) lua_newuserdata(L, sizeof(halfword));
4780 *a=n;
4781 lua_get_metatablelua(luatex_node);
4782 lua_setmetatable(L,-2);
4783 } /* else assume node and return argument */
4784 return 1;
4787 /* node.setfield */
4789 #define cleanup_late_lua(n) do { \
4790 if (late_lua_data(n) != 0) { \
4791 if (late_lua_type(n) == normal) { \
4792 delete_token_ref(late_lua_data(n)); \
4793 } else if (late_lua_type(n) == lua_refid_literal) { \
4794 luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \
4797 } while (0)
4799 #define cleanup_late_lua_name(n) do { \
4800 if (late_lua_name(n) != 0) { \
4801 delete_token_ref(late_lua_name(n)); \
4803 } while (0)
4805 static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s)
4807 int t = subtype(n);
4809 if (t == pdf_literal_node) {
4810 if (lua_key_eq(s, mode)) {
4811 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
4812 } else if (lua_key_eq(s, data)) {
4813 if (ini_version) {
4814 pdf_literal_data(n) = nodelib_gettoks(L, 3);
4815 } else {
4816 lua_pushvalue(L, 3);
4817 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4818 pdf_literal_type(n) = lua_refid_literal;
4820 } else {
4821 return nodelib_cantset(L, n, s);
4823 } else if (t == late_lua_node) {
4824 if (lua_key_eq(s, string)) {
4825 cleanup_late_lua(n) ; /* ls-hh */
4826 if (ini_version) {
4827 late_lua_data(n) = nodelib_gettoks(L, 3);
4828 late_lua_type(n) = normal;
4829 } else {
4830 lua_pushvalue(L, 3);
4831 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4832 late_lua_type(n) = lua_refid_literal;
4834 } else if (lua_key_eq(s, data)) {
4835 cleanup_late_lua(n) ; /* ls-hh */
4836 late_lua_data(n) = nodelib_gettoks(L, 3);
4837 late_lua_type(n) = normal;
4838 } else if (lua_key_eq(s, name)) {
4839 cleanup_late_lua_name(n) ; /* ls-hh */
4840 late_lua_name(n) = nodelib_gettoks(L, 3);
4841 } else {
4842 return nodelib_cantset(L, n, s);
4844 /* done */
4845 } else if (t == user_defined_node) {
4846 if (lua_key_eq(s, user_id)) {
4847 user_node_id(n) = (halfword) lua_tointeger(L, 3);
4848 } else if (lua_key_eq(s, type)) {
4849 user_node_type(n) = (halfword) lua_tointeger(L, 3);
4850 } else if (lua_key_eq(s, value)) {
4851 switch (user_node_type(n)) {
4852 case 'a':
4853 user_node_value(n) = nodelib_getlist(L, 3);
4854 break;
4855 case 'd':
4856 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4857 break;
4858 case 'l':
4859 lua_pushvalue(L, 3);
4860 if (user_node_value(n) != 0) {
4861 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
4863 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4864 break;
4865 case 'n':
4866 user_node_value(n) = nodelib_getlist(L, 3);
4867 break;
4868 case 's':
4869 user_node_value(n) = nodelib_getstring(L, 3);
4870 break;
4871 case 't':
4872 user_node_value(n) = nodelib_gettoks(L, 3);
4873 break;
4874 default:
4875 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4876 break;
4878 } else {
4879 return nodelib_cantset(L, n, s);
4881 } else if (t == pdf_annot_node) {
4882 if (lua_key_eq(s, width)) {
4883 width(n) = (halfword) lua_tointeger(L, 3);
4884 } else if (lua_key_eq(s, depth)) {
4885 depth(n) = (halfword) lua_tointeger(L, 3);
4886 } else if (lua_key_eq(s, height)) {
4887 height(n) = (halfword) lua_tointeger(L, 3);
4888 } else if (lua_key_eq(s, objnum)) {
4889 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
4890 } else if (lua_key_eq(s, data)) {
4891 pdf_annot_data(n) = nodelib_gettoks(L, 3);
4892 } else {
4893 return nodelib_cantset(L, n, s);
4895 } else if (t == pdf_dest_node) {
4896 if (lua_key_eq(s, width)) {
4897 width(n) = (halfword) lua_tointeger(L, 3);
4898 } else if (lua_key_eq(s, depth)) {
4899 depth(n) = (halfword) lua_tointeger(L, 3);
4900 } else if (lua_key_eq(s, height)) {
4901 height(n) = (halfword) lua_tointeger(L, 3);
4902 } else if (lua_key_eq(s, named_id)) {
4903 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
4904 } else if (lua_key_eq(s, dest_id)) {
4905 if (pdf_dest_named_id(n) == 1) {
4906 pdf_dest_id(n) = nodelib_gettoks(L, 3);
4907 } else {
4908 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
4910 } else if (lua_key_eq(s, dest_type)) {
4911 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
4912 } else if (lua_key_eq(s, xyz_zoom)) {
4913 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
4914 } else if (lua_key_eq(s, objnum)) {
4915 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
4916 } else {
4917 return nodelib_cantset(L, n, s);
4919 } else if (t == pdf_setmatrix_node) {
4920 if (lua_key_eq(s, data)) {
4921 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
4922 } else {
4923 return nodelib_cantset(L, n, s);
4925 } else if (t == pdf_refobj_node) {
4926 if (lua_key_eq(s, objnum)) {
4927 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
4928 } else {
4929 return nodelib_cantset(L, n, s);
4931 } else if (t == pdf_start_link_node) {
4932 if (lua_key_eq(s, width)) {
4933 width(n) = (halfword) lua_tointeger(L, 3);
4934 } else if (lua_key_eq(s, depth)) {
4935 depth(n) = (halfword) lua_tointeger(L, 3);
4936 } else if (lua_key_eq(s, height)) {
4937 height(n) = (halfword) lua_tointeger(L, 3);
4938 } else if (lua_key_eq(s, objnum)) {
4939 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
4940 } else if (lua_key_eq(s, link_attr)) {
4941 pdf_link_attr(n) = nodelib_gettoks(L, 3);
4942 } else if (lua_key_eq(s, action)) {
4943 pdf_link_action(n) = nodelib_getaction(L, 3);
4944 } else {
4945 return nodelib_cantset(L, n, s);
4947 } else if (t == write_node) {
4948 if (lua_key_eq(s, stream)) {
4949 write_stream(n) = (halfword) lua_tointeger(L, 3);
4950 } else if (lua_key_eq(s, data)) {
4951 write_tokens(n) = nodelib_gettoks(L, 3);
4952 } else {
4953 return nodelib_cantset(L, n, s);
4955 } else if (t == pdf_colorstack_node) {
4956 if (lua_key_eq(s, stack)) {
4957 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
4958 } else if (lua_key_eq(s, command)) {
4959 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
4960 } else if (lua_key_eq(s, data)) {
4961 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
4962 } else {
4963 return nodelib_cantset(L, n, s);
4965 } else if (t == pdf_action_node) {
4966 if (lua_key_eq(s, action_type)) {
4967 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
4968 } else if (lua_key_eq(s, named_id)) {
4969 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
4970 } else if (lua_key_eq(s, action_id)) {
4971 if (pdf_action_named_id(n) == 1) {
4972 pdf_action_id(n) = nodelib_gettoks(L, 3);
4973 } else {
4974 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
4976 } else if (lua_key_eq(s, file)) {
4977 pdf_action_file(n) = nodelib_gettoks(L, 3);
4978 } else if (lua_key_eq(s, new_window)) {
4979 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
4980 } else if (lua_key_eq(s, data)) {
4981 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
4982 } else {
4983 return nodelib_cantset(L, n, s);
4985 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
4986 if (lua_key_eq(s, width)) {
4987 width(n) = (halfword) lua_tointeger(L, 3);
4988 } else if (lua_key_eq(s, depth)) {
4989 depth(n) = (halfword) lua_tointeger(L, 3);
4990 } else if (lua_key_eq(s, height)) {
4991 height(n) = (halfword) lua_tointeger(L, 3);
4992 } else if (lua_key_eq(s, named_id)) {
4993 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
4994 } else if (lua_key_eq(s, thread_id)) {
4995 if (pdf_thread_named_id(n) == 1) {
4996 pdf_thread_id(n) = nodelib_gettoks(L, 3);
4997 } else {
4998 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
5000 } else if (lua_key_eq(s, thread_attr)) {
5001 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
5002 } else {
5003 return nodelib_cantset(L, n, s);
5005 } else if (t == special_node) {
5006 if (lua_key_eq(s, data)) {
5007 write_tokens(n) = nodelib_gettoks(L, 3);
5008 } else {
5009 return nodelib_cantset(L, n, s);
5011 } else if (t == open_node) {
5012 if (lua_key_eq(s, stream)) {
5013 write_stream(n) = (halfword) lua_tointeger(L, 3);
5014 } else if (lua_key_eq(s, name)) {
5015 open_name(n) = nodelib_getstring(L, 3);
5016 } else if (lua_key_eq(s, area)) {
5017 open_area(n) = nodelib_getstring(L, 3);
5018 } else if (lua_key_eq(s, ext)) {
5019 open_ext(n) = nodelib_getstring(L, 3);
5020 } else {
5021 return nodelib_cantset(L, n, s);
5023 } else if (t == close_node) {
5024 if (lua_key_eq(s, stream)) {
5025 write_stream(n) = (halfword) lua_tointeger(L, 3);
5026 } else {
5027 return nodelib_cantset(L, n, s);
5029 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
5030 (t == pdf_save_node) || (t == pdf_restore_node)) {
5031 return nodelib_cantset(L, n, s);
5032 } else {
5033 /* do nothing */
5035 return 0;
5038 static int lua_nodelib_fast_setfield(lua_State * L)
5040 const char *s;
5041 halfword n = *((halfword *) lua_touserdata(L, 1));
5042 int t = type(n);
5044 if (lua_type(L, 2) == LUA_TNUMBER) {
5045 if (lua_gettop(L) == 3) {
5046 int i = lua_tointeger(L, 2);
5047 int val = lua_tointeger(L, 3);
5048 if (val == UNUSED_ATTRIBUTE) {
5049 (void) unset_attribute(n, i, val);
5050 } else {
5051 set_attribute(n, i, val);
5053 } else {
5054 luaL_error(L, "incorrect number of arguments");
5056 return 0;
5059 s = lua_tostring(L, 2);
5061 /*if (lua_key_eq(s, id)) {
5062 type(n) = (quarteword) lua_tointeger(L, 3);
5063 }* else */
5064 if (lua_key_eq(s, next)) {
5065 halfword x = nodelib_getlist(L, 3);
5066 if (x>0 && type(x) == glue_spec_node) {
5067 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
5069 vlink(n) = x;
5070 } else if (lua_key_eq(s, prev)) {
5071 halfword x = nodelib_getlist(L, 3);
5072 if (x>0 && type(x) == glue_spec_node) {
5073 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
5075 alink(n) = x;
5076 } else if (lua_key_eq(s, attr)) {
5077 if (nodetype_has_attributes(type(n))) {
5078 nodelib_setattr(L, 3, n);
5080 } else if (t == glyph_node) {
5081 if (lua_key_eq(s, subtype)) {
5082 subtype(n) = (quarterword) lua_tointeger(L, 3);
5083 } else if (lua_key_eq(s, font)) {
5084 font(n) = (halfword) lua_tointeger(L, 3);
5085 } else if (lua_key_eq(s, char)) {
5086 character(n) = (halfword) lua_tointeger(L, 3);
5087 } else if (lua_key_eq(s, xoffset)) {
5088 x_displace(n) = (halfword) lua_tointeger(L, 3);
5089 } else if (lua_key_eq(s, yoffset)) {
5090 y_displace(n) = (halfword) lua_tointeger(L, 3);
5091 } else if (lua_key_eq(s, xadvance)) {
5092 x_advance(n) = (halfword) lua_tointeger(L, 3);
5093 } else if (lua_key_eq(s, width)) {
5094 /* not yet */
5095 } else if (lua_key_eq(s, height)) {
5096 /* not yet */
5097 } else if (lua_key_eq(s, depth)) {
5098 /* not yet */
5099 } else if (lua_key_eq(s, expansion_factor)) {
5100 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
5101 } else if (lua_key_eq(s, components)) {
5102 lig_ptr(n) = nodelib_getlist(L, 3);
5103 } else if (lua_key_eq(s, lang)) {
5104 set_char_lang(n, (halfword) lua_tointeger(L, 3));
5105 } else if (lua_key_eq(s, left)) {
5106 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
5107 } else if (lua_key_eq(s, right)) {
5108 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
5109 } else if (lua_key_eq(s, uchyph)) {
5110 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
5111 } else {
5112 return nodelib_cantset(L, n, s);
5114 } else if ((t == hlist_node) || (t == vlist_node)) {
5115 if (lua_key_eq(s, subtype)) {
5116 subtype(n) = (quarterword) lua_tointeger(L, 3);
5117 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
5118 list_ptr(n) = nodelib_getlist(L, 3);
5119 } else if (lua_key_eq(s, width)) {
5120 width(n) = (halfword) lua_tointeger(L, 3);
5121 } else if (lua_key_eq(s, height)) {
5122 height(n) = (halfword) lua_tointeger(L, 3);
5123 } else if (lua_key_eq(s, depth)) {
5124 depth(n) = (halfword) lua_tointeger(L, 3);
5125 } else if (lua_key_eq(s, dir)) {
5126 box_dir(n) = nodelib_getdir(L, 3, 1);
5127 } else if (lua_key_eq(s, shift)) {
5128 shift_amount(n) = (halfword) lua_tointeger(L, 3);
5129 } else if (lua_key_eq(s, glue_order)) {
5130 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5131 } else if (lua_key_eq(s, glue_sign)) {
5132 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5133 } else if (lua_key_eq(s, glue_set)) {
5134 glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
5135 } else {
5136 return nodelib_cantset(L, n, s);
5138 } else if (t == disc_node) {
5139 if (lua_key_eq(s, subtype)) {
5140 subtype(n) = (quarterword) lua_tointeger(L, 3);
5141 } else if (lua_key_eq(s, pre)) {
5142 set_disc_field(pre_break(n), nodelib_getlist(L, 3));
5143 } else if (lua_key_eq(s, post)) {
5144 set_disc_field(post_break(n), nodelib_getlist(L, 3));
5145 } else if (lua_key_eq(s, replace)) {
5146 set_disc_field(no_break(n), nodelib_getlist(L, 3));
5147 } else if (lua_key_eq(s, penalty)) {
5148 disc_penalty(n) = (quarterword) lua_tointeger(L, 3);
5149 } else {
5150 return nodelib_cantset(L, n, s);
5152 } else if (t == glue_node) {
5153 if (lua_key_eq(s, subtype)) {
5154 subtype(n) = (quarterword) lua_tointeger(L, 3);
5155 } else if (lua_key_eq(s, width)) {
5156 width(n) = (halfword) lua_tointeger(L, 3);
5157 } else if (lua_key_eq(s, stretch)) {
5158 stretch(n) = (halfword) lua_tointeger(L, 3);
5159 } else if (lua_key_eq(s, shrink)) {
5160 shrink(n) = (halfword) lua_tointeger(L, 3);
5161 } else if (lua_key_eq(s, stretch_order)) {
5162 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5163 } else if (lua_key_eq(s, shrink_order)) {
5164 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5165 } else if (lua_key_eq(s, leader)) {
5166 leader_ptr(n) = nodelib_getlist(L, 3);
5167 } else {
5168 return nodelib_cantset(L, n, s);
5170 } else if (t == kern_node) {
5171 if (lua_key_eq(s, subtype)) {
5172 subtype(n) = (quarterword) lua_tointeger(L, 3);
5173 } else if (lua_key_eq(s, kern)) {
5174 width(n) = (halfword) lua_tointeger(L, 3);
5175 } else if (lua_key_eq(s, expansion_factor)) {
5176 ex_kern(n) = (halfword) lua_tointeger(L, 3);
5177 } else {
5178 return nodelib_cantset(L, n, s);
5180 } else if (t == penalty_node) {
5181 if (lua_key_eq(s, subtype)) {
5182 /* dummy subtype */
5183 } else if (lua_key_eq(s, penalty)) {
5184 penalty(n) = (halfword) lua_tointeger(L, 3);
5185 } else {
5186 return nodelib_cantset(L, n, s);
5188 } else if (t == rule_node) {
5189 if (lua_key_eq(s, subtype)) {
5190 subtype(n) = (quarterword) lua_tointeger(L, 3);
5191 } else if (lua_key_eq(s, width)) {
5192 width(n) = (halfword) lua_tointeger(L, 3);
5193 } else if (lua_key_eq(s, height)) {
5194 height(n) = (halfword) lua_tointeger(L, 3);
5195 } else if (lua_key_eq(s, depth)) {
5196 depth(n) = (halfword) lua_tointeger(L, 3);
5197 } else if (lua_key_eq(s, dir)) {
5198 rule_dir(n) = nodelib_getdir(L, 3, 1);
5199 } else if (lua_key_eq(s, index)) {
5200 rule_index(n) = (halfword) lua_tointeger(L, 3);
5201 } else if (lua_key_eq(s, transform)) {
5202 rule_transform(n) = (halfword) lua_tointeger(L, 3);
5203 } else {
5204 return nodelib_cantset(L, n, s);
5206 } else if (t == dir_node) {
5207 if (lua_key_eq(s, dir)) {
5208 dir_dir(n) = nodelib_getdir(L, 3, 0);
5209 } else if (lua_key_eq(s, level)) {
5210 dir_level(n) = (halfword) lua_tointeger(L, 3);
5211 } else if (lua_key_eq(s, subtype)) { /* can be used for anything */
5212 subtype(n) = (quarterword) lua_tointeger(L, 3);
5213 } else {
5214 return nodelib_cantset(L, n, s);
5216 } else if (t == local_par_node) {
5217 if (lua_key_eq(s, pen_inter)) {
5218 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
5219 } else if (lua_key_eq(s, pen_broken)) {
5220 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
5221 } else if (lua_key_eq(s, dir)) {
5222 local_par_dir(n) = nodelib_getdir(L, 3, 1);
5223 } else if (lua_key_eq(s, box_left)) {
5224 local_box_left(n) = nodelib_getlist(L, 3);
5225 } else if (lua_key_eq(s, box_left_width)) {
5226 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
5227 } else if (lua_key_eq(s, box_right)) {
5228 local_box_right(n) = nodelib_getlist(L, 3);
5229 } else if (lua_key_eq(s, box_right_width)) {
5230 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
5231 } else {
5232 return nodelib_cantset(L, n, s);
5234 } else if (t == whatsit_node) {
5235 if (lua_key_eq(s, subtype)) {
5236 subtype(n) = (quarterword) lua_tointeger(L, 3);
5237 } else {
5238 lua_nodelib_setfield_whatsit(L, n, s);
5240 } else if (t == simple_noad) {
5241 if (lua_key_eq(s, subtype)) {
5242 subtype(n) = (quarterword) lua_tointeger(L, 3);
5243 } else if (lua_key_eq(s, nucleus)) {
5244 nucleus(n) = nodelib_getlist(L, 3);
5245 } else if (lua_key_eq(s, sub)) {
5246 subscr(n) = nodelib_getlist(L, 3);
5247 } else if (lua_key_eq(s, sup)) {
5248 supscr(n) = nodelib_getlist(L, 3);
5249 } else {
5250 return nodelib_cantset(L, n, s);
5252 } else if ((t == math_char_node) || (t == math_text_char_node)) {
5253 if (lua_key_eq(s, subtype)) {
5254 subtype(n) = (quarterword) lua_tointeger(L, 3);
5255 } else if (lua_key_eq(s, fam)) {
5256 math_fam(n) = (halfword) lua_tointeger(L, 3);
5257 } else if (lua_key_eq(s, char)) {
5258 math_character(n) = (halfword) lua_tointeger(L, 3);
5259 } else {
5260 return nodelib_cantset(L, n, s);
5262 } else if (t == mark_node) {
5263 if (lua_key_eq(s, subtype)) {
5264 subtype(n) = (quarterword) lua_tointeger(L, 3);
5265 } else if (lua_key_eq(s, class)) {
5266 mark_class(n) = (halfword) lua_tointeger(L, 3);
5267 } else if (lua_key_eq(s, mark)) {
5268 mark_ptr(n) = nodelib_gettoks(L, 3);
5269 } else {
5270 return nodelib_cantset(L, n, s);
5272 } else if (t == ins_node) {
5273 if (lua_key_eq(s, subtype)) {
5274 subtype(n) = (quarterword) lua_tointeger(L, 3);
5275 } else if (lua_key_eq(s, cost)) {
5276 float_cost(n) = (halfword) lua_tointeger(L, 3);
5277 } else if (lua_key_eq(s, depth)) {
5278 depth(n) = (halfword) lua_tointeger(L, 3);
5279 } else if (lua_key_eq(s, height)) {
5280 height(n) = (halfword) lua_tointeger(L, 3);
5281 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5282 ins_ptr(n) = nodelib_getlist(L, 3);
5283 /* glue */
5284 } else if (lua_key_eq(s, width)) {
5285 width(n) = (halfword) lua_tointeger(L, 3);
5286 } else if (lua_key_eq(s, stretch)) {
5287 stretch(n) = (halfword) lua_tointeger(L, 3);
5288 } else if (lua_key_eq(s, shrink)) {
5289 shrink(n) = (halfword) lua_tointeger(L, 3);
5290 } else if (lua_key_eq(s, stretch_order)) {
5291 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5292 } else if (lua_key_eq(s, shrink_order)) {
5293 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5294 } else {
5295 return nodelib_cantset(L, n, s);
5297 } else if (t == math_node) {
5298 if (lua_key_eq(s, subtype)) {
5299 subtype(n) = (quarterword) lua_tointeger(L, 3);
5300 } else if (lua_key_eq(s, surround)) {
5301 surround(n) = (halfword) lua_tointeger(L, 3);
5302 /* glue */
5303 } else if (lua_key_eq(s, width)) {
5304 width(n) = (halfword) lua_tointeger(L, 3);
5305 } else if (lua_key_eq(s, stretch)) {
5306 stretch(n) = (halfword) lua_tointeger(L, 3);
5307 } else if (lua_key_eq(s, shrink)) {
5308 shrink(n) = (halfword) lua_tointeger(L, 3);
5309 } else if (lua_key_eq(s, stretch_order)) {
5310 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5311 } else if (lua_key_eq(s, shrink_order)) {
5312 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5313 } else {
5314 return nodelib_cantset(L, n, s);
5316 } else if (t == fraction_noad) {
5317 if (lua_key_eq(s, subtype)) {
5318 subtype(n) = (quarterword) lua_tointeger(L, 3);
5319 } else if (lua_key_eq(s, width)) {
5320 thickness(n) = (halfword) lua_tointeger(L, 3);
5321 } else if (lua_key_eq(s, num)) {
5322 numerator(n) = nodelib_getlist(L, 3);
5323 } else if (lua_key_eq(s, denom)) {
5324 denominator(n) = nodelib_getlist(L, 3);
5325 } else if (lua_key_eq(s, left)) {
5326 left_delimiter(n) = nodelib_getlist(L, 3);
5327 } else if (lua_key_eq(s, right)) {
5328 right_delimiter(n) = nodelib_getlist(L, 3);
5329 } else {
5330 return nodelib_cantset(L, n, s);
5332 } else if (t == style_node) {
5333 if (lua_key_eq(s, subtype)) {
5334 /* dummy subtype */
5335 } else if (lua_key_eq(s, style)) {
5336 assign_math_style(L,3,subtype(n));
5337 } else {
5338 /* return nodelib_cantset(L, n, s); */
5340 } else if (t == accent_noad) {
5341 if (lua_key_eq(s, subtype)) {
5342 subtype(n) = (quarterword) lua_tointeger(L, 3);
5343 } else if (lua_key_eq(s, nucleus)) {
5344 nucleus(n) = nodelib_getlist(L, 3);
5345 } else if (lua_key_eq(s, sub)) {
5346 subscr(n) = nodelib_getlist(L, 3);
5347 } else if (lua_key_eq(s, sup)) {
5348 supscr(n) = nodelib_getlist(L, 3);
5349 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
5350 top_accent_chr(n) = nodelib_getlist(L, 3);
5351 } else if (lua_key_eq(s, bot_accent)) {
5352 bot_accent_chr(n) = nodelib_getlist(L, 3);
5353 } else if (lua_key_eq(s, overlay_accent)) {
5354 overlay_accent_chr(n) = nodelib_getlist(L, 3);
5355 } else {
5356 return nodelib_cantset(L, n, s);
5358 } else if (t == fence_noad) {
5359 if (lua_key_eq(s, subtype)) {
5360 subtype(n) = (quarterword) lua_tointeger(L, 3);
5361 } else if (lua_key_eq(s, delim)) {
5362 delimiter(n) = nodelib_getlist(L, 3);
5363 } else {
5364 return nodelib_cantset(L, n, s);
5366 } else if (t == delim_node) {
5367 if (lua_key_eq(s, subtype)) {
5368 subtype(n) = (quarterword) lua_tointeger(L, 3);
5369 } else if (lua_key_eq(s, small_fam)) {
5370 small_fam(n) = (halfword) lua_tointeger(L, 3);
5371 } else if (lua_key_eq(s, small_char)) {
5372 small_char(n) = (halfword) lua_tointeger(L, 3);
5373 } else if (lua_key_eq(s, large_fam)) {
5374 large_fam(n) = (halfword) lua_tointeger(L, 3);
5375 } else if (lua_key_eq(s, large_char)) {
5376 large_char(n) = (halfword) lua_tointeger(L, 3);
5377 } else {
5378 return nodelib_cantset(L, n, s);
5380 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
5381 if (lua_key_eq(s, subtype)) {
5382 subtype(n) = (quarterword) lua_tointeger(L, 3);
5383 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5384 math_list(n) = nodelib_getlist(L, 3);
5385 } else {
5386 return nodelib_cantset(L, n, s);
5388 } else if (t == radical_noad) {
5389 if (lua_key_eq(s, subtype)) {
5390 subtype(n) = (quarterword) lua_tointeger(L, 3);
5391 } else if (lua_key_eq(s, nucleus)) {
5392 nucleus(n) = nodelib_getlist(L, 3);
5393 } else if (lua_key_eq(s, sub)) {
5394 subscr(n) = nodelib_getlist(L, 3);
5395 } else if (lua_key_eq(s, sup)) {
5396 supscr(n) = nodelib_getlist(L, 3);
5397 } else if (lua_key_eq(s, left)) {
5398 left_delimiter(n) = nodelib_getlist(L, 3);
5399 } else if (lua_key_eq(s, degree)) {
5400 degree(n) = nodelib_getlist(L, 3);
5401 } else {
5402 return nodelib_cantset(L, n, s);
5404 } else if (t == margin_kern_node) {
5405 if (lua_key_eq(s, subtype)) {
5406 subtype(n) = (quarterword) lua_tointeger(L, 3);
5407 } else if (lua_key_eq(s, width)) {
5408 width(n) = (halfword) lua_tointeger(L, 3);
5409 } else if (lua_key_eq(s, glyph)) {
5410 margin_char(n) = nodelib_getlist(L, 3);
5411 } else {
5412 return nodelib_cantset(L, n, s);
5414 } else if (t == split_up_node) {
5415 if (lua_key_eq(s, subtype)) {
5416 subtype(n) = (quarterword) lua_tointeger(L, 3);
5417 } else if (lua_key_eq(s, last_ins_ptr)) {
5418 last_ins_ptr(n) = nodelib_getlist(L, 3);
5419 } else if (lua_key_eq(s, best_ins_ptr)) {
5420 best_ins_ptr(n) = nodelib_getlist(L, 3);
5421 } else if (lua_key_eq(s, broken_ptr)) {
5422 broken_ptr(n) = nodelib_getlist(L, 3);
5423 } else if (lua_key_eq(s, broken_ins)) {
5424 broken_ins(n) = nodelib_getlist(L, 3);
5425 } else {
5426 return nodelib_cantset(L, n, s);
5428 } else if (t == choice_node) {
5429 if (lua_key_eq(s, subtype)) {
5430 subtype(n) = (quarterword) lua_tointeger(L, 3);
5431 } else if (lua_key_eq(s, display)) {
5432 display_mlist(n) = nodelib_getlist(L, 3);
5433 } else if (lua_key_eq(s, text)) {
5434 text_mlist(n) = nodelib_getlist(L, 3);
5435 } else if (lua_key_eq(s, script)) {
5436 script_mlist(n) = nodelib_getlist(L, 3);
5437 } else if (lua_key_eq(s, scriptscript)) {
5438 script_script_mlist(n) = nodelib_getlist(L, 3);
5439 } else {
5440 return nodelib_cantset(L, n, s);
5442 } else if (t == inserting_node) {
5443 if (lua_key_eq(s, subtype)) {
5444 subtype(n) = (quarterword) lua_tointeger(L, 3);
5445 } else if (lua_key_eq(s, last_ins_ptr)) {
5446 last_ins_ptr(n) = nodelib_getlist(L, 3);
5447 } else if (lua_key_eq(s, best_ins_ptr)) {
5448 best_ins_ptr(n) = nodelib_getlist(L, 3);
5449 } else {
5450 return nodelib_cantset(L, n, s);
5452 } else if (t == attribute_node) {
5453 if (lua_key_eq(s, subtype)) {
5454 /* dummy subtype */
5455 } else if (lua_key_eq(s, number)) {
5456 attribute_id(n) = (halfword) lua_tointeger(L, 3);
5457 } else if (lua_key_eq(s, value)) {
5458 attribute_value(n) = (halfword) lua_tointeger(L, 3);
5459 } else {
5460 return nodelib_cantset(L, n, s);
5462 } else if (t == adjust_node) {
5463 if (lua_key_eq(s, subtype)) {
5464 subtype(n) = (quarterword) lua_tointeger(L, 3);
5465 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5466 adjust_ptr(n) = nodelib_getlist(L, 3);
5467 } else {
5468 return nodelib_cantset(L, n, s);
5470 } else if (t == unset_node) {
5471 if (lua_key_eq(s, subtype)) {
5472 /* dummy subtype */
5473 } else if (lua_key_eq(s, width)) {
5474 width(n) = (halfword) lua_tointeger(L, 3);
5475 } else if (lua_key_eq(s, height)) {
5476 height(n) = (halfword) lua_tointeger(L, 3);
5477 } else if (lua_key_eq(s, depth)) {
5478 depth(n) = (halfword) lua_tointeger(L, 3);
5479 } else if (lua_key_eq(s, dir)) {
5480 box_dir(n) = nodelib_getdir(L, 3, 1);
5481 } else if (lua_key_eq(s, shrink)) {
5482 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
5483 } else if (lua_key_eq(s, glue_order)) {
5484 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5485 } else if (lua_key_eq(s, glue_sign)) {
5486 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5487 } else if (lua_key_eq(s, stretch)) {
5488 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
5489 } else if (lua_key_eq(s, count)) {
5490 span_count(n) = (quarterword) lua_tointeger(L, 3);
5491 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5492 list_ptr(n) = nodelib_getlist(L, 3);
5493 } else {
5494 return nodelib_cantset(L, n, s);
5496 } else if (t == attribute_list_node) {
5497 if (lua_key_eq(s, subtype)) {
5498 /* dummy subtype */
5499 } else {
5500 return nodelib_cantset(L, n, s);
5502 } else if (t == boundary_node) {
5503 if (lua_key_eq(s, subtype)) {
5504 subtype(n) = (quarterword) lua_tointeger(L, 3);
5505 } else if (lua_key_eq(s, value)) {
5506 boundary_value(n) = lua_tointeger(L, 3);
5507 } else {
5508 return nodelib_cantset(L, n, s);
5510 } else if (t == glue_spec_node) {
5511 if (lua_key_eq(s, width)) {
5512 width(n) = (halfword) lua_tointeger(L, 3);
5513 } else if (lua_key_eq(s, stretch)) {
5514 stretch(n) = (halfword) lua_tointeger(L, 3);
5515 } else if (lua_key_eq(s, shrink)) {
5516 shrink(n) = (halfword) lua_tointeger(L, 3);
5517 } else if (lua_key_eq(s, stretch_order)) {
5518 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5519 } else if (lua_key_eq(s, shrink_order)) {
5520 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5521 } else {
5522 return nodelib_cantset(L, n, s);
5524 } else {
5525 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
5527 return 0;
5530 static int lua_nodelib_setfield(lua_State * L)
5532 /* [given-node] [...]*/
5533 halfword *p = lua_touserdata(L, 1);
5534 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
5535 return 0;
5537 /* [given-node] [mt-given-node]*/
5538 lua_get_metatablelua(luatex_node);
5539 /* [given-node] [mt-given-node] [mt-node]*/
5540 if ( (!lua_rawequal(L, -1, -2)) ) {
5541 return 0;
5543 /* prune stack and call getfield */
5544 lua_settop(L,3);
5545 return lua_nodelib_fast_setfield(L);
5548 /* node.direct.setfield */
5550 static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char *s)
5552 int t = subtype(n);
5553 if (t == pdf_literal_node) {
5554 if (lua_key_eq(s, mode)) {
5555 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
5556 } else if (lua_key_eq(s, data)) {
5557 if (ini_version) {
5558 pdf_literal_data(n) = nodelib_gettoks(L, 3);
5559 } else {
5560 lua_pushvalue(L, 3);
5561 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5562 pdf_literal_type(n) = lua_refid_literal;
5564 } else {
5565 return nodelib_cantset(L, n, s);
5567 } else if (t == late_lua_node) {
5568 if (lua_key_eq(s, string)) {
5569 cleanup_late_lua(n) ; /* ls-hh */
5570 if (ini_version) {
5571 late_lua_data(n) = nodelib_gettoks(L, 3);
5572 late_lua_type(n) = normal;
5573 } else {
5574 lua_pushvalue(L, 3);
5575 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5576 late_lua_type(n) = lua_refid_literal;
5578 } else if (lua_key_eq(s, data)) {
5579 cleanup_late_lua(n) ; /* ls-hh */
5580 late_lua_data(n) = nodelib_gettoks(L, 3);
5581 late_lua_type(n) = normal;
5582 } else if (lua_key_eq(s, name)) {
5583 cleanup_late_lua_name(n) ; /* ls-hh */
5584 late_lua_name(n) = nodelib_gettoks(L, 3);
5585 } else {
5586 return nodelib_cantset(L, n, s);
5588 } else if (t == user_defined_node) {
5589 if (lua_key_eq(s, user_id)) {
5590 user_node_id(n) = (halfword) lua_tointeger(L, 3);
5591 } else if (lua_key_eq(s, type)) {
5592 user_node_type(n) = (halfword) lua_tointeger(L, 3);
5593 } else if (lua_key_eq(s, value)) {
5594 switch (user_node_type(n)) {
5595 case 'a':
5596 user_node_value(n) = nodelib_getlist(L, 3);
5597 break;
5598 case 'd':
5599 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5600 break;
5601 case 'l':
5602 lua_pushvalue(L, 3);
5603 if (user_node_value(n) != 0) {
5604 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
5606 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5607 break;
5608 case 'n':
5609 user_node_value(n) = nodelib_getlist(L, 3);
5610 break;
5611 case 's':
5612 user_node_value(n) = nodelib_getstring(L, 3);
5613 break;
5614 case 't':
5615 user_node_value(n) = nodelib_gettoks(L, 3);
5616 break;
5617 default:
5618 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5619 break;
5621 } else {
5622 return nodelib_cantset(L, n, s);
5624 } else if (t == pdf_annot_node) {
5625 if (lua_key_eq(s, width)) {
5626 width(n) = (halfword) lua_tointeger(L, 3);
5627 } else if (lua_key_eq(s, depth)) {
5628 depth(n) = (halfword) lua_tointeger(L, 3);
5629 } else if (lua_key_eq(s, height)) {
5630 height(n) = (halfword) lua_tointeger(L, 3);
5631 } else if (lua_key_eq(s, objnum)) {
5632 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
5633 } else if (lua_key_eq(s, data)) {
5634 pdf_annot_data(n) = nodelib_gettoks(L, 3);
5635 } else {
5636 return nodelib_cantset(L, n, s);
5638 } else if (t == pdf_dest_node) {
5639 if (lua_key_eq(s, width)) {
5640 width(n) = (halfword) lua_tointeger(L, 3);
5641 } else if (lua_key_eq(s, depth)) {
5642 depth(n) = (halfword) lua_tointeger(L, 3);
5643 } else if (lua_key_eq(s, height)) {
5644 height(n) = (halfword) lua_tointeger(L, 3);
5645 } else if (lua_key_eq(s, named_id)) {
5646 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
5647 } else if (lua_key_eq(s, dest_id)) {
5648 if (pdf_dest_named_id(n) == 1) {
5649 pdf_dest_id(n) = nodelib_gettoks(L, 3);
5650 } else {
5651 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
5653 } else if (lua_key_eq(s, dest_type)) {
5654 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
5655 } else if (lua_key_eq(s, xyz_zoom)) {
5656 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
5657 } else if (lua_key_eq(s, objnum)) {
5658 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
5659 } else {
5660 return nodelib_cantset(L, n, s);
5662 } else if (t == pdf_setmatrix_node) {
5663 if (lua_key_eq(s, data)) {
5664 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
5665 } else {
5666 return nodelib_cantset(L, n, s);
5668 } else if (t == pdf_refobj_node) {
5669 if (lua_key_eq(s, objnum)) {
5670 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
5671 } else {
5672 return nodelib_cantset(L, n, s);
5674 } else if (t == pdf_start_link_node) {
5675 if (lua_key_eq(s, width)) {
5676 width(n) = (halfword) lua_tointeger(L, 3);
5677 } else if (lua_key_eq(s, depth)) {
5678 depth(n) = (halfword) lua_tointeger(L, 3);
5679 } else if (lua_key_eq(s, height)) {
5680 height(n) = (halfword) lua_tointeger(L, 3);
5681 } else if (lua_key_eq(s, objnum)) {
5682 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
5683 } else if (lua_key_eq(s, link_attr)) {
5684 pdf_link_attr(n) = nodelib_gettoks(L, 3);
5685 } else if (lua_key_eq(s, action)) {
5686 pdf_link_action(n) = nodelib_popdirect(n); /*nodelib_getaction(L, 3);*/
5687 } else {
5688 return nodelib_cantset(L, n, s);
5690 } else if (t == write_node) {
5691 if (lua_key_eq(s, stream)) {
5692 write_stream(n) = (halfword) lua_tointeger(L, 3);
5693 } else if (lua_key_eq(s, data)) {
5694 write_tokens(n) = nodelib_gettoks(L, 3);
5695 } else {
5696 return nodelib_cantset(L, n, s);
5698 } else if (t == pdf_colorstack_node) {
5699 if (lua_key_eq(s, stack)) {
5700 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
5701 } else if (lua_key_eq(s, command)) {
5702 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
5703 } else if (lua_key_eq(s, data)) {
5704 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
5705 } else {
5706 return nodelib_cantset(L, n, s);
5708 } else if (t == pdf_action_node) {
5709 if (lua_key_eq(s, action_type)) {
5710 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
5711 } else if (lua_key_eq(s, named_id)) {
5712 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
5713 } else if (lua_key_eq(s, action_id)) {
5714 if (pdf_action_named_id(n) == 1) {
5715 pdf_action_id(n) = nodelib_gettoks(L, 3);
5716 } else {
5717 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
5719 } else if (lua_key_eq(s, file)) {
5720 pdf_action_file(n) = nodelib_gettoks(L, 3);
5721 } else if (lua_key_eq(s, new_window)) {
5722 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
5723 } else if (lua_key_eq(s, data)) {
5724 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
5725 } else {
5726 return nodelib_cantset(L, n, s);
5728 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
5729 if (lua_key_eq(s, width)) {
5730 width(n) = (halfword) lua_tointeger(L, 3);
5731 } else if (lua_key_eq(s, depth)) {
5732 depth(n) = (halfword) lua_tointeger(L, 3);
5733 } else if (lua_key_eq(s, height)) {
5734 height(n) = (halfword) lua_tointeger(L, 3);
5735 } else if (lua_key_eq(s, named_id)) {
5736 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
5737 } else if (lua_key_eq(s, thread_id)) {
5738 if (pdf_thread_named_id(n) == 1) {
5739 pdf_thread_id(n) = nodelib_gettoks(L, 3);
5740 } else {
5741 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
5743 } else if (lua_key_eq(s, thread_attr)) {
5744 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
5745 } else {
5746 return nodelib_cantset(L, n, s);
5748 } else if (t == special_node) {
5749 if (lua_key_eq(s, data)) {
5750 write_tokens(n) = nodelib_gettoks(L, 3);
5751 } else {
5752 return nodelib_cantset(L, n, s);
5754 } else if (t == open_node) {
5755 if (lua_key_eq(s, stream)) {
5756 write_stream(n) = (halfword) lua_tointeger(L, 3);
5757 } else if (lua_key_eq(s, name)) {
5758 open_name(n) = nodelib_getstring(L, 3);
5759 } else if (lua_key_eq(s, area)) {
5760 open_area(n) = nodelib_getstring(L, 3);
5761 } else if (lua_key_eq(s, ext)) {
5762 open_ext(n) = nodelib_getstring(L, 3);
5763 } else {
5764 return nodelib_cantset(L, n, s);
5766 } else if (t == close_node) {
5767 if (lua_key_eq(s, stream)) {
5768 write_stream(n) = (halfword) lua_tointeger(L, 3);
5769 } else {
5770 return nodelib_cantset(L, n, s);
5772 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
5773 (t == pdf_save_node) || (t == pdf_restore_node)) {
5774 return nodelib_cantset(L, n, s);
5775 } else {
5776 /* do nothing */
5778 return 0;
5781 static int lua_nodelib_direct_setcharacter(lua_State * L)
5783 halfword n = lua_tointeger(L, 1);
5784 if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
5785 if (type(n) == glyph_node) {
5786 character(n) = (halfword) lua_tointeger(L, 2);
5787 } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
5788 math_character(n) = (halfword) lua_tointeger(L, 2);
5791 return 0;
5794 static int lua_nodelib_direct_setnext(lua_State * L)
5796 halfword n = lua_tointeger(L, 1);
5797 if (n) {
5798 if (lua_type(L, 2) == LUA_TNUMBER) {
5799 vlink(n) = (halfword) lua_tointeger(L, 2);
5800 } else {
5801 vlink(n) = null;
5804 return 0;
5807 static int lua_nodelib_direct_setprev(lua_State * L)
5809 halfword n = lua_tointeger(L, 1);
5810 if (n) {
5811 if (lua_type(L, 2) == LUA_TNUMBER) {
5812 alink(n) = (halfword) lua_tointeger(L, 2);
5813 } else {
5814 alink(n) = null;
5817 return 0;
5820 static int lua_nodelib_direct_setboth(lua_State * L)
5822 halfword n = lua_tointeger(L, 1);
5823 if (n) {
5824 if (lua_type(L, 2) == LUA_TNUMBER) {
5825 alink(n) = (halfword) lua_tointeger(L, 2);
5826 } else {
5827 alink(n) = null;
5829 if (lua_type(L, 3) == LUA_TNUMBER) {
5830 vlink(n) = (halfword) lua_tointeger(L, 3);
5831 } else {
5832 vlink(n) = null;
5835 return 0;
5838 static int lua_nodelib_direct_setlink(lua_State * L)
5840 if (lua_type(L, 1) == LUA_TNUMBER) {
5841 halfword a = lua_tointeger(L, 1);
5842 if (lua_type(L, 2) == LUA_TNUMBER) {
5843 halfword b = lua_tointeger(L, 2);
5844 vlink(a) = b;
5845 alink(b) = a;
5846 } else {
5847 vlink(a) = null;
5849 } else if (lua_type(L, 2) == LUA_TNUMBER) {
5850 halfword b = lua_tointeger(L, 2);
5851 alink(b) = null;
5853 return 0;
5856 static int lua_nodelib_direct_is_char(lua_State * L)
5858 halfword n = lua_tointeger(L, 1);
5859 if (type(n) != glyph_node) {
5860 lua_pushnil(L); /* no glyph at all */
5861 lua_pushinteger(L,type(n)); /* can save a lookup call */
5862 return 2;
5863 } else if (subtype(n) >= 256) {
5864 lua_pushboolean(L,0); /* a done glyph */
5865 } else if (lua_type(L,2) == LUA_TNUMBER) {
5866 halfword f = lua_tointeger(L, 2);
5867 if (f && f == font(n)) {
5868 lua_pushinteger(L,character(n)); /* a todo glyph in the asked font */
5869 } else {
5870 lua_pushboolean(L,0); /* a todo glyph in another font */
5872 } else {
5873 lua_pushinteger(L,character(n)); /* a todo glyph */
5875 return 1;
5878 static int lua_nodelib_direct_is_glyph(lua_State * L)
5880 halfword n = lua_tointeger(L, 1);
5881 if (type(n) != glyph_node) {
5882 lua_pushboolean(L,0);
5883 lua_pushinteger(L,type(n));
5884 } else {
5885 lua_pushinteger(L,character(n));
5886 lua_pushinteger(L,font(n));
5888 return 2;
5891 static int lua_nodelib_direct_setdiscretionary(lua_State * L)
5893 halfword n = lua_tointeger(L, 1);
5894 if (type(n) == disc_node) {
5895 int t = lua_gettop(L) ;
5896 if (t > 1) {
5897 set_disc_field(pre_break(n), lua_tointeger(L,2));
5898 if (t > 2) {
5899 set_disc_field(post_break(n), lua_tointeger(L,3));
5900 if (t > 3) {
5901 set_disc_field(no_break(n), lua_tointeger(L,4));
5902 if (t > 4) {
5903 subtype(n) = (quarterword) lua_tointeger(L,5);
5904 if (t > 5) {
5905 disc_penalty(n) = lua_tointeger(L,6);
5908 } else {
5909 set_disc_field(no_break(n), null);
5911 } else {
5912 set_disc_field(post_break(n), null);
5913 set_disc_field(no_break(n), null);
5915 } else {
5916 set_disc_field(pre_break(n), null);
5917 set_disc_field(post_break(n), null);
5918 set_disc_field(no_break(n), null);
5921 return 0;
5925 static int lua_nodelib_direct_setfield(lua_State * L)
5927 const char *s;
5929 halfword n = lua_tointeger(L, 1);
5930 int t = type(n);
5932 if (lua_type(L, 2) == LUA_TNUMBER) {
5933 if (lua_gettop(L) == 3) {
5934 int i = lua_tointeger(L, 2);
5935 int val = lua_tointeger(L, 3);
5936 if (val == UNUSED_ATTRIBUTE) {
5937 (void) unset_attribute(n, i, val);
5938 } else {
5939 set_attribute(n, i, val);
5941 } else {
5942 luaL_error(L, "incorrect number of arguments");
5944 return 0;
5947 s = lua_tostring(L, 2);
5949 /*if (lua_key_eq(s, id)) {
5950 type(n) = (quarteword) lua_tointeger(L, 3);
5951 } else*/
5952 if (lua_key_eq(s, next)) {
5953 halfword x = nodelib_popdirect(3);
5954 if (x>0 && type(x) == glue_spec_node) {
5955 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
5957 vlink(n) = x;
5958 } else if (lua_key_eq(s, prev)) {
5959 halfword x = nodelib_popdirect(3);
5960 if (x>0 && type(x) == glue_spec_node) {
5961 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
5963 alink(n) = x;
5964 } else if (lua_key_eq(s, attr)) {
5965 if (nodetype_has_attributes(type(n))) {
5966 nodelib_setattr(L, 3, n);
5968 } else if (t == glyph_node) {
5969 if (lua_key_eq(s, subtype)) {
5970 subtype(n) = (quarterword) lua_tointeger(L, 3);
5971 } else if (lua_key_eq(s, font)) {
5972 font(n) = (halfword) lua_tointeger(L, 3);
5973 } else if (lua_key_eq(s, char)) {
5974 character(n) = (halfword) lua_tointeger(L, 3);
5975 } else if (lua_key_eq(s, xoffset)) {
5976 x_displace(n) = (halfword) lua_tointeger(L, 3);
5977 } else if (lua_key_eq(s, yoffset)) {
5978 y_displace(n) = (halfword) lua_tointeger(L, 3);
5979 } else if (lua_key_eq(s, xadvance)) {
5980 x_advance(n) = (halfword) lua_tointeger(L, 3);
5981 } else if (lua_key_eq(s, expansion_factor)) {
5982 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
5983 } else if (lua_key_eq(s, components)) {
5984 lig_ptr(n) = nodelib_popdirect(3);
5985 } else if (lua_key_eq(s, lang)) {
5986 set_char_lang(n, (halfword) lua_tointeger(L, 3));
5987 } else if (lua_key_eq(s, left)) {
5988 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
5989 } else if (lua_key_eq(s, right)) {
5990 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
5991 } else if (lua_key_eq(s, uchyph)) {
5992 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
5993 } else if (lua_key_eq(s, width)) {
5994 /* not yet */
5995 } else if (lua_key_eq(s, height)) {
5996 /* not yet */
5997 } else if (lua_key_eq(s, depth)) {
5998 /* not yet */
5999 } else {
6000 return nodelib_cantset(L, n, s);
6002 } else if ((t == hlist_node) || (t == vlist_node)) {
6003 if (lua_key_eq(s, subtype)) {
6004 subtype(n) = (quarterword) lua_tointeger(L, 3);
6005 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
6006 list_ptr(n) = nodelib_popdirect(3);
6007 } else if (lua_key_eq(s, width)) {
6008 width(n) = (halfword) lua_tointeger(L, 3);
6009 } else if (lua_key_eq(s, height)) {
6010 height(n) = (halfword) lua_tointeger(L, 3);
6011 } else if (lua_key_eq(s, depth)) {
6012 depth(n) = (halfword) lua_tointeger(L, 3);
6013 } else if (lua_key_eq(s, dir)) {
6014 box_dir(n) = nodelib_getdir(L, 3, 1);
6015 } else if (lua_key_eq(s, shift)) {
6016 shift_amount(n) = (halfword) lua_tointeger(L, 3);
6017 } else if (lua_key_eq(s, glue_order)) {
6018 glue_order(n) = (quarterword) lua_tointeger(L, 3);
6019 } else if (lua_key_eq(s, glue_sign)) {
6020 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
6021 } else if (lua_key_eq(s, glue_set)) {
6022 glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
6023 } else {
6024 return nodelib_cantset(L, n, s);
6026 } else if (t == disc_node) {
6027 if (lua_key_eq(s, subtype)) {
6028 subtype(n) = (quarterword) lua_tointeger(L, 3);
6029 } else if (lua_key_eq(s, pre)) {
6030 set_disc_field(pre_break(n), nodelib_popdirect(3));
6031 } else if (lua_key_eq(s, post)) {
6032 set_disc_field(post_break(n), nodelib_popdirect(3));
6033 } else if (lua_key_eq(s, replace)) {
6034 set_disc_field(no_break(n), nodelib_popdirect(3));
6035 } else if (lua_key_eq(s, penalty)) {
6036 disc_penalty(n) = (quarterword) lua_tointeger(L, 3);
6037 } else {
6038 return nodelib_cantset(L, n, s);
6040 } else if (t == glue_node) {
6041 if (lua_key_eq(s, subtype)) {
6042 subtype(n) = (quarterword) lua_tointeger(L, 3);
6043 } else if (lua_key_eq(s, width)) {
6044 width(n) = (halfword) lua_tointeger(L, 3);
6045 } else if (lua_key_eq(s, stretch)) {
6046 stretch(n) = (halfword) lua_tointeger(L, 3);
6047 } else if (lua_key_eq(s, shrink)) {
6048 shrink(n) = (halfword) lua_tointeger(L, 3);
6049 } else if (lua_key_eq(s, stretch_order)) {
6050 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
6051 } else if (lua_key_eq(s, shrink_order)) {
6052 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
6053 } else if (lua_key_eq(s, leader)) {
6054 leader_ptr(n) = nodelib_popdirect(3);
6055 } else {
6056 return nodelib_cantset(L, n, s);
6058 } else if (t == kern_node) {
6059 if (lua_key_eq(s, subtype)) {
6060 subtype(n) = (quarterword) lua_tointeger(L, 3);
6061 } else if (lua_key_eq(s, kern)) {
6062 width(n) = (halfword) lua_tointeger(L, 3);
6063 } else if (lua_key_eq(s, expansion_factor)) {
6064 ex_kern(n) = (halfword) lua_tointeger(L, 3);
6065 } else {
6066 return nodelib_cantset(L, n, s);
6068 } else if (t == penalty_node) {
6069 if (lua_key_eq(s, subtype)) {
6070 /* dummy subtype */
6071 } else if (lua_key_eq(s, penalty)) {
6072 penalty(n) = (halfword) lua_tointeger(L, 3);
6073 } else {
6074 return nodelib_cantset(L, n, s);
6076 } else if (t == rule_node) {
6077 if (lua_key_eq(s, subtype)) {
6078 subtype(n) = (quarterword) lua_tointeger(L, 3);
6079 } else if (lua_key_eq(s, width)) {
6080 width(n) = (halfword) lua_tointeger(L, 3);
6081 } else if (lua_key_eq(s, height)) {
6082 height(n) = (halfword) lua_tointeger(L, 3);
6083 } else if (lua_key_eq(s, depth)) {
6084 depth(n) = (halfword) lua_tointeger(L, 3);
6085 } else if (lua_key_eq(s, dir)) {
6086 rule_dir(n) = nodelib_getdir(L, 3, 1);
6087 } else if (lua_key_eq(s, index)) {
6088 rule_index(n) = (halfword) lua_tointeger(L, 3);
6089 } else if (lua_key_eq(s, transform)) {
6090 rule_transform(n) = (halfword) lua_tointeger(L, 3);
6091 } else {
6092 return nodelib_cantset(L, n, s);
6094 } else if (t == dir_node) {
6095 if (lua_key_eq(s, dir)) {
6096 dir_dir(n) = nodelib_getdir(L, 3, 0);
6097 } else if (lua_key_eq(s, level)) {
6098 dir_level(n) = (halfword) lua_tointeger(L, 3);
6099 } else if (lua_key_eq(s, subtype)) { /* can be used for anything */
6100 subtype(n) = (quarterword) lua_tointeger(L, 3);
6101 } else {
6102 return nodelib_cantset(L, n, s);
6104 } else if (t == whatsit_node) {
6105 if (lua_key_eq(s, subtype)) {
6106 subtype(n) = (quarterword) lua_tointeger(L, 3);
6107 } else {
6108 lua_nodelib_direct_setfield_whatsit(L, n, s);
6110 } else if (t == local_par_node) {
6111 if (lua_key_eq(s, pen_inter)) {
6112 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
6113 } else if (lua_key_eq(s, pen_broken)) {
6114 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
6115 } else if (lua_key_eq(s, dir)) {
6116 local_par_dir(n) = nodelib_getdir(L, 3, 1);
6117 } else if (lua_key_eq(s, box_left)) {
6118 local_box_left(n) = nodelib_getlist(L, 3);
6119 } else if (lua_key_eq(s, box_left_width)) {
6120 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
6121 } else if (lua_key_eq(s, box_right)) {
6122 local_box_right(n) = nodelib_getlist(L, 3);
6123 } else if (lua_key_eq(s, box_right_width)) {
6124 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
6125 } else {
6126 return nodelib_cantset(L, n, s);
6128 } else if (t == simple_noad) {
6129 if (lua_key_eq(s, subtype)) {
6130 subtype(n) = (quarterword) lua_tointeger(L, 3);
6131 } else if (lua_key_eq(s, nucleus)) {
6132 nucleus(n) = nodelib_popdirect(3);
6133 } else if (lua_key_eq(s, sub)) {
6134 subscr(n) = nodelib_popdirect(3);
6135 } else if (lua_key_eq(s, sup)) {
6136 supscr(n) = nodelib_popdirect(3);
6137 } else {
6138 return nodelib_cantset(L, n, s);
6140 } else if ((t == math_char_node) || (t == math_text_char_node)) {
6141 if (lua_key_eq(s, subtype)) {
6142 subtype(n) = (quarterword) lua_tointeger(L, 3);
6143 } else if (lua_key_eq(s, fam)) {
6144 math_fam(n) = (halfword) lua_tointeger(L, 3);
6145 } else if (lua_key_eq(s, char)) {
6146 math_character(n) = (halfword) lua_tointeger(L, 3);
6147 } else {
6148 return nodelib_cantset(L, n, s);
6150 } else if (t == mark_node) {
6151 if (lua_key_eq(s, subtype)) {
6152 subtype(n) = (quarterword) lua_tointeger(L, 3);
6153 } else if (lua_key_eq(s, class)) {
6154 mark_class(n) = (halfword) lua_tointeger(L, 3);
6155 } else if (lua_key_eq(s, mark)) {
6156 mark_ptr(n) = nodelib_gettoks(L, 3);
6157 } else {
6158 return nodelib_cantset(L, n, s);
6160 } else if (t == ins_node) {
6161 if (lua_key_eq(s, subtype)) {
6162 subtype(n) = (quarterword) lua_tointeger(L, 3);
6163 } else if (lua_key_eq(s, cost)) {
6164 float_cost(n) = (halfword) lua_tointeger(L, 3);
6165 } else if (lua_key_eq(s, depth)) {
6166 depth(n) = (halfword) lua_tointeger(L, 3);
6167 } else if (lua_key_eq(s, height)) {
6168 height(n) = (halfword) lua_tointeger(L, 3);
6169 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
6170 ins_ptr(n) = nodelib_popdirect(3);
6171 /* glue */
6172 } else if (lua_key_eq(s, width)) {
6173 width(n) = (halfword) lua_tointeger(L, 3);
6174 } else if (lua_key_eq(s, stretch)) {
6175 stretch(n) = (halfword) lua_tointeger(L, 3);
6176 } else if (lua_key_eq(s, shrink)) {
6177 shrink(n) = (halfword) lua_tointeger(L, 3);
6178 } else if (lua_key_eq(s, stretch_order)) {
6179 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
6180 } else if (lua_key_eq(s, shrink_order)) {
6181 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
6182 } else {
6183 return nodelib_cantset(L, n, s);
6185 } else if (t == math_node) {
6186 if (lua_key_eq(s, subtype)) {
6187 subtype(n) = (quarterword) lua_tointeger(L, 3);
6188 } else if (lua_key_eq(s, surround)) {
6189 surround(n) = (halfword) lua_tointeger(L, 3);
6190 /* glue */
6191 } else if (lua_key_eq(s, width)) {
6192 width(n) = (halfword) lua_tointeger(L, 3);
6193 } else if (lua_key_eq(s, stretch)) {
6194 stretch(n) = (halfword) lua_tointeger(L, 3);
6195 } else if (lua_key_eq(s, shrink)) {
6196 shrink(n) = (halfword) lua_tointeger(L, 3);
6197 } else if (lua_key_eq(s, stretch_order)) {
6198 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
6199 } else if (lua_key_eq(s, shrink_order)) {
6200 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
6201 } else {
6202 return nodelib_cantset(L, n, s);
6204 } else if (t == fraction_noad) {
6205 if (lua_key_eq(s, subtype)) {
6206 subtype(n) = (quarterword) lua_tointeger(L, 3);
6207 } else if (lua_key_eq(s, width)) {
6208 thickness(n) = (halfword) lua_tointeger(L, 3);
6209 } else if (lua_key_eq(s, num)) {
6210 numerator(n) = nodelib_popdirect(3);
6211 } else if (lua_key_eq(s, denom)) {
6212 denominator(n) = nodelib_popdirect(3);
6213 } else if (lua_key_eq(s, left)) {
6214 left_delimiter(n) = nodelib_popdirect(3);
6215 } else if (lua_key_eq(s, right)) {
6216 right_delimiter(n) = nodelib_popdirect(3);
6217 } else {
6218 return nodelib_cantset(L, n, s);
6220 } else if (t == style_node) {
6221 if (lua_key_eq(s, subtype)) {
6222 /* dummy subtype */
6223 } else if (lua_key_eq(s, style)) {
6224 assign_math_style(L,2,subtype(n));
6225 } else {
6226 /* return nodelib_cantset(L, n, s); */
6228 } else if (t == accent_noad) {
6229 if (lua_key_eq(s, subtype)) {
6230 subtype(n) = (quarterword) lua_tointeger(L, 3);
6231 } else if (lua_key_eq(s, nucleus)) {
6232 nucleus(n) = nodelib_popdirect(3);
6233 } else if (lua_key_eq(s, sub)) {
6234 subscr(n) = nodelib_popdirect(3);
6235 } else if (lua_key_eq(s, sup)) {
6236 supscr(n) = nodelib_popdirect(3);
6237 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
6238 top_accent_chr(n) = nodelib_popdirect(3);
6239 } else if (lua_key_eq(s, bot_accent)) {
6240 bot_accent_chr(n) = nodelib_popdirect(3);
6241 } else if (lua_key_eq(s, overlay_accent)) {
6242 overlay_accent_chr(n) = nodelib_popdirect(3);
6243 } else {
6244 return nodelib_cantset(L, n, s);
6246 } else if (t == fence_noad) {
6247 if (lua_key_eq(s, subtype)) {
6248 subtype(n) = (quarterword) lua_tointeger(L, 3);
6249 } else if (lua_key_eq(s, delim)) {
6250 delimiter(n) = nodelib_popdirect(3);
6251 } else {
6252 return nodelib_cantset(L, n, s);
6254 } else if (t == delim_node) {
6255 if (lua_key_eq(s, subtype)) {
6256 subtype(n) = (quarterword) lua_tointeger(L, 3);
6257 } else if (lua_key_eq(s, small_fam)) {
6258 small_fam(n) = (halfword) lua_tointeger(L, 3);
6259 } else if (lua_key_eq(s, small_char)) {
6260 small_char(n) = (halfword) lua_tointeger(L, 3);
6261 } else if (lua_key_eq(s, large_fam)) {
6262 large_fam(n) = (halfword) lua_tointeger(L, 3);
6263 } else if (lua_key_eq(s, large_char)) {
6264 large_char(n) = (halfword) lua_tointeger(L, 3);
6265 } else {
6266 return nodelib_cantset(L, n, s);
6268 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
6269 if (lua_key_eq(s, subtype)) {
6270 subtype(n) = (quarterword) lua_tointeger(L, 3);
6271 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
6272 math_list(n) = nodelib_popdirect(3);
6273 } else {
6274 return nodelib_cantset(L, n, s);
6276 } else if (t == radical_noad) {
6277 if (lua_key_eq(s, subtype)) {
6278 subtype(n) = (quarterword) lua_tointeger(L, 3);
6279 } else if (lua_key_eq(s, nucleus)) {
6280 nucleus(n) = nodelib_popdirect(3);
6281 } else if (lua_key_eq(s, sub)) {
6282 subscr(n) = nodelib_popdirect(3);
6283 } else if (lua_key_eq(s, sup)) {
6284 supscr(n) = nodelib_popdirect(3);
6285 } else if (lua_key_eq(s, left)) {
6286 left_delimiter(n) = nodelib_popdirect(3);
6287 } else if (lua_key_eq(s, degree)) {
6288 degree(n) = nodelib_popdirect(3);
6289 } else {
6290 return nodelib_cantset(L, n, s);
6292 } else if (t == margin_kern_node) {
6293 if (lua_key_eq(s, subtype)) {
6294 subtype(n) = (quarterword) lua_tointeger(L, 3);
6295 } else if (lua_key_eq(s, width)) {
6296 width(n) = (halfword) lua_tointeger(L, 3);
6297 } else if (lua_key_eq(s, glyph)) {
6298 margin_char(n) = nodelib_popdirect(3);
6299 } else {
6300 return nodelib_cantset(L, n, s);
6302 } else if (t == split_up_node) {
6303 if (lua_key_eq(s, subtype)) {
6304 subtype(n) = (quarterword) lua_tointeger(L, 3);
6305 } else if (lua_key_eq(s, last_ins_ptr)) {
6306 last_ins_ptr(n) = nodelib_popdirect(3);
6307 } else if (lua_key_eq(s, best_ins_ptr)) {
6308 best_ins_ptr(n) = nodelib_popdirect(3);
6309 } else if (lua_key_eq(s, broken_ptr)) {
6310 broken_ptr(n) = nodelib_popdirect(3);
6311 } else if (lua_key_eq(s, broken_ins)) {
6312 broken_ins(n) = nodelib_popdirect(3);
6313 } else {
6314 return nodelib_cantset(L, n, s);
6316 } else if (t == choice_node) {
6317 if (lua_key_eq(s, subtype)) {
6318 subtype(n) = (quarterword) lua_tointeger(L, 3);
6319 } else if (lua_key_eq(s, display)) {
6320 display_mlist(n) = nodelib_popdirect(3);
6321 } else if (lua_key_eq(s, text)) {
6322 text_mlist(n) = nodelib_popdirect(3);
6323 } else if (lua_key_eq(s, script)) {
6324 script_mlist(n) = nodelib_popdirect(3);
6325 } else if (lua_key_eq(s, scriptscript)) {
6326 script_script_mlist(n) = nodelib_popdirect(3);
6327 } else {
6328 return nodelib_cantset(L, n, s);
6330 } else if (t == inserting_node) {
6331 if (lua_key_eq(s, subtype)) {
6332 subtype(n) = (quarterword) lua_tointeger(L, 3);
6333 } else if (lua_key_eq(s, last_ins_ptr)) {
6334 last_ins_ptr(n) = nodelib_popdirect(3);
6335 } else if (lua_key_eq(s, best_ins_ptr)) {
6336 best_ins_ptr(n) = nodelib_popdirect(3);
6337 } else {
6338 return nodelib_cantset(L, n, s);
6340 } else if (t == attribute_node) {
6341 if (lua_key_eq(s, subtype)) {
6342 /* dummy subtype */
6343 } else if (lua_key_eq(s, number)) {
6344 attribute_id(n) = (halfword) lua_tointeger(L, 3);
6345 } else if (lua_key_eq(s, value)) {
6346 attribute_value(n) = (halfword) lua_tointeger(L, 3);
6347 } else {
6348 return nodelib_cantset(L, n, s);
6350 } else if (t == adjust_node) {
6351 if (lua_key_eq(s, subtype)) {
6352 subtype(n) = (quarterword) lua_tointeger(L, 3);
6353 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
6354 adjust_ptr(n) = nodelib_popdirect(3);
6355 } else {
6356 return nodelib_cantset(L, n, s);
6358 } else if (t == unset_node) {
6359 if (lua_key_eq(s, subtype)) {
6360 /* dummy subtype */
6361 } else if (lua_key_eq(s, width)) {
6362 width(n) = (halfword) lua_tointeger(L, 3);
6363 } else if (lua_key_eq(s, height)) {
6364 height(n) = (halfword) lua_tointeger(L, 3);
6365 } else if (lua_key_eq(s, depth)) {
6366 depth(n) = (halfword) lua_tointeger(L, 3);
6367 } else if (lua_key_eq(s, dir)) {
6368 box_dir(n) = nodelib_getdir(L, 3, 1);
6369 } else if (lua_key_eq(s, shrink)) {
6370 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
6371 } else if (lua_key_eq(s, glue_order)) {
6372 glue_order(n) = (quarterword) lua_tointeger(L, 3);
6373 } else if (lua_key_eq(s, glue_sign)) {
6374 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
6375 } else if (lua_key_eq(s, stretch)) {
6376 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
6377 } else if (lua_key_eq(s, count)) {
6378 span_count(n) = (quarterword) lua_tointeger(L, 3);
6379 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
6380 list_ptr(n) = nodelib_popdirect(3);
6381 } else {
6382 return nodelib_cantset(L, n, s);
6384 } else if (t == attribute_list_node) {
6385 if (lua_key_eq(s, subtype)) {
6386 /* dummy subtype */
6387 } else {
6388 return nodelib_cantset(L, n, s);
6390 } else if (t == boundary_node) {
6391 if (lua_key_eq(s, subtype)) {
6392 subtype(n) = (quarterword) lua_tointeger(L, 3);
6393 } else if (lua_key_eq(s, value)) {
6394 boundary_value(n) = lua_tointeger(L, 3);
6395 } else {
6396 return nodelib_cantset(L, n, s);
6398 } else if (t == glue_spec_node) {
6399 if (lua_key_eq(s, width)) {
6400 width(n) = (halfword) lua_tointeger(L, 3);
6401 } else if (lua_key_eq(s, stretch)) {
6402 stretch(n) = (halfword) lua_tointeger(L, 3);
6403 } else if (lua_key_eq(s, shrink)) {
6404 shrink(n) = (halfword) lua_tointeger(L, 3);
6405 } else if (lua_key_eq(s, stretch_order)) {
6406 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
6407 } else if (lua_key_eq(s, shrink_order)) {
6408 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
6409 } else {
6410 return nodelib_cantset(L, n, s);
6412 } else {
6413 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
6415 return 0;
6418 /* boxes */
6420 static int direct_get_box_id(lua_State * L, int i)
6422 const char *s;
6423 int cur_cs1, cur_cmd1;
6424 size_t k = 0;
6425 int j = -1;
6426 switch (lua_type(L, i)) {
6427 case LUA_TSTRING:
6428 s = lua_tolstring(L, i, &k);
6429 cur_cs1 = string_lookup(s, k);
6430 cur_cmd1 = eq_type(cur_cs1);
6431 if (cur_cmd1 == char_given_cmd ||
6432 cur_cmd1 == math_given_cmd) {
6433 j = equiv(cur_cs1);
6435 break;
6436 case LUA_TNUMBER:
6437 j = lua_tointeger(L, (i));
6438 break;
6439 default:
6440 luaL_error(L, "argument must be a string or a number");
6441 j = -1; /* not a valid box id */
6443 return j;
6446 /* node.getbox = tex.getbox */
6448 /* node.direct.getbox */
6450 static int lua_nodelib_direct_getbox(lua_State * L)
6452 int t;
6453 int k = direct_get_box_id(L, -1);
6454 direct_check_index_range(k, "getbox");
6455 t = get_tex_box_register(k);
6456 if (t == null) {
6457 lua_pushnil(L);
6458 } else {
6459 lua_pushinteger(L, t);
6461 return 1;
6464 /* node.setbox = tex.setbox */
6465 /* node.setbox */
6467 static int lua_nodelib_direct_setbox(lua_State * L)
6469 int isglobal = 0;
6470 int j, k, err, t;
6471 int save_global_defs ;
6472 int n = lua_gettop(L);
6473 if (n == 3 && (lua_type(L, 1) == LUA_TSTRING)) {
6474 const char *s = lua_tostring(L, 1);
6475 if (lua_key_eq(s, global))
6476 isglobal = 1;
6478 t = lua_type(L, -1);
6479 k = direct_get_box_id(L, -2);
6480 direct_check_index_range(k, "setbox");
6481 if (t == LUA_TBOOLEAN) {
6482 j = lua_toboolean(L, -1);
6483 if (j == 0) {
6484 j = null;
6485 } else {
6486 return 0;
6488 } else if (t == LUA_TNIL) {
6489 j = null;
6490 } else {
6491 j = nodelib_popdirect(-1);
6492 if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
6493 luaL_error(L, "setbox: incompatible node type (%s)\n",get_node_name(type(j), subtype(j)));
6494 return 0;
6498 save_global_defs = int_par(global_defs_code);
6499 if (isglobal) {
6500 int_par(global_defs_code) = 1;
6502 err = set_tex_box_register(k, j);
6503 int_par(global_defs_code) = save_global_defs;
6504 if (err) {
6505 luaL_error(L, "incorrect value");
6507 return 0;
6510 /* node.is_node(n) */
6512 static int lua_nodelib_is_node(lua_State * L)
6514 if (maybe_isnode(L,1) == NULL)
6515 lua_pushboolean(L,0);
6516 else
6517 lua_pushboolean(L,1);
6518 return 1;
6521 /* node.direct.is_direct(n) (handy for mixed usage testing) */
6523 static int lua_nodelib_direct_is_direct(lua_State * L)
6524 { /*
6525 quick and dirty and faster than not node.is_node, this helper
6526 returns false or <direct>
6529 if (lua_type(L,1) == LUA_TNUMBER)
6530 lua_pushboolean(L,1);
6531 else
6532 lua_pushboolean(L,0);
6534 if (lua_type(L,1) != LUA_TNUMBER)
6535 lua_pushboolean(L,0);
6536 /* else return direct */
6537 return 1;
6540 /* node.direct.is_node(n) (handy for mixed usage testing) */
6542 static int lua_nodelib_direct_is_node(lua_State * L)
6543 { /*
6544 quick and dirty, only checks userdata, node.is_node is slower but
6545 more exact, this helper returns false or <node>
6548 halfword *n = lua_touserdata(L, 1);
6549 if (n != NULL) {
6550 lua_pushboolean(L,1);
6551 } else {
6552 lua_pushboolean(L,0);
6555 if (maybe_isnode(L,1) == NULL)
6556 lua_pushboolean(L,0);
6557 /* else assume and return node */
6558 return 1;
6562 Beware, enabling and disabling can result in an inconsistent properties table
6563 but it might make sense sometimes. Of course by default we have disabled this
6564 mechanism. And, one can always sweep the table empty.
6567 static int lua_nodelib_properties_set_mode(lua_State * L) /* hh */
6568 { /* <boolean> */
6569 if (lua_isboolean(L,1)) {
6570 lua_properties_enabled = lua_toboolean(L,1);
6572 if (lua_isboolean(L,2)) {
6573 lua_properties_use_metatable = lua_toboolean(L,2);
6575 return 0;
6578 /* We used to have variants in assigned defaults but they made no sense. */
6580 static int lua_nodelib_properties_flush_table(lua_State * L) /* hh */
6581 { /* <node|direct> <number> */
6582 lua_get_metatablelua(node_properties);
6583 lua_pushnil(L); /* initializes lua_next */
6584 while (lua_next(L,-2) != 0) {
6585 lua_pushvalue(L,-2);
6586 lua_pushnil(L);
6587 lua_settable(L,-5);
6588 lua_pop(L,1);
6590 return 1;
6593 /* maybe we should allocate a proper index 0..var_mem_max but not now */
6595 static int lua_nodelib_get_property(lua_State * L) /* hh */
6596 { /* <node> */
6597 halfword n = *((halfword *) lua_touserdata(L, 1));
6598 if (n == null) {
6599 lua_pushnil(L);
6600 } else {
6601 lua_get_metatablelua(node_properties);
6602 lua_rawgeti(L,-1,n);
6604 return 1;
6607 static int lua_nodelib_direct_get_property(lua_State * L) /* hh */
6608 { /* <direct> */
6609 halfword n = lua_tointeger(L, 1);
6610 if (n == null) {
6611 lua_pushnil(L);
6612 } else {
6613 lua_get_metatablelua(node_properties);
6614 lua_rawgeti(L,-1,n);
6616 return 1;
6619 static int lua_nodelib_set_property(lua_State * L) /* hh */
6621 /* <node> <value> */
6622 halfword n = *((halfword *) lua_touserdata(L, 1));
6623 if (n != null) {
6624 lua_settop(L,2);
6625 lua_get_metatablelua(node_properties);
6626 /* <node> <value> <propertytable> */
6627 lua_replace(L,-3);
6628 /* <propertytable> <value> */
6629 lua_rawseti(L,-2,n);
6631 return 0;
6634 static int lua_nodelib_direct_set_property(lua_State * L) /* hh */
6636 /* <direct> <value> */
6637 halfword n = lua_tointeger(L, 1);
6638 if (n != null) {
6639 lua_settop(L,2);
6640 lua_get_metatablelua(node_properties);
6641 /* <node> <value> <propertytable> */
6642 lua_replace(L,1);
6643 /* <propertytable> <value> */
6644 lua_rawseti(L,1,n);
6646 return 0;
6649 static int lua_nodelib_direct_properties_get_table(lua_State * L) /* hh */
6650 { /* <node|direct> */
6651 lua_get_metatablelua(node_properties);
6652 return 1;
6655 static int lua_nodelib_properties_get_table(lua_State * L) /* hh */
6656 { /* <node|direct> */
6657 lua_get_metatablelua(node_properties_indirect);
6658 return 1;
6661 /* bonus */
6663 static int lua_nodelib_get_property_t(lua_State * L) /* hh */
6664 { /* <table> <node> */
6665 halfword n = *((halfword *) lua_touserdata(L, 2));
6666 if (n == null) {
6667 lua_pushnil(L);
6668 } else {
6669 lua_rawgeti(L,1,n);
6671 return 1;
6674 static int lua_nodelib_set_property_t(lua_State * L) /* hh */
6676 /* <table> <node> <value> */
6677 halfword n = *((halfword *) lua_touserdata(L, 2));
6678 if (n != null) {
6679 lua_settop(L,3);
6680 lua_rawseti(L,1,n);
6682 return 0;
6685 /* extra helpers */
6687 static int lua_nodelib_effective_glue(lua_State * L)
6689 halfword *glue;
6690 halfword *parent;
6691 glue = lua_touserdata(L, 1);
6692 if ((glue == NULL) || (type(*glue) != glue_node)) {
6693 lua_pushnil(L) ;
6694 } else {
6695 int w = width(*glue) ;
6696 parent = lua_touserdata(L, 2);
6697 if ((parent != NULL) && ((type(*parent) == hlist_node) || (type(*parent) == vlist_node))) {
6698 if ((int)glue_sign(*parent) == 1) {
6699 if (stretch_order(*glue) == glue_order(*parent)) {
6700 w += stretch(*glue) * glue_set(*parent);
6702 } else if (glue_sign(*parent) == 2) {
6703 if (shrink_order(*glue) == glue_order(*parent)) {
6704 w -= shrink(*glue) * glue_set(*parent);
6708 lua_pushinteger(L,w);
6710 return 1;
6714 static int lua_nodelib_direct_effective_glue(lua_State * L)
6716 halfword glue = lua_tointeger(L, 1);
6717 if ((glue == null) || (type(glue) != glue_node)) {
6718 lua_pushnil(L) ;
6719 } else {
6720 int w = width(glue) ;
6721 halfword parent = lua_tointeger(L, 2);
6722 if ((parent != null) && ((type(parent) == hlist_node) || (type(parent) == vlist_node))) {
6723 if ((int)glue_sign(parent) == 1) {
6724 if (stretch_order(glue) == glue_order(parent)) {
6725 w += stretch(glue) * glue_set(parent);
6727 } else if (glue_sign(parent) == 2) {
6728 if (shrink_order(glue) == glue_order(parent)) {
6729 w -= shrink(glue) * glue_set(parent);
6733 lua_pushinteger(L,w);
6735 return 1;
6739 static const struct luaL_Reg nodelib_p[] = {
6740 {"__index", lua_nodelib_get_property_t},
6741 {"__newindex", lua_nodelib_set_property_t},
6742 {NULL, NULL} /* sentinel */
6745 static void lua_new_properties_table(lua_State * L)
6747 lua_pushstring(L,"node.properties");
6748 lua_newtable(L);
6749 lua_settable(L,LUA_REGISTRYINDEX);
6751 lua_pushstring(L,"node.properties.indirect");
6752 lua_newtable(L);
6753 luaL_newmetatable(L,"node.properties.indirect.meta");
6754 luaL_register(L, NULL, nodelib_p);
6755 lua_setmetatable(L,-2);
6756 lua_settable(L,LUA_REGISTRYINDEX);
6759 /* node.direct.* */
6761 static const struct luaL_Reg direct_nodelib_f[] = {
6762 {"copy", lua_nodelib_direct_copy},
6763 {"copy_list", lua_nodelib_direct_copy_list},
6764 {"count", lua_nodelib_direct_count},
6765 {"current_attr", lua_nodelib_direct_currentattr},
6766 {"dimensions", lua_nodelib_direct_dimensions},
6767 {"do_ligature_n", lua_nodelib_direct_do_ligature_n},
6768 {"end_of_math", lua_nodelib_direct_end_of_math},
6769 /* {"family_font", lua_nodelib_mfont}, */ /* no node argument */
6770 /* {"fields", lua_nodelib_fields}, */ /* no node argument */
6771 {"first_glyph", lua_nodelib_direct_first_glyph},
6772 {"flush_list", lua_nodelib_direct_flush_list},
6773 {"flush_node", lua_nodelib_direct_flush_node},
6774 {"free", lua_nodelib_direct_free},
6775 {"getbox", lua_nodelib_direct_getbox},
6776 {"getchar", lua_nodelib_direct_getcharacter},
6777 {"getdisc", lua_nodelib_direct_getdiscretionary},
6778 {"getfield", lua_nodelib_direct_getfield},
6779 {"getfont", lua_nodelib_direct_getfont},
6780 {"getid", lua_nodelib_direct_getid},
6781 {"getnext", lua_nodelib_direct_getnext},
6782 {"getprev", lua_nodelib_direct_getprev},
6783 {"getboth", lua_nodelib_direct_getboth},
6784 {"getlist", lua_nodelib_direct_getlist},
6785 {"getleader", lua_nodelib_direct_getleader},
6786 {"getsubtype", lua_nodelib_direct_getsubtype},
6787 {"has_glyph", lua_nodelib_direct_has_glyph},
6788 {"has_attribute", lua_nodelib_direct_has_attribute},
6789 {"get_attribute", lua_nodelib_direct_get_attribute},
6790 {"has_field", lua_nodelib_direct_has_field},
6791 {"is_char", lua_nodelib_direct_is_char},
6792 {"is_glyph", lua_nodelib_direct_is_glyph},
6793 {"hpack", lua_nodelib_direct_hpack},
6794 /* {"id", lua_nodelib_id}, */ /* no node argument */
6795 {"insert_after", lua_nodelib_direct_insert_after},
6796 {"insert_before", lua_nodelib_direct_insert_before},
6797 {"is_direct", lua_nodelib_direct_is_direct},
6798 {"is_node", lua_nodelib_direct_is_node},
6799 {"kerning", font_tex_direct_kerning},
6800 {"last_node", lua_nodelib_direct_last_node},
6801 {"length", lua_nodelib_direct_length},
6802 {"ligaturing", font_tex_direct_ligaturing},
6803 /* {"mlist_to_hlist", lua_nodelib_mlist_to_hset_properties_modelist}, */
6804 {"new", lua_nodelib_direct_new},
6805 {"tostring", lua_nodelib_direct_tostring},
6806 {"protect_glyphs", lua_nodelib_direct_protect_glyphs},
6807 {"protect_glyph", lua_nodelib_direct_protect_glyph},
6808 {"protrusion_skippable", lua_nodelib_direct_cp_skipable},
6809 {"remove", lua_nodelib_direct_remove},
6810 {"set_attribute", lua_nodelib_direct_set_attribute},
6811 {"setbox", lua_nodelib_direct_setbox},
6812 {"setfield", lua_nodelib_direct_setfield},
6813 {"setchar", lua_nodelib_direct_setcharacter},
6814 {"setdisc", lua_nodelib_direct_setdiscretionary},
6815 {"setnext", lua_nodelib_direct_setnext},
6816 {"setprev", lua_nodelib_direct_setprev},
6817 {"setboth", lua_nodelib_direct_setboth},
6818 {"setlink", lua_nodelib_direct_setlink},
6819 {"setlist", lua_nodelib_direct_setlist},
6820 {"setleader", lua_nodelib_direct_setleader},
6821 {"setsubtype", lua_nodelib_direct_setsubtype},
6822 {"slide", lua_nodelib_direct_slide},
6823 /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
6824 {"tail", lua_nodelib_direct_tail},
6825 {"todirect", lua_nodelib_direct_todirect},
6826 {"tonode", lua_nodelib_direct_tonode},
6827 {"traverse", lua_nodelib_direct_traverse},
6828 {"traverse_id", lua_nodelib_direct_traverse_filtered},
6829 {"traverse_char", lua_nodelib_direct_traverse_char},
6830 /* {"type", lua_nodelib_type}, */ /* no node argument */
6831 /* {"types", lua_nodelib_types}, */ /* no node argument */
6832 {"unprotect_glyphs", lua_nodelib_direct_unprotect_glyphs},
6833 {"unset_attribute", lua_nodelib_direct_unset_attribute},
6834 {"setglue",lua_nodelib_direct_set_glue},
6835 {"getglue",lua_nodelib_direct_get_glue},
6836 {"is_zero_glue",lua_nodelib_direct_is_zero_glue},
6837 {"usedlist", lua_nodelib_direct_usedlist},
6838 {"vpack", lua_nodelib_direct_vpack},
6839 /* {"whatsits", lua_nodelib_whatsits}, */ /* no node argument */
6840 {"write", lua_nodelib_direct_append},
6841 {"set_properties_mode",lua_nodelib_properties_set_mode},
6842 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6843 {"get_properties_table",lua_nodelib_direct_properties_get_table}, /* hh experiment */
6844 {"getproperty", lua_nodelib_direct_get_property},
6845 {"setproperty", lua_nodelib_direct_set_property},
6846 {"effective_glue", lua_nodelib_direct_effective_glue},
6847 /* done */
6848 {NULL, NULL} /* sentinel */
6851 /* node.* */
6853 static const struct luaL_Reg nodelib_f[] = {
6854 {"copy", lua_nodelib_copy},
6855 {"copy_list", lua_nodelib_copy_list},
6856 {"count", lua_nodelib_count},
6857 {"current_attr", lua_nodelib_currentattr},
6858 {"dimensions", lua_nodelib_dimensions},
6859 {"do_ligature_n", lua_nodelib_do_ligature_n},
6860 {"end_of_math", lua_nodelib_end_of_math},
6861 {"family_font", lua_nodelib_mfont},
6862 {"fields", lua_nodelib_fields},
6863 {"subtypes", lua_nodelib_subtypes},
6864 {"first_glyph", lua_nodelib_first_glyph},
6865 {"flush_list", lua_nodelib_flush_list},
6866 {"flush_node", lua_nodelib_flush_node},
6867 {"free", lua_nodelib_free},
6868 /* {"getbox", lua_nodelib_getbox}, */ /* tex.getbox */
6869 {"getnext", lua_nodelib_getnext},
6870 {"getprev", lua_nodelib_getprev},
6871 {"getboth", lua_nodelib_getboth},
6872 {"getdisc", lua_nodelib_getdiscretionary},
6873 {"getlist", lua_nodelib_getlist},
6874 {"getleader", lua_nodelib_getleader},
6875 {"getid", lua_nodelib_getid},
6876 {"getsubtype", lua_nodelib_getsubtype},
6877 {"getfont", lua_nodelib_getfont},
6878 {"getchar", lua_nodelib_getcharacter},
6879 {"getfield", lua_nodelib_getfield},
6880 {"setfield", lua_nodelib_setfield},
6881 {"has_glyph", lua_nodelib_has_glyph},
6882 {"has_attribute", lua_nodelib_has_attribute},
6883 {"get_attribute", lua_nodelib_get_attribute},
6884 {"has_field", lua_nodelib_has_field},
6885 {"is_char", lua_nodelib_is_char},
6886 {"is_glyph", lua_nodelib_is_glyph},
6887 {"hpack", lua_nodelib_hpack},
6888 {"id", lua_nodelib_id},
6889 {"insert_after", lua_nodelib_insert_after},
6890 {"insert_before", lua_nodelib_insert_before},
6891 {"is_node", lua_nodelib_is_node},
6892 {"kerning", font_tex_kerning},
6893 {"last_node", lua_nodelib_last_node},
6894 {"length", lua_nodelib_length},
6895 {"ligaturing", font_tex_ligaturing},
6896 {"mlist_to_hlist", lua_nodelib_mlist_to_hlist},
6897 {"new", lua_nodelib_new},
6898 {"next", lua_nodelib_next}, /* getnext is somewhat more efficient, and get* fits better in direct compatibility */
6899 {"prev", lua_nodelib_prev}, /* getprev is somewhat more efficient, and get* fits better in direct compatibility */
6900 {"tostring", lua_nodelib_tostring},
6901 {"protect_glyphs", lua_nodelib_protect_glyphs},
6902 {"protect_glyph", lua_nodelib_protect_glyph},
6903 {"protrusion_skippable", lua_nodelib_cp_skipable},
6904 {"remove", lua_nodelib_remove},
6905 /* {"setbox", lua_nodelib_setbox}, */ /* tex.setbox */
6906 {"set_attribute", lua_nodelib_set_attribute},
6907 {"slide", lua_nodelib_slide},
6908 {"subtype", lua_nodelib_subtype},
6909 {"tail", lua_nodelib_tail},
6910 {"traverse", lua_nodelib_traverse},
6911 {"traverse_id", lua_nodelib_traverse_filtered},
6912 {"traverse_char", lua_nodelib_traverse_char},
6913 {"type", lua_nodelib_type},
6914 {"types", lua_nodelib_types},
6915 {"unprotect_glyphs", lua_nodelib_unprotect_glyphs},
6916 {"unset_attribute", lua_nodelib_unset_attribute},
6917 {"setglue",lua_nodelib_set_glue},
6918 {"getglue",lua_nodelib_get_glue},
6919 {"is_zero_glue",lua_nodelib_is_zero_glue},
6920 {"usedlist", lua_nodelib_usedlist},
6921 {"vpack", lua_nodelib_vpack},
6922 {"whatsits", lua_nodelib_whatsits},
6923 {"write", lua_nodelib_append},
6924 /* experiment */
6925 /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ /* hh experiment */
6926 /* experiment */
6927 {"set_properties_mode",lua_nodelib_properties_set_mode}, /* hh experiment */
6928 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6929 {"get_properties_table",lua_nodelib_properties_get_table}, /* bonus */ /* hh experiment */
6930 {"getproperty", lua_nodelib_get_property}, /* hh experiment */
6931 {"setproperty", lua_nodelib_set_property}, /* hh experiment */
6932 {"effective_glue", lua_nodelib_effective_glue},
6933 /* done */
6934 {NULL, NULL} /* sentinel */
6937 static const struct luaL_Reg nodelib_m[] = {
6938 {"__index", lua_nodelib_fast_getfield},
6939 {"__newindex", lua_nodelib_fast_setfield},
6940 {"__tostring", lua_nodelib_tostring},
6941 {"__eq", lua_nodelib_equal},
6942 {NULL, NULL} /* sentinel */
6945 int luaopen_node(lua_State * L)
6948 lua_new_properties_table(L);
6950 /* the main metatable of node userdata */
6951 luaL_newmetatable(L, NODE_METATABLE);
6952 /* node.* */
6953 luaL_register(L, NULL, nodelib_m);
6954 luaL_register(L, "node", nodelib_f);
6955 /* node.direct */
6956 lua_pushstring(L,"direct");
6957 lua_newtable(L);
6958 luaL_register(L, NULL, direct_nodelib_f);
6959 lua_rawset(L,-3);
6960 return 1;
6963 void nodelist_to_lua(lua_State * L, int n)
6965 lua_pushinteger(L, n);
6966 lua_nodelib_push(L);
6969 int nodelist_from_lua(lua_State * L)
6971 if (lua_isnil(L, -1)) {
6972 return null;
6973 } else {
6974 halfword n= *check_isnode(L, -1);
6975 return (n ? n : null);