w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

lnodelib.c
Go to the documentation of this file.
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  After doing lots of tests with luatex and luajittex, with and without jit,
25  and with and without ffi, we came to the conclusion that userdata prevents
26  a speedup. We also found that the checking of metatables as well as assignment
27  comes with overhead that can't be neglected. This is normally not really a
28  problem but when processing fonts for more complex scripts it's quite some
29  overhead.
30 
31  Because the userdata approach has some benefits, we stick to this. We did
32  some experiments with fast access (assuming nodes), but eventually settled for
33  the direct approach. For code that is proven to be okay, one can use the
34  direct variants and operate on nodes more directly. Currently these are
35  numbers but don't rely on that property; treat them as abstractions. An
36  important aspect is that one cannot mix both methods, although with
37  node.direct.tonode and node.direct.todirect one can cast representations.
38 
39  So the advice is: use the indexed approach when possible and investigate the
40  direct one when speed might be an issue. For that reason we also provide some
41  get* and set* functions in the top level node namespace. There is a limited set
42  of getters for nodes and a generic getfield to complement them. The direct
43  namespace has a few more.
44 
45  Keep in mind that such speed considerations only make sense when we're accessing
46  nodes millions of times (which happens in font processing for instance). Setters
47  are less important as documents have not that many content related nodes and
48  setting many thousands of properties is hardly a burden contrary to millions of
49  consultations. And with millions, we're talking of tens of millions which is not
50  that common.
51 
52  Another change is that __index and __newindex are (as expected) exposed to
53  users but do no checking. The getfield and setfield functions do check. In
54  fact, a fast mode can be simulated by fast_getfield = __index but the (measured)
55  benefit on average runs is not that large (some 5% when we also use the other
56  fast ones) which is easily nilled by inefficient coding. The direct variants
57  on the other hand can be significantly faster but with the drawback of lack
58  of userdata features. With respect to speed: keep in mind that measuring
59  a speedup on these functions is not representative for a normal run, where
60  much more happens.
61 
62 */
63 
64 #include "ptexlib.h"
65 #include "lua/luatex-api.h"
66 #ifdef LuajitTeX
67 #include "lua/lauxlib_bridge.h"
68 #else
69 #include "lauxlib.h"
70 #endif
71 
72 /*
73 
74  These macros create and access pointers (indices) to keys which is faster. The
75  shortcuts are created as part of the initialization.
76 
77 */
78 
79 /*
80 
81  When the first argument to an accessor is a node, we can use it's metatable
82  entry when we are returning nodes, which saves a lookup.
83 
84 */
85 
86 #define fast_metatable(n) do { \
87  a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
88  *a = n; \
89  lua_getmetatable(L,1); \
90  lua_setmetatable(L,-2); \
91 } while (0)
92 
93 #define fast_metatable_or_nil(n) do { \
94  if (n) { \
95  a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
96  *a = n; \
97  lua_getmetatable(L,1); \
98  lua_setmetatable(L,-2); \
99  } else { \
100  lua_pushnil(L); \
101  } \
102 } while (0)
103 
104 #define fast_metatable_or_nil_alink(n) do { \
105  if (n) { \
106  alink(n) = null; \
107  a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
108  *a = n; \
109  lua_getmetatable(L,1); \
110  lua_setmetatable(L,-2); \
111  } else { \
112  lua_pushnil(L); \
113  } \
114 } while (0)
115 
116 #define fast_metatable_top(n) do { \
117  a = (halfword *) lua_newuserdata(L, sizeof(halfword)); \
118  *a = n; \
119  lua_getmetatable(L,-2); \
120  lua_setmetatable(L,-2); \
121 } while (0)
122 
123 /*
124 
125  This is a first step towards abstract direct nodes. When we have Lua 5.3 we
126  need to check all returned values for being integers. This might be another
127  level of abtraction.
128 
129 */
130 
131 #define nodelib_pushdirect(n) lua_pushinteger(L,n)
132 #define nodelib_popdirect(n) lua_tointeger(L,n)
133 
134 #define nodelib_pushdirect_or_nil(n) do { \
135  if (n==null) { \
136  lua_pushnil(L); \
137  } else { \
138  lua_pushinteger(L,n); \
139  } \
140 } while (0)
141 
142 #define nodelib_pushdirect_or_nil_alink(n) do { \
143  if (n==null) { \
144  lua_pushnil(L); \
145  } else { \
146  alink(n) = null; \
147  lua_pushinteger(L,n); \
148  } \
149 } while (0)
150 
151 #define nodelib_setattr(L, s, n) reassign_attribute(n,nodelib_getlist(L,s))
152 
153 #define nodelib_gettoks(L,a) tokenlist_from_lua(L)
154 
155 #define nodelib_getspec nodelib_getlist
156 #define nodelib_getaction nodelib_getlist
157 
158 /* fetching a field from a node .. we can often use the reuse bot-of-stack metatable */
159 
160 #define nodelib_pushlist(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
161 #define nodelib_pushattr(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
162 #define nodelib_pushaction(L,n) { lua_pushinteger(L,n); lua_nodelib_push(L); } /* can be: fast_metatable_or_nil(n) */
163 #define nodelib_pushstring(L,n) { char *ss=makecstring(n); lua_pushstring(L,ss); free(ss); }
164 
165 /* find prev, and fix backlinks .. can be a macro instead (only used a few times) */
166 
167 #define set_t_to_prev(head,current) \
168 t = head; \
169 while (vlink(t)!=current && t != null) { \
170  if (vlink(t)!=null) \
171  alink(vlink(t)) = t; \
172  t = vlink(t); \
173 }
174 
175 #define direct_check_index_range(j,s) \
176  if (j<0 || j > 65535) { \
177  luaL_error(L, "incorrect index value %d for tex.%s()", (int)j, s); \
178  }
179 
180 #define NODE_METATABLE "luatex.node"
181 
182 #define DEBUG 0
183 #define DEBUG_OUT stdout
184 
185 /* maybe these qualify as macros, not functions */
186 
188 {
189  halfword *p = lua_touserdata(L, i);
190  if (p != NULL) {
191  if (lua_getmetatable(L, i)) {
192  lua_get_metatablelua(luatex_node);
193  if (!lua_rawequal(L, -1, -2))
194  p = NULL;
195  lua_pop(L, 2);
196  }
197  }
198  return p;
199 }
200 
201 /* we could make the message a function and just inline the rest (via a macro) */
202 
204 {
205  halfword *p = maybe_isnode(L, i);
206  if (p != NULL)
207  return p;
208  formatted_error("node lib","lua <node> expected, not an object with type %s", luaL_typename(L, i));
209  return NULL;
210 }
211 
213 {
214  if (lua_type(L, i) == LUA_TSTRING) {
215  const char *s = lua_tostring(L, i);
216  if (s==lua_key_plus(TLT)) {
217  dir_dir(n) = 0 ;
218  subtype(n) = normal_dir;
219  } else if (s==lua_key_minus(TLT)) {
220  dir_dir(n) = 0 ;
221  subtype(n) = cancel_dir;
222  } else if (s==lua_key_plus(TRT)) {
223  dir_dir(n) = 1 ;
224  subtype(n) = normal_dir;
225  } else if (s==lua_key_minus(TRT)) {
226  dir_dir(n) = 1 ;
227  subtype(n) = cancel_dir;
228  } else if (s==lua_key_plus(LTL)) {
229  dir_dir(n) = 2 ;
230  subtype(n) = normal_dir;
231  } else if (s==lua_key_minus(LTL)) {
232  dir_dir(n) = 2 ;
233  subtype(n) = cancel_dir;
234  } else if (s==lua_key_plus(RTT)) {
235  dir_dir(n) = 3 ;
236  subtype(n) = normal_dir;
237  } else if (s==lua_key_minus(RTT)) {
238  dir_dir(n) = 3 ;
239  subtype(n) = cancel_dir;
240  } else {
241  luaL_error(L, "Bad direction specifier %s", s);
242  }
243  } else {
244  luaL_error(L, "Direction specifiers have to be strings");
245  }
246  return 0;
247 }
248 
249 static int nodelib_getdir_par(lua_State * L, int n)
250 {
251  if (lua_type(L, n) == LUA_TSTRING) {
252  const char *s = lua_tostring(L, n);
253  if (s==lua_key(TLT))
254  return 0 ;
255  else if (s==lua_key(TRT))
256  return 1 ;
257  else if (s==lua_key(LTL))
258  return 2 ;
259  else if (s==lua_key(RTT))
260  return 3 ;
261  else
262  luaL_error(L, "Bad direction specifier %s", s);
263  } else {
264  luaL_error(L, "Direction specifiers have to be strings");
265  }
266  return 0;
267 }
268 
269 static int nodelib_getdirection(lua_State * L, int n)
270 {
271  if (lua_type(L, n) == LUA_TNUMBER) {
272  int i = lua_tointeger(L, n);
274  return i;
275  } else {
276  luaL_error(L, "Direction specifiers have to be numbers");
277  }
278  return 0;
279 }
280 
281 int nodelib_getdir(lua_State * L, int n) /* the api public one */
282 {
283  return nodelib_getdir_par(L,n);
284 }
285 
286 /*
287 
288  This routine finds the numerical value of a string (or number) at
289  lua stack index |n|. If it is not a valid node type, returns -1
290 
291 */
292 
293 /* s = lua_tostring(L, 2); */
294 /* if (lua_key_eq(s, id)) { */
295 
297 {
298  if (data != NULL) {
299  int j;
300  const char *s = lua_tostring(L, n);
301  for (j = 0; data[j].id != -1; j++) {
302  if (s == data[j].name) {
303  return j;
304  }
305  }
306  }
307  return -1;
308 }
309 
311 {
312  if (data != NULL) {
313  int j;
314  const char *s = lua_tostring(L, n);
315  for (j = 0; data[j].id != -1; j++) {
316  if (s == data[j].name) {
317  return j;
318  }
319  }
320  }
321  return -1;
322 }
323 
325 {
326  int i = -1;
327  int t = lua_type(L, n);
328  if (t == LUA_TSTRING) {
330  if (i < 0) {
331  luaL_error(L, "invalid node type id: %s", lua_tostring(L, n));
332  }
333  } else if (t == LUA_TNUMBER) {
334  i = lua_tointeger(L,n);
335  if (! known_node_type(i)) {
336  luaL_error(L, "invalid node type id: %d", i);
337  }
338  } else {
339  luaL_error(L, "invalid node type id");
340  }
341  return i;
342 }
343 
345 {
346  int i = -1;
347  int t = lua_type(L, n);
348  if (t == LUA_TSTRING) {
350  if (i<0) {
351  luaL_error(L, "invalid whatsit type id: %s", lua_tostring(L, n));
352  }
353  } else if (t == LUA_TNUMBER) {
354  i = lua_tointeger(L,n);
355  if (! known_whatsit_type(i)) {
356  luaL_error(L, "invalid whatsit type id: %d", i);
357  }
358  } else {
359  luaL_error(L, "invalid whatsit type id");
360  }
361  return i;
362 }
363 
364 /* enable fixer ... more fixers can be added in the future */
365 
367 {
368  if (lua_type(L, -1) == LUA_TBOOLEAN) {
370  } else if (lua_type(L, -1) == LUA_TNUMBER) {
372  }
373  return 0;
374 }
375 
376 
377 /* two simple helpers to speed up and simplify lua code (replaced by getnext and getprev) */
378 
380 {
381  halfword *p = maybe_isnode(L,1);
382  if (p != NULL && *p && vlink(*p)) {
384  } else {
385  lua_pushnil(L);
386  }
387  return 1;
388 }
389 
391 {
392  halfword *p = maybe_isnode(L,1);
393  if (p != NULL && *p && alink(*p)) {
395  } else {
396  lua_pushnil(L);
397  }
398  return 1;
399 }
400 
401 /*
402 
403  Creates a userdata object for a number found at the stack top, if it is
404  representing a node (i.e. an pointer into |varmem|). It replaces the
405  stack entry with the new userdata, or pushes |nil| if the number is |null|,
406  or if the index is definately out of range. This test could be improved.
407 
408 */
409 
411 {
412  halfword n;
413  halfword *a;
414  n = -1;
415  if (lua_type(L, -1) == LUA_TNUMBER)
416  n = (int) lua_tointeger(L, -1);
417  lua_pop(L, 1);
418  if ((n == null) || (n < 0) || (n > var_mem_max)) {
419  lua_pushnil(L);
420  } else {
421  a = lua_newuserdata(L, sizeof(halfword));
422  *a = n;
423  lua_get_metatablelua(luatex_node);
424  lua_setmetatable(L, -2);
425  }
426  return;
427 }
428 
430 {
431  halfword *a;
432  if (n) {
433  a = lua_newuserdata(L, sizeof(halfword));
434  *a = n;
435  lua_get_metatablelua(luatex_node);
436  lua_setmetatable(L, -2);
437  } else {
438  lua_pushnil(L);
439  }
440  return;
441 }
442 
443 /* getting and setting fields (helpers) */
444 
446 {
447  if (lua_isuserdata(L, n)) {
448  halfword m = *check_isnode(L, n);
449  return m;
450  } else {
451  return null;
452  }
453 }
454 
456 {
457  size_t k;
458  const char *s = lua_tolstring(L, a, &k);
459  return maketexlstring(s, k);
460 }
461 
462 static int nodelib_cantset(lua_State * L, int n, const char *s)
463 {
464  luaL_error(L,"You cannot set field %s in a node of type %s",s,node_data[type(n)].name);
465  return 0;
466 }
467 
468 /* converts type strings to type ids */
469 
471 {
472  if (lua_type(L,1) == LUA_TSTRING) {
474  if (i >= 0) {
475  lua_pushinteger(L, i);
476  } else {
477  lua_pushnil(L);
478  }
479  } else {
480  lua_pushnil(L);
481  }
482  return 1;
483 }
484 
485 /* node.direct.getid */
486 
488 {
489  halfword n = lua_tointeger(L, 1);
490  if (n) {
491  lua_pushinteger(L, type(n));
492  } else {
493  lua_pushnil(L);
494  }
495  return 1;
496 }
497 
498  /* node.getid */
499 
501  {
502  /* [given-node] [...] */
503  halfword *p = lua_touserdata(L, 1);
504  if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
505  lua_pushnil(L);
506  return 1;
507  }
508  /* [given-node] [mt-given-node] */
509  lua_get_metatablelua(luatex_node);
510  /* [given-node] [mt-given-node] [mt-node] */
511  if (!lua_rawequal(L, -1, -2)) {
512  lua_pushnil(L);
513  } else {
514  lua_pushinteger(L, type(*p));
515  }
516  return 1;
517  }
518 
519 /* node.direct.getsubtype */
520 /* node.direct.setsubtype */
521 
523 {
524  halfword n = lua_tointeger(L, 1);
525  if (n) {
527  } else {
528  lua_pushnil(L);
529  }
530  return 1;
531 }
532 
534 {
535  halfword n = lua_tointeger(L, 1);
536  if ((n) && (lua_type(L,2) == LUA_TNUMBER)) {
537  subtype(n) = (halfword) lua_tointeger(L, 2);
538  }
539  return 0;
540 }
541 
542  /* node.getsubtype */
543 
545  {
546  halfword *p = lua_touserdata(L, 1);
547  if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
548  lua_pushnil(L);
549  } else {
550  lua_get_metatablelua(luatex_node);
551  if ( (!lua_rawequal(L, -1, -2)) || (! nodetype_has_subtype(*p))) {
552  lua_pushnil(L);
553  } else {
555  }
556  }
557  return 1;
558  }
559 
560 /* node.direct.getexpansion */
561 /* node.direct.setexpansion */
562 
564 {
565  halfword n = lua_tointeger(L, 1);
566  if (n != null) {
567  halfword t = type(n);
568  if (t == glyph_node) {
570  return 1;
571  } else if (t == kern_node) {
573  return 1;
574  }
575  }
576  lua_pushnil(L);
577  return 1;
578 }
579 
581 {
582  halfword n = lua_tointeger(L, 1);
583  if (n) {
584  halfword t = type(n);
585  halfword e = 0;
586  if (lua_type(L, 2) == LUA_TNUMBER) {
587  e = (halfword) lua_tointeger(L, 2);
588  }
589  if (t == glyph_node) {
590  ex_glyph(n) = e;
591  } else if ( t == kern_node) {
592  ex_kern(n) = e;
593  }
594  }
595  return 0;
596 }
597 
598 /* node.direct.getfont */
599 /* node.direct.setfont */
600 
602 {
603  halfword n = lua_tointeger(L, 1);
604  if (n != null) {
605  halfword t = type(n);
606  if (t == glyph_node) {
607  lua_pushinteger(L, font(n));
608  } else if ((t == math_char_node) || (t == math_text_char_node)) {
610  } else if (t == delim_node) {
612  } else {
613  lua_pushnil(L);
614  }
615  } else {
616  lua_pushnil(L);
617  }
618  return 1;
619 }
620 
622 {
623  halfword n = lua_tointeger(L, 1);
624  if ((n) && type(n) == glyph_node) {
625  font(n) = (halfword) lua_tointeger(L,2);
626  /* optional char */
627  if ((lua_type(L, 3) == LUA_TNUMBER)) {
629  }
630  }
631  return 0;
632 }
633 
634  /* node.getfont */
635 
637  {
638  halfword *n = lua_touserdata(L, 1);
639  if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
640  lua_pushnil(L);
641  } else {
642  halfword t = type(*n);
643  if (t == glyph_node) {
644  lua_pushinteger(L, font(*n));
645  } else if ((t == math_char_node) || (t == math_text_char_node)) {
647  } else if (t == delim_node) {
649  } else {
650  lua_pushnil(L);
651  }
652  }
653  return 1;
654  }
655 
656 /* node.direct.getchar */
657 /* node.direct.setchar */
658 
660 {
661  halfword n = lua_tointeger(L, 1);
662  if (n) {
663  halfword t = type(n);
664  if (t == glyph_node) {
666  } else if ((t == math_char_node) || (t == math_text_char_node)) {
668  } else if (t == delim_node) {
669  /* used in wide fonts */
671  } else {
672  lua_pushnil(L);
673  }
674  } else {
675  lua_pushnil(L);
676  }
677  return 1;
678 }
679 
681 {
682  halfword n = lua_tointeger(L, 1);
683  if (n) {
684  halfword t = type(n);
685  if ((t == math_char_node) || (t == math_text_char_node)) {
687  } else if (t == delim_node) {
689  } else if (t == fraction_noad) {
691  } else if (t == simple_noad) {
693  } else {
694  lua_pushnil(L);
695  }
696  } else {
697  lua_pushnil(L);
698  }
699  return 1;
700 }
701 
703 {
704  halfword n = lua_tointeger(L, 1);
705  if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
706  halfword t = type(n);
707  if (t == glyph_node) {
709  } else if ((t == math_char_node) || (t == math_text_char_node)) {
711  } else if (t == delim_node) {
712  /* used in wide fonts */
714  }
715  }
716  return 0;
717 }
718 
720 {
721  halfword n = lua_tointeger(L, 1);
722  if ((n) && (lua_type(L, 2) == LUA_TNUMBER)) {
723  halfword t = type(n);
724  if ((t == math_char_node) || (t == math_text_char_node)) {
725  math_fam(n) = (halfword) lua_tointeger(L, 2);
726  } else if (t == delim_node) {
728  } else if (t == fraction_noad) {
730  } else if (t == simple_noad) {
731  noad_fam(n) = (halfword) lua_tointeger(L, 2);
732  }
733  }
734  return 0;
735 }
736 
737  /* node.getchar */
738 
740  {
741  halfword *n = lua_touserdata(L, 1);
742  if ((n == NULL) || (! lua_getmetatable(L,1))) {
743  lua_pushnil(L);
744  } else {
745  halfword t = type(*n);
746  if (t == glyph_node) {
748  } else if ((t == math_char_node) || (t == math_text_char_node)) {
750  } else if (t == delim_node) {
751  /* used in wide fonts */
753  } else {
754  lua_pushnil(L);
755  }
756  }
757  return 1;
758  }
759 
760 /* node.direct.getcomponents */
761 /* node.direct.setcomponents */
762 
764 {
765  halfword n = lua_tointeger(L, 1);
766  if ((n) && (type(n) == glyph_node)) {
768  } else {
769  lua_pushnil(L);
770  }
771  return 1;
772 }
773 
775 {
776  halfword n = lua_tointeger(L, 1);
777  if ((n) && (type(n) == glyph_node)) {
778  if (lua_type(L, 2) == LUA_TNUMBER) {
779  lig_ptr(n) = (halfword) lua_tointeger(L, 2);
780  } else {
781  lig_ptr(n) = null;
782  }
783  }
784  return 0;
785 }
786 
787 /* node.direct.getlang */
788 /* node.direct.setlang */
789 
791 {
792  halfword n = lua_tointeger(L, 1);
793  if ((n) && (type(n) == glyph_node)) {
795  } else {
796  lua_pushnil(L);
797  }
798  return 1;
799 }
800 
802 {
803  halfword n = lua_tointeger(L, 1);
804  if ((n) && (type(n) == glyph_node)) {
805  if (lua_type(L, 2) == LUA_TNUMBER) {
807  } else {
808  /* nothing */
809  }
810  }
811  return 0;
812 }
813 
814 /* node.direct.getattributelist */
815 /* node.direct.setattributelist */
816 
818 {
819  halfword n = lua_tointeger(L, 1);
820  if ((n) && nodetype_has_attributes(type(n)) && node_attr(n) != null) {
822  } else {
823  lua_pushnil(L);
824  }
825  return 1;
826 }
827 
829 {
830  halfword n = lua_tointeger(L, 1);
831  if ((n) && nodetype_has_attributes(type(n))) {
832  int t = lua_type(L, 2);
833  if (t == LUA_TNUMBER) {
834  halfword a =lua_tointeger(L, 2);
835  if (type(a) == attribute_list_node) {
837  } else if (nodetype_has_attributes(type(a))) {
839  } else {
840  reassign_attribute(n,null);
841  }
842  } else if (t == LUA_TBOOLEAN) {
843  if (lua_toboolean(L,2)) {
845  } else {
846  reassign_attribute(n,null);
847  }
848  } else {
849  reassign_attribute(n,null);
850  }
851  return 0;
852  }
853  return 0;
854 }
855 /* node.direct.getpenalty */
856 /* node.direct.setpenalty */
857 
859 {
860  halfword n = lua_tointeger(L, 1);
861  if (n) {
862  halfword t = type(n);
863  if (t == penalty_node) {
865  } else if (t == disc_node) {
867  } else {
868  lua_pushnil(L);
869  }
870  } else {
871  lua_pushnil(L);
872  }
873  return 1;
874 }
875 
877 {
878  halfword n = lua_tointeger(L, 1);
879  if (n) {
880  halfword t = type(n);
881  if (t == penalty_node) {
882  if (lua_type(L, 2) == LUA_TNUMBER) {
883  penalty(n) = (halfword) lua_tointeger(L, 2);
884  } else {
885  penalty(n) = 0;
886  }
887  } else if (t == disc_node) {
888  if (lua_type(L, 2) == LUA_TNUMBER) {
890  } else {
891  penalty(n) = 0;
892  }
893  }
894  }
895  return 0;
896 }
897 
898 /* node.direct.getnucleus */
899 /* node.direct.getsub */
900 /* node.direct.getsup */
901 
903 {
904  halfword n = lua_tointeger(L, 1);
905  if (n) {
906  halfword t = type(n);
907  if (t == simple_noad || t == accent_noad || t == radical_noad) {
909  return 1;
910  }
911  }
912  lua_pushnil(L);
913  return 1;
914 }
915 
917 {
918  halfword n = lua_tointeger(L, 1);
919  if (n) {
920  halfword t = type(n);
921  if (t == simple_noad || t == accent_noad || t == radical_noad) {
922  if (lua_type(L, 2) == LUA_TNUMBER) {
923  nucleus(n) = lua_tointeger(L,2);
924  } else {
925  nucleus(n) = null;
926  }
927  }
928  }
929  return 0;
930 }
931 
933 {
934  halfword n = lua_tointeger(L, 1);
935  if (n) {
936  halfword t = type(n);
937  if (t == simple_noad || t == accent_noad || t == radical_noad) {
939  return 1;
940  }
941  }
942  lua_pushnil(L);
943  return 1;
944 }
945 
947 {
948  halfword n = lua_tointeger(L, 1);
949  if (n) {
950  halfword t = type(n);
951  if (t == simple_noad || t == accent_noad || t == radical_noad) {
952  if (lua_type(L, 2) == LUA_TNUMBER) {
953  subscr(n) = lua_tointeger(L,2);
954  } else {
955  subscr(n) = null;
956  }
957  }
958  }
959  return 0;
960 }
961 
963 {
964  halfword n = lua_tointeger(L, 1);
965  if (n) {
966  halfword t = type(n);
967  if (t == simple_noad || t == accent_noad || t == radical_noad) {
969  return 1;
970  }
971  }
972  lua_pushnil(L);
973  return 1;
974 }
975 
977 {
978  halfword n = lua_tointeger(L, 1);
979  if (n) {
980  halfword t = type(n);
981  if (t == simple_noad || t == accent_noad || t == radical_noad) {
982  if (lua_type(L, 2) == LUA_TNUMBER) {
983  supscr(n) = lua_tointeger(L,2);
984  } else {
985  supscr(n) = null;
986  }
987  }
988  }
989  return 0;
990 }
991 
992 /* node.direct.getkern (overlaps with getwidth) */
993 /* node.direct.setkern (overlaps with getwidth) */
994 
996 {
997  halfword n = lua_tointeger(L, 1);
998  if (n) {
999  halfword t = type(n);
1000  if (t == kern_node) {
1001  lua_pushnumber(L, width(n));
1002  if (lua_toboolean(L,2)) {
1004  return 2;
1005  }
1006  } else if (t == margin_kern_node) {
1007  lua_pushinteger(L, width(n));
1008  } else if (t == math_node) {
1010  } else {
1011  lua_pushnil(L);
1012  }
1013  } else {
1014  lua_pushnil(L);
1015  }
1016  return 1;
1017 }
1018 
1020 {
1021  halfword n = lua_tointeger(L, 1);
1022  if (n != null) {
1023  halfword t = type(n);
1024  if (t == kern_node || t == margin_kern_node) {
1025  if (lua_type(L, 2) == LUA_TNUMBER) {
1026  width(n) = (halfword) lua_roundnumber(L, 2);
1027  } else {
1028  width(n) = 0;
1029  }
1030  if (lua_type(L, 3) == LUA_TNUMBER) {
1031  subtype(n) = (halfword) lua_tointeger(L, 3);
1032  }
1033  } else if (t == math_node) {
1034  if (lua_type(L, 2) == LUA_TNUMBER) {
1035  surround(n) = (halfword) lua_roundnumber(L, 2);
1036  } else {
1037  surround(n) = 0;
1038  }
1039  }
1040  }
1041  return 0;
1042 }
1043 
1044 /* node.direct.getdir */
1045 /* node.direct.setdir */
1046 
1048 {
1049  halfword n = lua_tointeger(L, 1);
1050  if (n) {
1051  halfword t = type(n);
1052  if (t == dir_node) {
1054  } else if (t == hlist_node || t == vlist_node) {
1056  } else if (t == rule_node) {
1058  } else if (t == local_par_node) {
1060  } else {
1061  lua_pushnil(L);
1062  }
1063  } else {
1064  lua_pushnil(L);
1065  }
1066  return 1;
1067 }
1068 
1070 {
1071  halfword n = lua_tointeger(L, 1);
1072  if (n) {
1073  halfword t = type(n);
1074  if (t == dir_node) {
1077  return 2;
1078  } else if (t == hlist_node || t == vlist_node) {
1080  } else if (t == rule_node) {
1082  } else if (t == local_par_node) {
1084  } else {
1085  lua_pushnil(L);
1086  }
1087  } else {
1088  lua_pushnil(L);
1089  }
1090  return 1;
1091 }
1092 
1094 {
1095  halfword n = lua_tointeger(L, 1);
1096  if (n) {
1097  halfword t = type(n);
1098  if (t == dir_node) {
1099  nodelib_setdir_text(L, 2, n);
1100  } else if (t == hlist_node || type(n) == vlist_node) {
1101  box_dir(n) = nodelib_getdir_par(L, 2);
1102  } else if (t == rule_node) {
1103  rule_dir(n) = nodelib_getdir_par(L, 2);
1104  } else if (t == local_par_node) {
1106  }
1107  }
1108  return 0;
1109 }
1110 
1112 {
1113  halfword n = lua_tointeger(L, 1);
1114  if (n) {
1115  halfword t = type(n);
1116  if (t == dir_node) {
1118  if ((lua_type(L, 3) == LUA_TBOOLEAN)) {
1119  if (lua_toboolean(L, 3)) {
1120  subtype(n) = cancel_dir;
1121  } else {
1122  subtype(n) = normal_dir;
1123  }
1124  }
1125  } else if (t == hlist_node || type(n) == vlist_node) {
1127  } else if (t == rule_node) {
1129  } else if (t == local_par_node) {
1131  }
1132  }
1133  return 0;
1134 }
1135 
1136 /* node.direct.getoffsets */
1137 /* node.direct.setoffsets */
1138 
1140 {
1141  halfword n = lua_tointeger(L, 1);
1142  if (n) {
1143  if (type(n) == glyph_node) {
1146  return 2;
1147  } else if (type(n) == rule_node) {
1150  return 2;
1151  }
1152  }
1153  return 0;
1154 }
1155 
1157 {
1158  halfword n = lua_tointeger(L, 1);
1159  if (n) {
1160  if (type(n) == glyph_node) {
1161  if (lua_type(L, 2) == LUA_TNUMBER) {
1163  }
1164  if (lua_type(L, 3) == LUA_TNUMBER) {
1166  }
1167  } else if (type(n) == rule_node) {
1168  if (lua_type(L, 2) == LUA_TNUMBER) {
1170  }
1171  if (lua_type(L, 3) == LUA_TNUMBER) {
1173  }
1174  }
1175  }
1176  return 0;
1177 }
1178 
1179 /* node.direct.getdisc */
1180 /* node.direct.setdisc */
1181 
1183 {
1184  halfword n = lua_tointeger(L, 1);
1185  if ((n) && (type(n) == disc_node)) {
1189  if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
1193  return 6;
1194  }
1195  return 3;
1196  } else {
1197  return 0;
1198  }
1199 }
1200 
1202 {
1203  halfword n = lua_tointeger(L, 1);
1204  if (type(n) == disc_node) {
1205  int t = lua_gettop(L) ;
1206  if (t > 1) {
1208  if (t > 2) {
1210  if (t > 3) {
1212  if (t > 4) {
1214  if (t > 5) {
1215  disc_penalty(n) = lua_tointeger(L,6);
1216  }
1217  }
1218  } else {
1219  set_disc_field(no_break(n), null);
1220  }
1221  } else {
1222  set_disc_field(post_break(n), null);
1223  set_disc_field(no_break(n), null);
1224  }
1225  } else {
1226  set_disc_field(pre_break(n), null);
1227  set_disc_field(post_break(n), null);
1228  set_disc_field(no_break(n), null);
1229  }
1230  }
1231  return 0;
1232 }
1233 
1234  /* node.getdisc */
1235 
1237  {
1238  halfword *a;
1239  halfword *n = lua_touserdata(L, 1);
1240  if ((n != NULL) && (type(*n) == disc_node)) {
1244  if (lua_isboolean(L, 2) && lua_toboolean(L, 2)) {
1248  return 6;
1249  }
1250  return 3;
1251  }
1252  return 0;
1253  }
1254 
1255 /* node.direct.getwhd */
1256 /* node.direct.setwhd */
1257 
1258 # define push_list_whd(n) do { \
1259  lua_pushinteger(L, width(n)); \
1260  lua_pushinteger(L, height(n)); \
1261  lua_pushinteger(L, depth(n)); \
1262 } while (0)
1263 
1264 # define push_char_whd(n) do { \
1265  lua_pushinteger(L, char_width(font(n),character(n))); \
1266  lua_pushinteger(L, char_height(font(n),character(n))); \
1267  lua_pushinteger(L, char_depth(font(n),character(n))); \
1268 } while (0)
1269 
1270 # define push_char_ehd(n) do { \
1271  lua_pushinteger(L, char_width(font(n),character(n))); \
1272  lua_pushinteger(L, char_height(font(n),character(n))); \
1273  lua_pushinteger(L, char_depth(font(n),character(n))); \
1274  lua_pushinteger(L, ex_glyph(n)); \
1275 } while (0)
1276 
1278 {
1279  halfword n = lua_tointeger(L, 1);
1280  if (n != null) {
1281  halfword t = type(n);
1282  if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
1283  push_list_whd(n);
1284  return 3;
1285  } else if (t == glyph_node) {
1286  if (lua_toboolean(L,2)) {
1287  push_char_ehd(n);
1288  return 4;
1289  } else {
1290  push_char_whd(n);
1291  return 3;
1292  }
1293  } else if (t == glue_node) {
1294  halfword l = leader_ptr(n);
1295  if (l != null) {
1296  t = type(l) ;
1297  if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
1298  push_list_whd(l);
1299  return 3;
1300  }
1301  }
1302  }
1303  }
1304  return 0;
1305 }
1306 
1308 {
1309  halfword n = lua_tointeger(L, 1);
1310  if (n != null) {
1311  halfword t = type(n);
1312  if (t == glue_node) {
1313  n = leader_ptr(n);
1314  if (n == null) {
1315  return 0;
1316  } else {
1317  t = type(n);
1318  }
1319  }
1320  if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
1321  int t = lua_gettop(L) ;
1322  if (t > 1) {
1323  if ((lua_type(L, 2) == LUA_TNUMBER)) {
1324  width(n) = (halfword) lua_roundnumber(L, 2);
1325  } else {
1326  /* leave as is */
1327  }
1328  if (t > 2) {
1329  if ((lua_type(L, 3) == LUA_TNUMBER)) {
1330  height(n) = (halfword) lua_roundnumber(L, 3);
1331  } else {
1332  /* leave as is */
1333  }
1334  if (t > 3) {
1335  if ((lua_type(L, 4) == LUA_TNUMBER)) {
1336  depth(n) = (halfword) lua_roundnumber(L, 4);
1337  } else {
1338  /* leave as is */
1339  }
1340  }
1341  }
1342  }
1343  }
1344  }
1345  return 0;
1346 }
1347 
1348  /* node.getwhd */
1349 
1351  {
1352  halfword *n = lua_touserdata(L, 1);
1353  if (n != NULL) {
1354  halfword t = type(*n);
1355  if ((t == hlist_node) || (t == vlist_node) || (t == rule_node) || (t == unset_node)) {
1356  push_list_whd(*n);
1357  return 3;
1358  } else if (t == glyph_node) {
1359  if (lua_toboolean(L,2)) {
1360  push_char_ehd(*n);
1361  return 4;
1362  } else {
1363  push_char_whd(*n);
1364  return 3;
1365  }
1366  } else if (t == glue_node) {
1367  halfword l = leader_ptr(*n);
1368  if (l != null) {
1369  t = type(l) ;
1370  if ((t == hlist_node) || (t == vlist_node) || (t == rule_node)) {
1371  push_list_whd(l);
1372  return 3;
1373  }
1374  }
1375  }
1376  }
1377  return 0;
1378  }
1379 
1380 /* node.direct.getlist */
1381 
1383 {
1384  halfword n = lua_tointeger(L, 1);
1385  if (n == null) {
1386  lua_pushnil(L);
1387  } else {
1388  halfword t = type(n) ;
1389  if ((t == hlist_node) || (t == vlist_node)) {
1391  } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
1393  } else if (t == ins_node) {
1395  } else if (t == adjust_node) {
1397  } else {
1398  lua_pushnil(L);
1399  }
1400  }
1401  return 1;
1402 }
1403 
1405 {
1406  halfword n = lua_tointeger(L, 1);
1407  if (n != null) {
1408  halfword t = type(n) ;
1409  if ((t == hlist_node) || (t == vlist_node)) {
1410  if (lua_type(L,2) == LUA_TNUMBER) {
1411  list_ptr(n) = (halfword) lua_tointeger(L, 2);
1412  } else {
1413  list_ptr(n) = null;
1414  }
1415  } else if ((t == sub_box_node) || (t == sub_mlist_node)) {
1416  if (lua_type(L,2) == LUA_TNUMBER) {
1417  math_list(n) = (halfword) lua_tointeger(L, 2);
1418  } else {
1419  math_list(n) = null;
1420  }
1421  } else if (t == ins_node) {
1422  if (lua_type(L,2) == LUA_TNUMBER) {
1423  ins_ptr(n) = (halfword) lua_tointeger(L, 2);
1424  } else {
1425  ins_ptr(n) = null;
1426  }
1427  } else if (t == adjust_node) {
1428  if (lua_type(L,2) == LUA_TNUMBER) {
1429  adjust_ptr(n) = (halfword) lua_tointeger(L, 2);
1430  } else {
1431  adjust_ptr(n) = null;
1432  }
1433  }
1434  }
1435  return 0;
1436 }
1437 
1438  /* node.getlist */
1439 
1441  {
1442  halfword *a;
1443  halfword *n = lua_touserdata(L, 1);
1444  if ((n == NULL) || (! lua_getmetatable(L,1))) {
1445  lua_pushnil(L);
1446  } else if ((type(*n) == hlist_node) || (type(*n) == vlist_node)) {
1448  } else if ((type(*n) == sub_box_node) || (type(*n) == sub_mlist_node)) {
1450  } else if (type(*n) == ins_node) {
1452  } else if (type(*n) == adjust_node) {
1454  } else {
1455  lua_pushnil(L);
1456  }
1457  return 1;
1458  }
1459 
1460 /* node.direct.getleader */
1461 /* node.direct.setleader */
1462 
1464 {
1465  halfword n = lua_tointeger(L, 1);
1466  if ((n) && (type(n) == glue_node)) {
1468  } else {
1469  lua_pushnil(L);
1470  }
1471  return 1;
1472 }
1473 
1475 {
1476  halfword n = lua_tointeger(L, 1);
1477  if ((n) && (type(n) == glue_node)) {
1478  if (lua_type(L,2) == LUA_TNUMBER) {
1479  leader_ptr(n) = (halfword) lua_tointeger(L, 2);
1480  } else {
1481  leader_ptr(n) = null;
1482  }
1483  }
1484  return 0;
1485 }
1486 
1487 /* node.getleader */
1488 
1490  {
1491  halfword *a;
1492  halfword *n = lua_touserdata(L, 1);
1493  if ((n == NULL) || (! lua_getmetatable(L,1)) ) {
1494  lua_pushnil(L);
1495  } else if (type(*n) == glue_node) {
1497  } else {
1498  lua_pushnil(L);
1499  }
1500  return 1;
1501  }
1502 
1503 /* node.direct.getdata */
1504 /* node.direct.setdata */
1505 
1506 #define get_user_node_direct_value(L, n) do { \
1507  switch (user_node_type(n)) { \
1508  case 'a': \
1509  nodelib_pushdirect(user_node_value(n)); \
1510  break; \
1511  case 'd': \
1512  lua_pushinteger(L, user_node_value(n)); \
1513  break; \
1514  case 'l': \
1515  if (user_node_value(n) != 0) { \
1516  lua_rawgeti(L, LUA_REGISTRYINDEX, user_node_value(n)); \
1517  } else { \
1518  lua_pushnil(L); \
1519  } \
1520  break; \
1521  case 'n': \
1522  nodelib_pushdirect(user_node_value(n)); \
1523  break; \
1524  case 's': \
1525  nodelib_pushstring(L, user_node_value(n)); \
1526  break; \
1527  case 't': \
1528  tokenlist_to_lua(L, user_node_value(n)); \
1529  break; \
1530  default: \
1531  lua_pushinteger(L, user_node_value(n)); \
1532  break; \
1533  } \
1534 } while (0)
1535 
1536 #define set_user_node_direct_value(L,n,i) do { \
1537  switch (user_node_type(n)) { \
1538  case 'a': \
1539  user_node_value(n) = nodelib_getlist(L, i); \
1540  break; \
1541  case 'd': \
1542  user_node_value(n) = (halfword) lua_roundnumber(L, i); \
1543  break; \
1544  case 'l': \
1545  lua_pushvalue(L, i); \
1546  if (user_node_value(n) != 0) { \
1547  luaL_unref(L, LUA_REGISTRYINDEX,user_node_value(n)); \
1548  } \
1549  user_node_value(n) = luaL_ref(L, LUA_REGISTRYINDEX); \
1550  break; \
1551  case 'n': \
1552  user_node_value(n) = nodelib_getlist(L, i); \
1553  break; \
1554  case 's': \
1555  user_node_value(n) = nodelib_getstring(L, i); \
1556  break; \
1557  case 't': \
1558  user_node_value(n) = nodelib_gettoks(L, i); \
1559  break; \
1560  default: \
1561  user_node_value(n) = (halfword) lua_roundnumber(L, i); \
1562  break; \
1563  } \
1564 } while (0)
1565 
1566 #define get_pdf_literal_direct_value(L,n) do { \
1567  if (pdf_literal_type(n) == lua_refid_literal) { \
1568  lua_rawgeti(L, LUA_REGISTRYINDEX, pdf_literal_data(n)); \
1569  } else if (pdf_literal_type(n) == lua_refid_literal) { \
1570  tokenlist_to_luastring(L, pdf_literal_data(n)); \
1571  } \
1572 } while (0)
1573 
1574 #define set_pdf_literal_direct_normal(L,n,i) do { \
1575  if (ini_version) { \
1576  pdf_literal_data(n) = nodelib_gettoks(L, i); \
1577  pdf_literal_type(n) = normal; \
1578  } else { \
1579  lua_pushvalue(L, i); \
1580  pdf_literal_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); \
1581  pdf_literal_type(n) = lua_refid_literal; \
1582  } \
1583 } while (0)
1584 
1585 #define set_pdf_literal_direct_token(L,n,i) do { \
1586  pdf_literal_data(n) = nodelib_gettoks(L, i); \
1587 } while (0)
1588 
1589 #define cleanup_late_lua(n) do { \
1590  if (late_lua_data(n) != 0) { \
1591  if (late_lua_type(n) == normal) { \
1592  delete_token_ref(late_lua_data(n)); \
1593  } else if (late_lua_type(n) == lua_refid_literal) { \
1594  luaL_unref(L, LUA_REGISTRYINDEX,late_lua_data(n)); \
1595  } \
1596  } \
1597 } while (0)
1598 
1599 #define cleanup_late_lua_name(n) do { \
1600  if (late_lua_name(n) != 0) { \
1601  delete_token_ref(late_lua_name(n)); \
1602  } \
1603 } while (0)
1604 
1605 #define set_late_lua_direct_normal(L,n,i) do { \
1606  cleanup_late_lua(n) ; \
1607  if (ini_version) { \
1608  late_lua_data(n) = nodelib_gettoks(L, i); \
1609  late_lua_type(n) = normal; \
1610  } else if (lua_type(L, i) == LUA_TNUMBER) { \
1611  late_lua_data(n) = lua_tointeger(L,i); \
1612  late_lua_type(n) = lua_refid_call; \
1613  } else { \
1614  lua_pushvalue(L, i); \
1615  late_lua_data(n) = luaL_ref(L, LUA_REGISTRYINDEX); \
1616  late_lua_type(n) = lua_refid_literal; \
1617  } \
1618 } while (0)
1619 
1620 #define set_late_lua_direct_token(L,n,i) do { \
1621  cleanup_late_lua(n) ; \
1622  late_lua_data(n) = nodelib_gettoks(L, i); \
1623  late_lua_type(n) = normal; \
1624 } while (0)
1625 
1626 #define get_late_lua_direct_value(L,n) do { \
1627  if (late_lua_type(n) == lua_refid_literal) { \
1628  lua_rawgeti(L, LUA_REGISTRYINDEX, late_lua_data(n)); \
1629  } else if (late_lua_type(n) == lua_refid_call) { \
1630  lua_pushinteger(L, late_lua_data(n)); \
1631  } else if (late_lua_type(n) == normal) { \
1632  tokenlist_to_luastring(L, late_lua_data(n)); \
1633  } \
1634 } while (0)
1635 
1636 #define set_special_direct_value(L,n,i) do { \
1637  write_tokens(n) = nodelib_gettoks(L, i); \
1638 } while (0)
1639 
1640 #define get_special_direct_value(L,n) do { \
1641  tokenlist_to_luastring(L, write_tokens(n)); \
1642 } while (0)
1643 
1644 #define set_write_direct_value(L,n,i) do { \
1645  write_tokens(n) = nodelib_gettoks(L, i); \
1646 } while (0)
1647 
1648 #define xget_write_direct_value(L,n) do { \
1649  tokenlist_to_lua(L, write_tokens(n)); \
1650 } while (0)
1651 
1652 #define get_write_direct_value(L,n) do { \
1653  int l; \
1654  char *s; \
1655  expand_macros_in_tokenlist(n); \
1656  s = tokenlist_to_cstring(def_ref, 1, &l); \
1657  lua_pushlstring(L, s, (size_t) l); \
1658  free(s); \
1659  flush_list(def_ref); \
1660 } while (0)
1661 
1662 #define set_pdf_setmatrix_direct_value(L,n,i) do { \
1663  pdf_setmatrix_data(n) = nodelib_gettoks(L, i); \
1664 } while (0)
1665 
1666 #define get_pdf_setmatrix_direct_value(L,n) do { \
1667  tokenlist_to_luastring(L, pdf_setmatrix_data(n)); \
1668 } while (0)
1669 
1670 /*tex
1671 
1672  These getter and setter get |data| as well as |value| fields. One can
1673  make them equivalent to |getvalue| and |setvalue| if needed.
1674 
1675 */
1676 
1678 {
1679  halfword n = lua_tointeger(L, 1);
1680  if (n == null) {
1681  lua_pushnil(L);
1682  } else {
1683  halfword t = type(n) ;
1684  if (t == glyph_node) {
1686  } else if (t == boundary_node) {
1688  } else if (t == whatsit_node) {
1689  halfword s = subtype(n);
1690  if (s == user_defined_node) {
1692  } else if (s == pdf_literal_node) {
1694  /*tex A bonus. */
1696  return 2;
1697  } else if (s == late_lua_node) {
1699  } else if (s == pdf_setmatrix_node) {
1701  } else if (s == special_node) {
1703  } else if (s == write_node) {
1705  } else {
1706  lua_pushnil(L);
1707  }
1708  } else {
1709  lua_pushnil(L);
1710  }
1711  }
1712  return 1;
1713 }
1714 
1715 static int lua_nodelib_direct_setdata(lua_State * L) /* data and value */
1716 {
1717  halfword n = lua_tointeger(L, 1);
1718  if (n != null) {
1719  halfword t = type(n) ;
1720  if (t == glyph_node) {
1722  } else if (t == boundary_node) {
1724  } else if (t == whatsit_node) {
1725  halfword s = subtype(n);
1726  if (s == user_defined_node) {
1728  } else if (s == pdf_literal_node) {
1730  if (lua_type(L,2) == LUA_TNUMBER) {
1731  /*tex A bonus. */
1733  }
1734  } else if (s == late_lua_node) {
1736  } else if (s == pdf_setmatrix_node) {
1738  } else if (s == special_node) {
1740  } else if (s == write_node) {
1742  }
1743  }
1744  }
1745  return 0;
1746 }
1747 
1748 /* node.direct.getnext */
1749 /* node.direct.setnext */
1750 
1752 {
1753  halfword p = lua_tointeger(L, 1);
1754  if (p == null) {
1755  lua_pushnil(L);
1756  } else {
1758  }
1759  return 1;
1760 }
1761 
1763 {
1764  halfword n = lua_tointeger(L, 1);
1765  if (n) {
1766  if (lua_type(L, 2) == LUA_TNUMBER) {
1767  vlink(n) = (halfword) lua_tointeger(L, 2);
1768  } else {
1769  vlink(n) = null;
1770  }
1771  }
1772  return 0;
1773 }
1774 
1775  /* node.getnext */
1776 
1778  {
1779  halfword *a;
1780  /* [given-node] [...]*/
1781  halfword *p = lua_touserdata(L, 1);
1782  if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
1783  lua_pushnil(L);
1784  } else {
1785  /* [given-node] [mt-given-node]*/
1786  lua_get_metatablelua(luatex_node);
1787  /* [given-node] [mt-given-node] [mt-node]*/
1788  if (!lua_rawequal(L, -1, -2)) {
1789  lua_pushnil(L);
1790  } else {
1792  }
1793  }
1794  return 1; /* just one*/
1795  }
1796 
1797 /* node.direct.getprev */
1798 /* node.direct.setprev */
1799 
1801 {
1802  halfword p = lua_tointeger(L, 1);
1803  if (p == null) {
1804  lua_pushnil(L);
1805  } else {
1807  }
1808  return 1;
1809 }
1810 
1812 {
1813  halfword n = lua_tointeger(L, 1);
1814  if (n) {
1815  if (lua_type(L, 2) == LUA_TNUMBER) {
1816  alink(n) = (halfword) lua_tointeger(L, 2);
1817  } else {
1818  alink(n) = null;
1819  }
1820  }
1821  return 0;
1822 }
1823 
1824  /* node.getprev */
1825 
1827  {
1828  halfword *a;
1829  halfword *p = lua_touserdata(L, 1);
1830  if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
1831  lua_pushnil(L);
1832  } else {
1833  lua_get_metatablelua(luatex_node);
1834  if (!lua_rawequal(L, -1, -2)) {
1835  lua_pushnil(L);
1836  } else {
1838  }
1839  }
1840  return 1;
1841  }
1842 
1843 /* node.direct.getboth */
1844 /* node.direct.setboth */
1845 
1847 {
1848  halfword n = lua_tointeger(L, 1);
1849  if (n) {
1852  } else {
1853  lua_pushnil(L);
1854  lua_pushnil(L);
1855  }
1856  return 2;
1857 }
1858 
1860 {
1861  halfword n = lua_tointeger(L, 1);
1862  if (n) {
1863  if (lua_type(L, 2) == LUA_TNUMBER) {
1864  alink(n) = (halfword) lua_tointeger(L, 2);
1865  } else {
1866  alink(n) = null;
1867  }
1868  if (lua_type(L, 3) == LUA_TNUMBER) {
1869  vlink(n) = (halfword) lua_tointeger(L, 3);
1870  } else {
1871  vlink(n) = null;
1872  }
1873  }
1874  return 0;
1875 }
1876 
1877  /* node.getboth */
1878 
1880  {
1881  halfword *a;
1882  halfword *p = lua_touserdata(L, 1);
1883  if ( (p == NULL) || (! lua_getmetatable(L,1)) ) {
1884  lua_pushnil(L);
1885  lua_pushnil(L);
1886  } else {
1887  lua_get_metatablelua(luatex_node);
1888  if (lua_rawequal(L, -1, -2)) {
1891  } else {
1892  lua_pushnil(L);
1893  lua_pushnil(L);
1894  }
1895  }
1896  return 2;
1897  }
1898 
1899 /* node.direct.setlink */
1900 /* node.direct.setsplit */
1901 
1902 /*
1903  a b b nil c d : prev-a-b-c-next
1904  nil a b b nil c d nil : nil-a-b-c-nil
1905 */
1906 
1908 {
1909  int n = lua_gettop(L);
1910  int i;
1911  halfword h = null; /* head node */
1912  halfword t = null; /* tail node */
1913  halfword c = null; /* current node */
1914  for (i=1;i<=n;i++) {
1915  /*
1916  we don't go for the tail of the current node because we can inject
1917  between existing nodes and the nodes themselves can have old values
1918  for prev and next, so ... only single nodes are looked at!
1919  */
1920  if (lua_type(L, i) == LUA_TNUMBER) {
1921  c = lua_tointeger(L, i);
1922  if (c != t) {
1923  if (t != null) {
1924  vlink(t) = c;
1925  alink(c) = t;
1926  } else if (i > 1) {
1927  /* we assume that the first node is a kind of head */
1928  alink(c) = null;
1929  }
1930  t = c;
1931  if (h == null) {
1932  h = t;
1933  }
1934  } else {
1935  /* we ignore duplicate nodes which can be tails or the previous */
1936  }
1937  } else if (t == null) {
1938  /* we just ignore nil nodes and have no tail yet */
1939  } else {
1940  /* safeguard: a nil in the list can be meant as end so we nil the next of tail */
1941  vlink(t) = null;
1942  }
1943  }
1944  if (h == null) {
1945  /* no head */
1946  lua_pushnil(L);
1947  } else {
1948  /* first valid head */
1949  lua_pushinteger(L,h);
1950  }
1951  return 1;
1952 }
1953 
1955 {
1956  if (lua_type(L, 1) == LUA_TNUMBER && (lua_type(L, 2) == LUA_TNUMBER)) {
1957  halfword l = lua_tointeger(L, 1);
1958  halfword r = lua_tointeger(L, 2);
1959  if (l != r) {
1960  alink(vlink(l)) = null;
1961  vlink(alink(r)) = null;
1962  }
1963  vlink(l) = null;
1964  alink(r) = null;
1965  }
1966  return 0;
1967 }
1968 
1969 /* node.subtype (maybe also return them for other node types now) */
1970 
1972 {
1973  if (lua_type(L,1) == LUA_TSTRING) {
1975  if (i >= 0) {
1976  lua_pushinteger(L, i);
1977  } else {
1978  lua_pushnil(L);
1979  }
1980  } else {
1981  lua_pushnil(L);
1982  }
1983  return 1;
1984 }
1985 
1986 /* node.type (converts id numbers to type names) */
1987 
1989 {
1990  if (lua_type(L,1) == LUA_TNUMBER) {
1991  int i = lua_tointeger(L, 1);
1992  if (known_node_type(i)) {
1993  /* lua_pushstring(L, node_data[i].name); */
1995  return 1;
1996  }
1997  } else if (maybe_isnode(L, 1) != NULL) {
1998  /* lua_pushstring(L,"node"); */
2000  return 1;
2001  }
2002  lua_pushnil(L);
2003  return 1;
2004 }
2005 
2006 /* node.new (allocate a new node) */
2007 
2009 {
2010  int i, j;
2011  int t = lua_type(L, 1);
2012  if (t == LUA_TNUMBER) {
2013  i = lua_tointeger(L,1);
2014  if (! known_node_type(i)) {
2015  i = -1;
2016  }
2017  } else if (t == LUA_TSTRING) {
2019  } else {
2020  i = -1;
2021  }
2022  if (i < 0) {
2023  luaL_error(L, "invalid node id for creating new node");
2024  }
2025  t = lua_type(L, 2);
2026  if (i == whatsit_node) {
2027  if (t == LUA_TNUMBER) {
2028  j = lua_tointeger(L,2);
2029  if (! known_whatsit_type(j)) {
2030  j = -1;
2031  }
2032  } else if (t == LUA_TSTRING) {
2034  } else {
2035  j = -1;
2036  }
2037  if (j < 0) {
2038  luaL_error(L, "creating a whatsit requires the subtype number as a second argument");
2039  }
2040  } else if (t == LUA_TNUMBER) {
2041  j = (int) lua_tointeger(L, 2);
2042  } else if (t == LUA_TSTRING) {
2043  j = get_node_subtype_id_from_name(L,2,node_data[i].subtypes);
2044  } else {
2045  j = 0;
2046  }
2047  return new_node(i, j);
2048 }
2049 
2051 {
2054  return 1;
2055 }
2056 
2057 /* node.direct.new */
2058 
2060 {
2062  lua_pushinteger(L,n);
2063  return 1;
2064 }
2065 
2066 /* node.free (this function returns the 'next' node, because that may be helpful) */
2067 
2069 {
2070  halfword n;
2071  halfword p;
2072  if (lua_gettop(L) < 1) {
2073  lua_pushnil(L);
2074  return 1;
2075  } else if (lua_isnil(L, 1)) {
2076  return 1; /* the nil itself */
2077  }
2078  n = *(check_isnode(L, 1));
2079  p = vlink(n);
2080  flush_node(n);
2081  /* can be: lua_nodelib_push_fast(L, p); */
2082  lua_pushinteger(L, p);
2084  return 1;
2085 }
2086 
2087 /* node.direct.free */
2088 
2090 {
2091  halfword n = lua_tointeger(L,1);
2092  if (n == null) {
2093  lua_pushnil(L);
2094  } else {
2095  halfword p = vlink(n);
2096  flush_node(n);
2097  if (p == 0) {
2098  lua_pushnil(L);
2099  } else {
2100  lua_pushinteger(L,p);
2101  }
2102  }
2103  return 1;
2104 }
2105 
2106 /* node.flush_node (no next returned) */
2107 
2109 {
2110  if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
2111  return 0;
2112  } else {
2113  halfword n = *(check_isnode(L, 1));
2114  flush_node(n);
2115  return 0;
2116  }
2117 }
2118 
2119 /* node.direct.flush_node */
2120 
2122 {
2123  halfword n = lua_tointeger(L,1);
2124  if (n == null)
2125  return 0;
2126  flush_node(n);
2127  return 0;
2128 }
2129 
2130 /* node.flush_list */
2131 
2133 {
2134  if ((lua_gettop(L) < 1) || lua_isnil(L, 1)) {
2135  return 0;
2136  } else {
2137  halfword n_ptr = *check_isnode(L, 1);
2138  flush_node_list(n_ptr);
2139  return 0;
2140  }
2141 }
2142 
2143 /* node.direct.flush_list */
2144 
2146 {
2147  halfword n = lua_tointeger(L,1);
2148  if (n == null)
2149  return 0;
2150  flush_node_list(n);
2151  return 0;
2152 }
2153 
2154 /* remove a node from a list */
2155 
2156 #if DEBUG
2157 
2158  static void show_node_links (halfword l, const char * p)
2159  {
2160  halfword t = l;
2161  while (t) {
2162  fprintf(DEBUG_OUT, "%s t = %d, prev = %d, next = %d\n", p, (int)t, (int)alink(t), (int)vlink(t));
2163  t = vlink(t);
2164  }
2165  }
2166 
2167 #endif
2168 
2169 /* node.remove */
2170 
2172 {
2173  halfword head, current, t;
2174  if (lua_gettop(L) < 2)
2175  luaL_error(L, "Not enough arguments for node.remove()");
2176  head = *(check_isnode(L, 1));
2177  if (lua_isnil(L, 2))
2178  return 2; /* the arguments, as they are */
2179  current = *(check_isnode(L, 2));
2180  if (head == current) {
2181  if (alink(current)){
2183  }
2184  if (vlink(current)){
2186  }
2187 
2188  head = vlink(current);
2189  current = vlink(current);
2190  } else {
2191  t = alink(current);
2192  if (t == null || vlink(t) != current) {
2194  if (t == null) /* error! */
2195  luaL_error(L,"Attempt to node.remove() a non-existing node");
2196  }
2197  /* t is now the previous node */
2198  vlink(t) = vlink(current);
2199  if (vlink(current) != null)
2200  alink(vlink(current)) = t;
2201  current = vlink(current);
2202  }
2203  /* can be: lua_nodelib_push_fast(L, head); */
2206  /* can be: lua_nodelib_push_fast(L, current); */
2209  return 2;
2210 }
2211 
2212 /* node.direct.remove */
2213 
2215 {
2216  halfword current, t;
2218  if (head == null) {
2219  lua_pushnil(L);
2220  lua_pushnil(L);
2221  return 2 ;
2222  }
2224  if (current == null) {
2226  lua_pushnil(L);
2227  return 2 ;
2228  }
2229  if (head == current) {
2230  if (alink(current)){
2231  vlink( alink(current) ) = vlink(current);
2232  }
2233  if (vlink(current)){
2234  alink( vlink(current) ) = alink(current);
2235  }
2236  head = vlink(current);
2237  current = vlink(current);
2238  } else {
2239  t = alink(current);
2240  if (t == null || vlink(t) != current) {
2242  if (t == null) {
2243  luaL_error(L,"Attempt to node.direct.remove() a non-existing node");
2244  }
2245  }
2246  vlink(t) = vlink(current);
2247  if (vlink(current) != null)
2248  alink(vlink(current)) = t;
2249  current = vlink(current);
2250  }
2251  if (head == null) {
2252  lua_pushnil(L);
2253  } else {
2255  }
2256  if (current == null) {
2257  lua_pushnil(L);
2258  } else {
2260  }
2261  return 2;
2262 }
2263 
2264 /* node.insert_before (insert a node in a list) */
2265 
2267 {
2268  halfword head, current, n, t;
2269  if (lua_gettop(L) < 3) {
2270  luaL_error(L, "Not enough arguments for node.insert_before()");
2271  }
2272  if (lua_isnil(L, 3)) {
2273  lua_pop(L, 1);
2274  return 2;
2275  } else {
2276  n = *(check_isnode(L, 3));
2277  }
2278  if (lua_isnil(L, 1)) { /* no head */
2279  vlink(n) = null;
2280  alink(n) = null;
2282  lua_pushvalue(L, -1);
2283  return 2;
2284  } else {
2285  head = *(check_isnode(L, 1));
2286  }
2287  if (lua_isnil(L, 2)) {
2289  } else {
2290  current = *(check_isnode(L, 2));
2291  }
2292  if (head != current) {
2293  t = alink(current);
2294  if (t == null || vlink(t) != current) {
2296  if (t == null) { /* error! */
2297  luaL_error(L, "Attempt to node.insert_before() a non-existing node");
2298  }
2299  }
2300  couple_nodes(t, n);
2301  }
2303  if (head == current) {
2305  } else {
2307  }
2309  return 2;
2310 }
2311 
2312 /* node.direct.insert_before */
2313 
2315 {
2317  halfword n = lua_tointeger(L,3);
2318  if (n == null){
2319  /* no node */
2320  lua_pop(L, 1);
2321  return 2 ;
2322  }
2323  head = (halfword) lua_tointeger(L,1);
2325  /* no head, ignore current */
2326  if (head == null) {
2327  vlink(n) = null;
2328  alink(n) = null;
2329  lua_pushinteger(L, n);
2330  lua_pushvalue(L, -1);
2331  /* n, n */
2332  return 2;
2333  }
2334  /* no current */
2335  if (current == null)
2337  if (head != current) {
2338  halfword t = alink(current);
2339  if (t == null || vlink(t) != current) {
2341  }
2342  couple_nodes(t, n);
2343  }
2344  couple_nodes(n, current); /* nice but incompatible: couple_nodes(tail_of_list(n),current) */
2345  if (head == current) {
2346  lua_pushinteger(L, n);
2347  } else {
2349  }
2350  lua_pushinteger(L, n);
2351  return 2;
2352 }
2353 
2354 /* node.insert_after */
2355 
2357 {
2358  halfword head, current, n;
2359  if (lua_gettop(L) < 3) {
2360  luaL_error(L, "Not enough arguments for node.insert_after()");
2361  }
2362  if (lua_isnil(L, 3)) {
2363  lua_pop(L, 1);
2364  return 2;
2365  } else {
2366  n = *(check_isnode(L, 3));
2367  }
2368  if (lua_isnil(L, 1)) { /* no head */
2369  vlink(n) = null;
2370  alink(n) = null;
2372  lua_pushvalue(L, -1);
2373  return 2;
2374  } else {
2375  head = *(check_isnode(L, 1));
2376  }
2377  if (lua_isnil(L, 2)) {
2378  current = head;
2379  while (vlink(current) != null)
2380  current = vlink(current);
2381  } else {
2382  current = *(check_isnode(L, 2));
2383  }
2386 
2387  lua_pop(L, 2);
2389  return 2;
2390 }
2391 
2392 /* node.direct.insert_after */
2393 
2395 {
2397  /*[head][current][new]*/
2398  halfword n = lua_tointeger(L,3);
2399  if (n == null) {
2400  /* no node */
2401  return 2 ;
2402  }
2403  head = (halfword) lua_tointeger(L,1);
2405  if (head == null) {
2406  /* no head, ignore current */
2407  vlink(n) = null;
2408  alink(n) = null;
2409  lua_pushinteger(L,n);
2410  lua_pushvalue(L, -1);
2411  /* n, n */
2412  return 2;
2413  }
2414  if (current == null) {
2415  /* no current */
2416  current = head;
2417  while (vlink(current) != null)
2418  current = vlink(current);
2419  }
2420  try_couple_nodes(n, vlink(current)); /* nice but incompatible: try_couple_nodes(tail_of_list(n), vlink(current)); */
2422  lua_pop(L, 2);
2423  lua_pushinteger(L, n);
2424  return 2;
2425 }
2426 
2427 /* node.copy_list */
2428 
2429 /*
2430  we need to use an intermediate variable as otherwise target is used in the loop
2431  and subfields get overwritten (or something like that) which results in crashes
2432  and unexpected side effects
2433 */
2434 
2436 {
2437  halfword n, s = null;
2438  halfword m;
2439  if (lua_isnil(L, 1))
2440  return 1; /* the nil itself */
2441  n = *check_isnode(L, 1);
2442  if ((lua_gettop(L) > 1) && (!lua_isnil(L,2)))
2443  s = *check_isnode(L, 2);
2444  m = do_copy_node_list(n, s);
2446  return 1;
2447 }
2448 
2449 /* node.direct.copy_list */
2450 
2452 {
2453  halfword n = lua_tointeger(L,1);
2454  if (n == null) {
2455  lua_pushnil(L);
2456  } else {
2457  halfword s = lua_tointeger(L,2);
2458  halfword m;
2459  if (s == null) {
2460  m = do_copy_node_list(n,null);
2461  } else {
2462  m = do_copy_node_list(n,s);
2463  }
2464  lua_pushinteger(L,m);
2465  }
2466  return 1;
2467 }
2468 
2469 /* node.copy (deep copy) */
2470 
2472 {
2473  halfword n;
2474  if (lua_isnil(L, 1))
2475  return 1; /* the nil itself */
2476  n = *check_isnode(L, 1);
2477  n = copy_node(n);
2479  return 1;
2480 }
2481 
2482 /* node.direct.copy (deep copy) */
2483 
2485 {
2486  if (lua_isnil(L, 1)) {
2487  return 1; /* the nil itself */
2488  } else {
2489  /* beware, a glue node can have number 0 (zeropt) so we cannot test for null) */
2490  halfword n = lua_tointeger(L, 1);
2491  n = copy_node(n);
2492  lua_pushinteger(L, n);
2493  return 1;
2494  }
2495 }
2496 
2497 
2498 /* node.write (output a node to tex's processor) */
2499 
2501 {
2502  halfword n;
2503  int i;
2504  int j = lua_gettop(L);
2505  for (i = 1; i <= j; i++) {
2506  n = *check_isnode(L, i);
2507  tail_append(n);
2508  if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
2510  }
2511  while (vlink(n) != null) {
2512  n = vlink(n);
2513  tail_append(n);
2514  if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
2516  }
2517  }
2518  }
2519  return 0;
2520 }
2521 
2522 /* node.direct.write */
2523 
2525 {
2526  halfword m;
2527  int i;
2528  int j = lua_gettop(L);
2529  for (i = 1; i <= j; i++) {
2530  halfword n = lua_tointeger(L,i); /*lua_getnumber(L, i);*/
2531  if (n != null) {
2532  m = n ;
2533  tail_append(m);
2534  if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
2536  }
2537  while (vlink(m) != null) {
2538  m = vlink(m);
2539  tail_append(m);
2540  if (nodetype_has_attributes(type(n)) && node_attr(n) == null) {
2542  }
2543  }
2544  }
2545  }
2546  return 0;
2547 }
2548 
2549 /* node.last */
2550 
2552 {
2553  halfword m = pop_tail();
2554  /* can be: lua_nodelib_push_fast(L, m); */
2555  lua_pushinteger(L, m);
2557  return 1;
2558 }
2559 
2560 /* node.direct.last */
2561 
2563 {
2564  halfword m = pop_tail();
2565  lua_pushinteger(L, m);
2566  return 1;
2567 }
2568 
2569 /* node.hpack (build a hbox) */
2570 
2572 {
2573  halfword p;
2574  const char *s;
2575  int w = 0;
2576  int m = 1;
2577  int d = -1;
2578  halfword n = *(check_isnode(L, 1));
2579  if (lua_gettop(L) > 1) {
2580  w = lua_roundnumber(L, 2);
2581  if (lua_gettop(L) > 2) {
2582  if (lua_type(L, 3) == LUA_TSTRING) {
2583  s = lua_tostring(L, 3);
2584  if (lua_key_eq(s, exactly)) {
2585  m = 0;
2586  } else if (lua_key_eq(s, additional)) {
2587  m = 1;
2588  } else if (lua_key_eq(s, cal_expand_ratio)) {
2589  m = 2;
2590  } else if (lua_key_eq(s, subst_ex_font)) {
2591  m = 3;
2592  }
2593  } else if (lua_type(L, 3) == LUA_TNUMBER) {
2594  m = (int) lua_tointeger(L, 3);
2595  }
2596  if ((m<0) || (m>3)) {
2597  luaL_error(L, "wrong mode in hpack");
2598  }
2599  if (lua_gettop(L) > 3) {
2600  if (lua_type(L, 4) == LUA_TNUMBER) {
2601  d = nodelib_getdirection(L, 4);
2602  } else if (lua_type(L, 4) == LUA_TSTRING) {
2603  d = nodelib_getdir_par(L, 4);
2604  } else {
2605  lua_pushstring(L, "incorrect 4th argument");
2606  }
2607  }
2608  }
2609  }
2610  p = hpack(n, w, m, d);
2613  return 2;
2614 }
2615 
2616 /* node.direct.hpack */
2617 
2619 {
2620  halfword p;
2621  const char *s;
2622  int w = 0;
2623  int m = 1;
2624  int d = -1;
2625  halfword n = lua_tointeger(L,1);
2626  /* could be macro */
2627  if (lua_gettop(L) > 1) {
2628  w = lua_roundnumber(L, 2);
2629  if (lua_gettop(L) > 2) {
2630  if (lua_type(L, 3) == LUA_TSTRING) {
2631  s = lua_tostring(L, 3);
2632  if (lua_key_eq(s, additional)) {
2633  m = 1;
2634  } else if (lua_key_eq(s, exactly)) {
2635  m = 0;
2636  } else if (lua_key_eq(s, cal_expand_ratio)) {
2637  m = 2;
2638  } else if (lua_key_eq(s, subst_ex_font)) {
2639  m = 3;
2640  } else {
2641  luaL_error(L, "3rd argument should be either additional or exactly");
2642  }
2643  } else if (lua_type(L, 3) == LUA_TNUMBER) {
2644  m = (int) lua_tointeger(L, 3);
2645  } else {
2646  lua_pushstring(L, "incorrect 3rd argument");
2647  }
2648  if (lua_gettop(L) > 3) {
2649  if (lua_type(L, 4) == LUA_TNUMBER) {
2650  d = nodelib_getdirection(L, 4);
2651  } else if (lua_type(L, 4) == LUA_TSTRING) {
2652  d = nodelib_getdir_par(L, 4);
2653  } else {
2654  lua_pushstring(L, "incorrect 4th argument");
2655  }
2656  }
2657  }
2658  }
2659  /* till here */
2660  p = hpack(n, w, m, d);
2661  lua_pushinteger(L, p);
2663  return 2;
2664 }
2665 
2666 /* node.vpack (build a vbox) */
2667 
2669 {
2670  halfword p;
2671  const char *s;
2672  int w = 0;
2673  int m = 1;
2674  int d = -1;
2675  halfword n = *(check_isnode(L, 1));
2676  if (lua_gettop(L) > 1) {
2677  w = lua_roundnumber(L, 2);
2678  if (lua_gettop(L) > 2) {
2679  if (lua_type(L, 3) == LUA_TSTRING) {
2680  s = lua_tostring(L, 3);
2681  if (lua_key_eq(s, additional)) {
2682  m = 1;
2683  } else if (lua_key_eq(s, exactly)) {
2684  m = 0;
2685  } else {
2686  luaL_error(L, "3rd argument should be either additional or exactly");
2687  }
2688 
2689  if (lua_gettop(L) > 3) {
2690  if (lua_type(L, 4) == LUA_TNUMBER) {
2691  d = nodelib_getdirection(L, 4);
2692  } else if (lua_type(L, 4) == LUA_TSTRING) {
2693  d = nodelib_getdir_par(L, 4);
2694  } else {
2695  lua_pushstring(L, "incorrect 4th argument");
2696  }
2697  }
2698  }
2699 
2700  else if (lua_type(L, 3) == LUA_TNUMBER) {
2701  m= (int) lua_tointeger(L, 3);
2702  } else {
2703  lua_pushstring(L, "incorrect 3rd argument");
2704  }
2705  }
2706  }
2707  p = vpackage(n, w, m, max_dimen, d);
2710  return 2;
2711 }
2712 
2713 /* node.direct.vpack */
2714 
2716 {
2717  halfword p;
2718  const char *s;
2719  int w = 0;
2720  int m = 1;
2721  int d = -1;
2723  if (lua_gettop(L) > 1) {
2724  w = lua_roundnumber(L, 2);
2725  if (lua_gettop(L) > 2) {
2726  if (lua_type(L, 3) == LUA_TSTRING) {
2727  s = lua_tostring(L, 3);
2728  if (lua_key_eq(s, additional)) {
2729  m = 1;
2730  } else if (lua_key_eq(s, exactly)) {
2731  m = 0;
2732  } else {
2733  luaL_error(L, "3rd argument should be either additional or exactly");
2734  }
2735 
2736  if (lua_gettop(L) > 3) {
2737  if (lua_type(L, 4) == LUA_TNUMBER) {
2738  d = nodelib_getdirection(L, 4);
2739  } else if (lua_type(L, 4) == LUA_TSTRING) {
2740  d = nodelib_getdir_par(L, 4);
2741  } else {
2742  lua_pushstring(L, "incorrect 4th argument");
2743  }
2744  }
2745  }
2746 
2747  else if (lua_type(L, 3) == LUA_TNUMBER) {
2748  m= (int) lua_tointeger(L, 3);
2749  } else {
2750  lua_pushstring(L, "incorrect 3rd argument");
2751  }
2752  }
2753  }
2754  p = vpackage(n, w, m, max_dimen, d);
2755  lua_pushinteger(L, p);
2757  return 2;
2758 }
2759 
2760 /* node.dimensions (of a hlist or vlist) */
2761 
2763 {
2764  int top = lua_gettop(L);
2765  if (top > 0) {
2766  scaled_whd siz;
2767  glue_ratio g_mult = 1.0;
2768  int g_sign = normal;
2769  int g_order = normal;
2770  int i = 1;
2771  int d = -1;
2772  halfword n = null, p = null;
2773  if (lua_type(L, 1) == LUA_TNUMBER) {
2774  if (top < 4) {
2775  lua_pushnil(L);
2776  return 1;
2777  }
2778  i += 3;
2779  g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
2780  g_sign = (int) lua_tointeger(L, 2);
2781  g_order = (int) lua_tointeger(L, 3);
2782  }
2783  n = *(check_isnode(L, i));
2784  if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
2785  if (lua_type(L, (i + 1)) == LUA_TSTRING) {
2786  d = nodelib_getdir_par(L, (i + 1));
2787  } else {
2788  p = *(check_isnode(L, (i + 1)));
2789  }
2790  }
2791  if (lua_gettop(L) > (i + 1)) {
2792  if (lua_type(L, (i + 2)) == LUA_TNUMBER) {
2793  d = nodelib_getdirection(L, (i + 2));
2794  } else if (lua_type(L, (i + 2)) == LUA_TSTRING) {
2795  d = nodelib_getdir_par(L, (i + 2));
2796  }
2797  }
2798  siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
2799  lua_pushinteger(L, siz.wd);
2800  lua_pushinteger(L, siz.ht);
2801  lua_pushinteger(L, siz.dp);
2802  return 3;
2803  } else {
2804  luaL_error(L, "missing argument to 'dimensions' (node expected)");
2805  }
2806  return 0; /* not reached */
2807 }
2808 
2809 static int lua_nodelib_rangedimensions(lua_State * L) /* parent, first, last */
2810 {
2811  int top = lua_gettop(L);
2812  if (top > 1) {
2813  scaled_whd siz;
2814  halfword l = *(check_isnode(L, 1)); /* parent */
2815  halfword n = *(check_isnode(L, 2)); /* first */
2816  halfword p = null;
2817  if (top > 2) {
2818  p = *(check_isnode(L, 3)); /* last */
2819  }
2821  lua_pushinteger(L, siz.wd);
2822  lua_pushinteger(L, siz.ht);
2823  lua_pushinteger(L, siz.dp);
2824  return 3;
2825  } else {
2826  luaL_error(L, "missing argument to 'rangedimensions' (2 or more nodes expected)");
2827  }
2828  return 0; /* not reached */
2829 }
2830 
2831 /* node.direct.dimensions*/
2832 
2834 {
2835  int top = lua_gettop(L);
2836  if (top > 0) {
2837  scaled_whd siz;
2838  glue_ratio g_mult = 1.0;
2839  int g_sign = normal;
2840  int g_order = normal;
2841  int i = 1;
2842  int d = -1;
2843  halfword n = null;
2844  halfword p = null;
2845  if (top > 3) {
2846  i += 3;
2847  g_mult = (glue_ratio) lua_tonumber(L, 1); /* integer or float */
2848  g_sign = (int) lua_tointeger(L, 2);
2849  g_order = (int) lua_tointeger(L, 3);
2850  }
2851  n = (halfword) lua_tointeger(L,i);
2852  if (lua_gettop(L) > i && !lua_isnil(L, (i + 1))) {
2853  if (lua_type(L, (i + 1)) == LUA_TSTRING) {
2854  d = nodelib_getdir_par(L, (i + 1));
2855  } else {
2856  p = (halfword) lua_tointeger(L,i+1);
2857  }
2858  }
2859  if (lua_gettop(L) > (i + 1)) {
2860  if (lua_type(L, (i + 2)) == LUA_TNUMBER) {
2861  d = nodelib_getdirection(L, (i + 2));
2862  } else if (lua_type(L, (i + 2)) == LUA_TSTRING) {
2863  d = nodelib_getdir_par(L, (i + 2));
2864  }
2865  }
2866  siz = natural_sizes(n, p, g_mult, g_sign, g_order, d);
2867  lua_pushinteger(L, siz.wd);
2868  lua_pushinteger(L, siz.ht);
2869  lua_pushinteger(L, siz.dp);
2870  return 3;
2871  } else {
2872  luaL_error(L, "missing argument to 'dimensions' (direct node expected)");
2873  }
2874  return 0; /* not reached */
2875 }
2876 
2877 static int lua_nodelib_direct_rangedimensions(lua_State * L) /* parent, first, last */
2878 {
2879  int top = lua_gettop(L);
2880  if (top > 1) {
2881  scaled_whd siz;
2882  halfword l = (halfword) lua_tointeger(L,1); /* parent */
2883  halfword n = (halfword) lua_tointeger(L,2); /* first */
2884  halfword p = null;
2885  if (top > 2) {
2886  p = (halfword) lua_tointeger(L,3); /* last */
2887  }
2889  lua_pushinteger(L, siz.wd);
2890  lua_pushinteger(L, siz.ht);
2891  lua_pushinteger(L, siz.dp);
2892  return 3;
2893  } else {
2894  luaL_error(L, "missing argument to 'rangedimensions' (2 or more direct nodes expected)");
2895  }
2896  return 0; /* not reached */
2897 }
2898 
2899 /* node.mlist_to_hlist (create a hlist from a formula) */
2900 
2902 {
2903  int w;
2904  boolean m;
2905  halfword n = *(check_isnode(L, 1));
2906  assign_math_style(L,2,w);
2907  luaL_checkany(L, 3);
2908  m = lua_toboolean(L, 3);
2909  mlist_to_hlist(n, m, w);
2910  alink(vlink(temp_head)) = null;
2912  return 1;
2913 }
2914 
2915 /* node.family_font */
2916 
2918 {
2919  int s;
2920  int f = luaL_checkinteger(L, 1);
2921  if (lua_gettop(L) == 2)
2922  s = lua_tointeger(L, 2); /* this should be a multiple of 256 ! */
2923  else
2924  s = 0;
2926  return 1;
2927 }
2928 
2929 /*
2930  This function is similar to |get_node_type_id|, for field
2931  identifiers. It has to do some more work, because not all
2932  identifiers are valid for all types of nodes.
2933 
2934  We can make this faster if needed but when this needs to
2935  be called often something is wrong with the code.
2936 
2937 */
2938 
2939 static int get_node_field_id(lua_State * L, int n, int node)
2940 {
2941  int t = type(node);
2942  const char *s = lua_tostring(L, n);
2943 
2944  if (s == NULL)
2945  return -2;
2946 
2947  if (lua_key_eq(s, next)) {
2948  return 0;
2949  } else if (lua_key_eq(s, id)) {
2950  return 1;
2951  } else if (lua_key_eq(s, subtype)) {
2952  if (nodetype_has_subtype(t)) {
2953  return 2;
2954  }
2955  } else if (lua_key_eq(s, attr)) {
2956  if (nodetype_has_attributes(t)) {
2957  return 3;
2958  }
2959  } else if (lua_key_eq(s, prev)) {
2960  if (nodetype_has_prev(t)) {
2961  return -1;
2962  }
2963  } else {
2964  int j;
2965  field_info *fields ;
2966  if (t == whatsit_node) {
2968  } else {
2969  fields = node_data[t].fields;
2970  }
2971  if (lua_key_eq(s, list)) {
2972  s = lua_key(head);
2973  }
2974  if (fields != NULL) {
2975  for (j = 0; fields[j].lua != 0; j++) {
2976  // if (strcmp(s, fields[j]) == 0) {
2977  if (fields[j].name == s) {
2978  return j + 3;
2979  }
2980  }
2981  }
2982  }
2983  return -2;
2984 }
2985 
2986 /* node.has_field */
2987 
2989 {
2990  int i = -2;
2991  if (!lua_isnil(L, 1))
2992  i = get_node_field_id(L, 2, *(check_isnode(L, 1)));
2993  lua_pushboolean(L, (i != -2));
2994  return 1;
2995 }
2996 
2997 /* node.is_char (node[,font]) */
2998 
3000 {
3001  halfword n = *(check_isnode(L, 1));
3002  if (type(n) != glyph_node) {
3003  lua_pushnil(L); /* no glyph at all */
3004  lua_pushinteger(L,type(n)); /* can save a lookup call */
3005  return 2;
3006  } else if (subtype(n) >= 256) {
3007  lua_pushboolean(L,0); /* a done glyph */
3008  } else if (lua_type(L,2) == LUA_TNUMBER) {
3009  halfword f = lua_tointeger(L, 2);
3010  if (f && f == font(n)) {
3011  lua_pushinteger(L,character(n)); /* a todo glyph in the asked font */
3012  } else {
3013  lua_pushboolean(L,0); /* a todo glyph in another font */
3014  }
3015  } else {
3016  lua_pushinteger(L,character(n)); /* a todo glyph */
3017  }
3018  return 1;
3019 }
3020 
3022 {
3023  halfword n = *(check_isnode(L, 1));
3024  if (type(n) != glyph_node) {
3025  lua_pushboolean(L,0);
3026  lua_pushinteger(L,type(n));
3027  } else {
3029  lua_pushinteger(L,font(n));
3030  }
3031  return 2;
3032 }
3033 
3034 /* node.direct.has_field */
3035 
3037 {
3038  int i = -2;
3039  halfword n = lua_tointeger(L, 1);
3040  if (n != null)
3041  i = get_node_field_id(L, 2, n);
3042  lua_pushboolean(L, (i != -2));
3043  return 1;
3044 }
3045 
3046 /* fetch the list of valid node types */
3047 
3049 {
3050  int i;
3051  lua_newtable(L);
3052  for (i = 0; data[i].id != -1; i++) {
3053  lua_pushstring(L, data[i].name);
3054  lua_rawseti(L, -2, data[i].id);
3055  }
3056  return 1;
3057 }
3058 
3059 /* node.types */
3060 
3062 {
3063  return do_lua_nodelib_types(L, node_data);
3064 }
3065 
3066 /* node.whatsits */
3067 
3069 {
3071 }
3072 
3073 /* node.fields (fetch the list of valid fields) */
3074 
3076 {
3077  int i = -1;
3078  int offset = 2;
3079  field_info *fields;
3080  int t = get_valid_node_type_id(L, 1);
3081  if (t == whatsit_node) {
3084  } else {
3085  fields = node_data[t].fields;
3086  }
3087  lua_checkstack(L, 2);
3088  lua_newtable(L);
3090  lua_rawseti(L, -2, 0);
3092  lua_rawseti(L, -2, 1);
3093  if (nodetype_has_subtype(t)) {
3095  lua_rawseti(L, -2, 2);
3096  offset++;
3097  }
3098  if (nodetype_has_prev(t)) {
3100  lua_rawseti(L, -2, -1);
3101  }
3102  if (fields != NULL) {
3103  for (i = 0; fields[i].lua != 0; i++) {
3104  // lua_pushstring(L, fields[i]); /* todo */
3106  lua_rawseti(L, -2, (i + offset));
3107  }
3108  }
3109  return 1;
3110 }
3111 
3113 {
3114  int i = -1;
3116  const char *s ;
3117  int t = lua_type(L,1);
3118  if (t == LUA_TSTRING) {
3119  /*
3120  delimiter options (bit set)
3121  delimiter modes (bit set)
3122  */
3123  s = lua_tostring(L,1);
3126  else if (lua_key_eq(s,glue)) values = node_values_fill;
3127  /* backend */
3129  else if (lua_key_eq(s,pdf_action)) values = node_values_pdf_action;
3130  else if (lua_key_eq(s,pdf_window)) values = node_values_pdf_window;
3132  /* extras */
3133  else if (lua_key_eq(s,pagestate)) values = other_values_page_states;
3134  }
3135  if (values != NULL) {
3136  lua_checkstack(L, 2);
3137  lua_newtable(L);
3138  for (i = 0; values[i].id >= 0 ; i++) {
3140  lua_rawseti(L, -2, values[i].id);
3141  }
3142  } else {
3143  lua_pushnil(L);
3144  }
3145  return 1;
3146 }
3147 
3149 {
3150  int i = -1;
3151  subtype_info *subtypes = NULL;
3152  const char *s ;
3153  int t = lua_type(L,1);
3154  if (t == LUA_TSTRING) {
3155  /* official accessors */
3156  s = lua_tostring(L,1);
3157  if (lua_key_eq(s,glyph)) subtypes = node_subtypes_glyph;
3158  else if (lua_key_eq(s,glue)) subtypes = node_subtypes_glue;
3159  else if (lua_key_eq(s,dir)) subtypes = node_subtypes_dir;
3160  else if (lua_key_eq(s,boundary)) subtypes = node_subtypes_boundary;
3161  else if (lua_key_eq(s,penalty)) subtypes = node_subtypes_penalty;
3162  else if (lua_key_eq(s,kern)) subtypes = node_subtypes_kern;
3163  else if (lua_key_eq(s,rule)) subtypes = node_subtypes_rule;
3164  else if (lua_key_eq(s,list)
3165  || lua_key_eq(s,hlist)
3166  || lua_key_eq(s,vlist)) subtypes = node_subtypes_list; /* too many but ok as reserved */
3167  else if (lua_key_eq(s,adjust)) subtypes = node_subtypes_adjust;
3168  else if (lua_key_eq(s,disc)) subtypes = node_subtypes_disc;
3169  else if (lua_key_eq(s,fill)) subtypes = node_values_fill;
3170  else if (lua_key_eq(s,leader)) subtypes = node_subtypes_leader;
3171  else if (lua_key_eq(s,marginkern)) subtypes = node_subtypes_marginkern;
3172  else if (lua_key_eq(s,math)) subtypes = node_subtypes_math;
3173  else if (lua_key_eq(s,noad)) subtypes = node_subtypes_noad;
3174  else if (lua_key_eq(s,radical)) subtypes = node_subtypes_radical;
3175  else if (lua_key_eq(s,accent)) subtypes = node_subtypes_accent;
3176  else if (lua_key_eq(s,fence)) subtypes = node_subtypes_fence;
3177  /* backend */
3178  else if (lua_key_eq(s,pdf_destination)) subtypes = node_values_pdf_destination;
3179  else if (lua_key_eq(s,pdf_literal)) subtypes = node_values_pdf_literal;
3180  } else if (t == LUA_TNUMBER) {
3181  /* maybe */
3182  t = lua_tointeger(L,1);
3183  if (t == glyph_node) subtypes = node_subtypes_glyph;
3184  else if (t == glue_node) subtypes = node_subtypes_glue;
3185  else if (t == dir_node) subtypes = node_subtypes_dir;
3186  else if (t == boundary_node) subtypes = node_subtypes_boundary;
3187  else if (t == penalty_node) subtypes = node_subtypes_penalty;
3188  else if (t == kern_node) subtypes = node_subtypes_kern;
3189  else if (t == rule_node) subtypes = node_subtypes_rule;
3190  else if((t == hlist_node)
3191  || (t == vlist_node)) subtypes = node_subtypes_list;
3192  else if (t == adjust_node) subtypes = node_subtypes_adjust;
3193  else if (t == disc_node) subtypes = node_subtypes_disc;
3194  else if (t == glue_spec_node) subtypes = node_values_fill;
3195  else if (t == margin_kern_node) subtypes = node_subtypes_marginkern;
3196  else if (t == math_node) subtypes = node_subtypes_math;
3197  else if (t == simple_noad) subtypes = node_subtypes_noad;
3198  else if (t == radical_noad) subtypes = node_subtypes_radical;
3199  else if (t == accent_noad) subtypes = node_subtypes_accent;
3200  else if (t == fence_noad) subtypes = node_subtypes_fence;
3201  /* backend */
3202  else if (t == pdf_dest_node) subtypes = node_values_pdf_destination;
3203  else if (t == pdf_literal_node) subtypes = node_values_pdf_literal;
3204  }
3205  if (subtypes != NULL) {
3206  lua_checkstack(L, 2);
3207  lua_newtable(L);
3208  for (i = 0; subtypes[i].id >= 0 ; i++) {
3209  lua_rawgeti(L, LUA_REGISTRYINDEX, subtypes[i].lua);
3210  lua_rawseti(L, -2, subtypes[i].id);
3211  }
3212  } else {
3213  lua_pushnil(L);
3214  }
3215  return 1;
3216 }
3217 
3218 /* node.slide (find the end of a list and add prev links) */
3219 
3221 {
3222  halfword n;
3223  if (lua_isnil(L, 1))
3224  return 1; /* the nil itself */
3225  n = *check_isnode(L, 1);
3226  if (n == null)
3227  return 1; /* the old userdata */
3228  /* alink(t) = null; */ /* don't do this, |t|'s |alink| may be a valid pointer */
3229  while (vlink(n) != null) {
3230  alink(vlink(n)) = n;
3231  n = vlink(n);
3232  }
3234  return 1;
3235 }
3236 
3237 /* node.direct.slide */
3238 
3240 {
3241  halfword n = lua_tointeger(L, 1);
3242  if (n == null) {
3243  lua_pushnil(L);
3244  } else {
3245  while (vlink(n) != null) {
3246  alink(vlink(n)) = n;
3247  n = vlink(n);
3248  }
3249  lua_pushinteger(L, n);
3250  }
3251  return 1;
3252 }
3253 
3254 /* node.tail (find the end of a list) */
3255 
3257 {
3258  halfword n;
3259  if (lua_isnil(L, 1))
3260  return 1; /* the nil itself */
3261  n = *check_isnode(L, 1);
3262  if (n == null)
3263  return 1; /* the old userdata */
3264  while (vlink(n) != null)
3265  n = vlink(n);
3267  return 1;
3268 }
3269 
3270 /* node.direct.tail */
3271 
3273 {
3274  halfword n = lua_tointeger(L, 1);
3275  if (n == null) {
3276  lua_pushnil(L);
3277  } else {
3278  while (vlink(n) != null)
3279  n = vlink(n);
3280  lua_pushinteger(L, n);
3281  }
3282  return 1;
3283 }
3284 
3285 /* node.end_of_math (skip over math and return last) */
3286 
3288 {
3289  halfword n;
3290  if (lua_isnil(L, 1))
3291  return 0;
3292  n = *check_isnode(L, 1);
3293  if (n == null)
3294  return 0;
3295  if (type(n) == math_node && (subtype(n) == 1)) {
3297  return 1;
3298  }
3299  while (vlink(n) != null) {
3300  n = vlink(n);
3301  if (n && (type(n) == math_node) && (subtype(n) == 1)) {
3303  return 1;
3304  }
3305  }
3306  return 0;
3307 }
3308 
3309 /* node.direct.end_of_math */
3310 
3312 {
3313  halfword n = lua_tointeger(L, 1);
3314  if (n == null)
3315  return 0;
3316  if ((type(n)==math_node && (subtype(n)==1))) {
3317  lua_pushinteger(L, n);
3318  return 1;
3319  }
3320  while (vlink(n) != null) {
3321  n = vlink(n);
3322  if (n && (type(n)==math_node) && (subtype(n)==1)) {
3323  lua_pushinteger(L, n);
3324  return 1;
3325  }
3326  }
3327  return 0;
3328 }
3329 
3330 
3331 /* node.has_attribute (gets attribute) */
3332 
3334 {
3335  int i, val;
3336  halfword n = *check_isnode(L, 1);
3337  if (n != null) {
3338  i = lua_tointeger(L, 2);
3340  if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
3341  lua_pushinteger(L, val);
3342  return 1;
3343  }
3344  }
3345  lua_pushnil(L);
3346  return 1;
3347 }
3348 
3349 /* node.direct.has_attribute */
3350 
3352 {
3353  int i, val;
3354  halfword n = lua_tointeger(L, 1);
3355  if (n != null) {
3356  i = lua_tointeger(L, 2);
3358  if ((val = has_attribute(n, i, val)) > UNUSED_ATTRIBUTE) {
3359  lua_pushinteger(L, val);
3360  return 1;
3361  }
3362  }
3363  lua_pushnil(L);
3364  return 1;
3365 }
3366 
3367 /* node.get_attribute */
3368 
3370 {
3371  halfword p = *check_isnode(L, 1);
3372  if (nodetype_has_attributes(type(p))) {
3373  p = node_attr(p);
3374  if (p != null) {
3375  p = vlink(p);
3376  if (p != null) {
3377  int i = 0;
3378  if (lua_gettop(L) > 1) {
3379  i = lua_tointeger(L, 2);
3380  }
3381  while (p != null) {
3382  if (attribute_id(p) == i) {
3383  int ret = attribute_value(p);
3384  if (ret == UNUSED_ATTRIBUTE) {
3385  break;
3386  } else {
3388  return 1;
3389  }
3390  } else if (attribute_id(p) > i) {
3391  break;
3392  }
3393  p = vlink(p);
3394  }
3395  }
3396  }
3397  }
3398  lua_pushnil(L);
3399  return 1;
3400 }
3401 
3402 static int lua_nodelib_find_attribute(lua_State * L) /* returns attr value and node */
3403 {
3404  halfword c = *check_isnode(L, 1);
3405  halfword p ;
3406  int i = lua_tointeger(L, 2);
3407  while (c != null) {
3408  if (nodetype_has_attributes(type(c))) {
3409  p = node_attr(c);
3410  if (p != null) {
3411  p = vlink(p);
3412  while (p != null) {
3413  if (attribute_id(p) == i) {
3414  int ret = attribute_value(p);
3415  if (ret == UNUSED_ATTRIBUTE) {
3416  break;
3417  } else {
3420  return 2;
3421  }
3422  } else if (attribute_id(p) > i) {
3423  break;
3424  }
3425  p = vlink(p);
3426  }
3427  }
3428  }
3429  c = vlink(c);
3430  }
3431  /*
3432  lua_pushnil(L);
3433  lua_pushnil(L);
3434  return 2;
3435  */
3436  return 0;
3437 }
3438 
3439 /* node.direct.get_attribute */
3440 /* node.direct.set_attribute */
3441 /* node.direct.unset_attribute */
3442 /* node.direct.find_attribute */
3443 
3445 {
3446  register halfword p = lua_tointeger(L, 1);
3447  if (nodetype_has_attributes(type(p))) {
3448  p = node_attr(p);
3449  if (p != null) {
3450  p = vlink(p);
3451  if (p != null) {
3452  int i = 0;
3453  if (lua_gettop(L) > 1) {
3454  i = lua_tointeger(L, 2);
3455  }
3456  while (p != null) {
3457  if (attribute_id(p) == i) {
3458  int ret = attribute_value(p);
3459  if (ret == UNUSED_ATTRIBUTE) {
3460  break;
3461  } else {
3463  return 1;
3464  }
3465  } else if (attribute_id(p) > i) {
3466  break;
3467  }
3468  p = vlink(p);
3469  }
3470  }
3471  }
3472  }
3473  lua_pushnil(L);
3474  return 1;
3475 }
3476 
3478 {
3479  int i, val;
3480  halfword n = lua_tointeger(L, 1);
3481  if (n == null)
3482  return 0;
3483  if (lua_gettop(L) == 3) {
3484  i = (int) lua_tointeger(L, 2);
3485  val = (int) lua_tointeger(L, 3);
3486  if (val == UNUSED_ATTRIBUTE) {
3487  (void) unset_attribute(n, i, val);
3488  } else {
3489  set_attribute(n, i, val);
3490  }
3491  } else {
3492  luaL_error(L, "incorrect number of arguments");
3493  }
3494  return 0;
3495 }
3496 
3497 static int lua_nodelib_direct_find_attribute(lua_State * L) /* returns attr value and node */
3498 {
3499  halfword c = lua_tointeger(L, 1);
3500  halfword p ;
3501  int i = lua_tointeger(L, 2);
3502  while (c != null) {
3503  if (nodetype_has_attributes(type(c))) {
3504  p = node_attr(c);
3505  if (p != null) {
3506  p = vlink(p);
3507  while (p != null) {
3508  if (attribute_id(p) == i) {
3509  int ret = attribute_value(p);
3510  if (ret == UNUSED_ATTRIBUTE) {
3511  break;
3512  } else {
3514  lua_pushinteger(L,c);
3515  return 2;
3516  }
3517  } else if (attribute_id(p) > i) {
3518  break;
3519  }
3520  p = vlink(p);
3521  }
3522  }
3523  }
3524  c = vlink(c);
3525  }
3526  /*
3527  lua_pushnil(L);
3528  lua_pushnil(L);
3529  return 2;
3530  */
3531  return 0;
3532 }
3533 
3535 {
3536  halfword n = lua_tointeger(L, 1);
3537  if (n == null) {
3538  lua_pushnil(L);
3539  } else if (lua_gettop(L) <= 3) { /* a useless test, we never test for that elsewhere */
3540  int i = (int)luaL_checknumber(L, 2);
3541  int val = (int)luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
3542  int ret = unset_attribute(n, i, val);
3543  if (ret > UNUSED_ATTRIBUTE) {
3544  lua_pushinteger(L, ret);
3545  } else {
3546  lua_pushnil(L);
3547  }
3548  } else { /* can go */
3549  return luaL_error(L, "incorrect number of arguments");
3550  }
3551  return 1;
3552 }
3553 
3554 /* node.set_attribute */
3555 /* node.unset_attribute */
3556 
3558 {
3559  if (lua_gettop(L) == 3) {
3560  int i = lua_tointeger(L, 2);
3561  int val = lua_tointeger(L, 3);
3562  halfword n = *check_isnode(L, 1);
3563  if (val == UNUSED_ATTRIBUTE) {
3564  (void) unset_attribute(n, i, val);
3565  } else {
3566  set_attribute(n, i, val);
3567  }
3568  } else {
3569  luaL_error(L, "incorrect number of arguments");
3570  }
3571  return 0;
3572 }
3573 
3575 {
3576  if (lua_gettop(L) <= 3) {
3577  int i = luaL_checknumber(L, 2);
3578  int val = luaL_optnumber(L, 3, UNUSED_ATTRIBUTE);
3579  halfword n = *check_isnode(L, 1);
3580  int ret = unset_attribute(n, i, val);
3581  if (ret > UNUSED_ATTRIBUTE) {
3582  lua_pushinteger(L, ret);
3583  } else {
3584  lua_pushnil(L);
3585  }
3586  return 1;
3587  } else {
3588  return luaL_error(L, "incorrect number of arguments");
3589  }
3590 }
3591 
3592 /* node.direct.getwidth */
3593 /* node.direct.setwidth */
3594 /* node.direct.getheight (for consistency) */
3595 /* node.direct.setheight (for consistency) */
3596 /* node.direct.getdepth (for consistency) */
3597 /* node.direct.setdepth (for consistency) */
3598 
3599 /* split ifs for clearity .. compiler will optimize */
3600 
3602 {
3603  halfword n = lua_tointeger(L, 1);
3604  if (n) {
3605  halfword t = type(n);
3606  if (t == hlist_node || t == vlist_node || t == rule_node) {
3608  } else if (t == glyph_node) {
3610  if (lua_toboolean(L,2)) {
3612  return 2;
3613  }
3614  } else if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
3616  } else if (t == kern_node) {
3617  lua_pushinteger(L, width(n));
3618  if (lua_toboolean(L,2)) {
3620  return 2;
3621  }
3622  } else if (t == margin_kern_node) {
3624  } else if (t == unset_node) {
3626  } else {
3627  lua_pushnil(L);
3628  }
3629  } else {
3630  lua_pushnil(L);
3631  }
3632  return 1;
3633 }
3634 
3636 {
3637  halfword n = lua_tointeger(L, 1);
3638  if (n) {
3639  halfword t = type(n);
3640  if (t == hlist_node || t == vlist_node || t == rule_node || t == glue_node || t == glue_spec_node || t == math_node ||
3641  t == kern_node || t == margin_kern_node || t == ins_node || t == unset_node ||
3642  t == fraction_noad || t == radical_noad ) {
3643  if (lua_type(L, 2) == LUA_TNUMBER) {
3644  width(n) = lua_roundnumber(L,2);
3645  } else {
3646  width(n) = 0;
3647  }
3648  }
3649  }
3650  return 0;
3651 }
3652 
3654 {
3655  halfword n = lua_tointeger(L, 1);
3656  if (n) {
3657  halfword t = type(n);
3658  if (t == hlist_node || t == vlist_node || t == rule_node) {
3660  } else if (t == glyph_node) {
3662  } else if (t == unset_node || t == ins_node) {
3664  } else if (t == fence_noad) {
3666  } else {
3667  lua_pushnil(L);
3668  }
3669  } else {
3670  lua_pushnil(L);
3671  }
3672  return 1;
3673 }
3674 
3676 {
3677  halfword n = lua_tointeger(L, 1);
3678  if (n) {
3679  halfword t = type(n);
3680  halfword h = 0;
3681  if (lua_type(L, 2) == LUA_TNUMBER) {
3682  h = lua_roundnumber(L,2);
3683  }
3684  if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) {
3685  height(n) = h;
3686  } else if (t == fence_noad) {
3687  delimiterheight(n) = h;
3688  }
3689  }
3690  return 0;
3691 }
3692 
3694 {
3695  halfword n = lua_tointeger(L, 1);
3696  if (n) {
3697  halfword t = type(n);
3698  if (t == hlist_node || t == vlist_node || t == rule_node) {
3700  } else if (t == glyph_node) {
3702  } else if (t == unset_node || t == ins_node) {
3704  } else if (t == fence_noad) {
3706  } else {
3707  lua_pushnil(L);
3708  }
3709  } else {
3710  lua_pushnil(L);
3711  }
3712  return 1;
3713 }
3714 
3716 {
3717  halfword n = lua_tointeger(L, 1);
3718  if (n) {
3719  halfword t = type(n);
3720  halfword d = 0;
3721  if (lua_type(L, 2) == LUA_TNUMBER) {
3722  d = lua_roundnumber(L,2);
3723  }
3724  if (t == hlist_node || t == vlist_node || t == rule_node || t == unset_node) {
3725  depth(n) = d;
3726  } else if (t == fence_noad) {
3727  delimiterdepth(n) = d;
3728  }
3729  }
3730  return 0;
3731 }
3732 
3733 /* node.direct.getshift */
3734 /* node.direct.setshift */
3735 
3737 {
3738  halfword n = lua_tointeger(L, 1);
3739  if (n) {
3740  halfword t = type(n);
3741  if (t == hlist_node || t == vlist_node) {
3743  return 1;
3744  }
3745  }
3746  lua_pushnil(L);
3747  return 1;
3748 }
3749 
3751 {
3752  halfword n = lua_tointeger(L, 1);
3753  if (n) {
3754  halfword t = type(n);
3755  if (t == hlist_node || t == vlist_node) {
3756  if (lua_type(L, 2) == LUA_TNUMBER) {
3758  } else {
3759  shift_amount(n) = 0;
3760  }
3761  }
3762  }
3763  return 0;
3764 }
3765 
3766 /* node.direct.getglue */
3767 /* node.direct.setglue */
3768 /* node.direct.is_zero_glue */
3769 
3771 {
3772  halfword n = lua_tointeger(L, 1);
3773  if (n) {
3774  halfword t = type(n);
3775  if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
3781  return 5;
3782  } else if (t == hlist_node || t == vlist_node) {
3783  lua_pushnumber(L, (double) glue_set(n)); /* float */
3786  return 3;
3787  }
3788  }
3789  return 0;
3790 }
3791 
3793 {
3794  halfword n = lua_tointeger(L, 1);
3795  if (n) {
3796  int top = lua_gettop(L);
3797  halfword t = type(n);
3798  if (t == glue_node || t == glue_spec_node || t == math_node) {
3799  width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
3800  stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
3801  shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
3802  stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
3803  shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
3804  } else if (t == hlist_node || t == vlist_node) {
3805  glue_set(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? (glue_ratio) lua_tonumber(L,2) : 0;
3806  glue_order(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
3807  glue_sign(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
3808  return 3;
3809  }
3810  }
3811  return 0;
3812 }
3813 
3815 {
3816  halfword n = lua_tointeger(L, 1);
3817  if (n) {
3818  halfword t = type(n);
3819  if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
3820  lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
3821  return 1;
3822  } else if (t == hlist_node || t == vlist_node) {
3823  lua_pushboolean(L,(glue_set(n) == 0 && glue_order(n) == 0 && glue_sign(n) == 0));
3824  return 1;
3825  }
3826  }
3827  return 0;
3828 }
3829 
3830 /* node.getglue */
3831 /* node.setglue */
3832 /* node.is_zero_glue */
3833 
3835 {
3836  halfword n = *check_isnode(L, 1);
3837  if (n) {
3838  halfword t = type(n);
3839  if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
3845  return 5;
3846  } else if (t == hlist_node || t == vlist_node) {
3847  lua_pushnumber(L, (double) glue_set(n)); /* float */
3850  return 3;
3851  }
3852  }
3853  return luaL_error(L, "glue (spec) or list expected");
3854 }
3855 
3857 {
3858  halfword n = *check_isnode(L, 1);
3859  int top = lua_gettop(L) ;
3860  if (n) {
3861  halfword t = type(n);
3862  if (t == glue_node || t == glue_spec_node || t == math_node) {
3863  width(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? lua_roundnumber(L,2) : 0;
3864  stretch(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_roundnumber(L,3) : 0;
3865  shrink(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_roundnumber(L,4) : 0;
3866  stretch_order(n) = ((top > 4 && lua_type(L, 5) == LUA_TNUMBER)) ? lua_tointeger(L,5) : 0;
3867  shrink_order(n) = ((top > 5 && lua_type(L, 6) == LUA_TNUMBER)) ? lua_tointeger(L,6) : 0;
3868  } else if (t == hlist_node || t == vlist_node) {
3869  glue_set(n) = ((top > 1 && lua_type(L, 2) == LUA_TNUMBER)) ? (glue_ratio) lua_tonumber(L,2) : 0;
3870  glue_order(n) = ((top > 2 && lua_type(L, 3) == LUA_TNUMBER)) ? lua_tointeger(L,3) : 0;
3871  glue_sign(n) = ((top > 3 && lua_type(L, 4) == LUA_TNUMBER)) ? lua_tointeger(L,4) : 0;
3872  return 3;
3873  }
3874  return 0;
3875  }
3876  return luaL_error(L, "glue (spec) or list expected");
3877 }
3878 
3880 {
3881  halfword n = *check_isnode(L, 1);
3882  if (n != null) {
3883  halfword t = type(n);
3884  if (t == glue_node || t == glue_spec_node || t == math_node || t == ins_node) {
3885  lua_pushboolean(L,(width(n) == 0 && stretch(n) == 0 && shrink(n) == 0));
3886  return 1;
3887  } else if (t == hlist_node || t == vlist_node) {