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