beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / lua / lnodelib.c
bloba5d7d7439ee66531d268361d4a0532cfef7c0cd5
1 /* lnodelib.c
3 Copyright 2006-2013 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
7 LuaTeX is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License along
18 with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
24 The node getter and setter are adapted a bit by Hans and Luigi so blame
25 them! On the agenda: check all keys, maybe hide some fields that are not
26 supposed to be seen and set (scratch fields for the backend and par
27 builder).
29 After doing lots of tests with luatex and luajittex, with and without jit,
30 and with and without ffi, we came to the conclusion that userdata prevents
31 a speedup. We also found that the checking of metatables as well as assignment
32 comes with overhead that can't be neglected. This is normally not really a
33 problem but when processing fonts for more complex scripts it's quite some
34 overhead.
36 Because the userdata approach has some benefits, we stick to this. We did
37 some experiments with fast access (assuming nodes) and kept some of the code
38 commented here, but eventually settled for the direct approach. For code that
39 is proven to be okay, one can use the direct variants and operate on nodes
40 more directly. Currently these are numbers, but that might become light
41 userdata at one point, so *never* rely on that property. An important aspect
42 is that one cannot mix both methods, although with node.direct.tonode and
43 node.direct.todirect one can cast both representations.
45 So the advice is: use the indexed approach when possible and investigate the
46 direct one when speed might be an issue. For that reason we also provide the
47 get* and set* functions in the top level node namespace. There is a limited set
48 of getters.
50 getnext : parsing nodelist always involves this one
51 getprev : used less but is logical companion to getnext
52 getid : consulted a lot
53 getsubtype : consulted less but also a topper
54 getfont : used a lot in otf handling (glyph nodes are consulted a lot)
55 getchar : idem and also in other places
56 getlist : we often parse nested lists so this is a convenient one too (only hlist/vlist !)
57 getleader : comparable to list, seldom used in tex (but needs consulting
58 like lists)
59 getfield : generic getter, sufficient for the rest (other field names are
60 often shared so a specific getter makes no sense then)
62 Keep in mind that these only make sense when we're calling them millions of
63 times (which happens in font processing for instance). Setters are less important
64 as documents have not that many content related nodes (and setting many thousands
65 of properties is hardly a burden contrary to millions of consultations.)
67 Another change is that __index and __newindex are (as expected) exposed to
68 users but do no checking. The getfield and setfield functions do check. In
69 fact, fast mode can be simulated by fast_getfield = __index but the (measured)
70 benefit on average runs is not that large (some 5% when we also use the other
71 fast ones) which is easily nilled by inefficient coding. The direct variants
72 on the other hand can be significantly faster but with the drawback of lack
73 of userdata features. With respect to speed: keep in mind that measuring
74 a speedup on these functions is not representative for a normal run, where
75 much more happens.
77 todo : check and optimize the direct function when possible
79 todo : once the direct ones are proven we can redefine some of the less
80 critical normal ones to call the direct ones after checking for
81 a first argument being a node (like protect/unprotect)
83 The code below has quite some duplicated code but this is also a prelude
84 to light userdata for diretc nodes so we prefer this method. Some userdata
85 variants could call the direct functions but not now (also because we don't
86 want to touch the originals too much). As usual: blame Luigi and Hans for
87 issues with this code. You can blame HH for weird or inaccurate comments.
89 Todo: as a prelude to lua 5.3 we should use integer instead of number when
90 possible. A boring job. We can use the direct variants for testing this.
92 Remark: when a direct node is set, and an invalid one is passed (or nil) we
93 normally get zero and that is a predefined glue, so we get a message about
94 assigning to a glue which is fine. What we should do some day is make node
95 zero a dummy so that null then can be used as test.
97 Hans Hagen, Luigi Scarso (2011-2013)
101 #include "ptexlib.h"
102 #include "lua/luatex-api.h"
103 #ifdef LuajitTeX
104 #include "lua/lauxlib_bridge.h"
105 #else
106 #include "lauxlib.h"
107 #endif
111 These macros create and access pointers (indices) to keys which is faster. The
112 shortcuts are created as part of the initialization.
118 When the first argument to an accessor is a node, we can use it's metatable
119 entry when we are returning nodes, which saves a lookup.
123 #define fast_metatable(n) do { \
124 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
125 *a = n; \
126 lua_getmetatable(L,1); \
127 lua_setmetatable(L,-2); \
128 } while (0)
130 #define fast_metatable_or_nil(n) do { \
131 if (n) { \
132 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
133 *a = n; \
134 lua_getmetatable(L,1); \
135 lua_setmetatable(L,-2); \
136 } else { \
137 lua_pushnil(L); \
139 } while (0)
141 #define fast_metatable_or_nil_alink(n) do { \
142 if (n) { \
143 alink(n) = null; \
144 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
145 *a = n; \
146 lua_getmetatable(L,1); \
147 lua_setmetatable(L,-2); \
148 } else { \
149 lua_pushnil(L); \
151 } while (0)
153 #define fast_metatable_top(n) do { \
154 a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
155 *a = n; \
156 lua_getmetatable(L,-2); \
157 lua_setmetatable(L,-2); \
158 } while (0)
160 #define lua_push_node_metatablelua do { \
161 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node)); \
162 lua_gettable(L, LUA_REGISTRYINDEX); \
163 } while (0)
167 This is a first step towards abstract direct nodes. When we have Lua 5.3 we
168 need to check all returned values for being integers. This might be another
169 level of abtraction.
173 #define nodelib_pushdirect(n) lua_pushinteger(L,n)
174 #define nodelib_popdirect(n) lua_tointeger(L,n)
176 #define nodelib_pushdirect_or_nil(n) do { \
177 if (n==null) { \
178 lua_pushnil(L); \
179 } else { \
180 lua_pushinteger(L,n); \
182 } while (0)
184 #define nodelib_pushdirect_or_nil_alink(n) do { \
185 if (n==null) { \
186 lua_pushnil(L); \
187 } else { \
188 alink(n) = null; \
189 lua_pushinteger(L,n); \
191 } while (0)
193 #define nodelib_check_glue_spec(n,g,field) do { \
194 g = glue_ptr(n); \
195 v = (halfword) lua_tointeger(L, 3); \
196 if (!g) { \
197 g = new_node(glue_spec_node,0); \
198 add_glue_ref(g); \
199 glue_ptr(n) = g; \
200 field(g) = v; \
201 } else if (field(g) != v) { \
202 if (valid_node(g)) { \
203 int c = new_spec(g); \
204 delete_glue_ref(g); \
205 add_glue_ref(c); \
206 glue_ptr(n) = c; \
207 field(c) = v; \
208 } else { \
209 g = new_spec(g); \
210 add_glue_ref(g); \
211 glue_ptr(n) = g; \
212 field(g) = v; \
215 } while (0)
217 #define nodelib_setattr(L, s, n) reassign_attribute(n,nodelib_getlist(L,s))
219 #define nodelib_gettoks(L,a) tokenlist_from_lua(L)
221 #define nodelib_getspec nodelib_getlist
222 #define nodelib_getaction nodelib_getlist
224 /* fetching a field from a node .. we can often use the reuse bot-of-stack metatable */
226 #define nodelib_pushlist(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
227 #define nodelib_pushattr(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
228 #define nodelib_pushspec(L,n) { lua_pushinteger(L,n); lua_nodelib_push_spec(L); } /* can be: fast_metatable_or_nil(n) - different criterium? */
229 #define nodelib_pushaction(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
230 #define nodelib_pushstring(L,n) { char *ss=makecstring(n); lua_pushstring(L,ss); free(ss); }
232 /* find prev, and fix backlinks .. can be a macro instead (only used a few times) */
234 #define set_t_to_prev(head,current) \
235 t = head; \
236 while (vlink(t)!=current && t != null) { \
237 if (vlink(t)!=null) \
238 alink(vlink(t)) = t; \
239 t = vlink(t); \
242 #define box(A) eqtb[box_base+(A)].hh.rh
243 #define direct_check_index_range(j,s) \
244 if (j<0 || j > 65535) { \
245 luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s); \
248 #define NODE_METATABLE "luatex.node"
250 #define DEBUG 0
251 #define DEBUG_OUT stdout
253 /* maybe these qualify as macros, not functions */
255 static halfword *maybe_isnode(lua_State * L, int i)
257 halfword *p = lua_touserdata(L, i);
258 if (p != NULL) {
259 if (lua_getmetatable(L, i)) {
260 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
261 lua_gettable(L, LUA_REGISTRYINDEX);
262 if (!lua_rawequal(L, -1, -2))
263 p = NULL;
264 lua_pop(L, 2);
267 return p;
270 /* we could make the message a function and just inline the rest (via a macro) */
272 halfword *check_isnode(lua_State * L, int i)
274 halfword *p = maybe_isnode(L, i);
275 if (p != NULL)
276 return p;
277 formatted_error("node lib","lua <node> expected, not an object with type %s", luaL_typename(L, i));
278 return NULL;
283 This routine finds the numerical value of a string (or number) at
284 lua stack index |n|. If it is not a valid node type, returns -1
288 static int get_node_type_id_from_name(lua_State * L, int n, node_info * data)
290 int j;
291 const char *s = lua_tostring(L, n);
292 for (j = 0; data[j].id != -1; j++) {
293 if (strcmp(s, data[j].name) == 0) {
294 return j;
297 return -1;
300 static int get_valid_node_type_id(lua_State * L, int n)
302 int i = -1;
303 int t = lua_type(L, n);
304 if (t == LUA_TSTRING) {
305 i = get_node_type_id_from_name(L,n,node_data);
306 if (i<0) {
307 luaL_error(L, "invalid node type id: %s", lua_tostring(L, n));
309 } else if (t == LUA_TNUMBER) {
310 i = lua_tointeger(L,n);
311 if (! known_node_type(i)) {
312 luaL_error(L, "invalid node type id: %d", i);
314 } else {
315 luaL_error(L, "invalid node type id");
317 return i;
320 static int get_valid_node_subtype_id(lua_State * L, int n)
322 int i = -1;
323 int t = lua_type(L, n);
324 if (t == LUA_TSTRING) {
325 i = get_node_type_id_from_name(L,n,whatsit_node_data);
326 if (i<0) {
327 luaL_error(L, "invalid whatsit type id: %s", lua_tostring(L, n));
329 } else if (t == LUA_TNUMBER) {
330 i = lua_tointeger(L,n);
331 if (! known_whatsit_type(i)) {
332 luaL_error(L, "invalid whatsit type id: %d", i);
334 } else {
335 luaL_error(L, "invalid whatsit type id");
337 return i;
340 /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
342 static int lua_nodelib_next(lua_State * L)
344 halfword *p = maybe_isnode(L,1);
345 if (p != NULL && *p && vlink(*p)) {
346 lua_nodelib_push_fast(L,vlink(*p));
347 } else {
348 lua_pushnil(L);
350 return 1;
353 static int lua_nodelib_prev(lua_State * L)
355 halfword *p = maybe_isnode(L,1);
356 if (p != NULL && *p && alink(*p)) {
357 lua_nodelib_push_fast(L,alink(*p));
358 } else {
359 lua_pushnil(L);
361 return 1;
366 static void lua_nodelib_push_simple(lua_State * L, halfword p)
368 halfword *a;
369 a = (halfword *) lua_newuserdata(L, sizeof(halfword));
370 *a = p;
371 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
372 lua_gettable(L, LUA_REGISTRYINDEX);
373 lua_setmetatable(L, -2);
380 Creates a userdata object for a number found at the stack top, if it is
381 representing a node (i.e. an pointer into |varmem|). It replaces the
382 stack entry with the new userdata, or pushes |nil| if the number is |null|,
383 or if the index is definately out of range. This test could be improved.
387 void lua_nodelib_push(lua_State * L)
389 halfword n;
390 halfword *a;
391 n = -1;
392 if (lua_type(L, -1) == LUA_TNUMBER)
393 n = (int) lua_tointeger(L, -1);
394 lua_pop(L, 1);
395 if ((n == null) || (n < 0) || (n > var_mem_max)) {
396 lua_pushnil(L);
397 } else {
398 a = lua_newuserdata(L, sizeof(halfword));
399 *a = n;
400 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
401 lua_gettable(L, LUA_REGISTRYINDEX);
402 lua_setmetatable(L, -2);
404 return;
407 /* |spec_ptr| fields can legally be zero, which is why there is a special function. */
409 static void lua_nodelib_push_spec(lua_State * L)
411 halfword n;
412 halfword *a;
413 n = -1;
414 if (lua_type(L, -1) == LUA_TNUMBER)
415 n = (halfword) lua_tointeger(L, -1);
416 lua_pop(L, 1);
417 if ((n < 0) || (n > var_mem_max)) {
418 lua_pushnil(L);
419 } else {
420 a = lua_newuserdata(L, sizeof(halfword));
421 *a = n;
422 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
423 lua_gettable(L, LUA_REGISTRYINDEX);
424 lua_setmetatable(L, -2);
426 return;
429 void lua_nodelib_push_fast(lua_State * L, halfword n)
431 halfword *a;
432 if (n) {
433 a = lua_newuserdata(L, sizeof(halfword));
434 *a = n;
435 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
436 lua_gettable(L, LUA_REGISTRYINDEX);
437 lua_setmetatable(L, -2);
438 } else {
439 lua_pushnil(L);
441 return;
444 /* converts type strings to type ids */
446 static int lua_nodelib_id(lua_State * L)
448 if (lua_type(L,1) == LUA_TSTRING) {
449 int i = get_node_type_id_from_name(L, 1, node_data);
450 if (i >= 0) {
451 lua_pushinteger(L, i);
452 } else {
453 lua_pushnil(L);
455 } else {
456 lua_pushnil(L);
458 return 1;
461 /* node.getid */
463 static int lua_nodelib_getid(lua_State * L)
465 /* [given-node] [...] */
466 halfword *p = lua_touserdata(L, 1);
467 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
468 lua_pushnil(L);
469 return 1;
471 /* [given-node] [mt-given-node] */
472 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
473 lua_gettable(L, LUA_REGISTRYINDEX);
474 /* [given-node] [mt-given-node] [mt-node] */
475 if (!lua_rawequal(L, -1, -2)) {
476 lua_pushnil(L);
477 } else {
478 lua_pushinteger(L, type(*p));
480 return 1;
483 /* node.fast.getid
485 static int lua_nodelib_fast_getid(lua_State * L)
487 halfword *n;
488 n = (halfword *) lua_touserdata(L, 1);
489 lua_pushinteger(L, type(*n));
490 return 1;
495 /* node.direct.getid */
497 static int lua_nodelib_direct_getid(lua_State * L)
499 halfword n = lua_tointeger(L, 1);
500 if (n == null) {
501 lua_pushnil(L);
502 } else {
503 lua_pushinteger(L, type(n));
505 return 1;
508 /* node.getsubtype */
510 static int lua_nodelib_getsubtype(lua_State * L)
512 halfword *p = lua_touserdata(L, 1);
513 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
514 lua_pushnil(L);
515 } else {
516 lua_push_node_metatablelua;
517 if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
518 lua_pushnil(L);
519 } else {
520 lua_pushinteger(L, subtype(*p));
523 return 1;
526 /* node.fast.getsubtype
528 static int lua_nodelib_fast_getsubtype(lua_State * L)
530 halfword *n;
531 n = (halfword *) lua_touserdata(L, 1);
532 lua_pushinteger(L, subtype(*n));
533 return 1;
538 /* node.direct.getsubtype */
540 static int lua_nodelib_direct_getsubtype(lua_State * L)
542 halfword n = lua_tointeger(L, 1);
543 if (n == null) { /* no check, we assume sane use */
544 lua_pushnil(L);
545 } else {
546 lua_pushinteger(L, subtype(n));
548 return 1;
551 static int lua_nodelib_direct_setsubtype(lua_State * L)
553 halfword n = lua_tointeger(L, 1);
554 if ((n != null) && (lua_type(L,2) == LUA_TNUMBER)) {
555 subtype(n) = (halfword) lua_tointeger(L, 2);
557 return 0;
560 /* node.getfont */
562 static int lua_nodelib_getfont(lua_State * L)
564 halfword *p = lua_touserdata(L, 1);
565 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
566 lua_pushnil(L);
567 } else {
568 lua_push_node_metatablelua;
569 if ( (!lua_rawequal(L, -1, -2)) || (type(*p) != glyph_node) ) {
570 lua_pushnil(L);
571 } else {
572 lua_pushinteger(L, font(*p));
575 return 1;
578 /* node.fast.getfont
580 static int lua_nodelib_fast_getfont(lua_State * L)
582 halfword *n;
583 n = (halfword *) lua_touserdata(L, 1);
584 if (type(*n) != glyph_node) {
585 lua_pushnil(L);
586 } else {
587 lua_pushinteger(L, font(*n));
589 return 1;
594 /* node.direct.getfont */
598 static int lua_nodelib_direct_getfont(lua_State * L)
600 halfword n;
601 n = (halfword) lua_tointeger(L, 1);
602 if ((n == null) || (type(n) != glyph_node)) {
603 lua_pushnil(L);
604 } else {
605 lua_pushinteger(L, font(n));
607 return 1;
612 static int lua_nodelib_direct_getfont(lua_State * L) /* family_font is not yet in manual, what does arg 2 do */
614 halfword n = lua_tointeger(L, 1);
615 if (n != null) {
616 halfword t = type(n);
617 if (t == glyph_node) {
618 lua_pushinteger(L, font(n));
619 } else if ((t == math_char_node) || (t == math_text_char_node)) {
620 lua_pushinteger(L, fam_fnt(math_fam(n), 0));
621 } else {
622 lua_pushnil(L);
624 } else {
625 lua_pushnil(L);
627 return 1;
630 /* node.getchar */
632 static int lua_nodelib_getcharacter(lua_State * L)
634 halfword *n = lua_touserdata(L, 1);
635 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
636 lua_pushnil(L);
637 } else if (type(*n) == glyph_node) {
638 lua_pushinteger(L, character(*n));
639 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
640 lua_pushinteger(L, math_character(*n));
642 return 1;
645 /* node.fast.getchar
647 static int lua_nodelib_fast_getcharacter(lua_State * L)
649 halfword *n;
650 n = (halfword *) lua_touserdata(L, 1);
651 if (type(*n) == glyph_node) {
652 lua_pushinteger(L, character(*n));
653 } else if ((type(*n) == math_char_node) || (type(*n) == math_text_char_node)) {
654 lua_pushinteger(L, math_character(*n));
655 } else {
656 lua_pushnil(L);
658 return 1;
663 /* node.direct.getchar */
665 static int lua_nodelib_direct_getcharacter(lua_State * L)
667 halfword n = lua_tointeger(L, 1);
668 if (n == null) {
669 lua_pushnil(L);
670 } else if (type(n) == glyph_node) {
671 lua_pushinteger(L, character(n));
672 } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
673 lua_pushinteger(L, math_character(n));
674 } else {
675 lua_pushnil(L);
677 return 1;
680 /* node.getdisc */
682 static int lua_nodelib_direct_getdiscretionary(lua_State * L)
684 halfword n = lua_tointeger(L, 1);
685 if (n != null) {
686 if (type(n) == disc_node) {
687 nodelib_pushdirect_or_nil(vlink(pre_break(n)));
688 nodelib_pushdirect_or_nil(vlink(post_break(n)));
689 nodelib_pushdirect_or_nil(vlink(no_break(n)));
690 if (lua_isboolean(L, 2)) {
691 if (lua_toboolean(L, 2)) {
692 nodelib_pushdirect_or_nil(tlink(pre_break(n)));
693 nodelib_pushdirect_or_nil(tlink(post_break(n)));
694 nodelib_pushdirect_or_nil(tlink(no_break(n)));
695 return 6;
698 return 3;
701 lua_pushnil(L);
702 return 1;
705 static int lua_nodelib_getdiscretionary(lua_State * L)
707 halfword *a;
708 halfword *n = lua_touserdata(L, 1);
709 if (n != NULL) {
710 if (type(*n) == disc_node) {
711 fast_metatable_or_nil(vlink(pre_break(*n)));
712 fast_metatable_or_nil(vlink(post_break(*n)));
713 fast_metatable_or_nil(vlink(no_break(*n)));
714 if (lua_isboolean(L, 2)) {
715 if (lua_toboolean(L, 2)) {
716 fast_metatable_or_nil(tlink(pre_break(*n)));
717 fast_metatable_or_nil(tlink(post_break(*n)));
718 fast_metatable_or_nil(tlink(no_break(*n)));
719 return 6;
722 return 3;
725 lua_pushnil(L);
726 return 1;
730 /* node.getlist */
732 static int lua_nodelib_getlist(lua_State * L)
734 halfword *a;
735 halfword *n = lua_touserdata(L, 1);
736 if ((n == NULL) || (! lua_getmetatable(L,1))) {
737 lua_pushnil(L);
738 } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
739 fast_metatable_or_nil_alink(list_ptr(*n));
740 } else {
741 lua_pushnil(L);
743 return 1;
748 static int lua_nodelib_setlist(lua_State * L)
750 halfword *n = lua_touserdata(L, 1);
751 if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
752 if (lua_type(L,2) == LUA_TNIL) {
753 list_ptr(n) = null;
754 } else {
755 halfword *l = lua_touserdata(L, 2);
756 list_ptr(n) = l;
759 return 0;
764 /* node.direct.getlist */
766 static int lua_nodelib_direct_getlist(lua_State * L)
768 halfword n = lua_tointeger(L, 1);
769 if (n == null) {
770 lua_pushnil(L);
771 } else if ((type(n) == hlist_node) || (type(n) == vlist_node)) {
772 nodelib_pushdirect_or_nil_alink(list_ptr(n));
773 } else {
774 lua_pushnil(L);
776 return 1;
779 static int lua_nodelib_direct_setlist(lua_State * L)
781 halfword n = lua_tointeger(L, 1);
782 if ((n != null) && ((type(n) == hlist_node) || (type(n) == vlist_node))) {
783 if (lua_type(L,2) == LUA_TNUMBER) {
784 list_ptr(n) = (halfword) lua_tointeger(L, 2);
785 } else {
786 list_ptr(n) = null;
789 return 0;
792 /* node.getleader */
794 static int lua_nodelib_getleader(lua_State * L)
796 halfword *a;
797 halfword *n = lua_touserdata(L, 1);
798 if ( (n == NULL) || (! lua_getmetatable(L,1)) ) {
799 lua_pushnil(L);
800 } else if (type(*n) == glue_node) {
801 fast_metatable_or_nil(leader_ptr(*n));
802 } else {
803 lua_pushnil(L);
805 return 1;
808 /* node.direct.getleader */
810 static int lua_nodelib_direct_getleader(lua_State * L)
812 halfword n = lua_tointeger(L, 1);
813 if (n == null) {
814 lua_pushnil(L);
815 } else if (type(n) == glue_node) {
816 nodelib_pushdirect_or_nil(leader_ptr(n));
817 } else {
818 lua_pushnil(L);
820 return 1;
823 static int lua_nodelib_direct_setleader(lua_State * L)
825 halfword n = lua_tointeger(L, 1);
826 if ((n != null) && (type(n) == glue_node)) {
827 if (lua_type(L,2) == LUA_TNUMBER) {
828 leader_ptr(n) = (halfword) lua_tointeger(L, 2);
829 } else {
830 leader_ptr(n) = null;
833 return 0;
836 /* node.getnext */
838 static int lua_nodelib_getnext(lua_State * L)
840 halfword *a;
841 /* [given-node] [...]*/
842 halfword *p = lua_touserdata(L, 1);
843 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
844 lua_pushnil(L);
845 } else {
846 /* [given-node] [mt-given-node]*/
847 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
848 lua_gettable(L, LUA_REGISTRYINDEX);
849 /* [given-node] [mt-given-node] [mt-node]*/
850 if (!lua_rawequal(L, -1, -2)) {
851 lua_pushnil(L);
852 } else {
853 fast_metatable_or_nil(vlink(*p));
856 return 1; /* just one*/
859 /* node.fast.getnext
861 static int lua_nodelib_fast_getnext(lua_State * L)
863 halfword *a;
864 halfword *p = lua_touserdata(L, 1);
865 if ((p == NULL) || (!vlink(*p))){
866 lua_pushnil(L);
867 } else {
868 lua_settop(L,1);
869 lua_getmetatable(L,1);
870 a = lua_newuserdata(L, sizeof(halfword));
871 *a = vlink(*p);
872 lua_replace(L,1);
873 lua_setmetatable(L,1);
875 return 1;
880 /* node.direct.getnext */
882 static int lua_nodelib_direct_getnext(lua_State * L)
884 halfword p = lua_tointeger(L, 1);
885 if (p == null) {
886 lua_pushnil(L);
887 } else {
888 nodelib_pushdirect_or_nil(vlink(p));
890 return 1;
893 /* node.getprev */
895 static int lua_nodelib_getprev(lua_State * L)
897 halfword *a;
898 halfword *p = lua_touserdata(L, 1);
899 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
900 lua_pushnil(L);
901 } else {
902 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
903 lua_gettable(L, LUA_REGISTRYINDEX);
904 if (!lua_rawequal(L, -1, -2)) {
905 lua_pushnil(L);
906 } else {
907 fast_metatable_or_nil(alink(*p));
910 return 1;
913 static int lua_nodelib_getboth(lua_State * L)
915 halfword *a;
916 halfword *p = lua_touserdata(L, 1);
917 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
918 lua_pushnil(L);
919 lua_pushnil(L);
920 } else {
921 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
922 lua_gettable(L, LUA_REGISTRYINDEX);
923 if (!lua_rawequal(L, -1, -2)) {
924 lua_pushnil(L);
925 lua_pushnil(L);
926 } else {
927 fast_metatable_or_nil(alink(*p));
928 fast_metatable_or_nil(vlink(*p));
931 return 2;
934 /* node.fast.getprev
936 static int lua_nodelib_fast_getprev(lua_State * L)
938 halfword *a;
939 halfword *p = lua_touserdata(L, 1);
940 if ((p == NULL) || (!alink(*p))) {
941 lua_pushnil(L);
942 } else {
943 lua_settop(L,1);
944 lua_getmetatable(L,1);
945 a = lua_newuserdata(L, sizeof(halfword));
946 *a = alink(*p);
947 lua_replace(L,1);
948 lua_setmetatable(L,1);
950 return 1;
955 /* node.direct.getprev */
957 static int lua_nodelib_direct_getprev(lua_State * L)
959 halfword p = lua_tointeger(L, 1);
960 if (p == null) {
961 lua_pushnil(L);
962 } else {
963 nodelib_pushdirect_or_nil(alink(p));
965 return 1;
968 /* node.direct.getboth */
970 static int lua_nodelib_direct_getboth(lua_State * L)
972 halfword p = lua_tointeger(L, 1);
973 if (p == null) {
974 lua_pushnil(L);
975 lua_pushnil(L);
976 } else {
977 nodelib_pushdirect_or_nil(alink(p));
978 nodelib_pushdirect_or_nil(vlink(p));
980 return 2;
983 /* node.subtype (maybe also return them for other node types now) */
985 static int lua_nodelib_subtype(lua_State * L)
987 if (lua_type(L,1) == LUA_TSTRING) {
988 int i = get_node_type_id_from_name(L,1,whatsit_node_data);
989 if (i >= 0) {
990 lua_pushinteger(L, i);
991 } else {
992 lua_pushnil(L);
994 } else {
995 lua_pushnil(L);
997 return 1;
1000 /* node.type (converts id numbers to type names) */
1002 static int lua_nodelib_type(lua_State * L)
1004 if (lua_type(L,1) == LUA_TNUMBER) {
1005 int i = lua_tointeger(L, 1);
1006 if (known_node_type(i)) {
1007 lua_pushstring(L, node_data[i].name);
1008 return 1;
1010 } else if (maybe_isnode(L, 1) != NULL) {
1011 lua_pushstring(L,"node");
1012 return 1;
1014 lua_pushnil(L);
1015 return 1;
1018 /* node.new (allocate a new node) */
1020 static int lua_nodelib_new(lua_State * L)
1022 int i, j;
1023 halfword n = null;
1024 int t = lua_type(L, 1);
1025 if (t == LUA_TNUMBER) {
1026 i = lua_tointeger(L,1);
1027 if (! known_node_type(i)) {
1028 i = -1;
1030 } else if (t == LUA_TSTRING) {
1031 i = get_node_type_id_from_name(L,1,node_data);
1032 } else {
1033 i = -1;
1035 if (i < 0) {
1036 luaL_error(L, "invalid node id for creating new node");
1038 t = lua_type(L, 2);
1039 if (i == whatsit_node) {
1040 if (t == LUA_TNUMBER) {
1041 j = lua_tointeger(L,2);
1042 if (! known_whatsit_type(j)) {
1043 j = -1;
1045 } else if (t == LUA_TSTRING) {
1046 j = get_node_type_id_from_name(L,2,whatsit_node_data);
1047 } else {
1048 j = -1;
1050 if (j < 0) {
1051 luaL_error(L, "creating a whatsit requires the subtype number as a second argument");
1053 } else if (t == LUA_TNUMBER) {
1054 j = (int) lua_tointeger(L, 2);
1055 } else {
1056 j = 0;
1058 n = new_node(i, j);
1059 lua_nodelib_push_fast(L, n);
1060 return 1;
1063 /* node.direct.new (still with checking) */
1065 static int lua_nodelib_direct_new(lua_State * L)
1067 int j;
1068 halfword n ;
1069 int i = get_valid_node_type_id(L, 1);
1070 if (i == whatsit_node) {
1071 j = -1;
1072 if (lua_gettop(L) > 1)
1073 j = get_valid_node_subtype_id(L, 2);
1074 if (j < 0)
1075 luaL_error(L, "Creating a whatsit requires the subtype number as a second argument");
1076 } else {
1077 j = 0;
1078 if (lua_gettop(L) > 1)
1079 j = (int) lua_tointeger(L, 2);
1081 n = new_node(i, j);
1082 lua_pushinteger(L,n);
1083 return 1;
1086 /* node.free (this function returns the 'next' node, because that may be helpful) */
1088 static int lua_nodelib_free(lua_State * L)
1090 halfword n;
1091 halfword p;
1092 if (lua_gettop(L) < 1) {
1093 lua_pushnil(L);
1094 return 1;
1095 } else if (lua_isnil(L, 1)) {
1096 return 1; /* the nil itself */
1098 n = *(check_isnode(L, 1));
1099 p = vlink(n);
1100 flush_node(n);
1101 /* can be: lua_nodelib_push_fast(L, p); */
1102 lua_pushinteger(L, p);
1103 lua_nodelib_push(L);
1104 return 1;
1107 /* node.direct.free */
1109 static int lua_nodelib_direct_free(lua_State * L)
1111 halfword n = lua_tointeger(L,1);
1112 if (n == null) {
1113 lua_pushnil(L);
1114 } else {
1115 halfword p = vlink(n);
1116 flush_node(n);
1117 if (p == 0) {
1118 lua_pushnil(L);
1119 } else {
1120 lua_pushinteger(L,p);
1123 return 1;
1126 /* node.flush_node (no next returned) */
1128 static int lua_nodelib_flush_node(lua_State * L)
1130 if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
1131 return 0;
1132 } else {
1133 halfword n = *(check_isnode(L, 1));
1134 flush_node(n);
1135 return 0;
1139 /* node.direct.flush_node */
1141 static int lua_nodelib_direct_flush_node(lua_State * L)
1143 halfword n = lua_tointeger(L,1);
1144 if (n == null)
1145 return 0;
1146 flush_node(n);
1147 return 0;
1150 /* node.flush_list */
1152 static int lua_nodelib_flush_list(lua_State * L)
1154 if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
1155 return 0;
1156 } else {
1157 halfword n_ptr = *check_isnode(L, 1);
1158 flush_node_list(n_ptr);
1159 return 0;
1163 /* node.direct.flush_list */
1165 static int lua_nodelib_direct_flush_list(lua_State * L)
1167 halfword n = lua_tointeger(L,1);
1168 if (n == null)
1169 return 0;
1170 flush_node_list(n);
1171 return 0;
1174 /* remove a node from a list */
1176 #if DEBUG
1178 static void show_node_links (halfword l, const char * p)
1180 halfword t = l;
1181 while (t) {
1182 fprintf(DEBUG_OUT, "%s t = %d, prev = %d, next = %d\n", p, (int)t, (int)alink(t), (int)vlink(t));
1183 t = vlink(t);
1187 #endif
1189 /* node.remove */
1191 static int lua_nodelib_remove(lua_State * L)
1193 halfword head, current, t;
1194 if (lua_gettop(L) < 2)
1195 luaL_error(L, "Not enough arguments for node.remove()");
1196 head = *(check_isnode(L, 1));
1197 if (lua_isnil(L, 2))
1198 return 2; /* the arguments, as they are */
1199 current = *(check_isnode(L, 2));
1200 if (head == current) {
1201 if (alink(current)){
1202 vlink(alink(current)) = vlink(current);
1204 if (vlink(current)){
1205 alink( vlink(current)) = alink(current);
1208 head = vlink(current);
1209 current = vlink(current);
1210 } else {
1211 t = alink(current);
1212 if (t == null || vlink(t) != current) {
1213 set_t_to_prev(head, current);
1214 if (t == null) /* error! */
1215 luaL_error(L,"Attempt to node.remove() a non-existing node");
1217 /* t is now the previous node */
1218 vlink(t) = vlink(current);
1219 if (vlink(current) != null)
1220 alink(vlink(current)) = t;
1221 current = vlink(current);
1223 #if DEBUG
1224 show_node_links(head, "after");
1225 #endif
1226 /* can be: lua_nodelib_push_fast(L, head); */
1227 lua_pushinteger(L, head);
1228 lua_nodelib_push(L);
1229 /* can be: lua_nodelib_push_fast(L, current); */
1230 lua_pushinteger(L, current);
1231 lua_nodelib_push(L);
1232 return 2;
1235 /* node.direct.remove */
1237 static int lua_nodelib_direct_remove(lua_State * L)
1239 halfword current, t;
1240 halfword head = lua_tointeger(L,1);
1241 if (head == null) {
1242 lua_pushnil(L);
1243 lua_pushnil(L);
1244 return 2 ;
1246 current = (halfword) lua_tointeger(L,2);
1247 if (current == null) {
1248 lua_pushinteger(L, head);
1249 lua_pushnil(L);
1250 return 2 ;
1252 if (head == current) {
1253 if (alink(current)){
1254 vlink( alink(current) ) = vlink(current);
1256 if (vlink(current)){
1257 alink( vlink(current) ) = alink(current);
1259 head = vlink(current);
1260 current = vlink(current);
1261 } else {
1262 t = alink(current);
1263 if (t == null || vlink(t) != current) {
1264 set_t_to_prev(head, current);
1265 if (t == null) {
1266 luaL_error(L,"Attempt to node.direct.remove() a non-existing node");
1269 vlink(t) = vlink(current);
1270 if (vlink(current) != null)
1271 alink(vlink(current)) = t;
1272 current = vlink(current);
1274 if (head == null) {
1275 lua_pushnil(L);
1276 } else {
1277 lua_pushinteger(L, head);
1279 if (current == null) {
1280 lua_pushnil(L);
1281 } else {
1282 lua_pushinteger(L, current);
1284 return 2;
1287 /* node.insert_before (insert a node in a list) */
1289 static int lua_nodelib_insert_before(lua_State * L)
1291 halfword head, current, n, t;
1292 if (lua_gettop(L) < 3) {
1293 luaL_error(L, "Not enough arguments for node.insert_before()");
1295 if (lua_isnil(L, 3)) {
1296 lua_pop(L, 1);
1297 return 2;
1298 } else {
1299 n = *(check_isnode(L, 3));
1301 if (lua_isnil(L, 1)) { /* no head */
1302 vlink(n) = null;
1303 alink(n) = null;
1304 lua_nodelib_push_fast(L, n);
1305 lua_pushvalue(L, -1);
1306 return 2;
1307 } else {
1308 head = *(check_isnode(L, 1));
1310 if (lua_isnil(L, 2)) {
1311 current = tail_of_list(head);
1312 } else {
1313 current = *(check_isnode(L, 2));
1315 if (head != current) {
1316 t = alink(current);
1317 if (t == null || vlink(t) != current) {
1318 set_t_to_prev(head, current);
1319 if (t == null) { /* error! */
1320 luaL_error(L, "Attempt to node.insert_before() a non-existing node");
1323 couple_nodes(t, n);
1325 couple_nodes(n, current);
1326 if (head == current) {
1327 lua_nodelib_push_fast(L, n);
1328 } else {
1329 lua_nodelib_push_fast(L, head);
1331 lua_nodelib_push_fast(L, n);
1332 return 2;
1335 /* node.direct.insert_before */
1337 static int lua_nodelib_direct_insert_before(lua_State * L)
1339 halfword head, current;
1340 halfword n = lua_tointeger(L,3);
1341 if (n == null){
1342 /* no node */
1343 lua_pop(L, 1);
1344 return 2 ;
1346 head = (halfword) lua_tointeger(L,1);
1347 current = (halfword) lua_tointeger(L,2);
1348 /* no head, ignore current */
1349 if (head == null) {
1350 vlink(n) = null;
1351 alink(n) = null;
1352 lua_pushinteger(L, n);
1353 lua_pushvalue(L, -1);
1354 /* n, n */
1355 return 2;
1357 /* no current */
1358 if (current == null)
1359 current = tail_of_list(head);
1360 if (head != current) {
1361 halfword t = alink(current);
1362 if (t == null || vlink(t) != current)
1363 set_t_to_prev(head, current);
1364 couple_nodes(t, n);
1366 couple_nodes(n, current);
1367 if (head == current) {
1368 lua_pushinteger(L, n);
1369 } else {
1370 lua_pushinteger(L, head);
1372 lua_pushinteger(L, n);
1373 return 2;
1376 /* node.insert_after */
1378 static int lua_nodelib_insert_after(lua_State * L)
1380 halfword head, current, n;
1381 if (lua_gettop(L) < 3) {
1382 luaL_error(L, "Not enough arguments for node.insert_after()");
1384 if (lua_isnil(L, 3)) {
1385 lua_pop(L, 1);
1386 return 2;
1387 } else {
1388 n = *(check_isnode(L, 3));
1390 if (lua_isnil(L, 1)) { /* no head */
1391 vlink(n) = null;
1392 alink(n) = null;
1393 lua_nodelib_push_fast(L, n);
1394 lua_pushvalue(L, -1);
1395 return 2;
1396 } else {
1397 head = *(check_isnode(L, 1));
1399 if (lua_isnil(L, 2)) {
1400 current = head;
1401 while (vlink(current) != null)
1402 current = vlink(current);
1403 } else {
1404 current = *(check_isnode(L, 2));
1406 try_couple_nodes(n, vlink(current));
1407 couple_nodes(current, n);
1409 lua_pop(L, 2);
1410 lua_nodelib_push_fast(L, n);
1411 return 2;
1414 /* node.direct.insert_after */
1416 static int lua_nodelib_direct_insert_after(lua_State * L)
1418 halfword head, current;
1419 /*[head][current][new]*/
1420 halfword n = lua_tointeger(L,3);
1421 if (n == null) {
1422 /* no node */
1423 return 2 ;
1425 head = (halfword) lua_tointeger(L,1);
1426 current = (halfword) lua_tointeger(L,2);
1427 if (head == null) {
1428 /* no head, ignore current */
1429 vlink(n) = null;
1430 alink(n) = null;
1431 lua_pushinteger(L,n);
1432 lua_pushvalue(L, -1);
1433 /* n, n */
1434 return 2;
1436 if (current == null) {
1437 /* no current */
1438 current = head;
1439 while (vlink(current) != null)
1440 current = vlink(current);
1442 try_couple_nodes(n, vlink(current));
1443 couple_nodes(current, n);
1444 lua_pop(L, 2);
1445 lua_pushinteger(L, n);
1446 return 2;
1449 /* node.copy_list */
1452 we need to use an intermediate variable as otherwise target is used in the loop
1453 and subfields get overwritten (or something like that) which results in crashes
1454 and unexpected side effects
1457 static int lua_nodelib_copy_list(lua_State * L)
1459 halfword n, s = null;
1460 halfword m;
1461 if (lua_isnil(L, 1))
1462 return 1; /* the nil itself */
1463 n = *check_isnode(L, 1);
1464 if ((lua_gettop(L) > 1) && (!lua_isnil(L,2)))
1465 s = *check_isnode(L, 2);
1466 m = do_copy_node_list(n, s);
1467 lua_nodelib_push_fast(L,m);
1468 return 1;
1472 /* node.direct.copy_list */
1474 static int lua_nodelib_direct_copy_list(lua_State * L)
1476 halfword n = lua_tointeger(L,1);
1477 if (n == null) {
1478 lua_pushnil(L);
1479 } else {
1480 halfword s = lua_tointeger(L,2);
1481 halfword m;
1482 if (s == null) {
1483 m = do_copy_node_list(n,null);
1484 } else {
1485 m = do_copy_node_list(n,s);
1487 lua_pushinteger(L,m);
1489 return 1;
1492 /* node.copy (deep copy) */
1494 static int lua_nodelib_copy(lua_State * L)
1496 halfword n;
1497 if (lua_isnil(L, 1))
1498 return 1; /* the nil itself */
1499 n = *check_isnode(L, 1);
1500 n = copy_node(n);
1501 lua_nodelib_push_fast(L, n);
1502 return 1;
1505 /* node.direct.copy (deep copy) */
1507 static int lua_nodelib_direct_copy(lua_State * L)
1509 if (lua_isnil(L, 1)) {
1510 return 1; /* the nil itself */
1511 } else {
1512 /* beware, a glue node can have number 0 (zeropt) so we cannot test for null) */
1513 halfword n = lua_tointeger(L, 1);
1514 n = copy_node(n);
1515 lua_pushinteger(L, n);
1516 return 1;
1521 /* node.write (output a node to tex's processor) */
1523 static int lua_nodelib_append(lua_State * L)
1525 halfword n;
1526 int i;
1527 int j = lua_gettop(L);
1528 for (i = 1; i <= j; i++) {
1529 n = *check_isnode(L, i);
1530 tail_append(n);
1531 while (vlink(n) != null) {
1532 n = vlink(n);
1533 tail_append(n);
1536 return 0;
1539 /* node.direct.write */
1541 static int lua_nodelib_direct_append(lua_State * L)
1543 halfword m;
1544 int i;
1545 int j = lua_gettop(L);
1546 for (i = 1; i <= j; i++) {
1547 halfword n = lua_tointeger(L,i); /*lua_getnumber(L, i);*/
1548 if (n != null) {
1549 m = n ;
1550 tail_append(m);
1551 while (vlink(m) != null) {
1552 m = vlink(m);
1553 tail_append(m);
1557 return 0;
1560 /* node.last */
1562 static int lua_nodelib_last_node(lua_State * L)
1564 halfword m = pop_tail();
1565 /* can be: lua_nodelib_push_fast(L, m); */
1566 lua_pushinteger(L, m);
1567 lua_nodelib_push(L);
1568 return 1;
1571 /* node.direct.last */
1573 static int lua_nodelib_direct_last_node(lua_State * L)
1575 halfword m = pop_tail();
1576 lua_pushinteger(L, m);
1577 return 1;
1580 /* node.hpack (build a hbox) */
1582 static int lua_nodelib_hpack(lua_State * L)
1584 halfword p;
1585 const char *s;
1586 int w = 0;
1587 int m = 1;
1588 int d = -1;
1589 halfword n = *(check_isnode(L, 1));
1590 if (lua_gettop(L) > 1) {
1591 w = (int) lua_tointeger(L, 2);
1592 if (lua_gettop(L) > 2) {
1593 if (lua_type(L, 3) == LUA_TSTRING) {
1594 s = lua_tostring(L, 3);
1595 if (lua_key_eq(s, exactly)) {
1596 m = 0;
1597 } else if (lua_key_eq(s, additional)) {
1598 m = 1;
1599 } else if (lua_key_eq(s, cal_expand_ratio)) {
1600 m = 2;
1601 } else if (lua_key_eq(s, subst_ex_font)) {
1602 m = 3;
1604 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1605 m = (int) lua_tointeger(L, 3);
1607 if ((m<0) || (m>3)) {
1608 luaL_error(L, "wrong mode in hpack");
1610 if (lua_gettop(L) > 3) {
1611 if (lua_type(L, 4) == LUA_TSTRING) {
1612 d = nodelib_getdir(L, 4, 1);
1613 } else {
1614 lua_pushstring(L, "incorrect 4th argument");
1619 p = hpack(n, w, m, d);
1620 lua_nodelib_push_fast(L, p);
1621 lua_pushinteger(L, last_badness);
1622 return 2;
1625 /* node.direct.hpack */
1627 static int lua_nodelib_direct_hpack(lua_State * L)
1629 halfword p;
1630 const char *s;
1631 int w = 0;
1632 int m = 1;
1633 int d = -1;
1634 halfword n = lua_tointeger(L,1);
1635 /* could be macro */
1636 if (lua_gettop(L) > 1) {
1637 w = (int) lua_tointeger(L, 2);
1638 if (lua_gettop(L) > 2) {
1639 if (lua_type(L, 3) == LUA_TSTRING) {
1640 s = lua_tostring(L, 3);
1641 if (lua_key_eq(s, additional)) {
1642 m = 1;
1643 } else if (lua_key_eq(s, exactly)) {
1644 m = 0;
1645 } else if (lua_key_eq(s, cal_expand_ratio)) {
1646 m = 2;
1647 } else if (lua_key_eq(s, subst_ex_font)) {
1648 m = 3;
1649 } else {
1650 luaL_error(L, "3rd argument should be either additional or exactly");
1652 } else if (lua_type(L, 3) == LUA_TNUMBER) {
1653 m = (int) lua_tointeger(L, 3);
1654 } else {
1655 lua_pushstring(L, "incorrect 3rd argument");
1657 if (lua_gettop(L) > 3) {
1658 if (lua_type(L, 4) == LUA_TSTRING) {
1659 d = nodelib_getdir(L, 4, 1);
1660 } else {
1661 lua_pushstring(L, "incorrect 4th argument");
1666 /* till here */
1667 p = hpack(n, w, m, d);
1668 lua_pushinteger(L, p);
1669 lua_pushinteger(L, last_badness);
1670 return 2;
1673 /* node.vpack (build a vbox) */
1675 static int lua_nodelib_vpack(lua_State * L)
1677 halfword p;
1678 const char *s;
1679 int w = 0;
1680 int m = 1;
1681 int d = -1;
1682 halfword n = *(check_isnode(L, 1));
1683 if (lua_gettop(L) > 1) {
1684 w = (int) lua_tointeger(L, 2);
1685 if (lua_gettop(L) > 2) {
1686 if (lua_type(L, 3) == LUA_TSTRING) {
1687 s = lua_tostring(L, 3);
1688 if (lua_key_eq(s, additional)) {
1689 m = 1;
1690 } else if (lua_key_eq(s, exactly)) {
1691 m = 0;
1692 } else {
1693 luaL_error(L, "3rd argument should be either additional or exactly");
1696 if (lua_gettop(L) > 3) {
1697 if (lua_type(L, 4) == LUA_TSTRING) {
1698 d = nodelib_getdir(L, 4, 1);
1699 } else {
1700 lua_pushstring(L, "incorrect 4th argument");
1705 else if (lua_type(L, 3) == LUA_TNUMBER) {
1706 m= (int) lua_tointeger(L, 3);
1707 } else {
1708 lua_pushstring(L, "incorrect 3rd argument");
1712 p = vpackage(n, w, m, max_dimen, d);
1713 lua_nodelib_push_fast(L, p);
1714 lua_pushinteger(L, last_badness);
1715 return 2;
1718 /* node.direct.vpack */
1720 static int lua_nodelib_direct_vpack(lua_State * L)
1722 halfword p;
1723 const char *s;
1724 int w = 0;
1725 int m = 1;
1726 int d = -1;
1727 halfword n = (halfword) lua_tointeger(L,1);
1728 if (lua_gettop(L) > 1) {
1729 w = (int) lua_tointeger(L, 2);
1730 if (lua_gettop(L) > 2) {
1731 if (lua_type(L, 3) == LUA_TSTRING) {
1732 s = lua_tostring(L, 3);
1733 if (lua_key_eq(s, additional)) {
1734 m = 1;
1735 } else if (lua_key_eq(s, exactly)) {
1736 m = 0;
1737 } else {
1738 luaL_error(L, "3rd argument should be either additional or exactly");
1741 if (lua_gettop(L) > 3) {
1742 if (lua_type(L, 4) == LUA_TSTRING) {
1743 d = nodelib_getdir(L, 4, 1);
1744 } else {
1745 lua_pushstring(L, "incorrect 4th argument");
1750 else if (lua_type(L, 3) == LUA_TNUMBER) {
1751 m= (int) lua_tointeger(L, 3);
1752 } else {
1753 lua_pushstring(L, "incorrect 3rd argument");
1757 p = vpackage(n, w, m, max_dimen, d);
1758 lua_pushinteger(L, p);
1759 lua_pushinteger(L, last_badness);
1760 return 2;
1763 /* node.dimensions (of a hlist or vlist) */
1765 static int lua_nodelib_dimensions(lua_State * L)
1767 int top = lua_gettop(L);
1768 if (top > 0) {
1769 scaled_whd siz;
1770 glue_ratio g_mult = 1.0;
1771 int g_sign = normal;
1772 int g_order = normal;
1773 int i = 1;
1774 int d = -1;
1775 halfword n = null, p = null;
1776 if (lua_type(L, 1) == LUA_TNUMBER) {
1777 if (top < 4) {
1778 lua_pushnil(L);
1779 return 1;
1781 i += 3;
1782 g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
1783 g_sign = (int) lua_tointeger(L, 2);
1784 g_order = (int) lua_tointeger(L, 3);
1786 n = *(check_isnode(L, i));
1787 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1788 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1789 d = nodelib_getdir(L, (i + 1), 1);
1790 } else {
1791 p = *(check_isnode(L, (i + 1)));
1794 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING) {
1795 d = nodelib_getdir(L, (i + 2), 1);
1797 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1798 lua_pushinteger(L, siz.wd);
1799 lua_pushinteger(L, siz.ht);
1800 lua_pushinteger(L, siz.dp);
1801 return 3;
1802 } else {
1803 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1805 return 0; /* not reached */
1808 /* node.direct.dimensions*/
1810 static int lua_nodelib_direct_dimensions(lua_State * L)
1812 int top = lua_gettop(L);
1813 if (top > 0) {
1814 scaled_whd siz;
1815 glue_ratio g_mult = 1.0;
1816 int g_sign = normal;
1817 int g_order = normal;
1818 int i = 1;
1819 int d = -1;
1820 halfword n = null, p = null;
1821 if (top > 3) {
1822 i += 3;
1823 g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
1824 g_sign = (int) lua_tointeger(L, 2);
1825 g_order = (int) lua_tointeger(L, 3);
1827 n = (halfword) lua_tointeger(L,i);
1828 if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
1829 if (lua_type(L, (i + 1)) == LUA_TSTRING) {
1830 d = nodelib_getdir(L, (i + 1), 1);
1831 } else {
1832 p = (halfword) lua_tointeger(L,i+1);
1835 if (lua_gettop(L) > (i + 1) && lua_type(L, (i + 2)) == LUA_TSTRING)
1836 d = nodelib_getdir(L, (i + 2), 1);
1837 siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
1838 lua_pushinteger(L, siz.wd);
1839 lua_pushinteger(L, siz.ht);
1840 lua_pushinteger(L, siz.dp);
1841 return 3;
1842 } else {
1843 luaL_error(L, "missing argument to 'dimensions' (node expected)");
1845 return 0; /* not reached */
1848 /* node.mlist_to_hlist (create a hlist from a formula) */
1850 static int lua_nodelib_mlist_to_hlist(lua_State * L)
1852 int w;
1853 boolean m;
1854 halfword n = *(check_isnode(L, 1));
1855 assign_math_style(L,2,w);
1856 luaL_checkany(L, 3);
1857 m = lua_toboolean(L, 3);
1858 mlist_to_hlist(n, m, w);
1859 alink(vlink(temp_head)) = null; /*hh-ls */
1860 lua_nodelib_push_fast(L, vlink(temp_head));
1861 return 1;
1864 /* node.family_font */
1866 static int lua_nodelib_mfont(lua_State * L)
1868 int s;
1869 int f = luaL_checkinteger(L, 1);
1870 if (lua_gettop(L) == 2)
1871 s = lua_tointeger(L, 2); /* this should be a multiple of 256 ! */
1872 else
1873 s = 0;
1874 lua_pushinteger(L, fam_fnt(f,s));
1875 return 1;
1879 This function is similar to |get_node_type_id|, for field
1880 identifiers. It has to do some more work, because not all
1881 identifiers are valid for all types of nodes.
1883 If really needed we can optimize this one using a big if ..
1884 .. else like with the getter and setter.
1888 static int get_node_field_id(lua_State * L, int n, int node)
1890 int t = type(node);
1891 const char *s = lua_tostring(L, n);
1893 if (s == NULL)
1894 return -2;
1896 if (lua_key_eq(s, next)) {
1897 return 0;
1898 } else if (lua_key_eq(s, id)) {
1899 return 1;
1900 } else if (lua_key_eq(s, subtype)) {
1901 if (nodetype_has_subtype(t)) {
1902 return 2;
1904 } else if (lua_key_eq(s, attr)) {
1905 if (nodetype_has_attributes(t)) {
1906 return 3;
1908 } else if (lua_key_eq(s, prev)) {
1909 if (nodetype_has_prev(t)) {
1910 return -1;
1912 } else {
1913 int j;
1914 const char **fields = node_data[t].fields;
1915 if (t == whatsit_node) {
1916 fields = whatsit_node_data[subtype(node)].fields;
1918 if (lua_key_eq(s, list)) {
1919 /* head and list are equivalent; we don't catch extra virtual fields */
1920 s = luaS_head_ptr;
1922 if (fields != NULL) {
1923 for (j = 0; fields[j] != NULL; j++) {
1924 if (strcmp(s, fields[j]) == 0) {
1925 return j + 3;
1930 return -2;
1933 /* node.has_field */
1935 static int lua_nodelib_has_field(lua_State * L)
1937 int i = -2;
1938 if (!lua_isnil(L, 1))
1939 i = get_node_field_id(L, 2, *(check_isnode(L, 1)));
1940 lua_pushboolean(L, (i != -2));
1941 return 1;
1944 /* node.is_char (node[,font]) */
1946 static int lua_nodelib_is_char(lua_State * L)
1948 halfword f;
1949 halfword n = *(check_isnode(L, 1));
1950 if ((type(n) == glyph_node) && (subtype(n) < 256)) { /* <= 256 */
1951 if (lua_type(L,2) == LUA_TNUMBER) {
1952 f = (halfword) lua_tointeger(L, 2);
1953 if (f && f == font(n)) {
1954 lua_pushinteger(L,character(n));
1955 return 1;
1957 } else {
1958 lua_pushinteger(L,character(n));
1959 return 1;
1962 lua_pushboolean(L,0);
1963 return 1;
1966 /* node.direct.has_field */
1968 static int lua_nodelib_direct_has_field(lua_State * L)
1970 int i = -2;
1971 halfword n = lua_tointeger(L, 1);
1972 if (n != null)
1973 i = get_node_field_id(L, 2, n);
1974 lua_pushboolean(L, (i != -2));
1975 return 1;
1978 /* fetch the list of valid node types */
1980 static int do_lua_nodelib_types(lua_State * L, node_info * data)
1982 int i;
1983 lua_newtable(L);
1984 for (i = 0; data[i].id != -1; i++) {
1985 lua_pushstring(L, data[i].name);
1986 lua_rawseti(L, -2, data[i].id);
1988 return 1;
1991 /* node.types */
1993 static int lua_nodelib_types(lua_State * L)
1995 return do_lua_nodelib_types(L, node_data);
1998 /* node.whatsits */
2000 static int lua_nodelib_whatsits(lua_State * L)
2002 return do_lua_nodelib_types(L, whatsit_node_data);
2005 /* node.fields (fetch the list of valid fields) */
2007 static int lua_nodelib_fields(lua_State * L)
2009 int i = -1;
2010 int offset = 2;
2011 const char **fields;
2012 int t = get_valid_node_type_id(L, 1);
2013 if (t == whatsit_node) {
2014 t = get_valid_node_subtype_id(L, 2);
2015 fields = whatsit_node_data[t].fields;
2016 } else {
2017 fields = node_data[t].fields;
2019 lua_checkstack(L, 2);
2020 lua_newtable(L);
2021 lua_push_string_by_name(L,next);
2022 lua_rawseti(L, -2, 0);
2023 lua_push_string_by_name(L,id);
2024 lua_rawseti(L, -2, 1);
2025 if (nodetype_has_subtype(t)) {
2026 lua_push_string_by_name(L,subtype);
2027 lua_rawseti(L, -2, 2);
2028 offset++;
2030 if (nodetype_has_prev(t)) {
2031 lua_push_string_by_name(L,prev);
2032 lua_rawseti(L, -2, -1);
2034 if (fields != NULL) {
2035 for (i = 0; fields[i] != NULL; i++) {
2036 lua_pushstring(L, fields[i]); /* todo */
2037 lua_rawseti(L, -2, (i + offset));
2040 return 1;
2043 static int lua_nodelib_subtypes(lua_State * L)
2045 int i = -1;
2046 int l = 0;
2047 const char **subtypes = NULL;
2048 const char *s ;
2049 int t = lua_type(L,1);
2050 if (t == LUA_TSTRING) {
2051 /* official accessors */
2052 s = lua_tostring(L,1);
2053 if (lua_key_eq(s,glyph)) subtypes = node_subtypes_glyph;
2054 else if (lua_key_eq(s,glue)) { subtypes = node_subtypes_glue; l = 1; }
2055 else if (lua_key_eq(s,penalty)) subtypes = node_subtypes_penalty;
2056 else if (lua_key_eq(s,kern)) subtypes = node_subtypes_kern;
2057 else if (lua_key_eq(s,rule)) subtypes = node_subtypes_rule;
2058 else if (lua_key_eq(s,list)) subtypes = node_subtypes_list;
2059 else if (lua_key_eq(s,disc)) subtypes = node_subtypes_disc;
2060 else if (lua_key_eq(s,fill)) subtypes = node_subtypes_fill;
2061 else if (lua_key_eq(s,leader)) { subtypes = node_subtypes_leader; l = 2; }
2062 else if (lua_key_eq(s,marginkern)) subtypes = node_subtypes_marginkern;
2063 else if (lua_key_eq(s,math)) subtypes = node_subtypes_math;
2064 else if (lua_key_eq(s,noad)) subtypes = node_subtypes_noad;
2065 else if (lua_key_eq(s,radical)) subtypes = node_subtypes_radical;
2066 else if (lua_key_eq(s,accent)) subtypes = node_subtypes_accent;
2067 else if (lua_key_eq(s,fence)) subtypes = node_subtypes_fence;
2068 /* backend */
2069 else if (lua_key_eq(s,pdf_destination)) subtypes = node_subtypes_pdf_destination;
2070 else if (lua_key_eq(s,pdf_literal)) subtypes = node_subtypes_pdf_literal;
2071 } else if (t == LUA_TNUMBER) {
2072 /* maybe */
2073 t = lua_tointeger(L,1);
2074 if (t == glyph_node) subtypes = node_subtypes_glyph;
2075 else if (t == glue_node) { subtypes = node_subtypes_glue; l = 1; }
2076 else if (t == penalty_node) subtypes = node_subtypes_penalty;
2077 else if (t == kern_node) subtypes = node_subtypes_kern;
2078 else if (t == rule_node) subtypes = node_subtypes_rule;
2079 else if (t == hlist_node) subtypes = node_subtypes_list;
2080 else if (t == vlist_node) subtypes = node_subtypes_list;
2081 else if (t == disc_node) subtypes = node_subtypes_disc;
2082 else if (t == glue_spec_node) subtypes = node_subtypes_fill;
2083 else if (t == margin_kern_node) subtypes = node_subtypes_marginkern;
2084 else if (t == math_node) subtypes = node_subtypes_math;
2085 else if (t == simple_noad) subtypes = node_subtypes_noad;
2086 else if (t == radical_noad) subtypes = node_subtypes_radical;
2087 else if (t == accent_noad) subtypes = node_subtypes_accent;
2088 else if (t == fence_noad) subtypes = node_subtypes_fence;
2089 /* backend */
2090 else if (t == pdf_dest_node) subtypes = node_subtypes_pdf_destination;
2091 else if (t == pdf_literal_node) subtypes = node_subtypes_pdf_literal;
2093 if (subtypes != NULL) {
2094 lua_checkstack(L, 2);
2095 lua_newtable(L);
2096 if (l < 2) {
2097 for (i = 0; subtypes[i] != NULL; i++) {
2098 lua_pushstring(L, subtypes[i]); /* todo */
2099 lua_rawseti(L, -2, i);
2102 if (l > 0) {
2103 /* add leaders */
2104 for (i = 0; node_subtypes_leader[i] != NULL; i++) {
2105 lua_pushstring(L, node_subtypes_leader[i]); /* todo */
2106 lua_rawseti(L, -2, 100 + i);
2109 } else {
2110 lua_pushnil(L);
2112 return 1;
2115 /* node.slide (find the end of a list and add prev links) */
2117 static int lua_nodelib_slide(lua_State * L)
2119 halfword n;
2120 if (lua_isnil(L, 1))
2121 return 1; /* the nil itself */
2122 n = *check_isnode(L, 1);
2123 if (n == null)
2124 return 1; /* the old userdata */
2125 /* alink(t) = null; */ /* don't do this, |t|'s |alink| may be a valid pointer */
2126 while (vlink(n) != null) {
2127 alink(vlink(n)) = n;
2128 n = vlink(n);
2130 lua_nodelib_push_fast(L, n);
2131 return 1;
2134 /* node.direct.slide */
2136 static int lua_nodelib_direct_slide(lua_State * L)
2138 halfword n = lua_tointeger(L, 1);
2139 if (n == null) {
2140 lua_pushnil(L);
2141 } else {
2142 while (vlink(n) != null) {
2143 alink(vlink(n)) = n;
2144 n = vlink(n);
2146 lua_pushinteger(L, n);
2148 return 1;
2151 /* node.tail (find the end of a list) */
2153 static int lua_nodelib_tail(lua_State * L)
2155 halfword n;
2156 if (lua_isnil(L, 1))
2157 return 1; /* the nil itself */
2158 n = *check_isnode(L, 1);
2159 if (n == null)
2160 return 1; /* the old userdata */
2161 while (vlink(n) != null)
2162 n = vlink(n);
2163 lua_nodelib_push_fast(L, n);
2164 return 1;
2167 /* node.direct.tail */
2169 static int lua_nodelib_direct_tail(lua_State * L)
2171 halfword n = lua_tointeger(L, 1);
2172 if (n == null) {
2173 lua_pushnil(L);
2174 } else {
2175 while (vlink(n) != null)
2176 n = vlink(n);
2177 lua_pushinteger(L, n);
2179 return 1;
2182 /* node.end_of_math (skip over math and return last) */
2184 static int lua_nodelib_end_of_math(lua_State * L)
2186 halfword n;
2187 if (lua_isnil(L, 1))
2188 return 0;
2189 n = *check_isnode(L, 1);
2190 if (n == null)
2191 return 0;
2192 if (type(n) == math_node && (subtype(n) == 1)) {
2193 lua_nodelib_push_fast(L, n);
2194 return 1;
2196 while (vlink(n) != null) {
2197 n = vlink(n);
2198 if (n && (type(n) == math_node) && (subtype(n) == 1)) {
2199 lua_nodelib_push_fast(L, n);
2200 return 1;
2203 return 0;
2206 /* node.direct.end_of_math */
2208 static int lua_nodelib_direct_end_of_math(lua_State * L)
2210 halfword n = lua_tointeger(L, 1);
2211 if (n == null)
2212 return 0;
2213 if ((type(n)==math_node && (subtype(n)==1))) {
2214 lua_pushinteger(L, n);
2215 return 1;
2217 while (vlink(n) != null) {
2218 n = vlink(n);
2219 if (n && (type(n)==math_node) && (subtype(n)==1)) {
2220 lua_pushinteger(L, n);
2221 return 1;
2224 return 0;
2228 /* node.has_attribute (gets attribute) */
2230 static int lua_nodelib_has_attribute(lua_State * L)
2232 int i, val;
2233 halfword n = *check_isnode(L, 1);
2234 if (n != null) {
2235 i = lua_tointeger(L, 2);
2236 val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2237 if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
2238 lua_pushinteger(L, val);
2239 return 1;
2242 lua_pushnil(L);
2243 return 1;
2246 /* node.direct.has_attribute */
2248 static int lua_nodelib_direct_has_attribute(lua_State * L)
2250 int i, val;
2251 halfword n = lua_tointeger(L, 1);
2252 if (n != null) {
2253 i = lua_tointeger(L, 2);
2254 val = luaL_optinteger(L, 3, UNUSED_ATTRIBUTE);
2255 if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
2256 lua_pushinteger(L, val);
2257 return 1;
2260 lua_pushnil(L);
2261 return 1;
2264 /* node.get_attribute */
2266 static int lua_nodelib_get_attribute(lua_State * L)
2268 halfword p;
2269 p = *check_isnode(L, 1);
2270 if (nodetype_has_attributes(type(p))) {
2271 p = node_attr(p);
2272 if (p != null) {
2273 p = vlink(p);
2274 if (p != null) {
2275 int i = lua_tointeger(L, 2);
2276 while (p != null) {
2277 if (attribute_id(p) == i) {
2278 int ret = attribute_value(p);
2279 if (ret == UNUSED_ATTRIBUTE) {
2280 break;
2281 } else {
2282 lua_pushinteger(L,ret);
2283 return 1;
2285 } else if (attribute_id(p) > i) {
2286 break;
2288 p = vlink(p);
2293 lua_pushnil(L);
2294 return 1;
2297 /* node.direct.get_attribute */
2299 static int lua_nodelib_direct_get_attribute(lua_State * L)
2301 register halfword p = lua_tointeger(L, 1);
2302 if (nodetype_has_attributes(type(p))) {
2303 p = node_attr(p);
2304 if (p != null) {
2305 p = vlink(p);
2306 if (p != null) {
2307 int i = lua_tointeger(L, 2);
2308 while (p != null) {
2309 if (attribute_id(p) == i) {
2310 int ret = attribute_value(p);
2311 if (ret == UNUSED_ATTRIBUTE) {
2312 break;
2313 } else {
2314 lua_pushinteger(L,ret);
2315 return 1;
2317 } else if (attribute_id(p) > i) {
2318 break;
2320 p = vlink(p);
2325 lua_pushnil(L);
2326 return 1;
2329 /* node.set_attribute */
2331 static int lua_nodelib_set_attribute(lua_State * L)
2333 if (lua_gettop(L) == 3) {
2334 int i = lua_tointeger(L, 2);
2335 int val = lua_tointeger(L, 3);
2336 halfword n = *check_isnode(L, 1);
2337 if (val == UNUSED_ATTRIBUTE) {
2338 (void) unset_attribute(n, i, val);
2339 } else {
2340 set_attribute(n, i, val);
2342 } else {
2343 luaL_error(L, "incorrect number of arguments");
2345 return 0;
2348 /* node.direct.set_attribute */
2350 static int lua_nodelib_direct_set_attribute(lua_State * L)
2352 int i, val;
2353 halfword n = lua_tointeger(L, 1);
2354 if (n == null)
2355 return 0;
2356 if (lua_gettop(L) == 3) {
2357 i = (int) lua_tointeger(L, 2);
2358 val = (int) lua_tointeger(L, 3);
2359 if (val == UNUSED_ATTRIBUTE) {
2360 (void) unset_attribute(n, i, val);
2361 } else {
2362 set_attribute(n, i, val);
2364 } else {
2365 luaL_error(L, "incorrect number of arguments");
2367 return 0;
2370 /* node.unset_attribute */
2372 static int lua_nodelib_unset_attribute(lua_State * L)
2374 if (lua_gettop(L) <= 3) {
2375 int i = luaL_checknumber(L, 2);
2376 int val = luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2377 halfword n = *check_isnode(L, 1);
2378 int ret = unset_attribute(n, i, val);
2379 if (ret > UNUSED_ATTRIBUTE) {
2380 lua_pushinteger(L, ret);
2381 } else {
2382 lua_pushnil(L);
2384 return 1;
2385 } else {
2386 return luaL_error(L, "incorrect number of arguments");
2390 /* node.direct.unset_attribute */
2392 static int lua_nodelib_direct_unset_attribute(lua_State * L)
2394 int i, val, ret;
2395 halfword n = lua_tointeger(L, 1);
2396 if (n == null) {
2397 lua_pushnil(L);
2398 } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
2399 i=(int)luaL_checknumber(L, 2);
2400 val=(int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
2401 ret = unset_attribute(n, i, val);
2402 if (ret > UNUSED_ATTRIBUTE) {
2403 lua_pushinteger(L, ret);
2404 } else {
2405 lua_pushnil(L);
2407 } else { /* can go */
2408 return luaL_error(L, "incorrect number of arguments");
2410 return 1;
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 /* funny duplicate check
2501 n = (halfword) lua_tointeger(L, 2);
2503 lua_pop(L, 1);
2504 lua_pushcclosure(L, nodelib_direct_aux_next_filtered, 1);
2505 lua_pushinteger(L,n);
2506 lua_pushnil(L);
2507 return 3;
2510 /* node.direct.traverse_char */
2512 static int nodelib_direct_aux_next_char(lua_State * L)
2514 halfword t; /* traverser */
2515 /*int i = (int) lua_tointeger(L, lua_upvalueindex(1));*/
2516 if (lua_isnil(L, 2)) { /* first call */
2517 t = lua_tointeger(L,1) ;
2518 lua_settop(L,1);
2519 } else {
2520 t = lua_tointeger(L,2) ;
2521 t = vlink(t);
2522 lua_settop(L,2);
2524 while (1) {
2525 if (t == null) {
2526 break;
2527 } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
2528 lua_pushinteger(L,t);
2529 return 1;
2530 } else {
2531 t = vlink(t);
2534 lua_pushnil(L);
2535 return 1;
2538 static int lua_nodelib_direct_traverse_char(lua_State * L)
2540 halfword n;
2541 if (lua_isnil(L, 1)) {
2542 lua_pushcclosure(L, nodelib_aux_nil, 0);
2543 return 1;
2545 n = (halfword) lua_tointeger(L, 1);
2546 if (n == null) {
2547 lua_pushcclosure(L, nodelib_aux_nil, 0);
2548 return 1;
2550 lua_pushcclosure(L, nodelib_direct_aux_next_char, 0);
2551 lua_pushinteger(L,n);
2552 lua_pushnil(L);
2553 return 3;
2556 /* node.traverse */
2558 static int nodelib_aux_next(lua_State * L)
2560 halfword t; /* traverser */
2561 halfword *a; /* a or *a */
2562 if (lua_isnil(L, 2)) { /* first call */
2563 t = *check_isnode(L, 1);
2564 lua_settop(L,1);
2565 } else {
2566 t = *check_isnode(L, 2);
2567 t = vlink(t);
2568 lua_settop(L,2);
2570 if (t == null) {
2571 lua_pushnil(L);
2572 } else {
2573 fast_metatable_top(t);
2575 return 1;
2578 static int lua_nodelib_traverse(lua_State * L)
2580 halfword n;
2581 if (lua_isnil(L, 1)) {
2582 lua_pushcclosure(L, nodelib_aux_nil, 0);
2583 return 1;
2585 n = *check_isnode(L, 1);
2586 lua_pushcclosure(L, nodelib_aux_next, 0);
2587 lua_nodelib_push_fast(L, n);
2588 lua_pushnil(L);
2589 return 3;
2592 /* node.traverse_char */
2594 static int nodelib_aux_next_char(lua_State * L)
2596 halfword t; /* traverser */
2597 halfword *a;
2598 if (lua_isnil(L, 2)) { /* first call */
2599 t = *check_isnode(L, 1);
2600 lua_settop(L,1);
2601 } else {
2602 t = *check_isnode(L, 2);
2603 t = vlink(t);
2604 lua_settop(L,2);
2606 while (1) {
2607 if (t == null) {
2608 break;
2609 } else if ((type(t) == glyph_node) && (subtype(t) < 256)){
2610 fast_metatable_top(t);
2611 return 1;
2612 } else {
2613 t = vlink(t);
2616 return 1;
2619 static int lua_nodelib_traverse_char(lua_State * L)
2621 halfword n;
2622 if (lua_isnil(L, 1)) {
2623 lua_pushcclosure(L, nodelib_aux_nil, 0);
2624 return 1;
2626 n = *check_isnode(L, 1);
2627 lua_pushcclosure(L, nodelib_aux_next_char, 0);
2628 lua_nodelib_push_fast(L, n);
2629 lua_pushnil(L);
2630 return 3;
2633 /* node.direct.traverse */
2635 static int nodelib_direct_aux_next(lua_State * L)
2637 halfword t; /* traverser */
2638 /*int i = (int) lua_tointeger(L, lua_upvalueindex(1));*/
2639 if (lua_isnil(L, 2)) { /* first call */
2640 t = lua_tointeger(L,1) ;
2641 lua_settop(L,1);
2642 } else {
2643 t = lua_tointeger(L,2) ;
2644 t = vlink(t);
2645 lua_settop(L,2);
2647 if (t == null) {
2648 lua_pushnil(L);
2649 } else {
2650 lua_pushinteger(L,t);
2652 return 1;
2655 static int lua_nodelib_direct_traverse(lua_State * L)
2657 halfword n;
2658 if (lua_isnil(L, 1)) {
2659 lua_pushcclosure(L, nodelib_aux_nil, 0);
2660 return 1;
2662 n = (halfword) lua_tointeger(L, 1);
2663 if (n == null) {
2664 lua_pushcclosure(L, nodelib_aux_nil, 0);
2665 return 1;
2667 lua_pushcclosure(L, nodelib_direct_aux_next, 0);
2668 lua_pushinteger(L,n);
2669 lua_pushnil(L);
2670 return 3;
2673 /* counting */
2675 static int do_lua_nodelib_count(lua_State * L, halfword match, int i, halfword first1)
2677 int count = 0;
2678 int t = first1;
2679 while (t != match) {
2680 if (i < 0 || type(t) == i)
2681 count++;
2682 t = vlink(t);
2684 lua_pushinteger(L, count);
2685 return 1;
2688 /* node.length */
2690 static int lua_nodelib_length(lua_State * L)
2692 halfword n;
2693 halfword m = null;
2694 if (lua_isnil(L, 1)) {
2695 lua_pushinteger(L, 0);
2696 return 1;
2698 n = *check_isnode(L, 1);
2699 if (lua_gettop(L) == 2)
2700 m = *check_isnode(L, 2);
2701 return do_lua_nodelib_count(L, m, -1, n);
2704 /* node.direct.length */
2706 static int lua_nodelib_direct_length(lua_State * L)
2708 halfword m;
2709 halfword n = lua_tointeger(L, 1);
2710 if (n == 0) {
2711 lua_pushinteger(L, 0);
2712 return 1;
2714 m = (halfword) lua_tointeger(L, 2);
2715 return do_lua_nodelib_count(L, m, -1, n);
2718 /* node.count */
2720 static int lua_nodelib_count(lua_State * L)
2722 halfword n;
2723 halfword m = null;
2724 int i = lua_tointeger(L, 1);
2725 if (lua_isnil(L, 2)) {
2726 lua_pushinteger(L, 0);
2727 return 1;
2729 n = *check_isnode(L, 2);
2730 if (lua_gettop(L) == 3)
2731 m = *check_isnode(L, 3);
2732 return do_lua_nodelib_count(L, m, i, n);
2735 /* node.direct.count */
2737 static int lua_nodelib_direct_count(lua_State * L)
2739 return do_lua_nodelib_count(L,
2740 (halfword) lua_tointeger(L, 3), /* m */
2741 (int) lua_tointeger(L, 1), /* i */
2742 (halfword) lua_tointeger(L, 2) /* n */
2746 /* getting and setting fields (helpers) */
2748 int nodelib_getlist(lua_State * L, int n)
2750 if (lua_isuserdata(L, n)) {
2751 halfword m = *check_isnode(L, n);
2752 return m;
2753 } else {
2754 return null;
2758 int nodelib_getdir(lua_State * L, int n, int absolute_only)
2760 if (lua_type(L, n) == LUA_TSTRING) {
2761 const char *s = lua_tostring(L, n);
2762 RETURN_DIR_VALUES(TLT);
2763 RETURN_DIR_VALUES(TRT);
2764 RETURN_DIR_VALUES(LTL);
2765 RETURN_DIR_VALUES(RTT);
2766 luaL_error(L, "Bad direction specifier %s", s);
2767 } else {
2768 luaL_error(L, "Direction specifiers have to be strings");
2770 return 0;
2773 static str_number nodelib_getstring(lua_State * L, int a)
2775 size_t k;
2776 const char *s = lua_tolstring(L, a, &k);
2777 return maketexlstring(s, k);
2780 static int nodelib_cantset(lua_State * L, int n, const char *s)
2782 luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name);
2783 return 0;
2786 static int nodelib_nonwritable(lua_State * L, int n, const char *s)
2788 luaL_error(L,"You cannot set field %s in a non writable node of type %s",s,node_data[type(n)].name);
2789 return 0;
2792 /* node.direct.getfield */
2794 static void lua_nodelib_getfield_whatsit(lua_State * L, int n, const char *s)
2796 int t = subtype(n);
2797 if (t == user_defined_node) {
2798 if (lua_key_eq(s, user_id)) {
2799 lua_pushinteger(L, user_node_id(n));
2800 } else if (lua_key_eq(s, type)) {
2801 lua_pushinteger(L, user_node_type(n));
2802 } else if (lua_key_eq(s, value)) {
2803 switch (user_node_type(n)) {
2804 case 'a':
2805 nodelib_pushlist(L, user_node_value(n));
2806 break;
2807 case 'd':
2808 lua_pushinteger(L, user_node_value(n));
2809 break;
2810 case 'l':
2811 if (user_node_value(n) != 0) {
2812 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
2813 } else {
2814 lua_pushnil(L);
2816 break;
2817 case 'n':
2818 nodelib_pushlist(L, user_node_value(n));
2819 break;
2820 case 's':
2821 nodelib_pushstring(L, user_node_value(n));
2822 break;
2823 case 't':
2824 tokenlist_to_lua(L, user_node_value(n));
2825 break;
2826 default:
2827 lua_pushinteger(L, user_node_value(n));
2828 break;
2830 } else {
2831 lua_pushnil(L);
2833 } else if (t == pdf_literal_node) {
2834 if (lua_key_eq(s, mode)) {
2835 lua_pushinteger(L, pdf_literal_mode(n));
2836 } else if (lua_key_eq(s, data)) {
2837 if (pdf_literal_type(n) == lua_refid_literal) {
2838 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
2839 } else {
2840 tokenlist_to_luastring(L, pdf_literal_data(n));
2842 } else {
2843 lua_pushnil(L);
2845 } else if (t == late_lua_node) {
2846 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
2847 if (late_lua_type(n) == lua_refid_literal) {
2848 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
2849 } else {
2850 tokenlist_to_luastring(L, late_lua_data(n));
2852 } else if (lua_key_eq(s, name)) {
2853 tokenlist_to_luastring(L, late_lua_name(n));
2854 } else {
2855 lua_pushnil(L);
2857 } else if (t == pdf_annot_node) {
2858 if (lua_key_eq(s, width)) {
2859 lua_pushinteger(L, width(n));
2860 } else if (lua_key_eq(s, depth)) {
2861 lua_pushinteger(L, depth(n));
2862 } else if (lua_key_eq(s, height)) {
2863 lua_pushinteger(L, height(n));
2864 } else if (lua_key_eq(s, objnum)) {
2865 lua_pushinteger(L, pdf_annot_objnum(n));
2866 } else if (lua_key_eq(s, data)) {
2867 tokenlist_to_luastring(L, pdf_annot_data(n));
2868 } else {
2869 lua_pushnil(L);
2871 } else if (t == pdf_dest_node) {
2872 if (lua_key_eq(s, width)) {
2873 lua_pushinteger(L, width(n));
2874 } else if (lua_key_eq(s, depth)) {
2875 lua_pushinteger(L, depth(n));
2876 } else if (lua_key_eq(s, height)) {
2877 lua_pushinteger(L, height(n));
2878 } else if (lua_key_eq(s, named_id)) {
2879 lua_pushinteger(L, pdf_dest_named_id(n));
2880 } else if (lua_key_eq(s, dest_id)) {
2881 if (pdf_dest_named_id(n) == 1)
2882 tokenlist_to_luastring(L, pdf_dest_id(n));
2883 else
2884 lua_pushinteger(L, pdf_dest_id(n));
2885 } else if (lua_key_eq(s, dest_type)) {
2886 lua_pushinteger(L, pdf_dest_type(n));
2887 } else if (lua_key_eq(s, xyz_zoom)) {
2888 lua_pushinteger(L, pdf_dest_xyz_zoom(n));
2889 } else if (lua_key_eq(s, objnum)) {
2890 lua_pushinteger(L, pdf_dest_objnum(n));
2891 } else {
2892 lua_pushnil(L);
2894 } else if (t == pdf_setmatrix_node) {
2895 if (lua_key_eq(s, data)) {
2896 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
2897 } else {
2898 lua_pushnil(L);
2900 } else if (t == pdf_colorstack_node) {
2901 if (lua_key_eq(s, stack)) {
2902 lua_pushinteger(L, pdf_colorstack_stack(n));
2903 } else if (lua_key_eq(s, command)) {
2904 lua_pushinteger(L, pdf_colorstack_cmd(n));
2905 } else if (lua_key_eq(s, data)) {
2906 tokenlist_to_luastring(L, pdf_colorstack_data(n));
2907 } else {
2908 lua_pushnil(L);
2910 } else if (t == pdf_refobj_node) {
2911 if (lua_key_eq(s, objnum)) {
2912 lua_pushinteger(L, pdf_obj_objnum(n));
2913 } else {
2914 lua_pushnil(L);
2916 } else if (t == write_node) {
2917 if (lua_key_eq(s, stream)) {
2918 lua_pushinteger(L, write_stream(n));
2919 } else if (lua_key_eq(s, data)) {
2920 tokenlist_to_lua(L, write_tokens(n));
2921 } else {
2922 lua_pushnil(L);
2924 } else if (t == special_node) {
2925 if (lua_key_eq(s, data)) {
2926 tokenlist_to_luastring(L, write_tokens(n));
2927 } else {
2928 lua_pushnil(L);
2930 } else if (t == pdf_start_link_node) {
2931 if (lua_key_eq(s, width)) {
2932 lua_pushinteger(L, width(n));
2933 } else if (lua_key_eq(s, depth)) {
2934 lua_pushinteger(L, depth(n));
2935 } else if (lua_key_eq(s, height)) {
2936 lua_pushinteger(L, height(n));
2937 } else if (lua_key_eq(s, objnum)) {
2938 lua_pushinteger(L, pdf_link_objnum(n));
2939 } else if (lua_key_eq(s, link_attr)) {
2940 tokenlist_to_luastring(L, pdf_link_attr(n));
2941 } else if (lua_key_eq(s, action)) {
2942 nodelib_pushaction(L, pdf_link_action(n));
2943 } else {
2944 lua_pushnil(L);
2946 } else if (t == pdf_action_node) {
2947 if (lua_key_eq(s, action_type)) {
2948 lua_pushinteger(L, pdf_action_type(n));
2949 } else if (lua_key_eq(s, named_id)) {
2950 lua_pushinteger(L, pdf_action_named_id(n));
2951 } else if (lua_key_eq(s, action_id)) {
2952 if (pdf_action_named_id(n) == 1) {
2953 tokenlist_to_luastring(L, pdf_action_id(n));
2954 } else {
2955 lua_pushinteger(L, pdf_action_id(n));
2957 } else if (lua_key_eq(s, file)) {
2958 tokenlist_to_luastring(L, pdf_action_file(n));
2959 } else if (lua_key_eq(s, new_window)) {
2960 lua_pushinteger(L, pdf_action_new_window(n));
2961 } else if (lua_key_eq(s, data)) {
2962 tokenlist_to_luastring(L, pdf_action_tokens(n));
2963 } else if (lua_key_eq(s, ref_count)) {
2964 lua_pushinteger(L, pdf_action_refcount(n));
2965 } else {
2966 lua_pushnil(L);
2968 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
2969 if (lua_key_eq(s, width)) {
2970 lua_pushinteger(L, width(n));
2971 } else if (lua_key_eq(s, depth)) {
2972 lua_pushinteger(L, depth(n));
2973 } else if (lua_key_eq(s, height)) {
2974 lua_pushinteger(L, height(n));
2975 } else if (lua_key_eq(s, named_id)) {
2976 lua_pushinteger(L, pdf_thread_named_id(n));
2977 } else if (lua_key_eq(s, thread_id)) {
2978 if (pdf_thread_named_id(n) == 1) {
2979 tokenlist_to_luastring(L, pdf_thread_id(n));
2980 } else {
2981 lua_pushinteger(L, pdf_thread_id(n));
2983 } else if (lua_key_eq(s, thread_attr)) {
2984 tokenlist_to_luastring(L, pdf_thread_attr(n));
2985 } else {
2986 lua_pushnil(L);
2988 } else if (t == open_node) {
2989 if (lua_key_eq(s, stream)) {
2990 lua_pushinteger(L, write_stream(n));
2991 } else if (lua_key_eq(s, name)) {
2992 nodelib_pushstring(L, open_name(n));
2993 } else if (lua_key_eq(s, area)) {
2994 nodelib_pushstring(L, open_area(n));
2995 } else if (lua_key_eq(s, ext)) {
2996 nodelib_pushstring(L, open_ext(n));
2997 } else {
2998 lua_pushnil(L);
3000 } else if (t == close_node) {
3001 if (lua_key_eq(s, stream)) {
3002 lua_pushinteger(L, write_stream(n));
3003 } else {
3004 lua_pushnil(L);
3006 } else {
3007 lua_pushnil(L);
3011 static int lua_nodelib_fast_getfield(lua_State * L)
3014 the order is somewhat determined by the occurance of nodes and
3015 importance of fields
3018 halfword *a;
3019 const char *s;
3021 halfword n = *((halfword *) lua_touserdata(L, 1));
3022 int t = type(n);
3026 somenode[9] as interface to attributes ... 30% faster than has_attribute
3027 (1) because there is no lua function overhead, and (2) because we already
3028 know that we deal with a node so no checking is needed. The fast typecheck
3029 is needed (lua_check... is a slow down actually).
3033 if (lua_type(L, 2) == LUA_TNUMBER) {
3035 halfword p;
3036 int i;
3038 if (! nodetype_has_attributes(t)) {
3039 lua_pushnil(L);
3040 return 1;
3043 p = node_attr(n);
3044 if (p == null || vlink(p) == null) {
3045 lua_pushnil(L);
3046 return 1;
3048 i = (int) lua_tointeger(L, 2);
3049 p = vlink(p);
3050 while (p != null) {
3051 if (attribute_id(p) == i) {
3052 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
3053 lua_pushinteger(L, (int) attribute_value(p));
3054 } else {
3055 lua_pushnil(L);
3057 return 1;
3058 } else if (attribute_id(p) > i) {
3059 lua_pushnil(L);
3060 return 1;
3062 p = vlink(p);
3064 lua_pushnil(L);
3065 return 1;
3068 s = lua_tostring(L, 2);
3070 if (lua_key_eq(s, id)) {
3071 lua_pushinteger(L, t);
3072 } else if (lua_key_eq(s, next)) {
3073 fast_metatable_or_nil(vlink(n));
3074 } else if (lua_key_eq(s, prev)) {
3075 fast_metatable_or_nil(alink(n));
3076 } else if (lua_key_eq(s, attr)) {
3077 if (! nodetype_has_attributes(t)) {
3078 lua_pushnil(L);
3079 } else {
3080 nodelib_pushattr(L, node_attr(n));
3082 } else if (t == glyph_node) {
3083 /* candidates: fontchar (font,char) whd (width,height,depth) */
3084 if (lua_key_eq(s, subtype)) {
3085 lua_pushinteger(L, subtype(n));
3086 } else if (lua_key_eq(s, font)) {
3087 lua_pushinteger(L, font(n));
3088 } else if (lua_key_eq(s, char)) {
3089 lua_pushinteger(L, character(n));
3090 } else if (lua_key_eq(s, xoffset)) {
3091 lua_pushinteger(L, x_displace(n));
3092 } else if (lua_key_eq(s, yoffset)) {
3093 lua_pushinteger(L, y_displace(n));
3094 } else if (lua_key_eq(s, width)) {
3095 lua_pushinteger(L, char_width(font(n),character(n)));
3096 } else if (lua_key_eq(s, height)) {
3097 lua_pushinteger(L, char_height(font(n),character(n)));
3098 } else if (lua_key_eq(s, depth)) {
3099 lua_pushinteger(L, char_depth(font(n),character(n)));
3100 } else if (lua_key_eq(s, expansion_factor)) {
3101 lua_pushinteger(L, ex_glyph(n));
3102 } else if (lua_key_eq(s, components)) {
3103 fast_metatable_or_nil(lig_ptr(n));
3104 } else if (lua_key_eq(s, lang)) {
3105 lua_pushinteger(L, char_lang(n));
3106 } else if (lua_key_eq(s, left)) {
3107 lua_pushinteger(L, char_lhmin(n));
3108 } else if (lua_key_eq(s, right)) {
3109 lua_pushinteger(L, char_rhmin(n));
3110 } else if (lua_key_eq(s, uchyph)) {
3111 lua_pushinteger(L, char_uchyph(n));
3112 } else {
3113 lua_pushnil(L);
3115 } else if ((t == hlist_node) || (t == vlist_node)) {
3116 /* candidates: whd (width,height,depth) */
3117 if (lua_key_eq(s, subtype)) {
3118 lua_pushinteger(L, subtype(n));
3119 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
3120 fast_metatable_or_nil_alink(list_ptr(n));
3121 } else if (lua_key_eq(s, width)) {
3122 lua_pushinteger(L, width(n));
3123 } else if (lua_key_eq(s, height)) {
3124 lua_pushinteger(L, height(n));
3125 } else if (lua_key_eq(s, depth)) {
3126 lua_pushinteger(L, depth(n));
3127 } else if (lua_key_eq(s, dir)) {
3128 lua_push_dir_par(L, box_dir(n));
3129 } else if (lua_key_eq(s, shift)) {
3130 lua_pushinteger(L, shift_amount(n));
3131 } else if (lua_key_eq(s, glue_order)) {
3132 lua_pushinteger(L, glue_order(n));
3133 } else if (lua_key_eq(s, glue_sign)) {
3134 lua_pushinteger(L, glue_sign(n));
3135 } else if (lua_key_eq(s, glue_set)) {
3136 lua_pushnumber(L, (double) glue_set(n)); /* float */
3137 } else {
3138 lua_pushnil(L);
3140 } else if (t == disc_node) {
3141 if (lua_key_eq(s, subtype)) {
3142 lua_pushinteger(L, subtype(n));
3143 } else if (lua_key_eq(s, pre)) {
3144 fast_metatable_or_nil(vlink(pre_break(n)));
3145 } else if (lua_key_eq(s, post)) {
3146 fast_metatable_or_nil(vlink(post_break(n)));
3147 } else if (lua_key_eq(s, replace)) {
3148 fast_metatable_or_nil(vlink(no_break(n)));
3149 } else {
3150 lua_pushnil(L);
3152 } else if (t == glue_node) {
3153 if (lua_key_eq(s, subtype)) {
3154 lua_pushinteger(L, subtype(n));
3155 } else if (lua_key_eq(s, spec)) {
3156 nodelib_pushspec(L, glue_ptr(n));
3157 } else if (lua_key_eq(s, leader)) {
3158 fast_metatable_or_nil(leader_ptr(n));
3159 } else {
3160 n = glue_ptr(n);
3161 if (!n) {
3162 lua_pushinteger(L, 0); /* zero skip constant */
3163 } else if (lua_key_eq(s, width)) {
3164 lua_pushinteger(L, width(n));
3165 } else if (lua_key_eq(s, stretch)) {
3166 lua_pushinteger(L, stretch(n));
3167 } else if (lua_key_eq(s, shrink)) {
3168 lua_pushinteger(L, shrink(n));
3169 } else if (lua_key_eq(s, stretch_order)) {
3170 lua_pushinteger(L, stretch_order(n));
3171 } else if (lua_key_eq(s, shrink_order)) {
3172 lua_pushinteger(L, shrink_order(n));
3173 } else {
3174 lua_pushnil(L);
3177 } else if (t == glue_spec_node) {
3178 if (lua_key_eq(s, subtype)) {
3179 lua_pushinteger(L, 0); /* dummy, the only one that prevents move up */
3180 } else if (lua_key_eq(s, width)) {
3181 lua_pushinteger(L, width(n));
3182 } else if (lua_key_eq(s, stretch)) {
3183 lua_pushinteger(L, stretch(n));
3184 } else if (lua_key_eq(s, shrink)) {
3185 lua_pushinteger(L, shrink(n));
3186 } else if (lua_key_eq(s, stretch_order)) {
3187 lua_pushinteger(L, stretch_order(n));
3188 } else if (lua_key_eq(s, shrink_order)) {
3189 lua_pushinteger(L, shrink_order(n));
3190 } else if (lua_key_eq(s, ref_count)) {
3191 lua_pushinteger(L, glue_ref_count(n));
3192 } else if (lua_key_eq(s, writable)) {
3193 lua_pushboolean(L, valid_node(n));
3194 } else {
3195 lua_pushnil(L);
3197 } else if (t == kern_node) {
3198 if (lua_key_eq(s, subtype)) {
3199 lua_pushinteger(L, subtype(n));
3200 } else if (lua_key_eq(s, kern)) {
3201 lua_pushinteger(L, width(n));
3202 } else if (lua_key_eq(s, expansion_factor)) {
3203 lua_pushinteger(L, ex_kern(n));
3204 } else {
3205 lua_pushnil(L);
3207 } else if (t == penalty_node) {
3208 if (lua_key_eq(s, subtype)) {
3209 lua_pushinteger(L, subtype(n));
3210 } else if (lua_key_eq(s, penalty)) {
3211 lua_pushinteger(L, penalty(n));
3212 } else {
3213 lua_pushnil(L);
3215 } else if (t == rule_node) {
3216 /* candidates: whd (width,height,depth) */
3217 if (lua_key_eq(s, subtype)) {
3218 lua_pushinteger(L, subtype(n));
3219 } else if (lua_key_eq(s, width)) {
3220 lua_pushinteger(L, width(n));
3221 } else if (lua_key_eq(s, height)) {
3222 lua_pushinteger(L, height(n));
3223 } else if (lua_key_eq(s, depth)) {
3224 lua_pushinteger(L, depth(n));
3225 } else if (lua_key_eq(s, dir)) {
3226 lua_push_dir_par(L, rule_dir(n));
3227 } else if (lua_key_eq(s, index)) {
3228 lua_pushinteger(L, rule_index(n));
3229 } else if (lua_key_eq(s, transform)) {
3230 lua_pushinteger(L,rule_transform(n));
3231 } else {
3232 lua_pushnil(L);
3234 } else if (t == dir_node) {
3235 if (lua_key_eq(s, dir)) {
3236 lua_push_dir_text(L, dir_dir(n));
3237 } else if (lua_key_eq(s, level)) {
3238 lua_pushinteger(L, dir_level(n));
3239 } else if (lua_key_eq(s, dvi_ptr)) {
3240 lua_pushinteger(L, dir_dvi_ptr(n));
3241 } else if (lua_key_eq(s, dir_h)) {
3242 lua_pushinteger(L, dir_dvi_h(n));
3243 } else {
3244 lua_pushnil(L);
3246 } else if (t == local_par_node) {
3247 if (lua_key_eq(s, pen_inter)) {
3248 lua_pushinteger(L, local_pen_inter(n));
3249 } else if (lua_key_eq(s, pen_broken)) {
3250 lua_pushinteger(L, local_pen_broken(n));
3251 } else if (lua_key_eq(s, dir)) {
3252 lua_push_dir_par(L, local_par_dir(n));
3253 } else if (lua_key_eq(s, box_left)) {
3254 /* can be: fast_metatable_or_nil(local_box_left(n)) */
3255 nodelib_pushlist(L, local_box_left(n));
3256 } else if (lua_key_eq(s, box_left_width)) {
3257 lua_pushinteger(L, local_box_left_width(n));
3258 } else if (lua_key_eq(s, box_right)) {
3259 /* can be: fast_metatable_or_nil(local_box_right(n)) */
3260 nodelib_pushlist(L, local_box_right(n));
3261 } else if (lua_key_eq(s, box_right_width)) {
3262 lua_pushinteger(L, local_box_right_width(n));
3263 } else {
3264 lua_pushnil(L);
3266 } else if (t == whatsit_node) {
3267 if (lua_key_eq(s, subtype)) {
3268 lua_pushinteger(L, subtype(n));
3269 } else {
3270 lua_nodelib_getfield_whatsit(L, n, s);
3272 } else if (t == simple_noad) {
3273 if (lua_key_eq(s, subtype)) {
3274 lua_pushinteger(L, subtype(n));
3275 } else if (lua_key_eq(s, nucleus)) {
3276 fast_metatable_or_nil(nucleus(n));
3277 } else if (lua_key_eq(s, sub)) {
3278 fast_metatable_or_nil(subscr(n));
3279 } else if (lua_key_eq(s, sup)) {
3280 fast_metatable_or_nil(supscr(n));
3281 } else {
3282 lua_pushnil(L);
3284 } else if ((t == math_char_node) || (t == math_text_char_node)) {
3285 /* candidates: famchar (fam,char) */
3286 if (lua_key_eq(s, subtype)) {
3287 lua_pushinteger(L, subtype(n));
3288 } else if (lua_key_eq(s, fam)) {
3289 lua_pushinteger(L, math_fam(n));
3290 } else if (lua_key_eq(s, char)) {
3291 lua_pushinteger(L, math_character(n));
3292 } else {
3293 lua_pushnil(L);
3295 } else if (t == mark_node) {
3296 if (lua_key_eq(s, subtype)) {
3297 lua_pushinteger(L, subtype(n));
3298 } else if (lua_key_eq(s, class)) {
3299 lua_pushinteger(L, mark_class(n));
3300 } else if (lua_key_eq(s, mark)) {
3301 tokenlist_to_lua(L, mark_ptr(n));
3302 } else {
3303 lua_pushnil(L);
3305 } else if (t == ins_node) {
3306 if (lua_key_eq(s, subtype)) {
3307 lua_pushinteger(L, subtype(n));
3308 } else if (lua_key_eq(s, cost)) {
3309 lua_pushinteger(L, float_cost(n));
3310 } else if (lua_key_eq(s, depth)) {
3311 lua_pushinteger(L, depth(n));
3312 } else if (lua_key_eq(s, height)) {
3313 lua_pushinteger(L, height(n));
3314 } else if (lua_key_eq(s, spec)) {
3315 nodelib_pushspec(L, split_top_ptr(n));
3316 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3317 fast_metatable_or_nil_alink(ins_ptr(n));
3318 } else {
3319 lua_pushnil(L);
3321 } else if (t == math_node) {
3322 if (lua_key_eq(s, subtype)) {
3323 lua_pushinteger(L, subtype(n));
3324 } else if (lua_key_eq(s, surround)) {
3325 lua_pushinteger(L, surround(n));
3326 } else {
3327 lua_pushnil(L);
3329 } else if (t == fraction_noad) {
3330 if (lua_key_eq(s, subtype)) {
3331 lua_pushinteger(L, subtype(n));
3332 } else if (lua_key_eq(s, width)) {
3333 lua_pushinteger(L, thickness(n));
3334 } else if (lua_key_eq(s, num)) {
3335 fast_metatable_or_nil(numerator(n));
3336 } else if (lua_key_eq(s, denom)) {
3337 fast_metatable_or_nil(denominator(n));
3338 } else if (lua_key_eq(s, left)) {
3339 fast_metatable_or_nil(left_delimiter(n));
3340 } else if (lua_key_eq(s, right)) {
3341 fast_metatable_or_nil(right_delimiter(n));
3342 } else {
3343 lua_pushnil(L);
3345 } else if (t == style_node) {
3346 if (lua_key_eq(s, subtype)) {
3347 lua_pushinteger(L, subtype(n));
3348 } else if (lua_key_eq(s, style)) {
3349 lua_push_math_style_name(L,subtype(n));
3350 } else {
3351 lua_pushnil(L);
3353 } else if (t == accent_noad) {
3354 if (lua_key_eq(s, subtype)) {
3355 lua_pushinteger(L, subtype(n));
3356 } else if (lua_key_eq(s, nucleus)) {
3357 fast_metatable_or_nil(nucleus(n));
3358 } else if (lua_key_eq(s, sub)) {
3359 fast_metatable_or_nil(subscr(n));
3360 } else if (lua_key_eq(s, sup)) {
3361 fast_metatable_or_nil(supscr(n));
3362 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
3363 fast_metatable_or_nil(top_accent_chr(n));
3364 } else if (lua_key_eq(s, bot_accent)) {
3365 fast_metatable_or_nil(bot_accent_chr(n));
3366 } else if (lua_key_eq(s, overlay_accent)) {
3367 fast_metatable_or_nil(overlay_accent_chr(n));
3368 } else {
3369 lua_pushnil(L);
3371 } else if (t == fence_noad) {
3372 if (lua_key_eq(s, subtype)) {
3373 lua_pushinteger(L, subtype(n));
3374 } else if (lua_key_eq(s, delim)) {
3375 fast_metatable_or_nil(delimiter(n));
3376 } else {
3377 lua_pushnil(L);
3379 } else if (t == delim_node) {
3380 if (lua_key_eq(s, subtype)) {
3381 lua_pushinteger(L, subtype(n));
3382 } else if (lua_key_eq(s, small_fam)) {
3383 lua_pushinteger(L, small_fam(n));
3384 } else if (lua_key_eq(s, small_char)) {
3385 lua_pushinteger(L, small_char(n));
3386 } else if (lua_key_eq(s, large_fam)) {
3387 lua_pushinteger(L, large_fam(n));
3388 } else if (lua_key_eq(s, large_char)) {
3389 lua_pushinteger(L, large_char(n));
3390 } else {
3391 lua_pushnil(L);
3393 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
3394 if (lua_key_eq(s, subtype)) {
3395 lua_pushinteger(L, subtype(n));
3396 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3397 fast_metatable_or_nil_alink(math_list(n));
3398 } else {
3399 lua_pushnil(L);
3401 } else if (t == radical_noad) {
3402 if (lua_key_eq(s, subtype)) {
3403 lua_pushinteger(L, subtype(n));
3404 } else if (lua_key_eq(s, nucleus)) {
3405 fast_metatable_or_nil(nucleus(n));
3406 } else if (lua_key_eq(s, sub)) {
3407 fast_metatable_or_nil(subscr(n));
3408 } else if (lua_key_eq(s, sup)) {
3409 fast_metatable_or_nil(supscr(n));
3410 } else if (lua_key_eq(s, left)) {
3411 fast_metatable_or_nil(left_delimiter(n));
3412 } else if (lua_key_eq(s, degree)) {
3413 fast_metatable_or_nil(degree(n));
3414 } else {
3415 lua_pushnil(L);
3417 } else if (t == margin_kern_node) {
3418 if (lua_key_eq(s, subtype)) {
3419 lua_pushinteger(L, subtype(n));
3420 } else if (lua_key_eq(s, width)) {
3421 lua_pushinteger(L, width(n));
3422 } else if (lua_key_eq(s, glyph)) {
3423 fast_metatable_or_nil(margin_char(n));
3424 } else {
3425 lua_pushnil(L);
3427 } else if (t == split_up_node) {
3428 if (lua_key_eq(s, subtype)) {
3429 lua_pushinteger(L, subtype(n));
3430 } else if (lua_key_eq(s, last_ins_ptr)) {
3431 fast_metatable_or_nil(last_ins_ptr(n));
3432 } else if (lua_key_eq(s, best_ins_ptr)) {
3433 fast_metatable_or_nil(best_ins_ptr(n));
3434 } else if (lua_key_eq(s, broken_ptr)) {
3435 fast_metatable_or_nil(broken_ptr(n));
3436 } else if (lua_key_eq(s, broken_ins)) {
3437 fast_metatable_or_nil(broken_ins(n));
3438 } else {
3439 lua_pushnil(L);
3441 } else if (t == choice_node) {
3442 if (lua_key_eq(s, subtype)) {
3443 lua_pushinteger(L, subtype(n));
3444 } else if (lua_key_eq(s, display)) {
3445 fast_metatable_or_nil(display_mlist(n));
3446 } else if (lua_key_eq(s, text)) {
3447 fast_metatable_or_nil(text_mlist(n));
3448 } else if (lua_key_eq(s, script)) {
3449 fast_metatable_or_nil(script_mlist(n));
3450 } else if (lua_key_eq(s, scriptscript)) {
3451 fast_metatable_or_nil(script_script_mlist(n));
3452 } else {
3453 lua_pushnil(L);
3455 } else if (t == inserting_node) {
3456 if (lua_key_eq(s, subtype)) {
3457 lua_pushinteger(L, subtype(n));
3458 } else if (lua_key_eq(s, last_ins_ptr)) {
3459 fast_metatable_or_nil(last_ins_ptr(n));
3460 } else if (lua_key_eq(s, best_ins_ptr)) {
3461 fast_metatable_or_nil(best_ins_ptr(n));
3462 } else {
3463 lua_pushnil(L);
3465 } else if (t == attribute_node) {
3466 if (lua_key_eq(s, subtype)) {
3467 lua_pushinteger(L, subtype(n));
3468 } else if (lua_key_eq(s, number)) {
3469 lua_pushinteger(L, attribute_id(n));
3470 } else if (lua_key_eq(s, value)) {
3471 lua_pushinteger(L, attribute_value(n));
3472 } else {
3473 lua_pushnil(L);
3475 } else if (t == adjust_node) {
3476 if (lua_key_eq(s, subtype)) {
3477 lua_pushinteger(L, subtype(n));
3478 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
3479 fast_metatable_or_nil_alink(adjust_ptr(n));
3480 } else {
3481 lua_pushnil(L);
3483 } else if (t == unset_node) {
3484 if (lua_key_eq(s, subtype)) {
3485 lua_pushinteger(L, subtype(n));
3486 } else if (lua_key_eq(s, width)) {
3487 lua_pushinteger(L, width(n));
3488 } else if (lua_key_eq(s, height)) {
3489 lua_pushinteger(L, height(n));
3490 } else if (lua_key_eq(s, depth)) {
3491 lua_pushinteger(L, depth(n));
3492 } else if (lua_key_eq(s, dir)) {
3493 lua_push_dir_par(L, box_dir(n));
3494 } else if (lua_key_eq(s, shrink)) {
3495 lua_pushinteger(L, glue_shrink(n));
3496 } else if (lua_key_eq(s, glue_order)) {
3497 lua_pushinteger(L, glue_order(n));
3498 } else if (lua_key_eq(s, glue_sign)) {
3499 lua_pushinteger(L, glue_sign(n));
3500 } else if (lua_key_eq(s, stretch)) {
3501 lua_pushinteger(L, glue_stretch(n));
3502 } else if (lua_key_eq(s, count)) {
3503 lua_pushinteger(L, span_count(n));
3504 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
3505 fast_metatable_or_nil_alink(list_ptr(n));
3506 } else {
3507 lua_pushnil(L);
3509 } else if (t == attribute_list_node) {
3510 if (lua_key_eq(s, subtype)) {
3511 lua_pushinteger(L, subtype(n));
3512 } else {
3513 lua_pushnil(L);
3515 } else if (t == boundary_node) {
3516 if (lua_key_eq(s, subtype)) {
3517 lua_pushinteger(L, subtype(n));
3518 } else if (lua_key_eq(s, value)) {
3519 lua_pushinteger(L, boundary_value(n));
3520 } else {
3521 lua_pushnil(L);
3523 } else {
3524 lua_pushnil(L);
3526 return 1;
3529 static int lua_nodelib_getfield(lua_State * L)
3531 /* [given-node] [...]*/
3532 halfword *p = lua_touserdata(L, 1);
3533 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
3534 lua_pushnil(L) ;
3535 return 1;
3537 /* [given-node] [mt-given-node]*/
3538 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
3539 lua_gettable(L, LUA_REGISTRYINDEX);
3540 /* [given-node] [mt-given-node] [mt-node]*/
3541 if (!lua_rawequal(L, -1, -2)) {
3542 lua_pushnil(L) ;
3543 return 1;
3545 /* prune stack and call getfield */
3546 lua_settop(L,2);
3547 return lua_nodelib_fast_getfield(L);
3550 /* node.direct.getfield */
3552 static void lua_nodelib_direct_getfield_whatsit(lua_State * L, int n, const char *s)
3554 int t = subtype(n);
3555 if (t == user_defined_node) {
3556 if (lua_key_eq(s, user_id)) {
3557 lua_pushinteger(L, user_node_id(n));
3558 } else if (lua_key_eq(s, type)) {
3559 lua_pushinteger(L, user_node_type(n));
3560 } else if (lua_key_eq(s, value)) {
3561 switch (user_node_type(n)) {
3562 case 'a':
3563 nodelib_pushdirect(user_node_value(n));
3564 break;
3565 case 'd':
3566 lua_pushinteger(L, user_node_value(n));
3567 break;
3568 case 'l':
3569 if (user_node_value(n) != 0) {
3570 lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n));
3571 } else {
3572 lua_pushnil(L);
3574 break;
3575 case 'n':
3576 nodelib_pushdirect(user_node_value(n));
3577 break;
3578 case 's':
3579 nodelib_pushstring(L, user_node_value(n));
3580 break;
3581 case 't':
3582 tokenlist_to_lua(L, user_node_value(n));
3583 break;
3584 default:
3585 lua_pushinteger(L, user_node_value(n));
3586 break;
3588 } else {
3589 lua_pushnil(L);
3591 } else if (t == pdf_literal_node) {
3592 if (lua_key_eq(s, mode)) {
3593 lua_pushinteger(L, pdf_literal_mode(n));
3594 } else if (lua_key_eq(s, data)) {
3595 if (pdf_literal_type(n) == lua_refid_literal) {
3596 lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n));
3597 } else {
3598 tokenlist_to_luastring(L, pdf_literal_data(n));
3600 } else {
3601 lua_pushnil(L);
3603 } else if (t == late_lua_node) {
3604 if (lua_key_eq(s, string) || lua_key_eq(s, data)) {
3605 if (late_lua_type(n) == lua_refid_literal) {
3606 lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n));
3607 } else {
3608 tokenlist_to_luastring(L, late_lua_data(n));
3610 } else if (lua_key_eq(s, name)) {
3611 tokenlist_to_luastring(L, late_lua_name(n));
3612 } else {
3613 lua_pushnil(L);
3615 } else if (t == pdf_annot_node) {
3616 if (lua_key_eq(s, width)) {
3617 lua_pushinteger(L, width(n));
3618 } else if (lua_key_eq(s, depth)) {
3619 lua_pushinteger(L, depth(n));
3620 } else if (lua_key_eq(s, height)) {
3621 lua_pushinteger(L, height(n));
3622 } else if (lua_key_eq(s, objnum)) {
3623 lua_pushinteger(L, pdf_annot_objnum(n));
3624 } else if (lua_key_eq(s, data)) {
3625 tokenlist_to_luastring(L, pdf_annot_data(n));
3626 } else {
3627 lua_pushnil(L);
3629 } else if (t == pdf_dest_node) {
3630 if (lua_key_eq(s, width)) {
3631 lua_pushinteger(L, width(n));
3632 } else if (lua_key_eq(s, depth)) {
3633 lua_pushinteger(L, depth(n));
3634 } else if (lua_key_eq(s, height)) {
3635 lua_pushinteger(L, height(n));
3636 } else if (lua_key_eq(s, named_id)) {
3637 lua_pushinteger(L, pdf_dest_named_id(n));
3638 } else if (lua_key_eq(s, dest_id)) {
3639 if (pdf_dest_named_id(n) == 1)
3640 tokenlist_to_luastring(L, pdf_dest_id(n));
3641 else
3642 lua_pushinteger(L, pdf_dest_id(n));
3643 } else if (lua_key_eq(s, dest_type)) {
3644 lua_pushinteger(L, pdf_dest_type(n));
3645 } else if (lua_key_eq(s, xyz_zoom)) {
3646 lua_pushinteger(L, pdf_dest_xyz_zoom(n));
3647 } else if (lua_key_eq(s, objnum)) {
3648 lua_pushinteger(L, pdf_dest_objnum(n));
3649 } else {
3650 lua_pushnil(L);
3652 } else if (t == pdf_setmatrix_node) {
3653 if (lua_key_eq(s, data)) {
3654 tokenlist_to_luastring(L, pdf_setmatrix_data(n));
3655 } else {
3656 lua_pushnil(L);
3658 } else if (t == pdf_colorstack_node) {
3659 if (lua_key_eq(s, stack)) {
3660 lua_pushinteger(L, pdf_colorstack_stack(n));
3661 } else if (lua_key_eq(s, command)) {
3662 lua_pushinteger(L, pdf_colorstack_cmd(n));
3663 } else if (lua_key_eq(s, data)) {
3664 tokenlist_to_luastring(L, pdf_colorstack_data(n));
3665 } else {
3666 lua_pushnil(L);
3668 } else if (t == pdf_refobj_node) {
3669 if (lua_key_eq(s, objnum)) {
3670 lua_pushinteger(L, pdf_obj_objnum(n));
3671 } else {
3672 lua_pushnil(L);
3674 } else if (t == write_node) {
3675 if (lua_key_eq(s, stream)) {
3676 lua_pushinteger(L, write_stream(n));
3677 } else if (lua_key_eq(s, data)) {
3678 tokenlist_to_lua(L, write_tokens(n));
3679 } else {
3680 lua_pushnil(L);
3682 } else if (t == special_node) {
3683 if (lua_key_eq(s, data)) {
3684 tokenlist_to_luastring(L, write_tokens(n));
3685 } else {
3686 lua_pushnil(L);
3688 } else if (t == pdf_start_link_node) {
3689 if (lua_key_eq(s, width)) {
3690 lua_pushinteger(L, width(n));
3691 } else if (lua_key_eq(s, depth)) {
3692 lua_pushinteger(L, depth(n));
3693 } else if (lua_key_eq(s, height)) {
3694 lua_pushinteger(L, height(n));
3695 } else if (lua_key_eq(s, objnum)) {
3696 lua_pushinteger(L, pdf_link_objnum(n));
3697 } else if (lua_key_eq(s, link_attr)) {
3698 tokenlist_to_luastring(L, pdf_link_attr(n));
3699 } else if (lua_key_eq(s, action)) {
3700 nodelib_pushaction(L, pdf_link_action(n));
3701 } else {
3702 lua_pushnil(L);
3704 } else if (t == pdf_action_node) {
3705 if (lua_key_eq(s, action_type)) {
3706 lua_pushinteger(L, pdf_action_type(n));
3707 } else if (lua_key_eq(s, named_id)) {
3708 lua_pushinteger(L, pdf_action_named_id(n));
3709 } else if (lua_key_eq(s, action_id)) {
3710 if (pdf_action_named_id(n) == 1) {
3711 tokenlist_to_luastring(L, pdf_action_id(n));
3712 } else {
3713 lua_pushinteger(L, pdf_action_id(n));
3715 } else if (lua_key_eq(s, file)) {
3716 tokenlist_to_luastring(L, pdf_action_file(n));
3717 } else if (lua_key_eq(s, new_window)) {
3718 lua_pushinteger(L, pdf_action_new_window(n));
3719 } else if (lua_key_eq(s, data)) {
3720 tokenlist_to_luastring(L, pdf_action_tokens(n));
3721 } else if (lua_key_eq(s, ref_count)) {
3722 lua_pushinteger(L, pdf_action_refcount(n));
3723 } else {
3724 lua_pushnil(L);
3726 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
3727 if (lua_key_eq(s, width)) {
3728 lua_pushinteger(L, width(n));
3729 } else if (lua_key_eq(s, depth)) {
3730 lua_pushinteger(L, depth(n));
3731 } else if (lua_key_eq(s, height)) {
3732 lua_pushinteger(L, height(n));
3733 } else if (lua_key_eq(s, named_id)) {
3734 lua_pushinteger(L, pdf_thread_named_id(n));
3735 } else if (lua_key_eq(s, thread_id)) {
3736 if (pdf_thread_named_id(n) == 1) {
3737 tokenlist_to_luastring(L, pdf_thread_id(n));
3738 } else {
3739 lua_pushinteger(L, pdf_thread_id(n));
3741 } else if (lua_key_eq(s, thread_attr)) {
3742 tokenlist_to_luastring(L, pdf_thread_attr(n));
3743 } else {
3744 lua_pushnil(L);
3746 } else if (t == open_node) {
3747 if (lua_key_eq(s, stream)) {
3748 lua_pushinteger(L, write_stream(n));
3749 } else if (lua_key_eq(s, name)) {
3750 nodelib_pushstring(L, open_name(n));
3751 } else if (lua_key_eq(s, area)) {
3752 nodelib_pushstring(L, open_area(n));
3753 } else if (lua_key_eq(s, ext)) {
3754 nodelib_pushstring(L, open_ext(n));
3755 } else {
3756 lua_pushnil(L);
3758 } else if (t == close_node) {
3759 if (lua_key_eq(s, stream)) {
3760 lua_pushinteger(L, write_stream(n));
3761 } else {
3762 lua_pushnil(L);
3764 } else {
3765 lua_pushnil(L);
3769 static int lua_nodelib_direct_getfield(lua_State * L)
3772 const char *s;
3773 halfword n = lua_tointeger(L, 1);
3774 int t = type(n);
3775 if (lua_type(L, 2) == LUA_TNUMBER) {
3776 halfword p;
3777 int i;
3778 if (! nodetype_has_attributes(t)) {
3779 lua_pushnil(L) ;
3780 return 1;
3782 p = node_attr(n);
3783 if (p == null || vlink(p) == null) {
3784 lua_pushnil(L) ;
3785 return 1;
3787 i = (int) lua_tointeger(L, 2);
3788 p = vlink(p);
3789 while (p != null) {
3790 if (attribute_id(p) == i) {
3791 if ((int) attribute_value(p) > UNUSED_ATTRIBUTE) {
3792 lua_pushinteger(L, (int) attribute_value(p));
3793 } else {
3794 lua_pushnil(L);
3796 return 1;
3797 } else if (attribute_id(p) > i) {
3798 lua_pushnil(L) ;
3799 return 1;
3801 p = vlink(p);
3803 lua_pushnil(L) ;
3804 return 1;
3807 s = lua_tostring(L, 2);
3809 if (lua_key_eq(s, id)) {
3810 lua_pushinteger(L, t);
3811 } else if (lua_key_eq(s, next)) {
3812 nodelib_pushdirect_or_nil(vlink(n));
3813 } else if (lua_key_eq(s, prev)) {
3814 nodelib_pushdirect_or_nil(alink(n));
3815 } else if (lua_key_eq(s, subtype)) {
3816 if (t == glue_spec_node) {
3817 lua_pushinteger(L, 0); /* dummy, the only one */
3818 } else {
3819 lua_pushinteger(L, subtype(n));
3821 } else if (lua_key_eq(s, attr)) {
3822 if (! nodetype_has_attributes(t)) {
3823 lua_pushnil(L);
3824 } else {
3825 nodelib_pushattr(L, node_attr(n));
3827 } else if (t == glyph_node) {
3828 if (lua_key_eq(s, font)) {
3829 lua_pushinteger(L, font(n));
3830 } else if (lua_key_eq(s, char)) {
3831 lua_pushinteger(L, character(n));
3832 } else if (lua_key_eq(s, xoffset)) {
3833 lua_pushinteger(L, x_displace(n));
3834 } else if (lua_key_eq(s, yoffset)) {
3835 lua_pushinteger(L, y_displace(n));
3836 } else if (lua_key_eq(s, width)) {
3837 lua_pushinteger(L, char_width(font(n),character(n)));
3838 } else if (lua_key_eq(s, height)) {
3839 lua_pushinteger(L, char_height(font(n),character(n)));
3840 } else if (lua_key_eq(s, depth)) {
3841 lua_pushinteger(L, char_depth(font(n),character(n)));
3842 } else if (lua_key_eq(s, expansion_factor)) {
3843 lua_pushinteger(L, ex_glyph(n));
3844 } else if (lua_key_eq(s, components)) {
3845 nodelib_pushdirect_or_nil(lig_ptr(n));
3846 } else if (lua_key_eq(s, lang)) {
3847 lua_pushinteger(L, char_lang(n));
3848 } else if (lua_key_eq(s, left)) {
3849 lua_pushinteger(L, char_lhmin(n));
3850 } else if (lua_key_eq(s, right)) {
3851 lua_pushinteger(L, char_rhmin(n));
3852 } else if (lua_key_eq(s, uchyph)) {
3853 lua_pushinteger(L, char_uchyph(n));
3854 } else {
3855 lua_pushnil(L);
3857 } else if ((t == hlist_node) || (t == vlist_node)) {
3858 /* candidates: whd (width,height,depth) */
3859 if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
3860 nodelib_pushdirect_or_nil_alink(list_ptr(n));
3861 } else if (lua_key_eq(s, width)) {
3862 lua_pushinteger(L, width(n));
3863 } else if (lua_key_eq(s, height)) {
3864 lua_pushinteger(L, height(n));
3865 } else if (lua_key_eq(s, depth)) {
3866 lua_pushinteger(L, depth(n));
3867 } else if (lua_key_eq(s, dir)) {
3868 lua_push_dir_par(L, box_dir(n));
3869 } else if (lua_key_eq(s, shift)) {
3870 lua_pushinteger(L, shift_amount(n));
3871 } else if (lua_key_eq(s, glue_order)) {
3872 lua_pushinteger(L, glue_order(n));
3873 } else if (lua_key_eq(s, glue_sign)) {
3874 lua_pushinteger(L, glue_sign(n));
3875 } else if (lua_key_eq(s, glue_set)) {
3876 lua_pushnumber(L, (double) glue_set(n)); /* float */
3877 } else {
3878 lua_pushnil(L);
3880 } else if (t == disc_node) {
3881 if (lua_key_eq(s, pre)) {
3882 nodelib_pushdirect_or_nil(vlink(pre_break(n)));
3883 } else if (lua_key_eq(s, post)) {
3884 nodelib_pushdirect_or_nil(vlink(post_break(n)));
3885 } else if (lua_key_eq(s, replace)) {
3886 nodelib_pushdirect_or_nil(vlink(no_break(n)));
3887 } else {
3888 lua_pushnil(L);
3890 } else if (t == glue_node) {
3891 if (lua_key_eq(s, spec)) {
3892 nodelib_pushdirect(glue_ptr(n));
3893 } else if (lua_key_eq(s, leader)) {
3894 nodelib_pushdirect_or_nil(leader_ptr(n));
3895 } else {
3896 n = glue_ptr(n);
3897 if (!n) {
3898 lua_pushinteger(L, 0); /* zero skip constant */
3899 } else if (lua_key_eq(s, width)) {
3900 lua_pushinteger(L, width(n));
3901 } else if (lua_key_eq(s, stretch)) {
3902 lua_pushinteger(L, stretch(n));
3903 } else if (lua_key_eq(s, shrink)) {
3904 lua_pushinteger(L, shrink(n));
3905 } else if (lua_key_eq(s, stretch_order)) {
3906 lua_pushinteger(L, stretch_order(n));
3907 } else if (lua_key_eq(s, shrink_order)) {
3908 lua_pushinteger(L, shrink_order(n));
3909 } else {
3910 lua_pushnil(L);
3913 } else if (t == glue_spec_node) {
3914 if (lua_key_eq(s, width)) {
3915 lua_pushinteger(L, width(n));
3916 } else if (lua_key_eq(s, stretch)) {
3917 lua_pushinteger(L, stretch(n));
3918 } else if (lua_key_eq(s, shrink)) {
3919 lua_pushinteger(L, shrink(n));
3920 } else if (lua_key_eq(s, stretch_order)) {
3921 lua_pushinteger(L, stretch_order(n));
3922 } else if (lua_key_eq(s, shrink_order)) {
3923 lua_pushinteger(L, shrink_order(n));
3924 } else if (lua_key_eq(s, ref_count)) {
3925 lua_pushinteger(L, glue_ref_count(n));
3926 } else if (lua_key_eq(s, writable)) {
3927 lua_pushboolean(L, valid_node(n));
3928 } else {
3929 lua_pushnil(L);
3931 } else if (t == kern_node) {
3932 if (lua_key_eq(s, kern)) {
3933 lua_pushinteger(L, width(n));
3934 } else if (lua_key_eq(s, expansion_factor)) {
3935 lua_pushinteger(L, ex_kern(n));
3936 } else {
3937 lua_pushnil(L);
3939 } else if (t == penalty_node) {
3940 if (lua_key_eq(s, penalty)) {
3941 lua_pushinteger(L, penalty(n));
3942 } else {
3943 lua_pushnil(L);
3945 } else if (t == rule_node) {
3946 /* candidates: whd (width,height,depth) */
3947 if (lua_key_eq(s, width)) {
3948 lua_pushinteger(L, width(n));
3949 } else if (lua_key_eq(s, height)) {
3950 lua_pushinteger(L, height(n));
3951 } else if (lua_key_eq(s, depth)) {
3952 lua_pushinteger(L, depth(n));
3953 } else if (lua_key_eq(s, dir)) {
3954 lua_push_dir_par(L, rule_dir(n));
3955 } else if (lua_key_eq(s, index)) {
3956 lua_pushinteger(L, rule_index(n));
3957 } else if (lua_key_eq(s, transform)) {
3958 lua_pushinteger(L,rule_transform(n));
3959 } else {
3960 lua_pushnil(L);
3962 } else if (t == dir_node) {
3963 if (lua_key_eq(s, dir)) {
3964 lua_push_dir_text(L, dir_dir(n));
3965 } else if (lua_key_eq(s, level)) {
3966 lua_pushinteger(L, dir_level(n));
3967 } else if (lua_key_eq(s, dvi_ptr)) {
3968 lua_pushinteger(L, dir_dvi_ptr(n));
3969 } else if (lua_key_eq(s, dir_h)) {
3970 lua_pushinteger(L, dir_dvi_h(n));
3971 } else {
3972 lua_pushnil(L);
3974 } else if (t == local_par_node) {
3975 if (lua_key_eq(s, pen_inter)) {
3976 lua_pushinteger(L, local_pen_inter(n));
3977 } else if (lua_key_eq(s, pen_broken)) {
3978 lua_pushinteger(L, local_pen_broken(n));
3979 } else if (lua_key_eq(s, dir)) {
3980 lua_push_dir_par(L, local_par_dir(n));
3981 } else if (lua_key_eq(s, box_left)) {
3982 nodelib_pushdirect_or_nil(local_box_left(n));
3983 } else if (lua_key_eq(s, box_left_width)) {
3984 lua_pushinteger(L, local_box_left_width(n));
3985 } else if (lua_key_eq(s, box_right)) {
3986 nodelib_pushdirect_or_nil(local_box_right(n));
3987 } else if (lua_key_eq(s, box_right_width)) {
3988 lua_pushinteger(L, local_box_right_width(n));
3989 } else {
3990 lua_pushnil(L);
3992 } else if (t == whatsit_node) {
3993 lua_nodelib_direct_getfield_whatsit(L, n, s);
3994 } else if (t == simple_noad) {
3995 if (lua_key_eq(s, nucleus)) {
3996 nodelib_pushdirect_or_nil(nucleus(n));
3997 } else if (lua_key_eq(s, sub)) {
3998 nodelib_pushdirect_or_nil(subscr(n));
3999 } else if (lua_key_eq(s, sup)) {
4000 nodelib_pushdirect_or_nil(supscr(n));
4001 } else {
4002 lua_pushnil(L);
4004 } else if ((t == math_char_node) || (t == math_text_char_node)) {
4005 if (lua_key_eq(s, fam)) {
4006 lua_pushinteger(L, math_fam(n));
4007 } else if (lua_key_eq(s, char)) {
4008 lua_pushinteger(L, math_character(n));
4009 } else {
4010 lua_pushnil(L);
4012 } else if (t == mark_node) {
4013 if (lua_key_eq(s, class)) {
4014 lua_pushinteger(L, mark_class(n));
4015 } else if (lua_key_eq(s, mark)) {
4016 tokenlist_to_lua(L, mark_ptr(n));
4017 } else {
4018 lua_pushnil(L);
4020 } else if (t == ins_node) {
4021 if (lua_key_eq(s, cost)) {
4022 lua_pushinteger(L, float_cost(n));
4023 } else if (lua_key_eq(s, depth)) {
4024 lua_pushinteger(L, depth(n));
4025 } else if (lua_key_eq(s, height)) {
4026 lua_pushinteger(L, height(n));
4027 } else if (lua_key_eq(s, spec)) {
4028 nodelib_pushdirect_or_nil(split_top_ptr(n));
4029 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
4030 nodelib_pushdirect_or_nil_alink(ins_ptr(n));
4031 } else {
4032 lua_pushnil(L);
4034 } else if (t == math_node) {
4035 if (lua_key_eq(s, surround)) {
4036 lua_pushinteger(L, surround(n));
4037 } else {
4038 lua_pushnil(L);
4040 } else if (t == fraction_noad) {
4041 if (lua_key_eq(s, width)) {
4042 lua_pushinteger(L, thickness(n));
4043 } else if (lua_key_eq(s, num)) {
4044 nodelib_pushdirect_or_nil(numerator(n));
4045 } else if (lua_key_eq(s, denom)) {
4046 nodelib_pushdirect_or_nil(denominator(n));
4047 } else if (lua_key_eq(s, left)) {
4048 nodelib_pushdirect_or_nil(left_delimiter(n));
4049 } else if (lua_key_eq(s, right)) {
4050 nodelib_pushdirect_or_nil(right_delimiter(n));
4051 } else {
4052 lua_pushnil(L);
4054 } else if (t == style_node) {
4055 if (lua_key_eq(s, style)) {
4056 lua_push_math_style_name(L,subtype(n));
4057 } else {
4058 lua_pushnil(L);
4060 } else if (t == accent_noad) {
4061 if (lua_key_eq(s, nucleus)) {
4062 nodelib_pushdirect_or_nil(nucleus(n));
4063 } else if (lua_key_eq(s, sub)) {
4064 nodelib_pushdirect_or_nil(subscr(n));
4065 } else if (lua_key_eq(s, sup)) {
4066 nodelib_pushdirect_or_nil(supscr(n));
4067 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
4068 nodelib_pushdirect_or_nil(top_accent_chr(n));
4069 } else if (lua_key_eq(s, bot_accent)) {
4070 nodelib_pushdirect_or_nil(bot_accent_chr(n));
4071 } else if (lua_key_eq(s, overlay_accent)) {
4072 nodelib_pushdirect_or_nil(overlay_accent_chr(n));
4073 } else {
4074 lua_pushnil(L);
4076 } else if (t == fence_noad) {
4077 if (lua_key_eq(s, delim)) {
4078 nodelib_pushdirect_or_nil(delimiter(n));
4079 } else {
4080 lua_pushnil(L);
4082 } else if (t == delim_node) {
4083 if (lua_key_eq(s, small_fam)) {
4084 lua_pushinteger(L, small_fam(n));
4085 } else if (lua_key_eq(s, small_char)) {
4086 lua_pushinteger(L, small_char(n));
4087 } else if (lua_key_eq(s, large_fam)) {
4088 lua_pushinteger(L, large_fam(n));
4089 } else if (lua_key_eq(s, large_char)) {
4090 lua_pushinteger(L, large_char(n));
4091 } else {
4092 lua_pushnil(L);
4094 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
4095 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
4096 nodelib_pushdirect_or_nil_alink(math_list(n));
4097 } else {
4098 lua_pushnil(L);
4100 } else if (t == radical_noad) {
4101 if (lua_key_eq(s, nucleus)) {
4102 nodelib_pushdirect_or_nil(nucleus(n));
4103 } else if (lua_key_eq(s, sub)) {
4104 nodelib_pushdirect_or_nil(subscr(n));
4105 } else if (lua_key_eq(s, sup)) {
4106 nodelib_pushdirect_or_nil(supscr(n));
4107 } else if (lua_key_eq(s, left)) {
4108 nodelib_pushdirect_or_nil(left_delimiter(n));
4109 } else if (lua_key_eq(s, degree)) {
4110 nodelib_pushdirect_or_nil(degree(n));
4111 } else {
4112 lua_pushnil(L);
4114 } else if (t == margin_kern_node) {
4115 if (lua_key_eq(s, width)) {
4116 lua_pushinteger(L, width(n));
4117 } else if (lua_key_eq(s, glyph)) {
4118 nodelib_pushdirect_or_nil(margin_char(n));
4119 } else {
4120 lua_pushnil(L);
4122 } else if (t == split_up_node) {
4123 if (lua_key_eq(s, last_ins_ptr)) {
4124 nodelib_pushdirect_or_nil(last_ins_ptr(n));
4125 } else if (lua_key_eq(s, best_ins_ptr)) {
4126 nodelib_pushdirect_or_nil(best_ins_ptr(n));
4127 } else if (lua_key_eq(s, broken_ptr)) {
4128 nodelib_pushdirect_or_nil(broken_ptr(n));
4129 } else if (lua_key_eq(s, broken_ins)) {
4130 nodelib_pushdirect_or_nil(broken_ins(n));
4131 } else {
4132 lua_pushnil(L);
4134 } else if (t == choice_node) {
4135 if (lua_key_eq(s, display)) {
4136 nodelib_pushdirect_or_nil(display_mlist(n));
4137 } else if (lua_key_eq(s, text)) {
4138 nodelib_pushdirect_or_nil(text_mlist(n));
4139 } else if (lua_key_eq(s, script)) {
4140 nodelib_pushdirect_or_nil(script_mlist(n));
4141 } else if (lua_key_eq(s, scriptscript)) {
4142 nodelib_pushdirect_or_nil(script_script_mlist(n));
4143 } else {
4144 lua_pushnil(L);
4146 } else if (t == inserting_node) {
4147 if (lua_key_eq(s, last_ins_ptr)) {
4148 nodelib_pushdirect_or_nil(last_ins_ptr(n));
4149 } else if (lua_key_eq(s, best_ins_ptr)) {
4150 nodelib_pushdirect_or_nil(best_ins_ptr(n));
4151 } else {
4152 lua_pushnil(L);
4154 } else if (t == attribute_node) {
4155 if (lua_key_eq(s, number)) {
4156 lua_pushinteger(L, attribute_id(n));
4157 } else if (lua_key_eq(s, value)) {
4158 lua_pushinteger(L, attribute_value(n));
4159 } else {
4160 lua_pushnil(L);
4162 } else if (t == adjust_node) {
4163 if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
4164 nodelib_pushdirect_or_nil_alink(adjust_ptr(n));
4165 } else {
4166 lua_pushnil(L);
4168 } else if (t == unset_node) {
4169 if (lua_key_eq(s, width)) {
4170 lua_pushinteger(L, width(n));
4171 } else if (lua_key_eq(s, height)) {
4172 lua_pushinteger(L, height(n));
4173 } else if (lua_key_eq(s, depth)) {
4174 lua_pushinteger(L, depth(n));
4175 } else if (lua_key_eq(s, dir)) {
4176 lua_push_dir_par(L, box_dir(n));
4177 } else if (lua_key_eq(s, shrink)) {
4178 lua_pushinteger(L, glue_shrink(n));
4179 } else if (lua_key_eq(s, glue_order)) {
4180 lua_pushinteger(L, glue_order(n));
4181 } else if (lua_key_eq(s, glue_sign)) {
4182 lua_pushinteger(L, glue_sign(n));
4183 } else if (lua_key_eq(s, stretch)) {
4184 lua_pushinteger(L, glue_stretch(n));
4185 } else if (lua_key_eq(s, count)) {
4186 lua_pushinteger(L, span_count(n));
4187 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
4188 nodelib_pushdirect_or_nil_alink(list_ptr(n));
4189 } else {
4190 lua_pushnil(L);
4192 /* } else if (t == attribute_list_node) { */
4193 /* lua_pushnil(L); */
4194 } else if (t == boundary_node) {
4195 if (lua_key_eq(s, subtype)) {
4196 lua_pushinteger(L, subtype(n));
4197 } else if (lua_key_eq(s, value)) {
4198 lua_pushinteger(L, boundary_value(n));
4199 } else {
4200 lua_pushnil(L);
4202 } else {
4203 lua_pushnil(L);
4205 return 1;
4208 /* msg could be preallocated and shared */
4210 static void lua_nodelib_do_tostring(lua_State * L, halfword n, const char *tag)
4212 char *msg;
4213 char a[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
4214 char v[7] = { ' ', ' ', ' ', 'n', 'i', 'l', 0 };
4215 msg = xmalloc(256);
4216 if ((alink(n) != null) && (type(n) != attribute_node))
4217 snprintf(a, 7, "%6d", (int) alink(n));
4218 if (vlink(n) != null)
4219 snprintf(v, 7, "%6d", (int) vlink(n));
4220 snprintf(msg, 255, "<%s %s < %6d > %s : %s %d>", tag, a, (int) n, v, node_data[type(n)].name, subtype(n));
4221 lua_pushstring(L, msg);
4222 free(msg);
4223 return ;
4226 /* __tostring node.tostring */
4228 static int lua_nodelib_tostring(lua_State * L)
4230 halfword n = *check_isnode(L, 1);
4231 lua_nodelib_do_tostring(L, n, "node");
4232 return 1;
4235 /* node.direct.tostring */
4237 static int lua_nodelib_direct_tostring(lua_State * L)
4239 halfword n = lua_tointeger(L,1);
4240 if (n==0) {
4241 lua_pushnil(L);
4242 } else {
4243 lua_nodelib_do_tostring(L, n, "direct");
4245 return 1;
4248 /* __eq */
4250 static int lua_nodelib_equal(lua_State * L)
4252 halfword n = *((halfword *) lua_touserdata(L, 1));
4253 halfword m = *((halfword *) lua_touserdata(L, 2));
4254 lua_pushboolean(L, (n == m));
4255 return 1;
4258 /* node.ligaturing */
4260 static int font_tex_ligaturing(lua_State * L)
4262 /* on the stack are two nodes and a direction */
4263 /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */
4264 halfword tmp_head;
4265 halfword h;
4266 halfword t = null;
4267 halfword p ;
4268 if (lua_gettop(L) < 1) {
4269 lua_pushnil(L);
4270 lua_pushboolean(L, 0);
4271 return 2;
4273 h = *check_isnode(L, 1);
4274 if (lua_gettop(L) > 1) {
4275 t = *check_isnode(L, 2);
4277 tmp_head = new_node(nesting_node, 1);
4278 p = alink(h);
4279 couple_nodes(tmp_head, h);
4280 tlink(tmp_head) = t;
4281 t = handle_ligaturing(tmp_head, t);
4282 if (p != null) {
4283 vlink(p) = vlink(tmp_head) ;
4285 alink(vlink(tmp_head)) = p ;
4287 lua_pushinteger(L, vlink(tmp_head));
4288 lua_nodelib_push(L);
4290 lua_nodelib_push_fast(L, vlink(tmp_head));
4292 lua_pushinteger(L, t);
4293 lua_nodelib_push(L);
4295 lua_nodelib_push_fast(L, t);
4296 lua_pushboolean(L, 1);
4297 flush_node(tmp_head);
4298 return 3;
4301 static int font_tex_direct_ligaturing(lua_State * L)
4303 /* on the stack are two nodes and a direction */
4304 /* hh-ls: we need to deal with prev nodes when a range starts with a ligature */
4305 halfword tmp_head;
4306 halfword h;
4307 halfword t = null;
4308 halfword p ;
4309 if (lua_gettop(L) < 1) {
4310 lua_pushnil(L);
4311 lua_pushboolean(L, 0);
4312 return 2;
4314 h = lua_tointeger(L, 1);
4315 if (lua_gettop(L) > 1) {
4316 t = lua_tointeger(L, 2);
4318 tmp_head = new_node(nesting_node, 1);
4319 p = alink(h);
4320 couple_nodes(tmp_head, h);
4321 tlink(tmp_head) = t;
4322 t = handle_ligaturing(tmp_head, t);
4323 if (p != null) {
4324 vlink(p) = vlink(tmp_head) ;
4326 alink(vlink(tmp_head)) = p ;
4327 lua_pushinteger(L, vlink(tmp_head));
4328 lua_pushinteger(L, t);
4329 lua_pushboolean(L, 1);
4330 flush_node(tmp_head);
4331 return 3;
4334 /* node.kerning */
4336 static int font_tex_kerning(lua_State * L)
4338 /* on the stack are two nodes and a direction */
4340 halfword tmp_head;
4341 halfword h;
4342 halfword t = null;
4343 halfword p ;
4344 if (lua_gettop(L) < 1) {
4345 lua_pushnil(L);
4346 lua_pushboolean(L, 0);
4347 return 2;
4349 h = *check_isnode(L, 1);
4350 if (lua_gettop(L) > 1) {
4351 t = *check_isnode(L, 2);
4353 tmp_head = new_node(nesting_node, 1);
4354 p = alink(h);
4355 couple_nodes(tmp_head, h);
4356 tlink(tmp_head) = t;
4357 t = handle_kerning(tmp_head, t);
4358 if (p != null) {
4359 vlink(p) = vlink(tmp_head) ;
4361 alink(vlink(tmp_head)) = p ;
4363 lua_pushinteger(L, vlink(tmp_head));
4364 lua_nodelib_push(L);
4366 lua_nodelib_push_fast(L, vlink(tmp_head));
4368 lua_pushinteger(L, t);
4369 lua_nodelib_push(L);
4371 lua_nodelib_push_fast(L, t);
4372 lua_pushboolean(L, 1);
4373 flush_node(tmp_head);
4374 return 3;
4377 static int font_tex_direct_kerning(lua_State * L)
4379 /* on the stack are two nodes and a direction */
4381 halfword tmp_head;
4382 halfword h;
4383 halfword t = null;
4384 halfword p ;
4385 if (lua_gettop(L) < 1) {
4386 lua_pushnil(L);
4387 lua_pushboolean(L, 0);
4388 return 2;
4390 h = lua_tointeger(L, 1);
4391 if (lua_gettop(L) > 1) {
4392 t = lua_tointeger(L, 2);
4394 tmp_head = new_node(nesting_node, 1);
4395 p = alink(h);
4396 couple_nodes(tmp_head, h);
4397 tlink(tmp_head) = t;
4398 t = handle_kerning(tmp_head, t);
4399 if (p != null) {
4400 vlink(p) = vlink(tmp_head) ;
4402 alink(vlink(tmp_head)) = p ;
4403 lua_pushinteger(L, vlink(tmp_head));
4404 lua_pushinteger(L, t);
4405 lua_pushboolean(L, 1);
4406 flush_node(tmp_head);
4407 return 3;
4410 /* node.protect_glyphs (returns also boolean because that signals callback) */
4412 static int lua_nodelib_protect_glyphs(lua_State * L)
4414 int t = 0;
4415 halfword head = *check_isnode(L, 1);
4416 while (head != null) {
4417 if (type(head) == glyph_node) {
4418 int s = subtype(head);
4419 if (s <= 256) {
4420 t = 1;
4421 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4424 head = vlink(head);
4426 lua_pushboolean(L, t);
4427 lua_pushvalue(L, 1);
4428 return 2;
4431 static int lua_nodelib_protect_glyph(lua_State * L)
4433 halfword n = *check_isnode(L, 1);
4434 if (type(n) == glyph_node) {
4435 int s = subtype(n);
4436 if (s <= 256) {
4437 subtype(n) = (quarterword) (s == 1 ? 256 : 256 + s);
4440 return 0;
4443 /* node.direct.protect_glyphs */
4445 static int lua_nodelib_direct_protect_glyphs(lua_State * L)
4447 int t = 0;
4448 halfword head = (halfword) lua_tointeger(L,1);
4449 while (head != null) {
4450 if (type(head) == glyph_node) {
4451 int s = subtype(head);
4452 if (s <= 256) {
4453 t = 1;
4454 subtype(head) = (quarterword) (s == 1 ? 256 : 256 + s);
4457 head = vlink(head);
4459 lua_pushboolean(L, t);
4460 lua_pushvalue(L, 1);
4461 return 2;
4464 static int lua_nodelib_direct_protect_glyph(lua_State * L)
4466 halfword n = (halfword) lua_tointeger(L,1);
4467 if ((n != null) && (type(n) == glyph_node)) {
4468 int s = subtype(n);
4469 if (s <= 256) {
4470 subtype(n) = (quarterword) (s == 1 ? 256 : 256 + s);
4473 return 0;
4476 /* node.unprotect_glyphs (returns also boolean because that signals callback) */
4478 static int lua_nodelib_unprotect_glyphs(lua_State * L)
4480 int t = 0;
4481 halfword head = *(check_isnode(L, 1));
4482 while (head != null) {
4483 if (type(head) == glyph_node) {
4484 int s = subtype(head);
4485 if (s > 256) {
4486 t = 1;
4487 subtype(head) = (quarterword) (s - 256);
4490 head = vlink(head);
4492 lua_pushboolean(L, t);
4493 lua_pushvalue(L, 1);
4494 return 2;
4497 /* node.direct.unprotect_glyphs */
4499 static int lua_nodelib_direct_unprotect_glyphs(lua_State * L)
4501 int t = 0;
4502 halfword head = (halfword) lua_tointeger(L,1);
4503 while (head != null) {
4504 if (type(head) == glyph_node) {
4505 int s = subtype(head);
4506 if (s > 256) {
4507 t = 1;
4508 subtype(head) = (quarterword) (s - 256);
4511 head = vlink(head);
4513 lua_pushboolean(L, t);
4514 lua_pushvalue(L, 1);
4515 return 2;
4518 /* node.first_glyph */
4520 static int lua_nodelib_first_glyph(lua_State * L)
4522 /* on the stack are two nodes and a direction */
4523 halfword h, savetail = null, t = null;
4524 if (lua_gettop(L) < 1) {
4525 lua_pushnil(L);
4526 lua_pushboolean(L, 0);
4527 return 2;
4529 h = *(check_isnode(L, 1));
4530 if (lua_gettop(L) > 1) {
4531 t = *(check_isnode(L, 2));
4532 savetail = vlink(t);
4533 vlink(t) = null;
4535 while (h != null && (type(h) != glyph_node || !is_simple_character(h))) {
4536 h = vlink(h);
4538 if (savetail != null) {
4539 vlink(t) = savetail;
4541 lua_pushinteger(L, h);
4542 lua_nodelib_push(L);
4543 lua_pushboolean(L, (h == null ? 0 : 1));
4544 return 2;
4547 /* node.direct.first_glyph */
4549 static int lua_nodelib_direct_first_glyph(lua_State * L)
4551 halfword h,savetail,t;
4552 savetail = null;
4553 t = null;
4554 h = (halfword) lua_tointeger(L,1);
4555 if (h == null) {
4556 lua_pushnil(L);
4557 return 1;
4559 t = (halfword) lua_tointeger(L,2);
4560 if (t != null) {
4561 savetail = vlink(t);
4562 vlink(t) = null;
4564 while (h != null && (type(h) != glyph_node || !is_simple_character(h)))
4565 h = vlink(h);
4566 if (savetail != null)
4567 vlink(t) = savetail;
4568 lua_pushinteger(L, h);
4569 return 1; /* no need to also push a boolean if we have nil */
4572 /* new, fast and dumb ones: only signals that something needs to be processed */
4574 /* #define do_has_glyph(h) do { \ */
4575 /* while (h != null) { \ */
4576 /* if (type(h) == glyph_node) { \ */
4577 /* return h; \ */
4578 /* } else { \ */
4579 /* h = vlink(h); \ */
4580 /* } \ */
4581 /* } \ */
4582 /* return null; \ */
4583 /* } while (0) */
4585 /* node.has_glyph */
4587 static int lua_nodelib_has_glyph(lua_State * L)
4589 halfword *a;
4590 halfword h = (halfword) *(check_isnode(L,1)) ;
4591 while (h != null) {
4592 if ( (type(h) == glyph_node) || (type(h) == disc_node)) {
4593 fast_metatable(h);
4594 return 1;
4595 } else {
4596 h = vlink(h);
4599 lua_pushnil(L);
4600 return 1;
4603 /* node.direct.has_glyph */
4605 static int lua_nodelib_direct_has_glyph(lua_State * L)
4607 halfword h = (halfword) lua_tointeger(L,1) ;
4608 while (h != null) {
4609 if ((type(h) == glyph_node) || (type(h) == disc_node)) {
4610 nodelib_pushdirect(h);
4611 return 1;
4612 } else {
4613 h = vlink(h);
4616 lua_pushnil(L);
4617 return 1;
4620 /* this is too simplistic, but it helps Hans to get going */
4622 static halfword do_ligature_n(halfword prev, halfword stop, halfword lig)
4624 vlink(lig) = vlink(stop);
4625 vlink(stop) = null;
4626 lig_ptr(lig) = vlink(prev);
4627 vlink(prev) = lig;
4628 return lig;
4631 /* node.do_ligature_n(node prev, node last, node lig) */
4633 static int lua_nodelib_do_ligature_n(lua_State * L)
4635 halfword p;
4636 halfword n = *check_isnode(L, 1);
4637 halfword m = *check_isnode(L, 2);
4638 halfword o = *check_isnode(L, 3);
4639 if (alink(n) == null || vlink(alink(n)) != n) {
4640 halfword tmp_head = new_node(temp_node, 0);
4641 couple_nodes(tmp_head, n);
4642 p = do_ligature_n(tmp_head, m, o);
4643 flush_node(tmp_head);
4644 } else {
4645 p = do_ligature_n(alink(n), m, o);
4647 lua_pushinteger(L, p);
4648 lua_nodelib_push(L);
4649 return 1;
4652 /* node.direct.do_ligature_n(node prev, node last, node lig) */
4654 static int lua_nodelib_direct_do_ligature_n(lua_State * L)
4656 halfword p;
4657 halfword n = (halfword) lua_tointeger(L, 1);
4658 halfword m = (halfword) lua_tointeger(L, 2);
4659 halfword o = (halfword) lua_tointeger(L, 3);
4660 if ((n == null) || (m == null) || (o == null)) {
4661 lua_pushnil(L);
4662 } else {
4663 if (alink(n) == null || vlink(alink(n)) != n) {
4664 halfword tmp_head = new_node(temp_node, 0);
4665 couple_nodes(tmp_head, n);
4666 p = do_ligature_n(tmp_head, m, o);
4667 flush_node(tmp_head);
4668 } else {
4669 p = do_ligature_n(alink(n), m, o);
4671 lua_pushinteger(L, p);
4673 return 1;
4676 /* node.usedlist */
4678 static int lua_nodelib_usedlist(lua_State * L)
4680 lua_pushinteger(L, list_node_mem_usage());
4681 lua_nodelib_push(L);
4682 return 1;
4685 /* node.direct.usedlist */
4687 static int lua_nodelib_direct_usedlist(lua_State * L)
4689 lua_pushinteger(L, list_node_mem_usage());
4690 return 1;
4693 /* node.protrusion_skipable(node m) */
4695 static int lua_nodelib_cp_skipable(lua_State * L)
4697 halfword n = *check_isnode(L, 1);
4698 lua_pushboolean(L, cp_skipable(n));
4699 return 1;
4702 /* node.direct.protrusion_skipable(node m) */
4704 static int lua_nodelib_direct_cp_skipable(lua_State * L)
4706 halfword n = lua_tointeger(L, 1);
4707 if (n == null) {
4708 lua_pushnil(L);
4709 } else {
4710 lua_pushboolean(L, cp_skipable(n));
4712 return 1;
4716 /* node.currentattr(node m) */
4718 static int lua_nodelib_currentattr(lua_State * L)
4720 int u = lua_gettop(L);
4721 if (u == null) {
4722 /* query */
4723 halfword n ;
4724 /* current_attribute_list() return attr_list_cache */
4725 /* or null (attr_list_cache can also be null) */
4726 n = current_attribute_list();
4727 if (n) {
4728 lua_pushinteger(L, n);
4729 lua_nodelib_push(L);
4731 else
4732 lua_pushnil(L);
4733 return 1;
4734 } else {
4735 /* assign */
4736 normal_warning("node lib","assignment via node.current_attr(<list>) is not supported (yet)");
4737 return 0;
4742 /* node.direct.currentattr(node m) */
4744 static int lua_nodelib_direct_currentattr(lua_State * L)
4746 /* current_attribute_list() return attr_list_cache */
4747 /* or null (attr_list_cache can also be null) */
4748 halfword n = current_attribute_list();
4749 if (n)
4750 lua_pushinteger(L, n);
4751 else
4752 lua_pushnil(L);
4753 return 1;
4757 /* node.direct.todirect */
4759 static int lua_nodelib_direct_todirect(lua_State * L)
4761 if (lua_type(L,1) != LUA_TNUMBER) {
4762 /* assume node, no further testing, used in known situations */
4763 void *n ;
4764 n = lua_touserdata(L, 1);
4765 if (n == null) {
4766 lua_pushnil(L);
4767 } else {
4768 lua_pushinteger(L, *((halfword *)n) );
4770 } /* else assume direct and returns argument */
4771 return 1;
4775 /* node.direct.tonode */
4777 static int lua_nodelib_direct_tonode(lua_State * L)
4779 halfword *a;
4780 halfword n = lua_tointeger(L, 1);
4781 if (n != null) {
4782 a = (halfword *) lua_newuserdata(L, sizeof(halfword));
4783 *a=n;
4784 lua_push_node_metatablelua;
4785 lua_setmetatable(L,-2);
4786 } /* else assume node and return argument */
4787 return 1;
4790 /* node.setfield */
4792 /* ls-hh: normally a value will not be reassigned */
4794 #define cleanup_late_lua(n) do { \
4795 if (late_lua_data(n) != 0) { \
4796 if (late_lua_type(n) == normal) { \
4797 delete_token_ref(late_lua_data(n)); \
4798 } else if (late_lua_type(n) == lua_refid_literal) { \
4799 luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \
4802 } while (0)
4804 #define cleanup_late_lua_name(n) do { \
4805 if (late_lua_name(n) != 0) { \
4806 delete_token_ref(late_lua_name(n)); \
4808 } while (0)
4810 static int lua_nodelib_setfield_whatsit(lua_State * L, int n, const char *s)
4812 int t = subtype(n);
4814 if (t == pdf_literal_node) {
4815 if (lua_key_eq(s, mode)) {
4816 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
4817 } else if (lua_key_eq(s, data)) {
4818 if (ini_version) {
4819 pdf_literal_data(n) = nodelib_gettoks(L, 3);
4820 } else {
4821 lua_pushvalue(L, 3);
4822 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4823 pdf_literal_type(n) = lua_refid_literal;
4825 } else {
4826 return nodelib_cantset(L, n, s);
4828 } else if (t == late_lua_node) {
4829 if (lua_key_eq(s, string)) {
4830 cleanup_late_lua(n) ; /* ls-hh */
4831 if (ini_version) {
4832 late_lua_data(n) = nodelib_gettoks(L, 3);
4833 late_lua_type(n) = normal;
4834 } else {
4835 lua_pushvalue(L, 3);
4836 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4837 late_lua_type(n) = lua_refid_literal;
4839 } else if (lua_key_eq(s, data)) {
4840 cleanup_late_lua(n) ; /* ls-hh */
4841 late_lua_data(n) = nodelib_gettoks(L, 3);
4842 late_lua_type(n) = normal;
4843 } else if (lua_key_eq(s, name)) {
4844 cleanup_late_lua_name(n) ; /* ls-hh */
4845 late_lua_name(n) = nodelib_gettoks(L, 3);
4846 } else {
4847 return nodelib_cantset(L, n, s);
4849 /* done */
4850 } else if (t == user_defined_node) {
4851 if (lua_key_eq(s, user_id)) {
4852 user_node_id(n) = (halfword) lua_tointeger(L, 3);
4853 } else if (lua_key_eq(s, type)) {
4854 user_node_type(n) = (halfword) lua_tointeger(L, 3);
4855 } else if (lua_key_eq(s, value)) {
4856 switch (user_node_type(n)) {
4857 case 'a':
4858 user_node_value(n) = nodelib_getlist(L, 3);
4859 break;
4860 case 'd':
4861 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4862 break;
4863 case 'l':
4864 lua_pushvalue(L, 3);
4865 if (user_node_value(n) != 0) {
4866 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
4868 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
4869 break;
4870 case 'n':
4871 user_node_value(n) = nodelib_getlist(L, 3);
4872 break;
4873 case 's':
4874 user_node_value(n) = nodelib_getstring(L, 3);
4875 break;
4876 case 't':
4877 user_node_value(n) = nodelib_gettoks(L, 3);
4878 break;
4879 default:
4880 user_node_value(n) = (halfword) lua_tointeger(L, 3);
4881 break;
4883 } else {
4884 return nodelib_cantset(L, n, s);
4886 } else if (t == pdf_annot_node) {
4887 if (lua_key_eq(s, width)) {
4888 width(n) = (halfword) lua_tointeger(L, 3);
4889 } else if (lua_key_eq(s, depth)) {
4890 depth(n) = (halfword) lua_tointeger(L, 3);
4891 } else if (lua_key_eq(s, height)) {
4892 height(n) = (halfword) lua_tointeger(L, 3);
4893 } else if (lua_key_eq(s, objnum)) {
4894 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
4895 } else if (lua_key_eq(s, data)) {
4896 pdf_annot_data(n) = nodelib_gettoks(L, 3);
4897 } else {
4898 return nodelib_cantset(L, n, s);
4900 } else if (t == pdf_dest_node) {
4901 if (lua_key_eq(s, width)) {
4902 width(n) = (halfword) lua_tointeger(L, 3);
4903 } else if (lua_key_eq(s, depth)) {
4904 depth(n) = (halfword) lua_tointeger(L, 3);
4905 } else if (lua_key_eq(s, height)) {
4906 height(n) = (halfword) lua_tointeger(L, 3);
4907 } else if (lua_key_eq(s, named_id)) {
4908 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
4909 } else if (lua_key_eq(s, dest_id)) {
4910 if (pdf_dest_named_id(n) == 1) {
4911 pdf_dest_id(n) = nodelib_gettoks(L, 3);
4912 } else {
4913 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
4915 } else if (lua_key_eq(s, dest_type)) {
4916 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
4917 } else if (lua_key_eq(s, xyz_zoom)) {
4918 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
4919 } else if (lua_key_eq(s, objnum)) {
4920 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
4921 } else {
4922 return nodelib_cantset(L, n, s);
4924 } else if (t == pdf_setmatrix_node) {
4925 if (lua_key_eq(s, data)) {
4926 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
4927 } else {
4928 return nodelib_cantset(L, n, s);
4930 } else if (t == pdf_refobj_node) {
4931 if (lua_key_eq(s, objnum)) {
4932 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
4933 } else {
4934 return nodelib_cantset(L, n, s);
4936 } else if (t == pdf_start_link_node) {
4937 if (lua_key_eq(s, width)) {
4938 width(n) = (halfword) lua_tointeger(L, 3);
4939 } else if (lua_key_eq(s, depth)) {
4940 depth(n) = (halfword) lua_tointeger(L, 3);
4941 } else if (lua_key_eq(s, height)) {
4942 height(n) = (halfword) lua_tointeger(L, 3);
4943 } else if (lua_key_eq(s, objnum)) {
4944 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
4945 } else if (lua_key_eq(s, link_attr)) {
4946 pdf_link_attr(n) = nodelib_gettoks(L, 3);
4947 } else if (lua_key_eq(s, action)) {
4948 pdf_link_action(n) = nodelib_getaction(L, 3);
4949 } else {
4950 return nodelib_cantset(L, n, s);
4952 } else if (t == write_node) {
4953 if (lua_key_eq(s, stream)) {
4954 write_stream(n) = (halfword) lua_tointeger(L, 3);
4955 } else if (lua_key_eq(s, data)) {
4956 write_tokens(n) = nodelib_gettoks(L, 3);
4957 } else {
4958 return nodelib_cantset(L, n, s);
4960 } else if (t == pdf_colorstack_node) {
4961 if (lua_key_eq(s, stack)) {
4962 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
4963 } else if (lua_key_eq(s, command)) {
4964 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
4965 } else if (lua_key_eq(s, data)) {
4966 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
4967 } else {
4968 return nodelib_cantset(L, n, s);
4970 } else if (t == pdf_action_node) {
4971 if (lua_key_eq(s, action_type)) {
4972 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
4973 } else if (lua_key_eq(s, named_id)) {
4974 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
4975 } else if (lua_key_eq(s, action_id)) {
4976 if (pdf_action_named_id(n) == 1) {
4977 pdf_action_id(n) = nodelib_gettoks(L, 3);
4978 } else {
4979 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
4981 } else if (lua_key_eq(s, file)) {
4982 pdf_action_file(n) = nodelib_gettoks(L, 3);
4983 } else if (lua_key_eq(s, new_window)) {
4984 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
4985 } else if (lua_key_eq(s, data)) {
4986 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
4987 /* } else if (lua_key_eq(s, ref_count)) {
4988 pdf_action_refcount(n) = (halfword) lua_tointeger(L, 3); */
4989 } else {
4990 return nodelib_cantset(L, n, s);
4992 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
4993 if (lua_key_eq(s, width)) {
4994 width(n) = (halfword) lua_tointeger(L, 3);
4995 } else if (lua_key_eq(s, depth)) {
4996 depth(n) = (halfword) lua_tointeger(L, 3);
4997 } else if (lua_key_eq(s, height)) {
4998 height(n) = (halfword) lua_tointeger(L, 3);
4999 } else if (lua_key_eq(s, named_id)) {
5000 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
5001 } else if (lua_key_eq(s, thread_id)) {
5002 if (pdf_thread_named_id(n) == 1) {
5003 pdf_thread_id(n) = nodelib_gettoks(L, 3);
5004 } else {
5005 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
5007 } else if (lua_key_eq(s, thread_attr)) {
5008 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
5009 } else {
5010 return nodelib_cantset(L, n, s);
5012 } else if (t == special_node) {
5013 if (lua_key_eq(s, data)) {
5014 write_tokens(n) = nodelib_gettoks(L, 3);
5015 } else {
5016 return nodelib_cantset(L, n, s);
5018 } else if (t == open_node) {
5019 if (lua_key_eq(s, stream)) {
5020 write_stream(n) = (halfword) lua_tointeger(L, 3);
5021 } else if (lua_key_eq(s, name)) {
5022 open_name(n) = nodelib_getstring(L, 3);
5023 } else if (lua_key_eq(s, area)) {
5024 open_area(n) = nodelib_getstring(L, 3);
5025 } else if (lua_key_eq(s, ext)) {
5026 open_ext(n) = nodelib_getstring(L, 3);
5027 } else {
5028 return nodelib_cantset(L, n, s);
5030 } else if (t == close_node) {
5031 if (lua_key_eq(s, stream)) {
5032 write_stream(n) = (halfword) lua_tointeger(L, 3);
5033 } else {
5034 return nodelib_cantset(L, n, s);
5036 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
5037 (t == pdf_save_node) || (t == pdf_restore_node)) {
5038 return nodelib_cantset(L, n, s);
5039 } else {
5040 /* do nothing */
5042 return 0;
5045 static int lua_nodelib_fast_setfield(lua_State * L)
5047 halfword g, v;
5048 const char *s;
5049 halfword n = *((halfword *) lua_touserdata(L, 1));
5050 int t = type(n);
5052 if (lua_type(L, 2) == LUA_TNUMBER) {
5053 if (lua_gettop(L) == 3) {
5054 int i = lua_tointeger(L, 2);
5055 int val = lua_tointeger(L, 3);
5056 if (val == UNUSED_ATTRIBUTE) {
5057 (void) unset_attribute(n, i, val);
5058 } else {
5059 set_attribute(n, i, val);
5061 } else {
5062 luaL_error(L, "incorrect number of arguments");
5064 return 0;
5067 s = lua_tostring(L, 2);
5069 /*if (lua_key_eq(s, id)) {
5070 type(n) = (quarteword) lua_tointeger(L, 3);
5071 }* else */
5072 if (lua_key_eq(s, next)) {
5073 halfword x = nodelib_getlist(L, 3);
5074 if (x>0 && type(x) == glue_spec_node) {
5075 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
5077 vlink(n) = x;
5078 } else if (lua_key_eq(s, prev)) {
5079 halfword x = nodelib_getlist(L, 3);
5080 if (x>0 && type(x) == glue_spec_node) {
5081 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
5083 alink(n) = x;
5084 } else if (lua_key_eq(s, attr)) {
5085 if (nodetype_has_attributes(type(n))) {
5086 nodelib_setattr(L, 3, n);
5088 } else if (t == glyph_node) {
5089 if (lua_key_eq(s, subtype)) {
5090 subtype(n) = (quarterword) lua_tointeger(L, 3);
5091 } else if (lua_key_eq(s, font)) {
5092 font(n) = (halfword) lua_tointeger(L, 3);
5093 } else if (lua_key_eq(s, char)) {
5094 character(n) = (halfword) lua_tointeger(L, 3);
5095 } else if (lua_key_eq(s, xoffset)) {
5096 x_displace(n) = (halfword) lua_tointeger(L, 3);
5097 } else if (lua_key_eq(s, yoffset)) {
5098 y_displace(n) = (halfword) lua_tointeger(L, 3);
5099 } else if (lua_key_eq(s, width)) {
5100 /* not yet */
5101 } else if (lua_key_eq(s, height)) {
5102 /* not yet */
5103 } else if (lua_key_eq(s, depth)) {
5104 /* not yet */
5105 } else if (lua_key_eq(s, expansion_factor)) {
5106 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
5107 } else if (lua_key_eq(s, components)) {
5108 lig_ptr(n) = nodelib_getlist(L, 3);
5109 } else if (lua_key_eq(s, lang)) {
5110 set_char_lang(n, (halfword) lua_tointeger(L, 3));
5111 } else if (lua_key_eq(s, left)) {
5112 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
5113 } else if (lua_key_eq(s, right)) {
5114 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
5115 } else if (lua_key_eq(s, uchyph)) {
5116 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
5117 } else {
5118 return nodelib_cantset(L, n, s);
5120 } else if ((t == hlist_node) || (t == vlist_node)) {
5121 if (lua_key_eq(s, subtype)) {
5122 subtype(n) = (quarterword) lua_tointeger(L, 3);
5123 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
5124 list_ptr(n) = nodelib_getlist(L, 3);
5125 } else if (lua_key_eq(s, width)) {
5126 width(n) = (halfword) lua_tointeger(L, 3);
5127 } else if (lua_key_eq(s, height)) {
5128 height(n) = (halfword) lua_tointeger(L, 3);
5129 } else if (lua_key_eq(s, depth)) {
5130 depth(n) = (halfword) lua_tointeger(L, 3);
5131 } else if (lua_key_eq(s, dir)) {
5132 box_dir(n) = nodelib_getdir(L, 3, 1);
5133 } else if (lua_key_eq(s, shift)) {
5134 shift_amount(n) = (halfword) lua_tointeger(L, 3);
5135 } else if (lua_key_eq(s, glue_order)) {
5136 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5137 } else if (lua_key_eq(s, glue_sign)) {
5138 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5139 } else if (lua_key_eq(s, glue_set)) {
5140 glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
5141 } else {
5142 return nodelib_cantset(L, n, s);
5144 } else if (t == disc_node) {
5145 if (lua_key_eq(s, subtype)) {
5146 subtype(n) = (quarterword) lua_tointeger(L, 3);
5147 } else if (lua_key_eq(s, pre)) {
5148 set_disc_field(pre_break(n), nodelib_getlist(L, 3));
5149 } else if (lua_key_eq(s, post)) {
5150 set_disc_field(post_break(n), nodelib_getlist(L, 3));
5151 } else if (lua_key_eq(s, replace)) {
5152 set_disc_field(no_break(n), nodelib_getlist(L, 3));
5153 } else {
5154 return nodelib_cantset(L, n, s);
5156 } else if (t == glue_node) {
5157 if (lua_key_eq(s, subtype)) {
5158 subtype(n) = (quarterword) lua_tointeger(L, 3);
5159 } else if (lua_key_eq(s, spec)) {
5160 glue_ptr(n) = nodelib_getspec(L, 3);
5161 } else if (lua_key_eq(s, leader)) {
5162 leader_ptr(n) = nodelib_getlist(L, 3);
5163 } else if (lua_key_eq(s, width)) {
5164 nodelib_check_glue_spec(n, g, width);
5165 } else if (lua_key_eq(s, stretch)) {
5166 nodelib_check_glue_spec(n, g, stretch);
5167 } else if (lua_key_eq(s, shrink)) {
5168 nodelib_check_glue_spec(n, g, shrink);
5169 } else if (lua_key_eq(s, stretch_order)) {
5170 nodelib_check_glue_spec(n, g, stretch_order);
5171 } else if (lua_key_eq(s, shrink_order)) {
5172 nodelib_check_glue_spec(n, g, shrink_order);
5173 } else {
5174 return nodelib_cantset(L, n, s);
5176 } else if (t == glue_spec_node) {
5177 if (!valid_node(n)) {
5178 return nodelib_nonwritable(L, n, s);
5179 } else if (lua_key_eq(s, subtype)) {
5180 subtype(n) = (quarterword) lua_tointeger(L, 3); /* dummy, the only one that prevents move up */
5181 } else if (lua_key_eq(s, width)) {
5182 width(n) = (halfword) lua_tointeger(L, 3);
5183 } else if (lua_key_eq(s, stretch)) {
5184 stretch(n) = (halfword) lua_tointeger(L, 3);
5185 } else if (lua_key_eq(s, shrink)) {
5186 shrink(n) = (halfword) lua_tointeger(L, 3);
5187 } else if (lua_key_eq(s, stretch_order)) {
5188 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
5189 } else if (lua_key_eq(s, shrink_order)) {
5190 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
5191 } else {
5192 return nodelib_cantset(L, n, s);
5194 } else if (t == kern_node) {
5195 if (lua_key_eq(s, subtype)) {
5196 subtype(n) = (quarterword) lua_tointeger(L, 3);
5197 } else if (lua_key_eq(s, kern)) {
5198 width(n) = (halfword) lua_tointeger(L, 3);
5199 } else if (lua_key_eq(s, expansion_factor)) {
5200 ex_kern(n) = (halfword) lua_tointeger(L, 3);
5201 } else {
5202 return nodelib_cantset(L, n, s);
5204 } else if (t == penalty_node) {
5205 if (lua_key_eq(s, subtype)) {
5206 /* dummy subtype */
5207 } else if (lua_key_eq(s, penalty)) {
5208 penalty(n) = (halfword) lua_tointeger(L, 3);
5209 } else {
5210 return nodelib_cantset(L, n, s);
5212 } else if (t == rule_node) {
5213 if (lua_key_eq(s, subtype)) {
5214 subtype(n) = (quarterword) lua_tointeger(L, 3);
5215 } else if (lua_key_eq(s, width)) {
5216 width(n) = (halfword) lua_tointeger(L, 3);
5217 } else if (lua_key_eq(s, height)) {
5218 height(n) = (halfword) lua_tointeger(L, 3);
5219 } else if (lua_key_eq(s, depth)) {
5220 depth(n) = (halfword) lua_tointeger(L, 3);
5221 } else if (lua_key_eq(s, dir)) {
5222 rule_dir(n) = nodelib_getdir(L, 3, 1);
5223 } else if (lua_key_eq(s, index)) {
5224 rule_index(n) = (halfword) lua_tointeger(L, 3);
5225 } else if (lua_key_eq(s, transform)) {
5226 rule_transform(n) = (halfword) lua_tointeger(L, 3);
5227 } else {
5228 return nodelib_cantset(L, n, s);
5230 } else if (t == dir_node) {
5231 if (lua_key_eq(s, dir)) {
5232 dir_dir(n) = nodelib_getdir(L, 3, 0);
5233 } else if (lua_key_eq(s, level)) {
5234 dir_level(n) = (halfword) lua_tointeger(L, 3);
5235 } else if (lua_key_eq(s, dvi_ptr)) {
5236 dir_dvi_ptr(n) = (halfword) lua_tointeger(L, 3);
5237 } else if (lua_key_eq(s, dir_h)) {
5238 dir_dvi_h(n) = (halfword) lua_tointeger(L, 3);
5239 } else {
5240 return nodelib_cantset(L, n, s);
5242 } else if (t == local_par_node) {
5243 if (lua_key_eq(s, pen_inter)) {
5244 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
5245 } else if (lua_key_eq(s, pen_broken)) {
5246 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
5247 } else if (lua_key_eq(s, dir)) {
5248 local_par_dir(n) = nodelib_getdir(L, 3, 1);
5249 } else if (lua_key_eq(s, box_left)) {
5250 local_box_left(n) = nodelib_getlist(L, 3);
5251 } else if (lua_key_eq(s, box_left_width)) {
5252 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
5253 } else if (lua_key_eq(s, box_right)) {
5254 local_box_right(n) = nodelib_getlist(L, 3);
5255 } else if (lua_key_eq(s, box_right_width)) {
5256 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
5257 } else {
5258 return nodelib_cantset(L, n, s);
5260 } else if (t == whatsit_node) {
5261 if (lua_key_eq(s, subtype)) {
5262 subtype(n) = (quarterword) lua_tointeger(L, 3);
5263 } else {
5264 lua_nodelib_setfield_whatsit(L, n, s);
5266 } else if (t == simple_noad) {
5267 if (lua_key_eq(s, subtype)) {
5268 subtype(n) = (quarterword) lua_tointeger(L, 3);
5269 } else if (lua_key_eq(s, nucleus)) {
5270 nucleus(n) = nodelib_getlist(L, 3);
5271 } else if (lua_key_eq(s, sub)) {
5272 subscr(n) = nodelib_getlist(L, 3);
5273 } else if (lua_key_eq(s, sup)) {
5274 supscr(n) = nodelib_getlist(L, 3);
5275 } else {
5276 return nodelib_cantset(L, n, s);
5278 } else if ((t == math_char_node) || (t == math_text_char_node)) {
5279 if (lua_key_eq(s, subtype)) {
5280 subtype(n) = (quarterword) lua_tointeger(L, 3);
5281 } else if (lua_key_eq(s, fam)) {
5282 math_fam(n) = (halfword) lua_tointeger(L, 3);
5283 } else if (lua_key_eq(s, char)) {
5284 math_character(n) = (halfword) lua_tointeger(L, 3);
5285 } else {
5286 return nodelib_cantset(L, n, s);
5288 } else if (t == mark_node) {
5289 if (lua_key_eq(s, subtype)) {
5290 subtype(n) = (quarterword) lua_tointeger(L, 3);
5291 } else if (lua_key_eq(s, class)) {
5292 mark_class(n) = (halfword) lua_tointeger(L, 3);
5293 } else if (lua_key_eq(s, mark)) {
5294 mark_ptr(n) = nodelib_gettoks(L, 3);
5295 } else {
5296 return nodelib_cantset(L, n, s);
5298 } else if (t == ins_node) {
5299 if (lua_key_eq(s, subtype)) {
5300 subtype(n) = (quarterword) lua_tointeger(L, 3);
5301 } else if (lua_key_eq(s, cost)) {
5302 float_cost(n) = (halfword) lua_tointeger(L, 3);
5303 } else if (lua_key_eq(s, depth)) {
5304 depth(n) = (halfword) lua_tointeger(L, 3);
5305 } else if (lua_key_eq(s, height)) {
5306 height(n) = (halfword) lua_tointeger(L, 3);
5307 } else if (lua_key_eq(s, spec)) {
5308 split_top_ptr(n) = nodelib_getspec(L, 3);
5309 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5310 ins_ptr(n) = nodelib_getlist(L, 3);
5311 } else {
5312 return nodelib_cantset(L, n, s);
5314 } else if (t == math_node) {
5315 if (lua_key_eq(s, subtype)) {
5316 subtype(n) = (quarterword) lua_tointeger(L, 3);
5317 } else if (lua_key_eq(s, surround)) {
5318 surround(n) = (halfword) lua_tointeger(L, 3);
5319 } else {
5320 return nodelib_cantset(L, n, s);
5322 } else if (t == fraction_noad) {
5323 if (lua_key_eq(s, subtype)) {
5324 subtype(n) = (quarterword) lua_tointeger(L, 3);
5325 } else if (lua_key_eq(s, width)) {
5326 thickness(n) = (halfword) lua_tointeger(L, 3);
5327 } else if (lua_key_eq(s, num)) {
5328 numerator(n) = nodelib_getlist(L, 3);
5329 } else if (lua_key_eq(s, denom)) {
5330 denominator(n) = nodelib_getlist(L, 3);
5331 } else if (lua_key_eq(s, left)) {
5332 left_delimiter(n) = nodelib_getlist(L, 3);
5333 } else if (lua_key_eq(s, right)) {
5334 right_delimiter(n) = nodelib_getlist(L, 3);
5335 } else {
5336 return nodelib_cantset(L, n, s);
5338 } else if (t == style_node) {
5339 if (lua_key_eq(s, subtype)) {
5340 /* dummy subtype */
5341 } else if (lua_key_eq(s, style)) {
5342 assign_math_style(L,3,subtype(n));
5343 } else {
5344 /* return nodelib_cantset(L, n, s); */
5346 } else if (t == accent_noad) {
5347 if (lua_key_eq(s, subtype)) {
5348 subtype(n) = (quarterword) lua_tointeger(L, 3);
5349 } else if (lua_key_eq(s, nucleus)) {
5350 nucleus(n) = nodelib_getlist(L, 3);
5351 } else if (lua_key_eq(s, sub)) {
5352 subscr(n) = nodelib_getlist(L, 3);
5353 } else if (lua_key_eq(s, sup)) {
5354 supscr(n) = nodelib_getlist(L, 3);
5355 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
5356 top_accent_chr(n) = nodelib_getlist(L, 3);
5357 } else if (lua_key_eq(s, bot_accent)) {
5358 bot_accent_chr(n) = nodelib_getlist(L, 3);
5359 } else if (lua_key_eq(s, overlay_accent)) {
5360 overlay_accent_chr(n) = nodelib_getlist(L, 3);
5361 } else {
5362 return nodelib_cantset(L, n, s);
5364 } else if (t == fence_noad) {
5365 if (lua_key_eq(s, subtype)) {
5366 subtype(n) = (quarterword) lua_tointeger(L, 3);
5367 } else if (lua_key_eq(s, delim)) {
5368 delimiter(n) = nodelib_getlist(L, 3);
5369 } else {
5370 return nodelib_cantset(L, n, s);
5372 } else if (t == delim_node) {
5373 if (lua_key_eq(s, subtype)) {
5374 subtype(n) = (quarterword) lua_tointeger(L, 3);
5375 } else if (lua_key_eq(s, small_fam)) {
5376 small_fam(n) = (halfword) lua_tointeger(L, 3);
5377 } else if (lua_key_eq(s, small_char)) {
5378 small_char(n) = (halfword) lua_tointeger(L, 3);
5379 } else if (lua_key_eq(s, large_fam)) {
5380 large_fam(n) = (halfword) lua_tointeger(L, 3);
5381 } else if (lua_key_eq(s, large_char)) {
5382 large_char(n) = (halfword) lua_tointeger(L, 3);
5383 } else {
5384 return nodelib_cantset(L, n, s);
5386 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
5387 if (lua_key_eq(s, subtype)) {
5388 subtype(n) = (quarterword) lua_tointeger(L, 3);
5389 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5390 math_list(n) = nodelib_getlist(L, 3);
5391 } else {
5392 return nodelib_cantset(L, n, s);
5394 } else if (t == radical_noad) {
5395 if (lua_key_eq(s, subtype)) {
5396 subtype(n) = (quarterword) lua_tointeger(L, 3);
5397 } else if (lua_key_eq(s, nucleus)) {
5398 nucleus(n) = nodelib_getlist(L, 3);
5399 } else if (lua_key_eq(s, sub)) {
5400 subscr(n) = nodelib_getlist(L, 3);
5401 } else if (lua_key_eq(s, sup)) {
5402 supscr(n) = nodelib_getlist(L, 3);
5403 } else if (lua_key_eq(s, left)) {
5404 left_delimiter(n) = nodelib_getlist(L, 3);
5405 } else if (lua_key_eq(s, degree)) {
5406 degree(n) = nodelib_getlist(L, 3);
5407 } else {
5408 return nodelib_cantset(L, n, s);
5410 } else if (t == margin_kern_node) {
5411 if (lua_key_eq(s, subtype)) {
5412 subtype(n) = (quarterword) lua_tointeger(L, 3);
5413 } else if (lua_key_eq(s, width)) {
5414 width(n) = (halfword) lua_tointeger(L, 3);
5415 } else if (lua_key_eq(s, glyph)) {
5416 margin_char(n) = nodelib_getlist(L, 3);
5417 } else {
5418 return nodelib_cantset(L, n, s);
5420 } else if (t == split_up_node) {
5421 if (lua_key_eq(s, subtype)) {
5422 subtype(n) = (quarterword) lua_tointeger(L, 3);
5423 } else if (lua_key_eq(s, last_ins_ptr)) {
5424 last_ins_ptr(n) = nodelib_getlist(L, 3);
5425 } else if (lua_key_eq(s, best_ins_ptr)) {
5426 best_ins_ptr(n) = nodelib_getlist(L, 3);
5427 } else if (lua_key_eq(s, broken_ptr)) {
5428 broken_ptr(n) = nodelib_getlist(L, 3);
5429 } else if (lua_key_eq(s, broken_ins)) {
5430 broken_ins(n) = nodelib_getlist(L, 3);
5431 } else {
5432 return nodelib_cantset(L, n, s);
5434 } else if (t == choice_node) {
5435 if (lua_key_eq(s, subtype)) {
5436 subtype(n) = (quarterword) lua_tointeger(L, 3);
5437 } else if (lua_key_eq(s, display)) {
5438 display_mlist(n) = nodelib_getlist(L, 3);
5439 } else if (lua_key_eq(s, text)) {
5440 text_mlist(n) = nodelib_getlist(L, 3);
5441 } else if (lua_key_eq(s, script)) {
5442 script_mlist(n) = nodelib_getlist(L, 3);
5443 } else if (lua_key_eq(s, scriptscript)) {
5444 script_script_mlist(n) = nodelib_getlist(L, 3);
5445 } else {
5446 return nodelib_cantset(L, n, s);
5448 } else if (t == inserting_node) {
5449 if (lua_key_eq(s, subtype)) {
5450 subtype(n) = (quarterword) lua_tointeger(L, 3);
5451 } else if (lua_key_eq(s, last_ins_ptr)) {
5452 last_ins_ptr(n) = nodelib_getlist(L, 3);
5453 } else if (lua_key_eq(s, best_ins_ptr)) {
5454 best_ins_ptr(n) = nodelib_getlist(L, 3);
5455 } else {
5456 return nodelib_cantset(L, n, s);
5458 } else if (t == attribute_node) {
5459 if (lua_key_eq(s, subtype)) {
5460 /* dummy subtype */
5461 } else if (lua_key_eq(s, number)) {
5462 attribute_id(n) = (halfword) lua_tointeger(L, 3);
5463 } else if (lua_key_eq(s, value)) {
5464 attribute_value(n) = (halfword) lua_tointeger(L, 3);
5465 } else {
5466 return nodelib_cantset(L, n, s);
5468 } else if (t == adjust_node) {
5469 if (lua_key_eq(s, subtype)) {
5470 subtype(n) = (quarterword) lua_tointeger(L, 3);
5471 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
5472 adjust_ptr(n) = nodelib_getlist(L, 3);
5473 } else {
5474 return nodelib_cantset(L, n, s);
5476 } else if (t == unset_node) {
5477 if (lua_key_eq(s, subtype)) {
5478 /* dummy subtype */
5479 } else if (lua_key_eq(s, width)) {
5480 width(n) = (halfword) lua_tointeger(L, 3);
5481 } else if (lua_key_eq(s, height)) {
5482 height(n) = (halfword) lua_tointeger(L, 3);
5483 } else if (lua_key_eq(s, depth)) {
5484 depth(n) = (halfword) lua_tointeger(L, 3);
5485 } else if (lua_key_eq(s, dir)) {
5486 box_dir(n) = nodelib_getdir(L, 3, 1);
5487 } else if (lua_key_eq(s, shrink)) {
5488 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
5489 } else if (lua_key_eq(s, glue_order)) {
5490 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5491 } else if (lua_key_eq(s, glue_sign)) {
5492 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5493 } else if (lua_key_eq(s, stretch)) {
5494 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
5495 } else if (lua_key_eq(s, count)) {
5496 span_count(n) = (quarterword) lua_tointeger(L, 3);
5497 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
5498 list_ptr(n) = nodelib_getlist(L, 3);
5499 } else {
5500 return nodelib_cantset(L, n, s);
5502 } else if (t == attribute_list_node) {
5503 if (lua_key_eq(s, subtype)) {
5504 /* dummy subtype */
5505 } else {
5506 return nodelib_cantset(L, n, s);
5508 } else if (t == boundary_node) {
5509 if (lua_key_eq(s, subtype)) {
5510 subtype(n) = (quarterword) lua_tointeger(L, 3);
5511 } else if (lua_key_eq(s, value)) {
5512 boundary_value(n) = lua_tointeger(L, 3);
5513 } else {
5514 return nodelib_cantset(L, n, s);
5516 } else {
5517 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
5519 return 0;
5522 static int lua_nodelib_setfield(lua_State * L)
5524 /* [given-node] [...]*/
5525 halfword *p = lua_touserdata(L, 1);
5526 if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
5527 return 0;
5529 /* [given-node] [mt-given-node]*/
5530 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(luatex_node));
5531 lua_gettable(L, LUA_REGISTRYINDEX);
5532 /* [given-node] [mt-given-node] [mt-node]*/
5533 if ( (!lua_rawequal(L, -1, -2)) ) {
5534 return 0;
5536 /* prune stack and call getfield */
5537 lua_settop(L,3);
5538 return lua_nodelib_fast_setfield(L);
5541 /* node.direct.setfield */
5543 static int lua_nodelib_direct_setfield_whatsit(lua_State * L, int n, const char *s)
5545 int t = subtype(n);
5546 if (t == pdf_literal_node) {
5547 if (lua_key_eq(s, mode)) {
5548 pdf_literal_mode(n) = (quarterword) lua_tointeger(L, 3);
5549 } else if (lua_key_eq(s, data)) {
5550 if (ini_version) {
5551 pdf_literal_data(n) = nodelib_gettoks(L, 3);
5552 } else {
5553 lua_pushvalue(L, 3);
5554 pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5555 pdf_literal_type(n) = lua_refid_literal;
5557 } else {
5558 return nodelib_cantset(L, n, s);
5560 } else if (t == late_lua_node) {
5561 if (lua_key_eq(s, string)) {
5562 cleanup_late_lua(n) ; /* ls-hh */
5563 if (ini_version) {
5564 late_lua_data(n) = nodelib_gettoks(L, 3);
5565 late_lua_type(n) = normal;
5566 } else {
5567 lua_pushvalue(L, 3);
5568 late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5569 late_lua_type(n) = lua_refid_literal;
5571 } else if (lua_key_eq(s, data)) {
5572 cleanup_late_lua(n) ; /* ls-hh */
5573 late_lua_data(n) = nodelib_gettoks(L, 3);
5574 late_lua_type(n) = normal;
5575 } else if (lua_key_eq(s, name)) {
5576 cleanup_late_lua_name(n) ; /* ls-hh */
5577 late_lua_name(n) = nodelib_gettoks(L, 3);
5578 } else {
5579 return nodelib_cantset(L, n, s);
5581 } else if (t == user_defined_node) {
5582 if (lua_key_eq(s, user_id)) {
5583 user_node_id(n) = (halfword) lua_tointeger(L, 3);
5584 } else if (lua_key_eq(s, type)) {
5585 user_node_type(n) = (halfword) lua_tointeger(L, 3);
5586 } else if (lua_key_eq(s, value)) {
5587 switch (user_node_type(n)) {
5588 case 'a':
5589 user_node_value(n) = nodelib_getlist(L, 3);
5590 break;
5591 case 'd':
5592 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5593 break;
5594 case 'l':
5595 lua_pushvalue(L, 3);
5596 if (user_node_value(n) != 0) {
5597 luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n));
5599 user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX);
5600 break;
5601 case 'n':
5602 user_node_value(n) = nodelib_getlist(L, 3);
5603 break;
5604 case 's':
5605 user_node_value(n) = nodelib_getstring(L, 3);
5606 break;
5607 case 't':
5608 user_node_value(n) = nodelib_gettoks(L, 3);
5609 break;
5610 default:
5611 user_node_value(n) = (halfword) lua_tointeger(L, 3);
5612 break;
5614 } else {
5615 return nodelib_cantset(L, n, s);
5617 } else if (t == pdf_annot_node) {
5618 if (lua_key_eq(s, width)) {
5619 width(n) = (halfword) lua_tointeger(L, 3);
5620 } else if (lua_key_eq(s, depth)) {
5621 depth(n) = (halfword) lua_tointeger(L, 3);
5622 } else if (lua_key_eq(s, height)) {
5623 height(n) = (halfword) lua_tointeger(L, 3);
5624 } else if (lua_key_eq(s, objnum)) {
5625 pdf_annot_objnum(n) = (halfword) lua_tointeger(L, 3);
5626 } else if (lua_key_eq(s, data)) {
5627 pdf_annot_data(n) = nodelib_gettoks(L, 3);
5628 } else {
5629 return nodelib_cantset(L, n, s);
5631 } else if (t == pdf_dest_node) {
5632 if (lua_key_eq(s, width)) {
5633 width(n) = (halfword) lua_tointeger(L, 3);
5634 } else if (lua_key_eq(s, depth)) {
5635 depth(n) = (halfword) lua_tointeger(L, 3);
5636 } else if (lua_key_eq(s, height)) {
5637 height(n) = (halfword) lua_tointeger(L, 3);
5638 } else if (lua_key_eq(s, named_id)) {
5639 pdf_dest_named_id(n) = (quarterword) lua_tointeger(L, 3);
5640 } else if (lua_key_eq(s, dest_id)) {
5641 if (pdf_dest_named_id(n) == 1) {
5642 pdf_dest_id(n) = nodelib_gettoks(L, 3);
5643 } else {
5644 pdf_dest_id(n) = (halfword) lua_tointeger(L, 3);
5646 } else if (lua_key_eq(s, dest_type)) {
5647 pdf_dest_type(n) = (quarterword) lua_tointeger(L, 3);
5648 } else if (lua_key_eq(s, xyz_zoom)) {
5649 pdf_dest_xyz_zoom(n) = (halfword) lua_tointeger(L, 3);
5650 } else if (lua_key_eq(s, objnum)) {
5651 pdf_dest_objnum(n) = (halfword) lua_tointeger(L, 3);
5652 } else {
5653 return nodelib_cantset(L, n, s);
5655 } else if (t == pdf_setmatrix_node) {
5656 if (lua_key_eq(s, data)) {
5657 pdf_setmatrix_data(n) = nodelib_gettoks(L, 3);
5658 } else {
5659 return nodelib_cantset(L, n, s);
5661 } else if (t == pdf_refobj_node) {
5662 if (lua_key_eq(s, objnum)) {
5663 pdf_obj_objnum(n) = (halfword) lua_tointeger(L, 3);
5664 } else {
5665 return nodelib_cantset(L, n, s);
5667 } else if (t == pdf_start_link_node) {
5668 if (lua_key_eq(s, width)) {
5669 width(n) = (halfword) lua_tointeger(L, 3);
5670 } else if (lua_key_eq(s, depth)) {
5671 depth(n) = (halfword) lua_tointeger(L, 3);
5672 } else if (lua_key_eq(s, height)) {
5673 height(n) = (halfword) lua_tointeger(L, 3);
5674 } else if (lua_key_eq(s, objnum)) {
5675 pdf_link_objnum(n) = (halfword) lua_tointeger(L, 3);
5676 } else if (lua_key_eq(s, link_attr)) {
5677 pdf_link_attr(n) = nodelib_gettoks(L, 3);
5678 } else if (lua_key_eq(s, action)) {
5679 pdf_link_action(n) = nodelib_popdirect(n); /*nodelib_getaction(L, 3);*/
5680 } else {
5681 return nodelib_cantset(L, n, s);
5683 } else if (t == write_node) {
5684 if (lua_key_eq(s, stream)) {
5685 write_stream(n) = (halfword) lua_tointeger(L, 3);
5686 } else if (lua_key_eq(s, data)) {
5687 write_tokens(n) = nodelib_gettoks(L, 3);
5688 } else {
5689 return nodelib_cantset(L, n, s);
5691 } else if (t == pdf_colorstack_node) {
5692 if (lua_key_eq(s, stack)) {
5693 pdf_colorstack_stack(n) = (halfword) lua_tointeger(L, 3);
5694 } else if (lua_key_eq(s, command)) {
5695 pdf_colorstack_cmd(n) = (halfword) lua_tointeger(L, 3);
5696 } else if (lua_key_eq(s, data)) {
5697 pdf_colorstack_data(n) = nodelib_gettoks(L, 3);
5698 } else {
5699 return nodelib_cantset(L, n, s);
5701 } else if (t == pdf_action_node) {
5702 if (lua_key_eq(s, action_type)) {
5703 pdf_action_type(n) = (quarterword) lua_tointeger(L, 3);
5704 } else if (lua_key_eq(s, named_id)) {
5705 pdf_action_named_id(n) = (quarterword) lua_tointeger(L, 3);
5706 } else if (lua_key_eq(s, action_id)) {
5707 if (pdf_action_named_id(n) == 1) {
5708 pdf_action_id(n) = nodelib_gettoks(L, 3);
5709 } else {
5710 pdf_action_id(n) = (halfword) lua_tointeger(L, 3);
5712 } else if (lua_key_eq(s, file)) {
5713 pdf_action_file(n) = nodelib_gettoks(L, 3);
5714 } else if (lua_key_eq(s, new_window)) {
5715 pdf_action_new_window(n) = (halfword) lua_tointeger(L, 3);
5716 } else if (lua_key_eq(s, data)) {
5717 pdf_action_tokens(n) = nodelib_gettoks(L, 3);
5718 /* } else if (lua_key_eq(s, ref_count)) {
5719 pdf_action_refcount(n) = (halfword) lua_tointeger(L, 3); */
5720 } else {
5721 return nodelib_cantset(L, n, s);
5723 } else if ((t == pdf_thread_node) || (t == pdf_start_thread_node)) {
5724 if (lua_key_eq(s, width)) {
5725 width(n) = (halfword) lua_tointeger(L, 3);
5726 } else if (lua_key_eq(s, depth)) {
5727 depth(n) = (halfword) lua_tointeger(L, 3);
5728 } else if (lua_key_eq(s, height)) {
5729 height(n) = (halfword) lua_tointeger(L, 3);
5730 } else if (lua_key_eq(s, named_id)) {
5731 pdf_thread_named_id(n) = (quarterword) lua_tointeger(L, 3);
5732 } else if (lua_key_eq(s, thread_id)) {
5733 if (pdf_thread_named_id(n) == 1) {
5734 pdf_thread_id(n) = nodelib_gettoks(L, 3);
5735 } else {
5736 pdf_thread_id(n) = (halfword) lua_tointeger(L, 3);
5738 } else if (lua_key_eq(s, thread_attr)) {
5739 pdf_thread_attr(n) = nodelib_gettoks(L, 3);
5740 } else {
5741 return nodelib_cantset(L, n, s);
5743 } else if (t == special_node) {
5744 if (lua_key_eq(s, data)) {
5745 write_tokens(n) = nodelib_gettoks(L, 3);
5746 } else {
5747 return nodelib_cantset(L, n, s);
5749 } else if (t == open_node) {
5750 if (lua_key_eq(s, stream)) {
5751 write_stream(n) = (halfword) lua_tointeger(L, 3);
5752 } else if (lua_key_eq(s, name)) {
5753 open_name(n) = nodelib_getstring(L, 3);
5754 } else if (lua_key_eq(s, area)) {
5755 open_area(n) = nodelib_getstring(L, 3);
5756 } else if (lua_key_eq(s, ext)) {
5757 open_ext(n) = nodelib_getstring(L, 3);
5758 } else {
5759 return nodelib_cantset(L, n, s);
5761 } else if (t == close_node) {
5762 if (lua_key_eq(s, stream)) {
5763 write_stream(n) = (halfword) lua_tointeger(L, 3);
5764 } else {
5765 return nodelib_cantset(L, n, s);
5767 } else if ((t == pdf_end_link_node) || (t == pdf_end_thread_node) || (t == save_pos_node) ||
5768 (t == pdf_save_node) || (t == pdf_restore_node)) {
5769 return nodelib_cantset(L, n, s);
5770 } else {
5771 /* do nothing */
5773 return 0;
5776 static int lua_nodelib_direct_setcharacter(lua_State * L)
5778 halfword n = lua_tointeger(L, 1);
5779 if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
5780 if (type(n) == glyph_node) {
5781 character(n) = (halfword) lua_tointeger(L, 2);
5782 } else if ((type(n) == math_char_node) || (type(n) == math_text_char_node)) {
5783 math_character(n) = (halfword) lua_tointeger(L, 2);
5786 return 0;
5789 static int lua_nodelib_direct_setnext(lua_State * L)
5791 halfword n = lua_tointeger(L, 1);
5792 if (n) {
5793 if (lua_type(L, 2) == LUA_TNUMBER) {
5794 vlink(n) = (halfword) lua_tointeger(L, 2);
5795 } else {
5796 vlink(n) = null;
5799 return 0;
5802 static int lua_nodelib_direct_setprev(lua_State * L)
5804 halfword n = lua_tointeger(L, 1);
5805 if (n) {
5806 if (lua_type(L, 2) == LUA_TNUMBER) {
5807 alink(n) = (halfword) lua_tointeger(L, 2);
5808 } else {
5809 alink(n) = null;
5812 return 0;
5815 static int lua_nodelib_direct_setboth(lua_State * L)
5817 halfword n = lua_tointeger(L, 1);
5818 if (n) {
5819 if (lua_type(L, 2) == LUA_TNUMBER) {
5820 alink(n) = (halfword) lua_tointeger(L, 2);
5821 } else {
5822 alink(n) = null;
5824 if (lua_type(L, 3) == LUA_TNUMBER) {
5825 vlink(n) = (halfword) lua_tointeger(L, 3);
5826 } else {
5827 vlink(n) = null;
5830 return 0;
5833 static int lua_nodelib_direct_setlink(lua_State * L)
5835 if (lua_type(L, 1) == LUA_TNUMBER) {
5836 halfword a = lua_tointeger(L, 1);
5837 if (lua_type(L, 2) == LUA_TNUMBER) {
5838 halfword b = lua_tointeger(L, 2);
5839 vlink(a) = b;
5840 alink(b) = a;
5841 } else {
5842 vlink(a) = null;
5844 } else if (lua_type(L, 2) == LUA_TNUMBER) {
5845 halfword b = lua_tointeger(L, 2);
5846 alink(b) = null;
5848 return 0;
5851 static int lua_nodelib_direct_is_char(lua_State * L)
5853 halfword n = lua_tointeger(L, 1);
5854 if ((type(n) == glyph_node) && (subtype(n) < 256)) { /* <= 256 */
5855 if (lua_type(L,2) == LUA_TNUMBER) {
5856 halfword f = lua_tointeger(L, 2);
5857 if (f && f == font(n)) {
5858 lua_pushinteger(L,character(n));
5859 return 1;
5861 } else {
5862 lua_pushinteger(L,character(n));
5863 return 1;
5866 lua_pushboolean(L,0);
5867 return 1;
5870 static int lua_nodelib_direct_setdiscretionary(lua_State * L)
5872 halfword n = lua_tointeger(L, 1);
5873 if (type(n) == disc_node) {
5874 int t = lua_gettop(L) ;
5875 if (t > 1) {
5876 set_disc_field(pre_break(n), lua_tointeger(L,2));
5877 if (t > 2) {
5878 set_disc_field(post_break(n), lua_tointeger(L,3));
5879 if (t > 3) {
5880 set_disc_field(no_break(n), lua_tointeger(L,4));
5881 if (t > 4) {
5882 subtype(n) = (quarterword) lua_tointeger(L,5);
5883 if (t > 5) {
5884 penalty(n) = lua_tointeger(L,6);
5887 } else {
5888 set_disc_field(no_break(n), null);
5890 } else {
5891 set_disc_field(post_break(n), null);
5892 set_disc_field(no_break(n), null);
5894 } else {
5895 set_disc_field(pre_break(n), null);
5896 set_disc_field(post_break(n), null);
5897 set_disc_field(no_break(n), null);
5900 return 0;
5904 static int lua_nodelib_direct_setfield(lua_State * L)
5906 halfword g, v;
5907 const char *s;
5909 halfword n = lua_tointeger(L, 1);
5910 int t = type(n);
5912 if (lua_type(L, 2) == LUA_TNUMBER) {
5913 if (lua_gettop(L) == 3) {
5914 int i = lua_tointeger(L, 2);
5915 int val = lua_tointeger(L, 3);
5916 if (val == UNUSED_ATTRIBUTE) {
5917 (void) unset_attribute(n, i, val);
5918 } else {
5919 set_attribute(n, i, val);
5921 } else {
5922 luaL_error(L, "incorrect number of arguments");
5924 return 0;
5927 s = lua_tostring(L, 2);
5929 /*if (lua_key_eq(s, id)) {
5930 type(n) = (quarteword) lua_tointeger(L, 3);
5931 } else*/
5932 if (lua_key_eq(s, next)) {
5933 halfword x = nodelib_popdirect(3);
5934 if (x>0 && type(x) == glue_spec_node) {
5935 return luaL_error(L, "You can't assign a %s node to a next field\n", node_data[type(x)].name);
5937 vlink(n) = x;
5938 } else if (lua_key_eq(s, prev)) {
5939 halfword x = nodelib_popdirect(3);
5940 if (x>0 && type(x) == glue_spec_node) {
5941 return luaL_error(L, "You can't assign a %s node to a prev field\n", node_data[type(x)].name);
5943 alink(n) = x;
5944 } else if (lua_key_eq(s, attr)) {
5945 if (nodetype_has_attributes(type(n))) {
5946 nodelib_setattr(L, 3, n);
5948 } else if (t == glyph_node) {
5949 if (lua_key_eq(s, subtype)) {
5950 subtype(n) = (quarterword) lua_tointeger(L, 3);
5951 } else if (lua_key_eq(s, font)) {
5952 font(n) = (halfword) lua_tointeger(L, 3);
5953 } else if (lua_key_eq(s, char)) {
5954 character(n) = (halfword) lua_tointeger(L, 3);
5955 } else if (lua_key_eq(s, xoffset)) {
5956 x_displace(n) = (halfword) lua_tointeger(L, 3);
5957 } else if (lua_key_eq(s, yoffset)) {
5958 y_displace(n) = (halfword) lua_tointeger(L, 3);
5959 } else if (lua_key_eq(s, width)) {
5960 /* not yet */
5961 } else if (lua_key_eq(s, height)) {
5962 /* not yet */
5963 } else if (lua_key_eq(s, depth)) {
5964 /* not yet */
5965 } else if (lua_key_eq(s, expansion_factor)) {
5966 ex_glyph(n) = (halfword) lua_tointeger(L, 3);
5967 } else if (lua_key_eq(s, components)) {
5968 lig_ptr(n) = nodelib_popdirect(3);
5969 } else if (lua_key_eq(s, lang)) {
5970 set_char_lang(n, (halfword) lua_tointeger(L, 3));
5971 } else if (lua_key_eq(s, left)) {
5972 set_char_lhmin(n, (halfword) lua_tointeger(L, 3));
5973 } else if (lua_key_eq(s, right)) {
5974 set_char_rhmin(n, (halfword) lua_tointeger(L, 3));
5975 } else if (lua_key_eq(s, uchyph)) {
5976 set_char_uchyph(n, (halfword) lua_tointeger(L, 3));
5977 } else {
5978 return nodelib_cantset(L, n, s);
5980 } else if ((t == hlist_node) || (t == vlist_node)) {
5981 if (lua_key_eq(s, subtype)) {
5982 subtype(n) = (quarterword) lua_tointeger(L, 3);
5983 } else if (lua_key_eq(s, list) || lua_key_eq(s, head)) {
5984 list_ptr(n) = nodelib_popdirect(3);
5985 } else if (lua_key_eq(s, width)) {
5986 width(n) = (halfword) lua_tointeger(L, 3);
5987 } else if (lua_key_eq(s, height)) {
5988 height(n) = (halfword) lua_tointeger(L, 3);
5989 } else if (lua_key_eq(s, depth)) {
5990 depth(n) = (halfword) lua_tointeger(L, 3);
5991 } else if (lua_key_eq(s, dir)) {
5992 box_dir(n) = nodelib_getdir(L, 3, 1);
5993 } else if (lua_key_eq(s, shift)) {
5994 shift_amount(n) = (halfword) lua_tointeger(L, 3);
5995 } else if (lua_key_eq(s, glue_order)) {
5996 glue_order(n) = (quarterword) lua_tointeger(L, 3);
5997 } else if (lua_key_eq(s, glue_sign)) {
5998 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
5999 } else if (lua_key_eq(s, glue_set)) {
6000 glue_set(n) = (glue_ratio) lua_tonumber(L, 3); /* integer or float */
6001 } else {
6002 return nodelib_cantset(L, n, s);
6004 } else if (t == disc_node) {
6005 if (lua_key_eq(s, subtype)) {
6006 subtype(n) = (quarterword) lua_tointeger(L, 3);
6007 } else if (lua_key_eq(s, pre)) {
6008 set_disc_field(pre_break(n), nodelib_popdirect(3));
6009 } else if (lua_key_eq(s, post)) {
6010 set_disc_field(post_break(n), nodelib_popdirect(3));
6011 } else if (lua_key_eq(s, replace)) {
6012 set_disc_field(no_break(n), nodelib_popdirect(3));
6013 } else {
6014 return nodelib_cantset(L, n, s);
6016 } else if (t == glue_node) {
6017 if (lua_key_eq(s, subtype)) {
6018 subtype(n) = (quarterword) lua_tointeger(L, 3);
6019 } else if (lua_key_eq(s, spec)) {
6020 glue_ptr(n) = nodelib_popdirect(3);
6021 } else if (lua_key_eq(s, leader)) {
6022 leader_ptr(n) = nodelib_popdirect(3);
6023 } else if (lua_key_eq(s, width)) {
6024 nodelib_check_glue_spec(n, g, width);
6025 } else if (lua_key_eq(s, stretch)) {
6026 nodelib_check_glue_spec(n, g, stretch);
6027 } else if (lua_key_eq(s, shrink)) {
6028 nodelib_check_glue_spec(n, g, shrink);
6029 } else if (lua_key_eq(s, stretch_order)) {
6030 nodelib_check_glue_spec(n, g, stretch_order);
6031 } else if (lua_key_eq(s, shrink_order)) {
6032 nodelib_check_glue_spec(n, g, shrink_order);
6033 } else {
6034 return nodelib_cantset(L, n, s);
6036 } else if (t == glue_spec_node) {
6037 if (!valid_node(n)) {
6038 return nodelib_nonwritable(L, n, s);
6039 } else if (lua_key_eq(s, subtype)) {
6040 subtype(n) = (quarterword) lua_tointeger(L, 3); /* dummy, the only one that prevents move up */
6041 } else if (lua_key_eq(s, width)) {
6042 width(n) = (halfword) lua_tointeger(L, 3);
6043 } else if (lua_key_eq(s, stretch)) {
6044 stretch(n) = (halfword) lua_tointeger(L, 3);
6045 } else if (lua_key_eq(s, shrink)) {
6046 shrink(n) = (halfword) lua_tointeger(L, 3);
6047 } else if (lua_key_eq(s, stretch_order)) {
6048 stretch_order(n) = (quarterword) lua_tointeger(L, 3);
6049 } else if (lua_key_eq(s, shrink_order)) {
6050 shrink_order(n) = (quarterword) lua_tointeger(L, 3);
6051 } else {
6052 return nodelib_cantset(L, n, s);
6054 } else if (t == kern_node) {
6055 if (lua_key_eq(s, subtype)) {
6056 subtype(n) = (quarterword) lua_tointeger(L, 3);
6057 } else if (lua_key_eq(s, kern)) {
6058 width(n) = (halfword) lua_tointeger(L, 3);
6059 } else if (lua_key_eq(s, expansion_factor)) {
6060 ex_kern(n) = (halfword) lua_tointeger(L, 3);
6061 } else {
6062 return nodelib_cantset(L, n, s);
6064 } else if (t == penalty_node) {
6065 if (lua_key_eq(s, subtype)) {
6066 /* dummy subtype */
6067 } else if (lua_key_eq(s, penalty)) {
6068 penalty(n) = (halfword) lua_tointeger(L, 3);
6069 } else {
6070 return nodelib_cantset(L, n, s);
6072 } else if (t == rule_node) {
6073 if (lua_key_eq(s, subtype)) {
6074 subtype(n) = (quarterword) lua_tointeger(L, 3);
6075 } else if (lua_key_eq(s, width)) {
6076 width(n) = (halfword) lua_tointeger(L, 3);
6077 } else if (lua_key_eq(s, height)) {
6078 height(n) = (halfword) lua_tointeger(L, 3);
6079 } else if (lua_key_eq(s, depth)) {
6080 depth(n) = (halfword) lua_tointeger(L, 3);
6081 } else if (lua_key_eq(s, dir)) {
6082 rule_dir(n) = nodelib_getdir(L, 3, 1);
6083 } else if (lua_key_eq(s, index)) {
6084 rule_index(n) = (halfword) lua_tointeger(L, 3);
6085 } else if (lua_key_eq(s, transform)) {
6086 rule_transform(n) = (halfword) lua_tointeger(L, 3);
6087 } else {
6088 return nodelib_cantset(L, n, s);
6090 } else if (t == dir_node) {
6091 if (lua_key_eq(s, dir)) {
6092 dir_dir(n) = nodelib_getdir(L, 3, 0);
6093 } else if (lua_key_eq(s, level)) {
6094 dir_level(n) = (halfword) lua_tointeger(L, 3);
6095 } else if (lua_key_eq(s, dvi_ptr)) {
6096 dir_dvi_ptr(n) = (halfword) lua_tointeger(L, 3);
6097 } else if (lua_key_eq(s, dir_h)) {
6098 dir_dvi_h(n) = (halfword) lua_tointeger(L, 3);
6099 } else {
6100 return nodelib_cantset(L, n, s);
6102 } else if (t == whatsit_node) {
6103 if (lua_key_eq(s, subtype)) {
6104 subtype(n) = (quarterword) lua_tointeger(L, 3);
6105 } else {
6106 lua_nodelib_direct_setfield_whatsit(L, n, s);
6108 } else if (t == local_par_node) {
6109 if (lua_key_eq(s, pen_inter)) {
6110 local_pen_inter(n) = (halfword) lua_tointeger(L, 3);
6111 } else if (lua_key_eq(s, pen_broken)) {
6112 local_pen_broken(n) = (halfword) lua_tointeger(L, 3);
6113 } else if (lua_key_eq(s, dir)) {
6114 local_par_dir(n) = nodelib_getdir(L, 3, 1);
6115 } else if (lua_key_eq(s, box_left)) {
6116 local_box_left(n) = nodelib_getlist(L, 3);
6117 } else if (lua_key_eq(s, box_left_width)) {
6118 local_box_left_width(n) = (halfword) lua_tointeger(L, 3);
6119 } else if (lua_key_eq(s, box_right)) {
6120 local_box_right(n) = nodelib_getlist(L, 3);
6121 } else if (lua_key_eq(s, box_right_width)) {
6122 local_box_right_width(n) = (halfword) lua_tointeger(L, 3);
6123 } else {
6124 return nodelib_cantset(L, n, s);
6126 } else if (t == simple_noad) {
6127 if (lua_key_eq(s, subtype)) {
6128 subtype(n) = (quarterword) lua_tointeger(L, 3);
6129 } else if (lua_key_eq(s, nucleus)) {
6130 nucleus(n) = nodelib_popdirect(3);
6131 } else if (lua_key_eq(s, sub)) {
6132 subscr(n) = nodelib_popdirect(3);
6133 } else if (lua_key_eq(s, sup)) {
6134 supscr(n) = nodelib_popdirect(3);
6135 } else {
6136 return nodelib_cantset(L, n, s);
6138 } else if ((t == math_char_node) || (t == math_text_char_node)) {
6139 if (lua_key_eq(s, subtype)) {
6140 subtype(n) = (quarterword) lua_tointeger(L, 3);
6141 } else if (lua_key_eq(s, fam)) {
6142 math_fam(n) = (halfword) lua_tointeger(L, 3);
6143 } else if (lua_key_eq(s, char)) {
6144 math_character(n) = (halfword) lua_tointeger(L, 3);
6145 } else {
6146 return nodelib_cantset(L, n, s);
6148 } else if (t == mark_node) {
6149 if (lua_key_eq(s, subtype)) {
6150 subtype(n) = (quarterword) lua_tointeger(L, 3);
6151 } else if (lua_key_eq(s, class)) {
6152 mark_class(n) = (halfword) lua_tointeger(L, 3);
6153 } else if (lua_key_eq(s, mark)) {
6154 mark_ptr(n) = nodelib_gettoks(L, 3);
6155 } else {
6156 return nodelib_cantset(L, n, s);
6158 } else if (t == ins_node) {
6159 if (lua_key_eq(s, subtype)) {
6160 subtype(n) = (quarterword) lua_tointeger(L, 3);
6161 } else if (lua_key_eq(s, cost)) {
6162 float_cost(n) = (halfword) lua_tointeger(L, 3);
6163 } else if (lua_key_eq(s, depth)) {
6164 depth(n) = (halfword) lua_tointeger(L, 3);
6165 } else if (lua_key_eq(s, height)) {
6166 height(n) = (halfword) lua_tointeger(L, 3);
6167 } else if (lua_key_eq(s, spec)) {
6168 split_top_ptr(n) = nodelib_popdirect(3);
6169 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
6170 ins_ptr(n) = nodelib_popdirect(3);
6171 } else {
6172 return nodelib_cantset(L, n, s);
6174 } else if (t == math_node) {
6175 if (lua_key_eq(s, subtype)) {
6176 subtype(n) = (quarterword) lua_tointeger(L, 3);
6177 } else if (lua_key_eq(s, surround)) {
6178 surround(n) = (halfword) lua_tointeger(L, 3);
6179 } else {
6180 return nodelib_cantset(L, n, s);
6182 } else if (t == fraction_noad) {
6183 if (lua_key_eq(s, subtype)) {
6184 subtype(n) = (quarterword) lua_tointeger(L, 3);
6185 } else if (lua_key_eq(s, width)) {
6186 thickness(n) = (halfword) lua_tointeger(L, 3);
6187 } else if (lua_key_eq(s, num)) {
6188 numerator(n) = nodelib_popdirect(3);
6189 } else if (lua_key_eq(s, denom)) {
6190 denominator(n) = nodelib_popdirect(3);
6191 } else if (lua_key_eq(s, left)) {
6192 left_delimiter(n) = nodelib_popdirect(3);
6193 } else if (lua_key_eq(s, right)) {
6194 right_delimiter(n) = nodelib_popdirect(3);
6195 } else {
6196 return nodelib_cantset(L, n, s);
6198 } else if (t == style_node) {
6199 if (lua_key_eq(s, subtype)) {
6200 /* dummy subtype */
6201 } else if (lua_key_eq(s, style)) {
6202 assign_math_style(L,2,subtype(n));
6203 } else {
6204 /* return nodelib_cantset(L, n, s); */
6206 } else if (t == accent_noad) {
6207 if (lua_key_eq(s, subtype)) {
6208 subtype(n) = (quarterword) lua_tointeger(L, 3);
6209 } else if (lua_key_eq(s, nucleus)) {
6210 nucleus(n) = nodelib_popdirect(3);
6211 } else if (lua_key_eq(s, sub)) {
6212 subscr(n) = nodelib_popdirect(3);
6213 } else if (lua_key_eq(s, sup)) {
6214 supscr(n) = nodelib_popdirect(3);
6215 } else if ((lua_key_eq(s, top_accent))||(lua_key_eq(s, accent))) {
6216 top_accent_chr(n) = nodelib_popdirect(3);
6217 } else if (lua_key_eq(s, bot_accent)) {
6218 bot_accent_chr(n) = nodelib_popdirect(3);
6219 } else if (lua_key_eq(s, overlay_accent)) {
6220 overlay_accent_chr(n) = nodelib_popdirect(3);
6221 } else {
6222 return nodelib_cantset(L, n, s);
6224 } else if (t == fence_noad) {
6225 if (lua_key_eq(s, subtype)) {
6226 subtype(n) = (quarterword) lua_tointeger(L, 3);
6227 } else if (lua_key_eq(s, delim)) {
6228 delimiter(n) = nodelib_popdirect(3);
6229 } else {
6230 return nodelib_cantset(L, n, s);
6232 } else if (t == delim_node) {
6233 if (lua_key_eq(s, subtype)) {
6234 subtype(n) = (quarterword) lua_tointeger(L, 3);
6235 } else if (lua_key_eq(s, small_fam)) {
6236 small_fam(n) = (halfword) lua_tointeger(L, 3);
6237 } else if (lua_key_eq(s, small_char)) {
6238 small_char(n) = (halfword) lua_tointeger(L, 3);
6239 } else if (lua_key_eq(s, large_fam)) {
6240 large_fam(n) = (halfword) lua_tointeger(L, 3);
6241 } else if (lua_key_eq(s, large_char)) {
6242 large_char(n) = (halfword) lua_tointeger(L, 3);
6243 } else {
6244 return nodelib_cantset(L, n, s);
6246 } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
6247 if (lua_key_eq(s, subtype)) {
6248 subtype(n) = (quarterword) lua_tointeger(L, 3);
6249 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
6250 math_list(n) = nodelib_popdirect(3);
6251 } else {
6252 return nodelib_cantset(L, n, s);
6254 } else if (t == radical_noad) {
6255 if (lua_key_eq(s, subtype)) {
6256 subtype(n) = (quarterword) lua_tointeger(L, 3);
6257 } else if (lua_key_eq(s, nucleus)) {
6258 nucleus(n) = nodelib_popdirect(3);
6259 } else if (lua_key_eq(s, sub)) {
6260 subscr(n) = nodelib_popdirect(3);
6261 } else if (lua_key_eq(s, sup)) {
6262 supscr(n) = nodelib_popdirect(3);
6263 } else if (lua_key_eq(s, left)) {
6264 left_delimiter(n) = nodelib_popdirect(3);
6265 } else if (lua_key_eq(s, degree)) {
6266 degree(n) = nodelib_popdirect(3);
6267 } else {
6268 return nodelib_cantset(L, n, s);
6270 } else if (t == margin_kern_node) {
6271 if (lua_key_eq(s, subtype)) {
6272 subtype(n) = (quarterword) lua_tointeger(L, 3);
6273 } else if (lua_key_eq(s, width)) {
6274 width(n) = (halfword) lua_tointeger(L, 3);
6275 } else if (lua_key_eq(s, glyph)) {
6276 margin_char(n) = nodelib_popdirect(3);
6277 } else {
6278 return nodelib_cantset(L, n, s);
6280 } else if (t == split_up_node) {
6281 if (lua_key_eq(s, subtype)) {
6282 subtype(n) = (quarterword) lua_tointeger(L, 3);
6283 } else if (lua_key_eq(s, last_ins_ptr)) {
6284 last_ins_ptr(n) = nodelib_popdirect(3);
6285 } else if (lua_key_eq(s, best_ins_ptr)) {
6286 best_ins_ptr(n) = nodelib_popdirect(3);
6287 } else if (lua_key_eq(s, broken_ptr)) {
6288 broken_ptr(n) = nodelib_popdirect(3);
6289 } else if (lua_key_eq(s, broken_ins)) {
6290 broken_ins(n) = nodelib_popdirect(3);
6291 } else {
6292 return nodelib_cantset(L, n, s);
6294 } else if (t == choice_node) {
6295 if (lua_key_eq(s, subtype)) {
6296 subtype(n) = (quarterword) lua_tointeger(L, 3);
6297 } else if (lua_key_eq(s, display)) {
6298 display_mlist(n) = nodelib_popdirect(3);
6299 } else if (lua_key_eq(s, text)) {
6300 text_mlist(n) = nodelib_popdirect(3);
6301 } else if (lua_key_eq(s, script)) {
6302 script_mlist(n) = nodelib_popdirect(3);
6303 } else if (lua_key_eq(s, scriptscript)) {
6304 script_script_mlist(n) = nodelib_popdirect(3);
6305 } else {
6306 return nodelib_cantset(L, n, s);
6308 } else if (t == inserting_node) {
6309 if (lua_key_eq(s, subtype)) {
6310 subtype(n) = (quarterword) lua_tointeger(L, 3);
6311 } else if (lua_key_eq(s, last_ins_ptr)) {
6312 last_ins_ptr(n) = nodelib_popdirect(3);
6313 } else if (lua_key_eq(s, best_ins_ptr)) {
6314 best_ins_ptr(n) = nodelib_popdirect(3);
6315 } else {
6316 return nodelib_cantset(L, n, s);
6318 } else if (t == attribute_node) {
6319 if (lua_key_eq(s, subtype)) {
6320 /* dummy subtype */
6321 } else if (lua_key_eq(s, number)) {
6322 attribute_id(n) = (halfword) lua_tointeger(L, 3);
6323 } else if (lua_key_eq(s, value)) {
6324 attribute_value(n) = (halfword) lua_tointeger(L, 3);
6325 } else {
6326 return nodelib_cantset(L, n, s);
6328 } else if (t == adjust_node) {
6329 if (lua_key_eq(s, subtype)) {
6330 subtype(n) = (quarterword) lua_tointeger(L, 3);
6331 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))) {
6332 adjust_ptr(n) = nodelib_popdirect(3);
6333 } else {
6334 return nodelib_cantset(L, n, s);
6336 } else if (t == unset_node) {
6337 if (lua_key_eq(s, subtype)) {
6338 /* dummy subtype */
6339 } else if (lua_key_eq(s, width)) {
6340 width(n) = (halfword) lua_tointeger(L, 3);
6341 } else if (lua_key_eq(s, height)) {
6342 height(n) = (halfword) lua_tointeger(L, 3);
6343 } else if (lua_key_eq(s, depth)) {
6344 depth(n) = (halfword) lua_tointeger(L, 3);
6345 } else if (lua_key_eq(s, dir)) {
6346 box_dir(n) = nodelib_getdir(L, 3, 1);
6347 } else if (lua_key_eq(s, shrink)) {
6348 glue_shrink(n) = (halfword) lua_tointeger(L, 3);
6349 } else if (lua_key_eq(s, glue_order)) {
6350 glue_order(n) = (quarterword) lua_tointeger(L, 3);
6351 } else if (lua_key_eq(s, glue_sign)) {
6352 glue_sign(n) = (quarterword) lua_tointeger(L, 3);
6353 } else if (lua_key_eq(s, stretch)) {
6354 glue_stretch(n) = (halfword) lua_tointeger(L, 3);
6355 } else if (lua_key_eq(s, count)) {
6356 span_count(n) = (quarterword) lua_tointeger(L, 3);
6357 } else if ((lua_key_eq(s, list)) || (lua_key_eq(s, head))){
6358 list_ptr(n) = nodelib_popdirect(3);
6359 } else {
6360 return nodelib_cantset(L, n, s);
6362 } else if (t == attribute_list_node) {
6363 if (lua_key_eq(s, subtype)) {
6364 /* dummy subtype */
6365 } else {
6366 return nodelib_cantset(L, n, s);
6368 } else if (t == boundary_node) {
6369 if (lua_key_eq(s, subtype)) {
6370 subtype(n) = (quarterword) lua_tointeger(L, 3);
6371 } else if (lua_key_eq(s, value)) {
6372 boundary_value(n) = lua_tointeger(L, 3);
6373 } else {
6374 return nodelib_cantset(L, n, s);
6376 } else {
6377 return luaL_error(L, "You can't assign to this %s node (%d)\n", node_data[t].name, n);
6379 return 0;
6382 /* boxes */
6384 static int direct_get_box_id(lua_State * L, int i)
6386 const char *s;
6387 int cur_cs1, cur_cmd1;
6388 size_t k = 0;
6389 int j = -1;
6390 switch (lua_type(L, i)) {
6391 case LUA_TSTRING:
6392 s = lua_tolstring(L, i, &k);
6393 cur_cs1 = string_lookup(s, k);
6394 cur_cmd1 = eq_type(cur_cs1);
6395 if (cur_cmd1 == char_given_cmd ||
6396 cur_cmd1 == math_given_cmd) {
6397 j = equiv(cur_cs1);
6399 break;
6400 case LUA_TNUMBER:
6401 j = lua_tointeger(L, (i));
6402 break;
6403 default:
6404 luaL_error(L, "argument must be a string or a number");
6405 j = -1; /* not a valid box id */
6407 return j;
6410 /* node.getbox = tex.getbox */
6412 /* node.direct.getbox */
6414 static int lua_nodelib_direct_getbox(lua_State * L)
6416 int t;
6417 int k = direct_get_box_id(L, -1);
6418 direct_check_index_range(k, "getbox");
6419 t = get_tex_box_register(k);
6420 if (t == null) {
6421 lua_pushnil(L);
6422 } else {
6423 lua_pushinteger(L, t);
6425 return 1;
6428 /* node.setbox = tex.setbox */
6429 /* node.setbox */
6431 static int lua_nodelib_direct_setbox(lua_State * L)
6433 int isglobal = 0;
6434 int j, k, err, t;
6435 int save_global_defs ;
6436 int n = lua_gettop(L);
6437 if (n == 3 && (lua_type(L, 1) == LUA_TSTRING)) {
6438 const char *s = lua_tostring(L, 1);
6439 if (lua_key_eq(s, global))
6440 isglobal = 1;
6442 t = lua_type(L, -1);
6443 k = direct_get_box_id(L, -2);
6444 direct_check_index_range(k, "setbox");
6445 if (t == LUA_TBOOLEAN) {
6446 j = lua_toboolean(L, -1);
6447 if (j == 0) {
6448 j = null;
6449 } else {
6450 return 0;
6452 } else if (t == LUA_TNIL) {
6453 j = null;
6454 } else {
6455 j = nodelib_popdirect(-1);
6456 if (j != null && type(j) != hlist_node && type(j) != vlist_node) {
6457 luaL_error(L, "setbox: incompatible node type (%s)\n",get_node_name(type(j), subtype(j)));
6458 return 0;
6462 save_global_defs = int_par(global_defs_code);
6463 if (isglobal) {
6464 int_par(global_defs_code) = 1;
6466 err = set_tex_box_register(k, j);
6467 int_par(global_defs_code) = save_global_defs;
6468 if (err) {
6469 luaL_error(L, "incorrect value");
6471 return 0;
6474 /* node.is_node(n) */
6476 static int lua_nodelib_is_node(lua_State * L)
6478 if (maybe_isnode(L,1) == NULL)
6479 lua_pushboolean(L,0);
6480 else
6481 lua_pushboolean(L,1);
6482 return 1;
6485 /* node.direct.is_direct(n) (handy for mixed usage testing) */
6487 static int lua_nodelib_direct_is_direct(lua_State * L)
6488 { /*
6489 quick and dirty and faster than not node.is_node, this helper
6490 returns false or <direct>
6493 if (lua_type(L,1) == LUA_TNUMBER)
6494 lua_pushboolean(L,1);
6495 else
6496 lua_pushboolean(L,0);
6498 if (lua_type(L,1) != LUA_TNUMBER)
6499 lua_pushboolean(L,0);
6500 /* else return direct */
6501 return 1;
6504 /* node.direct.is_node(n) (handy for mixed usage testing) */
6506 static int lua_nodelib_direct_is_node(lua_State * L)
6507 { /*
6508 quick and dirty, only checks userdata, node.is_node is slower but
6509 more exact, this helper returns false or <node>
6512 halfword *n = lua_touserdata(L, 1);
6513 if (n != NULL) {
6514 lua_pushboolean(L,1);
6515 } else {
6516 lua_pushboolean(L,0);
6519 if (maybe_isnode(L,1) == NULL)
6520 lua_pushboolean(L,0);
6521 /* else assume and return node */
6522 return 1;
6525 /* node.fast.*
6527 static const struct luaL_Reg fast_nodelib_f[] = {
6528 {"getid", lua_nodelib_fast_getid},
6529 {"getsubtype", lua_nodelib_fast_getsubtype},
6530 {"getfont", lua_nodelib_fast_getfont},
6531 {"getchar", lua_nodelib_fast_getcharacter},
6532 {"getnext", lua_nodelib_fast_getnext},
6533 {"getprev", lua_nodelib_fast_getprev},
6534 {"getfield", lua_nodelib_fast_getfield},
6535 {"setfield", lua_nodelib_fast_setfield},
6536 {NULL, NULL}
6541 /* if really needed we can provide this:
6543 static int lua_nodelib_attributes_to_table(lua_State * L)
6544 { halfword n;
6545 register halfword attribute;
6546 if (lua_type(L,1) == LUA_TNUMBER) {
6547 n = lua_tointeger(L,1);
6548 } else {
6549 n = *((halfword *) lua_touserdata(L, 1));
6551 if ((n == null) || (! nodetype_has_attributes(type(n)))) {
6552 lua_pushnil(L);
6553 } else {
6554 attribute = node_attr(n);
6555 if (attribute == null || (attribute == cache_disabled)) {
6556 lua_pushnil(L);
6557 } else {
6558 if (! lua_istable(L,2)) {
6559 lua_newtable(L);
6561 while (attribute != null) {
6562 lua_pushinteger(L,(int)attribute_id(attribute));
6563 lua_pushinteger(L,(int)attribute_value(attribute));
6564 lua_rawset(L,-3);
6565 attribute = vlink(attribute) ;
6569 return 1 ;
6574 /* There is no gain here but let's keep it around:
6576 static int lua_nodelib_attributes_to_properties(lua_State * L)
6577 { halfword n;
6578 register halfword attribute;
6579 if (lua_type(L,1) == LUA_TNUMBER) {
6580 n = lua_tointeger(L,1);
6581 } else {
6582 n = *((halfword *) lua_touserdata(L, 1));
6584 if (n == null) {
6585 lua_pushnil(L);
6586 return 1;
6588 lua_rawgeti(L, LUA_REGISTRYINDEX, luaS_index(node_properties));
6589 lua_gettable(L, LUA_REGISTRYINDEX);
6590 while (n != null) {
6591 lua_rawseti(L, -1, luaS_index(attributes));
6592 lua_newtable(L);
6593 if (! nodetype_has_attributes(type(n))) {
6594 lua_pushnil(L);
6595 } else {
6596 attribute = node_attr(n);
6597 if (attribute == null || (attribute == cache_disabled)) {
6598 lua_pushnil(L);
6599 } else {
6600 while (attribute != null) {
6601 lua_pushinteger(L,(int)attribute_id(attribute));
6602 lua_pushinteger(L,(int)attribute_value(attribute));
6603 lua_rawset(L,-3);
6604 attribute = vlink(attribute) ;
6608 lua_rawset(L,-3);
6609 n = vlink(n);
6611 return 1 ;
6616 /* Beware, enabling and disabling can result in an inconsistent properties table
6617 but it might make sense sometimes. Of course by default we have disabled this
6618 mechanism. And, one can always sweep the table empty. */
6620 static int lua_nodelib_properties_set_mode(lua_State * L) /* hh */
6621 { /* <boolean> */
6622 if (lua_isboolean(L,1)) {
6623 lua_properties_enabled = lua_toboolean(L,1);
6625 if (lua_isboolean(L,2)) {
6626 lua_properties_use_metatable = lua_toboolean(L,2);
6628 return 0;
6631 /* We used to have variants in assigned defaults but they made no sense. */
6633 static int lua_nodelib_properties_flush_table(lua_State * L) /* hh */
6634 { /* <node|direct> <number> */
6635 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6636 lua_gettable(L, LUA_REGISTRYINDEX);
6637 lua_pushnil(L); /* initializes lua_next */
6638 while (lua_next(L,-2) != 0) {
6639 lua_pushvalue(L,-2);
6640 lua_pushnil(L);
6641 lua_settable(L,-5);
6642 lua_pop(L,1);
6644 return 1;
6647 /* maybe we should allocate a proper index 0..var_mem_max but not now */
6649 static int lua_nodelib_get_property(lua_State * L) /* hh */
6650 { /* <node> */
6651 halfword n = *((halfword *) lua_touserdata(L, 1));
6652 if (n == null) {
6653 lua_pushnil(L);
6654 } else {
6655 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6656 lua_gettable(L, LUA_REGISTRYINDEX);
6657 lua_rawgeti(L,-1,n);
6659 return 1;
6662 static int lua_nodelib_direct_get_property(lua_State * L) /* hh */
6663 { /* <direct> */
6664 halfword n = lua_tointeger(L, 1);
6665 if (n == null) {
6666 lua_pushnil(L);
6667 } else {
6668 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6669 lua_gettable(L, LUA_REGISTRYINDEX);
6670 lua_rawgeti(L,-1,n);
6672 return 1;
6675 static int lua_nodelib_set_property(lua_State * L) /* hh */
6677 /* <node> <value> */
6678 halfword n = *((halfword *) lua_touserdata(L, 1));
6679 if (n != null) {
6680 lua_settop(L,2);
6681 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6682 lua_gettable(L, LUA_REGISTRYINDEX);
6683 /* <node> <value> <propertytable> */
6684 lua_replace(L,-3);
6685 /* <propertytable> <value> */
6686 lua_rawseti(L,-2,n);
6688 return 0;
6691 static int lua_nodelib_direct_set_property(lua_State * L) /* hh */
6693 /* <direct> <value> */
6694 halfword n = lua_tointeger(L, 1);
6695 if (n != null) {
6696 lua_settop(L,2);
6697 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6698 lua_gettable(L, LUA_REGISTRYINDEX);
6699 /* <node> <value> <propertytable> */
6700 lua_replace(L,1);
6701 /* <propertytable> <value> */
6702 lua_rawseti(L,1,n);
6704 return 0;
6707 static int lua_nodelib_direct_properties_get_table(lua_State * L) /* hh */
6708 { /* <node|direct> */
6709 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties));
6710 lua_gettable(L, LUA_REGISTRYINDEX);
6711 return 1;
6714 static int lua_nodelib_properties_get_table(lua_State * L) /* hh */
6715 { /* <node|direct> */
6716 lua_rawgeti(L, LUA_REGISTRYINDEX, lua_key_index(node_properties_indirect));
6717 lua_gettable(L, LUA_REGISTRYINDEX);
6718 return 1;
6721 /* bonus */
6723 static int lua_nodelib_get_property_t(lua_State * L) /* hh */
6724 { /* <table> <node> */
6725 halfword n = *((halfword *) lua_touserdata(L, 2));
6726 if (n == null) {
6727 lua_pushnil(L);
6728 } else {
6729 lua_rawgeti(L,1,n);
6731 return 1;
6734 static int lua_nodelib_set_property_t(lua_State * L) /* hh */
6736 /* <table> <node> <value> */
6737 halfword n = *((halfword *) lua_touserdata(L, 2));
6738 if (n != null) {
6739 lua_settop(L,3);
6740 lua_rawseti(L,1,n);
6742 return 0;
6745 /* extra helpers */
6747 static int lua_nodelib_effective_glue(lua_State * L)
6749 halfword *glue;
6750 halfword *parent;
6751 glue = lua_touserdata(L, 1);
6752 if ((glue == NULL) || (type(*glue) != glue_node)) {
6753 lua_pushnil(L) ;
6754 } else {
6755 halfword s = glue_ptr(*glue);
6756 int w = width(s) ;
6757 parent = lua_touserdata(L, 2);
6758 if ((parent != NULL) && ((type(*parent) == hlist_node) || (type(*parent) == vlist_node))) {
6759 if ((int)glue_sign(*parent) == 1) {
6760 if (stretch_order(s) == glue_order(*parent)) {
6761 w += stretch(s) * glue_set(*parent);
6763 } else if (glue_sign(*parent) == 2) {
6764 if (shrink_order(s) == glue_order(*parent)) {
6765 w -= shrink(s) * glue_set(*parent);
6769 lua_pushinteger(L,w);
6771 return 1;
6775 static int lua_nodelib_direct_effective_glue(lua_State * L)
6777 halfword glue = lua_tointeger(L, 1);
6778 if ((glue == null) || (type(glue) != glue_node)) {
6779 lua_pushnil(L) ;
6780 } else {
6781 halfword s = glue_ptr(glue);
6782 int w = width(s) ;
6783 halfword parent = lua_tointeger(L, 2);
6784 if ((parent != null) && ((type(parent) == hlist_node) || (type(parent) == vlist_node))) {
6785 if ((int)glue_sign(parent) == 1) {
6786 if (stretch_order(s) == glue_order(parent)) {
6787 w += stretch(s) * glue_set(parent);
6789 } else if (glue_sign(parent) == 2) {
6790 if (shrink_order(s) == glue_order(parent)) {
6791 w -= shrink(s) * glue_set(parent);
6795 lua_pushinteger(L,w);
6797 return 1;
6801 static const struct luaL_Reg nodelib_p[] = {
6802 {"__index", lua_nodelib_get_property_t},
6803 {"__newindex", lua_nodelib_set_property_t},
6804 {NULL, NULL} /* sentinel */
6807 static void lua_new_properties_table(lua_State * L)
6809 lua_pushstring(L,"node.properties");
6810 lua_newtable(L);
6811 lua_settable(L,LUA_REGISTRYINDEX);
6813 lua_pushstring(L,"node.properties.indirect");
6814 lua_newtable(L);
6815 luaL_newmetatable(L,"node.properties.indirect.meta");
6816 luaL_register(L, NULL, nodelib_p);
6817 lua_setmetatable(L,-2);
6818 lua_settable(L,LUA_REGISTRYINDEX);
6821 /* node.direct.* */
6823 static const struct luaL_Reg direct_nodelib_f[] = {
6824 {"copy", lua_nodelib_direct_copy},
6825 {"copy_list", lua_nodelib_direct_copy_list},
6826 {"count", lua_nodelib_direct_count},
6827 {"current_attr", lua_nodelib_direct_currentattr},
6828 {"dimensions", lua_nodelib_direct_dimensions},
6829 {"do_ligature_n", lua_nodelib_direct_do_ligature_n},
6830 {"end_of_math", lua_nodelib_direct_end_of_math},
6831 /* {"family_font", lua_nodelib_mfont}, */ /* no node argument */
6832 /* {"fields", lua_nodelib_fields}, */ /* no node argument */
6833 {"first_glyph", lua_nodelib_direct_first_glyph},
6834 {"flush_list", lua_nodelib_direct_flush_list},
6835 {"flush_node", lua_nodelib_direct_flush_node},
6836 {"free", lua_nodelib_direct_free},
6837 {"getbox", lua_nodelib_direct_getbox},
6838 {"getchar", lua_nodelib_direct_getcharacter},
6839 {"getdisc", lua_nodelib_direct_getdiscretionary},
6840 {"getfield", lua_nodelib_direct_getfield},
6841 {"getfont", lua_nodelib_direct_getfont},
6842 {"getid", lua_nodelib_direct_getid},
6843 {"getnext", lua_nodelib_direct_getnext},
6844 {"getprev", lua_nodelib_direct_getprev},
6845 {"getboth", lua_nodelib_direct_getboth},
6846 {"getlist", lua_nodelib_direct_getlist},
6847 {"getleader", lua_nodelib_direct_getleader},
6848 {"getsubtype", lua_nodelib_direct_getsubtype},
6849 {"has_glyph", lua_nodelib_direct_has_glyph},
6850 {"has_attribute", lua_nodelib_direct_has_attribute},
6851 {"get_attribute", lua_nodelib_direct_get_attribute},
6852 {"has_field", lua_nodelib_direct_has_field},
6853 {"is_char", lua_nodelib_direct_is_char},
6854 {"hpack", lua_nodelib_direct_hpack},
6855 /* {"id", lua_nodelib_id}, */ /* no node argument */
6856 {"insert_after", lua_nodelib_direct_insert_after},
6857 {"insert_before", lua_nodelib_direct_insert_before},
6858 {"is_direct", lua_nodelib_direct_is_direct},
6859 {"is_node", lua_nodelib_direct_is_node},
6860 {"kerning", font_tex_direct_kerning},
6861 {"last_node", lua_nodelib_direct_last_node},
6862 {"length", lua_nodelib_direct_length},
6863 {"ligaturing", font_tex_direct_ligaturing},
6864 /* {"mlist_to_hlist", lua_nodelib_mlist_to_hset_properties_modelist}, */
6865 {"new", lua_nodelib_direct_new},
6866 {"tostring", lua_nodelib_direct_tostring},
6867 {"protect_glyphs", lua_nodelib_direct_protect_glyphs},
6868 {"protect_glyph", lua_nodelib_direct_protect_glyph},
6869 {"protrusion_skippable", lua_nodelib_direct_cp_skipable},
6870 {"remove", lua_nodelib_direct_remove},
6871 {"set_attribute", lua_nodelib_direct_set_attribute},
6872 {"setbox", lua_nodelib_direct_setbox},
6873 {"setfield", lua_nodelib_direct_setfield},
6874 {"setchar", lua_nodelib_direct_setcharacter},
6875 {"setdisc", lua_nodelib_direct_setdiscretionary},
6876 {"setnext", lua_nodelib_direct_setnext},
6877 {"setprev", lua_nodelib_direct_setprev},
6878 {"setboth", lua_nodelib_direct_setboth},
6879 {"setlink", lua_nodelib_direct_setlink},
6880 {"setlist", lua_nodelib_direct_setlist},
6881 {"setleader", lua_nodelib_direct_setleader},
6882 {"setsubtype", lua_nodelib_direct_setsubtype},
6883 {"slide", lua_nodelib_direct_slide},
6884 /* {"subtype", lua_nodelib_subtype}, */ /* no node argument */
6885 {"tail", lua_nodelib_direct_tail},
6886 {"todirect", lua_nodelib_direct_todirect},
6887 {"tonode", lua_nodelib_direct_tonode},
6888 {"traverse", lua_nodelib_direct_traverse},
6889 {"traverse_id", lua_nodelib_direct_traverse_filtered},
6890 {"traverse_char", lua_nodelib_direct_traverse_char},
6891 /* {"type", lua_nodelib_type}, */ /* no node argument */
6892 /* {"types", lua_nodelib_types}, */ /* no node argument */
6893 {"unprotect_glyphs", lua_nodelib_direct_unprotect_glyphs},
6894 {"unset_attribute", lua_nodelib_direct_unset_attribute},
6895 {"usedlist", lua_nodelib_direct_usedlist},
6896 {"vpack", lua_nodelib_direct_vpack},
6897 /* {"whatsits", lua_nodelib_whatsits}, */ /* no node argument */
6898 {"write", lua_nodelib_direct_append},
6899 {"set_properties_mode",lua_nodelib_properties_set_mode},
6900 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6901 {"get_properties_table",lua_nodelib_direct_properties_get_table}, /* hh experiment */
6902 {"getproperty", lua_nodelib_direct_get_property},
6903 {"setproperty", lua_nodelib_direct_set_property},
6904 {"effective_glue", lua_nodelib_direct_effective_glue},
6905 /* done */
6906 {NULL, NULL} /* sentinel */
6909 /* node.* */
6911 static const struct luaL_Reg nodelib_f[] = {
6912 {"copy", lua_nodelib_copy},
6913 {"copy_list", lua_nodelib_copy_list},
6914 {"count", lua_nodelib_count},
6915 {"current_attr", lua_nodelib_currentattr},
6916 {"dimensions", lua_nodelib_dimensions},
6917 {"do_ligature_n", lua_nodelib_do_ligature_n},
6918 {"end_of_math", lua_nodelib_end_of_math},
6919 {"family_font", lua_nodelib_mfont},
6920 {"fields", lua_nodelib_fields},
6921 {"subtypes", lua_nodelib_subtypes},
6922 {"first_glyph", lua_nodelib_first_glyph},
6923 {"flush_list", lua_nodelib_flush_list},
6924 {"flush_node", lua_nodelib_flush_node},
6925 {"free", lua_nodelib_free},
6926 /* {"getbox", lua_nodelib_getbox}, */ /* tex.getbox */
6927 {"getnext", lua_nodelib_getnext},
6928 {"getprev", lua_nodelib_getprev},
6929 {"getboth", lua_nodelib_getboth},
6930 {"getdisc", lua_nodelib_getdiscretionary},
6931 {"getlist", lua_nodelib_getlist},
6932 {"getleader", lua_nodelib_getleader},
6933 {"getid", lua_nodelib_getid},
6934 {"getsubtype", lua_nodelib_getsubtype},
6935 {"getfont", lua_nodelib_getfont},
6936 {"getchar", lua_nodelib_getcharacter},
6937 {"getfield", lua_nodelib_getfield},
6938 {"setfield", lua_nodelib_setfield},
6939 {"has_glyph", lua_nodelib_has_glyph},
6940 {"has_attribute", lua_nodelib_has_attribute},
6941 {"get_attribute", lua_nodelib_get_attribute},
6942 {"has_field", lua_nodelib_has_field},
6943 {"is_char", lua_nodelib_is_char},
6944 {"hpack", lua_nodelib_hpack},
6945 {"id", lua_nodelib_id},
6946 {"insert_after", lua_nodelib_insert_after},
6947 {"insert_before", lua_nodelib_insert_before},
6948 {"is_node", lua_nodelib_is_node},
6949 {"kerning", font_tex_kerning},
6950 {"last_node", lua_nodelib_last_node},
6951 {"length", lua_nodelib_length},
6952 {"ligaturing", font_tex_ligaturing},
6953 {"mlist_to_hlist", lua_nodelib_mlist_to_hlist},
6954 {"new", lua_nodelib_new},
6955 {"next", lua_nodelib_next}, /* getnext is somewhat more efficient, and get* fits better in direct compatibility */
6956 {"prev", lua_nodelib_prev}, /* getprev is somewhat more efficient, and get* fits better in direct compatibility */
6957 {"tostring", lua_nodelib_tostring},
6958 {"protect_glyphs", lua_nodelib_protect_glyphs},
6959 {"protect_glyph", lua_nodelib_protect_glyph},
6960 {"protrusion_skippable", lua_nodelib_cp_skipable},
6961 {"remove", lua_nodelib_remove},
6962 /* {"setbox", lua_nodelib_setbox}, */ /* tex.setbox */
6963 {"set_attribute", lua_nodelib_set_attribute},
6964 {"slide", lua_nodelib_slide},
6965 {"subtype", lua_nodelib_subtype},
6966 {"tail", lua_nodelib_tail},
6967 {"traverse", lua_nodelib_traverse},
6968 {"traverse_id", lua_nodelib_traverse_filtered},
6969 {"traverse_char", lua_nodelib_traverse_char},
6970 {"type", lua_nodelib_type},
6971 {"types", lua_nodelib_types},
6972 {"unprotect_glyphs", lua_nodelib_unprotect_glyphs},
6973 {"unset_attribute", lua_nodelib_unset_attribute},
6974 {"usedlist", lua_nodelib_usedlist},
6975 {"vpack", lua_nodelib_vpack},
6976 {"whatsits", lua_nodelib_whatsits},
6977 {"write", lua_nodelib_append},
6978 /* experiment */
6979 /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */ /* hh experiment */
6980 /* experiment */
6981 {"set_properties_mode",lua_nodelib_properties_set_mode}, /* hh experiment */
6982 {"flush_properties_table",lua_nodelib_properties_flush_table}, /* hh experiment */
6983 {"get_properties_table",lua_nodelib_properties_get_table}, /* bonus */ /* hh experiment */
6984 {"getproperty", lua_nodelib_get_property}, /* hh experiment */
6985 {"setproperty", lua_nodelib_set_property}, /* hh experiment */
6986 {"effective_glue", lua_nodelib_effective_glue},
6987 /* done */
6988 {NULL, NULL} /* sentinel */
6991 static const struct luaL_Reg nodelib_m[] = {
6992 {"__index", lua_nodelib_fast_getfield},
6993 {"__newindex", lua_nodelib_fast_setfield},
6994 {"__tostring", lua_nodelib_tostring},
6995 {"__eq", lua_nodelib_equal},
6996 {NULL, NULL} /* sentinel */
6999 int luaopen_node(lua_State * L)
7002 lua_new_properties_table(L);
7004 /* the main metatable of node userdata */
7005 luaL_newmetatable(L, NODE_METATABLE);
7006 /* node.* */
7007 luaL_register(L, NULL, nodelib_m);
7008 luaL_register(L, "node", nodelib_f);
7009 /* node.fast (experimental code)
7010 lua_pushstring(L,"fast");
7011 lua_newtable(L);
7012 luaL_register(L, NULL, fast_nodelib_f);
7013 lua_rawset(L,-3);
7015 /* node.direct */
7016 lua_pushstring(L,"direct");
7017 lua_newtable(L);
7018 luaL_register(L, NULL, direct_nodelib_f);
7019 lua_rawset(L,-3);
7020 /* initialization of keywords */
7021 /*initialize_luaS_indexes(L);*/
7022 return 1;
7025 void nodelist_to_lua(lua_State * L, int n)
7027 lua_pushinteger(L, n);
7028 lua_nodelib_push(L);
7031 int nodelist_from_lua(lua_State * L)
7033 if (lua_isnil(L, -1)) {
7034 return null;
7035 } else {
7036 halfword n= *check_isnode(L, -1);
7037 return (n ? n : null);